@cosmicdrift/kumiko-framework 0.389.0 → 0.390.1

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 (617) hide show
  1. package/AGENTS.md +9 -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/inbound-mail-triage.md +1 -0
  13. package/agents/examples/lane-routing.md +2 -1
  14. package/agents/examples/legal-pages.md +2 -2
  15. package/agents/examples/lifecycle-hooks.md +3 -3
  16. package/agents/examples/managed-config.md +4 -4
  17. package/agents/examples/managed-pages.md +1 -1
  18. package/agents/examples/relations.md +19 -4
  19. package/agents/examples/search.md +4 -4
  20. package/agents/examples/secrets-demo.md +9 -6
  21. package/agents/examples/state-machine.md +2 -2
  22. package/agents/examples/tenant-settings.md +1 -1
  23. package/agents/examples/user-data-rights.md +3 -6
  24. package/agents/examples/workflow-engine.md +53 -47
  25. package/agents/examples.md +4 -4
  26. package/agents/features.md +1 -1
  27. package/dist/api/auth-middleware.js +1 -1
  28. package/dist/api/auth-routes-invite.js +2 -1
  29. package/dist/api/entity-read-access.d.ts +3 -1
  30. package/dist/api/export/export-columns.d.ts +3 -1
  31. package/dist/api/export/export-route.js +3 -2
  32. package/dist/api/export/export-screen.d.ts +2 -1
  33. package/dist/api/extra-route.d.ts +3 -1
  34. package/dist/api/index.d.ts +23 -27
  35. package/dist/api/index.js +13 -15
  36. package/dist/api/jwt.js +1 -1
  37. package/dist/api/observability-middleware.d.ts +1 -1
  38. package/dist/api/observability-middleware.js +2 -1
  39. package/dist/api/request-context-internals.d.ts +31 -0
  40. package/dist/api/request-context-internals.js +11 -0
  41. package/dist/api/request-context-scopes.d.ts +14 -0
  42. package/dist/api/request-context-scopes.js +69 -0
  43. package/dist/api/request-context.d.ts +1 -40
  44. package/dist/api/request-context.js +22 -51
  45. package/dist/api/request-id-middleware.d.ts +1 -1
  46. package/dist/api/route-registrars.d.ts +2 -1
  47. package/dist/api/route-registrars.js +1 -1
  48. package/dist/api/routes.js +7 -3
  49. package/dist/api/server-boot-checks.d.ts +1 -1
  50. package/dist/api/server-boot-checks.js +2 -2
  51. package/dist/api/server-event-dispatcher.d.ts +6 -1
  52. package/dist/api/server-event-dispatcher.js +3 -4
  53. package/dist/api/server-extra-routes.d.ts +1 -1
  54. package/dist/api/server-extra-routes.js +2 -1
  55. package/dist/api/server-middleware.js +3 -1
  56. package/dist/api/server-routes.d.ts +2 -1
  57. package/dist/api/server-wiring.js +6 -4
  58. package/dist/api/server.d.ts +2 -1
  59. package/dist/api/sse-route.d.ts +2 -1
  60. package/dist/api/tenant-scoped-secrets.d.ts +2 -0
  61. package/dist/api/tenant-scoped-secrets.js +13 -0
  62. package/dist/api/websocket-route.d.ts +1 -1
  63. package/dist/auth/index.d.ts +0 -1
  64. package/dist/auth/roles.d.ts +0 -5
  65. package/dist/compliance/duration-spec.d.ts +0 -1
  66. package/dist/compliance/duration-spec.js +0 -5
  67. package/dist/compliance/index.d.ts +4 -4
  68. package/dist/compliance/index.js +2 -2
  69. package/dist/compliance/profiles.d.ts +0 -15
  70. package/dist/compliance/profiles.js +0 -23
  71. package/dist/config/index.d.ts +10 -10
  72. package/dist/config/index.js +13 -1
  73. package/dist/config/internals.d.ts +9 -0
  74. package/dist/config/internals.js +1 -0
  75. package/dist/consumer-cli-internals.d.ts +4 -0
  76. package/dist/consumer-cli-internals.js +1 -0
  77. package/dist/consumer-cli.d.ts +1 -4
  78. package/dist/consumer-cli.js +5 -1
  79. package/dist/crypto/event-pii.js +1 -1
  80. package/dist/crypto/index.d.ts +8 -9
  81. package/dist/crypto/index.js +7 -8
  82. package/dist/crypto/pg-kms-adapter.js +6 -1
  83. package/dist/db/apply-entity-event.d.ts +1 -1
  84. package/dist/db/apply-entity-event.js +15 -47
  85. package/dist/db/blind-index-cleanup.js +91 -77
  86. package/dist/db/collect-table-metas.js +1 -1
  87. package/dist/db/compound-types.d.ts +1 -1
  88. package/dist/db/compound-types.js +0 -7
  89. package/dist/db/config-seed.d.ts +2 -1
  90. package/dist/db/config-seed.js +6 -1
  91. package/dist/db/connection.d.ts +3 -1
  92. package/dist/db/connection.js +15 -5
  93. package/dist/db/cross-tenant-reads.d.ts +1 -1
  94. package/dist/db/cross-tenant-reads.js +1 -1
  95. package/dist/db/dialect.d.ts +0 -5
  96. package/dist/db/dialect.js +0 -3
  97. package/dist/db/driver-value-preparation.js +23 -2
  98. package/dist/db/eagerload.d.ts +2 -1
  99. package/dist/db/entity-field-encryption.d.ts +1 -1
  100. package/dist/db/entity-table-meta.d.ts +1 -1
  101. package/dist/db/event-store-executor-context.d.ts +3 -1
  102. package/dist/db/event-store-executor-context.js +4 -3
  103. package/dist/db/event-store-executor-read-filter.d.ts +1 -1
  104. package/dist/db/event-store-executor-read-rows.d.ts +2 -1
  105. package/dist/db/event-store-executor-read-search.d.ts +2 -1
  106. package/dist/db/event-store-executor-read-sort.d.ts +2 -1
  107. package/dist/db/event-store-executor-read.js +2 -2
  108. package/dist/db/event-store-executor-write-atomic.js +8 -7
  109. package/dist/db/event-store-executor-write-steps.d.ts +3 -2
  110. package/dist/db/event-store-executor-write.js +7 -4
  111. package/dist/db/event-store-executor.d.ts +1 -1
  112. package/dist/db/executor-managed-tables.d.ts +7 -1
  113. package/dist/db/executor-managed-tables.js +11 -2
  114. package/dist/db/index.d.ts +29 -28
  115. package/dist/db/index.js +22 -20
  116. package/dist/db/known-table-names.d.ts +6 -0
  117. package/dist/db/known-table-names.js +21 -0
  118. package/dist/db/list-aggregate-labels.d.ts +1 -1
  119. package/dist/db/located-timestamp.d.ts +1 -1
  120. package/dist/db/located-timestamp.js +0 -5
  121. package/dist/db/migrate-generator.d.ts +17 -1
  122. package/dist/db/migrate-generator.js +50 -20
  123. package/dist/db/migrate-primary-key.d.ts +12 -0
  124. package/dist/db/migrate-primary-key.js +45 -0
  125. package/dist/db/migrate-rls-diff.d.ts +20 -0
  126. package/dist/db/migrate-rls-diff.js +61 -0
  127. package/dist/db/migrate-runner.js +4 -0
  128. package/dist/db/money.d.ts +1 -1
  129. package/dist/db/money.js +1 -1
  130. package/dist/db/parent-ref-clause.d.ts +2 -1
  131. package/dist/db/pg-error.d.ts +2 -0
  132. package/dist/db/pg-error.js +11 -0
  133. package/dist/db/queries/ddl.d.ts +3 -0
  134. package/dist/db/queries/ddl.js +34 -1
  135. package/dist/db/queries/event-store.js +4 -2
  136. package/dist/db/queries/event-tenants.d.ts +2 -0
  137. package/dist/db/queries/event-tenants.js +17 -0
  138. package/dist/db/queries/rebuild-rls-guard.d.ts +2 -0
  139. package/dist/db/queries/rebuild-rls-guard.js +29 -0
  140. package/dist/db/queries/rls-boot-catalog.d.ts +16 -0
  141. package/dist/db/queries/rls-boot-catalog.js +39 -0
  142. package/dist/db/queries/rls-catalog.d.ts +6 -0
  143. package/dist/db/queries/rls-catalog.js +82 -0
  144. package/dist/db/queries/rls-scope.d.ts +3 -0
  145. package/dist/db/queries/rls-scope.js +17 -0
  146. package/dist/db/queries/rls-shape.d.ts +10 -0
  147. package/dist/db/queries/rls-shape.js +42 -0
  148. package/dist/db/queries/session-advisory-lock.d.ts +2 -0
  149. package/dist/db/queries/session-advisory-lock.js +23 -0
  150. package/dist/db/queries/shadow-swap.d.ts +1 -2
  151. package/dist/db/queries/shadow-swap.js +9 -25
  152. package/dist/db/queries/test-stack.d.ts +4 -1
  153. package/dist/db/queries/test-stack.js +84 -2
  154. package/dist/db/query.js +11 -7
  155. package/dist/db/reference-data.d.ts +1 -1
  156. package/dist/db/reference-data.js +6 -1
  157. package/dist/db/render-ddl.d.ts +6 -2
  158. package/dist/db/render-ddl.js +7 -7
  159. package/dist/db/render-rls-ddl.d.ts +35 -0
  160. package/dist/db/render-rls-ddl.js +127 -0
  161. package/dist/db/replay-migration-sql.d.ts +3 -1
  162. package/dist/db/replay-migration-sql.js +22 -5
  163. package/dist/db/replay-rls.d.ts +25 -0
  164. package/dist/db/replay-rls.js +156 -0
  165. package/dist/db/row-level-security-boot-check.d.ts +6 -0
  166. package/dist/db/row-level-security-boot-check.js +86 -0
  167. package/dist/db/row-level-security-connection.d.ts +3 -0
  168. package/dist/db/row-level-security-connection.js +213 -0
  169. package/dist/db/row-level-security-scope.d.ts +33 -0
  170. package/dist/db/row-level-security-scope.js +127 -0
  171. package/dist/db/scope-tenant-db-to-tenant.d.ts +3 -0
  172. package/dist/db/scope-tenant-db-to-tenant.js +14 -0
  173. package/dist/db/sql-identifier.d.ts +1 -0
  174. package/dist/db/sql-identifier.js +3 -0
  175. package/dist/db/table-builder.d.ts +2 -1
  176. package/dist/db/table-builder.js +1 -1
  177. package/dist/db/table-info.js +1 -1
  178. package/dist/db/table-push.d.ts +11 -2
  179. package/dist/db/table-push.js +15 -2
  180. package/dist/db/tenant-db-runner.d.ts +3 -1
  181. package/dist/db/tenant-db-runner.js +4 -3
  182. package/dist/db/tenant-db-scoped-rebind.d.ts +10 -0
  183. package/dist/db/tenant-db-scoped-rebind.js +33 -0
  184. package/dist/db/tenant-db-statement-runner.d.ts +13 -0
  185. package/dist/db/tenant-db-statement-runner.js +48 -0
  186. package/dist/db/tenant-db.d.ts +17 -12
  187. package/dist/db/tenant-db.js +49 -120
  188. package/dist/db/tenant-id-filter.d.ts +3 -0
  189. package/dist/db/tenant-id-filter.js +30 -0
  190. package/dist/db/transaction-serialization.d.ts +6 -0
  191. package/dist/db/transaction-serialization.js +60 -0
  192. package/dist/derivatives/delete-stored-file.js +1 -1
  193. package/dist/derivatives/index.d.ts +2 -5
  194. package/dist/derivatives/index.js +2 -3
  195. package/dist/engine/access.d.ts +2 -1
  196. package/dist/engine/access.js +1 -1
  197. package/dist/engine/boot-validator/entity-handler.d.ts +2 -1
  198. package/dist/engine/boot-validator/entity-handler.js +1 -1
  199. package/dist/engine/boot-validator/entity-list-aggregate-options.d.ts +1 -1
  200. package/dist/engine/boot-validator/list-table-aggregate-options.d.ts +1 -1
  201. package/dist/engine/boot-validator/list-table-aggregate-query.d.ts +2 -1
  202. package/dist/engine/boot-validator/nav.d.ts +3 -1
  203. package/dist/engine/boot-validator/nav.js +1 -1
  204. package/dist/engine/boot-validator/ownership.d.ts +2 -1
  205. package/dist/engine/boot-validator/parent-ref.d.ts +2 -1
  206. package/dist/engine/boot-validator/projection-list-screens.d.ts +2 -1
  207. package/dist/engine/boot-validator/query-refs.d.ts +2 -1
  208. package/dist/engine/boot-validator/screens-forms.d.ts +2 -1
  209. package/dist/engine/boot-validator/screens-kind-shared.d.ts +3 -1
  210. package/dist/engine/boot-validator/screens.d.ts +2 -1
  211. package/dist/engine/boot-validator/workspaces.d.ts +3 -1
  212. package/dist/engine/bridge-stub.d.ts +5 -2
  213. package/dist/engine/bridge-stub.js +39 -24
  214. package/dist/engine/config-helpers.d.ts +2 -2
  215. package/dist/engine/config-helpers.js +0 -9
  216. package/dist/engine/constants.d.ts +0 -10
  217. package/dist/engine/constants.js +0 -8
  218. package/dist/engine/create-app.js +1 -1
  219. package/dist/engine/define-feature.d.ts +2 -1
  220. package/dist/engine/define-feature.js +1 -2
  221. package/dist/engine/define-handler.d.ts +1 -1
  222. package/dist/engine/define-step.d.ts +0 -1
  223. package/dist/engine/define-step.js +0 -3
  224. package/dist/engine/embedded-derived.d.ts +1 -1
  225. package/dist/engine/entity-handlers.d.ts +2 -1
  226. package/dist/engine/entity-handlers.js +7 -7
  227. package/dist/engine/entity-list-runtime-options.js +3 -1
  228. package/dist/engine/entity-list-searchability.d.ts +2 -1
  229. package/dist/engine/event-def.d.ts +2 -1
  230. package/dist/engine/event-helpers.d.ts +3 -1
  231. package/dist/engine/event-helpers.js +3 -3
  232. package/dist/engine/extension-names.d.ts +2 -8
  233. package/dist/engine/extension-names.js +2 -2
  234. package/dist/engine/extension-selector-plugins.d.ts +1 -1
  235. package/dist/engine/extensions/storage-provider.d.ts +1 -2
  236. package/dist/engine/extensions/user-data.d.ts +0 -8
  237. package/dist/engine/factories.d.ts +2 -1
  238. package/dist/engine/feature-builder-state.d.ts +8 -1
  239. package/dist/engine/feature-changelog.d.ts +1 -1
  240. package/dist/engine/feature-config-events-jobs.d.ts +4 -1
  241. package/dist/engine/feature-entity-handlers.d.ts +5 -1
  242. package/dist/engine/feature-manifest.js +1 -1
  243. package/dist/engine/feature-ui-extensions.d.ts +7 -1
  244. package/dist/engine/feature-ui-extensions.js +6 -4
  245. package/dist/engine/field-access.d.ts +2 -1
  246. package/dist/engine/handler-field-references.d.ts +0 -4
  247. package/dist/engine/index.d.ts +57 -54
  248. package/dist/engine/index.js +22 -27
  249. package/dist/engine/instruction-fields.d.ts +1 -1
  250. package/dist/engine/personal-data-fields.d.ts +1 -1
  251. package/dist/engine/qualified-name.d.ts +0 -1
  252. package/dist/engine/read-claim.d.ts +2 -1
  253. package/dist/engine/registry-facade.js +0 -3
  254. package/dist/engine/registry-ingest.d.ts +2 -1
  255. package/dist/engine/registry-ingest.js +1 -2
  256. package/dist/engine/registry-state.d.ts +12 -2
  257. package/dist/engine/registry-state.js +2 -3
  258. package/dist/engine/registry-validate.d.ts +3 -1
  259. package/dist/engine/registry-validate.js +7 -7
  260. package/dist/engine/run-in.d.ts +1 -1
  261. package/dist/engine/run-in.js +0 -1
  262. package/dist/engine/schema-builder.d.ts +1 -1
  263. package/dist/engine/schema-builder.js +1 -1
  264. package/dist/engine/screen-filter-ops.d.ts +2 -1
  265. package/dist/engine/screen-filter-ops.js +0 -5
  266. package/dist/engine/soft-delete-cleanup.d.ts +1 -1
  267. package/dist/engine/soft-delete-cleanup.js +4 -4
  268. package/dist/engine/state-machine.js +2 -1
  269. package/dist/engine/steps/_read-source.js +1 -1
  270. package/dist/engine/steps/aggregate-append-event.js +2 -2
  271. package/dist/engine/steps/call-feature.js +2 -2
  272. package/dist/engine/steps/mail-send.js +1 -1
  273. package/dist/engine/steps/retry.js +1 -1
  274. package/dist/engine/steps/wait-for-event.js +1 -1
  275. package/dist/engine/steps/wait.js +1 -1
  276. package/dist/engine/steps/webhook-send.js +1 -1
  277. package/dist/engine/template-variables.d.ts +2 -1
  278. package/dist/engine/transfer-adjacency.d.ts +1 -1
  279. package/dist/engine/types/index.d.ts +8 -31
  280. package/dist/engine/types/index.js +2 -10
  281. package/dist/engine/validation.d.ts +2 -1
  282. package/dist/entrypoint/index.d.ts +7 -35
  283. package/dist/entrypoint/index.js +7 -1
  284. package/dist/entrypoint/internals.d.ts +40 -0
  285. package/dist/entrypoint/internals.js +1 -0
  286. package/dist/entrypoint/row-level-security-mode-check.d.ts +3 -0
  287. package/dist/entrypoint/row-level-security-mode-check.js +19 -0
  288. package/dist/env/dry-run-internals.d.ts +10 -0
  289. package/dist/env/dry-run-internals.js +1 -0
  290. package/dist/env/dry-run.d.ts +1 -10
  291. package/dist/env/dry-run.js +2 -1
  292. package/dist/env/index.d.ts +1 -85
  293. package/dist/env/index.js +6 -50
  294. package/dist/env/internals.d.ts +87 -0
  295. package/dist/env/internals.js +53 -0
  296. package/dist/errors/classes.js +2 -2
  297. package/dist/errors/index.d.ts +5 -14
  298. package/dist/errors/index.js +4 -9
  299. package/dist/errors/member-resolution.js +1 -1
  300. package/dist/errors/reasons.d.ts +0 -1
  301. package/dist/errors/reasons.js +7 -7
  302. package/dist/errors/serialize.d.ts +0 -18
  303. package/dist/errors/serialize.js +0 -27
  304. package/dist/es-ops/index.d.ts +4 -4
  305. package/dist/es-ops/index.js +2 -2
  306. package/dist/es-ops/operations-schema.d.ts +1 -1
  307. package/dist/es-ops/types.d.ts +4 -5
  308. package/dist/event-store/admin-api-internals.d.ts +14 -0
  309. package/dist/event-store/admin-api-internals.js +1 -0
  310. package/dist/event-store/admin-api.d.ts +1 -14
  311. package/dist/event-store/admin-api.js +11 -6
  312. package/dist/event-store/archive.js +4 -2
  313. package/dist/event-store/errors.js +2 -2
  314. package/dist/event-store/event-store.js +41 -34
  315. package/dist/event-store/events-schema.js +4 -1
  316. package/dist/event-store/index.d.ts +11 -13
  317. package/dist/event-store/index.js +7 -9
  318. package/dist/event-store/rebuild-dead-letter.js +4 -2
  319. package/dist/event-store/snapshot.js +4 -3
  320. package/dist/event-store/stream-scope.d.ts +2 -0
  321. package/dist/event-store/stream-scope.js +6 -0
  322. package/dist/event-store/upcaster-dead-letter.js +4 -2
  323. package/dist/event-store/upcaster.d.ts +2 -1
  324. package/dist/files/action-form-upload.d.ts +2 -1
  325. package/dist/files/action-form-upload.js +1 -1
  326. package/dist/files/assert-file-refs-belong-to-tenant.d.ts +2 -1
  327. package/dist/files/assert-file-refs-belong-to-tenant.js +1 -1
  328. package/dist/files/bind-pending-file-refs.d.ts +2 -1
  329. package/dist/files/bind-pending-file-refs.js +2 -1
  330. package/dist/files/bind-referenced-files.write.js +1 -1
  331. package/dist/files/create-file-ref-from-bytes.d.ts +6 -3
  332. package/dist/files/create-file-ref-from-bytes.js +3 -3
  333. package/dist/files/create-file-ref.d.ts +3 -2
  334. package/dist/files/create-file-ref.js +2 -2
  335. package/dist/files/dispose-removed-file-refs.d.ts +2 -1
  336. package/dist/files/dispose-removed-file-refs.js +1 -1
  337. package/dist/files/feature.js +2 -2
  338. package/dist/files/file-handle.js +1 -1
  339. package/dist/files/file-routes.d.ts +1 -1
  340. package/dist/files/file-routes.js +12 -2
  341. package/dist/files/index.d.ts +11 -13
  342. package/dist/files/index.js +5 -7
  343. package/dist/files/load-save-file-refs.d.ts +2 -1
  344. package/dist/files/load-save-file-refs.js +1 -1
  345. package/dist/files/provider-resolver.d.ts +5 -4
  346. package/dist/files/provider-resolver.js +4 -4
  347. package/dist/files/storage-tracking.js +4 -2
  348. package/dist/files/sweep-orphaned-uploads.d.ts +1 -1
  349. package/dist/files/sweep-orphaned-uploads.js +1 -1
  350. package/dist/i18n/index.d.ts +2 -8
  351. package/dist/i18n/index.js +1 -1
  352. package/dist/i18n/internals.d.ts +7 -0
  353. package/dist/i18n/internals.js +1 -0
  354. package/dist/i18n/required-surface-keys.d.ts +4 -1
  355. package/dist/internal/row-level-security.d.ts +3 -0
  356. package/dist/internal/row-level-security.js +3 -0
  357. package/dist/internal/stack-support.d.ts +1 -1
  358. package/dist/internal/stack-support.js +1 -1
  359. package/dist/internal/testing.d.ts +1 -0
  360. package/dist/internal/testing.js +9 -5
  361. package/dist/jobs/index.d.ts +1 -1
  362. package/dist/jobs/job-append-event.d.ts +12 -0
  363. package/dist/jobs/job-append-event.js +30 -0
  364. package/dist/jobs/job-runner-context.d.ts +2 -2
  365. package/dist/jobs/job-runner-context.js +46 -16
  366. package/dist/jobs/job-runner-execution.d.ts +1 -1
  367. package/dist/jobs/job-runner-execution.js +6 -4
  368. package/dist/jobs/job-runner-gates.d.ts +1 -1
  369. package/dist/jobs/job-runner-gates.js +0 -1
  370. package/dist/jobs/job-runner-helpers.d.ts +11 -4
  371. package/dist/jobs/job-runner-helpers.js +10 -1
  372. package/dist/jobs/job-runner-scope.d.ts +5 -2
  373. package/dist/jobs/job-runner-types.d.ts +2 -1
  374. package/dist/jobs/job-runner.js +19 -6
  375. package/dist/jobs/max-per-tenant.d.ts +1 -1
  376. package/dist/logging/index.d.ts +1 -2
  377. package/dist/logging/index.js +1 -1
  378. package/dist/logging/pino-logger.js +1 -1
  379. package/dist/logging/utils.d.ts +1 -0
  380. package/dist/logging/utils.js +6 -0
  381. package/dist/migrations/index.d.ts +3 -3
  382. package/dist/migrations/index.js +3 -3
  383. package/dist/migrations/pending-rebuilds.d.ts +1 -1
  384. package/dist/migrations/pending-rebuilds.js +1 -1
  385. package/dist/migrations/pii-event-backfill.js +4 -1
  386. package/dist/observability/escape-hatch-report.d.ts +2 -1
  387. package/dist/observability/index.d.ts +7 -15
  388. package/dist/observability/index.js +4 -12
  389. package/dist/observability/metric-validator.js +1 -1
  390. package/dist/observability/metrics-handle.d.ts +0 -1
  391. package/dist/observability/metrics-handle.js +2 -15
  392. package/dist/observability/recording-tracer.d.ts +1 -2
  393. package/dist/observability/recording-tracer.js +0 -6
  394. package/dist/observability/sensitive-filter.d.ts +0 -2
  395. package/dist/observability/sensitive-filter.js +0 -29
  396. package/dist/pipeline/active-membership.d.ts +2 -1
  397. package/dist/pipeline/active-membership.js +6 -2
  398. package/dist/pipeline/append-event-core.d.ts +2 -1
  399. package/dist/pipeline/append-event-core.js +2 -2
  400. package/dist/pipeline/attach-outside-transaction.d.ts +3 -0
  401. package/dist/pipeline/attach-outside-transaction.js +13 -0
  402. package/dist/pipeline/auth-claims-resolver.d.ts +2 -1
  403. package/dist/pipeline/cascade-handler.d.ts +2 -1
  404. package/dist/pipeline/cascade-handler.js +3 -2
  405. package/dist/pipeline/config-accessor-factory.d.ts +1 -1
  406. package/dist/pipeline/config-accessor-factory.js +1 -1
  407. package/dist/pipeline/context-services.d.ts +56 -0
  408. package/dist/pipeline/context-services.js +73 -0
  409. package/dist/pipeline/dispatch-batch.d.ts +2 -1
  410. package/dist/pipeline/dispatch-batch.js +31 -18
  411. package/dist/pipeline/dispatch-query.js +5 -4
  412. package/dist/pipeline/dispatch-scope.d.ts +6 -0
  413. package/dist/pipeline/dispatch-scope.js +27 -0
  414. package/dist/pipeline/dispatch-shared.d.ts +13 -9
  415. package/dist/pipeline/dispatch-shared.js +75 -198
  416. package/dist/pipeline/dispatch-stream.js +8 -4
  417. package/dist/pipeline/dispatch-write.d.ts +2 -1
  418. package/dist/pipeline/dispatch-write.js +10 -8
  419. package/dist/pipeline/dispatcher-utils.d.ts +3 -1
  420. package/dist/pipeline/dispatcher-utils.js +8 -2
  421. package/dist/pipeline/dispatcher.d.ts +3 -2
  422. package/dist/pipeline/dispatcher.js +4 -3
  423. package/dist/pipeline/event-consumer-state.d.ts +0 -1
  424. package/dist/pipeline/event-dispatcher-delivery.d.ts +1 -1
  425. package/dist/pipeline/event-dispatcher-delivery.js +4 -2
  426. package/dist/pipeline/event-dispatcher.d.ts +2 -2
  427. package/dist/pipeline/event-dispatcher.js +7 -3
  428. package/dist/pipeline/event-retention.js +59 -56
  429. package/dist/pipeline/handler-access-error.js +2 -1
  430. package/dist/pipeline/handler-context-auth.d.ts +5 -6
  431. package/dist/pipeline/handler-context-auth.js +7 -4
  432. package/dist/pipeline/handler-context-config.d.ts +2 -5
  433. package/dist/pipeline/handler-context-config.js +2 -2
  434. package/dist/pipeline/handler-context-db.d.ts +32 -7
  435. package/dist/pipeline/handler-context-db.js +26 -17
  436. package/dist/pipeline/handler-context-dispatch.d.ts +13 -7
  437. package/dist/pipeline/handler-context-dispatch.js +9 -8
  438. package/dist/pipeline/handler-context-events.d.ts +22 -36
  439. package/dist/pipeline/handler-context-events.js +36 -31
  440. package/dist/pipeline/handler-context-member-resolution.d.ts +2 -0
  441. package/dist/pipeline/handler-context-member-resolution.js +110 -0
  442. package/dist/pipeline/handler-context-notify.d.ts +3 -2
  443. package/dist/pipeline/handler-context-notify.js +1 -1
  444. package/dist/pipeline/handler-context-observability.d.ts +2 -4
  445. package/dist/pipeline/handler-context-observability.js +7 -5
  446. package/dist/pipeline/handler-context-phase-denials.d.ts +11 -0
  447. package/dist/pipeline/handler-context-phase-denials.js +98 -0
  448. package/dist/pipeline/handler-context-scope.d.ts +7 -10
  449. package/dist/pipeline/handler-context-scope.js +18 -20
  450. package/dist/pipeline/index.d.ts +9 -21
  451. package/dist/pipeline/index.js +5 -7
  452. package/dist/pipeline/irreversible-operation-gate.d.ts +1 -1
  453. package/dist/pipeline/irreversible-operation-gate.js +2 -2
  454. package/dist/pipeline/lifecycle-pipeline.d.ts +8 -7
  455. package/dist/pipeline/lifecycle-pipeline.js +9 -15
  456. package/dist/pipeline/member-read-only-transaction.js +11 -3
  457. package/dist/pipeline/member-reader.d.ts +1 -1
  458. package/dist/pipeline/member-reader.js +2 -2
  459. package/dist/pipeline/msp-rebuild.js +5 -3
  460. package/dist/pipeline/multi-stream-apply-context.js +3 -2
  461. package/dist/pipeline/notify-scope.d.ts +2 -1
  462. package/dist/pipeline/pre-handler-gates.d.ts +2 -1
  463. package/dist/pipeline/pre-transaction-reservations.d.ts +3 -3
  464. package/dist/pipeline/pre-transaction-reservations.js +9 -7
  465. package/dist/pipeline/projection-rebuild.js +12 -5
  466. package/dist/pipeline/projection-state.d.ts +0 -6
  467. package/dist/pipeline/projection-state.js +0 -5
  468. package/dist/pipeline/projections-runner.d.ts +2 -1
  469. package/dist/pipeline/projections-runner.js +10 -6
  470. package/dist/pipeline/system-hooks.d.ts +3 -1
  471. package/dist/pipeline/system-hooks.js +6 -4
  472. package/dist/pipeline/system-identity-switch.d.ts +4 -2
  473. package/dist/pipeline/system-identity-switch.js +51 -36
  474. package/dist/pipeline/typed-append-event.d.ts +2 -0
  475. package/dist/pipeline/typed-append-event.js +4 -0
  476. package/dist/pipeline/write-origin.js +2 -2
  477. package/dist/pipeline/write-result-masking.d.ts +1 -1
  478. package/dist/random/index.d.ts +1 -2
  479. package/dist/random/index.js +1 -2
  480. package/dist/rate-limit/bucket.d.ts +2 -1
  481. package/dist/rate-limit/middleware.js +2 -1
  482. package/dist/redis/index.d.ts +3 -4
  483. package/dist/redis/index.js +2 -2
  484. package/dist/schema-cli/apply-command.js +5 -2
  485. package/dist/schema-cli/baseline-command.js +7 -2
  486. package/dist/schema-cli/generate-command.js +7 -9
  487. package/dist/schema-cli/shared.d.ts +12 -2
  488. package/dist/schema-cli/shared.js +24 -2
  489. package/dist/schema-cli/status-command.js +8 -2
  490. package/dist/schema-cli/validate-command.js +48 -4
  491. package/dist/schema-cli.d.ts +0 -1
  492. package/dist/search/configure-tenant-index.d.ts +1 -3
  493. package/dist/search/configure-tenant-index.js +0 -4
  494. package/dist/search/index.d.ts +1 -4
  495. package/dist/search/index.js +0 -2
  496. package/dist/search/meilisearch-adapter-internals.d.ts +8 -0
  497. package/dist/search/meilisearch-adapter-internals.js +9 -0
  498. package/dist/search/meilisearch-adapter.d.ts +1 -8
  499. package/dist/search/meilisearch-adapter.js +6 -7
  500. package/dist/search/meilisearch-peer.d.ts +2 -0
  501. package/dist/search/meilisearch-peer.js +5 -0
  502. package/dist/search/reindex-entity.js +93 -87
  503. package/dist/secrets/index.d.ts +3 -4
  504. package/dist/secrets/index.js +2 -3
  505. package/dist/seeding/index.d.ts +2 -2
  506. package/dist/seeding/index.js +1 -2
  507. package/dist/time/index.d.ts +2 -2
  508. package/dist/time/index.js +1 -1
  509. package/dist/time/tz-context.d.ts +0 -5
  510. package/dist/time/tz-context.js +0 -9
  511. package/dist/ui-types/index.d.ts +8 -11
  512. package/dist/ui-types/index.js +3 -3
  513. package/dist/upgrade-changelog.d.ts +3 -2
  514. package/dist/upgrade-changelog.js +12 -8
  515. package/dist/upgrade-cli-internals.d.ts +8 -0
  516. package/dist/upgrade-cli-internals.js +63 -0
  517. package/dist/upgrade-cli.d.ts +2 -9
  518. package/dist/upgrade-cli.js +28 -70
  519. package/dist/utils/import-optional-peer.d.ts +6 -0
  520. package/dist/utils/import-optional-peer.js +19 -0
  521. package/dist/utils/index.d.ts +1 -4
  522. package/dist/utils/index.js +1 -4
  523. package/package.json +23 -19
  524. package/src/changes.json +236 -0
  525. package/dist/crypto/request-kms-cache.d.ts +0 -8
  526. package/dist/crypto/request-kms-cache.js +0 -21
  527. package/dist/engine/codemod/index.d.ts +0 -2
  528. package/dist/engine/codemod/index.js +0 -1
  529. package/dist/engine/codemod/pipeline-codemod.d.ts +0 -50
  530. package/dist/engine/codemod/pipeline-codemod.js +0 -536
  531. package/dist/engine/feature-ast/entity-field-types.d.ts +0 -13
  532. package/dist/engine/feature-ast/entity-field-types.js +0 -35
  533. package/dist/engine/feature-ast/extractors/ai-steps.d.ts +0 -6
  534. package/dist/engine/feature-ast/extractors/ai-steps.js +0 -254
  535. package/dist/engine/feature-ast/extractors/events.d.ts +0 -5
  536. package/dist/engine/feature-ast/extractors/events.js +0 -275
  537. package/dist/engine/feature-ast/extractors/handlers.d.ts +0 -24
  538. package/dist/engine/feature-ast/extractors/handlers.js +0 -358
  539. package/dist/engine/feature-ast/extractors/hooks.d.ts +0 -24
  540. package/dist/engine/feature-ast/extractors/hooks.js +0 -248
  541. package/dist/engine/feature-ast/extractors/index.d.ts +0 -14
  542. package/dist/engine/feature-ast/extractors/index.js +0 -13
  543. package/dist/engine/feature-ast/extractors/jobs-routes.d.ts +0 -7
  544. package/dist/engine/feature-ast/extractors/jobs-routes.js +0 -145
  545. package/dist/engine/feature-ast/extractors/projections-screens.d.ts +0 -10
  546. package/dist/engine/feature-ast/extractors/projections-screens.js +0 -195
  547. package/dist/engine/feature-ast/extractors/resolve-import.d.ts +0 -21
  548. package/dist/engine/feature-ast/extractors/resolve-import.js +0 -180
  549. package/dist/engine/feature-ast/extractors/round1.d.ts +0 -11
  550. package/dist/engine/feature-ast/extractors/round1.js +0 -87
  551. package/dist/engine/feature-ast/extractors/round2.d.ts +0 -7
  552. package/dist/engine/feature-ast/extractors/round2.js +0 -191
  553. package/dist/engine/feature-ast/extractors/round3.d.ts +0 -23
  554. package/dist/engine/feature-ast/extractors/round3.js +0 -292
  555. package/dist/engine/feature-ast/extractors/round5.d.ts +0 -9
  556. package/dist/engine/feature-ast/extractors/round5.js +0 -68
  557. package/dist/engine/feature-ast/extractors/round6.d.ts +0 -4
  558. package/dist/engine/feature-ast/extractors/round6.js +0 -17
  559. package/dist/engine/feature-ast/extractors/shared.d.ts +0 -94
  560. package/dist/engine/feature-ast/extractors/shared.js +0 -343
  561. package/dist/engine/feature-ast/index.d.ts +0 -16
  562. package/dist/engine/feature-ast/index.js +0 -10
  563. package/dist/engine/feature-ast/parse.d.ts +0 -31
  564. package/dist/engine/feature-ast/parse.js +0 -485
  565. package/dist/engine/feature-ast/patch.d.ts +0 -212
  566. package/dist/engine/feature-ast/patch.js +0 -611
  567. package/dist/engine/feature-ast/patcher.d.ts +0 -217
  568. package/dist/engine/feature-ast/patcher.js +0 -281
  569. package/dist/engine/feature-ast/pattern-change-schema.d.ts +0 -1238
  570. package/dist/engine/feature-ast/pattern-change-schema.js +0 -1072
  571. package/dist/engine/feature-ast/pattern-id-matchers.d.ts +0 -7
  572. package/dist/engine/feature-ast/pattern-id-matchers.js +0 -211
  573. package/dist/engine/feature-ast/pattern-id-schema.d.ts +0 -251
  574. package/dist/engine/feature-ast/pattern-id-schema.js +0 -166
  575. package/dist/engine/feature-ast/patterns.d.ts +0 -322
  576. package/dist/engine/feature-ast/patterns.js +0 -107
  577. package/dist/engine/feature-ast/render.d.ts +0 -47
  578. package/dist/engine/feature-ast/render.js +0 -666
  579. package/dist/engine/feature-ast/source-location.d.ts +0 -17
  580. package/dist/engine/feature-ast/source-location.js +0 -27
  581. package/dist/engine/pattern-library/index.d.ts +0 -2
  582. package/dist/engine/pattern-library/index.js +0 -3
  583. package/dist/engine/pattern-library/library.d.ts +0 -14
  584. package/dist/engine/pattern-library/library.js +0 -94
  585. package/dist/engine/pattern-library/mixed-schemas.d.ts +0 -16
  586. package/dist/engine/pattern-library/mixed-schemas.js +0 -559
  587. package/dist/engine/pattern-library/opaque-schemas.d.ts +0 -7
  588. package/dist/engine/pattern-library/opaque-schemas.js +0 -115
  589. package/dist/engine/pattern-library/shared-fields.d.ts +0 -122
  590. package/dist/engine/pattern-library/shared-fields.js +0 -88
  591. package/dist/engine/pattern-library/static-schemas.d.ts +0 -21
  592. package/dist/engine/pattern-library/static-schemas.js +0 -487
  593. package/dist/engine/pattern-library/types.d.ts +0 -158
  594. package/dist/engine/pattern-library/types.js +0 -36
  595. package/dist/engine/resolve-config-or-param.d.ts +0 -18
  596. package/dist/engine/resolve-config-or-param.js +0 -76
  597. package/src/scripts/codemod/README.md +0 -187
  598. package/src/scripts/codemod/codemod-support.ts +0 -334
  599. package/src/scripts/codemod/collect-source-files.ts +0 -48
  600. package/src/scripts/codemod/crypto-shredding-testing-move.ts +0 -119
  601. package/src/scripts/codemod/db-factory.ts +0 -810
  602. package/src/scripts/codemod/feature-factory.ts +0 -429
  603. package/src/scripts/codemod/feature-layout.ts +0 -424
  604. package/src/scripts/codemod/import-extensions.ts +0 -118
  605. package/src/scripts/codemod/migrate-cross-tenant.ts +0 -328
  606. package/src/scripts/codemod/migrate-db-raw.ts +0 -401
  607. package/src/scripts/codemod/migrate-open-to-all.ts +0 -235
  608. package/src/scripts/codemod/object-form.ts +0 -746
  609. package/src/scripts/codemod/package-merge.ts +0 -299
  610. package/src/scripts/codemod/pii-personal-migration.ts +0 -816
  611. package/src/scripts/codemod/remove-engine-payload-casts.ts +0 -318
  612. package/src/scripts/codemod/s3-imports.ts +0 -236
  613. package/src/scripts/codemod/tenant-db-options.ts +0 -454
  614. package/src/scripts/codemod/testing-injection.ts +0 -215
  615. package/src/scripts/codemod/testing-move-targets.ts +0 -161
  616. package/src/scripts/codemod/testing-move.ts +0 -542
  617. 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
- }