@heavybit/shared-lib 2.1.0 → 2.7.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 (296) hide show
  1. package/README.md +163 -2
  2. package/dist/cjs/access/index.js +9 -1
  3. package/dist/cjs/access/index.js.map +1 -1
  4. package/dist/cjs/approvals/index.js +137 -0
  5. package/dist/cjs/approvals/index.js.map +1 -0
  6. package/dist/cjs/audit/index.js +74 -0
  7. package/dist/cjs/audit/index.js.map +1 -0
  8. package/dist/cjs/cache/index.js +90 -16
  9. package/dist/cjs/cache/index.js.map +1 -1
  10. package/dist/cjs/cache/keyspace.js +101 -0
  11. package/dist/cjs/cache/keyspace.js.map +1 -0
  12. package/dist/cjs/common/circuit-breaker.js +74 -0
  13. package/dist/cjs/common/circuit-breaker.js.map +1 -0
  14. package/dist/cjs/common/index.js +4 -0
  15. package/dist/cjs/common/index.js.map +1 -1
  16. package/dist/cjs/common/internal-client.js +177 -0
  17. package/dist/cjs/common/internal-client.js.map +1 -0
  18. package/dist/cjs/common/internal-constants.js +12 -0
  19. package/dist/cjs/common/internal-constants.js.map +1 -0
  20. package/dist/cjs/common/internal-service-auth.js +160 -0
  21. package/dist/cjs/common/internal-service-auth.js.map +1 -0
  22. package/dist/cjs/common/money.js +215 -0
  23. package/dist/cjs/common/money.js.map +1 -0
  24. package/dist/cjs/common/phone.js +41 -22
  25. package/dist/cjs/common/phone.js.map +1 -1
  26. package/dist/cjs/common/time.js +28 -2
  27. package/dist/cjs/common/time.js.map +1 -1
  28. package/dist/cjs/config/index.js +139 -19
  29. package/dist/cjs/config/index.js.map +1 -1
  30. package/dist/cjs/contracts/notification-dispatch.js +1 -1
  31. package/dist/cjs/database/db.js +37 -0
  32. package/dist/cjs/database/db.js.map +1 -0
  33. package/dist/cjs/database/index.js +22 -51
  34. package/dist/cjs/database/index.js.map +1 -1
  35. package/dist/cjs/database/pagination.js +88 -0
  36. package/dist/cjs/database/pagination.js.map +1 -0
  37. package/dist/cjs/database/pool.js +60 -0
  38. package/dist/cjs/database/pool.js.map +1 -0
  39. package/dist/cjs/database/scoped-repository.js +132 -0
  40. package/dist/cjs/database/scoped-repository.js.map +1 -0
  41. package/dist/cjs/database/scopes.js +166 -0
  42. package/dist/cjs/database/scopes.js.map +1 -0
  43. package/dist/cjs/database/table-names.js +14 -0
  44. package/dist/cjs/database/table-names.js.map +1 -0
  45. package/dist/cjs/database/tables.js +71 -0
  46. package/dist/cjs/database/tables.js.map +1 -0
  47. package/dist/cjs/express/auth.js +64 -50
  48. package/dist/cjs/express/auth.js.map +1 -1
  49. package/dist/cjs/express/index.js +2 -0
  50. package/dist/cjs/express/index.js.map +1 -1
  51. package/dist/cjs/express/internal-caller.js +52 -0
  52. package/dist/cjs/express/internal-caller.js.map +1 -0
  53. package/dist/cjs/express/step-up.js +41 -0
  54. package/dist/cjs/express/step-up.js.map +1 -0
  55. package/dist/cjs/http/index.js +3 -71
  56. package/dist/cjs/http/index.js.map +1 -1
  57. package/dist/cjs/identity/index.js +269 -67
  58. package/dist/cjs/identity/index.js.map +1 -1
  59. package/dist/cjs/identity/step-up.js +52 -0
  60. package/dist/cjs/identity/step-up.js.map +1 -0
  61. package/dist/cjs/index.js +6 -0
  62. package/dist/cjs/index.js.map +1 -1
  63. package/dist/cjs/knex/columns.js +36 -0
  64. package/dist/cjs/knex/columns.js.map +1 -0
  65. package/dist/cjs/knex/index.js +26 -43
  66. package/dist/cjs/knex/index.js.map +1 -1
  67. package/dist/cjs/knex/migration-helpers.js +57 -0
  68. package/dist/cjs/knex/migration-helpers.js.map +1 -0
  69. package/dist/cjs/logging/redact.js +6 -11
  70. package/dist/cjs/logging/redact.js.map +1 -1
  71. package/dist/cjs/messaging/base-consumer.js +36 -0
  72. package/dist/cjs/messaging/base-consumer.js.map +1 -0
  73. package/dist/cjs/messaging/consumer.js +142 -73
  74. package/dist/cjs/messaging/consumer.js.map +1 -1
  75. package/dist/cjs/messaging/envelope.js +53 -10
  76. package/dist/cjs/messaging/envelope.js.map +1 -1
  77. package/dist/cjs/messaging/idempotency.js +95 -8
  78. package/dist/cjs/messaging/idempotency.js.map +1 -1
  79. package/dist/cjs/messaging/index.js +2 -1
  80. package/dist/cjs/messaging/index.js.map +1 -1
  81. package/dist/cjs/messaging/outbox.js +97 -55
  82. package/dist/cjs/messaging/outbox.js.map +1 -1
  83. package/dist/cjs/messaging/publisher.js +86 -38
  84. package/dist/cjs/messaging/publisher.js.map +1 -1
  85. package/dist/cjs/messaging/staff-notifier.js +4 -4
  86. package/dist/cjs/messaging/staff-notifier.js.map +1 -1
  87. package/dist/cjs/messaging/topology.js +41 -5
  88. package/dist/cjs/messaging/topology.js.map +1 -1
  89. package/dist/cjs/rate-limit/index.js +57 -6
  90. package/dist/cjs/rate-limit/index.js.map +1 -1
  91. package/dist/cjs/rate-limit/keys.js +47 -0
  92. package/dist/cjs/rate-limit/keys.js.map +1 -0
  93. package/dist/cjs/socket/index.js +127 -16
  94. package/dist/cjs/socket/index.js.map +1 -1
  95. package/dist/cjs/socket/ticket.js +124 -0
  96. package/dist/cjs/socket/ticket.js.map +1 -0
  97. package/dist/cjs/testing/index.js +23 -14
  98. package/dist/cjs/testing/index.js.map +1 -1
  99. package/dist/esm/access/index.js +9 -1
  100. package/dist/esm/access/index.js.map +1 -1
  101. package/dist/esm/approvals/index.js +127 -0
  102. package/dist/esm/approvals/index.js.map +1 -0
  103. package/dist/esm/audit/index.js +70 -0
  104. package/dist/esm/audit/index.js.map +1 -0
  105. package/dist/esm/cache/index.js +70 -13
  106. package/dist/esm/cache/index.js.map +1 -1
  107. package/dist/esm/cache/keyspace.js +95 -0
  108. package/dist/esm/cache/keyspace.js.map +1 -0
  109. package/dist/esm/common/circuit-breaker.js +70 -0
  110. package/dist/esm/common/circuit-breaker.js.map +1 -0
  111. package/dist/esm/common/index.js +4 -0
  112. package/dist/esm/common/index.js.map +1 -1
  113. package/dist/esm/common/internal-client.js +173 -0
  114. package/dist/esm/common/internal-client.js.map +1 -0
  115. package/dist/esm/common/internal-constants.js +9 -0
  116. package/dist/esm/common/internal-constants.js.map +1 -0
  117. package/dist/esm/common/internal-service-auth.js +150 -0
  118. package/dist/esm/common/internal-service-auth.js.map +1 -0
  119. package/dist/esm/common/money.js +207 -0
  120. package/dist/esm/common/money.js.map +1 -0
  121. package/dist/esm/common/phone.js +41 -22
  122. package/dist/esm/common/phone.js.map +1 -1
  123. package/dist/esm/common/time.js +27 -2
  124. package/dist/esm/common/time.js.map +1 -1
  125. package/dist/esm/config/index.js +135 -18
  126. package/dist/esm/config/index.js.map +1 -1
  127. package/dist/esm/contracts/notification-dispatch.js +1 -1
  128. package/dist/esm/database/db.js +32 -0
  129. package/dist/esm/database/db.js.map +1 -0
  130. package/dist/esm/database/index.js +9 -45
  131. package/dist/esm/database/index.js.map +1 -1
  132. package/dist/esm/database/pagination.js +81 -0
  133. package/dist/esm/database/pagination.js.map +1 -0
  134. package/dist/esm/database/pool.js +51 -0
  135. package/dist/esm/database/pool.js.map +1 -0
  136. package/dist/esm/database/scoped-repository.js +128 -0
  137. package/dist/esm/database/scoped-repository.js.map +1 -0
  138. package/dist/esm/database/scopes.js +157 -0
  139. package/dist/esm/database/scopes.js.map +1 -0
  140. package/dist/esm/database/table-names.js +11 -0
  141. package/dist/esm/database/table-names.js.map +1 -0
  142. package/dist/esm/database/tables.js +61 -0
  143. package/dist/esm/database/tables.js.map +1 -0
  144. package/dist/esm/express/auth.js +62 -48
  145. package/dist/esm/express/auth.js.map +1 -1
  146. package/dist/esm/express/index.js +2 -0
  147. package/dist/esm/express/index.js.map +1 -1
  148. package/dist/esm/express/internal-caller.js +49 -0
  149. package/dist/esm/express/internal-caller.js.map +1 -0
  150. package/dist/esm/express/step-up.js +38 -0
  151. package/dist/esm/express/step-up.js.map +1 -0
  152. package/dist/esm/http/index.js +3 -70
  153. package/dist/esm/http/index.js.map +1 -1
  154. package/dist/esm/identity/index.js +246 -64
  155. package/dist/esm/identity/index.js.map +1 -1
  156. package/dist/esm/identity/step-up.js +47 -0
  157. package/dist/esm/identity/step-up.js.map +1 -0
  158. package/dist/esm/index.js +6 -0
  159. package/dist/esm/index.js.map +1 -1
  160. package/dist/esm/knex/columns.js +28 -0
  161. package/dist/esm/knex/columns.js.map +1 -0
  162. package/dist/esm/knex/index.js +8 -34
  163. package/dist/esm/knex/index.js.map +1 -1
  164. package/dist/esm/knex/migration-helpers.js +51 -0
  165. package/dist/esm/knex/migration-helpers.js.map +1 -0
  166. package/dist/esm/logging/redact.js +3 -7
  167. package/dist/esm/logging/redact.js.map +1 -1
  168. package/dist/esm/messaging/base-consumer.js +32 -0
  169. package/dist/esm/messaging/base-consumer.js.map +1 -0
  170. package/dist/esm/messaging/consumer.js +139 -71
  171. package/dist/esm/messaging/consumer.js.map +1 -1
  172. package/dist/esm/messaging/envelope.js +50 -10
  173. package/dist/esm/messaging/envelope.js.map +1 -1
  174. package/dist/esm/messaging/idempotency.js +91 -7
  175. package/dist/esm/messaging/idempotency.js.map +1 -1
  176. package/dist/esm/messaging/index.js +2 -1
  177. package/dist/esm/messaging/index.js.map +1 -1
  178. package/dist/esm/messaging/outbox.js +97 -54
  179. package/dist/esm/messaging/outbox.js.map +1 -1
  180. package/dist/esm/messaging/publisher.js +86 -38
  181. package/dist/esm/messaging/publisher.js.map +1 -1
  182. package/dist/esm/messaging/staff-notifier.js +4 -4
  183. package/dist/esm/messaging/staff-notifier.js.map +1 -1
  184. package/dist/esm/messaging/topology.js +39 -4
  185. package/dist/esm/messaging/topology.js.map +1 -1
  186. package/dist/esm/rate-limit/index.js +41 -6
  187. package/dist/esm/rate-limit/index.js.map +1 -1
  188. package/dist/esm/rate-limit/keys.js +43 -0
  189. package/dist/esm/rate-limit/keys.js.map +1 -0
  190. package/dist/esm/socket/index.js +112 -17
  191. package/dist/esm/socket/index.js.map +1 -1
  192. package/dist/esm/socket/ticket.js +117 -0
  193. package/dist/esm/socket/ticket.js.map +1 -0
  194. package/dist/esm/testing/index.js +24 -15
  195. package/dist/esm/testing/index.js.map +1 -1
  196. package/dist/types/access/index.d.ts +9 -3
  197. package/dist/types/access/index.d.ts.map +1 -1
  198. package/dist/types/approvals/index.d.ts +99 -0
  199. package/dist/types/approvals/index.d.ts.map +1 -0
  200. package/dist/types/audit/index.d.ts +82 -0
  201. package/dist/types/audit/index.d.ts.map +1 -0
  202. package/dist/types/cache/index.d.ts +64 -14
  203. package/dist/types/cache/index.d.ts.map +1 -1
  204. package/dist/types/cache/keyspace.d.ts +84 -0
  205. package/dist/types/cache/keyspace.d.ts.map +1 -0
  206. package/dist/types/common/circuit-breaker.d.ts +51 -0
  207. package/dist/types/common/circuit-breaker.d.ts.map +1 -0
  208. package/dist/types/common/index.d.ts +4 -0
  209. package/dist/types/common/index.d.ts.map +1 -1
  210. package/dist/types/common/internal-client.d.ts +116 -0
  211. package/dist/types/common/internal-client.d.ts.map +1 -0
  212. package/dist/types/common/internal-constants.d.ts +9 -0
  213. package/dist/types/common/internal-constants.d.ts.map +1 -0
  214. package/dist/types/common/internal-service-auth.d.ts +102 -0
  215. package/dist/types/common/internal-service-auth.d.ts.map +1 -0
  216. package/dist/types/common/money.d.ts +104 -0
  217. package/dist/types/common/money.d.ts.map +1 -0
  218. package/dist/types/common/phone.d.ts +25 -15
  219. package/dist/types/common/phone.d.ts.map +1 -1
  220. package/dist/types/common/time.d.ts +20 -2
  221. package/dist/types/common/time.d.ts.map +1 -1
  222. package/dist/types/config/index.d.ts +251 -27
  223. package/dist/types/config/index.d.ts.map +1 -1
  224. package/dist/types/contracts/notification-dispatch.d.ts +13 -13
  225. package/dist/types/database/db.d.ts +46 -0
  226. package/dist/types/database/db.d.ts.map +1 -0
  227. package/dist/types/database/index.d.ts +9 -22
  228. package/dist/types/database/index.d.ts.map +1 -1
  229. package/dist/types/database/pagination.d.ts +68 -0
  230. package/dist/types/database/pagination.d.ts.map +1 -0
  231. package/dist/types/database/pool.d.ts +39 -0
  232. package/dist/types/database/pool.d.ts.map +1 -0
  233. package/dist/types/database/scoped-repository.d.ts +92 -0
  234. package/dist/types/database/scoped-repository.d.ts.map +1 -0
  235. package/dist/types/database/scopes.d.ts +159 -0
  236. package/dist/types/database/scopes.d.ts.map +1 -0
  237. package/dist/types/database/table-names.d.ts +13 -0
  238. package/dist/types/database/table-names.d.ts.map +1 -0
  239. package/dist/types/database/tables.d.ts +748 -0
  240. package/dist/types/database/tables.d.ts.map +1 -0
  241. package/dist/types/express/auth.d.ts +40 -24
  242. package/dist/types/express/auth.d.ts.map +1 -1
  243. package/dist/types/express/index.d.ts +2 -0
  244. package/dist/types/express/index.d.ts.map +1 -1
  245. package/dist/types/express/internal-caller.d.ts +53 -0
  246. package/dist/types/express/internal-caller.d.ts.map +1 -0
  247. package/dist/types/express/step-up.d.ts +38 -0
  248. package/dist/types/express/step-up.d.ts.map +1 -0
  249. package/dist/types/http/index.d.ts +3 -31
  250. package/dist/types/http/index.d.ts.map +1 -1
  251. package/dist/types/identity/index.d.ts +159 -21
  252. package/dist/types/identity/index.d.ts.map +1 -1
  253. package/dist/types/identity/step-up.d.ts +41 -0
  254. package/dist/types/identity/step-up.d.ts.map +1 -0
  255. package/dist/types/index.d.ts +6 -0
  256. package/dist/types/index.d.ts.map +1 -1
  257. package/dist/types/knex/columns.d.ts +15 -0
  258. package/dist/types/knex/columns.d.ts.map +1 -0
  259. package/dist/types/knex/index.d.ts +3 -11
  260. package/dist/types/knex/index.d.ts.map +1 -1
  261. package/dist/types/knex/migration-helpers.d.ts +28 -0
  262. package/dist/types/knex/migration-helpers.d.ts.map +1 -0
  263. package/dist/types/logging/redact.d.ts +2 -2
  264. package/dist/types/logging/redact.d.ts.map +1 -1
  265. package/dist/types/messaging/base-consumer.d.ts +33 -0
  266. package/dist/types/messaging/base-consumer.d.ts.map +1 -0
  267. package/dist/types/messaging/consumer.d.ts +59 -21
  268. package/dist/types/messaging/consumer.d.ts.map +1 -1
  269. package/dist/types/messaging/envelope.d.ts +50 -11
  270. package/dist/types/messaging/envelope.d.ts.map +1 -1
  271. package/dist/types/messaging/idempotency.d.ts +60 -3
  272. package/dist/types/messaging/idempotency.d.ts.map +1 -1
  273. package/dist/types/messaging/index.d.ts +7 -0
  274. package/dist/types/messaging/index.d.ts.map +1 -1
  275. package/dist/types/messaging/outbox.d.ts +62 -22
  276. package/dist/types/messaging/outbox.d.ts.map +1 -1
  277. package/dist/types/messaging/publisher.d.ts +54 -21
  278. package/dist/types/messaging/publisher.d.ts.map +1 -1
  279. package/dist/types/messaging/staff-notifier.d.ts +9 -9
  280. package/dist/types/messaging/staff-notifier.d.ts.map +1 -1
  281. package/dist/types/messaging/staff-recipients.d.ts +1 -1
  282. package/dist/types/messaging/topology.d.ts +40 -8
  283. package/dist/types/messaging/topology.d.ts.map +1 -1
  284. package/dist/types/rate-limit/index.d.ts +40 -4
  285. package/dist/types/rate-limit/index.d.ts.map +1 -1
  286. package/dist/types/rate-limit/keys.d.ts +52 -0
  287. package/dist/types/rate-limit/keys.d.ts.map +1 -0
  288. package/dist/types/socket/index.d.ts +86 -2
  289. package/dist/types/socket/index.d.ts.map +1 -1
  290. package/dist/types/socket/ticket.d.ts +90 -0
  291. package/dist/types/socket/ticket.d.ts.map +1 -0
  292. package/dist/types/testing/index.d.ts +31 -10
  293. package/dist/types/testing/index.d.ts.map +1 -1
  294. package/dist/types/types/index.d.ts +26 -14
  295. package/dist/types/types/index.d.ts.map +1 -1
  296. package/package.json +3 -1
