@beignet/core 0.0.2 → 0.0.4

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 (360) hide show
  1. package/CHANGELOG.md +173 -0
  2. package/README.md +821 -30
  3. package/dist/application/index.d.ts +28 -2
  4. package/dist/application/index.d.ts.map +1 -1
  5. package/dist/application/index.js +140 -12
  6. package/dist/application/index.js.map +1 -1
  7. package/dist/client/client.d.ts +2 -2
  8. package/dist/client/client.d.ts.map +1 -1
  9. package/dist/client/client.js +136 -48
  10. package/dist/client/client.js.map +1 -1
  11. package/dist/client/error-messages.d.ts +14 -0
  12. package/dist/client/error-messages.d.ts.map +1 -0
  13. package/dist/client/error-messages.js +23 -0
  14. package/dist/client/error-messages.js.map +1 -0
  15. package/dist/client/index.d.ts +8 -4
  16. package/dist/client/index.d.ts.map +1 -1
  17. package/dist/client/index.js +6 -2
  18. package/dist/client/index.js.map +1 -1
  19. package/dist/client/types.d.ts +35 -5
  20. package/dist/client/types.d.ts.map +1 -1
  21. package/dist/client-only.d.ts +8 -0
  22. package/dist/client-only.d.ts.map +1 -0
  23. package/dist/client-only.js +8 -0
  24. package/dist/client-only.js.map +1 -0
  25. package/dist/config/index.d.ts +5 -5
  26. package/dist/config/index.d.ts.map +1 -1
  27. package/dist/config/index.js +2 -2
  28. package/dist/config/index.js.map +1 -1
  29. package/dist/contracts/catalog-errors.d.ts +27 -0
  30. package/dist/contracts/catalog-errors.d.ts.map +1 -0
  31. package/dist/contracts/catalog-errors.js +69 -0
  32. package/dist/contracts/catalog-errors.js.map +1 -0
  33. package/dist/contracts/contract-builder.d.ts +15 -12
  34. package/dist/contracts/contract-builder.d.ts.map +1 -1
  35. package/dist/contracts/contract-builder.js +15 -41
  36. package/dist/contracts/contract-builder.js.map +1 -1
  37. package/dist/contracts/contract-group.d.ts +11 -8
  38. package/dist/contracts/contract-group.d.ts.map +1 -1
  39. package/dist/contracts/contract-group.js +13 -40
  40. package/dist/contracts/contract-group.js.map +1 -1
  41. package/dist/contracts/contract-like.d.ts +1 -1
  42. package/dist/contracts/contract-like.d.ts.map +1 -1
  43. package/dist/contracts/index.d.ts +13 -9
  44. package/dist/contracts/index.d.ts.map +1 -1
  45. package/dist/contracts/index.js +9 -5
  46. package/dist/contracts/index.js.map +1 -1
  47. package/dist/contracts/openapi-meta.d.ts +48 -0
  48. package/dist/contracts/openapi-meta.d.ts.map +1 -1
  49. package/dist/contracts/openapi-meta.js +3 -0
  50. package/dist/contracts/openapi-meta.js.map +1 -1
  51. package/dist/contracts/path-template.d.ts +1 -1
  52. package/dist/contracts/path-template.js +2 -2
  53. package/dist/contracts/path-template.js.map +1 -1
  54. package/dist/contracts/schema-shape.d.ts +37 -0
  55. package/dist/contracts/schema-shape.d.ts.map +1 -0
  56. package/dist/contracts/schema-shape.js +61 -0
  57. package/dist/contracts/schema-shape.js.map +1 -0
  58. package/dist/contracts/success-status.d.ts +32 -0
  59. package/dist/contracts/success-status.d.ts.map +1 -0
  60. package/dist/contracts/success-status.js +18 -0
  61. package/dist/contracts/success-status.js.map +1 -0
  62. package/dist/contracts/types.d.ts +25 -5
  63. package/dist/contracts/types.d.ts.map +1 -1
  64. package/dist/contracts/types.js.map +1 -1
  65. package/dist/contracts/utils.d.ts +1 -1
  66. package/dist/contracts/utils.d.ts.map +1 -1
  67. package/dist/contracts/utils.js +1 -1
  68. package/dist/contracts/utils.js.map +1 -1
  69. package/dist/domain/events.d.ts +1 -1
  70. package/dist/domain/events.d.ts.map +1 -1
  71. package/dist/domain/events.js +1 -1
  72. package/dist/domain/events.js.map +1 -1
  73. package/dist/domain/index.d.ts +3 -3
  74. package/dist/domain/index.d.ts.map +1 -1
  75. package/dist/domain/index.js +3 -3
  76. package/dist/domain/index.js.map +1 -1
  77. package/dist/errors/catalog.d.ts +9 -1
  78. package/dist/errors/catalog.d.ts.map +1 -1
  79. package/dist/errors/catalog.js +7 -1
  80. package/dist/errors/catalog.js.map +1 -1
  81. package/dist/errors/http.d.ts +10 -0
  82. package/dist/errors/http.d.ts.map +1 -1
  83. package/dist/errors/http.js +11 -1
  84. package/dist/errors/http.js.map +1 -1
  85. package/dist/errors/index.d.ts +4 -4
  86. package/dist/errors/index.d.ts.map +1 -1
  87. package/dist/errors/index.js +4 -4
  88. package/dist/errors/index.js.map +1 -1
  89. package/dist/errors/response.d.ts +4 -1
  90. package/dist/errors/response.d.ts.map +1 -1
  91. package/dist/errors/response.js.map +1 -1
  92. package/dist/events/index.d.ts +10 -12
  93. package/dist/events/index.d.ts.map +1 -1
  94. package/dist/events/index.js +10 -10
  95. package/dist/events/index.js.map +1 -1
  96. package/dist/idempotency/index.d.ts +5 -3
  97. package/dist/idempotency/index.d.ts.map +1 -1
  98. package/dist/idempotency/index.js.map +1 -1
  99. package/dist/jobs/index.d.ts +148 -16
  100. package/dist/jobs/index.d.ts.map +1 -1
  101. package/dist/jobs/index.js +174 -14
  102. package/dist/jobs/index.js.map +1 -1
  103. package/dist/notifications/index.d.ts +14 -16
  104. package/dist/notifications/index.d.ts.map +1 -1
  105. package/dist/notifications/index.js +14 -14
  106. package/dist/notifications/index.js.map +1 -1
  107. package/dist/openapi/index.d.ts +8 -3
  108. package/dist/openapi/index.d.ts.map +1 -1
  109. package/dist/openapi/index.js +41 -29
  110. package/dist/openapi/index.js.map +1 -1
  111. package/dist/openapi/schema-introspector.d.ts +37 -0
  112. package/dist/openapi/schema-introspector.d.ts.map +1 -1
  113. package/dist/openapi/schema-introspector.js +23 -17
  114. package/dist/openapi/schema-introspector.js.map +1 -1
  115. package/dist/outbox/index.d.ts +18 -4
  116. package/dist/outbox/index.d.ts.map +1 -1
  117. package/dist/outbox/index.js +104 -4
  118. package/dist/outbox/index.js.map +1 -1
  119. package/dist/ports/audit.d.ts +56 -10
  120. package/dist/ports/audit.d.ts.map +1 -1
  121. package/dist/ports/audit.js +71 -3
  122. package/dist/ports/audit.js.map +1 -1
  123. package/dist/ports/auth.d.ts +92 -0
  124. package/dist/ports/auth.d.ts.map +1 -1
  125. package/dist/ports/auth.js +92 -0
  126. package/dist/ports/auth.js.map +1 -1
  127. package/dist/ports/events.d.ts +2 -2
  128. package/dist/ports/events.d.ts.map +1 -1
  129. package/dist/ports/index.d.ts +62 -33
  130. package/dist/ports/index.d.ts.map +1 -1
  131. package/dist/ports/index.js +28 -34
  132. package/dist/ports/index.js.map +1 -1
  133. package/dist/ports/policy.d.ts +32 -3
  134. package/dist/ports/policy.d.ts.map +1 -1
  135. package/dist/ports/policy.js +13 -2
  136. package/dist/ports/policy.js.map +1 -1
  137. package/dist/ports/testing.d.ts +1030 -2
  138. package/dist/ports/testing.d.ts.map +1 -1
  139. package/dist/ports/testing.js +1031 -1
  140. package/dist/ports/testing.js.map +1 -1
  141. package/dist/ports/unbound.d.ts +21 -0
  142. package/dist/ports/unbound.d.ts.map +1 -0
  143. package/dist/ports/unbound.js +57 -0
  144. package/dist/ports/unbound.js.map +1 -0
  145. package/dist/ports/unit-of-work.d.ts +1 -1
  146. package/dist/ports/unit-of-work.d.ts.map +1 -1
  147. package/dist/ports/unit-of-work.js +1 -1
  148. package/dist/ports/unit-of-work.js.map +1 -1
  149. package/dist/providers/index.d.ts +3 -2
  150. package/dist/providers/index.d.ts.map +1 -1
  151. package/dist/providers/index.js +3 -2
  152. package/dist/providers/index.js.map +1 -1
  153. package/dist/providers/instrumentation.d.ts +46 -5
  154. package/dist/providers/instrumentation.d.ts.map +1 -1
  155. package/dist/providers/instrumentation.js +25 -6
  156. package/dist/providers/instrumentation.js.map +1 -1
  157. package/dist/providers/metadata.d.ts +39 -0
  158. package/dist/providers/metadata.d.ts.map +1 -0
  159. package/dist/providers/metadata.js +169 -0
  160. package/dist/providers/metadata.js.map +1 -0
  161. package/dist/providers/provider.d.ts +114 -9
  162. package/dist/providers/provider.d.ts.map +1 -1
  163. package/dist/providers/provider.js +3 -20
  164. package/dist/providers/provider.js.map +1 -1
  165. package/dist/schedules/index.d.ts +94 -13
  166. package/dist/schedules/index.d.ts.map +1 -1
  167. package/dist/schedules/index.js +66 -12
  168. package/dist/schedules/index.js.map +1 -1
  169. package/dist/server/audit-context.d.ts +29 -0
  170. package/dist/server/audit-context.d.ts.map +1 -0
  171. package/dist/server/audit-context.js +44 -0
  172. package/dist/server/audit-context.js.map +1 -0
  173. package/dist/server/context.d.ts +141 -0
  174. package/dist/server/context.d.ts.map +1 -0
  175. package/dist/server/context.js +39 -0
  176. package/dist/server/context.js.map +1 -0
  177. package/dist/server/contract-like.d.ts +1 -1
  178. package/dist/server/contract-like.d.ts.map +1 -1
  179. package/dist/server/contract-like.js +1 -1
  180. package/dist/server/contract-like.js.map +1 -1
  181. package/dist/server/health.d.ts +2 -2
  182. package/dist/server/health.d.ts.map +1 -1
  183. package/dist/server/hooks/auth.d.ts +89 -65
  184. package/dist/server/hooks/auth.d.ts.map +1 -1
  185. package/dist/server/hooks/auth.js +84 -55
  186. package/dist/server/hooks/auth.js.map +1 -1
  187. package/dist/server/hooks/cors.d.ts +1 -1
  188. package/dist/server/hooks/cors.d.ts.map +1 -1
  189. package/dist/server/hooks/errors.d.ts +2 -2
  190. package/dist/server/hooks/errors.d.ts.map +1 -1
  191. package/dist/server/hooks/errors.js +2 -2
  192. package/dist/server/hooks/errors.js.map +1 -1
  193. package/dist/server/hooks/idempotency.d.ts +78 -0
  194. package/dist/server/hooks/idempotency.d.ts.map +1 -0
  195. package/dist/server/hooks/idempotency.js +154 -0
  196. package/dist/server/hooks/idempotency.js.map +1 -0
  197. package/dist/server/hooks/index.d.ts +8 -7
  198. package/dist/server/hooks/index.d.ts.map +1 -1
  199. package/dist/server/hooks/index.js +6 -5
  200. package/dist/server/hooks/index.js.map +1 -1
  201. package/dist/server/hooks/logging.d.ts +2 -2
  202. package/dist/server/hooks/logging.d.ts.map +1 -1
  203. package/dist/server/hooks/logging.js +1 -1
  204. package/dist/server/hooks/logging.js.map +1 -1
  205. package/dist/server/hooks/rate-limit.d.ts +25 -7
  206. package/dist/server/hooks/rate-limit.d.ts.map +1 -1
  207. package/dist/server/hooks/rate-limit.js +47 -12
  208. package/dist/server/hooks/rate-limit.js.map +1 -1
  209. package/dist/server/hooks.d.ts +1 -1
  210. package/dist/server/hooks.d.ts.map +1 -1
  211. package/dist/server/hooks.js +1 -1
  212. package/dist/server/hooks.js.map +1 -1
  213. package/dist/server/http.d.ts +84 -6
  214. package/dist/server/http.d.ts.map +1 -1
  215. package/dist/server/index.d.ts +36 -12
  216. package/dist/server/index.d.ts.map +1 -1
  217. package/dist/server/index.js +24 -8
  218. package/dist/server/index.js.map +1 -1
  219. package/dist/server/instrumentation.d.ts +108 -0
  220. package/dist/server/instrumentation.d.ts.map +1 -0
  221. package/dist/server/instrumentation.js +297 -0
  222. package/dist/server/instrumentation.js.map +1 -0
  223. package/dist/server/openapi.d.ts +3 -3
  224. package/dist/server/openapi.d.ts.map +1 -1
  225. package/dist/server/openapi.js +1 -1
  226. package/dist/server/openapi.js.map +1 -1
  227. package/dist/server/providers/index.d.ts +3 -3
  228. package/dist/server/providers/index.d.ts.map +1 -1
  229. package/dist/server/providers/index.js +3 -3
  230. package/dist/server/providers/index.js.map +1 -1
  231. package/dist/server/providers/loadProviderConfig.d.ts +2 -2
  232. package/dist/server/providers/loadProviderConfig.d.ts.map +1 -1
  233. package/dist/server/providers/loadProviderConfig.js +2 -2
  234. package/dist/server/providers/loadProviderConfig.js.map +1 -1
  235. package/dist/server/request-context.d.ts +67 -0
  236. package/dist/server/request-context.d.ts.map +1 -0
  237. package/dist/server/request-context.js +79 -0
  238. package/dist/server/request-context.js.map +1 -0
  239. package/dist/server/server-context.d.ts +38 -0
  240. package/dist/server/server-context.d.ts.map +1 -0
  241. package/dist/server/server-context.js +38 -0
  242. package/dist/server/server-context.js.map +1 -0
  243. package/dist/server/server.d.ts +148 -35
  244. package/dist/server/server.d.ts.map +1 -1
  245. package/dist/server/server.js +482 -145
  246. package/dist/server/server.js.map +1 -1
  247. package/dist/server/types.d.ts +2 -2
  248. package/dist/server/types.d.ts.map +1 -1
  249. package/dist/server/types.js +2 -2
  250. package/dist/server/types.js.map +1 -1
  251. package/dist/server/use-case-route.d.ts +263 -0
  252. package/dist/server/use-case-route.d.ts.map +1 -0
  253. package/dist/server/use-case-route.js +77 -0
  254. package/dist/server/use-case-route.js.map +1 -0
  255. package/dist/server-only.d.ts +8 -0
  256. package/dist/server-only.d.ts.map +1 -0
  257. package/dist/server-only.js +8 -0
  258. package/dist/server-only.js.map +1 -0
  259. package/dist/tasks/index.d.ts +139 -0
  260. package/dist/tasks/index.d.ts.map +1 -0
  261. package/dist/tasks/index.js +98 -0
  262. package/dist/tasks/index.js.map +1 -0
  263. package/dist/testing/index.d.ts +611 -5
  264. package/dist/testing/index.d.ts.map +1 -1
  265. package/dist/testing/index.js +434 -4
  266. package/dist/testing/index.js.map +1 -1
  267. package/dist/tracing/index.d.ts +89 -0
  268. package/dist/tracing/index.d.ts.map +1 -0
  269. package/dist/tracing/index.js +101 -0
  270. package/dist/tracing/index.js.map +1 -0
  271. package/dist/uploads/client.d.ts +278 -0
  272. package/dist/uploads/client.d.ts.map +1 -0
  273. package/dist/uploads/client.js +428 -0
  274. package/dist/uploads/client.js.map +1 -0
  275. package/dist/uploads/index.d.ts +361 -0
  276. package/dist/uploads/index.d.ts.map +1 -0
  277. package/dist/uploads/index.js +543 -0
  278. package/dist/uploads/index.js.map +1 -0
  279. package/package.json +34 -3
  280. package/src/application/index.ts +193 -10
  281. package/src/client/client.ts +148 -150
  282. package/src/client/error-messages.ts +35 -0
  283. package/src/client/index.ts +12 -4
  284. package/src/client/types.ts +44 -5
  285. package/src/client-only.ts +7 -0
  286. package/src/config/index.ts +6 -6
  287. package/src/contracts/catalog-errors.ts +115 -0
  288. package/src/contracts/contract-builder.ts +39 -76
  289. package/src/contracts/contract-group.ts +33 -68
  290. package/src/contracts/contract-like.ts +1 -1
  291. package/src/contracts/index.ts +24 -11
  292. package/src/contracts/openapi-meta.ts +55 -0
  293. package/src/contracts/path-template.ts +2 -2
  294. package/src/contracts/schema-shape.ts +75 -0
  295. package/src/contracts/success-status.ts +68 -0
  296. package/src/contracts/types.ts +32 -5
  297. package/src/contracts/utils.ts +5 -2
  298. package/src/domain/events.ts +6 -2
  299. package/src/domain/index.ts +3 -3
  300. package/src/errors/catalog.ts +9 -1
  301. package/src/errors/http.ts +11 -1
  302. package/src/errors/index.ts +4 -4
  303. package/src/errors/response.ts +4 -1
  304. package/src/events/index.ts +12 -26
  305. package/src/idempotency/index.ts +5 -3
  306. package/src/jobs/index.ts +340 -29
  307. package/src/notifications/index.ts +17 -27
  308. package/src/openapi/index.ts +73 -38
  309. package/src/openapi/schema-introspector.ts +68 -17
  310. package/src/outbox/index.ts +151 -6
  311. package/src/ports/audit.ts +120 -11
  312. package/src/ports/auth.ts +132 -0
  313. package/src/ports/events.ts +2 -2
  314. package/src/ports/index.ts +104 -35
  315. package/src/ports/policy.ts +50 -3
  316. package/src/ports/testing.ts +2220 -33
  317. package/src/ports/unbound.ts +64 -0
  318. package/src/ports/unit-of-work.ts +6 -2
  319. package/src/providers/index.ts +16 -3
  320. package/src/providers/instrumentation.ts +93 -8
  321. package/src/providers/metadata.ts +234 -0
  322. package/src/providers/provider.ts +168 -9
  323. package/src/schedules/index.ts +173 -23
  324. package/src/server/audit-context.ts +45 -0
  325. package/src/server/context.ts +224 -0
  326. package/src/server/contract-like.ts +1 -1
  327. package/src/server/health.ts +2 -2
  328. package/src/server/hooks/auth.ts +175 -158
  329. package/src/server/hooks/cors.ts +1 -1
  330. package/src/server/hooks/errors.ts +7 -4
  331. package/src/server/hooks/idempotency.ts +263 -0
  332. package/src/server/hooks/index.ts +15 -12
  333. package/src/server/hooks/logging.ts +3 -3
  334. package/src/server/hooks/rate-limit.ts +85 -17
  335. package/src/server/hooks.ts +1 -1
  336. package/src/server/http.ts +112 -6
  337. package/src/server/index.ts +63 -12
  338. package/src/server/instrumentation.ts +470 -0
  339. package/src/server/openapi.ts +4 -4
  340. package/src/server/providers/index.ts +6 -3
  341. package/src/server/providers/loadProviderConfig.ts +4 -4
  342. package/src/server/request-context.ts +116 -0
  343. package/src/server/server-context.ts +44 -0
  344. package/src/server/server.ts +1045 -229
  345. package/src/server/types.ts +2 -2
  346. package/src/server/use-case-route.ts +430 -0
  347. package/src/server-only.ts +7 -0
  348. package/src/tasks/index.ts +275 -0
  349. package/src/testing/index.ts +1153 -6
  350. package/src/tracing/index.ts +176 -0
  351. package/src/uploads/client.ts +861 -0
  352. package/src/uploads/index.ts +1071 -0
  353. package/dist/ports/mailer.d.ts +0 -6
  354. package/dist/ports/mailer.d.ts.map +0 -1
  355. package/dist/ports/mailer.js +0 -2
  356. package/dist/ports/mailer.js.map +0 -1
  357. package/dist/ports/schedules.d.ts +0 -9
  358. package/dist/ports/schedules.d.ts.map +0 -1
  359. package/dist/ports/schedules.js +0 -2
  360. package/dist/ports/schedules.js.map +0 -1
