pipework 0.252.0 → 0.252.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (690) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/package.json +4 -3
  3. package/src/async/jobs/abortable-delay.ts +18 -0
  4. package/src/async/jobs/claims.ts +52 -0
  5. package/src/async/jobs/cron.ts +179 -0
  6. package/src/async/jobs/errors.ts +56 -0
  7. package/src/async/jobs/exclusion.ts +117 -0
  8. package/src/async/jobs/execute.ts +219 -0
  9. package/src/async/jobs/index.ts +10 -0
  10. package/src/async/jobs/listener.ts +135 -0
  11. package/src/async/jobs/namespace.ts +20 -0
  12. package/src/async/jobs/queue-door.ts +44 -0
  13. package/src/async/jobs/queue.ts +1012 -0
  14. package/src/async/jobs/run-script.ts +67 -0
  15. package/src/async/jobs/scheduler.ts +218 -0
  16. package/src/async/jobs/schedules-table.ts +37 -0
  17. package/src/async/jobs/serialize-error.ts +48 -0
  18. package/src/async/jobs/table.ts +191 -0
  19. package/src/async/pipeline/define.ts +53 -0
  20. package/src/async/pipeline/errors.ts +35 -0
  21. package/src/async/pipeline/execute.ts +53 -0
  22. package/src/async/pipeline/index.ts +13 -0
  23. package/src/async/pipeline/namespace.ts +12 -0
  24. package/src/async/pipeline/resume.ts +67 -0
  25. package/src/async/pipeline/run-steps.ts +98 -0
  26. package/src/async/pipeline/types.ts +57 -0
  27. package/src/async/state-machine/define.ts +64 -0
  28. package/src/async/state-machine/errors.ts +29 -0
  29. package/src/async/state-machine/index.ts +3 -0
  30. package/src/async/state-machine/namespace.ts +12 -0
  31. package/src/async/state-machine/transition.ts +90 -0
  32. package/src/async/state-machine/types.ts +37 -0
  33. package/src/async/steps/errors.ts +31 -0
  34. package/src/async/steps/graph.ts +1214 -0
  35. package/src/async/steps/hash.ts +40 -0
  36. package/src/async/steps/index.ts +7 -0
  37. package/src/async/steps/namespace.ts +7 -0
  38. package/src/async/steps/table.ts +97 -0
  39. package/src/async/steps/types.ts +318 -0
  40. package/src/audit/chain/index.ts +9 -0
  41. package/src/audit/chain/install.ts +113 -0
  42. package/src/audit/chain/retire.ts +52 -0
  43. package/src/audit/chain/verify.ts +257 -0
  44. package/src/audit/query/cursor.ts +37 -0
  45. package/src/audit/query/index.ts +9 -0
  46. package/src/audit/query/query.ts +223 -0
  47. package/src/audit/schema/audit-record-fields.ts +68 -0
  48. package/src/audit/schema/audit-record.ts +23 -0
  49. package/src/auth/auth/audit.ts +31 -0
  50. package/src/auth/auth/chain.ts +84 -0
  51. package/src/auth/auth/cookie.ts +136 -0
  52. package/src/auth/auth/email-links.ts +311 -0
  53. package/src/auth/auth/guard.ts +128 -0
  54. package/src/auth/auth/index.ts +18 -0
  55. package/src/auth/auth/multi-org.ts +337 -0
  56. package/src/auth/auth/namespace.ts +34 -0
  57. package/src/auth/auth/parse-expiry.ts +13 -0
  58. package/src/auth/auth/passwords.ts +110 -0
  59. package/src/auth/auth/schema.ts +110 -0
  60. package/src/auth/auth/sessions.ts +565 -0
  61. package/src/auth/auth/sign-in.ts +156 -0
  62. package/src/auth/auth/signing-keys.ts +69 -0
  63. package/src/auth/auth/types.ts +26 -0
  64. package/src/auth/auth/uuid.ts +10 -0
  65. package/src/auth/rbac/cache.ts +55 -0
  66. package/src/auth/rbac/check.ts +30 -0
  67. package/src/auth/rbac/create.ts +35 -0
  68. package/src/auth/rbac/index.ts +5 -0
  69. package/src/auth/rbac/middleware.ts +20 -0
  70. package/src/auth/rbac/namespace.ts +15 -0
  71. package/src/auth/rbac/resolve.ts +31 -0
  72. package/src/auth/rbac/schema.sql +31 -0
  73. package/src/auth/rbac/seed.ts +67 -0
  74. package/src/auth/rbac/tables.ts +32 -0
  75. package/src/auth/rbac/types.ts +65 -0
  76. package/src/auth/tenant/extract.ts +33 -0
  77. package/src/auth/tenant/in-tenant.ts +49 -0
  78. package/src/auth/tenant/index.ts +7 -0
  79. package/src/auth/tenant/namespace.ts +23 -0
  80. package/src/auth/tenant/propagate.ts +20 -0
  81. package/src/auth/tenant/rls.ts +120 -0
  82. package/src/auth/tenant/scope.ts +33 -0
  83. package/src/auth/tenant/scoped-db.ts +581 -0
  84. package/src/auth/tenant/types.ts +14 -0
  85. package/src/auth/tenant/validate.ts +27 -0
  86. package/src/cli/commands/add.ts +158 -0
  87. package/src/cli/commands/alerts.ts +98 -0
  88. package/src/cli/commands/check.ts +1418 -0
  89. package/src/cli/commands/codemod.ts +78 -0
  90. package/src/cli/commands/db.ts +356 -0
  91. package/src/cli/commands/dev.ts +101 -0
  92. package/src/cli/commands/generate.ts +75 -0
  93. package/src/cli/commands/init.ts +36 -0
  94. package/src/cli/commands/install.ts +28 -0
  95. package/src/cli/commands/lint.ts +62 -0
  96. package/src/cli/commands/migrate.ts +132 -0
  97. package/src/cli/commands/openapi.ts +63 -0
  98. package/src/cli/commands/remove.ts +72 -0
  99. package/src/cli/commands/run.ts +50 -0
  100. package/src/cli/commands/scope.ts +54 -0
  101. package/src/cli/commands/serve.ts +68 -0
  102. package/src/cli/commands/shard.ts +31 -0
  103. package/src/cli/commands/shared/config-pipework-version.ts +28 -0
  104. package/src/cli/commands/shared/find-config.ts +22 -0
  105. package/src/cli/commands/shared/load-config.ts +35 -0
  106. package/src/cli/commands/shared/pnpm-install.ts +95 -0
  107. package/src/cli/commands/shared/report-removed.ts +8 -0
  108. package/src/cli/commands/sync.ts +32 -0
  109. package/src/cli/commands/test.ts +307 -0
  110. package/src/cli/commands/upgrade.ts +48 -0
  111. package/src/cli/dev-bootstrap.ts +24 -0
  112. package/src/cli/errors.ts +10 -0
  113. package/src/cli/index.ts +303 -0
  114. package/src/cli/output.ts +17 -0
  115. package/src/cli/port.ts +15 -0
  116. package/src/cli/surface-kinds.ts +20 -0
  117. package/src/client/index.ts +4 -0
  118. package/src/client/poll.ts +130 -0
  119. package/src/client/report-fault.ts +119 -0
  120. package/src/core/config/app-pool.ts +19 -0
  121. package/src/core/config/aws-env.ts +29 -0
  122. package/src/core/config/base-dir.ts +24 -0
  123. package/src/core/config/discover.ts +64 -0
  124. package/src/core/config/env-resolve.ts +87 -0
  125. package/src/core/config/env-types.ts +116 -0
  126. package/src/core/config/env.ts +55 -0
  127. package/src/core/config/errors.ts +9 -0
  128. package/src/core/config/import-config.ts +40 -0
  129. package/src/core/config/index.ts +8 -0
  130. package/src/core/config/load.ts +417 -0
  131. package/src/core/config/namespace.ts +14 -0
  132. package/src/core/config/resolve.ts +195 -0
  133. package/src/core/config/schema.ts +488 -0
  134. package/src/core/config/statement-observer.ts +48 -0
  135. package/src/core/config/ts-inline-hooks.ts +75 -0
  136. package/src/core/config/ts-register.ts +4 -0
  137. package/src/core/config/ts-resolve-hooks.ts +101 -0
  138. package/src/core/errors/base.ts +49 -0
  139. package/src/core/errors/http.ts +146 -0
  140. package/src/core/errors/index.ts +2 -0
  141. package/src/core/errors/namespace.ts +31 -0
  142. package/src/core/lifecycle/drain.ts +33 -0
  143. package/src/core/lifecycle/health.ts +72 -0
  144. package/src/core/lifecycle/index.ts +4 -0
  145. package/src/core/lifecycle/namespace.ts +7 -0
  146. package/src/core/lifecycle/startup.ts +102 -0
  147. package/src/core/lifecycle/types.ts +36 -0
  148. package/src/core/logging/context.ts +60 -0
  149. package/src/core/logging/error-chain.ts +68 -0
  150. package/src/core/logging/index.ts +5 -0
  151. package/src/core/logging/logger.ts +65 -0
  152. package/src/core/logging/namespace.ts +16 -0
  153. package/src/core/logging/proxy.ts +22 -0
  154. package/src/core/logging/redact-match.ts +24 -0
  155. package/src/core/logging/types.ts +47 -0
  156. package/src/core/pipework.ts +566 -0
  157. package/src/core/runtime/broker.ts +69 -0
  158. package/src/core/surface/http.ts +133 -0
  159. package/src/core/surface/index.ts +11 -0
  160. package/src/core/surface/job-timeout.ts +40 -0
  161. package/src/core/surface/namespace.ts +13 -0
  162. package/src/core/surface/script.ts +33 -0
  163. package/src/core/surface/start.ts +142 -0
  164. package/src/core/surface/types.ts +225 -0
  165. package/src/core/surface/validate.ts +88 -0
  166. package/src/core/surface/worker.ts +528 -0
  167. package/src/core/validation/connectivity.ts +49 -0
  168. package/src/core/validation/domain.ts +99 -0
  169. package/src/core/validation/index.ts +5 -0
  170. package/src/core/validation/queue-tables.ts +312 -0
  171. package/src/core/validation/rls-role.ts +138 -0
  172. package/src/core/validation/startup.ts +51 -0
  173. package/src/core/validation/surfaces.ts +65 -0
  174. package/src/core/validation/types.ts +25 -0
  175. package/src/data/db/advisory-lock.ts +55 -0
  176. package/src/data/db/aggregates.ts +172 -0
  177. package/src/data/db/array-elements.ts +111 -0
  178. package/src/data/db/bulk-set.ts +53 -0
  179. package/src/data/db/col/index.ts +14 -0
  180. package/src/data/db/composed.ts +53 -0
  181. package/src/data/db/db.ts +276 -0
  182. package/src/data/db/excluded.ts +16 -0
  183. package/src/data/db/expressions.ts +473 -0
  184. package/src/data/db/filter.ts +90 -0
  185. package/src/data/db/function-source.ts +114 -0
  186. package/src/data/db/identifiers.ts +16 -0
  187. package/src/data/db/idx/index.ts +9 -0
  188. package/src/data/db/in-list.ts +49 -0
  189. package/src/data/db/index.ts +9 -0
  190. package/src/data/db/insert-split.ts +137 -0
  191. package/src/data/db/instrumentation.ts +82 -0
  192. package/src/data/db/maintenance.ts +28 -0
  193. package/src/data/db/namespace.ts +107 -0
  194. package/src/data/db/owner-labels.ts +9 -0
  195. package/src/data/db/pool.ts +187 -0
  196. package/src/data/db/query-label.ts +13 -0
  197. package/src/data/db/query-watch.ts +116 -0
  198. package/src/data/db/raw-client-warning.ts +37 -0
  199. package/src/data/db/readonly.ts +23 -0
  200. package/src/data/db/reservation.ts +151 -0
  201. package/src/data/db/schema-features.ts +14 -0
  202. package/src/data/db/serializable.ts +83 -0
  203. package/src/data/db/sql.ts +1 -0
  204. package/src/data/db/timeouts.ts +76 -0
  205. package/src/data/db/types.ts +18 -0
  206. package/src/data/db/unbound.ts +33 -0
  207. package/src/data/db/values.ts +29 -0
  208. package/src/data/domain/brand.ts +15 -0
  209. package/src/data/domain/build-factory.ts +193 -0
  210. package/src/data/domain/build-schema.ts +161 -0
  211. package/src/data/domain/build-table.ts +355 -0
  212. package/src/data/domain/define.ts +239 -0
  213. package/src/data/domain/external-registry.ts +34 -0
  214. package/src/data/domain/external.ts +77 -0
  215. package/src/data/domain/field.ts +279 -0
  216. package/src/data/domain/index.ts +13 -0
  217. package/src/data/domain/naming.ts +6 -0
  218. package/src/data/domain/projections.ts +57 -0
  219. package/src/data/domain/trace-safe-projection.ts +31 -0
  220. package/src/data/domain/traits.ts +108 -0
  221. package/src/data/domain/types.ts +289 -0
  222. package/src/data/jsonb/composed.ts +18 -0
  223. package/src/data/jsonb/index.ts +1 -0
  224. package/src/data/jsonb/namespace.ts +30 -0
  225. package/src/data/jsonb/query.ts +86 -0
  226. package/src/data/migrate/append-only-generate.ts +47 -0
  227. package/src/data/migrate/applied.ts +47 -0
  228. package/src/data/migrate/apply.ts +309 -0
  229. package/src/data/migrate/check.ts +119 -0
  230. package/src/data/migrate/diff.ts +357 -0
  231. package/src/data/migrate/door-generate.ts +130 -0
  232. package/src/data/migrate/framework-rls.ts +58 -0
  233. package/src/data/migrate/generate.ts +201 -0
  234. package/src/data/migrate/history.ts +215 -0
  235. package/src/data/migrate/index.ts +9 -0
  236. package/src/data/migrate/internal-definitions.ts +175 -0
  237. package/src/data/migrate/post-process.ts +73 -0
  238. package/src/data/migrate/pragma.ts +73 -0
  239. package/src/data/migrate/provision-framework.ts +147 -0
  240. package/src/data/migrate/rls-generate.ts +61 -0
  241. package/src/data/migrate/run.ts +124 -0
  242. package/src/data/migrate/safety.ts +167 -0
  243. package/src/data/migrate/snapshot.ts +368 -0
  244. package/src/data/migrate/sql-emit.ts +392 -0
  245. package/src/data/migrate/statements.ts +312 -0
  246. package/src/data/query/alias.ts +126 -0
  247. package/src/data/query/batch.ts +8 -0
  248. package/src/data/query/cache/core/cache.ts +78 -0
  249. package/src/data/query/cache/core/index.ts +1 -0
  250. package/src/data/query/cache/core/types.ts +29 -0
  251. package/src/data/query/cache/readme.md +230 -0
  252. package/src/data/query/casing.ts +76 -0
  253. package/src/data/query/collation.ts +11 -0
  254. package/src/data/query/column-builder.ts +370 -0
  255. package/src/data/query/column.ts +150 -0
  256. package/src/data/query/entity.ts +42 -0
  257. package/src/data/query/errors.ts +33 -0
  258. package/src/data/query/index.ts +14 -0
  259. package/src/data/query/logger.ts +47 -0
  260. package/src/data/query/operations.ts +45 -0
  261. package/src/data/query/pg-core/alias.ts +12 -0
  262. package/src/data/query/pg-core/checks.ts +32 -0
  263. package/src/data/query/pg-core/columns/all.ts +71 -0
  264. package/src/data/query/pg-core/columns/bigint.ts +110 -0
  265. package/src/data/query/pg-core/columns/bigserial.ts +128 -0
  266. package/src/data/query/pg-core/columns/boolean.ts +43 -0
  267. package/src/data/query/pg-core/columns/char.ts +85 -0
  268. package/src/data/query/pg-core/columns/cidr.ts +43 -0
  269. package/src/data/query/pg-core/columns/common.ts +366 -0
  270. package/src/data/query/pg-core/columns/custom.ts +232 -0
  271. package/src/data/query/pg-core/columns/date.common.ts +15 -0
  272. package/src/data/query/pg-core/columns/date.ts +112 -0
  273. package/src/data/query/pg-core/columns/double-precision.ts +55 -0
  274. package/src/data/query/pg-core/columns/enum.ts +201 -0
  275. package/src/data/query/pg-core/columns/index.ts +35 -0
  276. package/src/data/query/pg-core/columns/inet.ts +43 -0
  277. package/src/data/query/pg-core/columns/int.common.ts +57 -0
  278. package/src/data/query/pg-core/columns/integer.ts +53 -0
  279. package/src/data/query/pg-core/columns/interval.ts +83 -0
  280. package/src/data/query/pg-core/columns/json.ts +58 -0
  281. package/src/data/query/pg-core/columns/jsonb.ts +56 -0
  282. package/src/data/query/pg-core/columns/line.ts +117 -0
  283. package/src/data/query/pg-core/columns/macaddr.ts +43 -0
  284. package/src/data/query/pg-core/columns/macaddr8.ts +43 -0
  285. package/src/data/query/pg-core/columns/numeric.ts +227 -0
  286. package/src/data/query/pg-core/columns/point.ts +127 -0
  287. package/src/data/query/pg-core/columns/postgis_extension/geometry.ts +119 -0
  288. package/src/data/query/pg-core/columns/postgis_extension/utils.ts +47 -0
  289. package/src/data/query/pg-core/columns/real.ts +58 -0
  290. package/src/data/query/pg-core/columns/serial.ts +55 -0
  291. package/src/data/query/pg-core/columns/smallint.ts +53 -0
  292. package/src/data/query/pg-core/columns/smallserial.ts +60 -0
  293. package/src/data/query/pg-core/columns/text.ts +67 -0
  294. package/src/data/query/pg-core/columns/time.ts +72 -0
  295. package/src/data/query/pg-core/columns/timestamp.ts +163 -0
  296. package/src/data/query/pg-core/columns/uuid.ts +51 -0
  297. package/src/data/query/pg-core/columns/varchar.ts +89 -0
  298. package/src/data/query/pg-core/columns/vector_extension/bit.ts +68 -0
  299. package/src/data/query/pg-core/columns/vector_extension/halfvec.ts +80 -0
  300. package/src/data/query/pg-core/columns/vector_extension/sparsevec.ts +67 -0
  301. package/src/data/query/pg-core/columns/vector_extension/vector.ts +80 -0
  302. package/src/data/query/pg-core/db.ts +674 -0
  303. package/src/data/query/pg-core/dialect.ts +1404 -0
  304. package/src/data/query/pg-core/expressions.ts +25 -0
  305. package/src/data/query/pg-core/foreign-keys.ts +130 -0
  306. package/src/data/query/pg-core/index.ts +21 -0
  307. package/src/data/query/pg-core/indexes.ts +276 -0
  308. package/src/data/query/pg-core/policies.ts +56 -0
  309. package/src/data/query/pg-core/primary-keys.ts +62 -0
  310. package/src/data/query/pg-core/query-builders/count.ts +86 -0
  311. package/src/data/query/pg-core/query-builders/delete.ts +293 -0
  312. package/src/data/query/pg-core/query-builders/index.ts +7 -0
  313. package/src/data/query/pg-core/query-builders/insert.ts +452 -0
  314. package/src/data/query/pg-core/query-builders/query-builder.ts +123 -0
  315. package/src/data/query/pg-core/query-builders/query.ts +157 -0
  316. package/src/data/query/pg-core/query-builders/raw.ts +49 -0
  317. package/src/data/query/pg-core/query-builders/refresh-materialized-view.ts +108 -0
  318. package/src/data/query/pg-core/query-builders/select.ts +1346 -0
  319. package/src/data/query/pg-core/query-builders/select.types.ts +437 -0
  320. package/src/data/query/pg-core/query-builders/update.ts +626 -0
  321. package/src/data/query/pg-core/roles.ts +41 -0
  322. package/src/data/query/pg-core/schema.ts +72 -0
  323. package/src/data/query/pg-core/sequence.ts +41 -0
  324. package/src/data/query/pg-core/session.ts +292 -0
  325. package/src/data/query/pg-core/subquery.ts +46 -0
  326. package/src/data/query/pg-core/table.ts +252 -0
  327. package/src/data/query/pg-core/unique-constraint.ts +73 -0
  328. package/src/data/query/pg-core/utils/array.ts +95 -0
  329. package/src/data/query/pg-core/utils/index.ts +1 -0
  330. package/src/data/query/pg-core/utils.ts +104 -0
  331. package/src/data/query/pg-core/view-base.ts +14 -0
  332. package/src/data/query/pg-core/view-common.ts +1 -0
  333. package/src/data/query/pg-core/view.ts +435 -0
  334. package/src/data/query/pg-core/with-builder.ts +41 -0
  335. package/src/data/query/postgres-js/README.md +46 -0
  336. package/src/data/query/postgres-js/array-parser.ts +45 -0
  337. package/src/data/query/postgres-js/driver-error-boundary.ts +149 -0
  338. package/src/data/query/postgres-js/driver.ts +163 -0
  339. package/src/data/query/postgres-js/index.ts +2 -0
  340. package/src/data/query/postgres-js/session.ts +234 -0
  341. package/src/data/query/primary-key.ts +11 -0
  342. package/src/data/query/query-builders/query-builder.ts +19 -0
  343. package/src/data/query/query-builders/select.types.ts +175 -0
  344. package/src/data/query/query-promise.ts +35 -0
  345. package/src/data/query/relations.ts +725 -0
  346. package/src/data/query/runnable-query.ts +12 -0
  347. package/src/data/query/selection-proxy.ts +121 -0
  348. package/src/data/query/session.ts +8 -0
  349. package/src/data/query/sql/expressions/conditions.ts +741 -0
  350. package/src/data/query/sql/expressions/index.ts +2 -0
  351. package/src/data/query/sql/expressions/select.ts +45 -0
  352. package/src/data/query/sql/functions/aggregate.ts +129 -0
  353. package/src/data/query/sql/functions/index.ts +2 -0
  354. package/src/data/query/sql/functions/vector.ts +178 -0
  355. package/src/data/query/sql/index.ts +3 -0
  356. package/src/data/query/sql/sql.ts +794 -0
  357. package/src/data/query/subquery.ts +53 -0
  358. package/src/data/query/table.ts +208 -0
  359. package/src/data/query/table.utils.ts +2 -0
  360. package/src/data/query/tracing-utils.ts +3 -0
  361. package/src/data/query/tracing.ts +11 -0
  362. package/src/data/query/utils.ts +357 -0
  363. package/src/data/query/version.ts +4 -0
  364. package/src/data/query/view-common.ts +1 -0
  365. package/src/data/schema/branded.ts +13 -0
  366. package/src/data/schema/generated/coerce.ts +5 -0
  367. package/src/data/schema/generated/combinator.ts +6 -0
  368. package/src/data/schema/generated/encoding.ts +5 -0
  369. package/src/data/schema/generated/error.ts +6 -0
  370. package/src/data/schema/generated/format.ts +5 -0
  371. package/src/data/schema/generated/type-constructor.ts +10 -0
  372. package/src/data/schema/generated/type.ts +6 -0
  373. package/src/data/schema/index.ts +6 -0
  374. package/src/data/schema/json-schema.ts +33 -0
  375. package/src/data/schema/namespace.ts +55 -0
  376. package/src/data/schema/parse.ts +39 -0
  377. package/src/data/schema/types.ts +39 -0
  378. package/src/data/temporal/append-only.ts +134 -0
  379. package/src/data/temporal/close.ts +27 -0
  380. package/src/data/temporal/columns.ts +10 -0
  381. package/src/data/temporal/definition-queries.ts +70 -0
  382. package/src/data/temporal/errors.ts +10 -0
  383. package/src/data/temporal/get-current.ts +22 -0
  384. package/src/data/temporal/index.ts +9 -0
  385. package/src/data/temporal/namespace.ts +36 -0
  386. package/src/data/temporal/query.ts +25 -0
  387. package/src/data/temporal/resolve.ts +17 -0
  388. package/src/data/temporal/revise.ts +67 -0
  389. package/src/data/temporal/types.ts +22 -0
  390. package/src/data/valve/artifact.ts +33 -0
  391. package/src/data/valve/contract-diff.ts +21 -0
  392. package/src/data/valve/cross.ts +57 -0
  393. package/src/data/valve/crossing-ledger.ts +50 -0
  394. package/src/data/valve/decision.ts +44 -0
  395. package/src/data/valve/durable-crossing.ts +52 -0
  396. package/src/data/valve/execute-crossing.ts +77 -0
  397. package/src/data/valve/faucet.ts +56 -0
  398. package/src/data/valve/gate.ts +114 -0
  399. package/src/data/valve/graph.ts +77 -0
  400. package/src/data/valve/index.ts +53 -0
  401. package/src/data/valve/namespace.ts +57 -0
  402. package/src/data/valve/registry.ts +50 -0
  403. package/src/data/valve/schema/valve-crossing-fields.ts +23 -0
  404. package/src/data/valve/schema/valve-crossing.ts +9 -0
  405. package/src/data/valve/supply.ts +154 -0
  406. package/src/data/valve/types.ts +143 -0
  407. package/src/data/vector/columns.ts +27 -0
  408. package/src/data/vector/index.ts +4 -0
  409. package/src/data/vector/namespace.ts +33 -0
  410. package/src/data/vector/query.ts +85 -0
  411. package/src/data/vector/validate.ts +16 -0
  412. package/src/data/write/audit/actor.ts +15 -0
  413. package/src/data/write/audit/audit-columns.ts +18 -0
  414. package/src/data/write/audit/audit-select.ts +111 -0
  415. package/src/data/write/audit/bound-transaction.ts +14 -0
  416. package/src/data/write/audit/cte-compile.ts +32 -0
  417. package/src/data/write/audit/decode-returning.ts +47 -0
  418. package/src/data/write/audit/final-select.ts +43 -0
  419. package/src/data/write/audit/infra-audit.ts +36 -0
  420. package/src/data/write/audit/primary-key.ts +65 -0
  421. package/src/data/write/audit/projection.ts +41 -0
  422. package/src/data/write/audit/read-touches.ts +86 -0
  423. package/src/data/write/audit/touch-match.ts +78 -0
  424. package/src/data/write/audit/verb-delete.ts +62 -0
  425. package/src/data/write/audit/verb-insert.ts +36 -0
  426. package/src/data/write/audit/verb-select.ts +47 -0
  427. package/src/data/write/audit/verb-update.ts +60 -0
  428. package/src/data/write/audit/verb-upsert.ts +104 -0
  429. package/src/data/write/conflict.ts +43 -0
  430. package/src/data/write/delete.ts +38 -0
  431. package/src/data/write/execute.ts +243 -0
  432. package/src/data/write/index.ts +11 -0
  433. package/src/data/write/insert.ts +63 -0
  434. package/src/data/write/state.ts +43 -0
  435. package/src/data/write/update.ts +54 -0
  436. package/src/data/write/upsert.ts +58 -0
  437. package/src/data/write/values.ts +19 -0
  438. package/src/index.ts +230 -0
  439. package/src/infra/access-links/code.ts +70 -0
  440. package/src/infra/access-links/handle.ts +892 -0
  441. package/src/infra/access-links/index.ts +9 -0
  442. package/src/infra/access-links/namespace.ts +30 -0
  443. package/src/infra/access-links/person-check.ts +177 -0
  444. package/src/infra/access-links/schema.ts +71 -0
  445. package/src/infra/alerts/async-sources.ts +231 -0
  446. package/src/infra/alerts/audit.ts +36 -0
  447. package/src/infra/alerts/beat.ts +123 -0
  448. package/src/infra/alerts/client-faults.ts +111 -0
  449. package/src/infra/alerts/faults.ts +156 -0
  450. package/src/infra/alerts/handle.ts +778 -0
  451. package/src/infra/alerts/http.ts +192 -0
  452. package/src/infra/alerts/index.ts +12 -0
  453. package/src/infra/alerts/infra-sources.ts +180 -0
  454. package/src/infra/alerts/namespace.ts +81 -0
  455. package/src/infra/alerts/redact.ts +21 -0
  456. package/src/infra/alerts/request-faults.ts +41 -0
  457. package/src/infra/alerts/schema.ts +124 -0
  458. package/src/infra/alerts/sinks.ts +125 -0
  459. package/src/infra/alerts/source-options.ts +26 -0
  460. package/src/infra/alerts/sources.ts +503 -0
  461. package/src/infra/alerts/subsystem-sources.ts +137 -0
  462. package/src/infra/audit/emit.ts +87 -0
  463. package/src/infra/audit/index.ts +2 -0
  464. package/src/infra/audit/namespace.ts +22 -0
  465. package/src/infra/audit/schema.sql +35 -0
  466. package/src/infra/audit/types.ts +18 -0
  467. package/src/infra/aws/credentials.ts +147 -0
  468. package/src/infra/aws/sigv4.ts +140 -0
  469. package/src/infra/cache/create.ts +58 -0
  470. package/src/infra/cache/entry.ts +81 -0
  471. package/src/infra/cache/index.ts +4 -0
  472. package/src/infra/cache/namespace.ts +10 -0
  473. package/src/infra/cache/tenant.ts +93 -0
  474. package/src/infra/cache/types.ts +24 -0
  475. package/src/infra/crawl/audit.ts +35 -0
  476. package/src/infra/crawl/errors.ts +25 -0
  477. package/src/infra/crawl/handle.ts +693 -0
  478. package/src/infra/crawl/index.ts +9 -0
  479. package/src/infra/crawl/links.ts +160 -0
  480. package/src/infra/crawl/namespace.ts +36 -0
  481. package/src/infra/crawl/robots.ts +100 -0
  482. package/src/infra/crawl/schema.ts +89 -0
  483. package/src/infra/credit-line/handle.ts +883 -0
  484. package/src/infra/credit-line/index.ts +6 -0
  485. package/src/infra/credit-line/namespace.ts +7 -0
  486. package/src/infra/credit-line/schema.ts +96 -0
  487. package/src/infra/credits/handle.ts +706 -0
  488. package/src/infra/credits/index.ts +5 -0
  489. package/src/infra/credits/namespace.ts +7 -0
  490. package/src/infra/credits/schema.ts +83 -0
  491. package/src/infra/email/audit.ts +36 -0
  492. package/src/infra/email/inbound.ts +622 -0
  493. package/src/infra/email/index.ts +11 -0
  494. package/src/infra/email/mail.ts +517 -0
  495. package/src/infra/email/mime.ts +447 -0
  496. package/src/infra/email/namespace.ts +22 -0
  497. package/src/infra/email/providers.ts +111 -0
  498. package/src/infra/email/schema.ts +96 -0
  499. package/src/infra/email/sns.ts +200 -0
  500. package/src/infra/email/unsubscribe.ts +44 -0
  501. package/src/infra/fetch/address.ts +88 -0
  502. package/src/infra/fetch/connect-retry.ts +87 -0
  503. package/src/infra/fetch/handle.ts +329 -0
  504. package/src/infra/fetch/index.ts +7 -0
  505. package/src/infra/fetch/namespace.ts +70 -0
  506. package/src/infra/idempotency/index.ts +3 -0
  507. package/src/infra/idempotency/middleware.ts +87 -0
  508. package/src/infra/idempotency/store.ts +92 -0
  509. package/src/infra/idempotency/types.ts +30 -0
  510. package/src/infra/join-requests/handle.ts +312 -0
  511. package/src/infra/join-requests/index.ts +2 -0
  512. package/src/infra/join-requests/namespace.ts +7 -0
  513. package/src/infra/join-requests/schema.ts +33 -0
  514. package/src/infra/outbox/core.ts +165 -0
  515. package/src/infra/quota/errors.ts +32 -0
  516. package/src/infra/quota/handle.ts +215 -0
  517. package/src/infra/quota/index.ts +5 -0
  518. package/src/infra/quota/namespace.ts +7 -0
  519. package/src/infra/quota/schema.ts +15 -0
  520. package/src/infra/storage/backend.ts +34 -0
  521. package/src/infra/storage/handle.ts +513 -0
  522. package/src/infra/storage/index.ts +9 -0
  523. package/src/infra/storage/local.ts +104 -0
  524. package/src/infra/storage/namespace.ts +13 -0
  525. package/src/infra/storage/s3.ts +257 -0
  526. package/src/infra/storage/schema.ts +24 -0
  527. package/src/infra/support/handle.ts +854 -0
  528. package/src/infra/support/http.ts +229 -0
  529. package/src/infra/support/index.ts +7 -0
  530. package/src/infra/support/namespace.ts +12 -0
  531. package/src/infra/support/schema.ts +96 -0
  532. package/src/infra/webhook/inbound.ts +45 -0
  533. package/src/infra/webhook/index.ts +5 -0
  534. package/src/infra/webhook/namespace.ts +24 -0
  535. package/src/infra/webhook/outbound.ts +315 -0
  536. package/src/infra/webhook/sign.ts +32 -0
  537. package/src/infra/webhook/verify.ts +82 -0
  538. package/src/invariants/assert.ts +26 -0
  539. package/src/invariants/index.ts +1 -0
  540. package/src/lint/config.ts +56 -0
  541. package/src/lint/doctrine.ts +163 -0
  542. package/src/lint/include.ts +97 -0
  543. package/src/lint/index.ts +3 -0
  544. package/src/lint/preset.ts +10 -0
  545. package/src/lint/resolver.ts +218 -0
  546. package/src/lint/rules/no-reexports.ts +46 -0
  547. package/src/request/behavior/audited.ts +85 -0
  548. package/src/request/behavior/cached.ts +62 -0
  549. package/src/request/behavior/compose.ts +28 -0
  550. package/src/request/behavior/index.ts +5 -0
  551. package/src/request/behavior/namespace.ts +16 -0
  552. package/src/request/behavior/types.ts +26 -0
  553. package/src/request/behavior/versioned.ts +54 -0
  554. package/src/request/context/create.ts +103 -0
  555. package/src/request/context/guard.ts +49 -0
  556. package/src/request/context/index.ts +4 -0
  557. package/src/request/context/run-in-transaction.ts +200 -0
  558. package/src/request/context/store.ts +28 -0
  559. package/src/request/context/types.ts +50 -0
  560. package/src/request/di/builder.ts +535 -0
  561. package/src/request/di/index.ts +8 -0
  562. package/src/request/di/resolve.ts +271 -0
  563. package/src/request/di/types.ts +262 -0
  564. package/src/request/fitting/namespace.ts +7 -0
  565. package/src/request/fixture/batch.ts +71 -0
  566. package/src/request/fixture/builder.ts +26 -0
  567. package/src/request/fixture/errors.ts +10 -0
  568. package/src/request/fixture/index.ts +8 -0
  569. package/src/request/fixture/namespace.ts +23 -0
  570. package/src/request/fixture/paginate.ts +44 -0
  571. package/src/request/fixture/to-handlers.ts +260 -0
  572. package/src/request/fixture/types.ts +79 -0
  573. package/src/request/flow/act-as.ts +78 -0
  574. package/src/request/flow/namespace.ts +17 -0
  575. package/src/request/http/error-step.ts +42 -0
  576. package/src/request/http/file.ts +141 -0
  577. package/src/request/http/index.ts +4 -0
  578. package/src/request/http/middleware.ts +141 -0
  579. package/src/request/http/namespace.ts +5 -0
  580. package/src/request/http/rate-limit-classes.ts +170 -0
  581. package/src/request/http/response.ts +82 -0
  582. package/src/request/http/server.ts +916 -0
  583. package/src/request/http/sniff.ts +261 -0
  584. package/src/request/http/types.ts +250 -0
  585. package/src/request/http/upload.ts +284 -0
  586. package/src/request/internal/text.ts +6 -0
  587. package/src/request/openapi/generate.ts +205 -0
  588. package/src/request/openapi/index.ts +2 -0
  589. package/src/request/openapi/namespace.ts +7 -0
  590. package/src/test/auth.ts +13 -0
  591. package/src/test/auto-setup.ts +45 -0
  592. package/src/test/context.ts +91 -0
  593. package/src/test/crawl-fixture.ts +157 -0
  594. package/src/test/discover-fork.ts +17 -0
  595. package/src/test/fingerprint.ts +135 -0
  596. package/src/test/globals.d.ts +7 -0
  597. package/src/test/index.ts +19 -0
  598. package/src/test/namespace.ts +87 -0
  599. package/src/test/plugin.ts +189 -0
  600. package/src/test/progress.ts +185 -0
  601. package/src/test/reap-after-run.ts +28 -0
  602. package/src/test/reap.ts +286 -0
  603. package/src/test/reset.ts +253 -0
  604. package/src/test/savepoints.ts +172 -0
  605. package/src/test/setup.ts +1422 -0
  606. package/src/test/system-channel.ts +50 -0
  607. package/src/test/vitest-plugin.ts +142 -0
  608. package/src/test/vitest-workspace.ts +507 -0
  609. package/src/test/vitest.ts +333 -0
  610. package/src/test/watch.ts +105 -0
  611. package/src/trace/capture/bounded-serializer.ts +146 -0
  612. package/src/trace/cardinality/analyze.ts +173 -0
  613. package/src/trace/cardinality/branch-context.ts +214 -0
  614. package/src/trace/cardinality/check.ts +33 -0
  615. package/src/trace/cardinality/classify-edge.ts +64 -0
  616. package/src/trace/cardinality/structural-max.ts +107 -0
  617. package/src/trace/check/coverage-check.ts +188 -0
  618. package/src/trace/check/flow-check.ts +103 -0
  619. package/src/trace/check/flow-step-site.ts +234 -0
  620. package/src/trace/check/io-pattern.ts +116 -0
  621. package/src/trace/codemod/add-cardinality.ts +152 -0
  622. package/src/trace/codemod/run.ts +80 -0
  623. package/src/trace/entry/child-trace.ts +21 -0
  624. package/src/trace/entry/close-trace.ts +87 -0
  625. package/src/trace/entry/finalize-trace.ts +28 -0
  626. package/src/trace/entry/open-trace.ts +138 -0
  627. package/src/trace/entry/parent-trace.ts +20 -0
  628. package/src/trace/entry/parse-traceparent.ts +39 -0
  629. package/src/trace/entry/process-start.ts +38 -0
  630. package/src/trace/entry/trace-context.ts +26 -0
  631. package/src/trace/entry/tracing-enabled.ts +10 -0
  632. package/src/trace/external/record.ts +195 -0
  633. package/src/trace/external/report.ts +66 -0
  634. package/src/trace/namespace.ts +19 -0
  635. package/src/trace/partition/day.ts +47 -0
  636. package/src/trace/partition/index.ts +14 -0
  637. package/src/trace/partition/partition-name.ts +23 -0
  638. package/src/trace/partition/plan.ts +82 -0
  639. package/src/trace/partition/schedule.ts +26 -0
  640. package/src/trace/partition/startup-hook.ts +39 -0
  641. package/src/trace/partition/sync.ts +154 -0
  642. package/src/trace/partition/tables.ts +53 -0
  643. package/src/trace/read/tree.ts +83 -0
  644. package/src/trace/retain/copy-on-error.ts +76 -0
  645. package/src/trace/runtime/expire-stale-traces.ts +54 -0
  646. package/src/trace/runtime/flow-step.ts +147 -0
  647. package/src/trace/runtime/flush-steps.ts +31 -0
  648. package/src/trace/runtime/pending-writes.ts +54 -0
  649. package/src/trace/runtime/step-buffer.ts +298 -0
  650. package/src/trace/runtime/step-error.ts +21 -0
  651. package/src/trace/runtime/step-meta.ts +55 -0
  652. package/src/trace/runtime/thenable.ts +12 -0
  653. package/src/trace/runtime/truncate-trace.ts +62 -0
  654. package/src/trace/schema/trace-fields.ts +52 -0
  655. package/src/trace/schema/trace-retained.ts +22 -0
  656. package/src/trace/schema/trace-step-fields.ts +44 -0
  657. package/src/trace/schema/trace-step-retained.ts +25 -0
  658. package/src/trace/schema/trace-step.ts +18 -0
  659. package/src/trace/schema/trace.ts +12 -0
  660. package/src/trace/transformer/apply.ts +79 -0
  661. package/src/trace/transformer/build-meta-literal.ts +30 -0
  662. package/src/trace/transformer/find-flow-step-sites.ts +85 -0
  663. package/src/trace/transformer/inject-flow-step-import.ts +39 -0
  664. package/src/trace/transformer/transform-error.ts +14 -0
  665. package/src/trace/transformer/transform-flow-steps.ts +123 -0
  666. package/src/trace/transformer/wrap-function-declaration.ts +62 -0
  667. package/src/trace/transformer/wrap-variable-declaration.ts +67 -0
  668. package/src/workspace/affected.ts +110 -0
  669. package/src/workspace/changed-files.ts +163 -0
  670. package/src/workspace/check-deps.ts +213 -0
  671. package/src/workspace/checksum.ts +20 -0
  672. package/src/workspace/dependency-graph.ts +67 -0
  673. package/src/workspace/detect-pipework-copies.ts +93 -0
  674. package/src/workspace/discover.ts +206 -0
  675. package/src/workspace/generate.ts +401 -0
  676. package/src/workspace/index.ts +7 -0
  677. package/src/workspace/module-imports-pipework.ts +39 -0
  678. package/src/workspace/module-package-name.ts +12 -0
  679. package/src/workspace/scrub-git-env.ts +23 -0
  680. package/src/workspace/source-paths.ts +36 -0
  681. package/src/workspace/sync.ts +182 -0
  682. package/dist/REFERENCE.md +0 -1477
  683. package/dist/infra/access-links/rate-limit.d.ts +0 -10
  684. package/dist/infra/access-links/rate-limit.d.ts.map +0 -1
  685. package/dist/infra/access-links/rate-limit.js +0 -28
  686. package/dist/infra/access-links/rate-limit.js.map +0 -1
  687. package/dist/infra/email/sigv4.d.ts +0 -24
  688. package/dist/infra/email/sigv4.d.ts.map +0 -1
  689. package/dist/infra/email/sigv4.js +0 -55
  690. package/dist/infra/email/sigv4.js.map +0 -1
