@vritti/api-sdk 0.4.1 → 0.4.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.
- package/dist/catalog-resolver.cjs +72 -105
- package/dist/catalog-resolver.cjs.map +1 -1
- package/dist/catalog-resolver.d.cts +12 -20
- package/dist/catalog-resolver.d.ts +12 -20
- package/dist/catalog-resolver.js +72 -104
- package/dist/catalog-resolver.js.map +1 -1
- package/dist/license.d.cts +1 -1
- package/dist/license.d.ts +1 -1
- package/dist/{types-B7ArIjwo.d.cts → types-Cj6uMN5E.d.cts} +12 -4
- package/dist/{types-B7ArIjwo.d.ts → types-Cj6uMN5E.d.ts} +12 -4
- package/package.json +1 -1
package/dist/catalog-resolver.js
CHANGED
|
@@ -114,78 +114,40 @@ function snapshotFeatureKey(code, scope) {
|
|
|
114
114
|
return `${scope}.${code}`;
|
|
115
115
|
}
|
|
116
116
|
__name(snapshotFeatureKey, "snapshotFeatureKey");
|
|
117
|
-
var SNAPSHOT_SCHEMA_VERSION =
|
|
117
|
+
var SNAPSHOT_SCHEMA_VERSION = 5;
|
|
118
118
|
|
|
119
119
|
// src/catalog-resolver/catalog.builder.ts
|
|
120
|
-
function normalizeApiBuckets(doc) {
|
|
121
|
-
if (!doc) return doc;
|
|
122
|
-
let changed = false;
|
|
123
|
-
const next = {};
|
|
124
|
-
for (const [code, entry] of Object.entries(doc)) {
|
|
125
|
-
const legacy = entry.app;
|
|
126
|
-
if (legacy === void 0 || entry.graphql !== void 0 && entry.http !== void 0) {
|
|
127
|
-
next[code] = entry;
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
changed = true;
|
|
131
|
-
next[code] = {
|
|
132
|
-
...entry,
|
|
133
|
-
...entry.graphql === void 0 ? {
|
|
134
|
-
graphql: legacy
|
|
135
|
-
} : {},
|
|
136
|
-
...entry.http === void 0 ? {
|
|
137
|
-
http: legacy
|
|
138
|
-
} : {}
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
return changed ? next : doc;
|
|
142
|
-
}
|
|
143
|
-
__name(normalizeApiBuckets, "normalizeApiBuckets");
|
|
144
|
-
function normalizePlans(plans) {
|
|
145
|
-
let changed = false;
|
|
146
|
-
const next = {};
|
|
147
|
-
for (const [code, plan] of Object.entries(plans)) {
|
|
148
|
-
const unlockedPermissions = normalizeApiBuckets(plan.unlockedPermissions) ?? {};
|
|
149
|
-
if (unlockedPermissions !== plan.unlockedPermissions) changed = true;
|
|
150
|
-
next[code] = unlockedPermissions === plan.unlockedPermissions ? plan : {
|
|
151
|
-
...plan,
|
|
152
|
-
unlockedPermissions
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
return changed ? next : plans;
|
|
156
|
-
}
|
|
157
|
-
__name(normalizePlans, "normalizePlans");
|
|
158
120
|
function featureAppliesAtNode(applicableSiteTypes, siteType) {
|
|
159
121
|
return applicableSiteTypes.includes(siteType);
|
|
160
122
|
}
|
|
161
123
|
__name(featureAppliesAtNode, "featureAppliesAtNode");
|
|
162
124
|
function findFeatureByCode(snapshot, code) {
|
|
163
|
-
for (const feature of Object.values(snapshot.features
|
|
164
|
-
if (feature
|
|
125
|
+
for (const feature of Object.values(snapshot.features)) {
|
|
126
|
+
if (feature.code === code) return feature;
|
|
165
127
|
}
|
|
166
128
|
return void 0;
|
|
167
129
|
}
|
|
168
130
|
__name(findFeatureByCode, "findFeatureByCode");
|
|
169
131
|
function buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, siteType, scope, availableServices = []) {
|
|
170
132
|
if (!businessCode) return [];
|
|
171
|
-
const business = snapshot.businesses
|
|
133
|
+
const business = snapshot.businesses[businessCode];
|
|
172
134
|
if (!business) return [];
|
|
173
|
-
const plans =
|
|
135
|
+
const plans = business.plans;
|
|
174
136
|
const plan = planCode ? plans[planCode] : void 0;
|
|
175
|
-
const locks =
|
|
137
|
+
const locks = siteLocks;
|
|
176
138
|
const catalog = [];
|
|
177
139
|
const sortedApps = [
|
|
178
140
|
...business.apps
|
|
179
141
|
].sort((a, b) => a.name.localeCompare(b.name));
|
|
180
142
|
for (const app of sortedApps) {
|
|
181
|
-
const businessAppFeatures = app.features.filter((ref) => scope === void 0 || ref.scope === scope).map((ref) => snapshot.features
|
|
143
|
+
const businessAppFeatures = app.features.filter((ref) => scope === void 0 || ref.scope === scope).map((ref) => snapshot.features[snapshotFeatureKey(ref.code, ref.scope)]).filter((f) => !!f && // A UI bucket needs something to render, so a feature shipping no microfrontend is dropped.
|
|
182
144
|
// An API bucket renders nothing — there a feature is admitted by the surfaces it declares
|
|
183
145
|
// instead, so a GRAPHQL credential never resolves an HTTP-only feature. A surface-excluded
|
|
184
146
|
// feature vanishes from the catalog entirely, which is what makes resolution fail closed.
|
|
185
147
|
(isApiBucket(bucket) ? surfaceAllows(f.apiSurfaces, SURFACE_BY_BUCKET[bucket]) : !!(f.microfrontends?.web || f.microfrontends?.mobile)) && (siteType === void 0 || featureAppliesAtNode(f.applicableSiteTypes, siteType)));
|
|
186
148
|
if (businessAppFeatures.length === 0) continue;
|
|
187
149
|
for (const feature of businessAppFeatures) {
|
|
188
|
-
const membership = plan?.unlockedPermissions
|
|
150
|
+
const membership = plan?.unlockedPermissions[feature.code];
|
|
189
151
|
const web = feature.microfrontends?.web;
|
|
190
152
|
const mobile = feature.microfrontends?.mobile;
|
|
191
153
|
const memberOnBucket = membership?.[bucket] !== void 0;
|
|
@@ -229,11 +191,11 @@ function buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, s
|
|
|
229
191
|
__name(buildSiteCatalog, "buildSiteCatalog");
|
|
230
192
|
function isPlanMember(entry) {
|
|
231
193
|
if (!entry) return false;
|
|
232
|
-
return PLATFORMS.some((platform) => entry[platform] !== void 0)
|
|
194
|
+
return PLATFORMS.some((platform) => entry[platform] !== void 0);
|
|
233
195
|
}
|
|
234
196
|
__name(isPlanMember, "isPlanMember");
|
|
235
197
|
function surfaceAllows(surfaces, surface) {
|
|
236
|
-
return surface === void 0 || surfaces
|
|
198
|
+
return surface === void 0 || surfaces.includes(surface);
|
|
237
199
|
}
|
|
238
200
|
__name(surfaceAllows, "surfaceAllows");
|
|
239
201
|
function resolveLockReason(planLocked, siteLocked, missingServices) {
|
|
@@ -244,7 +206,7 @@ function resolveLockReason(planLocked, siteLocked, missingServices) {
|
|
|
244
206
|
}
|
|
245
207
|
__name(resolveLockReason, "resolveLockReason");
|
|
246
208
|
function unmetServices(feature, availableServices) {
|
|
247
|
-
return
|
|
209
|
+
return feature.requiredServices.filter((service) => !availableServices.includes(service));
|
|
248
210
|
}
|
|
249
211
|
__name(unmetServices, "unmetServices");
|
|
250
212
|
function isSiteLockedOnPlatform(entry, platform, code) {
|
|
@@ -255,7 +217,7 @@ __name(isSiteLockedOnPlatform, "isSiteLockedOnPlatform");
|
|
|
255
217
|
function buildPermissions(feature, businessCode, planMembership, siteLocks, plans, bucket, missingServices = []) {
|
|
256
218
|
const planUnlocked = new Set(planMembership?.[bucket] ?? []);
|
|
257
219
|
const lockEntry = siteLocks?.[feature.code];
|
|
258
|
-
const perms =
|
|
220
|
+
const perms = feature.permissions.filter((p) => p.isGlobal || p.businesses.includes(businessCode)).filter((p) => p.platforms.includes(bucket));
|
|
259
221
|
const deps = buildDependsMap(perms);
|
|
260
222
|
const codes = perms.map((p) => p.code);
|
|
261
223
|
const directlyPlanLocked = /* @__PURE__ */ new Set();
|
|
@@ -293,7 +255,7 @@ __name(buildPermissions, "buildPermissions");
|
|
|
293
255
|
function plansUnlockingClosure(plans, featureCode, closure, bucket) {
|
|
294
256
|
const result = [];
|
|
295
257
|
for (const [code, plan] of Object.entries(plans)) {
|
|
296
|
-
const unlocked = plan.unlockedPermissions
|
|
258
|
+
const unlocked = plan.unlockedPermissions[featureCode]?.[bucket];
|
|
297
259
|
if (unlocked && closure.every((c) => unlocked.includes(c))) result.push(code);
|
|
298
260
|
}
|
|
299
261
|
return result;
|
|
@@ -302,16 +264,16 @@ __name(plansUnlockingClosure, "plansUnlockingClosure");
|
|
|
302
264
|
function plansIncludingFeature(plans, featureCode, bucket) {
|
|
303
265
|
const result = [];
|
|
304
266
|
for (const [code, plan] of Object.entries(plans)) {
|
|
305
|
-
if (plan.unlockedPermissions
|
|
267
|
+
if (plan.unlockedPermissions[featureCode]?.[bucket] !== void 0) result.push(code);
|
|
306
268
|
}
|
|
307
269
|
return result;
|
|
308
270
|
}
|
|
309
271
|
__name(plansIncludingFeature, "plansIncludingFeature");
|
|
310
272
|
function buildSiteRoles(snapshot, businessCode) {
|
|
311
273
|
if (!businessCode) return [];
|
|
312
|
-
const business = snapshot.businesses
|
|
274
|
+
const business = snapshot.businesses[businessCode];
|
|
313
275
|
if (!business) return [];
|
|
314
|
-
return Object.values(business.roleTemplates
|
|
276
|
+
return Object.values(business.roleTemplates);
|
|
315
277
|
}
|
|
316
278
|
__name(buildSiteRoles, "buildSiteRoles");
|
|
317
279
|
|
|
@@ -331,11 +293,11 @@ function composeRoleGrants(params) {
|
|
|
331
293
|
const result = {};
|
|
332
294
|
const featureCodes = /* @__PURE__ */ new Set([
|
|
333
295
|
...Object.keys(baseFeatures ?? {}),
|
|
334
|
-
...Object.keys(additions
|
|
296
|
+
...Object.keys(additions)
|
|
335
297
|
]);
|
|
336
298
|
for (const code of featureCodes) {
|
|
337
299
|
const base = baseFeatures?.[code] ?? {};
|
|
338
|
-
const add = additions
|
|
300
|
+
const add = additions[code] ?? {};
|
|
339
301
|
const revokes = revoked?.[code];
|
|
340
302
|
const composed = {};
|
|
341
303
|
for (const bucket of PLATFORMS) {
|
|
@@ -368,32 +330,26 @@ var EMPTY_ROUTE = {
|
|
|
368
330
|
function resolveUserFeatures(params) {
|
|
369
331
|
const { snapshot, businessCode, planCode, siteLocks, platform, siteType, scope, availableServices } = params;
|
|
370
332
|
const bucket = BUCKET_BY_CLIENT[platform];
|
|
371
|
-
const roleFeatures =
|
|
372
|
-
const featureByCode = /* @__PURE__ */ __name((code) => scope ? snapshot.features
|
|
333
|
+
const roleFeatures = params.roleFeatures;
|
|
334
|
+
const featureByCode = /* @__PURE__ */ __name((code) => scope ? snapshot.features[snapshotFeatureKey(code, scope)] : findFeatureByCode(snapshot, code), "featureByCode");
|
|
373
335
|
const catalog = buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, siteType, scope, availableServices);
|
|
374
336
|
const catalogMap = new Map(catalog.map((f) => [
|
|
375
337
|
f.code,
|
|
376
338
|
f
|
|
377
339
|
]));
|
|
378
|
-
const businessPlans =
|
|
379
|
-
code,
|
|
380
|
-
{
|
|
381
|
-
...plan,
|
|
382
|
-
unlockedPermissions: normalizeApiBuckets(plan.unlockedPermissions) ?? {}
|
|
383
|
-
}
|
|
384
|
-
]));
|
|
340
|
+
const businessPlans = snapshot.businesses[businessCode]?.plans ?? {};
|
|
385
341
|
const currentUnlockedCodes = /* @__PURE__ */ new Set();
|
|
386
342
|
if (planCode && businessPlans[planCode]) {
|
|
387
|
-
for (const [featureCode, platforms] of Object.entries(businessPlans[planCode].unlockedPermissions
|
|
388
|
-
if (platforms
|
|
343
|
+
for (const [featureCode, platforms] of Object.entries(businessPlans[planCode].unlockedPermissions)) {
|
|
344
|
+
if (platforms[bucket] !== void 0) currentUnlockedCodes.add(featureCode);
|
|
389
345
|
}
|
|
390
346
|
}
|
|
391
347
|
const planAdds = /* @__PURE__ */ new Map();
|
|
392
348
|
for (const [planKey, plan] of Object.entries(businessPlans)) {
|
|
393
349
|
if (planKey === planCode) continue;
|
|
394
350
|
const adds = [];
|
|
395
|
-
for (const [featureCode, platforms] of Object.entries(plan.unlockedPermissions
|
|
396
|
-
if (platforms
|
|
351
|
+
for (const [featureCode, platforms] of Object.entries(plan.unlockedPermissions)) {
|
|
352
|
+
if (platforms[bucket] === void 0 || currentUnlockedCodes.has(featureCode)) continue;
|
|
397
353
|
const name = featureByCode(featureCode)?.name;
|
|
398
354
|
if (name) adds.push({
|
|
399
355
|
code: featureCode,
|
|
@@ -403,8 +359,8 @@ function resolveUserFeatures(params) {
|
|
|
403
359
|
planAdds.set(planKey, adds);
|
|
404
360
|
}
|
|
405
361
|
const grantedFeatures = /* @__PURE__ */ new Map();
|
|
406
|
-
for (const [code, grant] of Object.entries(roleFeatures
|
|
407
|
-
const granted = grant
|
|
362
|
+
for (const [code, grant] of Object.entries(roleFeatures)) {
|
|
363
|
+
const granted = grant[bucket];
|
|
408
364
|
if (granted === void 0) continue;
|
|
409
365
|
if (!grantedFeatures.has(code)) grantedFeatures.set(code, /* @__PURE__ */ new Set());
|
|
410
366
|
for (const perm of granted) grantedFeatures.get(code)?.add(perm);
|
|
@@ -416,20 +372,20 @@ function resolveUserFeatures(params) {
|
|
|
416
372
|
const route = isApiBucket(bucket) ? EMPTY_ROUTE : pickRouteForPlatform(catalogEntry, platform);
|
|
417
373
|
if (!route) continue;
|
|
418
374
|
const featureDeps = buildDependsMap(featureByCode(code)?.permissions ?? []);
|
|
419
|
-
const permByCode = new Map(
|
|
375
|
+
const permByCode = new Map(catalogEntry.permissions.map((p) => [
|
|
420
376
|
p.code,
|
|
421
377
|
p
|
|
422
378
|
]));
|
|
423
379
|
const grantedPerms = [
|
|
424
380
|
...filterGrantedByDeps(permsSet, featureDeps)
|
|
425
|
-
];
|
|
381
|
+
].filter((c) => permByCode.has(c));
|
|
426
382
|
const lockedPermissions = grantedPerms.map((c) => permByCode.get(c)).filter((p) => !!p?.locked).map((p) => ({
|
|
427
383
|
code: p.code,
|
|
428
384
|
reason: p.lockReason ?? null,
|
|
429
|
-
unlockPlans: p.unlockPlans
|
|
430
|
-
missingServices: p.missingServices
|
|
385
|
+
unlockPlans: p.unlockPlans,
|
|
386
|
+
missingServices: p.missingServices
|
|
431
387
|
}));
|
|
432
|
-
const upsell = catalogEntry.locked && catalogEntry.lockReason === "PLAN" ?
|
|
388
|
+
const upsell = catalogEntry.locked && catalogEntry.lockReason === "PLAN" ? catalogEntry.unlockPlans.map((plan) => ({
|
|
433
389
|
plan,
|
|
434
390
|
features: (planAdds.get(plan) ?? []).filter((f) => f.code !== code).map((f) => f.name)
|
|
435
391
|
})).filter((group) => group.features.length > 0) : [];
|
|
@@ -442,8 +398,8 @@ function resolveUserFeatures(params) {
|
|
|
442
398
|
permissions: grantedPerms,
|
|
443
399
|
locked: catalogEntry.locked ?? false,
|
|
444
400
|
lockReason: catalogEntry.lockReason ?? null,
|
|
445
|
-
unlockPlans: catalogEntry.unlockPlans
|
|
446
|
-
missingServices: catalogEntry.missingServices
|
|
401
|
+
unlockPlans: catalogEntry.unlockPlans,
|
|
402
|
+
missingServices: catalogEntry.missingServices,
|
|
447
403
|
lockedPermissions,
|
|
448
404
|
upsell,
|
|
449
405
|
route,
|
|
@@ -486,21 +442,14 @@ function buildPlanMatrix(snapshot, businessCode, planCode, siteLocks) {
|
|
|
486
442
|
}
|
|
487
443
|
__name(buildPlanMatrix, "buildPlanMatrix");
|
|
488
444
|
function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, siteType) {
|
|
489
|
-
const business = businessCode ? snapshot.businesses
|
|
490
|
-
const plans =
|
|
491
|
-
code,
|
|
492
|
-
{
|
|
493
|
-
...p,
|
|
494
|
-
unlockedPermissions: normalizeApiBuckets(p.unlockedPermissions) ?? {}
|
|
495
|
-
}
|
|
496
|
-
]));
|
|
445
|
+
const business = businessCode ? snapshot.businesses[businessCode] : void 0;
|
|
446
|
+
const plans = business?.plans ?? {};
|
|
497
447
|
const plan = planCode ? plans[planCode] : void 0;
|
|
498
448
|
const planMeta = {
|
|
499
449
|
code: planCode ?? "",
|
|
500
450
|
name: plan?.name ?? planCode ?? ""
|
|
501
451
|
};
|
|
502
|
-
const
|
|
503
|
-
const locks = normalizedLocks ?? {};
|
|
452
|
+
const locks = siteLocks ?? {};
|
|
504
453
|
if (!business || !plan) return {
|
|
505
454
|
plan: planMeta,
|
|
506
455
|
apps: [],
|
|
@@ -508,31 +457,51 @@ function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, sit
|
|
|
508
457
|
};
|
|
509
458
|
const apps = [];
|
|
510
459
|
for (const app of business.apps) {
|
|
511
|
-
|
|
512
|
-
|
|
460
|
+
const counts = {
|
|
461
|
+
web: {
|
|
462
|
+
unlocked: 0,
|
|
463
|
+
total: 0
|
|
464
|
+
},
|
|
465
|
+
mobile: {
|
|
466
|
+
unlocked: 0,
|
|
467
|
+
total: 0
|
|
468
|
+
},
|
|
469
|
+
graphql: {
|
|
470
|
+
unlocked: 0,
|
|
471
|
+
total: 0
|
|
472
|
+
},
|
|
473
|
+
http: {
|
|
474
|
+
unlocked: 0,
|
|
475
|
+
total: 0
|
|
476
|
+
}
|
|
477
|
+
};
|
|
513
478
|
const features = [];
|
|
514
479
|
for (const ref of app.features) {
|
|
515
480
|
if (!allScopes && ref.scope !== "SITE") continue;
|
|
516
481
|
const code = ref.code;
|
|
517
|
-
const feature = snapshot.features
|
|
482
|
+
const feature = snapshot.features[snapshotFeatureKey(code, ref.scope)];
|
|
518
483
|
if (!feature) continue;
|
|
519
484
|
if (siteType !== void 0 && !featureAppliesAtNode(feature.applicableSiteTypes, siteType)) continue;
|
|
520
485
|
const platforms = [
|
|
521
486
|
...UI_PLATFORMS.filter((p) => !!feature.microfrontends?.[p]),
|
|
522
|
-
...API_BUCKETS.filter((b) => feature.apiSurfaces
|
|
487
|
+
...API_BUCKETS.filter((b) => feature.apiSurfaces.includes(SURFACE_BY_BUCKET[b]))
|
|
523
488
|
];
|
|
524
|
-
const
|
|
489
|
+
const groupByCode = new Map(feature.permissionGroups.map((g) => [
|
|
490
|
+
g.code,
|
|
491
|
+
g
|
|
492
|
+
]));
|
|
493
|
+
const membership = plan.unlockedPermissions[code];
|
|
525
494
|
const featureInPlan = isPlanMember(membership);
|
|
526
|
-
const siteEntry =
|
|
527
|
-
const permissions =
|
|
495
|
+
const siteEntry = siteLocks?.[code];
|
|
496
|
+
const permissions = feature.permissions.filter((p) => p.isGlobal || p.businesses.includes(businessCode ?? "")).map((p) => {
|
|
528
497
|
const cell = /* @__PURE__ */ __name((plat) => {
|
|
529
|
-
if (!platforms.includes(plat)) return null;
|
|
498
|
+
if (!platforms.includes(plat) || !p.platforms.includes(plat)) return null;
|
|
530
499
|
const planCodes = membership?.[plat];
|
|
531
500
|
const inPlan = featureInPlan && planCodes !== void 0 && planCodes.includes(p.code);
|
|
532
501
|
const selected = inPlan && !isSiteLockedOnPlatform(siteEntry, plat, p.code);
|
|
533
502
|
const availableIn = inPlan ? [] : plansUnlockingPerm(plans, code, p.code, plat, planCode);
|
|
534
|
-
|
|
535
|
-
if (inPlan)
|
|
503
|
+
counts[plat].total += 1;
|
|
504
|
+
if (inPlan) counts[plat].unlocked += 1;
|
|
536
505
|
return {
|
|
537
506
|
inPlan,
|
|
538
507
|
selected,
|
|
@@ -542,7 +511,8 @@ function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, sit
|
|
|
542
511
|
return {
|
|
543
512
|
code: p.code,
|
|
544
513
|
label: p.label,
|
|
545
|
-
dependsOn: p.dependsOn
|
|
514
|
+
dependsOn: p.dependsOn,
|
|
515
|
+
group: p.group ? groupByCode.get(p.group) : void 0,
|
|
546
516
|
web: cell("web"),
|
|
547
517
|
mobile: cell("mobile"),
|
|
548
518
|
graphql: cell("graphql"),
|
|
@@ -567,8 +537,7 @@ function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, sit
|
|
|
567
537
|
code: app.code,
|
|
568
538
|
name: app.name,
|
|
569
539
|
icon: app.icon ?? null,
|
|
570
|
-
|
|
571
|
-
totalCount,
|
|
540
|
+
counts,
|
|
572
541
|
features
|
|
573
542
|
});
|
|
574
543
|
}
|
|
@@ -584,7 +553,7 @@ function plansUnlockingPerm(plans, featureCode, permCode, platform, excludeCode)
|
|
|
584
553
|
const names = [];
|
|
585
554
|
for (const [code, p] of Object.entries(plans)) {
|
|
586
555
|
if (code === excludeCode) continue;
|
|
587
|
-
if ((p.unlockedPermissions
|
|
556
|
+
if ((p.unlockedPermissions[featureCode]?.[platform] ?? []).includes(permCode)) names.push(p.name);
|
|
588
557
|
}
|
|
589
558
|
return names;
|
|
590
559
|
}
|
|
@@ -593,7 +562,7 @@ function plansIncludingFeature2(plans, featureCode, excludeCode) {
|
|
|
593
562
|
const names = [];
|
|
594
563
|
for (const [code, p] of Object.entries(plans)) {
|
|
595
564
|
if (code === excludeCode) continue;
|
|
596
|
-
if (isPlanMember(p.unlockedPermissions
|
|
565
|
+
if (isPlanMember(p.unlockedPermissions[featureCode])) names.push(p.name);
|
|
597
566
|
}
|
|
598
567
|
return names;
|
|
599
568
|
}
|
|
@@ -621,7 +590,6 @@ export {
|
|
|
621
590
|
isApiBucket,
|
|
622
591
|
isPlanMember,
|
|
623
592
|
isSiteLockedOnPlatform,
|
|
624
|
-
normalizeApiBuckets,
|
|
625
593
|
pickRouteForPlatform,
|
|
626
594
|
prereqClosure,
|
|
627
595
|
resolveUserFeatures,
|