@pithy-sh/core 0.10.0 → 0.12.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 (270) hide show
  1. package/dist/access/access.d.ts +172 -0
  2. package/dist/access/access.d.ts.map +1 -0
  3. package/dist/access/access.js +147 -0
  4. package/dist/access/acting.d.ts +49 -0
  5. package/dist/access/acting.d.ts.map +1 -0
  6. package/dist/access/acting.js +21 -0
  7. package/dist/access/policyCheck.d.ts +33 -0
  8. package/dist/access/policyCheck.d.ts.map +1 -0
  9. package/dist/access/policyCheck.js +48 -0
  10. package/dist/access/usage.d.ts +83 -0
  11. package/dist/access/usage.d.ts.map +1 -0
  12. package/dist/access/usage.js +104 -0
  13. package/dist/access/visibility.d.ts +66 -0
  14. package/dist/access/visibility.d.ts.map +1 -0
  15. package/dist/access/visibility.js +86 -0
  16. package/dist/audit/auditEvent.d.ts +5 -0
  17. package/dist/audit/auditEvent.d.ts.map +1 -1
  18. package/dist/audit/auditEvent.js +2 -0
  19. package/dist/audit/recorder.d.ts +10 -2
  20. package/dist/audit/recorder.d.ts.map +1 -1
  21. package/dist/capability/bindings.d.ts +47 -2
  22. package/dist/capability/bindings.d.ts.map +1 -1
  23. package/dist/capability/bindings.js +117 -7
  24. package/dist/capability/capability.d.ts +110 -28
  25. package/dist/capability/capability.d.ts.map +1 -1
  26. package/dist/capability/capability.js +2 -0
  27. package/dist/capability/manifest.d.ts +2 -1
  28. package/dist/capability/manifest.d.ts.map +1 -1
  29. package/dist/capability/manifest.js +1 -1
  30. package/dist/capability/purge.d.ts +80 -0
  31. package/dist/capability/purge.d.ts.map +1 -0
  32. package/dist/capability/purge.js +76 -0
  33. package/dist/capability/settings.d.ts +86 -2
  34. package/dist/capability/settings.d.ts.map +1 -1
  35. package/dist/capability/settings.js +80 -1
  36. package/dist/cli/commandCatalog.generated.d.ts +238 -24
  37. package/dist/cli/commandCatalog.generated.d.ts.map +1 -1
  38. package/dist/cli/commandCatalog.generated.js +251 -22
  39. package/dist/cli/commandFacts.d.ts +2 -1
  40. package/dist/cli/commandFacts.d.ts.map +1 -1
  41. package/dist/cli/commandFacts.js +2 -0
  42. package/dist/controlPlane/capability.d.ts.map +1 -1
  43. package/dist/controlPlane/capability.js +19 -2
  44. package/dist/controlPlane/context.d.ts +5 -0
  45. package/dist/controlPlane/context.d.ts.map +1 -1
  46. package/dist/controlPlane/context.js +3 -1
  47. package/dist/controlPlane/data/connection.d.ts +49 -12
  48. package/dist/controlPlane/data/connection.d.ts.map +1 -1
  49. package/dist/controlPlane/data/connection.js +56 -2
  50. package/dist/controlPlane/discovery/adminRoute.d.ts +29 -0
  51. package/dist/controlPlane/discovery/adminRoute.d.ts.map +1 -1
  52. package/dist/controlPlane/discovery/adminRoute.js +3 -0
  53. package/dist/controlPlane/error/errors.d.ts +4 -3
  54. package/dist/controlPlane/error/errors.d.ts.map +1 -1
  55. package/dist/controlPlane/http/cors.d.ts +4 -4
  56. package/dist/controlPlane/http/cors.js +4 -4
  57. package/dist/controlPlane/http/guard.d.ts +11 -0
  58. package/dist/controlPlane/http/guard.d.ts.map +1 -1
  59. package/dist/controlPlane/http/guard.js +17 -1
  60. package/dist/controlPlane/http/handlers.d.ts +139 -0
  61. package/dist/controlPlane/http/handlers.d.ts.map +1 -1
  62. package/dist/controlPlane/http/handlers.js +67 -4
  63. package/dist/controlPlane/http/readiness.d.ts +33 -0
  64. package/dist/controlPlane/http/readiness.d.ts.map +1 -0
  65. package/dist/controlPlane/http/readiness.js +39 -0
  66. package/dist/controlPlane/http/responses.d.ts +245 -0
  67. package/dist/controlPlane/http/responses.d.ts.map +1 -1
  68. package/dist/controlPlane/http/responses.js +101 -4
  69. package/dist/controlPlane/http/routes.d.ts +2 -0
  70. package/dist/controlPlane/http/routes.d.ts.map +1 -1
  71. package/dist/controlPlane/http/routes.js +31 -3
  72. package/dist/controlPlane/http/verify.d.ts.map +1 -1
  73. package/dist/controlPlane/http/verify.js +2 -1
  74. package/dist/controlPlane/migrationState/migrationState.d.ts +102 -0
  75. package/dist/controlPlane/migrationState/migrationState.d.ts.map +1 -0
  76. package/dist/controlPlane/migrationState/migrationState.js +142 -0
  77. package/dist/controlPlane/migrations/0003_connection_principal.d.ts +21 -0
  78. package/dist/controlPlane/migrations/0003_connection_principal.d.ts.map +1 -0
  79. package/dist/controlPlane/migrations/0003_connection_principal.js +33 -0
  80. package/dist/controlPlane/scope/scope.d.ts +23 -2
  81. package/dist/controlPlane/scope/scope.d.ts.map +1 -1
  82. package/dist/controlPlane/scope/scope.js +24 -3
  83. package/dist/createBackend.d.ts.map +1 -1
  84. package/dist/createBackend.js +9 -2
  85. package/dist/createEntrypoint.d.ts.map +1 -1
  86. package/dist/createEntrypoint.js +5 -3
  87. package/dist/crypto/envelope.d.ts +86 -0
  88. package/dist/crypto/envelope.d.ts.map +1 -0
  89. package/dist/crypto/envelope.js +129 -0
  90. package/dist/crypto/fieldKeys.d.ts +41 -0
  91. package/dist/crypto/fieldKeys.d.ts.map +1 -0
  92. package/dist/crypto/fieldKeys.js +56 -0
  93. package/dist/data/codecs.d.ts +23 -10
  94. package/dist/data/codecs.d.ts.map +1 -1
  95. package/dist/data/codecs.js +50 -36
  96. package/dist/entitlement/allowance.d.ts +25 -0
  97. package/dist/entitlement/allowance.d.ts.map +1 -0
  98. package/dist/entitlement/allowance.js +80 -0
  99. package/dist/entitlement/entitlement.d.ts +41 -0
  100. package/dist/entitlement/entitlement.d.ts.map +1 -1
  101. package/dist/entitlement/meter.d.ts +57 -0
  102. package/dist/entitlement/meter.d.ts.map +1 -0
  103. package/dist/entitlement/meter.js +13 -0
  104. package/dist/error/extend.d.ts +6 -5
  105. package/dist/error/extend.d.ts.map +1 -1
  106. package/dist/error/http.d.ts +168 -0
  107. package/dist/error/http.d.ts.map +1 -1
  108. package/dist/error/payload.d.ts +336 -0
  109. package/dist/error/payload.d.ts.map +1 -1
  110. package/dist/error/payload.js +116 -4
  111. package/dist/error/pithyError.d.ts +18 -7
  112. package/dist/error/pithyError.d.ts.map +1 -1
  113. package/dist/error/pithyError.js +6 -0
  114. package/dist/http/authContext.d.ts +7 -0
  115. package/dist/http/authContext.d.ts.map +1 -1
  116. package/dist/http/authContext.js +8 -1
  117. package/dist/http/scopeGates.d.ts +20 -0
  118. package/dist/http/scopeGates.d.ts.map +1 -0
  119. package/dist/http/scopeGates.js +36 -0
  120. package/dist/index.d.ts +1 -1
  121. package/dist/index.d.ts.map +1 -1
  122. package/dist/index.js +2 -2
  123. package/dist/logger/logger.d.ts +12 -5
  124. package/dist/logger/logger.d.ts.map +1 -1
  125. package/dist/logger/record.d.ts +98 -0
  126. package/dist/logger/record.d.ts.map +1 -1
  127. package/dist/migrations/capabilitySets.d.ts +23 -0
  128. package/dist/migrations/capabilitySets.d.ts.map +1 -0
  129. package/dist/migrations/capabilitySets.js +74 -0
  130. package/dist/migrations/registry.d.ts +26 -0
  131. package/dist/migrations/registry.d.ts.map +1 -1
  132. package/dist/migrations/registry.js +38 -7
  133. package/dist/migrations/state.d.ts +60 -0
  134. package/dist/migrations/state.d.ts.map +1 -0
  135. package/dist/migrations/state.js +46 -0
  136. package/dist/naming/feature.d.ts +27 -5
  137. package/dist/naming/feature.d.ts.map +1 -1
  138. package/dist/naming/feature.js +36 -6
  139. package/dist/naming/limits.d.ts +47 -3
  140. package/dist/naming/limits.d.ts.map +1 -1
  141. package/dist/naming/limits.js +47 -3
  142. package/dist/naming/provisionScope.d.ts +6 -0
  143. package/dist/naming/provisionScope.d.ts.map +1 -1
  144. package/dist/naming/provisionScope.js +8 -3
  145. package/dist/naming/resourceNames.d.ts +21 -2
  146. package/dist/naming/resourceNames.d.ts.map +1 -1
  147. package/dist/naming/resourceNames.js +21 -3
  148. package/dist/privacy/blindIndex.d.ts +27 -0
  149. package/dist/privacy/blindIndex.d.ts.map +1 -0
  150. package/dist/privacy/blindIndex.js +57 -0
  151. package/dist/privacy/classes.d.ts +142 -0
  152. package/dist/privacy/classes.d.ts.map +1 -0
  153. package/dist/privacy/classes.js +209 -0
  154. package/dist/privacy/classify.d.ts +336 -0
  155. package/dist/privacy/classify.d.ts.map +1 -0
  156. package/dist/privacy/classify.js +1024 -0
  157. package/dist/privacy/encrypted.d.ts +210 -0
  158. package/dist/privacy/encrypted.d.ts.map +1 -0
  159. package/dist/privacy/encrypted.js +350 -0
  160. package/dist/privacy/encryptedColumns.d.ts +64 -0
  161. package/dist/privacy/encryptedColumns.d.ts.map +1 -0
  162. package/dist/privacy/encryptedColumns.js +134 -0
  163. package/dist/privacy/fieldRotation.d.ts +34 -0
  164. package/dist/privacy/fieldRotation.d.ts.map +1 -0
  165. package/dist/privacy/fieldRotation.js +186 -0
  166. package/dist/privacy/inventory.d.ts +12 -0
  167. package/dist/privacy/inventory.d.ts.map +1 -0
  168. package/dist/privacy/inventory.js +154 -0
  169. package/dist/privacy/posture.d.ts +114 -0
  170. package/dist/privacy/posture.d.ts.map +1 -0
  171. package/dist/privacy/posture.js +136 -0
  172. package/dist/privacy/redact.d.ts +7 -0
  173. package/dist/privacy/redact.d.ts.map +1 -0
  174. package/dist/privacy/redact.js +404 -0
  175. package/dist/privacy/report.d.ts +58 -0
  176. package/dist/privacy/report.d.ts.map +1 -0
  177. package/dist/privacy/report.js +15 -0
  178. package/dist/privacy/retirement.d.ts +68 -0
  179. package/dist/privacy/retirement.d.ts.map +1 -0
  180. package/dist/privacy/retirement.js +72 -0
  181. package/dist/privacy/sealed.d.ts +87 -0
  182. package/dist/privacy/sealed.d.ts.map +1 -0
  183. package/dist/privacy/sealed.js +221 -0
  184. package/dist/privacy/types.d.ts +559 -0
  185. package/dist/privacy/types.d.ts.map +1 -0
  186. package/dist/privacy/types.js +2 -0
  187. package/dist/seed/writeD1.d.ts +7 -1
  188. package/dist/seed/writeD1.d.ts.map +1 -1
  189. package/dist/seed/writeD1.js +9 -3
  190. package/dist/seed/writeKv.d.ts +2 -0
  191. package/dist/seed/writeKv.d.ts.map +1 -1
  192. package/dist/seed/writeKv.js +6 -2
  193. package/dist/version.generated.d.ts +1 -1
  194. package/dist/version.generated.js +1 -1
  195. package/dist/worker/serviceLoopback.d.ts +36 -0
  196. package/dist/worker/serviceLoopback.d.ts.map +1 -0
  197. package/dist/worker/serviceLoopback.js +74 -0
  198. package/dist/workflow/faults.d.ts +12 -1
  199. package/dist/workflow/faults.d.ts.map +1 -1
  200. package/dist/workflow/faults.js +22 -15
  201. package/package.json +2 -2
  202. package/src/access/access.ts +298 -0
  203. package/src/access/acting.ts +59 -0
  204. package/src/access/policyCheck.ts +77 -0
  205. package/src/access/usage.ts +141 -0
  206. package/src/access/visibility.ts +109 -0
  207. package/src/audit/auditEvent.ts +4 -0
  208. package/src/audit/recorder.ts +10 -2
  209. package/src/capability/bindings.ts +159 -13
  210. package/src/capability/capability.ts +114 -29
  211. package/src/capability/purge.ts +124 -0
  212. package/src/capability/settings.ts +146 -2
  213. package/src/cli/commandCatalog.generated.ts +271 -22
  214. package/src/cli/commandFacts.ts +2 -0
  215. package/src/controlPlane/capability.ts +36 -1
  216. package/src/controlPlane/context.ts +4 -0
  217. package/src/controlPlane/data/connection.ts +90 -0
  218. package/src/controlPlane/discovery/adminRoute.ts +11 -0
  219. package/src/controlPlane/error/errors.ts +4 -3
  220. package/src/controlPlane/http/cors.ts +4 -4
  221. package/src/controlPlane/http/guard.ts +21 -0
  222. package/src/controlPlane/http/handlers.ts +98 -4
  223. package/src/controlPlane/http/readiness.ts +50 -0
  224. package/src/controlPlane/http/responses.ts +240 -2
  225. package/src/controlPlane/http/routes.ts +55 -1
  226. package/src/controlPlane/http/verify.ts +2 -0
  227. package/src/controlPlane/migrationState/migrationState.ts +200 -0
  228. package/src/controlPlane/migrations/0003_connection_principal.ts +37 -0
  229. package/src/controlPlane/scope/scope.ts +25 -2
  230. package/src/controlPlane/token/base64url.ts +1 -1
  231. package/src/createBackend.ts +28 -6
  232. package/src/createEntrypoint.ts +9 -3
  233. package/src/crypto/envelope.ts +196 -0
  234. package/src/crypto/fieldKeys.ts +76 -0
  235. package/src/data/codecs.ts +69 -37
  236. package/src/entitlement/allowance.ts +85 -0
  237. package/src/entitlement/entitlement.ts +38 -0
  238. package/src/entitlement/meter.ts +69 -0
  239. package/src/error/extend.ts +6 -5
  240. package/src/error/payload.ts +253 -4
  241. package/src/error/pithyError.ts +21 -7
  242. package/src/http/authContext.ts +13 -1
  243. package/src/http/scopeGates.ts +34 -0
  244. package/src/index.ts +2 -0
  245. package/src/logger/logger.ts +12 -5
  246. package/src/migrations/capabilitySets.ts +87 -0
  247. package/src/migrations/registry.ts +46 -2
  248. package/src/migrations/state.ts +94 -0
  249. package/src/naming/feature.ts +46 -7
  250. package/src/naming/limits.ts +35 -3
  251. package/src/naming/provisionScope.ts +19 -1
  252. package/src/naming/resourceNames.ts +52 -5
  253. package/src/privacy/blindIndex.ts +81 -0
  254. package/src/privacy/classes.ts +277 -0
  255. package/src/privacy/classify.ts +1447 -0
  256. package/src/privacy/encrypted.ts +513 -0
  257. package/src/privacy/encryptedColumns.ts +185 -0
  258. package/src/privacy/fieldRotation.ts +234 -0
  259. package/src/privacy/inventory.ts +147 -0
  260. package/src/privacy/posture.ts +205 -0
  261. package/src/privacy/redact.ts +423 -0
  262. package/src/privacy/report.ts +64 -0
  263. package/src/privacy/retirement.ts +102 -0
  264. package/src/privacy/sealed.ts +323 -0
  265. package/src/privacy/types.ts +804 -0
  266. package/src/seed/writeD1.ts +13 -4
  267. package/src/seed/writeKv.ts +6 -2
  268. package/src/version.generated.ts +1 -1
  269. package/src/worker/serviceLoopback.ts +105 -0
  270. package/src/workflow/faults.ts +51 -24
