@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
@@ -0,0 +1,224 @@
1
+ import type { HttpContractConfig } from "../contracts/index.js";
2
+ import type {
3
+ AnyPorts,
4
+ BoundGate,
5
+ GatePort,
6
+ PolicyDefinition,
7
+ } from "../ports/index.js";
8
+ import type { TraceContext } from "../tracing/index.js";
9
+ import type { HttpRequestLike, MaybePromise } from "./http.js";
10
+
11
+ /**
12
+ * Arguments passed to the `context.request` factory after a route is matched.
13
+ */
14
+ export type RequestContextArgs<Ports extends AnyPorts = AnyPorts> = {
15
+ /**
16
+ * Framework-neutral request.
17
+ */
18
+ req: HttpRequestLike;
19
+ /**
20
+ * Final app ports, including ports contributed by providers.
21
+ */
22
+ ports: Ports;
23
+ /**
24
+ * Matched contract, when the request resolved to a registered route.
25
+ */
26
+ contract?: HttpContractConfig;
27
+ /**
28
+ * Request correlation ID resolved by the server from the configured request
29
+ * ID header, or generated when the request did not send one.
30
+ */
31
+ requestId: string;
32
+ /**
33
+ * W3C trace context resolved by the server from the incoming `traceparent`
34
+ * header, or generated when the request did not send one. Spread this into
35
+ * the context (`...trace`) to correlate downstream activity.
36
+ */
37
+ trace: TraceContext;
38
+ };
39
+
40
+ /**
41
+ * Arguments passed to the `context.service` factory.
42
+ */
43
+ export type ServiceContextArgs<
44
+ Ports extends AnyPorts = AnyPorts,
45
+ ServiceInput = void,
46
+ > = {
47
+ /**
48
+ * Final app ports, including ports contributed by providers.
49
+ */
50
+ ports: Ports;
51
+ /**
52
+ * Caller-provided input such as the service actor or tenant.
53
+ */
54
+ input: ServiceInput;
55
+ /**
56
+ * Fresh correlation ID generated for this service context.
57
+ */
58
+ requestId: string;
59
+ /**
60
+ * Fresh W3C trace context generated for this service context. Spread this
61
+ * into the context (`...trace`) to correlate downstream activity.
62
+ */
63
+ trace: TraceContext;
64
+ };
65
+
66
+ /**
67
+ * App context without its `gate` property.
68
+ *
69
+ * Context factories return seeds; the server attaches the gate declared by
70
+ * the blueprint's `gate` selector, so hand-binding `gate` in a factory is a
71
+ * type error.
72
+ */
73
+ export type ContextSeed<Ctx> = Omit<Ctx, "gate"> & { gate?: never };
74
+
75
+ type ContextGateOption<Ctx, Ports extends AnyPorts> = [Ctx] extends [
76
+ { gate: BoundGate<infer TPolicies extends readonly PolicyDefinition[]> },
77
+ ]
78
+ ? {
79
+ /**
80
+ * Select the gate port the server attaches to every context it builds.
81
+ */
82
+ gate: (ports: Ports) => GatePort<ContextSeed<Ctx>, TPolicies>;
83
+ }
84
+ : {
85
+ /**
86
+ * Gate selection is only available when the context type declares a
87
+ * `gate` property.
88
+ */
89
+ gate?: never;
90
+ };
91
+
92
+ /**
93
+ * Context blueprint accepted by `createServer(...)`.
94
+ *
95
+ * The server owns context assembly: `request` and `service` return context
96
+ * seeds, and the server attaches the gate declared by `gate` so identity
97
+ * changes can never authorize against a stale context.
98
+ */
99
+ export type ServerContextOptions<
100
+ Ctx,
101
+ Ports extends AnyPorts = AnyPorts,
102
+ ServiceInput = void,
103
+ > = {
104
+ /**
105
+ * Build the per-request context seed.
106
+ */
107
+ request: (args: RequestContextArgs<Ports>) => MaybePromise<ContextSeed<Ctx>>;
108
+ /**
109
+ * Build a service context seed for schedules, outbox drains, tasks, and
110
+ * background work. Required before `server.createServiceContext(...)` can
111
+ * be called.
112
+ */
113
+ service?: (
114
+ args: ServiceContextArgs<Ports, ServiceInput>,
115
+ ) => MaybePromise<ContextSeed<Ctx>>;
116
+ } & ContextGateOption<Ctx, Ports>;
117
+
118
+ /**
119
+ * Context configuration accepted by `createServer(...)`.
120
+ *
121
+ * Contexts without a `gate` property may use the plain request-factory
122
+ * shorthand. Contexts with a `gate` must use the blueprint form so the server
123
+ * owns gate attachment.
124
+ */
125
+ export type ServerContextConfig<
126
+ Ctx,
127
+ Ports extends AnyPorts = AnyPorts,
128
+ ServiceInput = void,
129
+ > = [Ctx] extends [{ gate: unknown }]
130
+ ? ServerContextOptions<Ctx, Ports, ServiceInput>
131
+ :
132
+ | ((args: RequestContextArgs<Ports>) => MaybePromise<Ctx>)
133
+ | ServerContextOptions<Ctx, Ports, ServiceInput>;
134
+
135
+ /**
136
+ * Argument tuple for `createServiceContext(...)`.
137
+ *
138
+ * Servers without a declared service input are callable with no arguments;
139
+ * optional inputs stay optional at the call site.
140
+ */
141
+ export type ServiceContextInputArgs<ServiceInput> = [ServiceInput] extends [
142
+ // biome-ignore lint/suspicious/noConfusingVoidType: void marks "no declared service input" here
143
+ void,
144
+ ]
145
+ ? []
146
+ : undefined extends ServiceInput
147
+ ? [input?: ServiceInput]
148
+ : [input: ServiceInput];
149
+
150
+ type AnyGateSelector<Ports extends AnyPorts> = (
151
+ ports: Ports,
152
+ ) => Pick<GatePort<unknown>, "attach">;
153
+
154
+ /**
155
+ * Normalized runtime view of a server context configuration.
156
+ */
157
+ export type ResolvedServerContext<Ctx, Ports extends AnyPorts, ServiceInput> = {
158
+ request: (
159
+ args: RequestContextArgs<Ports>,
160
+ ) => MaybePromise<ContextSeed<Ctx> | Ctx>;
161
+ service?: (
162
+ args: ServiceContextArgs<Ports, ServiceInput>,
163
+ ) => MaybePromise<ContextSeed<Ctx>>;
164
+ gate?: AnyGateSelector<Ports>;
165
+ };
166
+
167
+ /**
168
+ * Normalize a server context configuration into its runtime parts.
169
+ */
170
+ export function resolveServerContext<Ctx, Ports extends AnyPorts, ServiceInput>(
171
+ config: ServerContextConfig<Ctx, Ports, ServiceInput>,
172
+ ): ResolvedServerContext<Ctx, Ports, ServiceInput> {
173
+ const value = config as
174
+ | ((args: RequestContextArgs<Ports>) => MaybePromise<Ctx>)
175
+ | (ResolvedServerContext<Ctx, Ports, ServiceInput> & {
176
+ gate?: AnyGateSelector<Ports>;
177
+ });
178
+
179
+ if (typeof value === "function") {
180
+ return { request: value };
181
+ }
182
+
183
+ return {
184
+ request: value.request,
185
+ service: value.service,
186
+ gate: value.gate,
187
+ };
188
+ }
189
+
190
+ /**
191
+ * Create the context finalizer for a resolved server context.
192
+ *
193
+ * When the blueprint declares a gate, the finalizer strips hand-assigned
194
+ * `gate` values from seeds and attaches the live gate. Without a gate
195
+ * declaration the seed is the context.
196
+ */
197
+ export function createContextFinalizer<
198
+ Ctx,
199
+ Ports extends AnyPorts,
200
+ ServiceInput,
201
+ >(
202
+ resolved: ResolvedServerContext<Ctx, Ports, ServiceInput>,
203
+ getPorts: () => Ports,
204
+ ): (seed: ContextSeed<Ctx> | Ctx) => Ctx {
205
+ const gateSelector = resolved.gate;
206
+ if (!gateSelector) {
207
+ return (seed) => seed as Ctx;
208
+ }
209
+
210
+ return (seed) => {
211
+ const target = seed as object;
212
+ const existing = Object.getOwnPropertyDescriptor(target, "gate");
213
+ if (existing && existing.get === undefined) {
214
+ if (process.env.NODE_ENV !== "production") {
215
+ console.warn(
216
+ "[beignet] Ignoring a hand-assigned ctx.gate value. The server context blueprint owns gate attachment; remove `gate` from context factories and hook additions.",
217
+ );
218
+ }
219
+ delete (target as { gate?: unknown }).gate;
220
+ }
221
+
222
+ return gateSelector(getPorts()).attach(target) as Ctx;
223
+ };
224
+ }
@@ -5,4 +5,4 @@ export {
5
5
  type ContractLike,
6
6
  type ResolveContract,
7
7
  resolveContract,
8
- } from "../contracts";
8
+ } from "../contracts/index.js";
@@ -3,8 +3,8 @@
3
3
  * Health check handler for Beignet server adapters.
