@rexezuge/shared 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/dist/Base64.d.ts +52 -0
  3. package/dist/Base64.d.ts.map +1 -0
  4. package/dist/Base64.js +81 -0
  5. package/dist/Base64.js.map +1 -0
  6. package/dist/Clock.d.ts +56 -0
  7. package/dist/Clock.d.ts.map +1 -0
  8. package/dist/Clock.js +59 -0
  9. package/dist/Clock.js.map +1 -0
  10. package/dist/CryptoUtil.d.ts +79 -0
  11. package/dist/CryptoUtil.d.ts.map +1 -0
  12. package/dist/CryptoUtil.js +97 -0
  13. package/dist/CryptoUtil.js.map +1 -0
  14. package/dist/CursorCodec.d.ts +61 -0
  15. package/dist/CursorCodec.d.ts.map +1 -0
  16. package/dist/CursorCodec.js +60 -0
  17. package/dist/CursorCodec.js.map +1 -0
  18. package/dist/EmailUtil.d.ts +29 -0
  19. package/dist/EmailUtil.d.ts.map +1 -0
  20. package/dist/EmailUtil.js +31 -0
  21. package/dist/EmailUtil.js.map +1 -0
  22. package/dist/ErrorSanitizationUtil.d.ts +69 -0
  23. package/dist/ErrorSanitizationUtil.d.ts.map +1 -0
  24. package/dist/ErrorSanitizationUtil.js +98 -0
  25. package/dist/ErrorSanitizationUtil.js.map +1 -0
  26. package/dist/IdGenerator.d.ts +27 -0
  27. package/dist/IdGenerator.d.ts.map +1 -0
  28. package/dist/IdGenerator.js +28 -0
  29. package/dist/IdGenerator.js.map +1 -0
  30. package/dist/Identity.d.ts +36 -0
  31. package/dist/Identity.d.ts.map +1 -0
  32. package/dist/Identity.js +39 -0
  33. package/dist/Identity.js.map +1 -0
  34. package/dist/LanguageTag.d.ts +25 -0
  35. package/dist/LanguageTag.d.ts.map +1 -0
  36. package/dist/LanguageTag.js +29 -0
  37. package/dist/LanguageTag.js.map +1 -0
  38. package/dist/LocaleUtil.d.ts +35 -0
  39. package/dist/LocaleUtil.d.ts.map +1 -0
  40. package/dist/LocaleUtil.js +97 -0
  41. package/dist/LocaleUtil.js.map +1 -0
  42. package/dist/PasswordFingerprint.d.ts +30 -0
  43. package/dist/PasswordFingerprint.d.ts.map +1 -0
  44. package/dist/PasswordFingerprint.js +33 -0
  45. package/dist/PasswordFingerprint.js.map +1 -0
  46. package/dist/RemoteUrlPolicy.d.ts +121 -0
  47. package/dist/RemoteUrlPolicy.d.ts.map +1 -0
  48. package/dist/RemoteUrlPolicy.js +339 -0
  49. package/dist/RemoteUrlPolicy.js.map +1 -0
  50. package/dist/Result.d.ts +32 -0
  51. package/dist/Result.d.ts.map +1 -0
  52. package/dist/Result.js +19 -0
  53. package/dist/Result.js.map +1 -0
  54. package/dist/SubrequestMeter.d.ts +204 -0
  55. package/dist/SubrequestMeter.d.ts.map +1 -0
  56. package/dist/SubrequestMeter.js +169 -0
  57. package/dist/SubrequestMeter.js.map +1 -0
  58. package/dist/TimeZoneUtil.d.ts +47 -0
  59. package/dist/TimeZoneUtil.d.ts.map +1 -0
  60. package/dist/TimeZoneUtil.js +101 -0
  61. package/dist/TimeZoneUtil.js.map +1 -0
  62. package/dist/TimestampUtil.d.ts +53 -0
  63. package/dist/TimestampUtil.d.ts.map +1 -0
  64. package/dist/TimestampUtil.js +69 -0
  65. package/dist/TimestampUtil.js.map +1 -0
  66. package/dist/TokenHashUtil.d.ts +34 -0
  67. package/dist/TokenHashUtil.d.ts.map +1 -0
  68. package/dist/TokenHashUtil.js +37 -0
  69. package/dist/TokenHashUtil.js.map +1 -0
  70. package/dist/UUIDUtil.d.ts +70 -0
  71. package/dist/UUIDUtil.d.ts.map +1 -0
  72. package/dist/UUIDUtil.js +79 -0
  73. package/dist/UUIDUtil.js.map +1 -0
  74. package/dist/index.d.ts +38 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +42 -0
  77. package/dist/index.js.map +1 -0
  78. package/package.json +34 -3
  79. package/README.md +0 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rexezuge
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Base64 codec for byte payloads.
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from `packages/shared/src/utils/Base64.ts` (Durable-DAV), the
7
+ * documented best form. Four implementations once existed — Durable-DAV's own,
8
+ * `DavReadCache`, and `aes-gcm` running the `String.fromCodePoint(...subarray)`
9
+ * + `btoa` form this file was written to replace. ChordDHT-Tracker and
10
+ * Mail-Otter carry no byte codec of their own; their `CryptoUtil`s use the
11
+ * `btoa`+transform form. This file is the canonical one for **standard**
12
+ * base64. The **base64url** alphabet is a different job and lives in
13
+ * `CryptoUtil` — that duplication is deliberate (different alphabet).
14
+ *
15
+ * ## Why not `String.fromCodePoint` + `btoa`
16
+ *
17
+ * The obvious encoder builds a binary string and `btoa`s it:
18
+ *
19
+ * ```ts
20
+ * let binary = '';
21
+ * for (let i = 0; i < bytes.length; i += 8192) {
22
+ * binary += String.fromCodePoint(...bytes.subarray(i, i + 8192));
23
+ * }
24
+ * return btoa(binary);
25
+ * ```
26
+ *
27
+ * That allocates roughly 2× the input as UTF-16 — up to 100 MB of garbage for a
28
+ * 50 MB payload, on top of the buffer and the result — and the variadic spread
29
+ * approaches the engine's argument limit. A direct 3-byte-to-4-char table is
30
+ * allocation-light and has no argument limit. `base64ToBytes` keeps the `atob`
31
+ * form: decoding allocates one binary string and one buffer, which is the
32
+ * output's own size rather than double it, and `atob` does the validation for
33
+ * free.
34
+ */
35
+ /**
36
+ * Encode `bytes` as standard base64 (with `=` padding).
37
+ *
38
+ * Not base64url: pre-binary KV file entries stored these as opaque values and
39
+ * `aes-gcm` stores them where `atob` reads them back. `CryptoUtil` has the
40
+ * URL-safe variant for the cases that need one.
41
+ */
42
+ declare function bytesToBase64(bytes: Uint8Array): string;
43
+ /**
44
+ * Decode standard base64.
45
+ *
46
+ * `atob` throws on malformed input rather than producing partial bytes, which is
47
+ * the right behaviour for every caller here: a corrupt cache entry or a mistyped
48
+ * key should fail loudly, not decrypt to noise.
49
+ */
50
+ declare function base64ToBytes(b64: string): Uint8Array;
51
+ export { bytesToBase64, base64ToBytes };
52
+ //# sourceMappingURL=Base64.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Base64.d.ts","sourceRoot":"","sources":["../src/Base64.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAIH;;;;;;GAMG;AACH,iBAAS,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAqBhD;AAED;;;;;;GAMG;AACH,iBAAS,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAK9C;AAED,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC"}
package/dist/Base64.js ADDED
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Base64 codec for byte payloads.
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from `packages/shared/src/utils/Base64.ts` (Durable-DAV), the
7
+ * documented best form. Four implementations once existed — Durable-DAV's own,
8
+ * `DavReadCache`, and `aes-gcm` running the `String.fromCodePoint(...subarray)`
9
+ * + `btoa` form this file was written to replace. ChordDHT-Tracker and
10
+ * Mail-Otter carry no byte codec of their own; their `CryptoUtil`s use the
11
+ * `btoa`+transform form. This file is the canonical one for **standard**
12
+ * base64. The **base64url** alphabet is a different job and lives in
13
+ * `CryptoUtil` — that duplication is deliberate (different alphabet).
14
+ *
15
+ * ## Why not `String.fromCodePoint` + `btoa`
16
+ *
17
+ * The obvious encoder builds a binary string and `btoa`s it:
18
+ *
19
+ * ```ts
20
+ * let binary = '';
21
+ * for (let i = 0; i < bytes.length; i += 8192) {
22
+ * binary += String.fromCodePoint(...bytes.subarray(i, i + 8192));
23
+ * }
24
+ * return btoa(binary);
25
+ * ```
26
+ *
27
+ * That allocates roughly 2× the input as UTF-16 — up to 100 MB of garbage for a
28
+ * 50 MB payload, on top of the buffer and the result — and the variadic spread
29
+ * approaches the engine's argument limit. A direct 3-byte-to-4-char table is
30
+ * allocation-light and has no argument limit. `base64ToBytes` keeps the `atob`
31
+ * form: decoding allocates one binary string and one buffer, which is the
32
+ * output's own size rather than double it, and `atob` does the validation for
33
+ * free.
34
+ */
35
+ const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
36
+ /**
37
+ * Encode `bytes` as standard base64 (with `=` padding).
38
+ *
39
+ * Not base64url: pre-binary KV file entries stored these as opaque values and
40
+ * `aes-gcm` stores them where `atob` reads them back. `CryptoUtil` has the
41
+ * URL-safe variant for the cases that need one.
42
+ */
43
+ function bytesToBase64(bytes) {
44
+ let out = '';
45
+ const len = bytes.length;
46
+ const remainder = len % 3;
47
+ const limit = len - remainder;
48
+ for (let i = 0; i < limit; i += 3) {
49
+ const triple = bytes[i] * 65_536 + bytes[i + 1] * 256 + bytes[i + 2];
50
+ out +=
51
+ BASE64_ALPHABET[(triple >> 18) & 63] +
52
+ BASE64_ALPHABET[(triple >> 12) & 63] +
53
+ BASE64_ALPHABET[(triple >> 6) & 63] +
54
+ BASE64_ALPHABET[triple & 63];
55
+ }
56
+ if (remainder === 1) {
57
+ const value = bytes[limit];
58
+ out += `${BASE64_ALPHABET[value >> 2]}${BASE64_ALPHABET[(value << 4) & 63]}==`;
59
+ }
60
+ else if (remainder === 2) {
61
+ const pair = (bytes[limit] << 8) | bytes[limit + 1];
62
+ out += `${BASE64_ALPHABET[pair >> 10]}${BASE64_ALPHABET[(pair >> 4) & 63]}${BASE64_ALPHABET[(pair << 2) & 63]}=`;
63
+ }
64
+ return out;
65
+ }
66
+ /**
67
+ * Decode standard base64.
68
+ *
69
+ * `atob` throws on malformed input rather than producing partial bytes, which is
70
+ * the right behaviour for every caller here: a corrupt cache entry or a mistyped
71
+ * key should fail loudly, not decrypt to noise.
72
+ */
73
+ function base64ToBytes(b64) {
74
+ const binary = atob(b64);
75
+ const out = new Uint8Array(binary.length);
76
+ for (let i = 0; i < binary.length; i += 1)
77
+ out[i] = (binary.codePointAt(i) ?? 0) & 0xff;
78
+ return out;
79
+ }
80
+ export { bytesToBase64, base64ToBytes };
81
+ //# sourceMappingURL=Base64.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Base64.js","sourceRoot":"","sources":["../src/Base64.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,MAAM,eAAe,GAAG,kEAAkE,CAAC;AAE3F;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,KAAiB;IACtC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;IACzB,MAAM,SAAS,GAAG,GAAG,GAAG,CAAC,CAAC;IAC1B,MAAM,KAAK,GAAG,GAAG,GAAG,SAAS,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACrE,GAAG;YACD,eAAe,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;gBACpC,eAAe,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;gBACpC,eAAe,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;gBACnC,eAAe,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC3B,GAAG,IAAI,GAAG,eAAe,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;IACjF,CAAC;SAAM,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACpD,GAAG,IAAI,GAAG,eAAe,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;IACnH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,GAAW;IAChC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;IACxF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Inject-able time source.
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from AWS-AccessBridge's `Clock.ts`, Mail-Otter's `Clock.ts` and
7
+ * ChordDHT-Tracker's `Clock.ts`. The three differ in surface, not concept: AWS
8
+ * names the seam `Clock` with `now(): number` and a shared `SYSTEM_CLOCK`;
9
+ * Mail-Otter/ChordDHT name it `IClock` with `nowMs()` and a mutable
10
+ * `FixedClock` carrying `setNowMs`/`advanceByMs`.
11
+ *
12
+ * ## Design decision
13
+ *
14
+ * The kit drops the `I` prefix on the interface (no `any`, no Hungarian drift;
15
+ * the consumer repos' own "no `I` on interfaces" cleanups point the same way),
16
+ * keeps AWS's single-method `now()` as the primary read, and keeps Mail-Otter's
17
+ * mutable `FixedClock` helpers — they cost nothing and are exactly what a test
18
+ * wants. `TimestampUtil`'s current-time reads go through `SYSTEM_CLOCK` by
19
+ * default; pass a `FixedClock` to pin them.
20
+ */
21
+ interface Clock {
22
+ /**
23
+ * Milliseconds since the Unix epoch.
24
+ */
25
+ now(): number;
26
+ }
27
+ /**
28
+ * The production clock. A single shared instance — it holds no state, so there
29
+ * is nothing to gain from more than one, and a default parameter needs a value.
30
+ */
31
+ declare class SystemClock implements Clock {
32
+ now(): number;
33
+ }
34
+ /**
35
+ * A clock seeded at `initialNowMs` and moved forward with `setNowMs`/`advanceByMs`.
36
+ *
37
+ * Two shapes were merged: AWS's `FixedClock` was immutable (constructed with the
38
+ * instant under test), Mail-Otter's was mutable. The mutable form is a superset
39
+ * and is what the time-dependent tests in every repo actually reach for, so a
40
+ * test either pins the instant up front or advances it as work happens.
41
+ */
42
+ declare class FixedClock implements Clock {
43
+ private currentMs;
44
+ constructor(initialNowMs?: number);
45
+ now(): number;
46
+ setNowMs(valueMs: number): void;
47
+ advanceByMs(deltaMs: number): void;
48
+ }
49
+ /**
50
+ * The shared production instance, for the common case where a caller wants "now"
51
+ * without choosing a clock. Stateless, so one instance is enough.
52
+ */
53
+ declare const SYSTEM_CLOCK: Clock;
54
+ export type { Clock };
55
+ export { SystemClock, FixedClock, SYSTEM_CLOCK };
56
+ //# sourceMappingURL=Clock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Clock.d.ts","sourceRoot":"","sources":["../src/Clock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,UAAU,KAAK;IACb;;OAEG;IACH,GAAG,IAAI,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,cAAM,WAAY,YAAW,KAAK;IAChC,GAAG,IAAI,MAAM;CAGd;AAED;;;;;;;GAOG;AACH,cAAM,UAAW,YAAW,KAAK;IAC/B,OAAO,CAAC,SAAS,CAAS;gBAEd,YAAY,SAAI;IAI5B,GAAG,IAAI,MAAM;IAIb,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI/B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAGnC;AAED;;;GAGG;AACH,QAAA,MAAM,YAAY,EAAE,KAAyB,CAAC;AAE9C,YAAY,EAAE,KAAK,EAAE,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC"}
package/dist/Clock.js ADDED
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Inject-able time source.
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from AWS-AccessBridge's `Clock.ts`, Mail-Otter's `Clock.ts` and
7
+ * ChordDHT-Tracker's `Clock.ts`. The three differ in surface, not concept: AWS
8
+ * names the seam `Clock` with `now(): number` and a shared `SYSTEM_CLOCK`;
9
+ * Mail-Otter/ChordDHT name it `IClock` with `nowMs()` and a mutable
10
+ * `FixedClock` carrying `setNowMs`/`advanceByMs`.
11
+ *
12
+ * ## Design decision
13
+ *
14
+ * The kit drops the `I` prefix on the interface (no `any`, no Hungarian drift;
15
+ * the consumer repos' own "no `I` on interfaces" cleanups point the same way),
16
+ * keeps AWS's single-method `now()` as the primary read, and keeps Mail-Otter's
17
+ * mutable `FixedClock` helpers — they cost nothing and are exactly what a test
18
+ * wants. `TimestampUtil`'s current-time reads go through `SYSTEM_CLOCK` by
19
+ * default; pass a `FixedClock` to pin them.
20
+ */
21
+ /**
22
+ * The production clock. A single shared instance — it holds no state, so there
23
+ * is nothing to gain from more than one, and a default parameter needs a value.
24
+ */
25
+ class SystemClock {
26
+ now() {
27
+ return Date.now();
28
+ }
29
+ }
30
+ /**
31
+ * A clock seeded at `initialNowMs` and moved forward with `setNowMs`/`advanceByMs`.
32
+ *
33
+ * Two shapes were merged: AWS's `FixedClock` was immutable (constructed with the
34
+ * instant under test), Mail-Otter's was mutable. The mutable form is a superset
35
+ * and is what the time-dependent tests in every repo actually reach for, so a
36
+ * test either pins the instant up front or advances it as work happens.
37
+ */
38
+ class FixedClock {
39
+ currentMs;
40
+ constructor(initialNowMs = 0) {
41
+ this.currentMs = initialNowMs;
42
+ }
43
+ now() {
44
+ return this.currentMs;
45
+ }
46
+ setNowMs(valueMs) {
47
+ this.currentMs = valueMs;
48
+ }
49
+ advanceByMs(deltaMs) {
50
+ this.currentMs += deltaMs;
51
+ }
52
+ }
53
+ /**
54
+ * The shared production instance, for the common case where a caller wants "now"
55
+ * without choosing a clock. Stateless, so one instance is enough.
56
+ */
57
+ const SYSTEM_CLOCK = new SystemClock();
58
+ export { SystemClock, FixedClock, SYSTEM_CLOCK };
59
+ //# sourceMappingURL=Clock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Clock.js","sourceRoot":"","sources":["../src/Clock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AASH;;;GAGG;AACH,MAAM,WAAW;IACf,GAAG;QACD,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC;IACpB,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,UAAU;IACN,SAAS,CAAS;IAE1B,YAAY,YAAY,GAAG,CAAC;QAC1B,IAAI,CAAC,SAAS,GAAG,YAAY,CAAC;IAChC,CAAC;IAED,GAAG;QACD,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,QAAQ,CAAC,OAAe;QACtB,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC;IAC3B,CAAC;IAED,WAAW,CAAC,OAAe;QACzB,IAAI,CAAC,SAAS,IAAI,OAAO,CAAC;IAC5B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,YAAY,GAAU,IAAI,WAAW,EAAE,CAAC;AAG9C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Hashing and key generation.
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from `CryptoUtil.ts` in Durable-DAV, Edge-Git, Mail-Meow,
7
+ * Mail-Otter, ChordDHT-Tracker and CalDAV-Bridge. Every copy carries
8
+ * `sha256Hex` and `randomBase64Url`; Edge-Git/Mail-Meow/Mail-Otter/ChordDHT add
9
+ * `hmacSha256Hex`; Mail-Meow adds the string overload `base64UrlEncode`;
10
+ * Durable-DAV uniquely factors the digest over raw bytes (`sha256HexOfBytes`) and
11
+ * rewrites base64url on the shared codec.
12
+ *
13
+ * ## Design decisions
14
+ *
15
+ * - The base64url alphabet is a **different alphabet for a different job** from
16
+ * `Base64.ts`, so the URL-safe transform stays here — but it delegates to the
17
+ * documented best encoder rather than re-spreading bytes (`String.fromCodePoint`
18
+ * + `btoa`), which was four copies of the ~2×-UTF-16 form `Base64.ts` replaced.
19
+ * - `sha256Hex` is defined over `sha256HexOfBytes` (Durable-DAV's shape): the
20
+ * digest then covers exactly the bytes presented, which matters when two sides
21
+ * compare a digest — an intermediate encoding is a place for them to disagree.
22
+ * - `hmacSha256Hex` is kept from the four repos that carry it.
23
+ *
24
+ * ## Left local
25
+ *
26
+ * ChordDHT-Tracker's `sha1Hex` is deliberately **not** here. SHA-1 is the Chord
27
+ * ring identifier hash (protocol compatibility), not a general security digest;
28
+ * surfacing it in the shared surface would invite exactly the misuse the
29
+ * `sonarjs/hashing` lint it carries a disable for is there to catch. A repo that
30
+ * needs a protocol-mandated SHA-1 computes it on a `BufferSource` itself.
31
+ */
32
+ declare class CryptoUtil {
33
+ /**
34
+ * SHA-256 of a string, hex-encoded.
35
+ *
36
+ * Encoded as UTF-8 first. For bytes you already hold, prefer `sha256HexOfBytes`
37
+ * — this overload is the reason a byte payload used to be laundered through
38
+ * `String.fromCodePoint` into a binary string and back, allocating roughly 2×
39
+ * the input as UTF-16 on the way.
40
+ */
41
+ static sha256Hex(value: string): Promise<string>;
42
+ /**
43
+ * SHA-256 of raw bytes, hex-encoded.
44
+ *
45
+ * The hash covers exactly these bytes. This matters where the digest is
46
+ * compared between two sides: any intermediate encoding is a place for the two
47
+ * to disagree for a reason that has nothing to do with the content.
48
+ */
49
+ static sha256HexOfBytes(bytes: Uint8Array): Promise<string>;
50
+ /**
51
+ * HMAC-SHA256 of `value` under `secret`, hex-encoded.
52
+ *
53
+ * A keyed MAC for a message a caller will recompute on the other side. The key
54
+ * is imported as non-extractable; a comparison against a re-derived MAC must be
55
+ * timing-safe on the caller's side — this helper returns the hex string, it does
56
+ * not compare.
57
+ */
58
+ static hmacSha256Hex(value: string, secret: string): Promise<string>;
59
+ private static toHex;
60
+ /**
61
+ * URL-safe base64 of `bytes` (no `+`, `/` or `=`).
62
+ *
63
+ * Delegates to the shared codec rather than rebuilding the binary string here:
64
+ * the URL-safe transform is applied to the standard alphabet because
65
+ * `Uint8Array#toBase64` is not guaranteed across Workers runtimes.
66
+ */
67
+ static toBase64Url(bytes: Uint8Array): string;
68
+ /**
69
+ * URL-safe base64 of a UTF-8 string.
70
+ *
71
+ * The same transform as {@link toBase64Url}, for callers holding text rather
72
+ * than bytes. This and `toBase64Url` used to be separate implementations in
73
+ * different packages; they are the same encoding and must not drift.
74
+ */
75
+ static base64UrlEncode(value: string): string;
76
+ static randomBase64Url(byteLength: number): string;
77
+ }
78
+ export { CryptoUtil };
79
+ //# sourceMappingURL=CryptoUtil.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CryptoUtil.d.ts","sourceRoot":"","sources":["../src/CryptoUtil.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,cAAM,UAAU;IACd;;;;;;;OAOG;WACiB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI7D;;;;;;OAMG;WACiB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IAKxE;;;;;;;OAOG;WACiB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAYjF,OAAO,CAAC,MAAM,CAAC,KAAK;IAIpB;;;;;;OAMG;WACW,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM;IAIpD;;;;;;OAMG;WACW,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;WAItC,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;CAG1D;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -0,0 +1,97 @@
1
+ import { bytesToBase64 } from './Base64';
2
+ /**
3
+ * Hashing and key generation.
4
+ *
5
+ * ## Provenance
6
+ *
7
+ * Converged from `CryptoUtil.ts` in Durable-DAV, Edge-Git, Mail-Meow,
8
+ * Mail-Otter, ChordDHT-Tracker and CalDAV-Bridge. Every copy carries
9
+ * `sha256Hex` and `randomBase64Url`; Edge-Git/Mail-Meow/Mail-Otter/ChordDHT add
10
+ * `hmacSha256Hex`; Mail-Meow adds the string overload `base64UrlEncode`;
11
+ * Durable-DAV uniquely factors the digest over raw bytes (`sha256HexOfBytes`) and
12
+ * rewrites base64url on the shared codec.
13
+ *
14
+ * ## Design decisions
15
+ *
16
+ * - The base64url alphabet is a **different alphabet for a different job** from
17
+ * `Base64.ts`, so the URL-safe transform stays here — but it delegates to the
18
+ * documented best encoder rather than re-spreading bytes (`String.fromCodePoint`
19
+ * + `btoa`), which was four copies of the ~2×-UTF-16 form `Base64.ts` replaced.
20
+ * - `sha256Hex` is defined over `sha256HexOfBytes` (Durable-DAV's shape): the
21
+ * digest then covers exactly the bytes presented, which matters when two sides
22
+ * compare a digest — an intermediate encoding is a place for them to disagree.
23
+ * - `hmacSha256Hex` is kept from the four repos that carry it.
24
+ *
25
+ * ## Left local
26
+ *
27
+ * ChordDHT-Tracker's `sha1Hex` is deliberately **not** here. SHA-1 is the Chord
28
+ * ring identifier hash (protocol compatibility), not a general security digest;
29
+ * surfacing it in the shared surface would invite exactly the misuse the
30
+ * `sonarjs/hashing` lint it carries a disable for is there to catch. A repo that
31
+ * needs a protocol-mandated SHA-1 computes it on a `BufferSource` itself.
32
+ */
33
+ class CryptoUtil {
34
+ /**
35
+ * SHA-256 of a string, hex-encoded.
36
+ *
37
+ * Encoded as UTF-8 first. For bytes you already hold, prefer `sha256HexOfBytes`
38
+ * — this overload is the reason a byte payload used to be laundered through
39
+ * `String.fromCodePoint` into a binary string and back, allocating roughly 2×
40
+ * the input as UTF-16 on the way.
41
+ */
42
+ static async sha256Hex(value) {
43
+ return this.sha256HexOfBytes(new TextEncoder().encode(value));
44
+ }
45
+ /**
46
+ * SHA-256 of raw bytes, hex-encoded.
47
+ *
48
+ * The hash covers exactly these bytes. This matters where the digest is
49
+ * compared between two sides: any intermediate encoding is a place for the two
50
+ * to disagree for a reason that has nothing to do with the content.
51
+ */
52
+ static async sha256HexOfBytes(bytes) {
53
+ const digest = await crypto.subtle.digest('SHA-256', bytes);
54
+ return this.toHex(new Uint8Array(digest));
55
+ }
56
+ /**
57
+ * HMAC-SHA256 of `value` under `secret`, hex-encoded.
58
+ *
59
+ * A keyed MAC for a message a caller will recompute on the other side. The key
60
+ * is imported as non-extractable; a comparison against a re-derived MAC must be
61
+ * timing-safe on the caller's side — this helper returns the hex string, it does
62
+ * not compare.
63
+ */
64
+ static async hmacSha256Hex(value, secret) {
65
+ const key = await crypto.subtle.importKey('raw', new TextEncoder().encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
66
+ const signature = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(value));
67
+ return this.toHex(new Uint8Array(signature));
68
+ }
69
+ static toHex(bytes) {
70
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');
71
+ }
72
+ /**
73
+ * URL-safe base64 of `bytes` (no `+`, `/` or `=`).
74
+ *
75
+ * Delegates to the shared codec rather than rebuilding the binary string here:
76
+ * the URL-safe transform is applied to the standard alphabet because
77
+ * `Uint8Array#toBase64` is not guaranteed across Workers runtimes.
78
+ */
79
+ static toBase64Url(bytes) {
80
+ return bytesToBase64(bytes).replaceAll('+', '-').replaceAll('/', '_').replace(/={0,2}$/, '');
81
+ }
82
+ /**
83
+ * URL-safe base64 of a UTF-8 string.
84
+ *
85
+ * The same transform as {@link toBase64Url}, for callers holding text rather
86
+ * than bytes. This and `toBase64Url` used to be separate implementations in
87
+ * different packages; they are the same encoding and must not drift.
88
+ */
89
+ static base64UrlEncode(value) {
90
+ return this.toBase64Url(new TextEncoder().encode(value));
91
+ }
92
+ static randomBase64Url(byteLength) {
93
+ return this.toBase64Url(crypto.getRandomValues(new Uint8Array(byteLength)));
94
+ }
95
+ }
96
+ export { CryptoUtil };
97
+ //# sourceMappingURL=CryptoUtil.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CryptoUtil.js","sourceRoot":"","sources":["../src/CryptoUtil.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU;IACd;;;;;;;OAOG;IACI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAa;QACzC,OAAO,IAAI,CAAC,gBAAgB,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAChE,CAAC;IAED;;;;;;OAMG;IACI,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,KAAiB;QACpD,MAAM,MAAM,GAAgB,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,KAAqB,CAAC,CAAC;QACzF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED;;;;;;;OAOG;IACI,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,KAAa,EAAE,MAAc;QAC7D,MAAM,GAAG,GAAc,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAClD,KAAK,EACL,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAChC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EACjC,KAAK,EACL,CAAC,MAAM,CAAC,CACT,CAAC;QACF,MAAM,SAAS,GAAgB,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtG,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;IAC/C,CAAC;IAEO,MAAM,CAAC,KAAK,CAAC,KAAiB;QACpC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClG,CAAC;IAED;;;;;;OAMG;IACI,MAAM,CAAC,WAAW,CAAC,KAAiB;QACzC,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED;;;;;;OAMG;IACI,MAAM,CAAC,eAAe,CAAC,KAAa;QACzC,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC3D,CAAC;IAEM,MAAM,CAAC,eAAe,CAAC,UAAkB;QAC9C,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC9E,CAAC;CACF;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Canonical opaque-cursor codec, plus the `Page<T>` shape it produces.
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from ChordDHT-Tracker's `utils/Cursor.ts` (a `Cursor` class + a
7
+ * `Page<T>` type), Edge-Git's `backend-data/.../CursorUtil.ts` (a `CursorUtil`
8
+ * class that adds `decodeOrThrow` + `isValidCursor`) and Mail-Otter's
9
+ * `CursorUtil.ts` (the minimal `encode`/`decode` pair). All three hand-rolled
10
+ * DAO pagination cursors and all three converged on `btoa(JSON.stringify(...))`
11
+ * / `JSON.parse(atob(...))`. Canonical name is **`CursorCodec`**; the cursor is an
12
+ * opaque token, so callers pass it through and never inspect it.
13
+ *
14
+ * ## Design decisions
15
+ *
16
+ * - The cursor is `btoa`/`atob`, which works in workerd *and* Node 24 (both
17
+ * expose browser globals now). No `Buffer` is used, so the same bundle runs in
18
+ * both.
19
+ * - `decode` never throws: a malformed or tampered cursor is `undefined`, which a
20
+ * DAO reads as "no cursor, start from the beginning" rather than an error an
21
+ * attacker can provoke. `decodeOrThrow` and `isValidCursor` are kept from
22
+ * Edge-Git for the call sites that *want* the strict behaviour.
23
+ * - **Layer 0 stays dependency-free.** Edge-Git's `decodeOrThrow` threw its
24
+ * `@edge-git/backend-errors` `BadRequestError`; the shared package imports
25
+ * nothing, so it throws a plain `Error` and leaves the HTTP mapping to the
26
+ * layer that owns the error taxonomy (the same "throw plain `Error`, map above"
27
+ * rule `Identity`/`EmailUtil` follow).
28
+ */
29
+ interface Page<T> {
30
+ readonly items: readonly T[];
31
+ readonly nextCursor?: string;
32
+ }
33
+ declare class CursorCodec {
34
+ static encode(value: unknown): string;
35
+ /**
36
+ * Decode a cursor, or `undefined` for a missing/malformed one.
37
+ *
38
+ * `atob`/`JSON.parse` throw on bad input; the `try` turns that into `undefined`
39
+ * so a corrupt cursor degrades to a first page instead of an uncaught throw.
40
+ */
41
+ static decode<T>(cursor: string | undefined | null): T | undefined;
42
+ /**
43
+ * Decode a cursor, throwing a plain `Error` on malformed input.
44
+ *
45
+ * For a call site that treats a bad cursor as a client error; the HTTP mapping
46
+ * to `BadRequest` is the caller's layer's job (see the file header).
47
+ */
48
+ static decodeOrThrow<T>(cursor: string | undefined | null): T | undefined;
49
+ /**
50
+ * Whether a cursor is well-formed. A missing cursor is valid (first page).
51
+ */
52
+ static isValidCursor(cursor: string | undefined | null): boolean;
53
+ /**
54
+ * Build a `Page`, omitting `nextCursor` entirely on the last page rather than
55
+ * carrying an explicit `undefined`.
56
+ */
57
+ static page<T>(items: readonly T[], nextCursor?: string): Page<T>;
58
+ }
59
+ export { CursorCodec };
60
+ export type { Page };
61
+ //# sourceMappingURL=CursorCodec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CursorCodec.d.ts","sourceRoot":"","sources":["../src/CursorCodec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,UAAU,IAAI,CAAC,CAAC;IACd,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,cAAM,WAAW;WACD,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;IAI5C;;;;;OAKG;WACW,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,SAAS;IASzE;;;;;OAKG;WACW,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,SAAS;IAShF;;OAEG;WACW,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO;IAUvE;;;OAGG;WACW,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;CAGzE;AAED,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,YAAY,EAAE,IAAI,EAAE,CAAC"}
@@ -0,0 +1,60 @@
1
+ class CursorCodec {
2
+ static encode(value) {
3
+ return btoa(JSON.stringify(value));
4
+ }
5
+ /**
6
+ * Decode a cursor, or `undefined` for a missing/malformed one.
7
+ *
8
+ * `atob`/`JSON.parse` throw on bad input; the `try` turns that into `undefined`
9
+ * so a corrupt cursor degrades to a first page instead of an uncaught throw.
10
+ */
11
+ static decode(cursor) {
12
+ if (!cursor)
13
+ return undefined;
14
+ try {
15
+ return JSON.parse(atob(cursor));
16
+ }
17
+ catch {
18
+ return undefined;
19
+ }
20
+ }
21
+ /**
22
+ * Decode a cursor, throwing a plain `Error` on malformed input.
23
+ *
24
+ * For a call site that treats a bad cursor as a client error; the HTTP mapping
25
+ * to `BadRequest` is the caller's layer's job (see the file header).
26
+ */
27
+ static decodeOrThrow(cursor) {
28
+ if (!cursor)
29
+ return undefined;
30
+ try {
31
+ return JSON.parse(atob(cursor));
32
+ }
33
+ catch {
34
+ throw new Error('Invalid cursor');
35
+ }
36
+ }
37
+ /**
38
+ * Whether a cursor is well-formed. A missing cursor is valid (first page).
39
+ */
40
+ static isValidCursor(cursor) {
41
+ if (!cursor)
42
+ return true;
43
+ try {
44
+ JSON.parse(atob(cursor));
45
+ return true;
46
+ }
47
+ catch {
48
+ return false;
49
+ }
50
+ }
51
+ /**
52
+ * Build a `Page`, omitting `nextCursor` entirely on the last page rather than
53
+ * carrying an explicit `undefined`.
54
+ */
55
+ static page(items, nextCursor) {
56
+ return nextCursor ? { items, nextCursor } : { items };
57
+ }
58
+ }
59
+ export { CursorCodec };
60
+ //# sourceMappingURL=CursorCodec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CursorCodec.js","sourceRoot":"","sources":["../src/CursorCodec.ts"],"names":[],"mappings":"AAiCA,MAAM,WAAW;IACR,MAAM,CAAC,MAAM,CAAC,KAAc;QACjC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACrC,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,MAAM,CAAI,MAAiC;QACvD,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAC9B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAM,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,aAAa,CAAI,MAAiC;QAC9D,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAC9B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAM,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,aAAa,CAAC,MAAiC;QAC3D,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,IAAI,CAAI,KAAmB,EAAE,UAAmB;QAC5D,OAAO,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;IACxD,CAAC;CACF;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { isValidEmailFormat, MAX_EMAIL_LENGTH } from './Identity';
2
+ /**
3
+ * Email address value helpers.
4
+ *
5
+ * ## Provenance
6
+ *
7
+ * Converged from Durable-DAV's `EmailUtil.ts` (a shape check) and Mail-Meow's
8
+ * `EmailUtil.ts` (address normalization). Durable-DAV's predicate `isValidEmailFormat`
9
+ * canonically lives in `Identity.ts` — the wider group's home, and the stricter
10
+ * of the two regexes found (see the merge note there) — and is re-exported here
11
+ * so `EmailUtil` is the one-stop surface for validation + normalization.
12
+ *
13
+ * `normalizeEmail` comes from Mail-Meow, whose header records why a single
14
+ * normalization rule is a correctness concern, not a cosmetic one: "This function
15
+ * used to exist four times, and the copies disagreed." One copy trimmed and
16
+ * lowercased, the others lowercased only, so `" Alice@Example.com "` and
17
+ * `"alice@example.com"` were the same account to one layer and different accounts
18
+ * to another — a different account key on each side of a boundary, and a stored
19
+ * registry row that its own service could not resolve.
20
+ *
21
+ * ## Design decision
22
+ *
23
+ * The kit keeps `normalizeEmail` and re-exports the validator; it does not
24
+ * re-introduce Edge-Git's `EmailAddress` value class, which is sugar over the
25
+ * same trim+lowercase and would be a second spelling of the same rule.
26
+ */
27
+ declare function normalizeEmail(email: string): string;
28
+ export { normalizeEmail, isValidEmailFormat, MAX_EMAIL_LENGTH };
29
+ //# sourceMappingURL=EmailUtil.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmailUtil.d.ts","sourceRoot":"","sources":["../src/EmailUtil.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,iBAAS,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,CAAC"}