@@ -0,0 +1,804 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { z } from "zod";
5
+ import type { SQLiteBoolean, SQLiteDate, SqliteJsonSchema } from "../data/codecs";
6
+ import type { MAX_RECURSION_DEPTH, ValueKind } from "./classify";
7
+
8
+ /**
9
+ * **The type gate: a marked value does not compile into a log, an audit record or an error detail** (#132).
10
+ *
11
+ * A marker brands a field's output type under the `privacy:` key (`./classes`). These types are what read
12
+ * that brand on the three internal surfaces — the logger's fields, `AuditEvent.metadata`, `PithyError.detail`
13
+ * — and refuse it at compile time, where the mistake is a red build rather than a row in an adopter's D1 that
14
+ * nobody can retract.
15
+ *
16
+ * ## What the compiler checks, exactly
17
+ *
18
+ * - **A marked value itself**, anywhere a field value goes: `log.info("m", { email: user.email })` fails.
19
+ * - **A marked value inside an object or an array, down to {@link PRIVACY_CHECK_DEPTH} levels below the field**:
20
+ * `{ user }`, `{ user: { email } }`, `{ users: [user] }`, `{ batch: { users: [user] } }` all fail.
21
+ * - **A marked key**: a record keyed by a marked value, `Record<User["email"], …>`, is refused like the value.
22
+ * - **A marked string as a message**: `log.info(user.email)`, `log.child(user.email)`, and `message`, `action` or
23
+ * `detail` on any `PithyError` constructor fail, because each takes {@link UnmarkedString}.
24
+ *
25
+ * ## What it does not, and cannot
26
+ *
27
+ * - **Deeper than {@link PRIVACY_CHECK_DEPTH}.** The bound is there so the walk terminates on a recursive type
28
+ * (a JSON alias, a tree), not for speed: measured with `tsc --extendedDiagnostics` (TypeScript 7.0.2,
29
+ * 2026-10-20, #132), the gate costs `@pithy-sh/auth` +0.6% types and +0.1% instantiations over `main`, and
30
+ * moving the bound from 1 to 9 changes either count by less than 0.01% on every package — and by about 330
31
+ * types and 5,400 instantiations on a file that logs a Hono `Context`, a `Kysely` instance and an
32
+ * eight-level object, because `Error`, functions, promises, maps and sets are not walked. Below the bound a
33
+ * value is not inspected.
34
+ * - **A template literal.** `` `signup for ${email}` `` is a `string` to TypeScript, whatever was
35
+ * interpolated, and no type can see through it. `detail` is where this matters most; interpolate the
36
+ * `redact`ed value, or the id, instead.
37
+ * - **A cast or an `unknown`.** A value the compiler cannot see is a value it cannot refuse.
38
+ *
39
+ * None of the three is checked at runtime either: a marker changes no runtime value, so a string that
40
+ * escaped the type is an ordinary string. `docs/PRIVACY.md` says the same to adopters.
41
+ */
42
+
43
+ /** How many levels of object or array below a field value the gate inspects. See the module note. */
44
+ export type PRIVACY_CHECK_DEPTH = 6;
45
+
46
+ /** Depth countdown: `Prev[3]` is `2`. Index past the end is `never`, which stops the walk. */
47
+ type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
48
+
49
+ /** One level down from `D`, and `never` from `never`: indexing {@link Prev} with `never` is not `never`. */
50
+ type Down<D extends number> = [D] extends [never] ? never : Prev[D];
51
+
52
+ /** `true` for `any`, so an untyped value is never mistaken for a marked one. */
53
+ type IsAny<T> = 0 extends 1 & T ? true : false;
54
+
55
+ /**
56
+ * Values whose structure is not data: walking an `Error`'s payload union or a `Request`'s methods would cost the
57
+ * compiler a great deal and could only ever find a brand somebody put there by hand.
58
+ */
59
+ type Opaque =
60
+ | Error
61
+ | Date
62
+ | RegExp
63
+ | ((...args: never[]) => unknown)
64
+ | PromiseLike<unknown>
65
+ | ReadonlyMap<unknown, unknown>
66
+ | ReadonlySet<unknown>;
67
+
68
+ /** Whether `T` carries a privacy brand. Distributes, so `marked | undefined` is `boolean` — test with `true extends`. */
69
+ export type IsMarked<T> =
70
+ IsAny<T> extends true
71
+ ? false
72
+ : T extends { readonly [z.core.$brand]: infer M }
73
+ ? [Extract<keyof M, `privacy:${string}`>] extends [never]
74
+ ? false
75
+ : true
76
+ : false;
77
+
78
+ /**
79
+ * Whether `T`, or anything up to `D` levels of object or array inside it, carries a privacy brand — in a value, or
80
+ * in a key: a `Record<User["email"], number>` holds every email it is keyed by.
81
+ */
82
+ export type ContainsMarked<T, D extends number = PRIVACY_CHECK_DEPTH> =
83
+ IsAny<T> extends true
84
+ ? false
85
+ : [D] extends [never]
86
+ ? false
87
+ : true extends IsMarked<T>
88
+ ? true
89
+ : T extends Opaque
90
+ ? false
91
+ : T extends readonly (infer E)[]
92
+ ? ContainsMarked<E, Down<D>>
93
+ : T extends object
94
+ ? true extends IsMarked<keyof T>
95
+ ? true
96
+ : true extends { [K in keyof T]-?: ContainsMarked<T[K], Down<D>> }[keyof T]
97
+ ? true
98
+ : false
99
+ : false;
100
+
101
+ /**
102
+ * The type a refused field takes, so the compiler's error reads as the rule: `Type 'string & $brand<…>' is not
103
+ * assignable to type '"A value marked with a privacy class …"'`.
104
+ */
105
+ export type PrivateValueRefused =
106
+ "A value marked with a privacy class cannot reach a log, an audit record or an error detail. Pass redact(Schema, value), or an unmarked field, instead.";
107
+
108
+ /**
109
+ * A record of fields, each one either kept as written or refused because it holds a marked value. A surface
110
+ * that accepts structured fields takes `F & Loggable<F>`: `F` infers from the call, and `Loggable<F>` replaces
111
+ * every field that carries a brand with {@link PrivateValueRefused}, so the call fails on that key alone.
112
+ */
113
+ export type Loggable<F> = { [K in keyof F]: true extends ContainsMarked<F[K]> ? PrivateValueRefused : F[K] };
114
+
115
+ /** No privacy brand. Any other brand — an adopter's `UserId` — is untouched. */
116
+ type NoPrivacyBrand = { readonly [z.core.$brand]?: { readonly [K in `privacy:${string}`]?: never } };
117
+
118
+ /**
119
+ * A string that is not marked. A plain `string` and a template literal both are; `user.email` from a `pii()`
120
+ * field is not. What a log message, a logger's name and `PithyError`'s `message`, `action` and `detail` take.
121
+ */
122
+ export type UnmarkedString = string & NoPrivacyBrand;
123
+
124
+ /**
125
+ * What `redact(schema, value)` returns, named by the schema: the type a caller names for a value it already redacted,
126
+ * `Redacted<typeof User>`. It is {@link RedactedOutput}, and it takes the schema rather than the value's type on
127
+ * purpose: a value's type cannot tell a plain object from the output of a transform, which `redact` may mask whole.
128
+ * Nor can a schema's: a class instance where an object with a mark beneath is expected is masked whole at runtime,
129
+ * outside the contract, and typed as the object it stands in for.
130
+ */
131
+ export type Redacted<S extends z.ZodType> = RedactedOutput<S>;
132
+
133
+ /**
134
+ * **What `redact(schema, value)` returns, read off the schema: the redaction contract (`./redact`) at the type level.**
135
+ *
136
+ * - **A marked position is a `string`**, beside the `null` or `undefined` its wrappers add: a marked node, or a
137
+ * position a mark reaches through no union option. A mark reached through an option applies where the value has
138
+ * that option's shape, so an option of another shape beside it keeps its own type: `z.union([pii(z.string()),
139
+ * z.array(z.string())])` is `string | string[]`.
140
+ * - **Every structural kind keeps its shape**: an object maps its fields, an array and a tuple their elements, a
141
+ * record and a map their values, a set its elements, and a marked key becomes `string`. Each wrapper keeps what it
142
+ * adds. A union is a union of its members and an intersection intersects its sides, each with every option's and
143
+ * every side's marks at each position: an array beside a tuple is typed index by index where the tuple names one,
144
+ * and a record or an open object beside an object types each key the object names. An intersection with a record
145
+ * on either side is `unknown`, as a record's masked keys rename the other side's keys too. The kit's three codecs
146
+ * are the schema they decode to, and a JSON column is known by the type `sqliteJson` returns, never by its shape.
147
+ * - **An opaque node is its own output**, or `unknown` where a mark sits anywhere beneath it or may, because `redact`
148
+ * masks it whole there. The search beneath it reads every schema once, to the one recursion limit, so an unmarked
149
+ * schema of any depth keeps its output. A recursion beneath it is `unknown` however it is written, as a type cannot
150
+ * tell one defined once from one built anew, which reaches the limit and is masked; so is a schema annotated
151
+ * `z.ZodType<T>` beneath it. That is the one place the type says `unknown`, with two more a type cannot see past: a
152
+ * schema annotated `z.ZodType<T>`, as a self-referencing `z.lazy` must be, names no kind; and `any`.
153
+ * - **A `.catch()` over a structure is read as the opaque node it may be**: `unknown` where a mark sits beneath it, a
154
+ * constant fallback included, as the type cannot tell one from a function, which `redact` masks whole. An
155
+ * `.overwrite()` keeps the type of the schema it is called on, so the type cannot see it.
156
+ * - **A position nested deeper than {@link REDACT_RECURSION_DEPTH} levels is `unknown`**, as `redact` masks it whole
157
+ * from the same depth: every object, array, tuple, record, map and set above it counts one.
158
+ */
159
+ export type RedactedOutput<S> = At<S, S, []>;
160
+
161
+ /**
162
+ * The one recursion limit, in levels of nesting: the type of `MAX_RECURSION_DEPTH`, the constant `redact` stops at. A
163
+ * position nested deeper than this is `unknown`, as `redact` masks it whole there.
164
+ */
165
+ export type REDACT_RECURSION_DEPTH = typeof MAX_RECURSION_DEPTH;
166
+
167
+ /** How deep a position is: one element per level of nesting above it, or `"past"` beyond the limit. */
168
+ type Depth = readonly unknown[] | "past";
169
+
170
+ /** One level of nesting below `D`. */
171
+ type Deeper<D extends Depth> = D extends readonly unknown[]
172
+ ? D["length"] extends REDACT_RECURSION_DEPTH
173
+ ? "past"
174
+ : [...D, 0]
175
+ : "past";
176
+
177
+ /** A schema kind, read off its definition. Anything that is not a schema has a kind no branch below names. */
178
+ type DefOf<S> = S extends { readonly _zod: { readonly def: infer D } } ? D : { readonly type: "not-a-schema" };
179
+
180
+ /** A schema's output, by its own `_zod`. Distributes over a union of schemas. */
181
+ type Out<S> = S extends { readonly _zod: { readonly output: infer O } } ? O : never;
182
+
183
+ /** A Zod schema, as a definition slot holds one. */
184
+ type Schema = { readonly _zod: { readonly output: unknown; readonly def: unknown } };
185
+
186
+ /** The wrappers that are the same position as what they wrap. */
187
+ type Wrapper = "optional" | "nullable" | "default" | "prefault" | "readonly" | "catch" | "nonoptional";
188
+
189
+ /** The kinds a value is walked into. */
190
+ type Structural = "object" | "array" | "tuple" | "record" | "map" | "set";
191
+
192
+ /**
193
+ * The schema one of the kit's three codecs decodes to, or `never` for any other node. A JSON column is known by the type
194
+ * `sqliteJson` names, never by its shape: an adopter's codec built the same way is opaque, as it is to `redact`.
195
+ */
196
+ type KitCodec<S> = S extends typeof SQLiteDate | typeof SQLiteBoolean
197
+ ? DefOf<S> extends { out: infer O }
198
+ ? O
199
+ : never
200
+ : SqliteJsonSchema<S>;
201
+
202
+ /**
203
+ * Whether a schema is a marked node: every value its output holds, `null` and `undefined` aside, carries a privacy
204
+ * brand, and the brand is its own. A union with one marked option among others is not one; it is read option by
205
+ * option. Nor is a pipe whose every output value takes every privacy brand it has from what it pipes into, such as
206
+ * `z.email().pipe(pii(z.string()))` or a transform that returns a marked value: the mark is beneath an opaque node, so
207
+ * `redact` masks it whole and the type is `unknown`. A marker on the pipe itself is the pipe's own, though one option
208
+ * of what it pipes into carries the same class: `pii(sqliteJson(z.union([pii(z.boolean()), z.array(z.number())])))`
209
+ * brands its array with `pii` too, and only the pipe's own marker can have put it there.
210
+ */
211
+ type IsMarkedNode<S> = [Exclude<Out<S>, null | undefined>] extends [never]
212
+ ? false
213
+ : false extends IsMarked<Exclude<Out<S>, null | undefined>>
214
+ ? false
215
+ : DefOf<S> extends { type: "pipe"; out: infer O }
216
+ ? true extends LacksBrand<Exclude<Out<O>, null | undefined>, PrivacyBrands<Out<S>>>
217
+ ? true
218
+ : [Exclude<Out<O>, null | undefined>] extends [never]
219
+ ? true
220
+ : false
221
+ : true;
222
+
223
+ /** The privacy brand keys on `T`'s output. Distributes. */
224
+ type PrivacyBrands<T> = T extends { readonly [z.core.$brand]: infer M } ? Extract<keyof M, `privacy:${string}`> : never;
225
+
226
+ /** Whether some member of `T` lacks a privacy brand in `B`. Distributes. */
227
+ type LacksBrand<T, B> = T extends unknown ? ([Exclude<B, PrivacyBrands<T>>] extends [never] ? false : true) : never;
228
+
229
+ /** The shape each kind of schema produces, as `kindsOf` reads it at runtime. */
230
+ interface SchemaKinds {
231
+ string: "string";
232
+ template_literal: "string";
233
+ number: "number";
234
+ nan: "number";
235
+ bigint: "bigint";
236
+ boolean: "boolean";
237
+ symbol: "symbol";
238
+ function: "function";
239
+ date: "date";
240
+ object: "object";
241
+ record: "object";
242
+ array: "array";
243
+ tuple: "array";
244
+ map: "map";
245
+ set: "set";
246
+ }
247
+
248
+ /** The shape of a value of type `T`, as `kindOfValue` reads it at runtime. Distributes; every shape for `unknown`. */
249
+ type OutKind<T> = T extends null | undefined
250
+ ? never
251
+ : T extends string
252
+ ? "string"
253
+ : T extends number
254
+ ? "number"
255
+ : T extends bigint
256
+ ? "bigint"
257
+ : T extends boolean
258
+ ? "boolean"
259
+ : T extends symbol
260
+ ? "symbol"
261
+ : T extends Date
262
+ ? "date"
263
+ : T extends readonly unknown[]
264
+ ? "array"
265
+ : T extends ReadonlyMap<unknown, unknown>
266
+ ? "map"
267
+ : T extends ReadonlySet<unknown>
268
+ ? "set"
269
+ : T extends (...args: never[]) => unknown
270
+ ? "function"
271
+ : T extends object
272
+ ? "object"
273
+ : ValueKind;
274
+
275
+ /**
276
+ * The shapes a schema's output can have, read the way `kindsOf` reads them: through wrappers, the options of a union,
277
+ * the sides of an intersection, a lazy and the kit's codecs. Every shape for an opaque node. Distributes.
278
+ */
279
+ type KindOf<S, D extends number = REDACT_TYPE_DEPTH> = [D] extends [never]
280
+ ? TooDeep
281
+ : S extends unknown
282
+ ? DefOf<S> extends { type: Wrapper; innerType: infer I }
283
+ ? KindOf<I, Down<D>>
284
+ : DefOf<S> extends { type: "union"; options: readonly (infer O)[] }
285
+ ? KindOf<O, Down<D>>
286
+ : DefOf<S> extends { type: "intersection"; left: infer L; right: infer R }
287
+ ? Extract<KindOf<L, Down<D>>, KindOf<R, Down<D>>>
288
+ : DefOf<S> extends { type: "lazy"; getter: () => infer I }
289
+ ? KindOf<I, Down<D>>
290
+ : DefOf<S> extends { type: infer T extends keyof SchemaKinds }
291
+ ? SchemaKinds[T]
292
+ : DefOf<S> extends { type: "literal" | "enum" }
293
+ ? OutKind<Out<S>>
294
+ : DefOf<S> extends { type: "null" | "undefined" | "void" | "never" }
295
+ ? never
296
+ : [KitCodec<S>] extends [never]
297
+ ? ValueKind
298
+ : KitCodec<S> extends infer C
299
+ ? KindOf<C, Down<D>>
300
+ : never
301
+ : never;
302
+
303
+ /**
304
+ * The shapes of value a position masks: every shape for a mark reached through no union option, and, for one reached
305
+ * through options, the shapes every option on the way has. `never` where nothing here is marked. Distributes.
306
+ */
307
+ type MaskedKinds<S, G = ValueKind, D extends number = REDACT_TYPE_DEPTH> = [D] extends [never]
308
+ ? TooDeep
309
+ : S extends unknown
310
+ ? IsMarkedNode<S> extends true
311
+ ? G
312
+ : DefOf<S> extends { type: Wrapper; innerType: infer I }
313
+ ? MaskedKinds<I, G, Down<D>>
314
+ : DefOf<S> extends { type: "union"; options: readonly (infer O)[] }
315
+ ? Gated<O, G, Down<D>>
316
+ : DefOf<S> extends { type: "intersection"; left: infer L; right: infer R }
317
+ ? MaskedKinds<L, G, Down<D>> | MaskedKinds<R, G, Down<D>>
318
+ : DefOf<S> extends { type: "lazy"; getter: () => infer I }
319
+ ? MaskedKinds<I, G, Down<D>>
320
+ : [KitCodec<S>] extends [never]
321
+ ? never
322
+ : MaskedKinds<KitCodec<S>, G, Down<D>>
323
+ : never;
324
+
325
+ /**
326
+ * Each union option's marks, narrowed to the shapes that option has. Distributes over the options. An option whose
327
+ * shapes the type cannot follow to the end leaves the position {@link TooDeep}.
328
+ */
329
+ type Gated<O, G, D extends number> = O extends unknown
330
+ ? TooDeep extends KindOf<O>
331
+ ? TooDeep
332
+ : MaskedKinds<O, Extract<G, KindOf<O>>, D>
333
+ : never;
334
+
335
+ /** A structural node's shape, where a mark masks it whole. */
336
+ type StructuralKind<S> =
337
+ DefOf<S> extends { type: "object" | "record" }
338
+ ? "object"
339
+ : DefOf<S> extends { type: "array" | "tuple" }
340
+ ? "array"
341
+ : DefOf<S> extends { type: "map" }
342
+ ? "map"
343
+ : DefOf<S> extends { type: "set" }
344
+ ? "set"
345
+ : never;
346
+
347
+ /** An output with each value of a masked shape `M` masked to a `string`. Distributes; `unknown` stays `unknown`. */
348
+ type MaskOut<T, M> = unknown extends T
349
+ ? T
350
+ : T extends null | undefined
351
+ ? T
352
+ : [OutKind<T>] extends [never]
353
+ ? T
354
+ : OutKind<T> extends M
355
+ ? string
356
+ : T;
357
+
358
+ /**
359
+ * Every node at a position: `S` flattened through its wrappers, the options of a union, the sides of an intersection,
360
+ * each lazy and the kit's codecs, stopping at a marked node. Distributes over a union of schemas.
361
+ */
362
+ type Nodes<S, D extends number = REDACT_TYPE_DEPTH> = [D] extends [never]
363
+ ? TooDeep
364
+ : S extends unknown
365
+ ? IsMarkedNode<S> extends true
366
+ ? S
367
+ : IsMadeCatch<S> extends true
368
+ ? S
369
+ : DefOf<S> extends { type: Wrapper; innerType: infer I }
370
+ ? Nodes<I, Down<D>>
371
+ : DefOf<S> extends { type: "union"; options: readonly (infer O)[] }
372
+ ? Nodes<O, Down<D>>
373
+ : DefOf<S> extends { type: "intersection"; left: infer L; right: infer R }
374
+ ? Nodes<L, Down<D>> | Nodes<R, Down<D>>
375
+ : DefOf<S> extends { type: "lazy"; getter: () => infer I }
376
+ ? Nodes<I, Down<D>>
377
+ : [KitCodec<S>] extends [never]
378
+ ? S
379
+ : Nodes<KitCodec<S>, Down<D>>
380
+ : never;
381
+
382
+ /**
383
+ * Whether a schema is a `.catch()` over a structure. A fallback function makes a new value, so `redact` masks it whole
384
+ * over a mark, as it does a transform; a constant one is walked. The type cannot tell the two apart, so it reads every
385
+ * such catch as the node it may be: `unknown` where a mark sits beneath it, and its own output where none does.
386
+ */
387
+ type IsMadeCatch<S> =
388
+ DefOf<S> extends { type: "catch"; innerType: infer I }
389
+ ? [Extract<KindOf<I>, "object" | "array" | "map" | "set">] extends [never]
390
+ ? false
391
+ : true
392
+ : false;
393
+
394
+ /**
395
+ * How many levels of wrapper, choice and lazy {@link Nodes} flattens at one position. Past it the position is typed
396
+ * `unknown`, never guessed: `redact` walks any number of them, so a concrete type there could be wrong.
397
+ */
398
+ export type REDACT_TYPE_DEPTH = 16;
399
+
400
+ /**
401
+ * What {@link Nodes}, {@link MaskedKinds} and {@link KindOf} answer where they run out of {@link REDACT_TYPE_DEPTH}: a
402
+ * kind no value has and a node no schema is, so a position that holds it is typed `unknown`.
403
+ */
404
+ type TooDeep = "past-the-type-depth";
405
+
406
+ /** Whether the type could not follow a position's wrappers and choices to the end. */
407
+ type Unfollowed<C> = TooDeep extends Nodes<C> ? true : TooDeep extends MaskedKinds<C> ? true : false;
408
+
409
+ /** Whether a node is one the walk goes into. */
410
+ type IsStructural<S> = DefOf<S> extends { type: Structural } ? true : false;
411
+
412
+ /** A search's answer: `true` when a mark was found, `"deep"` when none was but it ran out of depth. */
413
+ type Verdict<R> = true extends R ? true : "deep" extends R ? "deep" : false;
414
+
415
+ /**
416
+ * Whether a schema carries a mark anywhere beneath it: `true`, `false`, or `"deep"` where the search ran past the one
417
+ * recursion limit, or may. It reads level by level, every schema once; as the runtime search does, a level is one more
418
+ * object, array, tuple, record, map, set or lazy. It is `"deep"` wherever it meets a recursion, a getter or a lazy
419
+ * that comes round to a schema above it: a type cannot tell one defined once, which the runtime reads to its end, from
420
+ * one built anew each read, which reaches the limit and is masked whole. So is a schema annotated `z.ZodType<T>`,
421
+ * which names no kind the search could read inside.
422
+ */
423
+ type HasMark<S> = SearchLevel<S, never, never, []>;
424
+
425
+ /**
426
+ * One round of the search. `Cur` is still to read at depth `L`, `Next` waits for the level below, and `Seen` has been
427
+ * read. A schema is seen when it and one already read are each assignable to the other.
428
+ */
429
+ type SearchLevel<Cur, Next, Seen, L extends readonly unknown[]> = [Cur] extends [never]
430
+ ? [Next] extends [never]
431
+ ? false
432
+ : SearchLevel<Next, never, Seen, [...L, 0]>
433
+ : true extends Recurs<Cur, Seen>
434
+ ? "deep"
435
+ : Unseen<Cur, Seen> extends infer New
436
+ ? [New] extends [never]
437
+ ? SearchLevel<never, Next, Seen, L>
438
+ : true extends AnyBranded<New>
439
+ ? true
440
+ : true extends Unnamed<New>
441
+ ? "deep"
442
+ : [Nested<New>] extends [never]
443
+ ? SearchLevel<Children<New>, Next, Seen | New, L>
444
+ : L["length"] extends REDACT_RECURSION_DEPTH
445
+ ? "deep"
446
+ : SearchLevel<Children<Flat<New>>, Next | Children<Nested<New>>, Seen | New, L>
447
+ : never;
448
+
449
+ /**
450
+ * Whether a schema met again is a recursion: one among `Cur` already read, a level counted at it, that reaches itself.
451
+ * A schema used twice at two depths is met again too, and reaches no copy of itself. Distributes.
452
+ */
453
+ type Recurs<Cur, Seen> =
454
+ Nested<Cur> extends infer R
455
+ ? R extends unknown
456
+ ? true extends IsSeen<R, Seen>
457
+ ? Reaches<Children<R>, R, never>
458
+ : false
459
+ : never
460
+ : never;
461
+
462
+ /** Whether `T` is among the schemas beneath `Cur`, each read once. */
463
+ type Reaches<Cur, T, Seen> = [Cur] extends [never]
464
+ ? false
465
+ : true extends IsSeen<T, Cur>
466
+ ? true
467
+ : Reaches<Children<Unseen<Cur, Seen>>, T, Seen | Cur>;
468
+
469
+ /** The schemas among `N` not yet read. Distributes. */
470
+ type Unseen<N, Seen> = N extends unknown ? (true extends IsSeen<N, Seen> ? never : N) : never;
471
+
472
+ /** Whether `N` is one of `Seen`: each assignable to the other. */
473
+ type IsSeen<N, Seen> = Seen extends unknown
474
+ ? [N] extends [Seen]
475
+ ? [Seen] extends [N]
476
+ ? true
477
+ : false
478
+ : false
479
+ : never;
480
+
481
+ /** Whether any schema among `N` has a privacy brand on its output. Distributes. */
482
+ type AnyBranded<N> = N extends Schema ? IsMarked<Out<N>> : false;
483
+
484
+ /** The schemas among `N` a level of nesting is counted at. Distributes. */
485
+ type Nested<N> = N extends unknown ? (DefOf<N> extends { type: Structural | "lazy" } ? N : never) : never;
486
+
487
+ /** The schemas among `N` read at the level they sit at. Distributes. */
488
+ type Flat<N> = N extends unknown ? (DefOf<N> extends { type: Structural | "lazy" } ? never : N) : never;
489
+
490
+ /**
491
+ * Every schema a definition holds: a schema, a lazy's getter, a list of schemas, or an object's shape. An object's
492
+ * definition names its catchall only as a schema of any kind, so the catchall is read from its config. Distributes.
493
+ */
494
+ type Children<N> = N extends Schema
495
+ ?
496
+ | { [K in keyof DefOf<N>]-?: K extends "checks" | "catchall" ? never : SlotSchemas<DefOf<N>[K]> }[keyof DefOf<N>]
497
+ | OpenCatchall<N>
498
+ : never;
499
+
500
+ /** The schemas one slot of a definition holds. */
501
+ type SlotSchemas<V> = V extends Schema
502
+ ? V
503
+ : V extends () => infer R
504
+ ? Extract<R, Schema>
505
+ : V extends readonly (infer E)[]
506
+ ? Extract<E, Schema>
507
+ : V extends object
508
+ ? { [K in keyof V]-?: V[K] extends Schema ? V[K] : never }[keyof V]
509
+ : never;
510
+
511
+ /** Whether an opaque node among `N` carries a mark beneath it, or may. Distributes. */
512
+ type AnyOpaqueMarked<N> = N extends unknown
513
+ ? IsMarkedNode<N> extends true
514
+ ? false
515
+ : IsStructural<N> extends true
516
+ ? false
517
+ : HasMark<N>
518
+ : never;
519
+
520
+ /** Whether a node's schema type names no single kind: one typed `z.ZodType<T>`, whose definition could be any. */
521
+ type Unnamed<N> = N extends unknown
522
+ ? DefOf<N> extends { type: infer T }
523
+ ? string extends T
524
+ ? true
525
+ : IsUnion<T>
526
+ : true
527
+ : never;
528
+
529
+ /** Whether a union of string literals has more than one member. */
530
+ type IsUnion<T, U = T> = T extends unknown ? ([U] extends [T] ? false : true) : never;
531
+
532
+ /**
533
+ * One member's schema `S` at a position `D` levels deep, against `C`, every schema that reaches it. `C` decides whether
534
+ * the position is masked, and what is at each position below it; `S` decides the shape this member keeps.
535
+ */
536
+ type At<S, C, D extends Depth> = [S] extends [never]
537
+ ? never
538
+ : [D] extends ["past"]
539
+ ? unknown
540
+ : IsAny<Out<S>> extends true
541
+ ? unknown
542
+ : Unfollowed<C> extends true
543
+ ? unknown
544
+ : Verdict<AnyOpaqueMarked<Nodes<C>>> extends false
545
+ ? Masked<S, C, D, MaskedKinds<C>>
546
+ : unknown;
547
+
548
+ /**
549
+ * A position whose values of shape `M` are masked: a `string` where every shape is, and otherwise each member keeps
550
+ * its shape, with its values of a masked shape a `string`.
551
+ */
552
+ type Masked<S, C, D extends Depth, M> = [ValueKind] extends [M]
553
+ ? string | Extract<Out<S>, null | undefined>
554
+ : true extends Unnamed<Nodes<C>>
555
+ ? unknown
556
+ : Shaped<S, Nodes<C>, D, M>;
557
+
558
+ /** A structural result keeps a brand that is not a privacy class, as the copy is the same kind of value. */
559
+ type Rebrand<S, X> =
560
+ Out<S> extends { readonly [z.core.$brand]: infer B } ? KeptBrand<X, Exclude<keyof B, `privacy:${string}`>> : X;
561
+
562
+ /** `X` with the brands `K`, or `X` itself where there are none. */
563
+ type KeptBrand<X, K> = [K] extends [never] ? X : X & z.core.$brand<K & (string | number | symbol)>;
564
+
565
+ /**
566
+ * Keys renamed to `string` where a record at the position masks them: a string key, a number key's included, where its
567
+ * key schema marks any shape but a symbol, and a symbol key where it marks a symbol.
568
+ */
569
+ type KeyName<K, N> = K extends typeof z.core.$brand
570
+ ? never
571
+ : K extends symbol
572
+ ? "symbol" extends KeyMasks<N>
573
+ ? string
574
+ : K
575
+ : MasksStringKeys<N> extends true
576
+ ? string
577
+ : K;
578
+
579
+ /** Whether a record at the position masks its string keys: its key schema marks any shape but a symbol. */
580
+ type MasksStringKeys<N> = [Exclude<KeyMasks<N>, "symbol">] extends [never] ? false : true;
581
+
582
+ /**
583
+ * The shapes of key a record at the position masks. A key schema with an opaque node over a mark, such as
584
+ * `z.email().pipe(pii(z.string()))`, masks a key of every shape, as `redact` masks it whole, so its keys are plain
585
+ * strings and never keep the brand the opaque node's output carries.
586
+ */
587
+ type KeyMasks<N> =
588
+ Unfollowed<RecordKeys<N>> extends true
589
+ ? ValueKind
590
+ : Verdict<AnyOpaqueMarked<Nodes<RecordKeys<N>>>> extends false
591
+ ? MaskedKinds<RecordKeys<N>>
592
+ : ValueKind;
593
+
594
+ /**
595
+ * One schema at a position that is walked into, against `N`, every node at the position, with the values of a shape
596
+ * in `M` masked: a marked node is a `string`, a wrapper keeps what it adds, a union and an intersection keep their
597
+ * form, and a structural node maps by every node's schemas, or is a `string` where its shape is masked. Any other
598
+ * node, unmarked and with nothing marked beneath it, keeps its output type, which is what `redact` hands back.
599
+ */
600
+ type Shaped<S, N, D extends Depth, M> = S extends unknown
601
+ ? IsMarkedNode<S> extends true
602
+ ? string | Extract<Out<S>, null | undefined>
603
+ : StructuralKind<S> extends infer K
604
+ ? [K] extends [never]
605
+ ? Rebrand<S, ShapedNode<S, N, D, M>>
606
+ : K extends M
607
+ ? string
608
+ : Rebrand<S, ShapedNode<S, N, D, M>>
609
+ : never
610
+ : never;
611
+
612
+ /** {@link Shaped}, before a brand that is not a privacy class is put back. */
613
+ type ShapedNode<S, N, D extends Depth, M> = S extends unknown
614
+ ? DefOf<S> extends { type: "optional"; innerType: infer I }
615
+ ? Shaped<I, N, D, M> | undefined
616
+ : DefOf<S> extends { type: "nullable"; innerType: infer I }
617
+ ? Shaped<I, N, D, M> | null
618
+ : DefOf<S> extends { type: "default" | "prefault" | "nonoptional"; innerType: infer I }
619
+ ? Exclude<Shaped<I, N, D, M>, undefined>
620
+ : DefOf<S> extends { type: "catch"; innerType: infer I }
621
+ ? IsMadeCatch<S> extends true
622
+ ? MaskOut<Out<S>, M>
623
+ : Shaped<I, N, D, M>
624
+ : DefOf<S> extends { type: "readonly"; innerType: infer I }
625
+ ? z.core.util.MakeReadonly<Shaped<I, N, D, M>>
626
+ : DefOf<S> extends { type: "lazy"; getter: () => infer I }
627
+ ? Shaped<I, N, D, M>
628
+ : DefOf<S> extends { type: "union"; options: readonly (infer O)[] }
629
+ ? Shaped<O, N, D, M>
630
+ : DefOf<S> extends { type: "intersection"; left: infer L; right: infer R }
631
+ ? true extends HoldsRecord<Nodes<L>> | HoldsRecord<Nodes<R>>
632
+ ? unknown
633
+ : Shaped<L, N, D, M> & Shaped<R, N, D, M>
634
+ : DefOf<S> extends { type: Structural }
635
+ ? Walked<S, N, D>
636
+ : [KitCodec<S>] extends [never]
637
+ ? MaskOut<Out<S>, M>
638
+ : Shaped<KitCodec<S>, N, D, M>
639
+ : never;
640
+
641
+ /**
642
+ * Whether a record is among `N`, the nodes on one side of an intersection. A record's key schema renames the other
643
+ * side's keys at runtime, a masked key taking a placeholder name, so neither side's own keys describe the copy: the
644
+ * intersection is typed `unknown` rather than a narrower type that could be wrong. Distributes.
645
+ */
646
+ type HoldsRecord<N> = N extends unknown ? (DefOf<N> extends { type: "record" } ? true : false) : never;
647
+
648
+ /** A structural node, mapped by every node's schemas at the position. */
649
+ type Walked<S, N, D extends Depth, E extends Depth = Deeper<D>> =
650
+ DefOf<S> extends { type: "object"; shape: infer Shape }
651
+ ? WithNamed<
652
+ {
653
+ [K in keyof Out<S> as KeyName<K, N>]: K extends keyof Shape
654
+ ? At<Shape[K], Fields<N, K>, E>
655
+ : At<OpenCatchall<S>, Catchalls<N>, E> | NamedAt<OpenCatchall<S>, N, Exclude<NamedKeys<N>, keyof Shape>, E>;
656
+ },
657
+ [OpenCatchall<S>] extends [never] ? never : OpenCatchall<S>,
658
+ N,
659
+ Exclude<NamedKeys<N>, keyof Shape>,
660
+ E
661
+ >
662
+ : DefOf<S> extends { type: "record"; valueType: infer V }
663
+ ? string extends keyof Out<S>
664
+ ? WithNamed<
665
+ { [K in keyof Out<S> as KeyName<K, N>]: At<V, Fields<N, K>, E> | NamedAt<V, N, NamedKeys<N>, E> },
666
+ V,
667
+ N,
668
+ NamedKeys<N>,
669
+ E
670
+ >
671
+ : // A finite key set whose string keys are masked: each comes back a placeholder, so they are keyed by string.
672
+ // Mapped over the renamed keys themselves, as a remap drops a branded literal key rather than renaming it.
673
+ MasksStringKeys<N> extends true
674
+ ? {
675
+ [K in KeyName<keyof Out<S>, N>]: At<
676
+ V,
677
+ Fields<N, K extends symbol ? K : Exclude<keyof Out<S>, symbol>>,
678
+ E
679
+ >;
680
+ }
681
+ : { [K in keyof Out<S> as KeyName<K, N>]: At<V, Fields<N, K>, E> }
682
+ : DefOf<S> extends { type: "array"; element: infer El }
683
+ ? Beyond<El, N, [], E>
684
+ : DefOf<S> extends {
685
+ type: "tuple";
686
+ items: infer Items extends readonly z.core.SomeType[];
687
+ rest: infer R extends z.core.SomeType | null;
688
+ }
689
+ ? // The tuple's own items, rebuilt from them so a brand on it does not turn it into an array, then its rest.
690
+ z.output<z.ZodTuple<Items, null>> extends infer O extends readonly unknown[]
691
+ ? [
692
+ ...{ -readonly [K in keyof O]: K extends keyof Items ? At<Items[K], Elements<N, K>, E> : never },
693
+ ...(R extends z.core.SomeType ? Beyond<R, N, [...Items], E> : []),
694
+ ]
695
+ : never
696
+ : DefOf<S> extends { type: "map"; keyType: infer K; valueType: infer V }
697
+ ? Map<At<K, MapKeys<N>, E>, At<V, MapValues<N>, E>>
698
+ : DefOf<S> extends { type: "set"; valueType: infer V }
699
+ ? Set<At<V, SetElements<N>, E>>
700
+ : never;
701
+
702
+ /**
703
+ * The keys the objects at a position name. A record or an open object beside them takes each one where the value has
704
+ * it, at the position every schema there gives that key: `{ a: pii(…) }` beside a record masks the record's `a`.
705
+ */
706
+ type NamedKeys<N> = N extends unknown
707
+ ? DefOf<N> extends { type: "object"; shape: infer Shape }
708
+ ? Extract<keyof Shape, string>
709
+ : never
710
+ : never;
711
+
712
+ /** What a key in `Keys` holds, against every schema there, for a value parsed by `V`. Distributes over the keys. */
713
+ type NamedAt<V, N, Keys, D extends Depth> = Keys extends unknown ? At<V, Fields<N, Keys>, D> : never;
714
+
715
+ /** `Mapped`, with each key in `Keys` an optional field of its own where `V` lets a key no shape names through. */
716
+ type WithNamed<Mapped, V, N, Keys extends PropertyKey, D extends Depth> = [V] extends [never]
717
+ ? Mapped
718
+ : [Keys] extends [never]
719
+ ? Mapped
720
+ : Mapped & { [K in Keys as KeyName<K, N>]?: At<V, Fields<N, K>, D> };
721
+
722
+ /**
723
+ * An array's element, or a tuple's rest, from index `I["length"]` on: optional and one by one while a tuple beside it
724
+ * names the index, so each takes the items there, then any number past every tuple's items.
725
+ */
726
+ type Beyond<E, N, I extends unknown[], D extends Depth> =
727
+ true extends NamesIndex<N, `${I["length"]}`>
728
+ ? [At<E, Elements<N, `${I["length"]}`>, D>?, ...Beyond<E, N, [...I, unknown], D>]
729
+ : At<E, Past<N>, D>[];
730
+
731
+ /** Whether a tuple at the position names index `K`. */
732
+ type NamesIndex<N, K extends string> = N extends unknown
733
+ ? DefOf<N> extends { type: "tuple"; items: infer Items extends readonly unknown[] }
734
+ ? K extends keyof Items
735
+ ? true
736
+ : false
737
+ : false
738
+ : never;
739
+
740
+ /** The schemas at an index past every tuple's items: each array's element and each tuple's rest. */
741
+ type Past<N> = N extends unknown
742
+ ? DefOf<N> extends { type: "array"; element: infer E }
743
+ ? E
744
+ : DefOf<N> extends { type: "tuple"; rest: infer R }
745
+ ? Exclude<R, null>
746
+ : never
747
+ : never;
748
+
749
+ /** The schemas at object key `K`: each object's field there or its catchall, and each record's value. */
750
+ type Fields<N, K> = N extends unknown
751
+ ? DefOf<N> extends { type: "object"; shape: infer Shape }
752
+ ? K extends keyof Shape
753
+ ? Shape[K]
754
+ : OpenCatchall<N>
755
+ : DefOf<N> extends { type: "record"; valueType: infer V }
756
+ ? V
757
+ : never
758
+ : never;
759
+
760
+ /**
761
+ * An object's catchall when it lets an extra key through, or `never`. Zod's object type keeps the catchall only in
762
+ * its config, `$catchall<T>`, and TypeScript reads `T` back out of that alias. A loose object's config is `$loose`,
763
+ * which names no schema, so its catchall is `z.unknown()`, as Zod parses it: read out of `$loose`, `T` would be a
764
+ * schema of no kind, which the search beneath it reads as one that may be marked.
765
+ */
766
+ type OpenCatchall<N> = N extends { readonly _zod: { readonly config: infer Config } }
767
+ ? Config extends { readonly out: infer O }
768
+ ? string extends keyof O
769
+ ? [z.core.$loose] extends [Config]
770
+ ? z.ZodUnknown
771
+ : Config extends z.core.$catchall<infer T>
772
+ ? T
773
+ : never
774
+ : never
775
+ : never
776
+ : never;
777
+
778
+ /** The schemas at a key no object names. */
779
+ type Catchalls<N> = N extends unknown
780
+ ? DefOf<N> extends { type: "object" }
781
+ ? OpenCatchall<N>
782
+ : DefOf<N> extends { type: "record"; valueType: infer V }
783
+ ? V
784
+ : never
785
+ : never;
786
+
787
+ /** The schemas a record's keys are parsed by. */
788
+ type RecordKeys<N> = N extends unknown ? (DefOf<N> extends { type: "record"; keyType: infer K } ? K : never) : never;
789
+
790
+ /** The schemas of a map's keys, a map's values and a set's elements. */
791
+ type MapKeys<N> = N extends unknown ? (DefOf<N> extends { type: "map"; keyType: infer K } ? K : never) : never;
792
+ type MapValues<N> = N extends unknown ? (DefOf<N> extends { type: "map"; valueType: infer V } ? V : never) : never;
793
+ type SetElements<N> = N extends unknown ? (DefOf<N> extends { type: "set"; valueType: infer V } ? V : never) : never;
794
+
795
+ /** The schemas at element `K`, an index: each array's element, and each tuple's item there or its rest. */
796
+ type Elements<N, K> = N extends unknown
797
+ ? DefOf<N> extends { type: "array"; element: infer E }
798
+ ? E
799
+ : DefOf<N> extends { type: "tuple"; items: infer Items extends readonly unknown[]; rest: infer R }
800
+ ? K extends keyof Items
801
+ ? Items[K]
802
+ : Exclude<R, null>
803
+ : never
804
+ : never;