@vritti/api-sdk 0.3.13 → 0.3.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/dist/catalog-resolver.cjs +128 -22
- package/dist/catalog-resolver.cjs.map +1 -1
- package/dist/catalog-resolver.d.cts +27 -7
- package/dist/catalog-resolver.d.ts +27 -7
- package/dist/catalog-resolver.js +119 -21
- 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-CG-Ynwyf.d.cts → types-B7ArIjwo.d.cts} +25 -10
- package/dist/{types-CG-Ynwyf.d.ts → types-B7ArIjwo.d.ts} +25 -10
- package/package.json +1 -1
|
@@ -1,10 +1,28 @@
|
|
|
1
|
-
import { V as VersionSnapshot, S as SiteFeatureLocks, P as PlatformBucket, a as SiteType, b as ScopeType, c as ServiceCode, F as FeatureCatalogEntry, R as RoleItem, d as SnapshotFeature, e as PlatformCodes, f as
|
|
2
|
-
export { B as BusinessVocabulary, C as CatalogPermission,
|
|
1
|
+
import { V as VersionSnapshot, S as SiteFeatureLocks, P as PlatformBucket, a as SiteType, b as ScopeType, c as ServiceCode, F as FeatureCatalogEntry, R as RoleItem, d as SnapshotFeature, e as PlatformCodes, f as PlatformDenyCodes, A as ApiSurface, g as FeatureUnlocks, L as LockReason } from './types-B7ArIjwo.cjs';
|
|
2
|
+
export { h as API_BUCKETS, i as API_SURFACES, j as ApiBucket, B as BUCKET_BY_SURFACE, k as BusinessVocabulary, C as CatalogPermission, l as FeatureLocks, n as PLATFORMS, o as SERVICE_CODES, p as SITE_TYPES, q as SNAPSHOT_SCHEMA_VERSION, D as SURFACE_BY_BUCKET, r as SnapshotApp, s as SnapshotAppFeatureRef, t as SnapshotBusiness, u as SnapshotMicrofrontendMobile, w as SnapshotMicrofrontendWeb, v as SnapshotMicrofrontends, x as SnapshotPermission, y as SnapshotPlan, z as SnapshotRoleTemplate, U as UI_PLATFORMS, G as UiPlatformBucket, H as VocabularyEntry, m as isApiBucket, E as snapshotFeatureKey } from './types-B7ArIjwo.cjs';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Copies a legacy `app` bucket into whichever of `graphql`/`http` an entry lacks.
|
|
6
|
+
*
|
|
7
|
+
* Documents written before the API surfaces were entitled separately — old snapshots, old
|
|
8
|
+
* credential grants, old deny-lists — carry one `app` bucket that meant "any API surface".
|
|
9
|
+
* Normalising at read time is what lets those documents keep working without a re-key: an
|
|
10
|
+
* `app` grant admits both surfaces, and an `app` lock fails closed on both. Entries already
|
|
11
|
+
* carrying a surface bucket keep it — the legacy value only fills gaps.
|
|
12
|
+
*/
|
|
13
|
+
declare function normalizeApiBuckets<T extends PlatformCodes | PlatformDenyCodes>(doc: Record<string, T> | undefined): Record<string, T> | undefined;
|
|
4
14
|
declare function featureAppliesAtNode(applicableSiteTypes: SiteType[], siteType: SiteType): boolean;
|
|
5
15
|
declare function findFeatureByCode(snapshot: VersionSnapshot, code: string): SnapshotFeature | undefined;
|
|
6
16
|
declare function buildSiteCatalog(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, siteLocks: SiteFeatureLocks | undefined, bucket: PlatformBucket, siteType?: SiteType, scope?: ScopeType, availableServices?: ServiceCode[]): FeatureCatalogEntry[];
|
|
7
17
|
declare function isPlanMember(entry: PlatformCodes | undefined): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Whether a feature's declared API surfaces admit a caller's surface.
|
|
20
|
+
*
|
|
21
|
+
* Lenient on either side being unknown: a pre-flag snapshot declares nothing (`undefined`), and a
|
|
22
|
+
* caller resolving without a surface (cloud's matrix builders, UI buckets) filters nothing. Strictness
|
|
23
|
+
* comes from both sides being present — including a declared `[]`, which admits no surface at all.
|
|
24
|
+
*/
|
|
25
|
+
declare function surfaceAllows(surfaces: ApiSurface[] | undefined, surface: ApiSurface | undefined): boolean;
|
|
8
26
|
declare function isSiteLockedOnPlatform(entry: SiteFeatureLocks[string] | undefined, platform: PlatformBucket, code: string): boolean;
|
|
9
27
|
declare function buildSiteRoles(snapshot: VersionSnapshot, businessCode: string | undefined): RoleItem[];
|
|
10
28
|
|
|
@@ -29,10 +47,10 @@ declare function filterGrantedByDeps(granted: Set<string>, deps: DependsMap): Se
|
|
|
29
47
|
* The caller's surface, as the caller reports it.
|
|
30
48
|
*
|
|
31
49
|
* Finer than `PlatformBucket` on the mobile side — `ios` and `android` load different remote
|
|
32
|
-
* entries but share one grant bucket.
|
|
33
|
-
* variants because it has no UI.
|
|
50
|
+
* entries but share one grant bucket. The API platforms are one-to-one with their buckets: an
|
|
51
|
+
* API client has no variants because it has no UI.
|
|
34
52
|
*/
|
|
35
|
-
type ClientPlatform = 'web' | 'ios' | 'android' | '
|
|
53
|
+
type ClientPlatform = 'web' | 'ios' | 'android' | 'graphql' | 'http';
|
|
36
54
|
interface LockedPermission {
|
|
37
55
|
code: string;
|
|
38
56
|
reason: LockReason | null;
|
|
@@ -107,7 +125,8 @@ interface SiteMatrixPermission {
|
|
|
107
125
|
dependsOn: string[];
|
|
108
126
|
web: SiteMatrixCell | null;
|
|
109
127
|
mobile: SiteMatrixCell | null;
|
|
110
|
-
|
|
128
|
+
graphql: SiteMatrixCell | null;
|
|
129
|
+
http: SiteMatrixCell | null;
|
|
111
130
|
}
|
|
112
131
|
interface SiteMatrixFeature {
|
|
113
132
|
code: string;
|
|
@@ -118,6 +137,7 @@ interface SiteMatrixFeature {
|
|
|
118
137
|
platforms: PlatformBucket[];
|
|
119
138
|
inPlan: boolean;
|
|
120
139
|
availableIn: string[];
|
|
140
|
+
apiSurfaces?: ApiSurface[];
|
|
121
141
|
permissions: SiteMatrixPermission[];
|
|
122
142
|
}
|
|
123
143
|
interface SiteMatrixApp {
|
|
@@ -139,4 +159,4 @@ interface SiteMatrix {
|
|
|
139
159
|
declare function buildSiteMatrix(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, siteLocks: SiteFeatureLocks | undefined, siteType?: SiteType): SiteMatrix;
|
|
140
160
|
declare function buildPlanMatrix(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, siteLocks?: SiteFeatureLocks): SiteMatrix;
|
|
141
161
|
|
|
142
|
-
export { type ClientPlatform, type ComposeRoleGrantsParams, type DependsMap, FeatureCatalogEntry, FeatureUnlocks, LockReason, type LockedPermission, type PermissionFeature, PlatformBucket, PlatformCodes, PlatformDenyCodes, type ResolveUserFeaturesParams, type RevokedGrants, RoleItem, ScopeType, ServiceCode, SiteFeatureLocks, type SiteMatrix, type SiteMatrixApp, type SiteMatrixCell, type SiteMatrixFeature, type SiteMatrixPermission, SiteType, SnapshotFeature, VersionSnapshot, buildDependsMap, buildPlanMatrix, buildSiteCatalog, buildSiteMatrix, buildSiteRoles, cascadeLocked, composeRoleGrants, featureAppliesAtNode, filterGrantedByDeps, findFeatureByCode, isPlanMember, isSiteLockedOnPlatform, pickRouteForPlatform, prereqClosure, resolveUserFeatures };
|
|
162
|
+
export { ApiSurface, type ClientPlatform, type ComposeRoleGrantsParams, type DependsMap, FeatureCatalogEntry, FeatureUnlocks, LockReason, type LockedPermission, type PermissionFeature, PlatformBucket, PlatformCodes, PlatformDenyCodes, type ResolveUserFeaturesParams, type RevokedGrants, RoleItem, ScopeType, ServiceCode, SiteFeatureLocks, type SiteMatrix, type SiteMatrixApp, type SiteMatrixCell, type SiteMatrixFeature, type SiteMatrixPermission, SiteType, SnapshotFeature, VersionSnapshot, buildDependsMap, buildPlanMatrix, buildSiteCatalog, buildSiteMatrix, buildSiteRoles, cascadeLocked, composeRoleGrants, featureAppliesAtNode, filterGrantedByDeps, findFeatureByCode, isPlanMember, isSiteLockedOnPlatform, normalizeApiBuckets, pickRouteForPlatform, prereqClosure, resolveUserFeatures, surfaceAllows };
|
|
@@ -1,10 +1,28 @@
|
|
|
1
|
-
import { V as VersionSnapshot, S as SiteFeatureLocks, P as PlatformBucket, a as SiteType, b as ScopeType, c as ServiceCode, F as FeatureCatalogEntry, R as RoleItem, d as SnapshotFeature, e as PlatformCodes, f as
|
|
2
|
-
export { B as BusinessVocabulary, C as CatalogPermission,
|
|
1
|
+
import { V as VersionSnapshot, S as SiteFeatureLocks, P as PlatformBucket, a as SiteType, b as ScopeType, c as ServiceCode, F as FeatureCatalogEntry, R as RoleItem, d as SnapshotFeature, e as PlatformCodes, f as PlatformDenyCodes, A as ApiSurface, g as FeatureUnlocks, L as LockReason } from './types-B7ArIjwo.js';
|
|
2
|
+
export { h as API_BUCKETS, i as API_SURFACES, j as ApiBucket, B as BUCKET_BY_SURFACE, k as BusinessVocabulary, C as CatalogPermission, l as FeatureLocks, n as PLATFORMS, o as SERVICE_CODES, p as SITE_TYPES, q as SNAPSHOT_SCHEMA_VERSION, D as SURFACE_BY_BUCKET, r as SnapshotApp, s as SnapshotAppFeatureRef, t as SnapshotBusiness, u as SnapshotMicrofrontendMobile, w as SnapshotMicrofrontendWeb, v as SnapshotMicrofrontends, x as SnapshotPermission, y as SnapshotPlan, z as SnapshotRoleTemplate, U as UI_PLATFORMS, G as UiPlatformBucket, H as VocabularyEntry, m as isApiBucket, E as snapshotFeatureKey } from './types-B7ArIjwo.js';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Copies a legacy `app` bucket into whichever of `graphql`/`http` an entry lacks.
|
|
6
|
+
*
|
|
7
|
+
* Documents written before the API surfaces were entitled separately — old snapshots, old
|
|
8
|
+
* credential grants, old deny-lists — carry one `app` bucket that meant "any API surface".
|
|
9
|
+
* Normalising at read time is what lets those documents keep working without a re-key: an
|
|
10
|
+
* `app` grant admits both surfaces, and an `app` lock fails closed on both. Entries already
|
|
11
|
+
* carrying a surface bucket keep it — the legacy value only fills gaps.
|
|
12
|
+
*/
|
|
13
|
+
declare function normalizeApiBuckets<T extends PlatformCodes | PlatformDenyCodes>(doc: Record<string, T> | undefined): Record<string, T> | undefined;
|
|
4
14
|
declare function featureAppliesAtNode(applicableSiteTypes: SiteType[], siteType: SiteType): boolean;
|
|
5
15
|
declare function findFeatureByCode(snapshot: VersionSnapshot, code: string): SnapshotFeature | undefined;
|
|
6
16
|
declare function buildSiteCatalog(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, siteLocks: SiteFeatureLocks | undefined, bucket: PlatformBucket, siteType?: SiteType, scope?: ScopeType, availableServices?: ServiceCode[]): FeatureCatalogEntry[];
|
|
7
17
|
declare function isPlanMember(entry: PlatformCodes | undefined): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Whether a feature's declared API surfaces admit a caller's surface.
|
|
20
|
+
*
|
|
21
|
+
* Lenient on either side being unknown: a pre-flag snapshot declares nothing (`undefined`), and a
|
|
22
|
+
* caller resolving without a surface (cloud's matrix builders, UI buckets) filters nothing. Strictness
|
|
23
|
+
* comes from both sides being present — including a declared `[]`, which admits no surface at all.
|
|
24
|
+
*/
|
|
25
|
+
declare function surfaceAllows(surfaces: ApiSurface[] | undefined, surface: ApiSurface | undefined): boolean;
|
|
8
26
|
declare function isSiteLockedOnPlatform(entry: SiteFeatureLocks[string] | undefined, platform: PlatformBucket, code: string): boolean;
|
|
9
27
|
declare function buildSiteRoles(snapshot: VersionSnapshot, businessCode: string | undefined): RoleItem[];
|
|
10
28
|
|
|
@@ -29,10 +47,10 @@ declare function filterGrantedByDeps(granted: Set<string>, deps: DependsMap): Se
|
|
|
29
47
|
* The caller's surface, as the caller reports it.
|
|
30
48
|
*
|
|
31
49
|
* Finer than `PlatformBucket` on the mobile side — `ios` and `android` load different remote
|
|
32
|
-
* entries but share one grant bucket.
|
|
33
|
-
* variants because it has no UI.
|
|
50
|
+
* entries but share one grant bucket. The API platforms are one-to-one with their buckets: an
|
|
51
|
+
* API client has no variants because it has no UI.
|
|
34
52
|
*/
|
|
35
|
-
type ClientPlatform = 'web' | 'ios' | 'android' | '
|
|
53
|
+
type ClientPlatform = 'web' | 'ios' | 'android' | 'graphql' | 'http';
|
|
36
54
|
interface LockedPermission {
|
|
37
55
|
code: string;
|
|
38
56
|
reason: LockReason | null;
|
|
@@ -107,7 +125,8 @@ interface SiteMatrixPermission {
|
|
|
107
125
|
dependsOn: string[];
|
|
108
126
|
web: SiteMatrixCell | null;
|
|
109
127
|
mobile: SiteMatrixCell | null;
|
|
110
|
-
|
|
128
|
+
graphql: SiteMatrixCell | null;
|
|
129
|
+
http: SiteMatrixCell | null;
|
|
111
130
|
}
|
|
112
131
|
interface SiteMatrixFeature {
|
|
113
132
|
code: string;
|
|
@@ -118,6 +137,7 @@ interface SiteMatrixFeature {
|
|
|
118
137
|
platforms: PlatformBucket[];
|
|
119
138
|
inPlan: boolean;
|
|
120
139
|
availableIn: string[];
|
|
140
|
+
apiSurfaces?: ApiSurface[];
|
|
121
141
|
permissions: SiteMatrixPermission[];
|
|
122
142
|
}
|
|
123
143
|
interface SiteMatrixApp {
|
|
@@ -139,4 +159,4 @@ interface SiteMatrix {
|
|
|
139
159
|
declare function buildSiteMatrix(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, siteLocks: SiteFeatureLocks | undefined, siteType?: SiteType): SiteMatrix;
|
|
140
160
|
declare function buildPlanMatrix(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, siteLocks?: SiteFeatureLocks): SiteMatrix;
|
|
141
161
|
|
|
142
|
-
export { type ClientPlatform, type ComposeRoleGrantsParams, type DependsMap, FeatureCatalogEntry, FeatureUnlocks, LockReason, type LockedPermission, type PermissionFeature, PlatformBucket, PlatformCodes, PlatformDenyCodes, type ResolveUserFeaturesParams, type RevokedGrants, RoleItem, ScopeType, ServiceCode, SiteFeatureLocks, type SiteMatrix, type SiteMatrixApp, type SiteMatrixCell, type SiteMatrixFeature, type SiteMatrixPermission, SiteType, SnapshotFeature, VersionSnapshot, buildDependsMap, buildPlanMatrix, buildSiteCatalog, buildSiteMatrix, buildSiteRoles, cascadeLocked, composeRoleGrants, featureAppliesAtNode, filterGrantedByDeps, findFeatureByCode, isPlanMember, isSiteLockedOnPlatform, pickRouteForPlatform, prereqClosure, resolveUserFeatures };
|
|
162
|
+
export { ApiSurface, type ClientPlatform, type ComposeRoleGrantsParams, type DependsMap, FeatureCatalogEntry, FeatureUnlocks, LockReason, type LockedPermission, type PermissionFeature, PlatformBucket, PlatformCodes, PlatformDenyCodes, type ResolveUserFeaturesParams, type RevokedGrants, RoleItem, ScopeType, ServiceCode, SiteFeatureLocks, type SiteMatrix, type SiteMatrixApp, type SiteMatrixCell, type SiteMatrixFeature, type SiteMatrixPermission, SiteType, SnapshotFeature, VersionSnapshot, buildDependsMap, buildPlanMatrix, buildSiteCatalog, buildSiteMatrix, buildSiteRoles, cascadeLocked, composeRoleGrants, featureAppliesAtNode, filterGrantedByDeps, findFeatureByCode, isPlanMember, isSiteLockedOnPlatform, normalizeApiBuckets, pickRouteForPlatform, prereqClosure, resolveUserFeatures, surfaceAllows };
|
package/dist/catalog-resolver.js
CHANGED
|
@@ -75,12 +75,33 @@ __name(filterGrantedByDeps, "filterGrantedByDeps");
|
|
|
75
75
|
var PLATFORMS = [
|
|
76
76
|
"web",
|
|
77
77
|
"mobile",
|
|
78
|
-
"
|
|
78
|
+
"graphql",
|
|
79
|
+
"http"
|
|
79
80
|
];
|
|
80
81
|
var UI_PLATFORMS = [
|
|
81
82
|
"web",
|
|
82
83
|
"mobile"
|
|
83
84
|
];
|
|
85
|
+
var API_SURFACES = [
|
|
86
|
+
"GRAPHQL",
|
|
87
|
+
"HTTP"
|
|
88
|
+
];
|
|
89
|
+
var API_BUCKETS = [
|
|
90
|
+
"graphql",
|
|
91
|
+
"http"
|
|
92
|
+
];
|
|
93
|
+
var SURFACE_BY_BUCKET = {
|
|
94
|
+
graphql: "GRAPHQL",
|
|
95
|
+
http: "HTTP"
|
|
96
|
+
};
|
|
97
|
+
var BUCKET_BY_SURFACE = {
|
|
98
|
+
GRAPHQL: "graphql",
|
|
99
|
+
HTTP: "http"
|
|
100
|
+
};
|
|
101
|
+
function isApiBucket(bucket) {
|
|
102
|
+
return bucket === "graphql" || bucket === "http";
|
|
103
|
+
}
|
|
104
|
+
__name(isApiBucket, "isApiBucket");
|
|
84
105
|
var SITE_TYPES = [
|
|
85
106
|
"OUTLET",
|
|
86
107
|
"WAREHOUSE",
|
|
@@ -93,9 +114,47 @@ function snapshotFeatureKey(code, scope) {
|
|
|
93
114
|
return `${scope}.${code}`;
|
|
94
115
|
}
|
|
95
116
|
__name(snapshotFeatureKey, "snapshotFeatureKey");
|
|
96
|
-
var SNAPSHOT_SCHEMA_VERSION =
|
|
117
|
+
var SNAPSHOT_SCHEMA_VERSION = 4;
|
|
97
118
|
|
|
98
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");
|
|
99
158
|
function featureAppliesAtNode(applicableSiteTypes, siteType) {
|
|
100
159
|
return applicableSiteTypes.includes(siteType);
|
|
101
160
|
}
|
|
@@ -111,26 +170,28 @@ function buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, s
|
|
|
111
170
|
if (!businessCode) return [];
|
|
112
171
|
const business = snapshot.businesses?.[businessCode];
|
|
113
172
|
if (!business) return [];
|
|
114
|
-
const
|
|
115
|
-
const
|
|
173
|
+
const plans = normalizePlans(business.plans ?? {});
|
|
174
|
+
const plan = planCode ? plans[planCode] : void 0;
|
|
175
|
+
const locks = normalizeApiBuckets(siteLocks);
|
|
116
176
|
const catalog = [];
|
|
117
177
|
const sortedApps = [
|
|
118
178
|
...business.apps
|
|
119
179
|
].sort((a, b) => a.name.localeCompare(b.name));
|
|
120
180
|
for (const app of sortedApps) {
|
|
121
181
|
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.
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
|
|
182
|
+
// An API bucket renders nothing — there a feature is admitted by the surfaces it declares
|
|
183
|
+
// instead, so a GRAPHQL credential never resolves an HTTP-only feature. A surface-excluded
|
|
184
|
+
// feature vanishes from the catalog entirely, which is what makes resolution fail closed.
|
|
185
|
+
(isApiBucket(bucket) ? surfaceAllows(f.apiSurfaces, SURFACE_BY_BUCKET[bucket]) : !!(f.microfrontends?.web || f.microfrontends?.mobile)) && (siteType === void 0 || featureAppliesAtNode(f.applicableSiteTypes, siteType)));
|
|
125
186
|
if (businessAppFeatures.length === 0) continue;
|
|
126
187
|
for (const feature of businessAppFeatures) {
|
|
127
188
|
const membership = plan?.unlockedPermissions?.[feature.code];
|
|
128
189
|
const web = feature.microfrontends?.web;
|
|
129
190
|
const mobile = feature.microfrontends?.mobile;
|
|
130
191
|
const memberOnBucket = membership?.[bucket] !== void 0;
|
|
131
|
-
const sitePlatformLocked =
|
|
192
|
+
const sitePlatformLocked = locks?.[feature.code]?.[bucket] === null;
|
|
132
193
|
const missingServices = unmetServices(feature, availableServices);
|
|
133
|
-
const permissions = buildPermissions(feature, businessCode, membership,
|
|
194
|
+
const permissions = buildPermissions(feature, businessCode, membership, locks, plans, bucket, missingServices);
|
|
134
195
|
const lockReason = resolveLockReason(!memberOnBucket, sitePlatformLocked, missingServices);
|
|
135
196
|
const locked = lockReason !== null;
|
|
136
197
|
const unlockPlans = lockReason === "PLAN" ? plansIncludingFeature(plans, feature.code, bucket) : [];
|
|
@@ -167,9 +228,14 @@ function buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, s
|
|
|
167
228
|
}
|
|
168
229
|
__name(buildSiteCatalog, "buildSiteCatalog");
|
|
169
230
|
function isPlanMember(entry) {
|
|
170
|
-
|
|
231
|
+
if (!entry) return false;
|
|
232
|
+
return PLATFORMS.some((platform) => entry[platform] !== void 0) || entry.app !== void 0;
|
|
171
233
|
}
|
|
172
234
|
__name(isPlanMember, "isPlanMember");
|
|
235
|
+
function surfaceAllows(surfaces, surface) {
|
|
236
|
+
return surface === void 0 || surfaces === void 0 || surfaces.includes(surface);
|
|
237
|
+
}
|
|
238
|
+
__name(surfaceAllows, "surfaceAllows");
|
|
173
239
|
function resolveLockReason(planLocked, siteLocked, missingServices) {
|
|
174
240
|
if (planLocked) return "PLAN";
|
|
175
241
|
if (siteLocked) return "SITE";
|
|
@@ -279,7 +345,7 @@ function composeRoleGrants(params) {
|
|
|
279
345
|
if (revoke === null) continue;
|
|
280
346
|
composed[bucket] = revoke === void 0 ? merged : merged.filter((c) => !revoke.includes(c));
|
|
281
347
|
}
|
|
282
|
-
if (
|
|
348
|
+
if (PLATFORMS.every((bucket) => composed[bucket] === void 0)) continue;
|
|
283
349
|
result[code] = composed;
|
|
284
350
|
}
|
|
285
351
|
return result;
|
|
@@ -287,21 +353,35 @@ function composeRoleGrants(params) {
|
|
|
287
353
|
__name(composeRoleGrants, "composeRoleGrants");
|
|
288
354
|
|
|
289
355
|
// src/catalog-resolver/resolve-user-features.ts
|
|
356
|
+
var BUCKET_BY_CLIENT = {
|
|
357
|
+
web: "web",
|
|
358
|
+
ios: "mobile",
|
|
359
|
+
android: "mobile",
|
|
360
|
+
graphql: "graphql",
|
|
361
|
+
http: "http"
|
|
362
|
+
};
|
|
290
363
|
var EMPTY_ROUTE = {
|
|
291
364
|
remoteEntry: "",
|
|
292
365
|
exposedModule: "",
|
|
293
366
|
routePrefix: ""
|
|
294
367
|
};
|
|
295
368
|
function resolveUserFeatures(params) {
|
|
296
|
-
const { snapshot, businessCode, planCode, siteLocks,
|
|
297
|
-
const bucket = platform
|
|
369
|
+
const { snapshot, businessCode, planCode, siteLocks, platform, siteType, scope, availableServices } = params;
|
|
370
|
+
const bucket = BUCKET_BY_CLIENT[platform];
|
|
371
|
+
const roleFeatures = normalizeApiBuckets(params.roleFeatures) ?? {};
|
|
298
372
|
const featureByCode = /* @__PURE__ */ __name((code) => scope ? snapshot.features?.[snapshotFeatureKey(code, scope)] : findFeatureByCode(snapshot, code), "featureByCode");
|
|
299
373
|
const catalog = buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, siteType, scope, availableServices);
|
|
300
374
|
const catalogMap = new Map(catalog.map((f) => [
|
|
301
375
|
f.code,
|
|
302
376
|
f
|
|
303
377
|
]));
|
|
304
|
-
const businessPlans = snapshot.businesses[businessCode]?.plans ?? {}
|
|
378
|
+
const businessPlans = Object.fromEntries(Object.entries(snapshot.businesses[businessCode]?.plans ?? {}).map(([code, plan]) => [
|
|
379
|
+
code,
|
|
380
|
+
{
|
|
381
|
+
...plan,
|
|
382
|
+
unlockedPermissions: normalizeApiBuckets(plan.unlockedPermissions) ?? {}
|
|
383
|
+
}
|
|
384
|
+
]));
|
|
305
385
|
const currentUnlockedCodes = /* @__PURE__ */ new Set();
|
|
306
386
|
if (planCode && businessPlans[planCode]) {
|
|
307
387
|
for (const [featureCode, platforms] of Object.entries(businessPlans[planCode].unlockedPermissions ?? {})) {
|
|
@@ -333,7 +413,7 @@ function resolveUserFeatures(params) {
|
|
|
333
413
|
for (const [code, permsSet] of grantedFeatures) {
|
|
334
414
|
const catalogEntry = catalogMap.get(code);
|
|
335
415
|
if (!catalogEntry) continue;
|
|
336
|
-
const route = bucket
|
|
416
|
+
const route = isApiBucket(bucket) ? EMPTY_ROUTE : pickRouteForPlatform(catalogEntry, platform);
|
|
337
417
|
if (!route) continue;
|
|
338
418
|
const featureDeps = buildDependsMap(featureByCode(code)?.permissions ?? []);
|
|
339
419
|
const permByCode = new Map((catalogEntry.permissions ?? []).map((p) => [
|
|
@@ -378,6 +458,7 @@ function resolveUserFeatures(params) {
|
|
|
378
458
|
}
|
|
379
459
|
__name(resolveUserFeatures, "resolveUserFeatures");
|
|
380
460
|
function pickRouteForPlatform(entry, platform) {
|
|
461
|
+
if (platform === "graphql" || platform === "http") return null;
|
|
381
462
|
if (platform === "ios" || platform === "android") {
|
|
382
463
|
if (!entry.mobile) return null;
|
|
383
464
|
return {
|
|
@@ -406,13 +487,20 @@ function buildPlanMatrix(snapshot, businessCode, planCode, siteLocks) {
|
|
|
406
487
|
__name(buildPlanMatrix, "buildPlanMatrix");
|
|
407
488
|
function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, siteType) {
|
|
408
489
|
const business = businessCode ? snapshot.businesses?.[businessCode] : void 0;
|
|
409
|
-
const plans = business?.plans ?? {}
|
|
490
|
+
const plans = Object.fromEntries(Object.entries(business?.plans ?? {}).map(([code, p]) => [
|
|
491
|
+
code,
|
|
492
|
+
{
|
|
493
|
+
...p,
|
|
494
|
+
unlockedPermissions: normalizeApiBuckets(p.unlockedPermissions) ?? {}
|
|
495
|
+
}
|
|
496
|
+
]));
|
|
410
497
|
const plan = planCode ? plans[planCode] : void 0;
|
|
411
498
|
const planMeta = {
|
|
412
499
|
code: planCode ?? "",
|
|
413
500
|
name: plan?.name ?? planCode ?? ""
|
|
414
501
|
};
|
|
415
|
-
const
|
|
502
|
+
const normalizedLocks = normalizeApiBuckets(siteLocks);
|
|
503
|
+
const locks = normalizedLocks ?? {};
|
|
416
504
|
if (!business || !plan) return {
|
|
417
505
|
plan: planMeta,
|
|
418
506
|
apps: [],
|
|
@@ -431,11 +519,11 @@ function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, sit
|
|
|
431
519
|
if (siteType !== void 0 && !featureAppliesAtNode(feature.applicableSiteTypes, siteType)) continue;
|
|
432
520
|
const platforms = [
|
|
433
521
|
...UI_PLATFORMS.filter((p) => !!feature.microfrontends?.[p]),
|
|
434
|
-
|
|
522
|
+
...API_BUCKETS.filter((b) => feature.apiSurfaces === void 0 || feature.apiSurfaces.includes(SURFACE_BY_BUCKET[b]))
|
|
435
523
|
];
|
|
436
524
|
const membership = plan.unlockedPermissions?.[code];
|
|
437
525
|
const featureInPlan = isPlanMember(membership);
|
|
438
|
-
const siteEntry =
|
|
526
|
+
const siteEntry = normalizedLocks?.[code];
|
|
439
527
|
const permissions = (feature.permissions ?? []).filter((p) => p.isGlobal || p.businesses.includes(businessCode ?? "")).map((p) => {
|
|
440
528
|
const cell = /* @__PURE__ */ __name((plat) => {
|
|
441
529
|
if (!platforms.includes(plat)) return null;
|
|
@@ -457,7 +545,8 @@ function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, sit
|
|
|
457
545
|
dependsOn: p.dependsOn ?? [],
|
|
458
546
|
web: cell("web"),
|
|
459
547
|
mobile: cell("mobile"),
|
|
460
|
-
|
|
548
|
+
graphql: cell("graphql"),
|
|
549
|
+
http: cell("http")
|
|
461
550
|
};
|
|
462
551
|
});
|
|
463
552
|
features.push({
|
|
@@ -469,6 +558,7 @@ function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, sit
|
|
|
469
558
|
platforms,
|
|
470
559
|
inPlan: featureInPlan,
|
|
471
560
|
availableIn: featureInPlan ? [] : plansIncludingFeature2(plans, code, planCode),
|
|
561
|
+
apiSurfaces: feature.apiSurfaces,
|
|
472
562
|
permissions
|
|
473
563
|
});
|
|
474
564
|
}
|
|
@@ -509,10 +599,15 @@ function plansIncludingFeature2(plans, featureCode, excludeCode) {
|
|
|
509
599
|
}
|
|
510
600
|
__name(plansIncludingFeature2, "plansIncludingFeature");
|
|
511
601
|
export {
|
|
602
|
+
API_BUCKETS,
|
|
603
|
+
API_SURFACES,
|
|
604
|
+
BUCKET_BY_SURFACE,
|
|
512
605
|
PLATFORMS,
|
|
513
606
|
SERVICE_CODES,
|
|
514
607
|
SITE_TYPES,
|
|
515
608
|
SNAPSHOT_SCHEMA_VERSION,
|
|
609
|
+
SURFACE_BY_BUCKET,
|
|
610
|
+
UI_PLATFORMS,
|
|
516
611
|
buildDependsMap,
|
|
517
612
|
buildPlanMatrix,
|
|
518
613
|
buildSiteCatalog,
|
|
@@ -523,11 +618,14 @@ export {
|
|
|
523
618
|
featureAppliesAtNode,
|
|
524
619
|
filterGrantedByDeps,
|
|
525
620
|
findFeatureByCode,
|
|
621
|
+
isApiBucket,
|
|
526
622
|
isPlanMember,
|
|
527
623
|
isSiteLockedOnPlatform,
|
|
624
|
+
normalizeApiBuckets,
|
|
528
625
|
pickRouteForPlatform,
|
|
529
626
|
prereqClosure,
|
|
530
627
|
resolveUserFeatures,
|
|
531
|
-
snapshotFeatureKey
|
|
628
|
+
snapshotFeatureKey,
|
|
629
|
+
surfaceAllows
|
|
532
630
|
};
|
|
533
631
|
//# sourceMappingURL=catalog-resolver.js.map
|