pipework 0.252.0 → 0.253.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (695) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/infra/support/handle.d.ts +8 -1
  3. package/dist/infra/support/handle.d.ts.map +1 -1
  4. package/dist/infra/support/handle.js +9 -2
  5. package/dist/infra/support/handle.js.map +1 -1
  6. package/dist/infra/support/namespace.d.ts.map +1 -1
  7. package/package.json +4 -3
  8. package/src/async/jobs/abortable-delay.ts +18 -0
  9. package/src/async/jobs/claims.ts +52 -0
  10. package/src/async/jobs/cron.ts +179 -0
  11. package/src/async/jobs/errors.ts +56 -0
  12. package/src/async/jobs/exclusion.ts +117 -0
  13. package/src/async/jobs/execute.ts +219 -0
  14. package/src/async/jobs/index.ts +10 -0
  15. package/src/async/jobs/listener.ts +135 -0
  16. package/src/async/jobs/namespace.ts +20 -0
  17. package/src/async/jobs/queue-door.ts +44 -0
  18. package/src/async/jobs/queue.ts +1012 -0
  19. package/src/async/jobs/run-script.ts +67 -0
  20. package/src/async/jobs/scheduler.ts +218 -0
  21. package/src/async/jobs/schedules-table.ts +37 -0
  22. package/src/async/jobs/serialize-error.ts +48 -0
  23. package/src/async/jobs/table.ts +191 -0
  24. package/src/async/pipeline/define.ts +53 -0
  25. package/src/async/pipeline/errors.ts +35 -0
  26. package/src/async/pipeline/execute.ts +53 -0
  27. package/src/async/pipeline/index.ts +13 -0
  28. package/src/async/pipeline/namespace.ts +12 -0
  29. package/src/async/pipeline/resume.ts +67 -0
  30. package/src/async/pipeline/run-steps.ts +98 -0
  31. package/src/async/pipeline/types.ts +57 -0
  32. package/src/async/state-machine/define.ts +64 -0
  33. package/src/async/state-machine/errors.ts +29 -0
  34. package/src/async/state-machine/index.ts +3 -0
  35. package/src/async/state-machine/namespace.ts +12 -0
  36. package/src/async/state-machine/transition.ts +90 -0
  37. package/src/async/state-machine/types.ts +37 -0
  38. package/src/async/steps/errors.ts +31 -0
  39. package/src/async/steps/graph.ts +1214 -0
  40. package/src/async/steps/hash.ts +40 -0
  41. package/src/async/steps/index.ts +7 -0
  42. package/src/async/steps/namespace.ts +7 -0
  43. package/src/async/steps/table.ts +97 -0
  44. package/src/async/steps/types.ts +318 -0
  45. package/src/audit/chain/index.ts +9 -0
  46. package/src/audit/chain/install.ts +113 -0
  47. package/src/audit/chain/retire.ts +52 -0
  48. package/src/audit/chain/verify.ts +257 -0
  49. package/src/audit/query/cursor.ts +37 -0
  50. package/src/audit/query/index.ts +9 -0
  51. package/src/audit/query/query.ts +223 -0
  52. package/src/audit/schema/audit-record-fields.ts +68 -0
  53. package/src/audit/schema/audit-record.ts +23 -0
  54. package/src/auth/auth/audit.ts +31 -0
  55. package/src/auth/auth/chain.ts +84 -0
  56. package/src/auth/auth/cookie.ts +136 -0
  57. package/src/auth/auth/email-links.ts +311 -0
  58. package/src/auth/auth/guard.ts +128 -0
  59. package/src/auth/auth/index.ts +18 -0
  60. package/src/auth/auth/multi-org.ts +337 -0
  61. package/src/auth/auth/namespace.ts +34 -0
  62. package/src/auth/auth/parse-expiry.ts +13 -0
  63. package/src/auth/auth/passwords.ts +110 -0
  64. package/src/auth/auth/schema.ts +110 -0
  65. package/src/auth/auth/sessions.ts +565 -0
  66. package/src/auth/auth/sign-in.ts +156 -0
  67. package/src/auth/auth/signing-keys.ts +69 -0
  68. package/src/auth/auth/types.ts +26 -0
  69. package/src/auth/auth/uuid.ts +10 -0
  70. package/src/auth/rbac/cache.ts +55 -0
  71. package/src/auth/rbac/check.ts +30 -0
  72. package/src/auth/rbac/create.ts +35 -0
  73. package/src/auth/rbac/index.ts +5 -0
  74. package/src/auth/rbac/middleware.ts +20 -0
  75. package/src/auth/rbac/namespace.ts +15 -0
  76. package/src/auth/rbac/resolve.ts +31 -0
  77. package/src/auth/rbac/schema.sql +31 -0
  78. package/src/auth/rbac/seed.ts +67 -0
  79. package/src/auth/rbac/tables.ts +32 -0
  80. package/src/auth/rbac/types.ts +65 -0
  81. package/src/auth/tenant/extract.ts +33 -0
  82. package/src/auth/tenant/in-tenant.ts +49 -0
  83. package/src/auth/tenant/index.ts +7 -0
  84. package/src/auth/tenant/namespace.ts +23 -0
  85. package/src/auth/tenant/propagate.ts +20 -0
  86. package/src/auth/tenant/rls.ts +120 -0
  87. package/src/auth/tenant/scope.ts +33 -0
  88. package/src/auth/tenant/scoped-db.ts +581 -0
  89. package/src/auth/tenant/types.ts +14 -0
  90. package/src/auth/tenant/validate.ts +27 -0
  91. package/src/cli/commands/add.ts +158 -0
  92. package/src/cli/commands/alerts.ts +98 -0
  93. package/src/cli/commands/check.ts +1418 -0
  94. package/src/cli/commands/codemod.ts +78 -0
  95. package/src/cli/commands/db.ts +356 -0
  96. package/src/cli/commands/dev.ts +101 -0
  97. package/src/cli/commands/generate.ts +75 -0
  98. package/src/cli/commands/init.ts +36 -0
  99. package/src/cli/commands/install.ts +28 -0
  100. package/src/cli/commands/lint.ts +62 -0
  101. package/src/cli/commands/migrate.ts +132 -0
  102. package/src/cli/commands/openapi.ts +63 -0
  103. package/src/cli/commands/remove.ts +72 -0
  104. package/src/cli/commands/run.ts +50 -0
  105. package/src/cli/commands/scope.ts +54 -0
  106. package/src/cli/commands/serve.ts +68 -0
  107. package/src/cli/commands/shard.ts +31 -0
  108. package/src/cli/commands/shared/config-pipework-version.ts +28 -0
  109. package/src/cli/commands/shared/find-config.ts +22 -0
  110. package/src/cli/commands/shared/load-config.ts +35 -0
  111. package/src/cli/commands/shared/pnpm-install.ts +95 -0
  112. package/src/cli/commands/shared/report-removed.ts +8 -0
  113. package/src/cli/commands/sync.ts +32 -0
  114. package/src/cli/commands/test.ts +307 -0
  115. package/src/cli/commands/upgrade.ts +48 -0
  116. package/src/cli/dev-bootstrap.ts +24 -0
  117. package/src/cli/errors.ts +10 -0
  118. package/src/cli/index.ts +303 -0
  119. package/src/cli/output.ts +17 -0
  120. package/src/cli/port.ts +15 -0
  121. package/src/cli/surface-kinds.ts +20 -0
  122. package/src/client/index.ts +4 -0
  123. package/src/client/poll.ts +130 -0
  124. package/src/client/report-fault.ts +119 -0
  125. package/src/core/config/app-pool.ts +19 -0
  126. package/src/core/config/aws-env.ts +29 -0
  127. package/src/core/config/base-dir.ts +24 -0
  128. package/src/core/config/discover.ts +64 -0
  129. package/src/core/config/env-resolve.ts +87 -0
  130. package/src/core/config/env-types.ts +116 -0
  131. package/src/core/config/env.ts +55 -0
  132. package/src/core/config/errors.ts +9 -0
  133. package/src/core/config/import-config.ts +40 -0
  134. package/src/core/config/index.ts +8 -0
  135. package/src/core/config/load.ts +417 -0
  136. package/src/core/config/namespace.ts +14 -0
  137. package/src/core/config/resolve.ts +195 -0
  138. package/src/core/config/schema.ts +488 -0
  139. package/src/core/config/statement-observer.ts +48 -0
  140. package/src/core/config/ts-inline-hooks.ts +75 -0
  141. package/src/core/config/ts-register.ts +4 -0
  142. package/src/core/config/ts-resolve-hooks.ts +101 -0
  143. package/src/core/errors/base.ts +49 -0
  144. package/src/core/errors/http.ts +146 -0
  145. package/src/core/errors/index.ts +2 -0
  146. package/src/core/errors/namespace.ts +31 -0
  147. package/src/core/lifecycle/drain.ts +33 -0
  148. package/src/core/lifecycle/health.ts +72 -0
  149. package/src/core/lifecycle/index.ts +4 -0
  150. package/src/core/lifecycle/namespace.ts +7 -0
  151. package/src/core/lifecycle/startup.ts +102 -0
  152. package/src/core/lifecycle/types.ts +36 -0
  153. package/src/core/logging/context.ts +60 -0
  154. package/src/core/logging/error-chain.ts +68 -0
  155. package/src/core/logging/index.ts +5 -0
  156. package/src/core/logging/logger.ts +65 -0
  157. package/src/core/logging/namespace.ts +16 -0
  158. package/src/core/logging/proxy.ts +22 -0
  159. package/src/core/logging/redact-match.ts +24 -0
  160. package/src/core/logging/types.ts +47 -0
  161. package/src/core/pipework.ts +566 -0
  162. package/src/core/runtime/broker.ts +69 -0
  163. package/src/core/surface/http.ts +133 -0
  164. package/src/core/surface/index.ts +11 -0
  165. package/src/core/surface/job-timeout.ts +40 -0
  166. package/src/core/surface/namespace.ts +13 -0
  167. package/src/core/surface/script.ts +33 -0
  168. package/src/core/surface/start.ts +142 -0
  169. package/src/core/surface/types.ts +225 -0
  170. package/src/core/surface/validate.ts +88 -0
  171. package/src/core/surface/worker.ts +528 -0
  172. package/src/core/validation/connectivity.ts +49 -0
  173. package/src/core/validation/domain.ts +99 -0
  174. package/src/core/validation/index.ts +5 -0
  175. package/src/core/validation/queue-tables.ts +312 -0
  176. package/src/core/validation/rls-role.ts +138 -0
  177. package/src/core/validation/startup.ts +51 -0
  178. package/src/core/validation/surfaces.ts +65 -0
  179. package/src/core/validation/types.ts +25 -0
  180. package/src/data/db/advisory-lock.ts +55 -0
  181. package/src/data/db/aggregates.ts +172 -0
  182. package/src/data/db/array-elements.ts +111 -0
  183. package/src/data/db/bulk-set.ts +53 -0
  184. package/src/data/db/col/index.ts +14 -0
  185. package/src/data/db/composed.ts +53 -0
  186. package/src/data/db/db.ts +276 -0
  187. package/src/data/db/excluded.ts +16 -0
  188. package/src/data/db/expressions.ts +473 -0
  189. package/src/data/db/filter.ts +90 -0
  190. package/src/data/db/function-source.ts +114 -0
  191. package/src/data/db/identifiers.ts +16 -0
  192. package/src/data/db/idx/index.ts +9 -0
  193. package/src/data/db/in-list.ts +49 -0
  194. package/src/data/db/index.ts +9 -0
  195. package/src/data/db/insert-split.ts +137 -0
  196. package/src/data/db/instrumentation.ts +82 -0
  197. package/src/data/db/maintenance.ts +28 -0
  198. package/src/data/db/namespace.ts +107 -0
  199. package/src/data/db/owner-labels.ts +9 -0
  200. package/src/data/db/pool.ts +187 -0
  201. package/src/data/db/query-label.ts +13 -0
  202. package/src/data/db/query-watch.ts +116 -0
  203. package/src/data/db/raw-client-warning.ts +37 -0
  204. package/src/data/db/readonly.ts +23 -0
  205. package/src/data/db/reservation.ts +151 -0
  206. package/src/data/db/schema-features.ts +14 -0
  207. package/src/data/db/serializable.ts +83 -0
  208. package/src/data/db/sql.ts +1 -0
  209. package/src/data/db/timeouts.ts +76 -0
  210. package/src/data/db/types.ts +18 -0
  211. package/src/data/db/unbound.ts +33 -0
  212. package/src/data/db/values.ts +29 -0
  213. package/src/data/domain/brand.ts +15 -0
  214. package/src/data/domain/build-factory.ts +193 -0
  215. package/src/data/domain/build-schema.ts +161 -0
  216. package/src/data/domain/build-table.ts +355 -0
  217. package/src/data/domain/define.ts +239 -0
  218. package/src/data/domain/external-registry.ts +34 -0
  219. package/src/data/domain/external.ts +77 -0
  220. package/src/data/domain/field.ts +279 -0
  221. package/src/data/domain/index.ts +13 -0
  222. package/src/data/domain/naming.ts +6 -0
  223. package/src/data/domain/projections.ts +57 -0
  224. package/src/data/domain/trace-safe-projection.ts +31 -0
  225. package/src/data/domain/traits.ts +108 -0
  226. package/src/data/domain/types.ts +289 -0
  227. package/src/data/jsonb/composed.ts +18 -0
  228. package/src/data/jsonb/index.ts +1 -0
  229. package/src/data/jsonb/namespace.ts +30 -0
  230. package/src/data/jsonb/query.ts +86 -0
  231. package/src/data/migrate/append-only-generate.ts +47 -0
  232. package/src/data/migrate/applied.ts +47 -0
  233. package/src/data/migrate/apply.ts +309 -0
  234. package/src/data/migrate/check.ts +119 -0
  235. package/src/data/migrate/diff.ts +357 -0
  236. package/src/data/migrate/door-generate.ts +130 -0
  237. package/src/data/migrate/framework-rls.ts +58 -0
  238. package/src/data/migrate/generate.ts +201 -0
  239. package/src/data/migrate/history.ts +215 -0
  240. package/src/data/migrate/index.ts +9 -0
  241. package/src/data/migrate/internal-definitions.ts +175 -0
  242. package/src/data/migrate/post-process.ts +73 -0
  243. package/src/data/migrate/pragma.ts +73 -0
  244. package/src/data/migrate/provision-framework.ts +147 -0
  245. package/src/data/migrate/rls-generate.ts +61 -0
  246. package/src/data/migrate/run.ts +124 -0
  247. package/src/data/migrate/safety.ts +167 -0
  248. package/src/data/migrate/snapshot.ts +368 -0
  249. package/src/data/migrate/sql-emit.ts +392 -0
  250. package/src/data/migrate/statements.ts +312 -0
  251. package/src/data/query/alias.ts +126 -0
  252. package/src/data/query/batch.ts +8 -0
  253. package/src/data/query/cache/core/cache.ts +78 -0
  254. package/src/data/query/cache/core/index.ts +1 -0
  255. package/src/data/query/cache/core/types.ts +29 -0
  256. package/src/data/query/cache/readme.md +230 -0
  257. package/src/data/query/casing.ts +76 -0
  258. package/src/data/query/collation.ts +11 -0
  259. package/src/data/query/column-builder.ts +370 -0
  260. package/src/data/query/column.ts +150 -0
  261. package/src/data/query/entity.ts +42 -0
  262. package/src/data/query/errors.ts +33 -0
  263. package/src/data/query/index.ts +14 -0
  264. package/src/data/query/logger.ts +47 -0
  265. package/src/data/query/operations.ts +45 -0
  266. package/src/data/query/pg-core/alias.ts +12 -0
  267. package/src/data/query/pg-core/checks.ts +32 -0
  268. package/src/data/query/pg-core/columns/all.ts +71 -0
  269. package/src/data/query/pg-core/columns/bigint.ts +110 -0
  270. package/src/data/query/pg-core/columns/bigserial.ts +128 -0
  271. package/src/data/query/pg-core/columns/boolean.ts +43 -0
  272. package/src/data/query/pg-core/columns/char.ts +85 -0
  273. package/src/data/query/pg-core/columns/cidr.ts +43 -0
  274. package/src/data/query/pg-core/columns/common.ts +366 -0
  275. package/src/data/query/pg-core/columns/custom.ts +232 -0
  276. package/src/data/query/pg-core/columns/date.common.ts +15 -0
  277. package/src/data/query/pg-core/columns/date.ts +112 -0
  278. package/src/data/query/pg-core/columns/double-precision.ts +55 -0
  279. package/src/data/query/pg-core/columns/enum.ts +201 -0
  280. package/src/data/query/pg-core/columns/index.ts +35 -0
  281. package/src/data/query/pg-core/columns/inet.ts +43 -0
  282. package/src/data/query/pg-core/columns/int.common.ts +57 -0
  283. package/src/data/query/pg-core/columns/integer.ts +53 -0
  284. package/src/data/query/pg-core/columns/interval.ts +83 -0
  285. package/src/data/query/pg-core/columns/json.ts +58 -0
  286. package/src/data/query/pg-core/columns/jsonb.ts +56 -0
  287. package/src/data/query/pg-core/columns/line.ts +117 -0
  288. package/src/data/query/pg-core/columns/macaddr.ts +43 -0
  289. package/src/data/query/pg-core/columns/macaddr8.ts +43 -0
  290. package/src/data/query/pg-core/columns/numeric.ts +227 -0
  291. package/src/data/query/pg-core/columns/point.ts +127 -0
  292. package/src/data/query/pg-core/columns/postgis_extension/geometry.ts +119 -0
  293. package/src/data/query/pg-core/columns/postgis_extension/utils.ts +47 -0
  294. package/src/data/query/pg-core/columns/real.ts +58 -0
  295. package/src/data/query/pg-core/columns/serial.ts +55 -0
  296. package/src/data/query/pg-core/columns/smallint.ts +53 -0
  297. package/src/data/query/pg-core/columns/smallserial.ts +60 -0
  298. package/src/data/query/pg-core/columns/text.ts +67 -0
  299. package/src/data/query/pg-core/columns/time.ts +72 -0
  300. package/src/data/query/pg-core/columns/timestamp.ts +163 -0
  301. package/src/data/query/pg-core/columns/uuid.ts +51 -0
  302. package/src/data/query/pg-core/columns/varchar.ts +89 -0
  303. package/src/data/query/pg-core/columns/vector_extension/bit.ts +68 -0
  304. package/src/data/query/pg-core/columns/vector_extension/halfvec.ts +80 -0
  305. package/src/data/query/pg-core/columns/vector_extension/sparsevec.ts +67 -0
  306. package/src/data/query/pg-core/columns/vector_extension/vector.ts +80 -0
  307. package/src/data/query/pg-core/db.ts +674 -0
  308. package/src/data/query/pg-core/dialect.ts +1404 -0
  309. package/src/data/query/pg-core/expressions.ts +25 -0
  310. package/src/data/query/pg-core/foreign-keys.ts +130 -0
  311. package/src/data/query/pg-core/index.ts +21 -0
  312. package/src/data/query/pg-core/indexes.ts +276 -0
  313. package/src/data/query/pg-core/policies.ts +56 -0
  314. package/src/data/query/pg-core/primary-keys.ts +62 -0
  315. package/src/data/query/pg-core/query-builders/count.ts +86 -0
  316. package/src/data/query/pg-core/query-builders/delete.ts +293 -0
  317. package/src/data/query/pg-core/query-builders/index.ts +7 -0
  318. package/src/data/query/pg-core/query-builders/insert.ts +452 -0
  319. package/src/data/query/pg-core/query-builders/query-builder.ts +123 -0
  320. package/src/data/query/pg-core/query-builders/query.ts +157 -0
  321. package/src/data/query/pg-core/query-builders/raw.ts +49 -0
  322. package/src/data/query/pg-core/query-builders/refresh-materialized-view.ts +108 -0
  323. package/src/data/query/pg-core/query-builders/select.ts +1346 -0
  324. package/src/data/query/pg-core/query-builders/select.types.ts +437 -0
  325. package/src/data/query/pg-core/query-builders/update.ts +626 -0
  326. package/src/data/query/pg-core/roles.ts +41 -0
  327. package/src/data/query/pg-core/schema.ts +72 -0
  328. package/src/data/query/pg-core/sequence.ts +41 -0
  329. package/src/data/query/pg-core/session.ts +292 -0
  330. package/src/data/query/pg-core/subquery.ts +46 -0
  331. package/src/data/query/pg-core/table.ts +252 -0
  332. package/src/data/query/pg-core/unique-constraint.ts +73 -0
  333. package/src/data/query/pg-core/utils/array.ts +95 -0
  334. package/src/data/query/pg-core/utils/index.ts +1 -0
  335. package/src/data/query/pg-core/utils.ts +104 -0
  336. package/src/data/query/pg-core/view-base.ts +14 -0
  337. package/src/data/query/pg-core/view-common.ts +1 -0
  338. package/src/data/query/pg-core/view.ts +435 -0
  339. package/src/data/query/pg-core/with-builder.ts +41 -0
  340. package/src/data/query/postgres-js/README.md +46 -0
  341. package/src/data/query/postgres-js/array-parser.ts +45 -0
  342. package/src/data/query/postgres-js/driver-error-boundary.ts +149 -0
  343. package/src/data/query/postgres-js/driver.ts +163 -0
  344. package/src/data/query/postgres-js/index.ts +2 -0
  345. package/src/data/query/postgres-js/session.ts +234 -0
  346. package/src/data/query/primary-key.ts +11 -0
  347. package/src/data/query/query-builders/query-builder.ts +19 -0
  348. package/src/data/query/query-builders/select.types.ts +175 -0
  349. package/src/data/query/query-promise.ts +35 -0
  350. package/src/data/query/relations.ts +725 -0
  351. package/src/data/query/runnable-query.ts +12 -0
  352. package/src/data/query/selection-proxy.ts +121 -0
  353. package/src/data/query/session.ts +8 -0
  354. package/src/data/query/sql/expressions/conditions.ts +741 -0
  355. package/src/data/query/sql/expressions/index.ts +2 -0
  356. package/src/data/query/sql/expressions/select.ts +45 -0
  357. package/src/data/query/sql/functions/aggregate.ts +129 -0
  358. package/src/data/query/sql/functions/index.ts +2 -0
  359. package/src/data/query/sql/functions/vector.ts +178 -0
  360. package/src/data/query/sql/index.ts +3 -0
  361. package/src/data/query/sql/sql.ts +794 -0
  362. package/src/data/query/subquery.ts +53 -0
  363. package/src/data/query/table.ts +208 -0
  364. package/src/data/query/table.utils.ts +2 -0
  365. package/src/data/query/tracing-utils.ts +3 -0
  366. package/src/data/query/tracing.ts +11 -0
  367. package/src/data/query/utils.ts +357 -0
  368. package/src/data/query/version.ts +4 -0
  369. package/src/data/query/view-common.ts +1 -0
  370. package/src/data/schema/branded.ts +13 -0
  371. package/src/data/schema/generated/coerce.ts +5 -0
  372. package/src/data/schema/generated/combinator.ts +6 -0
  373. package/src/data/schema/generated/encoding.ts +5 -0
  374. package/src/data/schema/generated/error.ts +6 -0
  375. package/src/data/schema/generated/format.ts +5 -0
  376. package/src/data/schema/generated/type-constructor.ts +10 -0
  377. package/src/data/schema/generated/type.ts +6 -0
  378. package/src/data/schema/index.ts +6 -0
  379. package/src/data/schema/json-schema.ts +33 -0
  380. package/src/data/schema/namespace.ts +55 -0
  381. package/src/data/schema/parse.ts +39 -0
  382. package/src/data/schema/types.ts +39 -0
  383. package/src/data/temporal/append-only.ts +134 -0
  384. package/src/data/temporal/close.ts +27 -0
  385. package/src/data/temporal/columns.ts +10 -0
  386. package/src/data/temporal/definition-queries.ts +70 -0
  387. package/src/data/temporal/errors.ts +10 -0
  388. package/src/data/temporal/get-current.ts +22 -0
  389. package/src/data/temporal/index.ts +9 -0
  390. package/src/data/temporal/namespace.ts +36 -0
  391. package/src/data/temporal/query.ts +25 -0
  392. package/src/data/temporal/resolve.ts +17 -0
  393. package/src/data/temporal/revise.ts +67 -0
  394. package/src/data/temporal/types.ts +22 -0
  395. package/src/data/valve/artifact.ts +33 -0
  396. package/src/data/valve/contract-diff.ts +21 -0
  397. package/src/data/valve/cross.ts +57 -0
  398. package/src/data/valve/crossing-ledger.ts +50 -0
  399. package/src/data/valve/decision.ts +44 -0
  400. package/src/data/valve/durable-crossing.ts +52 -0
  401. package/src/data/valve/execute-crossing.ts +77 -0
  402. package/src/data/valve/faucet.ts +56 -0
  403. package/src/data/valve/gate.ts +114 -0
  404. package/src/data/valve/graph.ts +77 -0
  405. package/src/data/valve/index.ts +53 -0
  406. package/src/data/valve/namespace.ts +57 -0
  407. package/src/data/valve/registry.ts +50 -0
  408. package/src/data/valve/schema/valve-crossing-fields.ts +23 -0
  409. package/src/data/valve/schema/valve-crossing.ts +9 -0
  410. package/src/data/valve/supply.ts +154 -0
  411. package/src/data/valve/types.ts +143 -0
  412. package/src/data/vector/columns.ts +27 -0
  413. package/src/data/vector/index.ts +4 -0
  414. package/src/data/vector/namespace.ts +33 -0
  415. package/src/data/vector/query.ts +85 -0
  416. package/src/data/vector/validate.ts +16 -0
  417. package/src/data/write/audit/actor.ts +15 -0
  418. package/src/data/write/audit/audit-columns.ts +18 -0
  419. package/src/data/write/audit/audit-select.ts +111 -0
  420. package/src/data/write/audit/bound-transaction.ts +14 -0
  421. package/src/data/write/audit/cte-compile.ts +32 -0
  422. package/src/data/write/audit/decode-returning.ts +47 -0
  423. package/src/data/write/audit/final-select.ts +43 -0
  424. package/src/data/write/audit/infra-audit.ts +36 -0
  425. package/src/data/write/audit/primary-key.ts +65 -0
  426. package/src/data/write/audit/projection.ts +41 -0
  427. package/src/data/write/audit/read-touches.ts +86 -0
  428. package/src/data/write/audit/touch-match.ts +78 -0
  429. package/src/data/write/audit/verb-delete.ts +62 -0
  430. package/src/data/write/audit/verb-insert.ts +36 -0
  431. package/src/data/write/audit/verb-select.ts +47 -0
  432. package/src/data/write/audit/verb-update.ts +60 -0
  433. package/src/data/write/audit/verb-upsert.ts +104 -0
  434. package/src/data/write/conflict.ts +43 -0
  435. package/src/data/write/delete.ts +38 -0
  436. package/src/data/write/execute.ts +243 -0
  437. package/src/data/write/index.ts +11 -0
  438. package/src/data/write/insert.ts +63 -0
  439. package/src/data/write/state.ts +43 -0
  440. package/src/data/write/update.ts +54 -0
  441. package/src/data/write/upsert.ts +58 -0
  442. package/src/data/write/values.ts +19 -0
  443. package/src/index.ts +230 -0
  444. package/src/infra/access-links/code.ts +70 -0
  445. package/src/infra/access-links/handle.ts +892 -0
  446. package/src/infra/access-links/index.ts +9 -0
  447. package/src/infra/access-links/namespace.ts +30 -0
  448. package/src/infra/access-links/person-check.ts +177 -0
  449. package/src/infra/access-links/schema.ts +71 -0
  450. package/src/infra/alerts/async-sources.ts +231 -0
  451. package/src/infra/alerts/audit.ts +36 -0
  452. package/src/infra/alerts/beat.ts +123 -0
  453. package/src/infra/alerts/client-faults.ts +111 -0
  454. package/src/infra/alerts/faults.ts +156 -0
  455. package/src/infra/alerts/handle.ts +778 -0
  456. package/src/infra/alerts/http.ts +192 -0
  457. package/src/infra/alerts/index.ts +12 -0
  458. package/src/infra/alerts/infra-sources.ts +180 -0
  459. package/src/infra/alerts/namespace.ts +81 -0
  460. package/src/infra/alerts/redact.ts +21 -0
  461. package/src/infra/alerts/request-faults.ts +41 -0
  462. package/src/infra/alerts/schema.ts +124 -0
  463. package/src/infra/alerts/sinks.ts +125 -0
  464. package/src/infra/alerts/source-options.ts +26 -0
  465. package/src/infra/alerts/sources.ts +503 -0
  466. package/src/infra/alerts/subsystem-sources.ts +137 -0
  467. package/src/infra/audit/emit.ts +87 -0
  468. package/src/infra/audit/index.ts +2 -0
  469. package/src/infra/audit/namespace.ts +22 -0
  470. package/src/infra/audit/schema.sql +35 -0
  471. package/src/infra/audit/types.ts +18 -0
  472. package/src/infra/aws/credentials.ts +147 -0
  473. package/src/infra/aws/sigv4.ts +140 -0
  474. package/src/infra/cache/create.ts +58 -0
  475. package/src/infra/cache/entry.ts +81 -0
  476. package/src/infra/cache/index.ts +4 -0
  477. package/src/infra/cache/namespace.ts +10 -0
  478. package/src/infra/cache/tenant.ts +93 -0
  479. package/src/infra/cache/types.ts +24 -0
  480. package/src/infra/crawl/audit.ts +35 -0
  481. package/src/infra/crawl/errors.ts +25 -0
  482. package/src/infra/crawl/handle.ts +693 -0
  483. package/src/infra/crawl/index.ts +9 -0
  484. package/src/infra/crawl/links.ts +160 -0
  485. package/src/infra/crawl/namespace.ts +36 -0
  486. package/src/infra/crawl/robots.ts +100 -0
  487. package/src/infra/crawl/schema.ts +89 -0
  488. package/src/infra/credit-line/handle.ts +883 -0
  489. package/src/infra/credit-line/index.ts +6 -0
  490. package/src/infra/credit-line/namespace.ts +7 -0
  491. package/src/infra/credit-line/schema.ts +96 -0
  492. package/src/infra/credits/handle.ts +706 -0
  493. package/src/infra/credits/index.ts +5 -0
  494. package/src/infra/credits/namespace.ts +7 -0
  495. package/src/infra/credits/schema.ts +83 -0
  496. package/src/infra/email/audit.ts +36 -0
  497. package/src/infra/email/inbound.ts +622 -0
  498. package/src/infra/email/index.ts +11 -0
  499. package/src/infra/email/mail.ts +517 -0
  500. package/src/infra/email/mime.ts +447 -0
  501. package/src/infra/email/namespace.ts +22 -0
  502. package/src/infra/email/providers.ts +111 -0
  503. package/src/infra/email/schema.ts +96 -0
  504. package/src/infra/email/sns.ts +200 -0
  505. package/src/infra/email/unsubscribe.ts +44 -0
  506. package/src/infra/fetch/address.ts +88 -0
  507. package/src/infra/fetch/connect-retry.ts +87 -0
  508. package/src/infra/fetch/handle.ts +329 -0
  509. package/src/infra/fetch/index.ts +7 -0
  510. package/src/infra/fetch/namespace.ts +70 -0
  511. package/src/infra/idempotency/index.ts +3 -0
  512. package/src/infra/idempotency/middleware.ts +87 -0
  513. package/src/infra/idempotency/store.ts +92 -0
  514. package/src/infra/idempotency/types.ts +30 -0
  515. package/src/infra/join-requests/handle.ts +312 -0
  516. package/src/infra/join-requests/index.ts +2 -0
  517. package/src/infra/join-requests/namespace.ts +7 -0
  518. package/src/infra/join-requests/schema.ts +33 -0
  519. package/src/infra/outbox/core.ts +165 -0
  520. package/src/infra/quota/errors.ts +32 -0
  521. package/src/infra/quota/handle.ts +215 -0
  522. package/src/infra/quota/index.ts +5 -0
  523. package/src/infra/quota/namespace.ts +7 -0
  524. package/src/infra/quota/schema.ts +15 -0
  525. package/src/infra/storage/backend.ts +34 -0
  526. package/src/infra/storage/handle.ts +513 -0
  527. package/src/infra/storage/index.ts +9 -0
  528. package/src/infra/storage/local.ts +104 -0
  529. package/src/infra/storage/namespace.ts +13 -0
  530. package/src/infra/storage/s3.ts +257 -0
  531. package/src/infra/storage/schema.ts +24 -0
  532. package/src/infra/support/handle.ts +869 -0
  533. package/src/infra/support/http.ts +229 -0
  534. package/src/infra/support/index.ts +7 -0
  535. package/src/infra/support/namespace.ts +12 -0
  536. package/src/infra/support/schema.ts +96 -0
  537. package/src/infra/webhook/inbound.ts +45 -0
  538. package/src/infra/webhook/index.ts +5 -0
  539. package/src/infra/webhook/namespace.ts +24 -0
  540. package/src/infra/webhook/outbound.ts +315 -0
  541. package/src/infra/webhook/sign.ts +32 -0
  542. package/src/infra/webhook/verify.ts +82 -0
  543. package/src/invariants/assert.ts +26 -0
  544. package/src/invariants/index.ts +1 -0
  545. package/src/lint/config.ts +56 -0
  546. package/src/lint/doctrine.ts +163 -0
  547. package/src/lint/include.ts +97 -0
  548. package/src/lint/index.ts +3 -0
  549. package/src/lint/preset.ts +10 -0
  550. package/src/lint/resolver.ts +218 -0
  551. package/src/lint/rules/no-reexports.ts +46 -0
  552. package/src/request/behavior/audited.ts +85 -0
  553. package/src/request/behavior/cached.ts +62 -0
  554. package/src/request/behavior/compose.ts +28 -0
  555. package/src/request/behavior/index.ts +5 -0
  556. package/src/request/behavior/namespace.ts +16 -0
  557. package/src/request/behavior/types.ts +26 -0
  558. package/src/request/behavior/versioned.ts +54 -0
  559. package/src/request/context/create.ts +103 -0
  560. package/src/request/context/guard.ts +49 -0
  561. package/src/request/context/index.ts +4 -0
  562. package/src/request/context/run-in-transaction.ts +200 -0
  563. package/src/request/context/store.ts +28 -0
  564. package/src/request/context/types.ts +50 -0
  565. package/src/request/di/builder.ts +535 -0
  566. package/src/request/di/index.ts +8 -0
  567. package/src/request/di/resolve.ts +271 -0
  568. package/src/request/di/types.ts +262 -0
  569. package/src/request/fitting/namespace.ts +7 -0
  570. package/src/request/fixture/batch.ts +71 -0
  571. package/src/request/fixture/builder.ts +26 -0
  572. package/src/request/fixture/errors.ts +10 -0
  573. package/src/request/fixture/index.ts +8 -0
  574. package/src/request/fixture/namespace.ts +23 -0
  575. package/src/request/fixture/paginate.ts +44 -0
  576. package/src/request/fixture/to-handlers.ts +260 -0
  577. package/src/request/fixture/types.ts +79 -0
  578. package/src/request/flow/act-as.ts +78 -0
  579. package/src/request/flow/namespace.ts +17 -0
  580. package/src/request/http/error-step.ts +42 -0
  581. package/src/request/http/file.ts +141 -0
  582. package/src/request/http/index.ts +4 -0
  583. package/src/request/http/middleware.ts +141 -0
  584. package/src/request/http/namespace.ts +5 -0
  585. package/src/request/http/rate-limit-classes.ts +170 -0
  586. package/src/request/http/response.ts +82 -0
  587. package/src/request/http/server.ts +916 -0
  588. package/src/request/http/sniff.ts +261 -0
  589. package/src/request/http/types.ts +250 -0
  590. package/src/request/http/upload.ts +284 -0
  591. package/src/request/internal/text.ts +6 -0
  592. package/src/request/openapi/generate.ts +205 -0
  593. package/src/request/openapi/index.ts +2 -0
  594. package/src/request/openapi/namespace.ts +7 -0
  595. package/src/test/auth.ts +13 -0
  596. package/src/test/auto-setup.ts +45 -0
  597. package/src/test/context.ts +91 -0
  598. package/src/test/crawl-fixture.ts +157 -0
  599. package/src/test/discover-fork.ts +17 -0
  600. package/src/test/fingerprint.ts +135 -0
  601. package/src/test/globals.d.ts +7 -0
  602. package/src/test/index.ts +19 -0
  603. package/src/test/namespace.ts +87 -0
  604. package/src/test/plugin.ts +189 -0
  605. package/src/test/progress.ts +185 -0
  606. package/src/test/reap-after-run.ts +28 -0
  607. package/src/test/reap.ts +286 -0
  608. package/src/test/reset.ts +253 -0
  609. package/src/test/savepoints.ts +172 -0
  610. package/src/test/setup.ts +1422 -0
  611. package/src/test/system-channel.ts +50 -0
  612. package/src/test/vitest-plugin.ts +142 -0
  613. package/src/test/vitest-workspace.ts +507 -0
  614. package/src/test/vitest.ts +333 -0
  615. package/src/test/watch.ts +105 -0
  616. package/src/trace/capture/bounded-serializer.ts +146 -0
  617. package/src/trace/cardinality/analyze.ts +173 -0
  618. package/src/trace/cardinality/branch-context.ts +214 -0
  619. package/src/trace/cardinality/check.ts +33 -0
  620. package/src/trace/cardinality/classify-edge.ts +64 -0
  621. package/src/trace/cardinality/structural-max.ts +107 -0
  622. package/src/trace/check/coverage-check.ts +188 -0
  623. package/src/trace/check/flow-check.ts +103 -0
  624. package/src/trace/check/flow-step-site.ts +234 -0
  625. package/src/trace/check/io-pattern.ts +116 -0
  626. package/src/trace/codemod/add-cardinality.ts +152 -0
  627. package/src/trace/codemod/run.ts +80 -0
  628. package/src/trace/entry/child-trace.ts +21 -0
  629. package/src/trace/entry/close-trace.ts +87 -0
  630. package/src/trace/entry/finalize-trace.ts +28 -0
  631. package/src/trace/entry/open-trace.ts +138 -0
  632. package/src/trace/entry/parent-trace.ts +20 -0
  633. package/src/trace/entry/parse-traceparent.ts +39 -0
  634. package/src/trace/entry/process-start.ts +38 -0
  635. package/src/trace/entry/trace-context.ts +26 -0
  636. package/src/trace/entry/tracing-enabled.ts +10 -0
  637. package/src/trace/external/record.ts +195 -0
  638. package/src/trace/external/report.ts +66 -0
  639. package/src/trace/namespace.ts +19 -0
  640. package/src/trace/partition/day.ts +47 -0
  641. package/src/trace/partition/index.ts +14 -0
  642. package/src/trace/partition/partition-name.ts +23 -0
  643. package/src/trace/partition/plan.ts +82 -0
  644. package/src/trace/partition/schedule.ts +26 -0
  645. package/src/trace/partition/startup-hook.ts +39 -0
  646. package/src/trace/partition/sync.ts +154 -0
  647. package/src/trace/partition/tables.ts +53 -0
  648. package/src/trace/read/tree.ts +83 -0
  649. package/src/trace/retain/copy-on-error.ts +76 -0
  650. package/src/trace/runtime/expire-stale-traces.ts +54 -0
  651. package/src/trace/runtime/flow-step.ts +147 -0
  652. package/src/trace/runtime/flush-steps.ts +31 -0
  653. package/src/trace/runtime/pending-writes.ts +54 -0
  654. package/src/trace/runtime/step-buffer.ts +298 -0
  655. package/src/trace/runtime/step-error.ts +21 -0
  656. package/src/trace/runtime/step-meta.ts +55 -0
  657. package/src/trace/runtime/thenable.ts +12 -0
  658. package/src/trace/runtime/truncate-trace.ts +62 -0
  659. package/src/trace/schema/trace-fields.ts +52 -0
  660. package/src/trace/schema/trace-retained.ts +22 -0
  661. package/src/trace/schema/trace-step-fields.ts +44 -0
  662. package/src/trace/schema/trace-step-retained.ts +25 -0
  663. package/src/trace/schema/trace-step.ts +18 -0
  664. package/src/trace/schema/trace.ts +12 -0
  665. package/src/trace/transformer/apply.ts +79 -0
  666. package/src/trace/transformer/build-meta-literal.ts +30 -0
  667. package/src/trace/transformer/find-flow-step-sites.ts +85 -0
  668. package/src/trace/transformer/inject-flow-step-import.ts +39 -0
  669. package/src/trace/transformer/transform-error.ts +14 -0
  670. package/src/trace/transformer/transform-flow-steps.ts +123 -0
  671. package/src/trace/transformer/wrap-function-declaration.ts +62 -0
  672. package/src/trace/transformer/wrap-variable-declaration.ts +67 -0
  673. package/src/workspace/affected.ts +110 -0
  674. package/src/workspace/changed-files.ts +163 -0
  675. package/src/workspace/check-deps.ts +213 -0
  676. package/src/workspace/checksum.ts +20 -0
  677. package/src/workspace/dependency-graph.ts +67 -0
  678. package/src/workspace/detect-pipework-copies.ts +93 -0
  679. package/src/workspace/discover.ts +206 -0
  680. package/src/workspace/generate.ts +401 -0
  681. package/src/workspace/index.ts +7 -0
  682. package/src/workspace/module-imports-pipework.ts +39 -0
  683. package/src/workspace/module-package-name.ts +12 -0
  684. package/src/workspace/scrub-git-env.ts +23 -0
  685. package/src/workspace/source-paths.ts +36 -0
  686. package/src/workspace/sync.ts +182 -0
  687. package/dist/REFERENCE.md +0 -1477
  688. package/dist/infra/access-links/rate-limit.d.ts +0 -10
  689. package/dist/infra/access-links/rate-limit.d.ts.map +0 -1
  690. package/dist/infra/access-links/rate-limit.js +0 -28
  691. package/dist/infra/access-links/rate-limit.js.map +0 -1
  692. package/dist/infra/email/sigv4.d.ts +0 -24
  693. package/dist/infra/email/sigv4.d.ts.map +0 -1
  694. package/dist/infra/email/sigv4.js +0 -55
  695. package/dist/infra/email/sigv4.js.map +0 -1
