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