@beignet/core 0.0.1 → 0.0.2

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 (274) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +149 -4
  3. package/dist/application/index.d.ts +93 -9
  4. package/dist/application/index.d.ts.map +1 -1
  5. package/dist/application/index.js +11 -11
  6. package/dist/application/index.js.map +1 -1
  7. package/dist/client/client.d.ts +73 -12
  8. package/dist/client/client.d.ts.map +1 -1
  9. package/dist/client/client.js +37 -12
  10. package/dist/client/client.js.map +1 -1
  11. package/dist/client/index.d.ts +12 -0
  12. package/dist/client/index.d.ts.map +1 -1
  13. package/dist/client/index.js +6 -0
  14. package/dist/client/index.js.map +1 -1
  15. package/dist/client/types.d.ts +69 -8
  16. package/dist/client/types.d.ts.map +1 -1
  17. package/dist/config/index.d.ts +84 -0
  18. package/dist/config/index.d.ts.map +1 -1
  19. package/dist/config/index.js +36 -0
  20. package/dist/config/index.js.map +1 -1
  21. package/dist/contracts/contract-builder.d.ts +49 -22
  22. package/dist/contracts/contract-builder.d.ts.map +1 -1
  23. package/dist/contracts/contract-builder.js +48 -21
  24. package/dist/contracts/contract-builder.js.map +1 -1
  25. package/dist/contracts/contract-group.d.ts +35 -19
  26. package/dist/contracts/contract-group.d.ts.map +1 -1
  27. package/dist/contracts/contract-group.js +35 -19
  28. package/dist/contracts/contract-group.js.map +1 -1
  29. package/dist/contracts/contract-like.d.ts +4 -4
  30. package/dist/contracts/contract-like.d.ts.map +1 -1
  31. package/dist/contracts/contract-like.js +2 -1
  32. package/dist/contracts/contract-like.js.map +1 -1
  33. package/dist/contracts/index.d.ts +28 -0
  34. package/dist/contracts/index.d.ts.map +1 -1
  35. package/dist/contracts/index.js +12 -0
  36. package/dist/contracts/index.js.map +1 -1
  37. package/dist/contracts/openapi-meta.d.ts +8 -8
  38. package/dist/contracts/openapi-meta.d.ts.map +1 -1
  39. package/dist/contracts/path-template.d.ts +27 -0
  40. package/dist/contracts/path-template.d.ts.map +1 -1
  41. package/dist/contracts/path-template.js +6 -0
  42. package/dist/contracts/path-template.js.map +1 -1
  43. package/dist/contracts/types.d.ts +104 -10
  44. package/dist/contracts/types.d.ts.map +1 -1
  45. package/dist/contracts/types.js +15 -0
  46. package/dist/contracts/types.js.map +1 -1
  47. package/dist/contracts/utils.d.ts +6 -0
  48. package/dist/contracts/utils.d.ts.map +1 -1
  49. package/dist/contracts/utils.js +6 -0
  50. package/dist/contracts/utils.js.map +1 -1
  51. package/dist/domain/entity.d.ts +22 -11
  52. package/dist/domain/entity.d.ts.map +1 -1
  53. package/dist/domain/entity.js +5 -1
  54. package/dist/domain/entity.js.map +1 -1
  55. package/dist/domain/events.d.ts +5 -2
  56. package/dist/domain/events.d.ts.map +1 -1
  57. package/dist/domain/events.js +4 -1
  58. package/dist/domain/events.js.map +1 -1
  59. package/dist/domain/value-object.d.ts +19 -9
  60. package/dist/domain/value-object.d.ts.map +1 -1
  61. package/dist/domain/value-object.js +5 -1
  62. package/dist/domain/value-object.js.map +1 -1
  63. package/dist/errors/catalog.d.ts +40 -16
  64. package/dist/errors/catalog.d.ts.map +1 -1
  65. package/dist/errors/catalog.js +18 -7
  66. package/dist/errors/catalog.js.map +1 -1
  67. package/dist/errors/response.d.ts +16 -4
  68. package/dist/errors/response.d.ts.map +1 -1
  69. package/dist/errors/response.js +3 -3
  70. package/dist/errors/response.js.map +1 -1
  71. package/dist/errors/validation.d.ts +10 -1
  72. package/dist/errors/validation.d.ts.map +1 -1
  73. package/dist/errors/validation.js +3 -0
  74. package/dist/errors/validation.js.map +1 -1
  75. package/dist/events/index.d.ts +133 -0
  76. package/dist/events/index.d.ts.map +1 -1
  77. package/dist/events/index.js +30 -0
  78. package/dist/events/index.js.map +1 -1
  79. package/dist/idempotency/index.d.ts +355 -0
  80. package/dist/idempotency/index.d.ts.map +1 -0
  81. package/dist/idempotency/index.js +360 -0
  82. package/dist/idempotency/index.js.map +1 -0
  83. package/dist/jobs/index.d.ts +110 -0
  84. package/dist/jobs/index.d.ts.map +1 -1
  85. package/dist/jobs/index.js +22 -0
  86. package/dist/jobs/index.js.map +1 -1
  87. package/dist/mail/index.d.ts +149 -0
  88. package/dist/mail/index.d.ts.map +1 -1
  89. package/dist/mail/index.js +30 -0
  90. package/dist/mail/index.js.map +1 -1
  91. package/dist/notifications/index.d.ts +369 -0
  92. package/dist/notifications/index.d.ts.map +1 -0
  93. package/dist/notifications/index.js +310 -0
  94. package/dist/notifications/index.js.map +1 -0
  95. package/dist/openapi/index.d.ts +132 -16
  96. package/dist/openapi/index.d.ts.map +1 -1
  97. package/dist/openapi/index.js +1 -1
  98. package/dist/openapi/index.js.map +1 -1
  99. package/dist/outbox/index.d.ts +469 -0
  100. package/dist/outbox/index.d.ts.map +1 -0
  101. package/dist/outbox/index.js +482 -0
  102. package/dist/outbox/index.js.map +1 -0
  103. package/dist/pagination/index.d.ts +166 -0
  104. package/dist/pagination/index.d.ts.map +1 -0
  105. package/dist/pagination/index.js +96 -0
  106. package/dist/pagination/index.js.map +1 -0
  107. package/dist/ports/audit.d.ts +271 -0
  108. package/dist/ports/audit.d.ts.map +1 -1
  109. package/dist/ports/audit.js +128 -0
  110. package/dist/ports/audit.js.map +1 -1
  111. package/dist/ports/auth.d.ts +70 -0
  112. package/dist/ports/auth.d.ts.map +1 -1
  113. package/dist/ports/auth.js +30 -0
  114. package/dist/ports/auth.js.map +1 -1
  115. package/dist/ports/cache.d.ts +41 -0
  116. package/dist/ports/cache.d.ts.map +1 -1
  117. package/dist/ports/cache.js +10 -0
  118. package/dist/ports/cache.js.map +1 -1
  119. package/dist/ports/clock.d.ts +38 -0
  120. package/dist/ports/clock.d.ts.map +1 -1
  121. package/dist/ports/clock.js +20 -0
  122. package/dist/ports/clock.js.map +1 -1
  123. package/dist/ports/id-generator.d.ts +37 -0
  124. package/dist/ports/id-generator.d.ts.map +1 -1
  125. package/dist/ports/id-generator.js +22 -0
  126. package/dist/ports/id-generator.js.map +1 -1
  127. package/dist/ports/index.d.ts +83 -0
  128. package/dist/ports/index.d.ts.map +1 -1
  129. package/dist/ports/index.js +41 -5
  130. package/dist/ports/index.js.map +1 -1
  131. package/dist/ports/logger.d.ts +56 -0
  132. package/dist/ports/logger.d.ts.map +1 -1
  133. package/dist/ports/logger.js +17 -0
  134. package/dist/ports/logger.js.map +1 -1
  135. package/dist/ports/policy.d.ts +132 -0
  136. package/dist/ports/policy.d.ts.map +1 -1
  137. package/dist/ports/policy.js +45 -0
  138. package/dist/ports/policy.js.map +1 -1
  139. package/dist/ports/rate-limit.d.ts +25 -0
  140. package/dist/ports/rate-limit.d.ts.map +1 -1
  141. package/dist/ports/rate-limit.js +10 -0
  142. package/dist/ports/rate-limit.js.map +1 -1
  143. package/dist/ports/redaction.d.ts +101 -0
  144. package/dist/ports/redaction.d.ts.map +1 -1
  145. package/dist/ports/redaction.js +59 -0
  146. package/dist/ports/redaction.js.map +1 -1
  147. package/dist/ports/storage.d.ts +100 -0
  148. package/dist/ports/storage.d.ts.map +1 -1
  149. package/dist/ports/storage.js +10 -0
  150. package/dist/ports/storage.js.map +1 -1
  151. package/dist/ports/testing.d.ts +47 -0
  152. package/dist/ports/testing.d.ts.map +1 -1
  153. package/dist/ports/testing.js +23 -0
  154. package/dist/ports/testing.js.map +1 -1
  155. package/dist/ports/unit-of-work.d.ts +60 -3
  156. package/dist/ports/unit-of-work.d.ts.map +1 -1
  157. package/dist/ports/unit-of-work.js +11 -2
  158. package/dist/ports/unit-of-work.js.map +1 -1
  159. package/dist/providers/instrumentation.d.ts +204 -0
  160. package/dist/providers/instrumentation.d.ts.map +1 -1
  161. package/dist/providers/instrumentation.js +14 -0
  162. package/dist/providers/instrumentation.js.map +1 -1
  163. package/dist/providers/provider.d.ts +14 -1
  164. package/dist/providers/provider.d.ts.map +1 -1
  165. package/dist/providers/provider.js.map +1 -1
  166. package/dist/schedules/index.d.ts +246 -0
  167. package/dist/schedules/index.d.ts.map +1 -1
  168. package/dist/schedules/index.js +27 -0
  169. package/dist/schedules/index.js.map +1 -1
  170. package/dist/server/health.d.ts +14 -5
  171. package/dist/server/health.d.ts.map +1 -1
  172. package/dist/server/health.js +5 -2
  173. package/dist/server/health.js.map +1 -1
  174. package/dist/server/hooks/auth.d.ts +57 -0
  175. package/dist/server/hooks/auth.d.ts.map +1 -1
  176. package/dist/server/hooks/auth.js.map +1 -1
  177. package/dist/server/hooks/cors.d.ts +27 -0
  178. package/dist/server/hooks/cors.d.ts.map +1 -1
  179. package/dist/server/hooks/cors.js +12 -0
  180. package/dist/server/hooks/cors.js.map +1 -1
  181. package/dist/server/hooks/errors.d.ts +15 -6
  182. package/dist/server/hooks/errors.d.ts.map +1 -1
  183. package/dist/server/hooks/errors.js.map +1 -1
  184. package/dist/server/hooks/index.d.ts +3 -0
  185. package/dist/server/hooks/index.d.ts.map +1 -1
  186. package/dist/server/hooks/index.js +3 -0
  187. package/dist/server/hooks/index.js.map +1 -1
  188. package/dist/server/hooks/logging.d.ts +36 -0
  189. package/dist/server/hooks/logging.d.ts.map +1 -1
  190. package/dist/server/hooks/logging.js +6 -0
  191. package/dist/server/hooks/logging.js.map +1 -1
  192. package/dist/server/hooks/rate-limit.d.ts +33 -0
  193. package/dist/server/hooks/rate-limit.d.ts.map +1 -1
  194. package/dist/server/hooks/rate-limit.js +11 -0
  195. package/dist/server/hooks/rate-limit.js.map +1 -1
  196. package/dist/server/http.d.ts +170 -0
  197. package/dist/server/http.d.ts.map +1 -1
  198. package/dist/server/index.d.ts +18 -0
  199. package/dist/server/index.d.ts.map +1 -1
  200. package/dist/server/index.js +6 -0
  201. package/dist/server/index.js.map +1 -1
  202. package/dist/server/openapi.d.ts +5 -3
  203. package/dist/server/openapi.d.ts.map +1 -1
  204. package/dist/server/openapi.js +4 -2
  205. package/dist/server/openapi.js.map +1 -1
  206. package/dist/server/providers/loadProviderConfig.d.ts +9 -0
  207. package/dist/server/providers/loadProviderConfig.d.ts.map +1 -1
  208. package/dist/server/providers/loadProviderConfig.js +9 -0
  209. package/dist/server/providers/loadProviderConfig.js.map +1 -1
  210. package/dist/server/server.d.ts +107 -8
  211. package/dist/server/server.d.ts.map +1 -1
  212. package/dist/server/server.js +27 -7
  213. package/dist/server/server.js.map +1 -1
  214. package/dist/testing/index.d.ts +167 -0
  215. package/dist/testing/index.d.ts.map +1 -0
  216. package/dist/testing/index.js +119 -0
  217. package/dist/testing/index.js.map +1 -0
  218. package/package.json +21 -1
  219. package/src/application/index.ts +85 -22
  220. package/src/client/client.ts +73 -12
  221. package/src/client/index.ts +12 -0
  222. package/src/client/types.ts +70 -9
  223. package/src/config/index.ts +86 -0
  224. package/src/contracts/contract-builder.ts +49 -22
  225. package/src/contracts/contract-group.ts +35 -19
  226. package/src/contracts/contract-like.ts +4 -4
  227. package/src/contracts/index.ts +28 -1
  228. package/src/contracts/openapi-meta.ts +8 -8
  229. package/src/contracts/path-template.ts +27 -0
  230. package/src/contracts/types.ts +111 -10
  231. package/src/contracts/utils.ts +6 -0
  232. package/src/domain/entity.ts +22 -11
  233. package/src/domain/events.ts +5 -2
  234. package/src/domain/value-object.ts +19 -9
  235. package/src/errors/catalog.ts +40 -16
  236. package/src/errors/response.ts +16 -4
  237. package/src/errors/validation.ts +10 -1
  238. package/src/events/index.ts +134 -0
  239. package/src/idempotency/index.ts +767 -0
  240. package/src/jobs/index.ts +111 -0
  241. package/src/mail/index.ts +149 -0
  242. package/src/notifications/index.ts +771 -0
  243. package/src/openapi/index.ts +133 -16
  244. package/src/outbox/index.ts +1024 -0
  245. package/src/pagination/index.ts +278 -0
  246. package/src/ports/audit.ts +271 -0
  247. package/src/ports/auth.ts +70 -0
  248. package/src/ports/cache.ts +41 -0
  249. package/src/ports/clock.ts +38 -0
  250. package/src/ports/id-generator.ts +37 -0
  251. package/src/ports/index.ts +106 -11
  252. package/src/ports/logger.ts +56 -0
  253. package/src/ports/policy.ts +133 -0
  254. package/src/ports/rate-limit.ts +25 -0
  255. package/src/ports/redaction.ts +101 -0
  256. package/src/ports/storage.ts +100 -0
  257. package/src/ports/testing.ts +47 -0
  258. package/src/ports/unit-of-work.ts +60 -3
  259. package/src/providers/instrumentation.ts +204 -0
  260. package/src/providers/provider.ts +14 -1
  261. package/src/schedules/index.ts +247 -0
  262. package/src/server/health.ts +14 -5
  263. package/src/server/hooks/auth.ts +58 -0
  264. package/src/server/hooks/cors.ts +27 -0
  265. package/src/server/hooks/errors.ts +15 -6
  266. package/src/server/hooks/index.ts +3 -0
  267. package/src/server/hooks/logging.ts +36 -0
  268. package/src/server/hooks/rate-limit.ts +33 -0
  269. package/src/server/http.ts +170 -1
  270. package/src/server/index.ts +18 -1
  271. package/src/server/openapi.ts +5 -3
  272. package/src/server/providers/loadProviderConfig.ts +9 -0
  273. package/src/server/server.ts +107 -9
  274. package/src/testing/index.ts +337 -0
