@rexezuge/shared 1.0.1 → 1.0.3
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 +61 -0
- package/dist/Base64.js.map +1 -1
- package/dist/Clock.js.map +1 -1
- package/dist/CryptoUtil.js.map +1 -1
- package/dist/CursorCodec.js.map +1 -1
- package/dist/EmailUtil.js.map +1 -1
- package/dist/ErrorSanitizationUtil.js.map +1 -1
- package/dist/IdGenerator.js.map +1 -1
- package/dist/Identity.js.map +1 -1
- package/dist/LanguageTag.js.map +1 -1
- package/dist/LocaleUtil.js.map +1 -1
- package/dist/PasswordFingerprint.js.map +1 -1
- package/dist/RemoteUrlPolicy.js.map +1 -1
- package/dist/Result.js.map +1 -1
- package/dist/SubrequestMeter.js.map +1 -1
- package/dist/TimeZoneUtil.js.map +1 -1
- package/dist/TimestampUtil.js.map +1 -1
- package/dist/TokenHashUtil.js.map +1 -1
- package/dist/UUIDUtil.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# @rexezuge/shared
|
|
2
|
+
|
|
3
|
+
Pure platform-generic utilities (codecs, time, locale, crypto, `Result`, SSRF policy) for Cloudflare Workers.
|
|
4
|
+
|
|
5
|
+
Zero dependencies. One concept per file; the barrel only re-exports. Business-specific helpers (money, git oids, calendar sync, credential sharding) deliberately stay in their consumer repos.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @rexezuge/shared
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. What's inside
|
|
14
|
+
|
|
15
|
+
| Area | Exports |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| Byte codecs | `bytesToBase64`, `base64ToBytes` |
|
|
18
|
+
| Time | `SystemClock` / `FixedClock` (injectable `Clock`), `TimestampUtil`, `TimeZoneUtil` + `DEFAULT_TIME_ZONE` |
|
|
19
|
+
| Locale | `LocaleUtil` (`DEFAULT_LOCALE`, `SUPPORTED_LOCALES`, display names), `canonicalizeLanguageTag` |
|
|
20
|
+
| Email | `normalizeEmail`, `isValidEmailFormat`, `MAX_EMAIL_LENGTH` |
|
|
21
|
+
| Identifiers | `UUIDUtil`, `CryptoIdGenerator` / `FixedIdGenerator` (injectable `IdGenerator`) |
|
|
22
|
+
| Crypto + secrets | `CryptoUtil`, `TokenHashUtil`, `passwordFingerprint` |
|
|
23
|
+
| Error handling | `ErrorSanitizationUtil` (operator/client message split), `ok` / `err` / `getOrThrow` / `mapResult` + `Result` |
|
|
24
|
+
| Network policy | `normalizeRemoteUrl`, `resolveRedirectUrl`, `parseAllowedHosts`, `isPrivateOrInternalHost` (+ limits and blocklists) |
|
|
25
|
+
| Pagination | `CursorCodec` (opaque cursors, `Page`) |
|
|
26
|
+
| Subrequest accounting | `SubrequestCounter`, `SUBREQUEST_KINDS`, `subrequestSpend` (Cloudflare's 50-subrequest ceiling) |
|
|
27
|
+
|
|
28
|
+
## 2. Usage
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import {
|
|
32
|
+
CryptoIdGenerator,
|
|
33
|
+
CursorCodec,
|
|
34
|
+
ErrorSanitizationUtil,
|
|
35
|
+
normalizeEmail,
|
|
36
|
+
normalizeRemoteUrl,
|
|
37
|
+
ok,
|
|
38
|
+
SYSTEM_CLOCK,
|
|
39
|
+
} from '@rexezuge/shared';
|
|
40
|
+
|
|
41
|
+
normalizeEmail(' USER@Example.COM '); // 'user@example.com'
|
|
42
|
+
normalizeRemoteUrl('https://example.com/hook', { allowedHosts: parseAllowedHosts('example.com') }); // throws RemoteUrlRejectedError on SSRF targets
|
|
43
|
+
CursorCodec.encode({ id: 'abc', createdAt: 123 }); // opaque page cursor
|
|
44
|
+
const now = SYSTEM_CLOCK.now(); // inject FixedClock in tests
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Conventions worth knowing:
|
|
48
|
+
|
|
49
|
+
- **Clocks and ID generators are injectable.** Production code takes a `Clock` / `IdGenerator`; tests pass `FixedClock` / `FixedIdGenerator` instead of mocking time or randomness.
|
|
50
|
+
- **`Result` is for expected failures, exceptions for programmer errors.** `getOrThrow` bridges the two at boundaries.
|
|
51
|
+
- **`RemoteUrlPolicy` is fail-closed.** Private/internal hosts, over-long URLs, and excess redirects throw `RemoteUrlRejectedError` rather than fetching.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Verifying this package
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pnpm --filter @rexezuge/shared exec tsc -p tsconfig.json
|
|
59
|
+
pnpm --filter @rexezuge/shared typecheck
|
|
60
|
+
pnpm --filter @rexezuge/shared test
|
|
61
|
+
```
|
package/dist/Base64.js.map
CHANGED
|
@@ -1 +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"}
|
|
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","sourcesContent":["/**\n * Base64 codec for byte payloads.\n *\n * ## Provenance\n *\n * Converged from `packages/shared/src/utils/Base64.ts` (Durable-DAV), the\n * documented best form. Four implementations once existed — Durable-DAV's own,\n * `DavReadCache`, and `aes-gcm` running the `String.fromCodePoint(...subarray)`\n * + `btoa` form this file was written to replace. ChordDHT-Tracker and\n * Mail-Otter carry no byte codec of their own; their `CryptoUtil`s use the\n * `btoa`+transform form. This file is the canonical one for **standard**\n * base64. The **base64url** alphabet is a different job and lives in\n * `CryptoUtil` — that duplication is deliberate (different alphabet).\n *\n * ## Why not `String.fromCodePoint` + `btoa`\n *\n * The obvious encoder builds a binary string and `btoa`s it:\n *\n * ```ts\n * let binary = '';\n * for (let i = 0; i < bytes.length; i += 8192) {\n * binary += String.fromCodePoint(...bytes.subarray(i, i + 8192));\n * }\n * return btoa(binary);\n * ```\n *\n * That allocates roughly 2× the input as UTF-16 — up to 100 MB of garbage for a\n * 50 MB payload, on top of the buffer and the result — and the variadic spread\n * approaches the engine's argument limit. A direct 3-byte-to-4-char table is\n * allocation-light and has no argument limit. `base64ToBytes` keeps the `atob`\n * form: decoding allocates one binary string and one buffer, which is the\n * output's own size rather than double it, and `atob` does the validation for\n * free.\n */\n\nconst BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n/**\n * Encode `bytes` as standard base64 (with `=` padding).\n *\n * Not base64url: pre-binary KV file entries stored these as opaque values and\n * `aes-gcm` stores them where `atob` reads them back. `CryptoUtil` has the\n * URL-safe variant for the cases that need one.\n */\nfunction bytesToBase64(bytes: Uint8Array): string {\n let out = '';\n const len = bytes.length;\n const remainder = len % 3;\n const limit = len - remainder;\n for (let i = 0; i < limit; i += 3) {\n const triple = bytes[i] * 65_536 + bytes[i + 1] * 256 + bytes[i + 2];\n out +=\n BASE64_ALPHABET[(triple >> 18) & 63] +\n BASE64_ALPHABET[(triple >> 12) & 63] +\n BASE64_ALPHABET[(triple >> 6) & 63] +\n BASE64_ALPHABET[triple & 63];\n }\n if (remainder === 1) {\n const value = bytes[limit];\n out += `${BASE64_ALPHABET[value >> 2]}${BASE64_ALPHABET[(value << 4) & 63]}==`;\n } else if (remainder === 2) {\n const pair = (bytes[limit] << 8) | bytes[limit + 1];\n out += `${BASE64_ALPHABET[pair >> 10]}${BASE64_ALPHABET[(pair >> 4) & 63]}${BASE64_ALPHABET[(pair << 2) & 63]}=`;\n }\n return out;\n}\n\n/**\n * Decode standard base64.\n *\n * `atob` throws on malformed input rather than producing partial bytes, which is\n * the right behaviour for every caller here: a corrupt cache entry or a mistyped\n * key should fail loudly, not decrypt to noise.\n */\nfunction base64ToBytes(b64: string): Uint8Array {\n const binary = atob(b64);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) out[i] = (binary.codePointAt(i) ?? 0) & 0xff;\n return out;\n}\n\nexport { bytesToBase64, base64ToBytes };\n"]}
|
package/dist/Clock.js.map
CHANGED
|
@@ -1 +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"}
|
|
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","sourcesContent":["/**\n * Inject-able time source.\n *\n * ## Provenance\n *\n * Converged from AWS-AccessBridge's `Clock.ts`, Mail-Otter's `Clock.ts` and\n * ChordDHT-Tracker's `Clock.ts`. The three differ in surface, not concept: AWS\n * names the seam `Clock` with `now(): number` and a shared `SYSTEM_CLOCK`;\n * Mail-Otter/ChordDHT name it `IClock` with `nowMs()` and a mutable\n * `FixedClock` carrying `setNowMs`/`advanceByMs`.\n *\n * ## Design decision\n *\n * The kit drops the `I` prefix on the interface (no `any`, no Hungarian drift;\n * the consumer repos' own \"no `I` on interfaces\" cleanups point the same way),\n * keeps AWS's single-method `now()` as the primary read, and keeps Mail-Otter's\n * mutable `FixedClock` helpers — they cost nothing and are exactly what a test\n * wants. `TimestampUtil`'s current-time reads go through `SYSTEM_CLOCK` by\n * default; pass a `FixedClock` to pin them.\n */\n\ninterface Clock {\n /**\n * Milliseconds since the Unix epoch.\n */\n now(): number;\n}\n\n/**\n * The production clock. A single shared instance — it holds no state, so there\n * is nothing to gain from more than one, and a default parameter needs a value.\n */\nclass SystemClock implements Clock {\n now(): number {\n return Date.now();\n }\n}\n\n/**\n * A clock seeded at `initialNowMs` and moved forward with `setNowMs`/`advanceByMs`.\n *\n * Two shapes were merged: AWS's `FixedClock` was immutable (constructed with the\n * instant under test), Mail-Otter's was mutable. The mutable form is a superset\n * and is what the time-dependent tests in every repo actually reach for, so a\n * test either pins the instant up front or advances it as work happens.\n */\nclass FixedClock implements Clock {\n private currentMs: number;\n\n constructor(initialNowMs = 0) {\n this.currentMs = initialNowMs;\n }\n\n now(): number {\n return this.currentMs;\n }\n\n setNowMs(valueMs: number): void {\n this.currentMs = valueMs;\n }\n\n advanceByMs(deltaMs: number): void {\n this.currentMs += deltaMs;\n }\n}\n\n/**\n * The shared production instance, for the common case where a caller wants \"now\"\n * without choosing a clock. Stateless, so one instance is enough.\n */\nconst SYSTEM_CLOCK: Clock = new SystemClock();\n\nexport type { Clock };\nexport { SystemClock, FixedClock, SYSTEM_CLOCK };\n"]}
|
package/dist/CryptoUtil.js.map
CHANGED
|
@@ -1 +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"}
|
|
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","sourcesContent":["import { bytesToBase64 } from './Base64';\n\n/**\n * Hashing and key generation.\n *\n * ## Provenance\n *\n * Converged from `CryptoUtil.ts` in Durable-DAV, Edge-Git, Mail-Meow,\n * Mail-Otter, ChordDHT-Tracker and CalDAV-Bridge. Every copy carries\n * `sha256Hex` and `randomBase64Url`; Edge-Git/Mail-Meow/Mail-Otter/ChordDHT add\n * `hmacSha256Hex`; Mail-Meow adds the string overload `base64UrlEncode`;\n * Durable-DAV uniquely factors the digest over raw bytes (`sha256HexOfBytes`) and\n * rewrites base64url on the shared codec.\n *\n * ## Design decisions\n *\n * - The base64url alphabet is a **different alphabet for a different job** from\n * `Base64.ts`, so the URL-safe transform stays here — but it delegates to the\n * documented best encoder rather than re-spreading bytes (`String.fromCodePoint`\n * + `btoa`), which was four copies of the ~2×-UTF-16 form `Base64.ts` replaced.\n * - `sha256Hex` is defined over `sha256HexOfBytes` (Durable-DAV's shape): the\n * digest then covers exactly the bytes presented, which matters when two sides\n * compare a digest — an intermediate encoding is a place for them to disagree.\n * - `hmacSha256Hex` is kept from the four repos that carry it.\n *\n * ## Left local\n *\n * ChordDHT-Tracker's `sha1Hex` is deliberately **not** here. SHA-1 is the Chord\n * ring identifier hash (protocol compatibility), not a general security digest;\n * surfacing it in the shared surface would invite exactly the misuse the\n * `sonarjs/hashing` lint it carries a disable for is there to catch. A repo that\n * needs a protocol-mandated SHA-1 computes it on a `BufferSource` itself.\n */\nclass CryptoUtil {\n /**\n * SHA-256 of a string, hex-encoded.\n *\n * Encoded as UTF-8 first. For bytes you already hold, prefer `sha256HexOfBytes`\n * — this overload is the reason a byte payload used to be laundered through\n * `String.fromCodePoint` into a binary string and back, allocating roughly 2×\n * the input as UTF-16 on the way.\n */\n public static async sha256Hex(value: string): Promise<string> {\n return this.sha256HexOfBytes(new TextEncoder().encode(value));\n }\n\n /**\n * SHA-256 of raw bytes, hex-encoded.\n *\n * The hash covers exactly these bytes. This matters where the digest is\n * compared between two sides: any intermediate encoding is a place for the two\n * to disagree for a reason that has nothing to do with the content.\n */\n public static async sha256HexOfBytes(bytes: Uint8Array): Promise<string> {\n const digest: ArrayBuffer = await crypto.subtle.digest('SHA-256', bytes as BufferSource);\n return this.toHex(new Uint8Array(digest));\n }\n\n /**\n * HMAC-SHA256 of `value` under `secret`, hex-encoded.\n *\n * A keyed MAC for a message a caller will recompute on the other side. The key\n * is imported as non-extractable; a comparison against a re-derived MAC must be\n * timing-safe on the caller's side — this helper returns the hex string, it does\n * not compare.\n */\n public static async hmacSha256Hex(value: string, secret: string): Promise<string> {\n const key: CryptoKey = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n const signature: ArrayBuffer = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(value));\n return this.toHex(new Uint8Array(signature));\n }\n\n private static toHex(bytes: Uint8Array): string {\n return Array.from(bytes, (byte: number): string => byte.toString(16).padStart(2, '0')).join('');\n }\n\n /**\n * URL-safe base64 of `bytes` (no `+`, `/` or `=`).\n *\n * Delegates to the shared codec rather than rebuilding the binary string here:\n * the URL-safe transform is applied to the standard alphabet because\n * `Uint8Array#toBase64` is not guaranteed across Workers runtimes.\n */\n public static toBase64Url(bytes: Uint8Array): string {\n return bytesToBase64(bytes).replaceAll('+', '-').replaceAll('/', '_').replace(/={0,2}$/, '');\n }\n\n /**\n * URL-safe base64 of a UTF-8 string.\n *\n * The same transform as {@link toBase64Url}, for callers holding text rather\n * than bytes. This and `toBase64Url` used to be separate implementations in\n * different packages; they are the same encoding and must not drift.\n */\n public static base64UrlEncode(value: string): string {\n return this.toBase64Url(new TextEncoder().encode(value));\n }\n\n public static randomBase64Url(byteLength: number): string {\n return this.toBase64Url(crypto.getRandomValues(new Uint8Array(byteLength)));\n }\n}\n\nexport { CryptoUtil };\n"]}
|
package/dist/CursorCodec.js.map
CHANGED
|
@@ -1 +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"}
|
|
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","sourcesContent":["/**\n * Canonical opaque-cursor codec, plus the `Page<T>` shape it produces.\n *\n * ## Provenance\n *\n * Converged from ChordDHT-Tracker's `utils/Cursor.ts` (a `Cursor` class + a\n * `Page<T>` type), Edge-Git's `backend-data/.../CursorUtil.ts` (a `CursorUtil`\n * class that adds `decodeOrThrow` + `isValidCursor`) and Mail-Otter's\n * `CursorUtil.ts` (the minimal `encode`/`decode` pair). All three hand-rolled\n * DAO pagination cursors and all three converged on `btoa(JSON.stringify(...))`\n * / `JSON.parse(atob(...))`. Canonical name is **`CursorCodec`**; the cursor is an\n * opaque token, so callers pass it through and never inspect it.\n *\n * ## Design decisions\n *\n * - The cursor is `btoa`/`atob`, which works in workerd *and* Node 24 (both\n * expose browser globals now). No `Buffer` is used, so the same bundle runs in\n * both.\n * - `decode` never throws: a malformed or tampered cursor is `undefined`, which a\n * DAO reads as \"no cursor, start from the beginning\" rather than an error an\n * attacker can provoke. `decodeOrThrow` and `isValidCursor` are kept from\n * Edge-Git for the call sites that *want* the strict behaviour.\n * - **Layer 0 stays dependency-free.** Edge-Git's `decodeOrThrow` threw its\n * `@edge-git/backend-errors` `BadRequestError`; the shared package imports\n * nothing, so it throws a plain `Error` and leaves the HTTP mapping to the\n * layer that owns the error taxonomy (the same \"throw plain `Error`, map above\"\n * rule `Identity`/`EmailUtil` follow).\n */\ninterface Page<T> {\n readonly items: readonly T[];\n readonly nextCursor?: string;\n}\n\nclass CursorCodec {\n public static encode(value: unknown): string {\n return btoa(JSON.stringify(value));\n }\n\n /**\n * Decode a cursor, or `undefined` for a missing/malformed one.\n *\n * `atob`/`JSON.parse` throw on bad input; the `try` turns that into `undefined`\n * so a corrupt cursor degrades to a first page instead of an uncaught throw.\n */\n public static decode<T>(cursor: string | undefined | null): T | undefined {\n if (!cursor) return undefined;\n try {\n return JSON.parse(atob(cursor)) as T;\n } catch {\n return undefined;\n }\n }\n\n /**\n * Decode a cursor, throwing a plain `Error` on malformed input.\n *\n * For a call site that treats a bad cursor as a client error; the HTTP mapping\n * to `BadRequest` is the caller's layer's job (see the file header).\n */\n public static decodeOrThrow<T>(cursor: string | undefined | null): T | undefined {\n if (!cursor) return undefined;\n try {\n return JSON.parse(atob(cursor)) as T;\n } catch {\n throw new Error('Invalid cursor');\n }\n }\n\n /**\n * Whether a cursor is well-formed. A missing cursor is valid (first page).\n */\n public static isValidCursor(cursor: string | undefined | null): boolean {\n if (!cursor) return true;\n try {\n JSON.parse(atob(cursor));\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Build a `Page`, omitting `nextCursor` entirely on the last page rather than\n * carrying an explicit `undefined`.\n */\n public static page<T>(items: readonly T[], nextCursor?: string): Page<T> {\n return nextCursor ? { items, nextCursor } : { items };\n }\n}\n\nexport { CursorCodec };\nexport type { Page };\n"]}
|
package/dist/EmailUtil.js.map
CHANGED
|
@@ -1 +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"}
|
|
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","sourcesContent":["import { isValidEmailFormat, MAX_EMAIL_LENGTH } from './Identity';\n\n/**\n * Email address value helpers.\n *\n * ## Provenance\n *\n * Converged from Durable-DAV's `EmailUtil.ts` (a shape check) and Mail-Meow's\n * `EmailUtil.ts` (address normalization). Durable-DAV's predicate `isValidEmailFormat`\n * canonically lives in `Identity.ts` — the wider group's home, and the stricter\n * of the two regexes found (see the merge note there) — and is re-exported here\n * so `EmailUtil` is the one-stop surface for validation + normalization.\n *\n * `normalizeEmail` comes from Mail-Meow, whose header records why a single\n * normalization rule is a correctness concern, not a cosmetic one: \"This function\n * used to exist four times, and the copies disagreed.\" One copy trimmed and\n * lowercased, the others lowercased only, so `\" Alice@Example.com \"` and\n * `\"alice@example.com\"` were the same account to one layer and different accounts\n * to another — a different account key on each side of a boundary, and a stored\n * registry row that its own service could not resolve.\n *\n * ## Design decision\n *\n * The kit keeps `normalizeEmail` and re-exports the validator; it does not\n * re-introduce Edge-Git's `EmailAddress` value class, which is sugar over the\n * same trim+lowercase and would be a second spelling of the same rule.\n */\nfunction normalizeEmail(email: string): string {\n return email.trim().toLowerCase();\n}\n\nexport { normalizeEmail, isValidEmailFormat, MAX_EMAIL_LENGTH };\n"]}
|
|
@@ -1 +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"}
|
|
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","sourcesContent":["/**\n * Secret-safe error/log sanitization (Layer 0).\n *\n * ## Provenance\n *\n * Converged from `ErrorSanitizationUtil.ts` in Durable-DAV, Durable-DAV-Router,\n * Edge-Git, Edge-Sonic, Mail-Meow and Mail-Otter. All six redact the same secret\n * shapes (Bearer/Basic headers, token and secret key=value pairs, query-string\n * tokens, JWTs, Google OAuth tokens) and differ only in which extras they add:\n *\n * - Durable-DAV, Edge-Git, Durable-DAV-Router and Edge-Sonic also redact a\n * repo-specific personal-access-token scheme (`<repo>-pat:<token>`), sanitize\n * the **stack** as well as the message, and expose `stackForLog`.\n * - Mail-Meow and Mail-Otter omit all three and return `name: <redacted message>`\n * without a stack.\n *\n * ## Design decisions\n *\n * - **Stack sanitization is kept.** A stack trace repeats the error message and\n * can name the very secret the message carries, so redacting the message but\n * logging the raw stack — which Mail-Meow/Mail-Otter effectively do — is a\n * one-line leak. This is the stricter of the two shapes, so it is the one kept.\n * `stackForLog` stays for the structured-log payload path.\n * - **The PAT scheme is generalized, not dropped and not repo-hardcoded.** Four\n * repos each added their own `durable-dav-pat:` / `edge-git-pat:` /\n * `durable-dav-router-pat:` / `edge-sonic-pat:` literal. Hard-coding those\n * prefixes here would leak five repo identities into a shared package; dropping\n * the class would undo a safeguard four of six repos independently judged\n * necessary. The converged form is one generic `<word>-pat:<token>` pattern\n * that covers every repo's scheme without naming any.\n * - **Two correctness lessons from Mail-Otter's header are preserved in code and\n * comment.** `\\bbearer`/`\\bbasic` keep the leading word boundary — without it\n * the pattern parsed as \"word boundary, then the literal `earer`\", matched\n * nothing, and Authorization headers leaked verbatim while the suite stayed\n * green only because a Google token in the sample was caught elsewhere. And the\n * `SECRET_KV` set takes Mail-Meow's superset (`client_id`, bare `code`) over the\n * narrower alternatives.\n */\n\nconst BEARER_PATTERN = /\\bbearer\\s+\\S+/gi;\nconst BASIC_PATTERN = /\\bbasic\\s+\\S+/gi;\n// Any repo's personal-access-token scheme: `<something>-pat:<token>`. Generic on\n// purpose — see the header — so no specific repo's prefix is baked in.\nconst PAT_PATTERN = /\\b[\\w-]+-pat:[\\w-]+/gi;\nconst TOKEN_KV_PATTERN = /((?:access|refresh|id)[_-]?token\\s*[:=]\\s*).\\S*/gi;\nconst SECRET_KV_PATTERN = /((?:client[_-]?secret|client[_-]?id|auth[_-]?code|code[_-]?verifier|\\bcode)\\s*[:=]\\s*).\\S*/gi;\nconst TOKEN_QUERY_PATTERN = /([?&](?:access_token|refresh_token|code|client_secret)=).[^&\\s;}]*/gi;\nconst JWT_PATTERN = /eyJ[\\w-].+[\\w-].+[\\w./+=~-]/g;\nconst GOOGLE_TOKEN_PATTERN = /ya29..[\\w.-]+/g;\n\nclass ErrorSanitizationUtil {\n /**\n * Redact every recognizable secret shape from a single string.\n *\n * Replacements are inline string literals (not variables or templates) so a\n * `unicorn/no-unsafe-string-replacement`-style rule is satisfied and so CodeQL\n * models each `.replaceAll(regex, literal)` as a `js/clear-text-logging` masking\n * barrier. Order matters only in that the PAT scheme runs first; the rest are\n * disjoint.\n */\n public static sanitizeMessage(message: string): string {\n return message\n .replaceAll(PAT_PATTERN, '[REDACTED-PAT]')\n .replaceAll(BEARER_PATTERN, 'Bearer [REDACTED]')\n .replaceAll(BASIC_PATTERN, 'Basic [REDACTED]')\n .replaceAll(TOKEN_KV_PATTERN, '$1[REDACTED]')\n .replaceAll(SECRET_KV_PATTERN, '$1[REDACTED]')\n .replaceAll(TOKEN_QUERY_PATTERN, '$1[REDACTED]')\n .replaceAll(JWT_PATTERN, '[REDACTED-JWT]')\n .replaceAll(GOOGLE_TOKEN_PATTERN, '[REDACTED]');\n }\n\n /**\n * A redacted `name: message` (and stack) for a plain log line.\n *\n * Both the message and the stack are sanitized — see the header for why the\n * stack must be.\n */\n public static sanitizeErrorForLogging(error: unknown): string {\n if (error instanceof Error) {\n const redacted = this.sanitizeMessage(error.message);\n const stack = error.stack ? `\\n${this.sanitizeMessage(error.stack)}` : '';\n return `${error.name}: ${redacted}${stack}`;\n }\n return this.sanitizeMessage(String(error));\n }\n\n /**\n * A redacted error, for a structured log payload.\n *\n * `error instanceof Error ? (error.stack ?? error.message) : error` was written\n * out at many call sites, and every one of them bypassed the redaction above —\n * so an error whose message carried a credential would be logged in the clear. A\n * logging helper that only redacts when the caller remembers to call it is not a\n * redaction boundary; this is the single point every payload goes through.\n */\n public static stackForLog(error: unknown): unknown {\n return this.sanitizeErrorForLogging(error);\n }\n}\n\nexport { ErrorSanitizationUtil };\n"]}
|
package/dist/IdGenerator.js.map
CHANGED
|
@@ -1 +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"}
|
|
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","sourcesContent":["/**\n * Identifiers behind an interface, so ids can be pinned in a test.\n *\n * ## Provenance\n *\n * Taken from ChordDHT-Tracker's `IdGenerator.ts` — the only repo that factored\n * id generation behind a seam. `CryptoIdGenerator` is the production path (one\n * `crypto.randomUUID`), `FixedIdGenerator` is the test double that replays a\n * queued set and then synthesizes deterministic stand-ins so a test can assert\n * on the exact ids a code path produced.\n */\ninterface IdGenerator {\n randomUUID(): string;\n}\n\nclass CryptoIdGenerator implements IdGenerator {\n public randomUUID(): string {\n return crypto.randomUUID();\n }\n}\n\nclass FixedIdGenerator implements IdGenerator {\n private readonly queue: string[] = [];\n private counter = 0;\n\n constructor(ids: string | string[] = []) {\n const initial: string[] = Array.isArray(ids) ? ids : [ids];\n for (const id of initial) {\n if (id) this.queue.push(id);\n }\n }\n\n public queueId(id: string): void {\n this.queue.push(id);\n }\n\n public randomUUID(): string {\n const next: string | undefined = this.queue.shift();\n if (next !== undefined) return next;\n this.counter += 1;\n return `fixed-uuid-${this.counter.toString()}`;\n }\n}\n\nexport { CryptoIdGenerator, FixedIdGenerator };\nexport type { IdGenerator };\n"]}
|
package/dist/Identity.js.map
CHANGED
|
@@ -1 +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"}
|
|
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","sourcesContent":["/**\n * Identity-string well-formedness (Layer 0).\n *\n * ## Provenance\n *\n * Converged from Durable-DAV-Router's, Edge-Git's and Edge-Sonic's\n * `Identity.ts`. Router and Edge-Sonic are byte-identical and hold exactly one\n * helper — `isValidEmailFormat` — described as \"a cheap sanity check on an\n * identity the service did not choose\". Edge-Git's is larger: the same predicate\n * plus an `EmailAddress` value object and a `RepoFullName`/`repoDoKey` pair. The\n * value object duplicates `normalizeEmail` (see `EmailUtil.ts`); the\n * `owner/name` repo identifier, `.git`-stripping and Durable-Object key helpers\n * are **git business logic and are left local** — they are the same kind of\n * repo-specific concern as `GitOids`/`BranchValidation`.\n *\n * ## Design decision\n *\n * This file is the definitional home of `isValidEmailFormat` because that is what\n * the wider group (Router, Edge-Sonic, Edge-Git) file under \"Identity\". Two\n * regexes circulated for the same predicate: Durable-DAV's\n * `/^[^\\s@]+@[^\\s@.]+(?:\\.[^\\s@.]+)+$/` and the Router/Edge-Git/Sonic\n * `/^[^@\\s]+@[^\\s@][^\\s.@]*\\.[^\\s@]+$/`. Durable-DAV's is the **stricter** one —\n * it rejects a leading dot in the domain (`a@.b.c`) and consecutive dots, which\n * the other admits — so per the kit rule the stricter form is kept. `EmailUtil`\n * re-exports the predicate so the whole email surface is one import.\n *\n * Deliberately permissive about the local part (RFC 5322 allows far more than\n * this) and strict about the obvious mistakes: no whitespace, exactly one `@`,\n * a dot-separated domain, and a bounded total length. It is a shape check, not a\n * deliverability check — the authoritative validation is the identity provider.\n */\nconst EMAIL_FORMAT_RE = /^[^\\s@]+@[^\\s@.]+(?:\\.[^\\s@.]+)+$/;\n\nconst MAX_EMAIL_LENGTH = 254;\n\nfunction isValidEmailFormat(raw: string): boolean {\n const trimmed = raw.trim();\n return trimmed !== '' && trimmed.length <= MAX_EMAIL_LENGTH && EMAIL_FORMAT_RE.test(trimmed);\n}\n\nexport { isValidEmailFormat, MAX_EMAIL_LENGTH, EMAIL_FORMAT_RE };\n"]}
|
package/dist/LanguageTag.js.map
CHANGED
|
@@ -1 +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"}
|
|
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","sourcesContent":["/**\n * Single canonical language-tag implementation for backend + web.\n *\n * ## Provenance\n *\n * Converged from Durable-DAV-Router's `LanguageTag.ts` and Edge-Git's\n * `LanguageTag.ts`. The two are byte-identical — both were written to replace\n * the older `canonicalizeBackendLocaleTag` (shared) / `canonicalizeTag` (web\n * `i18n.ts`) split, which had drifted. Edge-Sonic has no such file (its web layer\n * uses the shared one directly), so it contributes nothing here beyond confirming\n * the shape.\n *\n * Import from here in both layers. This is generic BCP-47 casing, distinct from\n * `LocaleUtil`'s `canonicalizeLocaleTag`, which additionally titlecases a\n * four-letter script subtag for locale negotiation against a fixed table.\n */\nfunction canonicalizeLanguageTag(tag: string): string {\n const normalized = tag.trim().replaceAll('_', '-');\n const parts = normalized.split('-').filter(Boolean);\n if (parts.length === 0) return 'en';\n const language = (parts[0] ?? 'en').toLowerCase();\n if (parts.length === 1) return language;\n const rest = parts.slice(1).map((part) => (part.length === 2 ? part.toUpperCase() : part.toLowerCase()));\n return [language, ...rest].join('-');\n}\n\n/**\n * A BCP-47 language tag, canonicalized: `zh_TW`, `zh-tw`, and `zh-TW` all\n * canonicalize to `zh-TW`.\n */\ntype LanguageTag = string;\n\nexport { canonicalizeLanguageTag };\nexport type { LanguageTag };\n"]}
|
package/dist/LocaleUtil.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocaleUtil.js","sourceRoot":"","sources":["../src/LocaleUtil.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LocaleUtil.js","sourceRoot":"","sources":["../src/LocaleUtil.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Locale negotiation against a fixed support table.\n *\n * ## Provenance\n *\n * Converged from AWS-AccessBridge's, Mail-Meow's and Mail-Otter's\n * `LocaleUtil.ts`. The three share the same 12-locale table\n * (`en, de, fr, es, it, nl, pt, pl, ja, zh-CN, zh-TW, ko`) and the same\n * `isSupported`/`normalize`; Mail-Meow and Mail-Otter additionally carry\n * `negotiate`, `displayName` and `LOCALE_DISPLAY_NAMES`. The two fuller forms are\n * byte-identical and are kept — AWS is the subset.\n *\n * ## Design decision\n *\n * The kit kept the fuller Mail-Meow/Mail-Otter surface. `normalize` is the load-\n * bearing operation: it canonicalizes a tag, maps regional fallbacks toward the\n * supported table (a bare `zh` becomes `zh-CN`), and — distinct from the generic\n * `canonicalizeLanguageTag` — titlecases a four-letter script subtag so\n * `zh-hans-cn` canonicalizes correctly before negotiation. Non-negotiable input\n * falls back to `DEFAULT_LOCALE` rather than throwing; an Accept-Language header\n * is a hint, not a contract.\n */\nconst DEFAULT_LOCALE = 'en';\n\nconst SUPPORTED_LOCALES = ['en', 'de', 'fr', 'es', 'it', 'nl', 'pt', 'pl', 'ja', 'zh-CN', 'zh-TW', 'ko'] as const;\n\ntype SupportedLocale = (typeof SUPPORTED_LOCALES)[number];\n\nconst LOCALE_DISPLAY_NAMES: Record<SupportedLocale, string> = {\n en: 'English',\n de: 'Deutsch',\n fr: 'Français',\n es: 'Español',\n it: 'Italiano',\n nl: 'Nederlands',\n pt: 'Português',\n pl: 'Polski',\n ja: '日本語',\n 'zh-CN': '简体中文',\n 'zh-TW': '繁體中文',\n ko: '한국어',\n};\n\nfunction canonicalizeLocaleTag(tag: string): string {\n const normalized = tag.trim().replaceAll('_', '-');\n const parts = normalized.split('-').filter(Boolean);\n if (parts.length === 0) return '';\n const language = (parts[0] ?? '').toLowerCase();\n if (parts.length === 1) return language;\n const rest = parts.slice(1).map((part, index) => {\n if (index === parts.length - 2 && part.length === 4) {\n return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();\n }\n return part.length === 2 ? part.toUpperCase() : part.toLowerCase();\n });\n return [language, ...rest].join('-');\n}\n\nclass LocaleUtil {\n public static isSupported(locale: string | null | undefined): boolean {\n if (!locale || typeof locale !== 'string') return false;\n const canonical = canonicalizeLocaleTag(locale);\n return (SUPPORTED_LOCALES as readonly string[]).includes(canonical);\n }\n\n public static normalize(locale: string | null | undefined): SupportedLocale {\n if (!locale || typeof locale !== 'string') return DEFAULT_LOCALE;\n const canonical = canonicalizeLocaleTag(locale);\n if ((SUPPORTED_LOCALES as readonly string[]).includes(canonical)) {\n return canonical as SupportedLocale;\n }\n const base = canonical.split('-', 1)[0]?.toLowerCase() ?? '';\n if (base === 'zh') return 'zh-CN';\n const baseMatch = (SUPPORTED_LOCALES as readonly string[]).find((s) => s.toLowerCase() === base);\n if (baseMatch) return baseMatch as SupportedLocale;\n try {\n const negotiated = Intl.getCanonicalLocales(canonical);\n const primary = negotiated[0]?.split('-', 1)[0]?.toLowerCase() ?? '';\n const fallback = (SUPPORTED_LOCALES as readonly string[]).find((s) => s.toLowerCase() === primary);\n if (fallback) return fallback as SupportedLocale;\n } catch {\n // Ignore invalid tags and fall through to default.\n }\n return DEFAULT_LOCALE;\n }\n\n public static negotiate(preferred: string | null | undefined, fallback?: string | null): SupportedLocale {\n const primary = this.normalize(preferred);\n return primary === DEFAULT_LOCALE ? this.normalize(fallback) : primary;\n }\n\n public static displayName(locale: string | null | undefined): string {\n const normalized = this.normalize(locale);\n return LOCALE_DISPLAY_NAMES[normalized] ?? normalized;\n }\n}\n\nexport { LocaleUtil, DEFAULT_LOCALE, SUPPORTED_LOCALES, LOCALE_DISPLAY_NAMES };\nexport type { SupportedLocale };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PasswordFingerprint.js","sourceRoot":"","sources":["../src/PasswordFingerprint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,KAAK,UAAU,mBAAmB,CAAC,QAAgB;IACjD,OAAO,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"PasswordFingerprint.js","sourceRoot":"","sources":["../src/PasswordFingerprint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,KAAK,UAAU,mBAAmB,CAAC,QAAgB;IACjD,OAAO,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC","sourcesContent":["import { CryptoUtil } from './CryptoUtil';\n\n/**\n * A cheap, deterministic tag for a presented password.\n *\n * ## Provenance\n *\n * Taken from Durable-DAV's `packages/shared/src/utils/PasswordFingerprint.ts`\n * (the only repo that factored this). It is one unsalted SHA-256 that delegates\n * to `CryptoUtil.sha256Hex`.\n *\n * **Not a credential, and not a secret.** It is one unsalted SHA-256, so it is\n * exactly as crackable as the legacy unsalted digest it is sometimes confused\n * with — a rainbow table recovers it instantly, and two users who chose the same\n * password share a value. It exists to be a memo *key* and nothing else. Any\n * code that treats it as a password hash is wrong.\n *\n * ## Why it exists\n *\n * Password verification is memoized so a repeated request does not pay a PBKDF2\n * derivation again. The memo must distinguish \"this exact password was already\n * verified against this stored hash\" from \"someone presented a different password\n * for this username\". Keying on `username` alone would accept **any** password\n * for a recently-used username — a total authentication bypass. The lookup key\n * therefore includes this fingerprint: it makes the key specific to the password\n * actually presented, at the cost of one SHA-256 (microseconds) instead of one\n * PBKDF2 derivation (milliseconds, and on the Workers Free plan more than the\n * entire CPU budget).\n */\nasync function passwordFingerprint(password: string): Promise<string> {\n return CryptoUtil.sha256Hex(password);\n}\n\nexport { passwordFingerprint };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RemoteUrlPolicy.js","sourceRoot":"","sources":["../src/RemoteUrlPolicy.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RemoteUrlPolicy.js","sourceRoot":"","sources":["../src/RemoteUrlPolicy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,MAAM,qBAAqB,GAAG,IAAI,CAAC;AACnC,MAAM,aAAa,GAAG,CAAC,CAAC;AAExB;;GAEG;AACH,MAAM,qBAAqB,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,CAAU,CAAC;AAE3F;;GAEG;AACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,uBAAuB,EAAE,eAAe,EAAE,cAAc,CAAC,CAAC,CAAC;AAW3G,MAAM,sBAAuB,SAAQ,KAAK;IACxC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,2BAA2B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,KAAK,GAAG,GAAG;YAAE,OAAO,IAAI,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CAAC,MAAgB;IACrC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;IAC9B,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC;IAClD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,gBAAgB,CAAC,OAAe;IACvC,MAAM,MAAM,GAAG,kCAAkC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAChE,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACnD,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,UAAU,CAAC,UAAU,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,0CAA0C,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,GAAG,IAAI,CAAC,CAAC;AACnI,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,aAAa,CAAC,OAAe;IACpC,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACpC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACnD,6DAA6D;IAC7D,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1C,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,+CAA+C;IAC/C,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,OAAO,CAAC;AACxE,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,8BAA8B,CAAC,IAAY;IAClD,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9F,OAAO,CACL,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAClB,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC;QACpC,yEAAyE;QACzE,4EAA4E;QAC5E,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;QACrB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAC9D,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,IAAY,EAAE,YAA+B;IAClE,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;QACjC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC7C,IAAI,SAAS,KAAK,EAAE;YAAE,OAAO,KAAK,CAAC;QACnC,OAAO,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC;IACrF,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IACtB,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,IAAY;IACpC,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC;IAC7B,OAAO,GAAG,GAAG,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG;QAAE,GAAG,IAAI,CAAC,CAAC;IAChE,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,IAAY;IACnC,OAAO,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AACpE,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAS,uBAAuB,CAAC,QAAgB;IAC/C,MAAM,IAAI,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACtD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,eAAe,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAE/E,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAChC,OAAO,MAAM,KAAK,IAAI,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;IACnD,IAAI,8BAA8B,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACtD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,kBAAkB,CAAC,GAAY,EAAE,UAA4B,EAAE;IACtE,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,MAAM,IAAI,sBAAsB,CAAC,4BAA4B,CAAC,CAAC;IAC5F,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,OAAO,KAAK,EAAE;QAAE,MAAM,IAAI,sBAAsB,CAAC,uBAAuB,CAAC,CAAC;IAC9E,IAAI,OAAO,CAAC,MAAM,GAAG,qBAAqB;QAAE,MAAM,IAAI,sBAAsB,CAAC,6BAA6B,qBAAqB,aAAa,CAAC,CAAC;IAE9I,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,sBAAsB,CAAC,uCAAuC,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ;QAAE,MAAM,IAAI,sBAAsB,CAAC,0BAA0B,CAAC,CAAC;IAC5F,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE;QAAE,MAAM,IAAI,sBAAsB,CAAC,mEAAmE,CAAC,CAAC;IACtJ,IAAI,GAAG,CAAC,IAAI,KAAK,EAAE,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK;QAAE,MAAM,IAAI,sBAAsB,CAAC,2CAA2C,CAAC,CAAC;IAEzH,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IACxC,IAAI,IAAI,KAAK,EAAE;QAAE,MAAM,IAAI,sBAAsB,CAAC,+BAA+B,CAAC,CAAC;IACnF,IAAI,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,CAAC;QACpD,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;QAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QACd,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IAED,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,sBAAsB,CAAC,kBAAkB,IAAI,kBAAkB,CAAC,CAAC;IAC5G,KAAK,MAAM,MAAM,IAAI,qBAAqB,EAAE,CAAC;QAC3C,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,MAAM,IAAI,sBAAsB,CAAC,kBAAkB,IAAI,2BAA2B,CAAC,CAAC;IACjH,CAAC;IACD,IAAI,8BAA8B,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,sBAAsB,CAAC,kBAAkB,IAAI,+CAA+C,CAAC,CAAC;IAElJ,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,MAAM,KAAK,IAAI,IAAI,aAAa,CAAC,MAAM,CAAC;YAAE,MAAM,IAAI,sBAAsB,CAAC,kBAAkB,IAAI,0BAA0B,CAAC,CAAC;IACnI,CAAC;SAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAChC,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAAE,MAAM,IAAI,sBAAsB,CAAC,kBAAkB,IAAI,0BAA0B,CAAC,CAAC;IAC3H,CAAC;SAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,0EAA0E;QAC1E,MAAM,IAAI,sBAAsB,CAAC,kBAAkB,IAAI,oCAAoC,CAAC,CAAC;IAC/F,CAAC;IAED,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;IAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACd,OAAO,GAAG,CAAC,IAAI,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,kBAAkB,CAAC,OAAe,EAAE,QAAgB,EAAE,UAA4B,EAAE;IAC3F,IAAI,IAAS,CAAC;IACd,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,sBAAsB,CAAC,oCAAoC,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ;QAAE,MAAM,IAAI,sBAAsB,CAAC,gCAAgC,CAAC,CAAC;IACnG,4EAA4E;IAC5E,uDAAuD;IACvD,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACpE,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;QACf,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IACD,OAAO,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAY;IACrC,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG;SAC3D,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SAC5B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,aAAa,EACb,qBAAqB,EACrB,iBAAiB,GAClB,CAAC","sourcesContent":["/**\n * Egress policy and SSRF host predicates for user-supplied URLs.\n *\n * ## Provenance\n *\n * Merged from Durable-DAV's `packages/shared/src/net/RemoteUrlPolicy.ts` and the\n * `SsrfHosts.ts` of Durable-DAV-Router, Edge-Git and Edge-Sonic. The two were the\n * same problem solved twice: Durable-DAV's `RemoteUrlPolicy` is the full\n * validate-and-canonicalize policy (HTTPS-only, public-address-only, operator\n * allow-list, redirect re-validation); the Router/Edge-Git/Edge-Sonic\n * `SsrfHosts` are the lower-level \"is this host private?\" predicate the policy in\n * each repo leaned on. Canonical name is **`RemoteUrlPolicy`** (Durable-DAV's);\n * the host predicate it converges onto is exported as **`isPrivateOrInternalHost`**\n * (the common `isSsrfBlockedHost`-style composite from SsrfHosts).\n *\n * Scheduled replication / webhook delivery / git import turns a caller into\n * someone who can name a host this Worker connects to. Without a policy that is\n * server-side request forgery against Cloudflare's own egress: the metadata\n * service, the loopback interface, and anything reachable on a private network the\n * Worker happens to share.\n *\n * ## Design decisions\n *\n * - **The octet-accurate IP checks win over SsrfHosts' naive string prefixes.**\n * SsrfHosts' `isBlockedIpv6Host` matched `startsWith('fc')`/`'fd')`, which also\n * matches a *hostname* like `fcb.example.com`; Durable-DAV's `isBlockedIpv6` /\n * `isBlockedIpv4` parse the address (and decode IPv4-mapped IPv6) instead. The\n * kit keeps the rigorous form for both the URL policy and the exported\n * predicate, so there is one correct answer rather than two that drift.\n * - **`isPrivateOrInternalHost` is strictly safer than either source.** It folds\n * in SsrfHosts' raw-hostname handling (bare-integer/octal/hex/`0x`-dotted forms,\n * trailing-dot and bracket stripping, localhost names and `.local`/`.internal`/\n * `.home.arpa` suffixes) that Durable-DAV's URL-path checks could skip because\n * `new URL` had already canonicalized the host. A public IPv6 literal is allowed\n * exactly as `normalizeRemoteUrl` allows it; every private/loopback/unique-local/\n * link-local/zone/mapped form is refused.\n *\n * ## Known gap, stated rather than hidden\n *\n * DNS rebinding is not covered. A host that resolves to a public address at\n * validation time and a private one when the connection is made defeats every\n * check here. Closing it needs a resolution-aware fetch, which the platform does\n * not expose to a Worker. The upheld rule for such a deployment is to pin an\n * origin allow-list.\n */\n\nconst MAX_REMOTE_URL_LENGTH = 2048;\nconst MAX_REDIRECTS = 3;\n\n/**\n * Host suffixes that never name a real internet peer.\n */\nconst BLOCKED_HOST_SUFFIXES = ['.localhost', '.local', '.internal', '.home.arpa'] as const;\n\n/**\n * Hostnames that resolve inward by definition.\n */\nconst BLOCKED_HOSTNAMES = new Set(['localhost', 'localhost.localdomain', 'ip6-localhost', 'ip6-loopback']);\n\ntype UrlPolicyOptions = {\n /**\n * Hostnames (exact, or `.suffix` form) permitted regardless of the address\n * rules. Only ever populated from operator configuration, never from the\n * request body.\n */\n allowedHosts?: readonly string[];\n};\n\nclass RemoteUrlRejectedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'RemoteUrlRejectedError';\n }\n}\n\nfunction isIpv4Literal(host: string): boolean {\n return /^\\d{1,3}(?:\\.\\d{1,3}){3}$/.test(host);\n}\n\nfunction ipv4Octets(host: string): number[] | null {\n const parts = host.split('.');\n if (parts.length !== 4) return null;\n const octets: number[] = [];\n for (const part of parts) {\n if (!/^\\d{1,3}$/.test(part)) return null;\n const value = Number(part);\n if (value > 255) return null;\n octets.push(value);\n }\n return octets;\n}\n\n/**\n * Is this IPv4 literal in a range a Worker must never reach?\n *\n * `0.0.0.0/8` and `169.254.0.0/16` matter as much as RFC 1918: the first is\n * \"this host\" on Linux, the second is the cloud metadata endpoint.\n */\nfunction isBlockedIpv4(octets: number[]): boolean {\n const [a = 0, b = 0] = octets;\n if ([0, 10, 127].includes(a)) return true;\n if (a === 169 && b === 254) return true;\n if (a === 172 && b >= 16 && b <= 31) return true;\n if (a === 192 && b === 168) return true;\n if (a === 100 && b >= 64 && b <= 127) return true;\n return false;\n}\n\n/**\n * Decode an IPv4-mapped IPv6 address back into its four octets, or null.\n *\n * Both spellings have to be handled. `new URL` canonicalizes\n * `https://[::ffff:10.0.0.1]/` to the hex form `[::ffff:a00:1]`, so a check\n * written only against the dotted text never fires — and that address connects to\n * a private network.\n */\nfunction mappedIpv4Octets(literal: string): number[] | null {\n const dotted = /^::ffff:\\d{1,3}(?:\\.\\d{1,3}){3}$/.exec(literal);\n const dottedText = literal.slice('::ffff:'.length);\n if (dotted !== null) return ipv4Octets(dottedText);\n const hex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(literal);\n if (!hex?.[1] || !hex[2]) return null;\n const high = Number.parseInt(hex[1], 16);\n const low = Number.parseInt(hex[2], 16);\n return !Number.isFinite(high) || !Number.isFinite(low) ? null : [(high >> 8) & 0xff, high & 0xff, (low >> 8) & 0xff, low & 0xff];\n}\n\n/**\n * Is this IPv6 literal private, loopback, or an IPv4 address in disguise? `literal`\n * is the **unbracketed** inner form (e.g. `::1`, `fe80::1`).\n *\n * The last case is the one that matters: `::ffff:127.0.0.1` is a perfectly valid\n * URL and connects to loopback, so the embedded IPv4 must be re-checked rather\n * than the literal waved through because it \"is\" IPv6.\n */\nfunction isBlockedIpv6(literal: string): boolean {\n const lower = literal.toLowerCase();\n if (lower === '::' || lower === '::1') return true;\n // Zone ids (`fe80::1%eth0`) name a local interface directly.\n if (lower.includes('%')) return true;\n const mapped = mappedIpv4Octets(lower);\n if (mapped !== null) return isBlockedIpv4(mapped);\n const head = lower.split(':', 1)[0] ?? '';\n if (head === '') return false;\n const group = Number.parseInt(head.padStart(4, '0').slice(0, 4), 16);\n if (!Number.isFinite(group)) return false;\n // fc00::/7 unique-local, fe80::/10 link-local.\n return (group & 0xfe_00) === 0xfc_00 || (group & 0xff_c0) === 0xfe_80;\n}\n\n/**\n * Does this host name a numeric address in a non-canonical spelling? The strict\n * superset of Durable-DAV's `looksLikeObfuscatedNumericHost` and SsrfHosts'\n * `isEncodedNumericHost`, for the raw-hostname predicate.\n *\n * `2130706433`, `0177.0.0.1`, `0x7f000001` and `0x7f.1` all name `127.0.0.1`.\n * Through `new URL` these arrive already canonicalized (so `isBlockedIpv4` catches\n * them); a hostname handed to `isPrivateOrInternalHost` need not have gone through\n * `URL`, so a bare integer/octal/hex form is caught here directly. A legitimate\n * internet hostname is never all-digits, so over-blocking is not a risk.\n */\nfunction looksLikeObfuscatedNumericHost(host: string): boolean {\n if (isIpv4Literal(host) || host.startsWith('[') || !/^[0-9a-fx.]+$/i.test(host)) return false;\n return (\n /^0x[0-9a-f]+$/i.test(host) ||\n /^\\d+$/.test(host) ||\n /^0[0-7]+(?:\\.0[0-7]+)*$/.test(host) ||\n // An all-digits-and-dots host that is not a canonical dotted-quad — e.g.\n // `0177.0.0.1` or `0200.0250.0001.0001` — is an obfuscated numeric address.\n /^[\\d.]+$/.test(host) ||\n host.split('.').some((group) => /^0x[0-9a-f]+$/i.test(group))\n );\n}\n\nfunction hostIsAllowed(host: string, allowedHosts: readonly string[]): boolean {\n const lower = host.toLowerCase();\n return allowedHosts.some((entry) => {\n const candidate = entry.trim().toLowerCase();\n if (candidate === '') return false;\n return candidate.startsWith('.') ? lower.endsWith(candidate) : lower === candidate;\n });\n}\n\n/**\n * Strip one enclosing `[`…`]` pair (an IPv6 literal's URL brackets).\n */\nfunction stripBrackets(host: string): string {\n const h = host.trim();\n return h.startsWith('[') && h.endsWith(']') ? h.slice(1, -1) : h;\n}\n\n/**\n * Strip a bracketed wrapper and every trailing root-label dot.\n *\n * A fully-qualified name ends in a root label (`example.com.`) and `new URL` keeps\n * it; RFC 4918 §9.1.2 clients vary on sending it, so the canonical form is compared.\n */\nfunction stripTrailingDot(host: string): string {\n const unbracketed = stripBrackets(host);\n let end = unbracketed.length;\n while (end > 0 && unbracketed.charAt(end - 1) === '.') end -= 1;\n return unbracketed.slice(0, end);\n}\n\n/**\n * Host names that mean \"this machine or a local suffix\", not an internet peer.\n */\nfunction isLocalhostName(host: string): boolean {\n return BLOCKED_HOSTNAMES.has(host) || host.endsWith('.localhost');\n}\n\n/**\n * True when a URL host resolves to this machine or a private network.\n *\n * Intended for user-supplied URLs that the server will subsequently fetch. Such a\n * URL turns the process into a proxy into its own network: without this, a\n * user-supplied `baseUrl` can point at cloud metadata, a database host, or a\n * loopback admin port, and the response is readable by the caller.\n *\n * Encoded-numeric hosts are included because `http://2130706433/` and\n * `http://0177.0.0.1/` are ordinary-looking strings that name `127.0.0.1` after\n * parsing.\n *\n * A *strict, safer* predicate: an empty host, any private/loopback/link-local/\n * unique-local/mapped form, any localhost/suffix name, any obfuscated numeric\n * form, and any `:`-bearing host that is not a public IPv6 literal all return\n * true. It is a *syntactic* check — a public hostname can still resolve to a\n * private address (DNS rebinding) — so a hard-guarantee deployment additionally\n * pins an allow-list (see the file header).\n */\nfunction isPrivateOrInternalHost(hostname: string): boolean {\n const host = stripTrailingDot(hostname).toLowerCase();\n if (host.length === 0) return true;\n if (isLocalhostName(host)) return true;\n if (BLOCKED_HOST_SUFFIXES.some((suffix) => host.endsWith(suffix))) return true;\n\n if (isIpv4Literal(host)) {\n const octets = ipv4Octets(host);\n return octets === null || isBlockedIpv4(octets);\n }\n if (host.includes(':')) return isBlockedIpv6(host);\n if (looksLikeObfuscatedNumericHost(host)) return true;\n return false;\n}\n\n/**\n * Validate and canonicalise a remote URL.\n *\n * Throws `RemoteUrlRejectedError` with a message meant for the owner: every\n * rejection here is a configuration mistake or an attack, and saying which one\n * is what makes the difference between a fixable setup error and a support\n * ticket. Query and fragment are dropped — a WebDAV base URL has no use for\n * either, and keeping them would let `?a=b` smuggle a second meaning past the\n * path checks the sync engine does.\n */\nfunction normalizeRemoteUrl(raw: unknown, options: UrlPolicyOptions = {}): string {\n if (typeof raw !== 'string') throw new RemoteUrlRejectedError('remoteUrl must be a string');\n const trimmed = raw.trim();\n if (trimmed === '') throw new RemoteUrlRejectedError('remoteUrl is required');\n if (trimmed.length > MAX_REMOTE_URL_LENGTH) throw new RemoteUrlRejectedError(`remoteUrl must be at most ${MAX_REMOTE_URL_LENGTH} characters`);\n\n let url: URL;\n try {\n url = new URL(trimmed);\n } catch {\n throw new RemoteUrlRejectedError('remoteUrl is not a valid absolute URL');\n }\n\n if (url.protocol !== 'https:') throw new RemoteUrlRejectedError('remoteUrl must use https');\n if (url.username !== '' || url.password !== '') throw new RemoteUrlRejectedError('remoteUrl must not embed credentials; use the auth fields instead');\n if (url.port !== '' && url.port !== '443') throw new RemoteUrlRejectedError('remoteUrl must use the default https port');\n\n const host = url.hostname.toLowerCase();\n if (host === '') throw new RemoteUrlRejectedError('remoteUrl must include a host');\n if (hostIsAllowed(host, options.allowedHosts ?? [])) {\n url.search = '';\n url.hash = '';\n return url.href;\n }\n\n if (BLOCKED_HOSTNAMES.has(host)) throw new RemoteUrlRejectedError(`remoteUrl host ${host} is not routable`);\n for (const suffix of BLOCKED_HOST_SUFFIXES) {\n if (host.endsWith(suffix)) throw new RemoteUrlRejectedError(`remoteUrl host ${host} is not a public hostname`);\n }\n if (looksLikeObfuscatedNumericHost(host)) throw new RemoteUrlRejectedError(`remoteUrl host ${host} is a numeric address in a non-canonical form`);\n\n if (isIpv4Literal(host)) {\n const octets = ipv4Octets(host);\n if (octets === null || isBlockedIpv4(octets)) throw new RemoteUrlRejectedError(`remoteUrl host ${host} is not a public address`);\n } else if (host.startsWith('[')) {\n if (isBlockedIpv6(host.slice(1, -1))) throw new RemoteUrlRejectedError(`remoteUrl host ${host} is not a public address`);\n } else if (!host.includes('.')) {\n // A single-label name can only be resolved through a local search domain.\n throw new RemoteUrlRejectedError(`remoteUrl host ${host} is not a fully qualified hostname`);\n }\n\n url.search = '';\n url.hash = '';\n return url.href;\n}\n\n/**\n * Re-validate the target of a redirect.\n *\n * Called for every hop rather than once at the start. Validating the configured\n * URL and then following `Location` unchecked is a classic TOCTOU: the first\n * hop is public, the second is `169.254.169.254`, and the policy has already\n * returned by then.\n */\nfunction resolveRedirectUrl(baseUrl: string, location: string, options: UrlPolicyOptions = {}): string {\n let next: URL;\n try {\n next = new URL(location, baseUrl);\n } catch {\n throw new RemoteUrlRejectedError('redirect target is not a valid URL');\n }\n if (next.protocol !== 'https:') throw new RemoteUrlRejectedError('redirect target must use https');\n // Same host: no need to re-run the whole policy, and a redirect back to the\n // origin's own host is the overwhelmingly common case.\n if (next.host.toLowerCase() === new URL(baseUrl).host.toLowerCase()) {\n next.search = '';\n next.hash = '';\n return next.href;\n }\n return normalizeRemoteUrl(next.href, options);\n}\n\nfunction parseAllowedHosts(raw: unknown): string[] {\n return typeof raw !== 'string' || raw.trim() === '' ? [] : raw\n .split(',')\n .map((entry) => entry.trim())\n .filter((entry) => entry !== '');\n}\n\nexport {\n normalizeRemoteUrl,\n resolveRedirectUrl,\n parseAllowedHosts,\n isPrivateOrInternalHost,\n stripBrackets,\n stripTrailingDot,\n RemoteUrlRejectedError,\n MAX_REMOTE_URL_LENGTH,\n MAX_REDIRECTS,\n BLOCKED_HOST_SUFFIXES,\n BLOCKED_HOSTNAMES,\n};\nexport type { UrlPolicyOptions };\n"]}
|
package/dist/Result.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Result.js","sourceRoot":"","sources":["../src/Result.ts"],"names":[],"mappings":"AAmBA,SAAS,EAAE,CAAI,KAAQ;IACrB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAC7B,CAAC;AAED,SAAS,GAAG,CAAI,KAAQ;IACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC9B,CAAC;AAED,SAAS,IAAI,CAAO,MAAoB;IACtC,OAAO,MAAM,CAAC,EAAE,CAAC;AACnB,CAAC;AAED,SAAS,SAAS,CAAU,MAAoB,EAAE,EAAmB;IACnE,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AACnD,CAAC;AAED,SAAS,UAAU,CAAe,MAAoB;IACpD,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,MAAM,CAAC,KAAK,CAAC;IACnC,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB,CAAC;AAED,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"Result.js","sourceRoot":"","sources":["../src/Result.ts"],"names":[],"mappings":"AAmBA,SAAS,EAAE,CAAI,KAAQ;IACrB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAC7B,CAAC;AAED,SAAS,GAAG,CAAI,KAAQ;IACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC9B,CAAC;AAED,SAAS,IAAI,CAAO,MAAoB;IACtC,OAAO,MAAM,CAAC,EAAE,CAAC;AACnB,CAAC;AAED,SAAS,SAAS,CAAU,MAAoB,EAAE,EAAmB;IACnE,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AACnD,CAAC;AAED,SAAS,UAAU,CAAe,MAAoB;IACpD,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,MAAM,CAAC,KAAK,CAAC;IACnC,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB,CAAC;AAED,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC","sourcesContent":["/**\n * Minimal `Result` type for explicit error handling without exceptions.\n *\n * ## Provenance\n *\n * Converged from Edge-Git's `Result.ts` and ChordDHT-Tracker's `Result.ts`. The\n * two are byte-identical apart from a doc comment (Edge-Git added the header);\n * ChordDHT is the origin, Edge-Git the copy. Mail-Otter and the DAV repos are\n * the kind of repo this was ported *to*, so Edge-Git's documented form is kept\n * verbatim.\n *\n * When two variants are identical there is nothing stricter to choose; the\n * supported shape is `{ ok: true, value }` / `{ ok: false, error }` frozen at the\n * type level rather than thrown.\n */\ntype Ok<T> = { readonly ok: true; readonly value: T };\ntype Err<E> = { readonly ok: false; readonly error: E };\ntype Result<T, E = Error> = Ok<T> | Err<E>;\n\nfunction ok<T>(value: T): Result<T, never> {\n return { ok: true, value };\n}\n\nfunction err<E>(error: E): Result<never, E> {\n return { ok: false, error };\n}\n\nfunction isOk<T, E>(result: Result<T, E>): result is Ok<T> {\n return result.ok;\n}\n\nfunction mapResult<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> {\n return result.ok ? ok(fn(result.value)) : result;\n}\n\nfunction getOrThrow<T, E = Error>(result: Result<T, E>): T {\n if (!result.ok) throw result.error;\n return result.value;\n}\n\nexport { err, getOrThrow, isOk, mapResult, ok };\nexport type { Err, Ok, Result };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubrequestMeter.js","sourceRoot":"","sources":["../src/SubrequestMeter.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SubrequestMeter.js","sourceRoot":"","sources":["../src/SubrequestMeter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What one Worker invocation may spend, counted.\n *\n * ## Provenance\n *\n * Taken from Edge-Sonic's `packages/shared/src/utils/SubrequestMeter.ts`. It is\n * the only subrequest-accounting helper among the nine repos and the most\n * heavily measured; it is reproduced with its code unchanged and its prose\n * generalised away from Edge-Sonic's own layer names and issue docs. No other\n * repo carries a competing copy.\n *\n * ### Why this exists at all\n *\n * Cloudflare counts a **subrequest** per invocation and kills the invocation when\n * the count is exceeded — it does not throw something a `catch` can see, so the\n * whole invocation dies with `Too many subrequests by single Worker invocation`\n * and everything after the ceiling is lost. The only defence is to never issue the\n * request that crosses it.\n *\n * A subrequest is not only `fetch`. The platform's own D1 limits page states:\n *\n * > Queries per Worker invocation (read subrequest limits) — 1000 (Workers Paid) / **50 (Free)**\n *\n * So a D1 query is a subrequest, and on the Free plan a `KV` read, a Durable\n * Object RPC and a Secrets Store read are subrequests too. Budgeting **only**\n * `fetch` shipped a real bug: a scan chunk cost ~40 counted requests and ~200\n * uncounted ones, every chunk died at the ceiling, and the scan only ever\n * \"finished\" because each dead invocation left a little progress behind.\n *\n * ### Why the count is pessimistic\n *\n * The platform does not say whether a D1 `batch()` of N statements costs 1 or N.\n * The D1 page counts *queries*, which reads as N; the Workers page counts\n * subrequests, which reads as 1. So the meter charges **one per statement**, which\n * is the reading that cannot kill an invocation. If the friendlier reading turns\n * out to be right, the meter over-counts and a chunk does slightly less work per\n * poll — a cost in throughput, never a correctness or availability problem. That\n * asymmetry is the whole reason to choose it: an over-count is a slow scan, an\n * under-count is a dead one.\n *\n * Measured on a Free account on 2026-10-05 there are two budgets: external `fetch`\n * is 50 and **D1 statements are 1,000**, in a separate pool — 1,000 D1 statements\n * and 50 outbound requests in one invocation survive together. A D1 overrun\n * *throws* and an ordinary `catch` sees it; the external ceiling does not. This\n * counter's single ceiling covers both, which is the conservative choice: bounding\n * both by the resource that cannot be handled when it runs out is the choice that\n * cannot take the product down. That is not a licence to catch and continue — a\n * swallowed limit is still a limit.\n *\n * ### Why it is an interface and not a class everywhere\n *\n * Charge points below the layer that decides the budget accept the **interface**\n * as a constructor dependency, and the composition root hands them the one counter\n * for the invocation. Nothing that only spends subrequests constructs a meter.\n */\n\n/**\n * What spent the subrequests, for the operator-facing breakdown.\n *\n * `d1` is separated from `kv` and `fetch` because the three have different\n * remedies: a chunk that ran out on `fetch` needs a bigger request budget on a\n * Paid plan, and one that ran out on `d1` needs a smaller page size. Collapsing\n * them into a single number is how the ceiling became invisible in the first\n * place.\n */\ntype SubrequestKind = 'd1' | 'kv' | 'fetch' | 'rpc' | 'secret';\n\nconst SUBREQUEST_KINDS: readonly SubrequestKind[] = ['d1', 'kv', 'fetch', 'rpc', 'secret'];\n\n/**\n * The counter every charge point writes to.\n *\n * A method rather than a mutable field so a charge point can be handed the\n * *interface* and the test that owns the ceiling keeps the only real instance.\n * `charge` is the whole write surface; `spent` and `byKind` are the only read\n * surface a charge point needs.\n */\ninterface SubrequestMeter {\n /**\n * Record `count` subrequests issued.\n *\n * Never throws and never refuses. A meter that could reject would turn \"the\n * budget ran out\" into an error at a charge point deep inside a DAO, which is\n * the one place that cannot afford to decide anything — the decision belongs\n * *before* the work, in `canAfford`.\n */\n charge(count?: number, kind?: SubrequestKind): void;\n /**\n * Subrequests issued so far in this invocation.\n */\n readonly spent: number;\n /**\n * The ceiling this counter enforces, or `Infinity` when it enforces none.\n */\n readonly ceiling: number;\n /**\n * How many more fit, floored at zero.\n */\n readonly remaining: number;\n /**\n * Whether the ceiling has been reached.\n */\n readonly exhausted: boolean;\n /**\n * Whether `count` more would still fit.\n */\n canAfford(count?: number): boolean;\n /**\n * Lower this meter's effective ceiling for the current unit of work. Never\n * raises it — a narrower budget may only tighten the platform's ceiling, so a\n * caller asking for more than the platform allows is clamped rather than\n * trusted. The same asymmetry as everywhere else here: an over-count costs\n * throughput, an under-count costs an invocation.\n */\n setCeiling(limit: number): void;\n}\n\n/**\n * One counter per Worker invocation.\n *\n * `reset()` rather than a fresh instance per chunk because the counter is owned by\n * the **request scope**, which is created once per invocation: a chunk does not own\n * the budget, it borrows the invocation's. Constructing a new counter per chunk\n * would be a second place that decides what the ceiling is.\n */\nclass SubrequestCounter implements SubrequestMeter {\n private counts: number = 0;\n\n /**\n * Spend per kind, so a result can report *what* ran out rather than only that\n * something did. A single total is what made this ceiling un-diagnosable: the\n * operator saw \"paused\" and the possible causes have different fixes.\n */\n private readonly byKindSpent: Record<SubrequestKind, number> = { d1: 0, kv: 0, fetch: 0, rpc: 0, secret: 0 };\n /**\n * The platform's ceiling, or a narrower one `setCeiling` imposed for the current\n * unit of work. Restored to `limit` by `reset()`, so a narrowed ceiling cannot\n * leak past the chunk that asked for it.\n */\n private effective: number;\n\n constructor(private readonly limit: number = Infinity) {\n this.effective = limit;\n }\n\n public charge(count = 1, kind: SubrequestKind = 'd1'): void {\n if (count <= 0) return;\n this.counts += count;\n this.byKindSpent[kind] += count;\n }\n\n public get spent(): number {\n return this.counts;\n }\n\n /**\n * The **effective** ceiling: the platform's, or a narrower one a caller imposed.\n */\n public get ceiling(): number {\n return this.effective;\n }\n\n public get remaining(): number {\n if (this.effective === Infinity) return Infinity;\n return Math.max(0, this.effective - this.counts);\n }\n\n public get exhausted(): boolean {\n return this.counts >= this.effective;\n }\n\n public canAfford(count = 1): boolean {\n return this.counts + count <= this.effective;\n }\n\n public setCeiling(limit: number): void {\n // An unmetered counter stays unmetered: a ceiling of `Infinity` cannot be\n // lowered to a finite one, because the callers that would impose one are the\n // *production* ones and a test double asking for a bound must not start\n // refusing statements.\n if (!Number.isFinite(this.effective) || !Number.isFinite(limit)) return;\n this.effective = Math.max(0, Math.min(this.effective, Math.floor(limit)));\n }\n\n /**\n * Zero the count and restore the platform's ceiling.\n *\n * One method rather than a public `counts` field so \"start measuring again\" is a\n * named operation, and so the per-kind breakdown cannot drift out of step with\n * the total — exactly the kind of second-answer defect this file exists to\n * prevent. The ceiling is **restored**, not kept: a narrowed ceiling belongs to\n * the unit of work that asked for it.\n */\n public reset(): void {\n this.counts = 0;\n this.effective = this.limit;\n for (const kind of SUBREQUEST_KINDS) this.byKindSpent[kind] = 0;\n }\n\n /**\n * Spend per kind, as a plain object. A copy, so a caller cannot reach in and\n * change the totals the operator is shown.\n */\n public breakdown(): Record<SubrequestKind, number> {\n return { ...this.byKindSpent };\n }\n}\n\n/**\n * A meter that enforces nothing, for a caller that has not been given one.\n *\n * `Infinity` rather than a small number, because the alternative is a default\n * ceiling that a test would satisfy by accident — the failure this file is about\n * is a path that spends nothing because nothing was watching it, and a limit of 50\n * would hide that behind a passing assertion.\n */\nconst UNMETERED_SUBREQUESTS: SubrequestMeter = new SubrequestCounter(Infinity);\n\n/**\n * What an invocation spent, broken down.\n *\n * A total alone is what made this ceiling undiagnosable. An operator whose scan\n * keeps pausing was told \"paused\" and nothing else, while the causes have\n * different fixes.\n */\ninterface SubrequestSpend extends Record<SubrequestKind, number> {\n /**\n * Every subrequest spent, whatever its kind. The number the ceiling is enforced\n * against.\n */\n readonly total: number;\n}\n\n/**\n * Flatten a meter's breakdown into a report, total included.\n *\n * A function rather than a method on the counter so the *shape* the rest of the\n * system passes around — including the zeroes for kinds that spent nothing — is\n * built in one place. A caller that assembled it by hand would omit an absent kind,\n * and the operator surface would render a missing field as a missing measurement\n * rather than as `0`.\n */\nfunction subrequestSpend(byKind: Record<SubrequestKind, number>, total: number): SubrequestSpend {\n return { total, d1: byKind.d1, kv: byKind.kv, fetch: byKind.fetch, rpc: byKind.rpc, secret: byKind.secret };\n}\n\n/**\n * Nothing spent, for a code path that did no work — so a zero report is a\n * *measurement* rather than an absent field.\n */\nconst NO_SUBREQUESTS_SPENT: SubrequestSpend = subrequestSpend({ d1: 0, kv: 0, fetch: 0, rpc: 0, secret: 0 }, 0);\n\nexport { SubrequestCounter, UNMETERED_SUBREQUESTS, SUBREQUEST_KINDS, subrequestSpend, NO_SUBREQUESTS_SPENT };\nexport type { SubrequestMeter, SubrequestKind, SubrequestSpend };\n"]}
|
package/dist/TimeZoneUtil.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeZoneUtil.js","sourceRoot":"","sources":["../src/TimeZoneUtil.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TimeZoneUtil.js","sourceRoot":"","sources":["../src/TimeZoneUtil.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Time-zone validation and wall-clock helpers.\n *\n * ## Provenance\n *\n * Taken from Mail-Otter's `TimeZoneUtil.ts` (the only repo that factored the\n * zone-local day start behind a helper). It is well-documented and IANA-correct;\n * no other repo carries a competing copy, so it is kept with one fix.\n *\n * ## Design decision\n *\n * Mail-Otter's `normalize` used `this.isValid(timeZone) ? (timeZone as string).trim() : …`,\n * a type-cast to paper over the fact that `isValid` returns `boolean` and so\n * does not narrow `string | null | undefined`. The kit bans that pattern (no\n * non-null assertions, no `as`-laundering), so the runtime check is a module-level\n * **type guard** and `normalize` runs on the narrowed value. Same behaviour, no\n * cast.\n *\n * `getLocalDayStartUnixSeconds` keeps the two-pass DST handling and the warning\n * not to build it with `new Date('YYYY-MM-DDT00:00:00')` — a zone-less date-time\n * string parses in the runtime's zone, which is always UTC in Workers, silently\n * ignoring `timeZone` entirely.\n */\nconst DEFAULT_TIME_ZONE = 'UTC';\n\nconst WALL_CLOCK_FORMAT: Intl.DateTimeFormatOptions = {\n hour12: false,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n};\n\n/**\n * A run-time check that narrows to `string`, so callers do not have to cast.\n *\n * `new Intl.DateTimeFormat` throws a `RangeError` on an unknown zone; the guard\n * catches it and answers `false` for `null`/`undefined`/non-strings in one place.\n */\nfunction isTimeZoneString(value: string | null | undefined): value is string {\n if (!value || typeof value !== 'string') return false;\n const trimmed = value.trim();\n if (trimmed === '') return false;\n // Trim-then-validate, so `normalize`'s `.trim()` is load-bearing: Mail-Otter's\n // guard validated the *untrimmed* string, so a whitespace-padded IANA zone\n // threw in `Intl` and silently fell back to UTC. A padded zone is a typo, not an\n // unknown zone, so it is trimmed and accepted rather than defaulted.\n try {\n new Intl.DateTimeFormat('en-US', { timeZone: trimmed });\n return true;\n } catch {\n return false;\n }\n}\n\nclass TimeZoneUtil {\n public static isValid(timeZone: string | null | undefined): boolean {\n return isTimeZoneString(timeZone);\n }\n\n public static normalize(timeZone: string | null | undefined): string {\n return isTimeZoneString(timeZone) ? timeZone.trim() : DEFAULT_TIME_ZONE;\n }\n\n public static todayInZone(timeZone: string | null | undefined, now: Date = new Date()): string {\n const zone: string = this.normalize(timeZone);\n return new Intl.DateTimeFormat('en-CA', { timeZone: zone, year: 'numeric', month: '2-digit', day: '2-digit' }).format(now);\n }\n\n /**\n * Unix seconds of local midnight for the calendar day containing `now`.\n *\n * Two passes are needed because the zone offset depends on the instant: read\n * the wall clock in the target zone, treat that as UTC to derive the offset,\n * then re-anchor local midnight with the offset. The offset is sampled at\n * `now` rather than at the target midnight, which is exact except within a\n * few hours of a DST transition — irrelevant for a 24-hour window.\n *\n * Do NOT build this with `new Date('YYYY-MM-DDT00:00:00')`. A date-time\n * string with no zone designator parses in the *runtime's* zone, and the\n * Workers runtime is always UTC, which silently ignores `timeZone` entirely.\n *\n * An unknown zone falls back to UTC rather than throwing.\n */\n public static getLocalDayStartUnixSeconds(now: Date, timeZone: string | null | undefined): number {\n const zone: string = this.normalize(timeZone);\n const parts = new Intl.DateTimeFormat('en-CA', { timeZone: zone, ...WALL_CLOCK_FORMAT }).formatToParts(now);\n const part = (type: Intl.DateTimeFormatPartTypes): string => parts.find((p) => p.type === type)?.value ?? '0';\n const year = Number(part('year'));\n const month = Number(part('month'));\n const day = Number(part('day'));\n // Some ICU builds report midnight as hour 24 under `hour12: false`.\n const hour = Number(part('hour')) % 24;\n const minute = Number(part('minute'));\n const second = Number(part('second'));\n const wallClockAsUtcMs = Date.UTC(year, month - 1, day, hour, minute, second);\n const zoneOffsetMs = wallClockAsUtcMs - now.getTime();\n return Math.floor((Date.UTC(year, month - 1, day, 0, 0, 0) - zoneOffsetMs) / 1000);\n }\n}\n\nexport { TimeZoneUtil, DEFAULT_TIME_ZONE };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimestampUtil.js","sourceRoot":"","sources":["../src/TimestampUtil.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAc,MAAM,SAAS,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,aAAa;IACjB;;;;;OAKG;IACI,MAAM,CAAC,qCAAqC,CAAC,QAAe,YAAY;QAC7E,OAAO,KAAK,CAAC,GAAG,EAAE,CAAC;IACrB,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,gCAAgC,CAAC,QAAe,YAAY;QACxE,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IACxC,CAAC;IAEM,MAAM,CAAC,UAAU,CAAC,SAAiB,EAAE,OAAe;QACzD,OAAO,SAAS,GAAG,OAAO,GAAG,EAAE,CAAC;IAClC,CAAC;IAEM,MAAM,CAAC,QAAQ,CAAC,SAAiB,EAAE,KAAa;QACrD,OAAO,SAAS,GAAG,KAAK,GAAG,EAAE,GAAG,EAAE,CAAC;IACrC,CAAC;IAEM,MAAM,CAAC,OAAO,CAAC,SAAiB,EAAE,IAAY;QACnD,OAAO,SAAS,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IACzC,CAAC;IAEM,MAAM,CAAC,eAAe,CAAC,SAAiB,EAAE,OAAe;QAC9D,OAAO,SAAS,GAAG,OAAO,GAAG,EAAE,CAAC;IAClC,CAAC;IAEM,MAAM,CAAC,YAAY,CAAC,SAAiB,EAAE,IAAY;QACxD,OAAO,SAAS,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IACzC,CAAC;IAEM,MAAM,CAAC,kCAAkC,CAAC,SAAiB;QAChE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1D,CAAC;CACF;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"TimestampUtil.js","sourceRoot":"","sources":["../src/TimestampUtil.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAc,MAAM,SAAS,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,aAAa;IACjB;;;;;OAKG;IACI,MAAM,CAAC,qCAAqC,CAAC,QAAe,YAAY;QAC7E,OAAO,KAAK,CAAC,GAAG,EAAE,CAAC;IACrB,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,gCAAgC,CAAC,QAAe,YAAY;QACxE,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IACxC,CAAC;IAEM,MAAM,CAAC,UAAU,CAAC,SAAiB,EAAE,OAAe;QACzD,OAAO,SAAS,GAAG,OAAO,GAAG,EAAE,CAAC;IAClC,CAAC;IAEM,MAAM,CAAC,QAAQ,CAAC,SAAiB,EAAE,KAAa;QACrD,OAAO,SAAS,GAAG,KAAK,GAAG,EAAE,GAAG,EAAE,CAAC;IACrC,CAAC;IAEM,MAAM,CAAC,OAAO,CAAC,SAAiB,EAAE,IAAY;QACnD,OAAO,SAAS,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IACzC,CAAC;IAEM,MAAM,CAAC,eAAe,CAAC,SAAiB,EAAE,OAAe;QAC9D,OAAO,SAAS,GAAG,OAAO,GAAG,EAAE,CAAC;IAClC,CAAC;IAEM,MAAM,CAAC,YAAY,CAAC,SAAiB,EAAE,IAAY;QACxD,OAAO,SAAS,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IACzC,CAAC;IAEM,MAAM,CAAC,kCAAkC,CAAC,SAAiB;QAChE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1D,CAAC;CACF;AAED,OAAO,EAAE,aAAa,EAAE,CAAC","sourcesContent":["import { SYSTEM_CLOCK, type Clock } from './Clock';\n\n/**\n * Unix timestamps, in seconds and milliseconds.\n *\n * ## Provenance\n *\n * Converged from all nine `TimestampUtil.ts` copies. They fall into three\n * shapes: Durable-DAV's minimal two-method set (`getCurrentUnixTimestampInSeconds`\n * + `addDays`) with a deliberate \"seconds everywhere\" argument; AWS's compact set\n * plus an **injectable `Clock`** on the current-time readers; and the full\n * ChordDHT/Mail-Otter set (`…InMilliseconds`, `addMinutes`, `addHours`,\n * `subtractMinutes`, `subtractDays`, `convertIso…`) reading `Date.now()` directly.\n *\n * ## Design decisions\n *\n * - The **full method set** is kept: the union of the three shapes loses nothing\n * and each method exists because at least two repos independently reached for\n * it.\n * - The current-time reads go through an **injectable `Clock`** defaulting to\n * `SYSTEM_CLOCK` (AWS's shape). Reading the clock through one seam lets a test\n * pin \"now\" without racing `Date.now()`, and a caller cannot accidentally store\n * milliseconds in a column compared against seconds.\n * - Seconds is the storage unit (Durable-DAV's argument): where millisecond\n * precision is genuinely wanted — ordering within a single pass — reach for\n * `…InMilliseconds` (or `clock.now()`) explicitly, so the unit is visible at the\n * call site. `add*`/`subtract*` operate on the **second** unit and are pure\n * calendar arithmetic, never `Date` arithmetic, so they cannot pick up a\n * timezone or a DST transition.\n */\nclass TimestampUtil {\n /**\n * Now, in whole milliseconds.\n *\n * @param clock Inject a `FixedClock` to pin \"now\" in a test; production leaves\n * it defaulted.\n */\n public static getCurrentUnixTimestampInMilliseconds(clock: Clock = SYSTEM_CLOCK): number {\n return clock.now();\n }\n\n /**\n * Now, in whole seconds. The default storage unit.\n *\n * @param clock Inject a `FixedClock` to pin \"now\" in a test; production leaves\n * it defaulted.\n */\n public static getCurrentUnixTimestampInSeconds(clock: Clock = SYSTEM_CLOCK): number {\n return Math.floor(clock.now() / 1000);\n }\n\n public static addMinutes(timestamp: number, minutes: number): number {\n return timestamp + minutes * 60;\n }\n\n public static addHours(timestamp: number, hours: number): number {\n return timestamp + hours * 60 * 60;\n }\n\n public static addDays(timestamp: number, days: number): number {\n return timestamp + days * 60 * 60 * 24;\n }\n\n public static subtractMinutes(timestamp: number, minutes: number): number {\n return timestamp - minutes * 60;\n }\n\n public static subtractDays(timestamp: number, days: number): number {\n return timestamp - days * 60 * 60 * 24;\n }\n\n public static convertIsoToUnixTimestampInSeconds(isoString: string): number {\n return Math.floor(new Date(isoString).getTime() / 1000);\n }\n}\n\nexport { TimestampUtil };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenHashUtil.js","sourceRoot":"","sources":["../src/TokenHashUtil.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,aAAa;IACV,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAa;QACzC,OAAO,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;CACF;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"TokenHashUtil.js","sourceRoot":"","sources":["../src/TokenHashUtil.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,aAAa;IACV,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAa;QACzC,OAAO,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;CACF;AAED,OAAO,EAAE,aAAa,EAAE,CAAC","sourcesContent":["import { CryptoUtil } from './CryptoUtil';\n\n/**\n * The one-place hash for API / personal access tokens.\n *\n * ## Provenance\n *\n * Taken from AWS-AccessBridge's `TokenHashUtil.ts` — the only repo that factored\n * token hashing behind a named helper (as opposed to calling `CryptoUtil.sha256Hex`\n * inline, as Edge-Git does).\n *\n * A PAT is ~244 random bits from two UUIDs, so a plain SHA-256 hex digest is the\n * right storage form: the input is not dictionary-searchable, so no salt or\n * password KDF is needed, and the digest is indexable. Binding the digest for\n * storage means a D1 read or backup no longer carries a live credential.\n *\n * ## Design decisions\n *\n * - `sha256Hex` **delegates to `CryptoUtil.sha256Hex`** rather than reimplementing\n * the digest loop. AWS carried its own copy only because its `CryptoUtil` did\n * not yet exist to delegate to; the kit's does, and a second SHA-256\n * implementation is exactly the drift this package removes.\n * - **No timing-safe compare is shipped.** The brief says to keep an\n * HMAC/TimingSafe helper \"if present\"; none of the source repos carries one —\n * token verification compares two SHA-256 *hex strings*, and nothing in the\n * repos does it in constant time. Rather than invent a security primitive here\n * that has no provenance, the helper is left out; a verifier that must compare a\n * presented token's digest against a stored one does the byte-wise, length-\n * independent compare itself (a `crypto.subtle`-backed constant-time compare\n * belongs with the caller's chosen error mapping).\n */\nclass TokenHashUtil {\n public static async sha256Hex(token: string): Promise<string> {\n return CryptoUtil.sha256Hex(token);\n }\n}\n\nexport { TokenHashUtil };\n"]}
|
package/dist/UUIDUtil.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UUIDUtil.js","sourceRoot":"","sources":["../src/UUIDUtil.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,QAAQ;IACL,MAAM,CAAC,aAAa;QACzB,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,mBAAmB;QAC/B,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACjD,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAsCG;IACI,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,SAAiB,EAAE,GAAG,KAAwB;QAChF,MAAM,OAAO,GAAG,CAAC,SAAS,EAAE,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QACxF,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAU,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3H,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;IACjH,CAAC;CACF;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"UUIDUtil.js","sourceRoot":"","sources":["../src/UUIDUtil.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,QAAQ;IACL,MAAM,CAAC,aAAa;QACzB,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,mBAAmB;QAC/B,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACjD,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAsCG;IACI,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,SAAiB,EAAE,GAAG,KAAwB;QAChF,MAAM,OAAO,GAAG,CAAC,SAAS,EAAE,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QACxF,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAU,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3H,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;IACjH,CAAC;CACF;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC","sourcesContent":["/**\n * Primary keys.\n *\n * ## Provenance\n *\n * Converged from `UUIDUtil.ts` in Durable-DAV, AWS-AccessBridge, Edge-Git,\n * Mail-Otter (a re-export of the DAV form under the name `UIDUtility`), the\n * Router, CalDAV-Bridge, Mail-Meow and Edge-Sonic. Four carried the bare\n * `getRandomUUID`; Edge-Git and AWS added `getRandomUUIDNoDash`; Edge-Sonic added\n * the derived `deterministicId`. ChordDHT-Tracker has no UUIDUtil (its ids go\n * through `IdGenerator`).\n *\n * ## Design decision\n *\n * The whole requirement for a row whose id never appears on the wire is a v4 UUID\n * in canonical dashed form, so `getRandomUUID` is the base. `getRandomUUIDNoDash`\n * is kept from the AWS/Edge-Git form (two repos independently needed the compact\n * spelling). `deterministicId` is Edge-Sonic's and is the single most valuable\n * member — see its doc comment for why length-prefixing the parts is load-bearing.\n */\nclass UUIDUtil {\n public static getRandomUUID(): string {\n return crypto.randomUUID();\n }\n\n /**\n * The canonical form with the dashes removed, for a context that wants a\n * compact, dash-free hex-ish token.\n */\n public static getRandomUUIDNoDash(): string {\n return crypto.randomUUID().replaceAll('-', '');\n }\n\n /**\n * A UUID-shaped id derived from a namespace and its parts, stable across runs.\n *\n * ### Why this exists\n *\n * **Because \"create this\" is not idempotent.** A Cloudflare Workflow step is\n * cached by name and may be retried, so an import that mints a fresh id per\n * attempt writes the *same row twice* on every retry — and a user who pressed\n * the button three times finds four copies. `getRandomUUID` is right for the\n * path where each create really is a new row, and wrong for an import, where a\n * retried step is the *same* row.\n *\n * So an imported row's id is a function of `(namespace, ...parts)`: a retry\n * resolves the same id, the write rewrites it, and the outcome does not depend\n * on how many times the step ran.\n *\n * ### SHA-256, and why not MD5\n *\n * MD5 exists in one repo for a token scheme that specifies it, but this is a\n * collision question with a consequence: two different inputs sharing an id\n * means one overwrites the other, and MD5's collision resistance is not\n * something to lean on when `crypto.subtle` is available. 128 bits of SHA-256\n * is used, in canonical dashed form so the value is a UUID by inspection rather\n * than 32 hex characters used as one.\n *\n * ### Every part is **length-prefixed**, because a separator proves nothing\n *\n * The obvious implementation joins the parts with a delimiter, and the obvious\n * claim is that the delimiter cannot appear inside a part. That claim is\n * **false**: joining `[ns, a, b]` and joining `[ns, a\\u0000b]` both produce the\n * same string, so a delimiter — *any* delimiter — is forgeable by choosing a\n * part containing it. Two different inputs then hash to one id, and one\n * overwrites the other.\n *\n * So each part contributes its **length** before its bytes: `3:ns1:a1:b`. That\n * encoding is injective, because the length is recoverable from the bytes\n * themselves — there is exactly one way to parse it — so no choice of parts\n * produces the same string.\n */\n public static async deterministicId(namespace: string, ...parts: readonly string[]): Promise<string> {\n const payload = [namespace, ...parts].map((part) => `${part.length}:${part}`).join('');\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(payload));\n const hex = Array.from(new Uint8Array(digest).slice(0, 16), (byte): string => byte.toString(16).padStart(2, '0')).join('');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;\n }\n}\n\nexport { UUIDUtil };\n"]}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAe;AACf,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAExD,QAAQ;AACR,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEhE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEjE,UAAU;AACV,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEnG,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAGxD,oBAAoB;AACpB,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAe;AACf,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGpE,oBAAoB;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,kBAAkB;AAClB,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAGhE,kBAAkB;AAClB,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,aAAa,EACb,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAG3B,cAAc;AACd,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,oCAAoC;AACpC,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAGtI,yBAAyB;AACzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,iBAAiB;AACjB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAe;AACf,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAExD,QAAQ;AACR,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEhE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEjE,UAAU;AACV,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEnG,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAGxD,oBAAoB;AACpB,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAe;AACf,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGpE,oBAAoB;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,kBAAkB;AAClB,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAGhE,kBAAkB;AAClB,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,aAAa,EACb,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAG3B,cAAc;AACd,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,oCAAoC;AACpC,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAGtI,yBAAyB;AACzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,iBAAiB;AACjB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC","sourcesContent":["/**\n * `@rexezuge/shared` — the converged, platform-generic utilities distilled from\n * the nine Rexezuge Cloudflare Worker monorepos. One concept per file; this barrel\n * only re-exports. Business-specific helpers (money, git oids, calendar sync,\n * credential sharding, …) are deliberately left in their consumer repos.\n *\n * `isValidEmailFormat` / `MAX_EMAIL_LENGTH` are defined in `Identity.ts` and\n * re-exported by `EmailUtil.ts`; the barrel sources each name **once** (from\n * `EmailUtil`, the one-stop email surface) so an `export *` merge cannot silently\n * drop them to ambiguity.\n */\n\n// Byte codecs.\nexport { bytesToBase64, base64ToBytes } from './Base64';\n\n// Time.\nexport { SystemClock, FixedClock, SYSTEM_CLOCK } from './Clock';\nexport type { Clock } from './Clock';\nexport { TimestampUtil } from './TimestampUtil';\nexport { TimeZoneUtil, DEFAULT_TIME_ZONE } from './TimeZoneUtil';\n\n// Locale.\nexport { LocaleUtil, DEFAULT_LOCALE, SUPPORTED_LOCALES, LOCALE_DISPLAY_NAMES } from './LocaleUtil';\nexport type { SupportedLocale } from './LocaleUtil';\nexport { canonicalizeLanguageTag } from './LanguageTag';\nexport type { LanguageTag } from './LanguageTag';\n\n// Identity + email.\nexport { normalizeEmail, isValidEmailFormat, MAX_EMAIL_LENGTH } from './EmailUtil';\nexport { EMAIL_FORMAT_RE } from './Identity';\n\n// Identifiers.\nexport { UUIDUtil } from './UUIDUtil';\nexport { CryptoIdGenerator, FixedIdGenerator } from './IdGenerator';\nexport type { IdGenerator } from './IdGenerator';\n\n// Crypto + secrets.\nexport { CryptoUtil } from './CryptoUtil';\n\n// Error handling.\nexport { ErrorSanitizationUtil } from './ErrorSanitizationUtil';\nexport { err, getOrThrow, isOk, mapResult, ok } from './Result';\nexport type { Err, Ok, Result } from './Result';\n\n// Network policy.\nexport {\n normalizeRemoteUrl,\n resolveRedirectUrl,\n parseAllowedHosts,\n isPrivateOrInternalHost,\n stripBrackets,\n stripTrailingDot,\n RemoteUrlRejectedError,\n MAX_REMOTE_URL_LENGTH,\n MAX_REDIRECTS,\n BLOCKED_HOST_SUFFIXES,\n BLOCKED_HOSTNAMES,\n} from './RemoteUrlPolicy';\nexport type { UrlPolicyOptions } from './RemoteUrlPolicy';\n\n// Pagination.\nexport { CursorCodec } from './CursorCodec';\nexport type { Page } from './CursorCodec';\n\n// Cloudflare subrequest accounting.\nexport { SubrequestCounter, UNMETERED_SUBREQUESTS, SUBREQUEST_KINDS, subrequestSpend, NO_SUBREQUESTS_SPENT } from './SubrequestMeter';\nexport type { SubrequestMeter, SubrequestKind, SubrequestSpend } from './SubrequestMeter';\n\n// Auth-side memo helper.\nexport { passwordFingerprint } from './PasswordFingerprint';\n\n// Token hashing.\nexport { TokenHashUtil } from './TokenHashUtil';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rexezuge/shared",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"typescript": "6.0.3",
|
|
30
30
|
"vitest": "4.1.11"
|
|
31
31
|
},
|
|
32
|
+
"description": "Pure platform-generic utilities (codecs, time, locale, crypto, Result, SSRF policy) for Cloudflare Workers.",
|
|
32
33
|
"scripts": {
|
|
33
34
|
"build": "tsc -p tsconfig.json",
|
|
34
35
|
"typecheck": "tsc -p tsconfig.test.json --noEmit",
|