@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,107 @@
1
+ /**
2
+ * Schema introspection adapter.
3
+ *
4
+ * Abstracts the details of reading metadata from a schema library (e.g. Zod)
5
+ * so that the OpenAPI generator is not directly coupled to `_def` internals.
6
+ *
7
+ * A default Zod implementation is provided via `createZodIntrospector()`.
8
+ * To support a different schema library, implement this interface.
9
+ */
10
+ export interface SchemaIntrospector {
11
+ /**
12
+ * Extract the shape (field name → field schema) from an object schema.
13
+ * Returns undefined if the schema is not an object type or cannot be inspected.
14
+ */
15
+ getShape(schema: unknown): Record<string, unknown> | undefined;
16
+
17
+ /**
18
+ * Extract the user-supplied `.describe()` string from a schema.
19
+ */
20
+ getDescription(schema: unknown): string | undefined;
21
+
22
+ /**
23
+ * Return true if the schema represents an optional wrapper.
24
+ */
25
+ isOptional(schema: unknown): boolean;
26
+
27
+ /**
28
+ * If the schema is an optional wrapper, return the inner (unwrapped) schema.
29
+ * Otherwise return the original schema unchanged.
30
+ */
31
+ unwrapOptional(schema: unknown): unknown;
32
+ }
33
+
34
+ /**
35
+ * Create a schema introspector for Zod schemas.
36
+ *
37
+ * This accesses Zod's internal `_def` property, which is a common pattern in
38
+ * Zod ecosystem libraries but may break with major Zod updates. Each helper
39
+ * gracefully returns a safe default if the structure is unexpected.
40
+ */
41
+ export function createZodIntrospector(): SchemaIntrospector {
42
+ return {
43
+ getShape(schema: unknown): Record<string, unknown> | undefined {
44
+ if (!schema || typeof schema !== "object") return undefined;
45
+
46
+ const schemaDef = (schema as Record<string, unknown>)?._def;
47
+ if (!schemaDef || typeof schemaDef !== "object") return undefined;
48
+
49
+ if (!("shape" in schemaDef)) return undefined;
50
+
51
+ let shape: unknown;
52
+ if (typeof schemaDef.shape === "function") {
53
+ shape = schemaDef.shape();
54
+ } else if (typeof schemaDef.shape === "object") {
55
+ shape = schemaDef.shape;
56
+ }
57
+
58
+ if (!shape || typeof shape !== "object") return undefined;
59
+
60
+ return shape as Record<string, unknown>;
61
+ },
62
+
63
+ getDescription(schema: unknown): string | undefined {
64
+ if (!schema || typeof schema !== "object") return undefined;
65
+
66
+ const directDescription = (schema as { description?: unknown })
67
+ .description;
68
+ if (typeof directDescription === "string") {
69
+ return directDescription;
70
+ }
71
+
72
+ const schemaDef = (schema as Record<string, unknown>)?._def;
73
+ if (!schemaDef || typeof schemaDef !== "object") return undefined;
74
+
75
+ const description = (schemaDef as Record<string, unknown>).description;
76
+ return typeof description === "string" ? description : undefined;
77
+ },
78
+
79
+ isOptional(schema: unknown): boolean {
80
+ if (!schema || typeof schema !== "object") return false;
81
+
82
+ const schemaWithOptional = schema as {
83
+ isOptional?: () => boolean;
84
+ };
85
+ if (typeof schemaWithOptional.isOptional === "function") {
86
+ return schemaWithOptional.isOptional();
87
+ }
88
+
89
+ const schemaDef = (schema as Record<string, unknown>)?._def;
90
+ if (!schemaDef || typeof schemaDef !== "object") return false;
91
+
92
+ const def = schemaDef as Record<string, unknown>;
93
+ return def.typeName === "ZodOptional" || def.type === "optional";
94
+ },
95
+
96
+ unwrapOptional(schema: unknown): unknown {
97
+ const schemaDef = (schema as Record<string, unknown>)?._def;
98
+ const def = schemaDef as Record<string, unknown> | undefined;
99
+ if (def?.typeName !== "ZodOptional" && def?.type !== "optional") {
100
+ return schema;
101
+ }
102
+
103
+ const innerType = def?.innerType;
104
+ return innerType ?? schema;
105
+ },
106
+ };
107
+ }
@@ -0,0 +1,176 @@
1
+ import { redactValue } from "./redaction";
2
+
3
+ export type ActivityActorType = "anonymous" | "service" | "system" | "user";
4
+
5
+ export type AuditOutcome = "success" | "failure";
6
+
7
+ export type ActivityMetadataValue =
8
+ | ActivityMetadataValue[]
9
+ | boolean
10
+ | null
11
+ | number
12
+ | string
13
+ | { [key: string]: ActivityMetadataValue | undefined };
14
+
15
+ export type ActivityMetadata = Record<
16
+ string,
17
+ ActivityMetadataValue | undefined
18
+ >;
19
+
20
+ export interface ActivityActor {
21
+ type: ActivityActorType;
22
+ id?: string;
23
+ displayName?: string;
24
+ metadata?: ActivityMetadata;
25
+ }
26
+
27
+ export interface ActivityTenant {
28
+ id: string;
29
+ slug?: string;
30
+ metadata?: ActivityMetadata;
31
+ }
32
+
33
+ export interface ActivityResource {
34
+ type: string;
35
+ id?: string;
36
+ name?: string;
37
+ metadata?: ActivityMetadata;
38
+ }
39
+
40
+ export interface AuditLogEntry {
41
+ action: string;
42
+ actor: ActivityActor;
43
+ occurredAt: Date;
44
+ outcome: AuditOutcome;
45
+ metadata?: ActivityMetadata;
46
+ message?: string;
47
+ requestId?: string;
48
+ resource?: ActivityResource;
49
+ tenant?: ActivityTenant;
50
+ traceId?: string;
51
+ }
52
+
53
+ export type AuditLogEntryInput = Omit<
54
+ AuditLogEntry,
55
+ "occurredAt" | "outcome"
56
+ > & {
57
+ occurredAt?: Date;
58
+ outcome?: AuditOutcome;
59
+ };
60
+
61
+ export interface AuditLogPort {
62
+ record(entry: AuditLogEntryInput): Promise<void> | void;
63
+ }
64
+
65
+ export interface MemoryAuditLogPort extends AuditLogPort {
66
+ entries: AuditLogEntry[];
67
+ }
68
+
69
+ export interface AuditLogOptions {
70
+ redact?: (entry: AuditLogEntry) => AuditLogEntry;
71
+ }
72
+
73
+ export function createAnonymousActor(
74
+ options: Omit<ActivityActor, "type"> = {},
75
+ ): ActivityActor {
76
+ return { type: "anonymous", ...options };
77
+ }
78
+
79
+ export function createServiceActor(
80
+ id: string,
81
+ options: Omit<ActivityActor, "type" | "id"> = {},
82
+ ): ActivityActor {
83
+ return { type: "service", id, ...options };
84
+ }
85
+
86
+ export function createSystemActor(
87
+ id = "system",
88
+ options: Omit<ActivityActor, "type" | "id"> = {},
89
+ ): ActivityActor {
90
+ return { type: "system", id, ...options };
91
+ }
92
+
93
+ export function createUserActor(
94
+ id: string,
95
+ options: Omit<ActivityActor, "type" | "id"> = {},
96
+ ): ActivityActor {
97
+ return { type: "user", id, ...options };
98
+ }
99
+
100
+ export function createTenant(
101
+ id: string,
102
+ options: Omit<ActivityTenant, "id"> = {},
103
+ ): ActivityTenant {
104
+ return { id, ...options };
105
+ }
106
+
107
+ export function normalizeAuditLogEntry(
108
+ entry: AuditLogEntryInput,
109
+ ): AuditLogEntry {
110
+ return {
111
+ ...entry,
112
+ occurredAt: entry.occurredAt ?? new Date(),
113
+ outcome: entry.outcome ?? "success",
114
+ };
115
+ }
116
+
117
+ export function redactAuditLogEntry(entry: AuditLogEntry): AuditLogEntry {
118
+ return {
119
+ ...entry,
120
+ actor: {
121
+ ...entry.actor,
122
+ metadata: entry.actor.metadata
123
+ ? redactValue(entry.actor.metadata)
124
+ : entry.actor.metadata,
125
+ },
126
+ tenant: entry.tenant
127
+ ? {
128
+ ...entry.tenant,
129
+ metadata: entry.tenant.metadata
130
+ ? redactValue(entry.tenant.metadata)
131
+ : entry.tenant.metadata,
132
+ }
133
+ : entry.tenant,
134
+ resource: entry.resource
135
+ ? {
136
+ ...entry.resource,
137
+ metadata: entry.resource.metadata
138
+ ? redactValue(entry.resource.metadata)
139
+ : entry.resource.metadata,
140
+ }
141
+ : entry.resource,
142
+ metadata: entry.metadata ? redactValue(entry.metadata) : entry.metadata,
143
+ };
144
+ }
145
+
146
+ export function createRedactedAuditLog(
147
+ audit: AuditLogPort,
148
+ options: AuditLogOptions = {},
149
+ ): AuditLogPort {
150
+ return {
151
+ record(entry) {
152
+ const normalized = normalizeAuditLogEntry(entry);
153
+ const redacted = options.redact
154
+ ? options.redact(redactAuditLogEntry(normalized))
155
+ : redactAuditLogEntry(normalized);
156
+ return audit.record(redacted);
157
+ },
158
+ };
159
+ }
160
+
161
+ export function createMemoryAuditLog(
162
+ entries: AuditLogEntry[] = [],
163
+ options: AuditLogOptions = {},
164
+ ): MemoryAuditLogPort {
165
+ return {
166
+ entries,
167
+ record(entry) {
168
+ const normalized = normalizeAuditLogEntry(entry);
169
+ entries.push(
170
+ options.redact
171
+ ? options.redact(redactAuditLogEntry(normalized))
172
+ : redactAuditLogEntry(normalized),
173
+ );
174
+ },
175
+ };
176
+ }
@@ -0,0 +1,76 @@
1
+ export interface AuthRequestLike {
2
+ headers: Headers;
3
+ raw?: Request;
4
+ }
5
+
6
+ export interface AuthSession<User = unknown, Session = unknown> {
7
+ user: User;
8
+ session?: Session;
9
+ }
10
+
11
+ export class AuthUnauthorizedError extends Error {
12
+ readonly code = "UNAUTHORIZED";
13
+
14
+ constructor(message = "Unauthorized") {
15
+ super(message);
16
+ this.name = "AuthUnauthorizedError";
17
+ }
18
+ }
19
+
20
+ export interface AuthPort<
21
+ User = unknown,
22
+ Session = unknown,
23
+ RequestLike extends AuthRequestLike = AuthRequestLike,
24
+ > {
25
+ getSession(req: RequestLike): Promise<AuthSession<User, Session> | null>;
26
+ getUser(req: RequestLike): Promise<User | null>;
27
+ requireUser(req: RequestLike): Promise<User>;
28
+ }
29
+
30
+ type MaybePromise<T> = T | Promise<T>;
31
+
32
+ export type StaticAuthSessionFactory<
33
+ User,
34
+ Session,
35
+ RequestLike extends AuthRequestLike,
36
+ > = (req: RequestLike) => MaybePromise<AuthSession<User, Session> | null>;
37
+
38
+ export function createStaticAuth<
39
+ User,
40
+ Session = unknown,
41
+ RequestLike extends AuthRequestLike = AuthRequestLike,
42
+ >(
43
+ session:
44
+ | AuthSession<User, Session>
45
+ | null
46
+ | StaticAuthSessionFactory<User, Session, RequestLike>,
47
+ ): AuthPort<User, Session, RequestLike> {
48
+ async function resolveSession(req: RequestLike) {
49
+ return typeof session === "function" ? session(req) : session;
50
+ }
51
+
52
+ return {
53
+ async getSession(req) {
54
+ return resolveSession(req);
55
+ },
56
+ async getUser(req) {
57
+ return (await resolveSession(req))?.user ?? null;
58
+ },
59
+ async requireUser(req) {
60
+ const user = (await resolveSession(req))?.user ?? null;
61
+ if (!user) {
62
+ throw new AuthUnauthorizedError();
63
+ }
64
+
65
+ return user;
66
+ },
67
+ };
68
+ }
69
+
70
+ export function createAnonymousAuth<
71
+ User = unknown,
72
+ Session = unknown,
73
+ RequestLike extends AuthRequestLike = AuthRequestLike,
74
+ >(): AuthPort<User, Session, RequestLike> {
75
+ return createStaticAuth<User, Session, RequestLike>(null);
76
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * PortsBuilder - Mutable builder for composing ports during app initialization
3
+ *
4
+ * This builder is a small composition helper for tests and custom bootstrapping
5
+ * code that wants to assemble ports incrementally.
6
+ */
7
+
8
+ /**
9
+ * A mutable builder around a ports object.
10
+ * Used during app composition and provider registration.
11
+ */
12
+ export interface PortsBuilder<Ports> {
13
+ /**
14
+ * The current ports object being built.
15
+ * This is mutated internally when extend/replace are called.
16
+ */
17
+ ports: Ports;
18
+
19
+ /**
20
+ * Extend ports with a new key. If the key already exists, it's overwritten.
21
+ *
22
+ * Returns the same builder instance with an extended type:
23
+ * Ports & { [K in key]: Value }
24
+ */
25
+ extend<K extends string, V>(
26
+ key: K,
27
+ value: V,
28
+ ): PortsBuilder<Ports & { [P in K]: V }>;
29
+
30
+ /**
31
+ * Replace an existing key. Does not change the type, but updates the runtime value.
32
+ * Returns the same builder instance.
33
+ */
34
+ replace<K extends keyof Ports>(key: K, value: Ports[K]): PortsBuilder<Ports>;
35
+ }
36
+
37
+ /**
38
+ * Create a new PortsBuilder from an initial ports object.
39
+ *
40
+ * The builder wraps a mutable object internally and provides type-safe methods
41
+ * to extend or replace ports. This is used during application composition
42
+ * helpers that want to modify ports before passing them to a server.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const initialPorts = definePorts({ db: dbAdapter });
47
+ * const builder = createPortsBuilder(initialPorts);
48
+ *
49
+ * // Provider extends with cache
50
+ * builder.extend("cache", cacheAdapter);
51
+ *
52
+ * // Final ports includes both db and cache
53
+ * const finalPorts = builder.ports;
54
+ * ```
55
+ */
56
+ export function createPortsBuilder<Ports>(
57
+ initialPorts: Ports,
58
+ ): PortsBuilder<Ports> {
59
+ // Keep a mutable object internally
60
+ // biome-ignore lint/suspicious/noExplicitAny: internal mutable state needs any to accept arbitrary port extensions
61
+ const state: { ports: any } = {
62
+ ports: { ...initialPorts },
63
+ };
64
+
65
+ const builder: PortsBuilder<Ports> = {
66
+ get ports() {
67
+ // Could freeze in dev, but keep simple
68
+ return state.ports as Ports;
69
+ },
70
+ extend<K extends string, V>(
71
+ key: K,
72
+ value: V,
73
+ ): PortsBuilder<Ports & { [P in K]: V }> {
74
+ state.ports[key] = value;
75
+ return builder as unknown as PortsBuilder<Ports & { [P in K]: V }>;
76
+ },
77
+ replace<K extends keyof Ports>(
78
+ key: K,
79
+ value: Ports[K],
80
+ ): PortsBuilder<Ports> {
81
+ state.ports[key] = value;
82
+ return builder;
83
+ },
84
+ };
85
+
86
+ return builder;
87
+ }
88
+
89
+ /**
90
+ * Extract the Ports type from a PortsBuilder
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * type MyPorts = PortsOf<typeof builder>;
95
+ * ```
96
+ */
97
+ export type PortsOf<PB> = PB extends PortsBuilder<infer P> ? P : never;
@@ -0,0 +1,94 @@
1
+ export interface CacheSetOptions {
2
+ /**
3
+ * Time-to-live in seconds. Omit this for a value that does not expire.
4
+ */
5
+ ttlSeconds?: number;
6
+ }
7
+
8
+ export interface CachePort {
9
+ get(key: string): Promise<string | null>;
10
+ set(key: string, value: string, options?: CacheSetOptions): Promise<void>;
11
+ delete(key: string): Promise<boolean>;
12
+ has(key: string): Promise<boolean>;
13
+ remember(
14
+ key: string,
15
+ factory: () => Promise<string>,
16
+ options?: CacheSetOptions,
17
+ ): Promise<string>;
18
+ }
19
+
20
+ type MemoryCacheEntry = {
21
+ value: string;
22
+ expiresAt: number | null;
23
+ };
24
+
25
+ function resolveExpiresAt(options: CacheSetOptions | undefined): number | null {
26
+ if (options?.ttlSeconds == null) {
27
+ return null;
28
+ }
29
+
30
+ if (options.ttlSeconds <= 0) {
31
+ return Date.now();
32
+ }
33
+
34
+ return Date.now() + options.ttlSeconds * 1000;
35
+ }
36
+
37
+ function isExpired(entry: MemoryCacheEntry): boolean {
38
+ return entry.expiresAt != null && entry.expiresAt <= Date.now();
39
+ }
40
+
41
+ export function createMemoryCache(
42
+ initialValues: Record<string, string> = {},
43
+ ): CachePort {
44
+ const values = new Map<string, MemoryCacheEntry>(
45
+ Object.entries(initialValues).map(([key, value]) => [
46
+ key,
47
+ { value, expiresAt: null },
48
+ ]),
49
+ );
50
+
51
+ async function getFreshEntry(key: string): Promise<MemoryCacheEntry | null> {
52
+ const entry = values.get(key);
53
+ if (!entry) {
54
+ return null;
55
+ }
56
+
57
+ if (isExpired(entry)) {
58
+ values.delete(key);
59
+ return null;
60
+ }
61
+
62
+ return entry;
63
+ }
64
+
65
+ const cache: CachePort = {
66
+ async get(key) {
67
+ return (await getFreshEntry(key))?.value ?? null;
68
+ },
69
+ async set(key, value, options) {
70
+ values.set(key, {
71
+ value,
72
+ expiresAt: resolveExpiresAt(options),
73
+ });
74
+ },
75
+ async delete(key) {
76
+ return values.delete(key);
77
+ },
78
+ async has(key) {
79
+ return (await getFreshEntry(key)) != null;
80
+ },
81
+ async remember(key, factory, options) {
82
+ const cached = await cache.get(key);
83
+ if (cached != null) {
84
+ return cached;
85
+ }
86
+
87
+ const value = await factory();
88
+ await cache.set(key, value, options);
89
+ return value;
90
+ },
91
+ };
92
+
93
+ return cache;
94
+ }
@@ -0,0 +1,34 @@
1
+ export interface ClockPort {
2
+ now(): Date;
3
+ }
4
+
5
+ export interface FrozenClockPort extends ClockPort {
6
+ setNow(value: Date | string | number): void;
7
+ advance(milliseconds: number): void;
8
+ }
9
+
10
+ function toDate(value: Date | string | number): Date {
11
+ return value instanceof Date ? new Date(value.getTime()) : new Date(value);
12
+ }
13
+
14
+ export function createSystemClock(): ClockPort {
15
+ return {
16
+ now: () => new Date(),
17
+ };
18
+ }
19
+
20
+ export function createFrozenClock(
21
+ initial: Date | string | number = new Date(0),
22
+ ): FrozenClockPort {
23
+ let current = toDate(initial);
24
+
25
+ return {
26
+ now: () => new Date(current.getTime()),
27
+ setNow: (value) => {
28
+ current = toDate(value);
29
+ },
30
+ advance: (milliseconds) => {
31
+ current = new Date(current.getTime() + milliseconds);
32
+ },
33
+ };
34
+ }
@@ -0,0 +1,100 @@
1
+ import type {
2
+ EventPayloadDef,
3
+ InferEventPayload as InferContractEventPayload,
4
+ StandardSchema,
5
+ } from "../events";
6
+ import type {
7
+ JobDef as ContractJobDef,
8
+ InferJobPayload as InferContractJobPayload,
9
+ } from "../jobs";
10
+
11
+ /**
12
+ * Represents a defined Domain Event with name and payload schema.
13
+ * This is a minimal interface that ports need - implementations can use
14
+ * the full DomainEventDef from @beignet/core/domain if desired.
15
+ */
16
+ export interface DomainEventDef<
17
+ Name extends string = string,
18
+ Payload extends StandardSchema = StandardSchema,
19
+ > extends EventPayloadDef<Name, Payload> {}
20
+
21
+ /**
22
+ * Infer the payload type from a DomainEventDef.
23
+ */
24
+ export type InferEventPayload<E extends DomainEventDef> =
25
+ InferContractEventPayload<E>;
26
+
27
+ /**
28
+ * Represents a job definition with a typed payload schema.
29
+ *
30
+ * Job dispatchers use Beignet's first-class job definitions. Inline
31
+ * dispatchers can run the handler directly;
32
+ * durable dispatchers can ignore it and enqueue the job name plus parsed
33
+ * payload.
34
+ */
35
+ export type JobDef<
36
+ Name extends string = string,
37
+ Payload extends StandardSchema = StandardSchema,
38
+ Ctx = unknown,
39
+ > = ContractJobDef<Name, Payload, Ctx>;
40
+
41
+ /**
42
+ * Infer the payload type from a JobDef.
43
+ */
44
+ export type InferJobPayload<J extends JobDef> = InferContractJobPayload<J>;
45
+
46
+ /**
47
+ * An EventBus port for publishing and subscribing to domain events.
48
+ *
49
+ * This interface defines a framework-agnostic contract for event-driven
50
+ * communication within your application.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * import { createInMemoryEventBus } from "@beignet/provider-event-bus-memory";
55
+ *
56
+ * const eventBus = createInMemoryEventBus();
57
+ *
58
+ * // Subscribe to an event
59
+ * const unsubscribe = eventBus.subscribe(UserRegistered, (payload) => {
60
+ * console.log(`User registered: ${payload.email}`);
61
+ * });
62
+ *
63
+ * // Publish an event
64
+ * await eventBus.publish(UserRegistered, { userId: "123", email: "test@example.com" });
65
+ *
66
+ * // Unsubscribe when done
67
+ * unsubscribe();
68
+ * ```
69
+ */
70
+ export interface EventBusPort {
71
+ /**
72
+ * Publish a domain event with a typed payload.
73
+ */
74
+ publish<E extends DomainEventDef>(
75
+ event: E,
76
+ payload: InferEventPayload<E>,
77
+ ): Promise<void> | void;
78
+
79
+ /**
80
+ * Subscribe to a domain event. Returns an unsubscribe function.
81
+ */
82
+ subscribe<E extends DomainEventDef>(
83
+ event: E,
84
+ handler: (payload: InferEventPayload<E>) => Promise<void> | void,
85
+ ): () => void;
86
+ }
87
+
88
+ /**
89
+ * A port for dispatching explicit background jobs.
90
+ *
91
+ * Jobs represent work to do, not facts that happened. Implementations may run
92
+ * inline in tests, enqueue into a durable worker, or call an external job
93
+ * system.
94
+ */
95
+ export interface JobDispatcherPort {
96
+ dispatch<J extends JobDef>(
97
+ job: J,
98
+ payload: InferJobPayload<J>,
99
+ ): Promise<void> | void;
100
+ }