@@ -1,4 +1,8 @@
1
- import { redactValue } from "./redaction";
1
+ import {
2
+ type ProviderInstrumentationTarget,
3
+ resolveProviderInstrumentationPort,
4
+ } from "../providers/instrumentation.js";
5
+ import { redactValue } from "./redaction.js";
2
6
 
3
7
  /**
4
8
  * The normalized category of actor that caused application activity.
@@ -111,10 +115,11 @@ export interface ActivityResource {
111
115
  /**
112
116
  * A normalized audit/activity log entry.
113
117
  *
114
- * Application code usually creates these through an app-owned helper such as
115
- * `auditEntry(ctx, { action, resource })` so actor, tenant, request ID, and
116
- * trace ID are copied from context consistently. Durability depends on the
117
- * `AuditLogPort` implementation.
118
+ * Application code usually records entries through an audit port wrapped with
119
+ * `createAmbientAuditLog(...)` from `@beignet/core/server`, which fills
120
+ * missing actor, tenant, request ID, and trace ID fields from the ambient
121
+ * request context at record time. Durability depends on the `AuditLogPort`
122
+ * implementation.
118
123
  */
119
124
  export interface AuditLogEntry {
120
125
  /**
@@ -165,14 +170,18 @@ export interface AuditLogEntry {
165
170
  /**
166
171
  * Input accepted by `AuditLogPort.record(...)`.
167
172
  *
168
- * `occurredAt` and `outcome` are optional at call sites. Adapters that store
169
- * audit entries should call `normalizeAuditLogEntry(...)` before persistence or
170
- * otherwise apply equivalent defaults.
173
+ * `actor`, `occurredAt`, and `outcome` are optional at call sites. Wrappers
174
+ * such as `createAmbientAuditLog(...)` fill a missing actor from the ambient
175
+ * request context. Adapters that store audit entries should call
176
+ * `normalizeAuditLogEntry(...)` before persistence or otherwise apply
177
+ * equivalent defaults; entries without an actor normalize to an anonymous
178
+ * actor.
171
179
  */
172
180
  export type AuditLogEntryInput = Omit<
173
181
  AuditLogEntry,
174
- "occurredAt" | "outcome"
182
+ "actor" | "occurredAt" | "outcome"
175
183
  > & {
184
+ actor?: ActivityActor;
176
185
  occurredAt?: Date;
177
186
  outcome?: AuditOutcome;
178
187
  };
@@ -259,7 +268,7 @@ export function createServiceActor(
259
268
  /**
260
269
  * Create a system actor descriptor for framework or app-owned background work.
261
270
  *
262
- * Use this for scheduled tasks, scripts, maintenance jobs, and other work that
271
+ * Use this for schedules, scripts, maintenance jobs, and other work that
263
272
  * is not directly caused by a user or external service.
264
273
  *
265
274
  * @example
@@ -334,13 +343,15 @@ export function createTenant(
334
343
  * Fill default audit fields for an input entry.
335
344
  *
336
345
  * @param entry - Partial audit entry accepted by `AuditLogPort.record(...)`.
337
- * @returns A complete audit entry with `occurredAt` and `outcome` populated.
346
+ * @returns A complete audit entry with `actor`, `occurredAt`, and `outcome`
347
+ * populated. Entries without an actor default to an anonymous actor.
338
348
  */
339
349
  export function normalizeAuditLogEntry(
340
350
  entry: AuditLogEntryInput,
341
351
  ): AuditLogEntry {
342
352
  return {
343
353
  ...entry,
354
+ actor: entry.actor ?? createAnonymousActor(),
344
355
  occurredAt: entry.occurredAt ?? new Date(),
345
356
  outcome: entry.outcome ?? "success",
346
357
  };
@@ -409,6 +420,104 @@ export function createRedactedAuditLog(
409
420
  };
410
421
  }
411
422
 
423
+ /**
424
+ * Options for wrapping an audit log with instrumentation emission.
425
+ */
426
+ export interface InstrumentedAuditLogOptions {
427
+ /**
428
+ * Durable audit log to write first.
429
+ */
430
+ audit: AuditLogPort;
431
+ /**
432
+ * Instrumentation sink, port, or ports object. Pass the app ports object so
433
+ * the sink (`ports.instrumentation`, then `ports.devtools`) is resolved
434
+ * lazily on each write and observes provider startup order.
435
+ */
436
+ instrumentation?: ProviderInstrumentationTarget;
437
+ /**
438
+ * Whether to emit instrumentation events. Defaults to true.
439
+ */
440
+ emit?: boolean;
441
+ /**
442
+ * Optional app-owned redactor applied after Beignet's audit redaction.
443
+ */
444
+ redact?: (entry: AuditLogEntry) => AuditLogEntry;
445
+ }
446
+
447
+ function prepareInstrumentedEntry(
448
+ input: AuditLogEntryInput,
449
+ redact?: (entry: AuditLogEntry) => AuditLogEntry,
450
+ ): AuditLogEntry {
451
+ const redacted = redactAuditLogEntry(normalizeAuditLogEntry(input));
452
+ return redact ? redact(redacted) : redacted;
453
+ }
454
+
455
+ function auditSummary(entry: AuditLogEntry): string {
456
+ const resource = entry.resource?.id
457
+ ? `${entry.resource.type}:${entry.resource.id}`
458
+ : entry.resource?.type;
459
+ const outcome = entry.outcome === "failure" ? "failed" : "succeeded";
460
+ return resource
461
+ ? `${entry.action} ${outcome} for ${resource}`
462
+ : `${entry.action} ${outcome}`;
463
+ }
464
+
465
+ /**
466
+ * Wrap an audit log so durable audit writes also appear in instrumentation
467
+ * sinks such as devtools.
468
+ *
469
+ * Instrumentation failures are ignored so audit persistence remains the
470
+ * source of truth.
471
+ *
472
+ * @example
473
+ * ```ts
474
+ * const audit = createInstrumentedAuditLog({
475
+ * audit: createDrizzleAuditLog(db),
476
+ * instrumentation: ports,
477
+ * });
478
+ * ```
479
+ */
480
+ export function createInstrumentedAuditLog(
481
+ options: InstrumentedAuditLogOptions,
482
+ ): AuditLogPort {
483
+ return {
484
+ async record(input) {
485
+ const entry = prepareInstrumentedEntry(input, options.redact);
486
+
487
+ await options.audit.record(entry);
488
+
489
+ if (options.emit === false) return;
490
+
491
+ const port = resolveProviderInstrumentationPort(options.instrumentation);
492
+ if (!port) return;
493
+
494
+ try {
495
+ port.record({
496
+ type: "custom",
497
+ watcher: "audit",
498
+ name: entry.action,
499
+ label: "Audit",
500
+ summary: auditSummary(entry),
501
+ requestId: entry.requestId,
502
+ traceId: entry.traceId,
503
+ details: {
504
+ action: entry.action,
505
+ actor: entry.actor,
506
+ tenant: entry.tenant,
507
+ resource: entry.resource,
508
+ outcome: entry.outcome,
509
+ message: entry.message,
510
+ metadata: entry.metadata,
511
+ occurredAt: entry.occurredAt.toISOString(),
512
+ },
513
+ });
514
+ } catch {
515
+ // Instrumentation is an observer; durable audit writes must not depend on it.
516
+ }
517
+ },
518
+ };
519
+ }
520
+
412
521
  /**
413
522
  * Create an in-memory audit log for tests and local examples.
414
523
  *
package/src/ports/auth.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { ActivityTenant } from "./audit.js";
2
+
1
3
  /**
2
4
  * Minimal request shape consumed by Beignet auth ports.
3
5
  *
@@ -41,6 +43,136 @@ export class AuthUnauthorizedError extends Error {
41
43
  }
42
44
  }
43
45
 
46
+ /**
47
+ * Error thrown by tenant helpers when a workflow requires a tenant scope but
48
+ * the current context has none.
49
+ *
50
+ * The server maps this to a framework-owned 403 response, mirroring how
51
+ * `AuthUnauthorizedError` maps to a framework-owned 401.
52
+ */
53
+ export class TenantRequiredError extends Error {
54
+ readonly code = "TENANT_REQUIRED";
55
+ readonly status = 403;
56
+
57
+ constructor(message = "A tenant is required for this action.") {
58
+ super(message);
59
+ this.name = "TenantRequiredError";
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Options accepted by the `requireX(ctx)` context helpers.
65
+ */
66
+ export interface RequireOptions {
67
+ /**
68
+ * Create the error to throw instead of the framework default.
69
+ */
70
+ error?: () => unknown;
71
+ }
72
+
73
+ function throwRequired(
74
+ options: RequireOptions | undefined,
75
+ fallback: () => Error,
76
+ ): never {
77
+ throw options?.error ? options.error() : fallback();
78
+ }
79
+
80
+ /**
81
+ * Return the authenticated session from `ctx.auth` or throw.
82
+ *
83
+ * Throws `AuthUnauthorizedError` (a framework-owned 401) by default. Pass
84
+ * `options.error` to throw an app-owned error instead.
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * const session = requireSession(ctx);
89
+ * ```
90
+ */
91
+ export function requireSession<Session extends AuthSession>(
92
+ ctx: { auth?: Session | null },
93
+ options?: RequireOptions,
94
+ ): Session {
95
+ if (!ctx.auth) {
96
+ throwRequired(options, () => new AuthUnauthorizedError());
97
+ }
98
+
99
+ return ctx.auth;
100
+ }
101
+
102
+ /**
103
+ * Return the authenticated user from `ctx.auth` or throw.
104
+ *
105
+ * The user type is inferred from the app's `ctx.auth` session. Throws
106
+ * `AuthUnauthorizedError` (a framework-owned 401) by default.
107
+ *
108
+ * @example
109
+ * ```ts
110
+ * const user = requireUser(ctx);
111
+ * ```
112
+ */
113
+ export function requireUser<User>(
114
+ ctx: { auth?: AuthSession<User> | null },
115
+ options?: RequireOptions,
116
+ ): User {
117
+ return requireSession(ctx, options).user;
118
+ }
119
+
120
+ /**
121
+ * Return the authenticated user's ID from `ctx.auth` or throw.
122
+ *
123
+ * Throws `AuthUnauthorizedError` (a framework-owned 401) by default.
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * const userId = requireUserId(ctx);
128
+ * ```
129
+ */
130
+ export function requireUserId(
131
+ ctx: { auth?: AuthSession<{ id: string }> | null },
132
+ options?: RequireOptions,
133
+ ): string {
134
+ return requireUser(ctx, options).id;
135
+ }
136
+
137
+ /**
138
+ * Return the tenant scope from `ctx.tenant` or throw.
139
+ *
140
+ * Throws `TenantRequiredError` (a framework-owned 403) by default. Pass
141
+ * `options.error` to throw an app-owned error instead.
142
+ *
143
+ * @example
144
+ * ```ts
145
+ * const tenant = requireTenant(ctx);
146
+ * ```
147
+ */
148
+ export function requireTenant(
149
+ ctx: { tenant?: ActivityTenant | null },
150
+ options?: RequireOptions,
151
+ ): ActivityTenant {
152
+ if (!ctx.tenant) {
153
+ throwRequired(options, () => new TenantRequiredError());
154
+ }
155
+
156
+ return ctx.tenant;
157
+ }
158
+
159
+ /**
160
+ * Return the tenant ID from `ctx.tenant` or throw.
161
+ *
162
+ * Throws `TenantRequiredError` (a framework-owned 403) by default.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * const tenantId = requireTenantId(ctx);
167
+ * ```
168
+ */
169
+ export function requireTenantId(
170
+ ctx: { tenant?: ActivityTenant | null },
171
+ options?: RequireOptions,
172
+ ): string {
173
+ return requireTenant(ctx, options).id;
174
+ }
175
+
44
176
  /**
45
177
  * App-facing authentication port.
46
178
  *
@@ -2,11 +2,11 @@ import type {
2
2
  EventPayloadDef,
3
3
  InferEventPayload as InferContractEventPayload,
4
4
  StandardSchema,
5
- } from "../events";
5
+ } from "../events/index.js";
6
6
  import type {
7
7
  JobDef as ContractJobDef,
8
8
  InferJobPayload as InferContractJobPayload,
9
- } from "../jobs";
9
+ } from "../jobs/index.js";
10
10
 
11
11
  /**
12
12
  * Represents a defined Domain Event with name and payload schema.
@@ -27,9 +27,11 @@
27
27
  * - `@beignet/core/mail` owns `MailerPort` and mail test adapters
28
28
  * - `@beignet/core/notifications` owns notification helpers and test adapters
29
29
  * - `@beignet/core/outbox` owns durable outbox helpers and test adapters
30
- * - `@beignet/core/schedules` owns scheduled task definitions and runners
30
+ * - `@beignet/core/schedules` owns schedule definitions and runners
31
31
  */
32
32
 
33
+ import { createUnboundPort } from "./unbound.js";
34
+
33
35
  /**
34
36
  * A generic map of named "ports" (outbound dependencies) that your
35
37
  * application depends on: db, mailer, cache, event bus, etc.
@@ -39,28 +41,78 @@
39
41
  */
40
42
  export type AnyPorts = Record<string, unknown>;
41
43
 
44
+ /**
45
+ * Definition accepted by the curried `definePorts<P>()(...)` form.
46
+ */
47
+ export type DeferredPortsDefinition<
48
+ P extends AnyPorts,
49
+ Deferred extends readonly (keyof P & string)[],
50
+ > = {
51
+ /**
52
+ * Ports the app binds directly. Optional keys of `P` may be omitted here
53
+ * and contributed by providers instead.
54
+ */
55
+ bound: Omit<P, Deferred[number]>;
56
+ /**
57
+ * Port keys that providers contribute during server startup. Deferred keys
58
+ * boot as throwing placeholders; `createServer(...)` fails startup if any
59
+ * are still unbound after providers have started (see `onUnboundPorts`).
60
+ */
61
+ deferred: Deferred;
62
+ };
63
+
42
64
  /**
43
65
  * Define the set of ports (outbound dependencies) for your application.
44
66
  *
45
- * This is essentially a typed identity function. It:
46
- * - captures the exact shape of the provided `ports` object
47
- * - allows you to export `type AppPorts = typeof appPorts` in your app
67
+ * The identity form captures the exact shape of the provided `ports` object
68
+ * so you can export `type AppPorts = typeof appPorts`.
69
+ *
70
+ * The curried form, `definePorts<AppPorts>()({ bound, deferred })`, declares
71
+ * which port keys providers contribute at server startup. Deferred keys boot
72
+ * as throwing placeholders instead of hand-written stubs, and
73
+ * `createServer(...)` validates after provider startup that nothing is left
74
+ * unbound. Optional keys of `AppPorts` may go in either bucket.
48
75
  *
49
76
  * @example
50
77
  * ```ts
78
+ * // Identity form: every port is bound directly.
51
79
  * const appPorts = definePorts({
52
80
  * db: dbAdapter,
53
81
  * mailer: mailerAdapter,
54
82
  * });
55
- *
56
83
  * export type AppPorts = typeof appPorts;
57
- * ```
58
84
  *
59
- * @param ports - The ports object to define
60
- * @returns The same ports object, unchanged
85
+ * // Deferred form: providers contribute the rest at startup.
86
+ * export const appPorts = definePorts<AppPorts>()({
87
+ * bound: { gate },
88
+ * deferred: ["db", "mailer", "storage"],
89
+ * });
90
+ * ```
61
91
  */
62
- export function definePorts<P extends AnyPorts>(ports: P): P {
63
- return ports;
92
+ export function definePorts<P extends AnyPorts>(ports: P): P;
93
+ export function definePorts<P extends AnyPorts>(): <
94
+ const Deferred extends readonly (keyof P & string)[],
95
+ >(
96
+ definition: DeferredPortsDefinition<P, Deferred>,
97
+ ) => P;
98
+ export function definePorts<P extends AnyPorts>(
99
+ ports?: P,
100
+ ):
101
+ | P
102
+ | ((
103
+ definition: DeferredPortsDefinition<P, readonly (keyof P & string)[]>,
104
+ ) => P) {
105
+ if (ports !== undefined) {
106
+ return ports;
107
+ }
108
+
109
+ return (definition) => {
110
+ const result: AnyPorts = { ...(definition.bound as AnyPorts) };
111
+ for (const key of definition.deferred) {
112
+ result[key] = createUnboundPort(key);
113
+ }
114
+ return result as P;
115
+ };
64
116
  }
65
117
 
66
118
  /**
@@ -93,7 +145,7 @@ export type {
93
145
  IdempotencyPort,
94
146
  IdempotencyReservation,
95
147
  IdempotencyReserveInput,
96
- } from "../idempotency";
148
+ } from "../idempotency/index.js";
97
149
  /**
98
150
  * Notification port exports.
99
151
  */
@@ -104,7 +156,7 @@ export type {
104
156
  NotificationPort,
105
157
  SendNotificationOptions,
106
158
  SendNotificationResult,
107
- } from "../notifications";
159
+ } from "../notifications/index.js";
108
160
  /**
109
161
  * Transactional outbox port exports.
110
162
  */
@@ -118,7 +170,7 @@ export type {
118
170
  OutboxMessageKind,
119
171
  OutboxMessageStatus,
120
172
  OutboxPort,
121
- } from "../outbox";
173
+ } from "../outbox/index.js";
122
174
  /**
123
175
  * Audit log port exports.
124
176
  */
@@ -134,13 +186,15 @@ export type {
134
186
  AuditLogOptions,
135
187
  AuditLogPort,
136
188
  AuditOutcome,
189
+ InstrumentedAuditLogOptions,
137
190
  MemoryAuditLogPort,
138
- } from "./audit";
191
+ } from "./audit.js";
139
192
  /**
140
193
  * Audit log helper exports.
141
194
  */
142
195
  export {
143
196
  createAnonymousActor,
197
+ createInstrumentedAuditLog,
144
198
  createMemoryAuditLog,
145
199
  createRedactedAuditLog,
146
200
  createServiceActor,
@@ -149,7 +203,7 @@ export {
149
203
  createUserActor,
150
204
  normalizeAuditLogEntry,
151
205
  redactAuditLogEntry,
152
- } from "./audit";
206
+ } from "./audit.js";
153
207
  /**
154
208
  * Auth port exports.
155
209
  */
@@ -157,8 +211,9 @@ export type {
157
211
  AuthPort,
158
212
  AuthRequestLike,
159
213
  AuthSession,
214
+ RequireOptions,
160
215
  StaticAuthSessionFactory,
161
- } from "./auth";
216
+ } from "./auth.js";
162
217
  /**
163
218
  * Auth helper exports.
164
219
  */
@@ -166,7 +221,13 @@ export {
166
221
  AuthUnauthorizedError,
167
222
  createAnonymousAuth,
168
223
  createStaticAuth,
169
- } from "./auth";
224
+ requireSession,
225
+ requireTenant,
226
+ requireTenantId,
227
+ requireUser,
228
+ requireUserId,
229
+ TenantRequiredError,
230
+ } from "./auth.js";
170
231
  /**
171
232
  * Ports builder exports.
172
233
  */
