@cosmicdrift/kumiko-framework 0.385.0 → 0.387.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 (298) hide show
  1. package/LICENSE +21 -57
  2. package/README.md +2 -2
  3. package/agents/widgets.md +39 -39
  4. package/dist/api/api-constants.js +2 -2
  5. package/dist/api/auth-middleware.js +7 -7
  6. package/dist/api/auth-rate-limiters.js +7 -3
  7. package/dist/api/auth-routes-mfa.js +1 -1
  8. package/dist/api/auth-routes-session.js +1 -1
  9. package/dist/api/auth-routes-shared.js +7 -3
  10. package/dist/api/auth-routes-signup.js +1 -1
  11. package/dist/api/client-ip.js +3 -1
  12. package/dist/api/extra-route.js +1 -1
  13. package/dist/api/pii-leak-guard.js +4 -2
  14. package/dist/api/readiness.js +5 -5
  15. package/dist/api/redis-sse-broker.js +8 -6
  16. package/dist/api/request-context.d.ts +2 -0
  17. package/dist/api/request-context.js +16 -7
  18. package/dist/api/routes.js +2 -2
  19. package/dist/api/server.js +34 -33
  20. package/dist/api/sse-broker.js +1 -1
  21. package/dist/api/sse-route.d.ts +13 -13
  22. package/dist/api/sse-route.js +15 -15
  23. package/dist/auth/index.js +4 -4
  24. package/dist/auth/roles.d.ts +4 -4
  25. package/dist/auth/roles.js +24 -24
  26. package/dist/compliance/duration-spec.js +18 -20
  27. package/dist/compliance/index.js +2 -3
  28. package/dist/compliance/override-schema.d.ts +4 -4
  29. package/dist/compliance/override-schema.js +19 -22
  30. package/dist/compliance/profiles.d.ts +26 -29
  31. package/dist/compliance/profiles.js +62 -69
  32. package/dist/compliance/sub-processors.d.ts +28 -30
  33. package/dist/compliance/sub-processors.js +17 -21
  34. package/dist/consumer-cli.js +4 -4
  35. package/dist/crypto/blind-index.js +18 -17
  36. package/dist/crypto/ciphertext-pattern.js +1 -1
  37. package/dist/crypto/event-pii.js +3 -3
  38. package/dist/crypto/kek-source.d.ts +1 -1
  39. package/dist/crypto/kek-source.js +3 -2
  40. package/dist/crypto/kms-adapter.d.ts +1 -1
  41. package/dist/crypto/kms-adapter.js +4 -6
  42. package/dist/crypto/kms-wiring.d.ts +1 -2
  43. package/dist/crypto/kms-wiring.js +2 -2
  44. package/dist/crypto/pg-kms-adapter.js +2 -6
  45. package/dist/crypto/pii-field-encryption.js +4 -4
  46. package/dist/crypto/subject-resolver.d.ts +1 -1
  47. package/dist/crypto/subject-resolver.js +2 -2
  48. package/dist/db/apply-entity-event.d.ts +6 -6
  49. package/dist/db/apply-entity-event.js +55 -55
  50. package/dist/db/blind-index-cleanup.js +7 -7
  51. package/dist/db/collect-table-metas.js +10 -11
  52. package/dist/db/compound-types.d.ts +1 -1
  53. package/dist/db/compound-types.js +12 -12
  54. package/dist/db/cross-tenant-reads.d.ts +8 -0
  55. package/dist/db/cross-tenant-reads.js +23 -0
  56. package/dist/db/cursor.js +3 -4
  57. package/dist/db/dialect.d.ts +2 -2
  58. package/dist/db/dialect.js +2 -2
  59. package/dist/db/eagerload.d.ts +3 -3
  60. package/dist/db/eagerload.js +21 -12
  61. package/dist/db/entity-table-meta.d.ts +2 -2
  62. package/dist/db/entity-table-meta.js +4 -4
  63. package/dist/db/event-store-executor-context.d.ts +1 -1
  64. package/dist/db/event-store-executor-context.js +13 -13
  65. package/dist/db/event-store-executor-read.js +27 -28
  66. package/dist/db/event-store-executor-write.js +65 -70
  67. package/dist/db/located-timestamp.d.ts +11 -11
  68. package/dist/db/located-timestamp.js +29 -30
  69. package/dist/db/migrate-generator.d.ts +1 -1
  70. package/dist/db/migrate-generator.js +26 -19
  71. package/dist/db/migrate-runner.js +25 -25
  72. package/dist/db/money.d.ts +6 -6
  73. package/dist/db/money.js +29 -27
  74. package/dist/db/queries/backfill-pii.js +5 -5
  75. package/dist/db/queries/ddl.js +1 -1
  76. package/dist/db/queries/es-ops.d.ts +1 -1
  77. package/dist/db/queries/es-ops.js +1 -1
  78. package/dist/db/queries/event-consumer.js +3 -3
  79. package/dist/db/queries/event-store.js +4 -2
  80. package/dist/db/queries/projection-rebuild.js +3 -3
  81. package/dist/db/queries/raw-sql.d.ts +2 -2
  82. package/dist/db/queries/raw-sql.js +2 -2
  83. package/dist/db/queries/shadow-swap.js +19 -19
  84. package/dist/db/queries/test-stack.d.ts +4 -1
  85. package/dist/db/queries/test-stack.js +15 -2
  86. package/dist/db/query.d.ts +1 -1
  87. package/dist/db/query.js +6 -6
  88. package/dist/db/rebuild-marker.js +20 -21
  89. package/dist/db/replay-migration-sql.js +2 -2
  90. package/dist/db/schema-inspection.js +4 -5
  91. package/dist/db/table-builder.d.ts +1 -2
  92. package/dist/db/table-builder.js +82 -82
  93. package/dist/db/tenant-db.d.ts +2 -2
  94. package/dist/db/tenant-db.js +9 -2
  95. package/dist/derivatives/delete-stored-file.js +5 -2
  96. package/dist/derivatives/derivatives-context.js +1 -1
  97. package/dist/engine/boot-validator/access-roles.js +4 -3
  98. package/dist/engine/boot-validator/api-ext.js +14 -14
  99. package/dist/engine/boot-validator/config-deps.js +7 -6
  100. package/dist/engine/boot-validator/detail-screens.js +3 -3
  101. package/dist/engine/boot-validator/entity-handler.js +60 -61
  102. package/dist/engine/boot-validator/gdpr-storage.js +4 -4
  103. package/dist/engine/boot-validator/i18n-keys.js +1 -1
  104. package/dist/engine/boot-validator/index.d.ts +2 -2
  105. package/dist/engine/boot-validator/index.js +20 -20
  106. package/dist/engine/boot-validator/nav.js +5 -5
  107. package/dist/engine/boot-validator/ownership.js +12 -9
  108. package/dist/engine/boot-validator/parent-ref.js +1 -1
  109. package/dist/engine/boot-validator/pii-retention.js +50 -57
  110. package/dist/engine/boot-validator/projection-list-screens.js +7 -7
  111. package/dist/engine/boot-validator/query-refs.js +1 -1
  112. package/dist/engine/boot-validator/screens-actions.js +15 -16
  113. package/dist/engine/boot-validator/screens-forms.js +10 -11
  114. package/dist/engine/boot-validator/screens-lists.js +14 -15
  115. package/dist/engine/boot-validator/screens.js +34 -40
  116. package/dist/engine/boot-validator/security-baseline.js +3 -2
  117. package/dist/engine/boot-validator/transfer-graph.js +2 -2
  118. package/dist/engine/boot-validator/workspaces.js +3 -3
  119. package/dist/engine/bridge-stub.js +3 -4
  120. package/dist/engine/build-app-schema.js +75 -75
  121. package/dist/engine/build-config-feature-schema.js +50 -50
  122. package/dist/engine/build-target.js +20 -23
  123. package/dist/engine/codemod/pipeline-codemod.js +20 -13
  124. package/dist/engine/config-helpers.js +4 -4
  125. package/dist/engine/constants.js +2 -2
  126. package/dist/engine/create-app.js +2 -2
  127. package/dist/engine/define-feature.js +12 -11
  128. package/dist/engine/define-handler.js +12 -11
  129. package/dist/engine/define-step.js +1 -1
  130. package/dist/engine/define-workflow.d.ts +5 -5
  131. package/dist/engine/define-workflow.js +6 -6
  132. package/dist/engine/entity-handlers.js +13 -14
  133. package/dist/engine/event-def.js +2 -2
  134. package/dist/engine/extension-names.d.ts +16 -17
  135. package/dist/engine/extension-names.js +37 -38
  136. package/dist/engine/extensions/escape-hatch-usage.js +1 -1
  137. package/dist/engine/extensions/tenant-data.js +2 -2
  138. package/dist/engine/extensions/user-data.d.ts +23 -24
  139. package/dist/engine/factories.d.ts +14 -13
  140. package/dist/engine/factories.js +38 -37
  141. package/dist/engine/feature-ast/entity-field-types.js +1 -1
  142. package/dist/engine/feature-ast/extractors/handlers.js +1 -1
  143. package/dist/engine/feature-ast/extractors/hooks.js +1 -1
  144. package/dist/engine/feature-ast/extractors/shared.d.ts +2 -3
  145. package/dist/engine/feature-ast/extractors/shared.js +2 -3
  146. package/dist/engine/feature-ast/parse.js +13 -13
  147. package/dist/engine/feature-ast/patch.js +1 -1
  148. package/dist/engine/feature-ast/pattern-change-schema.d.ts +8 -0
  149. package/dist/engine/feature-ast/pattern-change-schema.js +1 -1
  150. package/dist/engine/feature-ast/patterns.d.ts +2 -2
  151. package/dist/engine/feature-ast/render.js +2 -2
  152. package/dist/engine/feature-config-events-jobs.js +15 -12
  153. package/dist/engine/feature-entity-handlers.js +9 -5
  154. package/dist/engine/feature-manifest.d.ts +9 -9
  155. package/dist/engine/feature-manifest.js +6 -7
  156. package/dist/engine/feature-ui-extensions.d.ts +3 -3
  157. package/dist/engine/feature-ui-extensions.js +30 -22
  158. package/dist/engine/field-access.js +5 -6
  159. package/dist/engine/index.d.ts +1 -0
  160. package/dist/engine/index.js +4 -4
  161. package/dist/engine/object-form.d.ts +1 -0
  162. package/dist/engine/object-form.js +14 -4
  163. package/dist/engine/ownership.js +3 -3
  164. package/dist/engine/parse-ref-target.js +5 -7
  165. package/dist/engine/pattern-library/index.js +2 -2
  166. package/dist/engine/pattern-library/library.js +2 -2
  167. package/dist/engine/pattern-library/types.js +3 -3
  168. package/dist/engine/pipeline.js +2 -2
  169. package/dist/engine/project-app-schema-for-roles.js +1 -1
  170. package/dist/engine/projection-helpers.js +9 -9
  171. package/dist/engine/qualified-name.js +2 -2
  172. package/dist/engine/registry-facade.js +1 -1
  173. package/dist/engine/registry-ingest.js +12 -12
  174. package/dist/engine/registry-state.js +17 -19
  175. package/dist/engine/registry-validate.js +12 -12
  176. package/dist/engine/run-in.js +2 -2
  177. package/dist/engine/run-pipeline.js +7 -0
  178. package/dist/engine/schema-builder.js +40 -38
  179. package/dist/engine/screen-filter-ops.js +17 -20
  180. package/dist/engine/screen-helpers.js +4 -3
  181. package/dist/engine/state-machine.d.ts +12 -12
  182. package/dist/engine/state-machine.js +7 -7
  183. package/dist/engine/steps/_resolver-utils.js +4 -3
  184. package/dist/engine/steps/for-each.js +4 -4
  185. package/dist/engine/steps/unsafe-projection-delete.js +1 -1
  186. package/dist/engine/steps/unsafe-projection-upsert.js +4 -4
  187. package/dist/engine/steps/wait-for-event.js +4 -4
  188. package/dist/engine/steps/workflow-system-events.js +3 -3
  189. package/dist/engine/tier-resolver-extension.d.ts +29 -27
  190. package/dist/engine/tier-resolver-extension.js +26 -26
  191. package/dist/engine/transfer-adjacency.js +2 -2
  192. package/dist/engine/validate-projection-allowlist.js +7 -27
  193. package/dist/engine/walk-step-instances.d.ts +2 -0
  194. package/dist/engine/walk-step-instances.js +38 -0
  195. package/dist/engine/where-rule-lint.js +1 -1
  196. package/dist/engine/write-handler-qn-extract.js +1 -1
  197. package/dist/entrypoint/index.js +3 -3
  198. package/dist/env/index.d.ts +7 -6
  199. package/dist/env/index.js +10 -9
  200. package/dist/errors/transition-details.js +7 -7
  201. package/dist/errors/write-error-info.d.ts +6 -6
  202. package/dist/errors/write-error-info.js +6 -6
  203. package/dist/es-ops/context.d.ts +9 -9
  204. package/dist/es-ops/context.js +28 -28
  205. package/dist/es-ops/index.js +7 -9
  206. package/dist/es-ops/operations-schema.js +4 -10
  207. package/dist/es-ops/runner.d.ts +11 -11
  208. package/dist/es-ops/runner.js +49 -53
  209. package/dist/es-ops/types.d.ts +55 -55
  210. package/dist/es-ops/types.js +11 -11
  211. package/dist/event-store/admin-api.js +6 -7
  212. package/dist/event-store/errors.js +1 -1
  213. package/dist/event-store/event-store.js +2 -2
  214. package/dist/event-store/rebuild-dead-letter.js +1 -1
  215. package/dist/files/feature.js +9 -10
  216. package/dist/files/file-handle.js +5 -6
  217. package/dist/files/file-ref-entity.js +15 -15
  218. package/dist/files/file-ref-table.js +7 -8
  219. package/dist/files/file-routes.d.ts +7 -0
  220. package/dist/files/file-routes.js +11 -5
  221. package/dist/files/in-memory-provider.js +8 -9
  222. package/dist/files/local-provider.js +18 -25
  223. package/dist/files/provider-resolver.d.ts +7 -7
  224. package/dist/files/storage-tracking.js +2 -2
  225. package/dist/files/zip-stream.d.ts +12 -19
  226. package/dist/files/zip-stream.js +44 -63
  227. package/dist/i18n/required-surface-keys.d.ts +1 -1
  228. package/dist/i18n/required-surface-keys.js +8 -8
  229. package/dist/internal/stack-support.d.ts +1 -1
  230. package/dist/internal/stack-support.js +1 -1
  231. package/dist/jobs/job-runner-helpers.d.ts +1 -2
  232. package/dist/jobs/job-runner-helpers.js +8 -18
  233. package/dist/jobs/job-runner-schedulers.d.ts +1 -1
  234. package/dist/jobs/job-runner-schedulers.js +3 -4
  235. package/dist/jobs/job-runner.js +17 -18
  236. package/dist/lifecycle/lifecycle.js +3 -5
  237. package/dist/lifecycle/signal-handlers.js +5 -4
  238. package/dist/logging/utils.d.ts +2 -1
  239. package/dist/logging/utils.js +38 -10
  240. package/dist/migrations/index.js +1 -1
  241. package/dist/migrations/kumiko-drift.js +14 -13
  242. package/dist/migrations/pending-rebuilds.d.ts +21 -20
  243. package/dist/migrations/pending-rebuilds.js +27 -27
  244. package/dist/migrations/projection-table-index.d.ts +3 -3
  245. package/dist/migrations/projection-table-index.js +8 -8
  246. package/dist/observability/metric-validator.js +1 -1
  247. package/dist/observability/metrics-handle.js +3 -3
  248. package/dist/pipeline/append-event-core.js +11 -2
  249. package/dist/pipeline/cascade-handler.d.ts +1 -1
  250. package/dist/pipeline/dispatch-batch.js +2 -2
  251. package/dist/pipeline/dispatch-query.js +10 -10
  252. package/dist/pipeline/dispatch-shared.d.ts +1 -0
  253. package/dist/pipeline/dispatch-shared.js +42 -19
  254. package/dist/pipeline/dispatch-stream.js +1 -1
  255. package/dist/pipeline/dispatch-write.js +3 -3
  256. package/dist/pipeline/dispatcher-utils.d.ts +1 -1
  257. package/dist/pipeline/dispatcher-utils.js +1 -1
  258. package/dist/pipeline/event-consumer-state.js +2 -2
  259. package/dist/pipeline/event-dispatcher-delivery.js +1 -1
  260. package/dist/pipeline/event-dispatcher.js +17 -28
  261. package/dist/pipeline/irreversible-operation-gate.js +1 -1
  262. package/dist/pipeline/lifecycle-pipeline.js +9 -9
  263. package/dist/pipeline/member-read-only-transaction.js +1 -3
  264. package/dist/pipeline/msp-rebuild.js +1 -1
  265. package/dist/pipeline/projection-rebuild.js +13 -12
  266. package/dist/pipeline/system-hooks.js +39 -41
  267. package/dist/pipeline/system-identity-switch.js +1 -3
  268. package/dist/pipeline/tenant-timezone-cache.js +1 -1
  269. package/dist/random/generate.d.ts +29 -29
  270. package/dist/random/generate.js +30 -30
  271. package/dist/random/words.js +20 -20
  272. package/dist/rate-limit/middleware.js +9 -5
  273. package/dist/redis/client.js +2 -2
  274. package/dist/redis/pubsub-signal.js +14 -17
  275. package/dist/schema-cli.js +116 -22
  276. package/dist/search/index.js +4 -4
  277. package/dist/search/purge-subject.js +4 -5
  278. package/dist/search/reindex-entity.js +6 -9
  279. package/dist/time/boot-tz-warning.d.ts +2 -2
  280. package/dist/time/boot-tz-warning.js +8 -8
  281. package/dist/time/iana.js +10 -10
  282. package/dist/time/index.js +9 -9
  283. package/dist/time/legacy-date.d.ts +2 -2
  284. package/dist/time/legacy-date.js +6 -8
  285. package/dist/time/polyfill.js +1 -1
  286. package/dist/time/tz-context.d.ts +1 -1
  287. package/dist/time/tz-context.js +1 -1
  288. package/dist/ui-types/app-schema.js +7 -7
  289. package/dist/ui-types/list-row-meta.js +4 -4
  290. package/dist/upgrade-cli.js +10 -9
  291. package/dist/utils/compare.js +1 -1
  292. package/package.json +4 -4
  293. package/src/changes.json +54 -0
  294. package/src/scripts/codemod/crypto-shredding-testing-move.ts +2 -2
  295. package/src/scripts/codemod/migrate-cross-tenant.ts +1 -1
  296. package/src/scripts/codemod/migrate-open-to-all.ts +1 -1
  297. package/src/scripts/codemod/pii-personal-migration.ts +17 -8
  298. package/src/scripts/codemod/unprocessable-error-details-reason.ts +2 -2
