pipework 0.252.0 → 0.252.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (690) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/package.json +4 -3
  3. package/src/async/jobs/abortable-delay.ts +18 -0
  4. package/src/async/jobs/claims.ts +52 -0
  5. package/src/async/jobs/cron.ts +179 -0
  6. package/src/async/jobs/errors.ts +56 -0
  7. package/src/async/jobs/exclusion.ts +117 -0
  8. package/src/async/jobs/execute.ts +219 -0
  9. package/src/async/jobs/index.ts +10 -0
  10. package/src/async/jobs/listener.ts +135 -0
  11. package/src/async/jobs/namespace.ts +20 -0
  12. package/src/async/jobs/queue-door.ts +44 -0
  13. package/src/async/jobs/queue.ts +1012 -0
  14. package/src/async/jobs/run-script.ts +67 -0
  15. package/src/async/jobs/scheduler.ts +218 -0
  16. package/src/async/jobs/schedules-table.ts +37 -0
  17. package/src/async/jobs/serialize-error.ts +48 -0
  18. package/src/async/jobs/table.ts +191 -0
  19. package/src/async/pipeline/define.ts +53 -0
  20. package/src/async/pipeline/errors.ts +35 -0
  21. package/src/async/pipeline/execute.ts +53 -0
  22. package/src/async/pipeline/index.ts +13 -0
  23. package/src/async/pipeline/namespace.ts +12 -0
  24. package/src/async/pipeline/resume.ts +67 -0
  25. package/src/async/pipeline/run-steps.ts +98 -0
  26. package/src/async/pipeline/types.ts +57 -0
  27. package/src/async/state-machine/define.ts +64 -0
  28. package/src/async/state-machine/errors.ts +29 -0
  29. package/src/async/state-machine/index.ts +3 -0
  30. package/src/async/state-machine/namespace.ts +12 -0
  31. package/src/async/state-machine/transition.ts +90 -0
  32. package/src/async/state-machine/types.ts +37 -0
  33. package/src/async/steps/errors.ts +31 -0
  34. package/src/async/steps/graph.ts +1214 -0
  35. package/src/async/steps/hash.ts +40 -0
  36. package/src/async/steps/index.ts +7 -0
  37. package/src/async/steps/namespace.ts +7 -0
  38. package/src/async/steps/table.ts +97 -0
  39. package/src/async/steps/types.ts +318 -0
  40. package/src/audit/chain/index.ts +9 -0
  41. package/src/audit/chain/install.ts +113 -0
  42. package/src/audit/chain/retire.ts +52 -0
  43. package/src/audit/chain/verify.ts +257 -0
  44. package/src/audit/query/cursor.ts +37 -0
  45. package/src/audit/query/index.ts +9 -0
  46. package/src/audit/query/query.ts +223 -0
  47. package/src/audit/schema/audit-record-fields.ts +68 -0
  48. package/src/audit/schema/audit-record.ts +23 -0
  49. package/src/auth/auth/audit.ts +31 -0
  50. package/src/auth/auth/chain.ts +84 -0
  51. package/src/auth/auth/cookie.ts +136 -0
  52. package/src/auth/auth/email-links.ts +311 -0
  53. package/src/auth/auth/guard.ts +128 -0
  54. package/src/auth/auth/index.ts +18 -0
  55. package/src/auth/auth/multi-org.ts +337 -0
  56. package/src/auth/auth/namespace.ts +34 -0
  57. package/src/auth/auth/parse-expiry.ts +13 -0
  58. package/src/auth/auth/passwords.ts +110 -0
  59. package/src/auth/auth/schema.ts +110 -0
  60. package/src/auth/auth/sessions.ts +565 -0
  61. package/src/auth/auth/sign-in.ts +156 -0
  62. package/src/auth/auth/signing-keys.ts +69 -0
  63. package/src/auth/auth/types.ts +26 -0
  64. package/src/auth/auth/uuid.ts +10 -0
  65. package/src/auth/rbac/cache.ts +55 -0
  66. package/src/auth/rbac/check.ts +30 -0
  67. package/src/auth/rbac/create.ts +35 -0
  68. package/src/auth/rbac/index.ts +5 -0
  69. package/src/auth/rbac/middleware.ts +20 -0
  70. package/src/auth/rbac/namespace.ts +15 -0
  71. package/src/auth/rbac/resolve.ts +31 -0
  72. package/src/auth/rbac/schema.sql +31 -0
  73. package/src/auth/rbac/seed.ts +67 -0
  74. package/src/auth/rbac/tables.ts +32 -0
  75. package/src/auth/rbac/types.ts +65 -0
  76. package/src/auth/tenant/extract.ts +33 -0
  77. package/src/auth/tenant/in-tenant.ts +49 -0
  78. package/src/auth/tenant/index.ts +7 -0
  79. package/src/auth/tenant/namespace.ts +23 -0
  80. package/src/auth/tenant/propagate.ts +20 -0
  81. package/src/auth/tenant/rls.ts +120 -0
  82. package/src/auth/tenant/scope.ts +33 -0
  83. package/src/auth/tenant/scoped-db.ts +581 -0
  84. package/src/auth/tenant/types.ts +14 -0
  85. package/src/auth/tenant/validate.ts +27 -0
  86. package/src/cli/commands/add.ts +158 -0
  87. package/src/cli/commands/alerts.ts +98 -0
  88. package/src/cli/commands/check.ts +1418 -0
  89. package/src/cli/commands/codemod.ts +78 -0
  90. package/src/cli/commands/db.ts +356 -0
  91. package/src/cli/commands/dev.ts +101 -0
  92. package/src/cli/commands/generate.ts +75 -0
  93. package/src/cli/commands/init.ts +36 -0
  94. package/src/cli/commands/install.ts +28 -0
  95. package/src/cli/commands/lint.ts +62 -0
  96. package/src/cli/commands/migrate.ts +132 -0
  97. package/src/cli/commands/openapi.ts +63 -0
  98. package/src/cli/commands/remove.ts +72 -0
  99. package/src/cli/commands/run.ts +50 -0
  100. package/src/cli/commands/scope.ts +54 -0
  101. package/src/cli/commands/serve.ts +68 -0
  102. package/src/cli/commands/shard.ts +31 -0
  103. package/src/cli/commands/shared/config-pipework-version.ts +28 -0
  104. package/src/cli/commands/shared/find-config.ts +22 -0
  105. package/src/cli/commands/shared/load-config.ts +35 -0
  106. package/src/cli/commands/shared/pnpm-install.ts +95 -0
  107. package/src/cli/commands/shared/report-removed.ts +8 -0
  108. package/src/cli/commands/sync.ts +32 -0
  109. package/src/cli/commands/test.ts +307 -0
  110. package/src/cli/commands/upgrade.ts +48 -0
  111. package/src/cli/dev-bootstrap.ts +24 -0
  112. package/src/cli/errors.ts +10 -0
  113. package/src/cli/index.ts +303 -0
  114. package/src/cli/output.ts +17 -0
  115. package/src/cli/port.ts +15 -0
  116. package/src/cli/surface-kinds.ts +20 -0
  117. package/src/client/index.ts +4 -0
  118. package/src/client/poll.ts +130 -0
  119. package/src/client/report-fault.ts +119 -0
  120. package/src/core/config/app-pool.ts +19 -0
  121. package/src/core/config/aws-env.ts +29 -0
  122. package/src/core/config/base-dir.ts +24 -0
  123. package/src/core/config/discover.ts +64 -0
  124. package/src/core/config/env-resolve.ts +87 -0
  125. package/src/core/config/env-types.ts +116 -0
  126. package/src/core/config/env.ts +55 -0
  127. package/src/core/config/errors.ts +9 -0
  128. package/src/core/config/import-config.ts +40 -0
  129. package/src/core/config/index.ts +8 -0
  130. package/src/core/config/load.ts +417 -0
  131. package/src/core/config/namespace.ts +14 -0
  132. package/src/core/config/resolve.ts +195 -0
  133. package/src/core/config/schema.ts +488 -0
  134. package/src/core/config/statement-observer.ts +48 -0
  135. package/src/core/config/ts-inline-hooks.ts +75 -0
  136. package/src/core/config/ts-register.ts +4 -0
  137. package/src/core/config/ts-resolve-hooks.ts +101 -0
  138. package/src/core/errors/base.ts +49 -0
  139. package/src/core/errors/http.ts +146 -0
  140. package/src/core/errors/index.ts +2 -0
  141. package/src/core/errors/namespace.ts +31 -0
  142. package/src/core/lifecycle/drain.ts +33 -0
  143. package/src/core/lifecycle/health.ts +72 -0
  144. package/src/core/lifecycle/index.ts +4 -0
  145. package/src/core/lifecycle/namespace.ts +7 -0
  146. package/src/core/lifecycle/startup.ts +102 -0
  147. package/src/core/lifecycle/types.ts +36 -0
  148. package/src/core/logging/context.ts +60 -0
  149. package/src/core/logging/error-chain.ts +68 -0
  150. package/src/core/logging/index.ts +5 -0
  151. package/src/core/logging/logger.ts +65 -0
  152. package/src/core/logging/namespace.ts +16 -0
  153. package/src/core/logging/proxy.ts +22 -0
  154. package/src/core/logging/redact-match.ts +24 -0
  155. package/src/core/logging/types.ts +47 -0
  156. package/src/core/pipework.ts +566 -0
  157. package/src/core/runtime/broker.ts +69 -0
  158. package/src/core/surface/http.ts +133 -0
  159. package/src/core/surface/index.ts +11 -0
  160. package/src/core/surface/job-timeout.ts +40 -0
  161. package/src/core/surface/namespace.ts +13 -0
  162. package/src/core/surface/script.ts +33 -0
  163. package/src/core/surface/start.ts +142 -0
  164. package/src/core/surface/types.ts +225 -0
  165. package/src/core/surface/validate.ts +88 -0
  166. package/src/core/surface/worker.ts +528 -0
  167. package/src/core/validation/connectivity.ts +49 -0
  168. package/src/core/validation/domain.ts +99 -0
  169. package/src/core/validation/index.ts +5 -0
  170. package/src/core/validation/queue-tables.ts +312 -0
  171. package/src/core/validation/rls-role.ts +138 -0
  172. package/src/core/validation/startup.ts +51 -0
  173. package/src/core/validation/surfaces.ts +65 -0
  174. package/src/core/validation/types.ts +25 -0
  175. package/src/data/db/advisory-lock.ts +55 -0
  176. package/src/data/db/aggregates.ts +172 -0
  177. package/src/data/db/array-elements.ts +111 -0
  178. package/src/data/db/bulk-set.ts +53 -0
  179. package/src/data/db/col/index.ts +14 -0
  180. package/src/data/db/composed.ts +53 -0
  181. package/src/data/db/db.ts +276 -0
  182. package/src/data/db/excluded.ts +16 -0
  183. package/src/data/db/expressions.ts +473 -0
  184. package/src/data/db/filter.ts +90 -0
  185. package/src/data/db/function-source.ts +114 -0
  186. package/src/data/db/identifiers.ts +16 -0
  187. package/src/data/db/idx/index.ts +9 -0
  188. package/src/data/db/in-list.ts +49 -0
  189. package/src/data/db/index.ts +9 -0
  190. package/src/data/db/insert-split.ts +137 -0
  191. package/src/data/db/instrumentation.ts +82 -0
  192. package/src/data/db/maintenance.ts +28 -0
  193. package/src/data/db/namespace.ts +107 -0
  194. package/src/data/db/owner-labels.ts +9 -0
  195. package/src/data/db/pool.ts +187 -0
  196. package/src/data/db/query-label.ts +13 -0
  197. package/src/data/db/query-watch.ts +116 -0
  198. package/src/data/db/raw-client-warning.ts +37 -0
  199. package/src/data/db/readonly.ts +23 -0
  200. package/src/data/db/reservation.ts +151 -0
  201. package/src/data/db/schema-features.ts +14 -0
  202. package/src/data/db/serializable.ts +83 -0
  203. package/src/data/db/sql.ts +1 -0
  204. package/src/data/db/timeouts.ts +76 -0
  205. package/src/data/db/types.ts +18 -0
  206. package/src/data/db/unbound.ts +33 -0
  207. package/src/data/db/values.ts +29 -0
  208. package/src/data/domain/brand.ts +15 -0
  209. package/src/data/domain/build-factory.ts +193 -0
  210. package/src/data/domain/build-schema.ts +161 -0
  211. package/src/data/domain/build-table.ts +355 -0
  212. package/src/data/domain/define.ts +239 -0
  213. package/src/data/domain/external-registry.ts +34 -0
  214. package/src/data/domain/external.ts +77 -0
  215. package/src/data/domain/field.ts +279 -0
  216. package/src/data/domain/index.ts +13 -0
  217. package/src/data/domain/naming.ts +6 -0
  218. package/src/data/domain/projections.ts +57 -0
  219. package/src/data/domain/trace-safe-projection.ts +31 -0
  220. package/src/data/domain/traits.ts +108 -0
  221. package/src/data/domain/types.ts +289 -0
  222. package/src/data/jsonb/composed.ts +18 -0
  223. package/src/data/jsonb/index.ts +1 -0
  224. package/src/data/jsonb/namespace.ts +30 -0
  225. package/src/data/jsonb/query.ts +86 -0
  226. package/src/data/migrate/append-only-generate.ts +47 -0
  227. package/src/data/migrate/applied.ts +47 -0
  228. package/src/data/migrate/apply.ts +309 -0
  229. package/src/data/migrate/check.ts +119 -0
  230. package/src/data/migrate/diff.ts +357 -0
  231. package/src/data/migrate/door-generate.ts +130 -0
  232. package/src/data/migrate/framework-rls.ts +58 -0
  233. package/src/data/migrate/generate.ts +201 -0
  234. package/src/data/migrate/history.ts +215 -0
  235. package/src/data/migrate/index.ts +9 -0
  236. package/src/data/migrate/internal-definitions.ts +175 -0
  237. package/src/data/migrate/post-process.ts +73 -0
  238. package/src/data/migrate/pragma.ts +73 -0
  239. package/src/data/migrate/provision-framework.ts +147 -0
  240. package/src/data/migrate/rls-generate.ts +61 -0
  241. package/src/data/migrate/run.ts +124 -0
  242. package/src/data/migrate/safety.ts +167 -0
  243. package/src/data/migrate/snapshot.ts +368 -0
  244. package/src/data/migrate/sql-emit.ts +392 -0
  245. package/src/data/migrate/statements.ts +312 -0
  246. package/src/data/query/alias.ts +126 -0
  247. package/src/data/query/batch.ts +8 -0
  248. package/src/data/query/cache/core/cache.ts +78 -0
  249. package/src/data/query/cache/core/index.ts +1 -0
  250. package/src/data/query/cache/core/types.ts +29 -0
  251. package/src/data/query/cache/readme.md +230 -0
  252. package/src/data/query/casing.ts +76 -0
  253. package/src/data/query/collation.ts +11 -0
  254. package/src/data/query/column-builder.ts +370 -0
  255. package/src/data/query/column.ts +150 -0
  256. package/src/data/query/entity.ts +42 -0
  257. package/src/data/query/errors.ts +33 -0
  258. package/src/data/query/index.ts +14 -0
  259. package/src/data/query/logger.ts +47 -0
  260. package/src/data/query/operations.ts +45 -0
  261. package/src/data/query/pg-core/alias.ts +12 -0
  262. package/src/data/query/pg-core/checks.ts +32 -0
  263. package/src/data/query/pg-core/columns/all.ts +71 -0
  264. package/src/data/query/pg-core/columns/bigint.ts +110 -0
  265. package/src/data/query/pg-core/columns/bigserial.ts +128 -0
  266. package/src/data/query/pg-core/columns/boolean.ts +43 -0
  267. package/src/data/query/pg-core/columns/char.ts +85 -0
  268. package/src/data/query/pg-core/columns/cidr.ts +43 -0
  269. package/src/data/query/pg-core/columns/common.ts +366 -0
  270. package/src/data/query/pg-core/columns/custom.ts +232 -0
  271. package/src/data/query/pg-core/columns/date.common.ts +15 -0
  272. package/src/data/query/pg-core/columns/date.ts +112 -0
  273. package/src/data/query/pg-core/columns/double-precision.ts +55 -0
  274. package/src/data/query/pg-core/columns/enum.ts +201 -0
  275. package/src/data/query/pg-core/columns/index.ts +35 -0
  276. package/src/data/query/pg-core/columns/inet.ts +43 -0
  277. package/src/data/query/pg-core/columns/int.common.ts +57 -0
  278. package/src/data/query/pg-core/columns/integer.ts +53 -0
  279. package/src/data/query/pg-core/columns/interval.ts +83 -0
  280. package/src/data/query/pg-core/columns/json.ts +58 -0
  281. package/src/data/query/pg-core/columns/jsonb.ts +56 -0
  282. package/src/data/query/pg-core/columns/line.ts +117 -0
  283. package/src/data/query/pg-core/columns/macaddr.ts +43 -0
  284. package/src/data/query/pg-core/columns/macaddr8.ts +43 -0
  285. package/src/data/query/pg-core/columns/numeric.ts +227 -0
  286. package/src/data/query/pg-core/columns/point.ts +127 -0
  287. package/src/data/query/pg-core/columns/postgis_extension/geometry.ts +119 -0
  288. package/src/data/query/pg-core/columns/postgis_extension/utils.ts +47 -0
  289. package/src/data/query/pg-core/columns/real.ts +58 -0
  290. package/src/data/query/pg-core/columns/serial.ts +55 -0
  291. package/src/data/query/pg-core/columns/smallint.ts +53 -0
  292. package/src/data/query/pg-core/columns/smallserial.ts +60 -0
  293. package/src/data/query/pg-core/columns/text.ts +67 -0
  294. package/src/data/query/pg-core/columns/time.ts +72 -0
  295. package/src/data/query/pg-core/columns/timestamp.ts +163 -0
  296. package/src/data/query/pg-core/columns/uuid.ts +51 -0
  297. package/src/data/query/pg-core/columns/varchar.ts +89 -0
  298. package/src/data/query/pg-core/columns/vector_extension/bit.ts +68 -0
  299. package/src/data/query/pg-core/columns/vector_extension/halfvec.ts +80 -0
  300. package/src/data/query/pg-core/columns/vector_extension/sparsevec.ts +67 -0
  301. package/src/data/query/pg-core/columns/vector_extension/vector.ts +80 -0
  302. package/src/data/query/pg-core/db.ts +674 -0
  303. package/src/data/query/pg-core/dialect.ts +1404 -0
  304. package/src/data/query/pg-core/expressions.ts +25 -0
  305. package/src/data/query/pg-core/foreign-keys.ts +130 -0
  306. package/src/data/query/pg-core/index.ts +21 -0
  307. package/src/data/query/pg-core/indexes.ts +276 -0
  308. package/src/data/query/pg-core/policies.ts +56 -0
  309. package/src/data/query/pg-core/primary-keys.ts +62 -0
  310. package/src/data/query/pg-core/query-builders/count.ts +86 -0
  311. package/src/data/query/pg-core/query-builders/delete.ts +293 -0
  312. package/src/data/query/pg-core/query-builders/index.ts +7 -0
  313. package/src/data/query/pg-core/query-builders/insert.ts +452 -0
  314. package/src/data/query/pg-core/query-builders/query-builder.ts +123 -0
  315. package/src/data/query/pg-core/query-builders/query.ts +157 -0
  316. package/src/data/query/pg-core/query-builders/raw.ts +49 -0
  317. package/src/data/query/pg-core/query-builders/refresh-materialized-view.ts +108 -0
  318. package/src/data/query/pg-core/query-builders/select.ts +1346 -0
  319. package/src/data/query/pg-core/query-builders/select.types.ts +437 -0
  320. package/src/data/query/pg-core/query-builders/update.ts +626 -0
  321. package/src/data/query/pg-core/roles.ts +41 -0
  322. package/src/data/query/pg-core/schema.ts +72 -0
  323. package/src/data/query/pg-core/sequence.ts +41 -0
  324. package/src/data/query/pg-core/session.ts +292 -0
  325. package/src/data/query/pg-core/subquery.ts +46 -0
  326. package/src/data/query/pg-core/table.ts +252 -0
  327. package/src/data/query/pg-core/unique-constraint.ts +73 -0
  328. package/src/data/query/pg-core/utils/array.ts +95 -0
  329. package/src/data/query/pg-core/utils/index.ts +1 -0
  330. package/src/data/query/pg-core/utils.ts +104 -0
  331. package/src/data/query/pg-core/view-base.ts +14 -0
  332. package/src/data/query/pg-core/view-common.ts +1 -0
  333. package/src/data/query/pg-core/view.ts +435 -0
  334. package/src/data/query/pg-core/with-builder.ts +41 -0
  335. package/src/data/query/postgres-js/README.md +46 -0
  336. package/src/data/query/postgres-js/array-parser.ts +45 -0
  337. package/src/data/query/postgres-js/driver-error-boundary.ts +149 -0
  338. package/src/data/query/postgres-js/driver.ts +163 -0
  339. package/src/data/query/postgres-js/index.ts +2 -0
  340. package/src/data/query/postgres-js/session.ts +234 -0
  341. package/src/data/query/primary-key.ts +11 -0
  342. package/src/data/query/query-builders/query-builder.ts +19 -0
  343. package/src/data/query/query-builders/select.types.ts +175 -0
  344. package/src/data/query/query-promise.ts +35 -0
  345. package/src/data/query/relations.ts +725 -0
  346. package/src/data/query/runnable-query.ts +12 -0
  347. package/src/data/query/selection-proxy.ts +121 -0
  348. package/src/data/query/session.ts +8 -0
  349. package/src/data/query/sql/expressions/conditions.ts +741 -0
  350. package/src/data/query/sql/expressions/index.ts +2 -0
  351. package/src/data/query/sql/expressions/select.ts +45 -0
  352. package/src/data/query/sql/functions/aggregate.ts +129 -0
  353. package/src/data/query/sql/functions/index.ts +2 -0
  354. package/src/data/query/sql/functions/vector.ts +178 -0
  355. package/src/data/query/sql/index.ts +3 -0
  356. package/src/data/query/sql/sql.ts +794 -0
  357. package/src/data/query/subquery.ts +53 -0
  358. package/src/data/query/table.ts +208 -0
  359. package/src/data/query/table.utils.ts +2 -0
  360. package/src/data/query/tracing-utils.ts +3 -0
  361. package/src/data/query/tracing.ts +11 -0
  362. package/src/data/query/utils.ts +357 -0
  363. package/src/data/query/version.ts +4 -0
  364. package/src/data/query/view-common.ts +1 -0
  365. package/src/data/schema/branded.ts +13 -0
  366. package/src/data/schema/generated/coerce.ts +5 -0
  367. package/src/data/schema/generated/combinator.ts +6 -0
  368. package/src/data/schema/generated/encoding.ts +5 -0
  369. package/src/data/schema/generated/error.ts +6 -0
  370. package/src/data/schema/generated/format.ts +5 -0
  371. package/src/data/schema/generated/type-constructor.ts +10 -0
  372. package/src/data/schema/generated/type.ts +6 -0
  373. package/src/data/schema/index.ts +6 -0
  374. package/src/data/schema/json-schema.ts +33 -0
  375. package/src/data/schema/namespace.ts +55 -0
  376. package/src/data/schema/parse.ts +39 -0
  377. package/src/data/schema/types.ts +39 -0
  378. package/src/data/temporal/append-only.ts +134 -0
  379. package/src/data/temporal/close.ts +27 -0
  380. package/src/data/temporal/columns.ts +10 -0
  381. package/src/data/temporal/definition-queries.ts +70 -0
  382. package/src/data/temporal/errors.ts +10 -0
  383. package/src/data/temporal/get-current.ts +22 -0
  384. package/src/data/temporal/index.ts +9 -0
  385. package/src/data/temporal/namespace.ts +36 -0
  386. package/src/data/temporal/query.ts +25 -0
  387. package/src/data/temporal/resolve.ts +17 -0
  388. package/src/data/temporal/revise.ts +67 -0
  389. package/src/data/temporal/types.ts +22 -0
  390. package/src/data/valve/artifact.ts +33 -0
  391. package/src/data/valve/contract-diff.ts +21 -0
  392. package/src/data/valve/cross.ts +57 -0
  393. package/src/data/valve/crossing-ledger.ts +50 -0
  394. package/src/data/valve/decision.ts +44 -0
  395. package/src/data/valve/durable-crossing.ts +52 -0
  396. package/src/data/valve/execute-crossing.ts +77 -0
  397. package/src/data/valve/faucet.ts +56 -0
  398. package/src/data/valve/gate.ts +114 -0
  399. package/src/data/valve/graph.ts +77 -0
  400. package/src/data/valve/index.ts +53 -0
  401. package/src/data/valve/namespace.ts +57 -0
  402. package/src/data/valve/registry.ts +50 -0
  403. package/src/data/valve/schema/valve-crossing-fields.ts +23 -0
  404. package/src/data/valve/schema/valve-crossing.ts +9 -0
  405. package/src/data/valve/supply.ts +154 -0
  406. package/src/data/valve/types.ts +143 -0
  407. package/src/data/vector/columns.ts +27 -0
  408. package/src/data/vector/index.ts +4 -0
  409. package/src/data/vector/namespace.ts +33 -0
  410. package/src/data/vector/query.ts +85 -0
  411. package/src/data/vector/validate.ts +16 -0
  412. package/src/data/write/audit/actor.ts +15 -0
  413. package/src/data/write/audit/audit-columns.ts +18 -0
  414. package/src/data/write/audit/audit-select.ts +111 -0
  415. package/src/data/write/audit/bound-transaction.ts +14 -0
  416. package/src/data/write/audit/cte-compile.ts +32 -0
  417. package/src/data/write/audit/decode-returning.ts +47 -0
  418. package/src/data/write/audit/final-select.ts +43 -0
  419. package/src/data/write/audit/infra-audit.ts +36 -0
  420. package/src/data/write/audit/primary-key.ts +65 -0
  421. package/src/data/write/audit/projection.ts +41 -0
  422. package/src/data/write/audit/read-touches.ts +86 -0
  423. package/src/data/write/audit/touch-match.ts +78 -0
  424. package/src/data/write/audit/verb-delete.ts +62 -0
  425. package/src/data/write/audit/verb-insert.ts +36 -0
  426. package/src/data/write/audit/verb-select.ts +47 -0
  427. package/src/data/write/audit/verb-update.ts +60 -0
  428. package/src/data/write/audit/verb-upsert.ts +104 -0
  429. package/src/data/write/conflict.ts +43 -0
  430. package/src/data/write/delete.ts +38 -0
  431. package/src/data/write/execute.ts +243 -0
  432. package/src/data/write/index.ts +11 -0
  433. package/src/data/write/insert.ts +63 -0
  434. package/src/data/write/state.ts +43 -0
  435. package/src/data/write/update.ts +54 -0
  436. package/src/data/write/upsert.ts +58 -0
  437. package/src/data/write/values.ts +19 -0
  438. package/src/index.ts +230 -0
  439. package/src/infra/access-links/code.ts +70 -0
  440. package/src/infra/access-links/handle.ts +892 -0
  441. package/src/infra/access-links/index.ts +9 -0
  442. package/src/infra/access-links/namespace.ts +30 -0
  443. package/src/infra/access-links/person-check.ts +177 -0
  444. package/src/infra/access-links/schema.ts +71 -0
  445. package/src/infra/alerts/async-sources.ts +231 -0
  446. package/src/infra/alerts/audit.ts +36 -0
  447. package/src/infra/alerts/beat.ts +123 -0
  448. package/src/infra/alerts/client-faults.ts +111 -0
  449. package/src/infra/alerts/faults.ts +156 -0
  450. package/src/infra/alerts/handle.ts +778 -0
  451. package/src/infra/alerts/http.ts +192 -0
  452. package/src/infra/alerts/index.ts +12 -0
  453. package/src/infra/alerts/infra-sources.ts +180 -0
  454. package/src/infra/alerts/namespace.ts +81 -0
  455. package/src/infra/alerts/redact.ts +21 -0
  456. package/src/infra/alerts/request-faults.ts +41 -0
  457. package/src/infra/alerts/schema.ts +124 -0
  458. package/src/infra/alerts/sinks.ts +125 -0
  459. package/src/infra/alerts/source-options.ts +26 -0
  460. package/src/infra/alerts/sources.ts +503 -0
  461. package/src/infra/alerts/subsystem-sources.ts +137 -0
  462. package/src/infra/audit/emit.ts +87 -0
  463. package/src/infra/audit/index.ts +2 -0
  464. package/src/infra/audit/namespace.ts +22 -0
  465. package/src/infra/audit/schema.sql +35 -0
  466. package/src/infra/audit/types.ts +18 -0
  467. package/src/infra/aws/credentials.ts +147 -0
  468. package/src/infra/aws/sigv4.ts +140 -0
  469. package/src/infra/cache/create.ts +58 -0
  470. package/src/infra/cache/entry.ts +81 -0
  471. package/src/infra/cache/index.ts +4 -0
  472. package/src/infra/cache/namespace.ts +10 -0
  473. package/src/infra/cache/tenant.ts +93 -0
  474. package/src/infra/cache/types.ts +24 -0
  475. package/src/infra/crawl/audit.ts +35 -0
  476. package/src/infra/crawl/errors.ts +25 -0
  477. package/src/infra/crawl/handle.ts +693 -0
  478. package/src/infra/crawl/index.ts +9 -0
  479. package/src/infra/crawl/links.ts +160 -0
  480. package/src/infra/crawl/namespace.ts +36 -0
  481. package/src/infra/crawl/robots.ts +100 -0
  482. package/src/infra/crawl/schema.ts +89 -0
  483. package/src/infra/credit-line/handle.ts +883 -0
  484. package/src/infra/credit-line/index.ts +6 -0
  485. package/src/infra/credit-line/namespace.ts +7 -0
  486. package/src/infra/credit-line/schema.ts +96 -0
  487. package/src/infra/credits/handle.ts +706 -0
  488. package/src/infra/credits/index.ts +5 -0
  489. package/src/infra/credits/namespace.ts +7 -0
  490. package/src/infra/credits/schema.ts +83 -0
  491. package/src/infra/email/audit.ts +36 -0
  492. package/src/infra/email/inbound.ts +622 -0
  493. package/src/infra/email/index.ts +11 -0
  494. package/src/infra/email/mail.ts +517 -0
  495. package/src/infra/email/mime.ts +447 -0
  496. package/src/infra/email/namespace.ts +22 -0
  497. package/src/infra/email/providers.ts +111 -0
  498. package/src/infra/email/schema.ts +96 -0
  499. package/src/infra/email/sns.ts +200 -0
  500. package/src/infra/email/unsubscribe.ts +44 -0
  501. package/src/infra/fetch/address.ts +88 -0
  502. package/src/infra/fetch/connect-retry.ts +87 -0
  503. package/src/infra/fetch/handle.ts +329 -0
  504. package/src/infra/fetch/index.ts +7 -0
  505. package/src/infra/fetch/namespace.ts +70 -0
  506. package/src/infra/idempotency/index.ts +3 -0
  507. package/src/infra/idempotency/middleware.ts +87 -0
  508. package/src/infra/idempotency/store.ts +92 -0
  509. package/src/infra/idempotency/types.ts +30 -0
  510. package/src/infra/join-requests/handle.ts +312 -0
  511. package/src/infra/join-requests/index.ts +2 -0
  512. package/src/infra/join-requests/namespace.ts +7 -0
  513. package/src/infra/join-requests/schema.ts +33 -0
  514. package/src/infra/outbox/core.ts +165 -0
  515. package/src/infra/quota/errors.ts +32 -0
  516. package/src/infra/quota/handle.ts +215 -0
  517. package/src/infra/quota/index.ts +5 -0
  518. package/src/infra/quota/namespace.ts +7 -0
  519. package/src/infra/quota/schema.ts +15 -0
  520. package/src/infra/storage/backend.ts +34 -0
  521. package/src/infra/storage/handle.ts +513 -0
  522. package/src/infra/storage/index.ts +9 -0
  523. package/src/infra/storage/local.ts +104 -0
  524. package/src/infra/storage/namespace.ts +13 -0
  525. package/src/infra/storage/s3.ts +257 -0
  526. package/src/infra/storage/schema.ts +24 -0
  527. package/src/infra/support/handle.ts +854 -0
  528. package/src/infra/support/http.ts +229 -0
  529. package/src/infra/support/index.ts +7 -0
  530. package/src/infra/support/namespace.ts +12 -0
  531. package/src/infra/support/schema.ts +96 -0
  532. package/src/infra/webhook/inbound.ts +45 -0
  533. package/src/infra/webhook/index.ts +5 -0
  534. package/src/infra/webhook/namespace.ts +24 -0
  535. package/src/infra/webhook/outbound.ts +315 -0
  536. package/src/infra/webhook/sign.ts +32 -0
  537. package/src/infra/webhook/verify.ts +82 -0
  538. package/src/invariants/assert.ts +26 -0
  539. package/src/invariants/index.ts +1 -0
  540. package/src/lint/config.ts +56 -0
  541. package/src/lint/doctrine.ts +163 -0
  542. package/src/lint/include.ts +97 -0
  543. package/src/lint/index.ts +3 -0
  544. package/src/lint/preset.ts +10 -0
  545. package/src/lint/resolver.ts +218 -0
  546. package/src/lint/rules/no-reexports.ts +46 -0
  547. package/src/request/behavior/audited.ts +85 -0
  548. package/src/request/behavior/cached.ts +62 -0
  549. package/src/request/behavior/compose.ts +28 -0
  550. package/src/request/behavior/index.ts +5 -0
  551. package/src/request/behavior/namespace.ts +16 -0
  552. package/src/request/behavior/types.ts +26 -0
  553. package/src/request/behavior/versioned.ts +54 -0
  554. package/src/request/context/create.ts +103 -0
  555. package/src/request/context/guard.ts +49 -0
  556. package/src/request/context/index.ts +4 -0
  557. package/src/request/context/run-in-transaction.ts +200 -0
  558. package/src/request/context/store.ts +28 -0
  559. package/src/request/context/types.ts +50 -0
  560. package/src/request/di/builder.ts +535 -0
  561. package/src/request/di/index.ts +8 -0
  562. package/src/request/di/resolve.ts +271 -0
  563. package/src/request/di/types.ts +262 -0
  564. package/src/request/fitting/namespace.ts +7 -0
  565. package/src/request/fixture/batch.ts +71 -0
  566. package/src/request/fixture/builder.ts +26 -0
  567. package/src/request/fixture/errors.ts +10 -0
  568. package/src/request/fixture/index.ts +8 -0
  569. package/src/request/fixture/namespace.ts +23 -0
  570. package/src/request/fixture/paginate.ts +44 -0
  571. package/src/request/fixture/to-handlers.ts +260 -0
  572. package/src/request/fixture/types.ts +79 -0
  573. package/src/request/flow/act-as.ts +78 -0
  574. package/src/request/flow/namespace.ts +17 -0
  575. package/src/request/http/error-step.ts +42 -0
  576. package/src/request/http/file.ts +141 -0
  577. package/src/request/http/index.ts +4 -0
  578. package/src/request/http/middleware.ts +141 -0
  579. package/src/request/http/namespace.ts +5 -0
  580. package/src/request/http/rate-limit-classes.ts +170 -0
  581. package/src/request/http/response.ts +82 -0
  582. package/src/request/http/server.ts +916 -0
  583. package/src/request/http/sniff.ts +261 -0
  584. package/src/request/http/types.ts +250 -0
  585. package/src/request/http/upload.ts +284 -0
  586. package/src/request/internal/text.ts +6 -0
  587. package/src/request/openapi/generate.ts +205 -0
  588. package/src/request/openapi/index.ts +2 -0
  589. package/src/request/openapi/namespace.ts +7 -0
  590. package/src/test/auth.ts +13 -0
  591. package/src/test/auto-setup.ts +45 -0
  592. package/src/test/context.ts +91 -0
  593. package/src/test/crawl-fixture.ts +157 -0
  594. package/src/test/discover-fork.ts +17 -0
  595. package/src/test/fingerprint.ts +135 -0
  596. package/src/test/globals.d.ts +7 -0
  597. package/src/test/index.ts +19 -0
  598. package/src/test/namespace.ts +87 -0
  599. package/src/test/plugin.ts +189 -0
  600. package/src/test/progress.ts +185 -0
  601. package/src/test/reap-after-run.ts +28 -0
  602. package/src/test/reap.ts +286 -0
  603. package/src/test/reset.ts +253 -0
  604. package/src/test/savepoints.ts +172 -0
  605. package/src/test/setup.ts +1422 -0
  606. package/src/test/system-channel.ts +50 -0
  607. package/src/test/vitest-plugin.ts +142 -0
  608. package/src/test/vitest-workspace.ts +507 -0
  609. package/src/test/vitest.ts +333 -0
  610. package/src/test/watch.ts +105 -0
  611. package/src/trace/capture/bounded-serializer.ts +146 -0
  612. package/src/trace/cardinality/analyze.ts +173 -0
  613. package/src/trace/cardinality/branch-context.ts +214 -0
  614. package/src/trace/cardinality/check.ts +33 -0
  615. package/src/trace/cardinality/classify-edge.ts +64 -0
  616. package/src/trace/cardinality/structural-max.ts +107 -0
  617. package/src/trace/check/coverage-check.ts +188 -0
  618. package/src/trace/check/flow-check.ts +103 -0
  619. package/src/trace/check/flow-step-site.ts +234 -0
  620. package/src/trace/check/io-pattern.ts +116 -0
  621. package/src/trace/codemod/add-cardinality.ts +152 -0
  622. package/src/trace/codemod/run.ts +80 -0
  623. package/src/trace/entry/child-trace.ts +21 -0
  624. package/src/trace/entry/close-trace.ts +87 -0
  625. package/src/trace/entry/finalize-trace.ts +28 -0
  626. package/src/trace/entry/open-trace.ts +138 -0
  627. package/src/trace/entry/parent-trace.ts +20 -0
  628. package/src/trace/entry/parse-traceparent.ts +39 -0
  629. package/src/trace/entry/process-start.ts +38 -0
  630. package/src/trace/entry/trace-context.ts +26 -0
  631. package/src/trace/entry/tracing-enabled.ts +10 -0
  632. package/src/trace/external/record.ts +195 -0
  633. package/src/trace/external/report.ts +66 -0
  634. package/src/trace/namespace.ts +19 -0
  635. package/src/trace/partition/day.ts +47 -0
  636. package/src/trace/partition/index.ts +14 -0
  637. package/src/trace/partition/partition-name.ts +23 -0
  638. package/src/trace/partition/plan.ts +82 -0
  639. package/src/trace/partition/schedule.ts +26 -0
  640. package/src/trace/partition/startup-hook.ts +39 -0
  641. package/src/trace/partition/sync.ts +154 -0
  642. package/src/trace/partition/tables.ts +53 -0
  643. package/src/trace/read/tree.ts +83 -0
  644. package/src/trace/retain/copy-on-error.ts +76 -0
  645. package/src/trace/runtime/expire-stale-traces.ts +54 -0
  646. package/src/trace/runtime/flow-step.ts +147 -0
  647. package/src/trace/runtime/flush-steps.ts +31 -0
  648. package/src/trace/runtime/pending-writes.ts +54 -0
  649. package/src/trace/runtime/step-buffer.ts +298 -0
  650. package/src/trace/runtime/step-error.ts +21 -0
  651. package/src/trace/runtime/step-meta.ts +55 -0
  652. package/src/trace/runtime/thenable.ts +12 -0
  653. package/src/trace/runtime/truncate-trace.ts +62 -0
  654. package/src/trace/schema/trace-fields.ts +52 -0
  655. package/src/trace/schema/trace-retained.ts +22 -0
  656. package/src/trace/schema/trace-step-fields.ts +44 -0
  657. package/src/trace/schema/trace-step-retained.ts +25 -0
  658. package/src/trace/schema/trace-step.ts +18 -0
  659. package/src/trace/schema/trace.ts +12 -0
  660. package/src/trace/transformer/apply.ts +79 -0
  661. package/src/trace/transformer/build-meta-literal.ts +30 -0
  662. package/src/trace/transformer/find-flow-step-sites.ts +85 -0
  663. package/src/trace/transformer/inject-flow-step-import.ts +39 -0
  664. package/src/trace/transformer/transform-error.ts +14 -0
  665. package/src/trace/transformer/transform-flow-steps.ts +123 -0
  666. package/src/trace/transformer/wrap-function-declaration.ts +62 -0
  667. package/src/trace/transformer/wrap-variable-declaration.ts +67 -0
  668. package/src/workspace/affected.ts +110 -0
  669. package/src/workspace/changed-files.ts +163 -0
  670. package/src/workspace/check-deps.ts +213 -0
  671. package/src/workspace/checksum.ts +20 -0
  672. package/src/workspace/dependency-graph.ts +67 -0
  673. package/src/workspace/detect-pipework-copies.ts +93 -0
  674. package/src/workspace/discover.ts +206 -0
  675. package/src/workspace/generate.ts +401 -0
  676. package/src/workspace/index.ts +7 -0
  677. package/src/workspace/module-imports-pipework.ts +39 -0
  678. package/src/workspace/module-package-name.ts +12 -0
  679. package/src/workspace/scrub-git-env.ts +23 -0
  680. package/src/workspace/source-paths.ts +36 -0
  681. package/src/workspace/sync.ts +182 -0
  682. package/dist/REFERENCE.md +0 -1477
  683. package/dist/infra/access-links/rate-limit.d.ts +0 -10
  684. package/dist/infra/access-links/rate-limit.d.ts.map +0 -1
  685. package/dist/infra/access-links/rate-limit.js +0 -28
  686. package/dist/infra/access-links/rate-limit.js.map +0 -1
  687. package/dist/infra/email/sigv4.d.ts +0 -24
  688. package/dist/infra/email/sigv4.d.ts.map +0 -1
  689. package/dist/infra/email/sigv4.js +0 -55
  690. package/dist/infra/email/sigv4.js.map +0 -1