@@ -174,23 +235,23 @@ export {
174
235
  createPortsBuilder,
175
236
  type PortsBuilder,
176
237
  type PortsOf,
177
- } from "./builder";
238
+ } from "./builder.js";
178
239
  /**
179
240
  * Cache port exports.
180
241
  */
181
- export type { CachePort, CacheSetOptions } from "./cache";
242
+ export type { CachePort, CacheSetOptions } from "./cache.js";
182
243
  /**
183
244
  * Cache helper exports.
184
245
  */
185
- export { createMemoryCache } from "./cache";
246
+ export { createMemoryCache } from "./cache.js";
186
247
  /**
187
248
  * Clock port exports.
188
249
  */
189
- export type { ClockPort, FrozenClockPort } from "./clock";
250
+ export type { ClockPort, FrozenClockPort } from "./clock.js";
190
251
  /**
191
252
  * Clock helper exports.
192
253
  */
193
- export { createFrozenClock, createSystemClock } from "./clock";
254
+ export { createFrozenClock, createSystemClock } from "./clock.js";
194
255
  /**
195
256
  * Event bus and job dispatcher port exports.
196
257
  */
@@ -201,18 +262,21 @@ export type {
201
262
  InferJobPayload,
202
263
  JobDef,
203
264
  JobDispatcherPort,
204
- } from "./events";
265
+ } from "./events.js";
205
266
  /**
206
267
  * ID generator port exports.
207
268
  */
