pipework 0.252.0 → 0.253.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (695) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/infra/support/handle.d.ts +8 -1
  3. package/dist/infra/support/handle.d.ts.map +1 -1
  4. package/dist/infra/support/handle.js +9 -2
  5. package/dist/infra/support/handle.js.map +1 -1
  6. package/dist/infra/support/namespace.d.ts.map +1 -1
  7. package/package.json +4 -3
  8. package/src/async/jobs/abortable-delay.ts +18 -0
  9. package/src/async/jobs/claims.ts +52 -0
  10. package/src/async/jobs/cron.ts +179 -0
  11. package/src/async/jobs/errors.ts +56 -0
  12. package/src/async/jobs/exclusion.ts +117 -0
  13. package/src/async/jobs/execute.ts +219 -0
  14. package/src/async/jobs/index.ts +10 -0
  15. package/src/async/jobs/listener.ts +135 -0
  16. package/src/async/jobs/namespace.ts +20 -0
  17. package/src/async/jobs/queue-door.ts +44 -0
  18. package/src/async/jobs/queue.ts +1012 -0
  19. package/src/async/jobs/run-script.ts +67 -0
  20. package/src/async/jobs/scheduler.ts +218 -0
  21. package/src/async/jobs/schedules-table.ts +37 -0
  22. package/src/async/jobs/serialize-error.ts +48 -0
  23. package/src/async/jobs/table.ts +191 -0
  24. package/src/async/pipeline/define.ts +53 -0
  25. package/src/async/pipeline/errors.ts +35 -0
  26. package/src/async/pipeline/execute.ts +53 -0
  27. package/src/async/pipeline/index.ts +13 -0
  28. package/src/async/pipeline/namespace.ts +12 -0
  29. package/src/async/pipeline/resume.ts +67 -0
  30. package/src/async/pipeline/run-steps.ts +98 -0
  31. package/src/async/pipeline/types.ts +57 -0
  32. package/src/async/state-machine/define.ts +64 -0
  33. package/src/async/state-machine/errors.ts +29 -0
  34. package/src/async/state-machine/index.ts +3 -0
  35. package/src/async/state-machine/namespace.ts +12 -0
  36. package/src/async/state-machine/transition.ts +90 -0
  37. package/src/async/state-machine/types.ts +37 -0
  38. package/src/async/steps/errors.ts +31 -0
  39. package/src/async/steps/graph.ts +1214 -0
  40. package/src/async/steps/hash.ts +40 -0
  41. package/src/async/steps/index.ts +7 -0
  42. package/src/async/steps/namespace.ts +7 -0
  43. package/src/async/steps/table.ts +97 -0
  44. package/src/async/steps/types.ts +318 -0
  45. package/src/audit/chain/index.ts +9 -0
  46. package/src/audit/chain/install.ts +113 -0
  47. package/src/audit/chain/retire.ts +52 -0
  48. package/src/audit/chain/verify.ts +257 -0
  49. package/src/audit/query/cursor.ts +37 -0
  50. package/src/audit/query/index.ts +9 -0
  51. package/src/audit/query/query.ts +223 -0
  52. package/src/audit/schema/audit-record-fields.ts +68 -0
  53. package/src/audit/schema/audit-record.ts +23 -0
  54. package/src/auth/auth/audit.ts +31 -0
  55. package/src/auth/auth/chain.ts +84 -0
  56. package/src/auth/auth/cookie.ts +136 -0
  57. package/src/auth/auth/email-links.ts +311 -0
  58. package/src/auth/auth/guard.ts +128 -0
  59. package/src/auth/auth/index.ts +18 -0
  60. package/src/auth/auth/multi-org.ts +337 -0
  61. package/src/auth/auth/namespace.ts +34 -0
  62. package/src/auth/auth/parse-expiry.ts +13 -0
  63. package/src/auth/auth/passwords.ts +110 -0
  64. package/src/auth/auth/schema.ts +110 -0
  65. package/src/auth/auth/sessions.ts +565 -0
  66. package/src/auth/auth/sign-in.ts +156 -0
  67. package/src/auth/auth/signing-keys.ts +69 -0
  68. package/src/auth/auth/types.ts +26 -0
  69. package/src/auth/auth/uuid.ts +10 -0
  70. package/src/auth/rbac/cache.ts +55 -0
  71. package/src/auth/rbac/check.ts +30 -0
  72. package/src/auth/rbac/create.ts +35 -0
  73. package/src/auth/rbac/index.ts +5 -0
  74. package/src/auth/rbac/middleware.ts +20 -0
  75. package/src/auth/rbac/namespace.ts +15 -0
  76. package/src/auth/rbac/resolve.ts +31 -0
  77. package/src/auth/rbac/schema.sql +31 -0
  78. package/src/auth/rbac/seed.ts +67 -0
  79. package/src/auth/rbac/tables.ts +32 -0
  80. package/src/auth/rbac/types.ts +65 -0
  81. package/src/auth/tenant/extract.ts +33 -0
  82. package/src/auth/tenant/in-tenant.ts +49 -0
  83. package/src/auth/tenant/index.ts +7 -0
  84. package/src/auth/tenant/namespace.ts +23 -0
  85. package/src/auth/tenant/propagate.ts +20 -0
  86. package/src/auth/tenant/rls.ts +120 -0
  87. package/src/auth/tenant/scope.ts +33 -0
  88. package/src/auth/tenant/scoped-db.ts +581 -0
  89. package/src/auth/tenant/types.ts +14 -0
  90. package/src/auth/tenant/validate.ts +27 -0
  91. package/src/cli/commands/add.ts +158 -0
  92. package/src/cli/commands/alerts.ts +98 -0
  93. package/src/cli/commands/check.ts +1418 -0
  94. package/src/cli/commands/codemod.ts +78 -0
  95. package/src/cli/commands/db.ts +356 -0
  96. package/src/cli/commands/dev.ts +101 -0
  97. package/src/cli/commands/generate.ts +75 -0
  98. package/src/cli/commands/init.ts +36 -0
  99. package/src/cli/commands/install.ts +28 -0
  100. package/src/cli/commands/lint.ts +62 -0
  101. package/src/cli/commands/migrate.ts +132 -0
  102. package/src/cli/commands/openapi.ts +63 -0
  103. package/src/cli/commands/remove.ts +72 -0
  104. package/src/cli/commands/run.ts +50 -0
  105. package/src/cli/commands/scope.ts +54 -0
  106. package/src/cli/commands/serve.ts +68 -0
  107. package/src/cli/commands/shard.ts +31 -0
  108. package/src/cli/commands/shared/config-pipework-version.ts +28 -0
  109. package/src/cli/commands/shared/find-config.ts +22 -0
  110. package/src/cli/commands/shared/load-config.ts +35 -0
  111. package/src/cli/commands/shared/pnpm-install.ts +95 -0
  112. package/src/cli/commands/shared/report-removed.ts +8 -0
  113. package/src/cli/commands/sync.ts +32 -0
  114. package/src/cli/commands/test.ts +307 -0
  115. package/src/cli/commands/upgrade.ts +48 -0
  116. package/src/cli/dev-bootstrap.ts +24 -0
  117. package/src/cli/errors.ts +10 -0
  118. package/src/cli/index.ts +303 -0
  119. package/src/cli/output.ts +17 -0
  120. package/src/cli/port.ts +15 -0
  121. package/src/cli/surface-kinds.ts +20 -0
  122. package/src/client/index.ts +4 -0
  123. package/src/client/poll.ts +130 -0
  124. package/src/client/report-fault.ts +119 -0
  125. package/src/core/config/app-pool.ts +19 -0
  126. package/src/core/config/aws-env.ts +29 -0
  127. package/src/core/config/base-dir.ts +24 -0
  128. package/src/core/config/discover.ts +64 -0
  129. package/src/core/config/env-resolve.ts +87 -0
  130. package/src/core/config/env-types.ts +116 -0
  131. package/src/core/config/env.ts +55 -0
  132. package/src/core/config/errors.ts +9 -0
  133. package/src/core/config/import-config.ts +40 -0
  134. package/src/core/config/index.ts +8 -0
  135. package/src/core/config/load.ts +417 -0
  136. package/src/core/config/namespace.ts +14 -0
  137. package/src/core/config/resolve.ts +195 -0
  138. package/src/core/config/schema.ts +488 -0
  139. package/src/core/config/statement-observer.ts +48 -0
  140. package/src/core/config/ts-inline-hooks.ts +75 -0
  141. package/src/core/config/ts-register.ts +4 -0
  142. package/src/core/config/ts-resolve-hooks.ts +101 -0
  143. package/src/core/errors/base.ts +49 -0
  144. package/src/core/errors/http.ts +146 -0
  145. package/src/core/errors/index.ts +2 -0
  146. package/src/core/errors/namespace.ts +31 -0
  147. package/src/core/lifecycle/drain.ts +33 -0
  148. package/src/core/lifecycle/health.ts +72 -0
  149. package/src/core/lifecycle/index.ts +4 -0
  150. package/src/core/lifecycle/namespace.ts +7 -0
  151. package/src/core/lifecycle/startup.ts +102 -0
  152. package/src/core/lifecycle/types.ts +36 -0
  153. package/src/core/logging/context.ts +60 -0
  154. package/src/core/logging/error-chain.ts +68 -0
  155. package/src/core/logging/index.ts +5 -0
  156. package/src/core/logging/logger.ts +65 -0
  157. package/src/core/logging/namespace.ts +16 -0
  158. package/src/core/logging/proxy.ts +22 -0
  159. package/src/core/logging/redact-match.ts +24 -0
  160. package/src/core/logging/types.ts +47 -0
  161. package/src/core/pipework.ts +566 -0
  162. package/src/core/runtime/broker.ts +69 -0
  163. package/src/core/surface/http.ts +133 -0
  164. package/src/core/surface/index.ts +11 -0
  165. package/src/core/surface/job-timeout.ts +40 -0
  166. package/src/core/surface/namespace.ts +13 -0
  167. package/src/core/surface/script.ts +33 -0
  168. package/src/core/surface/start.ts +142 -0
  169. package/src/core/surface/types.ts +225 -0
  170. package/src/core/surface/validate.ts +88 -0
  171. package/src/core/surface/worker.ts +528 -0
  172. package/src/core/validation/connectivity.ts +49 -0
  173. package/src/core/validation/domain.ts +99 -0
  174. package/src/core/validation/index.ts +5 -0
  175. package/src/core/validation/queue-tables.ts +312 -0
  176. package/src/core/validation/rls-role.ts +138 -0
  177. package/src/core/validation/startup.ts +51 -0
  178. package/src/core/validation/surfaces.ts +65 -0
  179. package/src/core/validation/types.ts +25 -0
  180. package/src/data/db/advisory-lock.ts +55 -0
  181. package/src/data/db/aggregates.ts +172 -0
  182. package/src/data/db/array-elements.ts +111 -0
  183. package/src/data/db/bulk-set.ts +53 -0
  184. package/src/data/db/col/index.ts +14 -0
  185. package/src/data/db/composed.ts +53 -0
  186. package/src/data/db/db.ts +276 -0
  187. package/src/data/db/excluded.ts +16 -0
  188. package/src/data/db/expressions.ts +473 -0
  189. package/src/data/db/filter.ts +90 -0
  190. package/src/data/db/function-source.ts +114 -0
  191. package/src/data/db/identifiers.ts +16 -0
  192. package/src/data/db/idx/index.ts +9 -0
  193. package/src/data/db/in-list.ts +49 -0
  194. package/src/data/db/index.ts +9 -0
  195. package/src/data/db/insert-split.ts +137 -0
  196. package/src/data/db/instrumentation.ts +82 -0
  197. package/src/data/db/maintenance.ts +28 -0
  198. package/src/data/db/namespace.ts +107 -0
  199. package/src/data/db/owner-labels.ts +9 -0
  200. package/src/data/db/pool.ts +187 -0
  201. package/src/data/db/query-label.ts +13 -0
  202. package/src/data/db/query-watch.ts +116 -0
  203. package/src/data/db/raw-client-warning.ts +37 -0
  204. package/src/data/db/readonly.ts +23 -0
  205. package/src/data/db/reservation.ts +151 -0
  206. package/src/data/db/schema-features.ts +14 -0
  207. package/src/data/db/serializable.ts +83 -0
  208. package/src/data/db/sql.ts +1 -0
  209. package/src/data/db/timeouts.ts +76 -0
  210. package/src/data/db/types.ts +18 -0
  211. package/src/data/db/unbound.ts +33 -0
  212. package/src/data/db/values.ts +29 -0
  213. package/src/data/domain/brand.ts +15 -0
  214. package/src/data/domain/build-factory.ts +193 -0
  215. package/src/data/domain/build-schema.ts +161 -0
  216. package/src/data/domain/build-table.ts +355 -0
  217. package/src/data/domain/define.ts +239 -0
  218. package/src/data/domain/external-registry.ts +34 -0
  219. package/src/data/domain/external.ts +77 -0
  220. package/src/data/domain/field.ts +279 -0
  221. package/src/data/domain/index.ts +13 -0
  222. package/src/data/domain/naming.ts +6 -0
  223. package/src/data/domain/projections.ts +57 -0
  224. package/src/data/domain/trace-safe-projection.ts +31 -0
  225. package/src/data/domain/traits.ts +108 -0
  226. package/src/data/domain/types.ts +289 -0
  227. package/src/data/jsonb/composed.ts +18 -0
  228. package/src/data/jsonb/index.ts +1 -0
  229. package/src/data/jsonb/namespace.ts +30 -0
  230. package/src/data/jsonb/query.ts +86 -0
  231. package/src/data/migrate/append-only-generate.ts +47 -0
  232. package/src/data/migrate/applied.ts +47 -0
  233. package/src/data/migrate/apply.ts +309 -0
  234. package/src/data/migrate/check.ts +119 -0
  235. package/src/data/migrate/diff.ts +357 -0
  236. package/src/data/migrate/door-generate.ts +130 -0
  237. package/src/data/migrate/framework-rls.ts +58 -0
  238. package/src/data/migrate/generate.ts +201 -0
  239. package/src/data/migrate/history.ts +215 -0
  240. package/src/data/migrate/index.ts +9 -0
  241. package/src/data/migrate/internal-definitions.ts +175 -0
  242. package/src/data/migrate/post-process.ts +73 -0
  243. package/src/data/migrate/pragma.ts +73 -0
  244. package/src/data/migrate/provision-framework.ts +147 -0
  245. package/src/data/migrate/rls-generate.ts +61 -0
  246. package/src/data/migrate/run.ts +124 -0
  247. package/src/data/migrate/safety.ts +167 -0
  248. package/src/data/migrate/snapshot.ts +368 -0
  249. package/src/data/migrate/sql-emit.ts +392 -0
  250. package/src/data/migrate/statements.ts +312 -0
  251. package/src/data/query/alias.ts +126 -0
  252. package/src/data/query/batch.ts +8 -0
  253. package/src/data/query/cache/core/cache.ts +78 -0
  254. package/src/data/query/cache/core/index.ts +1 -0
  255. package/src/data/query/cache/core/types.ts +29 -0
  256. package/src/data/query/cache/readme.md +230 -0
  257. package/src/data/query/casing.ts +76 -0
  258. package/src/data/query/collation.ts +11 -0
  259. package/src/data/query/column-builder.ts +370 -0
  260. package/src/data/query/column.ts +150 -0
  261. package/src/data/query/entity.ts +42 -0
  262. package/src/data/query/errors.ts +33 -0
  263. package/src/data/query/index.ts +14 -0
  264. package/src/data/query/logger.ts +47 -0
  265. package/src/data/query/operations.ts +45 -0
  266. package/src/data/query/pg-core/alias.ts +12 -0
  267. package/src/data/query/pg-core/checks.ts +32 -0
  268. package/src/data/query/pg-core/columns/all.ts +71 -0
  269. package/src/data/query/pg-core/columns/bigint.ts +110 -0
  270. package/src/data/query/pg-core/columns/bigserial.ts +128 -0
  271. package/src/data/query/pg-core/columns/boolean.ts +43 -0
  272. package/src/data/query/pg-core/columns/char.ts +85 -0
  273. package/src/data/query/pg-core/columns/cidr.ts +43 -0
  274. package/src/data/query/pg-core/columns/common.ts +366 -0
  275. package/src/data/query/pg-core/columns/custom.ts +232 -0
  276. package/src/data/query/pg-core/columns/date.common.ts +15 -0
  277. package/src/data/query/pg-core/columns/date.ts +112 -0
  278. package/src/data/query/pg-core/columns/double-precision.ts +55 -0
  279. package/src/data/query/pg-core/columns/enum.ts +201 -0
  280. package/src/data/query/pg-core/columns/index.ts +35 -0
  281. package/src/data/query/pg-core/columns/inet.ts +43 -0
  282. package/src/data/query/pg-core/columns/int.common.ts +57 -0
  283. package/src/data/query/pg-core/columns/integer.ts +53 -0
  284. package/src/data/query/pg-core/columns/interval.ts +83 -0
  285. package/src/data/query/pg-core/columns/json.ts +58 -0
  286. package/src/data/query/pg-core/columns/jsonb.ts +56 -0
  287. package/src/data/query/pg-core/columns/line.ts +117 -0
  288. package/src/data/query/pg-core/columns/macaddr.ts +43 -0
  289. package/src/data/query/pg-core/columns/macaddr8.ts +43 -0
  290. package/src/data/query/pg-core/columns/numeric.ts +227 -0
  291. package/src/data/query/pg-core/columns/point.ts +127 -0
  292. package/src/data/query/pg-core/columns/postgis_extension/geometry.ts +119 -0
  293. package/src/data/query/pg-core/columns/postgis_extension/utils.ts +47 -0
  294. package/src/data/query/pg-core/columns/real.ts +58 -0
  295. package/src/data/query/pg-core/columns/serial.ts +55 -0
  296. package/src/data/query/pg-core/columns/smallint.ts +53 -0
  297. package/src/data/query/pg-core/columns/smallserial.ts +60 -0
  298. package/src/data/query/pg-core/columns/text.ts +67 -0
  299. package/src/data/query/pg-core/columns/time.ts +72 -0
  300. package/src/data/query/pg-core/columns/timestamp.ts +163 -0
  301. package/src/data/query/pg-core/columns/uuid.ts +51 -0
  302. package/src/data/query/pg-core/columns/varchar.ts +89 -0
  303. package/src/data/query/pg-core/columns/vector_extension/bit.ts +68 -0
  304. package/src/data/query/pg-core/columns/vector_extension/halfvec.ts +80 -0
  305. package/src/data/query/pg-core/columns/vector_extension/sparsevec.ts +67 -0
  306. package/src/data/query/pg-core/columns/vector_extension/vector.ts +80 -0
  307. package/src/data/query/pg-core/db.ts +674 -0
  308. package/src/data/query/pg-core/dialect.ts +1404 -0
  309. package/src/data/query/pg-core/expressions.ts +25 -0
  310. package/src/data/query/pg-core/foreign-keys.ts +130 -0
  311. package/src/data/query/pg-core/index.ts +21 -0
  312. package/src/data/query/pg-core/indexes.ts +276 -0
  313. package/src/data/query/pg-core/policies.ts +56 -0
  314. package/src/data/query/pg-core/primary-keys.ts +62 -0
  315. package/src/data/query/pg-core/query-builders/count.ts +86 -0
  316. package/src/data/query/pg-core/query-builders/delete.ts +293 -0
  317. package/src/data/query/pg-core/query-builders/index.ts +7 -0
  318. package/src/data/query/pg-core/query-builders/insert.ts +452 -0
  319. package/src/data/query/pg-core/query-builders/query-builder.ts +123 -0
  320. package/src/data/query/pg-core/query-builders/query.ts +157 -0
  321. package/src/data/query/pg-core/query-builders/raw.ts +49 -0
  322. package/src/data/query/pg-core/query-builders/refresh-materialized-view.ts +108 -0
  323. package/src/data/query/pg-core/query-builders/select.ts +1346 -0
  324. package/src/data/query/pg-core/query-builders/select.types.ts +437 -0
  325. package/src/data/query/pg-core/query-builders/update.ts +626 -0
  326. package/src/data/query/pg-core/roles.ts +41 -0
  327. package/src/data/query/pg-core/schema.ts +72 -0
  328. package/src/data/query/pg-core/sequence.ts +41 -0
  329. package/src/data/query/pg-core/session.ts +292 -0
  330. package/src/data/query/pg-core/subquery.ts +46 -0
  331. package/src/data/query/pg-core/table.ts +252 -0
  332. package/src/data/query/pg-core/unique-constraint.ts +73 -0
  333. package/src/data/query/pg-core/utils/array.ts +95 -0
  334. package/src/data/query/pg-core/utils/index.ts +1 -0
  335. package/src/data/query/pg-core/utils.ts +104 -0
  336. package/src/data/query/pg-core/view-base.ts +14 -0
  337. package/src/data/query/pg-core/view-common.ts +1 -0
  338. package/src/data/query/pg-core/view.ts +435 -0
  339. package/src/data/query/pg-core/with-builder.ts +41 -0
  340. package/src/data/query/postgres-js/README.md +46 -0
  341. package/src/data/query/postgres-js/array-parser.ts +45 -0
  342. package/src/data/query/postgres-js/driver-error-boundary.ts +149 -0
  343. package/src/data/query/postgres-js/driver.ts +163 -0
  344. package/src/data/query/postgres-js/index.ts +2 -0
  345. package/src/data/query/postgres-js/session.ts +234 -0
  346. package/src/data/query/primary-key.ts +11 -0
  347. package/src/data/query/query-builders/query-builder.ts +19 -0
  348. package/src/data/query/query-builders/select.types.ts +175 -0
  349. package/src/data/query/query-promise.ts +35 -0
  350. package/src/data/query/relations.ts +725 -0
  351. package/src/data/query/runnable-query.ts +12 -0
  352. package/src/data/query/selection-proxy.ts +121 -0
  353. package/src/data/query/session.ts +8 -0
  354. package/src/data/query/sql/expressions/conditions.ts +741 -0
  355. package/src/data/query/sql/expressions/index.ts +2 -0
  356. package/src/data/query/sql/expressions/select.ts +45 -0
  357. package/src/data/query/sql/functions/aggregate.ts +129 -0
  358. package/src/data/query/sql/functions/index.ts +2 -0
  359. package/src/data/query/sql/functions/vector.ts +178 -0
  360. package/src/data/query/sql/index.ts +3 -0
  361. package/src/data/query/sql/sql.ts +794 -0
  362. package/src/data/query/subquery.ts +53 -0
  363. package/src/data/query/table.ts +208 -0
  364. package/src/data/query/table.utils.ts +2 -0
  365. package/src/data/query/tracing-utils.ts +3 -0
  366. package/src/data/query/tracing.ts +11 -0
  367. package/src/data/query/utils.ts +357 -0
  368. package/src/data/query/version.ts +4 -0
  369. package/src/data/query/view-common.ts +1 -0
  370. package/src/data/schema/branded.ts +13 -0
  371. package/src/data/schema/generated/coerce.ts +5 -0
  372. package/src/data/schema/generated/combinator.ts +6 -0
  373. package/src/data/schema/generated/encoding.ts +5 -0
  374. package/src/data/schema/generated/error.ts +6 -0
  375. package/src/data/schema/generated/format.ts +5 -0
  376. package/src/data/schema/generated/type-constructor.ts +10 -0
  377. package/src/data/schema/generated/type.ts +6 -0
  378. package/src/data/schema/index.ts +6 -0
  379. package/src/data/schema/json-schema.ts +33 -0
  380. package/src/data/schema/namespace.ts +55 -0
  381. package/src/data/schema/parse.ts +39 -0
  382. package/src/data/schema/types.ts +39 -0
  383. package/src/data/temporal/append-only.ts +134 -0
  384. package/src/data/temporal/close.ts +27 -0
  385. package/src/data/temporal/columns.ts +10 -0
  386. package/src/data/temporal/definition-queries.ts +70 -0
  387. package/src/data/temporal/errors.ts +10 -0
  388. package/src/data/temporal/get-current.ts +22 -0
  389. package/src/data/temporal/index.ts +9 -0
  390. package/src/data/temporal/namespace.ts +36 -0
  391. package/src/data/temporal/query.ts +25 -0
  392. package/src/data/temporal/resolve.ts +17 -0
  393. package/src/data/temporal/revise.ts +67 -0
  394. package/src/data/temporal/types.ts +22 -0
  395. package/src/data/valve/artifact.ts +33 -0
  396. package/src/data/valve/contract-diff.ts +21 -0
  397. package/src/data/valve/cross.ts +57 -0
  398. package/src/data/valve/crossing-ledger.ts +50 -0
  399. package/src/data/valve/decision.ts +44 -0
  400. package/src/data/valve/durable-crossing.ts +52 -0
  401. package/src/data/valve/execute-crossing.ts +77 -0
  402. package/src/data/valve/faucet.ts +56 -0
  403. package/src/data/valve/gate.ts +114 -0
  404. package/src/data/valve/graph.ts +77 -0
  405. package/src/data/valve/index.ts +53 -0
  406. package/src/data/valve/namespace.ts +57 -0
  407. package/src/data/valve/registry.ts +50 -0
  408. package/src/data/valve/schema/valve-crossing-fields.ts +23 -0
  409. package/src/data/valve/schema/valve-crossing.ts +9 -0
  410. package/src/data/valve/supply.ts +154 -0
  411. package/src/data/valve/types.ts +143 -0
  412. package/src/data/vector/columns.ts +27 -0
  413. package/src/data/vector/index.ts +4 -0
  414. package/src/data/vector/namespace.ts +33 -0
  415. package/src/data/vector/query.ts +85 -0
  416. package/src/data/vector/validate.ts +16 -0
  417. package/src/data/write/audit/actor.ts +15 -0
  418. package/src/data/write/audit/audit-columns.ts +18 -0
  419. package/src/data/write/audit/audit-select.ts +111 -0
  420. package/src/data/write/audit/bound-transaction.ts +14 -0
  421. package/src/data/write/audit/cte-compile.ts +32 -0
  422. package/src/data/write/audit/decode-returning.ts +47 -0
  423. package/src/data/write/audit/final-select.ts +43 -0
  424. package/src/data/write/audit/infra-audit.ts +36 -0
  425. package/src/data/write/audit/primary-key.ts +65 -0
  426. package/src/data/write/audit/projection.ts +41 -0
  427. package/src/data/write/audit/read-touches.ts +86 -0
  428. package/src/data/write/audit/touch-match.ts +78 -0
  429. package/src/data/write/audit/verb-delete.ts +62 -0
  430. package/src/data/write/audit/verb-insert.ts +36 -0
  431. package/src/data/write/audit/verb-select.ts +47 -0
  432. package/src/data/write/audit/verb-update.ts +60 -0
  433. package/src/data/write/audit/verb-upsert.ts +104 -0
  434. package/src/data/write/conflict.ts +43 -0
  435. package/src/data/write/delete.ts +38 -0
  436. package/src/data/write/execute.ts +243 -0
  437. package/src/data/write/index.ts +11 -0
  438. package/src/data/write/insert.ts +63 -0
  439. package/src/data/write/state.ts +43 -0
  440. package/src/data/write/update.ts +54 -0
  441. package/src/data/write/upsert.ts +58 -0
  442. package/src/data/write/values.ts +19 -0
  443. package/src/index.ts +230 -0
  444. package/src/infra/access-links/code.ts +70 -0
  445. package/src/infra/access-links/handle.ts +892 -0
  446. package/src/infra/access-links/index.ts +9 -0
  447. package/src/infra/access-links/namespace.ts +30 -0
  448. package/src/infra/access-links/person-check.ts +177 -0
  449. package/src/infra/access-links/schema.ts +71 -0
  450. package/src/infra/alerts/async-sources.ts +231 -0
  451. package/src/infra/alerts/audit.ts +36 -0
  452. package/src/infra/alerts/beat.ts +123 -0
  453. package/src/infra/alerts/client-faults.ts +111 -0
  454. package/src/infra/alerts/faults.ts +156 -0
  455. package/src/infra/alerts/handle.ts +778 -0
  456. package/src/infra/alerts/http.ts +192 -0
  457. package/src/infra/alerts/index.ts +12 -0
  458. package/src/infra/alerts/infra-sources.ts +180 -0
  459. package/src/infra/alerts/namespace.ts +81 -0
  460. package/src/infra/alerts/redact.ts +21 -0
  461. package/src/infra/alerts/request-faults.ts +41 -0
  462. package/src/infra/alerts/schema.ts +124 -0
  463. package/src/infra/alerts/sinks.ts +125 -0
  464. package/src/infra/alerts/source-options.ts +26 -0
  465. package/src/infra/alerts/sources.ts +503 -0
  466. package/src/infra/alerts/subsystem-sources.ts +137 -0
  467. package/src/infra/audit/emit.ts +87 -0
  468. package/src/infra/audit/index.ts +2 -0
  469. package/src/infra/audit/namespace.ts +22 -0
  470. package/src/infra/audit/schema.sql +35 -0
  471. package/src/infra/audit/types.ts +18 -0
  472. package/src/infra/aws/credentials.ts +147 -0
  473. package/src/infra/aws/sigv4.ts +140 -0
  474. package/src/infra/cache/create.ts +58 -0
  475. package/src/infra/cache/entry.ts +81 -0
  476. package/src/infra/cache/index.ts +4 -0
  477. package/src/infra/cache/namespace.ts +10 -0
  478. package/src/infra/cache/tenant.ts +93 -0
  479. package/src/infra/cache/types.ts +24 -0
  480. package/src/infra/crawl/audit.ts +35 -0
  481. package/src/infra/crawl/errors.ts +25 -0
  482. package/src/infra/crawl/handle.ts +693 -0
  483. package/src/infra/crawl/index.ts +9 -0
  484. package/src/infra/crawl/links.ts +160 -0
  485. package/src/infra/crawl/namespace.ts +36 -0
  486. package/src/infra/crawl/robots.ts +100 -0
  487. package/src/infra/crawl/schema.ts +89 -0
  488. package/src/infra/credit-line/handle.ts +883 -0
  489. package/src/infra/credit-line/index.ts +6 -0
  490. package/src/infra/credit-line/namespace.ts +7 -0
  491. package/src/infra/credit-line/schema.ts +96 -0
  492. package/src/infra/credits/handle.ts +706 -0
  493. package/src/infra/credits/index.ts +5 -0
  494. package/src/infra/credits/namespace.ts +7 -0
  495. package/src/infra/credits/schema.ts +83 -0
  496. package/src/infra/email/audit.ts +36 -0
  497. package/src/infra/email/inbound.ts +622 -0
  498. package/src/infra/email/index.ts +11 -0
  499. package/src/infra/email/mail.ts +517 -0
  500. package/src/infra/email/mime.ts +447 -0
  501. package/src/infra/email/namespace.ts +22 -0
  502. package/src/infra/email/providers.ts +111 -0
  503. package/src/infra/email/schema.ts +96 -0
  504. package/src/infra/email/sns.ts +200 -0
  505. package/src/infra/email/unsubscribe.ts +44 -0
  506. package/src/infra/fetch/address.ts +88 -0
  507. package/src/infra/fetch/connect-retry.ts +87 -0
  508. package/src/infra/fetch/handle.ts +329 -0
  509. package/src/infra/fetch/index.ts +7 -0
  510. package/src/infra/fetch/namespace.ts +70 -0
  511. package/src/infra/idempotency/index.ts +3 -0
  512. package/src/infra/idempotency/middleware.ts +87 -0
  513. package/src/infra/idempotency/store.ts +92 -0
  514. package/src/infra/idempotency/types.ts +30 -0
  515. package/src/infra/join-requests/handle.ts +312 -0
  516. package/src/infra/join-requests/index.ts +2 -0
  517. package/src/infra/join-requests/namespace.ts +7 -0
  518. package/src/infra/join-requests/schema.ts +33 -0
  519. package/src/infra/outbox/core.ts +165 -0
  520. package/src/infra/quota/errors.ts +32 -0
  521. package/src/infra/quota/handle.ts +215 -0
  522. package/src/infra/quota/index.ts +5 -0
  523. package/src/infra/quota/namespace.ts +7 -0
  524. package/src/infra/quota/schema.ts +15 -0
  525. package/src/infra/storage/backend.ts +34 -0
  526. package/src/infra/storage/handle.ts +513 -0
  527. package/src/infra/storage/index.ts +9 -0
  528. package/src/infra/storage/local.ts +104 -0
  529. package/src/infra/storage/namespace.ts +13 -0
  530. package/src/infra/storage/s3.ts +257 -0
  531. package/src/infra/storage/schema.ts +24 -0
  532. package/src/infra/support/handle.ts +869 -0
  533. package/src/infra/support/http.ts +229 -0
  534. package/src/infra/support/index.ts +7 -0
  535. package/src/infra/support/namespace.ts +12 -0
  536. package/src/infra/support/schema.ts +96 -0
  537. package/src/infra/webhook/inbound.ts +45 -0
  538. package/src/infra/webhook/index.ts +5 -0
  539. package/src/infra/webhook/namespace.ts +24 -0
  540. package/src/infra/webhook/outbound.ts +315 -0
  541. package/src/infra/webhook/sign.ts +32 -0
  542. package/src/infra/webhook/verify.ts +82 -0
  543. package/src/invariants/assert.ts +26 -0
  544. package/src/invariants/index.ts +1 -0
  545. package/src/lint/config.ts +56 -0
  546. package/src/lint/doctrine.ts +163 -0
  547. package/src/lint/include.ts +97 -0
  548. package/src/lint/index.ts +3 -0
  549. package/src/lint/preset.ts +10 -0
  550. package/src/lint/resolver.ts +218 -0
  551. package/src/lint/rules/no-reexports.ts +46 -0
  552. package/src/request/behavior/audited.ts +85 -0
  553. package/src/request/behavior/cached.ts +62 -0
  554. package/src/request/behavior/compose.ts +28 -0
  555. package/src/request/behavior/index.ts +5 -0
  556. package/src/request/behavior/namespace.ts +16 -0
  557. package/src/request/behavior/types.ts +26 -0
  558. package/src/request/behavior/versioned.ts +54 -0
  559. package/src/request/context/create.ts +103 -0
  560. package/src/request/context/guard.ts +49 -0
  561. package/src/request/context/index.ts +4 -0
  562. package/src/request/context/run-in-transaction.ts +200 -0
  563. package/src/request/context/store.ts +28 -0
  564. package/src/request/context/types.ts +50 -0
  565. package/src/request/di/builder.ts +535 -0
  566. package/src/request/di/index.ts +8 -0
  567. package/src/request/di/resolve.ts +271 -0
  568. package/src/request/di/types.ts +262 -0
  569. package/src/request/fitting/namespace.ts +7 -0
  570. package/src/request/fixture/batch.ts +71 -0
  571. package/src/request/fixture/builder.ts +26 -0
  572. package/src/request/fixture/errors.ts +10 -0
  573. package/src/request/fixture/index.ts +8 -0
  574. package/src/request/fixture/namespace.ts +23 -0
  575. package/src/request/fixture/paginate.ts +44 -0
  576. package/src/request/fixture/to-handlers.ts +260 -0
  577. package/src/request/fixture/types.ts +79 -0
  578. package/src/request/flow/act-as.ts +78 -0
  579. package/src/request/flow/namespace.ts +17 -0
  580. package/src/request/http/error-step.ts +42 -0
  581. package/src/request/http/file.ts +141 -0
  582. package/src/request/http/index.ts +4 -0
  583. package/src/request/http/middleware.ts +141 -0
  584. package/src/request/http/namespace.ts +5 -0
  585. package/src/request/http/rate-limit-classes.ts +170 -0
  586. package/src/request/http/response.ts +82 -0
  587. package/src/request/http/server.ts +916 -0
  588. package/src/request/http/sniff.ts +261 -0
  589. package/src/request/http/types.ts +250 -0
  590. package/src/request/http/upload.ts +284 -0
  591. package/src/request/internal/text.ts +6 -0
  592. package/src/request/openapi/generate.ts +205 -0
  593. package/src/request/openapi/index.ts +2 -0
  594. package/src/request/openapi/namespace.ts +7 -0
  595. package/src/test/auth.ts +13 -0
  596. package/src/test/auto-setup.ts +45 -0
  597. package/src/test/context.ts +91 -0
  598. package/src/test/crawl-fixture.ts +157 -0
  599. package/src/test/discover-fork.ts +17 -0
  600. package/src/test/fingerprint.ts +135 -0
  601. package/src/test/globals.d.ts +7 -0
  602. package/src/test/index.ts +19 -0
  603. package/src/test/namespace.ts +87 -0
  604. package/src/test/plugin.ts +189 -0
  605. package/src/test/progress.ts +185 -0
  606. package/src/test/reap-after-run.ts +28 -0
  607. package/src/test/reap.ts +286 -0
  608. package/src/test/reset.ts +253 -0
  609. package/src/test/savepoints.ts +172 -0
  610. package/src/test/setup.ts +1422 -0
  611. package/src/test/system-channel.ts +50 -0
  612. package/src/test/vitest-plugin.ts +142 -0
  613. package/src/test/vitest-workspace.ts +507 -0
  614. package/src/test/vitest.ts +333 -0
  615. package/src/test/watch.ts +105 -0
  616. package/src/trace/capture/bounded-serializer.ts +146 -0
  617. package/src/trace/cardinality/analyze.ts +173 -0
  618. package/src/trace/cardinality/branch-context.ts +214 -0
  619. package/src/trace/cardinality/check.ts +33 -0
  620. package/src/trace/cardinality/classify-edge.ts +64 -0
  621. package/src/trace/cardinality/structural-max.ts +107 -0
  622. package/src/trace/check/coverage-check.ts +188 -0
  623. package/src/trace/check/flow-check.ts +103 -0
  624. package/src/trace/check/flow-step-site.ts +234 -0
  625. package/src/trace/check/io-pattern.ts +116 -0
  626. package/src/trace/codemod/add-cardinality.ts +152 -0
  627. package/src/trace/codemod/run.ts +80 -0
  628. package/src/trace/entry/child-trace.ts +21 -0
  629. package/src/trace/entry/close-trace.ts +87 -0
  630. package/src/trace/entry/finalize-trace.ts +28 -0
  631. package/src/trace/entry/open-trace.ts +138 -0
  632. package/src/trace/entry/parent-trace.ts +20 -0
  633. package/src/trace/entry/parse-traceparent.ts +39 -0
  634. package/src/trace/entry/process-start.ts +38 -0
  635. package/src/trace/entry/trace-context.ts +26 -0
  636. package/src/trace/entry/tracing-enabled.ts +10 -0
  637. package/src/trace/external/record.ts +195 -0
  638. package/src/trace/external/report.ts +66 -0
  639. package/src/trace/namespace.ts +19 -0
  640. package/src/trace/partition/day.ts +47 -0
  641. package/src/trace/partition/index.ts +14 -0
  642. package/src/trace/partition/partition-name.ts +23 -0
  643. package/src/trace/partition/plan.ts +82 -0
  644. package/src/trace/partition/schedule.ts +26 -0
  645. package/src/trace/partition/startup-hook.ts +39 -0
  646. package/src/trace/partition/sync.ts +154 -0
  647. package/src/trace/partition/tables.ts +53 -0
  648. package/src/trace/read/tree.ts +83 -0
  649. package/src/trace/retain/copy-on-error.ts +76 -0
  650. package/src/trace/runtime/expire-stale-traces.ts +54 -0
  651. package/src/trace/runtime/flow-step.ts +147 -0
  652. package/src/trace/runtime/flush-steps.ts +31 -0
  653. package/src/trace/runtime/pending-writes.ts +54 -0
  654. package/src/trace/runtime/step-buffer.ts +298 -0
  655. package/src/trace/runtime/step-error.ts +21 -0
  656. package/src/trace/runtime/step-meta.ts +55 -0
  657. package/src/trace/runtime/thenable.ts +12 -0
  658. package/src/trace/runtime/truncate-trace.ts +62 -0
  659. package/src/trace/schema/trace-fields.ts +52 -0
  660. package/src/trace/schema/trace-retained.ts +22 -0
  661. package/src/trace/schema/trace-step-fields.ts +44 -0
  662. package/src/trace/schema/trace-step-retained.ts +25 -0
  663. package/src/trace/schema/trace-step.ts +18 -0
  664. package/src/trace/schema/trace.ts +12 -0
  665. package/src/trace/transformer/apply.ts +79 -0
  666. package/src/trace/transformer/build-meta-literal.ts +30 -0
  667. package/src/trace/transformer/find-flow-step-sites.ts +85 -0
  668. package/src/trace/transformer/inject-flow-step-import.ts +39 -0
  669. package/src/trace/transformer/transform-error.ts +14 -0
  670. package/src/trace/transformer/transform-flow-steps.ts +123 -0
  671. package/src/trace/transformer/wrap-function-declaration.ts +62 -0
  672. package/src/trace/transformer/wrap-variable-declaration.ts +67 -0
  673. package/src/workspace/affected.ts +110 -0
  674. package/src/workspace/changed-files.ts +163 -0
  675. package/src/workspace/check-deps.ts +213 -0
  676. package/src/workspace/checksum.ts +20 -0
  677. package/src/workspace/dependency-graph.ts +67 -0
  678. package/src/workspace/detect-pipework-copies.ts +93 -0
  679. package/src/workspace/discover.ts +206 -0
  680. package/src/workspace/generate.ts +401 -0
  681. package/src/workspace/index.ts +7 -0
  682. package/src/workspace/module-imports-pipework.ts +39 -0
  683. package/src/workspace/module-package-name.ts +12 -0
  684. package/src/workspace/scrub-git-env.ts +23 -0
  685. package/src/workspace/source-paths.ts +36 -0
  686. package/src/workspace/sync.ts +182 -0
  687. package/dist/REFERENCE.md +0 -1477
  688. package/dist/infra/access-links/rate-limit.d.ts +0 -10
  689. package/dist/infra/access-links/rate-limit.d.ts.map +0 -1
  690. package/dist/infra/access-links/rate-limit.js +0 -28
  691. package/dist/infra/access-links/rate-limit.js.map +0 -1
  692. package/dist/infra/email/sigv4.d.ts +0 -24
  693. package/dist/infra/email/sigv4.d.ts.map +0 -1
  694. package/dist/infra/email/sigv4.js +0 -55
  695. package/dist/infra/email/sigv4.js.map +0 -1
