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,157 @@
1
+ import { createServer, type IncomingHttpHeaders, type IncomingMessage, type ServerResponse } from 'node:http'
2
+ import { connect as netConnect, type AddressInfo, type Socket } from 'node:net'
3
+ import { readFile, stat } from 'node:fs/promises'
4
+ import { extname, join, normalize, sep } from 'node:path'
5
+ import type { FetchTarget } from '../infra/fetch/index.js'
6
+
7
+ const PUBLIC_ADDRESS = '93.184.216.34'
8
+
9
+ const TYPES: Record<string, string> = {
10
+ '.html': 'text/html', '.htm': 'text/html', '.xhtml': 'application/xhtml+xml', '.txt': 'text/plain',
11
+ '.pdf': 'application/pdf', '.xml': 'application/xml', '.css': 'text/css', '.js': 'text/javascript',
12
+ '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpeg',
13
+ }
14
+
15
+ /** What one path of a fixture site does instead of serving a file. */
16
+ export interface CrawlFixtureRoute {
17
+ /** Answer with a redirect to this URL (status 302 unless `status` is given). */
18
+ readonly redirect?: string
19
+ /** Answer with this status and no body (with `redirect`: the redirect's status). */
20
+ readonly status?: number
21
+ /** Wait this long before answering. */
22
+ readonly delayMs?: number
23
+ /** Answer 200 with this many generated bytes, streamed and never on disk, without a Content-Length. */
24
+ readonly bytes?: number
25
+ /** Content type of the generated bytes; default `application/pdf`. */
26
+ readonly contentType?: string
27
+ }
28
+
29
+ export interface CrawlFixtureOptions {
30
+ /** The directory served as every host's site: `/` is `index.html`, `/robots.txt` is the file of that name. Files carry an ETag and Last-Modified, and an `If-None-Match` that matches is answered 304. */
31
+ readonly root: string
32
+ /** The names that resolve, each to a fake public address (or the address given); any other name does not resolve. */
33
+ readonly hosts: readonly string[] | Readonly<Record<string, string>>
34
+ /** Per-path behaviour, keyed by the URL's path (`/big.pdf`), or by host and path (`example.test/`) for one host only; the host form wins. */
35
+ readonly routes?: Readonly<Record<string, CrawlFixtureRoute>>
36
+ }
37
+
38
+ /** One request the fixture server received. */
39
+ export interface CrawlFixtureRequest {
40
+ readonly method: string
41
+ /** The Host header without the port. */
42
+ readonly host: string
43
+ /** Path and query. */
44
+ readonly path: string
45
+ /** `Date.now()` when the request arrived. */
46
+ readonly at: number
47
+ readonly headers: IncomingHttpHeaders
48
+ }
49
+
50
+ export interface CrawlFixtureSite {
51
+ /** Pass as the `network` option of `crawl.create` (or `untrustedFetch.get`'s `resolve` and `connect`). */
52
+ readonly network: {
53
+ resolve: (hostname: string) => Promise<string[]>
54
+ connect: (target: FetchTarget) => Socket
55
+ }
56
+ /** Every request received, oldest first. */
57
+ readonly requests: CrawlFixtureRequest[]
58
+ close(): Promise<void>
59
+ }
60
+
61
+ function safePath(root: string, urlPath: string): string | null {
62
+ let decoded: string
63
+ try { decoded = decodeURIComponent(urlPath) } catch { return null }
64
+ const full = normalize(join(root, decoded))
65
+ const base = normalize(root)
66
+ return full === base || full.startsWith(base.endsWith(sep) ? base : base + sep) ? full : null
67
+ }
68
+
69
+ async function serveFile(root: string, pathname: string, req: IncomingMessage, res: ServerResponse): Promise<void> {
70
+ let file = safePath(root, pathname)
71
+ if (file === null) { res.statusCode = 400; res.end(); return }
72
+ try {
73
+ if ((await stat(file)).isDirectory()) file = join(file, 'index.html')
74
+ const info = await stat(file)
75
+ const etag = `"${info.size.toString(16)}-${Math.floor(info.mtimeMs).toString(16)}"`
76
+ res.setHeader('etag', etag)
77
+ res.setHeader('last-modified', info.mtime.toUTCString())
78
+ if (req.headers['if-none-match'] === etag) { res.statusCode = 304; res.end(); return }
79
+ const body = await readFile(file)
80
+ res.setHeader('content-type', TYPES[extname(file).toLowerCase()] ?? 'application/octet-stream')
81
+ res.end(body)
82
+ } catch {
83
+ res.statusCode = 404
84
+ res.setHeader('content-type', 'text/plain')
85
+ res.end('not found')
86
+ }
87
+ }
88
+
89
+ function streamBytes(res: ServerResponse, total: number, contentType: string): void {
90
+ res.setHeader('content-type', contentType)
91
+ const chunk = Buffer.alloc(64 * 1024, 0x25)
92
+ let sent = 0
93
+ let closed = false
94
+ res.on('close', () => { closed = true })
95
+ const pump = (): void => {
96
+ while (!closed && sent < total) {
97
+ const piece = sent + chunk.length <= total ? chunk : chunk.subarray(0, total - sent)
98
+ sent += piece.length
99
+ if (!res.write(piece)) { res.once('drain', pump); return }
100
+ }
101
+ if (!closed) res.end()
102
+ }
103
+ pump()
104
+ }
105
+
106
+ /**
107
+ * Serves a directory as a website on a local server, for testing a crawl with no outside fetch. `network` makes the
108
+ * hosts in `hosts` resolve to a fake public address and sends their connections to the local server, so the real
109
+ * address rules still run: a host not in `hosts` (such as `127.0.0.1`) is refused as it would be live. Use plain
110
+ * `http://<host>/` URLs; the port is the fixture's. Every request is recorded in `requests`.
111
+ */
112
+ export async function crawlFixtureSite(options: CrawlFixtureOptions): Promise<CrawlFixtureSite> {
113
+ const addresses: Record<string, string> = Array.isArray(options.hosts)
114
+ ? Object.fromEntries((options.hosts as readonly string[]).map(h => [h, PUBLIC_ADDRESS]))
115
+ : { ...(options.hosts as Record<string, string>) }
116
+ const requests: CrawlFixtureRequest[] = []
117
+ const sockets = new Set<Socket>()
118
+ const server = createServer((req, res) => {
119
+ const url = new URL(req.url ?? '/', 'http://fixture.invalid')
120
+ const host = (req.headers.host ?? '').replace(/:\d+$/, '')
121
+ requests.push({ method: req.method ?? 'GET', host, path: url.pathname + url.search, at: Date.now(), headers: req.headers })
122
+ const route = options.routes?.[`${host}${url.pathname}`] ?? options.routes?.[url.pathname]
123
+ const respond = async (): Promise<void> => {
124
+ if (route?.redirect !== undefined) {
125
+ res.statusCode = route.status ?? 302
126
+ res.setHeader('location', route.redirect)
127
+ res.end()
128
+ } else if (route?.bytes !== undefined) {
129
+ streamBytes(res, route.bytes, route.contentType ?? 'application/pdf')
130
+ } else if (route?.status !== undefined) {
131
+ res.statusCode = route.status
132
+ res.end()
133
+ } else {
134
+ await serveFile(options.root, url.pathname, req, res)
135
+ }
136
+ }
137
+ if (route?.delayMs !== undefined) setTimeout(() => { void respond() }, route.delayMs)
138
+ else void respond()
139
+ })
140
+ server.on('connection', s => { sockets.add(s); s.on('close', () => sockets.delete(s)) })
141
+ await new Promise<void>(resolve => server.listen(0, '127.0.0.1', resolve))
142
+ const port = (server.address() as AddressInfo).port
143
+ return {
144
+ network: {
145
+ resolve: (hostname) => {
146
+ const found = addresses[hostname]
147
+ return found === undefined ? Promise.reject(new Error('ENOTFOUND')) : Promise.resolve([found])
148
+ },
149
+ connect: () => netConnect(port, '127.0.0.1'),
150
+ },
151
+ requests,
152
+ close: async () => {
153
+ for (const s of sockets) s.destroy()
154
+ await new Promise<void>(resolve => server.close(() => resolve()))
155
+ },
156
+ }
157
+ }
@@ -0,0 +1,17 @@
1
+ import type { Manifold } from '../core/pipework.js'
2
+ import { discoverInstance } from '../core/config/discover.js'
3
+
4
+ /**
5
+ * Load this test fork's manifold and consume `PIPEWORK_CONFIG`.
6
+ *
7
+ * The override has exactly one reader: this fork's discovery. It is unset once
8
+ * that read succeeds, so nothing a test spawns — another package's `pipework
9
+ * migrate`, a CLI under test — inherits it and migrates the wrong package
10
+ * against the wrong manifold. Discovery failing leaves it set: the variable is
11
+ * part of the diagnosis.
12
+ */
13
+ export async function discoverForTestFork(): Promise<Manifold> {
14
+ const instance = await discoverInstance()
15
+ delete process.env['PIPEWORK_CONFIG']
16
+ return instance
17
+ }
@@ -0,0 +1,135 @@
1
+ import { createHash } from 'node:crypto'
2
+ import { readdirSync, readFileSync } from 'node:fs'
3
+ import { join, relative, sep } from 'node:path'
4
+ import type { Blueprint } from '../core/config/schema.js'
5
+ import type { ResolvedDatabase } from '../core/config/index.js'
6
+ import { VERSION } from '../core/runtime/broker.js'
7
+
8
+ // The template is keyed by its CONTENT, not by the run that happened to build
9
+ // it. Every input that changes what ends up inside a template database is
10
+ // folded into one hash, and that hash becomes the template's name — so a
11
+ // migration edit does not invalidate a template, it simply asks for a
12
+ // different one, and the stale one is reaped because nobody asks for it again.
13
+ //
14
+ // Content keying is what lets a template outlive the process that built it:
15
+ // a vitest run with `pool: 'forks'` + `isolate: true` gives every test file a
16
+ // fresh process, and a per-process key (pid, run nonce) meant every one of them
17
+ // replayed the whole migration stack. Issue #340.
18
+
19
+ /** Bump when pipework changes the SHAPE of what it puts in a template. */
20
+ const TEMPLATE_FORMAT_VERSION = 2
21
+
22
+ /**
23
+ * Everything that determines a template's contents. Serialized and hashed;
24
+ * anything omitted here is something two runs may disagree about while still
25
+ * sharing a template, so omissions are the way stale reuse happens.
26
+ */
27
+ export interface TemplateInputs {
28
+ /** Which configured database this template stands in for. */
29
+ readonly databaseName: string
30
+ /**
31
+ * The role that builds — and therefore owns — the template.
32
+ *
33
+ * `CREATE DATABASE ... WITH TEMPLATE` requires ownership of the template, so
34
+ * a template is only shareable among processes connecting as the same role.
35
+ * Keying on the owner means a second role builds its own rather than failing
36
+ * to clone, or worse, trying to drop a database it does not own.
37
+ */
38
+ readonly owner: string
39
+ /**
40
+ * The role the template's migrations run as, when `testOwnerUrl` names one.
41
+ *
42
+ * It decides who OWNS every migrated object, which decides what a
43
+ * `SECURITY DEFINER` function made by a migration can read. Omitted entirely
44
+ * when unconfigured, so a template built without the field keeps its name.
45
+ */
46
+ readonly migrationOwner?: string
47
+ readonly extensions: readonly string[]
48
+ readonly migrationTable: string
49
+ /** Hash of the migrations folder's contents, or `null` when unmigrated. */
50
+ readonly migrations: string | null
51
+ /** Framework-table provisioning depends on these blueprint sections. */
52
+ readonly trace: unknown
53
+ readonly audit: unknown
54
+ /** Framework tables ride the default database only. */
55
+ readonly isDefaultDatabase: boolean
56
+ /** Trace/audit day partitions are provisioned relative to the current day. */
57
+ readonly partitionDay: string
58
+ /** Internal definitions and emitted DDL travel with the pipework version. */
59
+ readonly pipeworkVersion: string
60
+ readonly formatVersion: number
61
+ }
62
+
63
+ /**
64
+ * Hash a migrations folder's contents: every file's path relative to the folder
65
+ * and its bytes, in a stable order. Path names are included so a rename is a
66
+ * change; a missing or unreadable folder hashes as absent.
67
+ */
68
+ export function hashMigrationsFolder(folder: string): string | null {
69
+ const files: string[] = []
70
+ const walk = (dir: string): void => {
71
+ let entries
72
+ try {
73
+ entries = readdirSync(dir, { withFileTypes: true })
74
+ } catch {
75
+ return
76
+ }
77
+ for (const entry of entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))) {
78
+ const full = join(dir, entry.name)
79
+ if (entry.isDirectory()) walk(full)
80
+ else if (entry.isFile()) files.push(full)
81
+ }
82
+ }
83
+ walk(folder)
84
+ if (files.length === 0) return null
85
+
86
+ const hash = createHash('sha256')
87
+ for (const file of files) {
88
+ // Normalize the separator so the same tree hashes alike on any platform.
89
+ hash.update(relative(folder, file).split(sep).join('/'))
90
+ hash.update('\0')
91
+ hash.update(readFileSync(file))
92
+ hash.update('\0')
93
+ }
94
+ return hash.digest('hex')
95
+ }
96
+
97
+ /**
98
+ * Collect the content inputs for one configured database's template.
99
+ *
100
+ * `partitionDay` is the current UTC date. Trace and audit partitions are
101
+ * created per day with a lead window, so a template built yesterday is missing
102
+ * today's partitions — keying on the day makes that invalidation automatic
103
+ * instead of a stale-data bug that only shows up after midnight.
104
+ */
105
+ export function templateInputs(
106
+ databaseName: string,
107
+ dbConfig: ResolvedDatabase,
108
+ blueprint: Blueprint,
109
+ isDefaultDatabase: boolean,
110
+ today: Date,
111
+ ): TemplateInputs {
112
+ return {
113
+ databaseName,
114
+ owner: new URL(dbConfig.url).username,
115
+ ...(dbConfig.testOwnerUrl !== undefined ? { migrationOwner: new URL(dbConfig.testOwnerUrl).username } : {}),
116
+ extensions: [...dbConfig.extensions].sort(),
117
+ migrationTable: dbConfig.migrationTable,
118
+ migrations: dbConfig.migrations === undefined ? null : hashMigrationsFolder(dbConfig.migrations),
119
+ trace: blueprint.trace ?? null,
120
+ audit: blueprint.audit ?? null,
121
+ isDefaultDatabase,
122
+ partitionDay: today.toISOString().slice(0, 10),
123
+ pipeworkVersion: VERSION,
124
+ formatVersion: TEMPLATE_FORMAT_VERSION,
125
+ }
126
+ }
127
+
128
+ /**
129
+ * The template's content fingerprint: 16 lowercase hex chars. Deliberately
130
+ * wider than the 12-char per-run nonce so a template name can never be mistaken
131
+ * for a run-owned database name.
132
+ */
133
+ export function templateFingerprint(inputs: TemplateInputs): string {
134
+ return createHash('sha256').update(JSON.stringify(inputs)).digest('hex').slice(0, 16)
135
+ }
@@ -0,0 +1,7 @@
1
+ import type { DB } from '../data/db/index.js'
2
+
3
+ declare global {
4
+ var db: DB
5
+ }
6
+
7
+ export {}
@@ -0,0 +1,19 @@
1
+ export { setupTestDatabases, teardownTestDatabases, getTestDatabase, getTestDatabases, type TestDatabase, type SetupOptions } from './setup.js'
2
+ export { flushPendingDrops, TEST_DROP_LOG_PREFIX, TEST_REAP_LOG_PREFIX } from './setup.js'
3
+ export {
4
+ SetupStalled,
5
+ logSlowPhases,
6
+ SETUP_PROGRESS_LOG_PREFIX,
7
+ type SetupPhase,
8
+ type SetupProgress,
9
+ type SetupProgressListener,
10
+ } from './progress.js'
11
+ export { armTestWatch, TEST_WATCH_LOG_PREFIX, type TestWatchTarget } from './watch.js'
12
+ export { beginTestIsolation, endTestIsolation, type TestContext, type TestDatabaseConnections } from './plugin.js'
13
+ export { setupPipeworkTests, useTestDb, useSetupDb, useTestInstance, useTestClient, type UseTestClientOptions, closeSetupConnections, SetupConnectionCloseError, teardownAfterAll, withFlow, type WithFlowOptions } from './vitest.js'
14
+ export { mockAuth, asTenant } from './auth.js'
15
+ export { withContext, withJobContext, type WithContextOptions } from './context.js'
16
+ export { pipework as vitestPlugin, type PipeworkVitestOptions } from './vitest-plugin.js'
17
+ export { resolveVitestConfig, resolveVitestModules } from './vitest-workspace.js'
18
+ export { tap, type ManagedConnection, type ConnectOptions } from '../data/db/pool.js'
19
+ export { crawlFixtureSite, type CrawlFixtureOptions, type CrawlFixtureRoute, type CrawlFixtureRequest, type CrawlFixtureSite } from './crawl-fixture.js'
@@ -0,0 +1,87 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+
4
+ // The clone-per-test database namespace, scoped to ONE project.
5
+ //
6
+ // pipework is consumed by many projects that may share a Postgres cluster. A
7
+ // hardcoded `pipework_test_` / `pipework_app_` prefix made every consumer's
8
+ // per-run test databases AND runtime roles collide in a single namespace: one
9
+ // project's reaper dropped another's databases, clones ended up owned by a
10
+ // foreign role, and `CREATE` on the cloned `public` schema was denied because
11
+ // the connecting role was not the owner. Scoping both prefixes per project
12
+ // isolates them — and isolates the reaper, so it only ever touches its own.
13
+ //
14
+ // Resolution order:
15
+ // 1. PIPEWORK_TEST_NAMESPACE — explicit override (CI, or a shared cluster
16
+ // whose default namespace is already polluted by legacy runs).
17
+ // 2. the consumer's package.json `name` — the natural per-project identifier.
18
+ // 3. `pipework` — fallback when neither is available.
19
+
20
+ let cached: string | null = null
21
+
22
+ /**
23
+ * Pure namespace resolution: pick the first non-empty source, then sanitize to
24
+ * a valid Postgres identifier prefix. Exported for direct testing — the impure
25
+ * {@link projectNamespace} wraps it with the actual env + package.json sources.
26
+ */
27
+ export function resolveNamespace(envOverride: string | undefined, pkgName: string | undefined): string {
28
+ const raw = envOverride !== undefined && envOverride.trim() !== '' ? envOverride
29
+ : pkgName !== undefined && pkgName.trim() !== '' ? pkgName
30
+ : 'pipework'
31
+ // Postgres identifiers are lowercase, alphanumeric + underscore, and must
32
+ // start with a letter. Collapse every other run of characters to one
33
+ // underscore so `@scope/name` and `scope-name` map to distinct, stable,
34
+ // legal tokens; prefix `p_` if the result would not start with a letter.
35
+ const token = raw.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '')
36
+ return /^[a-z]/.test(token) ? token : `p_${token}`
37
+ }
38
+
39
+ /** This project's namespace token, resolved once per process. */
40
+ export function projectNamespace(): string {
41
+ if (cached !== null) return cached
42
+ let pkgName: string | undefined
43
+ try {
44
+ pkgName = (JSON.parse(readFileSync(join(process.cwd(), 'package.json'), 'utf-8')) as { name?: string }).name
45
+ } catch {
46
+ // No readable package.json (e.g. a bare test harness) — fall back below.
47
+ }
48
+ cached = resolveNamespace(process.env['PIPEWORK_TEST_NAMESPACE'], pkgName)
49
+ return cached
50
+ }
51
+
52
+ /** Prefix for this project's per-run test databases: `<project>_test_`. */
53
+ export function testDbPrefix(): string {
54
+ return `${projectNamespace()}_test_`
55
+ }
56
+
57
+ /** Prefix for this project's per-run runtime (app) roles: `<project>_app_`. */
58
+ export function appRolePrefix(): string {
59
+ return `${projectNamespace()}_app_`
60
+ }
61
+
62
+ /**
63
+ * Prefix for this project's shared, content-keyed templates: `<project>_tmpl_`.
64
+ *
65
+ * Templates sit in their own prefix rather than under `testDbPrefix()` because
66
+ * they have a different lifecycle and a different reaping rule: a per-run clone
67
+ * dies with its run, a template deliberately outlives every run that uses it
68
+ * and is dropped only once no run wants it. Separate prefixes keep the reaper's
69
+ * two passes from having to tell the names apart by shape. Issue #340.
70
+ */
71
+ export function templateDbPrefix(): string {
72
+ return `${projectNamespace()}_tmpl_`
73
+ }
74
+
75
+ /**
76
+ * `LIKE` pattern matching every per-run test database of THIS project, with the
77
+ * prefix underscores escaped so they match literally. The reaper uses it to
78
+ * scope its sweep to its own namespace and never another project's databases.
79
+ */
80
+ export function testDbLikePattern(): string {
81
+ return `${testDbPrefix().replace(/_/g, '\\_')}%`
82
+ }
83
+
84
+ /** `LIKE` pattern matching every shared template of THIS project. */
85
+ export function templateDbLikePattern(): string {
86
+ return `${templateDbPrefix().replace(/_/g, '\\_')}%`
87
+ }
@@ -0,0 +1,189 @@
1
+ import postgres from 'postgres'
2
+ import { drizzle, type PostgresJsDatabase } from '../data/query/postgres-js/index.js'
3
+ import { sql } from '../data/query/index.js'
4
+ import type { Manifold } from '../core/pipework.js'
5
+ import { getTestDatabase, type TestDatabase } from './setup.js'
6
+ import { createTestContext as createCtx } from '../request/context/create.js'
7
+ import { runInContext } from '../request/context/store.js'
8
+ import type { Flow } from '../request/context/types.js'
9
+ import { randomUUID } from 'node:crypto'
10
+ import { createDebugFn, isObserverOnly } from '../data/db/instrumentation.js'
11
+ import { createStatementWatch } from '../data/db/query-watch.js'
12
+ import { markObservedConnection } from '../data/query/postgres-js/driver-error-boundary.js'
13
+ import type { ResolvedObservability } from '../core/config/load.js'
14
+ import { collapseTransactionsToSavepoints } from './savepoints.js'
15
+ import { splitLargeInserts } from '../data/db/insert-split.js'
16
+ import { settleTraceWritesBounded } from '../trace/runtime/pending-writes.js'
17
+ import { createSystemHandle } from './system-channel.js'
18
+ import { armTestWatch } from './watch.js'
19
+
20
+ export interface TestDatabaseConnections {
21
+ [name: string]: PostgresJsDatabase
22
+ }
23
+
24
+ export interface TestContext {
25
+ id: string
26
+ db: TestDatabaseConnections
27
+ }
28
+
29
+ interface ActiveTestConnection {
30
+ client: postgres.Sql
31
+ closeWatch?: () => Promise<void>
32
+ drizzle: PostgresJsDatabase
33
+ /** Same connection and transaction, statements sent with the test-only cross-tenant policy open. Set when the database has `rls`. */
34
+ system?: PostgresJsDatabase
35
+ /** A handle for one named door on the same connection; set when the database has `rls`. */
36
+ door?: (name: string) => PostgresJsDatabase
37
+ }
38
+
39
+ const contextConnections = new Map<string, Map<string, ActiveTestConnection>>()
40
+ const contextWatches = new Map<string, () => void>()
41
+
42
+ /** The slice of vitest's `task` the watch needs: `fullName` and the resolved `timeout`. */
43
+ export interface WatchedTask {
44
+ fullName: string
45
+ timeout: number
46
+ }
47
+
48
+ export async function beginTestIsolation(instance: Manifold, task?: WatchedTask): Promise<TestContext> {
49
+ const dbConnections: TestDatabaseConnections = {}
50
+ const contextId = randomUUID()
51
+ const connections = new Map<string, ActiveTestConnection>()
52
+
53
+ for (const [name] of instance.config.databases()) {
54
+ const testDb = getTestDatabase(name)
55
+ if (!testDb) {
56
+ throw new Error(`[pipework] Test database not set up for "${name}". Did setupTestDatabases() run?`)
57
+ }
58
+
59
+ const conn = await createIsolatedConnection(
60
+ testDb, connections, name, instance.config.observability, instance.config.database(name).rls !== undefined,
61
+ )
62
+ dbConnections[name] = conn
63
+
64
+ instance.pool.override(name, {
65
+ name,
66
+ client: connections.get(name)!.client,
67
+ drizzle: conn,
68
+ ...(connections.get(name)!.system !== undefined ? { system: connections.get(name)!.system! } : {}),
69
+ ...(connections.get(name)!.door !== undefined ? { door: connections.get(name)!.door! } : {}),
70
+ connectionIds() {
71
+ return Promise.reject(new Error(
72
+ '[pipework] connectionIds() is not available inside a test isolation context: the test connection is one transaction-pinned connection.\n' +
73
+ ' Fix: call connectionIds() on a pool opened with instance.pool.getOrCreate() or tap(), outside test isolation.',
74
+ ))
75
+ },
76
+ async close() { /* test harness manages lifecycle */ },
77
+ })
78
+ }
79
+
80
+ contextConnections.set(contextId, connections)
81
+ if (task !== undefined) {
82
+ const databases = [...connections.keys()].flatMap(n => {
83
+ const d = getTestDatabase(n)
84
+ return d ? [{ database: d.database, url: d.url }] : []
85
+ })
86
+ contextWatches.set(contextId, armTestWatch({ name: task.fullName, timeoutMs: task.timeout, databases }))
87
+ }
88
+ instance.isolation.markBegin()
89
+ return { id: contextId, db: dbConnections }
90
+ }
91
+
92
+ export async function endTestIsolation(instance: Manifold, ctx: TestContext): Promise<void> {
93
+ contextWatches.get(ctx.id)?.()
94
+ contextWatches.delete(ctx.id)
95
+ await settleTraceWritesBounded()
96
+ instance.pool.clearOverrides()
97
+
98
+ const connections = contextConnections.get(ctx.id)
99
+ if (!connections) {
100
+ instance.isolation.markEnd()
101
+ return
102
+ }
103
+
104
+ for (const [, conn] of connections) {
105
+ try {
106
+ await conn.drizzle.execute(sql.raw('ROLLBACK'))
107
+ } catch {
108
+ // Transaction may already be aborted
109
+ }
110
+ try {
111
+ await conn.client.end()
112
+ } catch {
113
+ // Connection may already be closed
114
+ }
115
+ await conn.closeWatch?.().catch(() => {})
116
+ }
117
+
118
+ contextConnections.delete(ctx.id)
119
+ instance.isolation.markEnd()
120
+ }
121
+
122
+ async function createIsolatedConnection(
123
+ testDb: TestDatabase,
124
+ connections: Map<string, ActiveTestConnection>,
125
+ name: string,
126
+ observability: ResolvedObservability,
127
+ withSystem: boolean,
128
+ ): Promise<PostgresJsDatabase> {
129
+ const debug = createDebugFn(observability)
130
+ const client = postgres(testDb.url, { max: 1, onnotice: () => {}, ...(debug ? { debug } : {}) })
131
+ if (isObserverOnly(observability)) markObservedConnection(client)
132
+ const watch = createStatementWatch({ database: name, url: testDb.url, slowQueryMs: observability.slowQueryMs, inFlightQueryMs: observability.inFlightQueryMs })
133
+ const db = drizzle(client, { statementWatch: watch.watch })
134
+
135
+ await db.execute(sql.raw('BEGIN'))
136
+ const join = collapseTransactionsToSavepoints(db, client)
137
+ splitLargeInserts(db)
138
+ let system: PostgresJsDatabase | undefined
139
+ let door: ((name: string) => PostgresJsDatabase) | undefined
140
+ if (withSystem) {
141
+ system = createSystemHandle(client)
142
+ join(system)
143
+ door = (doorName) => {
144
+ const handle = createSystemHandle(client, doorName)
145
+ join(handle)
146
+ return handle
147
+ }
148
+ }
149
+
150
+ connections.set(name, { client, closeWatch: watch.close, drizzle: db, ...(system !== undefined ? { system } : {}), ...(door !== undefined ? { door } : {}) })
151
+ return db
152
+ }
153
+
154
+ export function createTestContext(instance: Manifold, testConnections: TestContext, auth?: unknown, tenant?: string | null): Flow {
155
+ const ctx = createCtx(instance, randomUUID(), { auth, tenant })
156
+ for (const [name, drizzleDb] of Object.entries(testConnections.db)) {
157
+ ctx.transactions.set(name, { drizzle: drizzleDb, nonce: ctx._nonce, tenant: ctx.tenant })
158
+ }
159
+ return ctx
160
+ }
161
+
162
+ export async function propagateTestSessionVars(
163
+ instance: Manifold,
164
+ testConnections: TestContext,
165
+ tenant: string,
166
+ ): Promise<void> {
167
+ for (const [name, db] of Object.entries(testConnections.db)) {
168
+ const dbConfig = instance.config.database(name)
169
+ if (dbConfig.rls !== undefined) {
170
+ await db.execute(sql`SELECT set_config(${dbConfig.rls.sessionVar}, ${tenant}, true)`)
171
+ }
172
+ }
173
+ }
174
+
175
+ export function createSetupConnection(
176
+ testDb: TestDatabase,
177
+ observability?: ResolvedObservability,
178
+ ): { drizzle: PostgresJsDatabase; close: () => Promise<void> } {
179
+ const debug = observability ? createDebugFn(observability) : undefined
180
+ const client = postgres(testDb.url, { max: 1, onnotice: () => {}, ...(debug ? { debug } : {}) })
181
+ if (observability && isObserverOnly(observability)) markObservedConnection(client)
182
+ const watch = observability
183
+ ? createStatementWatch({ database: 'setup', url: testDb.url, slowQueryMs: observability.slowQueryMs, inFlightQueryMs: observability.inFlightQueryMs })
184
+ : undefined
185
+ const db = splitLargeInserts(drizzle(client, watch ? { statementWatch: watch.watch } : {}))
186
+ return { drizzle: db, close: async () => { await watch?.close(); await client.end() } }
187
+ }
188
+
189
+ export { runInContext }