@@ -0,0 +1,47 @@
1
+ import { sql } from '../query/index.js'
2
+ import type { DB } from '../db/index.js'
3
+ import { quoteIdentifier } from '../db/identifiers.js'
4
+
5
+ /**
6
+ * What the tracker table says has been applied, in whichever vocabulary the
7
+ * table currently speaks:
8
+ *
9
+ * - `tags`: the upgraded shape — applied = the exact set of recorded migration
10
+ * tags (see `applyMigrations`, which owns the membership semantics and the
11
+ * legacy-table upgrade).
12
+ * - `legacy-threshold`: a not-yet-upgraded table (no `tag` column) can only
13
+ * express the old high-water mark, `max(created_at)`. It is read for exactly
14
+ * one purpose: scoping the pre-apply SAFETY check to pending migrations, so
15
+ * a fully-current database with a destructive op in its applied history can
16
+ * still run a clean no-op `migrate`. `applyMigrations` upgrades the table on
17
+ * its next run, after which this variant never appears again.
18
+ *
19
+ * `null` — the table does not exist; nothing has been applied.
20
+ */
21
+ export type AppliedState =
22
+ | { kind: 'tags'; tags: ReadonlySet<string> }
23
+ | { kind: 'legacy-threshold'; threshold: number }
24
+
25
+ export async function readAppliedState(db: DB, migrationsTable: string): Promise<AppliedState | null> {
26
+ const quoted = quoteIdentifier(migrationsTable, 'migration table')
27
+
28
+ const [reg] = await db.execute(sql`SELECT to_regclass(${quoted}) AS reg`)
29
+ if (reg === undefined || reg['reg'] === null) return null
30
+
31
+ const [tagColumn] = await db.execute(
32
+ sql`SELECT 1 AS present FROM pg_attribute
33
+ WHERE attrelid = to_regclass(${quoted}) AND attname = 'tag' AND NOT attisdropped`,
34
+ )
35
+
36
+ if (tagColumn === undefined) {
37
+ const [row] = await db.execute(sql.raw(`SELECT max(created_at) AS last_applied FROM ${quoted}`))
38
+ const lastApplied = row?.['last_applied']
39
+ return {
40
+ kind: 'legacy-threshold',
41
+ threshold: lastApplied === null || lastApplied === undefined ? -1 : Number(lastApplied),
42
+ }
43
+ }
44
+
45
+ const rows = await db.execute(sql.raw(`SELECT tag FROM ${quoted} WHERE tag IS NOT NULL`))
46
+ return { kind: 'tags', tags: new Set(rows.map((row) => String(row['tag']))) }
47
+ }
@@ -0,0 +1,309 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { createHash } from 'node:crypto'
3
+ import postgres from 'postgres'
4
+ import { scanStatements } from './statements.js'
5
+ import { stripPragmaLines } from './pragma.js'
6
+ import { listMigrations } from './history.js'
7
+
8
+ const NO_TRANSACTION_PRAGMA = '-- pipework:no-transaction'
9
+
10
+ export interface ApplyOptions {
11
+ migrationsFolder: string
12
+ migrationsTable: string
13
+ connectionUrl: string
14
+ stripConcurrently?: boolean
15
+ /**
16
+ * Rewrite `CREATE TABLE` to `CREATE UNLOGGED TABLE`. A test database is
17
+ * dropped or rolled back and never needs crash durability, so skipping the
18
+ * WAL for its tables is free speed with no semantic change. Issue #325.
19
+ */
20
+ unloggedTables?: boolean
21
+ /**
22
+ * Called after each migration file is applied and tracked. Replaying a stack
23
+ * is the longest single step of test setup; without this it is one silent
24
+ * await and a caller watching for progress sees none. Issue #380.
25
+ */
26
+ onMigration?: (tag: string, index: number, total: number) => void
27
+ /**
28
+ * Called after each statement of a migration file lands (inside the file's
29
+ * transaction, when it has one), with the 1-based statement and the file's
30
+ * statement count, then the 1-based position of the file among those being
31
+ * applied and their count. A long file is otherwise silent until it commits.
32
+ * Issue #871.
33
+ */
34
+ onStatement?: (tag: string, statement: number, statements: number, index: number, total: number) => void
35
+ /**
36
+ * Called as each step before the first file finishes (tracker table, legacy
37
+ * tag recovery per file, the unique index, the applied read), with a detail
38
+ * naming it. Issue #871.
39
+ */
40
+ onPrepare?: (detail: string) => void
41
+ /**
42
+ * Called when a no-transaction migration resumes a half-applied file, with
43
+ * the statement it starts from (1-based) and how many the file holds.
44
+ * Issue #378.
45
+ */
46
+ onResume?: (tag: string, fromStatement: number, total: number) => void
47
+ }
48
+
49
+ export interface Migration {
50
+ tag: string
51
+ hash: string
52
+ /** Hash of the file with `expect-*` pragma lines removed; also accepted as the recorded one. */
53
+ pragmaFreeHash?: string
54
+ folderMillis: number
55
+ statements: string[]
56
+ noTransaction: boolean
57
+ }
58
+
59
+ export async function applyMigrations(options: ApplyOptions): Promise<number> {
60
+ const migrations = readMigrations(options)
61
+ if (migrations.length === 0) return 0
62
+
63
+ const client = postgres(options.connectionUrl, { max: 1, onnotice: () => {} })
64
+
65
+ try {
66
+ const table = quoteIdent(options.migrationsTable)
67
+ const prepared = (detail: string): void => options.onPrepare?.(detail)
68
+
69
+ // "Applied" is MEMBERSHIP — this exact migration (by tag, verified by
70
+ // content hash) has a tracker row — never a timestamp high-water mark.
71
+ // A threshold silently skips any unapplied migration dated earlier than
72
+ // the newest applied one: a branch merged late, or a second manifold
73
+ // sharing this tracker table whose whole journal predates the first
74
+ // manifold's newest entry (a real production incident for both).
75
+ await client.unsafe(`
76
+ CREATE TABLE IF NOT EXISTS ${table} (
77
+ id SERIAL PRIMARY KEY,
78
+ hash text NOT NULL,
79
+ created_at bigint,
80
+ tag text
81
+ )
82
+ `)
83
+ prepared('tracker table')
84
+ // Deployed databases predate the tag column: add it, then recover each
85
+ // legacy row's identity by matching its recorded content hash against the
86
+ // journal's files (min(id) claims one row per tag, so a duplicated hash
87
+ // can't double-claim). Rows matching no current journal entry keep a NULL
88
+ // tag and never participate in membership.
89
+ await client.unsafe(`ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS tag text`)
90
+ for (const [i, migration] of migrations.entries()) {
91
+ await client.unsafe(
92
+ `UPDATE ${table} SET tag = $1
93
+ WHERE id = (SELECT min(id) FROM ${table} WHERE hash = $2 AND tag IS NULL)`,
94
+ [migration.tag, migration.hash],
95
+ )
96
+ prepared(`tags ${i + 1}/${migrations.length}`)
97
+ }
98
+ await client.unsafe(
99
+ `CREATE UNIQUE INDEX IF NOT EXISTS ${quoteIdent(`${options.migrationsTable}_tag_key`)} ON ${table} (tag)`,
100
+ )
101
+ prepared('tag index')
102
+
103
+ const rows = await client.unsafe<{ tag: string | null; hash: string }[]>(
104
+ `SELECT tag, hash FROM ${table} WHERE tag IS NOT NULL`,
105
+ )
106
+ const appliedHashByTag = new Map(rows.map((row) => [row.tag!, row.hash]))
107
+ prepared('applied read')
108
+
109
+ // A no-transaction file has no rollback: interrupted between statements it
110
+ // leaves the database half-changed with no tracker row, and the rerun
111
+ // replays from the top and dies on the first already-applied statement.
112
+ // Nor can the file be edited to add guards — its content is immutable
113
+ // history. So each statement's completion is recorded as it lands, and a
114
+ // rerun starts from the first one not recorded. The table exists only for
115
+ // databases that actually have a no-transaction migration. Issue #378.
116
+ const progress = quoteIdent(progressTableName(options.migrationsTable))
117
+ const hasNoTransaction = migrations.some((migration) => migration.noTransaction)
118
+ const progressByTag = new Map<string, { hash: string; done: number }>()
119
+ if (hasNoTransaction) {
120
+ await client.unsafe(`
121
+ CREATE TABLE IF NOT EXISTS ${progress} (
122
+ tag text PRIMARY KEY,
123
+ hash text NOT NULL,
124
+ statements_done integer NOT NULL,
125
+ updated_at timestamptz NOT NULL DEFAULT now()
126
+ )
127
+ `)
128
+ const partial = await client.unsafe<{ tag: string; hash: string; statements_done: number }[]>(
129
+ `SELECT tag, hash, statements_done FROM ${progress}`,
130
+ )
131
+ for (const row of partial) {
132
+ progressByTag.set(row.tag, { hash: row.hash, done: row.statements_done })
133
+ }
134
+ prepared('progress table')
135
+ }
136
+
137
+ let applied = 0
138
+
139
+ for (const migration of migrations) {
140
+ const appliedHash = appliedHashByTag.get(migration.tag)
141
+ if (appliedHash !== undefined) {
142
+ if (!hashMatches(appliedHash, migration)) {
143
+ throw new Error(
144
+ `Migration "${migration.tag}" is recorded as applied in ${options.migrationsTable}, but its ` +
145
+ `file content has changed (recorded sha256 ${appliedHash.slice(0, 12)}…, file is now ` +
146
+ `${migration.hash.slice(0, 12)}…). Applied migrations are immutable history — put schema ` +
147
+ `changes in a NEW migration (\`pipework generate\`) instead of editing an applied one (adding "-- pipework:expect-*" lines is allowed). If two ` +
148
+ `manifolds share this database and both declare a migration tagged "${migration.tag}", that is ` +
149
+ `a schema-level collision no tracker can reconcile — give them separate databases or distinct ` +
150
+ `migrationTable names.`,
151
+ )
152
+ }
153
+ continue
154
+ }
155
+
156
+ if (migration.noTransaction) {
157
+ const from = resumePoint(migration, progressByTag.get(migration.tag), options.migrationsTable)
158
+ if (from > 0) options.onResume?.(migration.tag, from + 1, migration.statements.length)
159
+
160
+ for (let i = from; i < migration.statements.length; i++) {
161
+ await client.unsafe(migration.statements[i]!)
162
+ // Recorded AFTER the statement it describes: marking first would let
163
+ // a death between the mark and the statement skip work silently,
164
+ // which is worse than replaying one statement. The window that
165
+ // remains is exactly one statement wide — the one whose mark had not
166
+ // landed yet — instead of the whole file.
167
+ await client.unsafe(
168
+ `INSERT INTO ${progress} (tag, hash, statements_done) VALUES ($1, $2, $3)
169
+ ON CONFLICT (tag) DO UPDATE SET statements_done = EXCLUDED.statements_done, updated_at = now()`,
170
+ [migration.tag, migration.hash, i + 1],
171
+ )
172
+ options.onStatement?.(migration.tag, i + 1, migration.statements.length, applied + 1, migrations.length)
173
+ }
174
+ await client.unsafe(
175
+ `INSERT INTO ${table} ("hash", "created_at", "tag") VALUES ($1, $2, $3)`,
176
+ [migration.hash, migration.folderMillis, migration.tag],
177
+ )
178
+ await client.unsafe(`DELETE FROM ${progress} WHERE tag = $1`, [migration.tag])
179
+ } else {
180
+ await client.begin(async (tx) => {
181
+ for (const [i, stmt] of migration.statements.entries()) {
182
+ await tx.unsafe(stmt)
183
+ options.onStatement?.(migration.tag, i + 1, migration.statements.length, applied + 1, migrations.length)
184
+ }
185
+ await tx.unsafe(
186
+ `INSERT INTO ${table} ("hash", "created_at", "tag") VALUES ($1, $2, $3)`,
187
+ [migration.hash, migration.folderMillis, migration.tag],
188
+ )
189
+ })
190
+ }
191
+
192
+ applied++
193
+ options.onMigration?.(migration.tag, applied, migrations.length)
194
+ }
195
+
196
+ return applied
197
+ } finally {
198
+ await client.end()
199
+ }
200
+ }
201
+
202
+ export function readMigrations(options: ApplyOptions): Migration[] {
203
+ const migrations: Migration[] = []
204
+
205
+ for (const entry of listMigrations(options.migrationsFolder)) {
206
+ const filePath = `${options.migrationsFolder}/${entry.tag}.sql`
207
+ let raw = readFileSync(filePath, 'utf-8')
208
+ const noTransaction = raw.includes(NO_TRANSACTION_PRAGMA)
209
+
210
+ if (options.stripConcurrently === true) {
211
+ raw = raw.replace(/\bCONCURRENTLY\s+/gi, '')
212
+ }
213
+
214
+ if (options.unloggedTables === true) {
215
+ raw = makeTablesUnlogged(raw)
216
+ }
217
+
218
+ const statements = parseStatements(raw)
219
+
220
+ const fileText = readFileSync(filePath, 'utf-8')
221
+ migrations.push({
222
+ tag: entry.tag,
223
+ hash: sha256(fileText),
224
+ pragmaFreeHash: sha256(stripPragmaLines(fileText)),
225
+ folderMillis: entry.when,
226
+ statements,
227
+ noTransaction,
228
+ })
229
+ }
230
+
231
+ return migrations
232
+ }
233
+
234
+ function sha256(text: string): string {
235
+ return createHash('sha256').update(text).digest('hex')
236
+ }
237
+
238
+ /**
239
+ * True when a recorded hash is this migration's: the raw file hash, or the
240
+ * hash with `expect-*` pragma lines removed (those lines may be added to an
241
+ * applied file; nothing else may change).
242
+ */
243
+ function hashMatches(recorded: string, migration: Migration): boolean {
244
+ return recorded === migration.hash || recorded === migration.pragmaFreeHash
245
+ }
246
+
247
+ /**
248
+ * Split migration SQL into individual statements, honoring drizzle's
249
+ * `--> statement-breakpoint` as an explicit separator.
250
+ *
251
+ * The scanning rules live in `statements.ts`, shared with the safety gate so
252
+ * the runner and the gate cannot disagree about where a statement begins —
253
+ * they did, and the gate was the one that was wrong (#334).
254
+ */
255
+ export function parseStatements(raw: string): string[] {
256
+ return scanStatements(raw, { breakpointSeparator: true })
257
+ }
258
+
259
+ /** Companion to the tracker table, holding half-applied no-transaction files. */
260
+ export function progressTableName(migrationsTable: string): string {
261
+ return `${migrationsTable}_progress`
262
+ }
263
+
264
+ /**
265
+ * The statement index a half-applied no-transaction file resumes from. Zero
266
+ * when there is no record of one.
267
+ *
268
+ * A recorded partial whose hash no longer matches the file is refused rather
269
+ * than resumed: the mark counts statements in the file as it was, and the file
270
+ * on disk is now a different one, so no index into it means anything.
271
+ */
272
+ export function resumePoint(
273
+ migration: Migration,
274
+ recorded: { hash: string; done: number } | undefined,
275
+ migrationsTable: string,
276
+ ): number {
277
+ if (recorded === undefined) return 0
278
+ if (!hashMatches(recorded.hash, migration)) {
279
+ throw new Error(
280
+ `Migration "${migration.tag}" is half applied — ${recorded.done} of its statements ran before the ` +
281
+ `runner stopped, recorded in ${progressTableName(migrationsTable)} — and its file content has ` +
282
+ `changed since (recorded sha256 ${recorded.hash.slice(0, 12)}…, file is now ` +
283
+ `${migration.hash.slice(0, 12)}…). The recorded count indexes into the file as it was, so it ` +
284
+ `cannot be carried into the new one. Restore the file to the content that was running, let the ` +
285
+ `resume finish, and put the change in a NEW migration; or, if the half-applied statements have ` +
286
+ `been undone by hand, delete the "${migration.tag}" row from ` +
287
+ `${progressTableName(migrationsTable)} to start the file over.`,
288
+ )
289
+ }
290
+ // A count past the end means every statement landed and only the tracker row
291
+ // was missed: nothing left to run, and the caller writes the row.
292
+ return Math.min(recorded.done, migration.statements.length)
293
+ }
294
+
295
+ function quoteIdent(name: string): string {
296
+ return `"${name.replace(/"/g, '""')}"`
297
+ }
298
+
299
+ /**
300
+ * Rewrite every `CREATE TABLE` (including the `IF NOT EXISTS` form) to
301
+ * `CREATE UNLOGGED TABLE`. Used only when applying schema to a test database —
302
+ * a test database is dropped or rolled back, so the WAL its tables would
303
+ * generate is pure overhead. `CREATE UNLOGGED TABLE` is otherwise identical
304
+ * SQL: same columns, constraints, RLS, isolation. `TEMPORARY` and
305
+ * already-`UNLOGGED` tables are left alone. Issue #325.
306
+ */
307
+ export function makeTablesUnlogged(sql: string): string {
308
+ return sql.replace(/\bCREATE\s+TABLE\b/gi, 'CREATE UNLOGGED TABLE')
309
+ }
@@ -0,0 +1,119 @@
1
+ import { readFileSync, existsSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+ import { analyzeSQL, formatHazards, type MigrationHazard, type Severity } from './safety.js'
4
+ import { hasPragma, PRAGMA_FOR, type PragmaKind } from './pragma.js'
5
+ import type { AppliedState } from './applied.js'
6
+ import { listMigrations, type MigrationEntry } from './history.js'
7
+
8
+ export interface FileHazards {
9
+ file: string
10
+ hazards: MigrationHazard[]
11
+ /** Hazard classes this file raises but does not declare a pragma for. */
12
+ undeclared: PragmaKind[]
13
+ }
14
+
15
+ export interface MigrationCheckResult {
16
+ safe: boolean
17
+ hasDestructive: boolean
18
+ hasLocking: boolean
19
+ hasDynamic: boolean
20
+ /** True when every hazard raised is declared by its own migration. */
21
+ declared: boolean
22
+ fileHazards: FileHazards[]
23
+ }
24
+
25
+ /**
26
+ * Scans pending migrations for destructive and locking operations.
27
+ *
28
+ * `applied` is what the tracker table records as already applied (see
29
+ * `readAppliedState`); applied entries are skipped — their hazards are
30
+ * history, not a decision the operator still gets to make. Membership is by
31
+ * tag on an upgraded tracker, or by the old `when`-timestamp high-water mark
32
+ * on a tracker `applyMigrations` has not upgraded yet. Omitting `applied`
33
+ * (or passing null — no tracker table) scans every entry, the correct
34
+ * behaviour when nothing is known to be applied.
35
+ */
36
+ export function checkMigrations(migrationsFolder: string, applied?: AppliedState | null): MigrationCheckResult {
37
+ const entries = listMigrations(migrationsFolder)
38
+ const fileHazards: FileHazards[] = []
39
+ let hasDestructive = false
40
+ let hasLocking = false
41
+ let hasDynamic = false
42
+ let declared = true
43
+
44
+ const isApplied = (entry: MigrationEntry): boolean => {
45
+ if (applied === undefined || applied === null) return false
46
+ if (applied.kind === 'tags') return applied.tags.has(entry.tag)
47
+ return entry.when <= applied.threshold
48
+ }
49
+
50
+ for (const entry of entries) {
51
+ if (isApplied(entry)) continue
52
+
53
+ const sqlPath = join(migrationsFolder, `${entry.tag}.sql`)
54
+ if (!existsSync(sqlPath)) continue
55
+
56
+ const sql = readFileSync(sqlPath, 'utf-8')
57
+ const hazards = analyzeSQL(sql)
58
+
59
+ if (hazards.length > 0) {
60
+ // A hazard is authorized by a pragma in the migration that raises it —
61
+ // never by a flag on the deploy command, which would authorize this
62
+ // migration and every migration after it. Checked per file, per class.
63
+ const undeclared: PragmaKind[] = []
64
+ for (const kind of ['destructive', 'locking', 'dynamic'] as const) {
65
+ if (!hazards.some(h => h.severity === kind)) continue
66
+ if (kind === 'destructive') hasDestructive = true
67
+ if (kind === 'locking') hasLocking = true
68
+ if (kind === 'dynamic') hasDynamic = true
69
+ if (!hasPragma(sql, kind)) {
70
+ undeclared.push(kind)
71
+ declared = false
72
+ }
73
+ }
74
+ fileHazards.push({ file: `${entry.tag}.sql`, hazards, undeclared })
75
+ }
76
+ }
77
+
78
+ return {
79
+ safe: !hasDestructive && !hasLocking && !hasDynamic,
80
+ hasDestructive,
81
+ hasLocking,
82
+ hasDynamic,
83
+ declared,
84
+ fileHazards,
85
+ }
86
+ }
87
+
88
+ export function formatCheckResult(result: MigrationCheckResult): string {
89
+ if (result.declared) return ''
90
+
91
+ const lines: string[] = []
92
+ const undeclaredFiles = result.fileHazards.filter(f => f.undeclared.length > 0)
93
+ const n = undeclaredFiles.length
94
+
95
+ lines.push(
96
+ `Migration safety check: ${n} migration${n > 1 ? 's' : ''} raise${n > 1 ? '' : 's'} ` +
97
+ `hazards that ${n > 1 ? 'their own files do' : 'its own file does'} not declare.\n`,
98
+ )
99
+
100
+ for (const { file, hazards } of undeclaredFiles) {
101
+ lines.push(formatHazards(hazards, file))
102
+ }
103
+
104
+ lines.push('')
105
+ lines.push('Authorization belongs in the migration, not the deploy command.')
106
+ lines.push('Add the matching line to the top of each file above and commit it,')
107
+ lines.push('so the approval is reviewed in the diff and recorded in history:')
108
+ lines.push('')
109
+
110
+ for (const { file, undeclared } of undeclaredFiles) {
111
+ for (const kind of undeclared) {
112
+ lines.push(` ${file}: -- ${PRAGMA_FOR[kind]}`)
113
+ }
114
+ }
115
+
116
+ return lines.join('\n')
117
+ }
118
+
119
+ export type { MigrationHazard, Severity }