@pithy-sh/core 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/dist/audit/composed.d.ts +18 -0
  2. package/dist/audit/composed.d.ts.map +1 -0
  3. package/dist/audit/composed.js +28 -0
  4. package/dist/audit/recorder.d.ts +10 -2
  5. package/dist/audit/recorder.d.ts.map +1 -1
  6. package/dist/capability/capability.d.ts +23 -0
  7. package/dist/capability/capability.d.ts.map +1 -1
  8. package/dist/capability/capability.js +2 -0
  9. package/dist/capability/purge.d.ts +122 -0
  10. package/dist/capability/purge.d.ts.map +1 -0
  11. package/dist/capability/purge.js +131 -0
  12. package/dist/cli/commandCatalog.generated.d.ts +54 -2
  13. package/dist/cli/commandCatalog.generated.d.ts.map +1 -1
  14. package/dist/cli/commandCatalog.generated.js +61 -0
  15. package/dist/cli/commandFacts.d.ts +1 -0
  16. package/dist/cli/commandFacts.d.ts.map +1 -1
  17. package/dist/cli/commandFacts.js +1 -0
  18. package/dist/controlPlane/capability.d.ts.map +1 -1
  19. package/dist/controlPlane/capability.js +7 -0
  20. package/dist/controlPlane/data/connection.d.ts +2 -12
  21. package/dist/controlPlane/data/connection.d.ts.map +1 -1
  22. package/dist/controlPlane/data/connection.js +1 -1
  23. package/dist/controlPlane/discovery/adminRoute.d.ts +29 -0
  24. package/dist/controlPlane/discovery/adminRoute.d.ts.map +1 -1
  25. package/dist/controlPlane/discovery/adminRoute.js +3 -0
  26. package/dist/controlPlane/error/errors.d.ts +4 -3
  27. package/dist/controlPlane/error/errors.d.ts.map +1 -1
  28. package/dist/controlPlane/http/guard.d.ts.map +1 -1
  29. package/dist/controlPlane/http/guard.js +40 -1
  30. package/dist/controlPlane/http/handlers.d.ts +79 -0
  31. package/dist/controlPlane/http/handlers.d.ts.map +1 -1
  32. package/dist/controlPlane/http/handlers.js +37 -3
  33. package/dist/controlPlane/http/responses.d.ts +98 -0
  34. package/dist/controlPlane/http/responses.d.ts.map +1 -1
  35. package/dist/controlPlane/http/responses.js +41 -1
  36. package/dist/controlPlane/http/routes.d.ts +1 -0
  37. package/dist/controlPlane/http/routes.d.ts.map +1 -1
  38. package/dist/controlPlane/http/routes.js +17 -3
  39. package/dist/controlPlane/scope/scope.d.ts +13 -3
  40. package/dist/controlPlane/scope/scope.d.ts.map +1 -1
  41. package/dist/controlPlane/scope/scope.js +14 -4
  42. package/dist/createBackend.d.ts.map +1 -1
  43. package/dist/createBackend.js +2 -0
  44. package/dist/createEntrypoint.d.ts +7 -1
  45. package/dist/createEntrypoint.d.ts.map +1 -1
  46. package/dist/createEntrypoint.js +15 -5
  47. package/dist/crypto/envelope.d.ts +86 -0
  48. package/dist/crypto/envelope.d.ts.map +1 -0
  49. package/dist/crypto/envelope.js +129 -0
  50. package/dist/crypto/fieldKeys.d.ts +41 -0
  51. package/dist/crypto/fieldKeys.d.ts.map +1 -0
  52. package/dist/crypto/fieldKeys.js +56 -0
  53. package/dist/data/codecs.d.ts +23 -10
  54. package/dist/data/codecs.d.ts.map +1 -1
  55. package/dist/data/codecs.js +50 -36
  56. package/dist/error/extend.d.ts +6 -5
  57. package/dist/error/extend.d.ts.map +1 -1
  58. package/dist/error/http.d.ts +72 -0
  59. package/dist/error/http.d.ts.map +1 -1
  60. package/dist/error/payload.d.ts +144 -0
  61. package/dist/error/payload.d.ts.map +1 -1
  62. package/dist/error/payload.js +48 -0
  63. package/dist/error/pithyError.d.ts +18 -7
  64. package/dist/error/pithyError.d.ts.map +1 -1
  65. package/dist/error/pithyError.js +6 -0
  66. package/dist/http/validation.d.ts +11 -2
  67. package/dist/http/validation.d.ts.map +1 -1
  68. package/dist/http/validation.js +20 -3
  69. package/dist/index.d.ts +1 -1
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +2 -2
  72. package/dist/logger/logger.d.ts +12 -5
  73. package/dist/logger/logger.d.ts.map +1 -1
  74. package/dist/logger/record.d.ts +42 -0
  75. package/dist/logger/record.d.ts.map +1 -1
  76. package/dist/privacy/blindIndex.d.ts +27 -0
  77. package/dist/privacy/blindIndex.d.ts.map +1 -0
  78. package/dist/privacy/blindIndex.js +57 -0
  79. package/dist/privacy/classes.d.ts +142 -0
  80. package/dist/privacy/classes.d.ts.map +1 -0
  81. package/dist/privacy/classes.js +209 -0
  82. package/dist/privacy/classify.d.ts +336 -0
  83. package/dist/privacy/classify.d.ts.map +1 -0
  84. package/dist/privacy/classify.js +1024 -0
  85. package/dist/privacy/encrypted.d.ts +210 -0
  86. package/dist/privacy/encrypted.d.ts.map +1 -0
  87. package/dist/privacy/encrypted.js +350 -0
  88. package/dist/privacy/encryptedColumns.d.ts +64 -0
  89. package/dist/privacy/encryptedColumns.d.ts.map +1 -0
  90. package/dist/privacy/encryptedColumns.js +134 -0
  91. package/dist/privacy/fieldRotation.d.ts +34 -0
  92. package/dist/privacy/fieldRotation.d.ts.map +1 -0
  93. package/dist/privacy/fieldRotation.js +186 -0
  94. package/dist/privacy/inventory.d.ts +12 -0
  95. package/dist/privacy/inventory.d.ts.map +1 -0
  96. package/dist/privacy/inventory.js +154 -0
  97. package/dist/privacy/posture.d.ts +114 -0
  98. package/dist/privacy/posture.d.ts.map +1 -0
  99. package/dist/privacy/posture.js +136 -0
  100. package/dist/privacy/redact.d.ts +7 -0
  101. package/dist/privacy/redact.d.ts.map +1 -0
  102. package/dist/privacy/redact.js +404 -0
  103. package/dist/privacy/report.d.ts +58 -0
  104. package/dist/privacy/report.d.ts.map +1 -0
  105. package/dist/privacy/report.js +15 -0
  106. package/dist/privacy/retirement.d.ts +68 -0
  107. package/dist/privacy/retirement.d.ts.map +1 -0
  108. package/dist/privacy/retirement.js +72 -0
  109. package/dist/privacy/sealed.d.ts +87 -0
  110. package/dist/privacy/sealed.d.ts.map +1 -0
  111. package/dist/privacy/sealed.js +221 -0
  112. package/dist/privacy/types.d.ts +559 -0
  113. package/dist/privacy/types.d.ts.map +1 -0
  114. package/dist/privacy/types.js +2 -0
  115. package/dist/version.generated.d.ts +1 -1
  116. package/dist/version.generated.js +1 -1
  117. package/package.json +1 -1
  118. package/src/audit/composed.ts +30 -0
  119. package/src/audit/recorder.ts +10 -2
  120. package/src/capability/capability.ts +26 -0
  121. package/src/capability/purge.ts +187 -0
  122. package/src/cli/commandCatalog.generated.ts +65 -0
  123. package/src/cli/commandFacts.ts +1 -0
  124. package/src/controlPlane/capability.ts +11 -0
  125. package/src/controlPlane/discovery/adminRoute.ts +11 -0
  126. package/src/controlPlane/error/errors.ts +4 -3
  127. package/src/controlPlane/http/guard.ts +60 -1
  128. package/src/controlPlane/http/handlers.ts +57 -4
  129. package/src/controlPlane/http/responses.ts +100 -0
  130. package/src/controlPlane/http/routes.ts +31 -1
  131. package/src/controlPlane/scope/scope.ts +14 -3
  132. package/src/controlPlane/token/base64url.ts +1 -1
  133. package/src/createBackend.ts +4 -0
  134. package/src/createEntrypoint.ts +17 -2
  135. package/src/crypto/envelope.ts +196 -0
  136. package/src/crypto/fieldKeys.ts +76 -0
  137. package/src/data/codecs.ts +69 -37
  138. package/src/error/extend.ts +6 -5
  139. package/src/error/payload.ts +110 -0
  140. package/src/error/pithyError.ts +21 -7
  141. package/src/http/validation.ts +35 -3
  142. package/src/index.ts +1 -0
  143. package/src/logger/logger.ts +12 -5
  144. package/src/privacy/blindIndex.ts +81 -0
  145. package/src/privacy/classes.ts +277 -0
  146. package/src/privacy/classify.ts +1447 -0
  147. package/src/privacy/encrypted.ts +513 -0
  148. package/src/privacy/encryptedColumns.ts +185 -0
  149. package/src/privacy/fieldRotation.ts +234 -0
  150. package/src/privacy/inventory.ts +147 -0
  151. package/src/privacy/posture.ts +205 -0
  152. package/src/privacy/redact.ts +423 -0
  153. package/src/privacy/report.ts +64 -0
  154. package/src/privacy/retirement.ts +102 -0
  155. package/src/privacy/sealed.ts +323 -0
  156. package/src/privacy/types.ts +804 -0
  157. package/src/version.generated.ts +1 -1