@@ -64,27 +64,25 @@ export interface ComplianceProfile {
64
64
  };
65
65
  }
66
66
  /**
67
- * Profile-Schluessel die der Tenant-Admin im Onboarding waehlen darf.
68
- * `minimal-no-region` ist bewusst NICHT in der Liste — es ist der
69
- * Default-Fallback fuer "noch keine Wahl getroffen", mit sichtbarer
70
- * Warning. Production-Tenants sollen ein echtes Profile waehlen.
67
+ * Profile keys that the tenant admin may select during onboarding.
68
+ * `minimal-no-region` is intentionally excluded: it is the default fallback
69
+ * for "no choice made yet" and produces a visible warning. Production
70
+ * tenants must select an actual profile.
71
71
  */
72
72
  export declare const SELECTABLE_PROFILE_KEYS: readonly ["eu-dsgvo", "swiss-dsg", "de-hr-dsgvo-hgb"];
73
73
  /**
74
- * Top-Level-Properties des `ComplianceProfile`-Type, die ein Tenant-
75
- * Override modifizieren darf. Identifikations-Felder (key, region,
76
- * label, extends) sind ausgeschlossen — wer die overriden wuerde,
77
- * würde die Profile-Identität zerstoeren.
74
+ * Top-level `ComplianceProfile` properties that a tenant override may modify.
75
+ * Identity fields (key, region, label, extends) are excluded because
76
+ * overriding them would destroy the profile's identity.
78
77
  *
79
- * Single source of truth fuer:
80
- * - set-profile-Handler-Whitelist (Tippfehler-Reject)
81
- * - Snapshot-Test gegen Profile-Top-Level (Drift-Guard)
78
+ * This is the single source of truth for:
79
+ * - the set-profile handler whitelist, which rejects typos
80
+ * - the snapshot test that guards against drift from the profile's top level
82
81
  *
83
- * Wenn ein neues Top-Level-Property zu `ComplianceProfile` kommt
84
- * (z.B. `dataSubjectRights` oder `crossBorderTransferRules`), MUSS es
85
- * hier ergaenzt werden — sonst lehnt set-profile valide Overrides ab.
86
- * Der Snapshot-Test in profiles.test.ts faengt Drift in beide
87
- * Richtungen.
82
+ * When a new top-level property is added to `ComplianceProfile` (for example,
83
+ * `dataSubjectRights` or `crossBorderTransferRules`), it must be added here;
84
+ * otherwise set-profile rejects valid overrides. The snapshot test in
85
+ * profiles.test.ts detects drift in either direction.
88
86
  */
