@vritti/api-sdk 0.2.10 → 0.3.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/cache.cjs +252 -0
- package/dist/cache.cjs.map +1 -0
- package/dist/cache.d.cts +25 -0
- package/dist/cache.d.ts +25 -0
- package/dist/cache.js +214 -0
- package/dist/cache.js.map +1 -0
- package/dist/cache.service-_SuJIcNA.d.cts +20 -0
- package/dist/cache.service-_SuJIcNA.d.ts +20 -0
- package/dist/catalog-resolver.cjs +364 -0
- package/dist/catalog-resolver.cjs.map +1 -0
- package/dist/catalog-resolver.d.cts +109 -0
- package/dist/catalog-resolver.d.ts +109 -0
- package/dist/catalog-resolver.js +330 -0
- package/dist/catalog-resolver.js.map +1 -0
- package/dist/email.cjs +691 -0
- package/dist/email.cjs.map +1 -0
- package/dist/email.d.cts +35 -0
- package/dist/email.d.ts +35 -0
- package/dist/email.js +665 -0
- package/dist/email.js.map +1 -0
- package/dist/fastify-augmentation-CQPBNS5a.d.cts +105 -0
- package/dist/fastify-augmentation-CQPBNS5a.d.ts +105 -0
- package/dist/icons.cjs +13803 -0
- package/dist/icons.cjs.map +1 -0
- package/dist/icons.d.cts +8 -0
- package/dist/icons.d.ts +8 -0
- package/dist/icons.js +13778 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.cjs +742 -1367
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +103 -181
- package/dist/index.d.ts +103 -181
- package/dist/index.js +601 -1233
- package/dist/index.js.map +1 -1
- package/dist/license.cjs +104 -0
- package/dist/license.cjs.map +1 -0
- package/dist/license.d.cts +32 -0
- package/dist/license.d.ts +32 -0
- package/dist/license.js +75 -0
- package/dist/license.js.map +1 -0
- package/dist/money.cjs +93 -6
- package/dist/money.cjs.map +1 -1
- package/dist/money.d.cts +13 -1
- package/dist/money.d.ts +13 -1
- package/dist/money.js +115 -3
- package/dist/money.js.map +1 -1
- package/dist/nats.cjs +196 -179
- package/dist/nats.cjs.map +1 -1
- package/dist/nats.d.cts +13 -11
- package/dist/nats.d.ts +13 -11
- package/dist/nats.js +172 -155
- package/dist/nats.js.map +1 -1
- package/dist/types-DQRwj5rr.d.cts +113 -0
- package/dist/types-DQRwj5rr.d.ts +113 -0
- package/package.json +55 -1
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/catalog-resolver/index.ts
|
|
22
|
+
var catalog_resolver_exports = {};
|
|
23
|
+
__export(catalog_resolver_exports, {
|
|
24
|
+
PLATFORMS: () => PLATFORMS,
|
|
25
|
+
SNAPSHOT_SCHEMA_VERSION: () => SNAPSHOT_SCHEMA_VERSION,
|
|
26
|
+
buildBuCatalog: () => buildBuCatalog,
|
|
27
|
+
buildBuMatrix: () => buildBuMatrix,
|
|
28
|
+
buildBuRoles: () => buildBuRoles,
|
|
29
|
+
composeRoleGrants: () => composeRoleGrants,
|
|
30
|
+
isBuLockedOnPlatform: () => isBuLockedOnPlatform,
|
|
31
|
+
isPlanMember: () => isPlanMember,
|
|
32
|
+
pickRouteForPlatform: () => pickRouteForPlatform,
|
|
33
|
+
resolveUserFeatures: () => resolveUserFeatures
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(catalog_resolver_exports);
|
|
36
|
+
|
|
37
|
+
// src/catalog-resolver/catalog.builder.ts
|
|
38
|
+
function buildBuCatalog(snapshot, businessCode, planCode, buLocks, bucket) {
|
|
39
|
+
if (!businessCode) return [];
|
|
40
|
+
const business = snapshot.businesses?.[businessCode];
|
|
41
|
+
if (!business) return [];
|
|
42
|
+
const plan = planCode ? business.plans?.[planCode] : void 0;
|
|
43
|
+
const plans = business.plans ?? {};
|
|
44
|
+
const catalog = [];
|
|
45
|
+
for (const app of business.apps) {
|
|
46
|
+
const businessAppFeatures = app.features.map((code) => snapshot.features?.[code]).filter((f) => !!f && !!(f.microfrontends?.web || f.microfrontends?.mobile));
|
|
47
|
+
if (businessAppFeatures.length === 0) continue;
|
|
48
|
+
for (const feature of businessAppFeatures) {
|
|
49
|
+
const membership = plan?.unlockedPermissions?.[feature.code];
|
|
50
|
+
const web = feature.microfrontends?.web;
|
|
51
|
+
const mobile = feature.microfrontends?.mobile;
|
|
52
|
+
const permissions = buildPermissions(feature, businessCode, membership, buLocks, plans, bucket);
|
|
53
|
+
const memberOnBucket = membership?.[bucket] !== void 0;
|
|
54
|
+
const buPlatformLocked = buLocks?.[feature.code]?.[bucket] === null;
|
|
55
|
+
const locked = !memberOnBucket || buPlatformLocked;
|
|
56
|
+
const lockReason = !memberOnBucket ? "PLAN" : buPlatformLocked ? "BU" : null;
|
|
57
|
+
const unlockPlans = lockReason === "PLAN" ? plansIncludingFeature(plans, feature.code, bucket) : [];
|
|
58
|
+
catalog.push({
|
|
59
|
+
code: feature.code,
|
|
60
|
+
name: feature.name,
|
|
61
|
+
lucideIcon: feature.lucideIcon ?? null,
|
|
62
|
+
sfSymbol: feature.sfSymbol ?? "square",
|
|
63
|
+
materialSymbol: feature.materialSymbol ?? "square",
|
|
64
|
+
web: web ? {
|
|
65
|
+
remoteEntry: web.remoteEntry ?? "",
|
|
66
|
+
exposedModule: web.exposedModule ?? "",
|
|
67
|
+
routePrefix: web.routePrefix ?? ""
|
|
68
|
+
} : null,
|
|
69
|
+
mobile: mobile ? {
|
|
70
|
+
remoteEntryAndroid: mobile.remoteEntryAndroid ?? "",
|
|
71
|
+
remoteEntryIos: mobile.remoteEntryIos ?? "",
|
|
72
|
+
exposedModule: mobile.exposedModule ?? "",
|
|
73
|
+
routePrefix: mobile.routePrefix ?? ""
|
|
74
|
+
} : null,
|
|
75
|
+
appCode: app.code,
|
|
76
|
+
appName: app.name,
|
|
77
|
+
appIcon: app.icon ?? null,
|
|
78
|
+
appSortOrder: app.sortOrder ?? 0,
|
|
79
|
+
locked,
|
|
80
|
+
lockReason,
|
|
81
|
+
unlockPlans,
|
|
82
|
+
permissions
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return catalog;
|
|
87
|
+
}
|
|
88
|
+
__name(buildBuCatalog, "buildBuCatalog");
|
|
89
|
+
function isPlanMember(entry) {
|
|
90
|
+
return !!entry && (entry.web !== void 0 || entry.mobile !== void 0);
|
|
91
|
+
}
|
|
92
|
+
__name(isPlanMember, "isPlanMember");
|
|
93
|
+
function isBuLockedOnPlatform(entry, platform, code) {
|
|
94
|
+
const locks = entry?.[platform];
|
|
95
|
+
return locks === null || (locks?.includes(code) ?? false);
|
|
96
|
+
}
|
|
97
|
+
__name(isBuLockedOnPlatform, "isBuLockedOnPlatform");
|
|
98
|
+
function buildPermissions(feature, businessCode, planMembership, buLocks, plans, bucket) {
|
|
99
|
+
const planUnlocked = new Set(planMembership?.[bucket] ?? []);
|
|
100
|
+
const lockEntry = buLocks?.[feature.code];
|
|
101
|
+
return (feature.permissions ?? []).filter((p) => p.isGlobal || p.businesses.includes(businessCode)).map((p) => {
|
|
102
|
+
const planAllows = planUnlocked.has(p.code);
|
|
103
|
+
const buAllows = !isBuLockedOnPlatform(lockEntry, bucket, p.code);
|
|
104
|
+
const locked = !planAllows || !buAllows;
|
|
105
|
+
const lockReason = !planAllows ? "PLAN" : !buAllows ? "BU" : null;
|
|
106
|
+
const unlockPlans = lockReason === "PLAN" ? plansUnlockingPermission(plans, feature.code, p.code, bucket) : [];
|
|
107
|
+
return {
|
|
108
|
+
code: p.code,
|
|
109
|
+
locked,
|
|
110
|
+
lockReason,
|
|
111
|
+
unlockPlans
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
__name(buildPermissions, "buildPermissions");
|
|
116
|
+
function plansUnlockingPermission(plans, featureCode, permCode, bucket) {
|
|
117
|
+
const result = [];
|
|
118
|
+
for (const [code, plan] of Object.entries(plans)) {
|
|
119
|
+
if (plan.unlockedPermissions?.[featureCode]?.[bucket]?.includes(permCode)) result.push(code);
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
__name(plansUnlockingPermission, "plansUnlockingPermission");
|
|
124
|
+
function plansIncludingFeature(plans, featureCode, bucket) {
|
|
125
|
+
const result = [];
|
|
126
|
+
for (const [code, plan] of Object.entries(plans)) {
|
|
127
|
+
if (plan.unlockedPermissions?.[featureCode]?.[bucket] !== void 0) result.push(code);
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
__name(plansIncludingFeature, "plansIncludingFeature");
|
|
132
|
+
function buildBuRoles(snapshot, businessCode) {
|
|
133
|
+
if (!businessCode) return [];
|
|
134
|
+
const business = snapshot.businesses?.[businessCode];
|
|
135
|
+
if (!business) return [];
|
|
136
|
+
return Object.values(business.roleTemplates ?? {});
|
|
137
|
+
}
|
|
138
|
+
__name(buildBuRoles, "buildBuRoles");
|
|
139
|
+
|
|
140
|
+
// src/catalog-resolver/types.ts
|
|
141
|
+
var PLATFORMS = [
|
|
142
|
+
"web",
|
|
143
|
+
"mobile"
|
|
144
|
+
];
|
|
145
|
+
var SNAPSHOT_SCHEMA_VERSION = 1;
|
|
146
|
+
|
|
147
|
+
// src/catalog-resolver/bu-matrix.builder.ts
|
|
148
|
+
function buildBuMatrix(snapshot, businessCode, planCode, buLocks) {
|
|
149
|
+
const business = businessCode ? snapshot.businesses?.[businessCode] : void 0;
|
|
150
|
+
const plans = business?.plans ?? {};
|
|
151
|
+
const plan = planCode ? plans[planCode] : void 0;
|
|
152
|
+
const planMeta = {
|
|
153
|
+
code: planCode ?? "",
|
|
154
|
+
name: plan?.name ?? planCode ?? ""
|
|
155
|
+
};
|
|
156
|
+
const locks = buLocks ?? {};
|
|
157
|
+
if (!business || !plan) return {
|
|
158
|
+
plan: planMeta,
|
|
159
|
+
apps: [],
|
|
160
|
+
locks
|
|
161
|
+
};
|
|
162
|
+
const apps = [];
|
|
163
|
+
for (const app of business.apps) {
|
|
164
|
+
let unlockedCount = 0;
|
|
165
|
+
let totalCount = 0;
|
|
166
|
+
const features = [];
|
|
167
|
+
for (const code of app.features) {
|
|
168
|
+
const feature = snapshot.features?.[code];
|
|
169
|
+
if (!feature) continue;
|
|
170
|
+
const platforms = PLATFORMS.filter((p) => !!feature.microfrontends?.[p]);
|
|
171
|
+
if (platforms.length === 0) continue;
|
|
172
|
+
const membership = plan.unlockedPermissions?.[code];
|
|
173
|
+
const featureInPlan = isPlanMember(membership);
|
|
174
|
+
const buEntry = buLocks?.[code];
|
|
175
|
+
const permissions = (feature.permissions ?? []).filter((p) => p.isGlobal || p.businesses.includes(businessCode ?? "")).map((p) => {
|
|
176
|
+
const cell = /* @__PURE__ */ __name((plat) => {
|
|
177
|
+
if (!platforms.includes(plat)) return null;
|
|
178
|
+
const planCodes = membership?.[plat];
|
|
179
|
+
const inPlan = featureInPlan && planCodes !== void 0 && planCodes.includes(p.code);
|
|
180
|
+
const selected = inPlan && !isBuLockedOnPlatform(buEntry, plat, p.code);
|
|
181
|
+
const availableIn = inPlan ? [] : plansUnlockingPerm(plans, code, p.code, plat, planCode);
|
|
182
|
+
totalCount += 1;
|
|
183
|
+
if (inPlan) unlockedCount += 1;
|
|
184
|
+
return {
|
|
185
|
+
inPlan,
|
|
186
|
+
selected,
|
|
187
|
+
availableIn
|
|
188
|
+
};
|
|
189
|
+
}, "cell");
|
|
190
|
+
return {
|
|
191
|
+
code: p.code,
|
|
192
|
+
label: p.label,
|
|
193
|
+
web: cell("web"),
|
|
194
|
+
mobile: cell("mobile")
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
features.push({
|
|
198
|
+
code: feature.code,
|
|
199
|
+
name: feature.name,
|
|
200
|
+
icon: feature.lucideIcon ?? null,
|
|
201
|
+
platforms,
|
|
202
|
+
inPlan: featureInPlan,
|
|
203
|
+
availableIn: featureInPlan ? [] : plansIncludingFeature2(plans, code, planCode),
|
|
204
|
+
permissions
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
apps.push({
|
|
208
|
+
code: app.code,
|
|
209
|
+
name: app.name,
|
|
210
|
+
icon: app.icon ?? null,
|
|
211
|
+
unlockedCount,
|
|
212
|
+
totalCount,
|
|
213
|
+
features
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
plan: planMeta,
|
|
218
|
+
apps,
|
|
219
|
+
locks
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
__name(buildBuMatrix, "buildBuMatrix");
|
|
223
|
+
function plansUnlockingPerm(plans, featureCode, permCode, platform, excludeCode) {
|
|
224
|
+
const names = [];
|
|
225
|
+
for (const [code, p] of Object.entries(plans)) {
|
|
226
|
+
if (code === excludeCode) continue;
|
|
227
|
+
if ((p.unlockedPermissions?.[featureCode]?.[platform] ?? []).includes(permCode)) names.push(p.name);
|
|
228
|
+
}
|
|
229
|
+
return names;
|
|
230
|
+
}
|
|
231
|
+
__name(plansUnlockingPerm, "plansUnlockingPerm");
|
|
232
|
+
function plansIncludingFeature2(plans, featureCode, excludeCode) {
|
|
233
|
+
const names = [];
|
|
234
|
+
for (const [code, p] of Object.entries(plans)) {
|
|
235
|
+
if (code === excludeCode) continue;
|
|
236
|
+
if (isPlanMember(p.unlockedPermissions?.[featureCode])) names.push(p.name);
|
|
237
|
+
}
|
|
238
|
+
return names;
|
|
239
|
+
}
|
|
240
|
+
__name(plansIncludingFeature2, "plansIncludingFeature");
|
|
241
|
+
|
|
242
|
+
// src/catalog-resolver/compose-role-grants.ts
|
|
243
|
+
function unionBucket(base, add) {
|
|
244
|
+
if (base === void 0 && add === void 0) return void 0;
|
|
245
|
+
return [
|
|
246
|
+
.../* @__PURE__ */ new Set([
|
|
247
|
+
...base ?? [],
|
|
248
|
+
...add ?? []
|
|
249
|
+
])
|
|
250
|
+
];
|
|
251
|
+
}
|
|
252
|
+
__name(unionBucket, "unionBucket");
|
|
253
|
+
function composeRoleGrants(params) {
|
|
254
|
+
const { baseFeatures, additions, revoked } = params;
|
|
255
|
+
const result = {};
|
|
256
|
+
const featureCodes = /* @__PURE__ */ new Set([
|
|
257
|
+
...Object.keys(baseFeatures ?? {}),
|
|
258
|
+
...Object.keys(additions ?? {})
|
|
259
|
+
]);
|
|
260
|
+
for (const code of featureCodes) {
|
|
261
|
+
const base = baseFeatures?.[code] ?? {};
|
|
262
|
+
const add = additions?.[code] ?? {};
|
|
263
|
+
const revokes = revoked?.[code];
|
|
264
|
+
const composed = {};
|
|
265
|
+
for (const bucket of PLATFORMS) {
|
|
266
|
+
const merged = unionBucket(base[bucket], add[bucket]);
|
|
267
|
+
if (merged === void 0) continue;
|
|
268
|
+
const revoke = revokes?.[bucket];
|
|
269
|
+
if (revoke === null) continue;
|
|
270
|
+
composed[bucket] = revoke === void 0 ? merged : merged.filter((c) => !revoke.includes(c));
|
|
271
|
+
}
|
|
272
|
+
if (composed.web === void 0 && composed.mobile === void 0) continue;
|
|
273
|
+
result[code] = composed;
|
|
274
|
+
}
|
|
275
|
+
return result;
|
|
276
|
+
}
|
|
277
|
+
__name(composeRoleGrants, "composeRoleGrants");
|
|
278
|
+
|
|
279
|
+
// src/catalog-resolver/resolve-user-features.ts
|
|
280
|
+
function resolveUserFeatures(params) {
|
|
281
|
+
const { snapshot, businessCode, planCode, buLocks, roleFeatures, platform } = params;
|
|
282
|
+
const bucket = platform === "web" ? "web" : "mobile";
|
|
283
|
+
const catalog = buildBuCatalog(snapshot, businessCode, planCode, buLocks, bucket);
|
|
284
|
+
const catalogMap = new Map(catalog.map((f) => [
|
|
285
|
+
f.code,
|
|
286
|
+
f
|
|
287
|
+
]));
|
|
288
|
+
const grantedFeatures = /* @__PURE__ */ new Map();
|
|
289
|
+
for (const [code, grant] of Object.entries(roleFeatures ?? {})) {
|
|
290
|
+
const granted = grant?.[bucket];
|
|
291
|
+
if (granted === void 0) continue;
|
|
292
|
+
if (!grantedFeatures.has(code)) grantedFeatures.set(code, /* @__PURE__ */ new Set());
|
|
293
|
+
for (const perm of granted) grantedFeatures.get(code)?.add(perm);
|
|
294
|
+
}
|
|
295
|
+
const features = [];
|
|
296
|
+
for (const [code, permsSet] of grantedFeatures) {
|
|
297
|
+
const catalogEntry = catalogMap.get(code);
|
|
298
|
+
if (!catalogEntry) continue;
|
|
299
|
+
const route = pickRouteForPlatform(catalogEntry, platform);
|
|
300
|
+
if (!route) continue;
|
|
301
|
+
const permByCode = new Map((catalogEntry.permissions ?? []).map((p) => [
|
|
302
|
+
p.code,
|
|
303
|
+
p
|
|
304
|
+
]));
|
|
305
|
+
const grantedPerms = [
|
|
306
|
+
...permsSet
|
|
307
|
+
];
|
|
308
|
+
const lockedPermissions = grantedPerms.map((c) => permByCode.get(c)).filter((p) => !!p?.locked).map((p) => ({
|
|
309
|
+
code: p.code,
|
|
310
|
+
reason: p.lockReason ?? null,
|
|
311
|
+
unlockPlans: p.unlockPlans ?? []
|
|
312
|
+
}));
|
|
313
|
+
features.push({
|
|
314
|
+
code,
|
|
315
|
+
name: catalogEntry.name,
|
|
316
|
+
lucideIcon: catalogEntry.lucideIcon,
|
|
317
|
+
sfSymbol: catalogEntry.sfSymbol,
|
|
318
|
+
materialSymbol: catalogEntry.materialSymbol,
|
|
319
|
+
permissions: grantedPerms,
|
|
320
|
+
locked: catalogEntry.locked ?? false,
|
|
321
|
+
lockReason: catalogEntry.lockReason ?? null,
|
|
322
|
+
unlockPlans: catalogEntry.unlockPlans ?? [],
|
|
323
|
+
lockedPermissions,
|
|
324
|
+
route,
|
|
325
|
+
appCode: catalogEntry.appCode,
|
|
326
|
+
appName: catalogEntry.appName,
|
|
327
|
+
appIcon: catalogEntry.appIcon,
|
|
328
|
+
appSortOrder: catalogEntry.appSortOrder
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
return features;
|
|
332
|
+
}
|
|
333
|
+
__name(resolveUserFeatures, "resolveUserFeatures");
|
|
334
|
+
function pickRouteForPlatform(entry, platform) {
|
|
335
|
+
if (platform === "ios" || platform === "android") {
|
|
336
|
+
if (!entry.mobile) return null;
|
|
337
|
+
return {
|
|
338
|
+
remoteEntry: platform === "ios" ? entry.mobile.remoteEntryIos : entry.mobile.remoteEntryAndroid,
|
|
339
|
+
exposedModule: entry.mobile.exposedModule,
|
|
340
|
+
routePrefix: entry.mobile.routePrefix
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
if (!entry.web) return null;
|
|
344
|
+
return {
|
|
345
|
+
remoteEntry: entry.web.remoteEntry,
|
|
346
|
+
exposedModule: entry.web.exposedModule,
|
|
347
|
+
routePrefix: entry.web.routePrefix
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
__name(pickRouteForPlatform, "pickRouteForPlatform");
|
|
351
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
352
|
+
0 && (module.exports = {
|
|
353
|
+
PLATFORMS,
|
|
354
|
+
SNAPSHOT_SCHEMA_VERSION,
|
|
355
|
+
buildBuCatalog,
|
|
356
|
+
buildBuMatrix,
|
|
357
|
+
buildBuRoles,
|
|
358
|
+
composeRoleGrants,
|
|
359
|
+
isBuLockedOnPlatform,
|
|
360
|
+
isPlanMember,
|
|
361
|
+
pickRouteForPlatform,
|
|
362
|
+
resolveUserFeatures
|
|
363
|
+
});
|
|
364
|
+
//# sourceMappingURL=catalog-resolver.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/catalog-resolver/index.ts","../src/catalog-resolver/catalog.builder.ts","../src/catalog-resolver/types.ts","../src/catalog-resolver/bu-matrix.builder.ts","../src/catalog-resolver/compose-role-grants.ts","../src/catalog-resolver/resolve-user-features.ts"],"sourcesContent":["// Catalog resolver — the single shared implementation of snapshot resolution (BU catalog, BU matrix, user features)\nexport {\n type BuMatrix,\n type BuMatrixApp,\n type BuMatrixCell,\n type BuMatrixFeature,\n type BuMatrixPermission,\n buildBuMatrix,\n} from './bu-matrix.builder';\nexport { buildBuCatalog, buildBuRoles, isBuLockedOnPlatform, isPlanMember } from './catalog.builder';\nexport { type ComposeRoleGrantsParams, composeRoleGrants, type RevokedGrants } from './compose-role-grants';\nexport {\n type ClientPlatform,\n type LockedPermission,\n type PermissionFeature,\n pickRouteForPlatform,\n type ResolveUserFeaturesParams,\n resolveUserFeatures,\n} from './resolve-user-features';\nexport {\n type BuFeatureLocks,\n type CatalogPermission,\n type FeatureCatalogEntry,\n type FeatureUnlocks,\n type LockReason,\n PLATFORMS,\n type PlatformBucket,\n type PlatformCodes,\n type PlatformDenyCodes,\n type RoleItem,\n SNAPSHOT_SCHEMA_VERSION,\n type SnapshotApp,\n type SnapshotBusiness,\n type SnapshotFeature,\n type SnapshotMicrofrontendMobile,\n type SnapshotMicrofrontends,\n type SnapshotMicrofrontendWeb,\n type SnapshotPermission,\n type SnapshotPlan,\n type SnapshotRoleTemplate,\n type VersionSnapshot,\n} from './types';\n","import type {\n BuFeatureLocks,\n CatalogPermission,\n FeatureCatalogEntry,\n LockReason,\n PlatformBucket,\n PlatformCodes,\n RoleItem,\n SnapshotFeature,\n SnapshotPlan,\n VersionSnapshot,\n} from './types';\n\n// Builds the per-BU catalog for ONE platform bucket. The plan is the ceiling (membership + unlocks); buLocks is a\n// deny-list within the plan (undefined or absent entries ⇒ fully available). Each permission carries\n// locked + lockReason + unlockPlans, all evaluated against the requested bucket only.\nexport function buildBuCatalog(\n snapshot: VersionSnapshot,\n businessCode: string | undefined,\n planCode: string | undefined,\n buLocks: BuFeatureLocks | undefined,\n bucket: PlatformBucket,\n): FeatureCatalogEntry[] {\n if (!businessCode) return [];\n const business = snapshot.businesses?.[businessCode];\n if (!business) return [];\n const plan = planCode ? business.plans?.[planCode] : undefined;\n const plans = business.plans ?? {};\n\n const catalog: FeatureCatalogEntry[] = [];\n for (const app of business.apps) {\n // The app's renderable features (each feature pins to exactly one app)\n const businessAppFeatures = app.features\n .map((code) => snapshot.features?.[code])\n .filter((f): f is SnapshotFeature => !!f && !!(f.microfrontends?.web || f.microfrontends?.mobile));\n\n if (businessAppFeatures.length === 0) continue;\n\n // Emit EVERY business feature so a role's grant on a plan-omitted feature still resolves (rendered as a locked\n // tile with an upsell) instead of vanishing. Core filters the catalog down to what the user's role grants.\n for (const feature of businessAppFeatures) {\n const membership = plan?.unlockedPermissions?.[feature.code];\n // Routes are exposed wherever the feature SHIPS — membership never hides them. A role grant on a\n // plan-omitted (feature or platform) still resolves as a locked tile with an upsell instead of vanishing.\n const web = feature.microfrontends?.web;\n const mobile = feature.microfrontends?.mobile;\n\n const permissions = buildPermissions(feature, businessCode, membership, buLocks, plans, bucket);\n // Feature-level lock is EXPLICIT, never derived from permission locks: the plan must include the feature\n // on this bucket (membership) and the BU must not null-lock the platform. Permission-code locks only\n // disable individual actions — the feature still renders (sidebar/tile stays enabled).\n const memberOnBucket = membership?.[bucket] !== undefined;\n const buPlatformLocked = buLocks?.[feature.code]?.[bucket] === null;\n const locked = !memberOnBucket || buPlatformLocked;\n const lockReason: LockReason | null = !memberOnBucket ? 'PLAN' : buPlatformLocked ? 'BU' : null;\n const unlockPlans = lockReason === 'PLAN' ? plansIncludingFeature(plans, feature.code, bucket) : [];\n\n catalog.push({\n code: feature.code,\n name: feature.name,\n lucideIcon: feature.lucideIcon ?? null,\n sfSymbol: feature.sfSymbol ?? 'square',\n materialSymbol: feature.materialSymbol ?? 'square',\n web: web\n ? {\n remoteEntry: web.remoteEntry ?? '',\n exposedModule: web.exposedModule ?? '',\n routePrefix: web.routePrefix ?? '',\n }\n : null,\n mobile: mobile\n ? {\n remoteEntryAndroid: mobile.remoteEntryAndroid ?? '',\n remoteEntryIos: mobile.remoteEntryIos ?? '',\n exposedModule: mobile.exposedModule ?? '',\n routePrefix: mobile.routePrefix ?? '',\n }\n : null,\n appCode: app.code,\n appName: app.name,\n appIcon: app.icon ?? null,\n appSortOrder: app.sortOrder ?? 0,\n locked,\n lockReason,\n unlockPlans,\n permissions,\n });\n }\n }\n return catalog;\n}\n\n// A feature is a plan member when its unlock entry exists on at least one platform (even with zero actions)\nexport function isPlanMember(entry: PlatformCodes | undefined): boolean {\n return !!entry && (entry.web !== undefined || entry.mobile !== undefined);\n}\n\n// Per-platform BU-lock primitive: platform null locks the whole feature there; string[] locks those codes;\n// entry/platform absent ⇒ not locked\nexport function isBuLockedOnPlatform(\n entry: BuFeatureLocks[string] | undefined,\n platform: PlatformBucket,\n code: string,\n): boolean {\n const locks = entry?.[platform];\n return locks === null || (locks?.includes(code) ?? false);\n}\n\n// A feature's business-scoped permissions, each tagged with locked + reason against the plan and the BU deny-list.\n// Everything is bucket-scoped: a web resolution ignores mobile unlocks and mobile locks entirely.\nfunction buildPermissions(\n feature: SnapshotFeature,\n businessCode: string,\n planMembership: PlatformCodes | undefined,\n buLocks: BuFeatureLocks | undefined,\n plans: Record<string, SnapshotPlan>,\n bucket: PlatformBucket,\n): CatalogPermission[] {\n const planUnlocked = new Set(planMembership?.[bucket] ?? []);\n const lockEntry = buLocks?.[feature.code];\n\n return (feature.permissions ?? [])\n .filter((p) => p.isGlobal || p.businesses.includes(businessCode))\n .map((p) => {\n const planAllows = planUnlocked.has(p.code);\n const buAllows = !isBuLockedOnPlatform(lockEntry, bucket, p.code);\n const locked = !planAllows || !buAllows;\n // Plan is the ceiling, so a plan-lock wins over a BU-lock when reporting the reason\n const lockReason: LockReason | null = !planAllows ? 'PLAN' : !buAllows ? 'BU' : null;\n const unlockPlans = lockReason === 'PLAN' ? plansUnlockingPermission(plans, feature.code, p.code, bucket) : [];\n return { code: p.code, locked, lockReason, unlockPlans };\n });\n}\n\n// Plan codes (in the business) whose unlocked set includes this feature+permission on the bucket — upsell targets\nfunction plansUnlockingPermission(\n plans: Record<string, SnapshotPlan>,\n featureCode: string,\n permCode: string,\n bucket: PlatformBucket,\n): string[] {\n const result: string[] = [];\n for (const [code, plan] of Object.entries(plans)) {\n if (plan.unlockedPermissions?.[featureCode]?.[bucket]?.includes(permCode)) result.push(code);\n }\n return result;\n}\n\n// Plan codes (in the business) that include this feature on the bucket — the feature-level upsell targets\nfunction plansIncludingFeature(\n plans: Record<string, SnapshotPlan>,\n featureCode: string,\n bucket: PlatformBucket,\n): string[] {\n const result: string[] = [];\n for (const [code, plan] of Object.entries(plans)) {\n if (plan.unlockedPermissions?.[featureCode]?.[bucket] !== undefined) result.push(code);\n }\n return result;\n}\n\n// The business's role templates as provisionable role items for core (identical shapes)\nexport function buildBuRoles(snapshot: VersionSnapshot, businessCode: string | undefined): RoleItem[] {\n if (!businessCode) return [];\n const business = snapshot.businesses?.[businessCode];\n if (!business) return [];\n return Object.values(business.roleTemplates ?? {});\n}\n","// ——— Platform algebra ———\n// Everything in this domain (plan unlocks, role grants, BU locks) is stored per UI platform bucket.\n\nexport type PlatformBucket = 'web' | 'mobile';\n\nexport const PLATFORMS: PlatformBucket[] = ['web', 'mobile'];\n\n// Allow entry: a bucket key present (even []) = membership on that platform; the array holds permission codes\nexport interface PlatformCodes {\n web?: string[];\n mobile?: string[];\n}\n\n// Deny entry: null locks/revokes the whole bucket, string[] the listed codes, absent = untouched\nexport interface PlatformDenyCodes {\n web?: string[] | null;\n mobile?: string[] | null;\n}\n\n// Code-keyed allow-list — plan unlocks, role grants, and matrix selections all share this exact shape\nexport type FeatureUnlocks = Record<string, PlatformCodes>;\n\n// BU deny-list overlay (same shape as role revokes) — feature absent = fully available within the plan\nexport type BuFeatureLocks = Record<string, PlatformDenyCodes>;\n\n// ——— Snapshot document shape — what gets stored in versions.snapshot and signed into the catalog license ———\n\nexport interface SnapshotPermission {\n code: string;\n label: string;\n isGlobal: boolean;\n businesses: string[];\n}\n// WEB microfrontend route — a single remote entry. All non-null: a WEB microfrontend row is\n// CHECK-constrained to have remoteEntry set, and the feature↔MF link's module/route are NOT NULL.\nexport interface SnapshotMicrofrontendWeb {\n code: string;\n name: string;\n remoteEntry: string;\n exposedModule: string;\n routePrefix: string;\n}\n// MOBILE microfrontend route — per-OS remote entries (android + ios). All non-null: a MOBILE row is\n// CHECK-constrained to have both android + ios set, and the link's module/route are NOT NULL.\nexport interface SnapshotMicrofrontendMobile {\n code: string;\n name: string;\n remoteEntryAndroid: string;\n remoteEntryIos: string;\n exposedModule: string;\n routePrefix: string;\n}\n// Per-platform microfrontend routes — mirrors the PlatformCodes {web?, mobile?} bucket shape\nexport interface SnapshotMicrofrontends {\n web?: SnapshotMicrofrontendWeb;\n mobile?: SnapshotMicrofrontendMobile;\n}\nexport interface SnapshotFeature {\n code: string;\n name: string;\n lucideIcon: string;\n sfSymbol: string;\n materialSymbol: string;\n permissions: SnapshotPermission[];\n microfrontends: SnapshotMicrofrontends;\n}\nexport interface SnapshotApp {\n code: string;\n name: string;\n icon: string;\n sortOrder: number;\n features: string[];\n}\n// Also the shape provisioned to core as a role stub (the template's code is the durable org-role link)\nexport interface SnapshotRoleTemplate {\n name: string;\n code: string;\n // featureCode -> per-platform granted permission codes\n features: FeatureUnlocks;\n}\n// A plan is a lock overlay: the feature-permissions it UNLOCKS per platform (everything else renders locked).\n// Apps are derived from these.\nexport interface SnapshotPlan {\n code: string;\n name: string;\n isCustom: boolean;\n maxBusinessUnits: number | null;\n unlockedPermissions: FeatureUnlocks;\n}\nexport interface SnapshotBusiness {\n name: string;\n apps: SnapshotApp[];\n // Keyed by template code — the same key org roles link to\n roleTemplates: Record<string, SnapshotRoleTemplate>;\n plans: Record<string, SnapshotPlan>;\n}\nexport interface VersionSnapshot {\n // Shape revision hook for future migrations (absent = pre-versioned snapshots)\n schemaVersion?: number;\n features: Record<string, SnapshotFeature>;\n businesses: Record<string, SnapshotBusiness>;\n}\n\n// The current snapshot shape revision written by the cloud snapshot builder\nexport const SNAPSHOT_SCHEMA_VERSION = 1;\n\n// Why a permission/feature is locked: PLAN (org's plan doesn't unlock it) or BU (this BU restricts it)\nexport type LockReason = 'PLAN' | 'BU';\n\n// A catalog permission: its lock state + reason + (when plan-locked) the plans that would unlock it (upsell)\nexport interface CatalogPermission {\n code: string;\n locked: boolean;\n lockReason: LockReason | null;\n unlockPlans: string[];\n}\n\n// One resolved feature of the per-BU catalog\nexport interface FeatureCatalogEntry {\n code: string;\n name: string;\n lucideIcon: string | null;\n sfSymbol: string;\n materialSymbol: string;\n // Per-platform MF route — symmetric { web?, mobile? }; null when the feature has no MF for that platform.\n web: {\n remoteEntry: string;\n exposedModule: string;\n routePrefix: string;\n } | null;\n mobile: {\n remoteEntryAndroid: string;\n remoteEntryIos: string;\n exposedModule: string;\n routePrefix: string;\n } | null;\n appCode: string;\n appName: string;\n appIcon: string | null;\n appSortOrder: number;\n // Feature-level lock is explicit — plan non-membership or a BU whole-platform lock (never derived from\n // permission-code locks, which only disable individual actions)\n locked: boolean;\n lockReason: LockReason | null;\n // Plans (in the business) that would unlock the feature when it's plan-locked — for upsell\n unlockPlans: string[];\n permissions: CatalogPermission[];\n}\n\n// Role template pushed to core for provisioning — identical to the snapshot template shape\nexport type RoleItem = SnapshotRoleTemplate;\n","import { isBuLockedOnPlatform, isPlanMember } from './catalog.builder';\nimport { type BuFeatureLocks, PLATFORMS, type PlatformBucket, type SnapshotPlan, type VersionSnapshot } from './types';\n\n// A single (permission, platform) cell. null ⇒ the feature doesn't ship on that platform.\nexport interface BuMatrixCell {\n inPlan: boolean; // the org's plan unlocks this (feature, platform, permission)\n selected: boolean; // the BU currently has it enabled (never true when !inPlan)\n availableIn: string[]; // other plan names that unlock it — upsell; only when !inPlan\n}\n\nexport interface BuMatrixPermission {\n code: string;\n label: string;\n web: BuMatrixCell | null;\n mobile: BuMatrixCell | null;\n}\n\nexport interface BuMatrixFeature {\n code: string;\n name: string;\n icon: string | null;\n platforms: PlatformBucket[]; // platforms the feature ships on\n inPlan: boolean; // FEATURE-level: is this feature a member of the org's plan at all?\n availableIn: string[]; // plans that include the feature — upsell when !inPlan\n permissions: BuMatrixPermission[];\n}\n\nexport interface BuMatrixApp {\n code: string;\n name: string;\n icon: string | null;\n unlockedCount: number; // (feature × platform × permission) cells the plan unlocks\n totalCount: number; // all possible cells in this app\n features: BuMatrixFeature[];\n}\n\nexport interface BuMatrix {\n plan: { code: string; name: string };\n apps: BuMatrixApp[];\n // The stored BU deny-list verbatim — lock editors seed from this, never from derived selected flags\n locks: BuFeatureLocks;\n}\n\n// Builds the full apps/features/permissions matrix from the version snapshot — NOT filtered to plan members.\n// Every app/feature/permission renders; plan-locked items carry inPlan=false + availableIn (the upsell plans).\n// buLocks layers the BU's deny-list within the plan (undefined or absent entries ⇒ the full plan is selected).\nexport function buildBuMatrix(\n snapshot: VersionSnapshot,\n businessCode: string | undefined,\n planCode: string | undefined,\n buLocks: BuFeatureLocks | undefined,\n): BuMatrix {\n const business = businessCode ? snapshot.businesses?.[businessCode] : undefined;\n const plans = business?.plans ?? {};\n const plan = planCode ? plans[planCode] : undefined;\n const planMeta = { code: planCode ?? '', name: plan?.name ?? planCode ?? '' };\n const locks = buLocks ?? {};\n if (!business || !plan) return { plan: planMeta, apps: [], locks };\n\n const apps: BuMatrixApp[] = [];\n for (const app of business.apps) {\n let unlockedCount = 0;\n let totalCount = 0;\n const features: BuMatrixFeature[] = [];\n\n for (const code of app.features) {\n const feature = snapshot.features?.[code];\n if (!feature) continue;\n const platforms = PLATFORMS.filter((p) => !!feature.microfrontends?.[p]);\n if (platforms.length === 0) continue;\n\n const membership = plan.unlockedPermissions?.[code];\n const featureInPlan = isPlanMember(membership);\n const buEntry = buLocks?.[code];\n\n const permissions: BuMatrixPermission[] = (feature.permissions ?? [])\n .filter((p) => p.isGlobal || p.businesses.includes(businessCode ?? ''))\n .map((p) => {\n const cell = (plat: PlatformBucket): BuMatrixCell | null => {\n if (!platforms.includes(plat)) return null;\n const planCodes = membership?.[plat];\n const inPlan = featureInPlan && planCodes !== undefined && planCodes.includes(p.code);\n // Deny-list: an in-plan cell is selected unless the BU locks it on this platform\n const selected = inPlan && !isBuLockedOnPlatform(buEntry, plat, p.code);\n const availableIn = inPlan ? [] : plansUnlockingPerm(plans, code, p.code, plat, planCode);\n totalCount += 1;\n if (inPlan) unlockedCount += 1;\n return { inPlan, selected, availableIn };\n };\n return { code: p.code, label: p.label, web: cell('web'), mobile: cell('mobile') };\n });\n\n features.push({\n code: feature.code,\n name: feature.name,\n icon: feature.lucideIcon ?? null,\n platforms,\n inPlan: featureInPlan,\n availableIn: featureInPlan ? [] : plansIncludingFeature(plans, code, planCode),\n permissions,\n });\n }\n\n apps.push({ code: app.code, name: app.name, icon: app.icon ?? null, unlockedCount, totalCount, features });\n }\n\n return { plan: planMeta, apps, locks };\n}\n\n// Names of other plans (excluding the org's own) that unlock this feature+permission on the given platform\nfunction plansUnlockingPerm(\n plans: Record<string, SnapshotPlan>,\n featureCode: string,\n permCode: string,\n platform: PlatformBucket,\n excludeCode: string | undefined,\n): string[] {\n const names: string[] = [];\n for (const [code, p] of Object.entries(plans)) {\n if (code === excludeCode) continue;\n if ((p.unlockedPermissions?.[featureCode]?.[platform] ?? []).includes(permCode)) names.push(p.name);\n }\n return names;\n}\n\n// Names of other plans (excluding the org's own) that include this feature at all (membership) — feature-level upsell\nfunction plansIncludingFeature(\n plans: Record<string, SnapshotPlan>,\n featureCode: string,\n excludeCode: string | undefined,\n): string[] {\n const names: string[] = [];\n for (const [code, p] of Object.entries(plans)) {\n if (code === excludeCode) continue;\n if (isPlanMember(p.unlockedPermissions?.[featureCode])) names.push(p.name);\n }\n return names;\n}\n","import { type FeatureUnlocks, PLATFORMS, type PlatformCodes, type PlatformDenyCodes } from './types';\n\n// Grants removed from a base template — same deny algebra as BU locks\nexport type RevokedGrants = Record<string, PlatformDenyCodes>;\n\nexport interface ComposeRoleGrantsParams {\n baseFeatures: FeatureUnlocks | undefined;\n additions: FeatureUnlocks;\n revoked: RevokedGrants | undefined;\n}\n\n// Deduped union of two optional code lists — undefined on both sides means no platform membership\nfunction unionBucket(base: string[] | undefined, add: string[] | undefined): string[] | undefined {\n if (base === undefined && add === undefined) return undefined;\n return [...new Set([...(base ?? []), ...(add ?? [])])];\n}\n\n// Composes a based custom role's effective grants: merge(base ∪ additions) − revoked (design doc §10).\n// Platform membership survives a code revoke (may leave [] = view-only); a null revoke removes the\n// platform entirely; a feature with no surviving platform disappears. Inputs are never mutated.\nexport function composeRoleGrants(params: ComposeRoleGrantsParams): FeatureUnlocks {\n const { baseFeatures, additions, revoked } = params;\n\n const result: FeatureUnlocks = {};\n const featureCodes = new Set([...Object.keys(baseFeatures ?? {}), ...Object.keys(additions ?? {})]);\n\n for (const code of featureCodes) {\n const base = baseFeatures?.[code] ?? {};\n const add = additions?.[code] ?? {};\n const revokes = revoked?.[code];\n\n const composed: PlatformCodes = {};\n for (const bucket of PLATFORMS) {\n const merged = unionBucket(base[bucket], add[bucket]);\n if (merged === undefined) continue;\n const revoke = revokes?.[bucket];\n // null revokes the whole platform (membership + all codes); string[] subtracts codes but keeps membership\n if (revoke === null) continue;\n composed[bucket] = revoke === undefined ? merged : merged.filter((c) => !revoke.includes(c));\n }\n\n // A feature with no surviving platform membership disappears from the effective set\n if (composed.web === undefined && composed.mobile === undefined) continue;\n result[code] = composed;\n }\n\n return result;\n}\n","import { buildBuCatalog } from './catalog.builder';\nimport type { BuFeatureLocks, FeatureUnlocks, LockReason, PlatformBucket, VersionSnapshot } from './types';\n\n// Client surface requesting resolution — web picks the WEB route block, ios/android pick the MOBILE block per-OS\nexport type ClientPlatform = 'web' | 'ios' | 'android';\n\n// A granted permission that is locked, with why and which plans would unlock it (for upsell)\nexport interface LockedPermission {\n code: string;\n reason: LockReason | null;\n unlockPlans: string[];\n}\n\nexport interface PermissionFeature {\n code: string;\n name: string;\n lucideIcon: string | null;\n sfSymbol: string;\n materialSymbol: string;\n permissions: string[];\n // Lock overlay (for upsell): feature-level locked + reason + unlock plans, and the granted-but-locked permissions\n locked: boolean;\n lockReason: LockReason | null;\n unlockPlans: string[];\n lockedPermissions: LockedPermission[];\n route: {\n remoteEntry: string;\n exposedModule: string;\n routePrefix: string;\n };\n appCode: string;\n appName: string;\n appIcon: string | null;\n appSortOrder: number;\n}\n\nexport interface ResolveUserFeaturesParams {\n snapshot: VersionSnapshot;\n businessCode: string;\n planCode: string | undefined;\n // undefined = nothing BU-locked (the full plan is available)\n buLocks: BuFeatureLocks | undefined;\n // The user's composed role grants: featureCode -> { web?: [permCode…], mobile?: [permCode…] }\n roleFeatures: FeatureUnlocks;\n platform: ClientPlatform;\n}\n\n// Resolves the features + MF config a user sees at a BU: plan ∧ BU catalog intersected with the role's grants.\n// platform picks which microfrontend block flows into PermissionFeature.route:\n// 'web' → WEB block (remoteEntry + exposedModule + routePrefix)\n// 'ios' → MOBILE block, remoteEntry = remoteEntryIos\n// 'android' → MOBILE block, remoteEntry = remoteEntryAndroid\n// Features missing the requested platform's block are filtered out.\nexport function resolveUserFeatures(params: ResolveUserFeaturesParams): PermissionFeature[] {\n const { snapshot, businessCode, planCode, buLocks, roleFeatures, platform } = params;\n\n // Plan unlocks, BU locks, and role grants are all stored per platform; resolve only the requesting\n // surface's bucket. web → 'web'; ios/android → 'mobile'. (platform still drives the per-OS route below.)\n const bucket: PlatformBucket = platform === 'web' ? 'web' : 'mobile';\n\n // Plan ∧ BU overlay for this bucket — emits EVERY business feature (plan non-members come out fully locked)\n const catalog = buildBuCatalog(snapshot, businessCode, planCode, buLocks, bucket);\n const catalogMap = new Map(catalog.map((f) => [f.code, f]));\n\n // Granted permission set per feature, taking only this platform's grants\n const grantedFeatures = new Map<string, Set<string>>();\n for (const [code, grant] of Object.entries(roleFeatures ?? {})) {\n // Membership is the gate: undefined = not a member on this platform; [] = member with no actions (view-only)\n const granted = grant?.[bucket];\n if (granted === undefined) continue;\n if (!grantedFeatures.has(code)) grantedFeatures.set(code, new Set());\n for (const perm of granted) grantedFeatures.get(code)?.add(perm);\n }\n\n // Cross-reference the granted features with the catalog to build the response\n const features: PermissionFeature[] = [];\n for (const [code, permsSet] of grantedFeatures) {\n const catalogEntry = catalogMap.get(code);\n if (!catalogEntry) continue;\n\n const route = pickRouteForPlatform(catalogEntry, platform);\n // Feature isn't published to this platform — omit so client doesn't see an unloadable tile.\n if (!route) continue;\n\n // Plan/BU lock a subset of permissions; surface which GRANTED ones are locked + why + how to unlock (upsell)\n const permByCode = new Map((catalogEntry.permissions ?? []).map((p) => [p.code, p]));\n const grantedPerms = [...permsSet];\n const lockedPermissions: LockedPermission[] = grantedPerms\n .map((c) => permByCode.get(c))\n .filter((p): p is NonNullable<typeof p> => !!p?.locked)\n .map((p) => ({ code: p.code, reason: p.lockReason ?? null, unlockPlans: p.unlockPlans ?? [] }));\n\n features.push({\n code,\n name: catalogEntry.name,\n lucideIcon: catalogEntry.lucideIcon,\n sfSymbol: catalogEntry.sfSymbol,\n materialSymbol: catalogEntry.materialSymbol,\n permissions: grantedPerms,\n locked: catalogEntry.locked ?? false,\n lockReason: catalogEntry.lockReason ?? null,\n unlockPlans: catalogEntry.unlockPlans ?? [],\n lockedPermissions,\n route,\n appCode: catalogEntry.appCode,\n appName: catalogEntry.appName,\n appIcon: catalogEntry.appIcon,\n appSortOrder: catalogEntry.appSortOrder,\n });\n }\n\n return features;\n}\n\n// Selects the route block from a catalog entry for the requested platform.\n// Returns null when the catalog entry doesn't publish to that platform.\nexport function pickRouteForPlatform(\n entry: {\n web: {\n remoteEntry: string;\n exposedModule: string;\n routePrefix: string;\n } | null;\n mobile: {\n remoteEntryAndroid: string;\n remoteEntryIos: string;\n exposedModule: string;\n routePrefix: string;\n } | null;\n },\n platform: ClientPlatform,\n): { remoteEntry: string; exposedModule: string; routePrefix: string } | null {\n if (platform === 'ios' || platform === 'android') {\n if (!entry.mobile) return null;\n return {\n remoteEntry: platform === 'ios' ? entry.mobile.remoteEntryIos : entry.mobile.remoteEntryAndroid,\n exposedModule: entry.mobile.exposedModule,\n routePrefix: entry.mobile.routePrefix,\n };\n }\n // Web\n if (!entry.web) return null;\n return {\n remoteEntry: entry.web.remoteEntry,\n exposedModule: entry.web.exposedModule,\n routePrefix: entry.web.routePrefix,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;ACgBO,SAASA,eACdC,UACAC,cACAC,UACAC,SACAC,QAAsB;AAEtB,MAAI,CAACH,aAAc,QAAO,CAAA;AAC1B,QAAMI,WAAWL,SAASM,aAAaL,YAAAA;AACvC,MAAI,CAACI,SAAU,QAAO,CAAA;AACtB,QAAME,OAAOL,WAAWG,SAASG,QAAQN,QAAAA,IAAYO;AACrD,QAAMD,QAAQH,SAASG,SAAS,CAAC;AAEjC,QAAME,UAAiC,CAAA;AACvC,aAAWC,OAAON,SAASO,MAAM;AAE/B,UAAMC,sBAAsBF,IAAIG,SAC7BC,IAAI,CAACC,SAAShB,SAASc,WAAWE,IAAAA,CAAK,EACvCC,OAAO,CAACC,MAA4B,CAAC,CAACA,KAAK,CAAC,EAAEA,EAAEC,gBAAgBC,OAAOF,EAAEC,gBAAgBE,OAAK;AAEjG,QAAIR,oBAAoBS,WAAW,EAAG;AAItC,eAAWC,WAAWV,qBAAqB;AACzC,YAAMW,aAAajB,MAAMkB,sBAAsBF,QAAQP,IAAI;AAG3D,YAAMI,MAAMG,QAAQJ,gBAAgBC;AACpC,YAAMC,SAASE,QAAQJ,gBAAgBE;AAEvC,YAAMK,cAAcC,iBAAiBJ,SAAStB,cAAcuB,YAAYrB,SAASK,OAAOJ,MAAAA;AAIxF,YAAMwB,iBAAiBJ,aAAapB,MAAAA,MAAYK;AAChD,YAAMoB,mBAAmB1B,UAAUoB,QAAQP,IAAI,IAAIZ,MAAAA,MAAY;AAC/D,YAAM0B,SAAS,CAACF,kBAAkBC;AAClC,YAAME,aAAgC,CAACH,iBAAiB,SAASC,mBAAmB,OAAO;AAC3F,YAAMG,cAAcD,eAAe,SAASE,sBAAsBzB,OAAOe,QAAQP,MAAMZ,MAAAA,IAAU,CAAA;AAEjGM,cAAQwB,KAAK;QACXlB,MAAMO,QAAQP;QACdmB,MAAMZ,QAAQY;QACdC,YAAYb,QAAQa,cAAc;QAClCC,UAAUd,QAAQc,YAAY;QAC9BC,gBAAgBf,QAAQe,kBAAkB;QAC1ClB,KAAKA,MACD;UACEmB,aAAanB,IAAImB,eAAe;UAChCC,eAAepB,IAAIoB,iBAAiB;UACpCC,aAAarB,IAAIqB,eAAe;QAClC,IACA;QACJpB,QAAQA,SACJ;UACEqB,oBAAoBrB,OAAOqB,sBAAsB;UACjDC,gBAAgBtB,OAAOsB,kBAAkB;UACzCH,eAAenB,OAAOmB,iBAAiB;UACvCC,aAAapB,OAAOoB,eAAe;QACrC,IACA;QACJG,SAASjC,IAAIK;QACb6B,SAASlC,IAAIwB;QACbW,SAASnC,IAAIoC,QAAQ;QACrBC,cAAcrC,IAAIsC,aAAa;QAC/BnB;QACAC;QACAC;QACAN;MACF,CAAA;IACF;EACF;AACA,SAAOhB;AACT;AA1EgBX;AA6ET,SAASmD,aAAaC,OAAgC;AAC3D,SAAO,CAAC,CAACA,UAAUA,MAAM/B,QAAQX,UAAa0C,MAAM9B,WAAWZ;AACjE;AAFgByC;AAMT,SAASE,qBACdD,OACAE,UACArC,MAAY;AAEZ,QAAMsC,QAAQH,QAAQE,QAAAA;AACtB,SAAOC,UAAU,SAASA,OAAOC,SAASvC,IAAAA,KAAS;AACrD;AAPgBoC;AAWhB,SAASzB,iBACPJ,SACAtB,cACAuD,gBACArD,SACAK,OACAJ,QAAsB;AAEtB,QAAMqD,eAAe,IAAIC,IAAIF,iBAAiBpD,MAAAA,KAAW,CAAA,CAAE;AAC3D,QAAMuD,YAAYxD,UAAUoB,QAAQP,IAAI;AAExC,UAAQO,QAAQG,eAAe,CAAA,GAC5BT,OAAO,CAAC2C,MAAMA,EAAEC,YAAYD,EAAEtD,WAAWiD,SAAStD,YAAAA,CAAAA,EAClDc,IAAI,CAAC6C,MAAAA;AACJ,UAAME,aAAaL,aAAaM,IAAIH,EAAE5C,IAAI;AAC1C,UAAMgD,WAAW,CAACZ,qBAAqBO,WAAWvD,QAAQwD,EAAE5C,IAAI;AAChE,UAAMc,SAAS,CAACgC,cAAc,CAACE;AAE/B,UAAMjC,aAAgC,CAAC+B,aAAa,SAAS,CAACE,WAAW,OAAO;AAChF,UAAMhC,cAAcD,eAAe,SAASkC,yBAAyBzD,OAAOe,QAAQP,MAAM4C,EAAE5C,MAAMZ,MAAAA,IAAU,CAAA;AAC5G,WAAO;MAAEY,MAAM4C,EAAE5C;MAAMc;MAAQC;MAAYC;IAAY;EACzD,CAAA;AACJ;AAtBSL;AAyBT,SAASsC,yBACPzD,OACA0D,aACAC,UACA/D,QAAsB;AAEtB,QAAMgE,SAAmB,CAAA;AACzB,aAAW,CAACpD,MAAMT,IAAAA,KAAS8D,OAAOC,QAAQ9D,KAAAA,GAAQ;AAChD,QAAID,KAAKkB,sBAAsByC,WAAAA,IAAe9D,MAAAA,GAASmD,SAASY,QAAAA,EAAWC,QAAOlC,KAAKlB,IAAAA;EACzF;AACA,SAAOoD;AACT;AAXSH;AAcT,SAAShC,sBACPzB,OACA0D,aACA9D,QAAsB;AAEtB,QAAMgE,SAAmB,CAAA;AACzB,aAAW,CAACpD,MAAMT,IAAAA,KAAS8D,OAAOC,QAAQ9D,KAAAA,GAAQ;AAChD,QAAID,KAAKkB,sBAAsByC,WAAAA,IAAe9D,MAAAA,MAAYK,OAAW2D,QAAOlC,KAAKlB,IAAAA;EACnF;AACA,SAAOoD;AACT;AAVSnC;AAaF,SAASsC,aAAavE,UAA2BC,cAAgC;AACtF,MAAI,CAACA,aAAc,QAAO,CAAA;AAC1B,QAAMI,WAAWL,SAASM,aAAaL,YAAAA;AACvC,MAAI,CAACI,SAAU,QAAO,CAAA;AACtB,SAAOgE,OAAOG,OAAOnE,SAASoE,iBAAiB,CAAC,CAAA;AAClD;AALgBF;;;AC7JT,IAAMG,YAA8B;EAAC;EAAO;;AAmG5C,IAAMC,0BAA0B;;;AC1DhC,SAASC,cACdC,UACAC,cACAC,UACAC,SAAmC;AAEnC,QAAMC,WAAWH,eAAeD,SAASK,aAAaJ,YAAAA,IAAgBK;AACtE,QAAMC,QAAQH,UAAUG,SAAS,CAAC;AAClC,QAAMC,OAAON,WAAWK,MAAML,QAAAA,IAAYI;AAC1C,QAAMG,WAAW;IAAEC,MAAMR,YAAY;IAAIS,MAAMH,MAAMG,QAAQT,YAAY;EAAG;AAC5E,QAAMU,QAAQT,WAAW,CAAC;AAC1B,MAAI,CAACC,YAAY,CAACI,KAAM,QAAO;IAAEA,MAAMC;IAAUI,MAAM,CAAA;IAAID;EAAM;AAEjE,QAAMC,OAAsB,CAAA;AAC5B,aAAWC,OAAOV,SAASS,MAAM;AAC/B,QAAIE,gBAAgB;AACpB,QAAIC,aAAa;AACjB,UAAMC,WAA8B,CAAA;AAEpC,eAAWP,QAAQI,IAAIG,UAAU;AAC/B,YAAMC,UAAUlB,SAASiB,WAAWP,IAAAA;AACpC,UAAI,CAACQ,QAAS;AACd,YAAMC,YAAYC,UAAUC,OAAO,CAACC,MAAM,CAAC,CAACJ,QAAQK,iBAAiBD,CAAAA,CAAE;AACvE,UAAIH,UAAUK,WAAW,EAAG;AAE5B,YAAMC,aAAajB,KAAKkB,sBAAsBhB,IAAAA;AAC9C,YAAMiB,gBAAgBC,aAAaH,UAAAA;AACnC,YAAMI,UAAU1B,UAAUO,IAAAA;AAE1B,YAAMoB,eAAqCZ,QAAQY,eAAe,CAAA,GAC/DT,OAAO,CAACC,MAAMA,EAAES,YAAYT,EAAEjB,WAAW2B,SAAS/B,gBAAgB,EAAA,CAAA,EAClEgC,IAAI,CAACX,MAAAA;AACJ,cAAMY,OAAO,wBAACC,SAAAA;AACZ,cAAI,CAAChB,UAAUa,SAASG,IAAAA,EAAO,QAAO;AACtC,gBAAMC,YAAYX,aAAaU,IAAAA;AAC/B,gBAAME,SAASV,iBAAiBS,cAAc9B,UAAa8B,UAAUJ,SAASV,EAAEZ,IAAI;AAEpF,gBAAM4B,WAAWD,UAAU,CAACE,qBAAqBV,SAASM,MAAMb,EAAEZ,IAAI;AACtE,gBAAM8B,cAAcH,SAAS,CAAA,IAAKI,mBAAmBlC,OAAOG,MAAMY,EAAEZ,MAAMyB,MAAMjC,QAAAA;AAChFc,wBAAc;AACd,cAAIqB,OAAQtB,kBAAiB;AAC7B,iBAAO;YAAEsB;YAAQC;YAAUE;UAAY;QACzC,GAVa;AAWb,eAAO;UAAE9B,MAAMY,EAAEZ;UAAMgC,OAAOpB,EAAEoB;UAAOC,KAAKT,KAAK,KAAA;UAAQU,QAAQV,KAAK,QAAA;QAAU;MAClF,CAAA;AAEFjB,eAAS4B,KAAK;QACZnC,MAAMQ,QAAQR;QACdC,MAAMO,QAAQP;QACdmC,MAAM5B,QAAQ6B,cAAc;QAC5B5B;QACAkB,QAAQV;QACRa,aAAab,gBAAgB,CAAA,IAAKqB,uBAAsBzC,OAAOG,MAAMR,QAAAA;QACrE4B;MACF,CAAA;IACF;AAEAjB,SAAKgC,KAAK;MAAEnC,MAAMI,IAAIJ;MAAMC,MAAMG,IAAIH;MAAMmC,MAAMhC,IAAIgC,QAAQ;MAAM/B;MAAeC;MAAYC;IAAS,CAAA;EAC1G;AAEA,SAAO;IAAET,MAAMC;IAAUI;IAAMD;EAAM;AACvC;AA7DgBb;AAgEhB,SAAS0C,mBACPlC,OACA0C,aACAC,UACAC,UACAC,aAA+B;AAE/B,QAAMC,QAAkB,CAAA;AACxB,aAAW,CAAC3C,MAAMY,CAAAA,KAAMgC,OAAOC,QAAQhD,KAAAA,GAAQ;AAC7C,QAAIG,SAAS0C,YAAa;AAC1B,SAAK9B,EAAEI,sBAAsBuB,WAAAA,IAAeE,QAAAA,KAAa,CAAA,GAAInB,SAASkB,QAAAA,EAAWG,OAAMR,KAAKvB,EAAEX,IAAI;EACpG;AACA,SAAO0C;AACT;AAbSZ;AAgBT,SAASO,uBACPzC,OACA0C,aACAG,aAA+B;AAE/B,QAAMC,QAAkB,CAAA;AACxB,aAAW,CAAC3C,MAAMY,CAAAA,KAAMgC,OAAOC,QAAQhD,KAAAA,GAAQ;AAC7C,QAAIG,SAAS0C,YAAa;AAC1B,QAAIxB,aAAaN,EAAEI,sBAAsBuB,WAAAA,CAAY,EAAGI,OAAMR,KAAKvB,EAAEX,IAAI;EAC3E;AACA,SAAO0C;AACT;AAXSL,OAAAA,wBAAAA;;;AClHT,SAASQ,YAAYC,MAA4BC,KAAyB;AACxE,MAAID,SAASE,UAAaD,QAAQC,OAAW,QAAOA;AACpD,SAAO;OAAI,oBAAIC,IAAI;SAAKH,QAAQ,CAAA;SAASC,OAAO,CAAA;KAAI;;AACtD;AAHSF;AAQF,SAASK,kBAAkBC,QAA+B;AAC/D,QAAM,EAAEC,cAAcC,WAAWC,QAAO,IAAKH;AAE7C,QAAMI,SAAyB,CAAC;AAChC,QAAMC,eAAe,oBAAIP,IAAI;OAAIQ,OAAOC,KAAKN,gBAAgB,CAAC,CAAA;OAAOK,OAAOC,KAAKL,aAAa,CAAC,CAAA;GAAG;AAElG,aAAWM,QAAQH,cAAc;AAC/B,UAAMV,OAAOM,eAAeO,IAAAA,KAAS,CAAC;AACtC,UAAMZ,MAAMM,YAAYM,IAAAA,KAAS,CAAC;AAClC,UAAMC,UAAUN,UAAUK,IAAAA;AAE1B,UAAME,WAA0B,CAAC;AACjC,eAAWC,UAAUC,WAAW;AAC9B,YAAMC,SAASnB,YAAYC,KAAKgB,MAAAA,GAASf,IAAIe,MAAAA,CAAO;AACpD,UAAIE,WAAWhB,OAAW;AAC1B,YAAMiB,SAASL,UAAUE,MAAAA;AAEzB,UAAIG,WAAW,KAAM;AACrBJ,eAASC,MAAAA,IAAUG,WAAWjB,SAAYgB,SAASA,OAAOE,OAAO,CAACC,MAAM,CAACF,OAAOG,SAASD,CAAAA,CAAAA;IAC3F;AAGA,QAAIN,SAASQ,QAAQrB,UAAaa,SAASS,WAAWtB,OAAW;AACjEO,WAAOI,IAAAA,IAAQE;EACjB;AAEA,SAAON;AACT;AA3BgBL;;;ACiCT,SAASqB,oBAAoBC,QAAiC;AACnE,QAAM,EAAEC,UAAUC,cAAcC,UAAUC,SAASC,cAAcC,SAAQ,IAAKN;AAI9E,QAAMO,SAAyBD,aAAa,QAAQ,QAAQ;AAG5D,QAAME,UAAUC,eAAeR,UAAUC,cAAcC,UAAUC,SAASG,MAAAA;AAC1E,QAAMG,aAAa,IAAIC,IAAIH,QAAQI,IAAI,CAACC,MAAM;IAACA,EAAEC;IAAMD;GAAE,CAAA;AAGzD,QAAME,kBAAkB,oBAAIJ,IAAAA;AAC5B,aAAW,CAACG,MAAME,KAAAA,KAAUC,OAAOC,QAAQb,gBAAgB,CAAC,CAAA,GAAI;AAE9D,UAAMc,UAAUH,QAAQT,MAAAA;AACxB,QAAIY,YAAYC,OAAW;AAC3B,QAAI,CAACL,gBAAgBM,IAAIP,IAAAA,EAAOC,iBAAgBO,IAAIR,MAAM,oBAAIS,IAAAA,CAAAA;AAC9D,eAAWC,QAAQL,QAASJ,iBAAgBU,IAAIX,IAAAA,GAAOY,IAAIF,IAAAA;EAC7D;AAGA,QAAMG,WAAgC,CAAA;AACtC,aAAW,CAACb,MAAMc,QAAAA,KAAab,iBAAiB;AAC9C,UAAMc,eAAenB,WAAWe,IAAIX,IAAAA;AACpC,QAAI,CAACe,aAAc;AAEnB,UAAMC,QAAQC,qBAAqBF,cAAcvB,QAAAA;AAEjD,QAAI,CAACwB,MAAO;AAGZ,UAAME,aAAa,IAAIrB,KAAKkB,aAAaI,eAAe,CAAA,GAAIrB,IAAI,CAACsB,MAAM;MAACA,EAAEpB;MAAMoB;KAAE,CAAA;AAClF,UAAMC,eAAe;SAAIP;;AACzB,UAAMQ,oBAAwCD,aAC3CvB,IAAI,CAACyB,MAAML,WAAWP,IAAIY,CAAAA,CAAAA,EAC1BC,OAAO,CAACJ,MAAkC,CAAC,CAACA,GAAGK,MAAAA,EAC/C3B,IAAI,CAACsB,OAAO;MAAEpB,MAAMoB,EAAEpB;MAAM0B,QAAQN,EAAEO,cAAc;MAAMC,aAAaR,EAAEQ,eAAe,CAAA;IAAG,EAAA;AAE9Ff,aAASgB,KAAK;MACZ7B;MACA8B,MAAMf,aAAae;MACnBC,YAAYhB,aAAagB;MACzBC,UAAUjB,aAAaiB;MACvBC,gBAAgBlB,aAAakB;MAC7Bd,aAAaE;MACbI,QAAQV,aAAaU,UAAU;MAC/BE,YAAYZ,aAAaY,cAAc;MACvCC,aAAab,aAAaa,eAAe,CAAA;MACzCN;MACAN;MACAkB,SAASnB,aAAamB;MACtBC,SAASpB,aAAaoB;MACtBC,SAASrB,aAAaqB;MACtBC,cAActB,aAAasB;IAC7B,CAAA;EACF;AAEA,SAAOxB;AACT;AA3DgB5B;AA+DT,SAASgC,qBACdqB,OAaA9C,UAAwB;AAExB,MAAIA,aAAa,SAASA,aAAa,WAAW;AAChD,QAAI,CAAC8C,MAAMC,OAAQ,QAAO;AAC1B,WAAO;MACLC,aAAahD,aAAa,QAAQ8C,MAAMC,OAAOE,iBAAiBH,MAAMC,OAAOG;MAC7EC,eAAeL,MAAMC,OAAOI;MAC5BC,aAAaN,MAAMC,OAAOK;IAC5B;EACF;AAEA,MAAI,CAACN,MAAMO,IAAK,QAAO;AACvB,SAAO;IACLL,aAAaF,MAAMO,IAAIL;IACvBG,eAAeL,MAAMO,IAAIF;IACzBC,aAAaN,MAAMO,IAAID;EACzB;AACF;AA/BgB3B;","names":["buildBuCatalog","snapshot","businessCode","planCode","buLocks","bucket","business","businesses","plan","plans","undefined","catalog","app","apps","businessAppFeatures","features","map","code","filter","f","microfrontends","web","mobile","length","feature","membership","unlockedPermissions","permissions","buildPermissions","memberOnBucket","buPlatformLocked","locked","lockReason","unlockPlans","plansIncludingFeature","push","name","lucideIcon","sfSymbol","materialSymbol","remoteEntry","exposedModule","routePrefix","remoteEntryAndroid","remoteEntryIos","appCode","appName","appIcon","icon","appSortOrder","sortOrder","isPlanMember","entry","isBuLockedOnPlatform","platform","locks","includes","planMembership","planUnlocked","Set","lockEntry","p","isGlobal","planAllows","has","buAllows","plansUnlockingPermission","featureCode","permCode","result","Object","entries","buildBuRoles","values","roleTemplates","PLATFORMS","SNAPSHOT_SCHEMA_VERSION","buildBuMatrix","snapshot","businessCode","planCode","buLocks","business","businesses","undefined","plans","plan","planMeta","code","name","locks","apps","app","unlockedCount","totalCount","features","feature","platforms","PLATFORMS","filter","p","microfrontends","length","membership","unlockedPermissions","featureInPlan","isPlanMember","buEntry","permissions","isGlobal","includes","map","cell","plat","planCodes","inPlan","selected","isBuLockedOnPlatform","availableIn","plansUnlockingPerm","label","web","mobile","push","icon","lucideIcon","plansIncludingFeature","featureCode","permCode","platform","excludeCode","names","Object","entries","unionBucket","base","add","undefined","Set","composeRoleGrants","params","baseFeatures","additions","revoked","result","featureCodes","Object","keys","code","revokes","composed","bucket","PLATFORMS","merged","revoke","filter","c","includes","web","mobile","resolveUserFeatures","params","snapshot","businessCode","planCode","buLocks","roleFeatures","platform","bucket","catalog","buildBuCatalog","catalogMap","Map","map","f","code","grantedFeatures","grant","Object","entries","granted","undefined","has","set","Set","perm","get","add","features","permsSet","catalogEntry","route","pickRouteForPlatform","permByCode","permissions","p","grantedPerms","lockedPermissions","c","filter","locked","reason","lockReason","unlockPlans","push","name","lucideIcon","sfSymbol","materialSymbol","appCode","appName","appIcon","appSortOrder","entry","mobile","remoteEntry","remoteEntryIos","remoteEntryAndroid","exposedModule","routePrefix","web"]}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { P as PlatformBucket, B as BuFeatureLocks, V as VersionSnapshot, F as FeatureCatalogEntry, R as RoleItem, a as PlatformCodes, b as FeatureUnlocks, c as PlatformDenyCodes, L as LockReason } from './types-DQRwj5rr.cjs';
|
|
2
|
+
export { C as CatalogPermission, d as PLATFORMS, S as SNAPSHOT_SCHEMA_VERSION, e as SnapshotApp, f as SnapshotBusiness, g as SnapshotFeature, h as SnapshotMicrofrontendMobile, j as SnapshotMicrofrontendWeb, i as SnapshotMicrofrontends, k as SnapshotPermission, l as SnapshotPlan, m as SnapshotRoleTemplate } from './types-DQRwj5rr.cjs';
|
|
3
|
+
|
|
4
|
+
interface BuMatrixCell {
|
|
5
|
+
inPlan: boolean;
|
|
6
|
+
selected: boolean;
|
|
7
|
+
availableIn: string[];
|
|
8
|
+
}
|
|
9
|
+
interface BuMatrixPermission {
|
|
10
|
+
code: string;
|
|
11
|
+
label: string;
|
|
12
|
+
web: BuMatrixCell | null;
|
|
13
|
+
mobile: BuMatrixCell | null;
|
|
14
|
+
}
|
|
15
|
+
interface BuMatrixFeature {
|
|
16
|
+
code: string;
|
|
17
|
+
name: string;
|
|
18
|
+
icon: string | null;
|
|
19
|
+
platforms: PlatformBucket[];
|
|
20
|
+
inPlan: boolean;
|
|
21
|
+
availableIn: string[];
|
|
22
|
+
permissions: BuMatrixPermission[];
|
|
23
|
+
}
|
|
24
|
+
interface BuMatrixApp {
|
|
25
|
+
code: string;
|
|
26
|
+
name: string;
|
|
27
|
+
icon: string | null;
|
|
28
|
+
unlockedCount: number;
|
|
29
|
+
totalCount: number;
|
|
30
|
+
features: BuMatrixFeature[];
|
|
31
|
+
}
|
|
32
|
+
interface BuMatrix {
|
|
33
|
+
plan: {
|
|
34
|
+
code: string;
|
|
35
|
+
name: string;
|
|
36
|
+
};
|
|
37
|
+
apps: BuMatrixApp[];
|
|
38
|
+
locks: BuFeatureLocks;
|
|
39
|
+
}
|
|
40
|
+
declare function buildBuMatrix(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, buLocks: BuFeatureLocks | undefined): BuMatrix;
|
|
41
|
+
|
|
42
|
+
declare function buildBuCatalog(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, buLocks: BuFeatureLocks | undefined, bucket: PlatformBucket): FeatureCatalogEntry[];
|
|
43
|
+
declare function isPlanMember(entry: PlatformCodes | undefined): boolean;
|
|
44
|
+
declare function isBuLockedOnPlatform(entry: BuFeatureLocks[string] | undefined, platform: PlatformBucket, code: string): boolean;
|
|
45
|
+
declare function buildBuRoles(snapshot: VersionSnapshot, businessCode: string | undefined): RoleItem[];
|
|
46
|
+
|
|
47
|
+
type RevokedGrants = Record<string, PlatformDenyCodes>;
|
|
48
|
+
interface ComposeRoleGrantsParams {
|
|
49
|
+
baseFeatures: FeatureUnlocks | undefined;
|
|
50
|
+
additions: FeatureUnlocks;
|
|
51
|
+
revoked: RevokedGrants | undefined;
|
|
52
|
+
}
|
|
53
|
+
declare function composeRoleGrants(params: ComposeRoleGrantsParams): FeatureUnlocks;
|
|
54
|
+
|
|
55
|
+
type ClientPlatform = 'web' | 'ios' | 'android';
|
|
56
|
+
interface LockedPermission {
|
|
57
|
+
code: string;
|
|
58
|
+
reason: LockReason | null;
|
|
59
|
+
unlockPlans: string[];
|
|
60
|
+
}
|
|
61
|
+
interface PermissionFeature {
|
|
62
|
+
code: string;
|
|
63
|
+
name: string;
|
|
64
|
+
lucideIcon: string | null;
|
|
65
|
+
sfSymbol: string;
|
|
66
|
+
materialSymbol: string;
|
|
67
|
+
permissions: string[];
|
|
68
|
+
locked: boolean;
|
|
69
|
+
lockReason: LockReason | null;
|
|
70
|
+
unlockPlans: string[];
|
|
71
|
+
lockedPermissions: LockedPermission[];
|
|
72
|
+
route: {
|
|
73
|
+
remoteEntry: string;
|
|
74
|
+
exposedModule: string;
|
|
75
|
+
routePrefix: string;
|
|
76
|
+
};
|
|
77
|
+
appCode: string;
|
|
78
|
+
appName: string;
|
|
79
|
+
appIcon: string | null;
|
|
80
|
+
appSortOrder: number;
|
|
81
|
+
}
|
|
82
|
+
interface ResolveUserFeaturesParams {
|
|
83
|
+
snapshot: VersionSnapshot;
|
|
84
|
+
businessCode: string;
|
|
85
|
+
planCode: string | undefined;
|
|
86
|
+
buLocks: BuFeatureLocks | undefined;
|
|
87
|
+
roleFeatures: FeatureUnlocks;
|
|
88
|
+
platform: ClientPlatform;
|
|
89
|
+
}
|
|
90
|
+
declare function resolveUserFeatures(params: ResolveUserFeaturesParams): PermissionFeature[];
|
|
91
|
+
declare function pickRouteForPlatform(entry: {
|
|
92
|
+
web: {
|
|
93
|
+
remoteEntry: string;
|
|
94
|
+
exposedModule: string;
|
|
95
|
+
routePrefix: string;
|
|
96
|
+
} | null;
|
|
97
|
+
mobile: {
|
|
98
|
+
remoteEntryAndroid: string;
|
|
99
|
+
remoteEntryIos: string;
|
|
100
|
+
exposedModule: string;
|
|
101
|
+
routePrefix: string;
|
|
102
|
+
} | null;
|
|
103
|
+
}, platform: ClientPlatform): {
|
|
104
|
+
remoteEntry: string;
|
|
105
|
+
exposedModule: string;
|
|
106
|
+
routePrefix: string;
|
|
107
|
+
} | null;
|
|
108
|
+
|
|
109
|
+
export { BuFeatureLocks, type BuMatrix, type BuMatrixApp, type BuMatrixCell, type BuMatrixFeature, type BuMatrixPermission, type ClientPlatform, type ComposeRoleGrantsParams, FeatureCatalogEntry, FeatureUnlocks, LockReason, type LockedPermission, type PermissionFeature, PlatformBucket, PlatformCodes, PlatformDenyCodes, type ResolveUserFeaturesParams, type RevokedGrants, RoleItem, VersionSnapshot, buildBuCatalog, buildBuMatrix, buildBuRoles, composeRoleGrants, isBuLockedOnPlatform, isPlanMember, pickRouteForPlatform, resolveUserFeatures };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { P as PlatformBucket, B as BuFeatureLocks, V as VersionSnapshot, F as FeatureCatalogEntry, R as RoleItem, a as PlatformCodes, b as FeatureUnlocks, c as PlatformDenyCodes, L as LockReason } from './types-DQRwj5rr.js';
|
|
2
|
+
export { C as CatalogPermission, d as PLATFORMS, S as SNAPSHOT_SCHEMA_VERSION, e as SnapshotApp, f as SnapshotBusiness, g as SnapshotFeature, h as SnapshotMicrofrontendMobile, j as SnapshotMicrofrontendWeb, i as SnapshotMicrofrontends, k as SnapshotPermission, l as SnapshotPlan, m as SnapshotRoleTemplate } from './types-DQRwj5rr.js';
|
|
3
|
+
|
|
4
|
+
interface BuMatrixCell {
|
|
5
|
+
inPlan: boolean;
|
|
6
|
+
selected: boolean;
|
|
7
|
+
availableIn: string[];
|
|
8
|
+
}
|
|
9
|
+
interface BuMatrixPermission {
|
|
10
|
+
code: string;
|
|
11
|
+
label: string;
|
|
12
|
+
web: BuMatrixCell | null;
|
|
13
|
+
mobile: BuMatrixCell | null;
|
|
14
|
+
}
|
|
15
|
+
interface BuMatrixFeature {
|
|
16
|
+
code: string;
|
|
17
|
+
name: string;
|
|
18
|
+
icon: string | null;
|
|
19
|
+
platforms: PlatformBucket[];
|
|
20
|
+
inPlan: boolean;
|
|
21
|
+
availableIn: string[];
|
|
22
|
+
permissions: BuMatrixPermission[];
|
|
23
|
+
}
|
|
24
|
+
interface BuMatrixApp {
|
|
25
|
+
code: string;
|
|
26
|
+
name: string;
|
|
27
|
+
icon: string | null;
|
|
28
|
+
unlockedCount: number;
|
|
29
|
+
totalCount: number;
|
|
30
|
+
features: BuMatrixFeature[];
|
|
31
|
+
}
|
|
32
|
+
interface BuMatrix {
|
|
33
|
+
plan: {
|
|
34
|
+
code: string;
|
|
35
|
+
name: string;
|
|
36
|
+
};
|
|
37
|
+
apps: BuMatrixApp[];
|
|
38
|
+
locks: BuFeatureLocks;
|
|
39
|
+
}
|
|
40
|
+
declare function buildBuMatrix(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, buLocks: BuFeatureLocks | undefined): BuMatrix;
|
|
41
|
+
|
|
42
|
+
declare function buildBuCatalog(snapshot: VersionSnapshot, businessCode: string | undefined, planCode: string | undefined, buLocks: BuFeatureLocks | undefined, bucket: PlatformBucket): FeatureCatalogEntry[];
|
|
43
|
+
declare function isPlanMember(entry: PlatformCodes | undefined): boolean;
|
|
44
|
+
declare function isBuLockedOnPlatform(entry: BuFeatureLocks[string] | undefined, platform: PlatformBucket, code: string): boolean;
|
|
45
|
+
declare function buildBuRoles(snapshot: VersionSnapshot, businessCode: string | undefined): RoleItem[];
|
|
46
|
+
|
|
47
|
+
type RevokedGrants = Record<string, PlatformDenyCodes>;
|
|
48
|
+
interface ComposeRoleGrantsParams {
|
|
49
|
+
baseFeatures: FeatureUnlocks | undefined;
|
|
50
|
+
additions: FeatureUnlocks;
|
|
51
|
+
revoked: RevokedGrants | undefined;
|
|
52
|
+
}
|
|
53
|
+
declare function composeRoleGrants(params: ComposeRoleGrantsParams): FeatureUnlocks;
|
|
54
|
+
|
|
55
|
+
type ClientPlatform = 'web' | 'ios' | 'android';
|
|
56
|
+
interface LockedPermission {
|
|
57
|
+
code: string;
|
|
58
|
+
reason: LockReason | null;
|
|
59
|
+
unlockPlans: string[];
|
|
60
|
+
}
|
|
61
|
+
interface PermissionFeature {
|
|
62
|
+
code: string;
|
|
63
|
+
name: string;
|
|
64
|
+
lucideIcon: string | null;
|
|
65
|
+
sfSymbol: string;
|
|
66
|
+
materialSymbol: string;
|
|
67
|
+
permissions: string[];
|
|
68
|
+
locked: boolean;
|
|
69
|
+
lockReason: LockReason | null;
|
|
70
|
+
unlockPlans: string[];
|
|
71
|
+
lockedPermissions: LockedPermission[];
|
|
72
|
+
route: {
|
|
73
|
+
remoteEntry: string;
|
|
74
|
+
exposedModule: string;
|
|
75
|
+
routePrefix: string;
|
|
76
|
+
};
|
|
77
|
+
appCode: string;
|
|
78
|
+
appName: string;
|
|
79
|
+
appIcon: string | null;
|
|
80
|
+
appSortOrder: number;
|
|
81
|
+
}
|
|
82
|
+
interface ResolveUserFeaturesParams {
|
|
83
|
+
snapshot: VersionSnapshot;
|
|
84
|
+
businessCode: string;
|
|
85
|
+
planCode: string | undefined;
|
|
86
|
+
buLocks: BuFeatureLocks | undefined;
|
|
87
|
+
roleFeatures: FeatureUnlocks;
|
|
88
|
+
platform: ClientPlatform;
|
|
89
|
+
}
|
|
90
|
+
declare function resolveUserFeatures(params: ResolveUserFeaturesParams): PermissionFeature[];
|
|
91
|
+
declare function pickRouteForPlatform(entry: {
|
|
92
|
+
web: {
|
|
93
|
+
remoteEntry: string;
|
|
94
|
+
exposedModule: string;
|
|
95
|
+
routePrefix: string;
|
|
96
|
+
} | null;
|
|
97
|
+
mobile: {
|
|
98
|
+
remoteEntryAndroid: string;
|
|
99
|
+
remoteEntryIos: string;
|
|
100
|
+
exposedModule: string;
|
|
101
|
+
routePrefix: string;
|
|
102
|
+
} | null;
|
|
103
|
+
}, platform: ClientPlatform): {
|
|
104
|
+
remoteEntry: string;
|
|
105
|
+
exposedModule: string;
|
|
106
|
+
routePrefix: string;
|
|
107
|
+
} | null;
|
|
108
|
+
|
|
109
|
+
export { BuFeatureLocks, type BuMatrix, type BuMatrixApp, type BuMatrixCell, type BuMatrixFeature, type BuMatrixPermission, type ClientPlatform, type ComposeRoleGrantsParams, FeatureCatalogEntry, FeatureUnlocks, LockReason, type LockedPermission, type PermissionFeature, PlatformBucket, PlatformCodes, PlatformDenyCodes, type ResolveUserFeaturesParams, type RevokedGrants, RoleItem, VersionSnapshot, buildBuCatalog, buildBuMatrix, buildBuRoles, composeRoleGrants, isBuLockedOnPlatform, isPlanMember, pickRouteForPlatform, resolveUserFeatures };
|