@@ -0,0 +1,61 @@
1
+ import { sql } from 'drizzle-orm';
2
+ import { DEFAULT_OUTBOX_TABLE, DEFAULT_PROCESSED_EVENTS_TABLE, DEFAULT_SCHEDULER_RUNS_TABLE, OUTBOX_EXCHANGES, SCHEDULER_RUN_STATUSES } from './table-names.js';
3
+ import { char, datetime, index, int, json, mysqlEnum, mysqlTable, uniqueIndex, varchar } from 'drizzle-orm/mysql-core';
4
+ /**
5
+ * Drizzle definitions of the infrastructure tables every service may own. Each matches the Knex
6
+ * helper of the same name in `@heavybit/shared-lib/knex` (`outboxColumns`, `processedEventsColumns`,
7
+ * `schedulerRunsColumns`); a test keeps the two in step. Pass a custom name when a service needs one.
8
+ */
9
+ const ms = (name) => datetime(name, { mode: 'date', fsp: 3 });
10
+ const createdNow = (name) => ms(name).notNull().default(sql `CURRENT_TIMESTAMP(3)`);
11
+ export { DEFAULT_OUTBOX_TABLE, DEFAULT_PROCESSED_EVENTS_TABLE, DEFAULT_SCHEDULER_RUNS_TABLE, OUTBOX_EXCHANGES, SCHEDULER_RUN_STATUSES };
12
+ /** Transactional outbox (`event_outbox` by default): domain change and message in one transaction. */
13
+ export function outboxTable(name = DEFAULT_OUTBOX_TABLE) {
14
+ return mysqlTable(name, {
15
+ id: char('id', { length: 26 }).primaryKey(),
16
+ routingKey: varchar('routing_key', { length: 191 }).notNull(),
17
+ /** Logical exchange: `events` (topic fan-out) or `commands` (direct, one owner). */
18
+ exchange: mysqlEnum('exchange', OUTBOX_EXCHANGES).notNull().default('events'),
19
+ payload: json('payload').notNull(),
20
+ /** Correlation id of the request that staged the row; the relay sends it as `x-correlation-id`. */
21
+ correlationId: varchar('correlation_id', { length: 64 }),
22
+ attempts: int('attempts', { unsigned: true }).notNull().default(0),
23
+ lastError: varchar('last_error', { length: 500 }),
24
+ createdAt: createdNow('created_at'),
25
+ publishedAt: ms('published_at'),
26
+ }, (t) => [index(`${name}_published_at_id_index`).on(t.publishedAt, t.id)]);
27
+ }
28
+ /** Consumer idempotency ledger: one row per (consumer, event id). */
29
+ export function processedEventsTable(name = DEFAULT_PROCESSED_EVENTS_TABLE) {
30
+ return mysqlTable(name, {
31
+ id: char('id', { length: 26 }).primaryKey(),
32
+ consumer: varchar('consumer', { length: 191 }).notNull(),
33
+ eventId: varchar('event_id', { length: 64 }).notNull(),
34
+ processedAt: createdNow('processed_at'),
35
+ }, (t) => [
36
+ uniqueIndex(`${name}_consumer_event_id_unique`).on(t.consumer, t.eventId),
37
+ index(`${name}_processed_at_index`).on(t.processedAt),
38
+ ]);
39
+ }
40
+ /** Scheduled-job runs: one row per (job, run key), so a run is never executed twice. */
41
+ export function schedulerRunsTable(name = DEFAULT_SCHEDULER_RUNS_TABLE) {
42
+ return mysqlTable(name, {
43
+ id: char('id', { length: 26 }).primaryKey(),
44
+ job: varchar('job', { length: 191 }).notNull(),
45
+ runKey: varchar('run_key', { length: 191 }).notNull(),
46
+ status: mysqlEnum('status', SCHEDULER_RUN_STATUSES).notNull().default('running'),
47
+ error: varchar('error', { length: 500 }),
48
+ startedAt: createdNow('started_at'),
49
+ finishedAt: ms('finished_at'),
50
+ }, (t) => [
51
+ uniqueIndex(`${name}_job_run_key_unique`).on(t.job, t.runKey),
52
+ index(`${name}_job_started_at_index`).on(t.job, t.startedAt),
53
+ ]);
54
+ }
55
+ /** `event_outbox` with the default name. */
56
+ export const outbox = outboxTable();
57
+ /** `processed_events` with the default name. */
58
+ export const processedEvents = processedEventsTable();
59
+ /** `scheduler_runs` with the default name. */
60
+ export const schedulerRuns = schedulerRunsTable();
61
+ //# sourceMappingURL=tables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tables.js","sourceRoot":"","sources":["../../../src/database/tables.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,8BAA8B,EAAE,4BAA4B,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAChK,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEvH;;;;GAIG;AAEH,MAAM,EAAE,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;AACtE,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA,sBAAsB,CAAC,CAAC;AAE3F,OAAO,EAAE,oBAAoB,EAAE,8BAA8B,EAAE,4BAA4B,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,CAAC;AASxI,sGAAsG;AACtG,MAAM,UAAU,WAAW,CAAC,IAAI,GAAG,oBAAoB;IACrD,OAAO,UAAU,CAAC,IAAI,EAAE;QACtB,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,UAAU,EAAE;QAC3C,UAAU,EAAE,OAAO,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE;QAC7D,oFAAoF;QACpF,QAAQ,EAAE,SAAS,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC;QAC7E,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE;QAClC,mGAAmG;QACnG,aAAa,EAAE,OAAO,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACxD,QAAQ,EAAE,GAAG,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QAClE,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;QACjD,SAAS,EAAE,UAAU,CAAC,YAAY,CAAC;QACnC,WAAW,EAAE,EAAE,CAAC,cAAc,CAAC;KAChC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,oBAAoB,CAAC,IAAI,GAAG,8BAA8B;IACxE,OAAO,UAAU,CAAC,IAAI,EAAE;QACtB,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,UAAU,EAAE;QAC3C,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE;QACxD,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE;QACtD,WAAW,EAAE,UAAU,CAAC,cAAc,CAAC;KACxC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QACR,WAAW,CAAC,GAAG,IAAI,2BAA2B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC;QACzE,KAAK,CAAC,GAAG,IAAI,qBAAqB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;KACtD,CAAC,CAAC;AACL,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,kBAAkB,CAAC,IAAI,GAAG,4BAA4B;IACpE,OAAO,UAAU,CAAC,IAAI,EAAE;QACtB,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,UAAU,EAAE;QAC3C,GAAG,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE;QAC9C,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE;QACrD,MAAM,EAAE,SAAS,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;QAChF,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;QACxC,SAAS,EAAE,UAAU,CAAC,YAAY,CAAC;QACnC,UAAU,EAAE,EAAE,CAAC,aAAa,CAAC;KAC9B,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QACR,WAAW,CAAC,GAAG,IAAI,qBAAqB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC;QAC7D,KAAK,CAAC,GAAG,IAAI,uBAAuB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,SAAS,CAAC;KAC7D,CAAC,CAAC;AACL,CAAC;AAED,4CAA4C;AAC5C,MAAM,CAAC,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;AACpC,gDAAgD;AAChD,MAAM,CAAC,MAAM,eAAe,GAAG,oBAAoB,EAAE,CAAC;AACtD,8CAA8C;AAC9C,MAAM,CAAC,MAAM,aAAa,GAAG,kBAAkB,EAAE,CAAC"}
@@ -1,57 +1,77 @@
1
1
  import { hasAllPermissions, hasPermission, hasRole } from '../access/index.js';
