@beignet/core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +288 -0
  3. package/dist/application/index.d.ts +260 -0
  4. package/dist/application/index.d.ts.map +1 -0
  5. package/dist/application/index.js +324 -0
  6. package/dist/application/index.js.map +1 -0
  7. package/dist/client/client.d.ts +241 -0
  8. package/dist/client/client.d.ts.map +1 -0
  9. package/dist/client/client.js +531 -0
  10. package/dist/client/client.js.map +1 -0
  11. package/dist/client/index.d.ts +10 -0
  12. package/dist/client/index.d.ts.map +1 -0
  13. package/dist/client/index.js +8 -0
  14. package/dist/client/index.js.map +1 -0
  15. package/dist/client/types.d.ts +139 -0
  16. package/dist/client/types.d.ts.map +1 -0
  17. package/dist/client/types.js +2 -0
  18. package/dist/client/types.js.map +1 -0
  19. package/dist/config/index.d.ts +122 -0
  20. package/dist/config/index.d.ts.map +1 -0
  21. package/dist/config/index.js +216 -0
  22. package/dist/config/index.js.map +1 -0
  23. package/dist/contracts/contract-builder.d.ts +121 -0
  24. package/dist/contracts/contract-builder.d.ts.map +1 -0
  25. package/dist/contracts/contract-builder.js +346 -0
  26. package/dist/contracts/contract-builder.js.map +1 -0
  27. package/dist/contracts/contract-group.d.ts +106 -0
  28. package/dist/contracts/contract-group.d.ts.map +1 -0
  29. package/dist/contracts/contract-group.js +240 -0
  30. package/dist/contracts/contract-group.js.map +1 -0
  31. package/dist/contracts/contract-like.d.ts +21 -0
  32. package/dist/contracts/contract-like.d.ts.map +1 -0
  33. package/dist/contracts/contract-like.js +9 -0
  34. package/dist/contracts/contract-like.js.map +1 -0
  35. package/dist/contracts/index.d.ts +15 -0
  36. package/dist/contracts/index.d.ts.map +1 -0
  37. package/dist/contracts/index.js +11 -0
  38. package/dist/contracts/index.js.map +1 -0
  39. package/dist/contracts/openapi-meta.d.ts +23 -0
  40. package/dist/contracts/openapi-meta.d.ts.map +1 -0
  41. package/dist/contracts/openapi-meta.js +2 -0
  42. package/dist/contracts/openapi-meta.js.map +1 -0
  43. package/dist/contracts/path-template.d.ts +17 -0
  44. package/dist/contracts/path-template.d.ts.map +1 -0
  45. package/dist/contracts/path-template.js +50 -0
  46. package/dist/contracts/path-template.js.map +1 -0
  47. package/dist/contracts/rate-limit.d.ts +50 -0
  48. package/dist/contracts/rate-limit.d.ts.map +1 -0
  49. package/dist/contracts/rate-limit.js +2 -0
  50. package/dist/contracts/rate-limit.js.map +1 -0
  51. package/dist/contracts/types.d.ts +97 -0
  52. package/dist/contracts/types.d.ts.map +1 -0
  53. package/dist/contracts/types.js +54 -0
  54. package/dist/contracts/types.js.map +1 -0
  55. package/dist/contracts/utils.d.ts +3 -0
  56. package/dist/contracts/utils.d.ts.map +1 -0
  57. package/dist/contracts/utils.js +44 -0
  58. package/dist/contracts/utils.js.map +1 -0
  59. package/dist/domain/entity.d.ts +87 -0
  60. package/dist/domain/entity.d.ts.map +1 -0
  61. package/dist/domain/entity.js +155 -0
  62. package/dist/domain/entity.js.map +1 -0
  63. package/dist/domain/events.d.ts +41 -0
  64. package/dist/domain/events.d.ts.map +1 -0
  65. package/dist/domain/events.js +21 -0
  66. package/dist/domain/events.js.map +1 -0
  67. package/dist/domain/index.d.ts +14 -0
  68. package/dist/domain/index.d.ts.map +1 -0
  69. package/dist/domain/index.js +14 -0
  70. package/dist/domain/index.js.map +1 -0
  71. package/dist/domain/value-object.d.ts +60 -0
  72. package/dist/domain/value-object.d.ts.map +1 -0
  73. package/dist/domain/value-object.js +87 -0
  74. package/dist/domain/value-object.js.map +1 -0
  75. package/dist/errors/catalog.d.ts +71 -0
  76. package/dist/errors/catalog.d.ts.map +1 -0
  77. package/dist/errors/catalog.js +71 -0
  78. package/dist/errors/catalog.js.map +1 -0
  79. package/dist/errors/http.d.ts +77 -0
  80. package/dist/errors/http.d.ts.map +1 -0
  81. package/dist/errors/http.js +74 -0
  82. package/dist/errors/http.js.map +1 -0
  83. package/dist/errors/index.d.ts +10 -0
  84. package/dist/errors/index.d.ts.map +1 -0
  85. package/dist/errors/index.js +14 -0
  86. package/dist/errors/index.js.map +1 -0
  87. package/dist/errors/response.d.ts +26 -0
  88. package/dist/errors/response.d.ts.map +1 -0
  89. package/dist/errors/response.js +34 -0
  90. package/dist/errors/response.js.map +1 -0
  91. package/dist/errors/validation.d.ts +18 -0
  92. package/dist/errors/validation.d.ts.map +1 -0
  93. package/dist/errors/validation.js +21 -0
  94. package/dist/errors/validation.js.map +1 -0
  95. package/dist/events/index.d.ts +58 -0
  96. package/dist/events/index.d.ts.map +1 -0
  97. package/dist/events/index.js +102 -0
  98. package/dist/events/index.js.map +1 -0
  99. package/dist/jobs/index.d.ts +56 -0
  100. package/dist/jobs/index.d.ts.map +1 -0
  101. package/dist/jobs/index.js +89 -0
  102. package/dist/jobs/index.js.map +1 -0
  103. package/dist/mail/index.d.ts +75 -0
  104. package/dist/mail/index.d.ts.map +1 -0
  105. package/dist/mail/index.js +84 -0
  106. package/dist/mail/index.js.map +1 -0
  107. package/dist/openapi/index.d.ts +207 -0
  108. package/dist/openapi/index.d.ts.map +1 -0
  109. package/dist/openapi/index.js +449 -0
  110. package/dist/openapi/index.js.map +1 -0
  111. package/dist/openapi/schema-introspector.d.ts +38 -0
  112. package/dist/openapi/schema-introspector.d.ts.map +1 -0
  113. package/dist/openapi/schema-introspector.js +67 -0
  114. package/dist/openapi/schema-introspector.js.map +1 -0
  115. package/dist/ports/audit.d.ts +58 -0
  116. package/dist/ports/audit.d.ts.map +1 -0
  117. package/dist/ports/audit.js +74 -0
  118. package/dist/ports/audit.js.map +1 -0
  119. package/dist/ports/auth.d.ts +23 -0
  120. package/dist/ports/auth.d.ts.map +1 -0
  121. package/dist/ports/auth.js +31 -0
  122. package/dist/ports/auth.js.map +1 -0
  123. package/dist/ports/builder.d.ts +61 -0
  124. package/dist/ports/builder.d.ts.map +1 -0
  125. package/dist/ports/builder.js +48 -0
  126. package/dist/ports/builder.js.map +1 -0
  127. package/dist/ports/cache.d.ts +15 -0
  128. package/dist/ports/cache.d.ts.map +1 -0
  129. package/dist/ports/cache.js +57 -0
  130. package/dist/ports/cache.js.map +1 -0
  131. package/dist/ports/clock.d.ts +10 -0
  132. package/dist/ports/clock.d.ts.map +1 -0
  133. package/dist/ports/clock.js +21 -0
  134. package/dist/ports/clock.js.map +1 -0
  135. package/dist/ports/events.d.ts +71 -0
  136. package/dist/ports/events.d.ts.map +1 -0
  137. package/dist/ports/events.js +2 -0
  138. package/dist/ports/events.js.map +1 -0
  139. package/dist/ports/id-generator.d.ts +12 -0
  140. package/dist/ports/id-generator.d.ts.map +1 -0
  141. package/dist/ports/id-generator.js +22 -0
  142. package/dist/ports/id-generator.js.map +1 -0
  143. package/dist/ports/index.d.ts +98 -0
  144. package/dist/ports/index.d.ts.map +1 -0
  145. package/dist/ports/index.js +67 -0
  146. package/dist/ports/index.js.map +1 -0
  147. package/dist/ports/logger.d.ts +22 -0
  148. package/dist/ports/logger.d.ts.map +1 -0
  149. package/dist/ports/logger.js +34 -0
  150. package/dist/ports/logger.js.map +1 -0
  151. package/dist/ports/mailer.d.ts +6 -0
  152. package/dist/ports/mailer.d.ts.map +1 -0
  153. package/dist/ports/mailer.js +2 -0
  154. package/dist/ports/mailer.js.map +1 -0
  155. package/dist/ports/policy.d.ts +53 -0
  156. package/dist/ports/policy.d.ts.map +1 -0
  157. package/dist/ports/policy.js +81 -0
  158. package/dist/ports/policy.js.map +1 -0
  159. package/dist/ports/rate-limit.d.ts +41 -0
  160. package/dist/ports/rate-limit.d.ts.map +1 -0
  161. package/dist/ports/rate-limit.js +37 -0
  162. package/dist/ports/rate-limit.js.map +1 -0
  163. package/dist/ports/redaction.d.ts +26 -0
  164. package/dist/ports/redaction.d.ts.map +1 -0
  165. package/dist/ports/redaction.js +126 -0
  166. package/dist/ports/redaction.js.map +1 -0
  167. package/dist/ports/schedules.d.ts +9 -0
  168. package/dist/ports/schedules.d.ts.map +1 -0
  169. package/dist/ports/schedules.js +2 -0
  170. package/dist/ports/schedules.js.map +1 -0
  171. package/dist/ports/storage.d.ts +47 -0
  172. package/dist/ports/storage.d.ts.map +1 -0
  173. package/dist/ports/storage.js +185 -0
  174. package/dist/ports/storage.js.map +1 -0
  175. package/dist/ports/testing.d.ts +73 -0
  176. package/dist/ports/testing.d.ts.map +1 -0
  177. package/dist/ports/testing.js +105 -0
  178. package/dist/ports/testing.js.map +1 -0
  179. package/dist/ports/unit-of-work.d.ts +56 -0
  180. package/dist/ports/unit-of-work.d.ts.map +1 -0
  181. package/dist/ports/unit-of-work.js +64 -0
  182. package/dist/ports/unit-of-work.js.map +1 -0
  183. package/dist/providers/index.d.ts +8 -0
  184. package/dist/providers/index.d.ts.map +1 -0
  185. package/dist/providers/index.js +8 -0
  186. package/dist/providers/index.js.map +1 -0
  187. package/dist/providers/instrumentation.d.ts +91 -0
  188. package/dist/providers/instrumentation.d.ts.map +1 -0
  189. package/dist/providers/instrumentation.js +93 -0
  190. package/dist/providers/instrumentation.js.map +1 -0
  191. package/dist/providers/provider.d.ts +146 -0
  192. package/dist/providers/provider.d.ts.map +1 -0
  193. package/dist/providers/provider.js +31 -0
  194. package/dist/providers/provider.js.map +1 -0
  195. package/dist/schedules/index.d.ts +105 -0
  196. package/dist/schedules/index.d.ts.map +1 -0
  197. package/dist/schedules/index.js +178 -0
  198. package/dist/schedules/index.js.map +1 -0
  199. package/dist/server/contract-like.d.ts +5 -0
  200. package/dist/server/contract-like.d.ts.map +1 -0
  201. package/dist/server/contract-like.js +5 -0
  202. package/dist/server/contract-like.js.map +1 -0
  203. package/dist/server/health.d.ts +41 -0
  204. package/dist/server/health.d.ts.map +1 -0
  205. package/dist/server/health.js +46 -0
  206. package/dist/server/health.js.map +1 -0
  207. package/dist/server/hooks/auth.d.ts +42 -0
  208. package/dist/server/hooks/auth.d.ts.map +1 -0
  209. package/dist/server/hooks/auth.js +61 -0
  210. package/dist/server/hooks/auth.js.map +1 -0
  211. package/dist/server/hooks/cors.d.ts +13 -0
  212. package/dist/server/hooks/cors.d.ts.map +1 -0
  213. package/dist/server/hooks/cors.js +70 -0
  214. package/dist/server/hooks/cors.js.map +1 -0
  215. package/dist/server/hooks/errors.d.ts +66 -0
  216. package/dist/server/hooks/errors.d.ts.map +1 -0
  217. package/dist/server/hooks/errors.js +83 -0
  218. package/dist/server/hooks/errors.js.map +1 -0
  219. package/dist/server/hooks/index.d.ts +12 -0
  220. package/dist/server/hooks/index.d.ts.map +1 -0
  221. package/dist/server/hooks/index.js +12 -0
  222. package/dist/server/hooks/index.js.map +1 -0
  223. package/dist/server/hooks/logging.d.ts +33 -0
  224. package/dist/server/hooks/logging.d.ts.map +1 -0
  225. package/dist/server/hooks/logging.js +90 -0
  226. package/dist/server/hooks/logging.js.map +1 -0
  227. package/dist/server/hooks/rate-limit.d.ts +29 -0
  228. package/dist/server/hooks/rate-limit.d.ts.map +1 -0
  229. package/dist/server/hooks/rate-limit.js +93 -0
  230. package/dist/server/hooks/rate-limit.js.map +1 -0
  231. package/dist/server/hooks/utils.d.ts +9 -0
  232. package/dist/server/hooks/utils.d.ts.map +1 -0
  233. package/dist/server/hooks/utils.js +16 -0
  234. package/dist/server/hooks/utils.js.map +1 -0
  235. package/dist/server/hooks.d.ts +2 -0
  236. package/dist/server/hooks.d.ts.map +1 -0
  237. package/dist/server/hooks.js +2 -0
  238. package/dist/server/hooks.js.map +1 -0
  239. package/dist/server/http.d.ts +124 -0
  240. package/dist/server/http.d.ts.map +1 -0
  241. package/dist/server/http.js +2 -0
  242. package/dist/server/http.js.map +1 -0
  243. package/dist/server/index.d.ts +19 -0
  244. package/dist/server/index.d.ts.map +1 -0
  245. package/dist/server/index.js +15 -0
  246. package/dist/server/index.js.map +1 -0
  247. package/dist/server/openapi.d.ts +32 -0
  248. package/dist/server/openapi.d.ts.map +1 -0
  249. package/dist/server/openapi.js +43 -0
  250. package/dist/server/openapi.js.map +1 -0
  251. package/dist/server/providers/index.d.ts +4 -0
  252. package/dist/server/providers/index.d.ts.map +1 -0
  253. package/dist/server/providers/index.js +4 -0
  254. package/dist/server/providers/index.js.map +1 -0
  255. package/dist/server/providers/loadProviderConfig.d.ts +7 -0
  256. package/dist/server/providers/loadProviderConfig.d.ts.map +1 -0
  257. package/dist/server/providers/loadProviderConfig.js +42 -0
  258. package/dist/server/providers/loadProviderConfig.js.map +1 -0
  259. package/dist/server/server.d.ts +86 -0
  260. package/dist/server/server.d.ts.map +1 -0
  261. package/dist/server/server.js +1031 -0
  262. package/dist/server/server.js.map +1 -0
  263. package/dist/server/types.d.ts +3 -0
  264. package/dist/server/types.d.ts.map +1 -0
  265. package/dist/server/types.js +3 -0
  266. package/dist/server/types.js.map +1 -0
  267. package/package.json +129 -0
  268. package/src/application/index.ts +747 -0
  269. package/src/client/client.ts +1105 -0
  270. package/src/client/index.ts +45 -0
  271. package/src/client/types.ts +305 -0
  272. package/src/config/index.ts +497 -0
  273. package/src/contracts/contract-builder.ts +583 -0
  274. package/src/contracts/contract-group.ts +502 -0
  275. package/src/contracts/contract-like.ts +29 -0
  276. package/src/contracts/index.ts +53 -0
  277. package/src/contracts/openapi-meta.ts +22 -0
  278. package/src/contracts/path-template.ts +91 -0
  279. package/src/contracts/rate-limit.ts +50 -0
  280. package/src/contracts/types.ts +207 -0
  281. package/src/contracts/utils.ts +56 -0
  282. package/src/domain/entity.ts +256 -0
  283. package/src/domain/events.ts +52 -0
  284. package/src/domain/index.ts +18 -0
  285. package/src/domain/value-object.ts +135 -0
  286. package/src/errors/catalog.ts +149 -0
  287. package/src/errors/http.ts +80 -0
  288. package/src/errors/index.ts +28 -0
  289. package/src/errors/response.ts +54 -0
  290. package/src/errors/validation.ts +35 -0
  291. package/src/events/index.ts +246 -0
  292. package/src/jobs/index.ts +211 -0
  293. package/src/mail/index.ts +177 -0
  294. package/src/openapi/index.ts +865 -0
  295. package/src/openapi/schema-introspector.ts +107 -0
  296. package/src/ports/audit.ts +176 -0
  297. package/src/ports/auth.ts +76 -0
  298. package/src/ports/builder.ts +97 -0
  299. package/src/ports/cache.ts +94 -0
  300. package/src/ports/clock.ts +34 -0
  301. package/src/ports/events.ts +100 -0
  302. package/src/ports/id-generator.ts +36 -0
  303. package/src/ports/index.ts +221 -0
  304. package/src/ports/logger.ts +67 -0
  305. package/src/ports/policy.ts +242 -0
  306. package/src/ports/rate-limit.ts +91 -0
  307. package/src/ports/redaction.ts +199 -0
  308. package/src/ports/storage.ts +282 -0
  309. package/src/ports/testing.ts +234 -0
  310. package/src/ports/unit-of-work.ts +134 -0
  311. package/src/providers/index.ts +40 -0
  312. package/src/providers/instrumentation.ts +248 -0
  313. package/src/providers/provider.ts +191 -0
  314. package/src/schedules/index.ts +442 -0
  315. package/src/server/contract-like.ts +8 -0
  316. package/src/server/health.ts +82 -0
  317. package/src/server/hooks/auth.ts +147 -0
  318. package/src/server/hooks/cors.ts +87 -0
  319. package/src/server/hooks/errors.ts +126 -0
  320. package/src/server/hooks/index.ts +43 -0
  321. package/src/server/hooks/logging.ts +121 -0
  322. package/src/server/hooks/rate-limit.ts +171 -0
  323. package/src/server/hooks/utils.ts +16 -0
  324. package/src/server/hooks.ts +1 -0
  325. package/src/server/http.ts +189 -0
  326. package/src/server/index.ts +35 -0
  327. package/src/server/openapi.ts +72 -0
  328. package/src/server/providers/index.ts +3 -0
  329. package/src/server/providers/loadProviderConfig.ts +72 -0
  330. package/src/server/server.ts +1521 -0
  331. package/src/server/types.ts +2 -0