@@ -0,0 +1,18 @@
1
+ export type { AuthStrategy, AuthRequest, AuthContext, BaseAuth } from './types.js'
2
+ export { runAuthChain } from './chain.js'
3
+ export type { AuthEnricher, TenantResolver, AuthChainConfig, AuthChainResult } from './chain.js'
4
+ export { createSessions } from './sessions.js'
5
+ export type { SessionAuth, SessionStrategyOptions } from './sessions.js'
6
+ export type { Sessions, SessionConfig, TokenPair, TokenPayload, HttpTokenResult, HttpRequest, HttpResponse } from './sessions.js'
7
+ export type { CookieConfig, ResolvedCookieConfig } from './cookie.js'
8
+ export { resolveCookieConfig, buildSetCookieHeader, buildClearCookieHeader, parseCookieHeader } from './cookie.js'
9
+ export { createMultiOrgSessions } from './multi-org.js'
10
+ export type { MultiOrgConfig, MultiOrgSessions, ResolveLoginResult, AuthenticatedResult, OrgSelectResult, OrgMembership, OrgInfo, OrgMembershipDetail } from './multi-org.js'
11
+ export { createPasswords } from './passwords.js'
12
+ export type { Passwords, PasswordsConfig, ScryptParams, VerifyResult } from './passwords.js'
13
+ export { createSignIn } from './sign-in.js'
14
+ export type { SignIn, SignInConfig, SignInAttempt, SignInResult } from './sign-in.js'
15
+ export { createGuard } from './guard.js'
16
+ export type { Guard, GuardConfig, GuardKeys, GuardTake, GuardStatus } from './guard.js'
17
+ export { createEmailLinks } from './email-links.js'
18
+ export type { EmailLinks, EmailLinksConfig, EmailLinkPurpose, EmailLinkPurposeConfig, EmailLinkState, EmailLinkCheck, EmailLinkRefusal, RequestLimit } from './email-links.js'
@@ -0,0 +1,337 @@
1
+ import { SignJWT, jwtVerify } from 'jose'
2
+ import { parseExpiry } from './parse-expiry.js'
3
+ import { sql } from '../../data/db/sql.js'
4
+ import type { DB } from '../../data/db/index.js'
5
+ import { ForbiddenError, UnauthorizedError, ConflictError, NotFoundError } from '../../core/errors/index.js'
6
+ import { assertValidIdentifier } from '../../data/db/identifiers.js'
7
+ import { assertUuid } from './uuid.js'
8
+ import { checkSigningKeys, importSigningKey } from './signing-keys.js'
9
+ import type { Sessions, HttpResponse, HttpRequest, HttpTokenResult } from './sessions.js'
10
+ import { refuseScopedHandle } from '../tenant/scoped-db.js'
11
+
12
+ /** Configuration for multi-org sessions — base sessions, signing keys, org-select token TTL. */
13
+ export interface MultiOrgConfig {
14
+ readonly sessions: Sessions
15
+ readonly signing: { algorithm: 'ES256'; privateKey: string; publicKey: string }
16
+ readonly issuer: string
17
+ readonly audience: string
18
+ readonly orgSelectToken?: { readonly expiresIn?: string }
19
+ /**
20
+ * Membership table name. Default `pipework_user_orgs`, whose definition ships with the `orgs: {}`
21
+ * blueprint flag. A custom name means the app owns that table's DDL (org_id uuid, same columns).
22
+ */
23
+ readonly table?: string
24
+ readonly resolveOrgNames?: (db: DB, orgIds: string[]) => Promise<Map<string, string>>
25
+ }
26
+
27
+ /** A user's membership in an organization — userId, orgId, role. */
28
+ export interface OrgMembership {
29
+ readonly id: string
30
+ readonly orgId: string
31
+ readonly role: string | null
32
+ readonly joinedAt: Date
33
+ }
34
+
35
+ /** Basic organization info — id and display name. */
36
+ export interface OrgInfo {
37
+ readonly id: string
38
+ readonly name: string
39
+ }
40
+
41
+ /** Organization membership with display name — extends OrgMembership with org info. */
42
+ export interface OrgMembershipDetail {
43
+ readonly id: string
44
+ readonly name: string
45
+ readonly role: string | null
46
+ }
47
+
48
+ /** Result when user has exactly one org — direct authentication, no org selection needed. */
49
+ export interface AuthenticatedResult {
50
+ readonly type: 'authenticated'
51
+ readonly accessToken: string
52
+ readonly expiresIn: number
53
+ }
54
+
55
+ /** Result when user has multiple orgs — returns a session token for org selection. */
56
+ export interface OrgSelectResult {
57
+ readonly type: 'org_select'
58
+ readonly sessionToken: string
59
+ readonly orgs: readonly OrgInfo[]
60
+ }
61
+
62
+ /** Union result from resolveLogin() — either AuthenticatedResult or OrgSelectResult. */
63
+ export type ResolveLoginResult = AuthenticatedResult | OrgSelectResult
64
+
65
+ /** Multi-org session manager — login resolution, org selection, switching, membership CRUD. */
66
+ export interface MultiOrgSessions {
67
+ resolveLogin(
68
+ response: HttpResponse,
69
+ db: DB,
70
+ user: { id: string },
71
+ ): Promise<ResolveLoginResult>
72
+
73
+ selectOrg(
74
+ response: HttpResponse,
75
+ db: DB,
76
+ sessionToken: string,
77
+ orgId: string,
78
+ ): Promise<HttpTokenResult>
79
+
80
+ switchOrg(
81
+ response: HttpResponse,
82
+ db: DB,
83
+ request: Pick<HttpRequest, 'headers'> & { readonly method?: string },
84
+ orgId: string,
85
+ userId: string,
86
+ ): Promise<HttpTokenResult>
87
+
88
+ listOrgs(
89
+ db: DB,
90
+ userId: string,
91
+ ): Promise<{ orgs: readonly OrgMembershipDetail[] }>
92
+
93
+ addMember(
94
+ db: DB,
95
+ params: { userId: string; orgId: string; role?: string; addedBy?: string },
96
+ ): Promise<{ id: string }>
97
+
98
+ removeMember(
99
+ db: DB,
100
+ params: { userId: string; orgId: string },
101
+ ): Promise<void>
102
+
103
+ checkMembership(
104
+ db: DB,
105
+ userId: string,
106
+ orgId: string,
107
+ ): Promise<OrgMembership | null>
108
+ }
109
+
110
+ /**
111
+ * Creates a multi-org session manager with org selection flow and membership management.
112
+ * The default table comes from blueprint `orgs: {}`; org ids must be uuids.
113
+ */
114
+ export function createMultiOrgSessions(config: MultiOrgConfig): MultiOrgSessions {
115
+ const tableName = config.table ?? 'pipework_user_orgs'
116
+ assertValidIdentifier(tableName, 'multi-org membership table')
117
+ const t = sql.raw(`"${tableName}"`)
118
+
119
+ checkSigningKeys(config.signing, 'createMultiOrgSessions')
120
+
121
+ const orgSelectAudience = `${config.audience}:org-select`
122
+ const orgSelectExpiresIn = config.orgSelectToken?.expiresIn ?? '10m'
123
+
124
+ let cachedPrivateKey: CryptoKey | null = null
125
+ let cachedPublicKey: CryptoKey | null = null
126
+
127
+ async function getPrivateKey(): Promise<CryptoKey> {
128
+ if (cachedPrivateKey === null) {
129
+ cachedPrivateKey = await importSigningKey('private', config.signing, 'createMultiOrgSessions')
130
+ }
131
+ return cachedPrivateKey
132
+ }
133
+
134
+ async function getPublicKey(): Promise<CryptoKey> {
135
+ if (cachedPublicKey === null) {
136
+ cachedPublicKey = await importSigningKey('public', config.signing, 'createMultiOrgSessions')
137
+ }
138
+ return cachedPublicKey
139
+ }
140
+
141
+
142
+ async function signOrgSelectToken(userId: string): Promise<string> {
143
+ const key = await getPrivateKey()
144
+ const expiresInSeconds = parseExpiry(orgSelectExpiresIn)
145
+ return new SignJWT({ purpose: 'org_select' })
146
+ .setProtectedHeader({ alg: config.signing.algorithm })
147
+ .setSubject(userId)
148
+ .setIssuer(config.issuer)
149
+ .setAudience(orgSelectAudience)
150
+ .setIssuedAt()
151
+ .setExpirationTime(`${expiresInSeconds}s`)
152
+ .sign(key)
153
+ }
154
+
155
+ async function verifyOrgSelectToken(token: string): Promise<string> {
156
+ const key = await getPublicKey()
157
+ try {
158
+ const { payload } = await jwtVerify(token, key, {
159
+ algorithms: [config.signing.algorithm],
160
+ issuer: config.issuer,
161
+ audience: orgSelectAudience,
162
+ })
163
+ if (payload['purpose'] !== 'org_select') {
164
+ throw new Error('wrong purpose')
165
+ }
166
+ return payload.sub!
167
+ } catch {
168
+ throw new UnauthorizedError(
169
+ 'Invalid or expired organization selection token. Please log in again.',
170
+ )
171
+ }
172
+ }
173
+
174
+ async function requireMembership(db: DB, userId: string, orgId: string): Promise<void> {
175
+ assertUuid(orgId, 'orgId')
176
+ const rows = await db.execute(
177
+ sql`SELECT 1 FROM ${t} WHERE user_id = ${userId} AND org_id = ${orgId}`,
178
+ )
179
+ if (rows.length === 0) {
180
+ throw new ForbiddenError('You are not a member of this organization.')
181
+ }
182
+ }
183
+
184
+ async function resolveLogin(
185
+ response: HttpResponse,
186
+ db: DB,
187
+ user: { id: string },
188
+ ): Promise<ResolveLoginResult> {
189
+ const rows = await db.execute(
190
+ sql`SELECT org_id, role FROM ${t} WHERE user_id = ${user.id} ORDER BY joined_at`,
191
+ )
192
+
193
+ if (rows.length === 0) {
194
+ throw new ForbiddenError(
195
+ 'User has no organization memberships. Contact your administrator to be added to an organization.',
196
+ )
197
+ }
198
+
199
+ if (rows.length === 1) {
200
+ const orgId = rows[0]!['org_id'] as string
201
+ const result = await config.sessions.issueTokensHttp(response, db, { id: user.id, tenantId: orgId })
202
+ return { type: 'authenticated', accessToken: result.accessToken, expiresIn: result.expiresIn }
203
+ }
204
+
205
+ const orgIds = rows.map(r => r['org_id'] as string)
206
+ let orgNames: Map<string, string> | null = null
207
+ if (config.resolveOrgNames !== undefined) {
208
+ orgNames = await config.resolveOrgNames(db, orgIds)
209
+ }
210
+
211
+ const orgs: OrgInfo[] = orgIds.map(id => ({
212
+ id,
213
+ name: orgNames?.get(id) ?? id,
214
+ }))
215
+
216
+ const sessionToken = await signOrgSelectToken(user.id)
217
+ return { type: 'org_select', sessionToken, orgs }
218
+ }
219
+
220
+ async function selectOrg(
221
+ response: HttpResponse,
222
+ db: DB,
223
+ sessionToken: string,
224
+ orgId: string,
225
+ ): Promise<HttpTokenResult> {
226
+ const userId = await verifyOrgSelectToken(sessionToken)
227
+ await requireMembership(db, userId, orgId)
228
+ return config.sessions.issueTokensHttp(response, db, { id: userId, tenantId: orgId })
229
+ }
230
+
231
+ async function switchOrg(
232
+ response: HttpResponse,
233
+ db: DB,
234
+ request: Pick<HttpRequest, 'headers'> & { readonly method?: string },
235
+ orgId: string,
236
+ userId: string,
237
+ ): Promise<HttpTokenResult> {
238
+ config.sessions.assertSameSiteCookie(request)
239
+ await requireMembership(db, userId, orgId)
240
+ await config.sessions.revokeRefreshCookie(db, request)
241
+ return config.sessions.issueTokensHttp(response, db, { id: userId, tenantId: orgId })
242
+ }
243
+
244
+ async function listOrgs(
245
+ db: DB,
246
+ userId: string,
247
+ ): Promise<{ orgs: readonly OrgMembershipDetail[] }> {
248
+ const rows = await db.execute(
249
+ sql`SELECT org_id, role FROM ${t} WHERE user_id = ${userId} ORDER BY joined_at`,
250
+ )
251
+
252
+ const orgIds = rows.map(r => r['org_id'] as string)
253
+ let orgNames: Map<string, string> | null = null
254
+ if (config.resolveOrgNames !== undefined && orgIds.length > 0) {
255
+ orgNames = await config.resolveOrgNames(db, orgIds)
256
+ }
257
+
258
+ const orgs: OrgMembershipDetail[] = rows.map(r => {
259
+ const orgId = r['org_id'] as string
260
+ return {
261
+ id: orgId,
262
+ name: orgNames?.get(orgId) ?? orgId,
263
+ role: (r['role'] as string | null) ?? null,
264
+ }
265
+ })
266
+
267
+ return { orgs }
268
+ }
269
+
270
+ async function addMember(
271
+ db: DB,
272
+ params: { userId: string; orgId: string; role?: string; addedBy?: string },
273
+ ): Promise<{ id: string }> {
274
+ assertUuid(params.orgId, 'orgId')
275
+ const role = params.role ?? null
276
+ const addedBy = params.addedBy ?? null
277
+ const rows = await db.execute(
278
+ sql`INSERT INTO ${t} (user_id, org_id, role, added_by)
279
+ VALUES (${params.userId}, ${params.orgId}, ${role}, ${addedBy})
280
+ ON CONFLICT (user_id, org_id) DO NOTHING
281
+ RETURNING id`,
282
+ )
283
+
284
+ if (rows.length === 0) {
285
+ throw new ConflictError('User is already a member of this organization.')
286
+ }
287
+
288
+ return { id: rows[0]!['id'] as string }
289
+ }
290
+
291
+ async function removeMember(
292
+ db: DB,
293
+ params: { userId: string; orgId: string },
294
+ ): Promise<void> {
295
+ assertUuid(params.orgId, 'orgId')
296
+ const rows = await db.execute(
297
+ sql`DELETE FROM ${t} WHERE user_id = ${params.userId} AND org_id = ${params.orgId} RETURNING id`,
298
+ )
299
+
300
+ if (rows.length === 0) {
301
+ throw new NotFoundError('Membership')
302
+ }
303
+
304
+ await config.sessions.bumpVersion(db, params.userId)
305
+ }
306
+
307
+ async function checkMembershipFn(
308
+ db: DB,
309
+ userId: string,
310
+ orgId: string,
311
+ ): Promise<OrgMembership | null> {
312
+ assertUuid(orgId, 'orgId')
313
+ const rows = await db.execute(
314
+ sql`SELECT id, org_id, role, joined_at FROM ${t} WHERE user_id = ${userId} AND org_id = ${orgId}`,
315
+ )
316
+
317
+ if (rows.length === 0) return null
318
+
319
+ const row = rows[0]!
320
+ return {
321
+ id: row['id'] as string,
322
+ orgId: row['org_id'] as string,
323
+ role: (row['role'] as string | null) ?? null,
324
+ joinedAt: new Date(row['joined_at'] as string),
325
+ }
326
+ }
327
+
328
+ return refuseScopedHandle({
329
+ resolveLogin,
330
+ selectOrg,
331
+ switchOrg,
332
+ listOrgs,
333
+ addMember,
334
+ removeMember,
335
+ checkMembership: checkMembershipFn,
336
+ }, 'multiOrg', 'a user\'s memberships span tenants')
337
+ }
@@ -0,0 +1,34 @@
1
+ import { createSessions } from './sessions.js'
2
+ import { createMultiOrgSessions } from './multi-org.js'
3
+ import { createPasswords } from './passwords.js'
4
+ import { createSignIn } from './sign-in.js'
5
+ import { createGuard } from './guard.js'
6
+ import { createEmailLinks } from './email-links.js'
7
+ import { runAuthChain } from './chain.js'
8
+ import { resolveCookieConfig, parseCookieHeader, buildSetCookieHeader, buildClearCookieHeader } from './cookie.js'
9
+
10
+ /** Authentication namespace — session management, multi-org support, auth chain resolution. */
11
+ export const auth = {
12
+ /** Creates a Sessions manager with JWT access/refresh tokens, rotation, and reuse detection. */
13
+ createSessions,
14
+ /** Creates multi-org session management — org selection, switching, membership CRUD. */
15
+ createMultiOrg: createMultiOrgSessions,
16
+ /** Hashes and verifies passwords with scrypt; reports when a stored hash needs rehashing. */
17
+ passwords: createPasswords,
18
+ /** Guarded password sign-in that slows, then refuses, repeated failures per account and per client. */
19
+ signIn: createSignIn,
20
+ /** Guards wrong guesses at a secret the app checks itself: counted per key set before the check, reset on a right answer, refused with retryAfterSeconds. */
21
+ guard: createGuard,
22
+ /** Emailed single-use links that prove control of an address: password reset and address verification; the token is never stored. */
23
+ emailLinks: createEmailLinks,
24
+ /** Executes an auth chain (strategy pipeline) to resolve auth + tenant from a request. */
25
+ runChain: runAuthChain,
26
+ /** Resolves CookieConfig with defaults for secure cookie-based token delivery. */
27
+ resolveCookie: resolveCookieConfig,
28
+ /** Parses a Cookie header string into key-value pairs. */
29
+ parseCookie: parseCookieHeader,
30
+ /** Builds a Set-Cookie header string from name, value, and CookieConfig. */
31
+ buildSetCookie: buildSetCookieHeader,
32
+ /** Builds a Set-Cookie header that clears (expires) a cookie. */
33
+ buildClearCookie: buildClearCookieHeader,
34
+ }
@@ -0,0 +1,13 @@
1
+ export function parseExpiry(exp: string): number {
2
+ const match = exp.match(/^(\d+)([smhd])$/)
3
+ if (!match) throw new Error(`Invalid expiry format: ${exp}`)
4
+ const value = parseInt(match[1]!, 10)
5
+ const unit = match[2]
6
+ switch (unit) {
7
+ case 's': return value
8
+ case 'm': return value * 60
9
+ case 'h': return value * 3600
10
+ case 'd': return value * 86400
11
+ default: return value
12
+ }
13
+ }
@@ -0,0 +1,110 @@
1
+ import { scrypt, randomBytes, timingSafeEqual } from 'node:crypto'
2
+ import { ValidationError } from '../../core/errors/index.js'
3
+ import { getBaseLogger } from '../../core/logging/index.js'
4
+
5
+ export interface ScryptParams {
6
+ /** log2 of the CPU/memory cost N. Default 15. */
7
+ readonly ln: number
8
+ /** Block size. Default 8. */
9
+ readonly r: number
10
+ /** Parallelism. Default 3. */
11
+ readonly p: number
12
+ }
13
+
14
+ export interface PasswordsConfig {
15
+ readonly scrypt?: Partial<ScryptParams>
16
+ }
17
+
18
+ export interface VerifyResult {
19
+ readonly ok: boolean
20
+ /** True when the password matched but the stored hash used other parameters than the configured ones. */
21
+ readonly needsRehash: boolean
22
+ }
23
+
24
+ export interface Passwords {
25
+ /** Returns a PHC string `$scrypt$ln=15,r=8,p=3$<salt>$<hash>` for the password. */
26
+ hash(password: string): Promise<string>
27
+ /** Checks a password against a stored hash in constant time. A malformed stored hash is `ok: false`. */
28
+ verify(stored: string, password: string): Promise<VerifyResult>
29
+ /** Spends the cost of a verify against a fixed dummy hash, for an account that does not exist. */
30
+ verifyNone(password: string): Promise<{ ok: false }>
31
+ }
32
+
33
+ const DEFAULTS: ScryptParams = { ln: 15, r: 8, p: 3 }
34
+ const KEY_LENGTH = 32
35
+ const SALT_LENGTH = 16
36
+ const MAX_PASSWORD_BYTES = 4096
37
+ const STORED_RE = /^\$scrypt\$ln=(\d+),r=(\d+),p=(\d+)\$([A-Za-z0-9+/]+)\$([A-Za-z0-9+/]+)$/
38
+
39
+ function derive(password: string, salt: Buffer, params: ScryptParams, length: number): Promise<Buffer> {
40
+ const N = 2 ** params.ln
41
+ return new Promise((resolve, reject) => {
42
+ scrypt(password, salt, length, { N, r: params.r, p: params.p, maxmem: 256 * N * params.r + (1 << 20) }, (err, key) => {
43
+ if (err !== null) reject(err)
44
+ else resolve(key)
45
+ })
46
+ })
47
+ }
48
+
49
+ function normalize(password: string): string {
50
+ const normalized = password.normalize('NFC')
51
+ if (Buffer.byteLength(normalized, 'utf8') > MAX_PASSWORD_BYTES) {
52
+ throw new ValidationError({ password: [`must be at most ${MAX_PASSWORD_BYTES} bytes`] }, 'Password is too long.')
53
+ }
54
+ return normalized
55
+ }
56
+
57
+ function validParams(p: ScryptParams): boolean {
58
+ return Number.isInteger(p.ln) && p.ln >= 1 && p.ln <= 22
59
+ && Number.isInteger(p.r) && p.r >= 1 && p.r <= 32
60
+ && Number.isInteger(p.p) && p.p >= 1 && p.p <= 16
61
+ }
62
+
63
+ /**
64
+ * Creates the password hasher. Passwords are NFC-normalized and hashed with
65
+ * Node's scrypt (no dependency); there are no composition rules, and anything up
66
+ * to 4096 bytes of UTF-8 is accepted, so long passphrases and pasted passwords
67
+ * work. The hash records its own parameters, so raising `scrypt` later leaves old
68
+ * hashes verifiable and `verify` reports `needsRehash` for them.
69
+ *
70
+ * `verify` never throws on a bad stored string (it returns `ok: false` and logs),
71
+ * and `verifyNone` costs the same as a wrong password, so an unknown account is
72
+ * not distinguishable by timing.
73
+ */
74
+ export function createPasswords(config: PasswordsConfig = {}): Passwords {
75
+ const params: ScryptParams = { ...DEFAULTS, ...config.scrypt }
76
+ if (!validParams(params)) {
77
+ throw new ValidationError('auth.passwords scrypt params must satisfy 1<=ln<=22, 1<=r<=32, 1<=p<=16.')
78
+ }
79
+ const encode = (b: Buffer): string => b.toString('base64').replace(/=+$/, '')
80
+ let dummy: Promise<string> | undefined
81
+
82
+ async function hash(password: string): Promise<string> {
83
+ const salt = randomBytes(SALT_LENGTH)
84
+ const key = await derive(normalize(password), salt, params, KEY_LENGTH)
85
+ return `$scrypt$ln=${params.ln},r=${params.r},p=${params.p}$${encode(salt)}$${encode(key)}`
86
+ }
87
+
88
+ async function verify(stored: string, password: string): Promise<VerifyResult> {
89
+ const m = STORED_RE.exec(stored)
90
+ const storedParams = m === null ? null : { ln: Number(m[1]), r: Number(m[2]), p: Number(m[3]) }
91
+ if (m === null || storedParams === null || !validParams(storedParams)) {
92
+ getBaseLogger().error({ event: 'password hash malformed' }, 'stored password hash is malformed')
93
+ return { ok: false, needsRehash: false }
94
+ }
95
+ const salt = Buffer.from(m[4]!, 'base64')
96
+ const expected = Buffer.from(m[5]!, 'base64')
97
+ const key = await derive(normalize(password), salt, storedParams, expected.length)
98
+ const ok = key.length === expected.length && timingSafeEqual(key, expected)
99
+ const needsRehash = ok && (storedParams.ln !== params.ln || storedParams.r !== params.r || storedParams.p !== params.p)
100
+ return { ok, needsRehash }
101
+ }
102
+
103
+ async function verifyNone(password: string): Promise<{ ok: false }> {
104
+ dummy ??= hash(randomBytes(16).toString('hex'))
105
+ await verify(await dummy, password)
106
+ return { ok: false }
107
+ }
108
+
109
+ return { hash, verify, verifyNone }
110
+ }
@@ -0,0 +1,110 @@
1
+ // Definitions for the tables behind `auth.createSessions` and
2
+ // `auth.createMultiOrg`. Enabled with `sessions: {}` / `orgs: {}` in the
3
+ // blueprint; `pipework generate` then emits them into the default database's
4
+ // migrations. Emitted as IF NOT EXISTS so apps that created these tables by
5
+ // hand from the former .sql files migrate cleanly.
6
+ //
7
+ // `user_id` is text everywhere: its format is the app's. `tenant_id` and
8
+ // `org_id` are uuid so they can be the tenant id, but deliberately NOT
9
+ // `.tenant()`: a refresh token is looked up by its hash before any tenant is
10
+ // known, and a user's org list is read across orgs at sign-in, so tenant RLS on
11
+ // either table would hide the rows the lookup needs.
12
+ //
13
+ // A custom `createMultiOrg({ table })` name is outside these definitions: the
14
+ // app owns that table's DDL.
15
+
16
+ import { define } from '../../data/domain/index.js'
17
+ import { field } from '../../data/domain/field.js'
18
+ import { sql } from '../../data/db/sql.js'
19
+ import { index, unique } from '../../data/db/idx/index.js'
20
+
21
+ export const AUTH_TABLE_NAMES: ReadonlySet<string> = new Set([
22
+ 'pipework_refresh_tokens', 'pipework_auth_versions', 'pipework_user_orgs', 'pipework_signin_attempts', 'pipework_guard_attempts',
23
+ 'pipework_email_links', 'pipework_email_link_requests',
24
+ ])
25
+
26
+ export const refreshTokens = define('pipework_refresh_tokens', {
27
+ id: field.uuid().defaultRandom().primaryKey(),
28
+ userId: field.text(),
29
+ tenantId: field.uuid(),
30
+ tokenHash: field.text(),
31
+ familyId: field.uuid(),
32
+ revokedAt: field.timestamp().nullable(),
33
+ createdAt: field.timestamp().default('now'),
34
+ expiresAt: field.timestamp(),
35
+ }, {
36
+ indexes: (t) => ({
37
+ byHash: index('idx_pipework_refresh_tokens_hash').on(t['tokenHash']),
38
+ byUser: index('idx_pipework_refresh_tokens_user').on(t['userId']).where(sql`revoked_at IS NULL`),
39
+ byFamily: index('idx_pipework_refresh_tokens_family').on(t['familyId']),
40
+ }),
41
+ })
42
+
43
+ export const authVersions = define('pipework_auth_versions', {
44
+ userId: field.text().primaryKey(),
45
+ version: field.integer().default(1),
46
+ updatedAt: field.timestamp().default('now'),
47
+ })
48
+
49
+ export const userOrgs = define('pipework_user_orgs', {
50
+ id: field.uuid().defaultRandom().primaryKey(),
51
+ userId: field.text(),
52
+ orgId: field.uuid(),
53
+ role: field.text().nullable(),
54
+ joinedAt: field.timestamp().default('now'),
55
+ addedBy: field.text().nullable(),
56
+ }, {
57
+ indexes: (t) => ({
58
+ membership: unique('pipework_user_orgs_user_id_org_id_key').on(t['userId'], t['orgId']),
59
+ byUser: index('idx_pipework_user_orgs_user').on(t['userId']),
60
+ byOrg: index('idx_pipework_user_orgs_org').on(t['orgId']),
61
+ }),
62
+ })
63
+
64
+ // Behind `auth.signIn`. Not tenant-scoped: a sign-in happens before any tenant
65
+ // is known. `key` is 'account:<sha256 of the account>' or 'client:<address>'.
66
+ export const signinAttempts = define('pipework_signin_attempts', {
67
+ key: field.text().primaryKey(),
68
+ failures: field.integer().default(0),
69
+ firstFailureAt: field.timestamp().nullable(),
70
+ lastFailureAt: field.timestamp().nullable(),
71
+ lockedUntil: field.timestamp().nullable(),
72
+ })
73
+
74
+ // Behind `auth.guard`. Same shape as signinAttempts; `key` is
75
+ // '<guard name>:<sha256 of the sorted key entries>'. Not tenant-scoped.
76
+ export const guardAttempts = define('pipework_guard_attempts', {
77
+ key: field.text().primaryKey(),
78
+ failures: field.integer().default(0),
79
+ firstFailureAt: field.timestamp().nullable(),
80
+ lastFailureAt: field.timestamp().nullable(),
81
+ lockedUntil: field.timestamp().nullable(),
82
+ })
83
+
84
+ // Behind `auth.emailLinks`. Not tenant-scoped: a reset is asked for before any
85
+ // tenant is known. The link's token is never stored: `token_hash` is its sha256,
86
+ // and the token itself is an HMAC (keyed by the app's secret) of `id` and `nonce`.
87
+ export const emailLinks = define('pipework_email_links', {
88
+ id: field.uuid().primaryKey(),
89
+ purpose: field.text(),
90
+ userId: field.text(),
91
+ address: field.text(),
92
+ tokenHash: field.text(),
93
+ nonce: field.text(),
94
+ createdAt: field.timestamp().default('now'),
95
+ expiresAt: field.timestamp(),
96
+ usedAt: field.timestamp().nullable(),
97
+ endedAt: field.timestamp().nullable(),
98
+ }, {
99
+ indexes: (t) => ({
100
+ byHash: unique('pipework_email_links_token_hash_key').on(t['tokenHash']),
101
+ byUser: index('idx_pipework_email_links_user').on(t['userId'], t['purpose']),
102
+ }),
103
+ })
104
+
105
+ // Request counts behind `auth.emailLinks`; `key` is 'address:<sha256 of the address>' or 'client:<address>'.
106
+ export const emailLinkRequests = define('pipework_email_link_requests', {
107
+ key: field.text().primaryKey(),
108
+ count: field.integer().default(0),
109
+ windowStart: field.timestamp().default('now'),
110
+ })