@@ -0,0 +1,129 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { InternalError } from "../error/pithyError.js";
4
+ import { z } from "zod";
5
+ //#region src/crypto/envelope.ts
6
+ /**
7
+ * **The AES-256-GCM envelope: one primitive, two callers** (#390).
8
+ *
9
+ * It was `@pithy-sh/secrets`' own, ported from the CMS `secretsCrypto`, and it sealed that capability's rows and
10
+ * nothing else. Field encryption needs the same primitive inside an adopter's own Workers, and a capability may not
11
+ * depend on another's internals (principle 4), so it lives in core now and both callers import it from here. The
12
+ * format did not change: a row secrets sealed before the move opens after it, byte for byte.
13
+ *
14
+ * ## Two version axes
15
+ *
16
+ * `currentVersion` says which key seals new writes, and the `keyVersion` persisted on every envelope says which key
17
+ * opens it. A rotation adds a version, moves the pointer and keeps the old key until nothing is sealed under it, so
18
+ * a row opens under whichever version sealed it, for as long as that version is in the set. This is the
19
+ * *encryption-key* version. A secret's *value* version is a separate concern (`secrets/src/crypto/versionedValue.ts`).
20
+ *
21
+ * The config is the uniform `{ currentVersion, versions }` shape every versioned value uses, plus `lastRotatedAt`
22
+ * beside it as rotation metadata. Version keys are stringified integers, so reading the keys is a full-set read:
23
+ * every still-valid version, never the current one alone.
24
+ *
25
+ * ## The bound context is the caller's, and it is authenticated
26
+ *
27
+ * Every seal binds a **context** string as AES-GCM additional authenticated data. It is not encrypted; it is bound.
28
+ * Without it a ciphertext is valid under the key alone, so one lifted from one row and written into another opens
29
+ * cleanly, and every decision about which value a caller gets lives in the query above. With it, a moved ciphertext
30
+ * fails inside the primitive, however that query is later rewritten.
31
+ *
32
+ * The primitive takes the context whole, because what to bind is the caller's fact, not this module's:
33
+ *
34
+ * - `@pithy-sh/secrets` binds `pithy.secrets.v1:<stored name>` — exactly what it always bound.
35
+ * - A field marked `encrypted()` binds `pithy/enc/1:<declared name>:<field path>:<primary key>` (`../privacy/sealed`).
36
+ *
37
+ * Each prefix is versioned, so a later change to what is bound is a deliberate, visible break, and the two prefixes
38
+ * are distinct, so a secret's ciphertext never opens as a field and a field's never opens as a secret. **What is bound
39
+ * must be stable for the life of the ciphertext**: each caller states why its own context is.
40
+ *
41
+ * An empty context is refused on both halves. It binds nothing, and it would fail open rather than loudly.
42
+ */
43
+ /** The key set a seal draws from: which version is current, every still-valid key, and when it last rotated. */
44
+ const EncryptionConfig = z.object({
45
+ currentVersion: z.string().meta({ multiline: false }).describe("The version key (a stringified integer) whose key seals new writes — the active key."),
46
+ versions: z.record(z.string(), z.string().meta({ multiline: false })).describe("Every still-valid key: version key (stringified integer) → base64-encoded AES-256 key. Holds the current key plus any prior versions still needed to open values not yet re-sealed."),
47
+ lastRotatedAt: z.iso.datetime().meta({ multiline: false }).describe("ISO-8601 timestamp of the last rotation; the rotation cron compares against it to decide when to rotate.")
48
+ }).describe("A versioned AES-256 key set: the uniform versioned-value shape (currentVersion + versions) plus rotation metadata. Secrets' master key (`SECRETS_ENCRYPTION_KEYS`) and the field key (`PITHY_FIELD_KEYS`) both take it.");
49
+ /**
50
+ * One AES-256-GCM envelope: base64 ciphertext, base64 IV, and the key version that sealed it.
51
+ *
52
+ * The bound context is deliberately not in here. It is supplied by the caller on the way back in, from the row's own
53
+ * identity, so a row that has been moved cannot carry its old context with it.
54
+ */
55
+ const EncryptedEnvelope = z.object({
56
+ encryptedValue: z.string().min(1).describe("The AES-256-GCM ciphertext and tag, base64."),
57
+ iv: z.string().min(1).describe("The 12-byte initialization vector, base64. Fresh for every seal."),
58
+ keyVersion: z.number().int().describe("The version of the key that sealed this value: the key set entry that opens it.")
59
+ }).describe("An AES-256-GCM envelope: the ciphertext, its IV, and the key version that sealed it.");
60
+ /** Base64-encode raw bytes without spreading into `fromCharCode` (stack-safe, lint-clean). */
61
+ function toBase64(bytes) {
62
+ let binary = "";
63
+ for (const byte of bytes) binary += String.fromCharCode(byte);
64
+ return btoa(binary);
65
+ }
66
+ /** Decode base64 to raw bytes. */
67
+ function fromBase64(b64) {
68
+ return Uint8Array.from(atob(b64), (char) => char.charCodeAt(0));
69
+ }
70
+ /** The authenticated data for one seal. An empty context is refused: it would bind nothing. */
71
+ function additionalData(context) {
72
+ if (context.length === 0) throw new InternalError({ detail: "the envelope needs a context to bind; an empty context binds nothing" });
73
+ return Uint8Array.from(new TextEncoder().encode(context));
74
+ }
75
+ /** The raw key bytes for `version`, or a refusal naming the key set. Never the key itself. */
76
+ function keyBytes(config, version, options = {}) {
77
+ const b64 = config.versions[String(version)];
78
+ if (!b64) throw new InternalError({ detail: `encryption key version ${version} not present in ${options.keys ?? "the key set"}` });
79
+ return fromBase64(b64);
80
+ }
81
+ /** Import the AES-GCM key for `version` from the config, or throw if that version is absent. */
82
+ async function importKey(config, version, usage, options) {
83
+ return crypto.subtle.importKey("raw", keyBytes(config, version, options), "AES-GCM", false, usage);
84
+ }
85
+ /**
86
+ * Seal `plaintext` under the config's current key version, binding `context`. The IV is 12 fresh random bytes, so
87
+ * two seals of one value never share a ciphertext.
88
+ */
89
+ async function encryptValue(config, context, plaintext, options = {}) {
90
+ const aad = additionalData(context);
91
+ const keyVersion = Number(config.currentVersion);
92
+ const key = await importKey(config, keyVersion, ["encrypt"], options);
93
+ const iv = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(12));
94
+ const ciphertext = await crypto.subtle.encrypt({
95
+ name: "AES-GCM",
96
+ iv,
97
+ additionalData: aad
98
+ }, key, new TextEncoder().encode(plaintext));
99
+ return {
100
+ encryptedValue: toBase64(new Uint8Array(ciphertext)),
101
+ iv: toBase64(iv),
102
+ keyVersion
103
+ };
104
+ }
105
+ /**
106
+ * Open an envelope sealed under `context`. The key version may differ from `currentVersion` during a rotation window;
107
+ * the matching key must still be in the config.
108
+ *
109
+ * A missing key version, a tampered ciphertext, the wrong key, or a ciphertext sealed under another context all throw
110
+ * — never the plaintext or key material. GCM cannot tell those apart, and separating them for the caller would be an
111
+ * oracle: the `detail` names the context the open was *attempted under*, which is what an operator needs. Each caller
112
+ * binds a context composed from validated identifiers, so it is safe in a log; neither binds a value.
113
+ */
114
+ async function decryptValue(config, context, envelope, options = {}) {
115
+ const aad = additionalData(context);
116
+ const key = await importKey(config, envelope.keyVersion, ["decrypt"], options);
117
+ try {
118
+ const plaintext = await crypto.subtle.decrypt({
119
+ name: "AES-GCM",
120
+ iv: fromBase64(envelope.iv),
121
+ additionalData: aad
122
+ }, key, fromBase64(envelope.encryptedValue));
123
+ return new TextDecoder().decode(plaintext);
124
+ } catch (cause) {
125
+ throw new InternalError({ detail: `AES-GCM decrypt failed for '${context}' under key version ${envelope.keyVersion}: wrong key, tampered ciphertext, or a ciphertext sealed under a different context` }, { cause });
126
+ }
127
+ }
128
+ //#endregion
129
+ export { EncryptedEnvelope, EncryptionConfig, decryptValue, encryptValue, fromBase64, keyBytes, toBase64 };
@@ -0,0 +1,41 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { EncryptionConfig } from "./envelope";
4
+ /**
5
+ * **The field key: what an app Worker seals its encrypted fields with** (#390).
6
+ *
7
+ * `PITHY_FIELD_KEYS` is an {@link EncryptionConfig}, the same versioned shape as secrets' master key, and it is a
8
+ * **different key on purpose**. Field encryption seals and opens inside the adopter's own Workers, so every Worker that
9
+ * holds an encrypted field must hold the key it uses. Were that the master key `SECRETS_ENCRYPTION_KEYS`, every such
10
+ * Worker would hold the key to the whole secrets vault, and one compromised would open it. A key of its own limits
11
+ * that to the fields: a Worker that holds an encrypted field and composes no `secrets` is bound this key and never
12
+ * the master key.
13
+ *
14
+ * It is not a second mechanism: `pithy secrets provision` mints it beside the master key, in the same format, binds
15
+ * it to every Worker that holds an encrypted field, and the manager's at-rest cron rotates it every
16
+ * {@link FIELD_KEY_ROTATION_DAYS} days.
17
+ */
18
+ /** The binding an app Worker reads its field key through. Fixed across environments; only the store entry is scoped. */
19
+ export declare const FIELD_KEYS_BINDING = "PITHY_FIELD_KEYS";
20
+ /** How often the manager rotates the field key, in days. */
21
+ export declare const FIELD_KEY_ROTATION_DAYS = 30;
22
+ /** A Secrets Store binding: `.get()` resolves the plaintext inside the Worker. */
23
+ export interface FieldKeyBinding {
24
+ get(): Promise<string>;
25
+ }
26
+ /**
27
+ * Where a field key comes from: the Worker's `env.PITHY_FIELD_KEYS` binding (a Secrets Store binding deployed, a JSON
28
+ * string from `.dev.vars` locally), or a config a caller already resolved.
29
+ */
30
+ export type FieldKeys = FieldKeyBinding | string | EncryptionConfig;
31
+ /**
32
+ * Resolve a field key to its config. A missing binding, text that is not JSON, and JSON that is not a key set are each
33
+ * refused, and **nothing read is ever echoed**: what failed to parse is the key set.
34
+ */
35
+ export declare function resolveFieldKeys(keys: FieldKeys | undefined): Promise<EncryptionConfig>;
36
+ /**
37
+ * Every live version in a key set, newest first, as numbers. A version key that is not an integer is refused rather
38
+ * than sorted as text, where `"10"` sorts before `"9"`.
39
+ */
40
+ export declare function liveVersions(config: EncryptionConfig): number[];
41
+ //# sourceMappingURL=fieldKeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fieldKeys.d.ts","sourceRoot":"","sources":["../../src/crypto/fieldKeys.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;;;;;;GAaG;AAEH,wHAAwH;AACxH,eAAO,MAAM,kBAAkB,qBAAqB,CAAC;AAErD,4DAA4D;AAC5D,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAE1C,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,eAAe,GAAG,MAAM,GAAG,gBAAgB,CAAC;AAEpE;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAoB7F;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAM/D"}
@@ -0,0 +1,56 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { InternalError } from "../error/pithyError.js";
4
+ import { remedy } from "../cli/command.js";
5
+ import { EncryptionConfig } from "./envelope.js";
6
+ //#region src/crypto/fieldKeys.ts
7
+ /**
8
+ * **The field key: what an app Worker seals its encrypted fields with** (#390).
9
+ *
10
+ * `PITHY_FIELD_KEYS` is an {@link EncryptionConfig}, the same versioned shape as secrets' master key, and it is a
11
+ * **different key on purpose**. Field encryption seals and opens inside the adopter's own Workers, so every Worker that
12
+ * holds an encrypted field must hold the key it uses. Were that the master key `SECRETS_ENCRYPTION_KEYS`, every such
13
+ * Worker would hold the key to the whole secrets vault, and one compromised would open it. A key of its own limits
14
+ * that to the fields: a Worker that holds an encrypted field and composes no `secrets` is bound this key and never
15
+ * the master key.
16
+ *
17
+ * It is not a second mechanism: `pithy secrets provision` mints it beside the master key, in the same format, binds
18
+ * it to every Worker that holds an encrypted field, and the manager's at-rest cron rotates it every
19
+ * {@link FIELD_KEY_ROTATION_DAYS} days.
20
+ */
21
+ /** The binding an app Worker reads its field key through. Fixed across environments; only the store entry is scoped. */
22
+ const FIELD_KEYS_BINDING = "PITHY_FIELD_KEYS";
23
+ /** How often the manager rotates the field key, in days. */
24
+ const FIELD_KEY_ROTATION_DAYS = 30;
25
+ /**
26
+ * Resolve a field key to its config. A missing binding, text that is not JSON, and JSON that is not a key set are each
27
+ * refused, and **nothing read is ever echoed**: what failed to parse is the key set.
28
+ */
29
+ async function resolveFieldKeys(keys) {
30
+ let raw = keys;
31
+ if (keys === void 0 || keys === null) throw new InternalError({
32
+ message: "This Worker holds an encrypted field and no field key.",
33
+ action: `Bind ${FIELD_KEYS_BINDING}. ${remedy("secrets provision").say((command) => `${command} binds it to every Worker with an encrypted field.`)}`,
34
+ detail: `${FIELD_KEYS_BINDING} binding is not configured`
35
+ });
36
+ if (typeof keys === "object" && "get" in keys && typeof keys.get === "function") raw = await keys.get();
37
+ if (typeof raw === "string") try {
38
+ raw = JSON.parse(raw);
39
+ } catch {
40
+ throw new InternalError({ detail: `${FIELD_KEYS_BINDING} is not valid JSON` });
41
+ }
42
+ const parsed = EncryptionConfig.safeParse(raw);
43
+ if (!parsed.success) throw new InternalError({ detail: `${FIELD_KEYS_BINDING} is not a valid EncryptionConfig` });
44
+ return parsed.data;
45
+ }
46
+ /**
47
+ * Every live version in a key set, newest first, as numbers. A version key that is not an integer is refused rather
48
+ * than sorted as text, where `"10"` sorts before `"9"`.
49
+ */
50
+ function liveVersions(config) {
51
+ const versions = Object.keys(config.versions).map(Number);
52
+ if (!versions.every((version) => Number.isInteger(version))) throw new InternalError({ detail: `${FIELD_KEYS_BINDING}: a version key is not a stringified integer` });
53
+ return versions.sort((left, right) => right - left);
54
+ }
55
+ //#endregion
56
+ export { FIELD_KEYS_BINDING, FIELD_KEY_ROTATION_DAYS, liveVersions, resolveFieldKeys };
@@ -8,17 +8,29 @@ export declare const SQLiteDate: z.ZodCodec<z.ZodUnion<readonly [z.ZodNumber, z.
8
8
  /** JsonDate: Date ↔ ISO string, for dates nested inside `sqliteJson` payloads. */
9
9
  export declare const JsonDate: z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodDate]>, z.ZodDate>;