@@ -0,0 +1,156 @@
1
+ import { createHash } from 'node:crypto'
2
+ import { sql } from '../../data/db/sql.js'
3
+ import type { DB } from '../../data/db/index.js'
4
+ import { pipeSystem } from '../../data/db/db.js'
5
+ import { auditUnauthenticated } from './audit.js'
6
+ import { getBaseLogger } from '../../core/logging/index.js'
7
+ import type { Passwords } from './passwords.js'
8
+
9
+ export interface SignInConfig {
10
+ readonly passwords: Passwords
11
+ /** Failures per account within the window before it is locked. Default 5. */
12
+ readonly accountThreshold?: number
13
+ /** Failures per client address within the window before it is locked. Default 20. */
14
+ readonly clientThreshold?: number
15
+ /** Window since the first failure after which the count restarts. Default 900 seconds. */
16
+ readonly windowSeconds?: number
17
+ /** Longest single lock. Default 900 seconds. */
18
+ readonly maxLockSeconds?: number
19
+ }
20
+
21
+ export interface SignInAttempt {
22
+ readonly account: string
23
+ /** The client address; without it only the account is guarded. */
24
+ readonly client?: string
25
+ readonly password: string
26
+ /** Finds the account's user id and stored password hash, or null if there is no such account. */
27
+ readonly lookup: (db: DB, account: string) => Promise<{ userId: string; passwordHash: string } | null>
28
+ }
29
+
30
+ export type SignInResult =
31
+ | { readonly ok: true; readonly userId: string; readonly needsRehash: boolean }
32
+ | { readonly ok: false; readonly reason: 'invalid' | 'locked'; readonly retryAfterSeconds?: number }
33
+
34
+ export interface SignIn {
35
+ attempt(input: SignInAttempt): Promise<SignInResult>
36
+ }
37
+
38
+ interface Key { readonly key: string; readonly threshold: number }
39
+
40
+ /**
41
+ * Creates a guarded password sign-in. `attempt` needs an active Flow (a request,
42
+ * job or test context) and runs every statement, `lookup` included, on
43
+ * `pipe.system()`: outside the request transaction, committed on its own, so a
44
+ * route that answers a bad password by throwing `UnauthorizedError` (rolling the
45
+ * request back) still keeps the count. Failed attempts are counted per account and
46
+ * per client address in `pipework_signin_attempts` (blueprint `passwords: {}`), so
47
+ * counts survive restarts and are shared across processes. At the threshold each
48
+ * further failure locks the key for 2^(failures - threshold) seconds, capped at
49
+ * `maxLockSeconds`. Every attempt is counted, atomically per key, before the
50
+ * password is checked, so a burst of parallel guesses is locked out instead of
51
+ * all being verified. While any key is locked an attempt is refused with
52
+ * `reason: 'locked'` and `retryAfterSeconds`, without checking the password (a
53
+ * locked key is not counted further). A success deletes the account's key and
54
+ * gives the client key its count back. An unknown account runs a dummy verify
55
+ * and counts as a failure, reported as `'invalid'` like a wrong password.
56
+ *
57
+ * Tradeoff: locking is per account, so anyone who knows an account name can lock
58
+ * it out by failing on purpose. Each lock is capped (default 15 minutes) and the
59
+ * client key bounds how fast one address can do it.
60
+ *
61
+ * Every success, failure and refusal is logged, and audited (entity `SignIn`,
62
+ * verbs `success`, `fail`, `locked`; never the account string or password) when
63
+ * the Flow has an open trace step. Route a locked result to a 429 with
64
+ * `throw new TooManyRequestsError(result.retryAfterSeconds)`.
65
+ */
66
+ export function createSignIn(config: SignInConfig): SignIn {
67
+ const accountThreshold = config.accountThreshold ?? 5
68
+ const clientThreshold = config.clientThreshold ?? 20
69
+ const windowSeconds = config.windowSeconds ?? 900
70
+ const maxLockSeconds = config.maxLockSeconds ?? 900
71
+ const { passwords } = config
72
+
73
+ function keysFor(account: string, client: string | undefined): { accountKey: Key; all: Key[] } {
74
+ const normalized = account.normalize('NFC').trim().toLowerCase()
75
+ const accountKey = { key: 'account:' + createHash('sha256').update(normalized).digest('hex'), threshold: accountThreshold }
76
+ const all = [accountKey]
77
+ if (client !== undefined && client !== '') all.push({ key: 'client:' + client, threshold: clientThreshold })
78
+ return { accountKey, all }
79
+ }
80
+
81
+ // Counts the attempt before any password is checked, one statement per key, so
82
+ // a burst of parallel guesses is counted (and locked) before it is verified.
83
+ // The update applies only to a key that is not currently locked; a locked key
84
+ // returns no row and is read separately.
85
+ async function countAttempt(db: DB, { key, threshold }: Key): Promise<{ locked: boolean; failures: number; retryAfterSeconds: number }> {
86
+ const rows = await db.execute(sql`
87
+ INSERT INTO pipework_signin_attempts AS a (key, failures, first_failure_at, last_failure_at, locked_until)
88
+ VALUES (${key}, 1, now(), now(),
89
+ CASE WHEN 1 >= ${threshold}::int
90
+ THEN now() + least(power(2, 0), ${maxLockSeconds}::int) * interval '1 second' END)
91
+ ON CONFLICT (key) DO UPDATE SET
92
+ failures = CASE WHEN a.first_failure_at < now() - ${windowSeconds}::int * interval '1 second' THEN 1 ELSE a.failures + 1 END,
93
+ first_failure_at = CASE WHEN a.first_failure_at < now() - ${windowSeconds}::int * interval '1 second' THEN now() ELSE a.first_failure_at END,
94
+ last_failure_at = now(),
95
+ locked_until = CASE
96
+ WHEN (CASE WHEN a.first_failure_at < now() - ${windowSeconds}::int * interval '1 second' THEN 1 ELSE a.failures + 1 END) >= ${threshold}::int
97
+ THEN now() + least(
98
+ power(2, least((CASE WHEN a.first_failure_at < now() - ${windowSeconds}::int * interval '1 second' THEN 1 ELSE a.failures + 1 END) - ${threshold}::int, 30)),
99
+ ${maxLockSeconds}::int) * interval '1 second'
100
+ END
101
+ WHERE a.locked_until IS NULL OR a.locked_until <= now()
102
+ RETURNING failures, coalesce(ceil(extract(epoch FROM (locked_until - now()))), 0)::int AS remaining`)
103
+ if (rows.length > 0) {
104
+ return { locked: false, failures: Number(rows[0]!['failures']), retryAfterSeconds: Math.max(0, Number(rows[0]!['remaining'])) }
105
+ }
106
+ const held = await db.execute(sql`
107
+ SELECT failures, greatest(ceil(extract(epoch FROM (locked_until - now())))::int, 1) AS remaining
108
+ FROM pipework_signin_attempts WHERE key = ${key}`)
109
+ return { locked: true, failures: Number(held[0]?.['failures'] ?? 0), retryAfterSeconds: Number(held[0]?.['remaining'] ?? 1) }
110
+ }
111
+
112
+ const audit = (db: DB, verb: string, userId: string | null, details: Record<string, unknown>): Promise<void> =>
113
+ auditUnauthenticated(db, 'SignIn', verb, userId, details)
114
+
115
+ async function attempt(input: SignInAttempt): Promise<SignInResult> {
116
+ const db = pipeSystem()
117
+ const { accountKey, all } = keysFor(input.account, input.client)
118
+ const client = input.client ?? null
119
+ const base = { accountKey: accountKey.key, client }
120
+
121
+ const counted: Array<{ k: Key; r: { locked: boolean; failures: number; retryAfterSeconds: number } }> = []
122
+ for (const k of all) counted.push({ k, r: await countAttempt(db, k) })
123
+ const heldFor = Math.max(0, ...counted.filter(c => c.r.locked).map(c => c.r.retryAfterSeconds))
124
+ if (counted.some(c => c.r.locked)) {
125
+ getBaseLogger().warn({ event: 'sign-in refused', ...base, retryAfterSeconds: heldFor }, 'sign-in refused: locked')
126
+ await audit(db, 'locked', null, { ...base, failures: counted[0]!.r.failures, retryAfterSeconds: heldFor })
127
+ return { ok: false, reason: 'locked', retryAfterSeconds: heldFor }
128
+ }
129
+
130
+ const found = await input.lookup(db, input.account)
131
+ if (found === null) await passwords.verifyNone(input.password)
132
+ const verified = found === null ? null : await passwords.verify(found.passwordHash, input.password)
133
+
134
+ if (found !== null && verified !== null && verified.ok) {
135
+ await db.execute(sql`DELETE FROM pipework_signin_attempts WHERE key = ${accountKey.key}`)
136
+ for (const { k } of counted) {
137
+ if (k !== accountKey) {
138
+ await db.execute(sql`UPDATE pipework_signin_attempts SET failures = greatest(failures - 1, 0) WHERE key = ${k.key}`)
139
+ }
140
+ }
141
+ getBaseLogger().info({ event: 'sign-in success', ...base }, 'sign-in succeeded')
142
+ await audit(db, 'success', found.userId, { ...base, failures: 0, retryAfterSeconds: null })
143
+ return { ok: true, userId: found.userId, needsRehash: verified.needsRehash }
144
+ }
145
+
146
+ const retryAfterSeconds = Math.max(0, ...counted.map(c => c.r.retryAfterSeconds))
147
+ const details = { ...base, failures: counted[0]!.r.failures, retryAfterSeconds: retryAfterSeconds > 0 ? retryAfterSeconds : null }
148
+ getBaseLogger().warn({ event: 'sign-in failed', ...details }, 'sign-in failed')
149
+ await audit(db, 'fail', found?.userId ?? null, details)
150
+ return retryAfterSeconds > 0
151
+ ? { ok: false, reason: 'invalid', retryAfterSeconds }
152
+ : { ok: false, reason: 'invalid' }
153
+ }
154
+
155
+ return { attempt }
156
+ }
@@ -0,0 +1,69 @@
1
+ import { createPublicKey, createPrivateKey, type KeyObject } from 'node:crypto'
2
+ import { importPKCS8, importSPKI } from 'jose'
3
+ import { AuthConfigurationError } from '../../core/errors/index.js'
4
+
5
+ interface Signing { readonly algorithm: 'ES256'; readonly privateKey: string; readonly publicKey: string }
6
+
7
+ /**
8
+ * Parses both configured signing keys now, so a key that is not valid PEM stops the server at start.
9
+ * Returns the public key for synchronous verification. `owner` names the factory in the message.
10
+ */
11
+ export function checkSigningKeys(signing: Signing, owner: string): KeyObject {
12
+ let publicKey: KeyObject
13
+ try {
14
+ publicKey = createPublicKey(signing.publicKey)
15
+ } catch (error) {
16
+ throw keyFault('signing.publicKey', 'a valid SPKI PEM public key', owner, error)
17
+ }
18
+ let privateKey: KeyObject
19
+ try {
20
+ privateKey = createPrivateKey(signing.privateKey)
21
+ } catch (error) {
22
+ throw keyFault('signing.privateKey', 'a valid PKCS#8 PEM private key', owner, error)
23
+ }
24
+ assertFitsAlgorithm(publicKey, 'signing.publicKey', signing.algorithm, owner)
25
+ assertFitsAlgorithm(privateKey, 'signing.privateKey', signing.algorithm, owner)
26
+ return publicKey
27
+ }
28
+
29
+ /** Imports a configured key for jose; a failure is a configuration fault (500), never a refusal of a token. */
30
+ export async function importSigningKey(kind: 'public' | 'private', signing: Signing, owner: string): Promise<CryptoKey> {
31
+ try {
32
+ return kind === 'public'
33
+ ? await importSPKI(signing.publicKey, signing.algorithm)
34
+ : await importPKCS8(signing.privateKey, signing.algorithm)
35
+ } catch (error) {
36
+ throw keyFault(
37
+ kind === 'public' ? 'signing.publicKey' : 'signing.privateKey',
38
+ `a key usable with ${signing.algorithm}`, owner, error,
39
+ )
40
+ }
41
+ }
42
+
43
+ function keyFault(field: string, expected: string, owner: string, error: unknown): AuthConfigurationError {
44
+ const reason = error instanceof Error ? error.message : String(error)
45
+ return new AuthConfigurationError(
46
+ `[pipework] ${owner}: ${field} is not ${expected}: ${reason}`,
47
+ { field },
48
+ )
49
+ }
50
+
51
+ const CURVES: Record<string, string> = { ES256: 'prime256v1', ES384: 'secp384r1', ES512: 'secp521r1' }
52
+
53
+ function assertFitsAlgorithm(key: KeyObject, field: string, algorithm: string, owner: string): void {
54
+ const type = key.asymmetricKeyType
55
+ let fits: boolean | null = null
56
+ if (/^(RS|PS)\d+$/.test(algorithm)) {
57
+ fits = type === 'rsa' || (algorithm.startsWith('PS') && type === 'rsa-pss')
58
+ } else if (algorithm in CURVES) {
59
+ fits = type === 'ec' && key.asymmetricKeyDetails?.namedCurve === CURVES[algorithm]
60
+ } else if (algorithm === 'EdDSA') {
61
+ fits = type === 'ed25519' || type === 'ed448'
62
+ }
63
+ if (fits === null || fits) return
64
+ const curve = type === 'ec' ? ` (${key.asymmetricKeyDetails?.namedCurve ?? 'unknown curve'})` : ''
65
+ throw new AuthConfigurationError(
66
+ `[pipework] ${owner}: ${field} is a ${type ?? 'unknown'}${curve} key, which does not fit algorithm ${algorithm}`,
67
+ { field },
68
+ )
69
+ }
@@ -0,0 +1,26 @@
1
+ import type { DB } from '../../data/db/types.js'
2
+
3
+ /** Runtime auth context passed to strategies — carries the resolved DB and request metadata. */
4
+ export interface AuthContext {
5
+ readonly db: (name?: string) => DB
6
+ }
7
+
8
+ /** Pluggable auth strategy — implement authenticate() to extract auth from a request. */
9
+ export interface AuthStrategy<TAuth> {
10
+ readonly name: string
11
+ extract(request: AuthRequest, context: AuthContext): Promise<TAuth | null>
12
+ verify(extracted: TAuth, context: AuthContext): Promise<TAuth>
13
+ }
14
+
15
+ /** Normalized request shape passed to auth strategies — headers, the parsed `Cookie` header, and the upper-case HTTP method. */
16
+ export interface AuthRequest {
17
+ readonly headers: Readonly<Record<string, string | undefined>>
18
+ readonly cookies: Readonly<Record<string, string | undefined>>
19
+ readonly method?: string
20
+ }
21
+
22
+ /** Minimum auth shape — userId and tenantId. Extend for app-specific auth fields. */
23
+ export interface BaseAuth {
24
+ readonly userId: string
25
+ readonly tenantId: string
26
+ }
@@ -0,0 +1,10 @@
1
+ import { ValidationError } from '../../core/errors/index.js'
2
+
3
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
4
+
5
+ /** Throws a ValidationError unless `value` is a uuid; the session and org tables type tenant and org ids uuid. */
6
+ export function assertUuid(value: string, what: string): void {
7
+ if (!UUID_RE.test(value)) {
8
+ throw new ValidationError(`${what} must be a uuid, got "${value}". The pipework_refresh_tokens and pipework_user_orgs tables type it uuid.`)
9
+ }
10
+ }
@@ -0,0 +1,55 @@
1
+ import type { PermissionSet } from './types.js'
2
+
3
+ interface CacheEntry {
4
+ readonly set: PermissionSet
5
+ readonly expiresAt: number
6
+ }
7
+
8
+ export class PermissionCache {
9
+ private readonly store = new Map<string, CacheEntry>()
10
+ private readonly ttlMs: number
11
+
12
+ constructor(ttlMs: number) {
13
+ this.ttlMs = ttlMs
14
+ }
15
+
16
+ get(userId: string, tenantId: string, authVersion: number): PermissionSet | null {
17
+ const key = this.key(userId, tenantId, authVersion)
18
+ const entry = this.store.get(key)
19
+ if (!entry) return null
20
+ if (Date.now() > entry.expiresAt) {
21
+ this.store.delete(key)
22
+ return null
23
+ }
24
+ return entry.set
25
+ }
26
+
27
+ set(permissionSet: PermissionSet): void {
28
+ const key = this.key(permissionSet.userId, permissionSet.tenantId, permissionSet.authVersion)
29
+ this.store.set(key, {
30
+ set: permissionSet,
31
+ expiresAt: Date.now() + this.ttlMs,
32
+ })
33
+ }
34
+
35
+ invalidate(userId: string, tenantId: string): void {
36
+ const prefix = `${userId}:${tenantId}:`
37
+ for (const key of this.store.keys()) {
38
+ if (key.startsWith(prefix)) {
39
+ this.store.delete(key)
40
+ }
41
+ }
42
+ }
43
+
44
+ clear(): void {
45
+ this.store.clear()
46
+ }
47
+
48
+ get size(): number {
49
+ return this.store.size
50
+ }
51
+
52
+ private key(userId: string, tenantId: string, authVersion: number): string {
53
+ return `${userId}:${tenantId}:${authVersion}`
54
+ }
55
+ }
@@ -0,0 +1,30 @@
1
+ import type { ResolvedPermission } from './types.js'
2
+
3
+ const DEFAULT_HIERARCHY: readonly string[] = ['own', 'team', 'territory', 'tenant']
4
+
5
+ export function scopeSatisfies(
6
+ granted: string,
7
+ required: string,
8
+ hierarchy: readonly string[] = DEFAULT_HIERARCHY,
9
+ ): boolean {
10
+ const grantedIdx = hierarchy.indexOf(granted)
11
+ const requiredIdx = hierarchy.indexOf(required)
12
+ if (grantedIdx === -1 || requiredIdx === -1) return false
13
+ return grantedIdx >= requiredIdx
14
+ }
15
+
16
+ export function hasPermission(
17
+ permissions: readonly ResolvedPermission[],
18
+ resource: string,
19
+ action: string,
20
+ requiredScope?: string,
21
+ hierarchy: readonly string[] = DEFAULT_HIERARCHY,
22
+ ): boolean {
23
+ for (const perm of permissions) {
24
+ if (perm.resource === resource && perm.action === action) {
25
+ if (requiredScope === undefined) return true
26
+ if (scopeSatisfies(perm.scope, requiredScope, hierarchy)) return true
27
+ }
28
+ }
29
+ return false
30
+ }
@@ -0,0 +1,35 @@
1
+ import type { DB } from '../../data/db/index.js'
2
+ import type { RbacConfig, Rbac, PermissionSet, SeedData } from './types.js'
3
+ import { PermissionCache } from './cache.js'
4
+ import { resolveUserPermissions } from './resolve.js'
5
+ import { hasPermission } from './check.js'
6
+ import { seedRbac } from './seed.js'
7
+
8
+ /** Creates an Rbac instance from role/permission config — provides check, enforce, and seed operations. */
9
+ export function createRbac(config: RbacConfig): Rbac {
10
+ const cache = new PermissionCache(config.cacheTtlMs ?? 60_000)
11
+ const scopes = config.scopes ?? ['own', 'team', 'territory', 'tenant']
12
+
13
+ return {
14
+ async resolve(db: DB, userId: string, tenantId: string, authVersion: number): Promise<PermissionSet> {
15
+ const cached = cache.get(userId, tenantId, authVersion)
16
+ if (cached) return cached
17
+
18
+ const resolved = await resolveUserPermissions(db, userId, tenantId, authVersion, config)
19
+ cache.set(resolved)
20
+ return resolved
21
+ },
22
+
23
+ check(permissions: PermissionSet, resource: string, action: string, requiredScope?: string): boolean {
24
+ return hasPermission(permissions.permissions, resource, action, requiredScope, scopes)
25
+ },
26
+
27
+ invalidate(userId: string, tenantId: string): void {
28
+ cache.invalidate(userId, tenantId)
29
+ },
30
+
31
+ async seed(db: DB, data: SeedData): Promise<void> {
32
+ await seedRbac(db, data, config)
33
+ },
34
+ }
35
+ }
@@ -0,0 +1,5 @@
1
+ export type { RbacConfig, Rbac, PermissionSet, ResolvedPermission, Scope, SeedData, SeedPermission, SeedRole, SeedRolePermission, SeedUserRole } from './types.js'
2
+ export { hasPermission, scopeSatisfies } from './check.js'
3
+ export { PermissionCache } from './cache.js'
4
+ export { enforcePermission } from './middleware.js'
5
+ export { createRbac } from './create.js'
@@ -0,0 +1,20 @@
1
+ import type { DB } from '../../data/db/index.js'
2
+ import type { Rbac } from './types.js'
3
+ import { ForbiddenError } from '../../core/errors/index.js'
4
+
5
+ export async function enforcePermission(
6
+ rbac: Rbac,
7
+ db: DB,
8
+ userId: string,
9
+ tenantId: string,
10
+ authVersion: number,
11
+ resource: string,
12
+ action: string,
13
+ requiredScope?: string,
14
+ ): Promise<void> {
15
+ const permissions = await rbac.resolve(db, userId, tenantId, authVersion)
16
+ const granted = rbac.check(permissions, resource, action, requiredScope)
17
+ if (!granted) {
18
+ throw new ForbiddenError(`Missing permission: ${resource}:${action}`)
19
+ }
20
+ }
@@ -0,0 +1,15 @@
1
+ import { createRbac, hasPermission, enforcePermission, scopeSatisfies, PermissionCache } from './index.js'
2
+
3
+ /** Role-based access control namespace — permission checking, enforcement, scope hierarchy. */
4
+ export const rbac = {
5
+ /** Creates an Rbac instance from config (roles, permissions, hierarchy). */
6
+ create: createRbac,
7
+ /** Checks if a permission set includes the required resource/action/scope. Pure function, no DB. */
8
+ check: hasPermission,
9
+ /** Checks permission and throws ForbiddenError if denied. Loads permissions from DB with caching. */
10
+ enforce: enforcePermission,
11
+ /** Checks if a granted scope satisfies a required scope given a hierarchy (e.g. org > team > self). */
12
+ satisfies: scopeSatisfies,
13
+ /** LRU cache for resolved permissions — avoids repeated DB lookups within a request. */
14
+ PermissionCache,
15
+ }
@@ -0,0 +1,31 @@
1
+ import { sql } from '../../data/db/sql.js'
2
+ import type { DB } from '../../data/db/index.js'
3
+ import type { RbacConfig, PermissionSet, ResolvedPermission } from './types.js'
4
+ import { quoteIdentifier } from '../../data/db/identifiers.js'
5
+ import { resolveRbacTables } from './tables.js'
6
+
7
+ export async function resolveUserPermissions(
8
+ db: DB,
9
+ userId: string,
10
+ tenantId: string,
11
+ authVersion: number,
12
+ config: RbacConfig,
13
+ ): Promise<PermissionSet> {
14
+ const { userRoles: userRolesTable, rolePermissions: rolePermissionsTable, permissions: permissionsTable } = resolveRbacTables(config)
15
+
16
+ const rows = await db.execute(sql`
17
+ SELECT p.resource, p.action, rp.scope
18
+ FROM ${sql.raw(quoteIdentifier(userRolesTable, 'userRoles table'))} ur
19
+ JOIN ${sql.raw(quoteIdentifier(rolePermissionsTable, 'rolePermissions table'))} rp ON rp.role_id = ur.role_id
20
+ JOIN ${sql.raw(quoteIdentifier(permissionsTable, 'permissions table'))} p ON p.id = rp.permission_id
21
+ WHERE ur.user_id = ${userId} AND ur.tenant_id = ${tenantId}
22
+ `)
23
+
24
+ const permissions: ResolvedPermission[] = rows.map((row) => ({
25
+ resource: row['resource'] as string,
26
+ action: row['action'] as string,
27
+ scope: row['scope'] as string,
28
+ }))
29
+
30
+ return { userId, tenantId, authVersion, permissions }
31
+ }
@@ -0,0 +1,31 @@
1
+ CREATE TABLE IF NOT EXISTS pipework_permissions (
2
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
3
+ resource text NOT NULL,
4
+ action text NOT NULL,
5
+ UNIQUE (resource, action)
6
+ );
7
+
8
+ CREATE TABLE IF NOT EXISTS pipework_roles (
9
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
10
+ name text NOT NULL,
11
+ tenant_id text NOT NULL,
12
+ description text,
13
+ UNIQUE (tenant_id, name)
14
+ );
15
+
16
+ CREATE TABLE IF NOT EXISTS pipework_role_permissions (
17
+ role_id uuid NOT NULL REFERENCES pipework_roles(id) ON DELETE CASCADE,
18
+ permission_id uuid NOT NULL REFERENCES pipework_permissions(id) ON DELETE CASCADE,
19
+ scope text NOT NULL DEFAULT 'own',
20
+ PRIMARY KEY (role_id, permission_id),
21
+ CONSTRAINT valid_scope CHECK (scope = ANY(ARRAY['own', 'team', 'territory', 'tenant']))
22
+ );
23
+
24
+ CREATE TABLE IF NOT EXISTS pipework_user_roles (
25
+ user_id text NOT NULL,
26
+ role_id uuid NOT NULL REFERENCES pipework_roles(id) ON DELETE CASCADE,
27
+ tenant_id text NOT NULL,
28
+ PRIMARY KEY (user_id, role_id, tenant_id)
29
+ );
30
+
31
+ CREATE INDEX IF NOT EXISTS idx_user_roles_lookup ON pipework_user_roles (user_id, tenant_id);
@@ -0,0 +1,67 @@
1
+ import { sql } from '../../data/db/sql.js'
2
+ import type { DB } from '../../data/db/index.js'
3
+ import type { RbacConfig, SeedData } from './types.js'
4
+ import { quoteIdentifier } from '../../data/db/identifiers.js'
5
+ import { resolveRbacTables } from './tables.js'
6
+
7
+ export async function seedRbac(
8
+ db: DB,
9
+ data: SeedData,
10
+ config: RbacConfig,
11
+ ): Promise<void> {
12
+ const tables = resolveRbacTables(config)
13
+
14
+ const permQ = quoteIdentifier(tables.permissions, 'permissions table')
15
+ const rolesQ = quoteIdentifier(tables.roles, 'roles table')
16
+ const rolePermQ = quoteIdentifier(tables.rolePermissions, 'rolePermissions table')
17
+ const userRolesQ = quoteIdentifier(tables.userRoles, 'userRoles table')
18
+
19
+ for (const perm of data.permissions) {
20
+ await db.execute(sql`
21
+ INSERT INTO ${sql.raw(permQ)} (resource, action)
22
+ VALUES (${perm.resource}, ${perm.action})
23
+ ON CONFLICT (resource, action) DO NOTHING
24
+ `)
25
+ }
26
+
27
+ for (const role of data.roles) {
28
+ if (role.description !== undefined) {
29
+ await db.execute(sql`
30
+ INSERT INTO ${sql.raw(rolesQ)} (name, tenant_id, description)
31
+ VALUES (${role.name}, ${role.tenantId}, ${role.description})
32
+ ON CONFLICT (tenant_id, name) DO UPDATE SET
33
+ description = EXCLUDED.description
34
+ `)
35
+ } else {
36
+ await db.execute(sql`
37
+ INSERT INTO ${sql.raw(rolesQ)} (name, tenant_id)
38
+ VALUES (${role.name}, ${role.tenantId})
39
+ ON CONFLICT (tenant_id, name) DO UPDATE SET
40
+ description = EXCLUDED.description
41
+ `)
42
+ }
43
+
44
+ for (const rp of role.permissions) {
45
+ await db.execute(sql`
46
+ INSERT INTO ${sql.raw(rolePermQ)} (role_id, permission_id, scope)
47
+ SELECT r.id, p.id, ${rp.scope}
48
+ FROM ${sql.raw(rolesQ)} r, ${sql.raw(permQ)} p
49
+ WHERE r.name = ${role.name} AND r.tenant_id = ${role.tenantId}
50
+ AND p.resource = ${rp.resource} AND p.action = ${rp.action}
51
+ ON CONFLICT (role_id, permission_id) DO UPDATE SET scope = EXCLUDED.scope
52
+ `)
53
+ }
54
+ }
55
+
56
+ if (data.userRoles) {
57
+ for (const ur of data.userRoles) {
58
+ await db.execute(sql`
59
+ INSERT INTO ${sql.raw(userRolesQ)} (user_id, role_id, tenant_id)
60
+ SELECT ${ur.userId}, r.id, ${ur.tenantId}
61
+ FROM ${sql.raw(rolesQ)} r
62
+ WHERE r.name = ${ur.roleName} AND r.tenant_id = ${ur.tenantId}
63
+ ON CONFLICT (user_id, role_id, tenant_id) DO NOTHING
64
+ `)
65
+ }
66
+ }
67
+ }
@@ -0,0 +1,32 @@
1
+ import type { RbacConfig } from './types.js'
2
+ import { assertValidIdentifier } from '../../data/db/identifiers.js'
3
+
4
+ export interface RbacTableNames {
5
+ readonly permissions: string
6
+ readonly roles: string
7
+ readonly rolePermissions: string
8
+ readonly userRoles: string
9
+ }
10
+
11
+ export const RBAC_TABLE_DEFAULTS: RbacTableNames = {
12
+ permissions: 'pipework_permissions',
13
+ roles: 'pipework_roles',
14
+ rolePermissions: 'pipework_role_permissions',
15
+ userRoles: 'pipework_user_roles',
16
+ }
17
+
18
+ export function resolveRbacTables(config: RbacConfig): RbacTableNames {
19
+ const tables: RbacTableNames = {
20
+ permissions: config.table?.permissions ?? RBAC_TABLE_DEFAULTS.permissions,
21
+ roles: config.table?.roles ?? RBAC_TABLE_DEFAULTS.roles,
22
+ rolePermissions: config.table?.rolePermissions ?? RBAC_TABLE_DEFAULTS.rolePermissions,
23
+ userRoles: config.table?.userRoles ?? RBAC_TABLE_DEFAULTS.userRoles,
24
+ }
25
+
26
+ assertValidIdentifier(tables.permissions, 'permissions table')
27
+ assertValidIdentifier(tables.roles, 'roles table')
28
+ assertValidIdentifier(tables.rolePermissions, 'rolePermissions table')
29
+ assertValidIdentifier(tables.userRoles, 'userRoles table')
30
+
31
+ return tables
32
+ }
@@ -0,0 +1,65 @@
1
+ import type { DB } from '../../data/db/index.js'
2
+
3
+ export type Scope = 'own' | 'team' | 'territory' | 'tenant'
4
+
5
+ export interface RbacConfig {
6
+ readonly database: string
7
+ readonly scopes?: readonly string[]
8
+ readonly cacheTtlMs?: number
9
+ readonly table?: {
10
+ readonly permissions?: string
11
+ readonly roles?: string
12
+ readonly rolePermissions?: string
13
+ readonly userRoles?: string
14
+ }
15
+ }
16
+
17
+ export interface ResolvedPermission {
18
+ readonly resource: string
19
+ readonly action: string
20
+ readonly scope: string
21
+ }
22
+
23
+ export interface PermissionSet {
24
+ readonly userId: string
25
+ readonly tenantId: string
26
+ readonly authVersion: number
27
+ readonly permissions: readonly ResolvedPermission[]
28
+ }
29
+
30
+ export interface SeedPermission {
31
+ readonly resource: string
32
+ readonly action: string
33
+ }
34
+
35
+ export interface SeedRolePermission {
36
+ readonly resource: string
37
+ readonly action: string
38
+ readonly scope: string
39
+ }
40
+
41
+ export interface SeedRole {
42
+ readonly name: string
43
+ readonly tenantId: string
44
+ readonly description?: string
45
+ readonly permissions: readonly SeedRolePermission[]
46
+ }
47
+
48
+ export interface SeedUserRole {
49
+ readonly userId: string
50
+ readonly roleName: string
51
+ readonly tenantId: string
52
+ }
53
+
54
+ export interface SeedData {
55
+ readonly permissions: readonly SeedPermission[]
56
+ readonly roles: readonly SeedRole[]
57
+ readonly userRoles?: readonly SeedUserRole[]
58
+ }
59
+
60
+ export interface Rbac {
61
+ resolve(db: DB, userId: string, tenantId: string, authVersion: number): Promise<PermissionSet>
62
+ check(permissions: PermissionSet, resource: string, action: string, requiredScope?: string): boolean
63
+ invalidate(userId: string, tenantId: string): void
64
+ seed(db: DB, data: SeedData): Promise<void>
65
+ }