@typed/id 1.0.0-beta.0 → 1.0.0-beta.2
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 +81 -81
- package/dist/Ids.d.ts +2 -1
- package/dist/Ids.d.ts.map +1 -1
- package/dist/Ids.js +2 -1
- package/dist/Ksuid.js +1 -1
- package/package.json +10 -6
- package/src/Id.test.ts +85 -71
- package/src/Ids.ts +5 -1
- package/src/Ksuid.ts +1 -1
- package/dist/Id.test.d.ts +0 -2
- package/dist/Id.test.d.ts.map +0 -1
- package/dist/Id.test.js +0 -190
- package/tsconfig.json +0 -6
- package/vitest.config.ts +0 -8
package/README.md
CHANGED
|
@@ -24,17 +24,17 @@
|
|
|
24
24
|
```ts
|
|
25
25
|
import { Ids, Uuid5Namespace } from "@typed/id";
|
|
26
26
|
|
|
27
|
-
const id = yield* Ids.cuid;
|
|
28
|
-
const id = yield* Ids.ksuid;
|
|
29
|
-
const id = yield* Ids.nanoId;
|
|
30
|
-
const id = yield* Ids.ulid;
|
|
31
|
-
const id = yield* Ids.uuid4;
|
|
32
|
-
const id = yield* Ids.uuid5(
|
|
33
|
-
const id = yield* Ids.uuid7;
|
|
27
|
+
const id = yield * Ids.cuid;
|
|
28
|
+
const id = yield * Ids.ksuid;
|
|
29
|
+
const id = yield * Ids.nanoId;
|
|
30
|
+
const id = yield * Ids.ulid;
|
|
31
|
+
const id = yield * Ids.uuid4;
|
|
32
|
+
const id = yield * Ids.uuid5("https://effect.website", Uuid5Namespace.URL);
|
|
33
|
+
const id = yield * Ids.uuid7;
|
|
34
34
|
|
|
35
35
|
// Provide Ids services
|
|
36
|
-
Effect.provide(Ids.Default)
|
|
37
|
-
Effect.provide(Ids.Test())
|
|
36
|
+
Effect.provide(Ids.Default);
|
|
37
|
+
Effect.provide(Ids.Test());
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
## API reference
|
|
@@ -43,17 +43,17 @@ Effect.provide(Ids.Test())
|
|
|
43
43
|
|
|
44
44
|
Unified service for generating all ID types. Requires `DateTimes`, `RandomValues`, `CuidState`, and `Uuid7State` (use `Ids.Default` or `Ids.Test()` to provide them).
|
|
45
45
|
|
|
46
|
-
| Member
|
|
47
|
-
|
|
48
|
-
| `Ids.cuid`
|
|
49
|
-
| `Ids.ksuid`
|
|
50
|
-
| `Ids.nanoId`
|
|
51
|
-
| `Ids.ulid`
|
|
52
|
-
| `Ids.uuid4`
|
|
53
|
-
| `Ids.uuid5`
|
|
54
|
-
| `Ids.uuid7`
|
|
55
|
-
| `Ids.Default`
|
|
56
|
-
| `Ids.Test(options?)` | `Layer<Ids \| DateTimes \| RandomValues>`
|
|
46
|
+
| Member | Type | Description |
|
|
47
|
+
| -------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
|
|
48
|
+
| `Ids.cuid` | `Effect<Cuid, never, Ids>` | Generate a Cuid. |
|
|
49
|
+
| `Ids.ksuid` | `Effect<Ksuid, never, Ids>` | Generate a Ksuid. |
|
|
50
|
+
| `Ids.nanoId` | `Effect<NanoId, never, Ids>` | Generate a NanoId. |
|
|
51
|
+
| `Ids.ulid` | `Effect<Ulid, never, Ids>` | Generate a ULID. |
|
|
52
|
+
| `Ids.uuid4` | `Effect<Uuid4, never, Ids>` | Generate a UUID v4. |
|
|
53
|
+
| `Ids.uuid5` | `(name, namespace) => Effect<Uuid5, never, Ids>` | Generate a UUID v5 from a name and namespace. Also has `Ids.uuid5.dns`, `.url`, `.oid`, `.x500` taking a single `name`. |
|
|
54
|
+
| `Ids.uuid7` | `Effect<Uuid7, never, Ids>` | Generate a UUID v7. |
|
|
55
|
+
| `Ids.Default` | `Layer<Ids \| DateTimes \| RandomValues>` | Layer that provides `Ids` with default Cuid/Uuid7/DateTimes/RandomValues. |
|
|
56
|
+
| `Ids.Test(options?)` | `Layer<Ids \| DateTimes \| RandomValues>` | Layer for tests; optional `currentTime` and `envData`. |
|
|
57
57
|
|
|
58
58
|
**TestOptions:** `{ currentTime?: number | string | Date; envData?: string }`
|
|
59
59
|
|
|
@@ -61,104 +61,104 @@ Unified service for generating all ID types. Requires `DateTimes`, `RandomValues
|
|
|
61
61
|
|
|
62
62
|
### Cuid
|
|
63
63
|
|
|
64
|
-
| Export
|
|
65
|
-
|
|
66
|
-
| `Cuid`
|
|
67
|
-
| `Cuid` (type)
|
|
68
|
-
| `isCuid`
|
|
69
|
-
| `CuidState`
|
|
70
|
-
| `CuidState.Default` | `Layer<CuidState>`
|
|
71
|
-
| `cuid`
|
|
64
|
+
| Export | Type | Description |
|
|
65
|
+
| ------------------- | ---------------------------------- | -------------------------------------------------- |
|
|
66
|
+
| `Cuid` | `Schema<string, Cuid>` | Branded schema for Cuid strings. |
|
|
67
|
+
| `Cuid` (type) | `string` | Branded Cuid type. |
|
|
68
|
+
| `isCuid` | `(value: string) => value is Cuid` | Type guard. |
|
|
69
|
+
| `CuidState` | Service | Provides `next: Effect<CuidSeed>`. Used by `cuid`. |
|
|
70
|
+
| `CuidState.Default` | `Layer<CuidState>` | Default CuidState (uses `"node"` envData). |
|
|
71
|
+
| `cuid` | `Effect<Cuid, never, CuidState>` | Generate a Cuid. |
|
|
72
72
|
|
|
73
73
|
---
|
|
74
74
|
|
|
75
75
|
### Ksuid
|
|
76
76
|
|
|
77
|
-
| Export
|
|
78
|
-
|
|
79
|
-
| `Ksuid`
|
|
80
|
-
| `Ksuid` (type) | `string`
|
|
81
|
-
| `isKsuid`
|
|
82
|
-
| `ksuid`
|
|
77
|
+
| Export | Type | Description |
|
|
78
|
+
| -------------- | ------------------------------------------------- | ----------------------------------------- |
|
|
79
|
+
| `Ksuid` | `Schema<string, Ksuid>` | Branded schema for 27-char base62 Ksuids. |
|
|
80
|
+
| `Ksuid` (type) | `string` | Branded Ksuid type. |
|
|
81
|
+
| `isKsuid` | `(value: string) => value is Ksuid` | Type guard. |
|
|
82
|
+
| `ksuid` | `Effect<Ksuid, never, DateTimes \| RandomValues>` | Generate a Ksuid. |
|
|
83
83
|
|
|
84
84
|
---
|
|
85
85
|
|
|
86
86
|
### NanoId
|
|
87
87
|
|
|
88
|
-
| Export
|
|
89
|
-
|
|
90
|
-
| `NanoId`
|
|
91
|
-
| `NanoId` (type) | `string`
|
|
92
|
-
| `isNanoId`
|
|
93
|
-
| `nanoId`
|
|
88
|
+
| Export | Type | Description |
|
|
89
|
+
| --------------- | ------------------------------------- | -------------------------------------------- |
|
|
90
|
+
| `NanoId` | `Schema<string, NanoId>` | Branded schema for `[0-9a-zA-Z_-]+` strings. |
|
|
91
|
+
| `NanoId` (type) | `string` | Branded NanoId type. |
|
|
92
|
+
| `isNanoId` | `(value: string) => value is NanoId` | Type guard. |
|
|
93
|
+
| `nanoId` | `Effect<NanoId, never, RandomValues>` | Generate a 21-char NanoId. |
|
|
94
94
|
|
|
95
95
|
---
|
|
96
96
|
|
|
97
97
|
### Ulid
|
|
98
98
|
|
|
99
|
-
| Export
|
|
100
|
-
|
|
101
|
-
| `Ulid`
|
|
102
|
-
| `Ulid` (type) | `string`
|
|
103
|
-
| `isUlid`
|
|
104
|
-
| `ulid`
|
|
99
|
+
| Export | Type | Description |
|
|
100
|
+
| ------------- | ------------------------------------------------ | -------------------------------- |
|
|
101
|
+
| `Ulid` | `Schema<string, Ulid>` | Branded schema for ULID strings. |
|
|
102
|
+
| `Ulid` (type) | `string` | Branded Ulid type. |
|
|
103
|
+
| `isUlid` | `(value: string) => value is Ulid` | Type guard. |
|
|
104
|
+
| `ulid` | `Effect<Ulid, never, DateTimes \| RandomValues>` | Generate a ULID. |
|
|
105
105
|
|
|
106
106
|
---
|
|
107
107
|
|
|
108
108
|
### Uuid4
|
|
109
109
|
|
|
110
|
-
| Export
|
|
111
|
-
|
|
112
|
-
| `Uuid4`
|
|
113
|
-
| `Uuid4` (type) | `string`
|
|
114
|
-
| `isUuid4`
|
|
115
|
-
| `uuid4`
|
|
110
|
+
| Export | Type | Description |
|
|
111
|
+
| -------------- | ------------------------------------ | --------------------------- |
|
|
112
|
+
| `Uuid4` | `Schema<string, Uuid4>` | Branded schema for UUID v4. |
|
|
113
|
+
| `Uuid4` (type) | `string` | Branded Uuid4 type. |
|
|
114
|
+
| `isUuid4` | `(value: string) => value is Uuid4` | Type guard. |
|
|
115
|
+
| `uuid4` | `Effect<Uuid4, never, RandomValues>` | Generate a UUID v4. |
|
|
116
116
|
|
|
117
117
|
---
|
|
118
118
|
|
|
119
119
|
### Uuid5
|
|
120
120
|
|
|
121
|
-
| Export
|
|
122
|
-
|
|
123
|
-
| `Uuid5`
|
|
124
|
-
| `Uuid5` (type)
|
|
125
|
-
| `Uuid5Namespace`
|
|
126
|
-
| `isUuid5`
|
|
127
|
-
| `uuid5`
|
|
128
|
-
| `dnsUuid5`, `urlUuid5`, `oidUuid5`, `x500Uuid5` | `(name: string) => Effect<Uuid5>`
|
|
121
|
+
| Export | Type | Description |
|
|
122
|
+
| ----------------------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------ |
|
|
123
|
+
| `Uuid5` | `Schema<string, Uuid5>` | Branded schema for UUID v5. |
|
|
124
|
+
| `Uuid5` (type) | `string` | Branded Uuid5 type. |
|
|
125
|
+
| `Uuid5Namespace` | `Uint8Array` (type) + const object | Namespace type; const has `DNS`, `URL`, `OID`, `X500`. |
|
|
126
|
+
| `isUuid5` | `(value: string) => value is Uuid5` | Type guard. |
|
|
127
|
+
| `uuid5` | `(name, namespace) => Effect<Uuid5>` or `(namespace) => (name) => Effect<Uuid5>` | Generate UUID v5 from name + namespace. |
|
|
128
|
+
| `dnsUuid5`, `urlUuid5`, `oidUuid5`, `x500Uuid5` | `(name: string) => Effect<Uuid5>` | Pre-bound effects for standard namespaces. |
|
|
129
129
|
|
|
130
130
|
---
|
|
131
131
|
|
|
132
132
|
### Uuid7
|
|
133
133
|
|
|
134
|
-
| Export
|
|
135
|
-
|
|
136
|
-
| `Uuid7`
|
|
137
|
-
| `Uuid7` (type)
|
|
138
|
-
| `isUuid7`
|
|
139
|
-
| `Uuid7State`
|
|
140
|
-
| `Uuid7State.Default` | `Layer<Uuid7State>`
|
|
141
|
-
| `uuid7`
|
|
134
|
+
| Export | Type | Description |
|
|
135
|
+
| -------------------- | ----------------------------------- | ---------------------------------------------------- |
|
|
136
|
+
| `Uuid7` | `Schema<string, Uuid7>` | Branded schema for UUID v7. |
|
|
137
|
+
| `Uuid7` (type) | `string` | Branded Uuid7 type. |
|
|
138
|
+
| `isUuid7` | `(value: string) => value is Uuid7` | Type guard. |
|
|
139
|
+
| `Uuid7State` | Service | Provides `next: Effect<Uuid7Seed>`. Used by `uuid7`. |
|
|
140
|
+
| `Uuid7State.Default` | `Layer<Uuid7State>` | Default Uuid7State. |
|
|
141
|
+
| `uuid7` | `Effect<Uuid7, never, Uuid7State>` | Generate a UUID v7. |
|
|
142
142
|
|
|
143
143
|
---
|
|
144
144
|
|
|
145
145
|
### DateTimes
|
|
146
146
|
|
|
147
|
-
| Export
|
|
148
|
-
|
|
149
|
-
| `DateTimes`
|
|
150
|
-
| `DateTimes.now`
|
|
151
|
-
| `DateTimes.date`
|
|
152
|
-
| `DateTimes.Default`
|
|
153
|
-
| `DateTimes.Fixed(baseDate)` | `Layer<DateTimes>`
|
|
147
|
+
| Export | Type | Description |
|
|
148
|
+
| --------------------------- | ---------------------------------- | --------------------------------------------------------------- |
|
|
149
|
+
| `DateTimes` | Service | Provides `now: Effect<number>`, `date: Effect<Date>`. |
|
|
150
|
+
| `DateTimes.now` | `Effect<number, never, DateTimes>` | Current time in ms. |
|
|
151
|
+
| `DateTimes.date` | `Effect<Date, never, DateTimes>` | Current date. |
|
|
152
|
+
| `DateTimes.Default` | `Layer<DateTimes>` | Real clock. |
|
|
153
|
+
| `DateTimes.Fixed(baseDate)` | `Layer<DateTimes>` | Fixed time for tests; `baseDate` is `number \| string \| Date`. |
|
|
154
154
|
|
|
155
155
|
---
|
|
156
156
|
|
|
157
157
|
### RandomValues
|
|
158
158
|
|
|
159
|
-
| Export
|
|
160
|
-
|
|
161
|
-
| `RandomValues`
|
|
162
|
-
| `RandomValues.call(length)` | `Effect<Uint8Array, never, RandomValues>` | Request `length` cryptographically random bytes.
|
|
163
|
-
| `RandomValues.Default`
|
|
164
|
-
| `RandomValues.Random`
|
|
159
|
+
| Export | Type | Description |
|
|
160
|
+
| --------------------------- | ----------------------------------------- | ----------------------------------------------------- |
|
|
161
|
+
| `RandomValues` | Service | Provides a function `(length) => Effect<Uint8Array>`. |
|
|
162
|
+
| `RandomValues.call(length)` | `Effect<Uint8Array, never, RandomValues>` | Request `length` cryptographically random bytes. |
|
|
163
|
+
| `RandomValues.Default` | `Layer<RandomValues>` | Uses `crypto.getRandomValues`. |
|
|
164
|
+
| `RandomValues.Random` | `Layer<RandomValues>` | Uses Effect `Random` (e.g. for tests). |
|
package/dist/Ids.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type { Uuid4 } from "./Uuid4.js";
|
|
|
12
12
|
import { type Uuid5, Uuid5Namespace } from "./Uuid5.js";
|
|
13
13
|
import type { Uuid7 } from "./Uuid7.js";
|
|
14
14
|
import { Uuid7State } from "./Uuid7.js";
|
|
15
|
+
import { TestClock } from "effect/testing";
|
|
15
16
|
declare const Ids_base: ServiceMap.ServiceClass<Ids, "@typed/id/Ids", {
|
|
16
17
|
cuid: Effect.Effect<string & import("effect/Brand").Brand<"@typed/id/CUID">, never, never>;
|
|
17
18
|
ksuid: Effect.Effect<string & import("effect/Brand").Brand<"@typed/id/KSUID">, never, never>;
|
|
@@ -61,7 +62,7 @@ export declare class Ids extends Ids_base {
|
|
|
61
62
|
};
|
|
62
63
|
static readonly uuid7: Effect.Effect<Uuid7, never, Ids>;
|
|
63
64
|
static readonly Default: Layer.Layer<Ids | DateTimes | RandomValues, never, never>;
|
|
64
|
-
static readonly Test: (options?: TestOptions) => Layer.Layer<Ids | DateTimes | RandomValues>;
|
|
65
|
+
static readonly Test: (options?: TestOptions) => Layer.Layer<Ids | DateTimes | RandomValues | TestClock.TestClock>;
|
|
65
66
|
}
|
|
66
67
|
export type TestOptions = {
|
|
67
68
|
readonly currentTime?: number | string | Date;
|
package/dist/Ids.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Ids.d.ts","sourceRoot":"","sources":["../src/Ids.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAQ,SAAS,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,KAAK,KAAK,EAAS,cAAc,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAS,UAAU,EAAE,MAAM,YAAY,CAAC;;;;;;;;
|
|
1
|
+
{"version":3,"file":"Ids.d.ts","sourceRoot":"","sources":["../src/Ids.ts"],"names":[],"mappings":"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"}
|
package/dist/Ids.js
CHANGED
|
@@ -11,6 +11,7 @@ import { ulid } from "./Ulid.js";
|
|
|
11
11
|
import { uuid4 } from "./Uuid4.js";
|
|
12
12
|
import { uuid5, Uuid5Namespace } from "./Uuid5.js";
|
|
13
13
|
import { uuid7, Uuid7State } from "./Uuid7.js";
|
|
14
|
+
import { TestClock } from "effect/testing";
|
|
14
15
|
export class Ids extends ServiceMap.Service()("@typed/id/Ids", {
|
|
15
16
|
make: Effect.gen(function* () {
|
|
16
17
|
const services = yield* Effect.services();
|
|
@@ -47,5 +48,5 @@ export class Ids extends ServiceMap.Service()("@typed/id/Ids", {
|
|
|
47
48
|
static Test = (options) => Layer.effect(Ids, Ids.make).pipe(Layer.provide([
|
|
48
49
|
Layer.effect(CuidState, CuidState.make(options?.envData ?? "node")),
|
|
49
50
|
Uuid7State.Default,
|
|
50
|
-
]), Layer.provideMerge([DateTimes.Fixed(options?.currentTime ?? 0), RandomValues.Random]));
|
|
51
|
+
]), Layer.provideMerge([DateTimes.Fixed(options?.currentTime ?? 0), RandomValues.Random]), Layer.provideMerge(TestClock.layer({})));
|
|
51
52
|
}
|
package/dist/Ksuid.js
CHANGED
|
@@ -9,7 +9,7 @@ const PAYLOAD_BYTES = 16;
|
|
|
9
9
|
const TOTAL_BYTES = TIMESTAMP_BYTES + PAYLOAD_BYTES;
|
|
10
10
|
const STRING_LENGTH = 27;
|
|
11
11
|
// Schema
|
|
12
|
-
export const Ksuid = Schema.String.pipe(Schema.check(Schema.isPattern(/^[0-
|
|
12
|
+
export const Ksuid = Schema.String.pipe(Schema.check(Schema.isPattern(/^[0-9A-Za-z]{27}$/)), Schema.brand("@typed/id/KSUID"));
|
|
13
13
|
export const isKsuid = Schema.is(Ksuid);
|
|
14
14
|
// Public API
|
|
15
15
|
export const ksuid = Effect.zipWith(DateTimes.now, RandomValues.call(PAYLOAD_BYTES), (timestamp, payload) => {
|
package/package.json
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typed/id",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
4
|
-
"publishConfig": {
|
|
5
|
-
"access": "public"
|
|
6
|
-
},
|
|
3
|
+
"version": "1.0.0-beta.2",
|
|
7
4
|
"type": "module",
|
|
8
5
|
"exports": {
|
|
9
6
|
".": {
|
|
@@ -15,15 +12,22 @@
|
|
|
15
12
|
"import": "./dist/*.js"
|
|
16
13
|
}
|
|
17
14
|
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"effect": "4.0.0-beta.
|
|
19
|
+
"effect": "4.0.0-beta.21"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"typescript": "5.9.3",
|
|
23
23
|
"vitest": "4.0.18"
|
|
24
24
|
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"src"
|
|
28
|
+
],
|
|
25
29
|
"scripts": {
|
|
26
|
-
"build": "tsc",
|
|
30
|
+
"build": "[ -d dist ] || rm -f tsconfig.tsbuildinfo; tsc",
|
|
27
31
|
"test": "vitest run --passWithNoTests"
|
|
28
32
|
}
|
|
29
33
|
}
|
package/src/Id.test.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
|
-
import
|
|
2
|
+
import * as FastCheck from "effect/testing/FastCheck";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
3
4
|
import * as Cuid from "./Cuid.js";
|
|
4
5
|
import { Ids } from "./Ids.js";
|
|
5
6
|
import * as Ksuid from "./Ksuid.js";
|
|
@@ -15,91 +16,116 @@ const run = <A, E>(effect: Effect.Effect<A, E, Ids>) =>
|
|
|
15
16
|
Effect.runPromise(Effect.provide(effect, Ids.Test()));
|
|
16
17
|
|
|
17
18
|
describe("@typed/id", () => {
|
|
18
|
-
describe("type guards", () => {
|
|
19
|
+
describe("type guards (property-based)", () => {
|
|
19
20
|
describe("isUuid4", () => {
|
|
20
|
-
it("accepts
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
it("rejects invalid formats", () => {
|
|
25
|
-
expect(Uuid4.isUuid4("")).toBe(false);
|
|
26
|
-
expect(Uuid4.isUuid4("not-a-uuid")).toBe(false);
|
|
27
|
-
expect(Uuid4.isUuid4("f47ac10b-58cc-4372-a567-0e02b2c3d479".replace(/-/g, ""))).toBe(false);
|
|
28
|
-
expect(Uuid4.isUuid4("g47ac10b-58cc-4372-a567-0e02b2c3d479")).toBe(false); // invalid hex
|
|
21
|
+
it("accepts any UUID v4", () => {
|
|
22
|
+
FastCheck.assert(
|
|
23
|
+
FastCheck.property(FastCheck.uuid({ version: 4 }), (s) => Uuid4.isUuid4(s)),
|
|
24
|
+
);
|
|
29
25
|
});
|
|
30
|
-
it("rejects UUID
|
|
31
|
-
|
|
26
|
+
it("rejects non-UUID-v4 strings", () => {
|
|
27
|
+
const invalid = FastCheck.oneof(
|
|
28
|
+
FastCheck.constant(""),
|
|
29
|
+
FastCheck.string({ maxLength: 35 }).filter((s) => s.length < 36),
|
|
30
|
+
FastCheck.string().filter(
|
|
31
|
+
(s) =>
|
|
32
|
+
!/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(s),
|
|
33
|
+
),
|
|
34
|
+
);
|
|
35
|
+
FastCheck.assert(FastCheck.property(invalid, (s) => !Uuid4.isUuid4(s)));
|
|
32
36
|
});
|
|
33
37
|
});
|
|
34
38
|
|
|
35
39
|
describe("isUuid5", () => {
|
|
36
|
-
it("accepts
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
it("accepts any UUID v5", () => {
|
|
41
|
+
FastCheck.assert(
|
|
42
|
+
FastCheck.property(FastCheck.uuid({ version: 5 }), (s) => Uuid5.isUuid5(s)),
|
|
43
|
+
);
|
|
39
44
|
});
|
|
40
|
-
it("rejects
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
it("rejects non-UUID-v5 strings", () => {
|
|
46
|
+
const invalid = FastCheck.oneof(
|
|
47
|
+
FastCheck.constant(""),
|
|
48
|
+
FastCheck.string().filter(
|
|
49
|
+
(s) =>
|
|
50
|
+
!/^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(s),
|
|
51
|
+
),
|
|
52
|
+
);
|
|
53
|
+
FastCheck.assert(FastCheck.property(invalid, (s) => !Uuid5.isUuid5(s)));
|
|
43
54
|
});
|
|
44
55
|
});
|
|
45
56
|
|
|
46
57
|
describe("isUuid7", () => {
|
|
47
|
-
it("accepts
|
|
48
|
-
|
|
58
|
+
it("accepts any UUID v7", () => {
|
|
59
|
+
FastCheck.assert(
|
|
60
|
+
FastCheck.property(FastCheck.uuid({ version: 7 }), (s) => Uuid7.isUuid7(s)),
|
|
61
|
+
);
|
|
49
62
|
});
|
|
50
|
-
it("rejects
|
|
51
|
-
|
|
52
|
-
|
|
63
|
+
it("rejects non-UUID-v7 strings", () => {
|
|
64
|
+
const invalid = FastCheck.oneof(
|
|
65
|
+
FastCheck.constant(""),
|
|
66
|
+
FastCheck.string().filter(
|
|
67
|
+
(s) =>
|
|
68
|
+
!/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(s),
|
|
69
|
+
),
|
|
70
|
+
);
|
|
71
|
+
FastCheck.assert(FastCheck.property(invalid, (s) => !Uuid7.isUuid7(s)));
|
|
53
72
|
});
|
|
54
73
|
});
|
|
55
74
|
|
|
56
75
|
describe("isCuid", () => {
|
|
57
|
-
it("accepts
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
});
|
|
61
|
-
it("rejects
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
76
|
+
it("accepts any CUID-like string (lowercase letter + base36)", () => {
|
|
77
|
+
const cuidArb = FastCheck.stringMatching(/^[a-z][0-9a-z]+$/);
|
|
78
|
+
FastCheck.assert(FastCheck.property(cuidArb, (s) => Cuid.isCuid(s)));
|
|
79
|
+
});
|
|
80
|
+
it("rejects strings that do not match CUID pattern", () => {
|
|
81
|
+
const invalid = FastCheck.oneof(
|
|
82
|
+
FastCheck.constant(""),
|
|
83
|
+
FastCheck.string().filter((s) => !/^[a-z][0-9a-z]+$/.test(s)),
|
|
84
|
+
);
|
|
85
|
+
FastCheck.assert(FastCheck.property(invalid, (s) => !Cuid.isCuid(s)));
|
|
66
86
|
});
|
|
67
87
|
});
|
|
68
88
|
|
|
69
89
|
describe("isKsuid", () => {
|
|
70
|
-
it("accepts 27-char base62
|
|
71
|
-
|
|
72
|
-
assert(Ksuid.isKsuid(
|
|
73
|
-
});
|
|
74
|
-
it("rejects
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
90
|
+
it("accepts any 27-char base62 string", () => {
|
|
91
|
+
const ksuidArb = FastCheck.stringMatching(/^[0-9A-Za-z]{27}$/);
|
|
92
|
+
FastCheck.assert(FastCheck.property(ksuidArb, (s) => Ksuid.isKsuid(s)));
|
|
93
|
+
});
|
|
94
|
+
it("rejects non-KSUID strings", () => {
|
|
95
|
+
const invalid = FastCheck.oneof(
|
|
96
|
+
FastCheck.constant(""),
|
|
97
|
+
FastCheck.string().filter((s) => s.length !== 27 || !/^[0-9A-Za-z]{27}$/.test(s)),
|
|
98
|
+
);
|
|
99
|
+
FastCheck.assert(FastCheck.property(invalid, (s) => !Ksuid.isKsuid(s)));
|
|
78
100
|
});
|
|
79
101
|
});
|
|
80
102
|
|
|
81
103
|
describe("isNanoId", () => {
|
|
82
|
-
it("accepts
|
|
83
|
-
|
|
84
|
-
assert(NanoId.isNanoId(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
104
|
+
it("accepts any string with only 0-9a-zA-Z_-", () => {
|
|
105
|
+
const nanoIdArb = FastCheck.stringMatching(/^[0-9a-zA-Z_-]+$/);
|
|
106
|
+
FastCheck.assert(FastCheck.property(nanoIdArb, (s) => NanoId.isNanoId(s)));
|
|
107
|
+
});
|
|
108
|
+
it("rejects strings with invalid characters", () => {
|
|
109
|
+
const invalid = FastCheck.oneof(
|
|
110
|
+
FastCheck.constant(""),
|
|
111
|
+
FastCheck.string().filter((s) => !/^[0-9a-zA-Z_-]+$/.test(s)),
|
|
112
|
+
);
|
|
113
|
+
FastCheck.assert(FastCheck.property(invalid, (s) => !NanoId.isNanoId(s)));
|
|
91
114
|
});
|
|
92
115
|
});
|
|
93
116
|
|
|
94
117
|
describe("isUlid", () => {
|
|
95
|
-
it("accepts valid
|
|
96
|
-
|
|
97
|
-
});
|
|
98
|
-
it("rejects
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
118
|
+
it("accepts any valid ULID", () => {
|
|
119
|
+
FastCheck.assert(FastCheck.property(FastCheck.ulid(), (s) => Ulid.isUlid(s)));
|
|
120
|
+
});
|
|
121
|
+
it("rejects non-ULID strings", () => {
|
|
122
|
+
const invalid = FastCheck.oneof(
|
|
123
|
+
FastCheck.constant(""),
|
|
124
|
+
FastCheck.string().filter(
|
|
125
|
+
(s) => s.length !== 26 || !/^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/.test(s),
|
|
126
|
+
),
|
|
127
|
+
);
|
|
128
|
+
FastCheck.assert(FastCheck.property(invalid, (s) => !Ulid.isUlid(s)));
|
|
103
129
|
});
|
|
104
130
|
});
|
|
105
131
|
});
|
|
@@ -107,13 +133,11 @@ describe("@typed/id", () => {
|
|
|
107
133
|
describe("Ids service", () => {
|
|
108
134
|
it("uuid4 produces valid UUID v4", async () => {
|
|
109
135
|
const id = await run(Ids.uuid4);
|
|
110
|
-
expect(id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
|
|
111
136
|
expect(Uuid4.isUuid4(id)).toBe(true);
|
|
112
137
|
});
|
|
113
138
|
|
|
114
139
|
it("uuid5 produces valid UUID v5", async () => {
|
|
115
140
|
const id = await run(Ids.uuid5("hello", Uuid5.Uuid5Namespace.DNS));
|
|
116
|
-
expect(id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
|
|
117
141
|
expect(Uuid5.isUuid5(id)).toBe(true);
|
|
118
142
|
});
|
|
119
143
|
|
|
@@ -143,27 +167,23 @@ describe("@typed/id", () => {
|
|
|
143
167
|
|
|
144
168
|
it("uuid7 produces valid UUID v7", async () => {
|
|
145
169
|
const id = await run(Ids.uuid7);
|
|
146
|
-
expect(id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
|
|
147
170
|
expect(Uuid7.isUuid7(id)).toBe(true);
|
|
148
171
|
});
|
|
149
172
|
|
|
150
173
|
it("cuid produces valid CUID", async () => {
|
|
151
174
|
const id = await run(Ids.cuid);
|
|
152
175
|
expect(Cuid.isCuid(id)).toBe(true);
|
|
153
|
-
expect(id).toMatch(/^[a-z][0-9a-z]+$/);
|
|
154
176
|
});
|
|
155
177
|
|
|
156
178
|
it("ksuid produces valid KSUID", async () => {
|
|
157
179
|
const id = await run(Ids.ksuid);
|
|
158
180
|
expect(Ksuid.isKsuid(id)).toBe(true);
|
|
159
181
|
expect(id).toHaveLength(27);
|
|
160
|
-
expect(id).toMatch(/^[0-9a-zA-Z]{27}$/);
|
|
161
182
|
});
|
|
162
183
|
|
|
163
184
|
it("nanoId produces valid NanoId", async () => {
|
|
164
185
|
const id = await run(Ids.nanoId);
|
|
165
186
|
expect(NanoId.isNanoId(id)).toBe(true);
|
|
166
|
-
expect(id).toMatch(/^[0-9a-zA-Z_-]+$/);
|
|
167
187
|
expect(id).toHaveLength(21);
|
|
168
188
|
});
|
|
169
189
|
|
|
@@ -171,17 +191,11 @@ describe("@typed/id", () => {
|
|
|
171
191
|
const id = await run(Ids.ulid);
|
|
172
192
|
expect(Ulid.isUlid(id)).toBe(true);
|
|
173
193
|
expect(id).toHaveLength(26);
|
|
174
|
-
expect(id).toMatch(/^[0-9A-HJKMNP-TV-Z]{26}$/);
|
|
175
194
|
});
|
|
176
195
|
|
|
177
196
|
it("Ids.Test with fixed time yields deterministic time-based prefixes", async () => {
|
|
178
197
|
const runFixed = <A, E>(effect: Effect.Effect<A, E, Ids>) =>
|
|
179
|
-
effect.pipe(
|
|
180
|
-
Effect.provide(Ids.Test({})),
|
|
181
|
-
Effect.provide(TestClock.layer({})),
|
|
182
|
-
Random.withSeed(42),
|
|
183
|
-
Effect.runPromise,
|
|
184
|
-
);
|
|
198
|
+
effect.pipe(Effect.provide(Ids.Test({})), Random.withSeed(0), Effect.runPromise);
|
|
185
199
|
|
|
186
200
|
const [ulid1, ulid2, ksuid1, ksuid2] = await runFixed(
|
|
187
201
|
Effect.all([Ids.ulid, Ids.ulid, Ids.ksuid, Ids.ksuid], { concurrency: "unbounded" }),
|
package/src/Ids.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { uuid4 } from "./Uuid4.js";
|
|
|
17
17
|
import { type Uuid5, uuid5, Uuid5Namespace } from "./Uuid5.js";
|
|
18
18
|
import type { Uuid7 } from "./Uuid7.js";
|
|
19
19
|
import { uuid7, Uuid7State } from "./Uuid7.js";
|
|
20
|
+
import { TestClock } from "effect/testing";
|
|
20
21
|
|
|
21
22
|
export class Ids extends ServiceMap.Service<Ids>()("@typed/id/Ids", {
|
|
22
23
|
make: Effect.gen(function* () {
|
|
@@ -108,13 +109,16 @@ export class Ids extends ServiceMap.Service<Ids>()("@typed/id/Ids", {
|
|
|
108
109
|
Layer.provideMerge([DateTimes.Default, RandomValues.Default]),
|
|
109
110
|
);
|
|
110
111
|
|
|
111
|
-
static readonly Test = (
|
|
112
|
+
static readonly Test = (
|
|
113
|
+
options?: TestOptions,
|
|
114
|
+
): Layer.Layer<Ids | DateTimes | RandomValues | TestClock.TestClock> =>
|
|
112
115
|
Layer.effect(Ids, Ids.make).pipe(
|
|
113
116
|
Layer.provide([
|
|
114
117
|
Layer.effect(CuidState, CuidState.make(options?.envData ?? "node")),
|
|
115
118
|
Uuid7State.Default,
|
|
116
119
|
]),
|
|
117
120
|
Layer.provideMerge([DateTimes.Fixed(options?.currentTime ?? 0), RandomValues.Random]),
|
|
121
|
+
Layer.provideMerge(TestClock.layer({})),
|
|
118
122
|
);
|
|
119
123
|
}
|
|
120
124
|
|
package/src/Ksuid.ts
CHANGED
|
@@ -12,7 +12,7 @@ const STRING_LENGTH = 27;
|
|
|
12
12
|
|
|
13
13
|
// Schema
|
|
14
14
|
export const Ksuid = Schema.String.pipe(
|
|
15
|
-
Schema.check(Schema.isPattern(/^[0-
|
|
15
|
+
Schema.check(Schema.isPattern(/^[0-9A-Za-z]{27}$/)),
|
|
16
16
|
Schema.brand("@typed/id/KSUID"),
|
|
17
17
|
);
|
|
18
18
|
export type Ksuid = typeof Ksuid.Type;
|
package/dist/Id.test.d.ts
DELETED
package/dist/Id.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Id.test.d.ts","sourceRoot":"","sources":["../src/Id.test.ts"],"names":[],"mappings":""}
|
package/dist/Id.test.js
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import * as Effect from "effect/Effect";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
|
-
import * as Cuid from "./Cuid.js";
|
|
4
|
-
import { Ids } from "./Ids.js";
|
|
5
|
-
import * as Ksuid from "./Ksuid.js";
|
|
6
|
-
import * as NanoId from "./NanoId.js";
|
|
7
|
-
import * as Ulid from "./Ulid.js";
|
|
8
|
-
import * as Uuid4 from "./Uuid4.js";
|
|
9
|
-
import * as Uuid5 from "./Uuid5.js";
|
|
10
|
-
import * as Uuid7 from "./Uuid7.js";
|
|
11
|
-
const run = (effect) => Effect.runPromise(Effect.provide(effect, Ids.Test()));
|
|
12
|
-
describe("@typed/id", () => {
|
|
13
|
-
describe("type guards", () => {
|
|
14
|
-
describe("isUuid4", () => {
|
|
15
|
-
it("accepts valid UUID v4", () => {
|
|
16
|
-
expect(Uuid4.isUuid4("f47ac10b-58cc-4372-a567-0e02b2c3d479")).toBe(true);
|
|
17
|
-
expect(Uuid4.isUuid4("550e8400-e29b-41d4-a716-446655440000")).toBe(true);
|
|
18
|
-
});
|
|
19
|
-
it("rejects invalid formats", () => {
|
|
20
|
-
expect(Uuid4.isUuid4("")).toBe(false);
|
|
21
|
-
expect(Uuid4.isUuid4("not-a-uuid")).toBe(false);
|
|
22
|
-
expect(Uuid4.isUuid4("f47ac10b-58cc-4372-a567-0e02b2c3d479".replace(/-/g, ""))).toBe(false);
|
|
23
|
-
expect(Uuid4.isUuid4("g47ac10b-58cc-4372-a567-0e02b2c3d479")).toBe(false); // invalid hex
|
|
24
|
-
});
|
|
25
|
-
it("rejects UUID v5 as UUID v4", () => {
|
|
26
|
-
expect(Uuid4.isUuid4("886313e1-3b8a-5372-9b90-0c9aee199e5d")).toBe(false);
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
describe("isUuid5", () => {
|
|
30
|
-
it("accepts valid UUID v5", () => {
|
|
31
|
-
expect(Uuid5.isUuid5("886313e1-3b8a-5372-9b90-0c9aee199e5d")).toBe(true);
|
|
32
|
-
expect(Uuid5.isUuid5("c2ee5f2e-5b2e-5f2e-8b2e-5b2e5f2e8b2e")).toBe(true);
|
|
33
|
-
});
|
|
34
|
-
it("rejects invalid formats", () => {
|
|
35
|
-
expect(Uuid5.isUuid5("")).toBe(false);
|
|
36
|
-
expect(Uuid5.isUuid5("f47ac10b-58cc-4372-a567-0e02b2c3d479")).toBe(false); // v4
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
describe("isUuid7", () => {
|
|
40
|
-
it("accepts valid UUID v7", () => {
|
|
41
|
-
expect(Uuid7.isUuid7("018eebb4-1f2c-7c3a-8b4d-123456789abc")).toBe(true);
|
|
42
|
-
});
|
|
43
|
-
it("rejects invalid formats", () => {
|
|
44
|
-
expect(Uuid7.isUuid7("")).toBe(false);
|
|
45
|
-
expect(Uuid7.isUuid7("f47ac10b-58cc-4372-a567-0e02b2c3d479")).toBe(false); // v4
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
describe("isCuid", () => {
|
|
49
|
-
it("accepts valid CUID-like strings (lowercase letter + base36)", () => {
|
|
50
|
-
expect(Cuid.isCuid("c1234567890abcdefghijklmn")).toBe(true);
|
|
51
|
-
expect(Cuid.isCuid("a0")).toBe(true);
|
|
52
|
-
});
|
|
53
|
-
it("rejects invalid formats", () => {
|
|
54
|
-
expect(Cuid.isCuid("")).toBe(false);
|
|
55
|
-
expect(Cuid.isCuid("A123")).toBe(false); // must start with lowercase
|
|
56
|
-
expect(Cuid.isCuid("1abc")).toBe(false); // must start with letter
|
|
57
|
-
expect(Cuid.isCuid("c123-456")).toBe(false); // no hyphen
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
describe("isKsuid", () => {
|
|
61
|
-
it("accepts 27-char base62 strings", () => {
|
|
62
|
-
expect(Ksuid.isKsuid("0ujsszwN8NRYtYaMBZrYCVp4O1")).toBe(true);
|
|
63
|
-
expect(Ksuid.isKsuid("0123456789ABCDEFGHIJKLMNOP")).toBe(true);
|
|
64
|
-
});
|
|
65
|
-
it("rejects invalid formats", () => {
|
|
66
|
-
expect(Ksuid.isKsuid("")).toBe(false);
|
|
67
|
-
expect(Ksuid.isKsuid("short")).toBe(false);
|
|
68
|
-
expect(Ksuid.isKsuid("0ujsszwN8NRYtYaMBZrYCVp4O1!")).toBe(false); // 28 chars, invalid char
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
describe("isNanoId", () => {
|
|
72
|
-
it("accepts strings with only 0-9a-zA-Z_-", () => {
|
|
73
|
-
expect(NanoId.isNanoId("V1StGXR8_Z5jdHi6B-myT")).toBe(true);
|
|
74
|
-
expect(NanoId.isNanoId("abc123")).toBe(true);
|
|
75
|
-
expect(NanoId.isNanoId("_-_")).toBe(true);
|
|
76
|
-
});
|
|
77
|
-
it("rejects invalid characters", () => {
|
|
78
|
-
expect(NanoId.isNanoId("")).toBe(false);
|
|
79
|
-
expect(NanoId.isNanoId("space in id")).toBe(false);
|
|
80
|
-
expect(NanoId.isNanoId("dot.id")).toBe(false);
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
describe("isUlid", () => {
|
|
84
|
-
it("accepts valid ULIDs", () => {
|
|
85
|
-
expect(Ulid.isUlid("01ARZ3NDEKTSV4RRFFQ69G5FAV")).toBe(true);
|
|
86
|
-
expect(Ulid.isUlid("0123456789ABCDEFGHJKMNPQR")).toBe(true);
|
|
87
|
-
});
|
|
88
|
-
it("rejects invalid formats", () => {
|
|
89
|
-
expect(Ulid.isUlid("")).toBe(false);
|
|
90
|
-
expect(Ulid.isUlid("01ARZ3NDEKTSV4RRFFQ69G5FA")).toBe(false); // wrong length
|
|
91
|
-
expect(Ulid.isUlid("01ARZ3NDEKTSV4RRFFQ69G5FAV0")).toBe(false); // wrong length
|
|
92
|
-
expect(Ulid.isUlid("01ARZ3NDEKTSV4RRFFQ69G5FAI")).toBe(false); // I not in Crockford base32
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
describe("Ids service", () => {
|
|
97
|
-
it("uuid4 produces valid UUID v4", async () => {
|
|
98
|
-
const id = await run(Ids.uuid4);
|
|
99
|
-
expect(id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
|
|
100
|
-
expect(Uuid4.isUuid4(id)).toBe(true);
|
|
101
|
-
});
|
|
102
|
-
it("uuid5 produces valid UUID v5", async () => {
|
|
103
|
-
const id = await run(Ids.uuid5("hello", Uuid5.Uuid5Namespace.DNS));
|
|
104
|
-
expect(id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
|
|
105
|
-
expect(Uuid5.isUuid5(id)).toBe(true);
|
|
106
|
-
});
|
|
107
|
-
it("uuid5 is deterministic for same name and namespace", async () => {
|
|
108
|
-
const a = await run(Ids.uuid5("test", Uuid5.Uuid5Namespace.URL));
|
|
109
|
-
const b = await run(Ids.uuid5("test", Uuid5.Uuid5Namespace.URL));
|
|
110
|
-
expect(a).toBe(b);
|
|
111
|
-
});
|
|
112
|
-
it("uuid5 differs for different names", async () => {
|
|
113
|
-
const a = await run(Ids.uuid5("a", Uuid5.Uuid5Namespace.DNS));
|
|
114
|
-
const b = await run(Ids.uuid5("b", Uuid5.Uuid5Namespace.DNS));
|
|
115
|
-
expect(a).not.toBe(b);
|
|
116
|
-
});
|
|
117
|
-
it("uuid5 predefined namespaces work", async () => {
|
|
118
|
-
const dns = await run(Ids.uuid5.dns("example.com"));
|
|
119
|
-
const url = await run(Ids.uuid5.url("https://example.com"));
|
|
120
|
-
const oid = await run(Ids.uuid5.oid("1.2.3"));
|
|
121
|
-
const x500 = await run(Ids.uuid5.x500("cn=test"));
|
|
122
|
-
expect(Uuid5.isUuid5(dns)).toBe(true);
|
|
123
|
-
expect(Uuid5.isUuid5(url)).toBe(true);
|
|
124
|
-
expect(Uuid5.isUuid5(oid)).toBe(true);
|
|
125
|
-
expect(Uuid5.isUuid5(x500)).toBe(true);
|
|
126
|
-
expect(new Set([dns, url, oid, x500]).size).toBe(4);
|
|
127
|
-
});
|
|
128
|
-
it("uuid7 produces valid UUID v7", async () => {
|
|
129
|
-
const id = await run(Ids.uuid7);
|
|
130
|
-
expect(id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
|
|
131
|
-
expect(Uuid7.isUuid7(id)).toBe(true);
|
|
132
|
-
});
|
|
133
|
-
it("cuid produces valid CUID", async () => {
|
|
134
|
-
const id = await run(Ids.cuid);
|
|
135
|
-
expect(Cuid.isCuid(id)).toBe(true);
|
|
136
|
-
expect(id).toMatch(/^[a-z][0-9a-z]+$/);
|
|
137
|
-
});
|
|
138
|
-
it("ksuid produces valid KSUID", async () => {
|
|
139
|
-
const id = await run(Ids.ksuid);
|
|
140
|
-
expect(Ksuid.isKsuid(id)).toBe(true);
|
|
141
|
-
expect(id).toHaveLength(27);
|
|
142
|
-
expect(id).toMatch(/^[0-9a-zA-Z]{27}$/);
|
|
143
|
-
});
|
|
144
|
-
it("nanoId produces valid NanoId", async () => {
|
|
145
|
-
const id = await run(Ids.nanoId);
|
|
146
|
-
expect(NanoId.isNanoId(id)).toBe(true);
|
|
147
|
-
expect(id).toMatch(/^[0-9a-zA-Z_-]+$/);
|
|
148
|
-
expect(id).toHaveLength(21);
|
|
149
|
-
});
|
|
150
|
-
it("ulid produces valid ULID", async () => {
|
|
151
|
-
const id = await run(Ids.ulid);
|
|
152
|
-
expect(Ulid.isUlid(id)).toBe(true);
|
|
153
|
-
expect(id).toHaveLength(26);
|
|
154
|
-
expect(id).toMatch(/^[0-9A-HJKMNP-TV-Z]{26}$/);
|
|
155
|
-
});
|
|
156
|
-
it("Ids.Test with fixed time yields deterministic time-based prefixes", async () => {
|
|
157
|
-
const fixedTime = new Date("2025-01-15T12:00:00Z").getTime();
|
|
158
|
-
const runFixed = (effect) => Effect.runPromise(Effect.provide(effect, Ids.Test({ currentTime: fixedTime })));
|
|
159
|
-
const ulid1 = await runFixed(Ids.ulid);
|
|
160
|
-
const ulid2 = await runFixed(Ids.ulid);
|
|
161
|
-
const ksuid1 = await runFixed(Ids.ksuid);
|
|
162
|
-
const ksuid2 = await runFixed(Ids.ksuid);
|
|
163
|
-
expect(ulid1.slice(0, 10)).toBe(ulid2.slice(0, 10));
|
|
164
|
-
expect(ksuid1.slice(0, 5)).toBe(ksuid2.slice(0, 5));
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
describe("Ids.Default", () => {
|
|
168
|
-
it("runs all generators with default layer", async () => {
|
|
169
|
-
const program = Effect.gen(function* () {
|
|
170
|
-
const ids = yield* Ids;
|
|
171
|
-
const u4 = yield* ids.uuid4;
|
|
172
|
-
const u5 = yield* ids.uuid5("default-test", Uuid5.Uuid5Namespace.DNS);
|
|
173
|
-
const u7 = yield* ids.uuid7;
|
|
174
|
-
const c = yield* ids.cuid;
|
|
175
|
-
const k = yield* ids.ksuid;
|
|
176
|
-
const n = yield* ids.nanoId;
|
|
177
|
-
const u = yield* ids.ulid;
|
|
178
|
-
return { u4, u5, u7, c, k, n, u };
|
|
179
|
-
});
|
|
180
|
-
const result = await Effect.runPromise(Effect.provide(program, Ids.Default));
|
|
181
|
-
expect(Uuid4.isUuid4(result.u4)).toBe(true);
|
|
182
|
-
expect(Uuid5.isUuid5(result.u5)).toBe(true);
|
|
183
|
-
expect(Uuid7.isUuid7(result.u7)).toBe(true);
|
|
184
|
-
expect(Cuid.isCuid(result.c)).toBe(true);
|
|
185
|
-
expect(Ksuid.isKsuid(result.k)).toBe(true);
|
|
186
|
-
expect(NanoId.isNanoId(result.n)).toBe(true);
|
|
187
|
-
expect(Ulid.isUlid(result.u)).toBe(true);
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
});
|
package/tsconfig.json
DELETED