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,565 @@
1
+ import { verify as cryptoVerify } from 'node:crypto'
2
+ import { SignJWT, jwtVerify } from 'jose'
3
+ import { parseExpiry } from './parse-expiry.js'
4
+ import { sql } from '../../data/db/sql.js'
5
+ import type { DB } from '../../data/db/index.js'
6
+ import { UnauthorizedError, AuthUnavailableError, isPipeworkError } from '../../core/errors/index.js'
7
+ import type { AuthStrategy, AuthRequest, AuthContext, BaseAuth } from './types.js'
8
+ import { assertUuid } from './uuid.js'
9
+ import type { CookieConfig } from './cookie.js'
10
+ import { resolveCookieConfig, buildSetCookieHeader, buildClearCookieHeader, parseCookieHeader, assertSameSiteRequest } from './cookie.js'
11
+ import { checkSigningKeys, importSigningKey } from './signing-keys.js'
12
+ import type { ResolvedCookieConfig } from './cookie.js'
13
+ import type { HttpRequest, HttpResponse } from '../../request/http/types.js'
14
+ import { refuseScopedHandle } from '../tenant/scoped-db.js'
15
+
16
+ /** Session configuration — signing keys, issuer, audience, token TTLs, refresh rotation. */
17
+ export interface SessionConfig {
18
+ readonly signing: { algorithm: 'ES256'; privateKey: string; publicKey: string }
19
+ readonly issuer: string
20
+ readonly audience: string
21
+ /**
22
+ * `cookie` also delivers the access token as an HttpOnly cookie (default name `__pipework_access`,
23
+ * SameSite Lax so a link from another site arrives signed in, Path `/`), set and cleared with the refresh cookie.
24
+ */
25
+ readonly accessToken: { expiresIn: string; cookie?: CookieConfig }
26
+ readonly refreshToken: { expiresIn: string; rotateOnUse: boolean; reuseDetection: boolean; cookie?: CookieConfig }
27
+ readonly versionCheck: boolean
28
+ readonly versionCacheTtlMs?: number
29
+ readonly resolveRoles?: (db: DB, userId: string, tenantId: string) => Promise<string[]>
30
+ readonly environment?: string
31
+ /** Origins allowed to send the refresh cookie to `refreshHttp` / `revokeHttp` / `revokeRefreshCookie` / `revokeAllHttp`, besides the request's own host. */
32
+ readonly trustedOrigins?: readonly string[]
33
+ }
34
+
35
+ /** Access + refresh token pair returned by issueTokens(). */
36
+ export interface TokenPair {
37
+ readonly accessToken: string
38
+ readonly refreshToken: string
39
+ readonly expiresIn: number
40
+ }
41
+
42
+ /** Decoded JWT payload — userId, tenantId, roles, version. */
43
+ export interface TokenPayload {
44
+ readonly sub: string
45
+ readonly tid: string
46
+ readonly av: number
47
+ readonly roles: string[] | undefined
48
+ }
49
+
50
+ /** Result from HTTP token operations — the token pair plus whether cookies were set. */
51
+ export interface HttpTokenResult {
52
+ readonly accessToken: string
53
+ readonly expiresIn: number
54
+ }
55
+
56
+ /**
57
+ * The committed result of a refresh transaction. `refresh()` translates the
58
+ * non-`ok` variants into thrown `UnauthorizedError`s *after* the transaction
59
+ * commits, so a reuse-revocation is never rolled back by the signalling throw.
60
+ */
61
+ type RefreshOutcome =
62
+ | { readonly kind: 'ok'; readonly pair: TokenPair }
63
+ | { readonly kind: 'invalid' }
64
+ | { readonly kind: 'expired' }
65
+ | { readonly kind: 'reuse' }
66
+
67
+ export type { HttpRequest, HttpResponse }
68
+
69
+ /** What `sessions.strategy()` authenticates: the token's user and org, its roles, and where the token came from. */
70
+ export type SessionAuth = BaseAuth & { readonly roles: readonly string[]; readonly via: 'cookie' | 'header' }
71
+
72
+ /** Options for `sessions.strategy()`. */
73
+ export interface SessionStrategyOptions {
74
+ /** Origins (e.g. `https://app.example.com`) besides the request's own host allowed to send cookie-authenticated requests. */
75
+ readonly trustedOrigins?: readonly string[]
76
+ /**
77
+ * A cookie-authenticated GET/HEAD/OPTIONS that a browser marks cross-site (and not a top-level navigation,
78
+ * and whose Origin is neither ours nor trusted) is refused with 403 under `'refuse'` (default); `'allow'`
79
+ * lets such reads through. Bearer-header auth is never checked.
80
+ */
81
+ readonly crossSiteReads?: 'refuse' | 'allow'
82
+ }
83
+
84
+ /** Session manager with JWT issue/refresh/revoke lifecycle and cookie-based HTTP helpers. */
85
+ export interface Sessions {
86
+ issueTokens(db: DB, user: { id: string; tenantId: string; roles?: readonly string[] }): Promise<TokenPair>
87
+ refresh(db: DB, refreshToken: string): Promise<TokenPair>
88
+ revokeAll(db: DB, userId: string): Promise<void>
89
+ bumpVersion(db: DB, userId: string): Promise<void>
90
+ verifyAccessToken(token: string): Promise<TokenPayload>
91
+ /**
92
+ * The user a token these sessions signed names, checking signature, issuer and audience but not
93
+ * expiry or revocation; null otherwise. Synchronous and without the database, for rate-limit
94
+ * keys — never for authorization.
95
+ */
96
+ signedSubject(token: string): string | null
97
+ checkVersion(db: DB, userId: string, tokenVersion: number): Promise<boolean>
98
+ cleanExpiredTokens(db: DB): Promise<number>
99
+ /**
100
+ * The auth strategy for these sessions: `Authorization: Bearer` first, else the access cookie when
101
+ * `accessToken.cookie` is set. A cookie-authenticated request must come from the
102
+ * API's own origin or a trusted origin, else 403 `CROSS_SITE_REQUEST`; a read (GET/HEAD/OPTIONS) also passes as a
103
+ * top-level navigation or with no Sec-Fetch-Site and no Origin (see `crossSiteReads`). It never refreshes: the client
104
+ * calls the refresh route on a 401 "Access token expired" (a refresh here would trip reuse detection
105
+ * on concurrent requests). On an optional-auth route a token it refuses (expired, revoked, not ours)
106
+ * reads as signed out.
107
+ */
108
+ strategy(options?: SessionStrategyOptions): AuthStrategy<SessionAuth>
109
+ /** Throws 403 `CROSS_SITE_REQUEST` when a cookie-authenticated request is cross-site by the rule `refreshHttp` applies. */
110
+ assertSameSiteCookie(request: Pick<HttpRequest, 'headers'> & { readonly method?: string }): void
111
+ /** Revokes the refresh token in the request's refresh cookie, if any; sets no cookie. Refuses a cross-site request like `refreshHttp`. */
112
+ revokeRefreshCookie(db: DB, request: Pick<HttpRequest, 'headers'> & { readonly method?: string }): Promise<void>
113
+ issueTokensHttp(response: HttpResponse, db: DB, user: { id: string; tenantId: string; roles?: readonly string[] }): Promise<HttpTokenResult>
114
+ refreshHttp(response: HttpResponse, db: DB, request: Pick<HttpRequest, 'headers'> & { readonly method?: string }): Promise<HttpTokenResult>
115
+ revokeHttp(response: HttpResponse, db: DB, request: Pick<HttpRequest, 'headers'> & { readonly method?: string }): Promise<void>
116
+ /** Pass `request` to have the cookie-site check run before anything is revoked. */
117
+ revokeAllHttp(response: HttpResponse, db: DB, userId: string, request?: Pick<HttpRequest, 'headers'> & { readonly method?: string }): Promise<void>
118
+ }
119
+
120
+ /**
121
+ * Creates a Sessions manager with JWT access/refresh tokens, rotation, reuse detection, and cookie helpers.
122
+ * Its tables come from blueprint `sessions: {}`; `tenantId` must be a uuid.
123
+ */
124
+ export function createSessions(config: SessionConfig): Sessions {
125
+ const environment = config.environment ?? 'production'
126
+ if (environment === 'production') {
127
+ validateSigningKeys(config)
128
+ }
129
+
130
+ const verifyKey = checkSigningKeys(config.signing, 'createSessions')
131
+ let privateKey: CryptoKey | null = null
132
+ let publicKey: CryptoKey | null = null
133
+ const versionCache = new Map<string, { version: number; expiresAt: number }>()
134
+ const cacheTtl = config.versionCacheTtlMs ?? 60_000
135
+
136
+ async function getPrivateKey(): Promise<CryptoKey> {
137
+ if (!privateKey) privateKey = await importSigningKey('private', config.signing, 'createSessions')
138
+ return privateKey
139
+ }
140
+
141
+ async function getPublicKey(): Promise<CryptoKey> {
142
+ if (!publicKey) publicKey = await importSigningKey('public', config.signing, 'createSessions')
143
+ return publicKey
144
+ }
145
+
146
+
147
+ async function getOrCreateVersion(db: DB, userId: string): Promise<number> {
148
+ const rows = await db.execute(
149
+ sql`INSERT INTO pipework_auth_versions (user_id, version) VALUES (${userId}, 1)
150
+ ON CONFLICT (user_id) DO NOTHING
151
+ RETURNING version`
152
+ )
153
+ if (rows.length > 0) return rows[0]!['version'] as number
154
+
155
+ const existing = await db.execute(
156
+ sql`SELECT version FROM pipework_auth_versions WHERE user_id = ${userId}`
157
+ )
158
+ const row = existing[0]
159
+ if (row === undefined) return 1
160
+ return row['version'] as number
161
+ }
162
+
163
+ async function issueTokens(
164
+ db: DB,
165
+ user: { id: string; tenantId: string; roles?: readonly string[] },
166
+ familyId: string = crypto.randomUUID(),
167
+ ): Promise<TokenPair> {
168
+ assertUuid(user.tenantId, 'tenantId')
169
+ const key = await getPrivateKey()
170
+ const version = config.versionCheck ? await getOrCreateVersion(db, user.id) : 1
171
+ const expiresInSeconds = parseExpiry(config.accessToken.expiresIn)
172
+
173
+ const accessToken = await new SignJWT({ tid: user.tenantId, av: version, roles: user.roles })
174
+ .setProtectedHeader({ alg: config.signing.algorithm })
175
+ .setSubject(user.id)
176
+ .setIssuer(config.issuer)
177
+ .setAudience(config.audience)
178
+ .setIssuedAt()
179
+ .setExpirationTime(`${expiresInSeconds}s`)
180
+ .sign(key)
181
+
182
+ const refreshTokenValue = crypto.randomUUID()
183
+ const refreshHash = await hashToken(refreshTokenValue)
184
+ const refreshExpiresIn = parseExpiry(config.refreshToken.expiresIn)
185
+ const expiresAt = new Date(Date.now() + refreshExpiresIn * 1000)
186
+
187
+ await db.execute(
188
+ sql`INSERT INTO pipework_refresh_tokens (user_id, tenant_id, token_hash, family_id, expires_at)
189
+ VALUES (${user.id}, ${user.tenantId}, ${refreshHash}, ${familyId}::uuid, ${expiresAt.toISOString()}::timestamptz)`
190
+ )
191
+
192
+ return { accessToken, refreshToken: refreshTokenValue, expiresIn: expiresInSeconds }
193
+ }
194
+
195
+ async function refresh(db: DB, refreshToken: string): Promise<TokenPair> {
196
+ const tokenHash = await hashToken(refreshToken)
197
+
198
+ // The transaction must COMMIT in every branch, including reuse. Signalling
199
+ // reuse by throwing from inside the transaction would roll back the very
200
+ // family-revocation it just performed — so the transaction returns an
201
+ // outcome and the throw happens after it commits.
202
+ const outcome = await db.transaction(async (tx): Promise<RefreshOutcome> => {
203
+ const rows = await tx.execute(
204
+ sql`SELECT id, user_id, tenant_id, family_id, revoked_at, expires_at
205
+ FROM pipework_refresh_tokens
206
+ WHERE token_hash = ${tokenHash}
207
+ FOR UPDATE`
208
+ )
209
+
210
+ if (rows.length === 0) {
211
+ return { kind: 'invalid' }
212
+ }
213
+
214
+ const row = rows[0]!
215
+ const userId = row['user_id'] as string
216
+ const tenantId = row['tenant_id'] as string
217
+ const familyId = row['family_id'] as string
218
+ const revokedAt = row['revoked_at'] as string | null
219
+ const expiresAt = new Date(row['expires_at'] as string)
220
+
221
+ if (expiresAt < new Date()) {
222
+ return { kind: 'expired' }
223
+ }
224
+
225
+ if (revokedAt !== null) {
226
+ if (config.refreshToken.reuseDetection) {
227
+ await tx.execute(
228
+ sql`UPDATE pipework_refresh_tokens SET revoked_at = now()
229
+ WHERE family_id = ${familyId}::uuid AND revoked_at IS NULL`
230
+ )
231
+ }
232
+ return { kind: 'reuse' }
233
+ }
234
+
235
+ if (config.refreshToken.rotateOnUse) {
236
+ await tx.execute(
237
+ sql`UPDATE pipework_refresh_tokens SET revoked_at = now() WHERE token_hash = ${tokenHash}`
238
+ )
239
+ }
240
+
241
+ const roles = config.resolveRoles
242
+ ? await config.resolveRoles(tx, userId, tenantId)
243
+ : undefined
244
+
245
+ // Rotation stays within the same family — a replayed older token must be
246
+ // able to revoke every token descended from it, including this new one.
247
+ const pair = await issueTokens(
248
+ tx,
249
+ roles ? { id: userId, tenantId, roles } : { id: userId, tenantId },
250
+ familyId,
251
+ )
252
+ return { kind: 'ok', pair }
253
+ })
254
+
255
+ switch (outcome.kind) {
256
+ case 'invalid':
257
+ throw new UnauthorizedError('Invalid refresh token')
258
+ case 'expired':
259
+ throw new UnauthorizedError('Refresh token expired')
260
+ case 'reuse':
261
+ throw new UnauthorizedError('Refresh token reuse detected — all sessions revoked')
262
+ case 'ok':
263
+ return outcome.pair
264
+ }
265
+ }
266
+
267
+ async function revokeAll(db: DB, userId: string): Promise<void> {
268
+ await db.execute(
269
+ sql`UPDATE pipework_refresh_tokens SET revoked_at = now()
270
+ WHERE user_id = ${userId} AND revoked_at IS NULL`
271
+ )
272
+ }
273
+
274
+ async function bumpVersion(db: DB, userId: string): Promise<void> {
275
+ await db.execute(
276
+ sql`INSERT INTO pipework_auth_versions (user_id, version, updated_at)
277
+ VALUES (${userId}, 2, now())
278
+ ON CONFLICT (user_id)
279
+ DO UPDATE SET version = pipework_auth_versions.version + 1, updated_at = now()`
280
+ )
281
+ versionCache.delete(userId)
282
+ }
283
+
284
+ async function verifyAccessToken(token: string): Promise<TokenPayload> {
285
+ const key = await getPublicKey()
286
+ try {
287
+ const { payload } = await jwtVerify(token, key, {
288
+ algorithms: [config.signing.algorithm],
289
+ issuer: config.issuer,
290
+ audience: config.audience,
291
+ })
292
+ return {
293
+ sub: payload.sub!,
294
+ tid: payload['tid'] as string,
295
+ av: payload['av'] as number,
296
+ roles: payload['roles'] as string[] | undefined,
297
+ }
298
+ } catch (error) {
299
+ if ((error as { code?: unknown } | null)?.code === 'ERR_JWT_EXPIRED') {
300
+ throw new UnauthorizedError('Access token expired')
301
+ }
302
+ throw new UnauthorizedError('Invalid access token')
303
+ }
304
+ }
305
+
306
+ function signedSubject(token: unknown): string | null {
307
+ try {
308
+ if (typeof token !== 'string') return null
309
+ const parts = token.split('.')
310
+ if (parts.length !== 3) return null
311
+ const [header, body, signature] = parts as [string, string, string]
312
+ const head = JSON.parse(Buffer.from(header, 'base64url').toString('utf8')) as { alg?: unknown }
313
+ if (head.alg !== config.signing.algorithm) return null
314
+ const signed = cryptoVerify(
315
+ 'sha256', Buffer.from(`${header}.${body}`), { key: verifyKey, dsaEncoding: 'ieee-p1363' },
316
+ Buffer.from(signature, 'base64url'),
317
+ )
318
+ if (!signed) return null
319
+ const claims = JSON.parse(Buffer.from(body, 'base64url').toString('utf8')) as
320
+ { sub?: unknown; iss?: unknown; aud?: unknown }
321
+ if (claims.iss !== config.issuer) return null
322
+ const audiences = Array.isArray(claims.aud) ? claims.aud : [claims.aud]
323
+ if (!audiences.includes(config.audience)) return null
324
+ return typeof claims.sub === 'string' && claims.sub !== '' ? claims.sub : null
325
+ } catch {
326
+ return null
327
+ }
328
+ }
329
+
330
+ async function checkVersion(db: DB, userId: string, tokenVersion: number): Promise<boolean> {
331
+ const cached = versionCache.get(userId)
332
+ if (cached && cached.expiresAt > Date.now()) {
333
+ return cached.version === tokenVersion
334
+ }
335
+
336
+ const rows = await db.execute(
337
+ sql`SELECT version FROM pipework_auth_versions WHERE user_id = ${userId}`
338
+ )
339
+ const currentVersion = rows.length > 0 ? (rows[0]!['version'] as number) : 1
340
+ versionCache.set(userId, { version: currentVersion, expiresAt: Date.now() + cacheTtl })
341
+ return currentVersion === tokenVersion
342
+ }
343
+
344
+ async function cleanExpiredTokens(db: DB): Promise<number> {
345
+ const rows = await db.execute(
346
+ sql`DELETE FROM pipework_refresh_tokens WHERE expires_at < now() RETURNING id`
347
+ )
348
+ return rows.length
349
+ }
350
+
351
+ function getCookieConfig(): ResolvedCookieConfig {
352
+ const cookie = config.refreshToken.cookie
353
+ if (cookie === undefined) {
354
+ throw new Error('Cookie-based session methods require refreshToken.cookie configuration')
355
+ }
356
+ return resolveCookieConfig(cookie, config.environment ?? 'production')
357
+ }
358
+
359
+ function getAccessCookieConfig(): ResolvedCookieConfig | null {
360
+ const cookie = config.accessToken.cookie
361
+ if (cookie === undefined) return null
362
+ return resolveCookieConfig(cookie, environment, { name: '__pipework_access', sameSite: 'lax' })
363
+ }
364
+
365
+ // A browser sends Sec-Fetch-Site or Origin on every POST, so a request with neither is not a browser's
366
+ // and carries no cross-site risk: server-side proxies and native clients keep working.
367
+ function assertSameSiteCookie(request: { readonly headers: Readonly<Record<string, string | undefined>>; readonly method?: string }): void {
368
+ if (request.headers['sec-fetch-site'] === undefined && request.headers['origin'] === undefined) return
369
+ assertSameSiteRequest({ headers: request.headers }, config.trustedOrigins ?? [])
370
+ }
371
+
372
+ function getRefreshMaxAge(): number {
373
+ return parseExpiry(config.refreshToken.expiresIn)
374
+ }
375
+
376
+ function setCookies(response: HttpResponse, values: string[]): void {
377
+ response.header('Set-Cookie', values.length === 1 ? values[0]! : values)
378
+ }
379
+
380
+ function sessionCookies(resolved: ResolvedCookieConfig, pair: TokenPair): string[] {
381
+ const values = [buildSetCookieHeader(resolved, pair.refreshToken, getRefreshMaxAge())]
382
+ const access = getAccessCookieConfig()
383
+ if (access !== null) values.push(buildSetCookieHeader(access, pair.accessToken, pair.expiresIn))
384
+ return values
385
+ }
386
+
387
+ function clearCookies(resolved: ResolvedCookieConfig): string[] {
388
+ const values = [buildClearCookieHeader(resolved)]
389
+ const access = getAccessCookieConfig()
390
+ if (access !== null) values.push(buildClearCookieHeader(access))
391
+ return values
392
+ }
393
+
394
+ async function issueTokensHttp(
395
+ response: HttpResponse,
396
+ db: DB,
397
+ user: { id: string; tenantId: string; roles?: readonly string[] },
398
+ ): Promise<HttpTokenResult> {
399
+ const resolved = getCookieConfig()
400
+ const pair = await issueTokens(db, user)
401
+ setCookies(response, sessionCookies(resolved, pair))
402
+ return { accessToken: pair.accessToken, expiresIn: pair.expiresIn }
403
+ }
404
+
405
+ async function refreshHttp(
406
+ response: HttpResponse,
407
+ db: DB,
408
+ request: Pick<HttpRequest, 'headers'> & { readonly method?: string },
409
+ ): Promise<HttpTokenResult> {
410
+ const resolved = getCookieConfig()
411
+ const token = parseCookieHeader(request.headers['cookie'], resolved.name)
412
+ if (token === undefined) {
413
+ throw new UnauthorizedError('Missing refresh token cookie')
414
+ }
415
+ assertSameSiteCookie(request)
416
+ const pair = await refresh(db, token)
417
+ setCookies(response, sessionCookies(resolved, pair))
418
+ return { accessToken: pair.accessToken, expiresIn: pair.expiresIn }
419
+ }
420
+
421
+ async function revokeToken(db: DB, token: string): Promise<void> {
422
+ const tokenHash = await hashToken(token)
423
+ await db.execute(
424
+ sql`UPDATE pipework_refresh_tokens SET revoked_at = now()
425
+ WHERE token_hash = ${tokenHash} AND revoked_at IS NULL`
426
+ )
427
+ }
428
+
429
+ async function revokeHttp(
430
+ response: HttpResponse,
431
+ db: DB,
432
+ request: Pick<HttpRequest, 'headers'> & { readonly method?: string },
433
+ ): Promise<void> {
434
+ const resolved = getCookieConfig()
435
+ const token = parseCookieHeader(request.headers['cookie'], resolved.name)
436
+ if (token === undefined) {
437
+ throw new UnauthorizedError('Missing refresh token cookie')
438
+ }
439
+ assertSameSiteCookie(request)
440
+ await revokeToken(db, token)
441
+ setCookies(response, clearCookies(resolved))
442
+ }
443
+
444
+ async function revokeRefreshCookie(db: DB, request: Pick<HttpRequest, 'headers'> & { readonly method?: string }): Promise<void> {
445
+ const resolved = getCookieConfig()
446
+ const token = parseCookieHeader(request.headers['cookie'], resolved.name)
447
+ if (token === undefined) return
448
+ assertSameSiteCookie(request)
449
+ await revokeToken(db, token)
450
+ }
451
+
452
+ async function revokeAllHttp(
453
+ response: HttpResponse,
454
+ db: DB,
455
+ userId: string,
456
+ request?: Pick<HttpRequest, 'headers'> & { readonly method?: string },
457
+ ): Promise<void> {
458
+ const resolved = getCookieConfig()
459
+ if (request !== undefined) assertSameSiteCookie(request)
460
+ await revokeAll(db, userId)
461
+ setCookies(response, clearCookies(resolved))
462
+ }
463
+
464
+ function strategy(options: SessionStrategyOptions = {}): AuthStrategy<SessionAuth> {
465
+ const trusted = [...(config.trustedOrigins ?? []), ...(options.trustedOrigins ?? [])]
466
+ const crossSiteReads = options.crossSiteReads ?? 'refuse'
467
+ const tokens = new WeakMap<object, string>()
468
+ const accessCookieName = getAccessCookieConfig()?.name
469
+
470
+ return {
471
+ name: 'sessions',
472
+ extract(request: AuthRequest): Promise<SessionAuth | null> {
473
+ try {
474
+ return Promise.resolve(extractSync(request))
475
+ } catch (error) {
476
+ return Promise.reject(error instanceof Error ? error : new Error(String(error)))
477
+ }
478
+ },
479
+ async verify(extracted: SessionAuth, context: AuthContext): Promise<SessionAuth> {
480
+ const token = tokens.get(extracted)
481
+ if (token === undefined) throw new UnauthorizedError('Invalid access token')
482
+ const payload = await verifyAccessToken(token)
483
+ if (config.versionCheck) {
484
+ let current: boolean
485
+ try {
486
+ current = await checkVersion(context.db(), payload.sub, payload.av)
487
+ } catch (error) {
488
+ if (isPipeworkError(error)) throw error
489
+ throw new AuthUnavailableError('Authentication is unavailable: the session version check failed', { cause: error })
490
+ }
491
+ if (!current) throw new UnauthorizedError('Session revoked')
492
+ }
493
+ return { userId: payload.sub, tenantId: payload.tid, roles: payload.roles ?? [], via: extracted.via }
494
+ },
495
+ }
496
+
497
+ function extractSync(request: AuthRequest): SessionAuth | null {
498
+ let token: string | undefined
499
+ let via: 'cookie' | 'header' = 'header'
500
+ const authorization = request.headers['authorization']
501
+ if (authorization !== undefined && /^bearer /i.test(authorization)) {
502
+ token = authorization.slice(7).trim()
503
+ } else if (accessCookieName !== undefined) {
504
+ const cookie = request.cookies[accessCookieName]
505
+ if (cookie !== undefined && cookie !== '') {
506
+ token = cookie
507
+ via = 'cookie'
508
+ assertSameSiteRequest(request, trusted, crossSiteReads)
509
+ }
510
+ }
511
+ if (token === undefined || token === '') return null
512
+ const extracted: SessionAuth = { userId: '', tenantId: '', roles: [], via }
513
+ tokens.set(extracted, token)
514
+ return extracted
515
+ }
516
+ }
517
+
518
+ return refuseScopedHandle({
519
+ issueTokens, refresh, revokeAll, bumpVersion, verifyAccessToken, signedSubject, checkVersion, cleanExpiredTokens,
520
+ strategy, assertSameSiteCookie, revokeRefreshCookie, issueTokensHttp, refreshHttp, revokeHttp, revokeAllHttp,
521
+ }, 'sessions', 'session and refresh-token rows belong to the user, across tenants')
522
+ }
523
+
524
+ const TEST_KEY_PATTERNS = [
525
+ 'test', 'example', 'dummy', 'placeholder', 'changeme', 'insecure', 'dev-only',
526
+ ]
527
+
528
+ function validateSigningKeys(config: SessionConfig): void {
529
+ const problems: string[] = []
530
+ const { privateKey, publicKey } = config.signing
531
+
532
+ if (privateKey.length < 100) {
533
+ problems.push('Private key appears too short for ES256. Ensure you are using a real PKCS#8 key.')
534
+ }
535
+
536
+ if (publicKey.length < 80) {
537
+ problems.push('Public key appears too short for ES256. Ensure you are using a real SPKI key.')
538
+ }
539
+
540
+ const combined = (privateKey + publicKey).toLowerCase()
541
+ for (const pattern of TEST_KEY_PATTERNS) {
542
+ if (combined.includes(pattern)) {
543
+ problems.push(`Signing key material contains "${pattern}" — this looks like a test key.`)
544
+ break
545
+ }
546
+ }
547
+
548
+ if (!privateKey.includes('BEGIN') || !publicKey.includes('BEGIN')) {
549
+ problems.push('Keys should be PEM-encoded (BEGIN PRIVATE KEY / BEGIN PUBLIC KEY).')
550
+ }
551
+
552
+ if (problems.length > 0) {
553
+ throw new Error(
554
+ `[pipework] Session signing keys are not suitable for production:\n\n${problems.map(p => ` - ${p}`).join('\n')}\n\n` +
555
+ ' Generate production keys with: openssl ecparam -genkey -name prime256v1 -noout | openssl pkcs8 -topk8 -nocrypt\n',
556
+ )
557
+ }
558
+ }
559
+
560
+ async function hashToken(token: string): Promise<string> {
561
+ const encoder = new TextEncoder()
562
+ const data = encoder.encode(token)
563
+ const hash = await crypto.subtle.digest('SHA-256', data)
564
+ return Buffer.from(hash).toString('hex')
565
+ }