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,201 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
2
+ import { join, resolve } from 'node:path'
3
+ import { pathToFileURL } from 'node:url'
4
+ import { glob } from 'node:fs/promises'
5
+ import type { ResolvedDatabase, ResolvedDoor } from '../../core/config/load.js'
6
+ import { ConfigError } from '../../core/config/errors.js'
7
+ import { postProcessMigration } from './post-process.js'
8
+ import { diffDoors, doorSnapshots } from './door-generate.js'
9
+ import { generateRlsStatements } from './rls-generate.js'
10
+ import { generateAppendOnlyStatements } from './append-only-generate.js'
11
+ import { definitions } from '../domain/index.js'
12
+ import { buildSnapshot } from './snapshot.js'
13
+ import { deltaPath, listMigrations, readFoldedSnapshot, snapshotDelta } from './history.js'
14
+ import { diffSnapshots, diffOpTableName } from './diff.js'
15
+ import { emitSQL } from './sql-emit.js'
16
+ import { PARTITIONED_TRACE_TABLE_NAMES } from '../../trace/partition/tables.js'
17
+ import { AUTH_TABLE_NAMES } from '../../auth/auth/schema.js'
18
+ import { EMAIL_TABLE_NAMES } from '../../infra/email/schema.js'
19
+ import { SCHEDULE_TABLE_NAMES } from '../../async/jobs/schedules-table.js'
20
+
21
+ // Schema files are import()ed below. They may already be in Node's ESM module
22
+ // cache because `discoverInstance` transitively pulled them in (any surface or
23
+ // handler that imports a defined table loads the schema file along with it).
24
+ // A second evaluation would call pipe.define() again and crash on the registry
25
+ // duplicate-name guard, so we rely on the cache: previously-loaded files
26
+ // resolve to their cached exports (define() has already populated the registry
27
+ // from that first load); files reached only by the glob are evaluated fresh.
28
+
29
+ export interface GenerateResult {
30
+ database: string
31
+ migrationFile: string | null
32
+ snapshotFile: string | null
33
+ statements: number
34
+ }
35
+
36
+ export async function generateForDatabase(
37
+ dbConfig: ResolvedDatabase,
38
+ migrationName?: string,
39
+ internalDefinitions?: () => Promise<Record<string, unknown>>,
40
+ doors: readonly ResolvedDoor[] | (() => readonly ResolvedDoor[]) = [],
41
+ ): Promise<GenerateResult> {
42
+ if (dbConfig.schema === undefined) {
43
+ throw new ConfigError(
44
+ `Database "${dbConfig.name}" has no schema path configured.`,
45
+ `Add a schema path to your database config:\n\n` +
46
+ ` databases: {\n` +
47
+ ` ${dbConfig.name}: {\n` +
48
+ ` url: '...',\n` +
49
+ ` schema: './src/db/schema.ts', // <-- add this\n` +
50
+ ` migrations: '...',\n` +
51
+ ` },\n` +
52
+ ` }\n`,
53
+ )
54
+ }
55
+
56
+ if (dbConfig.migrations === undefined) {
57
+ throw new ConfigError(
58
+ `Database "${dbConfig.name}" has no migrations path configured.`,
59
+ `Add a migrations path to your database config:\n\n` +
60
+ ` databases: {\n` +
61
+ ` ${dbConfig.name}: {\n` +
62
+ ` url: '...',\n` +
63
+ ` schema: '...',\n` +
64
+ ` migrations: './migrations/${dbConfig.name}', // <-- add this\n` +
65
+ ` },\n` +
66
+ ` }\n`,
67
+ )
68
+ }
69
+
70
+ const schemaFiles = await resolveSchemaFiles(dbConfig.schema, dbConfig.baseDir)
71
+
72
+ if (schemaFiles.length === 0) {
73
+ const patterns = Array.isArray(dbConfig.schema) ? dbConfig.schema.join(', ') : dbConfig.schema
74
+ throw new ConfigError(
75
+ `No schema files found for database "${dbConfig.name}".`,
76
+ `Pattern(s): ${patterns}\n\n Check the "schema" path in your database config.`,
77
+ )
78
+ }
79
+
80
+ // ResolvedDatabase.migrations is absolute (resolved against baseDir at
81
+ // config-load time) — cwd plays no part.
82
+ const migrationsDir = dbConfig.migrations
83
+ const metaDir = join(migrationsDir, 'meta')
84
+
85
+ mkdirSync(metaDir, { recursive: true })
86
+
87
+ const imports: Record<string, unknown> = {}
88
+ for (const file of schemaFiles) {
89
+ const url = pathToFileURL(file).href
90
+ const mod: Record<string, unknown> = await import(url)
91
+ for (const [key, value] of Object.entries(mod)) {
92
+ imports[key] = value
93
+ }
94
+ }
95
+
96
+ // A thunk, invoked only AFTER the schema-file import loop: queue tables
97
+ // register at createQueue() time, and a queue module reached only by the
98
+ // schema glob registers during the loop above. Materializing the internal
99
+ // definitions before the imports (as the CLI once did) silently dropped
100
+ // those queues from the migration (D2, subseam audit 2026-07-16).
101
+ if (internalDefinitions !== undefined) {
102
+ for (const [key, value] of Object.entries(await internalDefinitions())) {
103
+ imports[key] = value
104
+ }
105
+ }
106
+
107
+ const prevSnapshot = readFoldedSnapshot(migrationsDir)
108
+ const currentSnapshot = buildSnapshot(imports, prevSnapshot.id)
109
+ // Doors are not tables, so the table diff never sees them: their policies are
110
+ // diffed against the doors the previous snapshot recorded.
111
+ const currentDoors = doorSnapshots(typeof doors === 'function' ? doors() : doors, dbConfig.rls?.platformRole, definitions())
112
+ const doorStatements = diffDoors(prevSnapshot.doors, currentDoors)
113
+ if (Object.keys(currentDoors).length > 0 || prevSnapshot.doors !== undefined) currentSnapshot.doors = currentDoors
114
+ const ops = diffSnapshots(prevSnapshot, currentSnapshot)
115
+ // Framework-owned partitioned tables (the trace family) stay in the snapshot
116
+ // but are never emitted into an application migration: they are PARTITION BY
117
+ // RANGE, and a bare CREATE TABLE leaves a partitioned table that rejects every
118
+ // insert with "no partition found". pipework provisions them — parent plus day
119
+ // partitions — itself. Issue #313.
120
+ const emittableOps = ops.filter(op => !PARTITIONED_TRACE_TABLE_NAMES.has(diffOpTableName(op)))
121
+ const statements = emitSQL(emittableOps).map(idempotentAuthTable)
122
+
123
+ if (statements.length === 0 && doorStatements.length === 0) {
124
+ return {
125
+ database: dbConfig.name,
126
+ migrationFile: null,
127
+ snapshotFile: null,
128
+ statements: 0,
129
+ }
130
+ }
131
+
132
+ const tag = freeTag(migrationsDir, migrationName)
133
+
134
+ const joined = statements.map(s => s + ';').join('\n')
135
+ const withTenantRls = dbConfig.rls !== undefined
136
+ ? generateRlsStatements(joined, definitions(), dbConfig.rls.sessionVar, dbConfig.rls.force)
137
+ : joined
138
+ // After the tenant policies: a door's policy goes on a table that is row-secured by then.
139
+ const withRls = doorStatements.length > 0
140
+ ? `${withTenantRls}${withTenantRls === '' ? '' : '\n\n'}${doorStatements.map(s => s + ';').join('\n')}`
141
+ : withTenantRls
142
+ const withAppendOnly = generateAppendOnlyStatements(withRls, definitions())
143
+ const sqlContent = postProcessMigration(withAppendOnly)
144
+ const migrationFile = join(migrationsDir, `${tag}.sql`)
145
+ writeFileSync(migrationFile, sqlContent, 'utf-8')
146
+
147
+ const snapshotFile = deltaPath(migrationsDir, tag)
148
+ writeFileSync(snapshotFile, JSON.stringify(snapshotDelta(prevSnapshot, currentSnapshot), null, 2), 'utf-8')
149
+
150
+ return {
151
+ database: dbConfig.name,
152
+ migrationFile,
153
+ snapshotFile,
154
+ statements: statements.length + doorStatements.length,
155
+ }
156
+ }
157
+
158
+ // The session, org, email and schedules tables predate their definitions: apps
159
+ // copied them by hand from SQL files. Their CREATE statements are IF NOT EXISTS so the first
160
+ // generated migration applies over those tables.
161
+ const AUTH_CREATE_RE = /^CREATE\s+(TABLE|(?:UNIQUE\s+)?INDEX)\s+("(?:[^"]|"")+")(\s+ON\s+"([^"]+)")?/
162
+
163
+ export function idempotentAuthTable(statement: string): string {
164
+ const m = AUTH_CREATE_RE.exec(statement)
165
+ if (m === null) return statement
166
+ const table = m[1] === 'TABLE' ? m[2]!.slice(1, -1) : m[4]
167
+ if (table === undefined || !(AUTH_TABLE_NAMES.has(table) || EMAIL_TABLE_NAMES.has(table) || SCHEDULE_TABLE_NAMES.has(table))) return statement
168
+ return statement.replace(AUTH_CREATE_RE, (_all, kind: string, name: string, on: string | undefined) =>
169
+ `CREATE ${kind} IF NOT EXISTS ${name}${on ?? ''}`)
170
+ }
171
+
172
+ /** `YYYYMMDDHHMMSS[_slug]` from the UTC clock, moved forward a second at a time until no migration holds that timestamp. */
173
+ function freeTag(migrationsDir: string, name?: string): string {
174
+ const taken = new Set(listMigrations(migrationsDir).map(m => m.tag.slice(0, 14)))
175
+ const slug = name === undefined ? '' : name.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_|_$/g, '')
176
+ const at = new Date()
177
+ at.setUTCMilliseconds(0)
178
+ for (;;) {
179
+ const stamp = at.toISOString().replace(/\D/g, '').slice(0, 14)
180
+ if (!taken.has(stamp)) return slug === '' ? stamp : `${stamp}_${slug}`
181
+ at.setTime(at.getTime() + 1000)
182
+ }
183
+ }
184
+
185
+ async function resolveSchemaFiles(schema: string | string[], baseDir: string): Promise<string[]> {
186
+ const patterns = Array.isArray(schema) ? schema : [schema]
187
+ const files: string[] = []
188
+
189
+ for (const pattern of patterns) {
190
+ const abs = resolve(baseDir, pattern)
191
+ if (!pattern.includes('*')) {
192
+ if (existsSync(abs)) files.push(abs)
193
+ } else {
194
+ for await (const match of glob(pattern, { cwd: baseDir })) {
195
+ files.push(resolve(baseDir, match))
196
+ }
197
+ }
198
+ }
199
+
200
+ return [...new Set(files)].sort()
201
+ }
@@ -0,0 +1,215 @@
1
+ import { existsSync, readFileSync, readdirSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+ import { EMPTY_SNAPSHOT, type PwSnapshot, type PwTableSnapshot, type PwPartitionSnapshot } from './snapshot.js'
4
+ import type { DoorSnapshot } from './door-generate.js'
5
+
6
+ export interface MigrationEntry {
7
+ tag: string
8
+ when: number
9
+ }
10
+
11
+ const LEGACY_TAG = /^\d{4}(_|$)/
12
+ const TIMESTAMP_TAG = /^\d{14}(_|$)/
13
+
14
+ type Sub<K extends keyof PwTableSnapshot> = Record<string, NonNullable<PwTableSnapshot[K]> extends Record<string, infer V> ? V | null : never>
15
+
16
+ export interface TableDelta {
17
+ name: string
18
+ schema: string
19
+ partitionBy: PwPartitionSnapshot | null
20
+ columns: Sub<'columns'>
21
+ indexes: Sub<'indexes'>
22
+ foreignKeys: Sub<'foreignKeys'>
23
+ checks: Sub<'checks'>
24
+ uniqueConstraints: Sub<'uniqueConstraints'>
25
+ compositePrimaryKeys: Sub<'compositePrimaryKeys'>
26
+ }
27
+
28
+ export interface SnapshotDelta {
29
+ version: 'pw1-delta'
30
+ tables: Record<string, TableDelta | null>
31
+ doors?: Record<string, DoorSnapshot | null>
32
+ }
33
+
34
+ const MAP_KEYS = ['columns', 'indexes', 'foreignKeys', 'checks', 'uniqueConstraints', 'compositePrimaryKeys'] as const
35
+
36
+ function readLegacyJournal(folder: string): { tag: string; when: number }[] | null {
37
+ const path = join(folder, 'meta', '_journal.json')
38
+ if (!existsSync(path)) return null
39
+ const journal = JSON.parse(readFileSync(path, 'utf-8')) as { entries?: { tag: string; when: number }[] }
40
+ return journal.entries ?? []
41
+ }
42
+
43
+ /** The folder's migrations in apply order: legacy `NNNN` tags by index, then timestamp tags by time. */
44
+ export function listMigrations(folder: string): MigrationEntry[] {
45
+ if (!existsSync(folder)) return []
46
+ const tags = readdirSync(folder, { withFileTypes: true })
47
+ .filter(e => e.isFile() && e.name.endsWith('.sql'))
48
+ .map(e => e.name.slice(0, -'.sql'.length))
49
+
50
+ const legacy: string[] = []
51
+ const stamped: string[] = []
52
+ for (const tag of tags) {
53
+ if (TIMESTAMP_TAG.test(tag)) stamped.push(tag)
54
+ else if (LEGACY_TAG.test(tag)) legacy.push(tag)
55
+ else {
56
+ throw new Error(
57
+ `Migration file "${tag}.sql" in ${folder} is not named like a migration. ` +
58
+ `Expected "NNNN_name.sql" (legacy index) or "YYYYMMDDHHMMSS_name.sql" (UTC timestamp).`,
59
+ )
60
+ }
61
+ }
62
+ const byText = (a: string, b: string): number => (a < b ? -1 : a > b ? 1 : 0)
63
+ legacy.sort((a, b) => Number(a.slice(0, 4)) - Number(b.slice(0, 4)) || byText(a, b))
64
+ stamped.sort((a, b) => byText(a.slice(0, 14), b.slice(0, 14)) || byText(a, b))
65
+
66
+ const journal = readLegacyJournal(folder)
67
+ if (journal !== null) {
68
+ for (const entry of journal) {
69
+ const path = `${folder}/${entry.tag}.sql`
70
+ if (!existsSync(path)) throw new Error(`Missing migration file: ${path}`)
71
+ }
72
+ }
73
+ const journalWhen = new Map((journal ?? []).map(e => [e.tag, e.when]))
74
+
75
+ return [
76
+ ...legacy.map(tag => ({ tag, when: journalWhen.get(tag) ?? Number(tag.slice(0, 4)) })),
77
+ ...stamped.map(tag => ({ tag, when: timestampMillis(tag) })),
78
+ ]
79
+ }
80
+
81
+ export function timestampMillis(tag: string): number {
82
+ const p = (from: number, to: number): number => Number(tag.slice(from, to))
83
+ return Date.UTC(p(0, 4), p(4, 6) - 1, p(6, 8), p(8, 10), p(10, 12), p(12, 14))
84
+ }
85
+
86
+ export function isTimestampTag(tag: string): boolean {
87
+ return TIMESTAMP_TAG.test(tag)
88
+ }
89
+
90
+ export function deltaPath(folder: string, tag: string): string {
91
+ return join(folder, 'meta', `${tag}.delta.json`)
92
+ }
93
+
94
+ function stable(value: unknown): string {
95
+ return JSON.stringify(value, (_key, v: unknown) => {
96
+ if (v !== null && typeof v === 'object' && !Array.isArray(v)) {
97
+ return Object.fromEntries(Object.entries(v).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)))
98
+ }
99
+ return v
100
+ })
101
+ }
102
+
103
+ function same(a: unknown, b: unknown): boolean {
104
+ return stable(a) === stable(b)
105
+ }
106
+
107
+ function diffMap<V>(prev: Record<string, V>, next: Record<string, V>): Record<string, V | null> {
108
+ const out: Record<string, V | null> = {}
109
+ for (const [key, value] of Object.entries(next)) {
110
+ if (!(key in prev) || !same(prev[key], value)) out[key] = value
111
+ }
112
+ for (const key of Object.keys(prev)) {
113
+ if (!(key in next)) out[key] = null
114
+ }
115
+ return out
116
+ }
117
+
118
+ /** The element-level change from one snapshot to the next; only changed tables, elements and doors appear. */
119
+ export function snapshotDelta(prev: PwSnapshot, next: PwSnapshot): SnapshotDelta {
120
+ const tables: Record<string, TableDelta | null> = {}
121
+ for (const [key, table] of Object.entries(next.tables)) {
122
+ const before = prev.tables[key]
123
+ const empty = before === undefined
124
+ const delta = {
125
+ name: table.name,
126
+ schema: table.schema,
127
+ partitionBy: table.partitionBy ?? null,
128
+ columns: diffMap(before?.columns ?? {}, table.columns),
129
+ indexes: diffMap(before?.indexes ?? {}, table.indexes),
130
+ foreignKeys: diffMap(before?.foreignKeys ?? {}, table.foreignKeys),
131
+ checks: diffMap(before?.checks ?? {}, table.checks),
132
+ uniqueConstraints: diffMap(before?.uniqueConstraints ?? {}, table.uniqueConstraints),
133
+ compositePrimaryKeys: diffMap(before?.compositePrimaryKeys ?? {}, table.compositePrimaryKeys),
134
+ } as TableDelta
135
+ const changed = empty
136
+ || before.name !== table.name
137
+ || before.schema !== table.schema
138
+ || !same(before.partitionBy ?? null, delta.partitionBy)
139
+ || MAP_KEYS.some(k => Object.keys(delta[k]).length > 0)
140
+ if (changed) tables[key] = delta
141
+ }
142
+ for (const key of Object.keys(prev.tables)) {
143
+ if (!(key in next.tables)) tables[key] = null
144
+ }
145
+
146
+ const delta: SnapshotDelta = { version: 'pw1-delta', tables }
147
+ if (next.doors !== undefined || prev.doors !== undefined) {
148
+ const doors = diffMap<DoorSnapshot>(prev.doors ?? {}, next.doors ?? {})
149
+ if (Object.keys(doors).length > 0) delta.doors = doors
150
+ }
151
+ return delta
152
+ }
153
+
154
+ function applyMap<V>(base: Record<string, V>, changes: Record<string, V | null>): Record<string, V> {
155
+ const out: Record<string, V> = { ...base }
156
+ for (const [key, value] of Object.entries(changes)) {
157
+ if (value === null) delete out[key]
158
+ else out[key] = value
159
+ }
160
+ return out
161
+ }
162
+
163
+ /** `snap` with `delta` applied. Pure: the input is not modified. */
164
+ export function applyDelta(snap: PwSnapshot, delta: SnapshotDelta): PwSnapshot {
165
+ const tables: Record<string, PwTableSnapshot> = { ...snap.tables }
166
+ for (const [key, change] of Object.entries(delta.tables)) {
167
+ if (change === null) {
168
+ delete tables[key]
169
+ continue
170
+ }
171
+ const base = tables[key]
172
+ tables[key] = {
173
+ name: change.name,
174
+ schema: change.schema,
175
+ columns: applyMap(base?.columns ?? {}, change.columns),
176
+ indexes: applyMap(base?.indexes ?? {}, change.indexes),
177
+ foreignKeys: applyMap(base?.foreignKeys ?? {}, change.foreignKeys),
178
+ checks: applyMap(base?.checks ?? {}, change.checks),
179
+ uniqueConstraints: applyMap(base?.uniqueConstraints ?? {}, change.uniqueConstraints),
180
+ compositePrimaryKeys: applyMap(base?.compositePrimaryKeys ?? {}, change.compositePrimaryKeys),
181
+ partitionBy: change.partitionBy ?? undefined,
182
+ }
183
+ }
184
+ const result: PwSnapshot = { ...snap, tables }
185
+ if (delta.doors !== undefined) {
186
+ result.doors = applyMap<DoorSnapshot>(snap.doors ?? {}, delta.doors) as NonNullable<PwSnapshot['doors']>
187
+ }
188
+ return result
189
+ }
190
+
191
+ /** The schema as of every migration in the folder: the legacy snapshot, then each timestamp migration's delta. */
192
+ export function readFoldedSnapshot(folder: string): PwSnapshot {
193
+ let snap = readLegacySnapshot(folder)
194
+ for (const { tag } of listMigrations(folder)) {
195
+ if (!isTimestampTag(tag)) continue
196
+ const path = deltaPath(folder, tag)
197
+ if (!existsSync(path)) {
198
+ throw new Error(`Missing snapshot delta ${path} for migration ${tag}.sql; the delta is written beside the migration by \`pipework generate\` and is committed with it.`)
199
+ }
200
+ snap = applyDelta(snap, JSON.parse(readFileSync(path, 'utf-8')) as SnapshotDelta)
201
+ }
202
+ return snap
203
+ }
204
+
205
+ function readLegacySnapshot(folder: string): PwSnapshot {
206
+ const journal = readLegacyJournal(folder)
207
+ if (journal === null || journal.length === 0) return EMPTY_SNAPSHOT
208
+ const last = journal[journal.length - 1] as { idx?: number }
209
+ const idx = last.idx ?? journal.length - 1
210
+ const path = join(folder, 'meta', `${String(idx).padStart(4, '0')}_snapshot.json`)
211
+ if (!existsSync(path)) return EMPTY_SNAPSHOT
212
+ const raw = JSON.parse(readFileSync(path, 'utf-8')) as { version?: string }
213
+ if (raw.version === '7') return EMPTY_SNAPSHOT
214
+ return raw as PwSnapshot
215
+ }
@@ -0,0 +1,9 @@
1
+ export { migrateAll, migrateOne, UnsafeMigrationError, type MigrateResult, type MigrateOptions } from './run.js'
2
+ export { checkMigrations, formatCheckResult, type MigrationCheckResult, type FileHazards, type MigrationHazard, type Severity } from './check.js'
3
+ export { hasPragma, PRAGMA_FOR, type PragmaKind } from './pragma.js'
4
+ export { readAppliedState, type AppliedState } from './applied.js'
5
+ export { analyzeSQL } from './safety.js'
6
+ export { generateForDatabase, type GenerateResult } from './generate.js'
7
+ export { postProcessMigration } from './post-process.js'
8
+ export { generateRlsStatements } from './rls-generate.js'
9
+ export { generateAppendOnlyStatements } from './append-only-generate.js'
@@ -0,0 +1,175 @@
1
+ // Pipework ships table DEFINITIONS for its own substrate — `trace`,
2
+ // `trace_step`, `trace_retained`, `trace_step_retained`, `audit_record` — but
3
+ // the migration generator only sees the consumer's `schema.ts` exports. Without
4
+ // this loader, enabling `trace: {}` or `audit: {}` in a blueprint produces a
5
+ // runtime crash on the first traced operation because the tables never reached
6
+ // the consumer's database. Loading is gated by the blueprint flags and by
7
+ // `isDefaultDatabase` because trace/audit always write to the default db.
8
+
9
+ import type { Blueprint } from '../../core/config/schema.js'
10
+
11
+ export async function loadInternalDefinitions(
12
+ blueprint: Blueprint,
13
+ options: { isDefaultDatabase: boolean },
14
+ ): Promise<Record<string, unknown>> {
15
+ if (!options.isDefaultDatabase) return {}
16
+
17
+ const result: Record<string, unknown> = {}
18
+
19
+ if (blueprint.trace !== undefined) {
20
+ const { trace } = await import('../../trace/schema/trace.js')
21
+ const { traceStep } = await import('../../trace/schema/trace-step.js')
22
+ const { traceRetained } = await import('../../trace/schema/trace-retained.js')
23
+ const { traceStepRetained } = await import('../../trace/schema/trace-step-retained.js')
24
+ result['__pipework_trace'] = trace
25
+ result['__pipework_trace_step'] = traceStep
26
+ result['__pipework_trace_retained'] = traceRetained
27
+ result['__pipework_trace_step_retained'] = traceStepRetained
28
+ }
29
+
30
+ if (blueprint.audit !== undefined) {
31
+ const { auditRecord } = await import('../../audit/schema/audit-record.js')
32
+ result['__pipework_audit_record'] = auditRecord
33
+ }
34
+
35
+ if (blueprint.valve !== undefined) {
36
+ const { valveCrossing } = await import('../valve/schema/valve-crossing.js')
37
+ result['__pipework_valve_crossing'] = valveCrossing
38
+ }
39
+
40
+ if (blueprint.accessLinks !== undefined) {
41
+ const { accessLinkCode, accessLink, accessLinkUse, accessLinkCheckSpent, accessLinkMiss } = await import('../../infra/access-links/schema.js')
42
+ result['__pipework_access_link_code'] = accessLinkCode
43
+ result['__pipework_access_link'] = accessLink
44
+ result['__pipework_access_link_use'] = accessLinkUse
45
+ result['__pipework_access_link_check_spent'] = accessLinkCheckSpent
46
+ result['__pipework_access_link_miss'] = accessLinkMiss
47
+ }
48
+
49
+ if (blueprint.joinRequests !== undefined) {
50
+ const { joinRequest } = await import('../../infra/join-requests/schema.js')
51
+ result['__pipework_join_request'] = joinRequest
52
+ }
53
+
54
+ if (blueprint.credits !== undefined) {
55
+ const { creditGrant, creditReservation, creditDraw, creditLedger, creditAccount } = await import('../../infra/credits/schema.js')
56
+ result['__pipework_credit_grant'] = creditGrant
57
+ result['__pipework_credit_reservation'] = creditReservation
58
+ result['__pipework_credit_draw'] = creditDraw
59
+ result['__pipework_credit_ledger'] = creditLedger
60
+ result['__pipework_credit_account'] = creditAccount
61
+ }
62
+
63
+ if (blueprint.creditLine !== undefined) {
64
+ const {
65
+ creditLine, creditLineReservation, creditLineEntry, creditLinePayment, creditLinePaymentApplication, creditLineAuthorization,
66
+ } = await import('../../infra/credit-line/schema.js')
67
+ result['__pipework_credit_line'] = creditLine
68
+ result['__pipework_credit_line_reservation'] = creditLineReservation
69
+ result['__pipework_credit_line_entry'] = creditLineEntry
70
+ result['__pipework_credit_line_payment'] = creditLinePayment
71
+ result['__pipework_credit_line_payment_application'] = creditLinePaymentApplication
72
+ result['__pipework_credit_line_authorization'] = creditLineAuthorization
73
+ }
74
+
75
+ if (blueprint.quota !== undefined) {
76
+ const { outboundQuota } = await import('../../infra/quota/schema.js')
77
+ result['__pipework_outbound_quota'] = outboundQuota
78
+ }
79
+
80
+ if (blueprint.storage !== undefined) {
81
+ const { storageFile } = await import('../../infra/storage/schema.js')
82
+ result['__pipework_storage_file'] = storageFile
83
+ }
84
+
85
+ if (blueprint.crawl !== undefined) {
86
+ const { crawls, crawlUrls, crawlHosts, crawlResources } = await import('../../infra/crawl/schema.js')
87
+ result['__pipework_crawl'] = crawls
88
+ result['__pipework_crawl_url'] = crawlUrls
89
+ result['__pipework_crawl_host'] = crawlHosts
90
+ result['__pipework_crawl_resource'] = crawlResources
91
+ }
92
+
93
+ if (blueprint.alerts !== undefined) {
94
+ const { alerts, alertOccurrences, alertDeliveries, alertSourceState, unitFaults, loopBeats, faults } = await import('../../infra/alerts/schema.js')
95
+ result['__pipework_alerts'] = alerts
96
+ result['__pipework_alert_occurrences'] = alertOccurrences
97
+ result['__pipework_alert_deliveries'] = alertDeliveries
98
+ result['__pipework_alert_source_state'] = alertSourceState
99
+ result['__pipework_unit_faults'] = unitFaults
100
+ result['__pipework_loop_beats'] = loopBeats
101
+ result['__pipework_faults'] = faults
102
+ }
103
+
104
+ if (blueprint.support !== undefined) {
105
+ const { supportTicket, supportMessage, supportLink, supportEventDelivery } = await import('../../infra/support/schema.js')
106
+ result['__pipework_support_ticket'] = supportTicket
107
+ result['__pipework_support_message'] = supportMessage
108
+ result['__pipework_support_link'] = supportLink
109
+ result['__pipework_support_event_delivery'] = supportEventDelivery
110
+ }
111
+
112
+ if (blueprint.sessions !== undefined) {
113
+ const { refreshTokens, authVersions } = await import('../../auth/auth/schema.js')
114
+ result['__pipework_refresh_tokens'] = refreshTokens
115
+ result['__pipework_auth_versions'] = authVersions
116
+ }
117
+
118
+ if (blueprint.orgs !== undefined) {
119
+ const { userOrgs } = await import('../../auth/auth/schema.js')
120
+ result['__pipework_user_orgs'] = userOrgs
121
+ }
122
+
123
+ if (blueprint.passwords !== undefined) {
124
+ const { signinAttempts } = await import('../../auth/auth/schema.js')
125
+ result['__pipework_signin_attempts'] = signinAttempts
126
+ }
127
+
128
+ if (blueprint.guards !== undefined) {
129
+ const { guardAttempts } = await import('../../auth/auth/schema.js')
130
+ result['__pipework_guard_attempts'] = guardAttempts
131
+ }
132
+
133
+ if (blueprint.emailLinks !== undefined) {
134
+ const { emailLinks, emailLinkRequests } = await import('../../auth/auth/schema.js')
135
+ result['__pipework_email_links'] = emailLinks
136
+ result['__pipework_email_link_requests'] = emailLinkRequests
137
+ }
138
+
139
+ if (blueprint.rateLimits !== undefined) {
140
+ const { rateLimitCounts } = await import('../../request/http/rate-limit-classes.js')
141
+ result['__pipework_rate_limit_counts'] = rateLimitCounts
142
+ }
143
+
144
+ if (blueprint.email !== undefined) {
145
+ const { emailMessages, emailSuppressions, emailInbound, emailUnsubscribes } = await import('../../infra/email/schema.js')
146
+ result['__pipework_email_messages'] = emailMessages
147
+ result['__pipework_email_suppressions'] = emailSuppressions
148
+ result['__pipework_email_inbound'] = emailInbound
149
+ result['__pipework_email_unsubscribes'] = emailUnsubscribes
150
+ }
151
+
152
+ // Queue tables register at createQueue() time (worker surfaces create their
153
+ // queue at construction, so config discovery populates the registry before
154
+ // generate snapshots). No blueprint flag — presence in the registry means a
155
+ // queue is in use. Like trace/audit, queue tables are only emitted into the
156
+ // default database's migrations.
157
+ const { queueDefinitions } = await import('../../async/jobs/table.js')
158
+ for (const [name, definition] of queueDefinitions()) {
159
+ result[`__pipework_queue_${name}`] = definition
160
+ }
161
+
162
+ // Registered when a step graph is defined.
163
+ const { stepDefinitions } = await import('../../async/steps/table.js')
164
+ for (const [name, definition] of stepDefinitions()) {
165
+ result[`__pipework_${name}`] = definition
166
+ }
167
+
168
+ // Registered when a worker surface declaring schedules is constructed.
169
+ const { schedulesDefinitions } = await import('../../async/jobs/schedules-table.js')
170
+ for (const [name, definition] of schedulesDefinitions()) {
171
+ result[`__pipework_${name}`] = definition
172
+ }
173
+
174
+ return result
175
+ }
@@ -0,0 +1,73 @@
1
+ import { stripComments, codeStartOffset } from './statements.js'
2
+
3
+ const CREATE_INDEX_RE = /\bCREATE\s+(UNIQUE\s+)?INDEX\b(?!\s+CONCURRENTLY)/i
4
+ const CONCURRENTLY_RE = /\bCONCURRENTLY\b/i
5
+
6
+ const NO_TRANSACTION_PRAGMA = '-- pipework:no-transaction'
7
+
8
+ /**
9
+ * Transform unsafe migration SQL emitted by the diff/sql-emit pipeline into
10
+ * safe SQL.
11
+ *
12
+ * `CREATE INDEX` → `CREATE INDEX CONCURRENTLY`, and the
13
+ * `-- pipework:no-transaction` pragma is prepended so the runner applies the
14
+ * migration outside a transaction (CONCURRENTLY cannot run inside one).
15
+ *
16
+ * Foreign-key safety (`NOT VALID` + `VALIDATE CONSTRAINT`) is decided upstream
17
+ * in `emitSQL`: Postgres rejects `NOT VALID` foreign keys on partitioned
18
+ * tables, and only the op metadata knows which tables are partitioned. A
19
+ * text-level pass here cannot tell, so it must not touch foreign keys. Issue #312.
20
+ */
21
+ export function postProcessMigration(sql: string): string {
22
+ const parts = sql.split(';')
23
+ const trailing = parts[parts.length - 1]
24
+ const rawStatements = parts.slice(0, -1)
25
+
26
+ const outputStatements: string[] = []
27
+ let hasConcurrently = false
28
+
29
+ for (const raw of rawStatements) {
30
+ // Match against the SQL with comments removed, not against the raw
31
+ // fragment. A statement and the comment above it share a `;`-fragment, so
32
+ // skipping fragments that *start with* `--` skipped the statement too and
33
+ // a commented CREATE INDEX silently kept its exclusive lock (#334).
34
+ // Comment text is equally unable to fake a match it should not have.
35
+ const code = stripComments(raw)
36
+ if (code.trim().length === 0) {
37
+ outputStatements.push(raw)
38
+ continue
39
+ }
40
+
41
+ if (CREATE_INDEX_RE.test(code)) {
42
+ // Rewrite only from where the SQL actually starts, so a leading comment
43
+ // that happens to say "CREATE INDEX" is not the thing rewritten.
44
+ const offset = codeStartOffset(raw)
45
+ const rewritten =
46
+ raw.slice(0, offset) +
47
+ raw.slice(offset).replace(/\b(CREATE\s+(?:UNIQUE\s+)?)(INDEX)\b/i, '$1$2 CONCURRENTLY')
48
+ outputStatements.push(rewritten)
49
+ hasConcurrently = true
50
+ continue
51
+ }
52
+
53
+ if (CONCURRENTLY_RE.test(code)) {
54
+ hasConcurrently = true
55
+ }
56
+
57
+ outputStatements.push(raw)
58
+ }
59
+
60
+ let result = outputStatements.join(';') + ';'
61
+
62
+ if (trailing !== undefined && trailing.trim().length > 0) {
63
+ result += trailing
64
+ }
65
+
66
+ if (hasConcurrently) {
67
+ result = result.startsWith(NO_TRANSACTION_PRAGMA)
68
+ ? result
69
+ : `${NO_TRANSACTION_PRAGMA}\n${result}`
70
+ }
71
+
72
+ return result
73
+ }