@@ -1,9 +1,18 @@
1
1
  type MaybePromise<T> = T | Promise<T>;
2
2
 
3
+ /**
4
+ * A policy decision that allows the requested ability.
5
+ */
3
6
  export type GateAllowedDecision = {
4
7
  allowed: true;
5
8
  };
6
9
 
10
+ /**
11
+ * A policy decision that denies the requested ability.
12
+ *
13
+ * Use `reason`, `code`, and `details` to preserve structured denial context for
14
+ * errors, audit logs, and tests.
15
+ */
7
16
  export type GateDeniedDecision = {
8
17
  allowed: false;
9
18
  reason?: string;
@@ -11,13 +20,33 @@ export type GateDeniedDecision = {
11
20
  details?: unknown;
12
21
  };
13
22
 
23
+ /**
24
+ * Normalized authorization decision returned by gate inspection.
25
+ */
14
26
  export type GateDecision = GateAllowedDecision | GateDeniedDecision;
27
+
28
+ /**
29
+ * Value a policy resolver may return.
30
+ *
31
+ * Returning `true`/`false` is convenient for simple policies. Return
32
+ * `allow()`/`deny(...)` when the caller needs a denial reason, code, or
33
+ * structured details.
34
+ */
15
35
  export type GatePolicyResult = boolean | GateDecision;
16
36
 
37
+ /**
38
+ * Function that decides whether a context can perform an ability.
39
+ *
40
+ * The first argument is always the application context. Policies that operate
41
+ * on a record receive that record as their second argument.
42
+ */
17
43
  export type PolicyResolver = (
18
44
  ...args: never[]
19
45
  ) => MaybePromise<GatePolicyResult>;
20
46
 
47
+ /**
48
+ * Typed collection of ability resolvers created by `definePolicy(...)`.
49
+ */
21
50
  export type PolicyDefinition<
22
51
  TPolicies extends Record<string, PolicyResolver> = Record<
23
52
  string,
@@ -27,6 +56,9 @@ export type PolicyDefinition<
27
56
  policies: TPolicies;
28
57
  };
