sigilid 1.1.0 → 1.2.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.
- package/README.md +75 -12
- package/dist/alphabet.js +1 -1
- package/dist/constants-CFnCjbhy.d.ts +7 -0
- package/dist/index.d.ts +2 -6
- package/dist/index.js +1 -1
- package/dist/native.d.ts +6 -0
- package/dist/native.js +1 -0
- package/dist/non-secure.js +1 -1
- package/dist/prefix.js +1 -1
- package/dist/typed.js +1 -1
- package/dist/validate.js +1 -1
- package/package.json +24 -9
package/README.md
CHANGED
|
@@ -24,10 +24,12 @@ const id = generateId(); // "K7gkJ_q3vR2nL8xH5eM0w"
|
|
|
24
24
|
- **URL-safe by default** — 64-character alphabet: `A-Z a-z 0-9 _ -`
|
|
25
25
|
- **Tree-shakeable** — subpath exports mean your bundle only includes what you import
|
|
26
26
|
- **Zero runtime dependencies** — no third-party code in production output
|
|
27
|
-
- **
|
|
27
|
+
- **Optional Node native fast path** — `sigilid/native` for Node-only throughput tuning
|
|
28
|
+
- **ESM-only** — works in modern Node, edge runtimes, and all major bundlers
|
|
28
29
|
- **Strong TypeScript support** — strict types, branded ID types, precise inference
|
|
29
30
|
- **Predictable behavior** — explicit errors on invalid input, no silent failures
|
|
30
|
-
- **One package,
|
|
31
|
+
- **One package, seven entrypoints** — `install sigilid`, then import only what you need
|
|
32
|
+
- **Companion native addon package** — only needed when using `sigilid/native`
|
|
31
33
|
|
|
32
34
|
---
|
|
33
35
|
|
|
@@ -38,14 +40,14 @@ one never pulls in the others.
|
|
|
38
40
|
|
|
39
41
|
| Import | Size |
|
|
40
42
|
| -------------------- | ------ |
|
|
41
|
-
| `sigilid` | ~
|
|
42
|
-
| `sigilid/non-secure` | ~
|
|
43
|
-
| `sigilid/prefix` | ~
|
|
44
|
-
| `sigilid/typed` | ~
|
|
45
|
-
| `sigilid/validate` | ~
|
|
46
|
-
| `sigilid/alphabet` | ~
|
|
43
|
+
| `sigilid` | ~297 B |
|
|
44
|
+
| `sigilid/non-secure` | ~214 B |
|
|
45
|
+
| `sigilid/prefix` | ~385 B |
|
|
46
|
+
| `sigilid/typed` | ~398 B |
|
|
47
|
+
| `sigilid/validate` | ~360 B |
|
|
48
|
+
| `sigilid/alphabet` | ~380 B |
|
|
47
49
|
|
|
48
|
-
Zero runtime dependencies. [Verified by size-limit on every PR.](
|
|
50
|
+
Zero runtime dependencies. [Verified by size-limit on every PR.](.github/workflows/size-limit.yml)
|
|
49
51
|
|
|
50
52
|
---
|
|
51
53
|
|
|
@@ -65,6 +67,14 @@ yarn add sigilid
|
|
|
65
67
|
|
|
66
68
|
Node 20+ required. Works in all modern runtimes that expose the Web Crypto API (`globalThis.crypto`).
|
|
67
69
|
|
|
70
|
+
Optional native path:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm install sigilid @sigilid/native-addon
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Use `@sigilid/native-addon` only if you plan to import `sigilid/native`.
|
|
77
|
+
|
|
68
78
|
---
|
|
69
79
|
|
|
70
80
|
## Quick start
|
|
@@ -133,6 +143,30 @@ generateNonSecureId(8); // 8-character ID
|
|
|
133
143
|
|
|
134
144
|
---
|
|
135
145
|
|
|
146
|
+
### `sigilid/native` — optional Node-only fast path
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
import { generateDefault, generateId } from "sigilid/native";
|
|
150
|
+
|
|
151
|
+
generateDefault(); // 21-character secure ID
|
|
152
|
+
generateDefault(32); // 32-character secure ID
|
|
153
|
+
|
|
154
|
+
// Alias that mirrors the root naming
|
|
155
|
+
generateId(21);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- Node-only entrypoint.
|
|
159
|
+
- Requires the companion addon package: `@sigilid/native-addon`.
|
|
160
|
+
- Uses secure randomness and the same default alphabet as `sigilid`.
|
|
161
|
+
- Throws a clear error if the addon is missing or the runtime is unsupported.
|
|
162
|
+
- Addon install tries prebuilt binaries first, then falls back to local `node-gyp` build.
|
|
163
|
+
- Publishing note: `sigilid` and `@sigilid/native-addon` are versioned/published separately.
|
|
164
|
+
|
|
165
|
+
If you want the broadest compatibility (browser, edge, and Node) stick to the root
|
|
166
|
+
`sigilid` import.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
136
170
|
### `sigilid/prefix` — prefixed IDs
|
|
137
171
|
|
|
138
172
|
```ts
|
|
@@ -333,6 +367,34 @@ similar. The subpath ecosystem is where `sigilid` earns its place.
|
|
|
333
367
|
If you are targeting an environment without Web Crypto, use `sigilid/non-secure`
|
|
334
368
|
with the understanding that `Math.random` is not cryptographically safe.
|
|
335
369
|
|
|
370
|
+
`sigilid/native` is a separate Node-only path. It depends on the companion addon
|
|
371
|
+
package and is not intended for browsers or edge runtimes.
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Benchmarking
|
|
376
|
+
|
|
377
|
+
For local performance checks, run:
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
npm ci
|
|
381
|
+
npm run build
|
|
382
|
+
npm run bench
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Native vs JS benchmark:
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
npm run build:native-addon
|
|
389
|
+
npm run bench:native
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
Build prebuilt binaries for publishing the addon:
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
npm run prebuild:native-addon
|
|
396
|
+
```
|
|
397
|
+
|
|
336
398
|
---
|
|
337
399
|
|
|
338
400
|
## Package exports
|
|
@@ -340,13 +402,14 @@ with the understanding that `Math.random` is not cryptographically safe.
|
|
|
340
402
|
| Import | Entry file | Description |
|
|
341
403
|
| -------------------- | -------------------- | ---------------------------------- |
|
|
342
404
|
| `sigilid` | `dist/index.js` | Secure root generator |
|
|
405
|
+
| `sigilid/native` | `dist/native.js` | Optional Node-only native fast path |
|
|
343
406
|
| `sigilid/non-secure` | `dist/non-secure.js` | Math.random-based generator |
|
|
344
407
|
| `sigilid/prefix` | `dist/prefix.js` | Prefixed ID helpers |
|
|
345
408
|
| `sigilid/typed` | `dist/typed.js` | Branded types and typed generators |
|
|
346
409
|
| `sigilid/validate` | `dist/validate.js` | Validation helpers |
|
|
347
410
|
| `sigilid/alphabet` | `dist/alphabet.js` | Custom alphabet factory |
|
|
348
411
|
|
|
349
|
-
All exports are
|
|
412
|
+
All exports are ESM (`.js`) with TypeScript declarations (`.d.ts`). Node.js 20+ required.
|
|
350
413
|
|
|
351
414
|
---
|
|
352
415
|
|
|
@@ -363,8 +426,8 @@ decisions and constraints contributors should keep in mind.
|
|
|
363
426
|
## Release and versioning
|
|
364
427
|
|
|
365
428
|
`sigilid` uses [Semantic Versioning](https://semver.org/). Breaking API changes
|
|
366
|
-
will bump the major version. Releases are
|
|
367
|
-
|
|
429
|
+
will bump the major version. Releases are cut from GitHub — bump the version in
|
|
430
|
+
`package.json`, tag the release, and the publish workflow handles the rest.
|
|
368
431
|
|
|
369
432
|
---
|
|
370
433
|
|
package/dist/alphabet.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
function a(t){if(typeof t!="string")throw new TypeError("alphabet must be a string");if(t.length<2)throw new RangeError("alphabet must have at least 2 characters");if(t.length>256)throw new RangeError("alphabet must have at most 256 characters");if(new Set(t).size!==t.length)throw new TypeError("alphabet has duplicate characters")}function g(t,r,c){let o=t.length,e=1;for(;e<o;)e=e<<1|1;let l=Math.ceil(1.6*e*r/o),n="";for(;n.length<r;){let s=c(l);for(let i=0;i<s.length&&n.length<r;i++){let u=s[i]&e;u<o&&(n+=t[u]);}}return n}function h(t){if(!Number.isInteger(t)||t<1||t>255)throw new RangeError(`length must be 1\u2013255, got ${t}`)}function m(t){let r=new Uint8Array(t);return crypto.getRandomValues(r),r}var p=21;function v(t){a(t);}function E(t){return a(t),{generate(r=p){return h(r),g(t,r,m)}}}export{E as createAlphabet,v as validateAlphabet};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL-safe alphabet used by default. 64 characters: A-Z, a-z, 0-9, _, -.
|
|
3
|
+
* Chosen to be safe in URLs, filenames, and most log formats without encoding.
|
|
4
|
+
*/
|
|
5
|
+
declare const DEFAULT_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
|
|
6
|
+
|
|
7
|
+
export { DEFAULT_ALPHABET as D };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* URL-safe alphabet used by default. 64 characters: A-Z, a-z, 0-9, _, -.
|
|
3
|
-
* Chosen to be safe in URLs, filenames, and most log formats without encoding.
|
|
4
|
-
*/
|
|
5
|
-
declare const DEFAULT_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
|
|
1
|
+
export { D as DEFAULT_ALPHABET } from './constants-CFnCjbhy.js';
|
|
6
2
|
|
|
7
3
|
/**
|
|
8
4
|
* Generates a cryptographically secure random ID.
|
|
@@ -16,4 +12,4 @@ declare const DEFAULT_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrst
|
|
|
16
12
|
*/
|
|
17
13
|
declare function generateId(length?: number): string;
|
|
18
14
|
|
|
19
|
-
export {
|
|
15
|
+
export { generateId };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
function s(t){if(!Number.isInteger(t)||t<1||t>255)throw new RangeError(`length must be 1\u2013255, got ${t}`)}var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";var n=1024,i=new Uint8Array(n),m=e,r=n;function a(t){r+t>n&&(crypto.getRandomValues(i),r=0);let o="",f=r+t;for(;r<f;)o+=m[i[r++]&63];return o}function w(t=21){return s(t),a(t)}export{e as DEFAULT_ALPHABET,w as generateId};
|
package/dist/native.d.ts
ADDED
package/dist/native.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {createRequire}from'module';function n(e){if(!Number.isInteger(e)||e<1||e>255)throw new RangeError(`length must be 1\u2013255, got ${e}`)}var a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";var d=createRequire(import.meta.url),u="@sigilid/native-addon";function f(){return typeof process<"u"&&typeof process.versions?.node=="string"}function o(e=u){if(!f())throw new Error("sigilid/native is only supported in Node.js.");try{let t=d(e);if(typeof t.generateDefault!="function")throw new TypeError(`${e} does not export generateDefault(length).`);return t}catch(t){let i=`sigilid/native failed to load ${e}. Install it with "npm install ${e}" and ensure native builds are available.`,r=new Error(i);throw t instanceof Error&&Object.defineProperty(r,"cause",{value:t,enumerable:false,configurable:true,writable:true}),r}}var l=o();function p(e=21){return n(e),l.generateDefault(e)}function h(e=21){return p(e)}export{a as DEFAULT_ALPHABET,p as generateDefault,h as generateId};
|
package/dist/non-secure.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
function n(r){if(!Number.isInteger(r)||r<1||r>255)throw new RangeError(`length must be 1\u2013255, got ${r}`)}var o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";var i=21;function f(r=i){n(r);let t="";for(let e=0;e<r;e++)t+=o[Math.random()*64|0];return t}export{f as generateNonSecureId};
|
package/dist/prefix.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
function n(r){if(!Number.isInteger(r)||r<1||r>255)throw new RangeError(`length must be 1\u2013255, got ${r}`)}function o(r){if(typeof r!="string"||r.length===0)throw new TypeError("prefix must be a non-empty string");if(!/^[a-z][a-z\d]*$/i.test(r))throw new TypeError("prefix must start with a letter and contain only alphanumeric characters")}var a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";var s=1024,u=new Uint8Array(s),c=a,e=s;function i(r){e+r>s&&(crypto.getRandomValues(u),e=0);let t="",f=e+r;for(;e<f;)t+=c[u[e++]&63];return t}function x(r,t=21){return o(r),n(t),`${r}_${i(t)}`}function E(r,t=21){return o(r),n(t),()=>`${r}_${i(t)}`}export{E as createPrefixedGenerator,x as generatePrefixedId};
|
package/dist/typed.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
function s(t){if(!Number.isInteger(t)||t<1||t>255)throw new RangeError(`length must be 1\u2013255, got ${t}`)}function a(t){if(typeof t!="string"||t.length===0)throw new TypeError("prefix must be a non-empty string");if(!/^[a-z][a-z\d]*$/i.test(t))throw new TypeError("prefix must start with a letter and contain only alphanumeric characters")}var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";var o=1024,d=new Uint8Array(o),u=i,e=o;function f(t){e+t>o&&(crypto.getRandomValues(d),e=0);let r="",n=e+t;for(;e<n;)r+=u[d[e++]&63];return r}function l(t){return t}function w(t,r=21){return t!==void 0&&a(t),s(r),()=>{let n=f(r);return t!==void 0?`${t}_${n}`:n}}export{l as castId,w as createTypedGenerator};
|
package/dist/validate.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";function a(t,e={}){if(typeof t!="string"||t.length===0)return false;if(e.alphabet!==void 0&&e.alphabet.length===0)throw new TypeError("
|
|
1
|
+
var r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";function a(t,e={}){if(typeof t!="string"||t.length===0)return false;if(e.alphabet!==void 0&&e.alphabet.length===0)throw new TypeError("alphabet option must not be empty");let n=t;if(e.prefix!==void 0){let i=`${e.prefix}_`;if(!t.startsWith(i))return false;n=t.slice(i.length);}if(e.length!==void 0&&n.length!==e.length||n.length===0)return false;if(e.alphabet!==void 0){let i=new Set(e.alphabet);for(let o of n)if(!i.has(o))return false}return true}function l(t,e={}){let n={alphabet:r,...e};return a(t,n)}function s(t,e={}){if(!l(t,e)){let n=t.length>8?`${t.slice(0,8)}\u2026`:t;throw new TypeError(`Invalid ID: "${n}"`)}}function g(t,e={}){return s(t,e),t}export{s as assertValidId,l as isValidId,g as parseId};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sigilid",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A tiny, tree-shakeable ID toolkit for TypeScript apps. Secure core with optional subpath exports for prefixed IDs, typed IDs, validation, and custom alphabets.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "moritzmyrz",
|
|
@@ -38,6 +38,10 @@
|
|
|
38
38
|
"types": "./dist/index.d.ts",
|
|
39
39
|
"import": "./dist/index.js"
|
|
40
40
|
},
|
|
41
|
+
"./native": {
|
|
42
|
+
"types": "./dist/native.d.ts",
|
|
43
|
+
"node": "./dist/native.js"
|
|
44
|
+
},
|
|
41
45
|
"./non-secure": {
|
|
42
46
|
"types": "./dist/non-secure.d.ts",
|
|
43
47
|
"import": "./dist/non-secure.js"
|
|
@@ -60,9 +64,17 @@
|
|
|
60
64
|
},
|
|
61
65
|
"./package.json": "./package.json"
|
|
62
66
|
},
|
|
63
|
-
"files": [
|
|
67
|
+
"files": [
|
|
68
|
+
"dist",
|
|
69
|
+
"README.md",
|
|
70
|
+
"LICENSE"
|
|
71
|
+
],
|
|
64
72
|
"scripts": {
|
|
65
73
|
"build": "tsup",
|
|
74
|
+
"build:native-addon": "npm --prefix packages/native-addon run build",
|
|
75
|
+
"prebuild:native-addon": "npm --prefix packages/native-addon run prebuild",
|
|
76
|
+
"release:check": "npm run lint && npm run typecheck && npm run test && npm run build",
|
|
77
|
+
"release:pack": "npm pack && npm pack ./packages/native-addon",
|
|
66
78
|
"test": "vitest run",
|
|
67
79
|
"test:watch": "vitest",
|
|
68
80
|
"test:coverage": "vitest run --coverage",
|
|
@@ -73,41 +85,44 @@
|
|
|
73
85
|
"clean": "rm -rf dist *.tsbuildinfo",
|
|
74
86
|
"verify": "npm run lint && npm run typecheck && npm run test && npm run build",
|
|
75
87
|
"playground": "tsx tools/playground.ts",
|
|
76
|
-
"bench": "tsx tools/benchmark.ts"
|
|
88
|
+
"bench": "tsx tools/benchmark.ts",
|
|
89
|
+
"bench:native": "tsx tools/benchmark-native.ts"
|
|
77
90
|
},
|
|
78
91
|
"size-limit": [
|
|
79
92
|
{
|
|
80
93
|
"path": "dist/index.js",
|
|
81
94
|
"brotli": true,
|
|
82
|
-
"limit": "
|
|
95
|
+
"limit": "265 B"
|
|
83
96
|
},
|
|
84
97
|
{
|
|
85
98
|
"path": "dist/non-secure.js",
|
|
86
99
|
"brotli": true,
|
|
87
|
-
"limit": "
|
|
100
|
+
"limit": "245 B"
|
|
88
101
|
},
|
|
89
102
|
{
|
|
90
103
|
"path": "dist/prefix.js",
|
|
91
104
|
"brotli": true,
|
|
92
|
-
"limit": "
|
|
105
|
+
"limit": "385 B"
|
|
93
106
|
},
|
|
94
107
|
{
|
|
95
108
|
"path": "dist/typed.js",
|
|
96
109
|
"brotli": true,
|
|
97
|
-
"limit": "
|
|
110
|
+
"limit": "420 B"
|
|
98
111
|
},
|
|
99
112
|
{
|
|
100
113
|
"path": "dist/validate.js",
|
|
101
114
|
"brotli": true,
|
|
102
|
-
"limit": "
|
|
115
|
+
"limit": "395 B"
|
|
103
116
|
},
|
|
104
117
|
{
|
|
105
118
|
"path": "dist/alphabet.js",
|
|
106
119
|
"brotli": true,
|
|
107
|
-
"limit": "
|
|
120
|
+
"limit": "415 B"
|
|
108
121
|
}
|
|
109
122
|
],
|
|
110
123
|
"devDependencies": {
|
|
124
|
+
"@sigilid/native-addon": "file:packages/native-addon",
|
|
125
|
+
"@types/node": "^24.5.2",
|
|
111
126
|
"@biomejs/biome": "^1.9.4",
|
|
112
127
|
"@size-limit/preset-small-lib": "^12.0.1",
|
|
113
128
|
"@vitest/coverage-v8": "^3.0.7",
|