@@ -0,0 +1,417 @@
1
+ import { resolve } from 'node:path'
2
+ import { trunkConfigSchema, type Blueprint, type Environment, type DatabaseConfig, type IsolationStrategy } from './schema.js'
3
+ import { resolveEnvironment, resolveEnvironmentStrict, resolveDbUrl, resolveTestOwnerUrl } from './resolve.js'
4
+ import { ConfigError } from './errors.js'
5
+ import { resolveEnvVars } from './env-resolve.js'
6
+ import { consumeConfigBaseDir } from './base-dir.js'
7
+ import type { StatementObserver } from './statement-observer.js'
8
+
9
+ export interface ResolvedObservability {
10
+ readonly slowQueryMs: number
11
+ /** Interval at which a still-running statement is reported; undefined = off. */
12
+ readonly inFlightQueryMs?: number | undefined
13
+ readonly logAllQueries: boolean
14
+ readonly poolMetricsInterval: number
15
+ /** Caller-supplied per-statement observer; undefined when not configured. */
16
+ readonly onStatement: StatementObserver | undefined
17
+ }
18
+
19
+ export interface ResolvedTrace {
20
+ readonly hotRetentionDays: number
21
+ readonly errorRetentionDays: number
22
+ readonly partitionLeadDays: number
23
+ readonly safetyFactor: number
24
+ /** Unset → the runtime step cap is open (truncation never fires). Set → cap is `structuralMax × safetyFactor`. */
25
+ readonly structuralMax: number | undefined
26
+ readonly captureInputs: boolean
27
+ /** Per-trace limit on steps recorded from outside the Node process via `trace.record`; not part of the structural cap. */
28
+ readonly maxExternalSteps: number
29
+ /**
30
+ * Consumer-extension I/O registry (Q9). Keys are lexical call patterns —
31
+ * either a bare identifier (`"fetch"`) or a single member access
32
+ * (`"cache.get"`) — and values declare whether the call is a read or a
33
+ * write. The Tier-2 coverage check unions this with the stock pipework
34
+ * registry (`pipe.*` writes, `pipe(...)`-chain reads).
35
+ */
36
+ readonly io: Readonly<Record<string, 'read' | 'write'>>
37
+ /**
38
+ * Maximum audit rows emitted per write+audit CTE statement (Q8 / Phase 6c).
39
+ * Bulk inserts whose `values.length × touches.length` would exceed this are
40
+ * split into chunks executed sequentially inside a transaction (or savepoint
41
+ * when already nested). Engineering knob: defaults to 5000, never zero.
42
+ */
43
+ readonly auditChunkSize: number
44
+ }
45
+
46
+ export interface ResolvedAudit {
47
+ readonly retentionDays: number | 'keep'
48
+ }
49
+
50
+ export interface ResolvedConfig {
51
+ readonly raw: Blueprint
52
+ /** The environment this process runs as: Blueprint `environment`, else `PIPEWORK_ENV`, else `NODE_ENV` (test/production), else development. Read it here rather than from `process.env`. */
53
+ readonly environment: Environment
54
+ /** The release read from `release.env`; null when not configured, unset or empty. */
55
+ readonly release: string | null
56
+ readonly observability: ResolvedObservability
57
+ readonly trace: ResolvedTrace
58
+ readonly audit: ResolvedAudit
59
+ readonly env: Readonly<Record<string, unknown>>
60
+ /** Declared cross-tenant read doors, by name, each with its database resolved. */
61
+ readonly doors: Readonly<Record<string, ResolvedDoor>>
62
+ /** Doors pipework declares for its own substrates, only where the default database has `rls.platformRole`. */
63
+ readonly frameworkDoors: Readonly<Record<string, ResolvedDoor>>
64
+ database(name?: string): ResolvedDatabase
65
+ databases(): ReadonlyMap<string, ResolvedDatabase>
66
+ databaseNames(): readonly string[]
67
+ defaultDatabaseName(): string
68
+ isolationStrategy(dbName: string): IsolationStrategy
69
+ }
70
+
71
+ export interface ResolvedDoor {
72
+ readonly name: string
73
+ /** SQL table name. */
74
+ readonly table: string
75
+ /** The database the table lives in — the default database when the door names none. */
76
+ readonly database: string
77
+ readonly reason: string
78
+ /** A door pipework declares for its own work (named `pipework.*`); not in config. */
79
+ readonly framework?: true
80
+ /** Operations a framework door opens; an app door is SELECT-only. */
81
+ readonly ops?: readonly ('select' | 'update' | 'delete')[]
82
+ }
83
+
84
+ export interface ResolvedDatabase {
85
+ readonly name: string
86
+ readonly url: string
87
+ readonly appUrl?: string
88
+ /** Platform mode only: the connection `pipe.system()` and `pipe.door()` run on, as `rls.platformRole`. */
89
+ readonly systemUrl?: string
90
+ /** Test mode only: the connection whose role migrates the template. See `testOwnerUrl` in the config schema. */
91
+ readonly testOwnerUrl?: string
92
+ /** Directory relative `migrations`/`schema` paths resolve against — the config file's directory (process.cwd() for directly-constructed configs). */
93
+ readonly baseDir: string
94
+ /** Glob patterns stay as authored; consumers glob them with `cwd: baseDir`. */
95
+ readonly schema: string | string[] | undefined
96
+ /** Absolute — resolved against baseDir at load time, so cwd never matters (D1). */
97
+ readonly migrations: string | undefined
98
+ readonly extensions: readonly string[]
99
+ readonly migrationTable: string
100
+ readonly pool: { max: number; idleTimeout: number; readonly publishReservation?: boolean; readonly settings?: Readonly<Record<string, string>> }
101
+ readonly rls?: { readonly sessionVar: string; readonly force: boolean; readonly platformRole?: string }
102
+ }
103
+
104
+ export function loadConfig(raw: unknown): ResolvedConfig {
105
+ // Consume before validation so a parse failure cannot leave the slot set for
106
+ // an unrelated later load.
107
+ const baseDir = consumeConfigBaseDir() ?? process.cwd()
108
+ const parsed = trunkConfigSchema.safeParse(raw)
109
+ if (!parsed.success) {
110
+ const issues = parsed.error.issues.map(i => ` - ${i.path.join('.')}: ${i.message}`).join('\n')
111
+ throw new ConfigError(
112
+ `Invalid pipework.config.ts:\n${issues}`,
113
+ 'Check your pipework.config.ts against the expected schema.',
114
+ )
115
+ }
116
+
117
+ const config = parsed.data
118
+ const environment = config.environment
119
+ ?? (config.requireEnvironment === true ? resolveEnvironmentStrict() : resolveEnvironment())
120
+ return buildResolved(config, environment, baseDir)
121
+ }
122
+
123
+ function stringifySettings(settings: Readonly<Record<string, string | number | boolean>>): Readonly<Record<string, string>> {
124
+ const out: Record<string, string> = {}
125
+ for (const [k, v] of Object.entries(settings)) out[k] = typeof v === 'boolean' ? (v ? 'on' : 'off') : String(v)
126
+ return out
127
+ }
128
+
129
+ function resolveRelease(def: Blueprint['release'], environment: Environment): string | null {
130
+ if (def === undefined) return null
131
+ const value = process.env[def.env]
132
+ if (value !== undefined && value !== '') return value
133
+ if (def.requiredIn?.includes(environment) === true) {
134
+ throw new ConfigError(
135
+ `Environment variable ${def.env} is not set, but the release is required in environment "${environment}".`,
136
+ `Set ${def.env} to this deploy's release (for example ${def.env}=2026.10.3), or remove "${environment}" from release.requiredIn.`,
137
+ )
138
+ }
139
+ return null
140
+ }
141
+
142
+ function buildResolved(config: Blueprint, environment: Environment, baseDir: string): ResolvedConfig {
143
+ const dbMap = new Map<string, ResolvedDatabase>()
144
+
145
+ // Defined here, not inline in the accessor, so the app-pair carve-out below
146
+ // and `isolationStrategy()` cannot answer the same question differently.
147
+ const isolationStrategyFor = (dbName: string): IsolationStrategy =>
148
+ config.test?.databases?.[dbName]?.isolation ?? config.test?.isolation ?? 'transaction'
149
+
150
+ // URL resolution is attempted for EVERY database here, but a failure is not
151
+ // thrown until a URL is first accessed. Two recorded consumer defects drive
152
+ // this shape: refusing at load meant runs that never open a connection
153
+ // (type-only test legs, `check`) still demanded DB env; and throwing on the
154
+ // first failure surfaced missing variables one per run. So failures are
155
+ // collected across all databases and the aggregate is thrown lazily, naming
156
+ // everything that must be fixed at once.
157
+ const urlIssues: ConfigError[] = []
158
+ const collect = (fn: () => string): string | undefined => {
159
+ try {
160
+ return fn()
161
+ } catch (err) {
162
+ if (err instanceof ConfigError) {
163
+ urlIssues.push(err)
164
+ return undefined
165
+ }
166
+ throw err
167
+ }
168
+ }
169
+ const refuseUrls = (): never => {
170
+ const details = urlIssues
171
+ .map(e => ` - ${e.message.replace(/^\[pipework\] /, '').trimEnd().split('\n').join('\n ')}`)
172
+ .join('\n')
173
+ throw new ConfigError(
174
+ `Database URL resolution failed (${String(urlIssues.length)} problem${urlIssues.length === 1 ? '' : 's'}):\n\n${details}`,
175
+ 'Fix every item above — they are all reported in this one run.',
176
+ )
177
+ }
178
+
179
+ for (const [name, dbConfig] of Object.entries(config.databases)) {
180
+ const url = collect(() => resolveDbUrl(dbConfig.url, dbConfig.testUrl, environment, name))
181
+ const appUrl = dbConfig.appUrl !== undefined
182
+ ? collect(() => resolveDbUrl(dbConfig.appUrl!, dbConfig.appTestUrl, environment, name, { strategy: isolationStrategyFor(name) }))
183
+ : undefined
184
+ const systemUrl = dbConfig.systemUrl !== undefined
185
+ ? collect(() => resolveDbUrl(dbConfig.systemUrl!, dbConfig.systemTestUrl, environment, name, { strategy: isolationStrategyFor(name), role: 'system' }))
186
+ : undefined
187
+ // Outside test mode the field is inert — production already migrates as
188
+ // `url`'s role — so it is neither resolved nor exposed. `{ resolved }`
189
+ // rather than a bare string so a failed resolution is still a property
190
+ // that refuses on access, not a property that quietly went missing.
191
+ const testOwner = dbConfig.testOwnerUrl !== undefined && environment === 'test'
192
+ ? { resolved: collect(() => resolveTestOwnerUrl(dbConfig.testOwnerUrl!, url, name)) }
193
+ : undefined
194
+ dbMap.set(name, resolveDatabase(name, dbConfig, url, appUrl, systemUrl, testOwner, baseDir, refuseUrls))
195
+ }
196
+
197
+ const declaredNames = [...dbMap.keys()]
198
+
199
+ const defaultDbName = config.defaultDatabase
200
+ if (defaultDbName !== undefined && !dbMap.has(defaultDbName)) {
201
+ const suggestion = closestMatch(defaultDbName, declaredNames)
202
+ throw new ConfigError(
203
+ `defaultDatabase "${defaultDbName}" is not a declared database.`,
204
+ suggestion !== null
205
+ ? `Did you mean "${suggestion}"? Declared databases: ${declaredNames.join(', ')}`
206
+ : `Declared databases: ${declaredNames.join(', ')}`,
207
+ )
208
+ }
209
+
210
+ // The database resolved by a no-name db()/pipe(): the sole database, or the
211
+ // explicitly-configured defaultDatabase. Undefined only when multiple are
212
+ // declared with no default — genuine ambiguity, which both no-name resolvers
213
+ // surface as a ConfigError.
214
+ const resolveDefaultName = (): string | undefined => {
215
+ if (declaredNames.length === 1) return declaredNames[0]!
216
+ if (defaultDbName !== undefined) return defaultDbName
217
+ return undefined
218
+ }
219
+
220
+ const doors: Record<string, ResolvedDoor> = {}
221
+ for (const [doorName, door] of Object.entries(config.doors ?? {})) {
222
+ // The schema refused a door with no resolvable database.
223
+ doors[doorName] = Object.freeze({ name: doorName, table: door.table, database: door.database ?? resolveDefaultName()!, reason: door.reason })
224
+ }
225
+
226
+ const frameworkDoors: Record<string, ResolvedDoor> = {}
227
+ const defaultName = resolveDefaultName()
228
+ if (config.storage !== undefined && defaultName !== undefined && dbMap.get(defaultName)?.rls?.platformRole !== undefined) {
229
+ frameworkDoors['pipework.storage_sweep'] = Object.freeze({
230
+ name: 'pipework.storage_sweep', table: 'storage_file', database: defaultName,
231
+ reason: 'the storage sweep expires files and finds objects no file references, across tenants',
232
+ framework: true as const, ops: ['select', 'delete'] as const,
233
+ })
234
+ }
235
+
236
+ const release = resolveRelease(config.release, environment)
237
+
238
+ const env = Object.freeze(resolveEnvVars((config.env ?? {}) as import('./env-types.js').EnvDefs, environment))
239
+
240
+ return {
241
+ raw: config,
242
+ environment,
243
+ release,
244
+ observability: {
245
+ slowQueryMs: config.observability?.slowQueryMs ?? 500,
246
+ inFlightQueryMs: config.observability?.inFlightQueryMs,
247
+ logAllQueries: config.observability?.logAllQueries ?? false,
248
+ poolMetricsInterval: config.observability?.poolMetricsInterval ?? 0,
249
+ onStatement: config.observability?.onStatement,
250
+ },
251
+ trace: {
252
+ hotRetentionDays: config.trace?.hotRetentionDays ?? 7,
253
+ errorRetentionDays: config.trace?.errorRetentionDays ?? 30,
254
+ partitionLeadDays: config.trace?.partitionLeadDays ?? 2,
255
+ safetyFactor: config.trace?.safetyFactor ?? 4,
256
+ structuralMax: config.trace?.structuralMax,
257
+ captureInputs: config.trace?.captureInputs ?? true,
258
+ maxExternalSteps: config.trace?.maxExternalSteps ?? 1000,
259
+ io: Object.freeze({ ...(config.trace?.io ?? {}) }),
260
+ auditChunkSize: config.trace?.auditChunkSize ?? 5000,
261
+ },
262
+ audit: {
263
+ retentionDays: config.audit?.retentionDays ?? 365,
264
+ },
265
+ env,
266
+ doors: Object.freeze(doors),
267
+ frameworkDoors: Object.freeze(frameworkDoors),
268
+
269
+ database(name?: string): ResolvedDatabase {
270
+ if (name === undefined) {
271
+ const resolved = resolveDefaultName()
272
+ if (resolved !== undefined) {
273
+ return dbMap.get(resolved)!
274
+ }
275
+ throw new ConfigError(
276
+ 'Multiple databases configured — you must specify which one.',
277
+ `Declared databases: ${declaredNames.join(', ')}\n\n Use db("${declaredNames[0]}") to specify which database, or set defaultDatabase in pipework.config.ts.`,
278
+ )
279
+ }
280
+ const db = dbMap.get(name)
281
+ if (!db) {
282
+ const suggestion = closestMatch(name, declaredNames)
283
+ const hint = suggestion !== null
284
+ ? `Did you mean "${suggestion}"? Declared databases: ${declaredNames.join(', ')}`
285
+ : `Declared databases: ${declaredNames.join(', ')}`
286
+ throw new ConfigError(`Unknown database "${name}".`, hint)
287
+ }
288
+ return db
289
+ },
290
+
291
+ databases(): ReadonlyMap<string, ResolvedDatabase> {
292
+ return dbMap
293
+ },
294
+
295
+ databaseNames(): readonly string[] {
296
+ return declaredNames
297
+ },
298
+
299
+ defaultDatabaseName(): string {
300
+ const resolved = resolveDefaultName()
301
+ if (resolved !== undefined) {
302
+ return resolved
303
+ }
304
+ throw new ConfigError(
305
+ 'Multiple databases configured — you must specify which one.',
306
+ `Declared databases: ${declaredNames.join(', ')}\n\n Set defaultDatabase in pipework.config.ts to pick one.`,
307
+ )
308
+ },
309
+
310
+ isolationStrategy(dbName: string): IsolationStrategy {
311
+ return isolationStrategyFor(dbName)
312
+ },
313
+ }
314
+ }
315
+
316
+ function resolveDatabase(
317
+ name: string,
318
+ config: DatabaseConfig,
319
+ url: string | undefined,
320
+ appUrl: string | undefined,
321
+ systemUrl: string | undefined,
322
+ testOwner: { resolved: string | undefined } | undefined,
323
+ baseDir: string,
324
+ refuseUrls: () => never,
325
+ ): ResolvedDatabase {
326
+ const resolved = {
327
+ name,
328
+ baseDir,
329
+ schema: config.schema,
330
+ // Absolutized here — the single place — so every consumer (generate,
331
+ // migrate safety gate, test template provisioning) is cwd-independent.
332
+ // resolve(base, abs) === abs, so already-absolute consumer paths stay valid.
333
+ migrations: config.migrations !== undefined ? resolve(baseDir, config.migrations) : undefined,
334
+ extensions: config.extensions ?? [],
335
+ migrationTable: config.migrationTable ?? `__pipework_migrations_${name}`,
336
+ pool: {
337
+ max: config.pool?.max ?? 10,
338
+ idleTimeout: config.pool?.idleTimeout ?? 30,
339
+ ...(config.pool?.publishReservation === true ? { publishReservation: true } : {}),
340
+ ...(config.pool?.settings !== undefined ? { settings: stringifySettings(config.pool.settings) } : {}),
341
+ },
342
+ ...(config.rls !== undefined
343
+ ? { rls: { sessionVar: config.rls.sessionVar, force: config.rls.force, ...(config.rls.platformRole !== undefined ? { platformRole: config.rls.platformRole } : {}) } }
344
+ : {}),
345
+ }
346
+ // Lazy URL properties, attached with defineProperty rather than object
347
+ // literal getters: a getter in a spread source is evaluated BY the spread,
348
+ // which would turn the deferred refusal back into a load-time one. A URL
349
+ // that failed to resolve throws the aggregate refusal on first access, so
350
+ // config metadata (names, migrations, pool sizing) stays usable by code
351
+ // paths that never dial a connection.
352
+ Object.defineProperty(resolved, 'url', {
353
+ enumerable: true,
354
+ get: () => url ?? refuseUrls(),
355
+ })
356
+ if (config.appUrl !== undefined) {
357
+ Object.defineProperty(resolved, 'appUrl', {
358
+ enumerable: true,
359
+ get: () => appUrl ?? refuseUrls(),
360
+ })
361
+ }
362
+ if (config.systemUrl !== undefined) {
363
+ Object.defineProperty(resolved, 'systemUrl', {
364
+ enumerable: true,
365
+ get: () => systemUrl ?? refuseUrls(),
366
+ })
367
+ }
368
+ // Only in test mode does this property exist at all: outside it the field is
369
+ // configured but meaningless, and an absent property is what every consumer
370
+ // already reads as "migrate as the test login".
371
+ if (testOwner !== undefined) {
372
+ Object.defineProperty(resolved, 'testOwnerUrl', {
373
+ enumerable: true,
374
+ get: () => testOwner.resolved ?? refuseUrls(),
375
+ })
376
+ }
377
+ return resolved as unknown as ResolvedDatabase
378
+ }
379
+
380
+ function closestMatch(input: string, candidates: string[]): string | null {
381
+ if (candidates.length === 0) return null
382
+
383
+ let best: string | null = null
384
+ let bestDistance = Infinity
385
+
386
+ for (const candidate of candidates) {
387
+ const d = levenshtein(input.toLowerCase(), candidate.toLowerCase())
388
+ if (d < bestDistance && d <= Math.max(input.length, candidate.length) * 0.6) {
389
+ bestDistance = d
390
+ best = candidate
391
+ }
392
+ }
393
+
394
+ return best
395
+ }
396
+
397
+ function levenshtein(a: string, b: string): number {
398
+ const m = a.length
399
+ const n = b.length
400
+ const dp: number[][] = Array.from({ length: m + 1 }, () => Array.from({ length: n + 1 }, () => 0))
401
+
402
+ for (let i = 0; i <= m; i++) dp[i]![0] = i
403
+ for (let j = 0; j <= n; j++) dp[0]![j] = j
404
+
405
+ for (let i = 1; i <= m; i++) {
406
+ for (let j = 1; j <= n; j++) {
407
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1
408
+ dp[i]![j] = Math.min(
409
+ dp[i - 1]![j]! + 1,
410
+ dp[i]![j - 1]! + 1,
411
+ dp[i - 1]![j - 1]! + cost,
412
+ )
413
+ }
414
+ }
415
+
416
+ return dp[m]![n]!
417
+ }
@@ -0,0 +1,14 @@
1
+ import { loadConfig, trunkConfigSchema, ConfigError } from './index.js'
2
+ import { discoverInstance } from './discover.js'
3
+
4
+ /** Configuration namespace — loads and resolves Blueprint configs, discovers pipework.config.ts. */
5
+ export const config = {
6
+ /** Parses and resolves a raw Blueprint into a ResolvedConfig with environment detection. */
7
+ load: loadConfig,
8
+ /** Walks up from cwd to find pipework.config.ts, imports it, and returns the Manifold. */
9
+ discover: discoverInstance,
10
+ /** The zod schema for Blueprint validation — useful for custom config tooling. */
11
+ configSchema: trunkConfigSchema,
12
+ /** Thrown for configuration problems — includes a suggestion for how to fix. */
13
+ ConfigError,
14
+ }
@@ -0,0 +1,195 @@
1
+ import type { Environment, IsolationStrategy } from './schema.js'
2
+ import { ConfigError } from './errors.js'
3
+ import { appPoolCreated } from './app-pool.js'
4
+
5
+ /**
6
+ * Passed when resolving the app-role pair (`appUrl`/`appTestUrl`), which carries
7
+ * the transaction-isolation carve-out on value-identity. Absent when resolving
8
+ * the owner pair (`url`/`testUrl`), which has no carve-out: that connection is
9
+ * dialed under every strategy.
10
+ */
11
+ export interface AppRolePair {
12
+ /** This database's resolved test-isolation strategy. */
13
+ readonly strategy: IsolationStrategy
14
+ /** Which connection's fields the pair names in refusals; default `app`. */
15
+ readonly role?: 'app' | 'system'
16
+ }
17
+
18
+ const ENVIRONMENTS: readonly string[] = ['test', 'development', 'production']
19
+
20
+ /**
21
+ * Strict resolution for Blueprint `requireEnvironment`: PIPEWORK_ENV, then
22
+ * NODE_ENV, each of which must name a known environment. Unset or unknown
23
+ * is an error rather than development.
24
+ */
25
+ export function resolveEnvironmentStrict(): Environment {
26
+ const hint = 'Set PIPEWORK_ENV or NODE_ENV to development, test or production.'
27
+ const explicit = process.env['PIPEWORK_ENV']
28
+ if (explicit !== undefined && explicit !== '') {
29
+ if (ENVIRONMENTS.includes(explicit)) return explicit as Environment
30
+ throw new ConfigError(
31
+ `PIPEWORK_ENV is ${JSON.stringify(explicit)}, which is not an environment, and requireEnvironment is set.`,
32
+ hint,
33
+ )
34
+ }
35
+ const nodeEnv = process.env['NODE_ENV']
36
+ if (nodeEnv !== undefined && nodeEnv !== '') {
37
+ if (ENVIRONMENTS.includes(nodeEnv)) return nodeEnv as Environment
38
+ throw new ConfigError(
39
+ `NODE_ENV is ${JSON.stringify(nodeEnv)}, which is not an environment, and requireEnvironment is set.`,
40
+ hint,
41
+ )
42
+ }
43
+ throw new ConfigError(
44
+ 'Neither PIPEWORK_ENV nor NODE_ENV is set, and requireEnvironment is set.',
45
+ hint,
46
+ )
47
+ }
48
+
49
+ export function resolveEnvironment(): Environment {
50
+ const explicit = process.env['PIPEWORK_ENV']
51
+ if (explicit === 'test' || explicit === 'development' || explicit === 'production') {
52
+ return explicit
53
+ }
54
+
55
+ const nodeEnv = process.env['NODE_ENV']
56
+ if (nodeEnv === 'test') return 'test'
57
+ if (nodeEnv === 'production') return 'production'
58
+
59
+ return 'development'
60
+ }
61
+
62
+ export function resolveDbUrl(
63
+ envVarName: string,
64
+ testEnvVarName: string | undefined,
65
+ environment: Environment,
66
+ dbName?: string,
67
+ appRolePair?: AppRolePair,
68
+ ): string {
69
+ if (environment === 'test') {
70
+ // The pair being resolved, so every refusal below names the fields the
71
+ // reader actually has to edit rather than always saying url/testUrl.
72
+ const urlField = appRolePair === undefined ? 'url' : appRolePair.role === 'system' ? 'systemUrl' : 'appUrl'
73
+ const testUrlField = appRolePair === undefined ? 'testUrl' : appRolePair.role === 'system' ? 'systemTestUrl' : 'appTestUrl'
74
+
75
+ if (testEnvVarName === undefined) {
76
+ throw new ConfigError(
77
+ `Database "${dbName ?? envVarName}" has no ${testUrlField} configured, but environment is "test".`,
78
+ `Add ${testUrlField} to your database config:\n\n` +
79
+ ` databases: {\n` +
80
+ ` ${dbName ?? 'app'}: {\n` +
81
+ ` ${urlField}: '${envVarName}',\n` +
82
+ ` ${testUrlField}: '${envVarName}_TEST', // <-- add this\n` +
83
+ ` },\n` +
84
+ ` }\n\n` +
85
+ `Then set ${envVarName}_TEST in your environment.`,
86
+ )
87
+ }
88
+
89
+ // D4a (subseam audit 2026-07-16): a testUrl that resolves to the real
90
+ // database means "tests" run against production — the harness
91
+ // creates/drops databases and rolls back transactions on what it assumes
92
+ // is a dedicated instance, and RLS-inertness goes unnoticed. Name-identity
93
+ // first: both fields reading one variable is a config-shape defect,
94
+ // regardless of what the variable holds.
95
+ if (testEnvVarName === envVarName) {
96
+ throw new ConfigError(
97
+ `Database "${dbName ?? envVarName}" uses the same environment variable "${envVarName}" for ${urlField} and ${testUrlField} — test isolation is defeated.`,
98
+ `${testUrlField} must be its own variable pointing at a separate database:\n\n` +
99
+ ` databases: {\n` +
100
+ ` ${dbName ?? 'app'}: {\n` +
101
+ ` ${urlField}: '${envVarName}',\n` +
102
+ ` ${testUrlField}: '${envVarName}_TEST', // <-- its own variable\n` +
103
+ ` },\n` +
104
+ ` }\n\n` +
105
+ `Then set ${envVarName}_TEST to a separate database's connection string.`,
106
+ )
107
+ }
108
+
109
+ const value = process.env[testEnvVarName]
110
+ if (value !== undefined && value !== '') {
111
+ const urlValue = process.env[envVarName]
112
+ // 0.17.1: value-identity on the app-role pair is a false positive under a
113
+ // strategy that never creates the app-role pool — the value satisfies
114
+ // config resolution and is then never dialed by it. The refusal stands
115
+ // wherever the pool IS created, and for the owner pair in every mode.
116
+ // Name-identity above is NOT carved out: one env var serving both fields
117
+ // carries no intent and cannot be told from a typo.
118
+ const inert = appRolePair !== undefined && !appPoolCreated(appRolePair.strategy)
119
+ if (!inert && urlValue !== undefined && urlValue !== '' && urlValue === value) {
120
+ throw new ConfigError(
121
+ `Database "${dbName ?? envVarName}": "${testEnvVarName}" and "${envVarName}" hold the identical connection string — test isolation is defeated.`,
122
+ `Tests would run against the same database "${envVarName}" points at. ` +
123
+ `Point ${testEnvVarName} at a separate database.` +
124
+ (appRolePair !== undefined
125
+ ? `\n\nIdentical app-role values are accepted only under "transaction" isolation, ` +
126
+ `where the harness overrides every role onto one rolled-back connection and the ` +
127
+ `app-role pool is never created. This database resolves to "${appRolePair.strategy}" ` +
128
+ `isolation, which creates it — so ${testEnvVarName} is genuinely dialed here.`
129
+ : ''),
130
+ )
131
+ }
132
+ return value
133
+ }
134
+
135
+ throw new ConfigError(
136
+ `Missing test database URL: environment variable "${testEnvVarName}" is not set.`,
137
+ `Set ${testEnvVarName} in .env.test (or .env.test.local for a machine-local value) or in your environment.`,
138
+ )
139
+ }
140
+
141
+ const value = process.env[envVarName]
142
+ if (value !== undefined && value !== '') return value
143
+
144
+ throw new ConfigError(
145
+ `Missing database URL: environment variable "${envVarName}" is not set.`,
146
+ `Set ${envVarName} in your .env file or environment.`,
147
+ )
148
+ }
149
+
150
+
151
+ /**
152
+ * Resolve `testOwnerUrl`: the connection whose ROLE migrates the test template.
153
+ *
154
+ * Outside test mode there is no such thing — production migrates as `url`'s
155
+ * role already — so this is only ever called with `environment === 'test'`.
156
+ *
157
+ * No identity refusal against `url` here, and deliberately so: the field names
158
+ * the variable holding the owner's credentials, and a venue that exports one
159
+ * `DATABASE_URL` per role set legitimately points this at the same variable
160
+ * name `url` uses. What that variable holds in test mode is the test cluster's
161
+ * owner. The isolation refusals stay where they belong, on `url`/`testUrl`,
162
+ * which is the connection tests actually run on.
163
+ */
164
+ export function resolveTestOwnerUrl(
165
+ envVarName: string,
166
+ testUrl: string | undefined,
167
+ dbName: string,
168
+ ): string {
169
+ const value = process.env[envVarName]
170
+ if (value === undefined || value === '') {
171
+ throw new ConfigError(
172
+ `Database "${dbName}": testOwnerUrl names "${envVarName}", which is not set.`,
173
+ `Set ${envVarName} to a connection string for the role that should migrate the test ` +
174
+ `template, or remove testOwnerUrl to migrate as the test login.`,
175
+ )
176
+ }
177
+
178
+ // The template is CREATEd on testUrl's server and then migrated on this one.
179
+ // Two different servers means the migrations land in a database nobody
180
+ // clones, and the template gets cloned empty — a silent, bewildering failure
181
+ // that is cheap to refuse here.
182
+ if (testUrl !== undefined) {
183
+ const owner = new URL(value)
184
+ const test = new URL(testUrl)
185
+ if (owner.host !== test.host) {
186
+ throw new ConfigError(
187
+ `Database "${dbName}": testOwnerUrl ("${envVarName}") points at ${owner.host}, but the test database is on ${test.host}.`,
188
+ `The template is created on the test server and migrated as the owner, so both must ` +
189
+ `be the same server. Point ${envVarName} at ${test.host}.`,
190
+ )
191
+ }
192
+ }
193
+
194
+ return value
195
+ }