@typed/id 0.12.0 → 0.13.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.
@@ -12,14 +12,8 @@ declare const DateTimes_base: import("effect/Context").TagClass<DateTimes, "Date
12
12
  }) => X) => [X] extends [Effect.Effect<infer A, infer E, infer R>] ? Effect.Effect<A, E, DateTimes | R> : [X] extends [PromiseLike<infer A_1>] ? Effect.Effect<A_1, import("effect/Cause").UnknownException, DateTimes> : Effect.Effect<X, never, DateTimes>;
13
13
  };
14
14
  export declare class DateTimes extends DateTimes_base {
15
- static readonly make: (now: Effect.Effect<number>) => Effect.Effect<{
16
- now: Effect.Effect<number, never, never>;
17
- date: Effect.Effect<Date, never, never>;
18
- }, never, never>;
19
- static readonly Default: Effect.Effect<{
20
- now: Effect.Effect<number, never, never>;
21
- date: Effect.Effect<Date, never, never>;
22
- }, never, never>;
23
- static readonly Fixed: (base: Date) => Layer.Layer<DateTimes, never, never>;
15
+ static readonly make: (now: Effect.Effect<number>) => Layer.Layer<DateTimes>;
16
+ static readonly Default: Layer.Layer<DateTimes>;
17
+ static readonly Fixed: (base: Date) => Layer.Layer<DateTimes>;
24
18
  }
25
19
  export {};