2
- import { safeEqual } from '../common/crypto.js';
3
2
  import { errorBody } from '../common/response.js';
4
3
  import { correlationId } from './middleware.js';
5
- import { CONTEXT_HEADERS, verifyIdentityHeaders } from '../identity/index.js';
6
- function resolveIdentity(req, options) {
7
- const result = verifyIdentityHeaders(req.headers, options.secret, { maxSkewMs: options.maxSkewMs });
8
- if (result.status === 'authenticated') {
9
- req.user = result.user;
10
- return 'ok';
11
- }
12
- if (result.status === 'invalid') {
13
- options.logger?.warn('Rejected forged or stale gateway identity', { reason: result.reason, path: req.path });
14
- return 'invalid';
15
- }
16
- return 'anonymous';
4
+ import { updateRequestContext } from '../context/index.js';
5
+ import { assertGatewaySecret, canonicalPath, verifyGatewayIdentity, } from '../identity/index.js';
6
+ /** Collapses the user's scope id lists into the request context's `key → id` map (lists are comma-joined). */
7
+ function contextScopes(user) {
8
+ return Object.fromEntries(Object.entries(user.scopes).filter(([, ids]) => ids.length).map(([key, ids]) => [key, ids.join(',')]));
17
9
  }
10
+ function createResolver(options) {
11
+ const secret = assertGatewaySecret(options.secret ?? process.env.GATEWAY_SIGNING_SECRET);
12
+ const reject = (req, reason) => {
13
+ const event = { reason, method: req.method, path: canonicalPath(req.originalUrl), requestId: correlationId(req) };
14
+ options.logger?.warn('Rejected gateway identity', { reason, method: event.method, path: event.path });
15
+ if (!options.onRejected)
16
+ return;
17
+ Promise.resolve()
18
+ .then(() => options.onRejected?.(event, req))
19
+ .catch((error) => options.logger?.error('Identity onRejected hook failed', { error: error.message }));
20
+ };
21
+ return (req) => {
22
+ const result = verifyGatewayIdentity({
23
+ headers: req.headers, method: req.method, path: req.originalUrl, secret, protocol: options.protocol,
24
+ maxAgeMs: options.maxAgeMs, maxFutureMs: options.maxFutureMs,
25
+ });
26
+ if (result.status === 'authenticated') {
27
+ req.user = result.user;
28
+ updateRequestContext({ userId: result.user.id, scopes: contextScopes(result.user) });
29
+ return 'ok';
30
+ }
31
+ if (result.status === 'invalid')
32
+ reject(req, result.reason);
33
+ return result.status === 'invalid' ? 'invalid' : 'anonymous';
34
+ };
35
+ }
36
+ const unauthenticated = (req, res, message = 'Authentication required') => res.status(401).json(errorBody('UNAUTHENTICATED', message, { requestId: correlationId(req) }));
18
37
  /**
19
- * Requires a valid gateway-signed identity and sets `req.user`; 401 UNAUTHENTICATED (with `requestId`) otherwise.
38
+ * Requires a valid gateway-signed (v2) identity and sets `req.user`; 401 UNAUTHENTICATED (with `requestId`)
39
+ * otherwise. Also fills the request context's `userId` and `scopes` so log lines carry them.
40
+ * Throws at startup when the secret is missing or shorter than 32 characters.
20
41
  *
21
- * @param options Secret, skew window and logger.
42
+ * @param options Protocol, secret, replay window, logger and rejection hook.
22
43
  * @returns Express middleware.
23
- * @example router.use(authenticateFromGateway({ secret: config.gatewaySecret, logger }));
44
+ * @example router.use(authenticateFromGateway({ protocol, logger, onRejected: publishSecurityEvent }));
24
45
  */
25
46
  export function authenticateFromGateway(options) {
47
+ const resolve = createResolver(options);
26
48
  return (req, res, next) => {
27
- if (resolveIdentity(req, options) === 'ok')
49
+ if (resolve(req) === 'ok')
28
50
  return next();
29
- res.status(401).json(errorBody('UNAUTHENTICATED', 'Authentication required', { requestId: correlationId(req) }));
51
+ unauthenticated(req, res);
30
52
  };
31
53
  }
32
54
  /**
33
- * Attaches `req.user` when a valid identity is present and continues anonymously when none is sent.
34
- * A forged or stale identity is still rejected with 401, never downgraded to anonymous.
55
+ * Attaches `req.user` when a valid identity is present and continues anonymously when none is sent,
56
+ * for public routes that personalise. A forged or stale identity is still rejected with 401, never
57
+ * downgraded to anonymous.
35
58
  *
36
- * @param options Secret, skew window and logger.
59
+ * @param options Same as {@link authenticateFromGateway}.
37
60
  * @returns Express middleware.
38
- * @example router.get('/products', optionalAuthFromGateway({ secret }), controller.list);
61
+ * @example router.get('/items', optionalAuthFromGateway({ protocol }), controller.list);
39
62
  */
40
63
  export function optionalAuthFromGateway(options) {
64
+ const resolve = createResolver(options);
41
65
  return (req, res, next) => {
42
- if (resolveIdentity(req, options) === 'invalid') {
43
- res.status(401).json(errorBody('UNAUTHENTICATED', 'Invalid identity', { requestId: correlationId(req) }));
44
- return;
45
- }
66
+ if (resolve(req) === 'invalid')
67
+ return unauthenticated(req, res, 'Invalid identity');
46
68
  next();
47
69
  };
48
70
  }
49
71
  function guard(check, message = 'You do not have permission to perform this action') {
50
72
  return (req, res, next) => {
51
- if (!req.user) {
52
- res.status(401).json(errorBody('UNAUTHENTICATED', 'Authentication required', { requestId: correlationId(req) }));
53
- return;
54
- }
73
+ if (!req.user)
74
+ return unauthenticated(req, res);
55
75
  if (!check(req.user)) {
56
76
  res.status(403).json(errorBody('FORBIDDEN', message, { requestId: correlationId(req) }));
57
77
  return;
@@ -61,36 +81,30 @@ function guard(check, message = 'You do not have permission to perform this acti
61
81
  }
62
82
  /**
63
83
  * Allows callers holding any of `permissions` (401 without identity, 403 FORBIDDEN otherwise).
84
+ * A super admin passes every permission guard.
64
85
  *
65
86
  * @example router.post('/refunds', requirePermission('refunds.create'), controller.create);
66
87
  */
67
88
  export const requirePermission = (...permissions) => guard((u) => hasPermission(u, ...permissions));
68
89
  /**
69
- * Allows callers holding every one of `permissions`.
90
+ * Allows callers holding every one of `permissions`. Accepts a list or rest arguments.
70
91
  *
71
92
  * @example router.delete('/x/:id', requireAllPermissions('x.read', 'x.delete'), controller.remove);
72
93
  */
73
- export const requireAllPermissions = (...permissions) => guard((u) => hasAllPermissions(u, ...permissions));
94
+ export const requireAllPermissions = (...permissions) => {
95
+ const required = permissions.flat();
96
+ return guard((u) => hasAllPermissions(u, ...required));
97
+ };
74
98
  /**
75
- * Allows callers with any of `roles`. Prefer permissions; roles are for coarse gates only.
99
+ * Allows callers whose session passed the one-time-code (second factor) check; 403 FORBIDDEN otherwise.
76
100
  *
77
- * @example router.use('/ops', requireRole('platform_admin'));
101
+ * @example router.post('/security/settings', requireOtpVerified(), controller.update);
78
102
  */
79
- export const requireRole = (...roles) => guard((u) => hasRole(u, ...roles), 'Insufficient role');
103
+ export const requireOtpVerified = () => guard((u) => u.otpVerified === true, 'One-time code verification is required');
80
104
  /**
81
- * Guards `/internal/*` routes: requires the service secret header (constant-time compare);
82
- * 401 UNAUTHENTICATED with `requestId` otherwise.
105
+ * Allows callers with any of `roles`. Prefer permissions; roles are for coarse gates only.
83
106
  *
84
- * @param secret The expected `x-internal-service-secret`; an empty secret rejects every call (fail closed).
85
- * @returns Express middleware.
86
- * @example router.use('/internal', requireInternalServiceSecret(config.internalSecret));
107
+ * @example router.use('/ops', requireRole('platform_admin'));
87
108
  */
88
- export function requireInternalServiceSecret(secret) {
89
- return (req, res, next) => {
90
- const provided = req.headers[CONTEXT_HEADERS.INTERNAL_SECRET];
91
- if (typeof provided === 'string' && secret && safeEqual(provided, secret))
92
- return next();
93
- res.status(401).json(errorBody('UNAUTHENTICATED', 'Invalid internal service credentials', { requestId: correlationId(req) }));
94
- };
95
- }
109
+ export const requireRole = (...roles) => guard((u) => hasRole(u, ...roles), 'Insufficient role');
96
110
  //# sourceMappingURL=auth.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/express/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/express/auth.ts"],"names":[],"mappings":"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"}
@@ -3,4 +3,6 @@ export * from './middleware.js';
3
3
  export * from './health.js';
4
4
  export * from './security.js';
5
5
  export * from './respond.js';
6
+ export * from './step-up.js';
7
+ export * from './internal-caller.js';
6
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/express/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/express/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { errorBody } from '../common/response.js';
2
+ import { internalServiceAuthConfigFromEnv, verifyInternalCaller } from '../common/internal-service-auth.js';
3
+ import { canonicalPath } from '../identity/index.js';
4
+ import { correlationId } from './middleware.js';
5
+ const isUnderPrefix = (path, prefix) => path === prefix || path.startsWith(`${prefix}/`);
6
+ /**
7
+ * Builds the internal-caller guard for a service, bound to its internal path prefix and accepted credentials.
8
+ *
9
+ * @param options Path prefix, credentials and logger.
10
+ * @returns `{ requireInternalCaller }`.
11
+ * @throws Error when the prefix is not an absolute path; ConfigError when env credentials are malformed.
12
+ * @example
13
+ * const { requireInternalCaller } = createInternalCallerGuards({ pathPrefix: '/internal', logger });
14
+ * router.get('/internal/records/:id', requireInternalCaller(['alpha-service']), controller.get);
15
+ */
16
+ export function createInternalCallerGuards(options) {
17
+ const prefix = options.pathPrefix.replace(/\/+$/, '');
18
+ if (!prefix.startsWith('/'))
19
+ throw new Error('createInternalCallerGuards: pathPrefix must be an absolute path such as /internal');
20
+ const credentials = options.credentials ?? internalServiceAuthConfigFromEnv().credentials;
21
+ return {
22
+ requireInternalCaller(allowed) {
23
+ if (!allowed.length)
24
+ throw new Error('requireInternalCaller: list at least one caller');
25
+ const callers = [...allowed];
26
+ return (req, res, next) => {
27
+ const path = canonicalPath(req.originalUrl);
28
+ const requestId = correlationId(req);
29
+ if (!isUnderPrefix(path, prefix)) {
30
+ options.logger?.warn('Internal guard outside the internal prefix', { path });
31
+ res.status(403).json(errorBody('FORBIDDEN', 'Not an internal route', { requestId }));
32
+ return;
33
+ }
34
+ const verdict = verifyInternalCaller({ headers: req.headers, credentials, allowed: callers });
35
+ if (verdict.ok) {
36
+ req.internalCaller = verdict.caller;
37
+ return next();
38
+ }
39
+ options.logger?.warn('Rejected internal caller', { reason: verdict.reason, caller: verdict.caller, path });
40
+ if (verdict.status === 401) {
41
+ res.status(401).json(errorBody('UNAUTHENTICATED', 'Invalid internal service credentials', { requestId }));
42
+ return;
43
+ }
44
+ res.status(403).json(errorBody('FORBIDDEN', 'This service may not call this route', { requestId }));
45
+ };
46
+ },
47
+ };
48
+ }
49
+ //# sourceMappingURL=internal-caller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal-caller.js","sourceRoot":"","sources":["../../../src/express/internal-caller.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,gCAAgC,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC5G,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAkChD,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,MAAc,EAAW,EAAE,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC;AAElH;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CAAC,OAAmC;IAC5E,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mFAAmF,CAAC,CAAC;IAClI,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,gCAAgC,EAAE,CAAC,WAAW,CAAC;IAE1F,OAAO;QACL,qBAAqB,CAAC,OAAO;YAC3B,IAAI,CAAC,OAAO,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;YACxF,MAAM,OAAO,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC;YAC7B,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;gBACzD,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;gBAC5C,MAAM,SAAS,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;gBACrC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;oBACjC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,4CAA4C,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;oBAC7E,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,uBAAuB,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;oBACrF,OAAO;gBACT,CAAC;gBACD,MAAM,OAAO,GAAG,oBAAoB,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;gBAC9F,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;oBACf,GAAG,CAAC,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;oBACpC,OAAO,IAAI,EAAE,CAAC;gBAChB,CAAC;gBACD,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,0BAA0B,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC3G,IAAI,OAAO,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBAC3B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,iBAAiB,EAAE,sCAAsC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;oBAC1G,OAAO;gBACT,CAAC;gBACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,sCAAsC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YACtG,CAAC,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { errorBody } from '../common/response.js';
2
+ import { DEFAULT_STEP_UP_WINDOW_MS, STEP_UP_REQUIRED_CODE, stepUpStatus, } from '../identity/step-up.js';
3
+ import { correlationId } from './middleware.js';
4
+ /**
5
+ * Builds the step-up guard for an app's catalogue. Must run after `authenticateFromGateway`, which sets
6
+ * `req.user.stepUpAt` only from the signed `x-step-up-at` header. Single-use proofs are consumed by the
7
+ * gateway; the service sees only the verified time. Throws at startup for an unknown scope or a bad window.
8
+ *
9
+ * @param options Catalogue, freshness window and clock.
10
+ * @returns `requireStepUp(scope, route?)` and `declaredStepUpRoutes()`.
11
+ * @example
12
+ * const { requireStepUp } = createStepUpGuards({ catalogue: stepUpScopes });
13
+ * router.post('/refunds/:id', requirePermission('refunds.create'), requireStepUp('refund-large', 'POST /refunds/:id'), controller.refund);
14
+ */
15
+ export function createStepUpGuards(options) {
16
+ const windowMs = options.windowMs ?? DEFAULT_STEP_UP_WINDOW_MS;
17
+ if (!Number.isFinite(windowMs) || windowMs <= 0)
18
+ throw new Error(`createStepUpGuards: windowMs must be positive (got ${windowMs})`);
19
+ const now = options.now ?? Date.now;
20
+ const declared = [];
21
+ const requireStepUp = (scope, route) => {
22
+ const rules = options.catalogue[scope];
23
+ if (!rules)
24
+ throw new Error(`requireStepUp: unknown step-up scope "${scope}"`);
25
+ declared.push({ scope, singleUse: rules.singleUse === true, ...(route ? { route } : {}) });
26
+ return (req, res, next) => {
27
+ if (!req.user) {
28
+ res.status(401).json(errorBody('UNAUTHENTICATED', 'Authentication required', { requestId: correlationId(req) }));
29
+ return;
30
+ }
31
+ if (stepUpStatus(req.user.stepUpAt, windowMs, now()) === 'fresh')
32
+ return next();
33
+ res.status(403).json({ ...errorBody(STEP_UP_REQUIRED_CODE, 'Please confirm it is you to continue', { requestId: correlationId(req) }), scope });
34
+ };
35
+ };
36
+ return { requireStepUp, declaredStepUpRoutes: () => declared.map((entry) => ({ ...entry })) };
37
+ }
38
+ //# sourceMappingURL=step-up.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-up.js","sourceRoot":"","sources":["../../../src/express/step-up.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EACL,yBAAyB,EAAE,qBAAqB,EAAE,YAAY,GAC/D,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA4BhD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAmB,OAA8B;IACjF,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,yBAAyB,CAAC;IAC/D,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,sDAAsD,QAAQ,GAAG,CAAC,CAAC;IACpI,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,MAAM,QAAQ,GAAkC,EAAE,CAAC;IAEnD,MAAM,aAAa,GAAG,CAAC,KAAQ,EAAE,KAAc,EAAkB,EAAE;QACjE,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,KAAK,GAAG,CAAC,CAAC;QAC/E,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,KAAK,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3F,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;YACzD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;gBACd,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,iBAAiB,EAAE,yBAAyB,EAAE,EAAE,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;gBACjH,OAAO;YACT,CAAC;YACD,IAAI,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,OAAO;gBAAE,OAAO,IAAI,EAAE,CAAC;YAChF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,SAAS,CAAC,qBAAqB,EAAE,sCAAsC,EAAE,EAAE,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAClJ,CAAC,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;AAChG,CAAC"}
@@ -1,73 +1,6 @@
1
- import { AppError, ServiceUnavailableError } from '../common/errors.js';
2
- import { sleep } from '../common/async.js';
3
- import { CONTEXT_HEADERS } from '../identity/index.js';
4
- import { silentLogger } from '../logging/index.js';
5
- export * from './safe-fetch.js';
6
- const RETRYABLE_STATUS = new Set([502, 503, 504]);
7
- const IDEMPOTENT = new Set(['GET', 'PUT', 'DELETE']);
8
1
  /**
9
- * Typed client for `/internal/*` calls between services. Unwraps the `{ success, data }`
10
- * envelope, maps upstream errors to AppErrors with the same status, and turns network failures
11
- * and timeouts into 503s.
2
+ * Outbound HTTP helpers. Service-to-service calls use `createInternalClient` (root export); calls to
3
+ * tenant-supplied URLs go through the SSRF-guarded {@link createSafeFetcher}.
12
4
  */
13
- export function createServiceClient(options) {
14
- const logger = options.logger ?? silentLogger;
15
- const base = options.baseUrl.replace(/\/+$/, '');
16
- async function request(method, path, opts = {}) {
17
- const url = new URL(base + path);
18
- for (const [key, value] of Object.entries(opts.query ?? {}))
19
- if (value !== undefined)
20
- url.searchParams.set(key, String(value));
21
- const retries = IDEMPOTENT.has(method) ? options.retries ?? 2 : 0;
22
- for (let attempt = 0;; attempt += 1) {
23
- const controller = new AbortController();
24
- const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? options.timeoutMs ?? 5000);
25
- try {
26
- const response = await fetch(url, {
27
- method,
28
- signal: controller.signal,
29
- headers: {
30
- accept: 'application/json',
31
- ...(opts.body !== undefined ? { 'content-type': 'application/json' } : {}),
32
- [CONTEXT_HEADERS.INTERNAL_SECRET]: options.internalSecret,
33
- [CONTEXT_HEADERS.CALLER_SERVICE]: options.callerService,
34
- ...(opts.correlationId ? { [CONTEXT_HEADERS.CORRELATION_ID]: opts.correlationId } : {}),
35
- ...opts.headers,
36
- },
37
- body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,
38
- });
39
- if (RETRYABLE_STATUS.has(response.status) && attempt < retries) {
40
- await sleep(200 * 2 ** attempt);
41
- continue;
42
- }
43
- const text = await response.text();
44
- const payload = text ? JSON.parse(text) : { success: response.ok, message: '' };
45
- if (!response.ok) {
46
- throw new AppError(response.status, payload.message || `Upstream error ${response.status}`, { code: payload.code, errors: payload.errors });
47
- }
48
- return (payload.data ?? payload);
49
- }
50
- catch (error) {
51
- if (error instanceof AppError)
52
- throw error;
53
- if (attempt < retries) {
54
- await sleep(200 * 2 ** attempt);
55
- continue;
56
- }
57
- logger.warn('Internal call failed', { method, url: url.pathname, error: error.message });
58
- throw new ServiceUnavailableError('Upstream service unavailable', { cause: error });
59
- }
60
- finally {
61
- clearTimeout(timer);
62
- }
63
- }
64
- }
65
- return {
66
- get: (path, opts) => request('GET', path, opts),
67
- post: (path, opts) => request('POST', path, opts),
68
- put: (path, opts) => request('PUT', path, opts),
69
- patch: (path, opts) => request('PATCH', path, opts),
70
- delete: (path, opts) => request('DELETE', path, opts),
71
- };
72
- }
5
+ export * from './safe-fetch.js';
73
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/http/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/http/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,iBAAiB,CAAC"}