@rexezuge/shared 0.0.0-stage → 1.0.1

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
@@ -0,0 +1,31 @@
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
+ function normalizeEmail(email) {
28
+ return email.trim().toLowerCase();
29
+ }
30
+ export { normalizeEmail, isValidEmailFormat, MAX_EMAIL_LENGTH };
31
+ //# sourceMappingURL=EmailUtil.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmailUtil.js","sourceRoot":"","sources":["../src/EmailUtil.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACpC,CAAC;AAED,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Secret-safe error/log sanitization (Layer 0).
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from `ErrorSanitizationUtil.ts` in Durable-DAV, Durable-DAV-Router,
7
+ * Edge-Git, Edge-Sonic, Mail-Meow and Mail-Otter. All six redact the same secret
8
+ * shapes (Bearer/Basic headers, token and secret key=value pairs, query-string
9
+ * tokens, JWTs, Google OAuth tokens) and differ only in which extras they add:
10
+ *
11
+ * - Durable-DAV, Edge-Git, Durable-DAV-Router and Edge-Sonic also redact a
12
+ * repo-specific personal-access-token scheme (`<repo>-pat:<token>`), sanitize
13
+ * the **stack** as well as the message, and expose `stackForLog`.
14
+ * - Mail-Meow and Mail-Otter omit all three and return `name: <redacted message>`
15
+ * without a stack.
16
+ *
17
+ * ## Design decisions
18
+ *
19
+ * - **Stack sanitization is kept.** A stack trace repeats the error message and
20
+ * can name the very secret the message carries, so redacting the message but
21
+ * logging the raw stack — which Mail-Meow/Mail-Otter effectively do — is a
22
+ * one-line leak. This is the stricter of the two shapes, so it is the one kept.
23
+ * `stackForLog` stays for the structured-log payload path.
24
+ * - **The PAT scheme is generalized, not dropped and not repo-hardcoded.** Four
25
+ * repos each added their own `durable-dav-pat:` / `edge-git-pat:` /
26
+ * `durable-dav-router-pat:` / `edge-sonic-pat:` literal. Hard-coding those
27
+ * prefixes here would leak five repo identities into a shared package; dropping
28
+ * the class would undo a safeguard four of six repos independently judged
29
+ * necessary. The converged form is one generic `<word>-pat:<token>` pattern
30
+ * that covers every repo's scheme without naming any.
31
+ * - **Two correctness lessons from Mail-Otter's header are preserved in code and
32
+ * comment.** `\bbearer`/`\bbasic` keep the leading word boundary — without it
33
+ * the pattern parsed as "word boundary, then the literal `earer`", matched
34
+ * nothing, and Authorization headers leaked verbatim while the suite stayed
35
+ * green only because a Google token in the sample was caught elsewhere. And the
36
+ * `SECRET_KV` set takes Mail-Meow's superset (`client_id`, bare `code`) over the
37
+ * narrower alternatives.
38
+ */
39
+ declare class ErrorSanitizationUtil {
40
+ /**
41
+ * Redact every recognizable secret shape from a single string.
42
+ *
43
+ * Replacements are inline string literals (not variables or templates) so a
44
+ * `unicorn/no-unsafe-string-replacement`-style rule is satisfied and so CodeQL
45
+ * models each `.replaceAll(regex, literal)` as a `js/clear-text-logging` masking
46
+ * barrier. Order matters only in that the PAT scheme runs first; the rest are
47
+ * disjoint.
48
+ */
49
+ static sanitizeMessage(message: string): string;
50
+ /**
51
+ * A redacted `name: message` (and stack) for a plain log line.
52
+ *
53
+ * Both the message and the stack are sanitized — see the header for why the
54
+ * stack must be.
55
+ */
56
+ static sanitizeErrorForLogging(error: unknown): string;
57
+ /**
58
+ * A redacted error, for a structured log payload.
59
+ *
60
+ * `error instanceof Error ? (error.stack ?? error.message) : error` was written
61
+ * out at many call sites, and every one of them bypassed the redaction above —
62
+ * so an error whose message carried a credential would be logged in the clear. A
63
+ * logging helper that only redacts when the caller remembers to call it is not a
64
+ * redaction boundary; this is the single point every payload goes through.
65
+ */
66
+ static stackForLog(error: unknown): unknown;
67
+ }
68
+ export { ErrorSanitizationUtil };
69
+ //# sourceMappingURL=ErrorSanitizationUtil.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorSanitizationUtil.d.ts","sourceRoot":"","sources":["../src/ErrorSanitizationUtil.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAaH,cAAM,qBAAqB;IACzB;;;;;;;;OAQG;WACW,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAYtD;;;;;OAKG;WACW,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;IAS7D;;;;;;;;OAQG;WACW,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;CAGnD;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Secret-safe error/log sanitization (Layer 0).
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from `ErrorSanitizationUtil.ts` in Durable-DAV, Durable-DAV-Router,
7
+ * Edge-Git, Edge-Sonic, Mail-Meow and Mail-Otter. All six redact the same secret
8
+ * shapes (Bearer/Basic headers, token and secret key=value pairs, query-string
9
+ * tokens, JWTs, Google OAuth tokens) and differ only in which extras they add:
10
+ *
11
+ * - Durable-DAV, Edge-Git, Durable-DAV-Router and Edge-Sonic also redact a
12
+ * repo-specific personal-access-token scheme (`<repo>-pat:<token>`), sanitize
13
+ * the **stack** as well as the message, and expose `stackForLog`.
14
+ * - Mail-Meow and Mail-Otter omit all three and return `name: <redacted message>`
15
+ * without a stack.
16
+ *
17
+ * ## Design decisions
18
+ *
19
+ * - **Stack sanitization is kept.** A stack trace repeats the error message and
20
+ * can name the very secret the message carries, so redacting the message but
21
+ * logging the raw stack — which Mail-Meow/Mail-Otter effectively do — is a
22
+ * one-line leak. This is the stricter of the two shapes, so it is the one kept.
23
+ * `stackForLog` stays for the structured-log payload path.
24
+ * - **The PAT scheme is generalized, not dropped and not repo-hardcoded.** Four
25
+ * repos each added their own `durable-dav-pat:` / `edge-git-pat:` /
26
+ * `durable-dav-router-pat:` / `edge-sonic-pat:` literal. Hard-coding those
27
+ * prefixes here would leak five repo identities into a shared package; dropping
28
+ * the class would undo a safeguard four of six repos independently judged
29
+ * necessary. The converged form is one generic `<word>-pat:<token>` pattern
30
+ * that covers every repo's scheme without naming any.
31
+ * - **Two correctness lessons from Mail-Otter's header are preserved in code and
32
+ * comment.** `\bbearer`/`\bbasic` keep the leading word boundary — without it
33
+ * the pattern parsed as "word boundary, then the literal `earer`", matched
34
+ * nothing, and Authorization headers leaked verbatim while the suite stayed
35
+ * green only because a Google token in the sample was caught elsewhere. And the
36
+ * `SECRET_KV` set takes Mail-Meow's superset (`client_id`, bare `code`) over the
37
+ * narrower alternatives.
38
+ */
39
+ const BEARER_PATTERN = /\bbearer\s+\S+/gi;
40
+ const BASIC_PATTERN = /\bbasic\s+\S+/gi;
41
+ // Any repo's personal-access-token scheme: `<something>-pat:<token>`. Generic on
42
+ // purpose — see the header — so no specific repo's prefix is baked in.
43
+ const PAT_PATTERN = /\b[\w-]+-pat:[\w-]+/gi;
44
+ const TOKEN_KV_PATTERN = /((?:access|refresh|id)[_-]?token\s*[:=]\s*).\S*/gi;
45
+ const SECRET_KV_PATTERN = /((?:client[_-]?secret|client[_-]?id|auth[_-]?code|code[_-]?verifier|\bcode)\s*[:=]\s*).\S*/gi;
46
+ const TOKEN_QUERY_PATTERN = /([?&](?:access_token|refresh_token|code|client_secret)=).[^&\s;}]*/gi;
47
+ const JWT_PATTERN = /eyJ[\w-].+[\w-].+[\w./+=~-]/g;
48
+ const GOOGLE_TOKEN_PATTERN = /ya29..[\w.-]+/g;
49
+ class ErrorSanitizationUtil {
50
+ /**
51
+ * Redact every recognizable secret shape from a single string.
52
+ *
53
+ * Replacements are inline string literals (not variables or templates) so a
54
+ * `unicorn/no-unsafe-string-replacement`-style rule is satisfied and so CodeQL
55
+ * models each `.replaceAll(regex, literal)` as a `js/clear-text-logging` masking
56
+ * barrier. Order matters only in that the PAT scheme runs first; the rest are
57
+ * disjoint.
58
+ */
59
+ static sanitizeMessage(message) {
60
+ return message
61
+ .replaceAll(PAT_PATTERN, '[REDACTED-PAT]')
62
+ .replaceAll(BEARER_PATTERN, 'Bearer [REDACTED]')
63
+ .replaceAll(BASIC_PATTERN, 'Basic [REDACTED]')
64
+ .replaceAll(TOKEN_KV_PATTERN, '$1[REDACTED]')
65
+ .replaceAll(SECRET_KV_PATTERN, '$1[REDACTED]')
66
+ .replaceAll(TOKEN_QUERY_PATTERN, '$1[REDACTED]')
67
+ .replaceAll(JWT_PATTERN, '[REDACTED-JWT]')
68
+ .replaceAll(GOOGLE_TOKEN_PATTERN, '[REDACTED]');
69
+ }
70
+ /**
71
+ * A redacted `name: message` (and stack) for a plain log line.
72
+ *
73
+ * Both the message and the stack are sanitized — see the header for why the
74
+ * stack must be.
75
+ */
76
+ static sanitizeErrorForLogging(error) {
77
+ if (error instanceof Error) {
78
+ const redacted = this.sanitizeMessage(error.message);
79
+ const stack = error.stack ? `\n${this.sanitizeMessage(error.stack)}` : '';
80
+ return `${error.name}: ${redacted}${stack}`;
81
+ }
82
+ return this.sanitizeMessage(String(error));
83
+ }
84
+ /**
85
+ * A redacted error, for a structured log payload.
86
+ *
87
+ * `error instanceof Error ? (error.stack ?? error.message) : error` was written
88
+ * out at many call sites, and every one of them bypassed the redaction above —
89
+ * so an error whose message carried a credential would be logged in the clear. A
90
+ * logging helper that only redacts when the caller remembers to call it is not a
91
+ * redaction boundary; this is the single point every payload goes through.
92
+ */
93
+ static stackForLog(error) {
94
+ return this.sanitizeErrorForLogging(error);
95
+ }
96
+ }
97
+ export { ErrorSanitizationUtil };
98
+ //# sourceMappingURL=ErrorSanitizationUtil.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorSanitizationUtil.js","sourceRoot":"","sources":["../src/ErrorSanitizationUtil.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAC1C,MAAM,aAAa,GAAG,iBAAiB,CAAC;AACxC,iFAAiF;AACjF,uEAAuE;AACvE,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAC5C,MAAM,gBAAgB,GAAG,mDAAmD,CAAC;AAC7E,MAAM,iBAAiB,GAAG,8FAA8F,CAAC;AACzH,MAAM,mBAAmB,GAAG,sEAAsE,CAAC;AACnG,MAAM,WAAW,GAAG,8BAA8B,CAAC;AACnD,MAAM,oBAAoB,GAAG,gBAAgB,CAAC;AAE9C,MAAM,qBAAqB;IACzB;;;;;;;;OAQG;IACI,MAAM,CAAC,eAAe,CAAC,OAAe;QAC3C,OAAO,OAAO;aACX,UAAU,CAAC,WAAW,EAAE,gBAAgB,CAAC;aACzC,UAAU,CAAC,cAAc,EAAE,mBAAmB,CAAC;aAC/C,UAAU,CAAC,aAAa,EAAE,kBAAkB,CAAC;aAC7C,UAAU,CAAC,gBAAgB,EAAE,cAAc,CAAC;aAC5C,UAAU,CAAC,iBAAiB,EAAE,cAAc,CAAC;aAC7C,UAAU,CAAC,mBAAmB,EAAE,cAAc,CAAC;aAC/C,UAAU,CAAC,WAAW,EAAE,gBAAgB,CAAC;aACzC,UAAU,CAAC,oBAAoB,EAAE,YAAY,CAAC,CAAC;IACpD,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,uBAAuB,CAAC,KAAc;QAClD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACrD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1E,OAAO,GAAG,KAAK,CAAC,IAAI,KAAK,QAAQ,GAAG,KAAK,EAAE,CAAC;QAC9C,CAAC;QACD,OAAO,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED;;;;;;;;OAQG;IACI,MAAM,CAAC,WAAW,CAAC,KAAc;QACtC,OAAO,IAAI,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;CACF;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Identifiers behind an interface, so ids can be pinned in a test.
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Taken from ChordDHT-Tracker's `IdGenerator.ts` — the only repo that factored
7
+ * id generation behind a seam. `CryptoIdGenerator` is the production path (one
8
+ * `crypto.randomUUID`), `FixedIdGenerator` is the test double that replays a
9
+ * queued set and then synthesizes deterministic stand-ins so a test can assert
10
+ * on the exact ids a code path produced.
11
+ */
12
+ interface IdGenerator {
13
+ randomUUID(): string;
14
+ }
15
+ declare class CryptoIdGenerator implements IdGenerator {
16
+ randomUUID(): string;
17
+ }
18
+ declare class FixedIdGenerator implements IdGenerator {
19
+ private readonly queue;
20
+ private counter;
21
+ constructor(ids?: string | string[]);
22
+ queueId(id: string): void;
23
+ randomUUID(): string;
24
+ }
25
+ export { CryptoIdGenerator, FixedIdGenerator };
26
+ export type { IdGenerator };
27
+ //# sourceMappingURL=IdGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IdGenerator.d.ts","sourceRoot":"","sources":["../src/IdGenerator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,UAAU,WAAW;IACnB,UAAU,IAAI,MAAM,CAAC;CACtB;AAED,cAAM,iBAAkB,YAAW,WAAW;IACrC,UAAU,IAAI,MAAM;CAG5B;AAED,cAAM,gBAAiB,YAAW,WAAW;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,OAAO,CAAK;gBAER,GAAG,GAAE,MAAM,GAAG,MAAM,EAAO;IAOhC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIzB,UAAU,IAAI,MAAM;CAM5B;AAED,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;AAC/C,YAAY,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,28 @@
1
+ class CryptoIdGenerator {
2
+ randomUUID() {
3
+ return crypto.randomUUID();
4
+ }
5
+ }
6
+ class FixedIdGenerator {
7
+ queue = [];
8
+ counter = 0;
9
+ constructor(ids = []) {
10
+ const initial = Array.isArray(ids) ? ids : [ids];
11
+ for (const id of initial) {
12
+ if (id)
13
+ this.queue.push(id);
14
+ }
15
+ }
16
+ queueId(id) {
17
+ this.queue.push(id);
18
+ }
19
+ randomUUID() {
20
+ const next = this.queue.shift();
21
+ if (next !== undefined)
22
+ return next;
23
+ this.counter += 1;
24
+ return `fixed-uuid-${this.counter.toString()}`;
25
+ }
26
+ }
27
+ export { CryptoIdGenerator, FixedIdGenerator };
28
+ //# sourceMappingURL=IdGenerator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IdGenerator.js","sourceRoot":"","sources":["../src/IdGenerator.ts"],"names":[],"mappings":"AAeA,MAAM,iBAAiB;IACd,UAAU;QACf,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,gBAAgB;IACH,KAAK,GAAa,EAAE,CAAC;IAC9B,OAAO,GAAG,CAAC,CAAC;IAEpB,YAAY,MAAyB,EAAE;QACrC,MAAM,OAAO,GAAa,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC3D,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;YACzB,IAAI,EAAE;gBAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAEM,OAAO,CAAC,EAAU;QACvB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC;IAEM,UAAU;QACf,MAAM,IAAI,GAAuB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACpD,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACpC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;QAClB,OAAO,cAAc,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;IACjD,CAAC;CACF;AAED,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Identity-string well-formedness (Layer 0).
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from Durable-DAV-Router's, Edge-Git's and Edge-Sonic's
7
+ * `Identity.ts`. Router and Edge-Sonic are byte-identical and hold exactly one
8
+ * helper — `isValidEmailFormat` — described as "a cheap sanity check on an
9
+ * identity the service did not choose". Edge-Git's is larger: the same predicate
10
+ * plus an `EmailAddress` value object and a `RepoFullName`/`repoDoKey` pair. The
11
+ * value object duplicates `normalizeEmail` (see `EmailUtil.ts`); the
12
+ * `owner/name` repo identifier, `.git`-stripping and Durable-Object key helpers
13
+ * are **git business logic and are left local** — they are the same kind of
14
+ * repo-specific concern as `GitOids`/`BranchValidation`.
15
+ *
16
+ * ## Design decision
17
+ *
18
+ * This file is the definitional home of `isValidEmailFormat` because that is what
19
+ * the wider group (Router, Edge-Sonic, Edge-Git) file under "Identity". Two
20
+ * regexes circulated for the same predicate: Durable-DAV's
21
+ * `/^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$/` and the Router/Edge-Git/Sonic
22
+ * `/^[^@\s]+@[^\s@][^\s.@]*\.[^\s@]+$/`. Durable-DAV's is the **stricter** one —
23
+ * it rejects a leading dot in the domain (`a@.b.c`) and consecutive dots, which
24
+ * the other admits — so per the kit rule the stricter form is kept. `EmailUtil`
25
+ * re-exports the predicate so the whole email surface is one import.
26
+ *
27
+ * Deliberately permissive about the local part (RFC 5322 allows far more than
28
+ * this) and strict about the obvious mistakes: no whitespace, exactly one `@`,
29
+ * a dot-separated domain, and a bounded total length. It is a shape check, not a
30
+ * deliverability check — the authoritative validation is the identity provider.
31
+ */
32
+ declare const EMAIL_FORMAT_RE: RegExp;
33
+ declare const MAX_EMAIL_LENGTH = 254;
34
+ declare function isValidEmailFormat(raw: string): boolean;
35
+ export { isValidEmailFormat, MAX_EMAIL_LENGTH, EMAIL_FORMAT_RE };
36
+ //# sourceMappingURL=Identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Identity.d.ts","sourceRoot":"","sources":["../src/Identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,QAAA,MAAM,eAAe,QAAsC,CAAC;AAE5D,QAAA,MAAM,gBAAgB,MAAM,CAAC;AAE7B,iBAAS,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGhD;AAED,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Identity-string well-formedness (Layer 0).
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from Durable-DAV-Router's, Edge-Git's and Edge-Sonic's
7
+ * `Identity.ts`. Router and Edge-Sonic are byte-identical and hold exactly one
8
+ * helper — `isValidEmailFormat` — described as "a cheap sanity check on an
9
+ * identity the service did not choose". Edge-Git's is larger: the same predicate
10
+ * plus an `EmailAddress` value object and a `RepoFullName`/`repoDoKey` pair. The
11
+ * value object duplicates `normalizeEmail` (see `EmailUtil.ts`); the
12
+ * `owner/name` repo identifier, `.git`-stripping and Durable-Object key helpers
13
+ * are **git business logic and are left local** — they are the same kind of
14
+ * repo-specific concern as `GitOids`/`BranchValidation`.
15
+ *
16
+ * ## Design decision
17
+ *
18
+ * This file is the definitional home of `isValidEmailFormat` because that is what
19
+ * the wider group (Router, Edge-Sonic, Edge-Git) file under "Identity". Two
20
+ * regexes circulated for the same predicate: Durable-DAV's
21
+ * `/^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$/` and the Router/Edge-Git/Sonic
22
+ * `/^[^@\s]+@[^\s@][^\s.@]*\.[^\s@]+$/`. Durable-DAV's is the **stricter** one —
23
+ * it rejects a leading dot in the domain (`a@.b.c`) and consecutive dots, which
24
+ * the other admits — so per the kit rule the stricter form is kept. `EmailUtil`
25
+ * re-exports the predicate so the whole email surface is one import.
26
+ *
27
+ * Deliberately permissive about the local part (RFC 5322 allows far more than
28
+ * this) and strict about the obvious mistakes: no whitespace, exactly one `@`,
29
+ * a dot-separated domain, and a bounded total length. It is a shape check, not a
30
+ * deliverability check — the authoritative validation is the identity provider.
31
+ */
32
+ const EMAIL_FORMAT_RE = /^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$/;
33
+ const MAX_EMAIL_LENGTH = 254;
34
+ function isValidEmailFormat(raw) {
35
+ const trimmed = raw.trim();
36
+ return trimmed !== '' && trimmed.length <= MAX_EMAIL_LENGTH && EMAIL_FORMAT_RE.test(trimmed);
37
+ }
38
+ export { isValidEmailFormat, MAX_EMAIL_LENGTH, EMAIL_FORMAT_RE };
39
+ //# sourceMappingURL=Identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Identity.js","sourceRoot":"","sources":["../src/Identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,eAAe,GAAG,mCAAmC,CAAC;AAE5D,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B,SAAS,kBAAkB,CAAC,GAAW;IACrC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,OAAO,OAAO,KAAK,EAAE,IAAI,OAAO,CAAC,MAAM,IAAI,gBAAgB,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAC/F,CAAC;AAED,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Single canonical language-tag implementation for backend + web.
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from Durable-DAV-Router's `LanguageTag.ts` and Edge-Git's
7
+ * `LanguageTag.ts`. The two are byte-identical — both were written to replace
8
+ * the older `canonicalizeBackendLocaleTag` (shared) / `canonicalizeTag` (web
9
+ * `i18n.ts`) split, which had drifted. Edge-Sonic has no such file (its web layer
10
+ * uses the shared one directly), so it contributes nothing here beyond confirming
11
+ * the shape.
12
+ *
13
+ * Import from here in both layers. This is generic BCP-47 casing, distinct from
14
+ * `LocaleUtil`'s `canonicalizeLocaleTag`, which additionally titlecases a
15
+ * four-letter script subtag for locale negotiation against a fixed table.
16
+ */
17
+ declare function canonicalizeLanguageTag(tag: string): string;
18
+ /**
19
+ * A BCP-47 language tag, canonicalized: `zh_TW`, `zh-tw`, and `zh-TW` all
20
+ * canonicalize to `zh-TW`.
21
+ */
22
+ type LanguageTag = string;
23
+ export { canonicalizeLanguageTag };
24
+ export type { LanguageTag };
25
+ //# sourceMappingURL=LanguageTag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LanguageTag.d.ts","sourceRoot":"","sources":["../src/LanguageTag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,iBAAS,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQpD;AAED;;;GAGG;AACH,KAAK,WAAW,GAAG,MAAM,CAAC;AAE1B,OAAO,EAAE,uBAAuB,EAAE,CAAC;AACnC,YAAY,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Single canonical language-tag implementation for backend + web.
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from Durable-DAV-Router's `LanguageTag.ts` and Edge-Git's
7
+ * `LanguageTag.ts`. The two are byte-identical — both were written to replace
8
+ * the older `canonicalizeBackendLocaleTag` (shared) / `canonicalizeTag` (web
9
+ * `i18n.ts`) split, which had drifted. Edge-Sonic has no such file (its web layer
10
+ * uses the shared one directly), so it contributes nothing here beyond confirming
11
+ * the shape.
12
+ *
13
+ * Import from here in both layers. This is generic BCP-47 casing, distinct from
14
+ * `LocaleUtil`'s `canonicalizeLocaleTag`, which additionally titlecases a
15
+ * four-letter script subtag for locale negotiation against a fixed table.
16
+ */
17
+ function canonicalizeLanguageTag(tag) {
18
+ const normalized = tag.trim().replaceAll('_', '-');
19
+ const parts = normalized.split('-').filter(Boolean);
20
+ if (parts.length === 0)
21
+ return 'en';
22
+ const language = (parts[0] ?? 'en').toLowerCase();
23
+ if (parts.length === 1)
24
+ return language;
25
+ const rest = parts.slice(1).map((part) => (part.length === 2 ? part.toUpperCase() : part.toLowerCase()));
26
+ return [language, ...rest].join('-');
27
+ }
28
+ export { canonicalizeLanguageTag };
29
+ //# sourceMappingURL=LanguageTag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LanguageTag.js","sourceRoot":"","sources":["../src/LanguageTag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,SAAS,uBAAuB,CAAC,GAAW;IAC1C,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACpD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAClD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IACxC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACzG,OAAO,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvC,CAAC;AAQD,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Locale negotiation against a fixed support table.
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from AWS-AccessBridge's, Mail-Meow's and Mail-Otter's
7
+ * `LocaleUtil.ts`. The three share the same 12-locale table
8
+ * (`en, de, fr, es, it, nl, pt, pl, ja, zh-CN, zh-TW, ko`) and the same
9
+ * `isSupported`/`normalize`; Mail-Meow and Mail-Otter additionally carry
10
+ * `negotiate`, `displayName` and `LOCALE_DISPLAY_NAMES`. The two fuller forms are
11
+ * byte-identical and are kept — AWS is the subset.
12
+ *
13
+ * ## Design decision
14
+ *
15
+ * The kit kept the fuller Mail-Meow/Mail-Otter surface. `normalize` is the load-
16
+ * bearing operation: it canonicalizes a tag, maps regional fallbacks toward the
17
+ * supported table (a bare `zh` becomes `zh-CN`), and — distinct from the generic
18
+ * `canonicalizeLanguageTag` — titlecases a four-letter script subtag so
19
+ * `zh-hans-cn` canonicalizes correctly before negotiation. Non-negotiable input
20
+ * falls back to `DEFAULT_LOCALE` rather than throwing; an Accept-Language header
21
+ * is a hint, not a contract.
22
+ */
23
+ declare const DEFAULT_LOCALE = "en";
24
+ declare const SUPPORTED_LOCALES: readonly ["en", "de", "fr", "es", "it", "nl", "pt", "pl", "ja", "zh-CN", "zh-TW", "ko"];
25
+ type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
26
+ declare const LOCALE_DISPLAY_NAMES: Record<SupportedLocale, string>;
27
+ declare class LocaleUtil {
28
+ static isSupported(locale: string | null | undefined): boolean;
29
+ static normalize(locale: string | null | undefined): SupportedLocale;
30
+ static negotiate(preferred: string | null | undefined, fallback?: string | null): SupportedLocale;
31
+ static displayName(locale: string | null | undefined): string;
32
+ }
33
+ export { LocaleUtil, DEFAULT_LOCALE, SUPPORTED_LOCALES, LOCALE_DISPLAY_NAMES };
34
+ export type { SupportedLocale };
35
+ //# sourceMappingURL=LocaleUtil.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocaleUtil.d.ts","sourceRoot":"","sources":["../src/LocaleUtil.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,QAAA,MAAM,cAAc,OAAO,CAAC;AAE5B,QAAA,MAAM,iBAAiB,yFAA0F,CAAC;AAElH,KAAK,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,QAAA,MAAM,oBAAoB,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAazD,CAAC;AAiBF,cAAM,UAAU;WACA,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO;WAMvD,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,eAAe;WAqB7D,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,eAAe;WAK1F,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM;CAIrE;AAED,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,CAAC;AAC/E,YAAY,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Locale negotiation against a fixed support table.
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Converged from AWS-AccessBridge's, Mail-Meow's and Mail-Otter's
7
+ * `LocaleUtil.ts`. The three share the same 12-locale table
8
+ * (`en, de, fr, es, it, nl, pt, pl, ja, zh-CN, zh-TW, ko`) and the same
9
+ * `isSupported`/`normalize`; Mail-Meow and Mail-Otter additionally carry
10
+ * `negotiate`, `displayName` and `LOCALE_DISPLAY_NAMES`. The two fuller forms are
11
+ * byte-identical and are kept — AWS is the subset.
12
+ *
13
+ * ## Design decision
14
+ *
15
+ * The kit kept the fuller Mail-Meow/Mail-Otter surface. `normalize` is the load-
16
+ * bearing operation: it canonicalizes a tag, maps regional fallbacks toward the
17
+ * supported table (a bare `zh` becomes `zh-CN`), and — distinct from the generic
18
+ * `canonicalizeLanguageTag` — titlecases a four-letter script subtag so
19
+ * `zh-hans-cn` canonicalizes correctly before negotiation. Non-negotiable input
20
+ * falls back to `DEFAULT_LOCALE` rather than throwing; an Accept-Language header
21
+ * is a hint, not a contract.
22
+ */
23
+ const DEFAULT_LOCALE = 'en';
24
+ const SUPPORTED_LOCALES = ['en', 'de', 'fr', 'es', 'it', 'nl', 'pt', 'pl', 'ja', 'zh-CN', 'zh-TW', 'ko'];
25
+ const LOCALE_DISPLAY_NAMES = {
26
+ en: 'English',
27
+ de: 'Deutsch',
28
+ fr: 'Français',
29
+ es: 'Español',
30
+ it: 'Italiano',
31
+ nl: 'Nederlands',
32
+ pt: 'Português',
33
+ pl: 'Polski',
34
+ ja: '日本語',
35
+ 'zh-CN': '简体中文',
36
+ 'zh-TW': '繁體中文',
37
+ ko: '한국어',
38
+ };
39
+ function canonicalizeLocaleTag(tag) {
40
+ const normalized = tag.trim().replaceAll('_', '-');
41
+ const parts = normalized.split('-').filter(Boolean);
42
+ if (parts.length === 0)
43
+ return '';
44
+ const language = (parts[0] ?? '').toLowerCase();
45
+ if (parts.length === 1)
46
+ return language;
47
+ const rest = parts.slice(1).map((part, index) => {
48
+ if (index === parts.length - 2 && part.length === 4) {
49
+ return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
50
+ }
51
+ return part.length === 2 ? part.toUpperCase() : part.toLowerCase();
52
+ });
53
+ return [language, ...rest].join('-');
54
+ }
55
+ class LocaleUtil {
56
+ static isSupported(locale) {
57
+ if (!locale || typeof locale !== 'string')
58
+ return false;
59
+ const canonical = canonicalizeLocaleTag(locale);
60
+ return SUPPORTED_LOCALES.includes(canonical);
61
+ }
62
+ static normalize(locale) {
63
+ if (!locale || typeof locale !== 'string')
64
+ return DEFAULT_LOCALE;
65
+ const canonical = canonicalizeLocaleTag(locale);
66
+ if (SUPPORTED_LOCALES.includes(canonical)) {
67
+ return canonical;
68
+ }
69
+ const base = canonical.split('-', 1)[0]?.toLowerCase() ?? '';
70
+ if (base === 'zh')
71
+ return 'zh-CN';
72
+ const baseMatch = SUPPORTED_LOCALES.find((s) => s.toLowerCase() === base);
73
+ if (baseMatch)
74
+ return baseMatch;
75
+ try {
76
+ const negotiated = Intl.getCanonicalLocales(canonical);
77
+ const primary = negotiated[0]?.split('-', 1)[0]?.toLowerCase() ?? '';
78
+ const fallback = SUPPORTED_LOCALES.find((s) => s.toLowerCase() === primary);
79
+ if (fallback)
80
+ return fallback;
81
+ }
82
+ catch {
83
+ // Ignore invalid tags and fall through to default.
84
+ }
85
+ return DEFAULT_LOCALE;
86
+ }
87
+ static negotiate(preferred, fallback) {
88
+ const primary = this.normalize(preferred);
89
+ return primary === DEFAULT_LOCALE ? this.normalize(fallback) : primary;
90
+ }
91
+ static displayName(locale) {
92
+ const normalized = this.normalize(locale);
93
+ return LOCALE_DISPLAY_NAMES[normalized] ?? normalized;
94
+ }
95
+ }
96
+ export { LocaleUtil, DEFAULT_LOCALE, SUPPORTED_LOCALES, LOCALE_DISPLAY_NAMES };
97
+ //# sourceMappingURL=LocaleUtil.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocaleUtil.js","sourceRoot":"","sources":["../src/LocaleUtil.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,cAAc,GAAG,IAAI,CAAC;AAE5B,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAU,CAAC;AAIlH,MAAM,oBAAoB,GAAoC;IAC5D,EAAE,EAAE,SAAS;IACb,EAAE,EAAE,SAAS;IACb,EAAE,EAAE,UAAU;IACd,EAAE,EAAE,SAAS;IACb,EAAE,EAAE,UAAU;IACd,EAAE,EAAE,YAAY;IAChB,EAAE,EAAE,WAAW;IACf,EAAE,EAAE,QAAQ;IACZ,EAAE,EAAE,KAAK;IACT,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,MAAM;IACf,EAAE,EAAE,KAAK;CACV,CAAC;AAEF,SAAS,qBAAqB,CAAC,GAAW;IACxC,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACpD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAChD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IACxC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC9C,IAAI,KAAK,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACpE,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IACrE,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU;IACP,MAAM,CAAC,WAAW,CAAC,MAAiC;QACzD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QACxD,MAAM,SAAS,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;QAChD,OAAQ,iBAAuC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACtE,CAAC;IAEM,MAAM,CAAC,SAAS,CAAC,MAAiC;QACvD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,OAAO,cAAc,CAAC;QACjE,MAAM,SAAS,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;QAChD,IAAK,iBAAuC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACjE,OAAO,SAA4B,CAAC;QACtC,CAAC;QACD,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QAC7D,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,OAAO,CAAC;QAClC,MAAM,SAAS,GAAI,iBAAuC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,CAAC;QACjG,IAAI,SAAS;YAAE,OAAO,SAA4B,CAAC;QACnD,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;YACvD,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;YACrE,MAAM,QAAQ,GAAI,iBAAuC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,CAAC;YACnG,IAAI,QAAQ;gBAAE,OAAO,QAA2B,CAAC;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,mDAAmD;QACrD,CAAC;QACD,OAAO,cAAc,CAAC;IACxB,CAAC;IAEM,MAAM,CAAC,SAAS,CAAC,SAAoC,EAAE,QAAwB;QACpF,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC1C,OAAO,OAAO,KAAK,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACzE,CAAC;IAEM,MAAM,CAAC,WAAW,CAAC,MAAiC;QACzD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC1C,OAAO,oBAAoB,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC;IACxD,CAAC;CACF;AAED,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * A cheap, deterministic tag for a presented password.
3
+ *
4
+ * ## Provenance
5
+ *
6
+ * Taken from Durable-DAV's `packages/shared/src/utils/PasswordFingerprint.ts`
7
+ * (the only repo that factored this). It is one unsalted SHA-256 that delegates
8
+ * to `CryptoUtil.sha256Hex`.
9
+ *
10
+ * **Not a credential, and not a secret.** It is one unsalted SHA-256, so it is
11
+ * exactly as crackable as the legacy unsalted digest it is sometimes confused
12
+ * with — a rainbow table recovers it instantly, and two users who chose the same
13
+ * password share a value. It exists to be a memo *key* and nothing else. Any
14
+ * code that treats it as a password hash is wrong.
15
+ *
16
+ * ## Why it exists
17
+ *
18
+ * Password verification is memoized so a repeated request does not pay a PBKDF2
19
+ * derivation again. The memo must distinguish "this exact password was already
20
+ * verified against this stored hash" from "someone presented a different password
21
+ * for this username". Keying on `username` alone would accept **any** password
22
+ * for a recently-used username — a total authentication bypass. The lookup key
23
+ * therefore includes this fingerprint: it makes the key specific to the password
24
+ * actually presented, at the cost of one SHA-256 (microseconds) instead of one
25
+ * PBKDF2 derivation (milliseconds, and on the Workers Free plan more than the
26
+ * entire CPU budget).
27
+ */
28
+ declare function passwordFingerprint(password: string): Promise<string>;
29
+ export { passwordFingerprint };
30
+ //# sourceMappingURL=PasswordFingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PasswordFingerprint.d.ts","sourceRoot":"","sources":["../src/PasswordFingerprint.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,iBAAe,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEpE;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { CryptoUtil } from './CryptoUtil';
2
+ /**
3
+ * A cheap, deterministic tag for a presented password.
4
+ *
5
+ * ## Provenance
6
+ *
7
+ * Taken from Durable-DAV's `packages/shared/src/utils/PasswordFingerprint.ts`
8
+ * (the only repo that factored this). It is one unsalted SHA-256 that delegates
9
+ * to `CryptoUtil.sha256Hex`.
10
+ *
11
+ * **Not a credential, and not a secret.** It is one unsalted SHA-256, so it is
12
+ * exactly as crackable as the legacy unsalted digest it is sometimes confused
13
+ * with — a rainbow table recovers it instantly, and two users who chose the same
14
+ * password share a value. It exists to be a memo *key* and nothing else. Any
15
+ * code that treats it as a password hash is wrong.
16
+ *
17
+ * ## Why it exists
18
+ *
19
+ * Password verification is memoized so a repeated request does not pay a PBKDF2
20
+ * derivation again. The memo must distinguish "this exact password was already
21
+ * verified against this stored hash" from "someone presented a different password
22
+ * for this username". Keying on `username` alone would accept **any** password
23
+ * for a recently-used username — a total authentication bypass. The lookup key
24
+ * therefore includes this fingerprint: it makes the key specific to the password
25
+ * actually presented, at the cost of one SHA-256 (microseconds) instead of one
26
+ * PBKDF2 derivation (milliseconds, and on the Workers Free plan more than the
27
+ * entire CPU budget).
28
+ */
29
+ async function passwordFingerprint(password) {
30
+ return CryptoUtil.sha256Hex(password);
31
+ }
32
+ export { passwordFingerprint };
33
+ //# sourceMappingURL=PasswordFingerprint.js.map