Files
pos/client/node_modules/nanoid/async/index.browser.js
jason d53c772dd6 Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00

35 lines
984 B
JavaScript

let random = async bytes => crypto.getRandomValues(new Uint8Array(bytes))
let customAlphabet = (alphabet, defaultSize = 21) => {
let mask = (2 << (Math.log(alphabet.length - 1) / Math.LN2)) - 1
let step = -~((1.6 * mask * defaultSize) / alphabet.length)
return async (size = defaultSize) => {
let id = ''
while (true) {
let bytes = crypto.getRandomValues(new Uint8Array(step))
let i = step | 0
while (i--) {
id += alphabet[bytes[i] & mask] || ''
if (id.length === size) return id
}
}
}
}
let nanoid = async (size = 21) => {
let id = ''
let bytes = crypto.getRandomValues(new Uint8Array((size |= 0)))
while (size--) {
let byte = bytes[size] & 63
if (byte < 36) {
id += byte.toString(36)
} else if (byte < 62) {
id += (byte - 26).toString(36).toUpperCase()
} else if (byte < 63) {
id += '_'
} else {
id += '-'
}
}
return id
}
export { nanoid, customAlphabet, random }