@inf-monkeys-tech/monkeys 1.0.65 → 1.0.68

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.
Files changed (66) hide show
  1. package/README.md +6 -0
  2. package/lib/contracts/capability.d.ts +4 -0
  3. package/lib/contracts/capability.d.ts.map +1 -1
  4. package/lib/contracts/capability.js +1 -0
  5. package/lib/contracts/capability.js.map +1 -1
  6. package/lib/contracts/declarative-control-http.d.ts +81420 -0
  7. package/lib/contracts/declarative-control-http.d.ts.map +1 -0
  8. package/lib/contracts/declarative-control-http.js +926 -0
  9. package/lib/contracts/declarative-control-http.js.map +1 -0
  10. package/lib/contracts/declarative-control.d.ts +17753 -0
  11. package/lib/contracts/declarative-control.d.ts.map +1 -0
  12. package/lib/contracts/declarative-control.js +1078 -0
  13. package/lib/contracts/declarative-control.js.map +1 -0
  14. package/lib/contracts/index.d.ts +2 -0
  15. package/lib/contracts/index.d.ts.map +1 -1
  16. package/lib/contracts/index.js +2 -0
  17. package/lib/contracts/index.js.map +1 -1
  18. package/lib/contracts/menu.d.ts +1 -1
  19. package/lib/contracts/page.d.ts +3 -3
  20. package/lib/contracts/semantic.d.ts +78 -1
  21. package/lib/contracts/semantic.d.ts.map +1 -1
  22. package/lib/contracts/semantic.js +27 -1
  23. package/lib/contracts/semantic.js.map +1 -1
  24. package/lib/contracts/tenant.d.ts +81 -12
  25. package/lib/contracts/tenant.d.ts.map +1 -1
  26. package/lib/contracts/tenant.js +279 -93
  27. package/lib/contracts/tenant.js.map +1 -1
  28. package/lib/contracts/trend.d.ts +4 -4
  29. package/lib/esm/contracts/index.mjs +2963 -1048
  30. package/lib/esm/contracts/index.mjs.map +1 -1
  31. package/lib/esm/index.mjs +5820 -3025
  32. package/lib/esm/index.mjs.map +1 -1
  33. package/lib/esm/runtime/index.mjs +2529 -632
  34. package/lib/esm/runtime/index.mjs.map +1 -1
  35. package/lib/esm/schemas/index.mjs +2081 -982
  36. package/lib/esm/schemas/index.mjs.map +1 -1
  37. package/lib/json-schema/capability-registry.schema.json +2 -1
  38. package/lib/json-schema/declarative-control-ontology-definition.schema.json +130 -0
  39. package/lib/json-schema/index.json +13 -0
  40. package/lib/json-schema/navigation-release.schema.json +2037 -0
  41. package/lib/json-schema/navigation-runtime-bundle.schema.json +7505 -0
  42. package/lib/json-schema/navigation.schema.json +4649 -0
  43. package/lib/json-schema/page-release.schema.json +2465 -0
  44. package/lib/json-schema/page-runtime-bundle.schema.json +5713 -0
  45. package/lib/json-schema/page.schema.json +7944 -0
  46. package/lib/json-schema/publication-plan.schema.json +1286 -0
  47. package/lib/json-schema/route-space.schema.json +93 -0
  48. package/lib/json-schema/stable-ref-alias-map.schema.json +535 -0
  49. package/lib/json-schema/tenant-product-config.schema.json +73 -0
  50. package/lib/json-schema/tenant-runtime-config.schema.json +73 -0
  51. package/lib/json-schema/workbench-release.schema.json +2481 -0
  52. package/lib/json-schema/workbench-runtime-bundle.schema.json +5290 -0
  53. package/lib/json-schema/workbench.schema.json +6698 -0
  54. package/lib/runtime/declarative-control-compiler.d.ts +141 -0
  55. package/lib/runtime/declarative-control-compiler.d.ts.map +1 -0
  56. package/lib/runtime/declarative-control-compiler.js +875 -0
  57. package/lib/runtime/declarative-control-compiler.js.map +1 -0
  58. package/lib/runtime/index.d.ts +1 -0
  59. package/lib/runtime/index.d.ts.map +1 -1
  60. package/lib/runtime/index.js +1 -0
  61. package/lib/runtime/index.js.map +1 -1
  62. package/lib/schemas/index.d.ts +14061 -3830
  63. package/lib/schemas/index.d.ts.map +1 -1
  64. package/lib/schemas/index.js +76 -4
  65. package/lib/schemas/index.js.map +1 -1
  66. package/package.json +1 -1
