@beignet/core 0.0.13 → 0.0.14
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.
- package/CHANGELOG.md +14 -0
- package/README.md +156 -2
- package/dist/entitlements/index.d.ts +234 -0
- package/dist/entitlements/index.d.ts.map +1 -0
- package/dist/entitlements/index.js +172 -0
- package/dist/entitlements/index.js.map +1 -0
- package/dist/error-reporting/index.d.ts +131 -0
- package/dist/error-reporting/index.d.ts.map +1 -0
- package/dist/error-reporting/index.js +112 -0
- package/dist/error-reporting/index.js.map +1 -0
- package/dist/flags/index.d.ts +293 -0
- package/dist/flags/index.d.ts.map +1 -0
- package/dist/flags/index.js +204 -0
- package/dist/flags/index.js.map +1 -0
- package/dist/locks/index.d.ts +155 -0
- package/dist/locks/index.d.ts.map +1 -0
- package/dist/locks/index.js +248 -0
- package/dist/locks/index.js.map +1 -0
- package/dist/payments/index.d.ts +430 -0
- package/dist/payments/index.d.ts.map +1 -0
- package/dist/payments/index.js +230 -0
- package/dist/payments/index.js.map +1 -0
- package/dist/ports/index.d.ts +61 -1
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +33 -0
- package/dist/ports/index.js.map +1 -1
- package/dist/ports/policy.d.ts +104 -0
- package/dist/ports/policy.d.ts.map +1 -1
- package/dist/ports/policy.js +102 -7
- package/dist/ports/policy.js.map +1 -1
- package/dist/search/index.d.ts +175 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +344 -0
- package/dist/search/index.js.map +1 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +9 -1
- package/dist/server/server.js.map +1 -1
- package/dist/testing/index.d.ts +46 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +33 -1
- package/dist/testing/index.js.map +1 -1
- package/package.json +25 -1
- package/src/entitlements/index.ts +479 -0
- package/src/error-reporting/index.ts +273 -0
- package/src/flags/index.ts +608 -0
- package/src/locks/index.ts +440 -0
- package/src/payments/index.ts +699 -0
- package/src/ports/index.ts +194 -0
- package/src/ports/policy.ts +272 -7
- package/src/search/index.ts +632 -0
- package/src/server/server.ts +15 -0
- package/src/testing/index.ts +83 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @beignet/core
|
|
2
2
|
|
|
3
|
+
## 0.0.14
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 0b106c3: Add first-class error reporting primitives and a Sentry-backed error reporting
|
|
8
|
+
provider.
|
|
9
|
+
- 6828442: Add first-class feature flag primitives, an OpenFeature-backed flags provider,
|
|
10
|
+
and devtools support for flag evaluation, exposure, and tracking events.
|
|
11
|
+
- edf5ddc: Add first-class entitlement primitives for product access checks, devtools-ready entitlement decision observation, and doctor checks for entitlement wiring drift. Generated billing slices expose a billing-backed entitlements port.
|
|
12
|
+
- bcd3864: Add lease-backed lock primitives and a Redis-backed locks provider.
|
|
13
|
+
- d51a35f: Add the provider-neutral payments port, memory payments adapter, Stripe payments provider, Next.js payment webhook route helper, `beignet make payments`, and first-class payments devtools view.
|
|
14
|
+
- 655c101: Add keyed authorization batch checks and best-effort policy decision observation, plus a first-class devtools watcher/view for policy decision events.
|
|
15
|
+
- bcd3864: Add a provider-neutral search port, memory adapter, and Meilisearch provider.
|
|
16
|
+
|
|
3
17
|
## 0.0.13
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
|
|
9
9
|
This package provides Beignet's framework primitives: contracts, server runtime,
|
|
10
10
|
typed client, use cases, ports, domain helpers, app errors, config, events,
|
|
11
|
-
idempotency, outbox, mail, notifications,
|
|
12
|
-
|
|
11
|
+
idempotency, locks, outbox, mail, notifications, payments, search, feature
|
|
12
|
+
flags, error reporting, schedules, uploads, entitlements, pagination helpers, testing
|
|
13
|
+
helpers, and OpenAPI generation.
|
|
13
14
|
|
|
14
15
|
## Installation
|
|
15
16
|
|
|
@@ -43,18 +44,24 @@ name the framework area they depend on.
|
|
|
43
44
|
| `@beignet/core/config` | Environment config validation |
|
|
44
45
|
| `@beignet/core/contracts` | HTTP contract builders, types, path helpers, and contract metadata |
|
|
45
46
|
| `@beignet/core/domain` | Entities, value objects, and domain events |
|
|
47
|
+
| `@beignet/core/entitlements` | Product access decision types, helpers, and static entitlement adapter |
|
|
48
|
+
| `@beignet/core/error-reporting` | Error reporting port, memory adapter, no-op adapter, and helpers |
|
|
46
49
|
| `@beignet/core/errors` | Error catalogs and response helpers |
|
|
47
50
|
| `@beignet/core/events` | Events and listeners |
|
|
51
|
+
| `@beignet/core/flags` | Feature flag definitions, FlagsPort, memory/static adapters, and helpers |
|
|
48
52
|
| `@beignet/core/idempotency` | Retry-safe command, webhook, and job primitives |
|
|
49
53
|
| `@beignet/core/jobs` | Job definitions, retry policies, and inline job dispatch |
|
|
54
|
+
| `@beignet/core/locks` | Lease-backed LocksPort, memory adapter, memory provider, and helpers |
|
|
50
55
|
| `@beignet/core/mail` | Mail port, memory mailer, and memory mailer provider |
|
|
51
56
|
| `@beignet/core/notifications` | Notification definitions, dispatchers, inline notifications provider, mail channels, and test adapters |
|
|
52
57
|
| `@beignet/core/openapi` | OpenAPI generation |
|
|
53
58
|
| `@beignet/core/outbox` | Durable event and job outbox |
|
|
59
|
+
| `@beignet/core/payments` | Payments port, memory payments adapter, and memory payments provider |
|
|
54
60
|
| `@beignet/core/pagination` | Offset/cursor page types, normalizers, and result helpers |
|
|
55
61
|
| `@beignet/core/ports` | App-facing ports, auth, audit, policies, cache, storage, logging, and redaction |
|
|
56
62
|
| `@beignet/core/ports/testing` | Port and policy test helpers |
|
|
57
63
|
| `@beignet/core/providers` | Provider lifecycle and instrumentation primitives |
|
|
64
|
+
| `@beignet/core/search` | Search index definitions, SearchPort, memory adapter, memory provider, and helpers |
|
|
58
65
|
| `@beignet/core/schedules` | Schedule primitives |
|
|
59
66
|
| `@beignet/core/server` | Framework-agnostic server runtime and hook helpers |
|
|
60
67
|
| `@beignet/core/server-only` | Static lint marker for modules that must stay out of client bundles |
|
|
@@ -177,6 +184,148 @@ Replace `createMemoryMailerProvider(...)` with a real mail provider such as
|
|
|
177
184
|
keep the inline notifications provider and run it from jobs or listeners, or
|
|
178
185
|
replace it with an app-owned dispatcher when delivery needs custom semantics.
|
|
179
186
|
|
|
187
|
+
## Entitlements
|
|
188
|
+
|
|
189
|
+
Use `@beignet/core/entitlements` for product access decisions derived from
|
|
190
|
+
app-owned billing or plan state. The resolver maps durable app state to
|
|
191
|
+
allow/deny decisions; `requireEntitlement(...)` enforces the decision from a
|
|
192
|
+
use case and throws a framework-owned 403 by default.
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
import {
|
|
196
|
+
createEntitlements,
|
|
197
|
+
type EntitlementDecisionObserver,
|
|
198
|
+
requireEntitlement,
|
|
199
|
+
} from "@beignet/core/entitlements";
|
|
200
|
+
|
|
201
|
+
function createBillingEntitlements(
|
|
202
|
+
billing: BillingRepository,
|
|
203
|
+
recordDecision?: EntitlementDecisionObserver,
|
|
204
|
+
) {
|
|
205
|
+
return createEntitlements({
|
|
206
|
+
async inspect(input) {
|
|
207
|
+
const account = await billing.findByTenantId(input.subject.id);
|
|
208
|
+
return account?.status === "active";
|
|
209
|
+
},
|
|
210
|
+
onDecision: recordDecision,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
await requireEntitlement(ctx, {
|
|
215
|
+
entitlement: "todos.create",
|
|
216
|
+
subject: { type: "tenant", id: tenantId },
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
`onDecision` is diagnostic only. Observer errors are ignored and cannot change
|
|
221
|
+
the entitlement result.
|
|
222
|
+
|
|
223
|
+
## Feature flags
|
|
224
|
+
|
|
225
|
+
Use `@beignet/core/flags` for typed feature flag definitions and
|
|
226
|
+
provider-neutral evaluation. Flags always carry a default value, and provider
|
|
227
|
+
failures return that default instead of throwing into product workflows.
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import { defineFlag, defineFlags } from "@beignet/core/flags";
|
|
231
|
+
|
|
232
|
+
export const billingFlags = defineFlags({
|
|
233
|
+
newCheckout: defineFlag.boolean("billing.new-checkout", {
|
|
234
|
+
default: false,
|
|
235
|
+
}),
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const enabled = await ctx.ports.flags.evaluate(billingFlags.newCheckout, {
|
|
239
|
+
context: {
|
|
240
|
+
targetingKey: ctx.actor.id,
|
|
241
|
+
tenant: ctx.tenant,
|
|
242
|
+
requestId: ctx.requestId,
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Plain evaluation does not record exposure. Call `recordExposure(...)`
|
|
248
|
+
explicitly when a user actually sees or can be affected by the flagged
|
|
249
|
+
behavior. Use `createMemoryFlags(...)` or `createStaticFlags(...)` in tests, or
|
|
250
|
+
install `@beignet/provider-flags-openfeature` for production providers.
|
|
251
|
+
String and number flags widen to `string` and `number` by default; pass a
|
|
252
|
+
generic when an app wants a closed variant union.
|
|
253
|
+
|
|
254
|
+
## Error reporting
|
|
255
|
+
|
|
256
|
+
Use `@beignet/core/error-reporting` for provider-neutral exception and message
|
|
257
|
+
capture. The port accepts severity, tags, user, contexts, extra metadata, and
|
|
258
|
+
request/trace correlation IDs.
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import { createMemoryErrorReporter } from "@beignet/core/error-reporting";
|
|
262
|
+
|
|
263
|
+
await ctx.ports.errorReporter.captureException(error, {
|
|
264
|
+
level: "error",
|
|
265
|
+
requestId: ctx.requestId,
|
|
266
|
+
traceId: ctx.traceId,
|
|
267
|
+
tags: { feature: "billing" },
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
const errorReporter = createMemoryErrorReporter();
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Use `createMemoryErrorReporter(...)` in tests, `createNoopErrorReporter()` when
|
|
274
|
+
an app needs a bound port without capture, or install
|
|
275
|
+
`@beignet/provider-error-reporting-sentry` for production providers.
|
|
276
|
+
|
|
277
|
+
## Locks and leases
|
|
278
|
+
|
|
279
|
+
Use `@beignet/core/locks` for provider-neutral lease-backed lock coordination.
|
|
280
|
+
Locks prevent overlapping schedules, singleton jobs, cache stampedes, and short
|
|
281
|
+
critical sections across multiple workers or servers.
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
import { createMemoryLocks } from "@beignet/core/locks";
|
|
285
|
+
|
|
286
|
+
await ctx.ports.locks.withLease(
|
|
287
|
+
"schedule:daily-report",
|
|
288
|
+
{ ttlMs: 60_000, waitMs: 0 },
|
|
289
|
+
async ({ lease }) => {
|
|
290
|
+
await runDailyReport(ctx, { fencingToken: lease.fencingToken });
|
|
291
|
+
},
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
const locks = createMemoryLocks();
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Use `createMemoryLocks(...)` in tests, `createMemoryLocksProvider()` for local
|
|
298
|
+
provider wiring, or install `@beignet/provider-locks-redis` for production
|
|
299
|
+
leases.
|
|
300
|
+
|
|
301
|
+
## Search
|
|
302
|
+
|
|
303
|
+
Use `@beignet/core/search` for provider-neutral search index definitions,
|
|
304
|
+
document indexing, and querying searchable read models.
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
import { defineSearchIndex } from "@beignet/core/search";
|
|
308
|
+
|
|
309
|
+
const issueSearchIndex = defineSearchIndex("issues", {
|
|
310
|
+
searchableAttributes: ["key", "title", "description"],
|
|
311
|
+
filterableAttributes: ["tenantId", "status"],
|
|
312
|
+
sortableAttributes: ["createdAt"],
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
await ctx.ports.search.indexDocuments(issueSearchIndex, issueDocument);
|
|
316
|
+
|
|
317
|
+
const results = await ctx.ports.search.search(issueSearchIndex, {
|
|
318
|
+
query: "billing",
|
|
319
|
+
filters: { tenantId },
|
|
320
|
+
sort: ["createdAt:desc"],
|
|
321
|
+
limit: 20,
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Use `createMemorySearch(...)` in tests, `createMemorySearchProvider()` for local
|
|
326
|
+
provider wiring, or install `@beignet/provider-search-meilisearch` for
|
|
327
|
+
production search.
|
|
328
|
+
|
|
180
329
|
## Provider metadata
|
|
181
330
|
|
|
182
331
|
Reusable provider packages should declare static metadata in `package.json`
|
|
@@ -665,6 +814,11 @@ await tester.assertMatrix([
|
|
|
665
814
|
},
|
|
666
815
|
]);
|
|
667
816
|
|
|
817
|
+
const permissions = await tester.gate.canMany(activity, {
|
|
818
|
+
publish: ["posts.publish", post],
|
|
819
|
+
});
|
|
820
|
+
expect(permissions.publish).toBe(true);
|
|
821
|
+
|
|
668
822
|
assertAuditEntry(audit.entries, {
|
|
669
823
|
action: "posts.publish",
|
|
670
824
|
actorId: "user_1",
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @beignet/core/entitlements
|
|
3
|
+
*
|
|
4
|
+
* Provider-neutral product access primitives for Beignet applications.
|
|
5
|
+
*/
|
|
6
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
7
|
+
/**
|
|
8
|
+
* Stable app-defined capability key, such as "issues.create".
|
|
9
|
+
*/
|
|
10
|
+
export type EntitlementKey = string;
|
|
11
|
+
/**
|
|
12
|
+
* Principal whose product access is being checked.
|
|
13
|
+
*/
|
|
14
|
+
export type EntitlementSubject = {
|
|
15
|
+
/**
|
|
16
|
+
* App-defined subject type, commonly "tenant" or "account".
|
|
17
|
+
*/
|
|
18
|
+
type: string;
|
|
19
|
+
/**
|
|
20
|
+
* Stable subject identifier.
|
|
21
|
+
*/
|
|
22
|
+
id: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Input for checking whether a subject has access to a capability.
|
|
26
|
+
*/
|
|
27
|
+
export type EntitlementCheckInput<TKey extends EntitlementKey = EntitlementKey> = {
|
|
28
|
+
/**
|
|
29
|
+
* Capability being checked.
|
|
30
|
+
*/
|
|
31
|
+
entitlement: TKey;
|
|
32
|
+
/**
|
|
33
|
+
* Tenant, account, or other app-owned subject whose product access is checked.
|
|
34
|
+
*/
|
|
35
|
+
subject: EntitlementSubject;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* An entitlement decision that allows the capability.
|
|
39
|
+
*/
|
|
40
|
+
export type EntitlementAllowedDecision = {
|
|
41
|
+
allowed: true;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* An entitlement decision that denies the capability.
|
|
45
|
+
*/
|
|
46
|
+
export type EntitlementDeniedDecision = {
|
|
47
|
+
allowed: false;
|
|
48
|
+
reason?: string;
|
|
49
|
+
code?: string;
|
|
50
|
+
details?: unknown;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Normalized entitlement decision.
|
|
54
|
+
*/
|
|
55
|
+
export type EntitlementDecision = EntitlementAllowedDecision | EntitlementDeniedDecision;
|
|
56
|
+
/**
|
|
57
|
+
* Value an entitlement resolver may return.
|
|
58
|
+
*/
|
|
59
|
+
export type EntitlementResolverResult = boolean | EntitlementDecision;
|
|
60
|
+
/**
|
|
61
|
+
* Entitlement port method that produced a decision.
|
|
62
|
+
*/
|
|
63
|
+
export type EntitlementDecisionSource = "can" | "inspect" | "require";
|
|
64
|
+
/**
|
|
65
|
+
* Optional context for entitlement checks.
|
|
66
|
+
*/
|
|
67
|
+
export type EntitlementCheckOptions<TContext = unknown> = {
|
|
68
|
+
/**
|
|
69
|
+
* Application context used for the check. Observers can use this to copy
|
|
70
|
+
* request correlation fields without coupling the resolver to app context.
|
|
71
|
+
*/
|
|
72
|
+
ctx?: TContext;
|
|
73
|
+
/**
|
|
74
|
+
* Source to report to observers. Port methods set this automatically.
|
|
75
|
+
*/
|
|
76
|
+
source?: EntitlementDecisionSource;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* App-facing product access port.
|
|
80
|
+
*/
|
|
81
|
+
export type EntitlementsPort<TKey extends EntitlementKey = EntitlementKey, TContext = unknown> = {
|
|
82
|
+
/**
|
|
83
|
+
* Return only whether the capability is allowed.
|
|
84
|
+
*/
|
|
85
|
+
can(input: EntitlementCheckInput<TKey>, options?: EntitlementCheckOptions<TContext>): Promise<boolean>;
|
|
86
|
+
/**
|
|
87
|
+
* Return the full allow/deny decision without throwing.
|
|
88
|
+
*/
|
|
89
|
+
inspect(input: EntitlementCheckInput<TKey>, options?: EntitlementCheckOptions<TContext>): Promise<EntitlementDecision>;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Function that decides whether an entitlement is granted.
|
|
93
|
+
*/
|
|
94
|
+
export type EntitlementResolver<TKey extends EntitlementKey = EntitlementKey> = (input: EntitlementCheckInput<TKey>) => MaybePromise<EntitlementResolverResult>;
|
|
95
|
+
/**
|
|
96
|
+
* Best-effort entitlement decision observation emitted by an entitlements port.
|
|
97
|
+
*
|
|
98
|
+
* Observers are diagnostic only. They do not participate in entitlement
|
|
99
|
+
* control flow and thrown/rejected observer errors are ignored.
|
|
100
|
+
*/
|
|
101
|
+
export type EntitlementDecisionObservation<TContext = unknown, TKey extends EntitlementKey = EntitlementKey> = {
|
|
102
|
+
/**
|
|
103
|
+
* Port helper that produced the decision.
|
|
104
|
+
*/
|
|
105
|
+
source: EntitlementDecisionSource;
|
|
106
|
+
/**
|
|
107
|
+
* Application context passed by the caller, when available.
|
|
108
|
+
*/
|
|
109
|
+
ctx?: TContext;
|
|
110
|
+
/**
|
|
111
|
+
* Capability being evaluated.
|
|
112
|
+
*/
|
|
113
|
+
entitlement: TKey;
|
|
114
|
+
/**
|
|
115
|
+
* Subject whose product access is checked.
|
|
116
|
+
*/
|
|
117
|
+
subject: EntitlementSubject;
|
|
118
|
+
/**
|
|
119
|
+
* Normalized decision, when resolver evaluation returned normally.
|
|
120
|
+
*/
|
|
121
|
+
decision?: EntitlementDecision;
|
|
122
|
+
/**
|
|
123
|
+
* Error thrown by the resolver, when evaluation failed.
|
|
124
|
+
*/
|
|
125
|
+
error?: unknown;
|
|
126
|
+
/**
|
|
127
|
+
* Resolver duration, excluding observer work.
|
|
128
|
+
*/
|
|
129
|
+
durationMs: number;
|
|
130
|
+
/**
|
|
131
|
+
* Correlation fields copied from the context when present.
|
|
132
|
+
*/
|
|
133
|
+
requestId?: string;
|
|
134
|
+
traceId?: string;
|
|
135
|
+
spanId?: string;
|
|
136
|
+
parentSpanId?: string;
|
|
137
|
+
traceparent?: string;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Best-effort observer called after each entitlement decision or resolver
|
|
141
|
+
* error.
|
|
142
|
+
*/
|
|
143
|
+
export type EntitlementDecisionObserver<TContext = unknown, TKey extends EntitlementKey = EntitlementKey> = (observation: EntitlementDecisionObservation<TContext, TKey>) => MaybePromise<void>;
|
|
144
|
+
/**
|
|
145
|
+
* Options for `createEntitlements(...)`.
|
|
146
|
+
*/
|
|
147
|
+
export type CreateEntitlementsOptions<TKey extends EntitlementKey = EntitlementKey, TContext = unknown> = {
|
|
148
|
+
/**
|
|
149
|
+
* Resolver that maps app-owned product state to an entitlement decision.
|
|
150
|
+
*/
|
|
151
|
+
inspect: EntitlementResolver<TKey>;
|
|
152
|
+
/**
|
|
153
|
+
* Optional best-effort observer for entitlement decisions.
|
|
154
|
+
*
|
|
155
|
+
* This hook is diagnostic only: it cannot change decisions or thrown errors.
|
|
156
|
+
*/
|
|
157
|
+
onDecision?: EntitlementDecisionObserver<TContext, TKey>;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Static grant map keyed by subject key.
|
|
161
|
+
*/
|
|
162
|
+
export type StaticEntitlementGrantMap<TKey extends EntitlementKey = EntitlementKey> = Record<string, readonly TKey[]>;
|
|
163
|
+
/**
|
|
164
|
+
* Options for `createStaticEntitlements(...)`.
|
|
165
|
+
*/
|
|
166
|
+
export type CreateStaticEntitlementsOptions<TKey extends EntitlementKey = EntitlementKey, TContext = unknown> = {
|
|
167
|
+
/**
|
|
168
|
+
* Granted capabilities keyed by subject. The default key is
|
|
169
|
+
* `${subject.type}:${subject.id}`.
|
|
170
|
+
*/
|
|
171
|
+
grants: StaticEntitlementGrantMap<TKey>;
|
|
172
|
+
/**
|
|
173
|
+
* Optional subject key mapper.
|
|
174
|
+
*/
|
|
175
|
+
subjectKey?: (subject: EntitlementSubject) => string;
|
|
176
|
+
/**
|
|
177
|
+
* Default denial decision fields.
|
|
178
|
+
*/
|
|
179
|
+
denied?: Omit<EntitlementDeniedDecision, "allowed">;
|
|
180
|
+
/**
|
|
181
|
+
* Optional best-effort observer for entitlement decisions.
|
|
182
|
+
*/
|
|
183
|
+
onDecision?: EntitlementDecisionObserver<TContext, TKey>;
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* Options accepted by `requireEntitlement(...)`.
|
|
187
|
+
*/
|
|
188
|
+
export type RequireEntitlementOptions<TKey extends EntitlementKey = EntitlementKey> = {
|
|
189
|
+
/**
|
|
190
|
+
* Create the error to throw instead of the framework default.
|
|
191
|
+
*/
|
|
192
|
+
error?: (decision: EntitlementDeniedDecision, input: EntitlementCheckInput<TKey>) => unknown;
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Context shape consumed by `requireEntitlement(...)`.
|
|
196
|
+
*/
|
|
197
|
+
export type EntitlementsContext<TKey extends EntitlementKey = EntitlementKey> = {
|
|
198
|
+
ports: {
|
|
199
|
+
entitlements: EntitlementsPort<TKey>;
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* Error thrown by `requireEntitlement(...)` when product access is denied.
|
|
204
|
+
*/
|
|
205
|
+
export declare class EntitlementRequiredError extends Error {
|
|
206
|
+
readonly code: string;
|
|
207
|
+
readonly status = 403;
|
|
208
|
+
readonly details?: unknown;
|
|
209
|
+
readonly entitlement: string;
|
|
210
|
+
readonly subject: EntitlementSubject;
|
|
211
|
+
constructor(input: EntitlementCheckInput, decision?: EntitlementDeniedDecision);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Create an explicit allow decision.
|
|
215
|
+
*/
|
|
216
|
+
export declare function allowEntitlement(): EntitlementAllowedDecision;
|
|
217
|
+
/**
|
|
218
|
+
* Create an explicit deny decision.
|
|
219
|
+
*/
|
|
220
|
+
export declare function denyEntitlement(reasonOrDecision?: string | Omit<EntitlementDeniedDecision, "allowed">): EntitlementDeniedDecision;
|
|
221
|
+
/**
|
|
222
|
+
* Create an entitlement port from an app-owned resolver.
|
|
223
|
+
*/
|
|
224
|
+
export declare function createEntitlements<TKey extends EntitlementKey = EntitlementKey, TContext = unknown>(options: CreateEntitlementsOptions<TKey, TContext>): EntitlementsPort<TKey, TContext>;
|
|
225
|
+
/**
|
|
226
|
+
* Create a static entitlement port for tests, starters, and simple apps.
|
|
227
|
+
*/
|
|
228
|
+
export declare function createStaticEntitlements<TKey extends EntitlementKey = EntitlementKey, TContext = unknown>(options: CreateStaticEntitlementsOptions<TKey, TContext>): EntitlementsPort<TKey, TContext>;
|
|
229
|
+
/**
|
|
230
|
+
* Require an entitlement or throw a framework-owned 403 error.
|
|
231
|
+
*/
|
|
232
|
+
export declare function requireEntitlement<TKey extends EntitlementKey = EntitlementKey>(ctx: EntitlementsContext<TKey>, input: EntitlementCheckInput<TKey>, options?: RequireEntitlementOptions<TKey>): Promise<EntitlementAllowedDecision>;
|
|
233
|
+
export {};
|
|
234
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/entitlements/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @beignet/core/entitlements
|
|
3
|
+
*
|
|
4
|
+
* Provider-neutral product access primitives for Beignet applications.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Error thrown by `requireEntitlement(...)` when product access is denied.
|
|
8
|
+
*/
|
|
9
|
+
export class EntitlementRequiredError extends Error {
|
|
10
|
+
code;
|
|
11
|
+
status = 403;
|
|
12
|
+
details;
|
|
13
|
+
entitlement;
|
|
14
|
+
subject;
|
|
15
|
+
constructor(input, decision = denyEntitlement()) {
|
|
16
|
+
super(decision.reason ??
|
|
17
|
+
`Entitlement "${input.entitlement}" is required for this action.`);
|
|
18
|
+
this.name = "EntitlementRequiredError";
|
|
19
|
+
this.code = decision.code ?? "ENTITLEMENT_REQUIRED";
|
|
20
|
+
this.details = decision.details;
|
|
21
|
+
this.entitlement = input.entitlement;
|
|
22
|
+
this.subject = input.subject;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create an explicit allow decision.
|
|
27
|
+
*/
|
|
28
|
+
export function allowEntitlement() {
|
|
29
|
+
return { allowed: true };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Create an explicit deny decision.
|
|
33
|
+
*/
|
|
34
|
+
export function denyEntitlement(reasonOrDecision) {
|
|
35
|
+
if (typeof reasonOrDecision === "string") {
|
|
36
|
+
return { allowed: false, reason: reasonOrDecision };
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
allowed: false,
|
|
40
|
+
...reasonOrDecision,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create an entitlement port from an app-owned resolver.
|
|
45
|
+
*/
|
|
46
|
+
export function createEntitlements(options) {
|
|
47
|
+
const observeDecision = createDecisionObserver(options.onDecision);
|
|
48
|
+
async function evaluate(input, checkOptions) {
|
|
49
|
+
const startedAt = entitlementNow();
|
|
50
|
+
try {
|
|
51
|
+
const decision = normalizeEntitlementDecision(await options.inspect(input));
|
|
52
|
+
observeDecision({
|
|
53
|
+
source: checkOptions?.source ?? "inspect",
|
|
54
|
+
ctx: checkOptions?.ctx,
|
|
55
|
+
entitlement: input.entitlement,
|
|
56
|
+
subject: input.subject,
|
|
57
|
+
decision,
|
|
58
|
+
durationMs: entitlementNow() - startedAt,
|
|
59
|
+
});
|
|
60
|
+
return decision;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
observeDecision({
|
|
64
|
+
source: checkOptions?.source ?? "inspect",
|
|
65
|
+
ctx: checkOptions?.ctx,
|
|
66
|
+
entitlement: input.entitlement,
|
|
67
|
+
subject: input.subject,
|
|
68
|
+
error,
|
|
69
|
+
durationMs: entitlementNow() - startedAt,
|
|
70
|
+
});
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
async can(input, checkOptions) {
|
|
76
|
+
return (await evaluate(input, { ...checkOptions, source: "can" }))
|
|
77
|
+
.allowed;
|
|
78
|
+
},
|
|
79
|
+
inspect(input, checkOptions) {
|
|
80
|
+
return evaluate(input, {
|
|
81
|
+
...checkOptions,
|
|
82
|
+
source: checkOptions?.source ?? "inspect",
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Create a static entitlement port for tests, starters, and simple apps.
|
|
89
|
+
*/
|
|
90
|
+
export function createStaticEntitlements(options) {
|
|
91
|
+
const subjectKey = options.subjectKey ?? defaultSubjectKey;
|
|
92
|
+
return createEntitlements({
|
|
93
|
+
inspect(input) {
|
|
94
|
+
const granted = options.grants[subjectKey(input.subject)] ?? [];
|
|
95
|
+
if (granted.includes(input.entitlement))
|
|
96
|
+
return allowEntitlement();
|
|
97
|
+
return denyEntitlement({
|
|
98
|
+
reason: `Entitlement "${input.entitlement}" is not granted.`,
|
|
99
|
+
code: "ENTITLEMENT_NOT_GRANTED",
|
|
100
|
+
details: {
|
|
101
|
+
entitlement: input.entitlement,
|
|
102
|
+
subject: input.subject,
|
|
103
|
+
},
|
|
104
|
+
...options.denied,
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
onDecision: options.onDecision,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Require an entitlement or throw a framework-owned 403 error.
|
|
112
|
+
*/
|
|
113
|
+
export async function requireEntitlement(ctx, input, options) {
|
|
114
|
+
const decision = await ctx.ports.entitlements.inspect(input, {
|
|
115
|
+
ctx,
|
|
116
|
+
source: "require",
|
|
117
|
+
});
|
|
118
|
+
if (decision.allowed)
|
|
119
|
+
return decision;
|
|
120
|
+
throw options?.error
|
|
121
|
+
? options.error(decision, input)
|
|
122
|
+
: new EntitlementRequiredError(input, decision);
|
|
123
|
+
}
|
|
124
|
+
function normalizeEntitlementDecision(result) {
|
|
125
|
+
if (typeof result === "boolean") {
|
|
126
|
+
return result ? allowEntitlement() : denyEntitlement();
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
function entitlementNow() {
|
|
131
|
+
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
132
|
+
}
|
|
133
|
+
function contextStringField(ctx, field) {
|
|
134
|
+
if (!ctx || typeof ctx !== "object")
|
|
135
|
+
return undefined;
|
|
136
|
+
const value = ctx[field];
|
|
137
|
+
return typeof value === "string" ? value : undefined;
|
|
138
|
+
}
|
|
139
|
+
function enrichObservation(observation) {
|
|
140
|
+
return {
|
|
141
|
+
...observation,
|
|
142
|
+
requestId: contextStringField(observation.ctx, "requestId"),
|
|
143
|
+
traceId: contextStringField(observation.ctx, "traceId"),
|
|
144
|
+
spanId: contextStringField(observation.ctx, "spanId"),
|
|
145
|
+
parentSpanId: contextStringField(observation.ctx, "parentSpanId"),
|
|
146
|
+
traceparent: contextStringField(observation.ctx, "traceparent"),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function isPromiseLike(value) {
|
|
150
|
+
return (value !== null &&
|
|
151
|
+
(typeof value === "object" || typeof value === "function") &&
|
|
152
|
+
typeof value.then === "function");
|
|
153
|
+
}
|
|
154
|
+
function createDecisionObserver(observer) {
|
|
155
|
+
return (observation) => {
|
|
156
|
+
if (!observer)
|
|
157
|
+
return;
|
|
158
|
+
try {
|
|
159
|
+
const result = observer(enrichObservation(observation));
|
|
160
|
+
if (isPromiseLike(result)) {
|
|
161
|
+
Promise.resolve(result).catch(() => undefined);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Observers are diagnostic only and must not affect entitlement checks.
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function defaultSubjectKey(subject) {
|
|
170
|
+
return `${subject.type}:${subject.id}`;
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/entitlements/index.ts"],"names":[],"mappings":"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"}
|