@@ -0,0 +1,134 @@
1
+ import { parseEventPayload } from "../events";
2
+ import type { DomainEventDef, EventBusPort, InferEventPayload } from "./events";
3
+
4
+ type MaybePromise<T> = T | Promise<T>;
5
+
6
+ export type UnitOfWorkCallback<TxPorts, Result> = (
7
+ tx: TxPorts,
8
+ ) => MaybePromise<Result>;
9
+
10
+ /**
11
+ * A transaction boundary for application workflows.
12
+ *
13
+ * The transaction ports are app-owned. A database adapter can provide
14
+ * transaction-scoped repositories, while test or in-memory adapters can use
15
+ * `createNoopUnitOfWork`.
16
+ */
17
+ export interface UnitOfWorkPort<TxPorts> {
18
+ transaction<Result>(
19
+ work: UnitOfWorkCallback<TxPorts, Result>,
20
+ ): Promise<Result>;
21
+ }
22
+
23
+ export interface NoopUnitOfWorkOptions<TxPorts> {
24
+ /**
25
+ * Runs after the callback completes successfully.
26
+ *
27
+ * Use this to flush buffered domain events after the work has committed.
28
+ */
29
+ afterCommit?: (tx: TxPorts) => MaybePromise<void>;
30
+
31
+ /**
32
+ * Runs after the callback throws.
33
+ *
34
+ * Use this to clear buffers or release test resources. The original error is
35
+ * rethrown after this hook runs.
36
+ */
37
+ afterRollback?: (error: unknown, tx: TxPorts) => MaybePromise<void>;
38
+ }
39
+
40
+ export interface RecordedDomainEvent {
41
+ event: DomainEventDef;
42
+ eventName: string;
43
+ payload: unknown;
44
+ }
45
+
46
+ export interface DomainEventRecorderPort {
47
+ record<E extends DomainEventDef>(
48
+ event: E,
49
+ payload: InferEventPayload<E>,
50
+ ): void;
51
+ }
52
+
53
+ export interface BufferedDomainEventRecorder extends DomainEventRecorderPort {
54
+ entries(): readonly RecordedDomainEvent[];
55
+ clear(): void;
56
+ flush(eventBus: EventBusPort): Promise<void>;
57
+ }
58
+
59
+ /**
60
+ * Create a simple Unit of Work implementation for tests, in-memory adapters,
61
+ * and infrastructure that already handles transactions elsewhere.
62
+ *
63
+ * This helper does not create database transactions. It gives applications the
64
+ * same UOW shape everywhere and runs commit/rollback hooks around the callback.
65
+ */
66
+ export function createNoopUnitOfWork<TxPorts>(
67
+ txPortsOrFactory: TxPorts | (() => TxPorts),
68
+ options: NoopUnitOfWorkOptions<TxPorts> = {},
69
+ ): UnitOfWorkPort<TxPorts> {
70
+ const createTxPorts =
71
+ typeof txPortsOrFactory === "function"
72
+ ? (txPortsOrFactory as () => TxPorts)
73
+ : () => txPortsOrFactory;
74
+
75
+ return {
76
+ async transaction<Result>(
77
+ work: UnitOfWorkCallback<TxPorts, Result>,
78
+ ): Promise<Result> {
79
+ const tx = createTxPorts();
80
+
81
+ let result: Result;
82
+
83
+ try {
84
+ result = await work(tx);
85
+ } catch (error) {
86
+ try {
87
+ await options.afterRollback?.(error, tx);
88
+ } catch {
89
+ // Preserve the application error that caused the rollback path.
90
+ }
91
+
92
+ throw error;
93
+ }
94
+
95
+ await options.afterCommit?.(tx);
96
+ return result;
97
+ },
98
+ };
99
+ }
100
+
101
+ /**
102
+ * Buffer domain events during a transaction and publish them only after the
103
+ * owning Unit of Work commits.
104
+ */
105
+ export function createDomainEventRecorder(): BufferedDomainEventRecorder {
106
+ const records: RecordedDomainEvent[] = [];
107
+
108
+ return {
109
+ record(event, payload) {
110
+ records.push({
111
+ event,
112
+ eventName: event.name,
113
+ payload,
114
+ });
115
+ },
116
+
117
+ entries() {
118
+ return records;
119
+ },
120
+
121
+ clear() {
122
+ records.length = 0;
123
+ },
124
+
125
+ async flush(eventBus) {
126
+ while (records.length > 0) {
127
+ const record = records[0];
128
+ const payload = await parseEventPayload(record.event, record.payload);
129
+ await eventBus.publish(record.event, payload);
130
+ records.shift();
131
+ }
132
+ },
133
+ };
134
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @beignet/core/providers
3
+ *
4
+ * Provider lifecycle and instrumentation primitives for Beignet.
5
+ */
6
+
7
+ export {
8
+ type BaseProviderInstrumentationEvent,
9
+ type CustomProviderInstrumentationEvent,
10
+ createProviderInstrumentation,
11
+ type ErrorProviderInstrumentationEvent,
12
+ type EventBusProviderInstrumentationEvent,
13
+ isProviderInstrumentation,
14
+ isProviderInstrumentationPort,
15
+ type JobProviderInstrumentationEvent,
16
+ type ProviderCustomInstrumentationEventInput,
17
+ type ProviderInstrumentation,
18
+ type ProviderInstrumentationEvent,
19
+ type ProviderInstrumentationEventInput,
20
+ type ProviderInstrumentationOptions,
21
+ type ProviderInstrumentationPort,
22
+ type ProviderInstrumentationTarget,
23
+ type ProviderInstrumentationWatcherName,
24
+ type ProviderLifecycleInstrumentationEvent,
25
+ type RequestProviderInstrumentationEvent,
26
+ resolveProviderInstrumentationPort,
27
+ type ScheduleProviderInstrumentationEvent,
28
+ type UseCaseProviderInstrumentationEvent,
29
+ } from "./instrumentation";
30
+ export {
31
+ createProvider,
32
+ type InferOutput,
33
+ type MaybePromise,
34
+ type ProvidedPortsOf,
35
+ type ProvidedPortsOfList,
36
+ type ProviderConfigDef,
37
+ type ProviderLifecycleContext,
38
+ type ProviderSetupResult,
39
+ type ServiceProvider,
40
+ } from "./provider";
@@ -0,0 +1,248 @@
1
+ import { type Redactor, redactValue } from "../ports/redaction";
2
+
3
+ export type ProviderInstrumentationWatcherName = string;
4
+
5
+ export interface BaseProviderInstrumentationEvent {
6
+ id?: string;
7
+ timestamp?: string;
8
+ requestId?: string;
9
+ traceId?: string;
10
+ spanId?: string;
11
+ parentSpanId?: string;
12
+ traceparent?: string;
13
+ watcher?: ProviderInstrumentationWatcherName;
14
+ details?: unknown;
15
+ }
16
+
17
+ export interface RequestProviderInstrumentationEvent
18
+ extends BaseProviderInstrumentationEvent {
19
+ type: "request";
20
+ method: string;
21
+ path: string;
22
+ contractName?: string;
23
+ status?: number;
24
+ durationMs?: number;
25
+ summary?: string;
26
+ }
27
+
28
+ export interface ErrorProviderInstrumentationEvent
29
+ extends BaseProviderInstrumentationEvent {
30
+ type: "error";
31
+ message: string;
32
+ stack?: string;
33
+ contractName?: string;
34
+ useCaseName?: string;
35
+ }
36
+
37
+ export interface UseCaseProviderInstrumentationEvent
38
+ extends BaseProviderInstrumentationEvent {
39
+ type: "usecase";
40
+ name: string;
41
+ kind?: "command" | "query";
42
+ phase: "start" | "end" | "error";
43
+ durationMs?: number;
44
+ error?: string;
45
+ }
46
+
47
+ export interface EventBusProviderInstrumentationEvent
48
+ extends BaseProviderInstrumentationEvent {
49
+ type: "eventBus";
50
+ eventName: string;
51
+ }
52
+
53
+ export interface JobProviderInstrumentationEvent
54
+ extends BaseProviderInstrumentationEvent {
55
+ type: "job";
56
+ jobName: string;
57
+ status: "scheduled" | "started" | "completed" | "failed";
58
+ }
59
+
60
+ export interface ScheduleProviderInstrumentationEvent
61
+ extends BaseProviderInstrumentationEvent {
62
+ type: "schedule";
63
+ scheduleName: string;
64
+ status: "started" | "completed" | "failed";
65
+ cron?: string;
66
+ timezone?: string;
67
+ }
68
+
69
+ export interface ProviderLifecycleInstrumentationEvent
70
+ extends BaseProviderInstrumentationEvent {
71
+ type: "provider";
72
+ providerName: string;
73
+ action: "setup" | "start" | "stop";
74
+ }
75
+
76
+ export interface CustomProviderInstrumentationEvent
77
+ extends BaseProviderInstrumentationEvent {
78
+ type: "custom";
79
+ name: string;
80
+ label?: string;
81
+ summary?: string;
82
+ }
83
+
84
+ export type ProviderInstrumentationEvent =
85
+ | RequestProviderInstrumentationEvent
86
+ | ErrorProviderInstrumentationEvent
87
+ | UseCaseProviderInstrumentationEvent
88
+ | EventBusProviderInstrumentationEvent
89
+ | JobProviderInstrumentationEvent
90
+ | ScheduleProviderInstrumentationEvent
91
+ | ProviderLifecycleInstrumentationEvent
92
+ | CustomProviderInstrumentationEvent;
93
+
94
+ export type ProviderInstrumentationEventInput = ProviderInstrumentationEvent;
95
+
96
+ export type ProviderCustomInstrumentationEventInput = Omit<
97
+ CustomProviderInstrumentationEvent,
98
+ "type"
99
+ >;
100
+
101
+ export interface ProviderInstrumentationPort<
102
+ EventInput extends
103
+ ProviderInstrumentationEventInput = ProviderInstrumentationEventInput,
104
+ WatcherName extends string = ProviderInstrumentationWatcherName,
105
+ RecordResult = unknown,
106
+ > {
107
+ record(event: EventInput): RecordResult;
108
+ isWatcherEnabled?(name: WatcherName): boolean;
109
+ }
110
+
111
+ export interface ProviderInstrumentationOptions {
112
+ providerName: string;
113
+ watcher?: ProviderInstrumentationWatcherName;
114
+ redact?: Redactor<ProviderInstrumentationEventInput>;
115
+ }
116
+
117
+ export interface ProviderInstrumentation {
118
+ port: ProviderInstrumentationPort | undefined;
119
+ isEnabled(watcher?: ProviderInstrumentationWatcherName): boolean;
120
+ record(event: ProviderInstrumentationEventInput): unknown;
121
+ custom(event: ProviderCustomInstrumentationEventInput): unknown;
122
+ }
123
+
124
+ export type ProviderInstrumentationTarget =
125
+ | ProviderInstrumentationPort
126
+ | ProviderInstrumentation
127
+ | {
128
+ devtools?: ProviderInstrumentationPort | ProviderInstrumentation;
129
+ instrumentation?: ProviderInstrumentationPort | ProviderInstrumentation;
130
+ }
131
+ | undefined;
132
+
133
+ function isObject(value: unknown): value is Record<string, unknown> {
134
+ return typeof value === "object" && value !== null;
135
+ }
136
+
137
+ export function isProviderInstrumentation(
138
+ value: unknown,
139
+ ): value is ProviderInstrumentation {
140
+ return (
141
+ isObject(value) &&
142
+ typeof value.record === "function" &&
143
+ typeof value.custom === "function" &&
144
+ typeof value.isEnabled === "function"
145
+ );
146
+ }
147
+
148
+ export function isProviderInstrumentationPort(
149
+ value: unknown,
150
+ ): value is ProviderInstrumentationPort {
151
+ return isObject(value) && typeof value.record === "function";
152
+ }
153
+
154
+ function resolveProviderInstrumentationValue(
155
+ value: unknown,
156
+ ): ProviderInstrumentationPort | undefined {
157
+ if (isProviderInstrumentation(value)) return value.port;
158
+ if (isProviderInstrumentationPort(value)) return value;
159
+ return undefined;
160
+ }
161
+
162
+ export function resolveProviderInstrumentationPort(
163
+ target: ProviderInstrumentationTarget,
164
+ ): ProviderInstrumentationPort | undefined {
165
+ if (!target) return undefined;
166
+
167
+ const directPort = resolveProviderInstrumentationValue(target);
168
+ if (directPort) return directPort;
169
+
170
+ if (!isObject(target)) return undefined;
171
+
172
+ return (
173
+ resolveProviderInstrumentationValue(target.instrumentation) ??
174
+ resolveProviderInstrumentationValue(target.devtools)
175
+ );
176
+ }
177
+
178
+ function withProviderDetails(providerName: string, details: unknown): unknown {
179
+ if (details === undefined) {
180
+ return { providerName };
181
+ }
182
+
183
+ if (isObject(details) && !Array.isArray(details)) {
184
+ return { ...details, providerName };
185
+ }
186
+
187
+ return { providerName, value: details };
188
+ }
189
+
190
+ export function createProviderInstrumentation(
191
+ target: ProviderInstrumentationTarget,
192
+ options: ProviderInstrumentationOptions,
193
+ ): ProviderInstrumentation {
194
+ if (isProviderInstrumentation(target)) {
195
+ return target;
196
+ }
197
+
198
+ const port = resolveProviderInstrumentationPort(target);
199
+
200
+ function isEnabled(watcher = options.watcher): boolean {
201
+ if (!port) return false;
202
+ if (!watcher) return true;
203
+ return port.isWatcherEnabled?.(watcher) ?? true;
204
+ }
205
+
206
+ function record(event: ProviderInstrumentationEventInput): unknown {
207
+ if (!port) return undefined;
208
+
209
+ const watcher = event.watcher ?? options.watcher;
210
+ if (watcher && !isEnabled(watcher)) return undefined;
211
+
212
+ const eventWithWatcher =
213
+ options.watcher && event.watcher === undefined
214
+ ? { ...event, watcher: options.watcher }
215
+ : event;
216
+
217
+ let redacted: ProviderInstrumentationEventInput;
218
+ try {
219
+ redacted = options.redact
220
+ ? options.redact(redactValue(eventWithWatcher))
221
+ : redactValue(eventWithWatcher);
222
+ } catch {
223
+ return undefined;
224
+ }
225
+
226
+ try {
227
+ return port.record(redacted);
228
+ } catch {
229
+ return undefined;
230
+ }
231
+ }
232
+
233
+ function custom(event: ProviderCustomInstrumentationEventInput): unknown {
234
+ return record({
235
+ ...event,
236
+ type: "custom",
237
+ watcher: event.watcher ?? options.watcher,
238
+ details: withProviderDetails(options.providerName, event.details),
239
+ });
240
+ }
241
+
242
+ return {
243
+ port,
244
+ isEnabled,
245
+ record,
246
+ custom,
247
+ };
248
+ }
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Provider system for Beignet
3
+ *
4
+ * Providers are modular extensions that can add new ports or replace existing ones
5
+ * during application initialization. They support configuration via Standard Schema
6
+ * and optional lifecycle hooks.
7
+ */
8
+
9
+ import type { StandardSchemaV1 } from "@standard-schema/spec";
10
+
11
+ type ProviderPorts = Record<string, unknown>;
12
+ declare const noProvidedPorts: unique symbol;
13
+ type NoProvidedPorts = { [noProvidedPorts]?: never };
14
+
15
+ /**
16
+ * Extract the output type from a Standard Schema.
17
+ * This is the validated/parsed type that results from schema validation.
18
+ */
19
+ export type InferOutput<T extends StandardSchemaV1> =
20
+ StandardSchemaV1.InferOutput<T>;
21
+
22
+ /**
23
+ * Configuration definition for a service provider.
24
+ * Specifies the schema for validating config and optional environment variable prefix.
25
+ */
26
+ export interface ProviderConfigDef<CfgSchema extends StandardSchemaV1> {
27
+ /**
28
+ * Standard Schema for validating provider configuration.
29
+ * Can be Zod, Valibot, ArkType, or any Standard Schema compatible library.
30
+ */
31
+ schema: CfgSchema;
32
+
33
+ /**
34
+ * Optional prefix to read env vars, e.g. "REDIS_".
35
+ * When provided, the implementation will read process.env keys starting with this prefix
36
+ * and pass them to the schema for validation.
37
+ */
38
+ envPrefix?: string;
39
+ }
40
+
41
+ export type MaybePromise<T> = T | Promise<T>;
42
+
43
+ export type ProviderLifecycleContext = {
44
+ ports: Readonly<ProviderPorts>;
45
+ };
46
+
47
+ export type ProviderSetupResult<ProvidedPorts extends ProviderPorts> = {
48
+ /**
49
+ * Ports contributed by this provider.
50
+ * Keys overwrite earlier ports with the same name at runtime. Prefer unique
51
+ * keys unless the replacement implements the same port contract.
52
+ */
53
+ ports?: ProvidedPorts;
54
+
55
+ /**
56
+ * Optional hook called after all providers have contributed their ports.
57
+ */
58
+ start?: (ctx: ProviderLifecycleContext) => MaybePromise<void>;
59
+
60
+ /**
61
+ * Optional hook called when the server is stopped.
62
+ */
63
+ stop?: (ctx: ProviderLifecycleContext) => MaybePromise<void>;
64
+ };
65
+
66
+ /**
67
+ * A service provider that can extend or replace ports during app initialization.
68
+ *
69
+ * Providers support:
70
+ * - Configuration via Standard Schema (any compatible library: Zod, Valibot, etc.)
71
+ * - Returning ports with new capabilities (e.g., cache, mailer)
72
+ * - Replacing existing ports by returning the same key
73
+ * - Optional start/stop hooks
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * const redisProvider = createProvider({
78
+ * name: "redis",
79
+ * config: {
80
+ * schema: z.object({ URL: z.string().url() }),
81
+ * envPrefix: "REDIS_",
82
+ * },
83
+ * async setup({ config }) {
84
+ * const client = new Redis(config.URL);
85
+ * return {
86
+ * ports: {
87
+ * cache: {
88
+ * get: (key) => client.get(key),
89
+ * set: (key, value) => client.set(key, value),
90
+ * },
91
+ * },
92
+ * stop: () => client.quit(),
93
+ * };
94
+ * },
95
+ * });
96
+ * ```
97
+ */
98
+ export interface ServiceProvider<
99
+ Ports,
100
+ CfgSchema extends StandardSchemaV1 = StandardSchemaV1<void, void>,
101
+ ProvidedPorts extends ProviderPorts = NoProvidedPorts,
102
+ > {
103
+ /**
104
+ * Unique name for this provider (used for logging/debugging)
105
+ */
106
+ name: string;
107
+
108
+ /**
109
+ * Optional configuration definition.
110
+ * If provided, the config will be loaded and validated before calling setup.
111
+ */
112
+ config?: ProviderConfigDef<CfgSchema>;
113
+
114
+ /**
115
+ * Setup phase: create the ports this provider contributes.
116
+ * Called during app initialization, before routes are registered.
117
+ *
118
+ * @param ctx.ports - Ports contributed by previous providers
119
+ * @param ctx.config - Validated config (if config was defined), or undefined
120
+ */
121
+ setup(ctx: {
122
+ ports: Readonly<Ports>;
123
+ config: InferOutput<CfgSchema> | undefined;
124
+ }): MaybePromise<ProviderSetupResult<ProvidedPorts>>;
125
+
126
+ /**
127
+ * Type-only marker for ports this provider contributes.
128
+ * Runtime provider objects do not need to set this property.
129
+ */
130
+ readonly __providedPorts?: ProvidedPorts;
131
+ }
132
+
133
+ /**
134
+ * Extract the ports a provider contributes.
135
+ */
136
+ export type ProvidedPortsOf<TProvider> =
137
+ TProvider extends ServiceProvider<
138
+ infer _Ports,
139
+ infer _CfgSchema,
140
+ infer ProvidedPorts
141
+ >
142
+ ? ProvidedPorts
143
+ : NoProvidedPorts;
144
+
145
+ type UnionToIntersection<T> = (
146
+ T extends unknown
147
+ ? (value: T) => void
148
+ : never
149
+ ) extends (value: infer I) => void
150
+ ? I
151
+ : never;
152
+
153
+ /**
154
+ * Extract and merge the ports contributed by a provider list.
155
+ */
156
+ export type ProvidedPortsOfList<TProviders> =
157
+ TProviders extends readonly unknown[]
158
+ ? [TProviders[number]] extends [never]
159
+ ? NoProvidedPorts
160
+ : UnionToIntersection<ProvidedPortsOf<TProviders[number]>>
161
+ : NoProvidedPorts;
162
+
163
+ /**
164
+ * Helper function to create a provider with proper type inference.
165
+ *
166
+ * This is a simple identity function that helps TypeScript infer the correct types
167
+ * for the provider definition.
168
+ *
169
+ * @example
170
+ * ```ts
171
+ * export const myProvider = createProvider({
172
+ * name: "my-provider",
173
+ * config: {
174
+ * schema: z.object({ apiKey: z.string() }),
175
+ * envPrefix: "MY_SERVICE_",
176
+ * },
177
+ * async setup({ config }) {
178
+ * return { ports: { myService: createMyService(config) } };
179
+ * },
180
+ * });
181
+ * ```
182
+ */
183
+ export function createProvider<
184
+ Ports = unknown,
185
+ CfgSchema extends StandardSchemaV1 = StandardSchemaV1<void, void>,
186
+ ProvidedPorts extends ProviderPorts = NoProvidedPorts,
187
+ >(
188
+ def: ServiceProvider<Ports, CfgSchema, ProvidedPorts>,
189
+ ): ServiceProvider<Ports, CfgSchema, ProvidedPorts> {
190
+ return def;
191
+ }