package/dist/DateTimes.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Effect, Layer } from 'effect';
2
2
  export class DateTimes extends Effect.Tag('DateTimes')() {
3
- static make = (now) => Effect.succeed({
3
+ static make = (now) => Layer.succeed(this, {
4
4
  now,
5
5
  date: now.pipe(Effect.map((millis) => new Date(millis))),
6
6
  });
@@ -1 +1 @@
1
- {"version":3,"file":"DateTimes.js","sourceRoot":"","sources":["../src/DateTimes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAqB,MAAM,QAAQ,CAAA;AAEzD,MAAM,OAAO,SAAU,SAAQ,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,EAMnD;IACD,MAAM,CAAU,IAAI,GAAG,CAAC,GAA0B,EAAE,EAAE,CACpD,MAAM,CAAC,OAAO,CAAC;QACb,GAAG;QACH,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;KACzD,CAAC,CAAA;IAEJ,MAAM,CAAU,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAA;IAEzF,MAAM,CAAU,KAAK,GAAG,CAAC,IAAU,EAAE,EAAE,CACrC,KAAK,CAAC,MAAM,CACV,SAAS,EACT,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAA;QACjC,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAA;QAClD,MAAM,GAAG,GAAG,KAAK,CAAC,iBAAiB,CAAC,IAAI,CACtC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACpB,4FAA4F;QAC5F,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CACtE,CACF,CAAA;QAED,OAAO;YACL,GAAG;YACH,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;SACzD,CAAA;IACH,CAAC,CAAC,CACH,CAAA"}
1
+ {"version":3,"file":"DateTimes.js","sourceRoot":"","sources":["../src/DateTimes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAqB,MAAM,QAAQ,CAAA;AAEzD,MAAM,OAAO,SAAU,SAAQ,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,EAMnD;IACD,MAAM,CAAU,IAAI,GAAG,CAAC,GAA0B,EAA0B,EAAE,CAC5E,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE;QAClB,GAAG;QACH,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;KACzD,CAAC,CAAA;IAEJ,MAAM,CAAU,OAAO,GAA2B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAA;IAEjH,MAAM,CAAU,KAAK,GAAG,CAAC,IAAU,EAA0B,EAAE,CAC7D,KAAK,CAAC,MAAM,CACV,SAAS,EACT,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAA;QACjC,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAA;QAClD,MAAM,GAAG,GAAG,KAAK,CAAC,iBAAiB,CAAC,IAAI,CACtC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACpB,4FAA4F;QAC5F,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CACtE,CACF,CAAA;QAED,OAAO;YACL,GAAG;YACH,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;SACzD,CAAA;IACH,CAAC,CAAC,CACH,CAAA"}
@@ -0,0 +1,7 @@
1
+ import * as Effect from 'effect/Effect';
2
+ import { GetRandomValues } from './GetRandomValues.js';
3
+ import { Schema } from 'effect';
4
+ export declare const Uuid4: Schema.brand<typeof Schema.UUID, "@typed/id/UUID4">;
5
+ export type Uuid4 = Schema.Schema.Type<typeof Uuid4>;
6
+ export declare const isUuid4: (value: string) => value is Uuid4;
7
+ export declare const makeUuid4: Effect.Effect<Uuid4, never, GetRandomValues>;
package/dist/Uuid4.js ADDED
@@ -0,0 +1,14 @@
1
+ import * as Effect from 'effect/Effect';
2
+ import { GetRandomValues } from './GetRandomValues.js';
3
+ import { Schema } from 'effect';
4
+ import { uuidStringify } from './UuidStringify.js';
5
+ export const Uuid4 = Schema.UUID.pipe(Schema.brand('@typed/id/UUID4'));
6
+ export const isUuid4 = Schema.is(Uuid4);
7
+ export const makeUuid4 = Effect.map(GetRandomValues.apply(16), uuid4FromSeed);
8
+ function uuid4FromSeed(seed) {
9
+ // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
10
+ seed[6] = (seed[6] & 0x0f) | 0x40;
11
+ seed[8] = (seed[8] & 0x3f) | 0x80;
12
+ return uuidStringify(seed);
13
+ }
14
+ //# sourceMappingURL=Uuid4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Uuid4.js","sourceRoot":"","sources":["../src/Uuid4.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,MAAM,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAGtE,MAAM,CAAC,MAAM,OAAO,GAAsC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAA;AAE1E,MAAM,CAAC,MAAM,SAAS,GAAiD,MAAM,CAAC,GAAG,CAC/E,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC,EACzB,aAAa,CACd,CAAA;AAED,SAAS,aAAa,CAAC,IAAgB;IACrC,gEAAgE;IAChE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAA;IACjC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAA;IAEjC,OAAO,aAAa,CAAC,IAAI,CAAU,CAAA;AACrC,CAAC"}
@@ -0,0 +1,26 @@
1
+ import * as Effect from 'effect/Effect';
2
+ import { GetRandomValues } from './GetRandomValues.js';
3
+ import { Layer, Schema } from 'effect';
4
+ import { DateTimes } from './DateTimes.js';
5
+ export declare const Uuid7: Schema.brand<typeof Schema.UUID, "@typed/id/UUID7">;
6
+ export type Uuid7 = Schema.Schema.Type<typeof Uuid7>;
7
+ export declare const isUuid7: (value: string) => value is Uuid7;
8
+ export type Uuid7Seed = {
9
+ readonly timestamp: number;
10
+ readonly seq: number;
11
+ readonly randomBytes: Uint8Array;
12
+ };
13
+ declare const Uuid7State_base: import("effect/Context").TagClass<Uuid7State, "Uuid7State", {
14
+ readonly next: Effect.Effect<Uuid7Seed>;
15
+ }> & Effect.Tag.Proxy<Uuid7State, {
16
+ readonly next: Effect.Effect<Uuid7Seed>;
17
+ }> & {
18
+ use: <X>(body: (_: {
19
+ readonly next: Effect.Effect<Uuid7Seed>;
20
+ }) => X) => [X] extends [Effect.Effect<infer A, infer E, infer R>] ? Effect.Effect<A, E, R | Uuid7State> : [X] extends [PromiseLike<infer A_1>] ? Effect.Effect<A_1, import("effect/Cause").UnknownException, Uuid7State> : Effect.Effect<X, never, Uuid7State>;
21
+ };
22
+ export declare class Uuid7State extends Uuid7State_base {
23
+ static Default: Layer.Layer<Uuid7State, never, GetRandomValues | DateTimes>;
24
+ }
25
+ export declare const makeUuid7: Effect.Effect<Uuid7, never, Uuid7State>;
26
+ export {};
package/dist/Uuid7.js ADDED
@@ -0,0 +1,71 @@
1
+ import * as Effect from 'effect/Effect';
2
+ import { GetRandomValues } from './GetRandomValues.js';
3
+ import { Layer, Schema } from 'effect';
4
+ import { DateTimes } from './DateTimes.js';
5
+ import { uuidStringify } from './UuidStringify.js';
6
+ export const Uuid7 = Schema.UUID.pipe(Schema.brand('@typed/id/UUID7'));
7
+ export const isUuid7 = Schema.is(Uuid7);
8
+ export class Uuid7State extends Effect.Tag('Uuid7State')() {
9
+ static Default = Layer.effect(this, Effect.gen(function* () {
10
+ const { now } = yield* DateTimes;
11
+ const getRandomValues = yield* GetRandomValues;
12
+ const state = {
13
+ msecs: Number.NEGATIVE_INFINITY,
14
+ seq: 0,
15
+ };
16
+ function updateV7State(now, randomBytes) {
17
+ if (now > state.msecs) {
18
+ // Time has moved on! Pick a new random sequence number
19
+ state.seq =
20
+ (randomBytes[6] << 23) | (randomBytes[7] << 16) | (randomBytes[8] << 8) | randomBytes[9];
21
+ state.msecs = now;
22
+ }
23
+ else {
24
+ // Bump sequence counter w/ 32-bit rollover
25
+ state.seq = (state.seq + 1) | 0;
26
+ // In case of rollover, bump timestamp to preserve monotonicity. This is
27
+ // allowed by the RFC and should self-correct as the system clock catches
28
+ // up. See https://www.rfc-editor.org/rfc/rfc9562.html#section-6.2-9.4
29
+ if (state.seq === 0) {
30
+ state.msecs++;
31
+ }
32
+ }
33
+ }
34
+ return {
35
+ next: Effect.gen(function* () {
36
+ const randomBytes = yield* getRandomValues(16);
37
+ updateV7State(yield* now, randomBytes);
38
+ return { timestamp: state.msecs, seq: state.seq, randomBytes };
39
+ }),
40
+ };
41
+ }));
42
+ }
43
+ export const makeUuid7 = Effect.map(Uuid7State.next, uuid7FromSeed);
44
+ function uuid7FromSeed({ timestamp, seq, randomBytes }) {
45
+ const result = new Uint8Array(16);
46
+ // byte 0-5: timestamp (48 bits)
47
+ result[0] = (timestamp / 0x10000000000) & 0xff;
48
+ result[1] = (timestamp / 0x100000000) & 0xff;
49
+ result[2] = (timestamp / 0x1000000) & 0xff;
50
+ result[3] = (timestamp / 0x10000) & 0xff;
51
+ result[4] = (timestamp / 0x100) & 0xff;
52
+ result[5] = timestamp & 0xff;
53
+ // byte 6: `version` (4 bits) | sequence bits 28-31 (4 bits)
54
+ result[6] = 0x70 | ((seq >>> 28) & 0x0f);
55
+ // byte 7: sequence bits 20-27 (8 bits)
56
+ result[7] = (seq >>> 20) & 0xff;
57
+ // byte 8: `variant` (2 bits) | sequence bits 14-19 (6 bits)
58
+ result[8] = 0x80 | ((seq >>> 14) & 0x3f);
59
+ // byte 9: sequence bits 6-13 (8 bits)
60
+ result[9] = (seq >>> 6) & 0xff;
61
+ // byte 10: sequence bits 0-5 (6 bits) | random (2 bits)
62
+ result[10] = ((seq << 2) & 0xff) | (randomBytes[10] & 0x03);
63
+ // bytes 11-15: random (40 bits)
64
+ result[11] = randomBytes[11];
65
+ result[12] = randomBytes[12];
66
+ result[13] = randomBytes[13];
67
+ result[14] = randomBytes[14];
68
+ result[15] = randomBytes[15];
69
+ return uuidStringify(result);
70
+ }
71
+ //# sourceMappingURL=Uuid7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Uuid7.js","sourceRoot":"","sources":["../src/Uuid7.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function uuidStringify(seed: Uint8Array): string;
@@ -0,0 +1,29 @@
1
+ const byteToHex = [];
2
+ for (let i = 0; i < 256; ++i) {
3
+ byteToHex.push((i + 0x100).toString(16).slice(1));
4
+ }
5
+ export function uuidStringify(seed) {
6
+ return (
7
+ // biome-ignore lint/style/useTemplate: Faster than template literals
8
+ byteToHex[seed[0]] +
9
+ byteToHex[seed[1]] +
10
+ byteToHex[seed[2]] +
11
+ byteToHex[seed[3]] +
12
+ '-' +
13
+ byteToHex[seed[4]] +
14
+ byteToHex[seed[5]] +
15
+ '-' +
16
+ byteToHex[seed[6]] +
17
+ byteToHex[seed[7]] +
18
+ '-' +
19
+ byteToHex[seed[8]] +
20
+ byteToHex[seed[9]] +
21
+ '-' +
22
+ byteToHex[seed[10]] +
23
+ byteToHex[seed[11]] +
24
+ byteToHex[seed[12]] +
25
+ byteToHex[seed[13]] +
26
+ byteToHex[seed[14]] +
27
+ byteToHex[seed[15]]);
28
+ }
29
+ //# sourceMappingURL=UuidStringify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UuidStringify.js","sourceRoot":"","sources":["../src/UuidStringify.ts"],"names":[],"mappings":"AAAA,MAAM,SAAS,GAAkB,EAAE,CAAA;AAEnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;IAC7B,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAgB;IAC5C,OAAO;IACL,qEAAqE;IACrE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,GAAG;QACH,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,GAAG;QACH,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,GAAG;QACH,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,GAAG;QACH,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnB,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnB,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnB,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnB,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnB,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CACpB,CAAA;AACH,CAAC"}
package/dist/index.d.ts CHANGED
@@ -2,4 +2,5 @@ export * from './DateTimes.js';
2
2
  export * from './GetRandomValues.js';
3
3
  export * from './NanoId.js';
4
4
  export * from './Ulid.js';
5
- export * from './Uuid.js';
5
+ export * from './Uuid4.js';
6
+ export * from './Uuid7.js';
package/dist/index.js CHANGED
@@ -2,5 +2,6 @@ export * from './DateTimes.js';
2
2
  export * from './GetRandomValues.js';
3
3
  export * from './NanoId.js';
4
4
  export * from './Ulid.js';
5
- export * from './Uuid.js';
5
+ export * from './Uuid4.js';
6
+ export * from './Uuid7.js';
6
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,sBAAsB,CAAA;AACpC,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,sBAAsB,CAAA;AACpC,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typed/id",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Common ID format generation for Effect",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/DateTimes.ts CHANGED
@@ -7,15 +7,15 @@ export class DateTimes extends Effect.Tag('DateTimes')<
7
7
  readonly date: Effect.Effect<Date>
8
8
  }
9
9
  >() {
10
- static readonly make = (now: Effect.Effect<number>) =>
11
- Effect.succeed({
10
+ static readonly make = (now: Effect.Effect<number>): Layer.Layer<DateTimes> =>
11
+ Layer.succeed(this, {
12
12
  now,
13
13
  date: now.pipe(Effect.map((millis) => new Date(millis))),
14
14
  })
15
15
 
16
- static readonly Default = this.make(Effect.clockWith((clock) => clock.currentTimeMillis))
16
+ static readonly Default: Layer.Layer<DateTimes> = this.make(Effect.clockWith((clock) => clock.currentTimeMillis))
17
17
 
18
- static readonly Fixed = (base: Date) =>
18
+ static readonly Fixed = (base: Date): Layer.Layer<DateTimes> =>
19
19
  Layer.effect(
20
20
  DateTimes,
21
21
  Effect.gen(function* () {
package/src/Uuid4.ts ADDED
@@ -0,0 +1,22 @@
1
+ import * as Effect from 'effect/Effect'
2
+ import { GetRandomValues } from './GetRandomValues.js'
3
+ import { Schema } from 'effect'
4
+ import { uuidStringify } from './UuidStringify.js'
5
+
6
+ export const Uuid4 = Schema.UUID.pipe(Schema.brand('@typed/id/UUID4'))
7
+ export type Uuid4 = Schema.Schema.Type<typeof Uuid4>
8
+
9
+ export const isUuid4: (value: string) => value is Uuid4 = Schema.is(Uuid4)
10
+
11
+ export const makeUuid4: Effect.Effect<Uuid4, never, GetRandomValues> = Effect.map(
12
+ GetRandomValues.apply(16),
13
+ uuid4FromSeed,
14
+ )
15
+
16
+ function uuid4FromSeed(seed: Uint8Array): Uuid4 {
17
+ // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
18
+ seed[6] = (seed[6] & 0x0f) | 0x40
19
+ seed[8] = (seed[8] & 0x3f) | 0x80
20
+
21
+ return uuidStringify(seed) as Uuid4
22
+ }
package/src/Uuid7.ts ADDED
@@ -0,0 +1,104 @@
1
+ import * as Effect from 'effect/Effect'
2
+ import { GetRandomValues } from './GetRandomValues.js'
3
+ import { Layer, Schema } from 'effect'
4
+ import { DateTimes } from './DateTimes.js'
5
+ import { uuidStringify } from './UuidStringify.js'
6
+
7
+ export const Uuid7 = Schema.UUID.pipe(Schema.brand('@typed/id/UUID7'))
8
+ export type Uuid7 = Schema.Schema.Type<typeof Uuid7>
9
+
10
+ export const isUuid7: (value: string) => value is Uuid7 = Schema.is(Uuid7)
11
+
12
+ export type Uuid7Seed = {
13
+ readonly timestamp: number
14
+ readonly seq: number
15
+ readonly randomBytes: Uint8Array
16
+ }
17
+
18
+ export class Uuid7State extends Effect.Tag('Uuid7State')<
19
+ Uuid7State,
20
+ {
21
+ readonly next: Effect.Effect<Uuid7Seed>
22
+ }
23
+ >() {
24
+ static Default: Layer.Layer<Uuid7State, never, GetRandomValues | DateTimes> = Layer.effect(
25
+ this,
26
+ Effect.gen(function* () {
27
+ const { now } = yield* DateTimes
28
+ const getRandomValues = yield* GetRandomValues
29
+
30
+ const state = {
31
+ msecs: Number.NEGATIVE_INFINITY,
32
+ seq: 0,
33
+ }
34
+
35
+ function updateV7State(now: number, randomBytes: Uint8Array) {
36
+ if (now > state.msecs) {
37
+ // Time has moved on! Pick a new random sequence number
38
+ state.seq =
39
+ (randomBytes[6] << 23) | (randomBytes[7] << 16) | (randomBytes[8] << 8) | randomBytes[9]
40
+ state.msecs = now
41
+ } else {
42
+ // Bump sequence counter w/ 32-bit rollover
43
+ state.seq = (state.seq + 1) | 0
44
+
45
+ // In case of rollover, bump timestamp to preserve monotonicity. This is
46
+ // allowed by the RFC and should self-correct as the system clock catches
47
+ // up. See https://www.rfc-editor.org/rfc/rfc9562.html#section-6.2-9.4
48
+ if (state.seq === 0) {
49
+ state.msecs++
50
+ }
51
+ }
52
+ }
53
+
54
+ return {
55
+ next: Effect.gen(function* () {
56
+ const randomBytes = yield* getRandomValues(16)
57
+ updateV7State(yield* now, randomBytes)
58
+ return { timestamp: state.msecs, seq: state.seq, randomBytes }
59
+ }),
60
+ }
61
+ }),
62
+ )
63
+ }
64
+
65
+ export const makeUuid7: Effect.Effect<Uuid7, never, Uuid7State> = Effect.map(
66
+ Uuid7State.next,
67
+ uuid7FromSeed,
68
+ )
69
+
70
+ function uuid7FromSeed({ timestamp, seq, randomBytes }: Uuid7Seed): Uuid7 {
71
+ const result = new Uint8Array(16)
72
+
73
+ // byte 0-5: timestamp (48 bits)
74
+ result[0] = (timestamp / 0x10000000000) & 0xff
75
+ result[1] = (timestamp / 0x100000000) & 0xff
76
+ result[2] = (timestamp / 0x1000000) & 0xff
77
+ result[3] = (timestamp / 0x10000) & 0xff
78
+ result[4] = (timestamp / 0x100) & 0xff
79
+ result[5] = timestamp & 0xff
80
+
81
+ // byte 6: `version` (4 bits) | sequence bits 28-31 (4 bits)
82
+ result[6] = 0x70 | ((seq >>> 28) & 0x0f)
83
+
84
+ // byte 7: sequence bits 20-27 (8 bits)
85
+ result[7] = (seq >>> 20) & 0xff
86
+
87
+ // byte 8: `variant` (2 bits) | sequence bits 14-19 (6 bits)
88
+ result[8] = 0x80 | ((seq >>> 14) & 0x3f)
89
+
90
+ // byte 9: sequence bits 6-13 (8 bits)
91
+ result[9] = (seq >>> 6) & 0xff
92
+
93
+ // byte 10: sequence bits 0-5 (6 bits) | random (2 bits)
94
+ result[10] = ((seq << 2) & 0xff) | (randomBytes[10] & 0x03)
95
+
96
+ // bytes 11-15: random (40 bits)
97
+ result[11] = randomBytes[11]
98
+ result[12] = randomBytes[12]
99
+ result[13] = randomBytes[13]
100
+ result[14] = randomBytes[14]
101
+ result[15] = randomBytes[15]
102
+
103
+ return uuidStringify(result) as Uuid7
104
+ }
@@ -0,0 +1,31 @@
1
+ const byteToHex: Array<string> = []
2
+
3
+ for (let i = 0; i < 256; ++i) {
4
+ byteToHex.push((i + 0x100).toString(16).slice(1))
5
+ }
6
+
7
+ export function uuidStringify(seed: Uint8Array): string {
8
+ return (
9
+ // biome-ignore lint/style/useTemplate: Faster than template literals
10
+ byteToHex[seed[0]] +
11
+ byteToHex[seed[1]] +
12
+ byteToHex[seed[2]] +
13
+ byteToHex[seed[3]] +
14
+ '-' +
15
+ byteToHex[seed[4]] +
16
+ byteToHex[seed[5]] +
17
+ '-' +
18
+ byteToHex[seed[6]] +
19
+ byteToHex[seed[7]] +
20
+ '-' +
21
+ byteToHex[seed[8]] +
22
+ byteToHex[seed[9]] +
23
+ '-' +
24
+ byteToHex[seed[10]] +
25
+ byteToHex[seed[11]] +
26
+ byteToHex[seed[12]] +
27
+ byteToHex[seed[13]] +
28
+ byteToHex[seed[14]] +
29
+ byteToHex[seed[15]]
30
+ )
31
+ }
package/src/id.test.ts CHANGED
@@ -1,6 +1,16 @@
1
1
  import { describe, expect, it } from '@effect/vitest'
2
- import { Effect } from 'effect'
3
- import { DateTimes, GetRandomValues, isUuid, makeNanoId, makeUlid, makeUuid } from './index.js'
2
+ import { Effect, flow } from 'effect'
3
+ import {
4
+ DateTimes,
5
+ GetRandomValues,
6
+ isUuid4,
7
+ isUuid7,
8
+ makeNanoId,
9
+ makeUlid,
10
+ makeUuid4,
11
+ makeUuid7,
12
+ Uuid7State,
13
+ } from './index.js'
4
14
 
5
15
  const makeTestValues = (length: number) => {
6
16
  const values = new Uint8Array(length)
@@ -10,19 +20,33 @@ const makeTestValues = (length: number) => {
10
20
  return values
11
21
  }
12
22
 
13
- const provideTestValues = Effect.provide([
14
- GetRandomValues.layer((length) => Effect.succeed(makeTestValues(length))),
15
- DateTimes.Fixed(new Date(0)),
16
- ])
23
+ const provideTestValues = flow(
24
+ Effect.provide(Uuid7State.Default),
25
+ Effect.provide([
26
+ GetRandomValues.layer((length) => Effect.succeed(makeTestValues(length))),
27
+ DateTimes.Fixed(new Date(0)),
28
+ ]),
29
+ )
17
30
 
18
31
  describe(__filename, () => {
19
- describe('Uuid', () => {
20
- it.effect('generates a UUID', () =>
32
+ describe('Uuid4', () => {
33
+ it.effect('generates a UUID v4', () =>
21
34
  Effect.gen(function* (_) {
22
- const id = yield* _(makeUuid)
23
- expect(id).toEqual('00010203-0405-0607-0809-0a0b0c0d0e0f')
35
+ const id = yield* _(makeUuid4)
36
+ expect(id).toMatchInlineSnapshot(`"00010203-0405-4607-8809-0a0b0c0d0e0f"`)
24
37
  expect(id.length).toEqual(36)
25
- expect(isUuid(id)).toEqual(true)
38
+ expect(isUuid4(id)).toEqual(true)
39
+ }).pipe(provideTestValues),
40
+ )
41
+ })
42
+
43
+ describe('Uuid7', () => {
44
+ it.effect('generates a UUID v7', () =>
45
+ Effect.gen(function* (_) {
46
+ const id = yield* _(makeUuid7)
47
+ expect(id).toMatchInlineSnapshot(`"00000000-0000-7030-9c20-260b0c0d0e0f"`)
48
+ expect(id.length).toEqual(36)
49
+ expect(isUuid7(id)).toEqual(true)
26
50
  }).pipe(provideTestValues),
27
51
  )
28
52
  })
@@ -31,8 +55,7 @@ describe(__filename, () => {
31
55
  it.effect('generates a NanoId', () =>
32
56
  Effect.gen(function* (_) {
33
57
  const id = yield* _(makeNanoId)
34
-
35
- expect(id).toEqual('0123456789abcdefghijk')
58
+ expect(id).toMatchInlineSnapshot(`"0123456789abcdefghijk"`)
36
59
  expect(id.length).toEqual(21)
37
60
  }).pipe(provideTestValues),
38
61
  )
package/src/index.ts CHANGED
@@ -2,4 +2,5 @@ export * from './DateTimes.js'
2
2
  export * from './GetRandomValues.js'
3
3
  export * from './NanoId.js'
4
4
  export * from './Ulid.js'
5
- export * from './Uuid.js'
5
+ export * from './Uuid4.js'
6
+ export * from './Uuid7.js'
package/src/Uuid.ts DELETED
@@ -1,76 +0,0 @@
1
- import * as Effect from 'effect/Effect'
2
- import { GetRandomValues } from './GetRandomValues.js'
3
- import { Schema } from 'effect'
4
-
5
- export const isUuid: (value: string) => value is Uuid = Schema.is(Schema.UUID) as any
6
-
7
- export const Uuid = Schema.UUID.pipe(Schema.brand('@typed/id/UUID'))
8
- export type Uuid = Schema.Schema.Type<typeof Uuid>
9
-
10
- export type UuidSeed = readonly [
11
- zero: number,
12
- one: number,
13
- two: number,
14
- three: number,
15
- four: number,
16
- five: number,
17
- six: number,
18
- seven: number,
19
- eight: number,
20
- nine: number,
21
- ten: number,
22
- eleven: number,
23
- twelve: number,
24
- thirteen: number,
25
- fourteen: number,
26
- fifteen: number,
27
- ]
28
-
29
- export const makeUuidSeed: Effect.Effect<UuidSeed, never, GetRandomValues> = GetRandomValues.apply(
30
- 32,
31
- ) as any
32
-
33
- export const makeUuid: Effect.Effect<Uuid, never, GetRandomValues> = Effect.map(makeUuidSeed, uuid4)
34
-
35
- /**
36
- * Convert array of 16 byte values to UUID string format of the form:
37
- * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
38
- */
39
- const byteToHex: Array<string> = []
40
-
41
- for (let i = 0; i < 256; ++i) {
42
- byteToHex.push((i + 0x100).toString(16).slice(1))
43
- }
44
-
45
- export function uuid4(seed: UuidSeed): Uuid {
46
- // Note: Be careful editing this code! It's been tuned for performance
47
- // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
48
- //
49
- // Note to future-self: No, you can't remove the `toLowerCase()` call.
50
- // REF: https://github.com/uuidjs/uuid/pull/677#issuecomment-1757351351
51
- return (
52
- (
53
- // biome-ignore lint/style/useTemplate: <explanation>
54
- byteToHex[seed[0]] +
55
- byteToHex[seed[1]] +
56
- byteToHex[seed[2]] +
57
- byteToHex[seed[3]] +
58
- '-' +
59
- byteToHex[seed[4]] +
60
- byteToHex[seed[5]] +
61
- '-' +
62
- byteToHex[seed[6]] +
63
- byteToHex[seed[7]] +
64
- '-' +
65
- byteToHex[seed[8]] +
66
- byteToHex[seed[9]] +
67
- '-' +
68
- byteToHex[seed[10]] +
69
- byteToHex[seed[11]] +
70
- byteToHex[seed[12]] +
71
- byteToHex[seed[13]] +
72
- byteToHex[seed[14]] +
73
- byteToHex[seed[15]]
74
- ).toLowerCase() as Uuid
75
- )
76
- }