89
87
  export declare const OVERRIDABLE_PROFILE_KEYS: ReadonlySet<string>;
90
88
  type DeepReadonly<T> = T extends object ? {
@@ -95,9 +93,9 @@ type DeepPartial<T> = T extends object ? {
95
93
  [K in keyof T]?: DeepPartial<T[K]>;
96
94
  } : T;
97
95
  /**
98
- * Pre-baked Profile-Liste (extends bereits aufgelöst). Beim Modul-Load
99
- * einmal berechnet — wirft bei Definition-Fehlern (Cycle, missing target)
100
- * sofort, nicht erst beim ersten Resolver-Call.
96
+ * Precomputed profile list with `extends` already resolved. It is computed
97
+ * once when the module loads, so definition errors (cycles or missing
98
+ * targets) are thrown immediately rather than on the first resolver call.
101
99
  */
102
100
  export declare const COMPLIANCE_PROFILES: Readonly<Record<ComplianceProfileKey, ComplianceProfile>>;
103
101
  export interface EffectiveComplianceProfile {
@@ -105,19 +103,18 @@ export interface EffectiveComplianceProfile {
105
103
  readonly warning?: "no-profile-selected";
106
104
  }
107
105
  /**
108
- * Liefert das effektive Compliance-Profile fuer einen Tenant inklusive
109
- * Tenant-Override.
106
+ * Returns the effective compliance profile for a tenant, including its
107
+ * tenant override.
110
108
  *
111
- * Edge-Case-Verhalten (gepinnt):
109
+ * Edge-case behavior:
112
110
  * - selection=undefined → minimal-no-region + warning="no-profile-selected"
113
- * - selection=valid + override=undefined → effective profile, kein warning
114
- * - selection=valid + override → deep-merged effective, kein warning
111
+ * - selection=valid + override=undefined → effective profile, no warning
112
+ * - selection=valid + override → deep-merged effective profile, no warning
115
113
  *
116
- * Production-Marker: das frueher hier vorgesehene "minimal-in-production"-
117
- * warning ist entfallen weil set-profile (Sprint 1.7 X1) minimal-no-region
118
- * nicht mehr als Tenant-Wahl akzeptiert. Wer Production-spezifisches
119
- * Verhalten braucht (z.B. Block-bei-Default), addiert den Marker spaeter
120
- * bei Bedarf.
114
+ * The former "minimal-in-production" warning was removed because
115
+ * set-profile no longer accepts minimal-no-region as a tenant selection.
116
+ * Production-specific behavior, such as blocking the default, can be added
117
+ * later if needed.
121
118
  */
122
119
  export declare function resolveComplianceProfile(args: {
123
120
  readonly selection?: ComplianceProfileKey;
@@ -1,37 +1,34 @@
1
- // Compliance-Profiles — DSGVO + sektorspezifische Regelwerke.
1
+ // Compliance profiles — GDPR + sector-specific regulations.
2
2
  //
3
- // Tenant-Admin waehlt ein Profile beim Onboarding (Pflicht). Profile
4
- // buendelt User-Rights (Forget-Grace, Restriction, Auskunftsfrist),
5
- // Notification-Sprache, Breach-Disclosure, Audit-Log-Retention,
6
- // Sub-Processor-Anforderungen und Tenant-Destroy-Grace.
3
+ // The tenant admin must select a profile during onboarding. A profile
4
+ // bundles user rights (forget grace period, restriction, access-request
5
+ // deadline), notification languages, breach disclosure, audit-log retention,
6
+ // subprocessor requirements, and the tenant-destruction grace period.
7
7
  //
8
- // MVP-Set: 3 Profile + 1 Default-Fallback. Erweiterung via `extends`
9
- // trivial — neue Laender (uk-gdpr, ca-pipeda, us-ccpa, hipaa-healthcare)
10
- // kommen on-demand wenn Customer fragt.
8
+ // Current set: three profiles plus one default fallback. Extending via
9
+ // `extends` is straightforward; additional jurisdictions (uk-gdpr,
10
+ // ca-pipeda, us-ccpa, hipaa-healthcare) can be added when needed.
11
11
  //
12
- // Edge-Case-Decisions (advisor-pinned 2026-05-06):
12
+ // Edge-case decisions:
13
13
  //
14
- // 1. Default-Fallback: `resolveComplianceProfile(undefined)` returnt
15
- // `minimal-no-region` mit `warning: "no-profile-selected"`. Caller
16
- // sieht das und kann Onboarding-Banner triggern. Nie still
17
- // resolven.
14
+ // 1. Default fallback: `resolveComplianceProfile(undefined)` returns
15
+ // `minimal-no-region` with `warning: "no-profile-selected"`. The caller
16
+ // can use this to trigger an onboarding banner; resolution is never
17
+ // silent.
18
18
  //
19
- // 2. extends-Chain-Tiefe: nur 1-Level. de-hr-dsgvo-hgb extends
20
- // eu-dsgvo, aber eu-dsgvo darf NICHT selbst extends haben. Boot-
21
- // Validator (Sprint 1.3) prueft.
19
+ // 2. Extends-chain depth: only one level is allowed. de-hr-dsgvo-hgb
20
+ // extends eu-dsgvo, but eu-dsgvo must not extend another profile. The
21
+ // boot validator checks this.
22
22
  //
23
- // 3. Deep-merge-Semantik vom Override: rekursiv. Override
24
- // `{ userRights: { gracePeriod: { days: 60 } } }` auf eu-dsgvo
25
- // laesst andere userRights-Felder unveraendert. Top-Level-Replace
26
- // gibt es NICHT — Override muss strukturell exakt das Pfad-Tree
27
- // treffen.
23
+ // 3. Override deep-merge semantics: merging is recursive. An override such
24
+ // as `{ userRights: { gracePeriod: { days: 60 } } }` on eu-dsgvo leaves
25
+ // the other userRights fields unchanged. Top-level replacement is not
26
+ // supported; the override must target the corresponding property path.
28
27
  //
29
- // 4. Required-Field-Override: Override-Type ist `DeepPartial<...>`.
30
- // TypeScript verhindert null-Drops zur Compile-Time. Runtime-Cast
31
- // durch Tenant-Admin-Override-Endpoint laeuft durch Zod-Schema
32
- // mit allen-Properties-optional (kein nullable).
33
- //
34
- // Siehe docs/plans/datenschutz/compliance-profiles.md.
28
+ // 4. Required-field overrides: the override type is `DeepPartial<...>`.
29
+ // TypeScript prevents null drops at compile time. Runtime casts from
30
+ // the tenant-admin override endpoint pass through a Zod schema with
31
+ // all properties optional, but not nullable.
35
32
  import { isPlainObject } from "../utils/is-plain-object.js";
36
33
  // --- Profile-Definitions (raw, before extends-Resolution) ---
37
34
  const RAW_PROFILES = {
@@ -155,12 +152,12 @@ const RAW_PROFILES = {
155
152
  tenantDestroyGracePeriod: { days: 30 },
156
153
  },
157
154
  };
158
- // --- Tenant-Auswählbare Liste (ohne minimal-no-region) ---
155
+ // --- Tenant-selectable list (excluding minimal-no-region) ---
159
156
  /**
160
- * Profile-Schluessel die der Tenant-Admin im Onboarding waehlen darf.
161
- * `minimal-no-region` ist bewusst NICHT in der Liste — es ist der
162
- * Default-Fallback fuer "noch keine Wahl getroffen", mit sichtbarer
163
- * Warning. Production-Tenants sollen ein echtes Profile waehlen.
157
+ * Profile keys that the tenant admin may select during onboarding.
158
+ * `minimal-no-region` is intentionally excluded: it is the default fallback
159
+ * for "no choice made yet" and produces a visible warning. Production
160
+ * tenants must select an actual profile.
164
161
  */
165
162
  export const SELECTABLE_PROFILE_KEYS = [
166
163
  "eu-dsgvo",
@@ -168,20 +165,18 @@ export const SELECTABLE_PROFILE_KEYS = [
168
165
  "de-hr-dsgvo-hgb",
169
166
  ];
170
167
  /**
171
- * Top-Level-Properties des `ComplianceProfile`-Type, die ein Tenant-
172
- * Override modifizieren darf. Identifikations-Felder (key, region,
173
- * label, extends) sind ausgeschlossen — wer die overriden wuerde,
174
- * würde die Profile-Identität zerstoeren.
168
+ * Top-level `ComplianceProfile` properties that a tenant override may modify.
169
+ * Identity fields (key, region, label, extends) are excluded because
170
+ * overriding them would destroy the profile's identity.
175
171
  *
176
- * Single source of truth fuer:
177
- * - set-profile-Handler-Whitelist (Tippfehler-Reject)
178
- * - Snapshot-Test gegen Profile-Top-Level (Drift-Guard)
172
+ * This is the single source of truth for:
173
+ * - the set-profile handler whitelist, which rejects typos
174
+ * - the snapshot test that guards against drift from the profile's top level
179
175
  *
180
- * Wenn ein neues Top-Level-Property zu `ComplianceProfile` kommt
181
- * (z.B. `dataSubjectRights` oder `crossBorderTransferRules`), MUSS es
182
- * hier ergaenzt werden — sonst lehnt set-profile valide Overrides ab.
183
- * Der Snapshot-Test in profiles.test.ts faengt Drift in beide
184
- * Richtungen.
176
+ * When a new top-level property is added to `ComplianceProfile` (for example,
177
+ * `dataSubjectRights` or `crossBorderTransferRules`), it must be added here;
178
+ * otherwise set-profile rejects valid overrides. The snapshot test in
179
+ * profiles.test.ts detects drift in either direction.
185
180
  */
186
181
  export const OVERRIDABLE_PROFILE_KEYS = new Set([
187
182
  "userRights",
@@ -192,11 +187,11 @@ export const OVERRIDABLE_PROFILE_KEYS = new Set([
192
187
  "tenantDestroyGracePeriod",
193
188
  "forgetDiscovery",
194
189
  ]);
195
- // Pfade die als ganzes Atom ersetzt werden (NICHT rekursiv gemergt).
196
- // Notwendig fuer Diskriminierte-Union-Types wo das Patch ein Schwester-
197
- // Property statt einer Override sein kann — z.B. retention von
198
- // { months: 24 } auf { years: 10 } wuerde sonst zu { months: 24, years: 10 }
199
- // werden, semantisch nonsense.
190
+ // These paths are replaced as atomic values rather than merged recursively.
191
+ // This is required for discriminated unions, where a patch may provide a
192
+ // sibling property instead of an override; for example, changing retention
193
+ // from { months: 24 } to { years: 10 } would otherwise produce
194
+ // { months: 24, years: 10 }, which is semantically invalid.
200
195
  const ATOMIC_PATHS = new Set([
201
196
  "userRights.gracePeriod",
202
197
  "userRights.auskunftFrist",
@@ -213,7 +208,7 @@ function deepMerge(base, patch, path = "") {
213
208
  const fullPath = path ? `${path}.${k}` : k;
214
209
  const existing = out[k];
215
210
  if (ATOMIC_PATHS.has(fullPath)) {
216
- // Atomic — replace komplett statt rekursiv mergen.
211
+ // Atomic — replace completely instead of merging recursively.
217
212
  out[k] = v;
218
213
  }
219
214
  else if (isPlainObject(existing) && isPlainObject(v)) {
@@ -226,13 +221,12 @@ function deepMerge(base, patch, path = "") {
226
221
  return out; // @cast-boundary generic-record
227
222
  }
228
223
  /**
229
- * Resolved ein Profile inklusive `extends`-Auflösung. Wirft wenn die
230
- * extends-Chain tiefer als 1 Level ist (vermeidet Cycles + macht
231
- * Boot-Validation einfach).
224
+ * Resolves a profile, including its `extends` chain. Throws when the chain
225
+ * is deeper than one level to prevent cycles and keep boot validation simple.
232
226
  *
233
- * Edge-Case (gepinnt): das `extends`-Target darf selbst KEIN extends
234
- * haben. Wer doch eine Mehrstufen-Hierarchie braucht, definiert die
235
- * Stufen explizit (z.B. `de-hr-strict extends eu-dsgvo`, statt
227
+ * The `extends` target itself must not extend another profile. A required
228
+ * multi-level hierarchy must instead be defined explicitly (for example,
229
+ * `de-hr-strict extends eu-dsgvo` rather than
236
230
  * `de-hr-strict extends de-hr-dsgvo-hgb extends eu-dsgvo`).
237
231
  */
238
232
  function resolveExtends(key) {
@@ -248,25 +242,24 @@ function resolveExtends(key) {
248
242
  raw);
249
243
  }
250
244
  /**
251
- * Pre-baked Profile-Liste (extends bereits aufgelöst). Beim Modul-Load
252
- * einmal berechnet — wirft bei Definition-Fehlern (Cycle, missing target)
253
- * sofort, nicht erst beim ersten Resolver-Call.
245
+ * Precomputed profile list with `extends` already resolved. It is computed
246
+ * once when the module loads, so definition errors (cycles or missing
247
+ * targets) are thrown immediately rather than on the first resolver call.
254
248
  */
255
249
  export const COMPLIANCE_PROFILES = Object.fromEntries(Object.keys(RAW_PROFILES).map((k) => [k, resolveExtends(k)])); // @cast-boundary dynamic-key
256
250
  /**
257
- * Liefert das effektive Compliance-Profile fuer einen Tenant inklusive
258
- * Tenant-Override.
251
+ * Returns the effective compliance profile for a tenant, including its
252
+ * tenant override.
259
253
  *
260
- * Edge-Case-Verhalten (gepinnt):
254
+ * Edge-case behavior:
261
255
  * - selection=undefined → minimal-no-region + warning="no-profile-selected"
262
- * - selection=valid + override=undefined → effective profile, kein warning
263
- * - selection=valid + override → deep-merged effective, kein warning
256
+ * - selection=valid + override=undefined → effective profile, no warning
257
+ * - selection=valid + override → deep-merged effective profile, no warning
264
258
  *
265
- * Production-Marker: das frueher hier vorgesehene "minimal-in-production"-
266
- * warning ist entfallen weil set-profile (Sprint 1.7 X1) minimal-no-region
267
- * nicht mehr als Tenant-Wahl akzeptiert. Wer Production-spezifisches
268
- * Verhalten braucht (z.B. Block-bei-Default), addiert den Marker spaeter
269
- * bei Bedarf.
259
+ * The former "minimal-in-production" warning was removed because
260
+ * set-profile no longer accepts minimal-no-region as a tenant selection.
261
+ * Production-specific behavior, such as blocking the default, can be added
262
+ * later if needed.
270
263
  */
271
264
  export function resolveComplianceProfile(args) {
272
265
  if (!args.selection) {
@@ -1,69 +1,67 @@
1
1
  /**
2
- * Bundle-Tier-Marker fuer SubProcessor.appliesTo. "all-tiers" matched
3
- * unabhaengig vom konkreten Tenant-Bundle (z.B. Hetzner als Hosting-
4
- * Provider). Konkrete Tier-Namen koennen per-Tenant gefiltert werden.
2
+ * Bundle tier marker for SubProcessor.appliesTo. "all-tiers" matches
3
+ * regardless of the tenant's specific bundle (for example, Hetzner as a
4
+ * hosting provider). Specific tier names can be filtered per tenant.
5
5
  */
6
6
  export type BundleTier = "all-tiers" | "standard" | "business" | "enterprise";
7
7
  /**
8
- * Beschreibt einen Auftragsverarbeiter (Art. 28 DSGVO) der von Kumiko
9
- * fuer den Plattform-Betrieb eingesetzt wird.
8
+ * Describes a processor within the meaning of GDPR Article 28 that Kumiko
9
+ * uses for platform operations.
10
10
  */
11
11
  export interface SubProcessor {
12
12
  /** Voller juristischer Name. */
13
13
  readonly name: string;
14
- /** Was macht der Sub-Processor fuer uns? */
14
+ /** What the sub-processor does for us. */
15
15
  readonly purpose: string;
16
16
  /** Sitz / Datenverarbeitungs-Region. */
17
17
  readonly region: string;
18
- /** Link zum Auftragsverarbeitungsvertrag (DPA/AVV). */
18
+ /** Link to the data processing agreement (DPA/AVV). */
19
19
  readonly dpa: string;
20
- /** Wann wurde der Sub-Processor zu unserer Plattform hinzugefuegt? */
20
+ /** Date when the sub-processor was added to the platform. */
21
21
  readonly addedAt: string;
22
22
  /**
23
- * Welche Bundle-Tiers nutzen diesen Sub-Processor?
24
- * Tenants nicht-betroffener Tiers brauchen keine Notification bei
25
- * Aenderungen.
23
+ * Bundle tiers that use this sub-processor.
24
+ * Tenants in unaffected tiers do not need notifications about changes.
26
25
  */
27
26
  readonly appliesTo: readonly BundleTier[];
28
27
  /**
29
- * Standard Contractual Clauses (SCC) fuer Drittlandsuebermittlung
30
- * abgeschlossen. Pflicht fuer alle Sub-Processors mit Sitz ausserhalb
31
- * EU/EWR.
28
+ * Whether Standard Contractual Clauses (SCC) for transfers to third
29
+ * countries have been concluded. Required for all sub-processors based
30
+ * outside the EU/EEA.
32
31
  */
33
32
  readonly sccRequired?: boolean;
34
33
  /**
35
- * Tenant muss explizit aktivieren (z.B. AI-Feature). Ohne Opt-In
36
- * werden keine Daten an diesen Sub-Processor gesendet.
34
+ * The tenant must explicitly activate this sub-processor (for example,
35
+ * for an AI feature). No data is sent to it without opt-in.
37
36
  */
38
37
  readonly optInOnly?: boolean;
39
38
  /**
40
- * Business Associate Agreement fuer HIPAA-Customers verfuegbar.
41
- * Relevant nur fuer hipaa-healthcare Compliance-Profile.
39
+ * Whether a Business Associate Agreement is available for HIPAA customers.
40
+ * Relevant only for hipaa-healthcare compliance profiles.
42
41
  */
43
42
  readonly hipaaBaaAvailable?: boolean;
44
43
  /**
45
- * Geplant aber noch nicht aktiv (Vorbereitung fuer kommenden Sprint).
46
- * Wird im Sub-Processor-Endpoint als "planned"-Sektion separat
47
- * ausgegeben damit Tenants schon Lead-Time bekommen.
44
+ * Planned but not yet active.
45
+ * The sub-processor endpoint outputs it in a separate "planned" section
46
+ * so tenants receive lead time for configuration.
48
47
  */
49
48
  readonly status?: "active" | "planned";
50
49
  }
51
50
  /**
52
- * Plattform-weite Sub-Processor-Liste.
51
+ * Platform-wide sub-processor list.
53
52
  *
54
- * Reihenfolge: nach addedAt (aelteste zuerst). Bei Aenderungen
55
- * Snapshot-Test im Test-File explizit updaten — der detektiert
56
- * stille Aenderungen.
53
+ * Ordered by addedAt (oldest first). Update the snapshot test explicitly
54
+ * when changing this list; it detects silent changes.
57
55
  */
58
56
  export declare const KUMIKO_SUB_PROCESSORS: readonly SubProcessor[];
59
57
  /**
60
- * Filter helper — nur aktive Sub-Processors (kein status="planned").
61
- * Genutzt vom oeffentlichen JSON-Endpoint (Sprint 1).
58
+ * Filter helper — active sub-processors only (excluding status="planned").
59
+ * Used by the public JSON endpoint.
62
60
  */
63
61
  export declare function getActiveSubProcessors(): readonly SubProcessor[];
64
62
  /**
65
- * Filter helper — nur geplante Sub-Processors (status="planned"). Werden
66
- * separat als "demnaechst aktiv"-Sektion ausgegeben damit Tenant-Admins
67
- * schon Lead-Time fuer Compliance-Profile-Konfiguration bekommen.
63
+ * Filter helper — planned sub-processors only (status="planned"). They are
64
+ * output separately in a "coming soon" section so tenant admins receive
65
+ * lead time for compliance profile configuration.
68
66
  */
69
67
  export declare function getPlannedSubProcessors(): readonly SubProcessor[];
@@ -1,31 +1,27 @@
1
- // Sub-Processor-Liste der Kumiko-Plattform.
1
+ // Kumiko platform sub-processors.
2
2
  //
3
- // Auftragsverarbeiter im Sinne von DSGVO Art. 28 die Kumiko fuer den
4
- // Plattform-Betrieb einsetzt. Wird oeffentlich exposed unter
5
- // /api/compliance/sub-processors (JSON, Sprint 1)
6
- // /api/compliance/sub-processors.rss (RSS, Sprint 1)
3
+ // Processors within the meaning of GDPR Article 28 that Kumiko uses for
4
+ // platform operations. Publicly exposed at:
5
+ // /api/compliance/sub-processors (JSON)
6
+ // /api/compliance/sub-processors.rss (RSS)
7
7
  //
8
8
  // Separate from the public marketing overview (kumiko.rocks/subprocessors),
9
9
  // which is compiled independently from templates/legal/_shared/subprocessors/
10
10
  // catalog.*.md. The two lists are not synced.
11
11
  //
12
- // Tenant-Admins muessen ueber Add/Change/Remove informiert werden mit
13
- // Lead-Time aus dem Compliance-Profile (typisch 30d). Cron-Job kommt
14
- // in Sprint 1 (compliance-profiles).
12
+ // Tenant admins must be informed of additions, changes, and removals with
13
+ // the lead time from the compliance profile (typically 30d). The notification
14
+ // cron is not available yet.
15
15
  //
16
16
  // SubProcessor has no "removed" state yet: a removed entry is deleted from
17
17
  // the array, so until the notification cron exists a removal is documented
18
18
  // only in the changelog. Removed so far: Mailbox.org (mailbox hosting),
19
- // replaced by ALL-INKL.COM on 2026-09-02.
20
- //
21
- // Quelle: docs/plans/datenschutz/compliance-profiles.md "Sub-Processor-
22
- // Management" + docs/plans/datenschutz/legal-artifacts.md.
19
+ // replaced by ALL-INKL.COM.
23
20
  /**
24
- * Plattform-weite Sub-Processor-Liste.
21
+ * Platform-wide sub-processor list.
25
22
  *
26
- * Reihenfolge: nach addedAt (aelteste zuerst). Bei Aenderungen
27
- * Snapshot-Test im Test-File explizit updaten — der detektiert
28
- * stille Aenderungen.
23
+ * Ordered by addedAt (oldest first). Update the snapshot test explicitly
24
+ * when changing this list; it detects silent changes.
29
25
  */
30
26
  export const KUMIKO_SUB_PROCESSORS = [
31
27
  {
@@ -107,16 +103,16 @@ export const KUMIKO_SUB_PROCESSORS = [
107
103
  },
108
104
  ];
109
105
  /**
110
- * Filter helper — nur aktive Sub-Processors (kein status="planned").
111
- * Genutzt vom oeffentlichen JSON-Endpoint (Sprint 1).
106
+ * Filter helper — active sub-processors only (excluding status="planned").
107
+ * Used by the public JSON endpoint.
112
108
  */
113
109
  export function getActiveSubProcessors() {
114
110
  return KUMIKO_SUB_PROCESSORS.filter((sp) => sp.status !== "planned");
115
111
  }
116
112
  /**
117
- * Filter helper — nur geplante Sub-Processors (status="planned"). Werden
118
- * separat als "demnaechst aktiv"-Sektion ausgegeben damit Tenant-Admins
119
- * schon Lead-Time fuer Compliance-Profile-Konfiguration bekommen.
113
+ * Filter helper — planned sub-processors only (status="planned"). They are
114
+ * output separately in a "coming soon" section so tenant admins receive
115
+ * lead time for compliance profile configuration.
120
116
  */
121
117
  export function getPlannedSubProcessors() {
122
118
  return KUMIKO_SUB_PROCESSORS.filter((sp) => sp.status === "planned");
@@ -12,7 +12,7 @@ import { ensureTemporalPolyfill } from "./time/index.js";
12
12
  // "--instance-id=<id>") out of argv regardless of position, leaving the
13
13
  // remaining positionals for sub/name — instead of two independent
14
14
  // positional/flag reads that silently misparse "--instance-id" with no
15
- // value, the "=" form, or a flag placed before the positionals (#1412).
15
+ // value, the "=" form, or a flag placed before the positionals.
16
16
  function parseConsumerCliArgs(argv) {
17
17
  const positionals = [];
18
18
  let instanceId;
@@ -57,9 +57,9 @@ export async function runConsumerCli(argv, out) {
57
57
  if (sub !== "status" && sub !== "restart") {
58
58
  // Unknown subcommand must be visible on stderr, not just a bare exit 1 —
59
59
  // ops invocations piping `2>&1 >/dev/null` or log pipelines that only
60
- // watch stderr would otherwise see a failure with zero explanation
61
- // (#1412). A bare help call (no subcommand at all) is not an error, so
62
- // it keeps exit 0 + stdout.
60
+ // watch stderr would otherwise see a failure with zero explanation.
61
+ // A bare help call (no subcommand at all) is not an error, so it keeps
62
+ // exit 0 + stdout.
63
63
  const write = sub === undefined ? out.log : out.err;
64
64
  if (sub !== undefined)
65
65
  out.err(` Unknown subcommand: ${sub}`);
@@ -1,23 +1,24 @@
1
- // Blind-Index für PII-Equality-Lookups (kumiko-framework#818).
2
- // `lookupable: true` auf einem Subject-annotierten text-Feld erzeugt eine
3
- // generierte Spalte `<snake>_bidx` mit deterministischem HMAC über den
4
- // KLARTEXT-Wert — Equality-Queries matchen `(col = $1 OR col_bidx = $2)`
5
- // und funktionieren damit für Klartext-Alt-Rows UND verschlüsselte Rows.
1
+ // Blind index for PII equality lookups.
2
+ // `lookupable: true` on a Subject-annotated text field generates a
3
+ // `<snake>_bidx` column containing a deterministic HMAC of the
4
+ // PLAINTEXT value. Equality queries match `(col = $1 OR col_bidx = $2)`
5
+ // and therefore work for both plaintext legacy rows and encrypted rows.
6
6
  //
7
- // Wertformat: kumiko-bidx:v1:<base64url(HMAC-SHA256(key, value))>
7
+ // Value format: kumiko-bidx:v1:<base64url(HMAC-SHA256(key, value))>
8
8
  //
9
- // HMAC ist byte-exact ohne Normalisierung — repliziert exakt die heutige
10
- // case-sensitive Equality-Semantik (Lowercasing wäre eine Verhaltensänderung).
9
+ // HMAC computation is byte-exact and performs no normalization, preserving
10
+ // the existing case-sensitive equality semantics (lowercasing would change
11
+ // the behavior).
11
12
  //
12
- // Der Key ist bewusst ein EIGENER 32-Byte-Key (env: KUMIKO_BLIND_INDEX_KEY),
13
- // nicht vom PLATFORM_KEK abgeleitet und nicht Teil des KmsAdapter-Contracts —
14
- // BYOK-Adapter dürfen ihn nie sehen. Rotation = Recompute aller bidx-Spalten
15
- // (Rollout-Fahrplan Schritt 7).
13
+ // The key is deliberately a SEPARATE 32-byte key (env:
14
+ // KUMIKO_BLIND_INDEX_KEY), not derived from PLATFORM_KEK and not part of the
15
+ // KmsAdapter contract, so BYOK adapters must never see it. Rotation requires
16
+ // recomputing all bidx columns.
16
17
  //
17
- // bidx-Werte leben NUR in der Projektion, nie in Event-Payloads: ein
18
- // deterministischer HMAC im immutablen Event wäre permanente Linkage und
19
- // bräche Forget. applyEntityEvent berechnet sie beim Apply (live + rebuild),
20
- // nach Key-Erase recomputet der Rebuild sie zu NULL.
18
+ // bidx values exist ONLY in the projection, never in event payloads: a
19
+ // deterministic HMAC in an immutable event would create permanent linkage
20
+ // and break erasure. applyEntityEvent computes them during Apply (live and
21
+ // rebuild); after key erasure, the rebuild recomputes them as NULL.
21
22
  import { createHmac } from "node:crypto";
22
23
  import { requestContext } from "../api/request-context.js";
23
24
  import { configuredPiiSubjectKms, decryptPiiFieldValues, isPiiCiphertext, PII_ERASED_SENTINEL, } from "./pii-field-encryption.js";
@@ -38,7 +39,7 @@ export function decodeBlindIndexKey(base64Key) {
38
39
  // Boot-injected app-wide key, mirroring configurePiiSubjectKms: run{Prod,Dev}App
39
40
  // call configureBlindIndexKey once; query compilers + applyEntityEvent resolve
40
41
  // lazily. Absent key = blind-indexing off (bidx columns stay NULL, equality
41
- // lookups match plaintext rows only — pre-#818 behavior).
42
+ // lookups match plaintext rows only).
42
43
  let injectedKey;
43
44
  export function configureBlindIndexKey(base64Key) {
44
45
  injectedKey = base64Key === undefined ? undefined : decodeBlindIndexKey(base64Key);
@@ -9,7 +9,7 @@ export function quoteIdent(name) {
9
9
  export function escapeLikePattern(value) {
10
10
  return value.replace(/[\\%_]/g, (m) => `\\${m}`);
11
11
  }
12
- // "v%" matches any format version (v1 no-AAD, v2 AAD-bound, #1263) — the
12
+ // "v%" matches any format version (v1 no-AAD, v2 AAD-bound) — the
13
13
  // subject key placement is stable across versions.
14
14
  export function subjectCiphertextLikePattern(subjectKey) {
15
15
  return `kumiko-pii:v%:${escapeLikePattern(subjectKey)}:%`;
@@ -1,4 +1,4 @@
1
- // PII on custom-event payloads (#799). Entity CRUD events get their PII
1
+ // PII on custom-event payloads. Entity CRUD events get their PII
2
2
  // encrypted by the executor; events written via ctx.appendEvent / MSP-apply /
3
3
  // low-level append() (delivery attempt-log, jobs run-logger) had no encrypt
4
4
  // path at all. `r.defineEvent(name, schema, { piiFields })` declares which
@@ -8,7 +8,7 @@
8
8
  // events skip the registry and take their stance from system-event-pii.ts
9
9
  // instead (fail-closed when missing).
10
10
  //
11
- // `piiFields` is a mandatory, explicit stance (fw#2558): a payload can only
11
+ // `piiFields` is a mandatory, explicit stance: a payload can only
12
12
  // go uncatalogued through a declared `piiFields: "none"`, never by omission —
13
13
  // defineEvent refuses to register an event without one. What used to be a
14
14
  // silent no-op (forgetting the option) is now either an explicit "none" or a
@@ -48,7 +48,7 @@ function isStructuredJsonValue(value) {
48
48
  return typeof value === "object" && value !== null;
49
49
  }
50
50
  // Encrypts catalogued payload fields under the declared subject's DEK
51
- // (user/tenant/self — resolveEventSubject, fw#2801). No-op when the event
51
+ // (user/tenant/self — resolveEventSubject). No-op when the event
52
52
  // type is uncatalogued or no subject KMS is configured (plaintext rollout
53
53
  // mode — the hard boot gate governs whether that is acceptable). A
54
54
  // user-subject field with an empty owner follows its declared `whenAbsent`
@@ -14,7 +14,7 @@ export type KekSourceEnv = {
14
14
  export type KekSourceOptions = {
15
15
  readonly fetch?: typeof globalThis.fetch;
16
16
  readonly logPrefix?: string;
17
- /** Where the boot line naming the KEK source goes. Defaults to `console.info`. */
17
+ /** Where the boot line naming the KEK source goes. Defaults to the process logger, or `console.info` before one is wired. */
18
18
  readonly log?: (message: string) => void;
19
19
  /** Env names to resolve, e.g. `kmsSlotsOf(schema)`. */
20
20
  readonly slots: readonly string[];
@@ -4,6 +4,8 @@
4
4
  // made at all. Any `*_CIPHERTEXT` in the env that names no requested slot is
5
5
  // ignored — a foreign ciphertext must never fail boot.
6
6
  import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
7
+ import { createFallbackLogger } from "../logging/utils.js";
8
+ const kekLog = createFallbackLogger("kumiko:kek");
7
9
  const SCALEWAY_KEY_MANAGER_API_VERSION = "v1alpha1";
8
10
  const DEFAULT_REGION = "fr-par";
9
11
  const DECRYPT_TIMEOUT_MS = 5_000;
@@ -107,8 +109,7 @@ export async function resolvePlatformKeks(env, options) {
107
109
  throw new Error(`${prefix}PLATFORM_KEK_PREVIOUS_VERSION must be set when PLATFORM_KEK_PREVIOUS is set.`);
108
110
  }
109
111
  const results = await Promise.all(slots.map((name) => resolveSlot(name, env, options, fetchImpl)));
110
- // biome-ignore lint/suspicious/noConsole: ops-visible fallback when no logger is wired
111
- const log = options.log ?? console.info;
112
+ const log = options.log ?? ((message) => kekLog.info(message));
112
113
  const resolved = {};
113
114
  slots.forEach((name, index) => {
114
115
  const result = results[index];
@@ -6,7 +6,7 @@ export declare const subjectIdSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
6
6
  userId: z.ZodUUID;
7
7
  }, z.core.$strip>, z.ZodObject<{
8
8
  kind: z.ZodLiteral<"tenant">;
9
- tenantId: z.ZodPipe<z.ZodUUID, z.ZodTransform<string, string>>;
9
+ tenantId: z.ZodUUID;
10
10
  }, z.core.$strip>, z.ZodObject<{
11
11
  kind: z.ZodLiteral<"record">;
12
12
  entity: z.ZodString;