29
58
 
59
+ /**
60
+ * Infer the application context type from a policy resolver.
61
+ */
30
62
  export type PolicyContext<TResolver> = TResolver extends (
31
63
  ctx: infer Ctx,
32
64
  ...args: never[]
@@ -34,6 +66,9 @@ export type PolicyContext<TResolver> = TResolver extends (
34
66
  ? Ctx
35
67
  : never;
36
68
 
69
+ /**
70
+ * Infer whether an ability needs a subject argument.
71
+ */
37
72
  export type PolicySubjectArgs<TResolver> = TResolver extends (
38
73
  ...args: infer TArgs
39
74
  ) => MaybePromise<GatePolicyResult>
@@ -50,6 +85,9 @@ type UnionToIntersection<T> = (
50
85
  ? U
51
86
  : never;
52
87
 
88
+ /**
89
+ * Merge the ability maps from multiple policy definitions.
90
+ */
53
91
  export type PolicyMapFromDefinitions<
54
92
  TPolicies extends readonly PolicyDefinition[],
55
93
  > = UnionToIntersection<
@@ -58,21 +96,40 @@ export type PolicyMapFromDefinitions<
58
96
  : never
59
97
  >;
60
98
 
99
+ /**
100
+ * Infer the application context type shared by a list of policy definitions.
101
+ */
61
102
  export type PolicyContextFromDefinitions<
62
103
  TPolicies extends readonly PolicyDefinition[],
63
104
  > = PolicyContext<
64
105
  PolicyMapFromDefinitions<TPolicies>[keyof PolicyMapFromDefinitions<TPolicies>]
65
106
  >;
66
107
 
108
+ /**
109
+ * Gate bound to a specific application context.
110
+ *
111
+ * Apps commonly attach this to request context as `ctx.gate` so use cases can
112
+ * call `ctx.gate.authorize("posts.update", post)` without passing `ctx` back
113
+ * into every authorization call.
114
+ */
67
115
  export type BoundGate<TPolicies extends readonly PolicyDefinition[]> = {
116
+ /**
117
+ * Return only whether the ability is allowed.
118
+ */
68
119
  can<TAbility extends keyof PolicyMapFromDefinitions<TPolicies> & string>(
69
120
  ability: TAbility,
70
121
  ...subject: PolicySubjectArgs<PolicyMapFromDefinitions<TPolicies>[TAbility]>
71
122
  ): Promise<boolean>;
123
+ /**
124
+ * Return the full allow/deny decision without throwing.
125
+ */
72
126
  inspect<TAbility extends keyof PolicyMapFromDefinitions<TPolicies> & string>(
73
127
  ability: TAbility,
74
128
  ...subject: PolicySubjectArgs<PolicyMapFromDefinitions<TPolicies>[TAbility]>
75
129
  ): Promise<GateDecision>;
130
+ /**
131
+ * Return an allowed decision or throw for denied abilities.
132
+ */
76
133
  authorize<
77
134
  TAbility extends keyof PolicyMapFromDefinitions<TPolicies> & string,
78
135
  >(
@@ -81,21 +138,40 @@ export type BoundGate<TPolicies extends readonly PolicyDefinition[]> = {
81
138
  ): Promise<GateAllowedDecision>;
82
139
  };
83
140
 
141
+ /**
142
+ * App-facing authorization gate.
143
+ *
144
+ * The gate evaluates app-owned policies. It is not an authentication provider:
145
+ * authenticate at the HTTP boundary first, then pass the resulting actor/user
146
+ * data into policy context.
147
+ */
84
148
  export type GatePort<
85
149
  TContext,
86
150
  TPolicies extends readonly PolicyDefinition[] = readonly PolicyDefinition[],
87
151
  > = {
152
+ /**
153
+ * Bind this gate to a context, usually during `createContext`.
154
+ */
88
155
  bind(ctx: TContext): BoundGate<TPolicies>;
156
+ /**
157
+ * Return only whether the ability is allowed for a context.
158
+ */
89
159
  can<TAbility extends keyof PolicyMapFromDefinitions<TPolicies> & string>(
90
160
  ctx: TContext,
91
161
  ability: TAbility,
92
162
  ...subject: PolicySubjectArgs<PolicyMapFromDefinitions<TPolicies>[TAbility]>
93
163
  ): Promise<boolean>;
164
+ /**
165
+ * Return the full allow/deny decision for a context without throwing.
166
+ */
94
167
  inspect<TAbility extends keyof PolicyMapFromDefinitions<TPolicies> & string>(
95
168
  ctx: TContext,
96
169
  ability: TAbility,
97
170
  ...subject: PolicySubjectArgs<PolicyMapFromDefinitions<TPolicies>[TAbility]>
98
171
  ): Promise<GateDecision>;
172
+ /**
173
+ * Return an allowed decision or throw for denied abilities.
174
+ */
99
175
  authorize<
100
176
  TAbility extends keyof PolicyMapFromDefinitions<TPolicies> & string,
101
177
  >(
@@ -105,6 +181,9 @@ export type GatePort<
105
181
  ): Promise<GateAllowedDecision>;
106
182
  };
107
183
 
184
+ /**
185
+ * Hook used to convert a denied decision into an application-specific error.
186
+ */
108
187
  export type GateDenyHandler<TContext> = (
109
188
  decision: GateDeniedDecision,
110
189
  params: {
@@ -114,14 +193,26 @@ export type GateDenyHandler<TContext> = (
114
193
  },
115
194
  ) => MaybePromise<Error | undefined>;
116
195
 
196
+ /**
197
+ * Options for `createGate(...)`.
198
+ */
117
199
  export type CreateGateOptions<
118
200
  TContext,
119
201
  TPolicies extends readonly PolicyDefinition[],
120
202
  > = {
203
+ /**
204
+ * Policy definitions to register.
205
+ */
121
206
  policies: TPolicies;
207
+ /**
208
+ * Optional mapper for denied authorization decisions.
209
+ */
122
210
  onDeny?: GateDenyHandler<TContext>;
123
211
  };
124
212
 
213
+ /**
214
+ * Default error thrown by `authorize(...)` when a policy denies access.
215
+ */
125
216
  export class GateAuthorizationError extends Error {
126
217
  readonly code: string;
127
218
  readonly status = 403;
@@ -135,10 +226,26 @@ export class GateAuthorizationError extends Error {
135
226
  }
136
227
  }
137
228
 
229
+ /**
230
+ * Create an explicit allow decision.
231
+ *
232
+ * @returns A normalized gate decision with `allowed: true`.
233
+ */
138
234
  export function allow(): GateAllowedDecision {
139
235
  return { allowed: true };
140
236
  }
141
237
 
238
+ /**
239
+ * Create an explicit deny decision.
240
+ *
241
+ * @example
242
+ * ```ts
243
+ * return deny("Only owners can edit this post");
244
+ * ```
245
+ *
246
+ * @param reasonOrDecision - Optional reason string or structured denial data.
247
+ * @returns A normalized gate decision with `allowed: false`.
248
+ */
142
249
  export function deny(
143
250
  reasonOrDecision?: string | Omit<GateDeniedDecision, "allowed">,
144
251
  ): GateDeniedDecision {
@@ -152,12 +259,38 @@ export function deny(
152
259
  };
153
260
  }
154
261
 
262
+ /**
263
+ * Define a typed group of authorization policies.
264
+ *
265
+ * Keep policy definitions near the feature that owns the business rule. The
266
+ * returned definition is registered with `createGate(...)`.
267
+ *
268
+ * @example
269
+ * ```ts
270
+ * export const postPolicy = definePolicy({
271
+ * "posts.update": (ctx, post: Post) => post.authorId === ctx.actor.id,
272
+ * });
273
+ * ```
274
+ *
275
+ * @param policies - Ability resolver map keyed by stable ability names.
276
+ * @returns A typed policy definition for registration with `createGate(...)`.
277
+ */
155
278
  export function definePolicy<
156
279
  const TPolicies extends Record<string, PolicyResolver>,
157
280
  >(policies: TPolicies): PolicyDefinition<TPolicies> {
158
281
  return { policies };
159
282
  }
160
283
 
284
+ /**
285
+ * Create an authorization gate from app-owned policy definitions.
286
+ *
287
+ * Register the gate as a port, then bind it to the request/background context:
288
+ * `gate: ports.gate.bind(context)`. Use cases can then call
289
+ * `ctx.gate.authorize(...)` for business authorization.
290
+ *
291
+ * @param options - Policy definitions and optional denial mapper.
292
+ * @returns A gate port that can evaluate registered abilities.
293
+ */
161
294
  export function createGate<
162
295
  TContext,
163
296
  const TPolicies extends readonly PolicyDefinition[],
@@ -1,3 +1,6 @@
1
+ /**
2
+ * Input for a single rate-limit hit.
3
+ */
1
4
  export interface RateLimitHitOptions {
2
5
  /**
3
6
  * Unique key for this rate limit window.
@@ -15,6 +18,9 @@ export interface RateLimitHitOptions {
15
18
  windowSec: number;
16
19
  }
17
20
 
21
+ /**
22
+ * Result of recording a rate-limit hit.
23
+ */
18
24
  export interface RateLimitResult {
19
25
  /**
20
26
  * True when the hit is within the configured limit.
@@ -36,7 +42,16 @@ export interface RateLimitResult {
36
42
  retryAfterSeconds: number | null;
37
43
  }
38
44
 
45
+ /**
46
+ * App-facing rate limiting port.
47
+ *
48
+ * Implement this with an atomic shared store such as Redis for production.
49
+ * Hook helpers call `hit(...)` to decide whether a request should continue.
50
+ */
39
51
  export interface RateLimitPort {
52
+ /**
53
+ * Record one hit for a rate-limit key and return the current decision.
54
+ */
40
55
  hit(options: RateLimitHitOptions): Promise<RateLimitResult>;
41
56
  }
42
57
 
@@ -55,6 +70,16 @@ function toRetryAfterSeconds(resetAt: number): number {
55
70
  return Math.max(0, Math.ceil((resetAt - Date.now()) / 1000));
56
71
  }
57
72
 
73
+ /**
74
+ * Create an in-memory rate limiter for tests, examples, and single-process
75
+ * development.
76
+ *
77
+ * This adapter is not durable or distributed. Production apps should use a
78
+ * provider backed by a shared atomic store when multiple processes or regions
79
+ * can serve requests.
80
+ *
81
+ * @returns A rate-limit port backed by a local `Map`.
82
+ */
58
83
  export function createMemoryRateLimiter(): RateLimitPort {
59
84
  const windows = new Map<string, MemoryRateLimitWindow>();
60
85
 
@@ -1,7 +1,19 @@
1
+ /**
2
+ * Default replacement used when a sensitive field is redacted.
3
+ */
1
4
  export const DEFAULT_REDACTED_VALUE = "[redacted]";
5
+ /**
6
+ * Default replacement used when recursive redaction exceeds `maxDepth`.
7
+ */
2
8
  export const DEFAULT_TRUNCATED_VALUE = "[truncated]";
9
+ /**
10
+ * Default replacement used when recursive redaction finds a circular object.
11
+ */
3
12
  export const DEFAULT_CIRCULAR_VALUE = "[circular]";
4
13
 
14
+ /**
15
+ * Exact header/object keys redacted by default.
16
+ */
5
17
  export const DEFAULT_SENSITIVE_KEYS = [
6
18
  "authorization",
7
19
  "cookie",
@@ -14,6 +26,11 @@ export const DEFAULT_SENSITIVE_KEYS = [
14
26
  "credentials",
15
27
  ] as const;
16
28
 
29
+ /**
30
+ * Key substrings redacted by default.
31
+ *
32
+ * Matching is case-insensitive.
33
+ */
17
34
  export const DEFAULT_SENSITIVE_KEY_TERMS = [
18
35
  "token",
19
36
  "password",
@@ -23,24 +40,66 @@ export const DEFAULT_SENSITIVE_KEY_TERMS = [
23
40
  "privatekey",
24
41
  ] as const;
25
42
 
43
+ /**
44
+ * Context passed to custom redaction key decisions.
45
+ */
26
46
  export interface RedactionDecisionContext {
47
+ /**
48
+ * Current object/header key being evaluated.
49
+ */
27
50
  key: string;
51
+ /**
52
+ * Path to the current value from the root object.
53
+ */
28
54
  path: readonly string[];
55
+ /**
56
+ * Current value being evaluated.
57
+ */
29
58
  value: unknown;
30
59
  }
31
60
 
61
+ /**
62
+ * Options that control recursive value and header redaction.
63
+ */
32
64
  export interface RedactionOptions {
65
+ /**
66
+ * Value used when a key is considered sensitive.
67
+ */
33
68
  replacement?: string;
69
+ /**
70
+ * Value used when recursion exceeds `maxDepth`.
71
+ */
34
72
  truncatedValue?: string;
73
+ /**
74
+ * Value used for circular references.
75
+ */
35
76
  circularValue?: string;
77
+ /**
78
+ * Maximum object/array depth to traverse before truncating.
79
+ */
36
80
  maxDepth?: number;
81
+ /**
82
+ * Additional exact keys to redact.
83
+ */
37
84
  sensitiveKeys?: readonly string[];
85
+ /**
86
+ * Additional case-insensitive key substrings to redact.
87
+ */
38
88
  sensitiveKeyTerms?: readonly string[];
89
+ /**
90
+ * Custom key-level redaction rule.
91
+ */
39
92
  shouldRedactKey?: (context: RedactionDecisionContext) => boolean;
40
93
  }
41
94
 
95
+ /**
96
+ * Function that returns a redacted copy of a value.
97
+ */
42
98
  export type Redactor<T = unknown> = (value: T) => T;
43
99
 
100
+ /**
101
+ * Header input shapes accepted by `redactHeaders(...)`.
102
+ */
44
103
  export type RedactableHeaders =
45
104
  | Headers
46
105
  | Iterable<readonly [string, unknown]>
@@ -50,6 +109,17 @@ function normalizeKey(key: string): string {
50
109
  return key.toLowerCase();
51
110
  }
52
111
 
112
+ /**
113
+ * Return whether a key should be redacted.
114
+ *
115
+ * Checks default exact keys, default key terms, user-provided exact keys,
116
+ * user-provided key terms, and finally `shouldRedactKey`.
117
+ *
118
+ * @param key - Object or header key to evaluate.
119
+ * @param options - Optional redaction behavior.
120
+ * @param context - Optional path/value context for custom decisions.
121
+ * @returns `true` when the key should be replaced.
122
+ */
53
123
  export function isSensitiveKey(
54
124
  key: string,
55
125
  options: RedactionOptions = {},
@@ -148,6 +218,20 @@ function redactUnknown(
148
218
  return output;
149
219
  }
150
220
 
221
+ /**
222
+ * Recursively redact a value using Beignet's default sensitive-key rules plus
223
+ * any custom rules in `options`.
224
+ *
225
+ * This returns a copy for objects and arrays. Primitive values are returned as
226
+ * is unless they are under a sensitive key. Some runtime shapes are normalized:
227
+ * `bigint` becomes a string, `Error` becomes a plain object with `name`,
228
+ * `message`, and `stack`, and class instances are copied from enumerable
229
+ * entries.
230
+ *
231
+ * @param value - Value to redact.
232
+ * @param options - Optional redaction behavior.
233
+ * @returns A redacted value typed as the input type for caller convenience.
234
+ */
151
235
  export function redactValue<T = unknown>(
152
236
  value: T,
153
237
  options: RedactionOptions = {},
@@ -176,6 +260,17 @@ function headerEntries(
176
260
  return Object.entries(headers);
177
261
  }
178
262
 
263
+ /**
264
+ * Redact headers into a plain object.
265
+ *
266
+ * Sensitive header names such as `authorization`, `cookie`, and token-like keys
267
+ * are replaced. Non-sensitive values are passed through `redactValue(...)` so
268
+ * nested object values are still sanitized.
269
+ *
270
+ * @param headers - Headers object, iterable entries, or plain object.
271
+ * @param options - Optional redaction behavior.
272
+ * @returns A plain object with redacted header values.
273
+ */
179
274
  export function redactHeaders(
180
275
  headers: RedactableHeaders,
181
276
  options: RedactionOptions = {},
@@ -192,6 +287,12 @@ export function redactHeaders(
192
287
  return output;
193
288
  }
194
289
 
290
+ /**
291
+ * Create a reusable redactor function from options.
292
+ *
293
+ * @param options - Redaction behavior to apply on each call.
294
+ * @returns A function that redacts values with the provided options.
295
+ */
195
296
  export function createRedactor<T = unknown>(
196
297
  options: RedactionOptions = {},
197
298
  ): Redactor<T> {
@@ -1,7 +1,16 @@
1
+ /**
2
+ * Object visibility understood by storage ports.
3
+ */
1
4
  export type StorageVisibility = "private" | "public";
2
5
 
6
+ /**
7
+ * String metadata stored alongside an object.
8
+ */
3
9
  export type StorageMetadata = Record<string, string>;
4
10
 
11
+ /**
12
+ * Body types accepted by `StoragePort.put(...)`.
13
+ */
5
14
  export type StorageBody =
6
15
  | string
7
16
  | ArrayBuffer
@@ -9,23 +18,63 @@ export type StorageBody =
9
18
  | Blob
10
19
  | ReadableStream<Uint8Array>;
11
20
 
21
+ /**
22
+ * Options for writing an object to storage.
23
+ */
12
24
  export interface StoragePutOptions {
25
+ /**
26
+ * MIME content type stored with the object.
27
+ */
13
28
  contentType?: string;
29
+ /**
30
+ * Cache-Control value stored with the object.
31
+ */
14
32
  cacheControl?: string;
33
+ /**
34
+ * Provider metadata stored with the object.
35
+ */
15
36
  metadata?: StorageMetadata;
37
+ /**
38
+ * Whether the object may receive a public URL.
39
+ */
16
40
  visibility?: StorageVisibility;
17
41
  }
18
42
 
43
+ /**
44
+ * Metadata for an object in storage.
45
+ */
19
46
  export interface StorageObject {
47
+ /**
48
+ * Object key. Keys are relative object-store paths, not filesystem paths or
49
+ * public URLs.
50
+ */
20
51
  key: string;
52
+ /**
53
+ * Object size in bytes.
54
+ */
21
55
  size: number;
22
56
  contentType?: string;
23
57
  cacheControl?: string;
58
+ /**
59
+ * Provider metadata stored with the object.
60
+ */
24
61
  metadata: StorageMetadata;
62
+ /**
63
+ * Object visibility.
64
+ */
25
65
  visibility: StorageVisibility;
66
+ /**
67
+ * Last modification timestamp.
68
+ */
26
69
  lastModified: Date;
27
70
  }
28
71
 
72
+ /**
73
+ * Object metadata plus a one-shot readable body.
74
+ *
75
+ * Like Fetch response bodies, storage bodies can be consumed once. Call `get`
76
+ * again if you need another reader.
77
+ */
29
78
  export interface StorageObjectBody extends StorageObject {
30
79
  /**
31
80
  * Whether this object body has already been consumed. Like Fetch response
@@ -33,25 +82,66 @@ export interface StorageObjectBody extends StorageObject {
33
82
  * buffering them.
34
83
  */
35
84
  readonly bodyUsed: boolean;
85
+ /**
86
+ * Consume the object as a readable byte stream.
87
+ */
36
88
  stream(): ReadableStream<Uint8Array>;
89
+ /**
90
+ * Consume the object as bytes.
91
+ */
37
92
  bytes(): Promise<Uint8Array>;
93
+ /**
94
+ * Consume the object as an ArrayBuffer.
95
+ */
38
96
  arrayBuffer(): Promise<ArrayBuffer>;
97
+ /**
98
+ * Consume the object as UTF-8 text.
99
+ */
39
100
  text(): Promise<string>;
40
101
  }
41
102
 
103
+ /**
104
+ * App-facing object storage port.
105
+ *
106
+ * Implement this with S3, R2, local disk, or a test adapter. Application code
107
+ * should depend on this interface instead of provider-specific SDKs.
108
+ */
42
109
  export interface StoragePort {
110
+ /**
111
+ * Store an object and return its metadata.
112
+ */
43
113
  put(
44
114
  key: string,
45
115
  body: StorageBody,
46
116
  options?: StoragePutOptions,
47
117
  ): Promise<StorageObject>;
118
+ /**
119
+ * Return object metadata and body, or `null` when missing.
120
+ */
48
121
  get(key: string): Promise<StorageObjectBody | null>;
122
+ /**
123
+ * Return object metadata without its body, or `null` when missing.
124
+ */
49
125
  stat(key: string): Promise<StorageObject | null>;
126
+ /**
127
+ * Delete an object.
128
+ *
129
+ * @returns `true` when the object existed.
130
+ */
50
131
  delete(key: string): Promise<boolean>;
132
+ /**
133
+ * Return whether an object exists.
134
+ */
51
135
  exists(key: string): Promise<boolean>;
136
+ /**
137
+ * Return a public URL when the object is public and the adapter can build one.
138
+ */
52
139
  publicUrl(key: string): Promise<string | null>;
53
140
  }
54
141
 
142
+ /**
143
+ * Options for `createMemoryStorage(...)`.
144
+ */
55
145
  export interface MemoryStorageOptions {
56
146
  /**
57
147
  * Base URL used by `publicUrl(...)` for objects written with
@@ -219,6 +309,16 @@ function joinPublicUrl(baseUrl: string, key: string): string {
219
309
  return `${base}/${encodedKey}`;
220
310
  }
221
311
 
312
+ /**
313
+ * Create an in-memory object storage adapter for tests, examples, and
314
+ * single-process development.
315
+ *
316
+ * This adapter validates object keys using Beignet's storage key rules. It is
317
+ * not durable and does not share objects across processes.
318
+ *
319
+ * @param options - Optional public URL base for public objects.
320
+ * @returns A storage port backed by a local `Map`.
321
+ */
222
322
  export function createMemoryStorage(
223
323
  options: MemoryStorageOptions = {},
224
324
  ): StoragePort {