@cosmicdrift/kumiko-framework 0.388.0 → 0.390.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 (711) hide show
  1. package/AGENTS.md +12 -4
  2. package/README.md +1 -1
  3. package/agents/examples/apex-surface-auth.md +2 -3
  4. package/agents/examples/api-worker-split.md +9 -2
  5. package/agents/examples/auth-claims.md +1 -1
  6. package/agents/examples/cross-feature-events.md +12 -12
  7. package/agents/examples/crypto-shredding-hr.md +2 -2
  8. package/agents/examples/encrypted-tenant-config.md +1 -1
  9. package/agents/examples/error-contract.md +12 -7
  10. package/agents/examples/event-sourcing.md +29 -29
  11. package/agents/examples/files-post-processing.md +10 -8
  12. package/agents/examples/golden-path.md +13 -1
  13. package/agents/examples/inbound-mail-triage.md +1 -0
  14. package/agents/examples/lane-routing.md +2 -1
  15. package/agents/examples/legal-pages.md +2 -2
  16. package/agents/examples/lifecycle-hooks.md +55 -2
  17. package/agents/examples/list-table-options.md +466 -0
  18. package/agents/examples/managed-config.md +4 -4
  19. package/agents/examples/managed-pages.md +1 -1
  20. package/agents/examples/pdf-audit-export.md +4 -2
  21. package/agents/examples/relations.md +19 -4
  22. package/agents/examples/search.md +4 -4
  23. package/agents/examples/secrets-demo.md +9 -6
  24. package/agents/examples/state-machine.md +5 -4
  25. package/agents/examples/tenant-isolation.md +73 -1
  26. package/agents/examples/tenant-settings.md +1 -1
  27. package/agents/examples/user-data-rights.md +3 -6
  28. package/agents/examples/workflow-engine.md +53 -47
  29. package/agents/examples.md +5 -4
  30. package/agents/features.md +1 -1
  31. package/agents/widgets.md +1 -0
  32. package/dist/api/api-constants.d.ts +1 -0
  33. package/dist/api/api-constants.js +2 -0
  34. package/dist/api/auth-middleware.js +1 -1
  35. package/dist/api/auth-routes-invite.js +2 -1
  36. package/dist/api/auth-routes-shared.d.ts +2 -0
  37. package/dist/api/auth-routes-shared.js +5 -0
  38. package/dist/api/client-error-route.js +2 -3
  39. package/dist/api/entity-read-access.d.ts +4 -1
  40. package/dist/api/entity-read-access.js +14 -0
  41. package/dist/api/export/export-cells-reference.d.ts +9 -0
  42. package/dist/api/export/export-cells-reference.js +21 -0
  43. package/dist/api/export/export-cells.d.ts +11 -0
  44. package/dist/api/export/export-cells.js +136 -0
  45. package/dist/api/export/export-ciphertext-guard.d.ts +2 -0
  46. package/dist/api/export/export-ciphertext-guard.js +27 -0
  47. package/dist/api/export/export-columns.d.ts +31 -0
  48. package/dist/api/export/export-columns.js +85 -0
  49. package/dist/api/export/export-errors.d.ts +4 -0
  50. package/dist/api/export/export-errors.js +14 -0
  51. package/dist/api/export/export-route.d.ts +4 -0
  52. package/dist/api/export/export-route.js +75 -0
  53. package/dist/api/export/export-rows.d.ts +13 -0
  54. package/dist/api/export/export-rows.js +62 -0
  55. package/dist/api/export/export-screen.d.ts +13 -0
  56. package/dist/api/export/export-screen.js +47 -0
  57. package/dist/api/export/export-xlsx-writer.d.ts +4 -0
  58. package/dist/api/export/export-xlsx-writer.js +21 -0
  59. package/dist/api/extra-route.d.ts +7 -1
  60. package/dist/api/index.d.ts +23 -27
  61. package/dist/api/index.js +13 -15
  62. package/dist/api/jwt.js +1 -1
  63. package/dist/api/observability-middleware.d.ts +1 -1
  64. package/dist/api/observability-middleware.js +2 -1
  65. package/dist/api/pii-leak-guard.d.ts +3 -0
  66. package/dist/api/pii-leak-guard.js +3 -2
  67. package/dist/api/request-context-internals.d.ts +31 -0
  68. package/dist/api/request-context-internals.js +11 -0
  69. package/dist/api/request-context-scopes.d.ts +14 -0
  70. package/dist/api/request-context-scopes.js +69 -0
  71. package/dist/api/request-context.d.ts +1 -40
  72. package/dist/api/request-context.js +22 -51
  73. package/dist/api/request-id-middleware.d.ts +1 -1
  74. package/dist/api/route-registrars.d.ts +2 -1
  75. package/dist/api/route-registrars.js +1 -1
  76. package/dist/api/routes.d.ts +16 -0
  77. package/dist/api/routes.js +9 -5
  78. package/dist/api/server-boot-checks.d.ts +1 -1
  79. package/dist/api/server-boot-checks.js +2 -2
  80. package/dist/api/server-event-dispatcher.d.ts +6 -1
  81. package/dist/api/server-event-dispatcher.js +3 -4
  82. package/dist/api/server-extra-routes.d.ts +1 -1
  83. package/dist/api/server-extra-routes.js +5 -1
  84. package/dist/api/server-middleware.js +3 -1
  85. package/dist/api/server-routes.d.ts +3 -2
  86. package/dist/api/server-routes.js +8 -2
  87. package/dist/api/server-wiring.js +8 -4
  88. package/dist/api/server.d.ts +2 -1
  89. package/dist/api/sse-route.d.ts +3 -1
  90. package/dist/api/sse-route.js +11 -1
  91. package/dist/api/tenant-scoped-secrets.d.ts +2 -0
  92. package/dist/api/tenant-scoped-secrets.js +13 -0
  93. package/dist/api/websocket-route.d.ts +1 -1
  94. package/dist/auth/index.d.ts +0 -1
  95. package/dist/auth/roles.d.ts +0 -5
  96. package/dist/compliance/duration-spec.d.ts +0 -1
  97. package/dist/compliance/duration-spec.js +0 -5
  98. package/dist/compliance/index.d.ts +4 -4
  99. package/dist/compliance/index.js +2 -2
  100. package/dist/compliance/profiles.d.ts +0 -15
  101. package/dist/compliance/profiles.js +0 -23
  102. package/dist/config/index.d.ts +11 -9
  103. package/dist/config/index.js +13 -1
  104. package/dist/config/internals.d.ts +9 -0
  105. package/dist/config/internals.js +1 -0
  106. package/dist/consumer-cli-internals.d.ts +4 -0
  107. package/dist/consumer-cli-internals.js +1 -0
  108. package/dist/consumer-cli.d.ts +1 -4
  109. package/dist/consumer-cli.js +5 -1
  110. package/dist/crypto/event-pii.js +1 -1
  111. package/dist/crypto/index.d.ts +8 -9
  112. package/dist/crypto/index.js +7 -8
  113. package/dist/crypto/pg-kms-adapter.d.ts +1 -0
  114. package/dist/crypto/pg-kms-adapter.js +17 -18
  115. package/dist/db/aggregate-sql.d.ts +2 -0
  116. package/dist/db/aggregate-sql.js +10 -0
  117. package/dist/db/apply-entity-event.d.ts +1 -1
  118. package/dist/db/apply-entity-event.js +15 -47
  119. package/dist/db/blind-index-cleanup.js +91 -77
  120. package/dist/db/closed-connection.js +12 -19
  121. package/dist/db/collect-table-metas.js +1 -1
  122. package/dist/db/compound-types.d.ts +1 -1
  123. package/dist/db/compound-types.js +0 -7
  124. package/dist/db/config-seed.d.ts +2 -1
  125. package/dist/db/config-seed.js +6 -1
  126. package/dist/db/connection.d.ts +7 -6
  127. package/dist/db/connection.js +43 -24
  128. package/dist/db/cross-tenant-reads.d.ts +1 -1
  129. package/dist/db/cross-tenant-reads.js +1 -1
  130. package/dist/db/dialect.d.ts +0 -5
  131. package/dist/db/dialect.js +0 -3
  132. package/dist/db/driver-row-coercion.js +4 -4
  133. package/dist/db/driver-value-preparation.js +6 -4
  134. package/dist/db/eagerload.d.ts +2 -1
  135. package/dist/db/entity-field-encryption.d.ts +1 -1
  136. package/dist/db/entity-table-meta.d.ts +1 -1
  137. package/dist/db/event-store-executor-context.d.ts +3 -1
  138. package/dist/db/event-store-executor-context.js +4 -3
  139. package/dist/db/event-store-executor-read-aggregate-currencies.d.ts +17 -0
  140. package/dist/db/event-store-executor-read-aggregate-currencies.js +40 -0
  141. package/dist/db/event-store-executor-read-aggregate.js +36 -5
  142. package/dist/db/event-store-executor-read-filter.d.ts +1 -1
  143. package/dist/db/event-store-executor-read-filter.js +6 -3
  144. package/dist/db/event-store-executor-read-rows.d.ts +2 -1
  145. package/dist/db/event-store-executor-read-search.d.ts +2 -1
  146. package/dist/db/event-store-executor-read-sort.d.ts +2 -1
  147. package/dist/db/event-store-executor-read.js +2 -2
  148. package/dist/db/event-store-executor-write-atomic.d.ts +4 -0
  149. package/dist/db/event-store-executor-write-atomic.js +42 -0
  150. package/dist/db/event-store-executor-write-steps.d.ts +3 -5
  151. package/dist/db/event-store-executor-write-steps.js +0 -5
  152. package/dist/db/event-store-executor-write.js +22 -19
  153. package/dist/db/event-store-executor.d.ts +1 -1
  154. package/dist/db/event-store-executor.js +2 -1
  155. package/dist/db/executor-managed-tables.d.ts +7 -1
  156. package/dist/db/executor-managed-tables.js +12 -3
  157. package/dist/db/index.d.ts +29 -28
  158. package/dist/db/index.js +22 -20
  159. package/dist/db/known-table-names.d.ts +6 -0
  160. package/dist/db/known-table-names.js +21 -0
  161. package/dist/db/list-aggregate-labels.d.ts +1 -1
  162. package/dist/db/located-timestamp.d.ts +1 -1
  163. package/dist/db/located-timestamp.js +0 -5
  164. package/dist/db/migrate-generator.d.ts +17 -1
  165. package/dist/db/migrate-generator.js +50 -20
  166. package/dist/db/migrate-primary-key.d.ts +12 -0
  167. package/dist/db/migrate-primary-key.js +45 -0
  168. package/dist/db/migrate-rls-diff.d.ts +20 -0
  169. package/dist/db/migrate-rls-diff.js +61 -0
  170. package/dist/db/migrate-runner.js +7 -3
  171. package/dist/db/money.d.ts +1 -1
  172. package/dist/db/money.js +1 -1
  173. package/dist/db/parent-ref-clause.d.ts +2 -1
  174. package/dist/db/pg-error.d.ts +2 -0
  175. package/dist/db/pg-error.js +37 -21
  176. package/dist/db/queries/backfill-pii.js +3 -6
  177. package/dist/db/queries/database-now.js +2 -1
  178. package/dist/db/queries/ddl.d.ts +3 -0
  179. package/dist/db/queries/ddl.js +34 -1
  180. package/dist/db/queries/event-store.js +4 -2
  181. package/dist/db/queries/event-tenants.d.ts +2 -0
  182. package/dist/db/queries/event-tenants.js +17 -0
  183. package/dist/db/queries/rebuild-rls-guard.d.ts +2 -0
  184. package/dist/db/queries/rebuild-rls-guard.js +29 -0
  185. package/dist/db/queries/rls-boot-catalog.d.ts +16 -0
  186. package/dist/db/queries/rls-boot-catalog.js +39 -0
  187. package/dist/db/queries/rls-catalog.d.ts +6 -0
  188. package/dist/db/queries/rls-catalog.js +82 -0
  189. package/dist/db/queries/rls-scope.d.ts +3 -0
  190. package/dist/db/queries/rls-scope.js +17 -0
  191. package/dist/db/queries/rls-shape.d.ts +10 -0
  192. package/dist/db/queries/rls-shape.js +42 -0
  193. package/dist/db/queries/session-advisory-lock.d.ts +2 -0
  194. package/dist/db/queries/session-advisory-lock.js +23 -0
  195. package/dist/db/queries/shadow-swap.d.ts +1 -2
  196. package/dist/db/queries/shadow-swap.js +11 -28
  197. package/dist/db/queries/test-stack.d.ts +4 -1
  198. package/dist/db/queries/test-stack.js +83 -2
  199. package/dist/db/query.d.ts +14 -0
  200. package/dist/db/query.js +77 -48
  201. package/dist/db/reference-data.d.ts +1 -1
  202. package/dist/db/reference-data.js +20 -3
  203. package/dist/db/render-ddl.d.ts +6 -2
  204. package/dist/db/render-ddl.js +7 -7
  205. package/dist/db/render-rls-ddl.d.ts +35 -0
  206. package/dist/db/render-rls-ddl.js +127 -0
  207. package/dist/db/replay-migration-sql.d.ts +3 -1
  208. package/dist/db/replay-migration-sql.js +22 -5
  209. package/dist/db/replay-rls.d.ts +25 -0
  210. package/dist/db/replay-rls.js +156 -0
  211. package/dist/db/row-level-security-boot-check.d.ts +5 -0
  212. package/dist/db/row-level-security-boot-check.js +85 -0
  213. package/dist/db/row-level-security-connection.d.ts +3 -0
  214. package/dist/db/row-level-security-connection.js +213 -0
  215. package/dist/db/row-level-security-scope.d.ts +33 -0
  216. package/dist/db/row-level-security-scope.js +127 -0
  217. package/dist/db/scope-tenant-db-to-tenant.d.ts +3 -0
  218. package/dist/db/scope-tenant-db-to-tenant.js +14 -0
  219. package/dist/db/sql-identifier.d.ts +1 -0
  220. package/dist/db/sql-identifier.js +3 -0
  221. package/dist/db/statement-timeout.js +2 -1
  222. package/dist/db/table-builder.d.ts +2 -1
  223. package/dist/db/table-builder.js +1 -1
  224. package/dist/db/table-info.js +1 -1
  225. package/dist/db/table-push.d.ts +11 -2
  226. package/dist/db/table-push.js +15 -2
  227. package/dist/db/tenant-db-runner.d.ts +3 -1
  228. package/dist/db/tenant-db-runner.js +4 -3
  229. package/dist/db/tenant-db-scoped-rebind.d.ts +10 -0
  230. package/dist/db/tenant-db-scoped-rebind.js +33 -0
  231. package/dist/db/tenant-db-statement-runner.d.ts +13 -0
  232. package/dist/db/tenant-db-statement-runner.js +48 -0
  233. package/dist/db/tenant-db-upsert.d.ts +5 -0
  234. package/dist/db/tenant-db-upsert.js +91 -0
  235. package/dist/db/tenant-db.d.ts +17 -12
  236. package/dist/db/tenant-db.js +60 -121
  237. package/dist/db/tenant-id-filter.d.ts +3 -0
  238. package/dist/db/tenant-id-filter.js +30 -0
  239. package/dist/db/transaction-serialization.d.ts +6 -0
  240. package/dist/db/transaction-serialization.js +60 -0
  241. package/dist/derivatives/delete-stored-file.js +1 -1
  242. package/dist/derivatives/index.d.ts +2 -5
  243. package/dist/derivatives/index.js +2 -3
  244. package/dist/engine/access.d.ts +2 -1
  245. package/dist/engine/access.js +1 -1
  246. package/dist/engine/boot-validator/bundled-lists-table.d.ts +2 -0
  247. package/dist/engine/boot-validator/bundled-lists-table.js +36 -0
  248. package/dist/engine/boot-validator/entity-handler.d.ts +2 -1
  249. package/dist/engine/boot-validator/entity-handler.js +1 -1
  250. package/dist/engine/boot-validator/entity-list-aggregate-options.d.ts +3 -0
  251. package/dist/engine/boot-validator/entity-list-aggregate-options.js +23 -0
  252. package/dist/engine/boot-validator/list-bulk-actions.d.ts +3 -0
  253. package/dist/engine/boot-validator/list-bulk-actions.js +49 -0
  254. package/dist/engine/boot-validator/list-column-layout.d.ts +8 -0
  255. package/dist/engine/boot-validator/list-column-layout.js +41 -0
  256. package/dist/engine/boot-validator/list-table-aggregate-options.d.ts +24 -0
  257. package/dist/engine/boot-validator/list-table-aggregate-options.js +145 -0
  258. package/dist/engine/boot-validator/list-table-aggregate-query.d.ts +11 -0
  259. package/dist/engine/boot-validator/list-table-aggregate-query.js +31 -0
  260. package/dist/engine/boot-validator/list-table-export-options.d.ts +1 -0
  261. package/dist/engine/boot-validator/list-table-export-options.js +27 -0
  262. package/dist/engine/boot-validator/list-table-options.d.ts +3 -0
  263. package/dist/engine/boot-validator/list-table-options.js +77 -0
  264. package/dist/engine/boot-validator/list-table-reject-unknown-keys.d.ts +1 -0
  265. package/dist/engine/boot-validator/list-table-reject-unknown-keys.js +7 -0
  266. package/dist/engine/boot-validator/nav.d.ts +3 -1
  267. package/dist/engine/boot-validator/nav.js +1 -1
  268. package/dist/engine/boot-validator/ownership.d.ts +2 -1
  269. package/dist/engine/boot-validator/parent-ref.d.ts +2 -1
  270. package/dist/engine/boot-validator/projection-list-screens.d.ts +2 -1
  271. package/dist/engine/boot-validator/projection-list-screens.js +3 -13
  272. package/dist/engine/boot-validator/query-refs.d.ts +2 -1
  273. package/dist/engine/boot-validator/related-list-table-rules.d.ts +4 -0
  274. package/dist/engine/boot-validator/related-list-table-rules.js +42 -0
  275. package/dist/engine/boot-validator/screens-forms.d.ts +2 -1
  276. package/dist/engine/boot-validator/screens-kind-entity-list.js +7 -0
  277. package/dist/engine/boot-validator/screens-kind-projection-list.js +4 -0
  278. package/dist/engine/boot-validator/screens-kind-shared.d.ts +3 -1
  279. package/dist/engine/boot-validator/screens-lists.js +12 -2
  280. package/dist/engine/boot-validator/screens.d.ts +2 -1
  281. package/dist/engine/boot-validator/workspaces.d.ts +3 -1
  282. package/dist/engine/bridge-stub.d.ts +5 -2
  283. package/dist/engine/bridge-stub.js +39 -24
  284. package/dist/engine/build-app-schema.d.ts +2 -1
  285. package/dist/engine/build-app-schema.js +9 -1
  286. package/dist/engine/build-config-feature-schema.js +6 -1
  287. package/dist/engine/config-helpers.d.ts +2 -2
  288. package/dist/engine/config-helpers.js +0 -9
  289. package/dist/engine/constants.d.ts +0 -10
  290. package/dist/engine/constants.js +0 -8
  291. package/dist/engine/create-app.js +1 -1
  292. package/dist/engine/define-feature.d.ts +2 -1
  293. package/dist/engine/define-feature.js +5 -2
  294. package/dist/engine/define-handler.d.ts +1 -1
  295. package/dist/engine/define-step.d.ts +0 -1
  296. package/dist/engine/define-step.js +0 -3
  297. package/dist/engine/embedded-derived.d.ts +1 -1
  298. package/dist/engine/entity-handlers.d.ts +2 -1
  299. package/dist/engine/entity-handlers.js +7 -7
  300. package/dist/engine/entity-list-runtime-options.js +3 -1
  301. package/dist/engine/entity-list-searchability.d.ts +2 -1
  302. package/dist/engine/event-def.d.ts +2 -1
  303. package/dist/engine/event-helpers.d.ts +3 -1
  304. package/dist/engine/event-helpers.js +3 -3
  305. package/dist/engine/extension-names.d.ts +2 -8
  306. package/dist/engine/extension-names.js +2 -2
  307. package/dist/engine/extension-selector-plugins.d.ts +1 -1
  308. package/dist/engine/extensions/storage-provider.d.ts +1 -2
  309. package/dist/engine/extensions/user-data.d.ts +0 -8
  310. package/dist/engine/factories.d.ts +2 -1
  311. package/dist/engine/feature-builder-state.d.ts +9 -1
  312. package/dist/engine/feature-builder-state.js +1 -0
  313. package/dist/engine/feature-changelog.d.ts +1 -1
  314. package/dist/engine/feature-config-events-jobs.d.ts +4 -1
  315. package/dist/engine/feature-entity-handlers.d.ts +5 -1
  316. package/dist/engine/feature-manifest.d.ts +1 -0
  317. package/dist/engine/feature-manifest.js +2 -1
  318. package/dist/engine/feature-ui-extensions.d.ts +7 -1
  319. package/dist/engine/feature-ui-extensions.js +6 -4
  320. package/dist/engine/field-access.d.ts +3 -1
  321. package/dist/engine/field-access.js +12 -0
  322. package/dist/engine/handler-field-references.d.ts +0 -4
  323. package/dist/engine/index.d.ts +58 -55
  324. package/dist/engine/index.js +23 -28
  325. package/dist/engine/instruction-fields.d.ts +1 -1
  326. package/dist/engine/personal-data-fields.d.ts +1 -1
  327. package/dist/engine/qualified-name.d.ts +0 -1
  328. package/dist/engine/read-claim.d.ts +2 -1
  329. package/dist/engine/registry-facade.js +0 -3
  330. package/dist/engine/registry-ingest.d.ts +2 -1
  331. package/dist/engine/registry-ingest.js +1 -2
  332. package/dist/engine/registry-state.d.ts +12 -2
  333. package/dist/engine/registry-state.js +2 -3
  334. package/dist/engine/registry-validate.d.ts +3 -1
  335. package/dist/engine/registry-validate.js +7 -7
  336. package/dist/engine/run-in.d.ts +1 -1
  337. package/dist/engine/run-in.js +0 -1
  338. package/dist/engine/schema-builder.d.ts +1 -1
  339. package/dist/engine/schema-builder.js +1 -1
  340. package/dist/engine/screen-filter-ops.d.ts +2 -1
  341. package/dist/engine/screen-filter-ops.js +2 -5
  342. package/dist/engine/soft-delete-cleanup.d.ts +1 -1
  343. package/dist/engine/soft-delete-cleanup.js +4 -4
  344. package/dist/engine/state-machine.js +2 -1
  345. package/dist/engine/steps/_read-source.js +1 -1
  346. package/dist/engine/steps/aggregate-append-event.js +2 -2
  347. package/dist/engine/steps/call-feature.js +2 -2
  348. package/dist/engine/steps/mail-send.js +1 -1
  349. package/dist/engine/steps/retry.js +1 -1
  350. package/dist/engine/steps/wait-for-event.js +1 -1
  351. package/dist/engine/steps/wait.js +1 -1
  352. package/dist/engine/steps/webhook-send.js +1 -1
  353. package/dist/engine/strip-disabled-features-from-app-schema.js +7 -3
  354. package/dist/engine/template-variables.d.ts +2 -1
  355. package/dist/engine/transfer-adjacency.d.ts +1 -1
  356. package/dist/engine/types/feature.d.ts +1 -0
  357. package/dist/engine/types/index.d.ts +8 -30
  358. package/dist/engine/types/index.js +2 -10
  359. package/dist/engine/types/screen.d.ts +1 -1
  360. package/dist/engine/types/screen.js +1 -1
  361. package/dist/engine/validation.d.ts +2 -1
  362. package/dist/entrypoint/index.d.ts +9 -35
  363. package/dist/entrypoint/index.js +10 -1
  364. package/dist/entrypoint/internals.d.ts +40 -0
  365. package/dist/entrypoint/internals.js +1 -0
  366. package/dist/entrypoint/row-level-security-mode-check.d.ts +3 -0
  367. package/dist/entrypoint/row-level-security-mode-check.js +19 -0
  368. package/dist/env/dry-run-internals.d.ts +10 -0
  369. package/dist/env/dry-run-internals.js +1 -0
  370. package/dist/env/dry-run.d.ts +1 -10
  371. package/dist/env/dry-run.js +2 -1
  372. package/dist/env/index.d.ts +1 -85
  373. package/dist/env/index.js +6 -50
  374. package/dist/env/internals.d.ts +87 -0
  375. package/dist/env/internals.js +53 -0
  376. package/dist/errors/classes.js +2 -2
  377. package/dist/errors/index.d.ts +5 -14
  378. package/dist/errors/index.js +4 -9
  379. package/dist/errors/member-resolution.js +1 -1
  380. package/dist/errors/reasons.d.ts +0 -1
  381. package/dist/errors/reasons.js +7 -7
  382. package/dist/errors/serialize.d.ts +0 -18
  383. package/dist/errors/serialize.js +0 -27
  384. package/dist/es-ops/index.d.ts +4 -4
  385. package/dist/es-ops/index.js +2 -2
  386. package/dist/es-ops/operations-schema.d.ts +1 -1
  387. package/dist/es-ops/types.d.ts +4 -5
  388. package/dist/event-store/admin-api-internals.d.ts +14 -0
  389. package/dist/event-store/admin-api-internals.js +1 -0
  390. package/dist/event-store/admin-api.d.ts +1 -14
  391. package/dist/event-store/admin-api.js +11 -6
  392. package/dist/event-store/archive.js +4 -2
  393. package/dist/event-store/errors.js +2 -2
  394. package/dist/event-store/event-store.d.ts +1 -0
  395. package/dist/event-store/event-store.js +42 -32
  396. package/dist/event-store/events-schema.js +4 -1
  397. package/dist/event-store/index.d.ts +11 -13
  398. package/dist/event-store/index.js +7 -9
  399. package/dist/event-store/provenance-append.js +1 -1
  400. package/dist/event-store/rebuild-dead-letter.js +4 -2
  401. package/dist/event-store/snapshot.js +4 -3
  402. package/dist/event-store/stream-scope.d.ts +2 -0
  403. package/dist/event-store/stream-scope.js +6 -0
  404. package/dist/event-store/upcaster-dead-letter.js +4 -2
  405. package/dist/event-store/upcaster.d.ts +2 -1
  406. package/dist/files/action-form-upload.d.ts +2 -1
  407. package/dist/files/action-form-upload.js +1 -1
  408. package/dist/files/assert-file-refs-belong-to-tenant.d.ts +2 -1
  409. package/dist/files/assert-file-refs-belong-to-tenant.js +1 -1
  410. package/dist/files/bind-pending-file-refs.d.ts +2 -1
  411. package/dist/files/bind-pending-file-refs.js +2 -1
  412. package/dist/files/bind-referenced-files.write.js +1 -1
  413. package/dist/files/create-file-ref-from-bytes.d.ts +6 -3
  414. package/dist/files/create-file-ref-from-bytes.js +6 -3
  415. package/dist/files/create-file-ref.d.ts +6 -2
  416. package/dist/files/create-file-ref.js +13 -4
  417. package/dist/files/dispose-removed-file-refs.d.ts +2 -1
  418. package/dist/files/dispose-removed-file-refs.js +1 -1
  419. package/dist/files/feature.js +2 -2
  420. package/dist/files/file-handle.js +1 -1
  421. package/dist/files/file-routes.d.ts +3 -1
  422. package/dist/files/file-routes.js +41 -4
  423. package/dist/files/index.d.ts +11 -13
  424. package/dist/files/index.js +5 -7
  425. package/dist/files/load-save-file-refs.d.ts +2 -1
  426. package/dist/files/load-save-file-refs.js +1 -1
  427. package/dist/files/provider-resolver.d.ts +6 -4
  428. package/dist/files/provider-resolver.js +5 -5
  429. package/dist/files/record-write-check.d.ts +6 -0
  430. package/dist/files/record-write-check.js +13 -0
  431. package/dist/files/storage-tracking.js +4 -2
  432. package/dist/files/sweep-orphaned-uploads.d.ts +1 -1
  433. package/dist/files/sweep-orphaned-uploads.js +1 -1
  434. package/dist/files/upload-ledger.d.ts +2 -2
  435. package/dist/files/upload-ledger.js +4 -4
  436. package/dist/i18n/index.d.ts +2 -8
  437. package/dist/i18n/index.js +1 -1
  438. package/dist/i18n/internals.d.ts +7 -0
  439. package/dist/i18n/internals.js +1 -0
  440. package/dist/i18n/required-surface-keys.d.ts +4 -1
  441. package/dist/i18n/required-surface-keys.js +7 -2
  442. package/dist/internal/row-level-security.d.ts +3 -0
  443. package/dist/internal/row-level-security.js +3 -0
  444. package/dist/internal/stack-support.d.ts +1 -1
  445. package/dist/internal/stack-support.js +1 -1
  446. package/dist/internal/testing.d.ts +1 -0
  447. package/dist/internal/testing.js +10 -6
  448. package/dist/jobs/index.d.ts +1 -1
  449. package/dist/jobs/job-append-event.d.ts +12 -0
  450. package/dist/jobs/job-append-event.js +30 -0
  451. package/dist/jobs/job-runner-context.d.ts +2 -2
  452. package/dist/jobs/job-runner-context.js +46 -16
  453. package/dist/jobs/job-runner-execution.d.ts +1 -1
  454. package/dist/jobs/job-runner-execution.js +6 -4
  455. package/dist/jobs/job-runner-gates.d.ts +1 -1
  456. package/dist/jobs/job-runner-gates.js +0 -1
  457. package/dist/jobs/job-runner-helpers.d.ts +11 -4
  458. package/dist/jobs/job-runner-helpers.js +10 -1
  459. package/dist/jobs/job-runner-scope.d.ts +5 -2
  460. package/dist/jobs/job-runner-scope.js +6 -6
  461. package/dist/jobs/job-runner-types.d.ts +2 -1
  462. package/dist/jobs/job-runner.js +22 -6
  463. package/dist/jobs/max-per-tenant.d.ts +1 -1
  464. package/dist/logging/index.d.ts +1 -2
  465. package/dist/logging/index.js +1 -1
  466. package/dist/logging/pino-logger.js +1 -1
  467. package/dist/logging/utils.d.ts +1 -0
  468. package/dist/logging/utils.js +6 -0
  469. package/dist/migrations/index.d.ts +3 -3
  470. package/dist/migrations/index.js +3 -3
  471. package/dist/migrations/pending-rebuilds.d.ts +1 -1
  472. package/dist/migrations/pending-rebuilds.js +1 -1
  473. package/dist/migrations/pii-event-backfill.js +4 -1
  474. package/dist/observability/escape-hatch-report.d.ts +2 -1
  475. package/dist/observability/escape-hatch-report.js +9 -2
  476. package/dist/observability/index.d.ts +7 -15
  477. package/dist/observability/index.js +4 -12
  478. package/dist/observability/metric-validator.js +1 -1
  479. package/dist/observability/metrics-handle.d.ts +0 -1
  480. package/dist/observability/metrics-handle.js +2 -15
  481. package/dist/observability/recording-tracer.d.ts +1 -2
  482. package/dist/observability/recording-tracer.js +0 -6
  483. package/dist/observability/sensitive-filter.d.ts +0 -2
  484. package/dist/observability/sensitive-filter.js +0 -29
  485. package/dist/pipeline/active-membership.d.ts +2 -1
  486. package/dist/pipeline/active-membership.js +6 -2
  487. package/dist/pipeline/after-rollback-sink.d.ts +6 -0
  488. package/dist/pipeline/after-rollback-sink.js +32 -0
  489. package/dist/pipeline/append-event-core.d.ts +2 -1
  490. package/dist/pipeline/append-event-core.js +2 -2
  491. package/dist/pipeline/attach-outside-transaction.d.ts +3 -0
  492. package/dist/pipeline/attach-outside-transaction.js +13 -0
  493. package/dist/pipeline/auth-claims-resolver.d.ts +2 -1
  494. package/dist/pipeline/cascade-handler.d.ts +2 -1
  495. package/dist/pipeline/cascade-handler.js +3 -2
  496. package/dist/pipeline/config-accessor-factory.d.ts +1 -1
  497. package/dist/pipeline/config-accessor-factory.js +1 -1
  498. package/dist/pipeline/context-services.d.ts +56 -0
  499. package/dist/pipeline/context-services.js +73 -0
  500. package/dist/pipeline/dispatch-batch.d.ts +2 -1
  501. package/dist/pipeline/dispatch-batch.js +39 -19
  502. package/dist/pipeline/dispatch-query.js +5 -4
  503. package/dist/pipeline/dispatch-scope.d.ts +6 -0
  504. package/dist/pipeline/dispatch-scope.js +27 -0
  505. package/dist/pipeline/dispatch-shared.d.ts +13 -9
  506. package/dist/pipeline/dispatch-shared.js +75 -194
  507. package/dist/pipeline/dispatch-stream.js +8 -4
  508. package/dist/pipeline/dispatch-write.d.ts +2 -1
  509. package/dist/pipeline/dispatch-write.js +10 -8
  510. package/dist/pipeline/dispatcher-utils.d.ts +3 -1
  511. package/dist/pipeline/dispatcher-utils.js +8 -2
  512. package/dist/pipeline/dispatcher.d.ts +3 -2
  513. package/dist/pipeline/dispatcher.js +4 -3
  514. package/dist/pipeline/event-consumer-state.d.ts +0 -1
  515. package/dist/pipeline/event-dispatcher-delivery.d.ts +1 -1
  516. package/dist/pipeline/event-dispatcher-delivery.js +7 -3
  517. package/dist/pipeline/event-dispatcher.d.ts +3 -2
  518. package/dist/pipeline/event-dispatcher.js +13 -12
  519. package/dist/pipeline/event-retention.js +59 -56
  520. package/dist/pipeline/handler-access-error.js +2 -1
  521. package/dist/pipeline/handler-context-auth.d.ts +5 -6
  522. package/dist/pipeline/handler-context-auth.js +7 -4
  523. package/dist/pipeline/handler-context-config.d.ts +2 -5
  524. package/dist/pipeline/handler-context-config.js +2 -2
  525. package/dist/pipeline/handler-context-db.d.ts +32 -7
  526. package/dist/pipeline/handler-context-db.js +26 -17
  527. package/dist/pipeline/handler-context-dispatch.d.ts +14 -6
  528. package/dist/pipeline/handler-context-dispatch.js +18 -5
  529. package/dist/pipeline/handler-context-events.d.ts +22 -38
  530. package/dist/pipeline/handler-context-events.js +42 -35
  531. package/dist/pipeline/handler-context-member-resolution.d.ts +2 -0
  532. package/dist/pipeline/handler-context-member-resolution.js +110 -0
  533. package/dist/pipeline/handler-context-notify.d.ts +3 -2
  534. package/dist/pipeline/handler-context-notify.js +1 -1
  535. package/dist/pipeline/handler-context-observability.d.ts +2 -4
  536. package/dist/pipeline/handler-context-observability.js +7 -5
  537. package/dist/pipeline/handler-context-phase-denials.d.ts +11 -0
  538. package/dist/pipeline/handler-context-phase-denials.js +98 -0
  539. package/dist/pipeline/handler-context-scope.d.ts +7 -10
  540. package/dist/pipeline/handler-context-scope.js +18 -20
  541. package/dist/pipeline/index.d.ts +9 -21
  542. package/dist/pipeline/index.js +5 -7
  543. package/dist/pipeline/irreversible-operation-gate.d.ts +1 -1
  544. package/dist/pipeline/irreversible-operation-gate.js +2 -2
  545. package/dist/pipeline/lifecycle-pipeline.d.ts +8 -7
  546. package/dist/pipeline/lifecycle-pipeline.js +9 -15
  547. package/dist/pipeline/member-read-only-transaction.js +11 -3
  548. package/dist/pipeline/member-reader.d.ts +1 -1
  549. package/dist/pipeline/member-reader.js +2 -2
  550. package/dist/pipeline/msp-rebuild.js +5 -3
  551. package/dist/pipeline/multi-stream-apply-context.js +3 -2
  552. package/dist/pipeline/notify-scope.d.ts +2 -1
  553. package/dist/pipeline/pre-handler-gates.d.ts +2 -1
  554. package/dist/pipeline/pre-transaction-reservations.d.ts +3 -3
  555. package/dist/pipeline/pre-transaction-reservations.js +9 -7
  556. package/dist/pipeline/projection-rebuild.js +12 -5
  557. package/dist/pipeline/projection-state.d.ts +0 -6
  558. package/dist/pipeline/projection-state.js +0 -5
  559. package/dist/pipeline/projections-runner.d.ts +2 -1
  560. package/dist/pipeline/projections-runner.js +10 -6
  561. package/dist/pipeline/system-hooks.d.ts +6 -2
  562. package/dist/pipeline/system-hooks.js +61 -10
  563. package/dist/pipeline/system-identity-switch.d.ts +4 -2
  564. package/dist/pipeline/system-identity-switch.js +51 -36
  565. package/dist/pipeline/typed-append-event.d.ts +2 -0
  566. package/dist/pipeline/typed-append-event.js +4 -0
  567. package/dist/pipeline/write-origin.js +2 -2
  568. package/dist/pipeline/write-result-masking.d.ts +1 -1
  569. package/dist/pipeline/write-result-masking.js +13 -10
  570. package/dist/random/index.d.ts +1 -2
  571. package/dist/random/index.js +1 -2
  572. package/dist/rate-limit/bucket.d.ts +2 -1
  573. package/dist/rate-limit/middleware.js +2 -1
  574. package/dist/redis/index.d.ts +3 -4
  575. package/dist/redis/index.js +2 -2
  576. package/dist/schema-cli/apply-command.js +5 -2
  577. package/dist/schema-cli/baseline-command.js +7 -2
  578. package/dist/schema-cli/generate-command.js +7 -9
  579. package/dist/schema-cli/shared.d.ts +4 -0
  580. package/dist/schema-cli/shared.js +21 -2
  581. package/dist/schema-cli/status-command.js +8 -2
  582. package/dist/schema-cli/validate-command.js +52 -4
  583. package/dist/schema-cli.d.ts +0 -1
  584. package/dist/search/configure-tenant-index.d.ts +1 -3
  585. package/dist/search/configure-tenant-index.js +0 -4
  586. package/dist/search/index.d.ts +1 -4
  587. package/dist/search/index.js +0 -2
  588. package/dist/search/meilisearch-adapter-internals.d.ts +8 -0
  589. package/dist/search/meilisearch-adapter-internals.js +9 -0
  590. package/dist/search/meilisearch-adapter.d.ts +1 -8
  591. package/dist/search/meilisearch-adapter.js +6 -7
  592. package/dist/search/meilisearch-peer.d.ts +2 -0
  593. package/dist/search/meilisearch-peer.js +5 -0
  594. package/dist/search/reindex-entity.js +107 -91
  595. package/dist/secrets/index.d.ts +3 -4
  596. package/dist/secrets/index.js +2 -3
  597. package/dist/seeding/index.d.ts +2 -2
  598. package/dist/seeding/index.js +1 -2
  599. package/dist/time/index.d.ts +2 -2
  600. package/dist/time/index.js +1 -1
  601. package/dist/time/tz-context.d.ts +0 -5
  602. package/dist/time/tz-context.js +0 -9
  603. package/dist/ui-types/index.d.ts +8 -11
  604. package/dist/ui-types/index.js +3 -3
  605. package/dist/upgrade-changelog.d.ts +3 -0
  606. package/dist/upgrade-changelog.js +18 -0
  607. package/dist/upgrade-cli-internals.d.ts +8 -0
  608. package/dist/upgrade-cli-internals.js +63 -0
  609. package/dist/upgrade-cli.d.ts +1 -18
  610. package/dist/upgrade-cli.js +29 -137
  611. package/dist/upgrade-marker-parse.d.ts +32 -0
  612. package/dist/upgrade-marker-parse.js +73 -0
  613. package/dist/utils/import-optional-peer.d.ts +6 -0
  614. package/dist/utils/import-optional-peer.js +19 -0
  615. package/dist/utils/index.d.ts +1 -4
  616. package/dist/utils/index.js +1 -4
  617. package/package.json +27 -20
  618. package/src/changes.json +451 -0
  619. package/dist/crypto/request-kms-cache.d.ts +0 -8
  620. package/dist/crypto/request-kms-cache.js +0 -21
  621. package/dist/engine/codemod/index.d.ts +0 -2
  622. package/dist/engine/codemod/index.js +0 -1
  623. package/dist/engine/codemod/pipeline-codemod.d.ts +0 -50
  624. package/dist/engine/codemod/pipeline-codemod.js +0 -536
  625. package/dist/engine/feature-ast/entity-field-types.d.ts +0 -13
  626. package/dist/engine/feature-ast/entity-field-types.js +0 -35
  627. package/dist/engine/feature-ast/extractors/ai-steps.d.ts +0 -6
  628. package/dist/engine/feature-ast/extractors/ai-steps.js +0 -254
  629. package/dist/engine/feature-ast/extractors/events.d.ts +0 -5
  630. package/dist/engine/feature-ast/extractors/events.js +0 -275
  631. package/dist/engine/feature-ast/extractors/handlers.d.ts +0 -24
  632. package/dist/engine/feature-ast/extractors/handlers.js +0 -358
  633. package/dist/engine/feature-ast/extractors/hooks.d.ts +0 -24
  634. package/dist/engine/feature-ast/extractors/hooks.js +0 -248
  635. package/dist/engine/feature-ast/extractors/index.d.ts +0 -14
  636. package/dist/engine/feature-ast/extractors/index.js +0 -13
  637. package/dist/engine/feature-ast/extractors/jobs-routes.d.ts +0 -7
  638. package/dist/engine/feature-ast/extractors/jobs-routes.js +0 -145
  639. package/dist/engine/feature-ast/extractors/projections-screens.d.ts +0 -10
  640. package/dist/engine/feature-ast/extractors/projections-screens.js +0 -195
  641. package/dist/engine/feature-ast/extractors/resolve-import.d.ts +0 -21
  642. package/dist/engine/feature-ast/extractors/resolve-import.js +0 -180
  643. package/dist/engine/feature-ast/extractors/round1.d.ts +0 -10
  644. package/dist/engine/feature-ast/extractors/round1.js +0 -81
  645. package/dist/engine/feature-ast/extractors/round2.d.ts +0 -7
  646. package/dist/engine/feature-ast/extractors/round2.js +0 -191
  647. package/dist/engine/feature-ast/extractors/round3.d.ts +0 -23
  648. package/dist/engine/feature-ast/extractors/round3.js +0 -292
  649. package/dist/engine/feature-ast/extractors/round5.d.ts +0 -9
  650. package/dist/engine/feature-ast/extractors/round5.js +0 -68
  651. package/dist/engine/feature-ast/extractors/round6.d.ts +0 -4
  652. package/dist/engine/feature-ast/extractors/round6.js +0 -17
  653. package/dist/engine/feature-ast/extractors/shared.d.ts +0 -94
  654. package/dist/engine/feature-ast/extractors/shared.js +0 -343
  655. package/dist/engine/feature-ast/index.d.ts +0 -16
  656. package/dist/engine/feature-ast/index.js +0 -10
  657. package/dist/engine/feature-ast/parse.d.ts +0 -31
  658. package/dist/engine/feature-ast/parse.js +0 -483
  659. package/dist/engine/feature-ast/patch.d.ts +0 -210
  660. package/dist/engine/feature-ast/patch.js +0 -610
  661. package/dist/engine/feature-ast/patcher.d.ts +0 -217
  662. package/dist/engine/feature-ast/patcher.js +0 -281
  663. package/dist/engine/feature-ast/pattern-change-schema.d.ts +0 -1476
  664. package/dist/engine/feature-ast/pattern-change-schema.js +0 -1226
  665. package/dist/engine/feature-ast/pattern-id-matchers.d.ts +0 -7
  666. package/dist/engine/feature-ast/pattern-id-matchers.js +0 -210
  667. package/dist/engine/feature-ast/patterns.d.ts +0 -318
  668. package/dist/engine/feature-ast/patterns.js +0 -106
  669. package/dist/engine/feature-ast/render.d.ts +0 -47
  670. package/dist/engine/feature-ast/render.js +0 -662
  671. package/dist/engine/feature-ast/source-location.d.ts +0 -17
  672. package/dist/engine/feature-ast/source-location.js +0 -27
  673. package/dist/engine/pattern-library/index.d.ts +0 -2
  674. package/dist/engine/pattern-library/index.js +0 -3
  675. package/dist/engine/pattern-library/library.d.ts +0 -14
  676. package/dist/engine/pattern-library/library.js +0 -93
  677. package/dist/engine/pattern-library/mixed-schemas.d.ts +0 -16
  678. package/dist/engine/pattern-library/mixed-schemas.js +0 -559
  679. package/dist/engine/pattern-library/opaque-schemas.d.ts +0 -7
  680. package/dist/engine/pattern-library/opaque-schemas.js +0 -115
  681. package/dist/engine/pattern-library/shared-fields.d.ts +0 -122
  682. package/dist/engine/pattern-library/shared-fields.js +0 -88
  683. package/dist/engine/pattern-library/static-schemas.d.ts +0 -20
  684. package/dist/engine/pattern-library/static-schemas.js +0 -478
  685. package/dist/engine/pattern-library/types.d.ts +0 -158
  686. package/dist/engine/pattern-library/types.js +0 -36
  687. package/dist/engine/provider-plugin-context.d.ts +0 -3
  688. package/dist/engine/provider-plugin-context.js +0 -28
  689. package/dist/engine/resolve-config-or-param.d.ts +0 -18
  690. package/dist/engine/resolve-config-or-param.js +0 -76
  691. package/src/scripts/codemod/README.md +0 -187
  692. package/src/scripts/codemod/codemod-support.ts +0 -334
  693. package/src/scripts/codemod/collect-source-files.ts +0 -48
  694. package/src/scripts/codemod/crypto-shredding-testing-move.ts +0 -119
  695. package/src/scripts/codemod/db-factory.ts +0 -810
  696. package/src/scripts/codemod/feature-factory.ts +0 -429
  697. package/src/scripts/codemod/feature-layout.ts +0 -424
  698. package/src/scripts/codemod/import-extensions.ts +0 -118
  699. package/src/scripts/codemod/migrate-cross-tenant.ts +0 -328
  700. package/src/scripts/codemod/migrate-db-raw.ts +0 -401
  701. package/src/scripts/codemod/migrate-open-to-all.ts +0 -235
  702. package/src/scripts/codemod/object-form.ts +0 -746
  703. package/src/scripts/codemod/package-merge.ts +0 -299
  704. package/src/scripts/codemod/pii-personal-migration.ts +0 -816
  705. package/src/scripts/codemod/remove-engine-payload-casts.ts +0 -318
  706. package/src/scripts/codemod/s3-imports.ts +0 -236
  707. package/src/scripts/codemod/tenant-db-options.ts +0 -454
  708. package/src/scripts/codemod/testing-injection.ts +0 -215
  709. package/src/scripts/codemod/testing-move-targets.ts +0 -161
  710. package/src/scripts/codemod/testing-move.ts +0 -542
  711. package/src/scripts/codemod/unprocessable-error-details-reason.ts +0 -411
