@vritti/api-sdk 0.3.12 → 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 +142 -20
- package/dist/catalog-resolver.cjs.map +1 -1
- package/dist/catalog-resolver.d.cts +32 -4
- package/dist/catalog-resolver.d.ts +32 -4
- package/dist/catalog-resolver.js +133 -19
- 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-BBK6MG-U.d.cts → types-B7ArIjwo.d.cts} +31 -3
- package/dist/{types-BBK6MG-U.d.ts → types-B7ArIjwo.d.ts} +31 -3
- 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
|
|
|
@@ -25,7 +43,14 @@ declare function prereqClosure(code: string, deps: DependsMap): string[];
|
|
|
25
43
|
declare function cascadeLocked(codes: string[], directlyLocked: Set<string>, deps: DependsMap): Set<string>;
|
|
26
44
|
declare function filterGrantedByDeps(granted: Set<string>, deps: DependsMap): Set<string>;
|
|
27
45
|
|
|
28
|
-
|
|
46
|
+
/**
|
|
47
|
+
* The caller's surface, as the caller reports it.
|
|
48
|
+
*
|
|
49
|
+
* Finer than `PlatformBucket` on the mobile side — `ios` and `android` load different remote
|
|
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.
|
|
52
|
+
*/
|
|
53
|
+
type ClientPlatform = 'web' | 'ios' | 'android' | 'graphql' | 'http';
|
|
29
54
|
interface LockedPermission {
|
|
30
55
|
code: string;
|
|
31
56
|
reason: LockReason | null;
|
|
@@ -100,6 +125,8 @@ interface SiteMatrixPermission {
|
|
|
100
125
|
dependsOn: string[];
|
|
101
126
|
web: SiteMatrixCell | null;
|
|
102
127
|
mobile: SiteMatrixCell | null;
|
|
128
|
+
graphql: SiteMatrixCell | null;
|
|
129
|
+
http: SiteMatrixCell | null;
|
|
103
130
|
}
|
|
104
131
|
interface SiteMatrixFeature {
|
|
105
132
|
code: string;
|
|
@@ -110,6 +137,7 @@ interface SiteMatrixFeature {
|
|
|
110
137
|
platforms: PlatformBucket[];
|
|
111
138
|
inPlan: boolean;
|
|
112
139
|
availableIn: string[];
|
|
140
|
+
apiSurfaces?: ApiSurface[];
|
|
113
141
|
permissions: SiteMatrixPermission[];
|
|
114
142
|
}
|
|
115
143
|
interface SiteMatrixApp {
|
|
@@ -131,4 +159,4 @@ interface SiteMatrix {
|
|
|
131
159
|
declare function buildSiteMatrix(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, siteLocks: SiteFeatureLocks | undefined, siteType?: SiteType): SiteMatrix;
|
|
132
160
|
declare function buildPlanMatrix(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, siteLocks?: SiteFeatureLocks): SiteMatrix;
|
|
133
161
|
|
|
134
|
-
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
|
|
|
@@ -25,7 +43,14 @@ declare function prereqClosure(code: string, deps: DependsMap): string[];
|
|
|
25
43
|
declare function cascadeLocked(codes: string[], directlyLocked: Set<string>, deps: DependsMap): Set<string>;
|
|
26
44
|
declare function filterGrantedByDeps(granted: Set<string>, deps: DependsMap): Set<string>;
|
|
27
45
|
|
|
28
|
-
|
|
46
|
+
/**
|
|
47
|
+
* The caller's surface, as the caller reports it.
|
|
48
|
+
*
|
|
49
|
+
* Finer than `PlatformBucket` on the mobile side — `ios` and `android` load different remote
|
|
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.
|
|
52
|
+
*/
|
|
53
|
+
type ClientPlatform = 'web' | 'ios' | 'android' | 'graphql' | 'http';
|
|
29
54
|
interface LockedPermission {
|
|
30
55
|
code: string;
|
|
31
56
|
reason: LockReason | null;
|
|
@@ -100,6 +125,8 @@ interface SiteMatrixPermission {
|
|
|
100
125
|
dependsOn: string[];
|
|
101
126
|
web: SiteMatrixCell | null;
|
|
102
127
|
mobile: SiteMatrixCell | null;
|
|
128
|
+
graphql: SiteMatrixCell | null;
|
|
129
|
+
http: SiteMatrixCell | null;
|
|
103
130
|
}
|
|
104
131
|
interface SiteMatrixFeature {
|
|
105
132
|
code: string;
|
|
@@ -110,6 +137,7 @@ interface SiteMatrixFeature {
|
|
|
110
137
|
platforms: PlatformBucket[];
|
|
111
138
|
inPlan: boolean;
|
|
112
139
|
availableIn: string[];
|
|
140
|
+
apiSurfaces?: ApiSurface[];
|
|
113
141
|
permissions: SiteMatrixPermission[];
|
|
114
142
|
}
|
|
115
143
|
interface SiteMatrixApp {
|
|
@@ -131,4 +159,4 @@ interface SiteMatrix {
|
|
|
131
159
|
declare function buildSiteMatrix(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, siteLocks: SiteFeatureLocks | undefined, siteType?: SiteType): SiteMatrix;
|
|
132
160
|
declare function buildPlanMatrix(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, siteLocks?: SiteFeatureLocks): SiteMatrix;
|
|
133
161
|
|
|
134
|
-
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
|
@@ -73,9 +73,35 @@ __name(filterGrantedByDeps, "filterGrantedByDeps");
|
|
|
73
73
|
|
|
74
74
|
// src/catalog-resolver/types.ts
|
|
75
75
|
var PLATFORMS = [
|
|
76
|
+
"web",
|
|
77
|
+
"mobile",
|
|
78
|
+
"graphql",
|
|
79
|
+
"http"
|
|
80
|
+
];
|
|
81
|
+
var UI_PLATFORMS = [
|
|
76
82
|
"web",
|
|
77
83
|
"mobile"
|
|
78
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");
|
|
79
105
|
var SITE_TYPES = [
|
|
80
106
|
"OUTLET",
|
|
81
107
|
"WAREHOUSE",
|
|
@@ -88,9 +114,47 @@ function snapshotFeatureKey(code, scope) {
|
|
|
88
114
|
return `${scope}.${code}`;
|
|
89
115
|
}
|
|
90
116
|
__name(snapshotFeatureKey, "snapshotFeatureKey");
|
|
91
|
-
var SNAPSHOT_SCHEMA_VERSION =
|
|
117
|
+
var SNAPSHOT_SCHEMA_VERSION = 4;
|
|
92
118
|
|
|
93
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");
|
|
94
158
|
function featureAppliesAtNode(applicableSiteTypes, siteType) {
|
|
95
159
|
return applicableSiteTypes.includes(siteType);
|
|
96
160
|
}
|
|
@@ -106,23 +170,28 @@ function buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, s
|
|
|
106
170
|
if (!businessCode) return [];
|
|
107
171
|
const business = snapshot.businesses?.[businessCode];
|
|
108
172
|
if (!business) return [];
|
|
109
|
-
const
|
|
110
|
-
const
|
|
173
|
+
const plans = normalizePlans(business.plans ?? {});
|
|
174
|
+
const plan = planCode ? plans[planCode] : void 0;
|
|
175
|
+
const locks = normalizeApiBuckets(siteLocks);
|
|
111
176
|
const catalog = [];
|
|
112
177
|
const sortedApps = [
|
|
113
178
|
...business.apps
|
|
114
179
|
].sort((a, b) => a.name.localeCompare(b.name));
|
|
115
180
|
for (const app of sortedApps) {
|
|
116
|
-
const businessAppFeatures = app.features.filter((ref) => scope === void 0 || ref.scope === scope).map((ref) => snapshot.features?.[snapshotFeatureKey(ref.code, ref.scope)]).filter((f) => !!f &&
|
|
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.
|
|
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)));
|
|
117
186
|
if (businessAppFeatures.length === 0) continue;
|
|
118
187
|
for (const feature of businessAppFeatures) {
|
|
119
188
|
const membership = plan?.unlockedPermissions?.[feature.code];
|
|
120
189
|
const web = feature.microfrontends?.web;
|
|
121
190
|
const mobile = feature.microfrontends?.mobile;
|
|
122
191
|
const memberOnBucket = membership?.[bucket] !== void 0;
|
|
123
|
-
const sitePlatformLocked =
|
|
192
|
+
const sitePlatformLocked = locks?.[feature.code]?.[bucket] === null;
|
|
124
193
|
const missingServices = unmetServices(feature, availableServices);
|
|
125
|
-
const permissions = buildPermissions(feature, businessCode, membership,
|
|
194
|
+
const permissions = buildPermissions(feature, businessCode, membership, locks, plans, bucket, missingServices);
|
|
126
195
|
const lockReason = resolveLockReason(!memberOnBucket, sitePlatformLocked, missingServices);
|
|
127
196
|
const locked = lockReason !== null;
|
|
128
197
|
const unlockPlans = lockReason === "PLAN" ? plansIncludingFeature(plans, feature.code, bucket) : [];
|
|
@@ -159,9 +228,14 @@ function buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, s
|
|
|
159
228
|
}
|
|
160
229
|
__name(buildSiteCatalog, "buildSiteCatalog");
|
|
161
230
|
function isPlanMember(entry) {
|
|
162
|
-
|
|
231
|
+
if (!entry) return false;
|
|
232
|
+
return PLATFORMS.some((platform) => entry[platform] !== void 0) || entry.app !== void 0;
|
|
163
233
|
}
|
|
164
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");
|
|
165
239
|
function resolveLockReason(planLocked, siteLocked, missingServices) {
|
|
166
240
|
if (planLocked) return "PLAN";
|
|
167
241
|
if (siteLocked) return "SITE";
|
|
@@ -271,7 +345,7 @@ function composeRoleGrants(params) {
|
|
|
271
345
|
if (revoke === null) continue;
|
|
272
346
|
composed[bucket] = revoke === void 0 ? merged : merged.filter((c) => !revoke.includes(c));
|
|
273
347
|
}
|
|
274
|
-
if (
|
|
348
|
+
if (PLATFORMS.every((bucket) => composed[bucket] === void 0)) continue;
|
|
275
349
|
result[code] = composed;
|
|
276
350
|
}
|
|
277
351
|
return result;
|
|
@@ -279,16 +353,35 @@ function composeRoleGrants(params) {
|
|
|
279
353
|
__name(composeRoleGrants, "composeRoleGrants");
|
|
280
354
|
|
|
281
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
|
+
};
|
|
363
|
+
var EMPTY_ROUTE = {
|
|
364
|
+
remoteEntry: "",
|
|
365
|
+
exposedModule: "",
|
|
366
|
+
routePrefix: ""
|
|
367
|
+
};
|
|
282
368
|
function resolveUserFeatures(params) {
|
|
283
|
-
const { snapshot, businessCode, planCode, siteLocks,
|
|
284
|
-
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) ?? {};
|
|
285
372
|
const featureByCode = /* @__PURE__ */ __name((code) => scope ? snapshot.features?.[snapshotFeatureKey(code, scope)] : findFeatureByCode(snapshot, code), "featureByCode");
|
|
286
373
|
const catalog = buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, siteType, scope, availableServices);
|
|
287
374
|
const catalogMap = new Map(catalog.map((f) => [
|
|
288
375
|
f.code,
|
|
289
376
|
f
|
|
290
377
|
]));
|
|
291
|
-
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
|
+
]));
|
|
292
385
|
const currentUnlockedCodes = /* @__PURE__ */ new Set();
|
|
293
386
|
if (planCode && businessPlans[planCode]) {
|
|
294
387
|
for (const [featureCode, platforms] of Object.entries(businessPlans[planCode].unlockedPermissions ?? {})) {
|
|
@@ -320,7 +413,7 @@ function resolveUserFeatures(params) {
|
|
|
320
413
|
for (const [code, permsSet] of grantedFeatures) {
|
|
321
414
|
const catalogEntry = catalogMap.get(code);
|
|
322
415
|
if (!catalogEntry) continue;
|
|
323
|
-
const route = pickRouteForPlatform(catalogEntry, platform);
|
|
416
|
+
const route = isApiBucket(bucket) ? EMPTY_ROUTE : pickRouteForPlatform(catalogEntry, platform);
|
|
324
417
|
if (!route) continue;
|
|
325
418
|
const featureDeps = buildDependsMap(featureByCode(code)?.permissions ?? []);
|
|
326
419
|
const permByCode = new Map((catalogEntry.permissions ?? []).map((p) => [
|
|
@@ -365,6 +458,7 @@ function resolveUserFeatures(params) {
|
|
|
365
458
|
}
|
|
366
459
|
__name(resolveUserFeatures, "resolveUserFeatures");
|
|
367
460
|
function pickRouteForPlatform(entry, platform) {
|
|
461
|
+
if (platform === "graphql" || platform === "http") return null;
|
|
368
462
|
if (platform === "ios" || platform === "android") {
|
|
369
463
|
if (!entry.mobile) return null;
|
|
370
464
|
return {
|
|
@@ -393,13 +487,20 @@ function buildPlanMatrix(snapshot, businessCode, planCode, siteLocks) {
|
|
|
393
487
|
__name(buildPlanMatrix, "buildPlanMatrix");
|
|
394
488
|
function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, siteType) {
|
|
395
489
|
const business = businessCode ? snapshot.businesses?.[businessCode] : void 0;
|
|
396
|
-
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
|
+
]));
|
|
397
497
|
const plan = planCode ? plans[planCode] : void 0;
|
|
398
498
|
const planMeta = {
|
|
399
499
|
code: planCode ?? "",
|
|
400
500
|
name: plan?.name ?? planCode ?? ""
|
|
401
501
|
};
|
|
402
|
-
const
|
|
502
|
+
const normalizedLocks = normalizeApiBuckets(siteLocks);
|
|
503
|
+
const locks = normalizedLocks ?? {};
|
|
403
504
|
if (!business || !plan) return {
|
|
404
505
|
plan: planMeta,
|
|
405
506
|
apps: [],
|
|
@@ -416,11 +517,13 @@ function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, sit
|
|
|
416
517
|
const feature = snapshot.features?.[snapshotFeatureKey(code, ref.scope)];
|
|
417
518
|
if (!feature) continue;
|
|
418
519
|
if (siteType !== void 0 && !featureAppliesAtNode(feature.applicableSiteTypes, siteType)) continue;
|
|
419
|
-
const platforms =
|
|
420
|
-
|
|
520
|
+
const platforms = [
|
|
521
|
+
...UI_PLATFORMS.filter((p) => !!feature.microfrontends?.[p]),
|
|
522
|
+
...API_BUCKETS.filter((b) => feature.apiSurfaces === void 0 || feature.apiSurfaces.includes(SURFACE_BY_BUCKET[b]))
|
|
523
|
+
];
|
|
421
524
|
const membership = plan.unlockedPermissions?.[code];
|
|
422
525
|
const featureInPlan = isPlanMember(membership);
|
|
423
|
-
const siteEntry =
|
|
526
|
+
const siteEntry = normalizedLocks?.[code];
|
|
424
527
|
const permissions = (feature.permissions ?? []).filter((p) => p.isGlobal || p.businesses.includes(businessCode ?? "")).map((p) => {
|
|
425
528
|
const cell = /* @__PURE__ */ __name((plat) => {
|
|
426
529
|
if (!platforms.includes(plat)) return null;
|
|
@@ -441,7 +544,9 @@ function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, sit
|
|
|
441
544
|
label: p.label,
|
|
442
545
|
dependsOn: p.dependsOn ?? [],
|
|
443
546
|
web: cell("web"),
|
|
444
|
-
mobile: cell("mobile")
|
|
547
|
+
mobile: cell("mobile"),
|
|
548
|
+
graphql: cell("graphql"),
|
|
549
|
+
http: cell("http")
|
|
445
550
|
};
|
|
446
551
|
});
|
|
447
552
|
features.push({
|
|
@@ -453,6 +558,7 @@ function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, sit
|
|
|
453
558
|
platforms,
|
|
454
559
|
inPlan: featureInPlan,
|
|
455
560
|
availableIn: featureInPlan ? [] : plansIncludingFeature2(plans, code, planCode),
|
|
561
|
+
apiSurfaces: feature.apiSurfaces,
|
|
456
562
|
permissions
|
|
457
563
|
});
|
|
458
564
|
}
|
|
@@ -493,10 +599,15 @@ function plansIncludingFeature2(plans, featureCode, excludeCode) {
|
|
|
493
599
|
}
|
|
494
600
|
__name(plansIncludingFeature2, "plansIncludingFeature");
|
|
495
601
|
export {
|
|
602
|
+
API_BUCKETS,
|
|
603
|
+
API_SURFACES,
|
|
604
|
+
BUCKET_BY_SURFACE,
|
|
496
605
|
PLATFORMS,
|
|
497
606
|
SERVICE_CODES,
|
|
498
607
|
SITE_TYPES,
|
|
499
608
|
SNAPSHOT_SCHEMA_VERSION,
|
|
609
|
+
SURFACE_BY_BUCKET,
|
|
610
|
+
UI_PLATFORMS,
|
|
500
611
|
buildDependsMap,
|
|
501
612
|
buildPlanMatrix,
|
|
502
613
|
buildSiteCatalog,
|
|
@@ -507,11 +618,14 @@ export {
|
|
|
507
618
|
featureAppliesAtNode,
|
|
508
619
|
filterGrantedByDeps,
|
|
509
620
|
findFeatureByCode,
|
|
621
|
+
isApiBucket,
|
|
510
622
|
isPlanMember,
|
|
511
623
|
isSiteLockedOnPlatform,
|
|
624
|
+
normalizeApiBuckets,
|
|
512
625
|
pickRouteForPlatform,
|
|
513
626
|
prereqClosure,
|
|
514
627
|
resolveUserFeatures,
|
|
515
|
-
snapshotFeatureKey
|
|
628
|
+
snapshotFeatureKey,
|
|
629
|
+
surfaceAllows
|
|
516
630
|
};
|
|
517
631
|
//# sourceMappingURL=catalog-resolver.js.map
|