UNPKG

@localsecurity/name-id

Version:

A utility to create and parse lexicographically sortable ID's with embeded model names and created timestamp

169 lines (124 loc) 3.67 kB
# @localsecurity/name-id A tiny TypeScript utility to create and parse lexicographically sortable IDs with embedded model names and creation timestamps. > **Use case:** Durable, globally unique IDs for NoSQL or single-table designs that sort newest-first. ## ✨ Features ✅ Generates stable IDs in the format: `model` _ `reversedTimestamp` `random` ✅ Converts legacy UUIDs to sortable IDs ✅ Extracts model name and timestamp ✅ Zero dependencies (besides `@localsecurity/types`) ✅ TypeScript-native with branded types for safety ## 🚀 Install ```bash npm install @localsecurity/name-id ``` ## 🔧 Usage ### Create a NameID ```ts import { NameID } from "@localsecurity/name-id"; // From a model name const id1 = new NameID("User"); console.log(id1.value); // => user_k9z8a1abcdef234567... // From an existing object with __typename and createdAt const id2 = new NameID({ __typename: "CameraEvent", createdAt: "2024-07-01T00:00:00.000Z" }); console.log(id2.value); // => cameraevent_k9z8a1abcdef234567... ``` ### Parse a NameID ```ts const parsed = NameID.parse(id1.value); console.log(parsed.name); // "User" console.log(parsed.timestamp); // Date ``` ### Type Guards ```ts import { isNameId, isUUID } from "@localsecurity/name-id"; isNameId("user_abc..."); // true isUUID("xxxxxxx-xxxx..."); // true ``` ### MutableModel You can extend MutableModel to get a base class with automatic nameId and timestamps: ```ts import { MutableModel } from "@localsecurity/name-id"; class MyModel extends MutableModel { data: string; constructor(init: Partial<MyModel>) { super("User"); Object.assign(this, init); } } ``` ### Example Worker ```ts import { Model } from '@localsecurity/types'; import { ModelName, NameID, NameIdString, isModelName } from "@localsecurity/name-id"; const ErrorResponse = (e: any) => Response.json({ error: e }, { status: 500 }); /** * Handle a request with a Model Name in the body */ async function handleName(request: Request) { const __typename = await request.text(); const execute = () => { if (isModelName(__typename)) { const nameId = new NameID(__typename).value; const createdAt = NameID.parse(nameId).timestamp.toISOString(); return Response.json({ nameId, createdAt, __typename }); } else { return ErrorResponse(`Not a valid Model Name ('${__typename}')`) } } try { return execute() } catch (e: any) { return ErrorResponse(e) } }; /** * Handle a request with a Model Object in the body */ async function handleObject(request: Request) { const object: Model[ModelName] = await request.json(); const __typename = object['__typename']; const execute = () => { if (isModelName(__typename)) { const nameId: NameIdString = new NameID(object).value; return Response.json({ nameId, ...object }); } else { return ErrorResponse(`Not a valid Model Name ('${__typename}')`) } } try { return execute() } catch (e: any) { return ErrorResponse(e) } }; /** * Worker entrypoint */ export default { async fetch(request: Request, env: any, ctx: any) { const contentType = request.headers.get("content-type") ?? ''; const execute = () => { if (contentType.includes("json")) return handleObject(request) else return handleName(request) } try { return execute() } catch (e: any) { return ErrorResponse(e) } } }; ``` ## 🧑‍💻 Development Build: ```bash npm run build ``` Lint: ```bash npm run lint ``` Format: ```bash npm run format ``` Bundle ESM: ```bash npm run bundle ``` ## 📄 License MIT © LocalSecurity