@@ -1,816 +0,0 @@
1
- #!/usr/bin/env bun
2
- // Migrates create*Field(...) calls from the old flag-based PII API (pii,
3
- // userOwned, tenantOwned, subjectRef, allowPlaintext, lookupable,
4
- // searchable, sensitive) to the author-facing personal/find API.
5
- // Idempotent — re-running is a no-op on already migrated fields (skipped once
6
- // a `personal` property is present).
7
- //
8
- // Mapping table (exact):
9
- // pii: true -> personal: "self"
10
- // userOwned: { ownerField: "x" } -> personal: { of: "x" }
11
- // tenantOwned: true -> personal: "tenant"
12
- // subjectRef: true -> personal: "ref"
13
- // allowPlaintext: "R" -> personal: false, reason: "<R, normalized to snake_case>"
14
- // lookupable: true (alone) -> find: "exact"
15
- // lookupable: true + searchable: true -> find: "fuzzy"
16
- // searchable: true (alone) -> find: "fuzzy"
17
- // sensitive: true -> find: "secret"
18
- // none of the above -> find: "none"
19
- // `find` only applies to text/longText fields, and only when the subject
20
- // is neither "ref" nor `personal: false` (see PersonalAnnotations in
21
- // packages/types/src/fields.ts). Never guesses: anything outside this
22
- // table is reported (file:line) instead of transformed.
23
- //
24
- // Usage: bun scripts/codemod/pii-personal-migration.ts <targetDir> [--dry-run | --report-stance]
25
- // --report-stance is read-only: it writes nothing and classifies fields
26
- // that carry no personal stance.
27
-
28
- import { readFileSync } from "node:fs";
29
- import { relative, resolve } from "node:path";
30
- import {
31
- PII_DIRECT_NAME_HINTS,
32
- PII_USER_OWNED_NAME_HINTS,
33
- PII_USER_REFERENCE_NAME_HINTS,
34
- } from "@cosmicdrift/kumiko-framework/engine";
35
- import { Glob } from "bun";
36
- import {
37
- type CallExpression,
38
- Node,
39
- type ObjectLiteralExpression,
40
- Project,
41
- type PropertyAssignment,
42
- type SourceFile,
43
- SyntaxKind,
44
- } from "ts-morph";
45
-
46
- const SUBJECT_FLAG_NAMES = [
47
- "pii",
48
- "userOwned",
49
- "tenantOwned",
50
- "subjectRef",
51
- "allowPlaintext",
52
- ] as const;
53
- type SubjectFlagName = (typeof SUBJECT_FLAG_NAMES)[number];
54
-
55
- // `create*Field` factories that accept `find` (text/longText) — see
56
- // packages/framework/src/engine/factories.ts.
57
- const TEXT_FIND_FACTORIES = new Set(["createTextField"]);
58
- const LONGTEXT_FIND_FACTORIES = new Set(["createLongTextField"]);
59
- // Accept `personal` but never `find` (PersonalAnnotationsNoFind).
60
- const NO_FIND_FACTORIES = new Set([
61
- "createSelectField",
62
- "createMultiSelectField",
63
- "createNumberField",
64
- "createBigIntField",
65
- "createDecimalField",
66
- "createEmbeddedField",
67
- "createEmbeddedListField",
68
- "createJsonbField",
69
- "createDateField",
70
- "createTimestampField",
71
- "createTzField",
72
- "createLocatedTimestampField",
73
- ]);
74
- // No personal-annotation support at all — a subject flag here is a bug.
75
- const NO_PERSONAL_FACTORIES = new Set([
76
- "createBooleanField",
77
- "createMoneyField",
78
- "createFileField",
79
- "createImageField",
80
- "createFilesField",
81
- "createImagesField",
82
- "createDerivedField",
83
- ]);
84
- // Overrides live in argument position 1, not 0.
85
- const OVERRIDES_ARG_INDEX_1 = new Set(["createEmbeddedField", "createEmbeddedListField"]);
86
-
87
- const FIELD_FACTORY_RE = /^create\w*Field$/;
88
-
89
- type ReportEntry = { readonly file: string; readonly line: number; readonly note: string };
90
- const FIND_BUCKETS = [
91
- "exact",
92
- "fuzzy",
93
- "none",
94
- "secret",
95
- "ref",
96
- "personal-false",
97
- "no-find",
98
- ] as const;
99
- type FindBucket = (typeof FIND_BUCKETS)[number];
100
-
101
- const reports: ReportEntry[] = [];
102
- const newLookupableSites: ReportEntry[] = [];
103
- const counts: Record<FindBucket, number> = {
104
- exact: 0,
105
- fuzzy: 0,
106
- none: 0,
107
- secret: 0,
108
- ref: 0,
109
- "personal-false": 0,
110
- "no-find": 0,
111
- };
112
-
113
- function report(node: Node, note: string): void {
114
- reports.push({
115
- file: node.getSourceFile().getFilePath(),
116
- line: node.getStartLineNumber(),
117
- note,
118
- });
119
- }
120
-
121
- function isTrueLiteral(node: Node | undefined): boolean {
122
- return !!node && node.getKind() === SyntaxKind.TrueKeyword;
123
- }
124
-
125
- function findProp(obj: ObjectLiteralExpression, name: string): PropertyAssignment | undefined {
126
- const p = obj.getProperty(name);
127
- return p && Node.isPropertyAssignment(p) ? p : undefined;
128
- }
129
-
130
- // Reason-string convention (infra/guards/guard-error-reasons.ts):
131
- // ^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$ — lowercase snake_case, optional
132
- // dot-namespacing. Old allowPlaintext values are free-form kebab-case.
133
- function normalizeReasonSlug(raw: string): string {
134
- const slug = raw
135
- .trim()
136
- .toLowerCase()
137
- .replace(/[^a-z0-9.]+/g, "_")
138
- .replace(/_+/g, "_")
139
- .replace(/^[._]+|[._]+$/g, "");
140
- return /^[0-9]/.test(slug) ? `_${slug}` : slug;
141
- }
142
-
143
- type FieldCall = { readonly name: string; readonly objArg: ObjectLiteralExpression };
144
-
145
- function collectFieldCalls(sourceFile: SourceFile): FieldCall[] {
146
- const calls: FieldCall[] = [];
147
- for (const call of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {
148
- const exprNode = call.getExpression();
149
- if (!Node.isIdentifier(exprNode)) continue;
150
- const name = exprNode.getText();
151
- // `createTenantConfig`/`createUserConfig`/etc. never match — they
152
- // don't end in "Field", so they're out of scope by construction.
153
- if (!FIELD_FACTORY_RE.test(name)) continue;
154
-
155
- const argIndex = OVERRIDES_ARG_INDEX_1.has(name) ? 1 : 0;
156
- const objArg = call.getArguments()[argIndex];
157
- if (objArg && Node.isObjectLiteralExpression(objArg)) {
158
- calls.push({ name, objArg });
159
- }
160
- }
161
- return calls;
162
- }
163
-
164
- function reportRawSubjectLiterals(
165
- sourceFile: SourceFile,
166
- handled: ReadonlySet<ObjectLiteralExpression>,
167
- ): void {
168
- for (const objLit of sourceFile.getDescendantsOfKind(SyntaxKind.ObjectLiteralExpression)) {
169
- if (handled.has(objLit)) continue;
170
- const found = [...SUBJECT_FLAG_NAMES, "piiEncrypted"].filter((n) => objLit.getProperty(n));
171
- if (found.length > 0) {
172
- report(
173
- objLit,
174
- `subject flag(s) [${found.join(", ")}] on an object literal that is not a create*Field(...) call`,
175
- );
176
- }
177
- }
178
- }
179
-
180
- type SubjectProp = { readonly name: SubjectFlagName; readonly prop: PropertyAssignment };
181
- type PersonalInit = { readonly personal: string; readonly reason: string | undefined };
182
- type FindSupport = "text" | "longText" | "none";
183
- type FindabilityProps = {
184
- readonly lookupable: PropertyAssignment | undefined;
185
- readonly searchable: PropertyAssignment | undefined;
186
- readonly sensitive: PropertyAssignment | undefined;
187
- };
188
-
189
- function singleSubjectFlag(obj: ObjectLiteralExpression): SubjectProp | undefined {
190
- const subjectProps = SUBJECT_FLAG_NAMES.map((n) => ({ name: n, prop: findProp(obj, n) })).filter(
191
- (x): x is { name: SubjectFlagName; prop: PropertyAssignment } => !!x.prop,
192
- );
193
- if (subjectProps.length === 0) {
194
- // `searchable`/`sensitive` alone remain valid, unrelated FieldDef
195
- // properties — left untouched. `lookupable` alone can never compile
196
- // (always an excess property without a `personal` to attach `find`
197
- // to). `anonymize` alone has no PersonalAnnotations arm to live on.
198
- const lookupableProp = findProp(obj, "lookupable");
199
- if (lookupableProp) {
200
- report(
201
- lookupableProp,
202
- "lookupable without any subject annotation — no `personal` to attach `find` to",
203
- );
204
- }
205
- const anonymizeProp = obj.getProperty("anonymize");
206
- if (anonymizeProp) {
207
- report(
208
- anonymizeProp,
209
- "anonymize without any subject annotation — no PersonalAnnotations arm accepts anonymize alone",
210
- );
211
- }
212
- return undefined;
213
- }
214
- if (subjectProps.length > 1) {
215
- const first = subjectProps[0];
216
- if (first) {
217
- report(
218
- first.prop,
219
- `multiple subject annotations on one field (${subjectProps.map((s) => s.name).join(", ")}) — needs a human decision on which subject is correct`,
220
- );
221
- }
222
- return undefined;
223
- }
224
- return subjectProps[0];
225
- }
226
-
227
- function findSupportOf(factoryName: string, subject: SubjectProp): FindSupport | undefined {
228
- if (NO_PERSONAL_FACTORIES.has(factoryName)) {
229
- report(
230
- subject.prop,
231
- `${factoryName} has no personal-annotation support — subject flag "${subject.name}" cannot be expressed here`,
232
- );
233
- return undefined;
234
- }
235
- if (TEXT_FIND_FACTORIES.has(factoryName)) return "text";
236
- if (LONGTEXT_FIND_FACTORIES.has(factoryName)) return "longText";
237
- if (NO_FIND_FACTORIES.has(factoryName)) return "none";
238
- report(
239
- subject.prop,
240
- `unrecognized field factory "${factoryName}" — cannot verify its PersonalAnnotations shape`,
241
- );
242
- return undefined;
243
- }
244
-
245
- function personalFromTrueFlag(
246
- personal: string,
247
- ): (subject: SubjectProp) => PersonalInit | undefined {
248
- return (subject) => {
249
- if (isTrueLiteral(subject.prop.getInitializer())) return { personal, reason: undefined };
250
- report(subject.prop, `${subject.name} is set to a non-\`true\` value — cannot infer intent`);
251
- return undefined;
252
- };
253
- }
254
-
255
- function personalFromAllowPlaintext(subject: SubjectProp): PersonalInit | undefined {
256
- const init = subject.prop.getInitializer();
257
- if (!init) {
258
- report(subject.prop, "allowPlaintext has no value");
259
- return undefined;
260
- }
261
- const reason = Node.isStringLiteral(init)
262
- ? `"${normalizeReasonSlug(init.getLiteralText())}"`
263
- : init.getText();
264
- return { personal: "false", reason };
265
- }
266
-
267
- function personalFromUserOwned(subject: SubjectProp): PersonalInit | undefined {
268
- const init = subject.prop.getInitializer();
269
- if (!init || !Node.isObjectLiteralExpression(init)) {
270
- report(subject.prop, "userOwned value is not an object literal — cannot extract ownerField");
271
- return undefined;
272
- }
273
- const ownerFieldInit = findProp(init, "ownerField")?.getInitializer();
274
- if (!ownerFieldInit) {
275
- report(subject.prop, 'userOwned is missing an "ownerField" property');
276
- return undefined;
277
- }
278
- return { personal: `{ of: ${ownerFieldInit.getText()} }`, reason: undefined };
279
- }
280
-
281
- // One row per subject flag of the mapping table in the file header; a row
282
- // reports and returns undefined when the flag value cannot be mapped.
283
- const PERSONAL_INIT_BY_SUBJECT: Record<
284
- SubjectFlagName,
285
- (subject: SubjectProp) => PersonalInit | undefined
286
- > = {
287
- pii: personalFromTrueFlag(`"self"`),
288
- userOwned: personalFromUserOwned,
289
- tenantOwned: personalFromTrueFlag(`"tenant"`),
290
- subjectRef: personalFromTrueFlag(`"ref"`),
291
- allowPlaintext: personalFromAllowPlaintext,
292
- };
293
-
294
- // These PersonalAnnotations arms carry no `find` field at all.
295
- function migrateFindlessSubject(
296
- obj: ObjectLiteralExpression,
297
- subject: SubjectProp,
298
- personal: PersonalInit,
299
- lookupableProp: PropertyAssignment | undefined,
300
- ): void {
301
- const isRef = subject.name === "subjectRef";
302
- if (lookupableProp) {
303
- report(
304
- lookupableProp,
305
- `lookupable combined with personal:${isRef ? '"ref"' : "false"} — findability doesn't apply to this subject, table has no mapping`,
306
- );
307
- // skip: reported above — lookupable doesn't apply to this subject, no mapping to migrate
308
- return;
309
- }
310
- applyTransform(obj, [subject.prop], {
311
- personal: personal.personal,
312
- reason: personal.reason,
313
- find: undefined,
314
- });
315
- counts[isRef ? "ref" : "personal-false"]++;
316
- }
317
-
318
- function migrateNoFindField(
319
- obj: ObjectLiteralExpression,
320
- factoryName: string,
321
- subject: SubjectProp,
322
- personal: PersonalInit,
323
- findability: FindabilityProps,
324
- ): void {
325
- const stray = findability.lookupable ?? findability.searchable ?? findability.sensitive;
326
- if (stray) {
327
- report(
328
- stray,
329
- `${factoryName} has no \`find\` in its PersonalAnnotations — findability flag present on a non-text field`,
330
- );
331
- // skip: reported above — findability flag on a non-text field, no valid find to attach
332
- return;
333
- }
334
- applyTransform(obj, [subject.prop], {
335
- personal: personal.personal,
336
- reason: undefined,
337
- find: undefined,
338
- });
339
- counts["no-find"]++;
340
- }
341
-
342
- // lookupable + searchable and searchable alone both map to "fuzzy".
343
- function findValueOf(findability: FindabilityProps): "exact" | "fuzzy" | "none" | "secret" {
344
- if (findability.sensitive) return "secret";
345
- if (findability.searchable) return "fuzzy";
346
- if (findability.lookupable) return "exact";
347
- return "none";
348
- }
349
-
350
- function migrateTextFindField(
351
- obj: ObjectLiteralExpression,
352
- subject: SubjectProp,
353
- personal: PersonalInit,
354
- findability: FindabilityProps,
355
- support: Exclude<FindSupport, "none">,
356
- ): void {
357
- const { lookupable, searchable, sensitive } = findability;
358
- if (sensitive && (lookupable || searchable)) {
359
- report(
360
- sensitive,
361
- 'sensitive combined with lookupable/searchable — two find values ("secret" vs "exact"/"fuzzy"), needs a human decision',
362
- );
363
- // skip: reported above — sensitive plus lookupable/searchable is an ambiguous find value
364
- return;
365
- }
366
-
367
- const find = findValueOf(findability);
368
- if (support === "longText" && (find === "exact" || find === "fuzzy")) {
369
- const findSite = lookupable ?? searchable;
370
- if (findSite) {
371
- report(
372
- findSite,
373
- 'lookupable/searchable on createLongTextField — only "none"/"secret" are valid find values on longText',
374
- );
375
- }
376
- // skip: reported above — exact/fuzzy find isn't valid on createLongTextField
377
- return;
378
- }
379
-
380
- // searchable-alone -> "fuzzy" makes expandPersonalAnnotations add
381
- // `lookupable: true`, which the field didn't carry before — that's a
382
- // new `_bidx` column (DDL migration), tracked separately for the report.
383
- if (searchable && !lookupable) {
384
- newLookupableSites.push({
385
- file: obj.getSourceFile().getFilePath(),
386
- line: subject.prop.getStartLineNumber(),
387
- // Guard keys on property name `reason`; this is console copy, not an error code.
388
- note: "needs a `_bidx` column migration",
389
- });
390
- }
391
-
392
- const removedProps = [subject.prop, lookupable, searchable, sensitive].filter(
393
- (p): p is PropertyAssignment => !!p,
394
- );
395
- applyTransform(obj, removedProps, { personal: personal.personal, reason: undefined, find });
396
- counts[find]++;
397
- }
398
-
399
- function processObjectLiteral(obj: ObjectLiteralExpression, factoryName: string): void {
400
- // skip: field already carries `personal` — already migrated, idempotent no-op
401
- if (obj.getProperty("personal")) return;
402
-
403
- const piiEncryptedProp = obj.getProperty("piiEncrypted");
404
- if (piiEncryptedProp) {
405
- report(
406
- piiEncryptedProp,
407
- "piiEncrypted: true on an entity field (removed from the type system) — needs a human decision, not a mechanical mapping",
408
- );
409
- // skip: reported above — piiEncrypted needs a human decision, not a mechanical mapping
410
- return;
411
- }
412
-
413
- const subject = singleSubjectFlag(obj);
414
- // skip: no subject flag, or several, reported by singleSubjectFlag where needed
415
- if (!subject) return;
416
- const support = findSupportOf(factoryName, subject);
417
- // skip: factory without a verifiable PersonalAnnotations shape, reported by findSupportOf
418
- if (!support) return;
419
- const personal = PERSONAL_INIT_BY_SUBJECT[subject.name](subject);
420
- // skip: flag value cannot be mapped, reported by its PERSONAL_INIT_BY_SUBJECT row
421
- if (!personal) return;
422
-
423
- const findability: FindabilityProps = {
424
- lookupable: findProp(obj, "lookupable"),
425
- searchable: findProp(obj, "searchable"),
426
- sensitive: findProp(obj, "sensitive"),
427
- };
428
- if (subject.name === "subjectRef" || subject.name === "allowPlaintext") {
429
- migrateFindlessSubject(obj, subject, personal, findability.lookupable);
430
- } else if (support === "none") {
431
- migrateNoFindField(obj, factoryName, subject, personal, findability);
432
- } else {
433
- migrateTextFindField(obj, subject, personal, findability, support);
434
- }
435
- }
436
-
437
- function applyTransform(
438
- obj: ObjectLiteralExpression,
439
- removedProps: readonly PropertyAssignment[],
440
- next: { personal: string; reason: string | undefined; find: string | undefined },
441
- ): void {
442
- const properties = obj.getProperties();
443
- // Call sites always pass at least subject.prop; without an anchor there is nowhere to insert.
444
- const anchor = removedProps[0];
445
- if (!anchor) {
446
- // skip: no removed prop to anchor inserts on — nothing to transform
447
- return;
448
- }
449
- const anchorIndex = properties.indexOf(anchor);
450
- const removedSet = new Set<PropertyAssignment>(removedProps);
451
- let insertIndex = 0;
452
- for (let i = 0; i < anchorIndex; i++) {
453
- const property = properties[i];
454
- if (!(property && Node.isPropertyAssignment(property) && removedSet.has(property)))
455
- insertIndex++;
456
- }
457
-
458
- for (const p of removedProps) p.remove();
459
-
460
- const newProps: { name: string; initializer: string }[] = [
461
- { name: "personal", initializer: next.personal },
462
- ];
463
- if (next.find) newProps.push({ name: "find", initializer: `"${next.find}"` });
464
- if (next.reason !== undefined) newProps.push({ name: "reason", initializer: next.reason });
465
-
466
- obj.insertPropertyAssignments(insertIndex, newProps);
467
- }
468
-
469
- function findSourceFiles(rootDir: string, extraExcludes: readonly string[] = []): string[] {
470
- const glob = new Glob("**/*.{ts,tsx}");
471
- const EXCLUDE = ["/node_modules/", "/dist/", "/build/", ...extraExcludes];
472
- const files: string[] = [];
473
- for (const file of glob.scanSync({ cwd: rootDir, dot: false })) {
474
- if (file.endsWith(".d.ts")) continue;
475
- const abs = resolve(rootDir, file);
476
- if (EXCLUDE.some((p) => abs.includes(p))) continue;
477
- files.push(abs);
478
- }
479
- return files.sort();
480
- }
481
-
482
- export type StanceClass = "direct" | "user-owned" | "user-reference" | "near-miss" | "unclassified";
483
-
484
- export type HintCategory = "direct" | "user-owned" | "user-reference";
485
-
486
- export type StanceSite = {
487
- readonly line: number;
488
- readonly field: string;
489
- readonly entity: string | null;
490
- readonly callee: string;
491
- readonly stance: StanceClass;
492
- readonly hint: string | undefined;
493
- readonly nearMissOf: HintCategory | undefined;
494
- };
495
-
496
- type CategorizedHint = readonly [hint: string, category: HintCategory];
497
-
498
- const ALL_PII_NAME_HINTS: readonly CategorizedHint[] = [
499
- ...[...PII_DIRECT_NAME_HINTS].map((hint): CategorizedHint => [hint, "direct"]),
500
- ...[...PII_USER_OWNED_NAME_HINTS].map((hint): CategorizedHint => [hint, "user-owned"]),
501
- ...[...PII_USER_REFERENCE_NAME_HINTS].map((hint): CategorizedHint => [hint, "user-reference"]),
502
- ];
503
-
504
- type FieldClassification = {
505
- readonly stance: StanceClass;
506
- readonly hint: string | undefined;
507
- readonly nearMissOf: HintCategory | undefined;
508
- };
509
-
510
- const REPORT_STANCE_CALLEES = new Set(["createTextField", "createLongTextField"]);
511
-
512
- // Mirrors guard-text-field-stance.ts's hasPersonalStance exactly.
513
- function reportStanceHasPersonalStance(obj: ObjectLiteralExpression): boolean {
514
- const prop = obj.getProperty("personal");
515
- if (!prop || !Node.isPropertyAssignment(prop)) return false;
516
- const init = prop.getInitializer();
517
- return (
518
- init !== undefined &&
519
- init.getKind() !== SyntaxKind.UndefinedKeyword &&
520
- !(Node.isIdentifier(init) && init.getText() === "undefined") &&
521
- init.getKind() !== SyntaxKind.NullKeyword
522
- );
523
- }
524
-
525
- function reportStanceEnclosingFieldName(call: CallExpression): string | undefined {
526
- let node = call.getParent();
527
- while (node) {
528
- if (Node.isPropertyAssignment(node)) {
529
- // getName() keeps the quotes of a string-literal key; computed keys have no static name.
530
- const nameNode = node.getNameNode();
531
- if (Node.isStringLiteral(nameNode) || Node.isNoSubstitutionTemplateLiteral(nameNode)) {
532
- return nameNode.getLiteralText();
533
- }
534
- return Node.isIdentifier(nameNode) ? nameNode.getText() : undefined;
535
- }
536
- node = node.getParent();
537
- }
538
- return undefined;
539
- }
540
-
541
- function reportStanceResolveEntity(call: CallExpression): string | null {
542
- let node: Node | undefined = call.getParent();
543
- let entityCall: CallExpression | undefined;
544
- while (node) {
545
- if (Node.isCallExpression(node)) {
546
- const expr = node.getExpression();
547
- if (Node.isIdentifier(expr) && expr.getText() === "createEntity") {
548
- entityCall = node;
549
- break;
550
- }
551
- }
552
- node = node.getParent();
553
- }
554
- if (!entityCall) return null;
555
-
556
- const firstArg = entityCall.getArguments()[0];
557
- if (firstArg && Node.isObjectLiteralExpression(firstArg)) {
558
- const tableProp = firstArg.getProperty("table");
559
- if (tableProp && Node.isPropertyAssignment(tableProp)) {
560
- const init = tableProp.getInitializer();
561
- if (init && Node.isStringLiteral(init)) return init.getLiteralText();
562
- }
563
- }
564
- const varDecl = entityCall.getParentIfKind(SyntaxKind.VariableDeclaration);
565
- return varDecl ? varDecl.getName() : null;
566
- }
567
-
568
- function isSegmentStart(fieldOriginal: string, index: number): boolean {
569
- return (
570
- index === 0 || /[A-Z]/.test(fieldOriginal[index] ?? "") || fieldOriginal[index - 1] === "_"
571
- );
572
- }
573
-
574
- // A hint only counts when it starts and ends on a segment boundary (index 0 /
575
- // end of field, an uppercase letter in the original, or `_`) — otherwise a
576
- // coincidental substring like "text" in "contextId" or "type" in "contentType"
577
- // would false-positive.
578
- function hintOccursAtBoundary(fieldLower: string, fieldOriginal: string, hint: string): boolean {
579
- let searchFrom = 0;
580
- for (;;) {
581
- const index = fieldLower.indexOf(hint, searchFrom);
582
- if (index === -1) return false;
583
- const end = index + hint.length;
584
- if (
585
- isSegmentStart(fieldOriginal, index) &&
586
- (end === fieldOriginal.length || isSegmentStart(fieldOriginal, end))
587
- ) {
588
- return true;
589
- }
590
- searchFrom = index + 1;
591
- }
592
- }
593
-
594
- function findLongestBoundaryHint(
595
- fieldLower: string,
596
- fieldOriginal: string,
597
- ): CategorizedHint | undefined {
598
- let best: CategorizedHint | undefined;
599
- for (const entry of ALL_PII_NAME_HINTS) {
600
- const [hint] = entry;
601
- if (best && hint.length <= best[0].length) continue;
602
- if (hintOccursAtBoundary(fieldLower, fieldOriginal, hint)) best = entry;
603
- }
604
- return best;
605
- }
606
-
607
- function segmentAlignedSuffixes(fieldOriginal: string): string[] {
608
- const fieldLower = fieldOriginal.toLowerCase();
609
- const starts: number[] = [];
610
- for (let index = 0; index < fieldOriginal.length; index++) {
611
- if (isSegmentStart(fieldOriginal, index)) starts.push(index);
612
- }
613
- // Hints are lowercase, so a hint's own segment boundary is unknowable. A
614
- // single-segment tail ("Number", "Owner") is too generic to align with one;
615
- // two or more segments ("UserId") are specific enough.
616
- return starts.slice(0, -1).map((index) => fieldLower.slice(index));
617
- }
618
-
619
- // The hint sets only carry exact full names, so a suffix variant of one
620
- // (e.g. "...UserId" of "assigneeUserId") otherwise slips through undetected.
621
- // The suffix must be the tail of the hint: plain `includes` matched "number"
622
- // inside "phonenumber" for "orderNumber".
623
- function findShortestHintContainingSuffix(fieldOriginal: string): CategorizedHint | undefined {
624
- let best: CategorizedHint | undefined;
625
- for (const suffix of segmentAlignedSuffixes(fieldOriginal)) {
626
- if (suffix.length < 5) continue;
627
- for (const entry of ALL_PII_NAME_HINTS) {
628
- const [hint] = entry;
629
- if (hint === suffix || !hint.endsWith(suffix)) continue;
630
- if (!best || hint.length < best[0].length) best = entry;
631
- }
632
- }
633
- return best;
634
- }
635
-
636
- function classifyFieldStance(field: string): FieldClassification {
637
- const fieldLower = field.replaceAll("_", "").toLowerCase();
638
- if (PII_DIRECT_NAME_HINTS.has(fieldLower)) {
639
- return { stance: "direct", hint: fieldLower, nearMissOf: undefined };
640
- }
641
- if (PII_USER_OWNED_NAME_HINTS.has(fieldLower)) {
642
- return { stance: "user-owned", hint: fieldLower, nearMissOf: undefined };
643
- }
644
- if (PII_USER_REFERENCE_NAME_HINTS.has(fieldLower)) {
645
- return { stance: "user-reference", hint: fieldLower, nearMissOf: undefined };
646
- }
647
- const nearMiss =
648
- findLongestBoundaryHint(field.toLowerCase(), field) ?? findShortestHintContainingSuffix(field);
649
- if (nearMiss) {
650
- return { stance: "near-miss", hint: nearMiss[0], nearMissOf: nearMiss[1] };
651
- }
652
- return { stance: "unclassified", hint: undefined, nearMissOf: undefined };
653
- }
654
-
655
- function createReportStanceProject(): Project {
656
- return new Project({ useInMemoryFileSystem: true, skipFileDependencyResolution: true });
657
- }
658
-
659
- export function reportStanceForSource(
660
- source: string,
661
- filePath: string,
662
- project: Project = createReportStanceProject(),
663
- ): StanceSite[] {
664
- const sourceFile = project.createSourceFile(filePath, source, { overwrite: true });
665
- try {
666
- return collectStanceSites(sourceFile);
667
- } finally {
668
- // A shared project would otherwise keep every scanned file's AST alive.
669
- project.removeSourceFile(sourceFile);
670
- }
671
- }
672
-
673
- function collectStanceSites(sourceFile: SourceFile): StanceSite[] {
674
- const sites: StanceSite[] = [];
675
- for (const call of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {
676
- const exprNode = call.getExpression();
677
- if (!Node.isIdentifier(exprNode)) continue;
678
- const callee = exprNode.getText();
679
- if (!REPORT_STANCE_CALLEES.has(callee)) continue;
680
-
681
- const args = call.getArguments();
682
- if (args.length > 0) {
683
- const options = args[0];
684
- if (!options || !Node.isObjectLiteralExpression(options)) continue;
685
- if (options.getProperties().some((p) => p.isKind(SyntaxKind.SpreadAssignment))) continue;
686
- if (reportStanceHasPersonalStance(options)) continue;
687
- }
688
-
689
- const enclosingField = reportStanceEnclosingFieldName(call);
690
- // A call with no enclosing field (e.g. a bare createTextField() at top
691
- // level) has no real name to classify — `createTextField(...)` would
692
- // otherwise false-positive as a near-miss on its own "Text".
693
- const { stance, hint, nearMissOf }: FieldClassification = enclosingField
694
- ? classifyFieldStance(enclosingField)
695
- : { stance: "unclassified", hint: undefined, nearMissOf: undefined };
696
-
697
- sites.push({
698
- line: call.getStartLineNumber(),
699
- field: enclosingField ?? `${callee}(...)`,
700
- entity: reportStanceResolveEntity(call),
701
- callee,
702
- stance,
703
- hint,
704
- nearMissOf,
705
- });
706
- }
707
- return sites;
708
- }
709
-
710
- function formatHintSuffix(site: StanceSite): string {
711
- if (!site.hint) return "";
712
- return site.nearMissOf
713
- ? ` (hint: ${site.hint}, near ${site.nearMissOf})`
714
- : ` (hint: ${site.hint})`;
715
- }
716
-
717
- function reportStance(rootDir: string): void {
718
- console.log(
719
- `Scanning every .ts/.tsx under ${rootDir} except node_modules/dist/build/*.d.ts — guard-text-field-stance scans packages/*/src/** only, so counts can differ outside that scope.`,
720
- );
721
-
722
- const totals: Record<StanceClass, number> = {
723
- direct: 0,
724
- "user-owned": 0,
725
- "user-reference": 0,
726
- "near-miss": 0,
727
- unclassified: 0,
728
- };
729
- let total = 0;
730
-
731
- const project = createReportStanceProject();
732
- for (const file of findSourceFiles(rootDir)) {
733
- const sites = reportStanceForSource(readFileSync(file, "utf8"), file, project);
734
- if (sites.length === 0) continue;
735
-
736
- console.log(`\n${relative(rootDir, file)}`);
737
- for (const site of sites) {
738
- totals[site.stance]++;
739
- total++;
740
- const entity = site.entity ?? "<unresolved>";
741
- const hintSuffix = formatHintSuffix(site);
742
- console.log(
743
- ` ${site.line} ${site.field} entity=${entity} ${site.callee} ${site.stance}${hintSuffix}`,
744
- );
745
- }
746
- }
747
-
748
- console.log("\nBy stance:");
749
- for (const [stance, count] of Object.entries(totals)) {
750
- if (count > 0) console.log(` ${stance}: ${count}`);
751
- }
752
- console.log(`Total: ${total}`);
753
-
754
- if (totals["near-miss"] > 0) {
755
- console.log(
756
- "\nHint sets in entity-handler.ts are exact name matches — near-miss field names slip past the boot heuristic.",
757
- );
758
- }
759
- }
760
-
761
- async function main(): Promise<void> {
762
- const positional = process.argv.slice(2).filter((a) => !a.startsWith("--"));
763
- const rootDir = resolve(positional[0] ?? process.cwd());
764
-
765
- if (process.argv.includes("--report-stance")) {
766
- reportStance(rootDir);
767
- // skip: report mode never rewrites, so the transform path below must not run
768
- return;
769
- }
770
-
771
- const dryRun = process.argv.includes("--dry-run");
772
- // engine/factories.ts constructs raw ResolvedPiiFlags literals as the
773
- // *implementation* of expandPersonalAnnotations (personal -> flags) —
774
- // not an authored override, so it's not a migration target.
775
- const files = findSourceFiles(rootDir, ["/engine/factories.ts"]);
776
- const project = new Project({
777
- skipAddingFilesFromTsConfig: true,
778
- skipFileDependencyResolution: true,
779
- });
780
-
781
- let touchedFiles = 0;
782
- for (const file of files) {
783
- const sourceFile = project.addSourceFileAtPath(file);
784
- const calls = collectFieldCalls(sourceFile);
785
- const handled = new Set(calls.map((c) => c.objArg));
786
- reportRawSubjectLiterals(sourceFile, handled);
787
-
788
- const countsBefore = { ...counts };
789
- for (const { name, objArg } of calls) processObjectLiteral(objArg, name);
790
- const changed = FIND_BUCKETS.some((k) => counts[k] !== countsBefore[k]);
791
-
792
- if (changed) {
793
- touchedFiles++;
794
- if (!dryRun) sourceFile.saveSync();
795
- }
796
- }
797
-
798
- console.log(`\nScanned ${files.length} files under ${rootDir}${dryRun ? " (dry-run)" : ""}.`);
799
- console.log(`Touched ${touchedFiles} files.\n`);
800
- console.log("Transformed, by find/personal bucket:");
801
- for (const [bucket, n] of Object.entries(counts)) {
802
- if (n > 0) console.log(` ${bucket}: ${n}`);
803
- }
804
- console.log(`\nNewly gains lookupable (needs a _bidx migration): ${newLookupableSites.length}`);
805
- for (const r of newLookupableSites) {
806
- console.log(` ${relative(rootDir, r.file)}:${r.line} — ${r.note}`);
807
- }
808
- console.log(`\nReported (not transformed): ${reports.length}`);
809
- for (const r of reports) {
810
- console.log(` ${relative(rootDir, r.file)}:${r.line} — ${r.note}`);
811
- }
812
- }
813
-
814
- if (import.meta.main) {
815
- await main();
816
- }