pipework 0.251.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 (730) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/core/config/load.d.ts +2 -0
  3. package/dist/core/config/load.d.ts.map +1 -1
  4. package/dist/core/config/load.js +1 -0
  5. package/dist/core/config/load.js.map +1 -1
  6. package/dist/core/config/namespace.d.ts +1 -0
  7. package/dist/core/config/namespace.d.ts.map +1 -1
  8. package/dist/core/config/schema.d.ts +2 -0
  9. package/dist/core/config/schema.d.ts.map +1 -1
  10. package/dist/core/config/schema.js +1 -0
  11. package/dist/core/config/schema.js.map +1 -1
  12. package/dist/core/surface/types.d.ts +1 -0
  13. package/dist/core/surface/types.d.ts.map +1 -1
  14. package/dist/data/db/namespace.d.ts +3 -0
  15. package/dist/data/db/namespace.d.ts.map +1 -1
  16. package/dist/data/db/namespace.js +3 -0
  17. package/dist/data/db/namespace.js.map +1 -1
  18. package/dist/data/db/pool.d.ts.map +1 -1
  19. package/dist/data/db/pool.js +6 -1
  20. package/dist/data/db/pool.js.map +1 -1
  21. package/dist/data/db/query-label.d.ts +5 -0
  22. package/dist/data/db/query-label.d.ts.map +1 -0
  23. package/dist/data/db/query-label.js +11 -0
  24. package/dist/data/db/query-label.js.map +1 -0
  25. package/dist/data/db/query-watch.d.ts +21 -0
  26. package/dist/data/db/query-watch.d.ts.map +1 -0
  27. package/dist/data/db/query-watch.js +90 -0
  28. package/dist/data/db/query-watch.js.map +1 -0
  29. package/dist/data/query/postgres-js/driver.js +1 -1
  30. package/dist/data/query/postgres-js/driver.js.map +1 -1
  31. package/dist/data/query/postgres-js/session.d.ts +5 -1
  32. package/dist/data/query/postgres-js/session.d.ts.map +1 -1
  33. package/dist/data/query/postgres-js/session.js +16 -11
  34. package/dist/data/query/postgres-js/session.js.map +1 -1
  35. package/dist/data/query/utils.d.ts +2 -0
  36. package/dist/data/query/utils.d.ts.map +1 -1
  37. package/dist/data/query/utils.js.map +1 -1
  38. package/dist/infra/credits/schema.d.ts +1 -1
  39. package/dist/test/plugin.d.ts.map +1 -1
  40. package/dist/test/plugin.js +10 -4
  41. package/dist/test/plugin.js.map +1 -1
  42. package/package.json +4 -3
  43. package/src/async/jobs/abortable-delay.ts +18 -0
  44. package/src/async/jobs/claims.ts +52 -0
  45. package/src/async/jobs/cron.ts +179 -0
  46. package/src/async/jobs/errors.ts +56 -0
  47. package/src/async/jobs/exclusion.ts +117 -0
  48. package/src/async/jobs/execute.ts +219 -0
  49. package/src/async/jobs/index.ts +10 -0
  50. package/src/async/jobs/listener.ts +135 -0
  51. package/src/async/jobs/namespace.ts +20 -0
  52. package/src/async/jobs/queue-door.ts +44 -0
  53. package/src/async/jobs/queue.ts +1012 -0
  54. package/src/async/jobs/run-script.ts +67 -0
  55. package/src/async/jobs/scheduler.ts +218 -0
  56. package/src/async/jobs/schedules-table.ts +37 -0
  57. package/src/async/jobs/serialize-error.ts +48 -0
  58. package/src/async/jobs/table.ts +191 -0
  59. package/src/async/pipeline/define.ts +53 -0
  60. package/src/async/pipeline/errors.ts +35 -0
  61. package/src/async/pipeline/execute.ts +53 -0
  62. package/src/async/pipeline/index.ts +13 -0
  63. package/src/async/pipeline/namespace.ts +12 -0
  64. package/src/async/pipeline/resume.ts +67 -0
  65. package/src/async/pipeline/run-steps.ts +98 -0
  66. package/src/async/pipeline/types.ts +57 -0
  67. package/src/async/state-machine/define.ts +64 -0
  68. package/src/async/state-machine/errors.ts +29 -0
  69. package/src/async/state-machine/index.ts +3 -0
  70. package/src/async/state-machine/namespace.ts +12 -0
  71. package/src/async/state-machine/transition.ts +90 -0
  72. package/src/async/state-machine/types.ts +37 -0
  73. package/src/async/steps/errors.ts +31 -0
  74. package/src/async/steps/graph.ts +1214 -0
  75. package/src/async/steps/hash.ts +40 -0
  76. package/src/async/steps/index.ts +7 -0
  77. package/src/async/steps/namespace.ts +7 -0
  78. package/src/async/steps/table.ts +97 -0
  79. package/src/async/steps/types.ts +318 -0
  80. package/src/audit/chain/index.ts +9 -0
  81. package/src/audit/chain/install.ts +113 -0
  82. package/src/audit/chain/retire.ts +52 -0
  83. package/src/audit/chain/verify.ts +257 -0
  84. package/src/audit/query/cursor.ts +37 -0
  85. package/src/audit/query/index.ts +9 -0
  86. package/src/audit/query/query.ts +223 -0
  87. package/src/audit/schema/audit-record-fields.ts +68 -0
  88. package/src/audit/schema/audit-record.ts +23 -0
  89. package/src/auth/auth/audit.ts +31 -0
  90. package/src/auth/auth/chain.ts +84 -0
  91. package/src/auth/auth/cookie.ts +136 -0
  92. package/src/auth/auth/email-links.ts +311 -0
  93. package/src/auth/auth/guard.ts +128 -0
  94. package/src/auth/auth/index.ts +18 -0
  95. package/src/auth/auth/multi-org.ts +337 -0
  96. package/src/auth/auth/namespace.ts +34 -0
  97. package/src/auth/auth/parse-expiry.ts +13 -0
  98. package/src/auth/auth/passwords.ts +110 -0
  99. package/src/auth/auth/schema.ts +110 -0
  100. package/src/auth/auth/sessions.ts +565 -0
  101. package/src/auth/auth/sign-in.ts +156 -0
  102. package/src/auth/auth/signing-keys.ts +69 -0
  103. package/src/auth/auth/types.ts +26 -0
  104. package/src/auth/auth/uuid.ts +10 -0
  105. package/src/auth/rbac/cache.ts +55 -0
  106. package/src/auth/rbac/check.ts +30 -0
  107. package/src/auth/rbac/create.ts +35 -0
  108. package/src/auth/rbac/index.ts +5 -0
  109. package/src/auth/rbac/middleware.ts +20 -0
  110. package/src/auth/rbac/namespace.ts +15 -0
  111. package/src/auth/rbac/resolve.ts +31 -0
  112. package/src/auth/rbac/schema.sql +31 -0
  113. package/src/auth/rbac/seed.ts +67 -0
  114. package/src/auth/rbac/tables.ts +32 -0
  115. package/src/auth/rbac/types.ts +65 -0
  116. package/src/auth/tenant/extract.ts +33 -0
  117. package/src/auth/tenant/in-tenant.ts +49 -0
  118. package/src/auth/tenant/index.ts +7 -0
  119. package/src/auth/tenant/namespace.ts +23 -0
  120. package/src/auth/tenant/propagate.ts +20 -0
  121. package/src/auth/tenant/rls.ts +120 -0
  122. package/src/auth/tenant/scope.ts +33 -0
  123. package/src/auth/tenant/scoped-db.ts +581 -0
  124. package/src/auth/tenant/types.ts +14 -0
  125. package/src/auth/tenant/validate.ts +27 -0
  126. package/src/cli/commands/add.ts +158 -0
  127. package/src/cli/commands/alerts.ts +98 -0
  128. package/src/cli/commands/check.ts +1418 -0
  129. package/src/cli/commands/codemod.ts +78 -0
  130. package/src/cli/commands/db.ts +356 -0
  131. package/src/cli/commands/dev.ts +101 -0
  132. package/src/cli/commands/generate.ts +75 -0
  133. package/src/cli/commands/init.ts +36 -0
  134. package/src/cli/commands/install.ts +28 -0
  135. package/src/cli/commands/lint.ts +62 -0
  136. package/src/cli/commands/migrate.ts +132 -0
  137. package/src/cli/commands/openapi.ts +63 -0
  138. package/src/cli/commands/remove.ts +72 -0
  139. package/src/cli/commands/run.ts +50 -0
  140. package/src/cli/commands/scope.ts +54 -0
  141. package/src/cli/commands/serve.ts +68 -0
  142. package/src/cli/commands/shard.ts +31 -0
  143. package/src/cli/commands/shared/config-pipework-version.ts +28 -0
  144. package/src/cli/commands/shared/find-config.ts +22 -0
  145. package/src/cli/commands/shared/load-config.ts +35 -0
  146. package/src/cli/commands/shared/pnpm-install.ts +95 -0
  147. package/src/cli/commands/shared/report-removed.ts +8 -0
  148. package/src/cli/commands/sync.ts +32 -0
  149. package/src/cli/commands/test.ts +307 -0
  150. package/src/cli/commands/upgrade.ts +48 -0
  151. package/src/cli/dev-bootstrap.ts +24 -0
  152. package/src/cli/errors.ts +10 -0
  153. package/src/cli/index.ts +303 -0
  154. package/src/cli/output.ts +17 -0
  155. package/src/cli/port.ts +15 -0
  156. package/src/cli/surface-kinds.ts +20 -0
  157. package/src/client/index.ts +4 -0
  158. package/src/client/poll.ts +130 -0
  159. package/src/client/report-fault.ts +119 -0
  160. package/src/core/config/app-pool.ts +19 -0
  161. package/src/core/config/aws-env.ts +29 -0
  162. package/src/core/config/base-dir.ts +24 -0
  163. package/src/core/config/discover.ts +64 -0
  164. package/src/core/config/env-resolve.ts +87 -0
  165. package/src/core/config/env-types.ts +116 -0
  166. package/src/core/config/env.ts +55 -0
  167. package/src/core/config/errors.ts +9 -0
  168. package/src/core/config/import-config.ts +40 -0
  169. package/src/core/config/index.ts +8 -0
  170. package/src/core/config/load.ts +417 -0
  171. package/src/core/config/namespace.ts +14 -0
  172. package/src/core/config/resolve.ts +195 -0
  173. package/src/core/config/schema.ts +488 -0
  174. package/src/core/config/statement-observer.ts +48 -0
  175. package/src/core/config/ts-inline-hooks.ts +75 -0
  176. package/src/core/config/ts-register.ts +4 -0
  177. package/src/core/config/ts-resolve-hooks.ts +101 -0
  178. package/src/core/errors/base.ts +49 -0
  179. package/src/core/errors/http.ts +146 -0
  180. package/src/core/errors/index.ts +2 -0
  181. package/src/core/errors/namespace.ts +31 -0
  182. package/src/core/lifecycle/drain.ts +33 -0
  183. package/src/core/lifecycle/health.ts +72 -0
  184. package/src/core/lifecycle/index.ts +4 -0
  185. package/src/core/lifecycle/namespace.ts +7 -0
  186. package/src/core/lifecycle/startup.ts +102 -0
  187. package/src/core/lifecycle/types.ts +36 -0
  188. package/src/core/logging/context.ts +60 -0
  189. package/src/core/logging/error-chain.ts +68 -0
  190. package/src/core/logging/index.ts +5 -0
  191. package/src/core/logging/logger.ts +65 -0
  192. package/src/core/logging/namespace.ts +16 -0
  193. package/src/core/logging/proxy.ts +22 -0
  194. package/src/core/logging/redact-match.ts +24 -0
  195. package/src/core/logging/types.ts +47 -0
  196. package/src/core/pipework.ts +566 -0
  197. package/src/core/runtime/broker.ts +69 -0
  198. package/src/core/surface/http.ts +133 -0
  199. package/src/core/surface/index.ts +11 -0
  200. package/src/core/surface/job-timeout.ts +40 -0
  201. package/src/core/surface/namespace.ts +13 -0
  202. package/src/core/surface/script.ts +33 -0
  203. package/src/core/surface/start.ts +142 -0
  204. package/src/core/surface/types.ts +225 -0
  205. package/src/core/surface/validate.ts +88 -0
  206. package/src/core/surface/worker.ts +528 -0
  207. package/src/core/validation/connectivity.ts +49 -0
  208. package/src/core/validation/domain.ts +99 -0
  209. package/src/core/validation/index.ts +5 -0
  210. package/src/core/validation/queue-tables.ts +312 -0
  211. package/src/core/validation/rls-role.ts +138 -0
  212. package/src/core/validation/startup.ts +51 -0
  213. package/src/core/validation/surfaces.ts +65 -0
  214. package/src/core/validation/types.ts +25 -0
  215. package/src/data/db/advisory-lock.ts +55 -0
  216. package/src/data/db/aggregates.ts +172 -0
  217. package/src/data/db/array-elements.ts +111 -0
  218. package/src/data/db/bulk-set.ts +53 -0
  219. package/src/data/db/col/index.ts +14 -0
  220. package/src/data/db/composed.ts +53 -0
  221. package/src/data/db/db.ts +276 -0
  222. package/src/data/db/excluded.ts +16 -0
  223. package/src/data/db/expressions.ts +473 -0
  224. package/src/data/db/filter.ts +90 -0
  225. package/src/data/db/function-source.ts +114 -0
  226. package/src/data/db/identifiers.ts +16 -0
  227. package/src/data/db/idx/index.ts +9 -0
  228. package/src/data/db/in-list.ts +49 -0
  229. package/src/data/db/index.ts +9 -0
  230. package/src/data/db/insert-split.ts +137 -0
  231. package/src/data/db/instrumentation.ts +82 -0
  232. package/src/data/db/maintenance.ts +28 -0
  233. package/src/data/db/namespace.ts +107 -0
  234. package/src/data/db/owner-labels.ts +9 -0
  235. package/src/data/db/pool.ts +187 -0
  236. package/src/data/db/query-label.ts +13 -0
  237. package/src/data/db/query-watch.ts +116 -0
  238. package/src/data/db/raw-client-warning.ts +37 -0
  239. package/src/data/db/readonly.ts +23 -0
  240. package/src/data/db/reservation.ts +151 -0
  241. package/src/data/db/schema-features.ts +14 -0
  242. package/src/data/db/serializable.ts +83 -0
  243. package/src/data/db/sql.ts +1 -0
  244. package/src/data/db/timeouts.ts +76 -0
  245. package/src/data/db/types.ts +18 -0
  246. package/src/data/db/unbound.ts +33 -0
  247. package/src/data/db/values.ts +29 -0
  248. package/src/data/domain/brand.ts +15 -0
  249. package/src/data/domain/build-factory.ts +193 -0
  250. package/src/data/domain/build-schema.ts +161 -0
  251. package/src/data/domain/build-table.ts +355 -0
  252. package/src/data/domain/define.ts +239 -0
  253. package/src/data/domain/external-registry.ts +34 -0
  254. package/src/data/domain/external.ts +77 -0
  255. package/src/data/domain/field.ts +279 -0
  256. package/src/data/domain/index.ts +13 -0
  257. package/src/data/domain/naming.ts +6 -0
  258. package/src/data/domain/projections.ts +57 -0
  259. package/src/data/domain/trace-safe-projection.ts +31 -0
  260. package/src/data/domain/traits.ts +108 -0
  261. package/src/data/domain/types.ts +289 -0
  262. package/src/data/jsonb/composed.ts +18 -0
  263. package/src/data/jsonb/index.ts +1 -0
  264. package/src/data/jsonb/namespace.ts +30 -0
  265. package/src/data/jsonb/query.ts +86 -0
  266. package/src/data/migrate/append-only-generate.ts +47 -0
  267. package/src/data/migrate/applied.ts +47 -0
  268. package/src/data/migrate/apply.ts +309 -0
  269. package/src/data/migrate/check.ts +119 -0
  270. package/src/data/migrate/diff.ts +357 -0
  271. package/src/data/migrate/door-generate.ts +130 -0
  272. package/src/data/migrate/framework-rls.ts +58 -0
  273. package/src/data/migrate/generate.ts +201 -0
  274. package/src/data/migrate/history.ts +215 -0
  275. package/src/data/migrate/index.ts +9 -0
  276. package/src/data/migrate/internal-definitions.ts +175 -0
  277. package/src/data/migrate/post-process.ts +73 -0
  278. package/src/data/migrate/pragma.ts +73 -0
  279. package/src/data/migrate/provision-framework.ts +147 -0
  280. package/src/data/migrate/rls-generate.ts +61 -0
  281. package/src/data/migrate/run.ts +124 -0
  282. package/src/data/migrate/safety.ts +167 -0
  283. package/src/data/migrate/snapshot.ts +368 -0
  284. package/src/data/migrate/sql-emit.ts +392 -0
  285. package/src/data/migrate/statements.ts +312 -0
  286. package/src/data/query/alias.ts +126 -0
  287. package/src/data/query/batch.ts +8 -0
  288. package/src/data/query/cache/core/cache.ts +78 -0
  289. package/src/data/query/cache/core/index.ts +1 -0
  290. package/src/data/query/cache/core/types.ts +29 -0
  291. package/src/data/query/cache/readme.md +230 -0
  292. package/src/data/query/casing.ts +76 -0
  293. package/src/data/query/collation.ts +11 -0
  294. package/src/data/query/column-builder.ts +370 -0
  295. package/src/data/query/column.ts +150 -0
  296. package/src/data/query/entity.ts +42 -0
  297. package/src/data/query/errors.ts +33 -0
  298. package/src/data/query/index.ts +14 -0
  299. package/src/data/query/logger.ts +47 -0
  300. package/src/data/query/operations.ts +45 -0
  301. package/src/data/query/pg-core/alias.ts +12 -0
  302. package/src/data/query/pg-core/checks.ts +32 -0
  303. package/src/data/query/pg-core/columns/all.ts +71 -0
  304. package/src/data/query/pg-core/columns/bigint.ts +110 -0
  305. package/src/data/query/pg-core/columns/bigserial.ts +128 -0
  306. package/src/data/query/pg-core/columns/boolean.ts +43 -0
  307. package/src/data/query/pg-core/columns/char.ts +85 -0
  308. package/src/data/query/pg-core/columns/cidr.ts +43 -0
  309. package/src/data/query/pg-core/columns/common.ts +366 -0
  310. package/src/data/query/pg-core/columns/custom.ts +232 -0
  311. package/src/data/query/pg-core/columns/date.common.ts +15 -0
  312. package/src/data/query/pg-core/columns/date.ts +112 -0
  313. package/src/data/query/pg-core/columns/double-precision.ts +55 -0
  314. package/src/data/query/pg-core/columns/enum.ts +201 -0
  315. package/src/data/query/pg-core/columns/index.ts +35 -0
  316. package/src/data/query/pg-core/columns/inet.ts +43 -0
  317. package/src/data/query/pg-core/columns/int.common.ts +57 -0
  318. package/src/data/query/pg-core/columns/integer.ts +53 -0
  319. package/src/data/query/pg-core/columns/interval.ts +83 -0
  320. package/src/data/query/pg-core/columns/json.ts +58 -0
  321. package/src/data/query/pg-core/columns/jsonb.ts +56 -0
  322. package/src/data/query/pg-core/columns/line.ts +117 -0
  323. package/src/data/query/pg-core/columns/macaddr.ts +43 -0
  324. package/src/data/query/pg-core/columns/macaddr8.ts +43 -0
  325. package/src/data/query/pg-core/columns/numeric.ts +227 -0
  326. package/src/data/query/pg-core/columns/point.ts +127 -0
  327. package/src/data/query/pg-core/columns/postgis_extension/geometry.ts +119 -0
  328. package/src/data/query/pg-core/columns/postgis_extension/utils.ts +47 -0
  329. package/src/data/query/pg-core/columns/real.ts +58 -0
  330. package/src/data/query/pg-core/columns/serial.ts +55 -0
  331. package/src/data/query/pg-core/columns/smallint.ts +53 -0
  332. package/src/data/query/pg-core/columns/smallserial.ts +60 -0
  333. package/src/data/query/pg-core/columns/text.ts +67 -0
  334. package/src/data/query/pg-core/columns/time.ts +72 -0
  335. package/src/data/query/pg-core/columns/timestamp.ts +163 -0
  336. package/src/data/query/pg-core/columns/uuid.ts +51 -0
  337. package/src/data/query/pg-core/columns/varchar.ts +89 -0
  338. package/src/data/query/pg-core/columns/vector_extension/bit.ts +68 -0
  339. package/src/data/query/pg-core/columns/vector_extension/halfvec.ts +80 -0
  340. package/src/data/query/pg-core/columns/vector_extension/sparsevec.ts +67 -0
  341. package/src/data/query/pg-core/columns/vector_extension/vector.ts +80 -0
  342. package/src/data/query/pg-core/db.ts +674 -0
  343. package/src/data/query/pg-core/dialect.ts +1404 -0
  344. package/src/data/query/pg-core/expressions.ts +25 -0
  345. package/src/data/query/pg-core/foreign-keys.ts +130 -0
  346. package/src/data/query/pg-core/index.ts +21 -0
  347. package/src/data/query/pg-core/indexes.ts +276 -0
  348. package/src/data/query/pg-core/policies.ts +56 -0
  349. package/src/data/query/pg-core/primary-keys.ts +62 -0
  350. package/src/data/query/pg-core/query-builders/count.ts +86 -0
  351. package/src/data/query/pg-core/query-builders/delete.ts +293 -0
  352. package/src/data/query/pg-core/query-builders/index.ts +7 -0
  353. package/src/data/query/pg-core/query-builders/insert.ts +452 -0
  354. package/src/data/query/pg-core/query-builders/query-builder.ts +123 -0
  355. package/src/data/query/pg-core/query-builders/query.ts +157 -0
  356. package/src/data/query/pg-core/query-builders/raw.ts +49 -0
  357. package/src/data/query/pg-core/query-builders/refresh-materialized-view.ts +108 -0
  358. package/src/data/query/pg-core/query-builders/select.ts +1346 -0
  359. package/src/data/query/pg-core/query-builders/select.types.ts +437 -0
  360. package/src/data/query/pg-core/query-builders/update.ts +626 -0
  361. package/src/data/query/pg-core/roles.ts +41 -0
  362. package/src/data/query/pg-core/schema.ts +72 -0
  363. package/src/data/query/pg-core/sequence.ts +41 -0
  364. package/src/data/query/pg-core/session.ts +292 -0
  365. package/src/data/query/pg-core/subquery.ts +46 -0
  366. package/src/data/query/pg-core/table.ts +252 -0
  367. package/src/data/query/pg-core/unique-constraint.ts +73 -0
  368. package/src/data/query/pg-core/utils/array.ts +95 -0
  369. package/src/data/query/pg-core/utils/index.ts +1 -0
  370. package/src/data/query/pg-core/utils.ts +104 -0
  371. package/src/data/query/pg-core/view-base.ts +14 -0
  372. package/src/data/query/pg-core/view-common.ts +1 -0
  373. package/src/data/query/pg-core/view.ts +435 -0
  374. package/src/data/query/pg-core/with-builder.ts +41 -0
  375. package/src/data/query/postgres-js/README.md +46 -0
  376. package/src/data/query/postgres-js/array-parser.ts +45 -0
  377. package/src/data/query/postgres-js/driver-error-boundary.ts +149 -0
  378. package/src/data/query/postgres-js/driver.ts +163 -0
  379. package/src/data/query/postgres-js/index.ts +2 -0
  380. package/src/data/query/postgres-js/session.ts +234 -0
  381. package/src/data/query/primary-key.ts +11 -0
  382. package/src/data/query/query-builders/query-builder.ts +19 -0
  383. package/src/data/query/query-builders/select.types.ts +175 -0
  384. package/src/data/query/query-promise.ts +35 -0
  385. package/src/data/query/relations.ts +725 -0
  386. package/src/data/query/runnable-query.ts +12 -0
  387. package/src/data/query/selection-proxy.ts +121 -0
  388. package/src/data/query/session.ts +8 -0
  389. package/src/data/query/sql/expressions/conditions.ts +741 -0
  390. package/src/data/query/sql/expressions/index.ts +2 -0
  391. package/src/data/query/sql/expressions/select.ts +45 -0
  392. package/src/data/query/sql/functions/aggregate.ts +129 -0
  393. package/src/data/query/sql/functions/index.ts +2 -0
  394. package/src/data/query/sql/functions/vector.ts +178 -0
  395. package/src/data/query/sql/index.ts +3 -0
  396. package/src/data/query/sql/sql.ts +794 -0
  397. package/src/data/query/subquery.ts +53 -0
  398. package/src/data/query/table.ts +208 -0
  399. package/src/data/query/table.utils.ts +2 -0
  400. package/src/data/query/tracing-utils.ts +3 -0
  401. package/src/data/query/tracing.ts +11 -0
  402. package/src/data/query/utils.ts +357 -0
  403. package/src/data/query/version.ts +4 -0
  404. package/src/data/query/view-common.ts +1 -0
  405. package/src/data/schema/branded.ts +13 -0
  406. package/src/data/schema/generated/coerce.ts +5 -0
  407. package/src/data/schema/generated/combinator.ts +6 -0
  408. package/src/data/schema/generated/encoding.ts +5 -0
  409. package/src/data/schema/generated/error.ts +6 -0
  410. package/src/data/schema/generated/format.ts +5 -0
  411. package/src/data/schema/generated/type-constructor.ts +10 -0
  412. package/src/data/schema/generated/type.ts +6 -0
  413. package/src/data/schema/index.ts +6 -0
  414. package/src/data/schema/json-schema.ts +33 -0
  415. package/src/data/schema/namespace.ts +55 -0
  416. package/src/data/schema/parse.ts +39 -0
  417. package/src/data/schema/types.ts +39 -0
  418. package/src/data/temporal/append-only.ts +134 -0
  419. package/src/data/temporal/close.ts +27 -0
  420. package/src/data/temporal/columns.ts +10 -0
  421. package/src/data/temporal/definition-queries.ts +70 -0
  422. package/src/data/temporal/errors.ts +10 -0
  423. package/src/data/temporal/get-current.ts +22 -0
  424. package/src/data/temporal/index.ts +9 -0
  425. package/src/data/temporal/namespace.ts +36 -0
  426. package/src/data/temporal/query.ts +25 -0
  427. package/src/data/temporal/resolve.ts +17 -0
  428. package/src/data/temporal/revise.ts +67 -0
  429. package/src/data/temporal/types.ts +22 -0
  430. package/src/data/valve/artifact.ts +33 -0
  431. package/src/data/valve/contract-diff.ts +21 -0
  432. package/src/data/valve/cross.ts +57 -0
  433. package/src/data/valve/crossing-ledger.ts +50 -0
  434. package/src/data/valve/decision.ts +44 -0
  435. package/src/data/valve/durable-crossing.ts +52 -0
  436. package/src/data/valve/execute-crossing.ts +77 -0
  437. package/src/data/valve/faucet.ts +56 -0
  438. package/src/data/valve/gate.ts +114 -0
  439. package/src/data/valve/graph.ts +77 -0
  440. package/src/data/valve/index.ts +53 -0
  441. package/src/data/valve/namespace.ts +57 -0
  442. package/src/data/valve/registry.ts +50 -0
  443. package/src/data/valve/schema/valve-crossing-fields.ts +23 -0
  444. package/src/data/valve/schema/valve-crossing.ts +9 -0
  445. package/src/data/valve/supply.ts +154 -0
  446. package/src/data/valve/types.ts +143 -0
  447. package/src/data/vector/columns.ts +27 -0
  448. package/src/data/vector/index.ts +4 -0
  449. package/src/data/vector/namespace.ts +33 -0
  450. package/src/data/vector/query.ts +85 -0
  451. package/src/data/vector/validate.ts +16 -0
  452. package/src/data/write/audit/actor.ts +15 -0
  453. package/src/data/write/audit/audit-columns.ts +18 -0
  454. package/src/data/write/audit/audit-select.ts +111 -0
  455. package/src/data/write/audit/bound-transaction.ts +14 -0
  456. package/src/data/write/audit/cte-compile.ts +32 -0
  457. package/src/data/write/audit/decode-returning.ts +47 -0
  458. package/src/data/write/audit/final-select.ts +43 -0
  459. package/src/data/write/audit/infra-audit.ts +36 -0
  460. package/src/data/write/audit/primary-key.ts +65 -0
  461. package/src/data/write/audit/projection.ts +41 -0
  462. package/src/data/write/audit/read-touches.ts +86 -0
  463. package/src/data/write/audit/touch-match.ts +78 -0
  464. package/src/data/write/audit/verb-delete.ts +62 -0
  465. package/src/data/write/audit/verb-insert.ts +36 -0
  466. package/src/data/write/audit/verb-select.ts +47 -0
  467. package/src/data/write/audit/verb-update.ts +60 -0
  468. package/src/data/write/audit/verb-upsert.ts +104 -0
  469. package/src/data/write/conflict.ts +43 -0
  470. package/src/data/write/delete.ts +38 -0
  471. package/src/data/write/execute.ts +243 -0
  472. package/src/data/write/index.ts +11 -0
  473. package/src/data/write/insert.ts +63 -0
  474. package/src/data/write/state.ts +43 -0
  475. package/src/data/write/update.ts +54 -0
  476. package/src/data/write/upsert.ts +58 -0
  477. package/src/data/write/values.ts +19 -0
  478. package/src/index.ts +230 -0
  479. package/src/infra/access-links/code.ts +70 -0
  480. package/src/infra/access-links/handle.ts +892 -0
  481. package/src/infra/access-links/index.ts +9 -0
  482. package/src/infra/access-links/namespace.ts +30 -0
  483. package/src/infra/access-links/person-check.ts +177 -0
  484. package/src/infra/access-links/schema.ts +71 -0
  485. package/src/infra/alerts/async-sources.ts +231 -0
  486. package/src/infra/alerts/audit.ts +36 -0
  487. package/src/infra/alerts/beat.ts +123 -0
  488. package/src/infra/alerts/client-faults.ts +111 -0
  489. package/src/infra/alerts/faults.ts +156 -0
  490. package/src/infra/alerts/handle.ts +778 -0
  491. package/src/infra/alerts/http.ts +192 -0
  492. package/src/infra/alerts/index.ts +12 -0
  493. package/src/infra/alerts/infra-sources.ts +180 -0
  494. package/src/infra/alerts/namespace.ts +81 -0
  495. package/src/infra/alerts/redact.ts +21 -0
  496. package/src/infra/alerts/request-faults.ts +41 -0
  497. package/src/infra/alerts/schema.ts +124 -0
  498. package/src/infra/alerts/sinks.ts +125 -0
  499. package/src/infra/alerts/source-options.ts +26 -0
  500. package/src/infra/alerts/sources.ts +503 -0
  501. package/src/infra/alerts/subsystem-sources.ts +137 -0
  502. package/src/infra/audit/emit.ts +87 -0
  503. package/src/infra/audit/index.ts +2 -0
  504. package/src/infra/audit/namespace.ts +22 -0
  505. package/src/infra/audit/schema.sql +35 -0
  506. package/src/infra/audit/types.ts +18 -0
  507. package/src/infra/aws/credentials.ts +147 -0
  508. package/src/infra/aws/sigv4.ts +140 -0
  509. package/src/infra/cache/create.ts +58 -0
  510. package/src/infra/cache/entry.ts +81 -0
  511. package/src/infra/cache/index.ts +4 -0
  512. package/src/infra/cache/namespace.ts +10 -0
  513. package/src/infra/cache/tenant.ts +93 -0
  514. package/src/infra/cache/types.ts +24 -0
  515. package/src/infra/crawl/audit.ts +35 -0
  516. package/src/infra/crawl/errors.ts +25 -0
  517. package/src/infra/crawl/handle.ts +693 -0
  518. package/src/infra/crawl/index.ts +9 -0
  519. package/src/infra/crawl/links.ts +160 -0
  520. package/src/infra/crawl/namespace.ts +36 -0
  521. package/src/infra/crawl/robots.ts +100 -0
  522. package/src/infra/crawl/schema.ts +89 -0
  523. package/src/infra/credit-line/handle.ts +883 -0
  524. package/src/infra/credit-line/index.ts +6 -0
  525. package/src/infra/credit-line/namespace.ts +7 -0
  526. package/src/infra/credit-line/schema.ts +96 -0
  527. package/src/infra/credits/handle.ts +706 -0
  528. package/src/infra/credits/index.ts +5 -0
  529. package/src/infra/credits/namespace.ts +7 -0
  530. package/src/infra/credits/schema.ts +83 -0
  531. package/src/infra/email/audit.ts +36 -0
  532. package/src/infra/email/inbound.ts +622 -0
  533. package/src/infra/email/index.ts +11 -0
  534. package/src/infra/email/mail.ts +517 -0
  535. package/src/infra/email/mime.ts +447 -0
  536. package/src/infra/email/namespace.ts +22 -0
  537. package/src/infra/email/providers.ts +111 -0
  538. package/src/infra/email/schema.ts +96 -0
  539. package/src/infra/email/sns.ts +200 -0
  540. package/src/infra/email/unsubscribe.ts +44 -0
  541. package/src/infra/fetch/address.ts +88 -0
  542. package/src/infra/fetch/connect-retry.ts +87 -0
  543. package/src/infra/fetch/handle.ts +329 -0
  544. package/src/infra/fetch/index.ts +7 -0
  545. package/src/infra/fetch/namespace.ts +70 -0
  546. package/src/infra/idempotency/index.ts +3 -0
  547. package/src/infra/idempotency/middleware.ts +87 -0
  548. package/src/infra/idempotency/store.ts +92 -0
  549. package/src/infra/idempotency/types.ts +30 -0
  550. package/src/infra/join-requests/handle.ts +312 -0
  551. package/src/infra/join-requests/index.ts +2 -0
  552. package/src/infra/join-requests/namespace.ts +7 -0
  553. package/src/infra/join-requests/schema.ts +33 -0
  554. package/src/infra/outbox/core.ts +165 -0
  555. package/src/infra/quota/errors.ts +32 -0
  556. package/src/infra/quota/handle.ts +215 -0
  557. package/src/infra/quota/index.ts +5 -0
  558. package/src/infra/quota/namespace.ts +7 -0
  559. package/src/infra/quota/schema.ts +15 -0
  560. package/src/infra/storage/backend.ts +34 -0
  561. package/src/infra/storage/handle.ts +513 -0
  562. package/src/infra/storage/index.ts +9 -0
  563. package/src/infra/storage/local.ts +104 -0
  564. package/src/infra/storage/namespace.ts +13 -0
  565. package/src/infra/storage/s3.ts +257 -0
  566. package/src/infra/storage/schema.ts +24 -0
  567. package/src/infra/support/handle.ts +854 -0
  568. package/src/infra/support/http.ts +229 -0
  569. package/src/infra/support/index.ts +7 -0
  570. package/src/infra/support/namespace.ts +12 -0
  571. package/src/infra/support/schema.ts +96 -0
  572. package/src/infra/webhook/inbound.ts +45 -0
  573. package/src/infra/webhook/index.ts +5 -0
  574. package/src/infra/webhook/namespace.ts +24 -0
  575. package/src/infra/webhook/outbound.ts +315 -0
  576. package/src/infra/webhook/sign.ts +32 -0
  577. package/src/infra/webhook/verify.ts +82 -0
  578. package/src/invariants/assert.ts +26 -0
  579. package/src/invariants/index.ts +1 -0
  580. package/src/lint/config.ts +56 -0
  581. package/src/lint/doctrine.ts +163 -0
  582. package/src/lint/include.ts +97 -0
  583. package/src/lint/index.ts +3 -0
  584. package/src/lint/preset.ts +10 -0
  585. package/src/lint/resolver.ts +218 -0
  586. package/src/lint/rules/no-reexports.ts +46 -0
  587. package/src/request/behavior/audited.ts +85 -0
  588. package/src/request/behavior/cached.ts +62 -0
  589. package/src/request/behavior/compose.ts +28 -0
  590. package/src/request/behavior/index.ts +5 -0
  591. package/src/request/behavior/namespace.ts +16 -0
  592. package/src/request/behavior/types.ts +26 -0
  593. package/src/request/behavior/versioned.ts +54 -0
  594. package/src/request/context/create.ts +103 -0
  595. package/src/request/context/guard.ts +49 -0
  596. package/src/request/context/index.ts +4 -0
  597. package/src/request/context/run-in-transaction.ts +200 -0
  598. package/src/request/context/store.ts +28 -0
  599. package/src/request/context/types.ts +50 -0
  600. package/src/request/di/builder.ts +535 -0
  601. package/src/request/di/index.ts +8 -0
  602. package/src/request/di/resolve.ts +271 -0
  603. package/src/request/di/types.ts +262 -0
  604. package/src/request/fitting/namespace.ts +7 -0
  605. package/src/request/fixture/batch.ts +71 -0
  606. package/src/request/fixture/builder.ts +26 -0
  607. package/src/request/fixture/errors.ts +10 -0
  608. package/src/request/fixture/index.ts +8 -0
  609. package/src/request/fixture/namespace.ts +23 -0
  610. package/src/request/fixture/paginate.ts +44 -0
  611. package/src/request/fixture/to-handlers.ts +260 -0
  612. package/src/request/fixture/types.ts +79 -0
  613. package/src/request/flow/act-as.ts +78 -0
  614. package/src/request/flow/namespace.ts +17 -0
  615. package/src/request/http/error-step.ts +42 -0
  616. package/src/request/http/file.ts +141 -0
  617. package/src/request/http/index.ts +4 -0
  618. package/src/request/http/middleware.ts +141 -0
  619. package/src/request/http/namespace.ts +5 -0
  620. package/src/request/http/rate-limit-classes.ts +170 -0
  621. package/src/request/http/response.ts +82 -0
  622. package/src/request/http/server.ts +916 -0
  623. package/src/request/http/sniff.ts +261 -0
  624. package/src/request/http/types.ts +250 -0
  625. package/src/request/http/upload.ts +284 -0
  626. package/src/request/internal/text.ts +6 -0
  627. package/src/request/openapi/generate.ts +205 -0
  628. package/src/request/openapi/index.ts +2 -0
  629. package/src/request/openapi/namespace.ts +7 -0
  630. package/src/test/auth.ts +13 -0
  631. package/src/test/auto-setup.ts +45 -0
  632. package/src/test/context.ts +91 -0
  633. package/src/test/crawl-fixture.ts +157 -0
  634. package/src/test/discover-fork.ts +17 -0
  635. package/src/test/fingerprint.ts +135 -0
  636. package/src/test/globals.d.ts +7 -0
  637. package/src/test/index.ts +19 -0
  638. package/src/test/namespace.ts +87 -0
  639. package/src/test/plugin.ts +189 -0
  640. package/src/test/progress.ts +185 -0
  641. package/src/test/reap-after-run.ts +28 -0
  642. package/src/test/reap.ts +286 -0
  643. package/src/test/reset.ts +253 -0
  644. package/src/test/savepoints.ts +172 -0
  645. package/src/test/setup.ts +1422 -0
  646. package/src/test/system-channel.ts +50 -0
  647. package/src/test/vitest-plugin.ts +142 -0
  648. package/src/test/vitest-workspace.ts +507 -0
  649. package/src/test/vitest.ts +333 -0
  650. package/src/test/watch.ts +105 -0
  651. package/src/trace/capture/bounded-serializer.ts +146 -0
  652. package/src/trace/cardinality/analyze.ts +173 -0
  653. package/src/trace/cardinality/branch-context.ts +214 -0
  654. package/src/trace/cardinality/check.ts +33 -0
  655. package/src/trace/cardinality/classify-edge.ts +64 -0
  656. package/src/trace/cardinality/structural-max.ts +107 -0
  657. package/src/trace/check/coverage-check.ts +188 -0
  658. package/src/trace/check/flow-check.ts +103 -0
  659. package/src/trace/check/flow-step-site.ts +234 -0
  660. package/src/trace/check/io-pattern.ts +116 -0
  661. package/src/trace/codemod/add-cardinality.ts +152 -0
  662. package/src/trace/codemod/run.ts +80 -0
  663. package/src/trace/entry/child-trace.ts +21 -0
  664. package/src/trace/entry/close-trace.ts +87 -0
  665. package/src/trace/entry/finalize-trace.ts +28 -0
  666. package/src/trace/entry/open-trace.ts +138 -0
  667. package/src/trace/entry/parent-trace.ts +20 -0
  668. package/src/trace/entry/parse-traceparent.ts +39 -0
  669. package/src/trace/entry/process-start.ts +38 -0
  670. package/src/trace/entry/trace-context.ts +26 -0
  671. package/src/trace/entry/tracing-enabled.ts +10 -0
  672. package/src/trace/external/record.ts +195 -0
  673. package/src/trace/external/report.ts +66 -0
  674. package/src/trace/namespace.ts +19 -0
  675. package/src/trace/partition/day.ts +47 -0
  676. package/src/trace/partition/index.ts +14 -0
  677. package/src/trace/partition/partition-name.ts +23 -0
  678. package/src/trace/partition/plan.ts +82 -0
  679. package/src/trace/partition/schedule.ts +26 -0
  680. package/src/trace/partition/startup-hook.ts +39 -0
  681. package/src/trace/partition/sync.ts +154 -0
  682. package/src/trace/partition/tables.ts +53 -0
  683. package/src/trace/read/tree.ts +83 -0
  684. package/src/trace/retain/copy-on-error.ts +76 -0
  685. package/src/trace/runtime/expire-stale-traces.ts +54 -0
  686. package/src/trace/runtime/flow-step.ts +147 -0
  687. package/src/trace/runtime/flush-steps.ts +31 -0
  688. package/src/trace/runtime/pending-writes.ts +54 -0
  689. package/src/trace/runtime/step-buffer.ts +298 -0
  690. package/src/trace/runtime/step-error.ts +21 -0
  691. package/src/trace/runtime/step-meta.ts +55 -0
  692. package/src/trace/runtime/thenable.ts +12 -0
  693. package/src/trace/runtime/truncate-trace.ts +62 -0
  694. package/src/trace/schema/trace-fields.ts +52 -0
  695. package/src/trace/schema/trace-retained.ts +22 -0
  696. package/src/trace/schema/trace-step-fields.ts +44 -0
  697. package/src/trace/schema/trace-step-retained.ts +25 -0
  698. package/src/trace/schema/trace-step.ts +18 -0
  699. package/src/trace/schema/trace.ts +12 -0
  700. package/src/trace/transformer/apply.ts +79 -0
  701. package/src/trace/transformer/build-meta-literal.ts +30 -0
  702. package/src/trace/transformer/find-flow-step-sites.ts +85 -0
  703. package/src/trace/transformer/inject-flow-step-import.ts +39 -0
  704. package/src/trace/transformer/transform-error.ts +14 -0
  705. package/src/trace/transformer/transform-flow-steps.ts +123 -0
  706. package/src/trace/transformer/wrap-function-declaration.ts +62 -0
  707. package/src/trace/transformer/wrap-variable-declaration.ts +67 -0
  708. package/src/workspace/affected.ts +110 -0
  709. package/src/workspace/changed-files.ts +163 -0
  710. package/src/workspace/check-deps.ts +213 -0
  711. package/src/workspace/checksum.ts +20 -0
  712. package/src/workspace/dependency-graph.ts +67 -0
  713. package/src/workspace/detect-pipework-copies.ts +93 -0
  714. package/src/workspace/discover.ts +206 -0
  715. package/src/workspace/generate.ts +401 -0
  716. package/src/workspace/index.ts +7 -0
  717. package/src/workspace/module-imports-pipework.ts +39 -0
  718. package/src/workspace/module-package-name.ts +12 -0
  719. package/src/workspace/scrub-git-env.ts +23 -0
  720. package/src/workspace/source-paths.ts +36 -0
  721. package/src/workspace/sync.ts +182 -0
  722. package/dist/REFERENCE.md +0 -1477
  723. package/dist/infra/access-links/rate-limit.d.ts +0 -10
  724. package/dist/infra/access-links/rate-limit.d.ts.map +0 -1
  725. package/dist/infra/access-links/rate-limit.js +0 -28
  726. package/dist/infra/access-links/rate-limit.js.map +0 -1
  727. package/dist/infra/email/sigv4.d.ts +0 -24
  728. package/dist/infra/email/sigv4.d.ts.map +0 -1
  729. package/dist/infra/email/sigv4.js +0 -55
  730. package/dist/infra/email/sigv4.js.map +0 -1
