@localsecurity/name-id
v1.1.0
Published
A utility to create and parse lexicographically sortable ID's with embeded model names and created timestamp
Readme
@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
npm install @localsecurity/name-id🔧 Usage
Create a NameID
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
const parsed = NameID.parse(id1.value);
console.log(parsed.name); // "User"
console.log(parsed.timestamp); // DateType Guards
import { isNameId, isUUID } from "@localsecurity/name-id";
isNameId("user_abc..."); // true
isUUID("xxxxxxx-xxxx..."); // trueMutableModel
You can extend MutableModel to get a base class with automatic nameId and timestamps:
import { MutableModel } from "@localsecurity/name-id";
class MyModel extends MutableModel {
data: string;
constructor(init: Partial<MyModel>) {
super("User");
Object.assign(this, init);
}
}Example Worker
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:
npm run buildLint:
npm run lintFormat:
npm run formatBundle ESM:
npm run bundle📄 License
MIT © LocalSecurity