4
4
  */
5
5
 
6
- import type { AnyPorts } from "../ports";
7
- import type { HttpRequestLike, HttpResponseLike } from "./types";
6
+ import type { AnyPorts } from "../ports/index.js";
7
+ import type { HttpRequestLike, HttpResponseLike } from "./types.js";
8
8
 
9
9
  /**
10
10
  * Health check result returned by health handlers.
@@ -1,205 +1,222 @@
1
- import {
2
- type AuthPort,
3
- type AuthSession,
4
- AuthUnauthorizedError,
5
- } from "../../ports";
6
- import type { HttpRequestLike, HttpResponse, ServerHook } from "../types";
1
+ import type { InferOutput, StandardSchema } from "../../contracts/index.js";
2
+ import { AuthUnauthorizedError } from "../../ports/index.js";
3
+ import type { HttpRequestLike, RouteHook } from "../types.js";
7
4
 
8
5
  type MaybePromise<T> = T | Promise<T>;
9
6
 
10
7
  /**
11
- * Authentication mode for one matched contract.
8
+ * Arguments passed to auth route-hook callbacks.
12
9
  */
13
- export type AuthHookMode = "public" | "optional" | "required";
14
-
15
- /**
16
- * Input accepted when resolving auth mode from contract metadata or options.
17
- *
18
- * `true` maps to `"required"`; `false`, `null`, and `undefined` map to
19
- * `"public"`.
20
- */
21
- export type AuthHookModeInput = AuthHookMode | boolean | null | undefined;
22
-
23
- /**
24
- * Minimal context shape required when `createAuthHooks(...)` reads
25
- * `ctx.ports.auth`.
26
- */
27
- export type CtxWithAuthPort = {
28
- ports: {
29
- auth: AuthPort;
30
- };
31
- };
32
-
33
- /**
34
- * Arguments passed to auth hook callbacks.
35
- */
36
- export type AuthHookArgs<Ctx> = {
10
+ export type AuthHookArgs<
11
+ Ctx,
12
+ HeadersSchema extends StandardSchema | undefined = undefined,
13
+ > = {
14
+ /**
15
+ * Framework-neutral request.
16
+ */
37
17
  req: HttpRequestLike;
18
+ /**
19
+ * Current route handler context.
20
+ */
38
21
  ctx: Ctx;
22
+ /**
23
+ * Matched contract metadata and schemas.
24
+ */
39
25
  contract: {
40
26
  metadata?: Record<string, unknown>;
41
27
  };
28
+ /**
29
+ * Parsed path parameters.
30
+ */
42
31
  path: unknown;
32
+ /**
33
+ * Parsed query parameters.
34
+ */
43
35
  query: unknown;
44
- headers: unknown;
36
+ /**
37
+ * Hook-owned request headers.
38
+ *
39
+ * When the auth hooks declare a `headers` schema, this is that schema's
40
+ * output parsed from the raw lowercase request header record. Without a
41
+ * schema it is the raw lowercase header record itself, so auth resolution
42
+ * never depends on each route's contract header schema.
43
+ */
44
+ headers: HeadersSchema extends StandardSchema
45
+ ? InferOutput<HeadersSchema>
46
+ : Record<string, string>;
47
+ /**
48
+ * Parsed request body.
49
+ */
45
50
  body: unknown;
46
51
  };
47
52
 
48
53
  /**
49
- * Arguments passed to the auth `assign` callback.
50
- */
51
- export type AuthHookAssignArgs<Ctx, Session> = AuthHookArgs<Ctx> & {
52
- session: Session | null;
53
- };
54
-
55
- /**
56
- * Arguments passed to the auth `unauthorized` callback.
57
- */
58
- export type AuthHookUnauthorizedArgs<Ctx, Session> = AuthHookArgs<Ctx> & {
59
- session: Session | null;
60
- };
61
-
62
- /**
63
- * Options for `createAuthHooks(...)`.
54
+ * Options for route-scoped auth hooks.
55
+ *
56
+ * Auth additions must not include `gate`: the server re-attaches the gate
57
+ * declared by the context blueprint after every hook, so elevated identities
58
+ * are authorized against the updated context automatically.
64
59
  */
65
- export type AuthHooksOptions<Ctx, Session> = {
60
+ export type AuthHooksOptions<
61
+ Ctx,
62
+ AddedCtx extends object & { gate?: never },
63
+ HeadersSchema extends StandardSchema | undefined = undefined,
64
+ > = {
66
65
  /**
67
- * Hook name used in diagnostics.
66
+ * Hook name prefix used in diagnostics.
68
67
  */
69
68
  name?: string;
70
69
  /**
71
- * Resolve whether the current contract is public, optional-auth, or required-auth.
70
+ * Optional Standard Schema for the credential headers this hook reads.
71
+ *
72
+ * The schema is validated against the raw lowercase request header record
73
+ * before `resolve` runs. On `required()` hooks a schema failure rejects the
74
+ * request with a framework-owned 401; on `optional()` hooks a schema failure
75
+ * skips auth resolution; `public()` hooks never parse headers.
72
76
  */
73
- mode?: (args: AuthHookArgs<Ctx>) => MaybePromise<AuthHookModeInput>;
77
+ headers?: HeadersSchema;
74
78
  /**
75
- * Custom session lookup. Required when context does not expose
76
- * `ctx.ports.auth`.
79
+ * Resolve authenticated context additions for the current request.
80
+ *
81
+ * Return `null` when the request is unauthenticated. Required hooks will
82
+ * reject that request; optional hooks will add no auth context.
77
83
  */
78
- getSession?: (args: AuthHookArgs<Ctx>) => MaybePromise<Session | null>;
84
+ resolve: (
85
+ args: AuthHookArgs<Ctx, HeadersSchema>,
86
+ ) => MaybePromise<AddedCtx | null>;
87
+ };
88
+
89
+ /**
90
+ * Route-scoped auth hook set.
91
+ */
92
+ export type AuthRouteHooks<Ctx, AddedCtx extends object & { gate?: never }> = {
79
93
  /**
80
- * Decide whether a resolved session counts as authenticated.
94
+ * Mark a route as intentionally public.
81
95
  */
82
- isAuthenticated?: (session: Session | null) => boolean;
96
+ public: () => RouteHook<Ctx, Record<string, never>>;
83
97
  /**
84
- * Return an updated context with auth/session fields attached.
98
+ * Resolve auth when present and add optional auth fields to the handler ctx.
85
99
  */
86
- assign?: (args: AuthHookAssignArgs<Ctx, Session>) => MaybePromise<Ctx>;
100
+ optional: () => RouteHook<Ctx, Partial<AddedCtx>>;
87
101
  /**
88
- * Return a custom unauthorized response for required-auth routes.
102
+ * Require auth and add authenticated fields to the handler ctx.
89
103
  */
90
- unauthorized?: (
91
- args: AuthHookUnauthorizedArgs<Ctx, Session>,
92
- ) => MaybePromise<HttpResponse>;
104
+ required: () => RouteHook<Ctx, AddedCtx>;
93
105
  };
94
106
 
95
- type InferAuthSession<TAuth> =
96
- TAuth extends AuthPort<infer User, infer SessionMetadata>
97
- ? AuthSession<User, SessionMetadata>
98
- : unknown;
99
-
100
- function modeFromInput(input: AuthHookModeInput): AuthHookMode {
101
- if (input === true || input === "required") return "required";
102
- if (input === "optional") return "optional";
103
- return "public";
107
+ function rawRequestHeaders(req: HttpRequestLike): Record<string, string> {
108
+ const record: Record<string, string> = {};
109
+ req.headers.forEach((value, key) => {
110
+ record[key.toLowerCase()] = value;
111
+ });
112
+ return record;
104
113
  }
105
114
 
106
- function defaultMode<Ctx>(args: AuthHookArgs<Ctx>): AuthHookMode {
107
- return modeFromInput(args.contract.metadata?.auth as AuthHookModeInput);
108
- }
115
+ type ParsedAuthHeaders = { ok: true; headers: unknown } | { ok: false };
109
116
 
110
- async function defaultGetSession<Ctx>(
111
- args: AuthHookArgs<Ctx>,
112
- ): Promise<unknown | null> {
113
- const auth = (args.ctx as { ports?: { auth?: AuthPort } }).ports?.auth;
114
- if (!auth) {
115
- throw new Error(
116
- "createAuthHooks requires ctx.ports.auth or an explicit getSession option.",
117
- );
117
+ async function parseAuthHeaders(
118
+ schema: StandardSchema | undefined,
119
+ req: HttpRequestLike,
120
+ ): Promise<ParsedAuthHeaders> {
121
+ const raw = rawRequestHeaders(req);
122
+ if (!schema) {
123
+ return { ok: true, headers: raw };
118
124
  }
119
125
 
120
- return auth.getSession(args.req);
121
- }
126
+ const result = await schema["~standard"].validate(raw);
127
+ if (result.issues) {
128
+ return { ok: false };
129
+ }
122
130
 
123
- function defaultIsAuthenticated<Session>(session: Session | null): boolean {
124
- return session !== null;
131
+ return { ok: true, headers: result.value };
125
132
  }
126
133
 
127
134
  /**
128
- * Create metadata-driven authentication hooks.
135
+ * Create route-scoped authentication hooks.
136
+ *
137
+ * The outer call binds the app context; the inner call takes auth options and
138
+ * infers the added context from `resolve`:
139
+ *
140
+ * ```ts
141
+ * const auth = createAuthHooks<AppContext>()({
142
+ * resolve: ({ ctx }) => (ctx.auth ? { user: ctx.auth.user } : null),
143
+ * });
144
+ * ```
145
+ *
146
+ * Use `auth.required()` on routes that require an authenticated actor and
147
+ * `auth.optional()` where handlers can use auth when present. The returned
148
+ * route hooks enrich handler `ctx`; business authorization still belongs in
149
+ * feature policies or use cases.
129
150
  *
130
- * By default the hook reads `contract.metadata.auth`: `"required"` or `true`
131
- * requires an authenticated session, `"optional"` attaches a session when one
132
- * exists, and missing/false metadata treats the route as public. The hook
133
- * identifies a user; business authorization still belongs in policies or use
134
- * cases.
151
+ * Declare a `headers` schema when credentials live in request headers. The
152
+ * hook validates the raw lowercase header record itself, so `resolve` receives
153
+ * typed headers without contract casts and a `required()` hook rejects
154
+ * missing or malformed credentials with a framework-owned 401.
135
155
  *
136
- * @param options - Optional auth mode, session lookup, context assignment, and
137
- * unauthorized response customization.
138
- * @returns A server hook that runs before route handlers.
156
+ * @returns A function that takes auth options and returns public, optional,
157
+ * and required route-hook factories.
139
158
  */
140
- export function createAuthHooks<Ctx extends CtxWithAuthPort>(
141
- options?: AuthHooksOptions<Ctx, InferAuthSession<Ctx["ports"]["auth"]>>,
142
- ): ServerHook<Ctx, Ctx["ports"]>;
143
- export function createAuthHooks<Ctx, Session>(
144
- options: AuthHooksOptions<Ctx, Session> & {
145
- getSession: (args: AuthHookArgs<Ctx>) => MaybePromise<Session | null>;
146
- },
147
- ): ServerHook<Ctx>;
148
- export function createAuthHooks<Ctx, Session>(
149
- options: AuthHooksOptions<Ctx, Session> = {},
150
- ): ServerHook<Ctx> {
151
- return {
152
- name: options.name ?? "auth",
153
- beforeHandle: async ({
154
- req,
155
- ctx,
156
- contract,
157
- path,
158
- query,
159
- headers,
160
- body,
161
- }) => {
162
- const args: AuthHookArgs<Ctx> = {
163
- req,
164
- ctx,
165
- contract,
166
- path,
167
- query,
159
+ export function createAuthHooks<Ctx>() {
160
+ return <
161
+ AddedCtx extends object & { gate?: never },
162
+ HeadersSchema extends StandardSchema | undefined = undefined,
163
+ >(
164
+ options: AuthHooksOptions<Ctx, AddedCtx, HeadersSchema>,
165
+ ): AuthRouteHooks<Ctx, AddedCtx> => {
166
+ const name = options.name ?? "auth";
167
+
168
+ const toAuthArgs = (
169
+ args: Parameters<RouteHook<Ctx, object>["resolve"]>[0],
170
+ headers: unknown,
171
+ ): AuthHookArgs<Ctx, HeadersSchema> =>
172
+ ({
173
+ req: args.req,
174
+ ctx: args.ctx,
175
+ contract: args.contract,
176
+ path: args.path,
177
+ query: args.query,
168
178
  headers,
169
- body,
170
- };
171
- const mode = modeFromInput(
172
- options.mode ? await options.mode(args) : defaultMode(args),
173
- );
174
-
175
- if (mode === "public") {
176
- return undefined;
177
- }
178
-
179
- const session = options.getSession
180
- ? await options.getSession(args)
181
- : ((await defaultGetSession(args)) as Session | null);
182
- const isAuthenticated =
183
- options.isAuthenticated?.(session) ?? defaultIsAuthenticated(session);
184
-
185
- if (mode === "required" && !isAuthenticated) {
186
- if (options.unauthorized) {
187
- return {
188
- ctx,
189
- response: await options.unauthorized({ ...args, session }),
190
- };
191
- }
192
-
193
- throw new AuthUnauthorizedError();
194
- }
195
-
196
- if (!options.assign) {
197
- return undefined;
198
- }
199
-
200
- return {
201
- ctx: await options.assign({ ...args, session }),
202
- };
203
- },
179
+ body: args.body,
180
+ }) as AuthHookArgs<Ctx, HeadersSchema>;
181
+
182
+ return {
183
+ public: () => ({
184
+ name: `${name}.public`,
185
+ resolve: () => undefined,
186
+ }),
187
+ optional: () => ({
188
+ name: `${name}.optional`,
189
+ resolve: async (args) => {
190
+ const parsed = await parseAuthHeaders(options.headers, args.req);
191
+ if (!parsed.ok) {
192
+ return undefined;
193
+ }
194
+
195
+ const additions = await options.resolve(
196
+ toAuthArgs(args, parsed.headers),
197
+ );
198
+
199
+ return additions ?? undefined;
200
+ },
201
+ }),
202
+ required: () => ({
203
+ name: `${name}.required`,
204
+ resolve: async (args) => {
205
+ const parsed = await parseAuthHeaders(options.headers, args.req);
206
+ if (!parsed.ok) {
207
+ throw new AuthUnauthorizedError();
208
+ }
209
+
210
+ const additions = await options.resolve(
211
+ toAuthArgs(args, parsed.headers),
212
+ );
213
+ if (!additions) {
214
+ throw new AuthUnauthorizedError();
215
+ }
216
+
217
+ return additions;
218
+ },
219
+ }),
220
+ };
204
221
  };
205
222
  }
@@ -2,7 +2,7 @@
2
2
  * CORS hook utilities for @beignet/core/server
3
3
  */
4
4
 
5
- import type { HttpRequestLike, ServerHook } from "../types";
5
+ import type { HttpRequestLike, ServerHook } from "../types.js";
6
6
 
7
7
  /**
8
8
  * CORS configuration for `createCorsHooks(...)`.
@@ -2,14 +2,17 @@
2
2
  * Framework-agnostic error mapping utilities for @beignet/core/server
3
3
  */
4
4
 
5
- import { createErrorResponseBody, type ErrorResponseBody } from "../../errors";
6
- import type { AppEnvironment } from "../health";
7
- import { getRequestIdFromContext } from "./utils";
5
+ import {
6
+ createErrorResponseBody,
7
+ type ErrorResponseBody,
8
+ } from "../../errors/index.js";
9
+ import type { AppEnvironment } from "../health.js";
10
+ import { getRequestIdFromContext } from "./utils.js";
8
11
 
9
12
  /**
10
13
  * Re-export `AppEnvironment` for convenience.
11
14
  */
12
- export type { AppEnvironment } from "../health";
15
+ export type { AppEnvironment } from "../health.js";
13
16
 
14
17
  /**
15
18
  * Framework-neutral response produced by an error mapper.