@typed/id 1.0.0-beta.4 → 1.0.0-beta.5
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 +171 -65
- package/dist/Cuid.d.ts +127 -12
- package/dist/Cuid.d.ts.map +1 -1
- package/dist/Cuid.js +133 -39
- package/dist/DateTimes.d.ts +64 -1
- package/dist/DateTimes.d.ts.map +1 -1
- package/dist/DateTimes.js +70 -3
- package/dist/Ids.d.ts +171 -28
- package/dist/Ids.d.ts.map +1 -1
- package/dist/Ids.js +159 -16
- package/dist/Ksuid.d.ts +51 -1
- package/dist/Ksuid.d.ts.map +1 -1
- package/dist/Ksuid.js +58 -6
- package/dist/NanoId.d.ts +47 -0
- package/dist/NanoId.d.ts.map +1 -1
- package/dist/NanoId.js +47 -0
- package/dist/RandomValues.d.ts +62 -3
- package/dist/RandomValues.d.ts.map +1 -1
- package/dist/RandomValues.js +72 -8
- package/dist/Ulid.d.ts +49 -1
- package/dist/Ulid.d.ts.map +1 -1
- package/dist/Ulid.js +53 -3
- package/dist/Uuid4.d.ts +47 -0
- package/dist/Uuid4.d.ts.map +1 -1
- package/dist/Uuid4.js +47 -0
- package/dist/Uuid5.d.ts +178 -6
- package/dist/Uuid5.d.ts.map +1 -1
- package/dist/Uuid5.js +151 -14
- package/dist/Uuid7.d.ts +120 -14
- package/dist/Uuid7.d.ts.map +1 -1
- package/dist/Uuid7.js +121 -13
- package/dist/__tests__/helpers.d.ts +7 -0
- package/dist/__tests__/helpers.d.ts.map +1 -0
- package/dist/__tests__/helpers.js +19 -0
- package/dist/__tests__/public-contract.type-test.d.ts +2 -0
- package/dist/__tests__/public-contract.type-test.d.ts.map +1 -0
- package/dist/__tests__/public-contract.type-test.js +3 -0
- package/dist/_sha.d.ts +32 -0
- package/dist/_sha.d.ts.map +1 -1
- package/dist/_sha.js +32 -0
- package/dist/_uuid-stringify.d.ts +15 -0
- package/dist/_uuid-stringify.d.ts.map +1 -1
- package/dist/_uuid-stringify.js +15 -0
- package/package.json +68 -14
- package/src/Cuid.ts +0 -124
- package/src/DateTimes.ts +0 -36
- package/src/Id.test.ts +0 -230
- package/src/Ids.ts +0 -128
- package/src/Ksuid.ts +0 -74
- package/src/NanoId.ts +0 -33
- package/src/RandomValues.ts +0 -33
- package/src/Ulid.ts +0 -51
- package/src/Uuid4.ts +0 -24
- package/src/Uuid5.ts +0 -71
- package/src/Uuid7.ts +0 -104
- package/src/_sha.ts +0 -11
- package/src/_uuid-stringify.ts +0 -30
- package/src/index.ts +0 -10
package/dist/Uuid7.d.ts
CHANGED
|
@@ -1,44 +1,150 @@
|
|
|
1
|
+
import * as Cause from "effect/Cause";
|
|
1
2
|
import * as Effect from "effect/Effect";
|
|
2
3
|
import * as Layer from "effect/Layer";
|
|
3
4
|
import * as Schema from "effect/Schema";
|
|
4
5
|
import * as Context from "effect/Context";
|
|
5
6
|
import { DateTimes } from "./DateTimes.js";
|
|
6
7
|
import { RandomValues } from "./RandomValues.js";
|
|
8
|
+
/**
|
|
9
|
+
* Effect Schema and branded string type for RFC UUID version 7 values.
|
|
10
|
+
* @remarks
|
|
11
|
+
* ## Why
|
|
12
|
+
* The schema verifies version and variant at transport boundaries; generated ordering is local to one Uuid7State, not a distributed total order.
|
|
13
|
+
* ## Ownership and lifetime
|
|
14
|
+
* This module-level schema value acquires no resources and is shared; no runtime freezing guarantee is implied.
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { Uuid7 } from "@typed/id/Uuid7"
|
|
18
|
+
* import { Schema } from "effect"
|
|
19
|
+
* const id = Schema.decodeUnknownSync(Uuid7)("01890f2e-7d6c-7cc0-98c4-dc0c0c07398f")
|
|
20
|
+
* ```
|
|
21
|
+
* @category Schemas
|
|
22
|
+
* @since 1.0.0
|
|
23
|
+
*/
|
|
7
24
|
export declare const Uuid7: Schema.brand<Schema.String, "@typed/id/UUID7">;
|
|
8
25
|
export type Uuid7 = typeof Uuid7.Type;
|
|
26
|
+
/**
|
|
27
|
+
* Tests whether a string is an RFC UUID version 7 value.
|
|
28
|
+
* @remarks
|
|
29
|
+
* ## Why
|
|
30
|
+
* Runtime refinement restores trust after serialization has erased the TypeScript brand.
|
|
31
|
+
* ## Ownership and lifetime
|
|
32
|
+
* This pure predicate acquires no resources and retains no input.
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { isUuid7 } from "@typed/id/Uuid7"
|
|
36
|
+
* const valid = isUuid7("01890f2e-7d6c-7cc0-98c4-dc0c0c07398f")
|
|
37
|
+
* ```
|
|
38
|
+
* @category Refinements
|
|
39
|
+
* @since 1.0.0
|
|
40
|
+
*/
|
|
9
41
|
export declare const isUuid7: (value: string) => value is Uuid7;
|
|
42
|
+
/**
|
|
43
|
+
* The validated time, sequence, and entropy used to format one UUID version 7.
|
|
44
|
+
* @remarks
|
|
45
|
+
* ## Why
|
|
46
|
+
* An explicit seed documents the exact inputs to version and variant bit layout and makes generator state testable.
|
|
47
|
+
* ## Ownership and lifetime
|
|
48
|
+
* This data acquires no resources; the producing service owns sequence state and transfers a fresh random byte array.
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* import type { Uuid7Seed } from "@typed/id/Uuid7"
|
|
52
|
+
* const seed: Uuid7Seed = { timestamp: 0, seq: 0, randomBytes: new Uint8Array(16) as Uuid7Seed["randomBytes"] }
|
|
53
|
+
* ```
|
|
54
|
+
* @category Models
|
|
55
|
+
* @since 1.0.0
|
|
56
|
+
*/
|
|
10
57
|
export type Uuid7Seed = {
|
|
58
|
+
/** Validated millisecond timestamp encoded into the UUID. @since 1.0.0 */
|
|
11
59
|
readonly timestamp: number;
|
|
60
|
+
/** Unsigned 32-bit sequence integer in the range [0, 0xffffffff]. @since 1.0.0 */
|
|
12
61
|
readonly seq: number;
|
|
62
|
+
/** Fresh entropy buffer whose final bytes complete the UUID payload. @since 1.0.0 */
|
|
13
63
|
readonly randomBytes: Uint8Array & {
|
|
14
64
|
length: 16;
|
|
15
65
|
};
|
|
16
66
|
};
|
|
17
|
-
declare const Uuid7State_base: Context.ServiceClass<Uuid7State, "@typed/id/Uuid7State",
|
|
18
|
-
|
|
19
|
-
seq: number;
|
|
20
|
-
randomBytes: Uint8Array<ArrayBufferLike> & {
|
|
21
|
-
length: 16;
|
|
22
|
-
};
|
|
23
|
-
}, never, never>> & {
|
|
24
|
-
readonly make: Effect.Effect<Effect.Effect<{
|
|
67
|
+
declare const Uuid7State_base: Context.ServiceClass<Uuid7State, "@typed/id/Uuid7State", {
|
|
68
|
+
next: Effect.Effect<{
|
|
25
69
|
timestamp: number;
|
|
26
70
|
seq: number;
|
|
27
71
|
randomBytes: Uint8Array<ArrayBufferLike> & {
|
|
28
|
-
length: 16;
|
|
72
|
+
readonly length: 16;
|
|
29
73
|
};
|
|
30
|
-
},
|
|
74
|
+
}, Cause.IllegalArgumentError, never>;
|
|
75
|
+
}> & {
|
|
76
|
+
readonly make: Effect.Effect<{
|
|
77
|
+
next: Effect.Effect<{
|
|
78
|
+
timestamp: number;
|
|
79
|
+
seq: number;
|
|
80
|
+
randomBytes: Uint8Array<ArrayBufferLike> & {
|
|
81
|
+
readonly length: 16;
|
|
82
|
+
};
|
|
83
|
+
}, Cause.IllegalArgumentError, never>;
|
|
84
|
+
}, never, DateTimes | RandomValues>;
|
|
31
85
|
};
|
|
86
|
+
/**
|
|
87
|
+
* Process-local Effect service that produces monotonic UUID version 7 seeds.
|
|
88
|
+
* @remarks
|
|
89
|
+
* ## Why
|
|
90
|
+
* Clock rollback and 32-bit sequence rollover are handled inside an explicit service, guaranteeing monotonicity only for one shared service instance.
|
|
91
|
+
* ## Ownership and lifetime
|
|
92
|
+
* Each Layer instance owns mutable timestamp and sequence state. A new process, worker, deployment, or Layer resets it; exact hydration identity must be serialized.
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* import { uuid7, Uuid7State } from "@typed/id/Uuid7"
|
|
96
|
+
* import { Effect } from "effect"
|
|
97
|
+
* const id = Effect.provide(uuid7, Uuid7State.Default)
|
|
98
|
+
* ```
|
|
99
|
+
* @category Services
|
|
100
|
+
* @since 1.0.0
|
|
101
|
+
*/
|
|
32
102
|
export declare class Uuid7State extends Uuid7State_base {
|
|
103
|
+
/**
|
|
104
|
+
* Reads the next validated seed from the current Uuid7State.
|
|
105
|
+
* @remarks
|
|
106
|
+
* ## Why
|
|
107
|
+
* The accessor exposes ordered state through Effect's service channel and reports timestamp exhaustion as `IllegalArgumentError`.
|
|
108
|
+
* ## Ownership and lifetime
|
|
109
|
+
* The Effect uses the state owned by its provided Layer and acquires no separate persistent resource.
|
|
110
|
+
* @category Services
|
|
111
|
+
* @since 1.0.0
|
|
112
|
+
*/
|
|
33
113
|
static readonly next: Effect.Effect<{
|
|
34
114
|
timestamp: number;
|
|
35
115
|
seq: number;
|
|
36
116
|
randomBytes: Uint8Array<ArrayBufferLike> & {
|
|
37
|
-
length: 16;
|
|
117
|
+
readonly length: 16;
|
|
38
118
|
};
|
|
39
|
-
},
|
|
40
|
-
|
|
119
|
+
}, Cause.IllegalArgumentError, Uuid7State>;
|
|
120
|
+
/**
|
|
121
|
+
* Provides Uuid7State from system time and Web Crypto entropy.
|
|
122
|
+
* @remarks
|
|
123
|
+
* ## Why
|
|
124
|
+
* The production default is explicit while remaining replaceable by deterministic service layers.
|
|
125
|
+
* ## Ownership and lifetime
|
|
126
|
+
* Layer acquisition creates one mutable sequence state owned by the surrounding Layer Scope.
|
|
127
|
+
* @category Layers
|
|
128
|
+
* @since 1.0.0
|
|
129
|
+
*/
|
|
130
|
+
static readonly Default: Layer.Layer<Uuid7State, never, never>;
|
|
41
131
|
}
|
|
42
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Generates one UUID version 7 from the current Uuid7State.
|
|
134
|
+
* @remarks
|
|
135
|
+
* ## Why
|
|
136
|
+
* Effectful generation makes the state boundary explicit and preserves `IllegalArgumentError` for invalid or exhausted timestamp space.
|
|
137
|
+
* ## Ownership and lifetime
|
|
138
|
+
* The Effect acquires no persistent resource and uses state owned by the provided Uuid7State Layer.
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* import { uuid7, Uuid7State } from "@typed/id/Uuid7"
|
|
142
|
+
* import { Effect } from "effect"
|
|
143
|
+
* const id = Effect.provide(uuid7, Uuid7State.Default)
|
|
144
|
+
* ```
|
|
145
|
+
* @category Generators
|
|
146
|
+
* @since 1.0.0
|
|
147
|
+
*/
|
|
148
|
+
export declare const uuid7: Effect.Effect<Uuid7, Cause.IllegalArgumentError, Uuid7State>;
|
|
43
149
|
export {};
|
|
44
150
|
//# sourceMappingURL=Uuid7.d.ts.map
|
package/dist/Uuid7.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Uuid7.d.ts","sourceRoot":"","sources":["../src/Uuid7.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,eAAO,MAAM,KAAK,gDAGjB,CAAC;AACF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC;AAEtC,eAAO,MAAM,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,IAAI,KAAwB,CAAC;AAE3E,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,UAAU,GAAG;QAAE,MAAM,EAAE,EAAE,CAAA;KAAE,CAAC;CACnD,CAAC
|
|
1
|
+
{"version":3,"file":"Uuid7.d.ts","sourceRoot":"","sources":["../src/Uuid7.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,KAAK,gDAGjB,CAAC;AACF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC;AAEtC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,IAAI,KAAwB,CAAC;AAE3E;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,qFAAqF;IACrF,QAAQ,CAAC,WAAW,EAAE,UAAU,GAAG;QAAE,MAAM,EAAE,EAAE,CAAA;KAAE,CAAC;CACnD,CAAC;;;;;;;;;;;;;;;;;;;;AAIF;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,UAAW,SAAQ,eA8D9B;IACA;;;;;;;;;OASG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI;;;;;;+CAGjB;IAEH;;;;;;;;;OASG;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,wCAErB;CACH;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,oBAAoB,EAAE,UAAU,CAG9E,CAAC"}
|
package/dist/Uuid7.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as Cause from "effect/Cause";
|
|
1
2
|
import * as Effect from "effect/Effect";
|
|
2
3
|
import * as Layer from "effect/Layer";
|
|
3
4
|
import * as Schema from "effect/Schema";
|
|
@@ -5,8 +6,56 @@ import * as Context from "effect/Context";
|
|
|
5
6
|
import { uuidStringify } from "./_uuid-stringify.js";
|
|
6
7
|
import { DateTimes } from "./DateTimes.js";
|
|
7
8
|
import { RandomValues } from "./RandomValues.js";
|
|
9
|
+
/**
|
|
10
|
+
* Effect Schema and branded string type for RFC UUID version 7 values.
|
|
11
|
+
* @remarks
|
|
12
|
+
* ## Why
|
|
13
|
+
* The schema verifies version and variant at transport boundaries; generated ordering is local to one Uuid7State, not a distributed total order.
|
|
14
|
+
* ## Ownership and lifetime
|
|
15
|
+
* This module-level schema value acquires no resources and is shared; no runtime freezing guarantee is implied.
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { Uuid7 } from "@typed/id/Uuid7"
|
|
19
|
+
* import { Schema } from "effect"
|
|
20
|
+
* const id = Schema.decodeUnknownSync(Uuid7)("01890f2e-7d6c-7cc0-98c4-dc0c0c07398f")
|
|
21
|
+
* ```
|
|
22
|
+
* @category Schemas
|
|
23
|
+
* @since 1.0.0
|
|
24
|
+
*/
|
|
8
25
|
export const Uuid7 = Schema.String.pipe(Schema.check(Schema.isUUID(7)), Schema.brand("@typed/id/UUID7"));
|
|
26
|
+
/**
|
|
27
|
+
* Tests whether a string is an RFC UUID version 7 value.
|
|
28
|
+
* @remarks
|
|
29
|
+
* ## Why
|
|
30
|
+
* Runtime refinement restores trust after serialization has erased the TypeScript brand.
|
|
31
|
+
* ## Ownership and lifetime
|
|
32
|
+
* This pure predicate acquires no resources and retains no input.
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { isUuid7 } from "@typed/id/Uuid7"
|
|
36
|
+
* const valid = isUuid7("01890f2e-7d6c-7cc0-98c4-dc0c0c07398f")
|
|
37
|
+
* ```
|
|
38
|
+
* @category Refinements
|
|
39
|
+
* @since 1.0.0
|
|
40
|
+
*/
|
|
9
41
|
export const isUuid7 = Schema.is(Uuid7);
|
|
42
|
+
const maximumTimestamp = 2 ** 48 - 1;
|
|
43
|
+
/**
|
|
44
|
+
* Process-local Effect service that produces monotonic UUID version 7 seeds.
|
|
45
|
+
* @remarks
|
|
46
|
+
* ## Why
|
|
47
|
+
* Clock rollback and 32-bit sequence rollover are handled inside an explicit service, guaranteeing monotonicity only for one shared service instance.
|
|
48
|
+
* ## Ownership and lifetime
|
|
49
|
+
* Each Layer instance owns mutable timestamp and sequence state. A new process, worker, deployment, or Layer resets it; exact hydration identity must be serialized.
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { uuid7, Uuid7State } from "@typed/id/Uuid7"
|
|
53
|
+
* import { Effect } from "effect"
|
|
54
|
+
* const id = Effect.provide(uuid7, Uuid7State.Default)
|
|
55
|
+
* ```
|
|
56
|
+
* @category Services
|
|
57
|
+
* @since 1.0.0
|
|
58
|
+
*/
|
|
10
59
|
export class Uuid7State extends Context.Service()("@typed/id/Uuid7State", {
|
|
11
60
|
make: Effect.gen(function* () {
|
|
12
61
|
const { now } = yield* DateTimes;
|
|
@@ -16,33 +65,92 @@ export class Uuid7State extends Context.Service()("@typed/id/Uuid7State", {
|
|
|
16
65
|
seq: 0,
|
|
17
66
|
};
|
|
18
67
|
function updateV7State(now, randomBytes) {
|
|
68
|
+
let msecs;
|
|
69
|
+
let seq;
|
|
19
70
|
if (now > state.msecs) {
|
|
20
71
|
// Time has moved on! Pick a new random sequence number
|
|
21
|
-
|
|
22
|
-
(randomBytes[6] <<
|
|
23
|
-
|
|
72
|
+
seq =
|
|
73
|
+
((randomBytes[6] << 24) |
|
|
74
|
+
(randomBytes[7] << 16) |
|
|
75
|
+
(randomBytes[8] << 8) |
|
|
76
|
+
randomBytes[9]) >>>
|
|
77
|
+
0;
|
|
78
|
+
msecs = now;
|
|
24
79
|
}
|
|
25
80
|
else {
|
|
26
81
|
// Bump sequence counter w/ 32-bit rollover
|
|
27
|
-
|
|
82
|
+
seq = (state.seq + 1) >>> 0;
|
|
83
|
+
msecs = state.msecs;
|
|
28
84
|
// In case of rollover, bump timestamp to preserve monotonicity. This is
|
|
29
85
|
// allowed by the RFC and should self-correct as the system clock catches
|
|
30
86
|
// up. See https://www.rfc-editor.org/rfc/rfc9562.html#section-6.2-9.4
|
|
31
|
-
if (
|
|
32
|
-
|
|
87
|
+
if (seq === 0) {
|
|
88
|
+
msecs++;
|
|
33
89
|
}
|
|
34
90
|
}
|
|
91
|
+
state.msecs = msecs;
|
|
92
|
+
state.seq = seq;
|
|
35
93
|
}
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
94
|
+
return {
|
|
95
|
+
next: Effect.gen(function* () {
|
|
96
|
+
const timestamp = yield* now;
|
|
97
|
+
if (!Number.isSafeInteger(timestamp) || timestamp < 0 || timestamp > maximumTimestamp) {
|
|
98
|
+
return yield* new Cause.IllegalArgumentError(`UUIDv7 timestamp must be a safe integer between 0 and ${maximumTimestamp}, received ${timestamp}`);
|
|
99
|
+
}
|
|
100
|
+
if (timestamp <= state.msecs &&
|
|
101
|
+
state.msecs === maximumTimestamp &&
|
|
102
|
+
state.seq === 0xffffffff) {
|
|
103
|
+
return yield* new Cause.IllegalArgumentError("UUIDv7 sequence rollover exceeds its 48-bit timestamp field");
|
|
104
|
+
}
|
|
105
|
+
const randomBytes = yield* getRandomValues(16);
|
|
106
|
+
updateV7State(timestamp, randomBytes);
|
|
107
|
+
return { timestamp: state.msecs, seq: state.seq, randomBytes };
|
|
108
|
+
}),
|
|
109
|
+
};
|
|
41
110
|
}),
|
|
42
111
|
}) {
|
|
43
|
-
|
|
44
|
-
|
|
112
|
+
/**
|
|
113
|
+
* Reads the next validated seed from the current Uuid7State.
|
|
114
|
+
* @remarks
|
|
115
|
+
* ## Why
|
|
116
|
+
* The accessor exposes ordered state through Effect's service channel and reports timestamp exhaustion as `IllegalArgumentError`.
|
|
117
|
+
* ## Ownership and lifetime
|
|
118
|
+
* The Effect uses the state owned by its provided Layer and acquires no separate persistent resource.
|
|
119
|
+
* @category Services
|
|
120
|
+
* @since 1.0.0
|
|
121
|
+
*/
|
|
122
|
+
static next = Effect.gen(function* () {
|
|
123
|
+
const { next } = yield* Uuid7State;
|
|
124
|
+
return yield* next;
|
|
125
|
+
});
|
|
126
|
+
/**
|
|
127
|
+
* Provides Uuid7State from system time and Web Crypto entropy.
|
|
128
|
+
* @remarks
|
|
129
|
+
* ## Why
|
|
130
|
+
* The production default is explicit while remaining replaceable by deterministic service layers.
|
|
131
|
+
* ## Ownership and lifetime
|
|
132
|
+
* Layer acquisition creates one mutable sequence state owned by the surrounding Layer Scope.
|
|
133
|
+
* @category Layers
|
|
134
|
+
* @since 1.0.0
|
|
135
|
+
*/
|
|
136
|
+
static Default = Layer.effect(Uuid7State, Uuid7State.make).pipe(Layer.provide([DateTimes.Default, RandomValues.Default]));
|
|
45
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Generates one UUID version 7 from the current Uuid7State.
|
|
140
|
+
* @remarks
|
|
141
|
+
* ## Why
|
|
142
|
+
* Effectful generation makes the state boundary explicit and preserves `IllegalArgumentError` for invalid or exhausted timestamp space.
|
|
143
|
+
* ## Ownership and lifetime
|
|
144
|
+
* The Effect acquires no persistent resource and uses state owned by the provided Uuid7State Layer.
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* import { uuid7, Uuid7State } from "@typed/id/Uuid7"
|
|
148
|
+
* import { Effect } from "effect"
|
|
149
|
+
* const id = Effect.provide(uuid7, Uuid7State.Default)
|
|
150
|
+
* ```
|
|
151
|
+
* @category Generators
|
|
152
|
+
* @since 1.0.0
|
|
153
|
+
*/
|
|
46
154
|
export const uuid7 = Effect.map(Uuid7State.next, uuid7FromSeed);
|
|
47
155
|
function uuid7FromSeed({ randomBytes, seq, timestamp }) {
|
|
48
156
|
const result = new Uint8Array(16);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as Exit from "effect/Exit";
|
|
2
|
+
import * as Layer from "effect/Layer";
|
|
3
|
+
import { RandomValues } from "../RandomValues.js";
|
|
4
|
+
export declare const expectIllegalArgument: (exit: Exit.Exit<unknown, unknown>) => void;
|
|
5
|
+
export declare const seededRandomValues: (seed: string | number) => Layer.Layer<RandomValues>;
|
|
6
|
+
export declare const zeroRandomValues: Layer.Layer<RandomValues>;
|
|
7
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/__tests__/helpers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAGtC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,eAAO,MAAM,qBAAqB,SAAU,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,SAStE,CAAC;AAEF,eAAO,MAAM,kBAAkB,SAAU,MAAM,GAAG,MAAM,KAAG,KAAK,CAAC,KAAK,CAAC,YAAY,CAIhF,CAAC;AAEJ,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,KAAK,CAAC,YAAY,CAOtD,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as Cause from "effect/Cause";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Exit from "effect/Exit";
|
|
4
|
+
import * as Layer from "effect/Layer";
|
|
5
|
+
import * as Random from "effect/Random";
|
|
6
|
+
import { expect } from "vitest";
|
|
7
|
+
import { RandomValues } from "../RandomValues.js";
|
|
8
|
+
export const expectIllegalArgument = (exit) => {
|
|
9
|
+
expect(Exit.isFailure(exit)).toBe(true);
|
|
10
|
+
if (Exit.isFailure(exit)) {
|
|
11
|
+
const failure = Cause.findErrorOption(exit.cause);
|
|
12
|
+
expect(failure._tag).toBe("Some");
|
|
13
|
+
if (failure._tag === "Some") {
|
|
14
|
+
expect(Cause.isIllegalArgumentError(failure.value)).toBe(true);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
export const seededRandomValues = (seed) => Layer.effect(RandomValues, RandomValues.pipe(Effect.provide(RandomValues.Random), Random.withSeed(seed)));
|
|
19
|
+
export const zeroRandomValues = Layer.succeed(RandomValues, RandomValues.of(Effect.fn((length) => Effect.succeed(new Uint8Array(length)))));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-contract.type-test.d.ts","sourceRoot":"","sources":["../../src/__tests__/public-contract.type-test.ts"],"names":[],"mappings":""}
|
package/dist/_sha.d.ts
CHANGED
|
@@ -1,4 +1,36 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
|
+
/**
|
|
3
|
+
* Digests bytes with Web Crypto SHA-1 and returns a fresh Uint8Array.
|
|
4
|
+
* @remarks
|
|
5
|
+
* ## Why
|
|
6
|
+
* This published low-level helper exposes the exact hash required by UUID version 5; SHA-1 here is identity derivation, not password or signature security. Missing Web Crypto and rejected `subtle.digest` promises are Effect defects because the typed error channel is `never`.
|
|
7
|
+
* ## Ownership and lifetime
|
|
8
|
+
* Each Effect owns one asynchronous Web Crypto request and transfers a fresh result buffer; it retains no input after completion.
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { sha1 } from "@typed/id/_sha"
|
|
12
|
+
* import { Effect } from "effect"
|
|
13
|
+
* const digest = Effect.runPromise(sha1(new TextEncoder().encode("name")))
|
|
14
|
+
* ```
|
|
15
|
+
* @category Hashing
|
|
16
|
+
* @since 1.0.0
|
|
17
|
+
*/
|
|
2
18
|
export declare const sha1: (data: BufferSource) => Effect.Effect<Uint8Array<ArrayBuffer>, never, never>;
|
|
19
|
+
/**
|
|
20
|
+
* Digests bytes with Web Crypto SHA-512 and returns a fresh Uint8Array.
|
|
21
|
+
* @remarks
|
|
22
|
+
* ## Why
|
|
23
|
+
* This published low-level helper exposes the exact domain-separated hash used by CUID formatting without hiding platform requirements. Missing Web Crypto and rejected `subtle.digest` promises are Effect defects because the typed error channel is `never`.
|
|
24
|
+
* ## Ownership and lifetime
|
|
25
|
+
* Each Effect owns one asynchronous Web Crypto request and transfers a fresh result buffer; it retains no input after completion.
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { sha512 } from "@typed/id/_sha"
|
|
29
|
+
* import { Effect } from "effect"
|
|
30
|
+
* const digest = Effect.runPromise(sha512(new TextEncoder().encode("seed")))
|
|
31
|
+
* ```
|
|
32
|
+
* @category Hashing
|
|
33
|
+
* @since 1.0.0
|
|
34
|
+
*/
|
|
3
35
|
export declare const sha512: (data: BufferSource) => Effect.Effect<Uint8Array<ArrayBuffer>, never, never>;
|
|
4
36
|
//# sourceMappingURL=_sha.d.ts.map
|
package/dist/_sha.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_sha.d.ts","sourceRoot":"","sources":["../src/_sha.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,eAAO,MAAM,IAAI,
|
|
1
|
+
{"version":3,"file":"_sha.d.ts","sourceRoot":"","sources":["../src/_sha.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,IAAI,SAAU,YAAY,yDAGpC,CAAC;AAEJ;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,MAAM,SAAU,YAAY,yDAGtC,CAAC"}
|
package/dist/_sha.js
CHANGED
|
@@ -1,3 +1,35 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
|
+
/**
|
|
3
|
+
* Digests bytes with Web Crypto SHA-1 and returns a fresh Uint8Array.
|
|
4
|
+
* @remarks
|
|
5
|
+
* ## Why
|
|
6
|
+
* This published low-level helper exposes the exact hash required by UUID version 5; SHA-1 here is identity derivation, not password or signature security. Missing Web Crypto and rejected `subtle.digest` promises are Effect defects because the typed error channel is `never`.
|
|
7
|
+
* ## Ownership and lifetime
|
|
8
|
+
* Each Effect owns one asynchronous Web Crypto request and transfers a fresh result buffer; it retains no input after completion.
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { sha1 } from "@typed/id/_sha"
|
|
12
|
+
* import { Effect } from "effect"
|
|
13
|
+
* const digest = Effect.runPromise(sha1(new TextEncoder().encode("name")))
|
|
14
|
+
* ```
|
|
15
|
+
* @category Hashing
|
|
16
|
+
* @since 1.0.0
|
|
17
|
+
*/
|
|
2
18
|
export const sha1 = (data) => Effect.promise(() => crypto.subtle.digest("SHA-1", data).then((buffer) => new Uint8Array(buffer)));
|
|
19
|
+
/**
|
|
20
|
+
* Digests bytes with Web Crypto SHA-512 and returns a fresh Uint8Array.
|
|
21
|
+
* @remarks
|
|
22
|
+
* ## Why
|
|
23
|
+
* This published low-level helper exposes the exact domain-separated hash used by CUID formatting without hiding platform requirements. Missing Web Crypto and rejected `subtle.digest` promises are Effect defects because the typed error channel is `never`.
|
|
24
|
+
* ## Ownership and lifetime
|
|
25
|
+
* Each Effect owns one asynchronous Web Crypto request and transfers a fresh result buffer; it retains no input after completion.
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { sha512 } from "@typed/id/_sha"
|
|
29
|
+
* import { Effect } from "effect"
|
|
30
|
+
* const digest = Effect.runPromise(sha512(new TextEncoder().encode("seed")))
|
|
31
|
+
* ```
|
|
32
|
+
* @category Hashing
|
|
33
|
+
* @since 1.0.0
|
|
34
|
+
*/
|
|
3
35
|
export const sha512 = (data) => Effect.promise(() => crypto.subtle.digest("SHA-512", data).then((buffer) => new Uint8Array(buffer)));
|
|
@@ -1,2 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats the first 16 bytes of a seed as a lowercase hyphenated UUID string.
|
|
3
|
+
* @remarks
|
|
4
|
+
* ## Why
|
|
5
|
+
* This published low-level helper centralizes UUID byte layout formatting but deliberately does not validate length, version, or variant bits.
|
|
6
|
+
* ## Ownership and lifetime
|
|
7
|
+
* This pure function acquires no resources, does not mutate or retain the seed, and returns a new string.
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { uuidStringify } from "@typed/id/_uuid-stringify"
|
|
11
|
+
* const text = uuidStringify(new Uint8Array(16))
|
|
12
|
+
* ```
|
|
13
|
+
* @category Formatting
|
|
14
|
+
* @since 1.0.0
|
|
15
|
+
*/
|
|
1
16
|
export declare function uuidStringify(seed: Uint8Array): string;
|
|
2
17
|
//# sourceMappingURL=_uuid-stringify.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_uuid-stringify.d.ts","sourceRoot":"","sources":["../src/_uuid-stringify.ts"],"names":[],"mappings":"AAMA,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAuBtD"}
|
|
1
|
+
{"version":3,"file":"_uuid-stringify.d.ts","sourceRoot":"","sources":["../src/_uuid-stringify.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAuBtD"}
|
package/dist/_uuid-stringify.js
CHANGED
|
@@ -2,6 +2,21 @@ const byteToHex = [];
|
|
|
2
2
|
for (let i = 0; i < 256; ++i) {
|
|
3
3
|
byteToHex.push((i + 0x100).toString(16).slice(1));
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* Formats the first 16 bytes of a seed as a lowercase hyphenated UUID string.
|
|
7
|
+
* @remarks
|
|
8
|
+
* ## Why
|
|
9
|
+
* This published low-level helper centralizes UUID byte layout formatting but deliberately does not validate length, version, or variant bits.
|
|
10
|
+
* ## Ownership and lifetime
|
|
11
|
+
* This pure function acquires no resources, does not mutate or retain the seed, and returns a new string.
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { uuidStringify } from "@typed/id/_uuid-stringify"
|
|
15
|
+
* const text = uuidStringify(new Uint8Array(16))
|
|
16
|
+
* ```
|
|
17
|
+
* @category Formatting
|
|
18
|
+
* @since 1.0.0
|
|
19
|
+
*/
|
|
5
20
|
export function uuidStringify(seed) {
|
|
6
21
|
return [
|
|
7
22
|
byteToHex[seed[0]],
|
package/package.json
CHANGED
|
@@ -1,33 +1,87 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typed/id",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.5",
|
|
4
|
+
"description": "Branded ID generators and facades for Typed applications.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://github.com/TylorS/typed-smol/tree/main/packages/id#readme",
|
|
7
|
+
"bugs": "https://github.com/TylorS/typed-smol/issues",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/TylorS/typed-smol.git",
|
|
11
|
+
"directory": "packages/id"
|
|
12
|
+
},
|
|
4
13
|
"files": [
|
|
5
|
-
"dist"
|
|
6
|
-
"src"
|
|
14
|
+
"dist"
|
|
7
15
|
],
|
|
8
16
|
"type": "module",
|
|
17
|
+
"sideEffects": false,
|
|
9
18
|
"exports": {
|
|
10
19
|
".": {
|
|
11
20
|
"types": "./dist/index.d.ts",
|
|
12
21
|
"import": "./dist/index.js"
|
|
13
22
|
},
|
|
14
|
-
"
|
|
15
|
-
"types": "./dist
|
|
16
|
-
"import": "./dist
|
|
23
|
+
"./Cuid": {
|
|
24
|
+
"types": "./dist/Cuid.d.ts",
|
|
25
|
+
"import": "./dist/Cuid.js"
|
|
26
|
+
},
|
|
27
|
+
"./DateTimes": {
|
|
28
|
+
"types": "./dist/DateTimes.d.ts",
|
|
29
|
+
"import": "./dist/DateTimes.js"
|
|
30
|
+
},
|
|
31
|
+
"./Ids": {
|
|
32
|
+
"types": "./dist/Ids.d.ts",
|
|
33
|
+
"import": "./dist/Ids.js"
|
|
34
|
+
},
|
|
35
|
+
"./Ksuid": {
|
|
36
|
+
"types": "./dist/Ksuid.d.ts",
|
|
37
|
+
"import": "./dist/Ksuid.js"
|
|
38
|
+
},
|
|
39
|
+
"./NanoId": {
|
|
40
|
+
"types": "./dist/NanoId.d.ts",
|
|
41
|
+
"import": "./dist/NanoId.js"
|
|
42
|
+
},
|
|
43
|
+
"./RandomValues": {
|
|
44
|
+
"types": "./dist/RandomValues.d.ts",
|
|
45
|
+
"import": "./dist/RandomValues.js"
|
|
46
|
+
},
|
|
47
|
+
"./Ulid": {
|
|
48
|
+
"types": "./dist/Ulid.d.ts",
|
|
49
|
+
"import": "./dist/Ulid.js"
|
|
50
|
+
},
|
|
51
|
+
"./Uuid4": {
|
|
52
|
+
"types": "./dist/Uuid4.d.ts",
|
|
53
|
+
"import": "./dist/Uuid4.js"
|
|
54
|
+
},
|
|
55
|
+
"./Uuid5": {
|
|
56
|
+
"types": "./dist/Uuid5.d.ts",
|
|
57
|
+
"import": "./dist/Uuid5.js"
|
|
58
|
+
},
|
|
59
|
+
"./Uuid7": {
|
|
60
|
+
"types": "./dist/Uuid7.d.ts",
|
|
61
|
+
"import": "./dist/Uuid7.js"
|
|
62
|
+
},
|
|
63
|
+
"./_sha": {
|
|
64
|
+
"types": "./dist/_sha.d.ts",
|
|
65
|
+
"import": "./dist/_sha.js"
|
|
66
|
+
},
|
|
67
|
+
"./_uuid-stringify": {
|
|
68
|
+
"types": "./dist/_uuid-stringify.d.ts",
|
|
69
|
+
"import": "./dist/_uuid-stringify.js"
|
|
17
70
|
}
|
|
18
71
|
},
|
|
19
72
|
"publishConfig": {
|
|
20
73
|
"access": "public"
|
|
21
74
|
},
|
|
22
|
-
"scripts": {
|
|
23
|
-
"build": "[ -d dist ] || rm -f tsconfig.tsbuildinfo; tsc",
|
|
24
|
-
"test": "vitest run --passWithNoTests"
|
|
25
|
-
},
|
|
26
75
|
"dependencies": {
|
|
27
|
-
"effect": "
|
|
76
|
+
"effect": "4.0.0-rc.112"
|
|
28
77
|
},
|
|
29
78
|
"devDependencies": {
|
|
30
|
-
"typescript": "
|
|
31
|
-
"vitest": "
|
|
79
|
+
"typescript": "7.0.2",
|
|
80
|
+
"vitest": "5.0.0"
|
|
81
|
+
},
|
|
82
|
+
"scripts": {
|
|
83
|
+
"build": "node -e \"const fs=require('node:fs'); fs.rmSync('dist',{recursive:true,force:true}); fs.rmSync('tsconfig.tsbuildinfo',{force:true})\" && tsc",
|
|
84
|
+
"test": "vitest run",
|
|
85
|
+
"test:types": "tsc -p tsconfig.type-tests.json && tsc -p tsconfig.tests.json"
|
|
32
86
|
}
|
|
33
|
-
}
|
|
87
|
+
}
|