@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
|
@@ -43,7 +43,6 @@ __export(catalog_resolver_exports, {
|
|
|
43
43
|
isApiBucket: () => isApiBucket,
|
|
44
44
|
isPlanMember: () => isPlanMember,
|
|
45
45
|
isSiteLockedOnPlatform: () => isSiteLockedOnPlatform,
|
|
46
|
-
normalizeApiBuckets: () => normalizeApiBuckets,
|
|
47
46
|
pickRouteForPlatform: () => pickRouteForPlatform,
|
|
48
47
|
prereqClosure: () => prereqClosure,
|
|
49
48
|
resolveUserFeatures: () => resolveUserFeatures,
|
|
@@ -165,78 +164,40 @@ function snapshotFeatureKey(code, scope) {
|
|
|
165
164
|
return `${scope}.${code}`;
|
|
166
165
|
}
|
|
167
166
|
__name(snapshotFeatureKey, "snapshotFeatureKey");
|
|
168
|
-
var SNAPSHOT_SCHEMA_VERSION =
|
|
167
|
+
var SNAPSHOT_SCHEMA_VERSION = 5;
|
|
169
168
|
|
|
170
169
|
// src/catalog-resolver/catalog.builder.ts
|
|
171
|
-
function normalizeApiBuckets(doc) {
|
|
172
|
-
if (!doc) return doc;
|
|
173
|
-
let changed = false;
|
|
174
|
-
const next = {};
|
|
175
|
-
for (const [code, entry] of Object.entries(doc)) {
|
|
176
|
-
const legacy = entry.app;
|
|
177
|
-
if (legacy === void 0 || entry.graphql !== void 0 && entry.http !== void 0) {
|
|
178
|
-
next[code] = entry;
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
changed = true;
|
|
182
|
-
next[code] = {
|
|
183
|
-
...entry,
|
|
184
|
-
...entry.graphql === void 0 ? {
|
|
185
|
-
graphql: legacy
|
|
186
|
-
} : {},
|
|
187
|
-
...entry.http === void 0 ? {
|
|
188
|
-
http: legacy
|
|
189
|
-
} : {}
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
return changed ? next : doc;
|
|
193
|
-
}
|
|
194
|
-
__name(normalizeApiBuckets, "normalizeApiBuckets");
|
|
195
|
-
function normalizePlans(plans) {
|
|
196
|
-
let changed = false;
|
|
197
|
-
const next = {};
|
|
198
|
-
for (const [code, plan] of Object.entries(plans)) {
|
|
199
|
-
const unlockedPermissions = normalizeApiBuckets(plan.unlockedPermissions) ?? {};
|
|
200
|
-
if (unlockedPermissions !== plan.unlockedPermissions) changed = true;
|
|
201
|
-
next[code] = unlockedPermissions === plan.unlockedPermissions ? plan : {
|
|
202
|
-
...plan,
|
|
203
|
-
unlockedPermissions
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
return changed ? next : plans;
|
|
207
|
-
}
|
|
208
|
-
__name(normalizePlans, "normalizePlans");
|
|
209
170
|
function featureAppliesAtNode(applicableSiteTypes, siteType) {
|
|
210
171
|
return applicableSiteTypes.includes(siteType);
|
|
211
172
|
}
|
|
212
173
|
__name(featureAppliesAtNode, "featureAppliesAtNode");
|
|
213
174
|
function findFeatureByCode(snapshot, code) {
|
|
214
|
-
for (const feature of Object.values(snapshot.features
|
|
215
|
-
if (feature
|
|
175
|
+
for (const feature of Object.values(snapshot.features)) {
|
|
176
|
+
if (feature.code === code) return feature;
|
|
216
177
|
}
|
|
217
178
|
return void 0;
|
|
218
179
|
}
|
|
219
180
|
__name(findFeatureByCode, "findFeatureByCode");
|
|
220
181
|
function buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, siteType, scope, availableServices = []) {
|
|
221
182
|
if (!businessCode) return [];
|
|
222
|
-
const business = snapshot.businesses
|
|
183
|
+
const business = snapshot.businesses[businessCode];
|
|
223
184
|
if (!business) return [];
|
|
224
|
-
const plans =
|
|
185
|
+
const plans = business.plans;
|
|
225
186
|
const plan = planCode ? plans[planCode] : void 0;
|
|
226
|
-
const locks =
|
|
187
|
+
const locks = siteLocks;
|
|
227
188
|
const catalog = [];
|
|
228
189
|
const sortedApps = [
|
|
229
190
|
...business.apps
|
|
230
191
|
].sort((a, b) => a.name.localeCompare(b.name));
|
|
231
192
|
for (const app of sortedApps) {
|
|
232
|
-
const businessAppFeatures = app.features.filter((ref) => scope === void 0 || ref.scope === scope).map((ref) => snapshot.features
|
|
193
|
+
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.
|
|
233
194
|
// An API bucket renders nothing — there a feature is admitted by the surfaces it declares
|
|
234
195
|
// instead, so a GRAPHQL credential never resolves an HTTP-only feature. A surface-excluded
|
|
235
196
|
// feature vanishes from the catalog entirely, which is what makes resolution fail closed.
|
|
236
197
|
(isApiBucket(bucket) ? surfaceAllows(f.apiSurfaces, SURFACE_BY_BUCKET[bucket]) : !!(f.microfrontends?.web || f.microfrontends?.mobile)) && (siteType === void 0 || featureAppliesAtNode(f.applicableSiteTypes, siteType)));
|
|
237
198
|
if (businessAppFeatures.length === 0) continue;
|
|
238
199
|
for (const feature of businessAppFeatures) {
|
|
239
|
-
const membership = plan?.unlockedPermissions
|
|
200
|
+
const membership = plan?.unlockedPermissions[feature.code];
|
|
240
201
|
const web = feature.microfrontends?.web;
|
|
241
202
|
const mobile = feature.microfrontends?.mobile;
|
|
242
203
|
const memberOnBucket = membership?.[bucket] !== void 0;
|
|
@@ -280,11 +241,11 @@ function buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, s
|
|
|
280
241
|
__name(buildSiteCatalog, "buildSiteCatalog");
|
|
281
242
|
function isPlanMember(entry) {
|
|
282
243
|
if (!entry) return false;
|
|
283
|
-
return PLATFORMS.some((platform) => entry[platform] !== void 0)
|
|
244
|
+
return PLATFORMS.some((platform) => entry[platform] !== void 0);
|
|
284
245
|
}
|
|
285
246
|
__name(isPlanMember, "isPlanMember");
|
|
286
247
|
function surfaceAllows(surfaces, surface) {
|
|
287
|
-
return surface === void 0 || surfaces
|
|
248
|
+
return surface === void 0 || surfaces.includes(surface);
|
|
288
249
|
}
|
|
289
250
|
__name(surfaceAllows, "surfaceAllows");
|
|
290
251
|
function resolveLockReason(planLocked, siteLocked, missingServices) {
|
|
@@ -295,7 +256,7 @@ function resolveLockReason(planLocked, siteLocked, missingServices) {
|
|
|
295
256
|
}
|
|
296
257
|
__name(resolveLockReason, "resolveLockReason");
|
|
297
258
|
function unmetServices(feature, availableServices) {
|
|
298
|
-
return
|
|
259
|
+
return feature.requiredServices.filter((service) => !availableServices.includes(service));
|
|
299
260
|
}
|
|
300
261
|
__name(unmetServices, "unmetServices");
|
|
301
262
|
function isSiteLockedOnPlatform(entry, platform, code) {
|
|
@@ -306,7 +267,7 @@ __name(isSiteLockedOnPlatform, "isSiteLockedOnPlatform");
|
|
|
306
267
|
function buildPermissions(feature, businessCode, planMembership, siteLocks, plans, bucket, missingServices = []) {
|
|
307
268
|
const planUnlocked = new Set(planMembership?.[bucket] ?? []);
|
|
308
269
|
const lockEntry = siteLocks?.[feature.code];
|
|
309
|
-
const perms =
|
|
270
|
+
const perms = feature.permissions.filter((p) => p.isGlobal || p.businesses.includes(businessCode)).filter((p) => p.platforms.includes(bucket));
|
|
310
271
|
const deps = buildDependsMap(perms);
|
|
311
272
|
const codes = perms.map((p) => p.code);
|
|
312
273
|
const directlyPlanLocked = /* @__PURE__ */ new Set();
|
|
@@ -344,7 +305,7 @@ __name(buildPermissions, "buildPermissions");
|
|
|
344
305
|
function plansUnlockingClosure(plans, featureCode, closure, bucket) {
|
|
345
306
|
const result = [];
|
|
346
307
|
for (const [code, plan] of Object.entries(plans)) {
|
|
347
|
-
const unlocked = plan.unlockedPermissions
|
|
308
|
+
const unlocked = plan.unlockedPermissions[featureCode]?.[bucket];
|
|
348
309
|
if (unlocked && closure.every((c) => unlocked.includes(c))) result.push(code);
|
|
349
310
|
}
|
|
350
311
|
return result;
|
|
@@ -353,16 +314,16 @@ __name(plansUnlockingClosure, "plansUnlockingClosure");
|
|
|
353
314
|
function plansIncludingFeature(plans, featureCode, bucket) {
|
|
354
315
|
const result = [];
|
|
355
316
|
for (const [code, plan] of Object.entries(plans)) {
|
|
356
|
-
if (plan.unlockedPermissions
|
|
317
|
+
if (plan.unlockedPermissions[featureCode]?.[bucket] !== void 0) result.push(code);
|
|
357
318
|
}
|
|
358
319
|
return result;
|
|
359
320
|
}
|
|
360
321
|
__name(plansIncludingFeature, "plansIncludingFeature");
|
|
361
322
|
function buildSiteRoles(snapshot, businessCode) {
|
|
362
323
|
if (!businessCode) return [];
|
|
363
|
-
const business = snapshot.businesses
|
|
324
|
+
const business = snapshot.businesses[businessCode];
|
|
364
325
|
if (!business) return [];
|
|
365
|
-
return Object.values(business.roleTemplates
|
|
326
|
+
return Object.values(business.roleTemplates);
|
|
366
327
|
}
|
|
367
328
|
__name(buildSiteRoles, "buildSiteRoles");
|
|
368
329
|
|
|
@@ -382,11 +343,11 @@ function composeRoleGrants(params) {
|
|
|
382
343
|
const result = {};
|
|
383
344
|
const featureCodes = /* @__PURE__ */ new Set([
|
|
384
345
|
...Object.keys(baseFeatures ?? {}),
|
|
385
|
-
...Object.keys(additions
|
|
346
|
+
...Object.keys(additions)
|
|
386
347
|
]);
|
|
387
348
|
for (const code of featureCodes) {
|
|
388
349
|
const base = baseFeatures?.[code] ?? {};
|
|
389
|
-
const add = additions
|
|
350
|
+
const add = additions[code] ?? {};
|
|
390
351
|
const revokes = revoked?.[code];
|
|
391
352
|
const composed = {};
|
|
392
353
|
for (const bucket of PLATFORMS) {
|
|
@@ -419,32 +380,26 @@ var EMPTY_ROUTE = {
|
|
|
419
380
|
function resolveUserFeatures(params) {
|
|
420
381
|
const { snapshot, businessCode, planCode, siteLocks, platform, siteType, scope, availableServices } = params;
|
|
421
382
|
const bucket = BUCKET_BY_CLIENT[platform];
|
|
422
|
-
const roleFeatures =
|
|
423
|
-
const featureByCode = /* @__PURE__ */ __name((code) => scope ? snapshot.features
|
|
383
|
+
const roleFeatures = params.roleFeatures;
|
|
384
|
+
const featureByCode = /* @__PURE__ */ __name((code) => scope ? snapshot.features[snapshotFeatureKey(code, scope)] : findFeatureByCode(snapshot, code), "featureByCode");
|
|
424
385
|
const catalog = buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, siteType, scope, availableServices);
|
|
425
386
|
const catalogMap = new Map(catalog.map((f) => [
|
|
426
387
|
f.code,
|
|
427
388
|
f
|
|
428
389
|
]));
|
|
429
|
-
const businessPlans =
|
|
430
|
-
code,
|
|
431
|
-
{
|
|
432
|
-
...plan,
|
|
433
|
-
unlockedPermissions: normalizeApiBuckets(plan.unlockedPermissions) ?? {}
|
|
434
|
-
}
|
|
435
|
-
]));
|
|
390
|
+
const businessPlans = snapshot.businesses[businessCode]?.plans ?? {};
|
|
436
391
|
const currentUnlockedCodes = /* @__PURE__ */ new Set();
|
|
437
392
|
if (planCode && businessPlans[planCode]) {
|
|
438
|
-
for (const [featureCode, platforms] of Object.entries(businessPlans[planCode].unlockedPermissions
|
|
439
|
-
if (platforms
|
|
393
|
+
for (const [featureCode, platforms] of Object.entries(businessPlans[planCode].unlockedPermissions)) {
|
|
394
|
+
if (platforms[bucket] !== void 0) currentUnlockedCodes.add(featureCode);
|
|
440
395
|
}
|
|
441
396
|
}
|
|
442
397
|
const planAdds = /* @__PURE__ */ new Map();
|
|
443
398
|
for (const [planKey, plan] of Object.entries(businessPlans)) {
|
|
444
399
|
if (planKey === planCode) continue;
|
|
445
400
|
const adds = [];
|
|
446
|
-
for (const [featureCode, platforms] of Object.entries(plan.unlockedPermissions
|
|
447
|
-
if (platforms
|
|
401
|
+
for (const [featureCode, platforms] of Object.entries(plan.unlockedPermissions)) {
|
|
402
|
+
if (platforms[bucket] === void 0 || currentUnlockedCodes.has(featureCode)) continue;
|
|
448
403
|
const name = featureByCode(featureCode)?.name;
|
|
449
404
|
if (name) adds.push({
|
|
450
405
|
code: featureCode,
|
|
@@ -454,8 +409,8 @@ function resolveUserFeatures(params) {
|
|
|
454
409
|
planAdds.set(planKey, adds);
|
|
455
410
|
}
|
|
456
411
|
const grantedFeatures = /* @__PURE__ */ new Map();
|
|
457
|
-
for (const [code, grant] of Object.entries(roleFeatures
|
|
458
|
-
const granted = grant
|
|
412
|
+
for (const [code, grant] of Object.entries(roleFeatures)) {
|
|
413
|
+
const granted = grant[bucket];
|
|
459
414
|
if (granted === void 0) continue;
|
|
460
415
|
if (!grantedFeatures.has(code)) grantedFeatures.set(code, /* @__PURE__ */ new Set());
|
|
461
416
|
for (const perm of granted) grantedFeatures.get(code)?.add(perm);
|
|
@@ -467,20 +422,20 @@ function resolveUserFeatures(params) {
|
|
|
467
422
|
const route = isApiBucket(bucket) ? EMPTY_ROUTE : pickRouteForPlatform(catalogEntry, platform);
|
|
468
423
|
if (!route) continue;
|
|
469
424
|
const featureDeps = buildDependsMap(featureByCode(code)?.permissions ?? []);
|
|
470
|
-
const permByCode = new Map(
|
|
425
|
+
const permByCode = new Map(catalogEntry.permissions.map((p) => [
|
|
471
426
|
p.code,
|
|
472
427
|
p
|
|
473
428
|
]));
|
|
474
429
|
const grantedPerms = [
|
|
475
430
|
...filterGrantedByDeps(permsSet, featureDeps)
|
|
476
|
-
];
|
|
431
|
+
].filter((c) => permByCode.has(c));
|
|
477
432
|
const lockedPermissions = grantedPerms.map((c) => permByCode.get(c)).filter((p) => !!p?.locked).map((p) => ({
|
|
478
433
|
code: p.code,
|
|
479
434
|
reason: p.lockReason ?? null,
|
|
480
|
-
unlockPlans: p.unlockPlans
|
|
481
|
-
missingServices: p.missingServices
|
|
435
|
+
unlockPlans: p.unlockPlans,
|
|
436
|
+
missingServices: p.missingServices
|
|
482
437
|
}));
|
|
483
|
-
const upsell = catalogEntry.locked && catalogEntry.lockReason === "PLAN" ?
|
|
438
|
+
const upsell = catalogEntry.locked && catalogEntry.lockReason === "PLAN" ? catalogEntry.unlockPlans.map((plan) => ({
|
|
484
439
|
plan,
|
|
485
440
|
features: (planAdds.get(plan) ?? []).filter((f) => f.code !== code).map((f) => f.name)
|
|
486
441
|
})).filter((group) => group.features.length > 0) : [];
|
|
@@ -493,8 +448,8 @@ function resolveUserFeatures(params) {
|
|
|
493
448
|
permissions: grantedPerms,
|
|
494
449
|
locked: catalogEntry.locked ?? false,
|
|
495
450
|
lockReason: catalogEntry.lockReason ?? null,
|
|
496
|
-
unlockPlans: catalogEntry.unlockPlans
|
|
497
|
-
missingServices: catalogEntry.missingServices
|
|
451
|
+
unlockPlans: catalogEntry.unlockPlans,
|
|
452
|
+
missingServices: catalogEntry.missingServices,
|
|
498
453
|
lockedPermissions,
|
|
499
454
|
upsell,
|
|
500
455
|
route,
|
|
@@ -537,21 +492,14 @@ function buildPlanMatrix(snapshot, businessCode, planCode, siteLocks) {
|
|
|
537
492
|
}
|
|
538
493
|
__name(buildPlanMatrix, "buildPlanMatrix");
|
|
539
494
|
function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, siteType) {
|
|
540
|
-
const business = businessCode ? snapshot.businesses
|
|
541
|
-
const plans =
|
|
542
|
-
code,
|
|
543
|
-
{
|
|
544
|
-
...p,
|
|
545
|
-
unlockedPermissions: normalizeApiBuckets(p.unlockedPermissions) ?? {}
|
|
546
|
-
}
|
|
547
|
-
]));
|
|
495
|
+
const business = businessCode ? snapshot.businesses[businessCode] : void 0;
|
|
496
|
+
const plans = business?.plans ?? {};
|
|
548
497
|
const plan = planCode ? plans[planCode] : void 0;
|
|
549
498
|
const planMeta = {
|
|
550
499
|
code: planCode ?? "",
|
|
551
500
|
name: plan?.name ?? planCode ?? ""
|
|
552
501
|
};
|
|
553
|
-
const
|
|
554
|
-
const locks = normalizedLocks ?? {};
|
|
502
|
+
const locks = siteLocks ?? {};
|
|
555
503
|
if (!business || !plan) return {
|
|
556
504
|
plan: planMeta,
|
|
557
505
|
apps: [],
|
|
@@ -559,31 +507,51 @@ function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, sit
|
|
|
559
507
|
};
|
|
560
508
|
const apps = [];
|
|
561
509
|
for (const app of business.apps) {
|
|
562
|
-
|
|
563
|
-
|
|
510
|
+
const counts = {
|
|
511
|
+
web: {
|
|
512
|
+
unlocked: 0,
|
|
513
|
+
total: 0
|
|
514
|
+
},
|
|
515
|
+
mobile: {
|
|
516
|
+
unlocked: 0,
|
|
517
|
+
total: 0
|
|
518
|
+
},
|
|
519
|
+
graphql: {
|
|
520
|
+
unlocked: 0,
|
|
521
|
+
total: 0
|
|
522
|
+
},
|
|
523
|
+
http: {
|
|
524
|
+
unlocked: 0,
|
|
525
|
+
total: 0
|
|
526
|
+
}
|
|
527
|
+
};
|
|
564
528
|
const features = [];
|
|
565
529
|
for (const ref of app.features) {
|
|
566
530
|
if (!allScopes && ref.scope !== "SITE") continue;
|
|
567
531
|
const code = ref.code;
|
|
568
|
-
const feature = snapshot.features
|
|
532
|
+
const feature = snapshot.features[snapshotFeatureKey(code, ref.scope)];
|
|
569
533
|
if (!feature) continue;
|
|
570
534
|
if (siteType !== void 0 && !featureAppliesAtNode(feature.applicableSiteTypes, siteType)) continue;
|
|
571
535
|
const platforms = [
|
|
572
536
|
...UI_PLATFORMS.filter((p) => !!feature.microfrontends?.[p]),
|
|
573
|
-
...API_BUCKETS.filter((b) => feature.apiSurfaces
|
|
537
|
+
...API_BUCKETS.filter((b) => feature.apiSurfaces.includes(SURFACE_BY_BUCKET[b]))
|
|
574
538
|
];
|
|
575
|
-
const
|
|
539
|
+
const groupByCode = new Map(feature.permissionGroups.map((g) => [
|
|
540
|
+
g.code,
|
|
541
|
+
g
|
|
542
|
+
]));
|
|
543
|
+
const membership = plan.unlockedPermissions[code];
|
|
576
544
|
const featureInPlan = isPlanMember(membership);
|
|
577
|
-
const siteEntry =
|
|
578
|
-
const permissions =
|
|
545
|
+
const siteEntry = siteLocks?.[code];
|
|
546
|
+
const permissions = feature.permissions.filter((p) => p.isGlobal || p.businesses.includes(businessCode ?? "")).map((p) => {
|
|
579
547
|
const cell = /* @__PURE__ */ __name((plat) => {
|
|
580
|
-
if (!platforms.includes(plat)) return null;
|
|
548
|
+
if (!platforms.includes(plat) || !p.platforms.includes(plat)) return null;
|
|
581
549
|
const planCodes = membership?.[plat];
|
|
582
550
|
const inPlan = featureInPlan && planCodes !== void 0 && planCodes.includes(p.code);
|
|
583
551
|
const selected = inPlan && !isSiteLockedOnPlatform(siteEntry, plat, p.code);
|
|
584
552
|
const availableIn = inPlan ? [] : plansUnlockingPerm(plans, code, p.code, plat, planCode);
|
|
585
|
-
|
|
586
|
-
if (inPlan)
|
|
553
|
+
counts[plat].total += 1;
|
|
554
|
+
if (inPlan) counts[plat].unlocked += 1;
|
|
587
555
|
return {
|
|
588
556
|
inPlan,
|
|
589
557
|
selected,
|
|
@@ -593,7 +561,8 @@ function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, sit
|
|
|
593
561
|
return {
|
|
594
562
|
code: p.code,
|
|
595
563
|
label: p.label,
|
|
596
|
-
dependsOn: p.dependsOn
|
|
564
|
+
dependsOn: p.dependsOn,
|
|
565
|
+
group: p.group ? groupByCode.get(p.group) : void 0,
|
|
597
566
|
web: cell("web"),
|
|
598
567
|
mobile: cell("mobile"),
|
|
599
568
|
graphql: cell("graphql"),
|
|
@@ -618,8 +587,7 @@ function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, sit
|
|
|
618
587
|
code: app.code,
|
|
619
588
|
name: app.name,
|
|
620
589
|
icon: app.icon ?? null,
|
|
621
|
-
|
|
622
|
-
totalCount,
|
|
590
|
+
counts,
|
|
623
591
|
features
|
|
624
592
|
});
|
|
625
593
|
}
|
|
@@ -635,7 +603,7 @@ function plansUnlockingPerm(plans, featureCode, permCode, platform, excludeCode)
|
|
|
635
603
|
const names = [];
|
|
636
604
|
for (const [code, p] of Object.entries(plans)) {
|
|
637
605
|
if (code === excludeCode) continue;
|
|
638
|
-
if ((p.unlockedPermissions
|
|
606
|
+
if ((p.unlockedPermissions[featureCode]?.[platform] ?? []).includes(permCode)) names.push(p.name);
|
|
639
607
|
}
|
|
640
608
|
return names;
|
|
641
609
|
}
|
|
@@ -644,7 +612,7 @@ function plansIncludingFeature2(plans, featureCode, excludeCode) {
|
|
|
644
612
|
const names = [];
|
|
645
613
|
for (const [code, p] of Object.entries(plans)) {
|
|
646
614
|
if (code === excludeCode) continue;
|
|
647
|
-
if (isPlanMember(p.unlockedPermissions
|
|
615
|
+
if (isPlanMember(p.unlockedPermissions[featureCode])) names.push(p.name);
|
|
648
616
|
}
|
|
649
617
|
return names;
|
|
650
618
|
}
|
|
@@ -673,7 +641,6 @@ __name(plansIncludingFeature2, "plansIncludingFeature");
|
|
|
673
641
|
isApiBucket,
|
|
674
642
|
isPlanMember,
|
|
675
643
|
isSiteLockedOnPlatform,
|
|
676
|
-
normalizeApiBuckets,
|
|
677
644
|
pickRouteForPlatform,
|
|
678
645
|
prereqClosure,
|
|
679
646
|
resolveUserFeatures,
|