10
10
  /**
11
- * sqliteJson: T ↔ JSON string, validated by `schema` on both sides. Decode
12
- * accepts a JSON string or an already-parsed value; the result is validated
13
- * against `schema` before it reaches the app.
14
- *
15
- * **Both `JSON` functions throw**, and both were reachable. `JSON.parse` throws a
16
- * `SyntaxError` on any string that is not a JSON document — which a column holding
17
- * text an older writer put there, or a payload a customer's Worker returned, can be.
18
- * `JSON.stringify` throws a `TypeError` on a `BigInt` and on a cycle, either of
19
- * which a `schema` can legitimately admit. Both become an issue (#358).
11
+ * sqliteJson: T ↔ JSON string, validated by `schema` on both sides. Decode accepts a JSON string or an
12
+ * already-parsed value; the result is validated against `schema` before it reaches the app.
20
13
  */
21
- export declare function sqliteJson<T extends z.ZodType>(schema: T): z.ZodCodec<z.ZodUnion<readonly [z.ZodString, T]>, T>;
14
+ export declare function sqliteJson<T extends z.ZodType>(schema: T): SqliteJson<T>;
15
+ /**
16
+ * Names the type `sqliteJson` returns, and nothing else. A type only: no value carries it. `Redacted<T>` reads a JSON
17
+ * column's fields through it, as `redact` reads them through {@link isSqliteJson}, so an adopter's codec of the same
18
+ * shape is opaque to both.
19
+ */
20
+ declare const kitJsonColumn: unique symbol;
21
+ /** What `sqliteJson(schema)` returns: the kit's JSON column over `schema`. Clones keep it, as they return `this`. */
22
+ export type SqliteJson<T extends z.ZodType> = z.ZodCodec<z.ZodUnion<[z.ZodString, T]>, T> & {
23
+ readonly [kitJsonColumn]: T;
24
+ };
25
+ /** The schema a kit JSON column decodes to, or `never` for any other node. */
26
+ export type SqliteJsonSchema<S> = S extends {
27
+ readonly [kitJsonColumn]: infer T;
28
+ } ? T : never;
29
+ /**
30
+ * Whether a schema is a JSON column `sqliteJson` built, or a clone of one (`.describe()`, `.meta()`), read by its
31
+ * decode. `redact` walks such a column's fields one by one, and treats every other codec as opaque.
32
+ */
33
+ export declare function isSqliteJson(schema: z.ZodType): boolean;
22
34
  export declare const MAX_TIMEZONE_LENGTH = 64;
