pipework 0.252.0 → 0.253.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 (695) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/infra/support/handle.d.ts +8 -1
  3. package/dist/infra/support/handle.d.ts.map +1 -1
  4. package/dist/infra/support/handle.js +9 -2
  5. package/dist/infra/support/handle.js.map +1 -1
  6. package/dist/infra/support/namespace.d.ts.map +1 -1
  7. package/package.json +4 -3
  8. package/src/async/jobs/abortable-delay.ts +18 -0
  9. package/src/async/jobs/claims.ts +52 -0
  10. package/src/async/jobs/cron.ts +179 -0
  11. package/src/async/jobs/errors.ts +56 -0
  12. package/src/async/jobs/exclusion.ts +117 -0
  13. package/src/async/jobs/execute.ts +219 -0
  14. package/src/async/jobs/index.ts +10 -0
  15. package/src/async/jobs/listener.ts +135 -0
  16. package/src/async/jobs/namespace.ts +20 -0
  17. package/src/async/jobs/queue-door.ts +44 -0
  18. package/src/async/jobs/queue.ts +1012 -0
  19. package/src/async/jobs/run-script.ts +67 -0
  20. package/src/async/jobs/scheduler.ts +218 -0
  21. package/src/async/jobs/schedules-table.ts +37 -0
  22. package/src/async/jobs/serialize-error.ts +48 -0
  23. package/src/async/jobs/table.ts +191 -0
  24. package/src/async/pipeline/define.ts +53 -0
  25. package/src/async/pipeline/errors.ts +35 -0
  26. package/src/async/pipeline/execute.ts +53 -0
  27. package/src/async/pipeline/index.ts +13 -0
  28. package/src/async/pipeline/namespace.ts +12 -0
  29. package/src/async/pipeline/resume.ts +67 -0
  30. package/src/async/pipeline/run-steps.ts +98 -0
  31. package/src/async/pipeline/types.ts +57 -0
  32. package/src/async/state-machine/define.ts +64 -0
  33. package/src/async/state-machine/errors.ts +29 -0
  34. package/src/async/state-machine/index.ts +3 -0
  35. package/src/async/state-machine/namespace.ts +12 -0
  36. package/src/async/state-machine/transition.ts +90 -0
  37. package/src/async/state-machine/types.ts +37 -0
  38. package/src/async/steps/errors.ts +31 -0
  39. package/src/async/steps/graph.ts +1214 -0
  40. package/src/async/steps/hash.ts +40 -0
  41. package/src/async/steps/index.ts +7 -0
  42. package/src/async/steps/namespace.ts +7 -0
  43. package/src/async/steps/table.ts +97 -0
  44. package/src/async/steps/types.ts +318 -0
  45. package/src/audit/chain/index.ts +9 -0
  46. package/src/audit/chain/install.ts +113 -0
  47. package/src/audit/chain/retire.ts +52 -0
  48. package/src/audit/chain/verify.ts +257 -0
  49. package/src/audit/query/cursor.ts +37 -0
  50. package/src/audit/query/index.ts +9 -0
  51. package/src/audit/query/query.ts +223 -0
  52. package/src/audit/schema/audit-record-fields.ts +68 -0
  53. package/src/audit/schema/audit-record.ts +23 -0
  54. package/src/auth/auth/audit.ts +31 -0
  55. package/src/auth/auth/chain.ts +84 -0
  56. package/src/auth/auth/cookie.ts +136 -0
  57. package/src/auth/auth/email-links.ts +311 -0
  58. package/src/auth/auth/guard.ts +128 -0
  59. package/src/auth/auth/index.ts +18 -0
  60. package/src/auth/auth/multi-org.ts +337 -0
  61. package/src/auth/auth/namespace.ts +34 -0
  62. package/src/auth/auth/parse-expiry.ts +13 -0
  63. package/src/auth/auth/passwords.ts +110 -0
  64. package/src/auth/auth/schema.ts +110 -0
  65. package/src/auth/auth/sessions.ts +565 -0
  66. package/src/auth/auth/sign-in.ts +156 -0
  67. package/src/auth/auth/signing-keys.ts +69 -0
  68. package/src/auth/auth/types.ts +26 -0
  69. package/src/auth/auth/uuid.ts +10 -0
  70. package/src/auth/rbac/cache.ts +55 -0
  71. package/src/auth/rbac/check.ts +30 -0
  72. package/src/auth/rbac/create.ts +35 -0
  73. package/src/auth/rbac/index.ts +5 -0
  74. package/src/auth/rbac/middleware.ts +20 -0
  75. package/src/auth/rbac/namespace.ts +15 -0
  76. package/src/auth/rbac/resolve.ts +31 -0
  77. package/src/auth/rbac/schema.sql +31 -0
  78. package/src/auth/rbac/seed.ts +67 -0
  79. package/src/auth/rbac/tables.ts +32 -0
  80. package/src/auth/rbac/types.ts +65 -0
  81. package/src/auth/tenant/extract.ts +33 -0
  82. package/src/auth/tenant/in-tenant.ts +49 -0
  83. package/src/auth/tenant/index.ts +7 -0
  84. package/src/auth/tenant/namespace.ts +23 -0
  85. package/src/auth/tenant/propagate.ts +20 -0
  86. package/src/auth/tenant/rls.ts +120 -0
  87. package/src/auth/tenant/scope.ts +33 -0
  88. package/src/auth/tenant/scoped-db.ts +581 -0
  89. package/src/auth/tenant/types.ts +14 -0
  90. package/src/auth/tenant/validate.ts +27 -0
  91. package/src/cli/commands/add.ts +158 -0
  92. package/src/cli/commands/alerts.ts +98 -0
  93. package/src/cli/commands/check.ts +1418 -0
  94. package/src/cli/commands/codemod.ts +78 -0
  95. package/src/cli/commands/db.ts +356 -0
  96. package/src/cli/commands/dev.ts +101 -0
  97. package/src/cli/commands/generate.ts +75 -0
  98. package/src/cli/commands/init.ts +36 -0
  99. package/src/cli/commands/install.ts +28 -0
  100. package/src/cli/commands/lint.ts +62 -0
  101. package/src/cli/commands/migrate.ts +132 -0
  102. package/src/cli/commands/openapi.ts +63 -0
  103. package/src/cli/commands/remove.ts +72 -0
  104. package/src/cli/commands/run.ts +50 -0
  105. package/src/cli/commands/scope.ts +54 -0
  106. package/src/cli/commands/serve.ts +68 -0
  107. package/src/cli/commands/shard.ts +31 -0
  108. package/src/cli/commands/shared/config-pipework-version.ts +28 -0
  109. package/src/cli/commands/shared/find-config.ts +22 -0
  110. package/src/cli/commands/shared/load-config.ts +35 -0
  111. package/src/cli/commands/shared/pnpm-install.ts +95 -0
  112. package/src/cli/commands/shared/report-removed.ts +8 -0
  113. package/src/cli/commands/sync.ts +32 -0
  114. package/src/cli/commands/test.ts +307 -0
  115. package/src/cli/commands/upgrade.ts +48 -0
  116. package/src/cli/dev-bootstrap.ts +24 -0
  117. package/src/cli/errors.ts +10 -0
  118. package/src/cli/index.ts +303 -0
  119. package/src/cli/output.ts +17 -0
  120. package/src/cli/port.ts +15 -0
  121. package/src/cli/surface-kinds.ts +20 -0
  122. package/src/client/index.ts +4 -0
  123. package/src/client/poll.ts +130 -0
  124. package/src/client/report-fault.ts +119 -0
  125. package/src/core/config/app-pool.ts +19 -0
  126. package/src/core/config/aws-env.ts +29 -0
  127. package/src/core/config/base-dir.ts +24 -0
  128. package/src/core/config/discover.ts +64 -0
  129. package/src/core/config/env-resolve.ts +87 -0
  130. package/src/core/config/env-types.ts +116 -0
  131. package/src/core/config/env.ts +55 -0
  132. package/src/core/config/errors.ts +9 -0
  133. package/src/core/config/import-config.ts +40 -0
  134. package/src/core/config/index.ts +8 -0
  135. package/src/core/config/load.ts +417 -0
  136. package/src/core/config/namespace.ts +14 -0
  137. package/src/core/config/resolve.ts +195 -0
  138. package/src/core/config/schema.ts +488 -0
  139. package/src/core/config/statement-observer.ts +48 -0
  140. package/src/core/config/ts-inline-hooks.ts +75 -0
  141. package/src/core/config/ts-register.ts +4 -0
  142. package/src/core/config/ts-resolve-hooks.ts +101 -0
  143. package/src/core/errors/base.ts +49 -0
  144. package/src/core/errors/http.ts +146 -0
  145. package/src/core/errors/index.ts +2 -0
  146. package/src/core/errors/namespace.ts +31 -0
  147. package/src/core/lifecycle/drain.ts +33 -0
  148. package/src/core/lifecycle/health.ts +72 -0
  149. package/src/core/lifecycle/index.ts +4 -0
  150. package/src/core/lifecycle/namespace.ts +7 -0
  151. package/src/core/lifecycle/startup.ts +102 -0
  152. package/src/core/lifecycle/types.ts +36 -0
  153. package/src/core/logging/context.ts +60 -0
  154. package/src/core/logging/error-chain.ts +68 -0
  155. package/src/core/logging/index.ts +5 -0
  156. package/src/core/logging/logger.ts +65 -0
  157. package/src/core/logging/namespace.ts +16 -0
  158. package/src/core/logging/proxy.ts +22 -0
  159. package/src/core/logging/redact-match.ts +24 -0
  160. package/src/core/logging/types.ts +47 -0
  161. package/src/core/pipework.ts +566 -0
  162. package/src/core/runtime/broker.ts +69 -0
  163. package/src/core/surface/http.ts +133 -0
  164. package/src/core/surface/index.ts +11 -0
  165. package/src/core/surface/job-timeout.ts +40 -0
  166. package/src/core/surface/namespace.ts +13 -0
  167. package/src/core/surface/script.ts +33 -0
  168. package/src/core/surface/start.ts +142 -0
  169. package/src/core/surface/types.ts +225 -0
  170. package/src/core/surface/validate.ts +88 -0
  171. package/src/core/surface/worker.ts +528 -0
  172. package/src/core/validation/connectivity.ts +49 -0
  173. package/src/core/validation/domain.ts +99 -0
  174. package/src/core/validation/index.ts +5 -0
  175. package/src/core/validation/queue-tables.ts +312 -0
  176. package/src/core/validation/rls-role.ts +138 -0
  177. package/src/core/validation/startup.ts +51 -0
  178. package/src/core/validation/surfaces.ts +65 -0
  179. package/src/core/validation/types.ts +25 -0
  180. package/src/data/db/advisory-lock.ts +55 -0
  181. package/src/data/db/aggregates.ts +172 -0
  182. package/src/data/db/array-elements.ts +111 -0
  183. package/src/data/db/bulk-set.ts +53 -0
  184. package/src/data/db/col/index.ts +14 -0
  185. package/src/data/db/composed.ts +53 -0
  186. package/src/data/db/db.ts +276 -0
  187. package/src/data/db/excluded.ts +16 -0
  188. package/src/data/db/expressions.ts +473 -0
  189. package/src/data/db/filter.ts +90 -0
  190. package/src/data/db/function-source.ts +114 -0
  191. package/src/data/db/identifiers.ts +16 -0
  192. package/src/data/db/idx/index.ts +9 -0
  193. package/src/data/db/in-list.ts +49 -0
  194. package/src/data/db/index.ts +9 -0
  195. package/src/data/db/insert-split.ts +137 -0
  196. package/src/data/db/instrumentation.ts +82 -0
  197. package/src/data/db/maintenance.ts +28 -0
  198. package/src/data/db/namespace.ts +107 -0
  199. package/src/data/db/owner-labels.ts +9 -0
  200. package/src/data/db/pool.ts +187 -0
  201. package/src/data/db/query-label.ts +13 -0
  202. package/src/data/db/query-watch.ts +116 -0
  203. package/src/data/db/raw-client-warning.ts +37 -0
  204. package/src/data/db/readonly.ts +23 -0
  205. package/src/data/db/reservation.ts +151 -0
  206. package/src/data/db/schema-features.ts +14 -0
  207. package/src/data/db/serializable.ts +83 -0
  208. package/src/data/db/sql.ts +1 -0
  209. package/src/data/db/timeouts.ts +76 -0
  210. package/src/data/db/types.ts +18 -0
  211. package/src/data/db/unbound.ts +33 -0
  212. package/src/data/db/values.ts +29 -0
  213. package/src/data/domain/brand.ts +15 -0
  214. package/src/data/domain/build-factory.ts +193 -0
  215. package/src/data/domain/build-schema.ts +161 -0
  216. package/src/data/domain/build-table.ts +355 -0
  217. package/src/data/domain/define.ts +239 -0
  218. package/src/data/domain/external-registry.ts +34 -0
  219. package/src/data/domain/external.ts +77 -0
  220. package/src/data/domain/field.ts +279 -0
  221. package/src/data/domain/index.ts +13 -0
  222. package/src/data/domain/naming.ts +6 -0
  223. package/src/data/domain/projections.ts +57 -0
  224. package/src/data/domain/trace-safe-projection.ts +31 -0
  225. package/src/data/domain/traits.ts +108 -0
  226. package/src/data/domain/types.ts +289 -0
  227. package/src/data/jsonb/composed.ts +18 -0
  228. package/src/data/jsonb/index.ts +1 -0
  229. package/src/data/jsonb/namespace.ts +30 -0
  230. package/src/data/jsonb/query.ts +86 -0
  231. package/src/data/migrate/append-only-generate.ts +47 -0
  232. package/src/data/migrate/applied.ts +47 -0
  233. package/src/data/migrate/apply.ts +309 -0
  234. package/src/data/migrate/check.ts +119 -0
  235. package/src/data/migrate/diff.ts +357 -0
  236. package/src/data/migrate/door-generate.ts +130 -0
  237. package/src/data/migrate/framework-rls.ts +58 -0
  238. package/src/data/migrate/generate.ts +201 -0
  239. package/src/data/migrate/history.ts +215 -0
  240. package/src/data/migrate/index.ts +9 -0
  241. package/src/data/migrate/internal-definitions.ts +175 -0
  242. package/src/data/migrate/post-process.ts +73 -0
  243. package/src/data/migrate/pragma.ts +73 -0
  244. package/src/data/migrate/provision-framework.ts +147 -0
  245. package/src/data/migrate/rls-generate.ts +61 -0
  246. package/src/data/migrate/run.ts +124 -0
  247. package/src/data/migrate/safety.ts +167 -0
  248. package/src/data/migrate/snapshot.ts +368 -0
  249. package/src/data/migrate/sql-emit.ts +392 -0
  250. package/src/data/migrate/statements.ts +312 -0
  251. package/src/data/query/alias.ts +126 -0
  252. package/src/data/query/batch.ts +8 -0
  253. package/src/data/query/cache/core/cache.ts +78 -0
  254. package/src/data/query/cache/core/index.ts +1 -0
  255. package/src/data/query/cache/core/types.ts +29 -0
  256. package/src/data/query/cache/readme.md +230 -0
  257. package/src/data/query/casing.ts +76 -0
  258. package/src/data/query/collation.ts +11 -0
  259. package/src/data/query/column-builder.ts +370 -0
  260. package/src/data/query/column.ts +150 -0
  261. package/src/data/query/entity.ts +42 -0
  262. package/src/data/query/errors.ts +33 -0
  263. package/src/data/query/index.ts +14 -0
  264. package/src/data/query/logger.ts +47 -0
  265. package/src/data/query/operations.ts +45 -0
  266. package/src/data/query/pg-core/alias.ts +12 -0
  267. package/src/data/query/pg-core/checks.ts +32 -0
  268. package/src/data/query/pg-core/columns/all.ts +71 -0
  269. package/src/data/query/pg-core/columns/bigint.ts +110 -0
  270. package/src/data/query/pg-core/columns/bigserial.ts +128 -0
  271. package/src/data/query/pg-core/columns/boolean.ts +43 -0
  272. package/src/data/query/pg-core/columns/char.ts +85 -0
  273. package/src/data/query/pg-core/columns/cidr.ts +43 -0
  274. package/src/data/query/pg-core/columns/common.ts +366 -0
  275. package/src/data/query/pg-core/columns/custom.ts +232 -0
  276. package/src/data/query/pg-core/columns/date.common.ts +15 -0
  277. package/src/data/query/pg-core/columns/date.ts +112 -0
  278. package/src/data/query/pg-core/columns/double-precision.ts +55 -0
  279. package/src/data/query/pg-core/columns/enum.ts +201 -0
  280. package/src/data/query/pg-core/columns/index.ts +35 -0
  281. package/src/data/query/pg-core/columns/inet.ts +43 -0
  282. package/src/data/query/pg-core/columns/int.common.ts +57 -0
  283. package/src/data/query/pg-core/columns/integer.ts +53 -0
  284. package/src/data/query/pg-core/columns/interval.ts +83 -0
  285. package/src/data/query/pg-core/columns/json.ts +58 -0
  286. package/src/data/query/pg-core/columns/jsonb.ts +56 -0
  287. package/src/data/query/pg-core/columns/line.ts +117 -0
  288. package/src/data/query/pg-core/columns/macaddr.ts +43 -0
  289. package/src/data/query/pg-core/columns/macaddr8.ts +43 -0
  290. package/src/data/query/pg-core/columns/numeric.ts +227 -0
  291. package/src/data/query/pg-core/columns/point.ts +127 -0
  292. package/src/data/query/pg-core/columns/postgis_extension/geometry.ts +119 -0
  293. package/src/data/query/pg-core/columns/postgis_extension/utils.ts +47 -0
  294. package/src/data/query/pg-core/columns/real.ts +58 -0
  295. package/src/data/query/pg-core/columns/serial.ts +55 -0
  296. package/src/data/query/pg-core/columns/smallint.ts +53 -0
  297. package/src/data/query/pg-core/columns/smallserial.ts +60 -0
  298. package/src/data/query/pg-core/columns/text.ts +67 -0
  299. package/src/data/query/pg-core/columns/time.ts +72 -0
  300. package/src/data/query/pg-core/columns/timestamp.ts +163 -0
  301. package/src/data/query/pg-core/columns/uuid.ts +51 -0
  302. package/src/data/query/pg-core/columns/varchar.ts +89 -0
  303. package/src/data/query/pg-core/columns/vector_extension/bit.ts +68 -0
  304. package/src/data/query/pg-core/columns/vector_extension/halfvec.ts +80 -0
  305. package/src/data/query/pg-core/columns/vector_extension/sparsevec.ts +67 -0
  306. package/src/data/query/pg-core/columns/vector_extension/vector.ts +80 -0
  307. package/src/data/query/pg-core/db.ts +674 -0
  308. package/src/data/query/pg-core/dialect.ts +1404 -0
  309. package/src/data/query/pg-core/expressions.ts +25 -0
  310. package/src/data/query/pg-core/foreign-keys.ts +130 -0
  311. package/src/data/query/pg-core/index.ts +21 -0
  312. package/src/data/query/pg-core/indexes.ts +276 -0
  313. package/src/data/query/pg-core/policies.ts +56 -0
  314. package/src/data/query/pg-core/primary-keys.ts +62 -0
  315. package/src/data/query/pg-core/query-builders/count.ts +86 -0
  316. package/src/data/query/pg-core/query-builders/delete.ts +293 -0
  317. package/src/data/query/pg-core/query-builders/index.ts +7 -0
  318. package/src/data/query/pg-core/query-builders/insert.ts +452 -0
  319. package/src/data/query/pg-core/query-builders/query-builder.ts +123 -0
  320. package/src/data/query/pg-core/query-builders/query.ts +157 -0
  321. package/src/data/query/pg-core/query-builders/raw.ts +49 -0
  322. package/src/data/query/pg-core/query-builders/refresh-materialized-view.ts +108 -0
  323. package/src/data/query/pg-core/query-builders/select.ts +1346 -0
  324. package/src/data/query/pg-core/query-builders/select.types.ts +437 -0
  325. package/src/data/query/pg-core/query-builders/update.ts +626 -0
  326. package/src/data/query/pg-core/roles.ts +41 -0
  327. package/src/data/query/pg-core/schema.ts +72 -0
  328. package/src/data/query/pg-core/sequence.ts +41 -0
  329. package/src/data/query/pg-core/session.ts +292 -0
  330. package/src/data/query/pg-core/subquery.ts +46 -0
  331. package/src/data/query/pg-core/table.ts +252 -0
  332. package/src/data/query/pg-core/unique-constraint.ts +73 -0
  333. package/src/data/query/pg-core/utils/array.ts +95 -0
  334. package/src/data/query/pg-core/utils/index.ts +1 -0
  335. package/src/data/query/pg-core/utils.ts +104 -0
  336. package/src/data/query/pg-core/view-base.ts +14 -0
  337. package/src/data/query/pg-core/view-common.ts +1 -0
  338. package/src/data/query/pg-core/view.ts +435 -0
  339. package/src/data/query/pg-core/with-builder.ts +41 -0
  340. package/src/data/query/postgres-js/README.md +46 -0
  341. package/src/data/query/postgres-js/array-parser.ts +45 -0
  342. package/src/data/query/postgres-js/driver-error-boundary.ts +149 -0
  343. package/src/data/query/postgres-js/driver.ts +163 -0
  344. package/src/data/query/postgres-js/index.ts +2 -0
  345. package/src/data/query/postgres-js/session.ts +234 -0
  346. package/src/data/query/primary-key.ts +11 -0
  347. package/src/data/query/query-builders/query-builder.ts +19 -0
  348. package/src/data/query/query-builders/select.types.ts +175 -0
  349. package/src/data/query/query-promise.ts +35 -0
  350. package/src/data/query/relations.ts +725 -0
  351. package/src/data/query/runnable-query.ts +12 -0
  352. package/src/data/query/selection-proxy.ts +121 -0
  353. package/src/data/query/session.ts +8 -0
  354. package/src/data/query/sql/expressions/conditions.ts +741 -0
  355. package/src/data/query/sql/expressions/index.ts +2 -0
  356. package/src/data/query/sql/expressions/select.ts +45 -0
  357. package/src/data/query/sql/functions/aggregate.ts +129 -0
  358. package/src/data/query/sql/functions/index.ts +2 -0
  359. package/src/data/query/sql/functions/vector.ts +178 -0
  360. package/src/data/query/sql/index.ts +3 -0
  361. package/src/data/query/sql/sql.ts +794 -0
  362. package/src/data/query/subquery.ts +53 -0
  363. package/src/data/query/table.ts +208 -0
  364. package/src/data/query/table.utils.ts +2 -0
  365. package/src/data/query/tracing-utils.ts +3 -0
  366. package/src/data/query/tracing.ts +11 -0
  367. package/src/data/query/utils.ts +357 -0
  368. package/src/data/query/version.ts +4 -0
  369. package/src/data/query/view-common.ts +1 -0
  370. package/src/data/schema/branded.ts +13 -0
  371. package/src/data/schema/generated/coerce.ts +5 -0
  372. package/src/data/schema/generated/combinator.ts +6 -0
  373. package/src/data/schema/generated/encoding.ts +5 -0
  374. package/src/data/schema/generated/error.ts +6 -0
  375. package/src/data/schema/generated/format.ts +5 -0
  376. package/src/data/schema/generated/type-constructor.ts +10 -0
  377. package/src/data/schema/generated/type.ts +6 -0
  378. package/src/data/schema/index.ts +6 -0
  379. package/src/data/schema/json-schema.ts +33 -0
  380. package/src/data/schema/namespace.ts +55 -0
  381. package/src/data/schema/parse.ts +39 -0
  382. package/src/data/schema/types.ts +39 -0
  383. package/src/data/temporal/append-only.ts +134 -0
  384. package/src/data/temporal/close.ts +27 -0
  385. package/src/data/temporal/columns.ts +10 -0
  386. package/src/data/temporal/definition-queries.ts +70 -0
  387. package/src/data/temporal/errors.ts +10 -0
  388. package/src/data/temporal/get-current.ts +22 -0
  389. package/src/data/temporal/index.ts +9 -0
  390. package/src/data/temporal/namespace.ts +36 -0
  391. package/src/data/temporal/query.ts +25 -0
  392. package/src/data/temporal/resolve.ts +17 -0
  393. package/src/data/temporal/revise.ts +67 -0
  394. package/src/data/temporal/types.ts +22 -0
  395. package/src/data/valve/artifact.ts +33 -0
  396. package/src/data/valve/contract-diff.ts +21 -0
  397. package/src/data/valve/cross.ts +57 -0
  398. package/src/data/valve/crossing-ledger.ts +50 -0
  399. package/src/data/valve/decision.ts +44 -0
  400. package/src/data/valve/durable-crossing.ts +52 -0
  401. package/src/data/valve/execute-crossing.ts +77 -0
  402. package/src/data/valve/faucet.ts +56 -0
  403. package/src/data/valve/gate.ts +114 -0
  404. package/src/data/valve/graph.ts +77 -0
  405. package/src/data/valve/index.ts +53 -0
  406. package/src/data/valve/namespace.ts +57 -0
  407. package/src/data/valve/registry.ts +50 -0
  408. package/src/data/valve/schema/valve-crossing-fields.ts +23 -0
  409. package/src/data/valve/schema/valve-crossing.ts +9 -0
  410. package/src/data/valve/supply.ts +154 -0
  411. package/src/data/valve/types.ts +143 -0
  412. package/src/data/vector/columns.ts +27 -0
  413. package/src/data/vector/index.ts +4 -0
  414. package/src/data/vector/namespace.ts +33 -0
  415. package/src/data/vector/query.ts +85 -0
  416. package/src/data/vector/validate.ts +16 -0
  417. package/src/data/write/audit/actor.ts +15 -0
  418. package/src/data/write/audit/audit-columns.ts +18 -0
  419. package/src/data/write/audit/audit-select.ts +111 -0
  420. package/src/data/write/audit/bound-transaction.ts +14 -0
  421. package/src/data/write/audit/cte-compile.ts +32 -0
  422. package/src/data/write/audit/decode-returning.ts +47 -0
  423. package/src/data/write/audit/final-select.ts +43 -0
  424. package/src/data/write/audit/infra-audit.ts +36 -0
  425. package/src/data/write/audit/primary-key.ts +65 -0
  426. package/src/data/write/audit/projection.ts +41 -0
  427. package/src/data/write/audit/read-touches.ts +86 -0
  428. package/src/data/write/audit/touch-match.ts +78 -0
  429. package/src/data/write/audit/verb-delete.ts +62 -0
  430. package/src/data/write/audit/verb-insert.ts +36 -0
  431. package/src/data/write/audit/verb-select.ts +47 -0
  432. package/src/data/write/audit/verb-update.ts +60 -0
  433. package/src/data/write/audit/verb-upsert.ts +104 -0
  434. package/src/data/write/conflict.ts +43 -0
  435. package/src/data/write/delete.ts +38 -0
  436. package/src/data/write/execute.ts +243 -0
  437. package/src/data/write/index.ts +11 -0
  438. package/src/data/write/insert.ts +63 -0
  439. package/src/data/write/state.ts +43 -0
  440. package/src/data/write/update.ts +54 -0
  441. package/src/data/write/upsert.ts +58 -0
  442. package/src/data/write/values.ts +19 -0
  443. package/src/index.ts +230 -0
  444. package/src/infra/access-links/code.ts +70 -0
  445. package/src/infra/access-links/handle.ts +892 -0
  446. package/src/infra/access-links/index.ts +9 -0
  447. package/src/infra/access-links/namespace.ts +30 -0
  448. package/src/infra/access-links/person-check.ts +177 -0
  449. package/src/infra/access-links/schema.ts +71 -0
  450. package/src/infra/alerts/async-sources.ts +231 -0
  451. package/src/infra/alerts/audit.ts +36 -0
  452. package/src/infra/alerts/beat.ts +123 -0
  453. package/src/infra/alerts/client-faults.ts +111 -0
  454. package/src/infra/alerts/faults.ts +156 -0
  455. package/src/infra/alerts/handle.ts +778 -0
  456. package/src/infra/alerts/http.ts +192 -0
  457. package/src/infra/alerts/index.ts +12 -0
  458. package/src/infra/alerts/infra-sources.ts +180 -0
  459. package/src/infra/alerts/namespace.ts +81 -0
  460. package/src/infra/alerts/redact.ts +21 -0
  461. package/src/infra/alerts/request-faults.ts +41 -0
  462. package/src/infra/alerts/schema.ts +124 -0
  463. package/src/infra/alerts/sinks.ts +125 -0
  464. package/src/infra/alerts/source-options.ts +26 -0
  465. package/src/infra/alerts/sources.ts +503 -0
  466. package/src/infra/alerts/subsystem-sources.ts +137 -0
  467. package/src/infra/audit/emit.ts +87 -0
  468. package/src/infra/audit/index.ts +2 -0
  469. package/src/infra/audit/namespace.ts +22 -0
  470. package/src/infra/audit/schema.sql +35 -0
  471. package/src/infra/audit/types.ts +18 -0
  472. package/src/infra/aws/credentials.ts +147 -0
  473. package/src/infra/aws/sigv4.ts +140 -0
  474. package/src/infra/cache/create.ts +58 -0
  475. package/src/infra/cache/entry.ts +81 -0
  476. package/src/infra/cache/index.ts +4 -0
  477. package/src/infra/cache/namespace.ts +10 -0
  478. package/src/infra/cache/tenant.ts +93 -0
  479. package/src/infra/cache/types.ts +24 -0
  480. package/src/infra/crawl/audit.ts +35 -0
  481. package/src/infra/crawl/errors.ts +25 -0
  482. package/src/infra/crawl/handle.ts +693 -0
  483. package/src/infra/crawl/index.ts +9 -0
  484. package/src/infra/crawl/links.ts +160 -0
  485. package/src/infra/crawl/namespace.ts +36 -0
  486. package/src/infra/crawl/robots.ts +100 -0
  487. package/src/infra/crawl/schema.ts +89 -0
  488. package/src/infra/credit-line/handle.ts +883 -0
  489. package/src/infra/credit-line/index.ts +6 -0
  490. package/src/infra/credit-line/namespace.ts +7 -0
  491. package/src/infra/credit-line/schema.ts +96 -0
  492. package/src/infra/credits/handle.ts +706 -0
  493. package/src/infra/credits/index.ts +5 -0
  494. package/src/infra/credits/namespace.ts +7 -0
  495. package/src/infra/credits/schema.ts +83 -0
  496. package/src/infra/email/audit.ts +36 -0
  497. package/src/infra/email/inbound.ts +622 -0
  498. package/src/infra/email/index.ts +11 -0
  499. package/src/infra/email/mail.ts +517 -0
  500. package/src/infra/email/mime.ts +447 -0
  501. package/src/infra/email/namespace.ts +22 -0
  502. package/src/infra/email/providers.ts +111 -0
  503. package/src/infra/email/schema.ts +96 -0
  504. package/src/infra/email/sns.ts +200 -0
  505. package/src/infra/email/unsubscribe.ts +44 -0
  506. package/src/infra/fetch/address.ts +88 -0
  507. package/src/infra/fetch/connect-retry.ts +87 -0
  508. package/src/infra/fetch/handle.ts +329 -0
  509. package/src/infra/fetch/index.ts +7 -0
  510. package/src/infra/fetch/namespace.ts +70 -0
  511. package/src/infra/idempotency/index.ts +3 -0
  512. package/src/infra/idempotency/middleware.ts +87 -0
  513. package/src/infra/idempotency/store.ts +92 -0
  514. package/src/infra/idempotency/types.ts +30 -0
  515. package/src/infra/join-requests/handle.ts +312 -0
  516. package/src/infra/join-requests/index.ts +2 -0
  517. package/src/infra/join-requests/namespace.ts +7 -0
  518. package/src/infra/join-requests/schema.ts +33 -0
  519. package/src/infra/outbox/core.ts +165 -0
  520. package/src/infra/quota/errors.ts +32 -0
  521. package/src/infra/quota/handle.ts +215 -0
  522. package/src/infra/quota/index.ts +5 -0
  523. package/src/infra/quota/namespace.ts +7 -0
  524. package/src/infra/quota/schema.ts +15 -0
  525. package/src/infra/storage/backend.ts +34 -0
  526. package/src/infra/storage/handle.ts +513 -0
  527. package/src/infra/storage/index.ts +9 -0
  528. package/src/infra/storage/local.ts +104 -0
  529. package/src/infra/storage/namespace.ts +13 -0
  530. package/src/infra/storage/s3.ts +257 -0
  531. package/src/infra/storage/schema.ts +24 -0
  532. package/src/infra/support/handle.ts +869 -0
  533. package/src/infra/support/http.ts +229 -0
  534. package/src/infra/support/index.ts +7 -0
  535. package/src/infra/support/namespace.ts +12 -0
  536. package/src/infra/support/schema.ts +96 -0
  537. package/src/infra/webhook/inbound.ts +45 -0
  538. package/src/infra/webhook/index.ts +5 -0
  539. package/src/infra/webhook/namespace.ts +24 -0
  540. package/src/infra/webhook/outbound.ts +315 -0
  541. package/src/infra/webhook/sign.ts +32 -0
  542. package/src/infra/webhook/verify.ts +82 -0
  543. package/src/invariants/assert.ts +26 -0
  544. package/src/invariants/index.ts +1 -0
  545. package/src/lint/config.ts +56 -0
  546. package/src/lint/doctrine.ts +163 -0
  547. package/src/lint/include.ts +97 -0
  548. package/src/lint/index.ts +3 -0
  549. package/src/lint/preset.ts +10 -0
  550. package/src/lint/resolver.ts +218 -0
  551. package/src/lint/rules/no-reexports.ts +46 -0
  552. package/src/request/behavior/audited.ts +85 -0
  553. package/src/request/behavior/cached.ts +62 -0
  554. package/src/request/behavior/compose.ts +28 -0
  555. package/src/request/behavior/index.ts +5 -0
  556. package/src/request/behavior/namespace.ts +16 -0
  557. package/src/request/behavior/types.ts +26 -0
  558. package/src/request/behavior/versioned.ts +54 -0
  559. package/src/request/context/create.ts +103 -0
  560. package/src/request/context/guard.ts +49 -0
  561. package/src/request/context/index.ts +4 -0
  562. package/src/request/context/run-in-transaction.ts +200 -0
  563. package/src/request/context/store.ts +28 -0
  564. package/src/request/context/types.ts +50 -0
  565. package/src/request/di/builder.ts +535 -0
  566. package/src/request/di/index.ts +8 -0
  567. package/src/request/di/resolve.ts +271 -0
  568. package/src/request/di/types.ts +262 -0
  569. package/src/request/fitting/namespace.ts +7 -0
  570. package/src/request/fixture/batch.ts +71 -0
  571. package/src/request/fixture/builder.ts +26 -0
  572. package/src/request/fixture/errors.ts +10 -0
  573. package/src/request/fixture/index.ts +8 -0
  574. package/src/request/fixture/namespace.ts +23 -0
  575. package/src/request/fixture/paginate.ts +44 -0
  576. package/src/request/fixture/to-handlers.ts +260 -0
  577. package/src/request/fixture/types.ts +79 -0
  578. package/src/request/flow/act-as.ts +78 -0
  579. package/src/request/flow/namespace.ts +17 -0
  580. package/src/request/http/error-step.ts +42 -0
  581. package/src/request/http/file.ts +141 -0
  582. package/src/request/http/index.ts +4 -0
  583. package/src/request/http/middleware.ts +141 -0
  584. package/src/request/http/namespace.ts +5 -0
  585. package/src/request/http/rate-limit-classes.ts +170 -0
  586. package/src/request/http/response.ts +82 -0
  587. package/src/request/http/server.ts +916 -0
  588. package/src/request/http/sniff.ts +261 -0
  589. package/src/request/http/types.ts +250 -0
  590. package/src/request/http/upload.ts +284 -0
  591. package/src/request/internal/text.ts +6 -0
  592. package/src/request/openapi/generate.ts +205 -0
  593. package/src/request/openapi/index.ts +2 -0
  594. package/src/request/openapi/namespace.ts +7 -0
  595. package/src/test/auth.ts +13 -0
  596. package/src/test/auto-setup.ts +45 -0
  597. package/src/test/context.ts +91 -0
  598. package/src/test/crawl-fixture.ts +157 -0
  599. package/src/test/discover-fork.ts +17 -0
  600. package/src/test/fingerprint.ts +135 -0
  601. package/src/test/globals.d.ts +7 -0
  602. package/src/test/index.ts +19 -0
  603. package/src/test/namespace.ts +87 -0
  604. package/src/test/plugin.ts +189 -0
  605. package/src/test/progress.ts +185 -0
  606. package/src/test/reap-after-run.ts +28 -0
  607. package/src/test/reap.ts +286 -0
  608. package/src/test/reset.ts +253 -0
  609. package/src/test/savepoints.ts +172 -0
  610. package/src/test/setup.ts +1422 -0
  611. package/src/test/system-channel.ts +50 -0
  612. package/src/test/vitest-plugin.ts +142 -0
  613. package/src/test/vitest-workspace.ts +507 -0
  614. package/src/test/vitest.ts +333 -0
  615. package/src/test/watch.ts +105 -0
  616. package/src/trace/capture/bounded-serializer.ts +146 -0
  617. package/src/trace/cardinality/analyze.ts +173 -0
  618. package/src/trace/cardinality/branch-context.ts +214 -0
  619. package/src/trace/cardinality/check.ts +33 -0
  620. package/src/trace/cardinality/classify-edge.ts +64 -0
  621. package/src/trace/cardinality/structural-max.ts +107 -0
  622. package/src/trace/check/coverage-check.ts +188 -0
  623. package/src/trace/check/flow-check.ts +103 -0
  624. package/src/trace/check/flow-step-site.ts +234 -0
  625. package/src/trace/check/io-pattern.ts +116 -0
  626. package/src/trace/codemod/add-cardinality.ts +152 -0
  627. package/src/trace/codemod/run.ts +80 -0
  628. package/src/trace/entry/child-trace.ts +21 -0
  629. package/src/trace/entry/close-trace.ts +87 -0
  630. package/src/trace/entry/finalize-trace.ts +28 -0
  631. package/src/trace/entry/open-trace.ts +138 -0
  632. package/src/trace/entry/parent-trace.ts +20 -0
  633. package/src/trace/entry/parse-traceparent.ts +39 -0
  634. package/src/trace/entry/process-start.ts +38 -0
  635. package/src/trace/entry/trace-context.ts +26 -0
  636. package/src/trace/entry/tracing-enabled.ts +10 -0
  637. package/src/trace/external/record.ts +195 -0
  638. package/src/trace/external/report.ts +66 -0
  639. package/src/trace/namespace.ts +19 -0
  640. package/src/trace/partition/day.ts +47 -0
  641. package/src/trace/partition/index.ts +14 -0
  642. package/src/trace/partition/partition-name.ts +23 -0
  643. package/src/trace/partition/plan.ts +82 -0
  644. package/src/trace/partition/schedule.ts +26 -0
  645. package/src/trace/partition/startup-hook.ts +39 -0
  646. package/src/trace/partition/sync.ts +154 -0
  647. package/src/trace/partition/tables.ts +53 -0
  648. package/src/trace/read/tree.ts +83 -0
  649. package/src/trace/retain/copy-on-error.ts +76 -0
  650. package/src/trace/runtime/expire-stale-traces.ts +54 -0
  651. package/src/trace/runtime/flow-step.ts +147 -0
  652. package/src/trace/runtime/flush-steps.ts +31 -0
  653. package/src/trace/runtime/pending-writes.ts +54 -0
  654. package/src/trace/runtime/step-buffer.ts +298 -0
  655. package/src/trace/runtime/step-error.ts +21 -0
  656. package/src/trace/runtime/step-meta.ts +55 -0
  657. package/src/trace/runtime/thenable.ts +12 -0
  658. package/src/trace/runtime/truncate-trace.ts +62 -0
  659. package/src/trace/schema/trace-fields.ts +52 -0
  660. package/src/trace/schema/trace-retained.ts +22 -0
  661. package/src/trace/schema/trace-step-fields.ts +44 -0
  662. package/src/trace/schema/trace-step-retained.ts +25 -0
  663. package/src/trace/schema/trace-step.ts +18 -0
  664. package/src/trace/schema/trace.ts +12 -0
  665. package/src/trace/transformer/apply.ts +79 -0
  666. package/src/trace/transformer/build-meta-literal.ts +30 -0
  667. package/src/trace/transformer/find-flow-step-sites.ts +85 -0
  668. package/src/trace/transformer/inject-flow-step-import.ts +39 -0
  669. package/src/trace/transformer/transform-error.ts +14 -0
  670. package/src/trace/transformer/transform-flow-steps.ts +123 -0
  671. package/src/trace/transformer/wrap-function-declaration.ts +62 -0
  672. package/src/trace/transformer/wrap-variable-declaration.ts +67 -0
  673. package/src/workspace/affected.ts +110 -0
  674. package/src/workspace/changed-files.ts +163 -0
  675. package/src/workspace/check-deps.ts +213 -0
  676. package/src/workspace/checksum.ts +20 -0
  677. package/src/workspace/dependency-graph.ts +67 -0
  678. package/src/workspace/detect-pipework-copies.ts +93 -0
  679. package/src/workspace/discover.ts +206 -0
  680. package/src/workspace/generate.ts +401 -0
  681. package/src/workspace/index.ts +7 -0
  682. package/src/workspace/module-imports-pipework.ts +39 -0
  683. package/src/workspace/module-package-name.ts +12 -0
  684. package/src/workspace/scrub-git-env.ts +23 -0
  685. package/src/workspace/source-paths.ts +36 -0
  686. package/src/workspace/sync.ts +182 -0
  687. package/dist/REFERENCE.md +0 -1477
  688. package/dist/infra/access-links/rate-limit.d.ts +0 -10
  689. package/dist/infra/access-links/rate-limit.d.ts.map +0 -1
  690. package/dist/infra/access-links/rate-limit.js +0 -28
  691. package/dist/infra/access-links/rate-limit.js.map +0 -1
  692. package/dist/infra/email/sigv4.d.ts +0 -24
  693. package/dist/infra/email/sigv4.d.ts.map +0 -1
  694. package/dist/infra/email/sigv4.js +0 -55
  695. package/dist/infra/email/sigv4.js.map +0 -1
