@lowerdeck/id 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+
2
+ $ microbundle
3
+ No name was provided for external module '@lowerdeck/error' in output.globals – guessing 'error'
4
+ No name was provided for external module '@lowerdeck/hash' in output.globals – guessing 'hash'
5
+ Build "@lowerdeck/id" to dist:
6
+ 1164 B: index.cjs.gz
7
+ 1029 B: index.cjs.br
8
+ 1057 B: index.modern.js.gz
9
+ 938 B: index.modern.js.br
10
+ 1130 B: index.module.js.gz
11
+ 1010 B: index.module.js.br
12
+ 1247 B: index.umd.js.gz
13
+ 1109 B: index.umd.js.br
@@ -0,0 +1,21 @@
1
+
2
+ $ vitest run --passWithNoTests
3
+ [?25l
4
+  RUN  v3.2.4 /Users/tobias/code/metorial/metorial-enterprise/oss/src/packages/shared/id
5
+
6
+ [?2026h
7
+  ❯ src/id.test.ts [queued]
8
+
9
+  Test Files 0 passed (1)
10
+  Tests 0 passed (0)
11
+  Start at 10:23:46
12
+  Duration 101ms
13
+ [?2026l ✓ src/id.test.ts (1 test) 2ms
14
+ ✓ id > generateId 1ms
15
+
16
+  Test Files  1 passed (1)
17
+  Tests  1 passed (1)
18
+  Start at  10:23:46
19
+  Duration  270ms (transform 65ms, setup 0ms, collect 83ms, tests 2ms, environment 0ms, prepare 41ms)
20
+
21
+ [?25h
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # `@lowerdeck/id`
2
+
3
+ Generate various types of unique IDs with prefixes. Supports sorted IDs with timestamps, unsorted random IDs, key IDs with checksums, and Snowflake-style distributed IDs.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @lowerdeck/id
9
+ yarn add @lowerdeck/id
10
+ bun add @lowerdeck/id
11
+ pnpm add @lowerdeck/id
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ### Sorted IDs (with timestamp)
17
+
18
+ ```typescript
19
+ import { generateId } from '@lowerdeck/id';
20
+
21
+ // Generate sorted ID with timestamp prefix
22
+ const id = generateId('user', 16);
23
+ console.log(id); // 'user_01HQRS9Z3K7M2N5P'
24
+
25
+ // IDs are sortable by creation time
26
+ const id1 = generateId('order');
27
+ const id2 = generateId('order');
28
+ console.log(id1 < id2); // true
29
+ ```
30
+
31
+ ### Unsorted Random IDs
32
+
33
+ ```typescript
34
+ import { generateCustomId } from '@lowerdeck/id';
35
+
36
+ // Generate random ID
37
+ const id = generateCustomId('session', 24);
38
+ console.log(id); // 'session_abc123xyz789'
39
+
40
+ // Without prefix
41
+ const randomId = generateCustomId(undefined, 16);
42
+ ```
43
+
44
+ ### Plain IDs and Codes
45
+
46
+ ```typescript
47
+ import { generatePlainId, generateCode } from '@lowerdeck/id';
48
+
49
+ // Alphanumeric string
50
+ const plainId = generatePlainId(12);
51
+ console.log(plainId); // 'aBc123XyZ456'
52
+
53
+ // Numeric code
54
+ const code = generateCode(6);
55
+ console.log(code); // '123456'
56
+ ```
57
+
58
+ ### Snowflake IDs
59
+
60
+ ```typescript
61
+ import { generateSnowflakeId } from '@lowerdeck/id';
62
+
63
+ // Generate distributed ID
64
+ const snowflake = generateSnowflakeId('sf');
65
+ console.log(snowflake); // 'sf_1234567890123456789'
66
+ ```
67
+
68
+ ### Type-safe ID Generator
69
+
70
+ ```typescript
71
+ import { createIdGenerator } from '@lowerdeck/id';
72
+
73
+ const ids = createIdGenerator({
74
+ user: 'user',
75
+ order: 'order',
76
+ session: 'session'
77
+ });
78
+
79
+ // Type-safe ID generation
80
+ const userId = ids.user(); // 'user_...'
81
+ const orderId = ids.order(); // 'order_...'
82
+ ```
83
+
84
+ ## License
85
+
86
+ This project is licensed under the Apache License 2.0.
87
+
88
+ <div align="center">
89
+ <sub>Built with ❤️ by <a href="https://metorial.com">Metorial</a></sub>
90
+ </div>
package/dist/id.d.ts ADDED
@@ -0,0 +1,41 @@
1
+ import short from 'short-uuid';
2
+ export declare let idTime: () => string;
3
+ export declare let idType: {
4
+ sorted: (prefix: string, length?: number) => {
5
+ prefix: string;
6
+ length: number;
7
+ type: "sorted";
8
+ };
9
+ unsorted: (prefix: string, length?: number) => {
10
+ prefix: string;
11
+ length: number;
12
+ type: "unsorted";
13
+ };
14
+ key: (prefix: string, length?: number) => {
15
+ prefix: string;
16
+ length: number;
17
+ type: "key";
18
+ };
19
+ };
20
+ export declare let createIdGenerator: <T extends {
21
+ [key: string]: {
22
+ prefix: string;
23
+ length: number;
24
+ type: "sorted" | "key" | "unsorted";
25
+ };
26
+ }>(idPrefixes: T) => {
27
+ generateId: (prefix: keyof T) => Promise<string>;
28
+ generateIdSync: (prefix: keyof T) => string;
29
+ idPrefixes: { [key in keyof T]: string; };
30
+ normalizeUUID: (prefix: keyof T, uuid: string) => string;
31
+ };
32
+ export declare let createUuidTranslator: (prefix: string) => {
33
+ fromUUID: (uuid: string) => string;
34
+ toUUID: (id: string) => short.UUID;
35
+ };
36
+ export declare let generateCustomId: (prefix?: string, length?: number) => string;
37
+ export declare let generatePlainId: (length?: number) => string;
38
+ export declare let generateId: (prefix: string, length?: number) => string;
39
+ export declare let generateCode: (length?: number) => string;
40
+ export declare let generateSnowflakeId: (prefix?: string) => string;
41
+ //# sourceMappingURL=id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,YAAY,CAAC;AAY/B,eAAO,IAAI,MAAM,cAA2D,CAAC;AAgB7E,eAAO,IAAI,MAAM;qBACE,MAAM,WAAU,MAAM;;;;;uBASpB,MAAM,WAAU,MAAM;;;;;kBAS3B,MAAM,WAAU,MAAM;;;;;CAKrC,CAAC;AAEF,eAAO,IAAI,iBAAiB,GAC1B,CAAC,SAAS;IACR,CAAC,GAAG,EAAE,MAAM,GAAG;QACb,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,UAAU,CAAC;KACrC,CAAC;CACH,EAED,YAAY,CAAC;yBAyBgB,MAAM,CAAC;6BAkBT,MAAM,CAAC;mBAuBrB,GAAG;4BAGU,MAAM,CAAC,QAAQ,MAAM;CAoBhD,CAAC;AAEF,eAAO,IAAI,oBAAoB,GAAI,QAAQ,MAAM;qBAS5B,MAAM;iBACV,MAAM;CAYtB,CAAC;AAEF,eAAO,IAAI,gBAAgB,GAAI,SAAS,MAAM,EAAE,SAAQ,MAAW,WAIlE,CAAC;AAEF,eAAO,IAAI,eAAe,GAAI,SAAQ,MAAW,WAEhD,CAAC;AAEF,eAAO,IAAI,UAAU,GAAI,QAAQ,MAAM,EAAE,SAAQ,MAAW,WAO3D,CAAC;AAEF,eAAO,IAAI,YAAY,GAAI,SAAQ,MAAU,WAE5C,CAAC;AAEF,eAAO,IAAI,mBAAmB,GAAI,SAAS,MAAM,WAIhD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=id.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id.test.d.ts","sourceRoot":"","sources":["../src/id.test.ts"],"names":[],"mappings":""}
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ var e=require("@lowerdeck/error"),r=require("@lowerdeck/hash"),t=require("nanoid"),n=require("short-uuid"),i=require("snowflake-uuid");function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var u=/*#__PURE__*/o(n).default("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"),s=t.customAlphabet("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",20),a=t.customAlphabet("0123456789",6),f=function(){return(new Date).getTime().toString(36).padStart(9,"0")},d=new i.Worker(0,0,{workerIdBits:12,sequenceBits:12}),c=new Set,p=function(e){if(e.endsWith("_")&&(e=e.slice(0,-1)),c.has(e))throw new Error("Prefix "+e+" already exists")},h={sorted:function(e,r){return void 0===r&&(r=22),p(e),{prefix:e,length:r,type:"sorted"}},unsorted:function(e,r){return void 0===r&&(r=22),p(e),{prefix:e,length:r,type:"unsorted"}},key:function(e,r){return void 0===r&&(r=50),p(e),{prefix:e,length:r,type:"key"}}};exports.createIdGenerator=function(e){for(var t in e)e[t].prefix.endsWith("_")||(e[t].prefix=e[t].prefix+"_");var n=new Set;for(var i in e){var o=e[i].prefix;if(n.has(o))throw new Error("Prefix "+o+" already exists");n.add(o)}var a=function(r){var t=e[r];if(!t)throw new Error("Invalid prefix: "+r);return t};return{generateId:function(e){try{var t=a(e),n=t.length;if("sorted"==t.type){var i=f(),o=n-i.length;return o<10&&(o=10),Promise.resolve(""+t.prefix+i+s(o))}if("unsorted"==t.type)return Promise.resolve(""+t.prefix+s(n));var u=""+t.prefix+s(n);return Promise.resolve(r.Hash.sha512(u)).then(function(e){return""+u+e.slice(0,6)})}catch(e){return Promise.reject(e)}},generateIdSync:function(e){var r=a(e),t=r.length;if("sorted"==r.type){var n=f(),i=t-n.length;return i<10&&(i=10),""+r.prefix+n+s(i)}if("unsorted"==r.type)return""+r.prefix+s(t);throw new Error("Cannot generate key id synchronously")},idPrefixes:Object.entries(e).reduce(function(e,r){return e[r[0]]=r[1].prefix,e},{}),normalizeUUID:function(e,r){return""+a(e).prefix+u.fromUUID(r)}}},exports.createUuidTranslator=function(r){if(r.endsWith("_")||(r+="_"),c.has(r))throw new Error("Prefix "+r+" already exists");return c.add(r),{fromUUID:function(e){return""+r+u.fromUUID(e)},toUUID:function(t){if(!t.startsWith(r))throw new e.ServiceError(e.badRequestError({message:"ID "+t+" does not start with prefix "+r}));return u.toUUID(t.slice(r.length))}}},exports.generateCode=function(e){return void 0===e&&(e=6),a(e)},exports.generateCustomId=function(e,r){return void 0===r&&(r=20),e&&!e.endsWith("_")&&(e+="_"),""+e+s(r)},exports.generateId=function(e,r){void 0===r&&(r=20);var t=f(),n=r-t.length;return n<10&&(n=10),""+e+t+s(n)},exports.generatePlainId=function(e){return void 0===e&&(e=20),s(e)},exports.generateSnowflakeId=function(e){return e&&!e.endsWith("_")&&(e+="_"),""+e+d.nextId().toString(36)},exports.idTime=f,exports.idType=h;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/id.ts"],"sourcesContent":["import { ServiceError, badRequestError } from '@lowerdeck/error';\nimport { Hash } from '@lowerdeck/hash';\nimport { customAlphabet } from 'nanoid';\nimport short from 'short-uuid';\nimport { Worker } from 'snowflake-uuid';\n\nlet translator = short('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');\n\nlet _defaultId = customAlphabet(\n '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',\n 20\n);\n\nlet _code = customAlphabet('0123456789', 6);\n\nexport let idTime = () => new Date().getTime().toString(36).padStart(9, '0');\n\nlet snowflakeIdGenerator = new Worker(0, 0, {\n workerIdBits: 12,\n sequenceBits: 12\n});\n\nlet seenPrefixes = new Set<string>();\nlet checkPrefix = (prefix: string) => {\n if (prefix.endsWith('_')) prefix = prefix.slice(0, -1);\n\n if (seenPrefixes.has(prefix)) {\n throw new Error(`Prefix ${prefix} already exists`);\n }\n};\n\nexport let idType = {\n sorted: (prefix: string, length: number = 22) => {\n checkPrefix(prefix);\n\n return {\n prefix,\n length,\n type: 'sorted' as const\n };\n },\n unsorted: (prefix: string, length: number = 22) => {\n checkPrefix(prefix);\n\n return {\n prefix,\n length,\n type: 'unsorted' as const\n };\n },\n key: (prefix: string, length: number = 50) => {\n checkPrefix(prefix);\n\n return { prefix, length, type: 'key' as const };\n }\n};\n\nexport let createIdGenerator = <\n T extends {\n [key: string]: {\n prefix: string;\n length: number;\n type: 'sorted' | 'key' | 'unsorted';\n };\n }\n>(\n idPrefixes: T\n) => {\n for (let key in idPrefixes) {\n if (!idPrefixes[key].prefix.endsWith('_')) {\n idPrefixes[key].prefix = `${idPrefixes[key].prefix}_`;\n }\n }\n\n let seenPrefixes = new Set<string>();\n for (let key in idPrefixes) {\n let prefix = idPrefixes[key].prefix;\n if (seenPrefixes.has(prefix)) {\n throw new Error(`Prefix ${prefix} already exists`);\n }\n seenPrefixes.add(prefix);\n }\n\n let getIdDescription = (prefix: keyof T) => {\n let pf = idPrefixes[prefix];\n if (!pf) throw new Error(`Invalid prefix: ${prefix as string}`);\n\n return pf;\n };\n\n return {\n generateId: async (prefix: keyof T) => {\n let desc = getIdDescription(prefix);\n let length = desc.length;\n\n if (desc.type == 'sorted') {\n let date = idTime();\n\n let remainingLength = length - date.length;\n if (remainingLength < 10) remainingLength = 10;\n\n return `${desc.prefix}${date}${_defaultId(remainingLength)}`;\n } else if (desc.type == 'unsorted') {\n return `${desc.prefix}${_defaultId(length)}`;\n } else {\n let main = `${desc.prefix}${_defaultId(length)}`;\n return `${main}${(await Hash.sha512(main)).slice(0, 6)}`;\n }\n },\n generateIdSync: (prefix: keyof T) => {\n let desc = getIdDescription(prefix);\n let length = desc.length;\n\n if (desc.type == 'sorted') {\n let date = idTime();\n\n let remainingLength = length - date.length;\n if (remainingLength < 10) remainingLength = 10;\n\n return `${desc.prefix}${date}${_defaultId(remainingLength)}`;\n } else if (desc.type == 'unsorted') {\n return `${desc.prefix}${_defaultId(length)}`;\n } else {\n throw new Error('Cannot generate key id synchronously');\n }\n },\n idPrefixes: Object.entries(idPrefixes).reduce(\n (acc, [key, value]) => {\n // @ts-ignore\n acc[key] = value.prefix;\n return acc;\n },\n {} as { [key in keyof T]: string }\n ),\n\n normalizeUUID: (prefix: keyof T, uuid: string) => {\n let desc = getIdDescription(prefix);\n\n return `${desc.prefix}${translator.fromUUID(uuid)}`;\n }\n\n // toUUID: (prefix: keyof T, id: string) => {\n // let desc = getIdDescription(prefix);\n\n // if (!id.startsWith(desc.prefix)) {\n // throw new ServiceError(\n // badRequestError({\n // message: `ID ${id} does not start with prefix ${desc.prefix}`\n // })\n // );\n // }\n\n // return translator.toUUID(id.slice(desc.prefix.length));\n // }\n };\n};\n\nexport let createUuidTranslator = (prefix: string) => {\n if (!prefix.endsWith('_')) prefix = `${prefix}_`;\n\n if (seenPrefixes.has(prefix)) {\n throw new Error(`Prefix ${prefix} already exists`);\n }\n seenPrefixes.add(prefix);\n\n return {\n fromUUID: (uuid: string) => `${prefix}${translator.fromUUID(uuid)}`,\n toUUID: (id: string) => {\n if (!id.startsWith(prefix)) {\n throw new ServiceError(\n badRequestError({\n message: `ID ${id} does not start with prefix ${prefix}`\n })\n );\n }\n\n return translator.toUUID(id.slice(prefix.length));\n }\n };\n};\n\nexport let generateCustomId = (prefix?: string, length: number = 20) => {\n if (prefix && !prefix.endsWith('_')) prefix = `${prefix}_`;\n\n return `${prefix}${_defaultId(length)}`;\n};\n\nexport let generatePlainId = (length: number = 20) => {\n return _defaultId(length);\n};\n\nexport let generateId = (prefix: string, length: number = 20) => {\n let date = idTime();\n\n let remainingLength = length - date.length;\n if (remainingLength < 10) remainingLength = 10;\n\n return `${prefix}${date}${_defaultId(remainingLength)}`;\n};\n\nexport let generateCode = (length: number = 6) => {\n return _code(length);\n};\n\nexport let generateSnowflakeId = (prefix?: string) => {\n if (prefix && !prefix.endsWith('_')) prefix = `${prefix}_`;\n\n return `${prefix}${snowflakeIdGenerator.nextId().toString(36)}`;\n};\n"],"names":["translator","_defaultId","customAlphabet","_code","idTime","Date","getTime","toString","padStart","snowflakeIdGenerator","Worker","workerIdBits","sequenceBits","seenPrefixes","Set","checkPrefix","prefix","endsWith","slice","has","Error","idType","sorted","length","type","unsorted","key","idPrefixes","add","getIdDescription","pf","generateId","desc","date","remainingLength","Promise","resolve","main","Hash","sha512","then","_Hash$sha","e","reject","generateIdSync","Object","entries","reduce","acc","_ref","normalizeUUID","uuid","fromUUID","toUUID","id","startsWith","ServiceError","badRequestError","message","nextId"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from './id';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,MAAM,CAAC"}
@@ -0,0 +1,2 @@
1
+ import{ServiceError as e,badRequestError as r}from"@lowerdeck/error";import{Hash as t}from"@lowerdeck/hash";import{customAlphabet as i}from"nanoid";import n from"short-uuid";import{Worker as o}from"snowflake-uuid";let s=n("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"),f=i("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",20),d=i("0123456789",6),l=()=>(new Date).getTime().toString(36).padStart(9,"0"),$=new o(0,0,{workerIdBits:12,sequenceBits:12}),a=new Set,h=e=>{if(e.endsWith("_")&&(e=e.slice(0,-1)),a.has(e))throw new Error(`Prefix ${e} already exists`)},p={sorted:(e,r=22)=>(h(e),{prefix:e,length:r,type:"sorted"}),unsorted:(e,r=22)=>(h(e),{prefix:e,length:r,type:"unsorted"}),key:(e,r=50)=>(h(e),{prefix:e,length:r,type:"key"})},x=e=>{for(let r in e)e[r].prefix.endsWith("_")||(e[r].prefix=`${e[r].prefix}_`);let r=new Set;for(let t in e){let i=e[t].prefix;if(r.has(i))throw new Error(`Prefix ${i} already exists`);r.add(i)}let i=r=>{let t=e[r];if(!t)throw new Error(`Invalid prefix: ${r}`);return t};return{generateId:async e=>{let r=i(e),n=r.length;if("sorted"==r.type){let e=l(),t=n-e.length;return t<10&&(t=10),`${r.prefix}${e}${f(t)}`}if("unsorted"==r.type)return`${r.prefix}${f(n)}`;{let e=`${r.prefix}${f(n)}`;return`${e}${(await t.sha512(e)).slice(0,6)}`}},generateIdSync:e=>{let r=i(e),t=r.length;if("sorted"==r.type){let e=l(),i=t-e.length;return i<10&&(i=10),`${r.prefix}${e}${f(i)}`}if("unsorted"==r.type)return`${r.prefix}${f(t)}`;throw new Error("Cannot generate key id synchronously")},idPrefixes:Object.entries(e).reduce((e,[r,t])=>(e[r]=t.prefix,e),{}),normalizeUUID:(e,r)=>`${i(e).prefix}${s.fromUUID(r)}`}},w=t=>{if(t.endsWith("_")||(t=`${t}_`),a.has(t))throw new Error(`Prefix ${t} already exists`);return a.add(t),{fromUUID:e=>`${t}${s.fromUUID(e)}`,toUUID:i=>{if(!i.startsWith(t))throw new e(r({message:`ID ${i} does not start with prefix ${t}`}));return s.toUUID(i.slice(t.length))}}},u=(e,r=20)=>(e&&!e.endsWith("_")&&(e=`${e}_`),`${e}${f(r)}`),y=(e=20)=>f(e),g=(e,r=20)=>{let t=l(),i=r-t.length;return i<10&&(i=10),`${e}${t}${f(i)}`},m=(e=6)=>d(e),I=e=>(e&&!e.endsWith("_")&&(e=`${e}_`),`${e}${$.nextId().toString(36)}`);export{x as createIdGenerator,w as createUuidTranslator,m as generateCode,u as generateCustomId,g as generateId,y as generatePlainId,I as generateSnowflakeId,l as idTime,p as idType};
2
+ //# sourceMappingURL=index.modern.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.modern.js","sources":["../src/id.ts"],"sourcesContent":["import { ServiceError, badRequestError } from '@lowerdeck/error';\nimport { Hash } from '@lowerdeck/hash';\nimport { customAlphabet } from 'nanoid';\nimport short from 'short-uuid';\nimport { Worker } from 'snowflake-uuid';\n\nlet translator = short('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');\n\nlet _defaultId = customAlphabet(\n '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',\n 20\n);\n\nlet _code = customAlphabet('0123456789', 6);\n\nexport let idTime = () => new Date().getTime().toString(36).padStart(9, '0');\n\nlet snowflakeIdGenerator = new Worker(0, 0, {\n workerIdBits: 12,\n sequenceBits: 12\n});\n\nlet seenPrefixes = new Set<string>();\nlet checkPrefix = (prefix: string) => {\n if (prefix.endsWith('_')) prefix = prefix.slice(0, -1);\n\n if (seenPrefixes.has(prefix)) {\n throw new Error(`Prefix ${prefix} already exists`);\n }\n};\n\nexport let idType = {\n sorted: (prefix: string, length: number = 22) => {\n checkPrefix(prefix);\n\n return {\n prefix,\n length,\n type: 'sorted' as const\n };\n },\n unsorted: (prefix: string, length: number = 22) => {\n checkPrefix(prefix);\n\n return {\n prefix,\n length,\n type: 'unsorted' as const\n };\n },\n key: (prefix: string, length: number = 50) => {\n checkPrefix(prefix);\n\n return { prefix, length, type: 'key' as const };\n }\n};\n\nexport let createIdGenerator = <\n T extends {\n [key: string]: {\n prefix: string;\n length: number;\n type: 'sorted' | 'key' | 'unsorted';\n };\n }\n>(\n idPrefixes: T\n) => {\n for (let key in idPrefixes) {\n if (!idPrefixes[key].prefix.endsWith('_')) {\n idPrefixes[key].prefix = `${idPrefixes[key].prefix}_`;\n }\n }\n\n let seenPrefixes = new Set<string>();\n for (let key in idPrefixes) {\n let prefix = idPrefixes[key].prefix;\n if (seenPrefixes.has(prefix)) {\n throw new Error(`Prefix ${prefix} already exists`);\n }\n seenPrefixes.add(prefix);\n }\n\n let getIdDescription = (prefix: keyof T) => {\n let pf = idPrefixes[prefix];\n if (!pf) throw new Error(`Invalid prefix: ${prefix as string}`);\n\n return pf;\n };\n\n return {\n generateId: async (prefix: keyof T) => {\n let desc = getIdDescription(prefix);\n let length = desc.length;\n\n if (desc.type == 'sorted') {\n let date = idTime();\n\n let remainingLength = length - date.length;\n if (remainingLength < 10) remainingLength = 10;\n\n return `${desc.prefix}${date}${_defaultId(remainingLength)}`;\n } else if (desc.type == 'unsorted') {\n return `${desc.prefix}${_defaultId(length)}`;\n } else {\n let main = `${desc.prefix}${_defaultId(length)}`;\n return `${main}${(await Hash.sha512(main)).slice(0, 6)}`;\n }\n },\n generateIdSync: (prefix: keyof T) => {\n let desc = getIdDescription(prefix);\n let length = desc.length;\n\n if (desc.type == 'sorted') {\n let date = idTime();\n\n let remainingLength = length - date.length;\n if (remainingLength < 10) remainingLength = 10;\n\n return `${desc.prefix}${date}${_defaultId(remainingLength)}`;\n } else if (desc.type == 'unsorted') {\n return `${desc.prefix}${_defaultId(length)}`;\n } else {\n throw new Error('Cannot generate key id synchronously');\n }\n },\n idPrefixes: Object.entries(idPrefixes).reduce(\n (acc, [key, value]) => {\n // @ts-ignore\n acc[key] = value.prefix;\n return acc;\n },\n {} as { [key in keyof T]: string }\n ),\n\n normalizeUUID: (prefix: keyof T, uuid: string) => {\n let desc = getIdDescription(prefix);\n\n return `${desc.prefix}${translator.fromUUID(uuid)}`;\n }\n\n // toUUID: (prefix: keyof T, id: string) => {\n // let desc = getIdDescription(prefix);\n\n // if (!id.startsWith(desc.prefix)) {\n // throw new ServiceError(\n // badRequestError({\n // message: `ID ${id} does not start with prefix ${desc.prefix}`\n // })\n // );\n // }\n\n // return translator.toUUID(id.slice(desc.prefix.length));\n // }\n };\n};\n\nexport let createUuidTranslator = (prefix: string) => {\n if (!prefix.endsWith('_')) prefix = `${prefix}_`;\n\n if (seenPrefixes.has(prefix)) {\n throw new Error(`Prefix ${prefix} already exists`);\n }\n seenPrefixes.add(prefix);\n\n return {\n fromUUID: (uuid: string) => `${prefix}${translator.fromUUID(uuid)}`,\n toUUID: (id: string) => {\n if (!id.startsWith(prefix)) {\n throw new ServiceError(\n badRequestError({\n message: `ID ${id} does not start with prefix ${prefix}`\n })\n );\n }\n\n return translator.toUUID(id.slice(prefix.length));\n }\n };\n};\n\nexport let generateCustomId = (prefix?: string, length: number = 20) => {\n if (prefix && !prefix.endsWith('_')) prefix = `${prefix}_`;\n\n return `${prefix}${_defaultId(length)}`;\n};\n\nexport let generatePlainId = (length: number = 20) => {\n return _defaultId(length);\n};\n\nexport let generateId = (prefix: string, length: number = 20) => {\n let date = idTime();\n\n let remainingLength = length - date.length;\n if (remainingLength < 10) remainingLength = 10;\n\n return `${prefix}${date}${_defaultId(remainingLength)}`;\n};\n\nexport let generateCode = (length: number = 6) => {\n return _code(length);\n};\n\nexport let generateSnowflakeId = (prefix?: string) => {\n if (prefix && !prefix.endsWith('_')) prefix = `${prefix}_`;\n\n return `${prefix}${snowflakeIdGenerator.nextId().toString(36)}`;\n};\n"],"names":["translator","short","_defaultId","customAlphabet","_code","idTime","Date","getTime","toString","padStart","snowflakeIdGenerator","Worker","workerIdBits","sequenceBits","seenPrefixes","Set","checkPrefix","prefix","endsWith","slice","has","Error","idType","sorted","length","type","unsorted","key","createIdGenerator","idPrefixes","add","getIdDescription","pf","generateId","async","desc","date","remainingLength","main","Hash","sha512","generateIdSync","Object","entries","reduce","acc","value","normalizeUUID","uuid","fromUUID","createUuidTranslator","toUUID","id","startsWith","ServiceError","badRequestError","message","generateCustomId","generatePlainId","generateCode","generateSnowflakeId","nextId"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{ServiceError as r,badRequestError as e}from"@lowerdeck/error";import{Hash as t}from"@lowerdeck/hash";import{customAlphabet as n}from"nanoid";import i from"short-uuid";import{Worker as o}from"snowflake-uuid";var f=i("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"),u=n("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",20),s=n("0123456789",6),d=function(){return(new Date).getTime().toString(36).padStart(9,"0")},a=new o(0,0,{workerIdBits:12,sequenceBits:12}),c=new Set,h=function(r){if(r.endsWith("_")&&(r=r.slice(0,-1)),c.has(r))throw new Error("Prefix "+r+" already exists")},p={sorted:function(r,e){return void 0===e&&(e=22),h(r),{prefix:r,length:e,type:"sorted"}},unsorted:function(r,e){return void 0===e&&(e=22),h(r),{prefix:r,length:e,type:"unsorted"}},key:function(r,e){return void 0===e&&(e=50),h(r),{prefix:r,length:e,type:"key"}}},x=function(r){for(var e in r)r[e].prefix.endsWith("_")||(r[e].prefix=r[e].prefix+"_");var n=new Set;for(var i in r){var o=r[i].prefix;if(n.has(o))throw new Error("Prefix "+o+" already exists");n.add(o)}var s=function(e){var t=r[e];if(!t)throw new Error("Invalid prefix: "+e);return t};return{generateId:function(r){try{var e=s(r),n=e.length;if("sorted"==e.type){var i=d(),o=n-i.length;return o<10&&(o=10),Promise.resolve(""+e.prefix+i+u(o))}if("unsorted"==e.type)return Promise.resolve(""+e.prefix+u(n));var f=""+e.prefix+u(n);return Promise.resolve(t.sha512(f)).then(function(r){return""+f+r.slice(0,6)})}catch(r){return Promise.reject(r)}},generateIdSync:function(r){var e=s(r),t=e.length;if("sorted"==e.type){var n=d(),i=t-n.length;return i<10&&(i=10),""+e.prefix+n+u(i)}if("unsorted"==e.type)return""+e.prefix+u(t);throw new Error("Cannot generate key id synchronously")},idPrefixes:Object.entries(r).reduce(function(r,e){return r[e[0]]=e[1].prefix,r},{}),normalizeUUID:function(r,e){return""+s(r).prefix+f.fromUUID(e)}}},l=function(t){if(t.endsWith("_")||(t+="_"),c.has(t))throw new Error("Prefix "+t+" already exists");return c.add(t),{fromUUID:function(r){return""+t+f.fromUUID(r)},toUUID:function(n){if(!n.startsWith(t))throw new r(e({message:"ID "+n+" does not start with prefix "+t}));return f.toUUID(n.slice(t.length))}}},v=function(r,e){return void 0===e&&(e=20),r&&!r.endsWith("_")&&(r+="_"),""+r+u(e)},w=function(r){return void 0===r&&(r=20),u(r)},m=function(r,e){void 0===e&&(e=20);var t=d(),n=e-t.length;return n<10&&(n=10),""+r+t+u(n)},y=function(r){return void 0===r&&(r=6),s(r)},g=function(r){return r&&!r.endsWith("_")&&(r+="_"),""+r+a.nextId().toString(36)};export{x as createIdGenerator,l as createUuidTranslator,y as generateCode,v as generateCustomId,m as generateId,w as generatePlainId,g as generateSnowflakeId,d as idTime,p as idType};
2
+ //# sourceMappingURL=index.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.module.js","sources":["../src/id.ts"],"sourcesContent":["import { ServiceError, badRequestError } from '@lowerdeck/error';\nimport { Hash } from '@lowerdeck/hash';\nimport { customAlphabet } from 'nanoid';\nimport short from 'short-uuid';\nimport { Worker } from 'snowflake-uuid';\n\nlet translator = short('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');\n\nlet _defaultId = customAlphabet(\n '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',\n 20\n);\n\nlet _code = customAlphabet('0123456789', 6);\n\nexport let idTime = () => new Date().getTime().toString(36).padStart(9, '0');\n\nlet snowflakeIdGenerator = new Worker(0, 0, {\n workerIdBits: 12,\n sequenceBits: 12\n});\n\nlet seenPrefixes = new Set<string>();\nlet checkPrefix = (prefix: string) => {\n if (prefix.endsWith('_')) prefix = prefix.slice(0, -1);\n\n if (seenPrefixes.has(prefix)) {\n throw new Error(`Prefix ${prefix} already exists`);\n }\n};\n\nexport let idType = {\n sorted: (prefix: string, length: number = 22) => {\n checkPrefix(prefix);\n\n return {\n prefix,\n length,\n type: 'sorted' as const\n };\n },\n unsorted: (prefix: string, length: number = 22) => {\n checkPrefix(prefix);\n\n return {\n prefix,\n length,\n type: 'unsorted' as const\n };\n },\n key: (prefix: string, length: number = 50) => {\n checkPrefix(prefix);\n\n return { prefix, length, type: 'key' as const };\n }\n};\n\nexport let createIdGenerator = <\n T extends {\n [key: string]: {\n prefix: string;\n length: number;\n type: 'sorted' | 'key' | 'unsorted';\n };\n }\n>(\n idPrefixes: T\n) => {\n for (let key in idPrefixes) {\n if (!idPrefixes[key].prefix.endsWith('_')) {\n idPrefixes[key].prefix = `${idPrefixes[key].prefix}_`;\n }\n }\n\n let seenPrefixes = new Set<string>();\n for (let key in idPrefixes) {\n let prefix = idPrefixes[key].prefix;\n if (seenPrefixes.has(prefix)) {\n throw new Error(`Prefix ${prefix} already exists`);\n }\n seenPrefixes.add(prefix);\n }\n\n let getIdDescription = (prefix: keyof T) => {\n let pf = idPrefixes[prefix];\n if (!pf) throw new Error(`Invalid prefix: ${prefix as string}`);\n\n return pf;\n };\n\n return {\n generateId: async (prefix: keyof T) => {\n let desc = getIdDescription(prefix);\n let length = desc.length;\n\n if (desc.type == 'sorted') {\n let date = idTime();\n\n let remainingLength = length - date.length;\n if (remainingLength < 10) remainingLength = 10;\n\n return `${desc.prefix}${date}${_defaultId(remainingLength)}`;\n } else if (desc.type == 'unsorted') {\n return `${desc.prefix}${_defaultId(length)}`;\n } else {\n let main = `${desc.prefix}${_defaultId(length)}`;\n return `${main}${(await Hash.sha512(main)).slice(0, 6)}`;\n }\n },\n generateIdSync: (prefix: keyof T) => {\n let desc = getIdDescription(prefix);\n let length = desc.length;\n\n if (desc.type == 'sorted') {\n let date = idTime();\n\n let remainingLength = length - date.length;\n if (remainingLength < 10) remainingLength = 10;\n\n return `${desc.prefix}${date}${_defaultId(remainingLength)}`;\n } else if (desc.type == 'unsorted') {\n return `${desc.prefix}${_defaultId(length)}`;\n } else {\n throw new Error('Cannot generate key id synchronously');\n }\n },\n idPrefixes: Object.entries(idPrefixes).reduce(\n (acc, [key, value]) => {\n // @ts-ignore\n acc[key] = value.prefix;\n return acc;\n },\n {} as { [key in keyof T]: string }\n ),\n\n normalizeUUID: (prefix: keyof T, uuid: string) => {\n let desc = getIdDescription(prefix);\n\n return `${desc.prefix}${translator.fromUUID(uuid)}`;\n }\n\n // toUUID: (prefix: keyof T, id: string) => {\n // let desc = getIdDescription(prefix);\n\n // if (!id.startsWith(desc.prefix)) {\n // throw new ServiceError(\n // badRequestError({\n // message: `ID ${id} does not start with prefix ${desc.prefix}`\n // })\n // );\n // }\n\n // return translator.toUUID(id.slice(desc.prefix.length));\n // }\n };\n};\n\nexport let createUuidTranslator = (prefix: string) => {\n if (!prefix.endsWith('_')) prefix = `${prefix}_`;\n\n if (seenPrefixes.has(prefix)) {\n throw new Error(`Prefix ${prefix} already exists`);\n }\n seenPrefixes.add(prefix);\n\n return {\n fromUUID: (uuid: string) => `${prefix}${translator.fromUUID(uuid)}`,\n toUUID: (id: string) => {\n if (!id.startsWith(prefix)) {\n throw new ServiceError(\n badRequestError({\n message: `ID ${id} does not start with prefix ${prefix}`\n })\n );\n }\n\n return translator.toUUID(id.slice(prefix.length));\n }\n };\n};\n\nexport let generateCustomId = (prefix?: string, length: number = 20) => {\n if (prefix && !prefix.endsWith('_')) prefix = `${prefix}_`;\n\n return `${prefix}${_defaultId(length)}`;\n};\n\nexport let generatePlainId = (length: number = 20) => {\n return _defaultId(length);\n};\n\nexport let generateId = (prefix: string, length: number = 20) => {\n let date = idTime();\n\n let remainingLength = length - date.length;\n if (remainingLength < 10) remainingLength = 10;\n\n return `${prefix}${date}${_defaultId(remainingLength)}`;\n};\n\nexport let generateCode = (length: number = 6) => {\n return _code(length);\n};\n\nexport let generateSnowflakeId = (prefix?: string) => {\n if (prefix && !prefix.endsWith('_')) prefix = `${prefix}_`;\n\n return `${prefix}${snowflakeIdGenerator.nextId().toString(36)}`;\n};\n"],"names":["translator","short","_defaultId","customAlphabet","_code","idTime","Date","getTime","toString","padStart","snowflakeIdGenerator","Worker","workerIdBits","sequenceBits","seenPrefixes","Set","checkPrefix","prefix","endsWith","slice","has","Error","idType","sorted","length","type","unsorted","key","createIdGenerator","idPrefixes","add","getIdDescription","pf","generateId","desc","date","remainingLength","Promise","resolve","main","Hash","sha512","then","_Hash$sha","e","reject","generateIdSync","Object","entries","reduce","acc","_ref","normalizeUUID","uuid","fromUUID","createUuidTranslator","toUUID","id","startsWith","ServiceError","badRequestError","message","generateCustomId","generatePlainId","generateCode","generateSnowflakeId","nextId"],"mappings":"sNAMA,IAAIA,EAAaC,EAAM,kEAEnBC,EAAaC,EACf,iEACA,IAGEC,EAAQD,EAAe,aAAc,GAE9BE,EAAS,WAAH,OAAa,IAAAC,MAAOC,UAAUC,SAAS,IAAIC,SAAS,EAAG,IAAI,EAExEC,EAAuB,IAAIC,EAAO,EAAG,EAAG,CAC1CC,aAAc,GACdC,aAAc,KAGZC,EAAe,IAAIC,IACnBC,EAAc,SAACC,GAGjB,GAFIA,EAAOC,SAAS,OAAMD,EAASA,EAAOE,MAAM,GAAI,IAEhDL,EAAaM,IAAIH,GACnB,MAAU,IAAAI,MAAK,UAAWJ,EAAuB,kBAErD,EAEWK,EAAS,CAClBC,OAAQ,SAACN,EAAgBO,GAGvB,YAHuBA,IAAAA,IAAAA,EAAiB,IACxCR,EAAYC,GAEL,CACLA,OAAAA,EACAO,OAAAA,EACAC,KAAM,SAEV,EACAC,SAAU,SAACT,EAAgBO,GAGzB,YAHyBA,IAAAA,IAAAA,EAAiB,IAC1CR,EAAYC,GAEL,CACLA,OAAAA,EACAO,OAAAA,EACAC,KAAM,WAEV,EACAE,IAAK,SAACV,EAAgBO,GAGpB,YAHqC,IAAjBA,IAAAA,EAAiB,IACrCR,EAAYC,GAEL,CAAEA,OAAAA,EAAQO,OAAAA,EAAQC,KAAM,MACjC,GAGSG,EAAoB,SAS7BC,GAEA,IAAK,IAAIF,KAAOE,EACTA,EAAWF,GAAKV,OAAOC,SAAS,OACnCW,EAAWF,GAAKV,OAAYY,EAAWF,GAAKV,OAC9C,KAGF,IAAIH,EAAe,IAAIC,IACvB,IAAK,IAAIY,KAAOE,EAAY,CAC1B,IAAIZ,EAASY,EAAWF,GAAKV,OAC7B,GAAIH,EAAaM,IAAIH,GACnB,MAAM,IAAII,MAAgBJ,UAAAA,qBAE5BH,EAAagB,IAAIb,EACnB,CAEA,IAAIc,EAAmB,SAACd,GACtB,IAAIe,EAAKH,EAAWZ,GACpB,IAAKe,EAAI,UAAUX,MAAyBJ,mBAAAA,GAE5C,OAAOe,CACT,EAEA,MAAO,CACLC,WAAUA,SAAShB,GAAmB,IACpC,IAAIiB,EAAOH,EAAiBd,GACxBO,EAASU,EAAKV,OAElB,GAAiB,UAAbU,EAAKT,KAAkB,CACzB,IAAIU,EAAO9B,IAEP+B,EAAkBZ,EAASW,EAAKX,OAGpC,OAFIY,EAAkB,KAAIA,EAAkB,IAE5CC,QAAAC,QAAUJ,GAAAA,EAAKjB,OAASkB,EAAOjC,EAAWkC,GAC5C,CAAO,GAAiB,YAAbF,EAAKT,KACd,OAAAY,QAAAC,QAAA,GAAUJ,EAAKjB,OAASf,EAAWsB,IAEnC,IAAIe,EAAI,GAAML,EAAKjB,OAASf,EAAWsB,GAAU,OAAAa,QAAAC,QACzBE,EAAKC,OAAOF,IAAKG,KAAAC,SAAAA,GAAzC,MAAA,GAAUJ,EAAOI,EAA0BxB,MAAM,EAAG,EAAK,EAE7D,CAAC,MAAAyB,GAAAP,OAAAA,QAAAQ,OAAAD,EACDE,CAAAA,EAAAA,eAAgB,SAAC7B,GACf,IAAIiB,EAAOH,EAAiBd,GACxBO,EAASU,EAAKV,OAElB,GAAiB,UAAbU,EAAKT,KAAkB,CACzB,IAAIU,EAAO9B,IAEP+B,EAAkBZ,EAASW,EAAKX,OAGpC,OAFIY,EAAkB,KAAIA,EAAkB,IAElCF,GAAAA,EAAKjB,OAASkB,EAAOjC,EAAWkC,EAC5C,CAAWF,GAAa,YAAbA,EAAKT,KACd,SAAUS,EAAKjB,OAASf,EAAWsB,GAEnC,MAAM,IAAIH,MAAM,uCAEpB,EACAQ,WAAYkB,OAAOC,QAAQnB,GAAYoB,OACrC,SAACC,EAAGC,GAGF,OADAD,EAFQC,MAAOA,EAAA,GAEElC,OACViC,CACT,EACA,CAAA,GAGFE,cAAe,SAACnC,EAAiBoC,GAG/B,MAAA,GAFWtB,EAAiBd,GAEbA,OAASjB,EAAWsD,SAASD,EAC9C,EAgBJ,EAEWE,EAAuB,SAACtC,GAGjC,GAFKA,EAAOC,SAAS,OAAMD,GAAqB,KAE5CH,EAAaM,IAAIH,GACnB,MAAM,IAAII,MAAK,UAAWJ,EAAM,mBAIlC,OAFAH,EAAagB,IAAIb,GAEV,CACLqC,SAAU,SAACD,GAAY,MAAA,GAAQpC,EAASjB,EAAWsD,SAASD,EAAK,EACjEG,OAAQ,SAACC,GACP,IAAKA,EAAGC,WAAWzC,GACjB,MAAU,IAAA0C,EACRC,EAAgB,CACdC,QAAO,MAAQJ,EAAE,+BAA+BxC,KAKtD,OAAOjB,EAAWwD,OAAOC,EAAGtC,MAAMF,EAAOO,QAC3C,EAEJ,EAEWsC,EAAmB,SAAC7C,EAAiBO,GAG9C,YAH8C,IAAAA,IAAAA,EAAiB,IAC3DP,IAAWA,EAAOC,SAAS,OAAMD,GAAkB,KAEvD,GAAUA,EAASf,EAAWsB,EAChC,EAEWuC,EAAkB,SAACvC,GAC5B,YAD4BA,IAAAA,IAAAA,EAAiB,IACtCtB,EAAWsB,EACpB,EAEWS,EAAa,SAAChB,EAAgBO,QAAA,IAAAA,IAAAA,EAAiB,IACxD,IAAIW,EAAO9B,IAEP+B,EAAkBZ,EAASW,EAAKX,OAGpC,OAFIY,EAAkB,KAAIA,EAAkB,IAElCnB,GAAAA,EAASkB,EAAOjC,EAAWkC,EACvC,EAEW4B,EAAe,SAACxC,GACzB,YAD0C,IAAjBA,IAAAA,EAAiB,GACnCpB,EAAMoB,EACf,EAEWyC,EAAsB,SAAChD,GAGhC,OAFIA,IAAWA,EAAOC,SAAS,OAAMD,GAAkB,KAEvD,GAAUA,EAASP,EAAqBwD,SAAS1D,SAAS,GAC5D"}
@@ -0,0 +1,2 @@
1
+ !function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("@lowerdeck/error"),require("@lowerdeck/hash"),require("nanoid"),require("short-uuid"),require("snowflake-uuid")):"function"==typeof define&&define.amd?define(["exports","@lowerdeck/error","@lowerdeck/hash","nanoid","short-uuid","snowflake-uuid"],r):r((e||self).id={},e.error,e.hash,e.nanoid,e.shortUuid,e.snowflakeUuid)}(this,function(e,r,t,n,i,o){function u(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var f=/*#__PURE__*/u(i).default("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"),d=n.customAlphabet("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",20),a=n.customAlphabet("0123456789",6),s=function(){return(new Date).getTime().toString(36).padStart(9,"0")},c=new o.Worker(0,0,{workerIdBits:12,sequenceBits:12}),h=new Set,l=function(e){if(e.endsWith("_")&&(e=e.slice(0,-1)),h.has(e))throw new Error("Prefix "+e+" already exists")},p={sorted:function(e,r){return void 0===r&&(r=22),l(e),{prefix:e,length:r,type:"sorted"}},unsorted:function(e,r){return void 0===r&&(r=22),l(e),{prefix:e,length:r,type:"unsorted"}},key:function(e,r){return void 0===r&&(r=50),l(e),{prefix:e,length:r,type:"key"}}};e.createIdGenerator=function(e){for(var r in e)e[r].prefix.endsWith("_")||(e[r].prefix=e[r].prefix+"_");var n=new Set;for(var i in e){var o=e[i].prefix;if(n.has(o))throw new Error("Prefix "+o+" already exists");n.add(o)}var u=function(r){var t=e[r];if(!t)throw new Error("Invalid prefix: "+r);return t};return{generateId:function(e){try{var r=u(e),n=r.length;if("sorted"==r.type){var i=s(),o=n-i.length;return o<10&&(o=10),Promise.resolve(""+r.prefix+i+d(o))}if("unsorted"==r.type)return Promise.resolve(""+r.prefix+d(n));var f=""+r.prefix+d(n);return Promise.resolve(t.Hash.sha512(f)).then(function(e){return""+f+e.slice(0,6)})}catch(e){return Promise.reject(e)}},generateIdSync:function(e){var r=u(e),t=r.length;if("sorted"==r.type){var n=s(),i=t-n.length;return i<10&&(i=10),""+r.prefix+n+d(i)}if("unsorted"==r.type)return""+r.prefix+d(t);throw new Error("Cannot generate key id synchronously")},idPrefixes:Object.entries(e).reduce(function(e,r){return e[r[0]]=r[1].prefix,e},{}),normalizeUUID:function(e,r){return""+u(e).prefix+f.fromUUID(r)}}},e.createUuidTranslator=function(e){if(e.endsWith("_")||(e+="_"),h.has(e))throw new Error("Prefix "+e+" already exists");return h.add(e),{fromUUID:function(r){return""+e+f.fromUUID(r)},toUUID:function(t){if(!t.startsWith(e))throw new r.ServiceError(r.badRequestError({message:"ID "+t+" does not start with prefix "+e}));return f.toUUID(t.slice(e.length))}}},e.generateCode=function(e){return void 0===e&&(e=6),a(e)},e.generateCustomId=function(e,r){return void 0===r&&(r=20),e&&!e.endsWith("_")&&(e+="_"),""+e+d(r)},e.generateId=function(e,r){void 0===r&&(r=20);var t=s(),n=r-t.length;return n<10&&(n=10),""+e+t+d(n)},e.generatePlainId=function(e){return void 0===e&&(e=20),d(e)},e.generateSnowflakeId=function(e){return e&&!e.endsWith("_")&&(e+="_"),""+e+c.nextId().toString(36)},e.idTime=s,e.idType=p});
2
+ //# sourceMappingURL=index.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.umd.js","sources":["../src/id.ts"],"sourcesContent":["import { ServiceError, badRequestError } from '@lowerdeck/error';\nimport { Hash } from '@lowerdeck/hash';\nimport { customAlphabet } from 'nanoid';\nimport short from 'short-uuid';\nimport { Worker } from 'snowflake-uuid';\n\nlet translator = short('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');\n\nlet _defaultId = customAlphabet(\n '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',\n 20\n);\n\nlet _code = customAlphabet('0123456789', 6);\n\nexport let idTime = () => new Date().getTime().toString(36).padStart(9, '0');\n\nlet snowflakeIdGenerator = new Worker(0, 0, {\n workerIdBits: 12,\n sequenceBits: 12\n});\n\nlet seenPrefixes = new Set<string>();\nlet checkPrefix = (prefix: string) => {\n if (prefix.endsWith('_')) prefix = prefix.slice(0, -1);\n\n if (seenPrefixes.has(prefix)) {\n throw new Error(`Prefix ${prefix} already exists`);\n }\n};\n\nexport let idType = {\n sorted: (prefix: string, length: number = 22) => {\n checkPrefix(prefix);\n\n return {\n prefix,\n length,\n type: 'sorted' as const\n };\n },\n unsorted: (prefix: string, length: number = 22) => {\n checkPrefix(prefix);\n\n return {\n prefix,\n length,\n type: 'unsorted' as const\n };\n },\n key: (prefix: string, length: number = 50) => {\n checkPrefix(prefix);\n\n return { prefix, length, type: 'key' as const };\n }\n};\n\nexport let createIdGenerator = <\n T extends {\n [key: string]: {\n prefix: string;\n length: number;\n type: 'sorted' | 'key' | 'unsorted';\n };\n }\n>(\n idPrefixes: T\n) => {\n for (let key in idPrefixes) {\n if (!idPrefixes[key].prefix.endsWith('_')) {\n idPrefixes[key].prefix = `${idPrefixes[key].prefix}_`;\n }\n }\n\n let seenPrefixes = new Set<string>();\n for (let key in idPrefixes) {\n let prefix = idPrefixes[key].prefix;\n if (seenPrefixes.has(prefix)) {\n throw new Error(`Prefix ${prefix} already exists`);\n }\n seenPrefixes.add(prefix);\n }\n\n let getIdDescription = (prefix: keyof T) => {\n let pf = idPrefixes[prefix];\n if (!pf) throw new Error(`Invalid prefix: ${prefix as string}`);\n\n return pf;\n };\n\n return {\n generateId: async (prefix: keyof T) => {\n let desc = getIdDescription(prefix);\n let length = desc.length;\n\n if (desc.type == 'sorted') {\n let date = idTime();\n\n let remainingLength = length - date.length;\n if (remainingLength < 10) remainingLength = 10;\n\n return `${desc.prefix}${date}${_defaultId(remainingLength)}`;\n } else if (desc.type == 'unsorted') {\n return `${desc.prefix}${_defaultId(length)}`;\n } else {\n let main = `${desc.prefix}${_defaultId(length)}`;\n return `${main}${(await Hash.sha512(main)).slice(0, 6)}`;\n }\n },\n generateIdSync: (prefix: keyof T) => {\n let desc = getIdDescription(prefix);\n let length = desc.length;\n\n if (desc.type == 'sorted') {\n let date = idTime();\n\n let remainingLength = length - date.length;\n if (remainingLength < 10) remainingLength = 10;\n\n return `${desc.prefix}${date}${_defaultId(remainingLength)}`;\n } else if (desc.type == 'unsorted') {\n return `${desc.prefix}${_defaultId(length)}`;\n } else {\n throw new Error('Cannot generate key id synchronously');\n }\n },\n idPrefixes: Object.entries(idPrefixes).reduce(\n (acc, [key, value]) => {\n // @ts-ignore\n acc[key] = value.prefix;\n return acc;\n },\n {} as { [key in keyof T]: string }\n ),\n\n normalizeUUID: (prefix: keyof T, uuid: string) => {\n let desc = getIdDescription(prefix);\n\n return `${desc.prefix}${translator.fromUUID(uuid)}`;\n }\n\n // toUUID: (prefix: keyof T, id: string) => {\n // let desc = getIdDescription(prefix);\n\n // if (!id.startsWith(desc.prefix)) {\n // throw new ServiceError(\n // badRequestError({\n // message: `ID ${id} does not start with prefix ${desc.prefix}`\n // })\n // );\n // }\n\n // return translator.toUUID(id.slice(desc.prefix.length));\n // }\n };\n};\n\nexport let createUuidTranslator = (prefix: string) => {\n if (!prefix.endsWith('_')) prefix = `${prefix}_`;\n\n if (seenPrefixes.has(prefix)) {\n throw new Error(`Prefix ${prefix} already exists`);\n }\n seenPrefixes.add(prefix);\n\n return {\n fromUUID: (uuid: string) => `${prefix}${translator.fromUUID(uuid)}`,\n toUUID: (id: string) => {\n if (!id.startsWith(prefix)) {\n throw new ServiceError(\n badRequestError({\n message: `ID ${id} does not start with prefix ${prefix}`\n })\n );\n }\n\n return translator.toUUID(id.slice(prefix.length));\n }\n };\n};\n\nexport let generateCustomId = (prefix?: string, length: number = 20) => {\n if (prefix && !prefix.endsWith('_')) prefix = `${prefix}_`;\n\n return `${prefix}${_defaultId(length)}`;\n};\n\nexport let generatePlainId = (length: number = 20) => {\n return _defaultId(length);\n};\n\nexport let generateId = (prefix: string, length: number = 20) => {\n let date = idTime();\n\n let remainingLength = length - date.length;\n if (remainingLength < 10) remainingLength = 10;\n\n return `${prefix}${date}${_defaultId(remainingLength)}`;\n};\n\nexport let generateCode = (length: number = 6) => {\n return _code(length);\n};\n\nexport let generateSnowflakeId = (prefix?: string) => {\n if (prefix && !prefix.endsWith('_')) prefix = `${prefix}_`;\n\n return `${prefix}${snowflakeIdGenerator.nextId().toString(36)}`;\n};\n"],"names":["translator","_defaultId","customAlphabet","_code","idTime","Date","getTime","toString","padStart","snowflakeIdGenerator","Worker","workerIdBits","sequenceBits","seenPrefixes","Set","checkPrefix","prefix","endsWith","slice","has","Error","idType","sorted","length","type","unsorted","key","idPrefixes","add","getIdDescription","pf","generateId","desc","date","remainingLength","Promise","resolve","main","Hash","sha512","then","_Hash$sha","e","reject","generateIdSync","Object","entries","reduce","acc","_ref","normalizeUUID","uuid","fromUUID","toUUID","id","startsWith","ServiceError","badRequestError","message","nextId"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@lowerdeck/id",
3
+ "version": "1.0.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "author": "Tobias Herber",
8
+ "license": "Apache 2",
9
+ "type": "module",
10
+ "source": "src/index.ts",
11
+ "exports": {
12
+ "require": "./dist/index.cjs",
13
+ "default": "./dist/index.modern.js"
14
+ },
15
+ "main": "./dist/index.cjs",
16
+ "module": "./dist/index.module.js",
17
+ "types": "dist/index.d.ts",
18
+ "unpkg": "./dist/index.umd.js",
19
+ "scripts": {
20
+ "test": "vitest run --passWithNoTests",
21
+ "lint": "prettier src/**/*.ts --check",
22
+ "build": "microbundle"
23
+ },
24
+ "dependencies": {
25
+ "@lowerdeck/hash": "^1.0.0",
26
+ "@lowerdeck/error": "^1.0.0",
27
+ "nanoid": "^5.0.7",
28
+ "short-uuid": "^5.2.0",
29
+ "snowflake-uuid": "^1.0.0"
30
+ },
31
+ "devDependencies": {
32
+ "microbundle": "^0.15.1",
33
+ "@lowerdeck/tsconfig": "^1.0.0",
34
+ "typescript": "^5.8.3",
35
+ "vitest": "^3.1.2"
36
+ }
37
+ }
package/src/id.test.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { createIdGenerator, idType } from './id';
3
+
4
+ describe('id', () => {
5
+ test('generateId', async () => {
6
+ let fact = createIdGenerator({
7
+ test: idType.sorted('test', 25)
8
+ });
9
+
10
+ expect((await fact.generateId('test')).startsWith('test_')).toBeTruthy();
11
+ expect((await fact.generateId('test')).length).toBe(30);
12
+ });
13
+ });
package/src/id.ts ADDED
@@ -0,0 +1,209 @@
1
+ import { ServiceError, badRequestError } from '@lowerdeck/error';
2
+ import { Hash } from '@lowerdeck/hash';
3
+ import { customAlphabet } from 'nanoid';
4
+ import short from 'short-uuid';
5
+ import { Worker } from 'snowflake-uuid';
6
+
7
+ let translator = short('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
8
+
9
+ let _defaultId = customAlphabet(
10
+ '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
11
+ 20
12
+ );
13
+
14
+ let _code = customAlphabet('0123456789', 6);
15
+
16
+ export let idTime = () => new Date().getTime().toString(36).padStart(9, '0');
17
+
18
+ let snowflakeIdGenerator = new Worker(0, 0, {
19
+ workerIdBits: 12,
20
+ sequenceBits: 12
21
+ });
22
+
23
+ let seenPrefixes = new Set<string>();
24
+ let checkPrefix = (prefix: string) => {
25
+ if (prefix.endsWith('_')) prefix = prefix.slice(0, -1);
26
+
27
+ if (seenPrefixes.has(prefix)) {
28
+ throw new Error(`Prefix ${prefix} already exists`);
29
+ }
30
+ };
31
+
32
+ export let idType = {
33
+ sorted: (prefix: string, length: number = 22) => {
34
+ checkPrefix(prefix);
35
+
36
+ return {
37
+ prefix,
38
+ length,
39
+ type: 'sorted' as const
40
+ };
41
+ },
42
+ unsorted: (prefix: string, length: number = 22) => {
43
+ checkPrefix(prefix);
44
+
45
+ return {
46
+ prefix,
47
+ length,
48
+ type: 'unsorted' as const
49
+ };
50
+ },
51
+ key: (prefix: string, length: number = 50) => {
52
+ checkPrefix(prefix);
53
+
54
+ return { prefix, length, type: 'key' as const };
55
+ }
56
+ };
57
+
58
+ export let createIdGenerator = <
59
+ T extends {
60
+ [key: string]: {
61
+ prefix: string;
62
+ length: number;
63
+ type: 'sorted' | 'key' | 'unsorted';
64
+ };
65
+ }
66
+ >(
67
+ idPrefixes: T
68
+ ) => {
69
+ for (let key in idPrefixes) {
70
+ if (!idPrefixes[key].prefix.endsWith('_')) {
71
+ idPrefixes[key].prefix = `${idPrefixes[key].prefix}_`;
72
+ }
73
+ }
74
+
75
+ let seenPrefixes = new Set<string>();
76
+ for (let key in idPrefixes) {
77
+ let prefix = idPrefixes[key].prefix;
78
+ if (seenPrefixes.has(prefix)) {
79
+ throw new Error(`Prefix ${prefix} already exists`);
80
+ }
81
+ seenPrefixes.add(prefix);
82
+ }
83
+
84
+ let getIdDescription = (prefix: keyof T) => {
85
+ let pf = idPrefixes[prefix];
86
+ if (!pf) throw new Error(`Invalid prefix: ${prefix as string}`);
87
+
88
+ return pf;
89
+ };
90
+
91
+ return {
92
+ generateId: async (prefix: keyof T) => {
93
+ let desc = getIdDescription(prefix);
94
+ let length = desc.length;
95
+
96
+ if (desc.type == 'sorted') {
97
+ let date = idTime();
98
+
99
+ let remainingLength = length - date.length;
100
+ if (remainingLength < 10) remainingLength = 10;
101
+
102
+ return `${desc.prefix}${date}${_defaultId(remainingLength)}`;
103
+ } else if (desc.type == 'unsorted') {
104
+ return `${desc.prefix}${_defaultId(length)}`;
105
+ } else {
106
+ let main = `${desc.prefix}${_defaultId(length)}`;
107
+ return `${main}${(await Hash.sha512(main)).slice(0, 6)}`;
108
+ }
109
+ },
110
+ generateIdSync: (prefix: keyof T) => {
111
+ let desc = getIdDescription(prefix);
112
+ let length = desc.length;
113
+
114
+ if (desc.type == 'sorted') {
115
+ let date = idTime();
116
+
117
+ let remainingLength = length - date.length;
118
+ if (remainingLength < 10) remainingLength = 10;
119
+
120
+ return `${desc.prefix}${date}${_defaultId(remainingLength)}`;
121
+ } else if (desc.type == 'unsorted') {
122
+ return `${desc.prefix}${_defaultId(length)}`;
123
+ } else {
124
+ throw new Error('Cannot generate key id synchronously');
125
+ }
126
+ },
127
+ idPrefixes: Object.entries(idPrefixes).reduce(
128
+ (acc, [key, value]) => {
129
+ // @ts-ignore
130
+ acc[key] = value.prefix;
131
+ return acc;
132
+ },
133
+ {} as { [key in keyof T]: string }
134
+ ),
135
+
136
+ normalizeUUID: (prefix: keyof T, uuid: string) => {
137
+ let desc = getIdDescription(prefix);
138
+
139
+ return `${desc.prefix}${translator.fromUUID(uuid)}`;
140
+ }
141
+
142
+ // toUUID: (prefix: keyof T, id: string) => {
143
+ // let desc = getIdDescription(prefix);
144
+
145
+ // if (!id.startsWith(desc.prefix)) {
146
+ // throw new ServiceError(
147
+ // badRequestError({
148
+ // message: `ID ${id} does not start with prefix ${desc.prefix}`
149
+ // })
150
+ // );
151
+ // }
152
+
153
+ // return translator.toUUID(id.slice(desc.prefix.length));
154
+ // }
155
+ };
156
+ };
157
+
158
+ export let createUuidTranslator = (prefix: string) => {
159
+ if (!prefix.endsWith('_')) prefix = `${prefix}_`;
160
+
161
+ if (seenPrefixes.has(prefix)) {
162
+ throw new Error(`Prefix ${prefix} already exists`);
163
+ }
164
+ seenPrefixes.add(prefix);
165
+
166
+ return {
167
+ fromUUID: (uuid: string) => `${prefix}${translator.fromUUID(uuid)}`,
168
+ toUUID: (id: string) => {
169
+ if (!id.startsWith(prefix)) {
170
+ throw new ServiceError(
171
+ badRequestError({
172
+ message: `ID ${id} does not start with prefix ${prefix}`
173
+ })
174
+ );
175
+ }
176
+
177
+ return translator.toUUID(id.slice(prefix.length));
178
+ }
179
+ };
180
+ };
181
+
182
+ export let generateCustomId = (prefix?: string, length: number = 20) => {
183
+ if (prefix && !prefix.endsWith('_')) prefix = `${prefix}_`;
184
+
185
+ return `${prefix}${_defaultId(length)}`;
186
+ };
187
+
188
+ export let generatePlainId = (length: number = 20) => {
189
+ return _defaultId(length);
190
+ };
191
+
192
+ export let generateId = (prefix: string, length: number = 20) => {
193
+ let date = idTime();
194
+
195
+ let remainingLength = length - date.length;
196
+ if (remainingLength < 10) remainingLength = 10;
197
+
198
+ return `${prefix}${date}${_defaultId(remainingLength)}`;
199
+ };
200
+
201
+ export let generateCode = (length: number = 6) => {
202
+ return _code(length);
203
+ };
204
+
205
+ export let generateSnowflakeId = (prefix?: string) => {
206
+ if (prefix && !prefix.endsWith('_')) prefix = `${prefix}_`;
207
+
208
+ return `${prefix}${snowflakeIdGenerator.nextId().toString(36)}`;
209
+ };
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './id';
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "@lowerdeck/tsconfig/base.json",
4
+ "exclude": [
5
+ "dist"
6
+ ],
7
+ "include": [
8
+ "src"
9
+ ],
10
+ "compilerOptions": {
11
+ "outDir": "dist"
12
+ }
13
+ }