23
35
  /**
24
36
  * Trim, validate, and canonicalize an IANA timezone; anything invalid becomes
@@ -33,4 +45,5 @@ export declare function isValidIanaTimezone(value: string): boolean;
33
45
  * to `undefined` on both decode and encode rather than throwing.
34
46
  */
35
47
  export declare const IanaTimezone: z.ZodCodec<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodOptional<z.ZodString>>;
48
+ export {};
36
49
  //# sourceMappingURL=codecs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"codecs.d.ts","sourceRoot":"","sources":["../../src/data/codecs.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA+CxB,+EAA+E;AAC/E,eAAO,MAAM,aAAa,8GAGxB,CAAC;AAoBH,6EAA6E;AAC7E,eAAO,MAAM,UAAU,mFAGrB,CAAC;AAEH,kFAAkF;AAClF,eAAO,MAAM,QAAQ,mFAGnB,CAAC;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,wDA8BxD;AAED,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CASxE;AAED,sFAAsF;AACtF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,mFAGvB,CAAC"}
1
+ {"version":3,"file":"codecs.d.ts","sourceRoot":"","sources":["../../src/data/codecs.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA+CxB,+EAA+E;AAC/E,eAAO,MAAM,aAAa,8GAGxB,CAAC;AAoBH,6EAA6E;AAC7E,eAAO,MAAM,UAAU,mFAGrB,CAAC;AAEH,kFAAkF;AAClF,eAAO,MAAM,QAAQ,mFAGnB,CAAC;AA0CH;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAKxE;AAED;;;;GAIG;AACH,OAAO,CAAC,MAAM,aAAa,EAAE,OAAO,MAAM,CAAC;AAE3C,qHAAqH;AACrH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IAC1F,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;CAC7B,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,CAAC,GAAG,KAAK,CAAC;AAE9F;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,GAAG,OAAO,CAGvD;AAED,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CASxE;AAED,sFAAsF;AACtF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,mFAGvB,CAAC"}
@@ -64,47 +64,61 @@ const JsonDate = z.codec(z.union([
64
64
  encode: (value) => value.toISOString()
65
65
  });
66
66
  /**
67
- * sqliteJson: T ↔ JSON string, validated by `schema` on both sides. Decode
68
- * accepts a JSON string or an already-parsed value; the result is validated
69
- * against `schema` before it reaches the app.
67
+ * sqliteJson's decode: a JSON string is parsed, an already-parsed value passes through. One function for every
68
+ * column, so `isSqliteJson` can tell the kit's codec from any other by its decode.
70
69
  *
71
- * **Both `JSON` functions throw**, and both were reachable. `JSON.parse` throws a
72
- * `SyntaxError` on any string that is not a JSON document — which a column holding
73
- * text an older writer put there, or a payload a customer's Worker returned, can be.
74
- * `JSON.stringify` throws a `TypeError` on a `BigInt` and on a cycle, either of
75
- * which a `schema` can legitimately admit. Both become an issue (#358).
70
+ * **`JSON.parse` throws**, and it was reachable: a column holding text an older writer put there, or a payload a
71
+ * customer's Worker returned, need not be a JSON document. That becomes an issue (#358).
72
+ */
73
+ function decodeJson(value, payload) {
74
+ if (typeof value !== "string") return value;
75
+ try {
76
+ return JSON.parse(value);
77
+ } catch {
78
+ payload.issues.push({
79
+ code: "invalid_format",
80
+ format: "json",
81
+ input: value,
82
+ message: "Not valid JSON."
83
+ });
84
+ return z.NEVER;
85
+ }
86
+ }
87
+ /**
88
+ * sqliteJson's encode. **`JSON.stringify` throws** on a `BigInt` and on a cycle, either of which a schema can
89
+ * legitimately admit, so that becomes an issue too (#358).
90
+ */
91
+ function encodeJson(value, payload) {
92
+ try {
93
+ const json = JSON.stringify(value);
94
+ if (typeof json === "string") return json;
95
+ } catch {}
96
+ payload.issues.push({
97
+ code: "invalid_format",
98
+ format: "json",
99
+ input: void 0,
100
+ message: "Not serializable as JSON."
101
+ });
102
+ return z.NEVER;
103
+ }
104
+ /**
105
+ * sqliteJson: T ↔ JSON string, validated by `schema` on both sides. Decode accepts a JSON string or an
106
+ * already-parsed value; the result is validated against `schema` before it reaches the app.
76
107
  */
77
108
  function sqliteJson(schema) {
78
109
  return z.codec(z.union([z.string(), schema]), schema, {
79
- decode: (value, payload) => {
80
- if (typeof value !== "string") return value;
81
- try {
82
- return JSON.parse(value);
83
- } catch {
84
- payload.issues.push({
85
- code: "invalid_format",
86
- format: "json",
87
- input: value,
88
- message: "Not valid JSON."
89
- });
90
- return z.NEVER;
91
- }
92
- },
93
- encode: (value, payload) => {
94
- try {
95
- const json = JSON.stringify(value);
96
- if (typeof json === "string") return json;
97
- } catch {}
98
- payload.issues.push({
99
- code: "invalid_format",
100
- format: "json",
101
- input: void 0,
102
- message: "Not serializable as JSON."
103
- });
104
- return z.NEVER;
105
- }
110
+ decode: decodeJson,
111
+ encode: encodeJson
106
112
  });
107
113
  }
114
+ /**
115
+ * Whether a schema is a JSON column `sqliteJson` built, or a clone of one (`.describe()`, `.meta()`), read by its
116
+ * decode. `redact` walks such a column's fields one by one, and treats every other codec as opaque.
117
+ */
118
+ function isSqliteJson(schema) {
119
+ const def = schema._zod.def;
120
+ return def.type === "pipe" && def.transform === decodeJson;
121
+ }
108
122
  const MAX_TIMEZONE_LENGTH = 64;
109
123
  /**
110
124
  * Trim, validate, and canonicalize an IANA timezone; anything invalid becomes
@@ -134,4 +148,4 @@ const IanaTimezone = z.codec(z.string().nullish(), z.string().optional(), {
134
148
  encode: (value) => normalizeIanaTimezone(value)
135
149
  });
136
150
  //#endregion
137
- export { IanaTimezone, JsonDate, MAX_TIMEZONE_LENGTH, SQLiteBoolean, SQLiteDate, isValidIanaTimezone, normalizeIanaTimezone, sqliteJson };
151
+ export { IanaTimezone, JsonDate, MAX_TIMEZONE_LENGTH, SQLiteBoolean, SQLiteDate, isSqliteJson, isValidIanaTimezone, normalizeIanaTimezone, sqliteJson };
@@ -1,6 +1,7 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
3
  import type { MessageParams } from "../i18n/catalog";
4
+ import type { UnmarkedString } from "../privacy/types";
4
5
  import type { ErrorPayload, KitErrorDomain } from "./payload";
5
6
  import { ExtendedErrorPayload } from "./payload";
6
7
  /**
@@ -84,11 +85,11 @@ export declare function defineErrorPayload<const Code extends `${string}/${strin
84
85
  /** The HTTP status this code maps to. A 4xx or a 5xx — an error is not a success. */
85
86
  status: number;
86
87
  /** Public, safe-to-expose summary. Sent to clients and shown in the terminal. */
87
- message: string;
88
- /** Operator remediation hint. Becomes the CLI action line. Never sent to a client. */
89
- action?: string;
90
- /** Internal context for logs + audit. NEVER serialized to clients — the HTTP codec strips it. */
91
- detail?: string;
88
+ message: UnmarkedString;
89
+ /** Operator remediation hint. Becomes the CLI action line. Never sent to a client. Never a marked value (#132). */
90
+ action?: UnmarkedString;
91
+ /** Internal context for logs + audit. NEVER serialized to clients — the HTTP codec strips it. Never a marked value (#132). */
92
+ detail?: UnmarkedString;
92
93
  /**
93
94
  * Values a translating client interpolates into its own wording for this code. Client-facing:
94
95
  * these cross the boundary with `message`, unlike `action` and `detail`.
@@ -1 +1 @@
1
- {"version":3,"file":"extend.d.ts","sourceRoot":"","sources":["../../src/error/extend.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAMjD;;;;GAIG;AACH,KAAK,cAAc,CAAC,IAAI,SAAS,MAAM,IAAI,IAAI,SAAS,GAAG,cAAc,IAAI,MAAM,EAAE,GACjF;IAAE,IAAI,EAAE,2EAA2E,CAAA;CAAE,GACrF,OAAO,CAAC;AAEZ;;;;;GAKG;AACH,MAAM,MAAM,cAAc,CAAC,IAAI,SAAS,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GACrG,oBAAoB,GAAG;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,GACrC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAE1C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,KAAK,CAAC,IAAI,SAAS,GAAG,MAAM,IAAI,MAAM,EAAE,EAClE,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE,IAAI,GACT,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,CAEjC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,IAAI,SAAS,GAAG,MAAM,IAAI,MAAM,EAAE,EACzE,OAAO,EAAE;IACP,uGAAuG;IACvG,IAAI,EAAE,IAAI,CAAC;IACX,qFAAqF;IACrF,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iGAAiG;IACjG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB,GAAG,cAAc,CAAC,IAAI,CAAC,GACvB,cAAc,CAAC,IAAI,CAAC,CAiBtB"}
1
+ {"version":3,"file":"extend.d.ts","sourceRoot":"","sources":["../../src/error/extend.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAMjD;;;;GAIG;AACH,KAAK,cAAc,CAAC,IAAI,SAAS,MAAM,IAAI,IAAI,SAAS,GAAG,cAAc,IAAI,MAAM,EAAE,GACjF;IAAE,IAAI,EAAE,2EAA2E,CAAA;CAAE,GACrF,OAAO,CAAC;AAEZ;;;;;GAKG;AACH,MAAM,MAAM,cAAc,CAAC,IAAI,SAAS,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GACrG,oBAAoB,GAAG;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,GACrC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAE1C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,KAAK,CAAC,IAAI,SAAS,GAAG,MAAM,IAAI,MAAM,EAAE,EAClE,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE,IAAI,GACT,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,CAEjC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,IAAI,SAAS,GAAG,MAAM,IAAI,MAAM,EAAE,EACzE,OAAO,EAAE;IACP,uGAAuG;IACvG,IAAI,EAAE,IAAI,CAAC;IACX,qFAAqF;IACrF,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,OAAO,EAAE,cAAc,CAAC;IACxB,mHAAmH;IACnH,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,8HAA8H;IAC9H,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB,GAAG,cAAc,CAAC,IAAI,CAAC,GACvB,cAAc,CAAC,IAAI,CAAC,CAiBtB"}
@@ -68,6 +68,16 @@ export declare const HttpError: z.ZodCodec<z.ZodUnion<readonly [z.ZodDiscriminat
68
68
  params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
69
69
  code: z.ZodLiteral<"auth/session_not_fresh">;
70
70
  status: z.ZodLiteral<403>;
71
+ }, z.core.$strip>, z.ZodObject<{
72
+ message: z.ZodString;
73
+ params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
74
+ code: z.ZodLiteral<"auth/account_suspended">;
75
+ status: z.ZodLiteral<403>;
76
+ }, z.core.$strip>, z.ZodObject<{
77
+ message: z.ZodString;
78
+ params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
79
+ code: z.ZodLiteral<"auth/account_deleted">;
80
+ status: z.ZodLiteral<403>;
71
81
  }, z.core.$strip>, z.ZodObject<{
72
82
  message: z.ZodString;
73
83
  params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
@@ -648,6 +658,26 @@ export declare const HttpError: z.ZodCodec<z.ZodUnion<readonly [z.ZodDiscriminat
648
658
  params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
649
659
  code: z.ZodLiteral<"organization/nomination_invalid">;
650
660
  status: z.ZodLiteral<400>;
661
+ }, z.core.$strip>, z.ZodObject<{
662
+ message: z.ZodString;
663
+ params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
664
+ code: z.ZodLiteral<"organization/last_owner">;
665
+ status: z.ZodLiteral<409>;
666
+ }, z.core.$strip>, z.ZodObject<{
667
+ message: z.ZodString;
668
+ params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
669
+ code: z.ZodLiteral<"organization/already_member">;
670
+ status: z.ZodLiteral<409>;
671
+ }, z.core.$strip>, z.ZodObject<{
672
+ message: z.ZodString;
673
+ params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
674
+ code: z.ZodLiteral<"organization/seat_limit_reached">;
675
+ status: z.ZodLiteral<409>;
676
+ }, z.core.$strip>, z.ZodObject<{
677
+ message: z.ZodString;
678
+ params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
679
+ code: z.ZodLiteral<"organization/organization_suspended">;
680
+ status: z.ZodLiteral<403>;
651
681
  }, z.core.$strip>, z.ZodObject<{
652
682
  message: z.ZodString;
653
683
  params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
@@ -821,6 +851,20 @@ export declare const HttpError: z.ZodCodec<z.ZodUnion<readonly [z.ZodDiscriminat
821
851
  detail: z.ZodOptional<z.ZodString>;
822
852
  code: z.ZodLiteral<"auth/session_not_fresh">;
823
853
  status: z.ZodLiteral<403>;
854
+ }, z.core.$strip>, z.ZodObject<{
855
+ message: z.ZodString;
856
+ params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
857
+ action: z.ZodOptional<z.ZodString>;
858
+ detail: z.ZodOptional<z.ZodString>;
859
+ code: z.ZodLiteral<"auth/account_suspended">;
860
+ status: z.ZodLiteral<403>;
861
+ }, z.core.$strip>, z.ZodObject<{
862
+ message: z.ZodString;
863
+ params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
864
+ action: z.ZodOptional<z.ZodString>;
865
+ detail: z.ZodOptional<z.ZodString>;
866
+ code: z.ZodLiteral<"auth/account_deleted">;
867
+ status: z.ZodLiteral<403>;
824
868
  }, z.core.$strip>, z.ZodObject<{
825
869
  message: z.ZodString;
826
870
  params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
@@ -1633,6 +1677,34 @@ export declare const HttpError: z.ZodCodec<z.ZodUnion<readonly [z.ZodDiscriminat
1633
1677
  detail: z.ZodOptional<z.ZodString>;
1634
1678
  code: z.ZodLiteral<"organization/nomination_invalid">;
1635
1679
  status: z.ZodLiteral<400>;
1680
+ }, z.core.$strip>, z.ZodObject<{
1681
+ message: z.ZodString;
1682
+ params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
1683
+ action: z.ZodOptional<z.ZodString>;
1684
+ detail: z.ZodOptional<z.ZodString>;
1685
+ code: z.ZodLiteral<"organization/last_owner">;
1686
+ status: z.ZodLiteral<409>;
1687
+ }, z.core.$strip>, z.ZodObject<{
1688
+ message: z.ZodString;
1689
+ params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
1690
+ action: z.ZodOptional<z.ZodString>;
1691
+ detail: z.ZodOptional<z.ZodString>;
1692
+ code: z.ZodLiteral<"organization/already_member">;
1693
+ status: z.ZodLiteral<409>;
1694
+ }, z.core.$strip>, z.ZodObject<{
1695
+ message: z.ZodString;
1696
+ params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
1697
+ action: z.ZodOptional<z.ZodString>;
1698
+ detail: z.ZodOptional<z.ZodString>;
1699
+ code: z.ZodLiteral<"organization/seat_limit_reached">;
1700
+ status: z.ZodLiteral<409>;
1701
+ }, z.core.$strip>, z.ZodObject<{
1702
+ message: z.ZodString;
1703
+ params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
1704
+ action: z.ZodOptional<z.ZodString>;
1705
+ detail: z.ZodOptional<z.ZodString>;
1706
+ code: z.ZodLiteral<"organization/organization_suspended">;
1707
+ status: z.ZodLiteral<403>;
1636
1708
  }, z.core.$strip>, z.ZodObject<{
1637
1709
  message: z.ZodString;
1638
1710
  params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/error/http.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/error/http.ts"],"names":[],"mappings":"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"}