@prsm/entitle 2.1.1 → 2.2.0
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/README.md +4 -0
- package/package.json +1 -1
- package/src/entitlements.js +49 -18
- package/types/entitlements.d.ts +54 -14
package/README.md
CHANGED
|
@@ -175,6 +175,10 @@ Returns the subject's effective plan name.
|
|
|
175
175
|
|
|
176
176
|
Returns the full effective snapshot `{ plan, features, limits }`, for a settings or billing page.
|
|
177
177
|
|
|
178
|
+
### `entitlements.catalog()`
|
|
179
|
+
|
|
180
|
+
Returns the static configuration `{ defaultPlan, plans, features, limits }`: every declared plan, the default plan, and the full feature and limit universes. Where `describe` resolves a single subject, `catalog` exposes the whole offering, for a plan comparison table, an admin dashboard, or documenting what the system grants. Subject-independent and read-only, so it never touches storage. The returned object is a fresh copy.
|
|
181
|
+
|
|
178
182
|
### `entitlements.close()`
|
|
179
183
|
|
|
180
184
|
Releases driver resources.
|
package/package.json
CHANGED
package/src/entitlements.js
CHANGED
|
@@ -11,8 +11,8 @@ import ms from "@prsm/ms"
|
|
|
11
11
|
* A per-subject override layered on top of the subject's plan. Shallow-merges
|
|
12
12
|
* over the plan, so you only specify what differs (the enterprise customer who
|
|
13
13
|
* negotiated more seats, or got one feature switched on).
|
|
14
|
-
* @property {Record<string, boolean>} [features]
|
|
15
|
-
* @property {Record<string, number|null>} [limits]
|
|
14
|
+
* @property {Record<string, boolean>} [features] - feature flags to override for this subject; merged over the plan's features, so include only the ones that differ
|
|
15
|
+
* @property {Record<string, number|null>} [limits] - limit ceilings to override for this subject; merged over the plan's limits, so include only the ones that differ (`null` means unlimited)
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -29,9 +29,17 @@ import ms from "@prsm/ms"
|
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* @typedef {Object} Effective
|
|
32
|
-
* @property {string} plan - the effective plan name
|
|
33
|
-
* @property {Record<string, boolean>} features
|
|
34
|
-
* @property {Record<string, number|null>} limits
|
|
32
|
+
* @property {string} plan - the effective plan name (the default plan if the subject is unassigned)
|
|
33
|
+
* @property {Record<string, boolean>} features - the resolved feature flags, after applying the subject's override on top of the plan
|
|
34
|
+
* @property {Record<string, number|null>} limits - the resolved limit ceilings, after applying the subject's override on top of the plan (`null` means unlimited)
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @typedef {Object} Catalog
|
|
39
|
+
* @property {string} defaultPlan - the plan applied to a subject with no assignment
|
|
40
|
+
* @property {Record<string, Plan>} plans - the declared plan catalog (your pricing tiers)
|
|
41
|
+
* @property {string[]} features - the full feature universe (declared, or derived from the union across plans)
|
|
42
|
+
* @property {string[]} limits - the full limit universe (declared, or derived from the union across plans)
|
|
35
43
|
*/
|
|
36
44
|
|
|
37
45
|
/**
|
|
@@ -200,9 +208,32 @@ export function createEntitlements(options = {}) {
|
|
|
200
208
|
return driver.setup()
|
|
201
209
|
},
|
|
202
210
|
|
|
211
|
+
/**
|
|
212
|
+
* The static configuration of this resolver: the plan catalog, the default
|
|
213
|
+
* plan, and the full feature and limit universes. Unlike describe(), which
|
|
214
|
+
* resolves a single subject, this exposes every plan and every declared key
|
|
215
|
+
* - for plan comparison tables, admin dashboards, or documenting what the
|
|
216
|
+
* system offers. Subject-independent, so it never touches storage. The
|
|
217
|
+
* returned object is a fresh copy; mutating it does not affect the resolver.
|
|
218
|
+
* @returns {Catalog}
|
|
219
|
+
*/
|
|
220
|
+
catalog() {
|
|
221
|
+
return {
|
|
222
|
+
defaultPlan,
|
|
223
|
+
plans: Object.fromEntries(
|
|
224
|
+
Object.entries(catalog).map(([name, p]) => [name, {
|
|
225
|
+
features: { ...(p.features ?? {}) },
|
|
226
|
+
limits: { ...(p.limits ?? {}) },
|
|
227
|
+
}]),
|
|
228
|
+
),
|
|
229
|
+
features: [...featureUniverse],
|
|
230
|
+
limits: [...limitUniverse],
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
|
|
203
234
|
/**
|
|
204
235
|
* Assign a subject to a plan. Takes effect immediately.
|
|
205
|
-
* @param {string} subject
|
|
236
|
+
* @param {string} subject - the subject identifier (whatever id you key entitlements by, such as an account or user id)
|
|
206
237
|
* @param {string} plan - a key of the plan catalog
|
|
207
238
|
*/
|
|
208
239
|
async assign(subject, plan) {
|
|
@@ -216,7 +247,7 @@ export function createEntitlements(options = {}) {
|
|
|
216
247
|
* Remove a subject's plan assignment, reverting them to the default plan.
|
|
217
248
|
* Distinct from assigning the default plan explicitly: an unassigned subject
|
|
218
249
|
* follows `defaultPlan` if it later changes.
|
|
219
|
-
* @param {string} subject
|
|
250
|
+
* @param {string} subject - the subject identifier whose assignment is removed
|
|
220
251
|
*/
|
|
221
252
|
async unassign(subject) {
|
|
222
253
|
if (!subject) throw new Error("unassign requires a `subject`")
|
|
@@ -230,8 +261,8 @@ export function createEntitlements(options = {}) {
|
|
|
230
261
|
* accumulate: overriding `seats`, then later overriding `sso`, leaves both in
|
|
231
262
|
* place, and overriding a key again updates just that key. Use clearOverride
|
|
232
263
|
* to remove overrides. Takes effect immediately.
|
|
233
|
-
* @param {string} subject
|
|
234
|
-
* @param {Override} data
|
|
264
|
+
* @param {string} subject - the subject identifier to override
|
|
265
|
+
* @param {Override} data - the features and/or limits to override; merged into any existing override
|
|
235
266
|
*/
|
|
236
267
|
async override(subject, data) {
|
|
237
268
|
if (!subject) throw new Error("override requires a `subject`")
|
|
@@ -244,8 +275,8 @@ export function createEntitlements(options = {}) {
|
|
|
244
275
|
* Remove overrides for a subject. With no `keys`, removes the entire override
|
|
245
276
|
* and the subject falls back to plain plan entitlements. With `keys`, removes
|
|
246
277
|
* only those override entries (reverting them to the plan) and keeps the rest.
|
|
247
|
-
* @param {string} subject
|
|
248
|
-
* @param {{ features?: string[], limits?: string[] }} [keys]
|
|
278
|
+
* @param {string} subject - the subject identifier whose override is cleared
|
|
279
|
+
* @param {{ features?: string[], limits?: string[] }} [keys] - the specific feature and limit keys to revert; omit to clear the entire override
|
|
249
280
|
*/
|
|
250
281
|
async clearOverride(subject, keys) {
|
|
251
282
|
if (!subject) throw new Error("clearOverride requires a `subject`")
|
|
@@ -259,7 +290,7 @@ export function createEntitlements(options = {}) {
|
|
|
259
290
|
|
|
260
291
|
/**
|
|
261
292
|
* The subject's effective plan name (the default plan if unassigned).
|
|
262
|
-
* @param {string} subject
|
|
293
|
+
* @param {string} subject - the subject identifier to resolve
|
|
263
294
|
* @returns {Promise<string>}
|
|
264
295
|
*/
|
|
265
296
|
async plan(subject) {
|
|
@@ -270,8 +301,8 @@ export function createEntitlements(options = {}) {
|
|
|
270
301
|
* Whether a capability flag is granted to the subject. Throws on a feature
|
|
271
302
|
* key outside the declared/derived universe, so typos surface instead of
|
|
272
303
|
* silently returning false.
|
|
273
|
-
* @param {string} subject
|
|
274
|
-
* @param {string} feature
|
|
304
|
+
* @param {string} subject - the subject identifier to resolve
|
|
305
|
+
* @param {string} feature - the feature key to check; must be in the declared/derived feature universe
|
|
275
306
|
* @returns {Promise<boolean>}
|
|
276
307
|
*/
|
|
277
308
|
async can(subject, feature) {
|
|
@@ -288,8 +319,8 @@ export function createEntitlements(options = {}) {
|
|
|
288
319
|
* subject's plan does not grant - never silently unlimited. Throws on a key
|
|
289
320
|
* outside the declared/derived universe. This is the static ceiling; it does
|
|
290
321
|
* not read usage.
|
|
291
|
-
* @param {string} subject
|
|
292
|
-
* @param {string} key
|
|
322
|
+
* @param {string} subject - the subject identifier to resolve
|
|
323
|
+
* @param {string} key - the limit key to resolve; must be in the declared/derived limit universe
|
|
293
324
|
* @returns {Promise<number|null>}
|
|
294
325
|
*/
|
|
295
326
|
limit(subject, key) {
|
|
@@ -301,7 +332,7 @@ export function createEntitlements(options = {}) {
|
|
|
301
332
|
* reads current usage from the meter for the metric of the same name. This is
|
|
302
333
|
* the composition seam: entitle supplies the limit, meter supplies the usage.
|
|
303
334
|
* Requires a `meter` to have been passed to `createEntitlements`.
|
|
304
|
-
* @param {string} subject
|
|
335
|
+
* @param {string} subject - the subject identifier; must match the id usage is recorded under in the meter
|
|
305
336
|
* @param {string} key - a limit key that is also a meter metric
|
|
306
337
|
* @param {{ period?: any, range?: any }} [usageQuery] - forwarded to `meter.usage`
|
|
307
338
|
* @returns {Promise<CheckResult>}
|
|
@@ -328,7 +359,7 @@ export function createEntitlements(options = {}) {
|
|
|
328
359
|
|
|
329
360
|
/**
|
|
330
361
|
* The subject's full effective entitlements, for a settings or billing page.
|
|
331
|
-
* @param {string} subject
|
|
362
|
+
* @param {string} subject - the subject identifier to resolve
|
|
332
363
|
* @returns {Promise<Effective>}
|
|
333
364
|
*/
|
|
334
365
|
async describe(subject) {
|
package/types/entitlements.d.ts
CHANGED
|
@@ -9,9 +9,19 @@
|
|
|
9
9
|
export function createEntitlements(options?: EntitlementsOptions): {
|
|
10
10
|
/** Create the backing tables if they do not exist. Idempotent. */
|
|
11
11
|
setup(): any;
|
|
12
|
+
/**
|
|
13
|
+
* The static configuration of this resolver: the plan catalog, the default
|
|
14
|
+
* plan, and the full feature and limit universes. Unlike describe(), which
|
|
15
|
+
* resolves a single subject, this exposes every plan and every declared key
|
|
16
|
+
* - for plan comparison tables, admin dashboards, or documenting what the
|
|
17
|
+
* system offers. Subject-independent, so it never touches storage. The
|
|
18
|
+
* returned object is a fresh copy; mutating it does not affect the resolver.
|
|
19
|
+
* @returns {Catalog}
|
|
20
|
+
*/
|
|
21
|
+
catalog(): Catalog;
|
|
12
22
|
/**
|
|
13
23
|
* Assign a subject to a plan. Takes effect immediately.
|
|
14
|
-
* @param {string} subject
|
|
24
|
+
* @param {string} subject - the subject identifier (whatever id you key entitlements by, such as an account or user id)
|
|
15
25
|
* @param {string} plan - a key of the plan catalog
|
|
16
26
|
*/
|
|
17
27
|
assign(subject: string, plan: string): Promise<void>;
|
|
@@ -19,7 +29,7 @@ export function createEntitlements(options?: EntitlementsOptions): {
|
|
|
19
29
|
* Remove a subject's plan assignment, reverting them to the default plan.
|
|
20
30
|
* Distinct from assigning the default plan explicitly: an unassigned subject
|
|
21
31
|
* follows `defaultPlan` if it later changes.
|
|
22
|
-
* @param {string} subject
|
|
32
|
+
* @param {string} subject - the subject identifier whose assignment is removed
|
|
23
33
|
*/
|
|
24
34
|
unassign(subject: string): Promise<void>;
|
|
25
35
|
/**
|
|
@@ -28,16 +38,16 @@ export function createEntitlements(options?: EntitlementsOptions): {
|
|
|
28
38
|
* accumulate: overriding `seats`, then later overriding `sso`, leaves both in
|
|
29
39
|
* place, and overriding a key again updates just that key. Use clearOverride
|
|
30
40
|
* to remove overrides. Takes effect immediately.
|
|
31
|
-
* @param {string} subject
|
|
32
|
-
* @param {Override} data
|
|
41
|
+
* @param {string} subject - the subject identifier to override
|
|
42
|
+
* @param {Override} data - the features and/or limits to override; merged into any existing override
|
|
33
43
|
*/
|
|
34
44
|
override(subject: string, data: Override): Promise<void>;
|
|
35
45
|
/**
|
|
36
46
|
* Remove overrides for a subject. With no `keys`, removes the entire override
|
|
37
47
|
* and the subject falls back to plain plan entitlements. With `keys`, removes
|
|
38
48
|
* only those override entries (reverting them to the plan) and keeps the rest.
|
|
39
|
-
* @param {string} subject
|
|
40
|
-
* @param {{ features?: string[], limits?: string[] }} [keys]
|
|
49
|
+
* @param {string} subject - the subject identifier whose override is cleared
|
|
50
|
+
* @param {{ features?: string[], limits?: string[] }} [keys] - the specific feature and limit keys to revert; omit to clear the entire override
|
|
41
51
|
*/
|
|
42
52
|
clearOverride(subject: string, keys?: {
|
|
43
53
|
features?: string[];
|
|
@@ -45,7 +55,7 @@ export function createEntitlements(options?: EntitlementsOptions): {
|
|
|
45
55
|
}): Promise<void>;
|
|
46
56
|
/**
|
|
47
57
|
* The subject's effective plan name (the default plan if unassigned).
|
|
48
|
-
* @param {string} subject
|
|
58
|
+
* @param {string} subject - the subject identifier to resolve
|
|
49
59
|
* @returns {Promise<string>}
|
|
50
60
|
*/
|
|
51
61
|
plan(subject: string): Promise<string>;
|
|
@@ -53,8 +63,8 @@ export function createEntitlements(options?: EntitlementsOptions): {
|
|
|
53
63
|
* Whether a capability flag is granted to the subject. Throws on a feature
|
|
54
64
|
* key outside the declared/derived universe, so typos surface instead of
|
|
55
65
|
* silently returning false.
|
|
56
|
-
* @param {string} subject
|
|
57
|
-
* @param {string} feature
|
|
66
|
+
* @param {string} subject - the subject identifier to resolve
|
|
67
|
+
* @param {string} feature - the feature key to check; must be in the declared/derived feature universe
|
|
58
68
|
* @returns {Promise<boolean>}
|
|
59
69
|
*/
|
|
60
70
|
can(subject: string, feature: string): Promise<boolean>;
|
|
@@ -64,8 +74,8 @@ export function createEntitlements(options?: EntitlementsOptions): {
|
|
|
64
74
|
* subject's plan does not grant - never silently unlimited. Throws on a key
|
|
65
75
|
* outside the declared/derived universe. This is the static ceiling; it does
|
|
66
76
|
* not read usage.
|
|
67
|
-
* @param {string} subject
|
|
68
|
-
* @param {string} key
|
|
77
|
+
* @param {string} subject - the subject identifier to resolve
|
|
78
|
+
* @param {string} key - the limit key to resolve; must be in the declared/derived limit universe
|
|
69
79
|
* @returns {Promise<number|null>}
|
|
70
80
|
*/
|
|
71
81
|
limit(subject: string, key: string): Promise<number | null>;
|
|
@@ -74,7 +84,7 @@ export function createEntitlements(options?: EntitlementsOptions): {
|
|
|
74
84
|
* reads current usage from the meter for the metric of the same name. This is
|
|
75
85
|
* the composition seam: entitle supplies the limit, meter supplies the usage.
|
|
76
86
|
* Requires a `meter` to have been passed to `createEntitlements`.
|
|
77
|
-
* @param {string} subject
|
|
87
|
+
* @param {string} subject - the subject identifier; must match the id usage is recorded under in the meter
|
|
78
88
|
* @param {string} key - a limit key that is also a meter metric
|
|
79
89
|
* @param {{ period?: any, range?: any }} [usageQuery] - forwarded to `meter.usage`
|
|
80
90
|
* @returns {Promise<CheckResult>}
|
|
@@ -85,7 +95,7 @@ export function createEntitlements(options?: EntitlementsOptions): {
|
|
|
85
95
|
}): Promise<CheckResult>;
|
|
86
96
|
/**
|
|
87
97
|
* The subject's full effective entitlements, for a settings or billing page.
|
|
88
|
-
* @param {string} subject
|
|
98
|
+
* @param {string} subject - the subject identifier to resolve
|
|
89
99
|
* @returns {Promise<Effective>}
|
|
90
100
|
*/
|
|
91
101
|
describe(subject: string): Promise<Effective>;
|
|
@@ -108,7 +118,13 @@ export type Plan = {
|
|
|
108
118
|
* negotiated more seats, or got one feature switched on).
|
|
109
119
|
*/
|
|
110
120
|
export type Override = {
|
|
121
|
+
/**
|
|
122
|
+
* - feature flags to override for this subject; merged over the plan's features, so include only the ones that differ
|
|
123
|
+
*/
|
|
111
124
|
features?: Record<string, boolean>;
|
|
125
|
+
/**
|
|
126
|
+
* - limit ceilings to override for this subject; merged over the plan's limits, so include only the ones that differ (`null` means unlimited)
|
|
127
|
+
*/
|
|
112
128
|
limits?: Record<string, number | null>;
|
|
113
129
|
};
|
|
114
130
|
export type EntitlementsOptions = {
|
|
@@ -151,12 +167,36 @@ export type EntitlementsOptions = {
|
|
|
151
167
|
};
|
|
152
168
|
export type Effective = {
|
|
153
169
|
/**
|
|
154
|
-
* - the effective plan name
|
|
170
|
+
* - the effective plan name (the default plan if the subject is unassigned)
|
|
155
171
|
*/
|
|
156
172
|
plan: string;
|
|
173
|
+
/**
|
|
174
|
+
* - the resolved feature flags, after applying the subject's override on top of the plan
|
|
175
|
+
*/
|
|
157
176
|
features: Record<string, boolean>;
|
|
177
|
+
/**
|
|
178
|
+
* - the resolved limit ceilings, after applying the subject's override on top of the plan (`null` means unlimited)
|
|
179
|
+
*/
|
|
158
180
|
limits: Record<string, number | null>;
|
|
159
181
|
};
|
|
182
|
+
export type Catalog = {
|
|
183
|
+
/**
|
|
184
|
+
* - the plan applied to a subject with no assignment
|
|
185
|
+
*/
|
|
186
|
+
defaultPlan: string;
|
|
187
|
+
/**
|
|
188
|
+
* - the declared plan catalog (your pricing tiers)
|
|
189
|
+
*/
|
|
190
|
+
plans: Record<string, Plan>;
|
|
191
|
+
/**
|
|
192
|
+
* - the full feature universe (declared, or derived from the union across plans)
|
|
193
|
+
*/
|
|
194
|
+
features: string[];
|
|
195
|
+
/**
|
|
196
|
+
* - the full limit universe (declared, or derived from the union across plans)
|
|
197
|
+
*/
|
|
198
|
+
limits: string[];
|
|
199
|
+
};
|
|
160
200
|
export type CheckResult = {
|
|
161
201
|
/**
|
|
162
202
|
* - whether current usage is below the limit (always true when the limit is unlimited)
|