@@ -0,0 +1,188 @@
1
+ // Tier-2 coverage check (Q9): every I/O call site is inside a `@flow_step`,
2
+ // and a flow_step performs at most one I/O — at most one write, in particular.
3
+ // Without this, the trace is gap-prone by construction: an unannotated read or
4
+ // write goes silently untraced and the build doesn't notice.
5
+ //
6
+ // Ships as warning (Phase 6f): violations are surfaced but do not fail
7
+ // `pipework check`. Once the consumer corpus has been migrated, Phase 7a
8
+ // flips it to an error.
9
+ //
10
+ // Two rules:
11
+ // - flow/io-outside-flow-step — an I/O call appears outside any annotated
12
+ // flow_step function. The runtime can't open a `trace_step` for it.
13
+ // - flow/multi-io-per-flow-step — a flow_step body contains more than one
14
+ // I/O call. Split it so each I/O is its own step. The stricter variant,
15
+ // more than one *write* in the same step, is reported as
16
+ // flow/multi-write-per-flow-step — surfaces the Q8 one-write-per-step
17
+ // rule with its own diagnostic.
18
+ //
19
+ // Lexical: I/O inside a nested closure inside a flow_step body still counts
20
+ // as "inside the flow_step" — otherwise writes hide inside callbacks. The
21
+ // cardinality analyzer's "don't follow nested closures" convention is the
22
+ // opposite default, by design (Q1 vs Q9).
23
+
24
+ import { readFileSync, existsSync } from 'node:fs'
25
+ import { join } from 'node:path'
26
+ import { parse } from '@typescript-eslint/parser'
27
+ import { collectFlowStepSites, isNode, type AstNode, type FlowStepSite } from './flow-step-site.js'
28
+ import { classifyIo, type IoKind } from './io-pattern.js'
29
+
30
+ export interface CoverageViolation {
31
+ readonly rule: string
32
+ readonly file: string
33
+ readonly line: number
34
+ readonly message: string
35
+ }
36
+
37
+ export interface CoverageCheckResult {
38
+ readonly violations: readonly CoverageViolation[]
39
+ readonly scanned: number
40
+ }
41
+
42
+ interface IoSite {
43
+ readonly kind: IoKind
44
+ /** 1-based line. */
45
+ readonly line: number
46
+ /** Character offset of the call expression in the file (for in-range checks). */
47
+ readonly start: number
48
+ }
49
+
50
+ /**
51
+ * Tier-2 coverage check across `sourceFiles` (paths relative to `cwd`).
52
+ *
53
+ * `extras` extends the stock pipework I/O registry with consumer-declared
54
+ * patterns from `config.trace.io`. Defaults to empty — the stock registry
55
+ * (`pipe.*` writes, `pipe(...)`-chain reads) is always live.
56
+ */
57
+ export function checkCoverage(
58
+ cwd: string,
59
+ sourceFiles: readonly string[],
60
+ extras: Readonly<Record<string, IoKind>> = {},
61
+ ): CoverageCheckResult {
62
+ const violations: CoverageViolation[] = []
63
+ let scanned = 0
64
+
65
+ for (const file of sourceFiles) {
66
+ const abs = join(cwd, file)
67
+ if (!existsSync(abs)) continue
68
+
69
+ let program: AstNode | null = null
70
+ let sites: readonly FlowStepSite[] = []
71
+ try {
72
+ // Read the file once — #322: it was being read (and parsed) twice here.
73
+ const source = readFileSync(abs, 'utf-8')
74
+ program = parseProgram(source, file)
75
+ sites = collectFlowStepSites(source, file)
76
+ } catch {
77
+ // Unparseable — leave syntax errors to the type checker.
78
+ continue
79
+ }
80
+ scanned++
81
+
82
+ const ioSites = collectIoSites(program, extras)
83
+ const flowStepRanges = collectFlowStepRanges(sites)
84
+
85
+ for (const io of ioSites) {
86
+ const enclosing = flowStepRanges.find(r => io.start >= r.bodyStart && io.start < r.bodyEnd)
87
+ if (enclosing === undefined) {
88
+ violations.push({
89
+ rule: 'flow/io-outside-flow-step',
90
+ file,
91
+ line: io.line,
92
+ message:
93
+ `I/O ${io.kind} is outside any @flow_step. Wrap it in a standalone function and ` +
94
+ `annotate that function with @flow_step so the runtime can open a trace_step for it.`,
95
+ })
96
+ }
97
+ }
98
+
99
+ for (const range of flowStepRanges) {
100
+ const inside = ioSites.filter(s => s.start >= range.bodyStart && s.start < range.bodyEnd)
101
+ if (inside.length <= 1) continue
102
+
103
+ const writes = inside.filter(s => s.kind === 'write')
104
+ if (writes.length > 1) {
105
+ violations.push({
106
+ rule: 'flow/multi-write-per-flow-step',
107
+ file,
108
+ line: range.line,
109
+ message:
110
+ `@flow_step "${range.name}" performs ${String(writes.length)} writes. A flow_step ` +
111
+ `may perform at most one write (Q8). Split each write into its own flow_step.`,
112
+ })
113
+ continue
114
+ }
115
+
116
+ violations.push({
117
+ rule: 'flow/multi-io-per-flow-step',
118
+ file,
119
+ line: range.line,
120
+ message:
121
+ `@flow_step "${range.name}" performs ${String(inside.length)} I/O calls. A flow_step ` +
122
+ `may perform at most one I/O call. Split each call into its own flow_step.`,
123
+ })
124
+ }
125
+ }
126
+
127
+ return { violations, scanned }
128
+ }
129
+
130
+ interface FlowStepRange {
131
+ readonly name: string
132
+ readonly line: number
133
+ readonly bodyStart: number
134
+ readonly bodyEnd: number
135
+ }
136
+
137
+ function collectFlowStepRanges(sites: readonly FlowStepSite[]): FlowStepRange[] {
138
+ const ranges: FlowStepRange[] = []
139
+ for (const site of sites) {
140
+ const body = site.subject.body
141
+ if (body === null) continue
142
+ ranges.push({
143
+ name: site.subject.name,
144
+ line: site.subject.line,
145
+ bodyStart: body.range[0],
146
+ bodyEnd: body.range[1],
147
+ })
148
+ }
149
+ return ranges
150
+ }
151
+
152
+ function collectIoSites(program: AstNode, extras: Readonly<Record<string, IoKind>>): IoSite[] {
153
+ const out: IoSite[] = []
154
+ walk(program, node => {
155
+ if (node.type !== 'CallExpression') return
156
+ const kind = classifyIo(node, extras)
157
+ if (kind === null) return
158
+ out.push({ kind, line: node.loc.start.line, start: node.range[0] })
159
+ })
160
+ return out
161
+ }
162
+
163
+ const SKIP_KEYS = new Set(['loc', 'range', 'parent'])
164
+
165
+ function walk(node: AstNode, visit: (n: AstNode) => void): void {
166
+ visit(node)
167
+ for (const key of Object.keys(node)) {
168
+ if (SKIP_KEYS.has(key)) continue
169
+ const value = node[key]
170
+ if (Array.isArray(value)) {
171
+ for (const item of value) {
172
+ if (isNode(item)) walk(item, visit)
173
+ }
174
+ } else if (isNode(value)) {
175
+ walk(value, visit)
176
+ }
177
+ }
178
+ }
179
+
180
+ function parseProgram(code: string, fileName: string): AstNode {
181
+ return parse(code, {
182
+ ...(fileName.endsWith('.tsx') ? { jsx: true } : {}),
183
+ range: true,
184
+ loc: true,
185
+ comment: true,
186
+ sourceType: 'module',
187
+ }) as unknown as AstNode
188
+ }
@@ -0,0 +1,103 @@
1
+ // The `flow` check: validates `@flow_step` annotations across a set of source
2
+ // files. This is the syntactic tier — it rejects what is locally wrong about an
3
+ // annotation without consulting the call graph. Three rules:
4
+ //
5
+ // - a `@flow_step` block must document a standalone function, not a method;
6
+ // - every `@downstream` must declare its cardinality (`step` | `branch`);
7
+ // - the annotation must parse.
8
+ //
9
+ // Cardinality is *correct* only relative to the call graph — that is the
10
+ // cardinality analyzer's job, not this one. See PLAN.tracing.md, component 2.
11
+
12
+ import { readFileSync, existsSync } from 'node:fs'
13
+ import { join } from 'node:path'
14
+ import { collectFlowStepSites, type FlowStepSite } from './flow-step-site.js'
15
+
16
+ export interface FlowViolation {
17
+ readonly rule: string
18
+ readonly file: string
19
+ readonly line: number
20
+ readonly message: string
21
+ }
22
+
23
+ export interface FlowCheckResult {
24
+ readonly violations: readonly FlowViolation[]
25
+ readonly scanned: number
26
+ }
27
+
28
+ /** Validates every `@flow_step` annotation in `sourceFiles` (paths relative to `cwd`). */
29
+ export function checkFlowAnnotations(cwd: string, sourceFiles: readonly string[]): FlowCheckResult {
30
+ const violations: FlowViolation[] = []
31
+ let scanned = 0
32
+
33
+ for (const file of sourceFiles) {
34
+ const abs = join(cwd, file)
35
+ if (!existsSync(abs)) continue
36
+
37
+ let sites: readonly FlowStepSite[]
38
+ try {
39
+ sites = collectFlowStepSites(readFileSync(abs, 'utf-8'), file)
40
+ } catch {
41
+ // Unparseable file — leave syntax errors to the type checker.
42
+ continue
43
+ }
44
+ scanned++
45
+
46
+ for (const site of sites) {
47
+ collectSiteViolations(file, site, violations)
48
+ }
49
+ }
50
+
51
+ return { violations, scanned }
52
+ }
53
+
54
+ function collectSiteViolations(file: string, site: FlowStepSite, out: FlowViolation[]): void {
55
+ const { subject, annotation, commentLine } = site
56
+
57
+ if (subject.shape === 'orphan') {
58
+ out.push({
59
+ rule: 'flow/orphan-annotation',
60
+ file,
61
+ line: commentLine,
62
+ message:
63
+ '@flow_step JSDoc is not attached to a function. A flow step must document a '
64
+ + 'standalone function declaration so it has a stable path:symbol identity.',
65
+ })
66
+ } else if (subject.shape === 'method') {
67
+ out.push({
68
+ rule: 'flow/no-method-flow-step',
69
+ file,
70
+ line: subject.line,
71
+ message:
72
+ `@flow_step on method "${subject.name}" — a method cannot be a flow step. It carries `
73
+ + `hidden "this" state, so the trace boundary is untrustworthy. Extract "${subject.name}" `
74
+ + 'into a standalone function.',
75
+ })
76
+ }
77
+
78
+ if (annotation.kind === 'invalid') {
79
+ for (const err of annotation.errors) {
80
+ out.push({
81
+ rule: 'flow/invalid-annotation',
82
+ file,
83
+ line: commentLine + err.line - 1,
84
+ message: err.message,
85
+ })
86
+ }
87
+ return
88
+ }
89
+
90
+ for (const edge of annotation.annotation.downstream) {
91
+ if (edge.cardinality === null) {
92
+ out.push({
93
+ rule: 'flow/missing-cardinality',
94
+ file,
95
+ line: commentLine,
96
+ message:
97
+ `@downstream ${edge.path}:${edge.symbol} is missing a cardinality. Add "step" or `
98
+ + `"branch": @downstream ${edge.path}:${edge.symbol} branch. A branch is an edge `
99
+ + 'traversed more than once (loop, batch, recursion, fan-out).',
100
+ })
101
+ }
102
+ }
103
+ }
@@ -0,0 +1,234 @@
1
+ // Locates `@flow_step` annotation sites in a TypeScript source file: each site
2
+ // pairs a parsed annotation with the declaration it documents and how that
3
+ // declaration is shaped — a standalone function, a method, or nothing at all.
4
+ // The `flow` check and the cardinality analyzer both build on this; it is the
5
+ // one place that answers "where are the flow steps in this file".
6
+
7
+ import { parse } from '@typescript-eslint/parser'
8
+ import { parseFlowStepAnnotation, type FlowStepParseResult } from 'pipework-flow-parser'
9
+
10
+ interface Position {
11
+ readonly line: number
12
+ readonly column: number
13
+ }
14
+
15
+ interface SourceLocation {
16
+ readonly start: Position
17
+ readonly end: Position
18
+ }
19
+
20
+ /** A structurally-typed ESTree node — enough to walk without a parser type dependency. */
21
+ export interface AstNode {
22
+ readonly type: string
23
+ readonly range: readonly [number, number]
24
+ readonly loc: SourceLocation
25
+ readonly [key: string]: unknown
26
+ }
27
+
28
+ interface CommentNode {
29
+ readonly type: 'Block' | 'Line'
30
+ readonly value: string
31
+ readonly range: readonly [number, number]
32
+ readonly loc: SourceLocation
33
+ }
34
+
35
+ interface Program extends AstNode {
36
+ readonly comments: readonly CommentNode[]
37
+ }
38
+
39
+ /**
40
+ * How a `@flow_step`-annotated declaration is shaped.
41
+ *
42
+ * - `function` — a standalone function (declaration or a `const` bound to an
43
+ * arrow / function expression). The only legal shape.
44
+ * - `method` — a class method, class field bound to a function, or object
45
+ * literal method. Banned: a method carries hidden `this` state, so the trace
46
+ * boundary is untrustworthy. See PLAN.tracing.md, Q3.
47
+ * - `orphan` — the JSDoc block documents no declaration the analyzer can see.
48
+ */
49
+ export type FlowStepShape = 'function' | 'method' | 'orphan'
50
+
51
+ export interface FlowStepSubject {
52
+ readonly shape: FlowStepShape
53
+ /** Declared name, or `<anonymous>` / `<computed>` when none can be read. */
54
+ readonly name: string
55
+ /** 1-based line of the declaration, or of the JSDoc block when orphaned. */
56
+ readonly line: number
57
+ /** The declaration node, or `null` when orphaned. */
58
+ readonly node: AstNode | null
59
+ /**
60
+ * The documented function's executable body — what the cardinality analyzer
61
+ * walks. `null` exactly when `node` is `null` (an orphan): every `function`
62
+ * and `method` subject resolves to a function with a body.
63
+ */
64
+ readonly body: AstNode | null
65
+ }
66
+
67
+ export interface FlowStepSite {
68
+ /** Parsed content of the `@flow_step` JSDoc block — never `not-a-flow-step`. */
69
+ readonly annotation: Exclude<FlowStepParseResult, { kind: 'not-a-flow-step' }>
70
+ /** The declaration the block documents, and how it is shaped. */
71
+ readonly subject: FlowStepSubject
72
+ /** 1-based line where the `@flow_step` JSDoc block opens. */
73
+ readonly commentLine: number
74
+ }
75
+
76
+ interface Candidate {
77
+ readonly node: AstNode
78
+ readonly shape: Exclude<FlowStepShape, 'orphan'>
79
+ readonly name: string
80
+ readonly body: AstNode | null
81
+ }
82
+
83
+ const flowStepSiteCache = new Map<string, FlowStepSite[]>()
84
+
85
+ /**
86
+ * Parse `code` and return every `@flow_step` site it contains, in source order.
87
+ *
88
+ * Memoized by source text: the flow, cardinality, and coverage checks each scan
89
+ * the same file, and the parse-and-walk produces a bit-identical result every
90
+ * time — the cache collapses it to one parse per file. Issue #322.
91
+ *
92
+ * Throws if `code` is not parseable — callers scanning many files should catch
93
+ * and skip, leaving syntax errors to the type checker. A `fileName` ending in
94
+ * `.tsx` parses with JSX enabled.
95
+ */
96
+ export function collectFlowStepSites(code: string, fileName?: string): FlowStepSite[] {
97
+ const jsx = fileName?.endsWith('.tsx') === true
98
+ const key = jsx ? 'jsx\0' + code : code
99
+ const cached = flowStepSiteCache.get(key)
100
+ if (cached !== undefined) return cached
101
+ const sites = parseFlowStepSites(code, jsx)
102
+ flowStepSiteCache.set(key, sites)
103
+ return sites
104
+ }
105
+
106
+ function parseFlowStepSites(code: string, jsx: boolean): FlowStepSite[] {
107
+ const program = parse(code, {
108
+ ...(jsx ? { jsx: true } : {}),
109
+ range: true,
110
+ loc: true,
111
+ comment: true,
112
+ sourceType: 'module',
113
+ }) as unknown as Program
114
+
115
+ const candidates: Candidate[] = []
116
+ walk(program, node => {
117
+ const candidate = classify(node)
118
+ if (candidate !== null) candidates.push(candidate)
119
+ })
120
+ candidates.sort((a, b) => a.node.range[0] - b.node.range[0])
121
+
122
+ const sites: FlowStepSite[] = []
123
+ for (const comment of program.comments) {
124
+ if (comment.type !== 'Block') continue
125
+ const annotation = parseFlowStepAnnotation(`/*${comment.value}*/`)
126
+ if (annotation.kind === 'not-a-flow-step') continue
127
+ sites.push({
128
+ annotation,
129
+ subject: subjectFor(comment, candidates),
130
+ commentLine: comment.loc.start.line,
131
+ })
132
+ }
133
+ return sites
134
+ }
135
+
136
+ /** The declaration a `@flow_step` block documents: the nearest one that follows it. */
137
+ function subjectFor(comment: CommentNode, candidates: readonly Candidate[]): FlowStepSubject {
138
+ const documented = candidates.find(c => c.node.range[0] >= comment.range[1])
139
+ if (documented === undefined) {
140
+ return { shape: 'orphan', name: '<unknown>', line: comment.loc.start.line, node: null, body: null }
141
+ }
142
+ return {
143
+ shape: documented.shape,
144
+ name: documented.name,
145
+ line: documented.node.loc.start.line,
146
+ node: documented.node,
147
+ body: documented.body,
148
+ }
149
+ }
150
+
151
+ /** Classifies a node as a flow-step-able declaration, or `null` if it is not one. */
152
+ function classify(node: AstNode): Candidate | null {
153
+ switch (node.type) {
154
+ case 'FunctionDeclaration':
155
+ return { node, shape: 'function', name: readName(node['id']), body: bodyOf(node) }
156
+ case 'VariableDeclaration': {
157
+ const bound = functionBoundDeclarator(node)
158
+ if (bound === null) return null
159
+ return { node, shape: 'function', name: readName(bound['id']), body: bodyOf(bound['init']) }
160
+ }
161
+ case 'MethodDefinition':
162
+ case 'TSAbstractMethodDefinition':
163
+ return { node, shape: 'method', name: readName(node['key']), body: bodyOf(node['value']) }
164
+ case 'PropertyDefinition':
165
+ case 'TSAbstractPropertyDefinition':
166
+ case 'Property':
167
+ return isFunctionExpression(node['value'])
168
+ ? { node, shape: 'method', name: readName(node['key']), body: bodyOf(node['value']) }
169
+ : null
170
+ default:
171
+ return null
172
+ }
173
+ }
174
+
175
+ /** The executable `body` of a function node — a `BlockStatement` or, for a
176
+ * concise arrow, the returned expression. `null` when `fn` is not a function. */
177
+ function bodyOf(fn: unknown): AstNode | null {
178
+ if (!isNode(fn)) return null
179
+ const body = fn['body']
180
+ return isNode(body) ? body : null
181
+ }
182
+
183
+ /** The first declarator in a `VariableDeclaration` bound to a function, or `null`. */
184
+ function functionBoundDeclarator(node: AstNode): AstNode | null {
185
+ const declarations = node['declarations']
186
+ if (!Array.isArray(declarations)) return null
187
+ for (const declarator of declarations) {
188
+ if (isNode(declarator) && isFunctionExpression(declarator['init'])) return declarator
189
+ }
190
+ return null
191
+ }
192
+
193
+ function isFunctionExpression(value: unknown): boolean {
194
+ return isNode(value)
195
+ && (value.type === 'ArrowFunctionExpression' || value.type === 'FunctionExpression')
196
+ }
197
+
198
+ function readName(keyOrId: unknown): string {
199
+ if (!isNode(keyOrId)) return '<anonymous>'
200
+ switch (keyOrId.type) {
201
+ case 'Identifier':
202
+ return String(keyOrId['name'])
203
+ case 'PrivateIdentifier':
204
+ return `#${String(keyOrId['name'])}`
205
+ case 'Literal':
206
+ return String(keyOrId['value'])
207
+ default:
208
+ return '<computed>'
209
+ }
210
+ }
211
+
212
+ const SKIP_KEYS = new Set(['loc', 'range', 'parent'])
213
+
214
+ /** Depth-first visit of every node reachable from `node`, parents before children. */
215
+ function walk(node: AstNode, visit: (n: AstNode) => void): void {
216
+ visit(node)
217
+ for (const key of Object.keys(node)) {
218
+ if (SKIP_KEYS.has(key)) continue
219
+ const value = node[key]
220
+ if (Array.isArray(value)) {
221
+ for (const item of value) {
222
+ if (isNode(item)) walk(item, visit)
223
+ }
224
+ } else if (isNode(value)) {
225
+ walk(value, visit)
226
+ }
227
+ }
228
+ }
229
+
230
+ export function isNode(value: unknown): value is AstNode {
231
+ return typeof value === 'object'
232
+ && value !== null
233
+ && typeof (value as { type?: unknown }).type === 'string'
234
+ }
@@ -0,0 +1,116 @@
1
+ // The I/O call-target registry consumed by the Tier-2 coverage check. Given a
2
+ // `CallExpression`, classifies it as a read, a write, or not-I/O.
3
+ //
4
+ // Stock list (pipework-owned, lexical):
5
+ // - Writes: `pipe.insert / pipe.update / pipe.delete / pipe.upsert /
6
+ // pipe.bulkSet`. These are the locked write entrypoints from Q8; the
7
+ // raw-write lint rule (component 13) backs them up.
8
+ // - Reads: any call whose callee chains off `pipe(...)` — e.g.
9
+ // `pipe('db').execute(...)`, `pipe(name).select(...)`,
10
+ // `pipe('db').query.users.findMany(...)`. The `pipe(name)` accessor only
11
+ // exists to perform I/O, so any method called on its result counts.
12
+ //
13
+ // Consumer extension (Q9): cache, external HTTP, queue publishes — anything
14
+ // outside the stock list — is registered through `pipework.config.ts` under
15
+ // `trace.io`. The registry is a `Record<string, 'read' | 'write'>` where the
16
+ // key is a lexical call pattern: a bare identifier (`"fetch"`) matches an
17
+ // identifier callee; an `"object.method"` pattern matches a single-level
18
+ // member-access callee. The schema validator rejects anything more elaborate —
19
+ // type resolution is out of scope, lexical matching is the contract.
20
+
21
+ import { isNode, type AstNode } from './flow-step-site.js'
22
+
23
+ export type IoKind = 'read' | 'write'
24
+
25
+ const PIPE_WRITE_METHODS = new Set(['insert', 'update', 'delete', 'upsert', 'bulkSet'])
26
+
27
+ /**
28
+ * Classify `call` against the stock I/O registry and the optional consumer
29
+ * `extras` registry, or return `null` if the call is not I/O. `extras` is the
30
+ * `Record` shape `config.trace.io` resolves to — keys are lexical patterns
31
+ * (`"fetch"` or `"cache.get"`), values are `'read' | 'write'`.
32
+ *
33
+ * `call` must be a `CallExpression`; callers walk the AST and hand each one
34
+ * over. This function is pure over the node — no parent lookups, no type
35
+ * resolution. Lexical match only.
36
+ */
37
+ export function classifyIo(
38
+ call: AstNode,
39
+ extras: Readonly<Record<string, IoKind>> = {},
40
+ ): IoKind | null {
41
+ if (call.type !== 'CallExpression') return null
42
+ const callee = call['callee']
43
+ if (!isNode(callee)) return null
44
+
45
+ if (isPipeWriteCallee(callee)) return 'write'
46
+ if (chainsOffPipeAccessor(callee)) return 'read'
47
+
48
+ return matchExtras(callee, extras)
49
+ }
50
+
51
+ /** `pipe.<verb>` where `<verb>` is one of the locked write entrypoints. */
52
+ function isPipeWriteCallee(callee: AstNode): boolean {
53
+ if (callee.type !== 'MemberExpression') return false
54
+ if (callee['computed'] === true) return false
55
+
56
+ const object = callee['object']
57
+ const property = callee['property']
58
+ if (!isNode(object) || object.type !== 'Identifier' || object['name'] !== 'pipe') return false
59
+ if (!isNode(property) || property.type !== 'Identifier') return false
60
+
61
+ const name = property['name']
62
+ return typeof name === 'string' && PIPE_WRITE_METHODS.has(name)
63
+ }
64
+
65
+ /**
66
+ * The callee is a chain off `pipe(...)` — anywhere up the member-expression
67
+ * spine. `pipe('db').execute(sql)` matches; `pipe('db').query.users.findMany()`
68
+ * matches; `pipe.update(t)` (no call on `pipe`) does not.
69
+ */
70
+ function chainsOffPipeAccessor(callee: AstNode): boolean {
71
+ let cursor: AstNode = callee
72
+ while (cursor.type === 'MemberExpression') {
73
+ const object = cursor['object']
74
+ if (!isNode(object)) return false
75
+ if (isPipeInvocation(object)) return true
76
+ cursor = object
77
+ }
78
+ return false
79
+ }
80
+
81
+ /** `pipe(...)` — a call expression whose callee is the identifier `pipe`. */
82
+ function isPipeInvocation(node: AstNode): boolean {
83
+ if (node.type !== 'CallExpression') return false
84
+ const callee = node['callee']
85
+ return isNode(callee) && callee.type === 'Identifier' && callee['name'] === 'pipe'
86
+ }
87
+
88
+ /**
89
+ * Looks up `callee` against the consumer registry. Two shapes match:
90
+ * - Identifier `foo` → key `"foo"`
91
+ * - Non-computed MemberExpression `obj.method` (Identifier object,
92
+ * Identifier property) → key `"obj.method"`
93
+ * Anything else falls through (returns `null`) — the stock registry has
94
+ * already exited above, so this is the not-I/O bucket.
95
+ */
96
+ function matchExtras(
97
+ callee: AstNode,
98
+ extras: Readonly<Record<string, IoKind>>,
99
+ ): IoKind | null {
100
+ if (callee.type === 'Identifier') {
101
+ const name = callee['name']
102
+ if (typeof name !== 'string') return null
103
+ return extras[name] ?? null
104
+ }
105
+ if (callee.type === 'MemberExpression' && callee['computed'] !== true) {
106
+ const object = callee['object']
107
+ const property = callee['property']
108
+ if (!isNode(object) || object.type !== 'Identifier') return null
109
+ if (!isNode(property) || property.type !== 'Identifier') return null
110
+ const objectName = object['name']
111
+ const propertyName = property['name']
112
+ if (typeof objectName !== 'string' || typeof propertyName !== 'string') return null
113
+ return extras[`${objectName}.${propertyName}`] ?? null
114
+ }
115
+ return null
116
+ }