208
- export type { IdGeneratorPort, SequenceIdGeneratorPort } from "./id-generator";
269
+ export type {
270
+ IdGeneratorPort,
271
+ SequenceIdGeneratorPort,
272
+ } from "./id-generator.js";
209
273
  /**
210
274
  * ID generator helper exports.
211
275
  */
212
276
  export {
213
277
  createSequenceIdGenerator,
214
278
  createUuidIdGenerator,
215
- } from "./id-generator";
279
+ } from "./id-generator.js";
216
280
  /**
217
281
  * Logger port exports.
218
282
  */
@@ -221,11 +285,11 @@ export type {
221
285
  LogLevel,
222
286
  MemoryLogEntry,
223
287
  MemoryLoggerPort,
224
- } from "./logger";
288
+ } from "./logger.js";
225
289
  /**
226
290
  * Logger helper exports.
227
291
  */
228
- export { createMemoryLogger, createNoopLogger } from "./logger";
292
+ export { createMemoryLogger, createNoopLogger } from "./logger.js";
229
293
  /**
230
294
  * Policy and authorization gate type exports.
231
295
  */
@@ -233,6 +297,7 @@ export type {
233
297
  BoundGate,
234
298
  CreateGateOptions,
235
299
  GateAllowedDecision,
300
+ GateContext,
236
301
  GateDecision,
237
302
  GateDeniedDecision,
238
303
  GateDenyHandler,
@@ -243,7 +308,7 @@ export type {
243
308
  PolicyMapFromDefinitions,
244
309
  PolicyResolver,
245
310
  PolicySubjectArgs,
246
- } from "./policy";
311
+ } from "./policy.js";
247
312
  /**
248
313
  * Policy and authorization gate helper exports.
249
314
  */