@@ -0,0 +1,875 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveWorkbenchEntry = exports.validateWorkbenchRuntimeSet = exports.compileNavigationRuntimeBundle = exports.compileWorkbenchRuntimeBundle = exports.compilePageRuntimeBundle = exports.materializeRouteSpacePath = exports.compileRouteClaims = exports.accessPolicyChainImplies = exports.declarativeProductResourceRevisionHash = exports.declarativeProductResourceSourceHash = exports.declarativeRouteSpaceRevisionHash = exports.declarativeRouteSpaceSourceHash = exports.declarativeCreateTemplateRevisionHash = exports.declarativeCreateTemplateSourceHash = exports.canonicalContentHash = exports.sameRevisionRef = exports.sameStableRef = exports.revisionRefKey = exports.stableRefKey = exports.DeclarativeControlCompilationError = void 0;
4
+ const common_1 = require("../contracts/common");
5
+ const render_tree_compiler_1 = require("./render-tree-compiler");
6
+ const declarative_control_1 = require("../contracts/declarative-control");
7
+ class DeclarativeControlCompilationError extends Error {
8
+ constructor(code, path, message) {
9
+ super(`${code} at ${path}: ${message}`);
10
+ this.code = code;
11
+ this.path = path;
12
+ this.name = 'DeclarativeControlCompilationError';
13
+ }
14
+ }
15
+ exports.DeclarativeControlCompilationError = DeclarativeControlCompilationError;
16
+ const scopedIdentityKey = (reference) => `${reference.kind}:${reference.id}:${reference.ownerRepo}`;
17
+ const scopeKey = (scope) => `${scopedIdentityKey(scope.tenantRef)}:${scopedIdentityKey(scope.dataSpaceRef)}:${scope.teamRef ? scopedIdentityKey(scope.teamRef) : ''}`;
18
+ const stableRefKey = (reference) => `${reference.visibility}:${reference.tenantScope ? scopeKey(reference.tenantScope) : ''}:${reference.kind}:${reference.id}:${reference.ownerRepo}`;
19
+ exports.stableRefKey = stableRefKey;
20
+ const revisionRefKey = (reference) => `${(0, exports.stableRefKey)(reference)}@${reference.revision}:v${reference.schemaVersion}:${reference.contentHash.toLowerCase()}`;
21
+ exports.revisionRefKey = revisionRefKey;
22
+ const sameStableRef = (left, right) => (0, exports.stableRefKey)(left) === (0, exports.stableRefKey)(right);
23
+ exports.sameStableRef = sameStableRef;
24
+ const sameRevisionRef = (left, right) => (0, exports.revisionRefKey)(left) === (0, exports.revisionRefKey)(right);
25
+ exports.sameRevisionRef = sameRevisionRef;
26
+ const assertUniqueRegistryKeys = (keys, path) => {
27
+ const seen = new Set();
28
+ keys.forEach((key, index) => {
29
+ if (seen.has(key)) {
30
+ throw new DeclarativeControlCompilationError('REGISTRY_CONFLICT', `${path}[${index}]`, `Duplicate registry identity: ${key}`);
31
+ }
32
+ seen.add(key);
33
+ });
34
+ };
35
+ const stableSerialize = (value) => {
36
+ if (value === undefined)
37
+ return 'null';
38
+ if (value === null || typeof value !== 'object')
39
+ return JSON.stringify(value) ?? 'null';
40
+ if (Array.isArray(value))
41
+ return `[${value.map((item) => stableSerialize(item)).join(',')}]`;
42
+ const record = value;
43
+ return `{${Object.keys(record)
44
+ .filter((key) => record[key] !== undefined)
45
+ .sort()
46
+ .map((key) => `${JSON.stringify(key)}:${stableSerialize(record[key])}`)
47
+ .join(',')}}`;
48
+ };
49
+ const SHA256_INITIAL = [
50
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
51
+ 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
52
+ ];
53
+ const SHA256_ROUND = [
54
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
55
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
56
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
57
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
58
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
59
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
60
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
61
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
62
+ ];
63
+ const rotateRight = (value, amount) => (value >>> amount) | (value << (32 - amount));
64
+ const sha256Hex = (value) => {
65
+ const source = [...new TextEncoder().encode(value)];
66
+ const bitLength = source.length * 8;
67
+ source.push(0x80);
68
+ while (source.length % 64 !== 56)
69
+ source.push(0);
70
+ const high = Math.floor(bitLength / 4294967296);
71
+ const low = bitLength >>> 0;
72
+ for (let shift = 24; shift >= 0; shift -= 8)
73
+ source.push((high >>> shift) & 0xff);
74
+ for (let shift = 24; shift >= 0; shift -= 8)
75
+ source.push((low >>> shift) & 0xff);
76
+ const hash = [...SHA256_INITIAL];
77
+ const words = new Array(64).fill(0);
78
+ for (let offset = 0; offset < source.length; offset += 64) {
79
+ for (let index = 0; index < 16; index += 1) {
80
+ const start = offset + index * 4;
81
+ words[index] = ((source[start] << 24) | (source[start + 1] << 16) | (source[start + 2] << 8) | source[start + 3]) >>> 0;
82
+ }
83
+ for (let index = 16; index < 64; index += 1) {
84
+ const previous = words[index - 15];
85
+ const recent = words[index - 2];
86
+ const small0 = rotateRight(previous, 7) ^ rotateRight(previous, 18) ^ (previous >>> 3);
87
+ const small1 = rotateRight(recent, 17) ^ rotateRight(recent, 19) ^ (recent >>> 10);
88
+ words[index] = (words[index - 16] + small0 + words[index - 7] + small1) >>> 0;
89
+ }
90
+ let [a, b, c, d, e, f, g, h] = hash;
91
+ for (let index = 0; index < 64; index += 1) {
92
+ const big1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
93
+ const choice = (e & f) ^ (~e & g);
94
+ const temp1 = (h + big1 + choice + SHA256_ROUND[index] + words[index]) >>> 0;
95
+ const big0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
96
+ const majority = (a & b) ^ (a & c) ^ (b & c);
97
+ const temp2 = (big0 + majority) >>> 0;
98
+ h = g;
99
+ g = f;
100
+ f = e;
101
+ e = (d + temp1) >>> 0;
102
+ d = c;
103
+ c = b;
104
+ b = a;
105
+ a = (temp1 + temp2) >>> 0;
106
+ }
107
+ hash[0] = (hash[0] + a) >>> 0;
108
+ hash[1] = (hash[1] + b) >>> 0;
109
+ hash[2] = (hash[2] + c) >>> 0;
110
+ hash[3] = (hash[3] + d) >>> 0;
111
+ hash[4] = (hash[4] + e) >>> 0;
112
+ hash[5] = (hash[5] + f) >>> 0;
113
+ hash[6] = (hash[6] + g) >>> 0;
114
+ hash[7] = (hash[7] + h) >>> 0;
115
+ }
116
+ return hash.map((part) => part.toString(16).padStart(8, '0')).join('');
117
+ };
118
+ const canonicalContentHash = (value) => sha256Hex(stableSerialize(value));
119
+ exports.canonicalContentHash = canonicalContentHash;
120
+ const declarativeCreateTemplateSourceHash = (document) => (0, exports.canonicalContentHash)(document);
121
+ exports.declarativeCreateTemplateSourceHash = declarativeCreateTemplateSourceHash;
122
+ const declarativeCreateTemplateRevisionHash = (registration) => (0, exports.canonicalContentHash)(registration.document);
123
+ exports.declarativeCreateTemplateRevisionHash = declarativeCreateTemplateRevisionHash;
124
+ const declarativeRouteSpaceSourceHash = (routeSpace) => (0, exports.canonicalContentHash)(routeSpace);
125
+ exports.declarativeRouteSpaceSourceHash = declarativeRouteSpaceSourceHash;
126
+ const declarativeRouteSpaceRevisionHash = (registration) => (0, exports.canonicalContentHash)(registration.routeSpace);
127
+ exports.declarativeRouteSpaceRevisionHash = declarativeRouteSpaceRevisionHash;
128
+ const declarativeProductResourceSourceHash = (document) => (0, exports.canonicalContentHash)(document);
129
+ exports.declarativeProductResourceSourceHash = declarativeProductResourceSourceHash;
130
+ const declarativeProductResourceRevisionHash = (registration) => (0, exports.canonicalContentHash)(registration.document);
131
+ exports.declarativeProductResourceRevisionHash = declarativeProductResourceRevisionHash;
132
+ const deepFreeze = (value) => {
133
+ if (value === null || typeof value !== 'object' || Object.isFrozen(value))
134
+ return value;
135
+ Object.values(value).forEach((child) => deepFreeze(child));
136
+ return Object.freeze(value);
137
+ };
138
+ const assertTenantCompatible = (reference, scope, path) => {
139
+ if (reference.visibility === 'tenant' && scopeKey(reference.tenantScope) !== scopeKey(scope)) {
140
+ throw new DeclarativeControlCompilationError('CROSS_TENANT_REFERENCE', path, `Reference ${reference.kind}/${reference.id} belongs to another tenant scope.`);
141
+ }
142
+ };
143
+ const assertSameTenantScope = (candidate, expected, path) => {
144
+ if (scopeKey(candidate) !== scopeKey(expected)) {
145
+ throw new DeclarativeControlCompilationError('CROSS_TENANT_REFERENCE', path, 'Record and release tenant scopes do not match.');
146
+ }
147
+ };
148
+ const stableFromRevision = (reference) => declarative_control_1.StableRefSchema.parse({
149
+ kind: reference.kind,
150
+ id: reference.id,
151
+ ownerRepo: reference.ownerRepo,
152
+ visibility: reference.visibility,
153
+ ...(reference.tenantScope ? { tenantScope: reference.tenantScope } : {}),
154
+ });
155
+ const assertRevisionIdentity = (reference, expectedKind, expectedId, scope, path) => {
156
+ if (reference.kind !== expectedKind || reference.id !== expectedId) {
157
+ throw new DeclarativeControlCompilationError('REVISION_MISMATCH', path, `Expected ${expectedKind}/${expectedId}, received ${reference.kind}/${reference.id}.`);
158
+ }
159
+ assertTenantCompatible(reference, scope, path);
160
+ };
161
+ const dependencyKey = (role, reference) => `${role}:${(0, exports.revisionRefKey)(reference)}`;
162
+ const requireDependencies = (snapshot, required) => {
163
+ const available = new Set(snapshot.map((dependency) => dependencyKey(dependency.role, dependency.revisionRef)));
164
+ for (const dependency of required) {
165
+ const key = dependencyKey(dependency.role, dependency.revisionRef);
166
+ if (!available.has(key)) {
167
+ throw new DeclarativeControlCompilationError('DEPENDENCY_MISSING', 'dependencySnapshot', `Missing exact ${dependency.role} dependency ${(0, exports.revisionRefKey)(dependency.revisionRef)}.`);
168
+ }
169
+ }
170
+ };
171
+ const assertDependencyScopes = (snapshot, scope) => snapshot.forEach((dependency, index) => assertTenantCompatible(dependency.revisionRef, scope, `dependencySnapshot[${index}].revisionRef`));
172
+ const requireReleaseReady = (release) => {
173
+ if (release.evidence.validation.result !== 'pass') {
174
+ throw new DeclarativeControlCompilationError('RELEASE_VALIDATION_FAILED', 'evidence.validation.result', 'Runtime bundles require a passing release validation result.');
175
+ }
176
+ };
177
+ const refSet = (values) => new Set(values.map(exports.stableRefKey));
178
+ const chainRequiresAll = (policies, field) => {
179
+ if (field === 'permissionAllOf')
180
+ return new Set(policies.flatMap((policy) => policy.permissionAllOf));
181
+ if (field === 'groupAllOf')
182
+ return refSet(policies.flatMap((policy) => policy.groupAllOf));
183
+ return new Set(policies.flatMap((policy) => policy.conditionAllOf.map(exports.revisionRefKey)));
184
+ };
185
+ const chainImpliesAny = (policies, targetAny, allValues, anyValues) => {
186
+ if (targetAny.size === 0)
187
+ return true;
188
+ if ([...allValues].some((value) => targetAny.has(value)))
189
+ return true;
190
+ return policies.some((policy) => {
191
+ const values = anyValues(policy);
192
+ return values.length > 0 && values.every((value) => targetAny.has(value));
193
+ });
194
+ };
195
+ const accessPolicyChainImplies = (policyInputs, targetInput) => {
196
+ const policies = policyInputs.map((policy) => declarative_control_1.AccessPolicySchema.parse(policy));
197
+ const target = declarative_control_1.AccessPolicySchema.parse(targetInput);
198
+ if (target.authenticated && !policies.some((policy) => policy.authenticated))
199
+ return false;
200
+ const permissionAll = chainRequiresAll(policies, 'permissionAllOf');
201
+ if (target.permissionAllOf.some((permission) => !permissionAll.has(permission)))
202
+ return false;
203
+ if (!chainImpliesAny(policies, new Set(target.permissionAnyOf), permissionAll, (policy) => policy.permissionAnyOf))
204
+ return false;
205
+ const groupAll = chainRequiresAll(policies, 'groupAllOf');
206
+ if (target.groupAllOf.some((group) => !groupAll.has((0, exports.stableRefKey)(group))))
207
+ return false;
208
+ if (!chainImpliesAny(policies, refSet(target.groupAnyOf), groupAll, (policy) => policy.groupAnyOf.map(exports.stableRefKey)))
209
+ return false;
210
+ const conditionAll = chainRequiresAll(policies, 'conditionAllOf');
211
+ if (target.conditionAllOf.some((condition) => !conditionAll.has((0, exports.revisionRefKey)(condition))))
212
+ return false;
213
+ return true;
214
+ };
215
+ exports.accessPolicyChainImplies = accessPolicyChainImplies;
216
+ const normalizePath = (path, routeSpace) => {
217
+ let normalized = path;
218
+ if (!routeSpace.caseSensitive) {
219
+ normalized = normalized
220
+ .split('/')
221
+ .map((segment) => segment.startsWith(':') ? segment : segment.toLowerCase())
222
+ .join('/');
223
+ }
224
+ if (routeSpace.trailingSlash === 'remove' && normalized.length > 1)
225
+ normalized = normalized.replace(/\/+$/, '');
226
+ if (routeSpace.trailingSlash === 'require' && normalized.length > 1 && !normalized.endsWith('/'))
227
+ normalized += '/';
228
+ return normalized;
229
+ };
230
+ const compileRouteClaims = (input) => {
231
+ const registrations = input.routeSpaces.map((entry, index) => {
232
+ const revisionRef = declarative_control_1.RevisionRefSchema.parse(entry.revisionRef);
233
+ const routeSpace = declarative_control_1.RouteSpaceSchema.parse(entry.routeSpace);
234
+ if (revisionRef.kind !== 'route-space' || revisionRef.id !== routeSpace.routeSpaceId) {
235
+ throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', `routeSpaces[${index}]`, 'RouteSpace registration identity does not match its pinned revision.');
236
+ }
237
+ return { revisionRef, routeSpace };
238
+ });
239
+ assertUniqueRegistryKeys(registrations.map((entry) => (0, exports.revisionRefKey)(entry.revisionRef)), 'routeSpaces');
240
+ const routeSpacesByRevision = new Map(registrations.map((entry) => [(0, exports.revisionRefKey)(entry.revisionRef), entry.routeSpace]));
241
+ const normalizedPaths = new Set();
242
+ const compiled = [];
243
+ input.claims.forEach((inputClaim, index) => {
244
+ const parsedClaim = 'surface' in inputClaim
245
+ ? declarative_control_1.RouteClaimSchema.parse(inputClaim)
246
+ : declarative_control_1.LegacyRouteClaimSchema.parse(inputClaim);
247
+ const routeSpace = routeSpacesByRevision.get((0, exports.revisionRefKey)(parsedClaim.routeSpaceRevisionRef));
248
+ if (!routeSpace)
249
+ throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISSING', `routeClaims[${index}].routeSpaceRevisionRef`, 'No exact RouteSpace registration exists.');
250
+ const claim = declarative_control_1.RouteClaimSchema.parse({
251
+ ...parsedClaim,
252
+ surface: 'surface' in parsedClaim ? parsedClaim.surface : routeSpace.supportedSurface,
253
+ });
254
+ if (routeSpace.supportedSurface !== claim.surface) {
255
+ throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', `routeClaims[${index}].surface`, `Route claim surface ${claim.surface} does not match RouteSpace ${routeSpace.routeSpaceId}.`);
256
+ }
257
+ if (claim.surface !== input.surface)
258
+ return;
259
+ const normalizedPath = normalizePath(claim.pathTemplate, routeSpace);
260
+ const knownParameters = new Set(routeSpace.parameters.map((parameter) => parameter.name));
261
+ const pathParameters = [...normalizedPath.matchAll(/:([A-Za-z][A-Za-z0-9_-]*)/g)].map((match) => match[1]);
262
+ if (new Set(pathParameters).size !== pathParameters.length) {
263
+ throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', `routeClaims[${index}].pathTemplate`, 'Route parameters must be unique within a path.');
264
+ }
265
+ const unknownParameter = pathParameters.find((parameter) => !knownParameters.has(parameter));
266
+ if (unknownParameter) {
267
+ throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', `routeClaims[${index}].pathTemplate`, `Route parameter ${unknownParameter} is not declared by ${routeSpace.routeSpaceId}.`);
268
+ }
269
+ const reserved = routeSpace.reservedPaths.some((candidate) => {
270
+ const normalizedReserved = normalizePath(candidate, routeSpace);
271
+ return normalizedPath === normalizedReserved || normalizedPath.startsWith(`${normalizedReserved}/`);
272
+ });
273
+ if (reserved)
274
+ throw new DeclarativeControlCompilationError('ROUTE_RESERVED', `routeClaims[${index}].pathTemplate`, `Route ${normalizedPath} is reserved by ${routeSpace.routeSpaceId}.`);
275
+ const routeIdentity = `${(0, exports.revisionRefKey)(claim.routeSpaceRevisionRef)}:${normalizedPath}`;
276
+ if (normalizedPaths.has(routeIdentity))
277
+ throw new DeclarativeControlCompilationError('ROUTE_CONFLICT', `routeClaims[${index}].pathTemplate`, `Duplicate normalized route ${normalizedPath}.`);
278
+ normalizedPaths.add(routeIdentity);
279
+ compiled.push(declarative_control_1.CompiledRouteClaimSchema.parse({
280
+ ...claim,
281
+ normalizedPath,
282
+ matcher: {
283
+ surface: claim.surface,
284
+ caseSensitive: routeSpace.caseSensitive,
285
+ trailingSlash: routeSpace.trailingSlash,
286
+ parameters: routeSpace.parameters,
287
+ },
288
+ }));
289
+ });
290
+ if (!compiled.some((claim) => claim.kind === 'canonical')) {
291
+ throw new DeclarativeControlCompilationError('ROUTE_CONFLICT', 'routeClaims', 'At least one canonical route claim is required.');
292
+ }
293
+ return Object.freeze(compiled);
294
+ };
295
+ exports.compileRouteClaims = compileRouteClaims;
296
+ const routeParameterPattern = (type) => {
297
+ if (type === 'integer')
298
+ return /^-?\d+$/;
299
+ if (type === 'uuid')
300
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
301
+ if (type === 'slug')
302
+ return /^[A-Za-z0-9]+(?:[._-][A-Za-z0-9]+)*$/;
303
+ return /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
304
+ };
305
+ /**
306
+ * Materializes the browser URL owned by a RouteSpace from an application-relative
307
+ * compiled route. Declarations and runtime resolution remain application-relative;
308
+ * only this boundary applies product bases such as /:teamId or /kernel.
309
+ */
310
+ const materializeRouteSpacePath = (input) => {
311
+ const routeSpace = declarative_control_1.RouteSpaceSchema.parse(input.routeSpace);
312
+ const applicationPath = declarative_control_1.RoutePathTemplateSchema.parse(input.applicationPath);
313
+ const basePath = routeSpace.basePath === '/' ? '' : routeSpace.basePath.replace(/\/+$/, '');
314
+ let browserTemplate = normalizePath(`${basePath}${applicationPath === '/' ? '/' : applicationPath}` || '/', routeSpace);
315
+ const parameters = input.parameters || {};
316
+ const declared = new Map(routeSpace.parameters.map((parameter) => [parameter.name, parameter]));
317
+ const referenced = [...browserTemplate.matchAll(/:([A-Za-z][A-Za-z0-9_-]*)/g)].map((match) => match[1]);
318
+ for (const name of referenced) {
319
+ const definition = declared.get(name);
320
+ const raw = parameters[name];
321
+ if (!definition || raw === undefined || raw === null || String(raw).trim() === '') {
322
+ throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', 'parameters', `Route parameter ${name} is not resolved by ${routeSpace.routeSpaceId}.`);
323
+ }
324
+ const value = String(raw);
325
+ if (!routeParameterPattern(definition.type).test(value)) {
326
+ throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', `parameters.${name}`, `Route parameter ${name} does not satisfy ${definition.type}.`);
327
+ }
328
+ browserTemplate = browserTemplate.replace(`:${name}`, encodeURIComponent(value));
329
+ }
330
+ const unknown = Object.keys(parameters).find((name) => !declared.has(name));
331
+ if (unknown)
332
+ throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', `parameters.${unknown}`, `RouteSpace ${routeSpace.routeSpaceId} does not declare ${unknown}.`);
333
+ return browserTemplate;
334
+ };
335
+ exports.materializeRouteSpacePath = materializeRouteSpacePath;
336
+ const renderTreeDepth = (tree) => {
337
+ const byId = new Map(tree.nodes.map((node) => [node.nodeId, node]));
338
+ let maximum = 0;
339
+ tree.nodes.forEach((node) => {
340
+ let depth = 1;
341
+ let parentId = node.parentNodeId;
342
+ while (parentId) {
343
+ depth += 1;
344
+ parentId = byId.get(parentId)?.parentNodeId;
345
+ }
346
+ maximum = Math.max(maximum, depth);
347
+ });
348
+ return maximum;
349
+ };
350
+ const compareLegacyEntityRef = (reference, revision) => reference.kind === revision.kind
351
+ && reference.id === revision.id
352
+ && String(reference.version) === String(revision.revision)
353
+ && reference.ownerRepo === revision.ownerRepo;
354
+ const pageDependencies = (page, compilerRevisionRef) => [
355
+ ...page.routeClaims.map((claim) => ({ role: 'route-space', revisionRef: claim.routeSpaceRevisionRef })),
356
+ { role: 'shell', revisionRef: page.shellRevisionRef },
357
+ ...page.capabilityInstances.flatMap((instance) => [
358
+ { role: 'capability', revisionRef: instance.capabilityRevisionRef },
359
+ { role: 'provider', revisionRef: instance.providerRevisionRef },
360
+ { role: 'schema', revisionRef: instance.propertySchemaRevisionRef },
361
+ ]),
362
+ ...page.ontologyBindings.flatMap((binding) => [
363
+ { role: 'ontology-definition', revisionRef: binding.ontologyDefinitionRevisionRef },
364
+ ...(binding.viewRevisionRef ? [{ role: 'view', revisionRef: binding.viewRevisionRef }] : []),
365
+ ...(binding.projectionRevisionRef ? [{ role: 'projection', revisionRef: binding.projectionRevisionRef }] : []),
366
+ { role: 'schema', revisionRef: binding.renderModelSchemaRevisionRef },
367
+ ]),
368
+ ...page.actionBindings.flatMap((binding) => [
369
+ { role: 'action', revisionRef: binding.commandRevisionRef },
370
+ { role: 'schema', revisionRef: binding.sourceIntentSchemaRevisionRef },
371
+ { role: 'schema', revisionRef: binding.inputSchemaRevisionRef },
372
+ { role: 'schema', revisionRef: binding.resultSchemaRevisionRef },
373
+ ...(binding.compensationCommandRevisionRef ? [{ role: 'action', revisionRef: binding.compensationCommandRevisionRef }] : []),
374
+ ]),
375
+ ...page.tokenRevisionRefs.map((revisionRef) => ({ role: 'token', revisionRef })),
376
+ { role: 'performance-budget', revisionRef: page.performanceBudgetRef },
377
+ { role: 'observation-policy', revisionRef: page.observationPolicyRevisionRef },
378
+ { role: 'compiler', revisionRef: compilerRevisionRef },
379
+ ];
380
+ const compilePageRuntimeBundle = (input) => {
381
+ const page = declarative_control_1.PageSchema.parse(input.page);
382
+ const pageRevisionRef = declarative_control_1.RevisionRefSchema.parse(input.pageRevisionRef);
383
+ const release = declarative_control_1.PageReleaseSchema.parse(input.release);
384
+ const releaseRevisionRef = declarative_control_1.RevisionRefSchema.parse(input.releaseRevisionRef);
385
+ const compilerRevisionRef = declarative_control_1.RevisionRefSchema.parse(input.compilerRevisionRef);
386
+ const scope = declarative_control_1.TenantScopeSchema.parse(page.tenantScope);
387
+ assertSameTenantScope(release.tenantScope, scope, 'release.tenantScope');
388
+ assertRevisionIdentity(pageRevisionRef, 'page', page.pageId, scope, 'pageRevisionRef');
389
+ assertRevisionIdentity(release.pageRevisionRef, 'page', page.pageId, scope, 'release.pageRevisionRef');
390
+ if (!(0, exports.sameRevisionRef)(pageRevisionRef, release.pageRevisionRef))
391
+ throw new DeclarativeControlCompilationError('REVISION_MISMATCH', 'release.pageRevisionRef', 'Release does not pin the supplied Page revision.');
392
+ assertRevisionIdentity(releaseRevisionRef, 'page-release', release.releaseSlotId, scope, 'releaseRevisionRef');
393
+ requireReleaseReady(release);
394
+ requireDependencies(release.dependencySnapshot, pageDependencies(page, compilerRevisionRef));
395
+ assertDependencyScopes(release.dependencySnapshot, scope);
396
+ if (page.renderTree.nodes.length > input.limits.maxRenderNodes)
397
+ throw new DeclarativeControlCompilationError('RENDER_NODE_LIMIT_EXCEEDED', 'page.renderTree.nodes', 'RenderTree exceeds the caller-approved node limit.');
398
+ if (renderTreeDepth(page.renderTree) > input.limits.maxRenderDepth)
399
+ throw new DeclarativeControlCompilationError('RENDER_DEPTH_EXCEEDED', 'page.renderTree.nodes', 'RenderTree exceeds the caller-approved depth limit.');
400
+ const renderTree = (0, render_tree_compiler_1.compileRenderTree)(page.renderTree).tree;
401
+ const instancesByNode = new Map(page.capabilityInstances.map((instance) => [instance.nodeId, instance]));
402
+ const registrations = input.capabilityRegistry.map((registration, registrationIndex) => ({
403
+ ...registration,
404
+ capabilityRevisionRef: declarative_control_1.RevisionRefSchema.parse(registration.capabilityRevisionRef),
405
+ providerRevisionRef: declarative_control_1.RevisionRefSchema.parse(registration.providerRevisionRef),
406
+ inputPorts: registration.inputPorts.map((port, portIndex) => {
407
+ const schemaRevisionRef = declarative_control_1.RevisionRefSchema.parse(port.schemaRevisionRef);
408
+ if (schemaRevisionRef.kind !== 'schema') {
409
+ throw new DeclarativeControlCompilationError('PORT_TYPE_MISMATCH', `capabilityRegistry[${registrationIndex}].inputPorts[${portIndex}].schemaRevisionRef`, 'Capability ports must pin schema revisions.');
410
+ }
411
+ return { ...port, schemaRevisionRef };
412
+ }),
413
+ outputPorts: registration.outputPorts.map((port, portIndex) => {
414
+ const schemaRevisionRef = declarative_control_1.RevisionRefSchema.parse(port.schemaRevisionRef);
415
+ if (schemaRevisionRef.kind !== 'schema') {
416
+ throw new DeclarativeControlCompilationError('PORT_TYPE_MISMATCH', `capabilityRegistry[${registrationIndex}].outputPorts[${portIndex}].schemaRevisionRef`, 'Capability ports must pin schema revisions.');
417
+ }
418
+ return { ...port, schemaRevisionRef };
419
+ }),
420
+ }));
421
+ assertUniqueRegistryKeys(registrations.map((registration) => `${(0, exports.revisionRefKey)(registration.capabilityRevisionRef)}:${(0, exports.revisionRefKey)(registration.providerRevisionRef)}`), 'capabilityRegistry');
422
+ const registrationsByPair = new Map(registrations.map((registration) => [
423
+ `${(0, exports.revisionRefKey)(registration.capabilityRevisionRef)}:${(0, exports.revisionRefKey)(registration.providerRevisionRef)}`,
424
+ registration,
425
+ ]));
426
+ page.capabilityInstances.forEach((instance, index) => {
427
+ const node = renderTree.nodes.find((candidate) => candidate.nodeId === instance.nodeId);
428
+ if (!node || !compareLegacyEntityRef(node.capabilityRef, instance.capabilityRevisionRef)
429
+ || !node.providerRef || !compareLegacyEntityRef(node.providerRef, instance.providerRevisionRef)
430
+ || node.pageRef.id !== page.pageId) {
431
+ throw new DeclarativeControlCompilationError('CAPABILITY_BINDING_MISMATCH', `capabilityInstances[${index}]`, 'RenderTree node identity does not match the declared capability/provider instance.');
432
+ }
433
+ const registration = registrationsByPair.get(`${(0, exports.revisionRefKey)(instance.capabilityRevisionRef)}:${(0, exports.revisionRefKey)(instance.providerRevisionRef)}`);
434
+ if (!registration?.editorEligible) {
435
+ throw new DeclarativeControlCompilationError('CAPABILITY_NOT_EDITOR_ELIGIBLE', `capabilityInstances[${index}]`, 'Capability/provider pair is not editor-eligible.');
436
+ }
437
+ if (instance.allowedSideEffects.some((sideEffect) => !registration.allowedSideEffects.includes(sideEffect))) {
438
+ throw new DeclarativeControlCompilationError('CAPABILITY_BINDING_MISMATCH', `capabilityInstances[${index}].allowedSideEffects`, 'Page requests undeclared provider side effects.');
439
+ }
440
+ });
441
+ page.ontologyBindings.forEach((binding, index) => {
442
+ const instance = page.capabilityInstances.find((candidate) => candidate.instanceId === binding.target.capabilityInstanceId);
443
+ const registration = instance && registrationsByPair.get(`${(0, exports.revisionRefKey)(instance.capabilityRevisionRef)}:${(0, exports.revisionRefKey)(instance.providerRevisionRef)}`);
444
+ const port = registration?.inputPorts.find((candidate) => candidate.name === binding.target.port);
445
+ if (!port || !(0, exports.sameRevisionRef)(port.schemaRevisionRef, binding.renderModelSchemaRevisionRef)) {
446
+ throw new DeclarativeControlCompilationError('PORT_TYPE_MISMATCH', `ontologyBindings[${index}].target.port`, 'Ontology render model does not match the registered capability input port.');
447
+ }
448
+ });
449
+ page.actionBindings.forEach((binding, index) => {
450
+ const instance = page.capabilityInstances.find((candidate) => candidate.instanceId === binding.source.capabilityInstanceId);
451
+ const registration = instance && registrationsByPair.get(`${(0, exports.revisionRefKey)(instance.capabilityRevisionRef)}:${(0, exports.revisionRefKey)(instance.providerRevisionRef)}`);
452
+ const port = registration?.outputPorts.find((candidate) => candidate.name === binding.source.port);
453
+ if (!port || !(0, exports.sameRevisionRef)(port.schemaRevisionRef, binding.sourceIntentSchemaRevisionRef)) {
454
+ throw new DeclarativeControlCompilationError('PORT_TYPE_MISMATCH', `actionBindings[${index}].sourceIntentSchemaRevisionRef`, 'Action source intent does not match the registered capability output port.');
455
+ }
456
+ });
457
+ const routeClaims = (0, exports.compileRouteClaims)({ claims: page.routeClaims, routeSpaces: input.routeSpaces, surface: release.target.surface });
458
+ const releaseRoute = routeClaims.find((claim) => claim.kind === 'canonical' && claim.normalizedPath === release.target.normalizedPath);
459
+ if (!releaseRoute || !(0, exports.sameRevisionRef)(releaseRoute.routeSpaceRevisionRef, release.target.routeSpaceRevisionRef)) {
460
+ throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', 'release.target', 'Release target does not match a canonical Page route claim.');
461
+ }
462
+ if (!page.supportedSurfaces.includes(release.target.surface)) {
463
+ throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', 'release.target.surface', 'Page does not support the release surface.');
464
+ }
465
+ const unsigned = {
466
+ contract: 'PageRuntimeBundle',
467
+ schemaVersion: 1,
468
+ tenantScope: scope,
469
+ releaseRevisionRef,
470
+ compilerRevisionRef,
471
+ generation: input.generation,
472
+ dependencySnapshot: release.dependencySnapshot,
473
+ rebuildable: true,
474
+ diagnostics: [],
475
+ pageId: page.pageId,
476
+ pageRevisionRef,
477
+ surface: release.target.surface,
478
+ routeClaims,
479
+ shellRevisionRef: page.shellRevisionRef,
480
+ renderTree,
481
+ capabilityInstances: page.capabilityInstances,
482
+ ontologyBindings: page.ontologyBindings,
483
+ actionBindings: page.actionBindings,
484
+ pageAccessPolicy: page.pageAccessPolicy,
485
+ tokenRevisionRefs: page.tokenRevisionRefs,
486
+ performanceBudgetRef: page.performanceBudgetRef,
487
+ observationPolicyRevisionRef: page.observationPolicyRevisionRef,
488
+ privacyClassification: page.privacyClassification,
489
+ };
490
+ return deepFreeze(declarative_control_1.PageRuntimeBundleSchema.parse({ ...unsigned, contentHash: (0, exports.canonicalContentHash)(unsigned) }));
491
+ };
492
+ exports.compilePageRuntimeBundle = compilePageRuntimeBundle;
493
+ const workbenchDependencyRole = (kind) => {
494
+ switch (kind) {
495
+ case 'workflow': return 'workflow';
496
+ case 'agent': return 'agent';
497
+ case 'capability': return 'capability';
498
+ case 'design': return 'design';
499
+ case 'built-in-application': return 'built-in-application';
500
+ default: return 'workflow';
501
+ }
502
+ };
503
+ const workbenchDependencies = (workbench, compilerRevisionRef) => [
504
+ ...workbench.routeClaims.map((claim) => ({ role: 'route-space', revisionRef: claim.routeSpaceRevisionRef })),
505
+ ...workbench.appInstances.flatMap((instance) => [
506
+ { role: workbenchDependencyRole(instance.targetRevisionRef.kind), revisionRef: instance.targetRevisionRef },
507
+ { role: 'provider', revisionRef: instance.providerRevisionRef },
508
+ { role: 'schema', revisionRef: instance.inputSchemaRevisionRef },
509
+ ]),
510
+ { role: 'capability', revisionRef: workbench.layout.hostCapabilityRevisionRef },
511
+ { role: 'provider', revisionRef: workbench.layout.hostProviderRevisionRef },
512
+ { role: 'layout-policy', revisionRef: workbench.layout.layoutPolicyRevisionRef },
513
+ ...workbench.layout.tokenRevisionRefs.map((revisionRef) => ({ role: 'token', revisionRef })),
514
+ { role: 'performance-budget', revisionRef: workbench.performanceBudgetRef },
515
+ { role: 'observation-policy', revisionRef: workbench.observationPolicyRevisionRef },
516
+ { role: 'compiler', revisionRef: compilerRevisionRef },
517
+ ];
518
+ const compileWorkbenchRuntimeBundle = (input) => {
519
+ const workbench = declarative_control_1.WorkbenchSchema.parse(input.workbench);
520
+ const workbenchRevisionRef = declarative_control_1.RevisionRefSchema.parse(input.workbenchRevisionRef);
521
+ const release = declarative_control_1.WorkbenchReleaseSchema.parse(input.release);
522
+ const releaseRevisionRef = declarative_control_1.RevisionRefSchema.parse(input.releaseRevisionRef);
523
+ const compilerRevisionRef = declarative_control_1.RevisionRefSchema.parse(input.compilerRevisionRef);
524
+ const scope = declarative_control_1.TenantScopeSchema.parse(workbench.tenantScope);
525
+ assertSameTenantScope(release.tenantScope, scope, 'release.tenantScope');
526
+ if (workbench.purpose === 'template')
527
+ throw new DeclarativeControlCompilationError('WORKBENCH_TEMPLATE_UNRELEASABLE', 'workbench.purpose', 'Workbench templates cannot be activated.');
528
+ if (workbench.groups.length > input.limits.maxWorkbenchGroups || workbench.appInstances.length > input.limits.maxWorkbenchInstances) {
529
+ throw new DeclarativeControlCompilationError('WORKBENCH_INSTANCE_LIMIT_EXCEEDED', 'workbench', 'Workbench exceeds caller-approved compilation limits.');
530
+ }
531
+ assertRevisionIdentity(workbenchRevisionRef, 'workbench', workbench.workbenchId, scope, 'workbenchRevisionRef');
532
+ assertRevisionIdentity(release.workbenchRevisionRef, 'workbench', workbench.workbenchId, scope, 'release.workbenchRevisionRef');
533
+ if (!(0, exports.sameRevisionRef)(workbenchRevisionRef, release.workbenchRevisionRef))
534
+ throw new DeclarativeControlCompilationError('REVISION_MISMATCH', 'release.workbenchRevisionRef', 'Release does not pin the supplied Workbench revision.');
535
+ assertRevisionIdentity(releaseRevisionRef, 'workbench-release', release.releaseSlotId, scope, 'releaseRevisionRef');
536
+ if (release.target.workbenchId !== workbench.workbenchId)
537
+ throw new DeclarativeControlCompilationError('REVISION_MISMATCH', 'release.target.workbenchId', 'Release target does not match Workbench identity.');
538
+ requireReleaseReady(release);
539
+ requireDependencies(release.dependencySnapshot, workbenchDependencies(workbench, compilerRevisionRef));
540
+ assertDependencyScopes(release.dependencySnapshot, scope);
541
+ const routeClaims = (0, exports.compileRouteClaims)({ claims: workbench.routeClaims, routeSpaces: input.routeSpaces, surface: release.target.surface });
542
+ const releaseRoute = routeClaims.find((claim) => claim.kind === 'canonical' && claim.normalizedPath === release.target.normalizedPath);
543
+ if (!releaseRoute || !(0, exports.sameRevisionRef)(releaseRoute.routeSpaceRevisionRef, release.target.routeSpaceRevisionRef)) {
544
+ throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', 'release.target', 'Release target does not match a canonical Workbench route claim.');
545
+ }
546
+ const targetRegistry = input.targetRegistry.map((registration) => ({
547
+ stableTargetRef: declarative_control_1.StableRefSchema.parse(registration.stableTargetRef),
548
+ targetRevisionRef: declarative_control_1.RevisionRefSchema.parse(registration.targetRevisionRef),
549
+ accessPolicy: declarative_control_1.AccessPolicySchema.parse(registration.accessPolicy),
550
+ }));
551
+ assertUniqueRegistryKeys(targetRegistry.map((registration) => (0, exports.stableRefKey)(registration.stableTargetRef)), 'targetRegistry');
552
+ const targetsByStableRef = new Map(targetRegistry.map((registration) => [(0, exports.stableRefKey)(registration.stableTargetRef), registration]));
553
+ const groupsById = new Map(workbench.groups.map((group) => [group.groupId, group]));
554
+ const appInstances = workbench.appInstances.map((instance, index) => {
555
+ const stableTarget = declarative_control_1.StableRefSchema.parse({
556
+ kind: instance.targetRevisionRef.kind,
557
+ id: instance.targetRevisionRef.id,
558
+ ownerRepo: instance.targetRevisionRef.ownerRepo,
559
+ visibility: instance.targetRevisionRef.visibility,
560
+ ...(instance.targetRevisionRef.tenantScope ? { tenantScope: instance.targetRevisionRef.tenantScope } : {}),
561
+ });
562
+ const registration = targetsByStableRef.get((0, exports.stableRefKey)(stableTarget));
563
+ if (!registration || !(0, exports.sameStableRef)(registration.stableTargetRef, stableFromRevision(registration.targetRevisionRef))
564
+ || !(0, exports.sameRevisionRef)(registration.targetRevisionRef, instance.targetRevisionRef)) {
565
+ throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', `appInstances[${index}].targetRevisionRef`, 'Workbench app target is not present at the exact registered revision.');
566
+ }
567
+ assertTenantCompatible(instance.targetRevisionRef, scope, `appInstances[${index}].targetRevisionRef`);
568
+ const group = groupsById.get(instance.groupId);
569
+ const chain = [workbench.workbenchAccessPolicy, ...(group?.accessPolicy ? [group.accessPolicy] : []), instance.accessPolicy];
570
+ if (!(0, exports.accessPolicyChainImplies)(chain, registration.accessPolicy)) {
571
+ throw new DeclarativeControlCompilationError('AUDIENCE_WIDER_THAN_TARGET', `appInstances[${index}].accessPolicy`, 'Workbench and instance audience is wider than the target audience.');
572
+ }
573
+ return { ...instance, targetAccessPolicy: registration.accessPolicy };
574
+ });
575
+ const unsigned = {
576
+ contract: 'WorkbenchRuntimeBundle',
577
+ schemaVersion: 1,
578
+ tenantScope: scope,
579
+ releaseRevisionRef,
580
+ compilerRevisionRef,
581
+ generation: input.generation,
582
+ dependencySnapshot: release.dependencySnapshot,
583
+ rebuildable: true,
584
+ diagnostics: [],
585
+ workbenchId: workbench.workbenchId,
586
+ workbenchRevisionRef,
587
+ surface: release.target.surface,
588
+ routeClaims,
589
+ groups: workbench.groups,
590
+ appInstances,
591
+ defaultEntry: workbench.defaultEntry,
592
+ layout: workbench.layout,
593
+ workbenchAccessPolicy: workbench.workbenchAccessPolicy,
594
+ personalPreferencesPolicy: workbench.personalPreferencesPolicy,
595
+ target: { ...release.target, routeClaim: releaseRoute },
596
+ performanceBudgetRef: workbench.performanceBudgetRef,
597
+ observationPolicyRevisionRef: workbench.observationPolicyRevisionRef,
598
+ privacyClassification: workbench.privacyClassification,
599
+ };
600
+ return deepFreeze(declarative_control_1.WorkbenchRuntimeBundleSchema.parse({ ...unsigned, contentHash: (0, exports.canonicalContentHash)(unsigned) }));
601
+ };
602
+ exports.compileWorkbenchRuntimeBundle = compileWorkbenchRuntimeBundle;
603
+ const navigationDepth = (navigation) => {
604
+ const byId = new Map(navigation.nodes.map((node) => [node.nodeId, node]));
605
+ let maximum = 0;
606
+ navigation.nodes.forEach((node) => {
607
+ let depth = 1;
608
+ let parentId = node.parentNodeId;
609
+ while (parentId) {
610
+ depth += 1;
611
+ parentId = byId.get(parentId)?.parentNodeId ?? null;
612
+ }
613
+ maximum = Math.max(maximum, depth);
614
+ });
615
+ return maximum;
616
+ };
617
+ const orderedNavigationNodes = (navigation) => {
618
+ const children = new Map();
619
+ navigation.nodes.forEach((node) => {
620
+ const parent = node.parentNodeId ?? '';
621
+ const siblings = children.get(parent) ?? [];
622
+ children.set(parent, [...siblings, node]);
623
+ });
624
+ children.forEach((siblings) => siblings.sort((left, right) => left.order - right.order || left.nodeId.localeCompare(right.nodeId)));
625
+ const ordered = [];
626
+ const append = (parentId) => {
627
+ for (const node of children.get(parentId) ?? []) {
628
+ ordered.push(node);
629
+ append(node.nodeId);
630
+ }
631
+ };
632
+ append('');
633
+ return ordered;
634
+ };
635
+ const navigationDependencies = (navigation, release, compilerRevisionRef) => [
636
+ ...release.resolvedTargets.flatMap((target) => [
637
+ { role: target.targetRevisionRef.kind === 'domain-command' ? 'action' : target.targetRevisionRef.kind, revisionRef: target.targetRevisionRef },
638
+ ...(target.releaseRevisionRef ? [{ role: target.releaseRevisionRef.kind, revisionRef: target.releaseRevisionRef }] : []),
639
+ ]),
640
+ { role: 'performance-budget', revisionRef: navigation.performanceBudgetRef },
641
+ { role: 'observation-policy', revisionRef: navigation.observationPolicyRevisionRef },
642
+ { role: 'compiler', revisionRef: compilerRevisionRef },
643
+ ];
644
+ const compileNavigationRuntimeBundle = (input) => {
645
+ const navigation = declarative_control_1.NavigationSchema.parse(input.navigation);
646
+ const navigationRevisionRef = declarative_control_1.RevisionRefSchema.parse(input.navigationRevisionRef);
647
+ const release = declarative_control_1.NavigationReleaseSchema.parse(input.release);
648
+ const releaseRevisionRef = declarative_control_1.RevisionRefSchema.parse(input.releaseRevisionRef);
649
+ const compilerRevisionRef = declarative_control_1.RevisionRefSchema.parse(input.compilerRevisionRef);
650
+ const scope = declarative_control_1.TenantScopeSchema.parse(navigation.tenantScope);
651
+ assertSameTenantScope(release.tenantScope, scope, 'release.tenantScope');
652
+ if (navigation.nodes.length > input.limits.maxNavigationNodes)
653
+ throw new DeclarativeControlCompilationError('NAV_NODE_LIMIT_EXCEEDED', 'navigation.nodes', 'Navigation exceeds the caller-approved node limit.');
654
+ if (navigationDepth(navigation) > input.limits.maxNavigationDepth)
655
+ throw new DeclarativeControlCompilationError('NAV_DEPTH_EXCEEDED', 'navigation.nodes', 'Navigation exceeds the caller-approved depth limit.');
656
+ assertRevisionIdentity(navigationRevisionRef, 'navigation', navigation.navigationId, scope, 'navigationRevisionRef');
657
+ assertRevisionIdentity(release.navigationRevisionRef, 'navigation', navigation.navigationId, scope, 'release.navigationRevisionRef');
658
+ if (!(0, exports.sameRevisionRef)(navigationRevisionRef, release.navigationRevisionRef))
659
+ throw new DeclarativeControlCompilationError('REVISION_MISMATCH', 'release.navigationRevisionRef', 'Release does not pin the supplied Navigation revision.');
660
+ assertRevisionIdentity(releaseRevisionRef, 'navigation-release', release.releaseSlotId, scope, 'releaseRevisionRef');
661
+ if (release.target.surface !== navigation.supportedSurfaces.find((surface) => surface === release.target.surface)
662
+ || !navigation.placements.includes(release.target.placement)) {
663
+ throw new DeclarativeControlCompilationError('REVISION_MISMATCH', 'release.target', 'Navigation release target is not declared by the Navigation record.');
664
+ }
665
+ requireReleaseReady(release);
666
+ requireDependencies(release.dependencySnapshot, navigationDependencies(navigation, release, compilerRevisionRef));
667
+ assertDependencyScopes(release.dependencySnapshot, scope);
668
+ const targetRegistry = input.targetRegistry.map((registration, index) => {
669
+ const common = {
670
+ stableTargetRef: declarative_control_1.StableRefSchema.parse(registration.stableTargetRef),
671
+ targetRevisionRef: declarative_control_1.RevisionRefSchema.parse(registration.targetRevisionRef),
672
+ surface: declarative_control_1.ProductSurfaceSchema.parse(registration.surface),
673
+ accessPolicy: declarative_control_1.AccessPolicySchema.parse(registration.accessPolicy),
674
+ };
675
+ if (registration.kind === 'route') {
676
+ const routeClaim = declarative_control_1.CompiledRouteClaimSchema.parse(registration.routeClaim);
677
+ if (routeClaim.surface !== common.surface) {
678
+ throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', `targetRegistry[${index}].routeClaim.surface`, 'Navigation route claim must match its registered surface.');
679
+ }
680
+ return {
681
+ ...common,
682
+ kind: 'route',
683
+ releaseRevisionRef: registration.releaseRevisionRef ? declarative_control_1.RevisionRefSchema.parse(registration.releaseRevisionRef) : undefined,
684
+ routeClaim,
685
+ };
686
+ }
687
+ if (registration.kind === 'registered-menu-action') {
688
+ const sourceCatalogRevisionRef = declarative_control_1.RevisionRefSchema.parse(registration.sourceCatalogRevisionRef);
689
+ if (sourceCatalogRevisionRef.kind !== 'application-menu-catalog' || registration.targetRevisionRef.kind !== 'menu-action') {
690
+ throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', 'targetRegistry', 'Registered Menu Actions require exact menu-action and application-menu-catalog revisions.');
691
+ }
692
+ if (registration.inputSchemaRef && !registration.validateInput) {
693
+ throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', 'targetRegistry', 'Registered Menu Actions with input schemas require the active catalog validator.');
694
+ }
695
+ return { ...common, kind: 'registered-menu-action', applicationId: registration.applicationId, actionRef: registration.actionRef, inputSchemaRef: registration.inputSchemaRef, validateInput: registration.validateInput, sourceCatalogRevisionRef };
696
+ }
697
+ if (registration.targetRevisionRef.kind !== 'domain-command') {
698
+ throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', 'targetRegistry', 'Governed DomainCommand actions require an exact domain-command revision.');
699
+ }
700
+ const inputSchemaRevisionRef = declarative_control_1.RevisionRefSchema.parse(registration.inputSchemaRevisionRef);
701
+ const resultSchemaRevisionRef = registration.resultSchemaRevisionRef
702
+ ? declarative_control_1.RevisionRefSchema.parse(registration.resultSchemaRevisionRef)
703
+ : undefined;
704
+ if (inputSchemaRevisionRef.kind !== 'schema' || (resultSchemaRevisionRef && resultSchemaRevisionRef.kind !== 'schema')) {
705
+ throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', 'targetRegistry', 'Governed DomainCommand actions require exact input and output Schema revisions.');
706
+ }
707
+ return { ...common, kind: 'governed-domain-command', inputSchemaRevisionRef, resultSchemaRevisionRef };
708
+ });
709
+ assertUniqueRegistryKeys(targetRegistry.map((registration) => (0, exports.stableRefKey)(registration.stableTargetRef)), 'targetRegistry');
710
+ const targetsByStableRef = new Map(targetRegistry.map((registration) => [(0, exports.stableRefKey)(registration.stableTargetRef), registration]));
711
+ const releasedByNodeId = new Map(release.resolvedTargets.map((target) => [target.nodeId, target]));
712
+ const nodesById = new Map(navigation.nodes.map((node) => [node.nodeId, node]));
713
+ const nodes = orderedNavigationNodes(navigation).map((node, index) => {
714
+ const ancestors = [];
715
+ let parentId = node.parentNodeId;
716
+ while (parentId) {
717
+ const parent = nodesById.get(parentId);
718
+ if (parent?.kind === 'group')
719
+ ancestors.unshift(parent.audience);
720
+ parentId = parent?.parentNodeId ?? null;
721
+ }
722
+ if (node.kind !== 'target')
723
+ return { ...node, ancestorAccessPolicies: ancestors };
724
+ if (!['page', 'workbench', 'menu-action', 'domain-command'].includes(node.targetRef.kind)) {
725
+ throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', `nodes[${index}].targetRef.kind`, 'Navigation targets may reference only Page, Workbench, registered Menu Action, or DomainCommand identities.');
726
+ }
727
+ const registration = targetsByStableRef.get((0, exports.stableRefKey)(node.targetRef));
728
+ const released = releasedByNodeId.get(node.nodeId);
729
+ if (!registration || !released
730
+ || !(0, exports.sameStableRef)(registration.stableTargetRef, stableFromRevision(registration.targetRevisionRef))
731
+ || !(0, exports.sameStableRef)(registration.stableTargetRef, released.stableTargetRef)
732
+ || !(0, exports.sameRevisionRef)(registration.targetRevisionRef, released.targetRevisionRef)
733
+ || (registration.kind === 'route' && (Boolean(registration.releaseRevisionRef) !== Boolean(released.releaseRevisionRef)
734
+ || (registration.releaseRevisionRef && released.releaseRevisionRef && !(0, exports.sameRevisionRef)(registration.releaseRevisionRef, released.releaseRevisionRef))))) {
735
+ throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', `nodes[${index}].targetRef`, 'Navigation target is not resolved to the exact active release recorded by NavigationRelease.');
736
+ }
737
+ if (registration.surface !== release.target.surface) {
738
+ throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', `nodes[${index}].targetRef`, 'Navigation target is active on another surface.');
739
+ }
740
+ assertTenantCompatible(registration.targetRevisionRef, scope, `nodes[${index}].targetRef`);
741
+ if (!(0, exports.accessPolicyChainImplies)([...ancestors, node.audience], registration.accessPolicy)) {
742
+ throw new DeclarativeControlCompilationError('AUDIENCE_WIDER_THAN_TARGET', `nodes[${index}].audience`, 'Effective Navigation audience is wider than the target audience.');
743
+ }
744
+ const mappedInput = Object.fromEntries(Object.entries(node.parameterMapping).map(([name, source]) => {
745
+ if (source.kind !== 'constant') {
746
+ throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', `nodes[${index}].parameterMapping.${name}`, 'Navigation actions accept only publication-time constant input.');
747
+ }
748
+ return [name, source.value];
749
+ }));
750
+ let resolvedTarget;
751
+ if (registration.kind === 'route') {
752
+ resolvedTarget = { ...released, kind: 'route', accessPolicy: registration.accessPolicy, routeClaim: registration.routeClaim };
753
+ }
754
+ else if (registration.kind === 'registered-menu-action') {
755
+ if (!registration.inputSchemaRef && Object.keys(mappedInput).length > 0) {
756
+ throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', `nodes[${index}].parameterMapping`, 'The registered Menu Action does not accept input.');
757
+ }
758
+ let input;
759
+ try {
760
+ input = common_1.JsonObjectSchema.parse(registration.validateInput ? registration.validateInput(mappedInput) : mappedInput);
761
+ }
762
+ catch (error) {
763
+ throw new DeclarativeControlCompilationError('NAV_ACTION_INPUT_INVALID', `nodes[${index}].parameterMapping`, `Registered Menu Action input failed its active catalog schema: ${error instanceof Error ? error.message : String(error)}`);
764
+ }
765
+ const sourceDependency = release.dependencySnapshot.find((dependency) => dependency.role === 'application-menu-catalog' && (0, exports.sameRevisionRef)(dependency.revisionRef, registration.sourceCatalogRevisionRef));
766
+ if (!sourceDependency)
767
+ throw new DeclarativeControlCompilationError('DEPENDENCY_MISSING', `nodes[${index}].targetRef`, 'Registered Menu Action source catalog is not pinned by NavigationRelease.');
768
+ resolvedTarget = {
769
+ ...released,
770
+ kind: 'registered-menu-action',
771
+ accessPolicy: registration.accessPolicy,
772
+ execution: 'client',
773
+ applicationId: registration.applicationId,
774
+ actionRef: registration.actionRef,
775
+ ...(registration.inputSchemaRef ? { inputSchemaRef: registration.inputSchemaRef } : {}),
776
+ input,
777
+ sourceCatalogRevisionRef: registration.sourceCatalogRevisionRef,
778
+ };
779
+ }
780
+ else {
781
+ const inputDependency = release.dependencySnapshot.find((dependency) => dependency.role === 'schema' && (0, exports.sameRevisionRef)(dependency.revisionRef, registration.inputSchemaRevisionRef));
782
+ const resultDependency = registration.resultSchemaRevisionRef
783
+ ? release.dependencySnapshot.find((dependency) => dependency.role === 'schema' && (0, exports.sameRevisionRef)(dependency.revisionRef, registration.resultSchemaRevisionRef))
784
+ : undefined;
785
+ if (!inputDependency || (registration.resultSchemaRevisionRef && !resultDependency)) {
786
+ throw new DeclarativeControlCompilationError('DEPENDENCY_MISSING', `nodes[${index}].targetRef`, 'Governed DomainCommand schemas are not pinned by NavigationRelease.');
787
+ }
788
+ resolvedTarget = {
789
+ ...released,
790
+ kind: 'governed-domain-command',
791
+ accessPolicy: registration.accessPolicy,
792
+ execution: 'server',
793
+ commandRevisionRef: registration.targetRevisionRef,
794
+ inputSchemaRevisionRef: registration.inputSchemaRevisionRef,
795
+ ...(registration.resultSchemaRevisionRef ? { resultSchemaRevisionRef: registration.resultSchemaRevisionRef } : {}),
796
+ input: common_1.JsonObjectSchema.parse(mappedInput),
797
+ };
798
+ }
799
+ return {
800
+ ...node,
801
+ ancestorAccessPolicies: ancestors,
802
+ resolvedTarget,
803
+ };
804
+ });
805
+ const unsigned = {
806
+ contract: 'NavigationRuntimeBundle',
807
+ schemaVersion: 1,
808
+ tenantScope: scope,
809
+ releaseRevisionRef,
810
+ compilerRevisionRef,
811
+ generation: input.generation,
812
+ dependencySnapshot: release.dependencySnapshot,
813
+ rebuildable: true,
814
+ diagnostics: [],
815
+ navigationId: navigation.navigationId,
816
+ navigationRevisionRef,
817
+ surface: release.target.surface,
818
+ placement: release.target.placement,
819
+ nodes,
820
+ performanceBudgetRef: navigation.performanceBudgetRef,
821
+ observationPolicyRevisionRef: navigation.observationPolicyRevisionRef,
822
+ };
823
+ return deepFreeze(declarative_control_1.NavigationRuntimeBundleSchema.parse({ ...unsigned, contentHash: (0, exports.canonicalContentHash)(unsigned) }));
824
+ };
825
+ exports.compileNavigationRuntimeBundle = compileNavigationRuntimeBundle;
826
+ const validateWorkbenchRuntimeSet = (bundleInputs) => {
827
+ const bundles = bundleInputs.map((bundle) => declarative_control_1.WorkbenchRuntimeBundleSchema.parse(bundle));
828
+ if (bundles.length === 0) {
829
+ throw new DeclarativeControlCompilationError('WORKBENCH_RELEASE_SET_INVALID', 'bundles', 'An active Workbench release set must retain at least one Workbench.');
830
+ }
831
+ const first = bundles[0];
832
+ const seenIds = new Set();
833
+ const seenOrders = new Set();
834
+ let defaultCount = 0;
835
+ bundles.forEach((bundle, index) => {
836
+ if (scopeKey(bundle.tenantScope) !== scopeKey(first.tenantScope)
837
+ || bundle.surface !== first.surface
838
+ || !(0, exports.sameStableRef)(bundle.target.environmentRef, first.target.environmentRef)) {
839
+ throw new DeclarativeControlCompilationError('WORKBENCH_RELEASE_SET_INVALID', `bundles[${index}]`, 'Workbench release set entries must share tenant, environment, and surface.');
840
+ }
841
+ if (seenIds.has(bundle.workbenchId))
842
+ throw new DeclarativeControlCompilationError('WORKBENCH_RELEASE_SET_INVALID', `bundles[${index}].workbenchId`, 'Workbench identities must be unique in an active release set.');
843
+ if (seenOrders.has(bundle.target.order))
844
+ throw new DeclarativeControlCompilationError('WORKBENCH_RELEASE_SET_INVALID', `bundles[${index}].target.order`, 'Workbench order values must be unique in an active release set.');
845
+ seenIds.add(bundle.workbenchId);
846
+ seenOrders.add(bundle.target.order);
847
+ if (bundle.target.isDefaultCandidate)
848
+ defaultCount += 1;
849
+ });
850
+ if (defaultCount > 1)
851
+ throw new DeclarativeControlCompilationError('WORKBENCH_RELEASE_SET_INVALID', 'bundles', 'An active Workbench release set may have at most one default candidate.');
852
+ return Object.freeze([...bundles].sort((left, right) => left.target.order - right.target.order || left.workbenchId.localeCompare(right.workbenchId)));
853
+ };
854
+ exports.validateWorkbenchRuntimeSet = validateWorkbenchRuntimeSet;
855
+ const resolveWorkbenchEntry = (input) => {
856
+ if (input.requestedWorkbenchId) {
857
+ const requested = input.bundles.find((bundle) => bundle.workbenchId === input.requestedWorkbenchId);
858
+ if (!requested)
859
+ return { status: 'not-found', workbenchId: input.requestedWorkbenchId };
860
+ if (!input.isAllowed(requested))
861
+ return { status: 'forbidden', workbenchId: input.requestedWorkbenchId };
862
+ return { status: 'resolved', bundle: requested, source: 'explicit' };
863
+ }
864
+ const allowed = input.bundles
865
+ .filter(input.isAllowed)
866
+ .sort((left, right) => left.target.order - right.target.order || left.workbenchId.localeCompare(right.workbenchId));
867
+ const defaultBundle = allowed.find((bundle) => bundle.target.isDefaultCandidate);
868
+ if (defaultBundle)
869
+ return { status: 'resolved', bundle: defaultBundle, source: 'default' };
870
+ if (allowed[0])
871
+ return { status: 'resolved', bundle: allowed[0], source: 'first-accessible' };
872
+ return { status: 'forbidden', workbenchId: '' };
873
+ };
874
+ exports.resolveWorkbenchEntry = resolveWorkbenchEntry;
875
+ //# sourceMappingURL=declarative-control-compiler.js.map