@@ -0,0 +1,488 @@
1
+ import { z } from 'zod/v4'
2
+ import type { StatementObserver } from './statement-observer.js'
3
+
4
+ const SETTING_NAME = /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)?$/
5
+
6
+ const databaseSchema = z.object({
7
+ url: z.string().describe('Environment variable name that holds the connection URL'),
8
+ testUrl: z.string().optional().describe('Environment variable name for the test database URL — required when environment is "test"'),
9
+ adminUrl: z.string().optional().describe('Environment variable name for the admin connection URL — used by `pipework db setup`'),
10
+ appUrl: z.string().optional().describe('Environment variable name for the runtime app-role connection URL — a non-owner, non-BYPASSRLS role that RLS policies enforce against. Runtime transactions use this; falls back to url when unset (RLS then inert).'),
11
+ appTestUrl: z.string().optional().describe('Environment variable name for the test app-role connection URL'),
12
+ systemUrl: z.string().optional().describe('Environment variable name for the platform-role connection URL — the role `pipe.system()` and `pipe.door()` run on when `rls.platformRole` is set. Must be a non-owner, non-BYPASSRLS, non-superuser role named `rls.platformRole`; it reaches a tenant table only through a declared door.'),
13
+ systemTestUrl: z.string().optional().describe('Environment variable name for the test platform-role connection URL'),
14
+ testOwnerUrl: z.string().optional().describe('Environment variable name for the connection URL whose ROLE migrates the test template — test mode only. Production migrates as the database owner, so a SECURITY DEFINER function a migration creates runs with that role\'s rights; in test the same function used to be owned by the ordinary test login and behaved differently. Point this at a role that owns migrated objects the way production does (typically BYPASSRLS). Only the template\'s migrations run on it: the template is still created, cloned, and connected to as testUrl, so the RLS bootstrap probe and tenant isolation are unchanged.'),
15
+ schema: z.union([z.string(), z.array(z.string())]).optional().describe('Path(s) or glob(s) to Drizzle table definition files, relative to repo root'),
16
+ migrations: z.string().optional().describe('Path to migrations directory, relative to repo root'),
17
+ extensions: z.array(z.string()).optional().describe('PostgreSQL extensions to ensure exist'),
18
+ migrationTable: z.string().optional().describe('Custom migration tracking table name'),
19
+ pool: z.object({
20
+ max: z.number().int().positive().optional(),
21
+ idleTimeout: z.number().int().nonnegative().optional(),
22
+ publishReservation: z.boolean().optional().describe('Publish this database\'s pool capacity (the sum of its pools\' `max`) to the server as pools are created and closed, so `pool.connectionBudget(name)` in any pipework process on the server can subtract it. Adds one presence connection per server and tags pool connections with application_name "pipework:<id>" (a `settings.application_name` of your own wins, and those connections are then counted as held but not attributed to this process). Default false.'),
23
+ settings: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).superRefine((settings, ctx) => {
24
+ for (const name of Object.keys(settings)) {
25
+ if (!SETTING_NAME.test(name)) {
26
+ ctx.addIssue({
27
+ code: 'custom',
28
+ path: [name],
29
+ message: `"${name}" is not a valid session setting name: use letters, digits and underscores, optionally one dot for a custom setting (for example "statement_timeout" or "myapp.tenant"). Fix: rename the key.`,
30
+ })
31
+ }
32
+ }
33
+ }).optional().describe('Session settings (GUCs) sent in the startup packet of every pooled connection, so a connection replaced at max_lifetime carries them again. An unknown non-dotted name makes the connection fail.'),
34
+ }).optional(),
35
+ rls: z.object({
36
+ sessionVar: z.string().default('pipework.tenant_id'),
37
+ force: z.boolean().default(true),
38
+ platformRole: z.string().regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, 'platformRole must be a plain Postgres role name (letters, digits, underscores)').optional().describe('Name of the platform role (set `systemUrl` to a connection as it). Setting it turns platform mode on: the system channel runs on that role, generated policies name it, and a tenant table is readable by it only through a door declared in `doors`.'),
39
+ }).optional(),
40
+ }).superRefine((db, ctx) => {
41
+ const platformRole = db.rls?.platformRole
42
+ if (db.systemUrl !== undefined && platformRole === undefined) {
43
+ ctx.addIssue({
44
+ code: 'custom',
45
+ path: ['systemUrl'],
46
+ message: '`systemUrl` is set but `rls.platformRole` is not. Fix: name the platform role in `rls: { platformRole: \'...\' }`, or remove `systemUrl`.',
47
+ })
48
+ }
49
+ if (platformRole !== undefined && db.systemUrl === undefined) {
50
+ ctx.addIssue({
51
+ code: 'custom',
52
+ path: ['rls', 'platformRole'],
53
+ message: `\`rls.platformRole\` ("${platformRole}") is set but \`systemUrl\` is not. Fix: set \`systemUrl\` (and \`systemTestUrl\`) to the environment variable that holds the connection URL for that role.`,
54
+ })
55
+ }
56
+ })
57
+
58
+ const DOOR_NAME = /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$/
59
+
60
+ const doorSchema = z.object({
61
+ table: z.string().regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, 'table is a plain SQL table name').describe('SQL name of the tenant-scoped table the door opens to SELECT'),
62
+ database: z.string().optional().describe('Database the table lives in; defaults to the default database'),
63
+ reason: z.string().min(1).describe('Why platform code reads this table across tenants'),
64
+ })
65
+
66
+ const testIsolationStrategy = z.enum(['transaction', 'database', 'container'])
67
+
68
+ const testSchema = z.object({
69
+ isolation: testIsolationStrategy.default('transaction'),
70
+ templateBuildWaitMs: z.number().int().positive().optional().describe(
71
+ 'How long a test process waits for another process to finish building the shared template before failing (default 120000)',
72
+ ),
73
+ dropBatchSize: z.number().int().positive().optional().describe(
74
+ 'How many finished per-file test databases pile up before they are dropped together (default 8). Every DROP DATABASE forces an immediate cluster-wide checkpoint that the dropping backend waits out, so dropping one per test file puts that wait on every teardown; 1 restores the drop-per-file behaviour',
75
+ ),
76
+ databasePerFile: z.boolean().optional().describe(
77
+ 'Give every test file its own freshly cloned database (default false). By default a test process clones its database once and returns it to the template\'s state between files, cloning again only when a file changed something a reset cannot undo (schema, database settings, prepared transactions, materialized views). true restores a clone and a queued drop per file; each clone writes the whole template to disk and each drop forces a checkpoint. A reset restores: every row of every table (cleared and reloaded to the clone\'s contents, even a change rolled back), every sequence, and the database\'s name (it is renamed before each file, so a timer, job loop or pool left by an earlier file cannot reach the next one\'s database). It does not restore, and the next file takes a fresh clone instead: schema (tables, columns, indexes, constraints, functions, triggers, policies, types, extensions), ALTER DATABASE settings and privileges, large objects, materialized view contents, prepared transactions, and rows of a table row-level security hides from the admin role (one it does not own); with such a table the database is not kept at all. Never restored: anything outside the database (roles and their settings, other databases, files, S3, caches in your process, module state, timers) and server statistics',
78
+ ),
79
+ setupStallMs: z.number().int().positive().optional().describe(
80
+ 'How long test setup may make no progress before it fails by name (default 120000). The bound is on phase advance, not on total elapsed time, so a healthy setup queued behind other processes never trips it',
81
+ ),
82
+ statementTimeoutMs: z.number().int().nonnegative().optional().describe(
83
+ 'statement_timeout set on every per-test database (default 120000; 0 disables). A test process killed mid-statement leaves a backend that runs to completion — Postgres notices a dead client only when it next writes to the socket — holding locks and blocking the drop',
84
+ ),
85
+ idleInTransactionTimeoutMs: z.number().int().nonnegative().optional().describe(
86
+ 'idle_in_transaction_session_timeout set on every per-test database (default 120000; 0 disables). Reaps a backend left inside an open transaction by a process killed between statements',
87
+ ),
88
+ clientCheckIntervalMs: z.number().int().nonnegative().optional().describe(
89
+ 'client_connection_check_interval set on every per-test database (default 1000; 0 disables). Makes a backend poll the client socket mid-statement and abort when the peer is gone, which is the case a statement_timeout alone waits out. Linux only; elsewhere Postgres accepts the setting and ignores it',
90
+ ),
91
+ databases: z.record(z.string(), z.object({
92
+ isolation: testIsolationStrategy.optional(),
93
+ })).optional(),
94
+ })
95
+
96
+ const environmentSchema = z.enum(['development', 'test', 'production'])
97
+
98
+ const releaseSchema = z.object({
99
+ env: z.string().min(1).describe('Name of the environment variable that holds the app\'s release (a deploy number, tag or commit)'),
100
+ requiredIn: z.array(environmentSchema).optional().describe('Environments in which the app refuses to start when the variable is unset or empty'),
101
+ })
102
+
103
+ const ioPatternKey = z.string().regex(
104
+ /^[A-Za-z_$][A-Za-z0-9_$]*(\.[A-Za-z_$][A-Za-z0-9_$]*)?$/,
105
+ 'I/O pattern must be a bare identifier ("fetch") or a single member access ("cache.get")',
106
+ )
107
+
108
+ const traceSchema = z.object({
109
+ hotRetentionDays: z.number().int().positive().default(7).describe('Days of `trace` / `trace_step` partitions kept before they are dropped'),
110
+ errorRetentionDays: z.number().int().positive().default(30).describe('Days of `trace_retained` / `trace_step_retained` partitions kept before they are dropped'),
111
+ partitionLeadDays: z.number().int().nonnegative().default(2).describe('Days of partitions pre-created ahead of today so writes never race partition creation'),
112
+ safetyFactor: z.number().int().positive().default(4).describe('Per-trace step cap is `structuralMax × safetyFactor`; the cap firing is a bug signal, not a load condition'),
113
+ structuralMax: z.number().int().nonnegative().optional().describe('Longest chain of `step` edges through the flow graph, derived by `pipework check` from `@downstream` annotations. Unset → no runtime cap (truncation never fires). Set by hand or copied from the value `pipework check` prints; the check refuses to pass if the configured value diverges from what the analyzer derives'),
114
+ captureInputs: z.boolean().default(true).describe('Tier-2 input capture kill-switch; set false to suppress `trace_step.captured_inputs` framework-wide while keeping Tier-1 (timing, status, error) intact'),
115
+ maxExternalSteps: z.number().int().nonnegative().default(1000).describe('Per-trace limit on steps recorded from outside the Node process with `trace.record`; they do not count against the structural step cap, and reports over the limit are dropped'),
116
+ io: z.record(ioPatternKey, z.enum(['read', 'write'])).optional().describe('Consumer extension of the Tier-2 I/O call-target registry. Keys are call patterns ("fetch" or "cache.get"); values declare whether the call is a read or a write. Patterns match lexically against the call\'s callee — no type resolution.'),
117
+ auditChunkSize: z.number().int().positive().default(5000).describe('Maximum audit rows emitted in a single write+audit statement. Bulk inserts under @flow_step that would exceed this are split into N chunks executed sequentially inside a transaction. Counted as `values.length × touches.length` so multi-target writes do not slip through. Engineering knob — the runtime always preserves atomicity across chunks via savepoint or transaction wrap.'),
118
+ })
119
+
120
+ const auditSchema = z.object({
121
+ retentionDays: z.union([z.number().int().positive(), z.literal('keep')]).default(365).describe('Days of `audit_record` partitions kept before they are dropped, or `\'keep\'` to never drop them (remove one tenant\'s records with `audit.removeTenant`); the audit substrate has its own retention independent of trace storage'),
122
+ chain: z.boolean().default(false).describe('Hash-link every `audit_record` row to the one before it, per tenant, so an edited or deleted row is detectable (`audit.verify`). Opt-in: a trigger takes a row lock on the tenant\'s chain head, so one tenant\'s audited writes serialize from the first audit row until their transaction commits'),
123
+ })
124
+
125
+ const valveSchema = z.object({})
126
+
127
+ const accessLinksSchema = z.object({})
128
+
129
+ const joinRequestsSchema = z.object({})
130
+
131
+ const creditsSchema = z.object({})
132
+
133
+ const creditLineSchema = z.object({})
134
+
135
+ const quotaSchema = z.object({})
136
+
137
+ const storageSchema = z.object({})
138
+ const crawlSchema = z.object({
139
+ requireApproval: z.boolean().default(false).describe('When true, `start` records a crawl as awaiting_approval and queues nothing until `approve(id)`'),
140
+ })
141
+ const alertsSchema = z.object({})
142
+ const supportSchema = z.object({})
143
+
144
+ const sessionsSchema = z.object({})
145
+
146
+ const orgsSchema = z.object({})
147
+
148
+ const passwordsSchema = z.object({})
149
+
150
+ const guardsSchema = z.object({})
151
+
152
+ const emailLinksSchema = z.object({})
153
+
154
+ const rateLimitsSchema = z.object({})
155
+
156
+ const emailSchema = z.object({})
157
+
158
+ // Issue #325 — opt-in fast path for `check` / `test`. The fast path may trade
159
+ // coverage (fewer modules/tiers now, all of it at the gate) but never accuracy.
160
+ const fastPathSchema = z.object({
161
+ default: z.enum(['fast', 'full']).default('full').describe('Verdict for a `check`/`test` invocation with no --fast/--full flag'),
162
+ baseBranches: z.array(z.string().regex(/^[A-Za-z0-9._/-]+$/)).optional().describe(
163
+ 'Base refs a branch-scoped diff (--fast, bare check/test) is taken against, first match wins. '
164
+ + 'Any committish works — a local branch, "origin/main", a tag. Default: [\'integration\', \'main\'].',
165
+ ),
166
+ test: z.object({
167
+ tiers: z.array(z.string()).default(['unit', 'contract', 'isolation']).describe('Test profiles a --fast run includes; property/stress tiers are deferred to the full run'),
168
+ propertyNumRuns: z.number().int().positive().optional().describe('fast-check numRuns for property tests on the fast path — a quantified statistical trade'),
169
+ }).optional(),
170
+ })
171
+
172
+ const observabilitySchema = z.object({
173
+ slowQueryMs: z.number().int().positive().optional().describe('Warn when a query exceeds this duration in ms'),
174
+ inFlightQueryMs: z.number().int().positive().optional().describe('While a statement is still running, log what it is waiting on every this many ms (unset = off)'),
175
+ logAllQueries: z.boolean().optional().describe('Log every query at debug level'),
176
+ poolMetricsInterval: z.number().int().nonnegative().optional().describe('Seconds between pool metric summaries (0 = disabled)'),
177
+ // NOT z.function(): in zod 4 that returns a *validating wrapper*, so the
178
+ // parsed value is not the function the caller passed (identity is lost, and
179
+ // every call pays argument validation) — on a hook that fires once per wire
180
+ // statement, both are disqualifying. z.custom admits the function unchanged.
181
+ onStatement: z.custom<StatementObserver>(v => typeof v === 'function', { message: 'Expected a function' })
182
+ .optional()
183
+ .describe('Per-statement observer — fires once per statement written to the wire, including driver-issued BEGIN/SAVEPOINT/COMMIT/ROLLBACK'),
184
+ })
185
+
186
+ const envVarDefSchema = z.discriminatedUnion('type', [
187
+ z.object({ type: z.literal('string'), required: z.boolean().optional(), default: z.string().optional(), sensitive: z.boolean().optional(), defaults: z.record(z.string(), z.string()).optional() }),
188
+ z.object({ type: z.literal('number'), required: z.boolean().optional(), default: z.number().optional(), sensitive: z.boolean().optional(), defaults: z.record(z.string(), z.string()).optional() }),
189
+ z.object({ type: z.literal('boolean'), required: z.boolean().optional(), default: z.boolean().optional(), sensitive: z.boolean().optional(), defaults: z.record(z.string(), z.string()).optional() }),
190
+ z.object({ type: z.literal('string[]'), separator: z.string().optional(), required: z.boolean().optional(), default: z.array(z.string()).optional(), sensitive: z.boolean().optional(), defaults: z.record(z.string(), z.string()).optional() }),
191
+ ])
192
+
193
+ const exportsValueSchema = z.union([
194
+ z.string().describe('Source file path — projected to { types, import } in dist'),
195
+ z.object({
196
+ types: z.string(),
197
+ import: z.string(),
198
+ }).describe('Explicit dist paths (escape hatch)'),
199
+ ])
200
+
201
+ const GENERATED_ONLY_MODULE_FIELDS = [
202
+ 'dependencies', 'devDependencies', 'peerDependencies', 'exports', 'scripts',
203
+ 'tsconfig', 'name', 'version', 'private', 'files', 'publishConfig',
204
+ ] as const
205
+
206
+ const moduleConfigSchema = z.object({
207
+ managed: z.boolean().optional().describe('false: the module\'s package.json and tsconfig files are hand-written; sync writes none of them, and the package name is read from its own package.json (default: true)'),
208
+ dependencies: z.record(z.string(), z.string()).optional().describe('Runtime dependencies (npm packages and workspace:* refs)'),
209
+ devDependencies: z.record(z.string(), z.string().nullable()).optional().describe('Dev dependencies merged with top-level defaults; null removes a key that would otherwise be generated (typescript, vitest, or a top-level devDependency)'),
210
+ peerDependencies: z.record(z.string(), z.string()).optional().describe('Peer dependencies for a shared/published "leaf" library — e.g. { pipework: "^0.14.0" } so each consuming workspace provides one pipework instance instead of the leaf bundling its own'),
211
+ exports: z.record(z.string(), exportsValueSchema).optional().describe('Export map — subpath → source file or { types, import }'),
212
+ scripts: z.record(z.string(), z.string().nullable()).optional().describe('npm scripts merged with defaults (build, lint, test, type-check); null removes a key, including a default'),
213
+ tsconfig: z.record(z.string(), z.unknown()).optional().describe('Merged into the module\'s tsconfig.json compilerOptions over the generated base, e.g. { noUnusedLocals: false } or { noUnusedParameters: true }'),
214
+ name: z.string().optional().describe('Override package name (default: @{project}/{basename})'),
215
+ version: z.string().optional().describe('Package version (default: 0.0.0)'),
216
+ private: z.boolean().optional().describe('Whether package is private (default: true)'),
217
+ files: z.array(z.string()).optional().describe('npm "files" allowlist for a published module'),
218
+ publishConfig: z.record(z.string(), z.unknown()).optional().describe('npm "publishConfig" (e.g. access, registry) for a published module'),
219
+ }).superRefine((mod, ctx) => {
220
+ if (mod.managed !== false) return
221
+ for (const field of GENERATED_ONLY_MODULE_FIELDS) {
222
+ if (mod[field] !== undefined) {
223
+ ctx.addIssue({
224
+ code: 'custom',
225
+ path: [field],
226
+ message: `"${field}" has no effect on a module with managed: false, because sync writes none of its package.json or tsconfig files. Fix: remove "${field}" (it belongs in the module's own package.json), or remove managed: false.`,
227
+ })
228
+ }
229
+ }
230
+ })
231
+
232
+ const coverageConfigSchema = z.object({
233
+ enabled: z.boolean().optional().describe(
234
+ 'Collect coverage for this run. Vitest treats coverage as a root-level option, so this ' +
235
+ 'belongs on the top-level `vitest.coverage` — a module or profile that sets `coverage` ' +
236
+ 'is refused by name rather than silently ignored. Gate it on an env var by computing ' +
237
+ 'the boolean in pipework.config.ts.',
238
+ ),
239
+ provider: z.enum(['v8', 'istanbul']).optional(),
240
+ include: z.array(z.string()).optional(),
241
+ exclude: z.array(z.string()).optional(),
242
+ reporter: z.array(z.string()).optional(),
243
+ reportsDirectory: z.string().optional(),
244
+ thresholds: z.object({
245
+ lines: z.number().min(0).max(100).optional(),
246
+ functions: z.number().min(0).max(100).optional(),
247
+ branches: z.number().min(0).max(100).optional(),
248
+ statements: z.number().min(0).max(100).optional(),
249
+ }).optional(),
250
+ })
251
+
252
+ const poolSchema = z.enum(['threads', 'forks', 'vmThreads', 'vmForks']).describe(
253
+ 'Vitest worker pool. Pipework defaults to "forks" — a test that sets a process-wide ' +
254
+ 'Postgres session must not share a worker with another.',
255
+ )
256
+
257
+ const vitestProfileSchema = z.object({
258
+ include: z.array(z.string()).optional(),
259
+ exclude: z.array(z.string()).optional().describe(
260
+ 'Extra exclude globs, MERGED with vitest\'s own defaults (node_modules, .git) rather ' +
261
+ 'than replacing them — vitest replaces, which silently un-excludes node_modules.',
262
+ ),
263
+ pool: poolSchema.optional(),
264
+ isolate: z.boolean().optional().describe(
265
+ 'Run each test file in a fresh worker. Pipework defaults to `false` — pipework\'s own ' +
266
+ 'per-test database isolation already separates test state, and re-isolating the worker ' +
267
+ 'costs a process spawn per file. Set `true` for a suite that relies on vitest\'s default.',
268
+ ),
269
+ database: z.boolean().optional(),
270
+ setupFiles: z.array(z.string()).optional(),
271
+ testTimeout: z.number().int().positive().optional(),
272
+ hookTimeout: z.number().int().positive().optional(),
273
+ env: z.record(z.string(), z.string()).optional(),
274
+ coverage: coverageConfigSchema.optional(),
275
+ extra: z.record(z.string(), z.unknown()).optional(),
276
+ manual: z.boolean().optional().describe('Exclude from default and --all runs — only run via --suite'),
277
+ })
278
+
279
+ const vitestModuleSchema = vitestProfileSchema.extend({
280
+ profiles: z.record(
281
+ z.string().refine(s => !s.includes(':'), 'Profile names cannot contain ":" — it is used as the project name separator'),
282
+ vitestProfileSchema,
283
+ ).optional(),
284
+ })
285
+
286
+ const lintModuleSchema = z.object({
287
+ include: z.array(z.string().min(1)).min(1).optional().describe(
288
+ 'File globs this module lints, relative to the module directory, replacing the default. ' +
289
+ 'Set it when the module\'s sources are not under `src` (e.g. ["app/src/**/*.ts"]). ' +
290
+ 'A module whose globs match no file fails the lint pass rather than reporting green.',
291
+ ),
292
+ rules: z.record(z.string(), z.unknown()).optional().describe(
293
+ 'Rule entries applied only to this module. Merged after `extra.rules`, so a module ' +
294
+ 'rule overrides the global one. Reference plugins registered via `extra.plugins`.',
295
+ ),
296
+ configs: z.array(z.unknown()).optional().describe(
297
+ 'Additional flat-config entries applied only to this module. Each entry is a ' +
298
+ 'standalone eslint flat-config block.',
299
+ ),
300
+ })
301
+
302
+ const lintSchema = z.object({
303
+ include: z.array(z.string().min(1)).min(1).optional().describe(
304
+ 'File globs every module lints, relative to the module directory, replacing the default. ' +
305
+ 'The default covers `src` plus the `src` of each workspace package under the module. ' +
306
+ 'Override per module with `modules.<path>.include`.',
307
+ ),
308
+ extra: z.object({
309
+ plugins: z.record(z.string(), z.unknown()).optional().describe(
310
+ 'Plugin instances registered in pipework\'s lint block (e.g. { react: reactPlugin }). ' +
311
+ 'Rules under `extra.rules` (or any `modules` entry) can then reference them as `pluginName/ruleName`.',
312
+ ),
313
+ rules: z.record(z.string(), z.unknown()).optional().describe(
314
+ 'Rule entries merged into pipework\'s lint block. ' +
315
+ 'Can override pipework defaults or add rules from `extra.plugins` or built-in eslint.',
316
+ ),
317
+ configs: z.array(z.unknown()).optional().describe(
318
+ 'Additional flat-config entries appended to the returned array (e.g. test-file overrides, ' +
319
+ 'per-glob rule relaxations). Each entry is a standalone eslint flat-config block.',
320
+ ),
321
+ }).optional().describe(
322
+ 'Consumer extensions to pipework\'s generated eslint config, applied everywhere. ' +
323
+ 'Pipework owns the base block (typescript-eslint plugin/parser, `pipework` plugin, default rules); ' +
324
+ '`extra` lets consumers register additional plugins, override or add rules, and append config blocks.',
325
+ ),
326
+ modules: z.record(z.string(), lintModuleSchema).optional().describe(
327
+ 'Per-module lint overrides keyed by relative path or glob (e.g. "packages/warehouse" or ' +
328
+ '"packages/*"), resolved the same way as the top-level `modules` map. Rules and config blocks ' +
329
+ 'declared here apply only to the matching module, on top of `extra`. Plugins stay global — ' +
330
+ 'register them under `extra.plugins` and reference their rules from any module.',
331
+ ),
332
+ })
333
+
334
+ const vitestSchema = z.object({
335
+ testTimeout: z.number().int().positive().optional(),
336
+ hookTimeout: z.number().int().positive().optional(),
337
+ inlineDeps: z.array(z.string().min(1)).optional(),
338
+ database: z.boolean().optional(),
339
+ include: z.array(z.string()).optional(),
340
+ exclude: z.array(z.string()).optional().describe(
341
+ 'Extra exclude globs, MERGED with vitest\'s own defaults (node_modules, .git) rather ' +
342
+ 'than replacing them — vitest replaces, which silently un-excludes node_modules.',
343
+ ),
344
+ pool: poolSchema.optional(),
345
+ isolate: z.boolean().optional().describe(
346
+ 'Run each test file in a fresh worker. Pipework defaults to `false`; set `true` for a ' +
347
+ 'suite that relies on vitest\'s own default. Overridable per module and per profile.',
348
+ ),
349
+ coverage: coverageConfigSchema.optional().describe(
350
+ 'Coverage, applied at the vitest root where vitest reads it. A module or profile that ' +
351
+ 'sets `coverage` is refused by name — vitest ignores coverage inside a project.',
352
+ ),
353
+ modules: z.record(z.string(), vitestModuleSchema).optional(),
354
+ extra: z.record(z.string(), z.unknown()).optional().describe(
355
+ 'Top-level vitest config — spread into defineConfig({...}). ' +
356
+ 'Put `test`-level keys (reporters, sequence, cache, bail, etc.) under `extra.test`; ' +
357
+ 'put outer Vite-level keys (resolve, plugins, etc.) at the top of `extra`. ' +
358
+ 'Pipework owns `test.projects` — define modules in `vitest.modules` instead.',
359
+ ),
360
+ })
361
+
362
+ const modulesSchema = z.record(
363
+ z.string(),
364
+ z.union([
365
+ moduleConfigSchema,
366
+ z.string().describe('Shorthand — empty config, value is ignored (key is the path)'),
367
+ ]),
368
+ ).describe('Modules keyed by relative path (or glob). Value is package.json fields or empty string shorthand.')
369
+
370
+ export const trunkConfigSchema = z.object({
371
+ doors: z.record(z.string().regex(DOOR_NAME, 'a door name is lowercase dotted words such as "admission.ledger"'), doorSchema).optional().describe('Named cross-tenant read doors. `pipe.door(name, fn)` reads the door\'s table across tenants on the platform role; generated migrations create a policy for exactly that table. Needs `rls.platformRole` on the door\'s database.'),
372
+ name: z.string().optional().describe('Project name — used as npm scope for generated packages'),
373
+ databases: z.record(z.string(), databaseSchema),
374
+ defaultDatabase: z.string().optional().describe('Name of the database a no-name `db()` / `pipe()` resolves to when multiple databases are configured — must be a key of `databases`. Unnecessary with a single database (that one is always the default).'),
375
+ scripts: z.record(z.string(), z.string()).optional().describe('Root-level npm scripts merged into generated package.json (preinstall is reserved)'),
376
+ packageManager: z.string()
377
+ .regex(
378
+ /^pnpm@\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/,
379
+ 'packageManager must be "pnpm@<major>.<minor>.<patch>" — the generated workspace is pnpm-only '
380
+ + '(pnpm-workspace.yaml, `pnpm install`), so npm and yarn are not accepted.',
381
+ )
382
+ .optional()
383
+ .describe('The packageManager field written to the generated root package.json. The pnpm version is a fact about your box, not about pipework; unset, pipework writes its own default.'),
384
+ dependencies: z.record(z.string(), z.string()).optional().describe('Root-level runtime dependencies'),
385
+ devDependencies: z.record(z.string(), z.string()).optional().describe('Shared dev dependencies — merged into every module'),
386
+ modules: modulesSchema.optional().describe('Module definitions keyed by path or glob'),
387
+ vitest: vitestSchema.optional().describe('Centralized vitest configuration — workspace defaults and per-module overrides'),
388
+ lint: lintSchema.optional().describe('Centralized eslint configuration — consumer plugins, rules, and extra flat-config blocks'),
389
+ environment: environmentSchema.optional(),
390
+ requireEnvironment: z.boolean().optional().describe('When true and `environment` is not set, an unset or unknown PIPEWORK_ENV / NODE_ENV is a ConfigError naming the variable and value, instead of resolving to development'),
391
+ release: releaseSchema.optional().describe('The release this process runs, read from an environment variable; written on every trace and on the job row of the worker that ran it'),
392
+ test: testSchema.optional(),
393
+ trace: traceSchema.optional().describe('Trace substrate retention and partitioning'),
394
+ audit: auditSchema.optional().describe('Audit substrate retention; independent of trace storage'),
395
+ valve: valveSchema.optional().describe('Valve substrate — opts the valve_crossing ledger table into generated migrations'),
396
+ accessLinks: accessLinksSchema.optional().describe('Access links — opts the access_link_code, access_link, access_link_use and access_link_check_spent tables into generated migrations'),
397
+ joinRequests: joinRequestsSchema.optional().describe('Join requests — opts the join_request table into generated migrations'),
398
+ credits: creditsSchema.optional().describe('Prepaid usage credits — opts the credit_grant, credit_reservation, credit_draw, credit_ledger and credit_account tables into generated migrations'),
399
+ creditLine: creditLineSchema.optional().describe('Postpaid credit line — opts the credit_line, credit_line_reservation, credit_line_entry, credit_line_payment, credit_line_payment_application and credit_line_authorization tables into generated migrations'),
400
+ quota: quotaSchema.optional().describe('Outbound quota — opts the outbound_quota table into generated migrations'),
401
+ alerts: alertsSchema.optional().describe('Alerts — opts the pipework_alerts, pipework_alert_deliveries and pipework_alert_source_state pipework_unit_faults and pipework_loop_beats tables into generated migrations'),
402
+ support: supportSchema.optional().describe('Support tickets — opts the support_ticket, support_message, support_link and support_event_delivery tables into generated migrations'),
403
+ crawl: crawlSchema.optional().describe('Site crawler — opts the pipework_crawl, pipework_crawl_url, pipework_crawl_host and pipework_crawl_resource tables into generated migrations; without it `crawl.create` refuses'),
404
+ storage: storageSchema.optional().describe('File storage — opts the storage_file table into generated migrations'),
405
+ sessions: sessionsSchema.optional().describe('Sessions — opts the pipework_refresh_tokens and pipework_auth_versions tables into generated migrations'),
406
+ orgs: orgsSchema.optional().describe('Multi-org — opts the pipework_user_orgs table into generated migrations'),
407
+ passwords: passwordsSchema.optional().describe('Password sign-in — opts the pipework_signin_attempts table into generated migrations'),
408
+ guards: guardsSchema.optional().describe('Guarded secrets — opts the pipework_guard_attempts table into generated migrations'),
409
+ emailLinks: emailLinksSchema.optional().describe('Emailed single-use links (password reset, address verification) — opts the pipework_email_links and pipework_email_link_requests tables into generated migrations'),
410
+ rateLimits: rateLimitsSchema.optional().describe('Per-route-class rate limits — opts the pipework_rate_limit_counts table into generated migrations'),
411
+ email: emailSchema.optional().describe('Email — opts the pipework_email_messages, pipework_email_suppressions, pipework_email_inbound and pipework_email_unsubscribes tables into generated migrations'),
412
+ fastPath: fastPathSchema.optional().describe('Opt-in fast path for `check` / `test` — affected-scoped, tier-trimmed iteration'),
413
+ observability: observabilitySchema.optional(),
414
+ env: z.record(z.string(), envVarDefSchema).optional().describe(
415
+ 'Declared environment variables — the canonical home for runtime config (ports, service tokens, '
416
+ + 'bucket names, feature flags). Each is read once, validated/coerced to its declared type, and exposed '
417
+ + 'typed on `manifold.env`, instead of scattered ad-hoc `process.env` reads across handlers.',
418
+ ),
419
+ }).superRefine((config, ctx) => {
420
+ const names = Object.keys(config.databases)
421
+ const defaultName = config.defaultDatabase ?? (names.length === 1 ? names[0] : undefined)
422
+ for (const [door, def] of Object.entries(config.doors ?? {})) {
423
+ if (door.startsWith('pipework.')) {
424
+ ctx.addIssue({
425
+ code: 'custom',
426
+ path: ['doors', door],
427
+ message: `door "${door}": names starting "pipework." are reserved for doors pipework declares itself. Fix: rename the door.`,
428
+ })
429
+ continue
430
+ }
431
+ const database = def.database ?? defaultName
432
+ if (database === undefined) {
433
+ ctx.addIssue({
434
+ code: 'custom',
435
+ path: ['doors', door, 'database'],
436
+ message: `door "${door}" names no database and there is no default database. Fix: set \`database\` on the door or \`defaultDatabase\` in the config.`,
437
+ })
438
+ continue
439
+ }
440
+ const db = config.databases[database]
441
+ if (db === undefined) {
442
+ ctx.addIssue({
443
+ code: 'custom',
444
+ path: ['doors', door, 'database'],
445
+ message: `door "${door}" names database "${database}", which is not declared. Declared databases: ${names.join(', ')}.`,
446
+ })
447
+ continue
448
+ }
449
+ if (db.rls?.platformRole === undefined) {
450
+ ctx.addIssue({
451
+ code: 'custom',
452
+ path: ['doors', door],
453
+ message: `door "${door}" is declared on database "${database}", which has no \`rls.platformRole\`. Doors need a platform role that is not BYPASSRLS. Fix: set \`rls.platformRole\` and \`systemUrl\` on "${database}", or remove the door.`,
454
+ })
455
+ }
456
+ }
457
+ })
458
+
459
+ export type Blueprint = z.infer<typeof trunkConfigSchema>
460
+ // The shape a caller passes to `createManifold` — fields with schema defaults
461
+ // (e.g. everything under `trace`) are optional here, where `Blueprint` (the
462
+ // parsed result) has them filled in.
463
+ export type BlueprintInput = z.input<typeof trunkConfigSchema>
464
+ export type DatabaseConfig = z.infer<typeof databaseSchema>
465
+ export type DoorConfig = z.infer<typeof doorSchema>
466
+ export type TestConfig = z.infer<typeof testSchema>
467
+ export type Environment = z.infer<typeof environmentSchema>
468
+ export type TraceConfig = z.infer<typeof traceSchema>
469
+ export type AuditConfig = z.infer<typeof auditSchema>
470
+ export type ValveConfig = z.infer<typeof valveSchema>
471
+ export type AccessLinksConfig = z.infer<typeof accessLinksSchema>
472
+ export type JoinRequestsBlueprintConfig = z.infer<typeof joinRequestsSchema>
473
+ export type CreditsBlueprintConfig = z.infer<typeof creditsSchema>
474
+ export type CreditLineBlueprintConfig = z.infer<typeof creditLineSchema>
475
+ export type QuotaBlueprintConfig = z.infer<typeof quotaSchema>
476
+ export type AlertsBlueprintConfig = z.infer<typeof alertsSchema>
477
+ export type CrawlBlueprintConfig = z.infer<typeof crawlSchema>
478
+ export type StorageBlueprintConfig = z.infer<typeof storageSchema>
479
+ export type FastPathConfig = z.infer<typeof fastPathSchema>
480
+ export type IsolationStrategy = z.infer<typeof testIsolationStrategy>
481
+ export type ObservabilityConfig = z.infer<typeof observabilitySchema>
482
+ export type ModuleConfig = z.infer<typeof moduleConfigSchema>
483
+ export type VitestConfig = z.infer<typeof vitestSchema>
484
+ export type LintConfig = z.infer<typeof lintSchema>
485
+ export type LintModuleConfig = z.infer<typeof lintModuleSchema>
486
+ export type VitestModuleConfig = z.infer<typeof vitestModuleSchema>
487
+ export type VitestProfileConfig = z.infer<typeof vitestProfileSchema>
488
+ export type CoverageConfig = z.infer<typeof coverageConfigSchema>
@@ -0,0 +1,48 @@
1
+ /**
2
+ * One statement as it is handed to the driver for writing to the wire —
3
+ * including the transaction-control statements the driver issues on its own
4
+ * (`BEGIN`, `SAVEPOINT`, `COMMIT`, `ROLLBACK`), which no application-level hook
5
+ * can see.
6
+ */
7
+ export interface StatementEvent {
8
+ /**
9
+ * The driver's connection ordinal — a process-local monotonic counter
10
+ * assigned when the connection object is constructed. It is NOT the
11
+ * PostgreSQL backend pid: it is unique and stable per connection for that
12
+ * connection's lifetime within this process, and meaningless across
13
+ * processes. Correct as a key for per-connection accounting (a transaction is
14
+ * pinned to one connection); wrong for correlating with `pg_stat_activity`.
15
+ */
16
+ readonly connectionId: number
17
+ /** The statement text, untruncated. */
18
+ readonly query: string
19
+ /** Bind parameters for this statement, in ordinal position. */
20
+ readonly parameters: readonly unknown[]
21
+ }
22
+
23
+ /**
24
+ * Caller-supplied per-statement observer. Fires once per statement written to
25
+ * the wire, on every connection the manifold owns — pooled connections and the
26
+ * test harness's own connections alike.
27
+ *
28
+ * Pure observation: the return value is discarded and the statement is never
29
+ * mutated. It runs synchronously on the driver's write path, so it must be
30
+ * cheap and must not throw.
31
+ *
32
+ * Counts wire truth, not application intent. Two consequences worth knowing
33
+ * before you assert on a total: the driver issues its own transaction control
34
+ * (`BEGIN`/`SAVEPOINT`/`COMMIT`/`ROLLBACK`), and it issues one `pg_catalog.pg_type`
35
+ * lookup per connection the first time that connection is used.
36
+ *
37
+ * Adds no leak surface. Installing an observer requires turning on the driver's
38
+ * `debug` hook, which would otherwise start serializing bind parameters onto
39
+ * every query error; pipework's driver error boundary puts those errors back to
40
+ * their unobserved shape, so **every statement path pipework mediates —
41
+ * `pipe()`, every `pipe.*` write, `connection.drizzle`, transactions and
42
+ * savepoints — exposes exactly what it exposed before**. The single exception
43
+ * is the raw `ManagedConnection.client` door: queries issued through it are
44
+ * outside the boundary and their errors do serialize bind parameters. Reading
45
+ * `.client` on an observed connection logs a warning saying so, once per
46
+ * database.
47
+ */
48
+ export type StatementObserver = (event: StatementEvent) => void
@@ -0,0 +1,75 @@
1
+ import { register } from 'node:module'
2
+ import { existsSync } from 'node:fs'
3
+
4
+ export const TS_HOOKS = Symbol.for('pipework.tsHooks')
5
+
6
+ export function registerTsResolveHooks(): void {
7
+ if (Reflect.get(globalThis, TS_HOOKS) !== undefined) return
8
+ // Built package: the compiled transforming hook sits beside this file, so every
9
+ // in-process CLI path (run, seed, ...) applies @flow_step like serve and dev do.
10
+ if (existsSync(new URL('./ts-resolve-hooks.js', import.meta.url))) {
11
+ register('./ts-resolve-hooks.js', import.meta.url)
12
+ Reflect.set(globalThis, TS_HOOKS, 'transforming')
13
+ return
14
+ }
15
+ {
16
+ // Marker contract: globalThis[Symbol.for('pipework.tsHooks')] is 'transforming'
17
+ // once the @flow_step-applying loader is installed (by ts-register.js, or by this
18
+ // function when the built ts-resolve-hooks.js sits beside it); a hook registered
19
+ // later would run first and shadow it, so then nothing more is installed.
20
+ // Source-mode runs, where the compiled hook does not exist, install one inline
21
+ // hook and mark 'inline'.
22
+ // Self-contained mirror of ts-resolve-hooks.ts, registered as a `data:` URL so
23
+ // it works during pipework's own source-mode runs where the compiled
24
+ // ts-resolve-hooks.js does not exist yet. `resolve` maps a relative specifier
25
+ // to its backing TS file (.js→.ts + extensionless); `load` fully transpiles it
26
+ // (parameter properties, enums, namespaces) via Node's bundled
27
+ // `stripTypeScriptTypes` — `--experimental-strip-types` only erases annotations
28
+ // and rejects those features. Keep resolve and strip in sync with ts-resolve-hooks.ts, which also applies @flow_step.
29
+ const code = `
30
+ import { existsSync } from 'node:fs'
31
+ import { readFile } from 'node:fs/promises'
32
+ import { fileURLToPath } from 'node:url'
33
+ import { stripTypeScriptTypes } from 'node:module'
34
+
35
+ function tsCandidates(specifier) {
36
+ const jsMatch = specifier.match(/\\.([cm]?)js$/);
37
+ if (jsMatch !== null) {
38
+ return [specifier.slice(0, -jsMatch[0].length) + '.' + (jsMatch[1] || '') + 'ts'];
39
+ }
40
+ if (/\\.[cm]?tsx?$/.test(specifier)) return [];
41
+ return [specifier + '.ts', specifier + '.js', specifier + '/index.ts', specifier + '/index.js'];
42
+ }
43
+
44
+ export function resolve(specifier, context, nextResolve) {
45
+ const parent = context.parentURL || '';
46
+ const isLocal = (specifier.startsWith('./') || specifier.startsWith('../'))
47
+ && !parent.includes('/node_modules/') && !parent.includes('/dist/');
48
+ if (isLocal) {
49
+ for (const candidate of tsCandidates(specifier)) {
50
+ let candidatePath = null;
51
+ try {
52
+ const url = new URL(candidate, parent);
53
+ if (url.protocol === 'file:') candidatePath = fileURLToPath(url);
54
+ } catch {}
55
+ if (candidatePath !== null && existsSync(candidatePath)) {
56
+ return nextResolve(candidate, context);
57
+ }
58
+ }
59
+ }
60
+ return nextResolve(specifier, context);
61
+ }
62
+
63
+ export async function load(url, context, nextLoad) {
64
+ if (url.endsWith('.ts') && !url.includes('/node_modules/')) {
65
+ const source = await readFile(fileURLToPath(url), 'utf8');
66
+ const transformed = stripTypeScriptTypes(source, { mode: 'transform', sourceMap: true, sourceUrl: url });
67
+ return { format: 'module', source: transformed, shortCircuit: true };
68
+ }
69
+ return nextLoad(url, context);
70
+ }
71
+ `
72
+ register(`data:text/javascript,${encodeURIComponent(code)}`)
73
+ Reflect.set(globalThis, TS_HOOKS, 'inline')
74
+ }
75
+ }
@@ -0,0 +1,4 @@
1
+ import { register } from 'node:module'
2
+ register('./ts-resolve-hooks.js', import.meta.url)
3
+ // Tells registerTsResolveHooks() this loader is installed; it must not shadow it.
4
+ Reflect.set(globalThis, Symbol.for('pipework.tsHooks'), 'transforming')