@@ -253,7 +318,7 @@ export {
253
318
  definePolicy,
254
319
  deny,
255
320
  GateAuthorizationError,
256
- } from "./policy";
321
+ } from "./policy.js";
257
322
  /**
258
323
  * Rate limit port exports.
259
324
  */
@@ -261,11 +326,11 @@ export type {
261
326
  RateLimitHitOptions,
262
327
  RateLimitPort,
263
328
  RateLimitResult,
264
- } from "./rate-limit";
329
+ } from "./rate-limit.js";
265
330
  /**
266
331
  * Rate limit helper exports.
267
332
  */
268
- export { createMemoryRateLimiter } from "./rate-limit";
333
+ export { createMemoryRateLimiter } from "./rate-limit.js";
269
334
  /**
270
335
  * Redaction helper exports.
271
336
  */
@@ -283,7 +348,7 @@ export {
283
348
  type Redactor,
284
349
  redactHeaders,
285
350
  redactValue,
286
- } from "./redaction";
351
+ } from "./redaction.js";
287
352
  /**
288
353
  * Storage port exports.
289
354
  */
@@ -296,11 +361,15 @@ export type {
296
361
  StoragePort,
297
362
  StoragePutOptions,
298
363
  StorageVisibility,
299
- } from "./storage";
364
+ } from "./storage.js";
300
365
  /**
301
366
  * Storage helper exports.
302
367
  */
303
- export { createMemoryStorage } from "./storage";
368
+ export { createMemoryStorage } from "./storage.js";
369
+ /**
370
+ * Unbound (deferred) port helper exports.
371
+ */
372
+ export { createUnboundPort, isUnboundPort } from "./unbound.js";
304
373
  /**
305
374
  * Unit of Work port exports.
306
375
  */
@@ -313,4 +382,4 @@ export {
313
382
  type RecordedDomainEvent,
314
383
  type UnitOfWorkCallback,
315
384
  type UnitOfWorkPort,
316
- } from "./unit-of-work";
385
+ } from "./unit-of-work.js";