@inf-monkeys-tech/monkeys 1.0.72 → 1.1.0
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/lib/contracts/aggregate-commit.d.ts +155 -0
- package/lib/contracts/aggregate-commit.d.ts.map +1 -0
- package/lib/contracts/aggregate-commit.js +112 -0
- package/lib/contracts/aggregate-commit.js.map +1 -0
- package/lib/contracts/capability.d.ts +3 -0
- package/lib/contracts/capability.d.ts.map +1 -1
- package/lib/contracts/capability.js +1 -1
- package/lib/contracts/capability.js.map +1 -1
- package/lib/contracts/common.d.ts +2 -0
- package/lib/contracts/common.d.ts.map +1 -1
- package/lib/contracts/common.js +34 -1
- package/lib/contracts/common.js.map +1 -1
- package/lib/contracts/component-assembly.d.ts +118 -0
- package/lib/contracts/component-assembly.d.ts.map +1 -0
- package/lib/contracts/component-assembly.js +61 -0
- package/lib/contracts/component-assembly.js.map +1 -0
- package/lib/contracts/declarative-control-http.d.ts +101608 -44791
- package/lib/contracts/declarative-control-http.d.ts.map +1 -1
- package/lib/contracts/declarative-control-http.js +1358 -86
- package/lib/contracts/declarative-control-http.js.map +1 -1
- package/lib/contracts/declarative-control.d.ts +9668 -3376
- package/lib/contracts/declarative-control.d.ts.map +1 -1
- package/lib/contracts/declarative-control.js +2585 -186
- package/lib/contracts/declarative-control.js.map +1 -1
- package/lib/contracts/index.d.ts +6 -0
- package/lib/contracts/index.d.ts.map +1 -1
- package/lib/contracts/index.js +6 -0
- package/lib/contracts/index.js.map +1 -1
- package/lib/contracts/legacy-route.d.ts +15 -0
- package/lib/contracts/legacy-route.d.ts.map +1 -0
- package/lib/contracts/legacy-route.js +13 -0
- package/lib/contracts/legacy-route.js.map +1 -0
- package/lib/contracts/menu.d.ts +12 -0
- package/lib/contracts/menu.d.ts.map +1 -1
- package/lib/contracts/page-binding-dependencies.d.ts +25 -0
- package/lib/contracts/page-binding-dependencies.d.ts.map +1 -0
- package/lib/contracts/page-binding-dependencies.js +54 -0
- package/lib/contracts/page-binding-dependencies.js.map +1 -0
- package/lib/contracts/page-expression.d.ts +106 -0
- package/lib/contracts/page-expression.d.ts.map +1 -0
- package/lib/contracts/page-expression.js +136 -0
- package/lib/contracts/page-expression.js.map +1 -0
- package/lib/contracts/page-stream.d.ts +101 -0
- package/lib/contracts/page-stream.d.ts.map +1 -0
- package/lib/contracts/page-stream.js +66 -0
- package/lib/contracts/page-stream.js.map +1 -0
- package/lib/contracts/page.d.ts +24 -0
- package/lib/contracts/page.d.ts.map +1 -1
- package/lib/contracts/page.js +2 -0
- package/lib/contracts/page.js.map +1 -1
- package/lib/contracts/record-editor-draft.d.ts +95 -0
- package/lib/contracts/record-editor-draft.d.ts.map +1 -0
- package/lib/contracts/record-editor-draft.js +35 -0
- package/lib/contracts/record-editor-draft.js.map +1 -0
- package/lib/contracts/render.d.ts +16 -0
- package/lib/contracts/render.d.ts.map +1 -1
- package/lib/contracts/render.js +3 -1
- package/lib/contracts/render.js.map +1 -1
- package/lib/contracts/semantic.d.ts +48 -1
- package/lib/contracts/semantic.d.ts.map +1 -1
- package/lib/contracts/semantic.js +22 -19
- package/lib/contracts/semantic.js.map +1 -1
- package/lib/contracts/tenant.d.ts +112 -6
- package/lib/contracts/tenant.d.ts.map +1 -1
- package/lib/contracts/tenant.js +14 -1
- package/lib/contracts/tenant.js.map +1 -1
- package/lib/esm/contracts/index.mjs +6921 -3032
- package/lib/esm/contracts/index.mjs.map +1 -1
- package/lib/esm/index.mjs +11333 -4947
- package/lib/esm/index.mjs.map +1 -1
- package/lib/esm/runtime/index.mjs +11514 -4411
- package/lib/esm/runtime/index.mjs.map +1 -1
- package/lib/esm/schemas/index.mjs +7282 -2571
- package/lib/esm/schemas/index.mjs.map +1 -1
- package/lib/json-schema/aggregate-commit-request.schema.json +426 -0
- package/lib/json-schema/capability-manifest.schema.json +1 -0
- package/lib/json-schema/capability-registry.schema.json +1 -0
- package/lib/json-schema/declarative-route-owner-index.schema.json +1092 -0
- package/lib/json-schema/declarative-workbench-catalog.schema.json +769 -0
- package/lib/json-schema/design-capability-catalog-artifact.schema.json +2787 -0
- package/lib/json-schema/domain-command-definition.schema.json +18 -0
- package/lib/json-schema/domain-query-definition.schema.json +1406 -0
- package/lib/json-schema/index.json +7 -0
- package/lib/json-schema/legacy-route-takeover-authorization.schema.json +601 -0
- package/lib/json-schema/navigation-release.schema.json +296 -0
- package/lib/json-schema/navigation-runtime-bundle.schema.json +48 -8
- package/lib/json-schema/navigation.schema.json +47 -8
- package/lib/json-schema/overlay-node.schema.json +281 -0
- package/lib/json-schema/page-definition.schema.json +34 -0
- package/lib/json-schema/page-release.schema.json +1520 -626
- package/lib/json-schema/page-runtime-bundle.schema.json +5980 -401
- package/lib/json-schema/page-runtime-descriptor.schema.json +34 -0
- package/lib/json-schema/page.schema.json +7333 -1482
- package/lib/json-schema/permission-alternative-policy.schema.json +60 -0
- package/lib/json-schema/product-declaration.schema.json +53 -0
- package/lib/json-schema/render-node.schema.json +281 -0
- package/lib/json-schema/render-tree.schema.json +281 -0
- package/lib/json-schema/tenant-product-config.schema.json +88 -0
- package/lib/json-schema/tenant-runtime-config.schema.json +88 -0
- package/lib/json-schema/view-provider-descriptor.schema.json +1 -0
- package/lib/json-schema/workbench-release.schema.json +1520 -626
- package/lib/json-schema/workbench-runtime-bundle.schema.json +686 -20
- package/lib/json-schema/workbench.schema.json +1196 -0
- package/lib/runtime/component-assembly.d.ts +4 -0
- package/lib/runtime/component-assembly.d.ts.map +1 -0
- package/lib/runtime/component-assembly.js +126 -0
- package/lib/runtime/component-assembly.js.map +1 -0
- package/lib/runtime/declarative-control-compiler.d.ts +66 -5
- package/lib/runtime/declarative-control-compiler.d.ts.map +1 -1
- package/lib/runtime/declarative-control-compiler.js +862 -109
- package/lib/runtime/declarative-control-compiler.js.map +1 -1
- package/lib/runtime/index.d.ts +5 -0
- package/lib/runtime/index.d.ts.map +1 -1
- package/lib/runtime/index.js +7 -0
- package/lib/runtime/index.js.map +1 -1
- package/lib/runtime/page-expression.d.ts +9 -0
- package/lib/runtime/page-expression.d.ts.map +1 -0
- package/lib/runtime/page-expression.js +257 -0
- package/lib/runtime/page-expression.js.map +1 -0
- package/lib/runtime/page-stream.d.ts +24 -0
- package/lib/runtime/page-stream.d.ts.map +1 -0
- package/lib/runtime/page-stream.js +65 -0
- package/lib/runtime/page-stream.js.map +1 -0
- package/lib/runtime/record-editor-draft.d.ts +29 -0
- package/lib/runtime/record-editor-draft.d.ts.map +1 -0
- package/lib/runtime/record-editor-draft.js +161 -0
- package/lib/runtime/record-editor-draft.js.map +1 -0
- package/lib/runtime/target-render-model.d.ts +4 -0
- package/lib/runtime/target-render-model.d.ts.map +1 -0
- package/lib/runtime/target-render-model.js +28 -0
- package/lib/runtime/target-render-model.js.map +1 -0
- package/lib/runtime/tenant-config.d.ts +2 -0
- package/lib/runtime/tenant-config.d.ts.map +1 -1
- package/lib/runtime/tenant-config.js +6 -1
- package/lib/runtime/tenant-config.js.map +1 -1
- package/lib/schemas/index.d.ts +6957 -2171
- package/lib/schemas/index.d.ts.map +1 -1
- package/lib/schemas/index.js +86 -8
- package/lib/schemas/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
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;
|
|
3
|
+
exports.resolveWorkbenchEntry = exports.validateWorkbenchRuntimeSet = exports.compileNavigationRuntimeBundle = exports.compileWorkbenchRuntimeBundle = exports.compilePageRuntimeBundle = exports.materializeRouteSpacePath = exports.matchCompiledRouteClaim = exports.compileRouteClaims = exports.compiledRouteClaimsOverlap = exports.accessPolicyChainImplies = exports.parseExactDesignCapabilityCatalogArtifact = exports.parseExactProductDeclarativeCapabilityRegistration = exports.compileDesignCapabilityCatalogArtifact = exports.designCapabilityCatalogArtifactHash = exports.declarativeProductResourceRevisionHash = exports.declarativeProductResourceSourceHash = exports.declarativeRouteSpaceRevisionHash = exports.declarativeRouteSpaceSourceHash = exports.declarativeCreateTemplateRevisionHash = exports.declarativeCreateTemplateSourceHash = exports.compileDeclarativeWorkbenchCatalog = exports.compileDeclarativeRouteOwnerIndex = exports.permissionAlternativePolicyAllows = exports.parseExactLegacyRouteTakeoverAuthorization = exports.legacyRouteTakeoverAuthorizationHash = exports.compileLegacyRouteTakeoverAuthorization = exports.declarativeWorkbenchCatalogProjectionId = exports.declarativeRouteOwnerIndexProjectionId = exports.declarativeRuntimeProjectionId = exports.canonicalContentHash = exports.sameRevisionRef = exports.sameStableRef = exports.revisionRefKey = exports.stableRefKey = exports.DeclarativeControlCompilationError = void 0;
|
|
4
4
|
const common_1 = require("../contracts/common");
|
|
5
|
+
const declarative_control_http_1 = require("../contracts/declarative-control-http");
|
|
5
6
|
const render_tree_compiler_1 = require("./render-tree-compiler");
|
|
6
7
|
const declarative_control_1 = require("../contracts/declarative-control");
|
|
7
8
|
class DeclarativeControlCompilationError extends Error {
|
|
@@ -46,19 +47,16 @@ const stableSerialize = (value) => {
|
|
|
46
47
|
.map((key) => `${JSON.stringify(key)}:${stableSerialize(record[key])}`)
|
|
47
48
|
.join(',')}}`;
|
|
48
49
|
};
|
|
49
|
-
const SHA256_INITIAL = [
|
|
50
|
-
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
|
51
|
-
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
|
52
|
-
];
|
|
50
|
+
const SHA256_INITIAL = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19];
|
|
53
51
|
const SHA256_ROUND = [
|
|
54
|
-
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98,
|
|
53
|
+
0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
|
54
|
+
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8,
|
|
55
|
+
0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
|
56
|
+
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
|
|
57
|
+
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
|
58
|
+
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
|
|
59
|
+
0xc67178f2,
|
|
62
60
|
];
|
|
63
61
|
const rotateRight = (value, amount) => (value >>> amount) | (value << (32 - amount));
|
|
64
62
|
const sha256Hex = (value) => {
|
|
@@ -78,7 +76,8 @@ const sha256Hex = (value) => {
|
|
|
78
76
|
for (let offset = 0; offset < source.length; offset += 64) {
|
|
79
77
|
for (let index = 0; index < 16; index += 1) {
|
|
80
78
|
const start = offset + index * 4;
|
|
81
|
-
words[index] =
|
|
79
|
+
words[index] =
|
|
80
|
+
((source[start] << 24) | (source[start + 1] << 16) | (source[start + 2] << 8) | source[start + 3]) >>> 0;
|
|
82
81
|
}
|
|
83
82
|
for (let index = 16; index < 64; index += 1) {
|
|
84
83
|
const previous = words[index - 15];
|
|
@@ -117,6 +116,104 @@ const sha256Hex = (value) => {
|
|
|
117
116
|
};
|
|
118
117
|
const canonicalContentHash = (value) => sha256Hex(stableSerialize(value));
|
|
119
118
|
exports.canonicalContentHash = canonicalContentHash;
|
|
119
|
+
/**
|
|
120
|
+
* Names one immutable Runtime Bundle projection by its exact Release evidence.
|
|
121
|
+
* The fixed-size digest stays below Data Server's 256-byte projection id limit
|
|
122
|
+
* even when a governed release slot uses the maximum contract identifier size.
|
|
123
|
+
*/
|
|
124
|
+
const declarativeRuntimeProjectionId = (resourceKind, releaseSlotId, releaseRevisionRef) => `drb:${(0, exports.canonicalContentHash)({ resourceKind, releaseSlotId, releaseRevisionRef })}`;
|
|
125
|
+
exports.declarativeRuntimeProjectionId = declarativeRuntimeProjectionId;
|
|
126
|
+
/** Names the rebuildable route-owner index for one tenant environment surface. */
|
|
127
|
+
const declarativeRouteOwnerIndexProjectionId = (tenantScope, environmentRef, surface) => `dri:${(0, exports.canonicalContentHash)({
|
|
128
|
+
tenantScope: {
|
|
129
|
+
teamRef: tenantScope.teamRef ? { kind: tenantScope.teamRef.kind, id: tenantScope.teamRef.id } : null,
|
|
130
|
+
},
|
|
131
|
+
environmentRef,
|
|
132
|
+
surface,
|
|
133
|
+
})}`;
|
|
134
|
+
exports.declarativeRouteOwnerIndexProjectionId = declarativeRouteOwnerIndexProjectionId;
|
|
135
|
+
const declarativeWorkbenchCatalogProjectionId = (tenantScope, environmentRef, surface) => `dwc:${(0, exports.canonicalContentHash)({
|
|
136
|
+
tenantScope: {
|
|
137
|
+
teamRef: tenantScope.teamRef ? { kind: tenantScope.teamRef.kind, id: tenantScope.teamRef.id } : null,
|
|
138
|
+
},
|
|
139
|
+
environmentRef,
|
|
140
|
+
surface,
|
|
141
|
+
})}`;
|
|
142
|
+
exports.declarativeWorkbenchCatalogProjectionId = declarativeWorkbenchCatalogProjectionId;
|
|
143
|
+
const takeoverHashSource = (authorization) => authorization;
|
|
144
|
+
const compileLegacyRouteTakeoverAuthorization = (input) => {
|
|
145
|
+
const unsigned = {
|
|
146
|
+
...input,
|
|
147
|
+
contract: 'LegacyRouteTakeoverAuthorization',
|
|
148
|
+
schemaVersion: 1,
|
|
149
|
+
};
|
|
150
|
+
return deepFreeze(declarative_control_1.LegacyRouteTakeoverAuthorizationSchema.parse({
|
|
151
|
+
...unsigned,
|
|
152
|
+
contentHash: (0, exports.canonicalContentHash)(takeoverHashSource(unsigned)),
|
|
153
|
+
}));
|
|
154
|
+
};
|
|
155
|
+
exports.compileLegacyRouteTakeoverAuthorization = compileLegacyRouteTakeoverAuthorization;
|
|
156
|
+
const legacyRouteTakeoverAuthorizationHash = (input) => (0, exports.canonicalContentHash)(takeoverHashSource(input));
|
|
157
|
+
exports.legacyRouteTakeoverAuthorizationHash = legacyRouteTakeoverAuthorizationHash;
|
|
158
|
+
const parseExactLegacyRouteTakeoverAuthorization = (input) => {
|
|
159
|
+
const parsed = declarative_control_1.LegacyRouteTakeoverAuthorizationSchema.parse(input);
|
|
160
|
+
const { contentHash, ...unsigned } = parsed;
|
|
161
|
+
if (contentHash !== (0, exports.legacyRouteTakeoverAuthorizationHash)(unsigned)) {
|
|
162
|
+
throw new DeclarativeControlCompilationError('ROUTE_TAKEOVER_INVALID', 'contentHash', 'Legacy route takeover authorization content hash is not exact.');
|
|
163
|
+
}
|
|
164
|
+
return deepFreeze(parsed);
|
|
165
|
+
};
|
|
166
|
+
exports.parseExactLegacyRouteTakeoverAuthorization = parseExactLegacyRouteTakeoverAuthorization;
|
|
167
|
+
const permissionAlternativePolicyAllows = (policyInput, permissionCodes) => {
|
|
168
|
+
const parsed = declarative_control_1.PermissionAlternativePolicySchema.parse(policyInput);
|
|
169
|
+
const available = permissionCodes instanceof Set ? permissionCodes : new Set(permissionCodes);
|
|
170
|
+
return parsed.alternatives.some((alternative) => alternative.every((permission) => available.has(permission)));
|
|
171
|
+
};
|
|
172
|
+
exports.permissionAlternativePolicyAllows = permissionAlternativePolicyAllows;
|
|
173
|
+
const compileDeclarativeRouteOwnerIndex = (input) => {
|
|
174
|
+
const entries = input.entries
|
|
175
|
+
.map((entry) => ({ ...entry }))
|
|
176
|
+
.sort((left, right) => {
|
|
177
|
+
const leftKey = `${left.resourceKind}:${left.releaseSlotId}`;
|
|
178
|
+
const rightKey = `${right.resourceKind}:${right.releaseSlotId}`;
|
|
179
|
+
return leftKey.localeCompare(rightKey);
|
|
180
|
+
});
|
|
181
|
+
const unsigned = {
|
|
182
|
+
contract: 'DeclarativeRouteOwnerIndex',
|
|
183
|
+
schemaVersion: 1,
|
|
184
|
+
tenantScope: declarative_control_1.TenantScopeSchema.parse(input.tenantScope),
|
|
185
|
+
environmentRef: declarative_control_1.StableRefSchema.parse(input.environmentRef),
|
|
186
|
+
surface: input.surface,
|
|
187
|
+
generation: input.generation,
|
|
188
|
+
entries,
|
|
189
|
+
rebuildable: true,
|
|
190
|
+
};
|
|
191
|
+
return deepFreeze(declarative_control_1.DeclarativeRouteOwnerIndexSchema.parse({
|
|
192
|
+
...unsigned,
|
|
193
|
+
contentHash: (0, exports.canonicalContentHash)(unsigned),
|
|
194
|
+
}));
|
|
195
|
+
};
|
|
196
|
+
exports.compileDeclarativeRouteOwnerIndex = compileDeclarativeRouteOwnerIndex;
|
|
197
|
+
const compileDeclarativeWorkbenchCatalog = (input) => {
|
|
198
|
+
const entries = input.entries
|
|
199
|
+
.map((entry) => ({ ...entry }))
|
|
200
|
+
.sort((left, right) => left.order - right.order || left.workbenchId.localeCompare(right.workbenchId));
|
|
201
|
+
const unsigned = {
|
|
202
|
+
contract: 'DeclarativeWorkbenchCatalog',
|
|
203
|
+
schemaVersion: 1,
|
|
204
|
+
tenantScope: declarative_control_1.TenantScopeSchema.parse(input.tenantScope),
|
|
205
|
+
environmentRef: declarative_control_1.StableRefSchema.parse(input.environmentRef),
|
|
206
|
+
surface: input.surface,
|
|
207
|
+
generation: input.generation,
|
|
208
|
+
entries,
|
|
209
|
+
rebuildable: true,
|
|
210
|
+
};
|
|
211
|
+
return deepFreeze(declarative_control_1.DeclarativeWorkbenchCatalogSchema.parse({
|
|
212
|
+
...unsigned,
|
|
213
|
+
contentHash: (0, exports.canonicalContentHash)(unsigned),
|
|
214
|
+
}));
|
|
215
|
+
};
|
|
216
|
+
exports.compileDeclarativeWorkbenchCatalog = compileDeclarativeWorkbenchCatalog;
|
|
120
217
|
const declarativeCreateTemplateSourceHash = (document) => (0, exports.canonicalContentHash)(document);
|
|
121
218
|
exports.declarativeCreateTemplateSourceHash = declarativeCreateTemplateSourceHash;
|
|
122
219
|
const declarativeCreateTemplateRevisionHash = (registration) => (0, exports.canonicalContentHash)(registration.document);
|
|
@@ -129,6 +226,98 @@ const declarativeProductResourceSourceHash = (document) => (0, exports.canonical
|
|
|
129
226
|
exports.declarativeProductResourceSourceHash = declarativeProductResourceSourceHash;
|
|
130
227
|
const declarativeProductResourceRevisionHash = (registration) => (0, exports.canonicalContentHash)(registration.document);
|
|
131
228
|
exports.declarativeProductResourceRevisionHash = declarativeProductResourceRevisionHash;
|
|
229
|
+
const designCapabilityCatalogHashSource = (input) => ({
|
|
230
|
+
contract: 'DesignCapabilityCatalogArtifact',
|
|
231
|
+
schemaVersion: 1,
|
|
232
|
+
sourceRef: input.sourceRef,
|
|
233
|
+
entries: input.entries,
|
|
234
|
+
});
|
|
235
|
+
const designCapabilityCatalogArtifactHash = (input) => (0, exports.canonicalContentHash)(designCapabilityCatalogHashSource(input));
|
|
236
|
+
exports.designCapabilityCatalogArtifactHash = designCapabilityCatalogArtifactHash;
|
|
237
|
+
const compileDesignCapabilityCatalogArtifact = (input) => {
|
|
238
|
+
const entries = input.entries
|
|
239
|
+
.map((entry) => ({ ...entry }))
|
|
240
|
+
.sort((left, right) => left.manifest.id.localeCompare(right.manifest.id));
|
|
241
|
+
entries.forEach((entry, index) => {
|
|
242
|
+
const registration = entry.declarativeRegistration;
|
|
243
|
+
const { registrationRevisionRef: _registrationRevisionRef, sourceContentHash: _sourceContentHash, ...unsignedRegistration } = registration;
|
|
244
|
+
const registrationHash = (0, exports.canonicalContentHash)(unsignedRegistration);
|
|
245
|
+
if (registration.capabilityRevisionRef.id !== entry.manifest.id ||
|
|
246
|
+
registration.capabilityRevisionRef.ownerRepo !== entry.manifest.ownerRepo ||
|
|
247
|
+
String(registration.capabilityRevisionRef.revision) !== String(entry.manifest.capabilityVersion) ||
|
|
248
|
+
registration.capabilityRevisionRef.contentHash !== (0, exports.canonicalContentHash)(entry.manifest) ||
|
|
249
|
+
registration.providerRevisionRef.id !== entry.provider.providerId ||
|
|
250
|
+
registration.providerRevisionRef.ownerRepo !== entry.provider.ownerRepo ||
|
|
251
|
+
String(registration.providerRevisionRef.revision) !== String(entry.provider.providerVersion) ||
|
|
252
|
+
registration.providerRevisionRef.contentHash !== (0, exports.canonicalContentHash)(entry.provider) ||
|
|
253
|
+
registration.sourceContentHash !== registrationHash ||
|
|
254
|
+
registration.registrationRevisionRef.contentHash !== registrationHash) {
|
|
255
|
+
throw new DeclarativeControlCompilationError('DESIGN_CATALOG_INVALID', `entries[${index}]`, 'Design capability manifest, provider and authoring registration are not exact.');
|
|
256
|
+
}
|
|
257
|
+
registration.schemaDocuments.forEach((schema, schemaIndex) => {
|
|
258
|
+
if (schema.schemaRevisionRef.ownerRepo !== 'monkeys-design' ||
|
|
259
|
+
schema.schemaRevisionRef.visibility !== 'global' ||
|
|
260
|
+
schema.schemaRevisionRef.contentHash !== (0, exports.canonicalContentHash)(schema.document)) {
|
|
261
|
+
throw new DeclarativeControlCompilationError('DESIGN_CATALOG_INVALID', `entries[${index}].declarativeRegistration.schemaDocuments[${schemaIndex}]`, 'Design Schema documents require exact global monkeys-design authority.');
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
const sourceContentHash = (0, exports.designCapabilityCatalogArtifactHash)({
|
|
266
|
+
sourceRef: input.sourceRef,
|
|
267
|
+
entries,
|
|
268
|
+
});
|
|
269
|
+
const sourceRevisionRef = declarative_control_1.RevisionRefSchema.parse({
|
|
270
|
+
kind: 'design-capability-catalog',
|
|
271
|
+
id: input.sourceRef,
|
|
272
|
+
ownerRepo: 'monkeys-design',
|
|
273
|
+
visibility: 'global',
|
|
274
|
+
revision: input.revision,
|
|
275
|
+
schemaVersion: 1,
|
|
276
|
+
contentHash: sourceContentHash,
|
|
277
|
+
});
|
|
278
|
+
return deepFreeze(declarative_control_http_1.DesignCapabilityCatalogArtifactSchema.parse({
|
|
279
|
+
contract: 'DesignCapabilityCatalogArtifact',
|
|
280
|
+
schemaVersion: 1,
|
|
281
|
+
sourceRef: input.sourceRef,
|
|
282
|
+
sourceRevisionRef,
|
|
283
|
+
entries,
|
|
284
|
+
sourceContentHash,
|
|
285
|
+
}));
|
|
286
|
+
};
|
|
287
|
+
exports.compileDesignCapabilityCatalogArtifact = compileDesignCapabilityCatalogArtifact;
|
|
288
|
+
/** Validate immutable product-owned capability provenance from an application release. */
|
|
289
|
+
const parseExactProductDeclarativeCapabilityRegistration = (input) => {
|
|
290
|
+
const entry = declarative_control_http_1.ProductDeclarativeCapabilityRegistrationSchema.parse(input);
|
|
291
|
+
const registration = entry.declarativeRegistration;
|
|
292
|
+
const { registrationRevisionRef: _registrationRevisionRef, sourceContentHash: _sourceContentHash, ...unsignedRegistration } = registration;
|
|
293
|
+
if (registration.capabilityRevisionRef.contentHash !== (0, exports.canonicalContentHash)(entry.manifest) ||
|
|
294
|
+
registration.providerRevisionRef.contentHash !== (0, exports.canonicalContentHash)(entry.provider) ||
|
|
295
|
+
registration.sourceContentHash !== (0, exports.canonicalContentHash)(unsignedRegistration) ||
|
|
296
|
+
registration.registrationRevisionRef.contentHash !== registration.sourceContentHash) {
|
|
297
|
+
throw new DeclarativeControlCompilationError('PRODUCT_CAPABILITY_CATALOG_INVALID', 'declarativeRegistration', 'Product capability manifest, provider and authoring registration are not exact.');
|
|
298
|
+
}
|
|
299
|
+
registration.schemaDocuments.forEach((schema, schemaIndex) => {
|
|
300
|
+
if (schema.schemaRevisionRef.contentHash !== (0, exports.canonicalContentHash)(schema.document)) {
|
|
301
|
+
throw new DeclarativeControlCompilationError('PRODUCT_CAPABILITY_CATALOG_INVALID', `declarativeRegistration.schemaDocuments[${schemaIndex}]`, 'Product capability Schema document does not match its exact RevisionRef.');
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
return deepFreeze(entry);
|
|
305
|
+
};
|
|
306
|
+
exports.parseExactProductDeclarativeCapabilityRegistration = parseExactProductDeclarativeCapabilityRegistration;
|
|
307
|
+
const parseExactDesignCapabilityCatalogArtifact = (input) => {
|
|
308
|
+
const parsed = declarative_control_http_1.DesignCapabilityCatalogArtifactSchema.parse(input);
|
|
309
|
+
const expected = (0, exports.compileDesignCapabilityCatalogArtifact)({
|
|
310
|
+
sourceRef: parsed.sourceRef,
|
|
311
|
+
revision: parsed.sourceRevisionRef.revision,
|
|
312
|
+
entries: parsed.entries,
|
|
313
|
+
});
|
|
314
|
+
if (parsed.sourceContentHash !== expected.sourceContentHash ||
|
|
315
|
+
!(0, exports.sameRevisionRef)(parsed.sourceRevisionRef, expected.sourceRevisionRef)) {
|
|
316
|
+
throw new DeclarativeControlCompilationError('DESIGN_CATALOG_INVALID', 'sourceRevisionRef', 'Design capability catalog artifact provenance or content hash is not exact.');
|
|
317
|
+
}
|
|
318
|
+
return deepFreeze(parsed);
|
|
319
|
+
};
|
|
320
|
+
exports.parseExactDesignCapabilityCatalogArtifact = parseExactDesignCapabilityCatalogArtifact;
|
|
132
321
|
const deepFreeze = (value) => {
|
|
133
322
|
if (value === null || typeof value !== 'object' || Object.isFrozen(value))
|
|
134
323
|
return value;
|
|
@@ -170,16 +359,27 @@ const requireDependencies = (snapshot, required) => {
|
|
|
170
359
|
};
|
|
171
360
|
const assertDependencyScopes = (snapshot, scope) => snapshot.forEach((dependency, index) => assertTenantCompatible(dependency.revisionRef, scope, `dependencySnapshot[${index}].revisionRef`));
|
|
172
361
|
const requireReleaseReady = (release) => {
|
|
362
|
+
if (release.operation === 'deactivate') {
|
|
363
|
+
throw new DeclarativeControlCompilationError('RELEASE_OPERATION_INVALID', 'operation', 'A deactivation Release cannot produce an active runtime bundle.');
|
|
364
|
+
}
|
|
173
365
|
if (release.evidence.validation.result !== 'pass') {
|
|
174
366
|
throw new DeclarativeControlCompilationError('RELEASE_VALIDATION_FAILED', 'evidence.validation.result', 'Runtime bundles require a passing release validation result.');
|
|
175
367
|
}
|
|
176
368
|
};
|
|
177
369
|
const refSet = (values) => new Set(values.map(exports.stableRefKey));
|
|
178
370
|
const chainRequiresAll = (policies, field) => {
|
|
179
|
-
if (field === 'permissionAllOf')
|
|
180
|
-
return new Set(policies.flatMap((policy) =>
|
|
181
|
-
|
|
182
|
-
|
|
371
|
+
if (field === 'permissionAllOf') {
|
|
372
|
+
return new Set(policies.flatMap((policy) => [
|
|
373
|
+
...policy.permissionAllOf,
|
|
374
|
+
...(policy.permissionAnyOf.length === 1 ? policy.permissionAnyOf : []),
|
|
375
|
+
]));
|
|
376
|
+
}
|
|
377
|
+
if (field === 'groupAllOf') {
|
|
378
|
+
return refSet(policies.flatMap((policy) => [
|
|
379
|
+
...policy.groupAllOf,
|
|
380
|
+
...(policy.groupAnyOf.length === 1 ? policy.groupAnyOf : []),
|
|
381
|
+
]));
|
|
382
|
+
}
|
|
183
383
|
return new Set(policies.flatMap((policy) => policy.conditionAllOf.map(exports.revisionRefKey)));
|
|
184
384
|
};
|
|
185
385
|
const chainImpliesAny = (policies, targetAny, allValues, anyValues) => {
|
|
@@ -218,7 +418,7 @@ const normalizePath = (path, routeSpace) => {
|
|
|
218
418
|
if (!routeSpace.caseSensitive) {
|
|
219
419
|
normalized = normalized
|
|
220
420
|
.split('/')
|
|
221
|
-
.map((segment) => segment.startsWith(':') ? segment : segment.toLowerCase())
|
|
421
|
+
.map((segment) => (segment.startsWith(':') ? segment : segment.toLowerCase()))
|
|
222
422
|
.join('/');
|
|
223
423
|
}
|
|
224
424
|
if (routeSpace.trailingSlash === 'remove' && normalized.length > 1)
|
|
@@ -227,7 +427,65 @@ const normalizePath = (path, routeSpace) => {
|
|
|
227
427
|
normalized += '/';
|
|
228
428
|
return normalized;
|
|
229
429
|
};
|
|
430
|
+
const acceptedTrailingSlashStates = (claim) => {
|
|
431
|
+
if (claim.matcher.trailingSlash === 'remove')
|
|
432
|
+
return new Set([false, true]);
|
|
433
|
+
if (claim.matcher.trailingSlash === 'require')
|
|
434
|
+
return new Set([true]);
|
|
435
|
+
return new Set([claim.normalizedPath.length > 1 && claim.normalizedPath.endsWith('/')]);
|
|
436
|
+
};
|
|
437
|
+
const routeSegmentParameter = (segment) => segment.match(/^[:$]([A-Za-z][A-Za-z0-9_-]*)$/)?.[1];
|
|
438
|
+
const parameterTypeFor = (claim, name) => claim.matcher.parameters.find((parameter) => parameter.name === name)?.type;
|
|
439
|
+
const compiledRouteClaimsOverlap = (leftInput, rightInput) => {
|
|
440
|
+
const left = declarative_control_1.CompiledRouteClaimSchema.parse(leftInput);
|
|
441
|
+
const right = declarative_control_1.CompiledRouteClaimSchema.parse(rightInput);
|
|
442
|
+
if (![...acceptedTrailingSlashStates(left)].some((state) => acceptedTrailingSlashStates(right).has(state)))
|
|
443
|
+
return false;
|
|
444
|
+
const leftSegments = left.normalizedPath.split('/').filter(Boolean);
|
|
445
|
+
const rightSegments = right.normalizedPath.split('/').filter(Boolean);
|
|
446
|
+
if (leftSegments.length !== rightSegments.length)
|
|
447
|
+
return false;
|
|
448
|
+
return leftSegments.every((leftSegment, index) => {
|
|
449
|
+
const rightSegment = rightSegments[index];
|
|
450
|
+
const leftParameter = routeSegmentParameter(leftSegment);
|
|
451
|
+
const rightParameter = routeSegmentParameter(rightSegment);
|
|
452
|
+
if (!leftParameter && !rightParameter) {
|
|
453
|
+
if (left.matcher.caseSensitive && right.matcher.caseSensitive)
|
|
454
|
+
return leftSegment === rightSegment;
|
|
455
|
+
return leftSegment.toLowerCase() === rightSegment.toLowerCase();
|
|
456
|
+
}
|
|
457
|
+
if (leftParameter && !rightParameter) {
|
|
458
|
+
const type = parameterTypeFor(left, leftParameter);
|
|
459
|
+
return !!type && routeParameterPattern(type).test(rightSegment);
|
|
460
|
+
}
|
|
461
|
+
if (!leftParameter && rightParameter) {
|
|
462
|
+
const type = parameterTypeFor(right, rightParameter);
|
|
463
|
+
return !!type && routeParameterPattern(type).test(leftSegment);
|
|
464
|
+
}
|
|
465
|
+
const leftType = parameterTypeFor(left, leftParameter);
|
|
466
|
+
const rightType = parameterTypeFor(right, rightParameter);
|
|
467
|
+
if (!leftType || !rightType)
|
|
468
|
+
return false;
|
|
469
|
+
return !(leftType === 'integer' && rightType === 'uuid') && !(leftType === 'uuid' && rightType === 'integer');
|
|
470
|
+
});
|
|
471
|
+
};
|
|
472
|
+
exports.compiledRouteClaimsOverlap = compiledRouteClaimsOverlap;
|
|
230
473
|
const compileRouteClaims = (input) => {
|
|
474
|
+
const embeddedTakeovers = input.claims.flatMap((claim) => {
|
|
475
|
+
const authorization = 'legacyRouteTakeoverAuthorization' in claim ? claim.legacyRouteTakeoverAuthorization : undefined;
|
|
476
|
+
return authorization ? [authorization] : [];
|
|
477
|
+
});
|
|
478
|
+
const takeoverAuthorizations = [...(input.legacyRouteTakeoverAuthorizations ?? []), ...embeddedTakeovers].map((authorization, index) => {
|
|
479
|
+
try {
|
|
480
|
+
return (0, exports.parseExactLegacyRouteTakeoverAuthorization)(authorization);
|
|
481
|
+
}
|
|
482
|
+
catch (error) {
|
|
483
|
+
if (error instanceof DeclarativeControlCompilationError) {
|
|
484
|
+
throw new DeclarativeControlCompilationError(error.code, `legacyRouteTakeoverAuthorizations[${index}].${error.path}`, error.message);
|
|
485
|
+
}
|
|
486
|
+
throw error;
|
|
487
|
+
}
|
|
488
|
+
});
|
|
231
489
|
const registrations = input.routeSpaces.map((entry, index) => {
|
|
232
490
|
const revisionRef = declarative_control_1.RevisionRefSchema.parse(entry.revisionRef);
|
|
233
491
|
const routeSpace = declarative_control_1.RouteSpaceSchema.parse(entry.routeSpace);
|
|
@@ -238,18 +496,16 @@ const compileRouteClaims = (input) => {
|
|
|
238
496
|
});
|
|
239
497
|
assertUniqueRegistryKeys(registrations.map((entry) => (0, exports.revisionRefKey)(entry.revisionRef)), 'routeSpaces');
|
|
240
498
|
const routeSpacesByRevision = new Map(registrations.map((entry) => [(0, exports.revisionRefKey)(entry.revisionRef), entry.routeSpace]));
|
|
241
|
-
const normalizedPaths = new Set();
|
|
242
499
|
const compiled = [];
|
|
243
500
|
input.claims.forEach((inputClaim, index) => {
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const routeSpace = routeSpacesByRevision.get((0, exports.revisionRefKey)(parsedClaim.routeSpaceRevisionRef));
|
|
501
|
+
const { legacyRouteTakeoverAuthorization: _authorization, ...runtimeClaim } = inputClaim;
|
|
502
|
+
const legacyClaim = 'surface' in runtimeClaim ? declarative_control_1.RouteClaimSchema.parse(runtimeClaim) : declarative_control_1.LegacyRouteClaimSchema.parse(runtimeClaim);
|
|
503
|
+
const routeSpace = routeSpacesByRevision.get((0, exports.revisionRefKey)(legacyClaim.routeSpaceRevisionRef));
|
|
248
504
|
if (!routeSpace)
|
|
249
505
|
throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISSING', `routeClaims[${index}].routeSpaceRevisionRef`, 'No exact RouteSpace registration exists.');
|
|
250
506
|
const claim = declarative_control_1.RouteClaimSchema.parse({
|
|
251
|
-
...
|
|
252
|
-
surface: 'surface' in
|
|
507
|
+
...legacyClaim,
|
|
508
|
+
surface: 'surface' in legacyClaim ? legacyClaim.surface : routeSpace.supportedSurface,
|
|
253
509
|
});
|
|
254
510
|
if (routeSpace.supportedSurface !== claim.surface) {
|
|
255
511
|
throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', `routeClaims[${index}].surface`, `Route claim surface ${claim.surface} does not match RouteSpace ${routeSpace.routeSpaceId}.`);
|
|
@@ -266,26 +522,43 @@ const compileRouteClaims = (input) => {
|
|
|
266
522
|
if (unknownParameter) {
|
|
267
523
|
throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', `routeClaims[${index}].pathTemplate`, `Route parameter ${unknownParameter} is not declared by ${routeSpace.routeSpaceId}.`);
|
|
268
524
|
}
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const
|
|
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({
|
|
525
|
+
const matcher = {
|
|
526
|
+
surface: claim.surface,
|
|
527
|
+
caseSensitive: routeSpace.caseSensitive,
|
|
528
|
+
trailingSlash: routeSpace.trailingSlash,
|
|
529
|
+
parameters: routeSpace.parameters,
|
|
530
|
+
};
|
|
531
|
+
const compiledClaim = declarative_control_1.CompiledRouteClaimSchema.parse({
|
|
280
532
|
...claim,
|
|
281
533
|
normalizedPath,
|
|
282
|
-
matcher
|
|
534
|
+
matcher,
|
|
535
|
+
});
|
|
536
|
+
const reserved = routeSpace.reservedPaths.some((candidate) => {
|
|
537
|
+
const normalizedReserved = normalizePath(candidate, routeSpace);
|
|
538
|
+
const reservedClaim = declarative_control_1.CompiledRouteClaimSchema.parse({
|
|
539
|
+
kind: 'canonical',
|
|
540
|
+
routeSpaceRevisionRef: claim.routeSpaceRevisionRef,
|
|
541
|
+
pathTemplate: candidate,
|
|
283
542
|
surface: claim.surface,
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
543
|
+
normalizedPath: normalizedReserved,
|
|
544
|
+
matcher,
|
|
545
|
+
});
|
|
546
|
+
return ((0, exports.compiledRouteClaimsOverlap)(compiledClaim, reservedClaim) ||
|
|
547
|
+
normalizedPath.startsWith(`${normalizedReserved.replace(/\/+$/, '')}/`));
|
|
548
|
+
});
|
|
549
|
+
if (reserved) {
|
|
550
|
+
const takeover = takeoverAuthorizations.find((authorization) => compiledClaim.kind === 'canonical' &&
|
|
551
|
+
authorization.normalizedPath === compiledClaim.normalizedPath &&
|
|
552
|
+
(0, exports.sameRevisionRef)(authorization.routeSpaceRevisionRef, compiledClaim.routeSpaceRevisionRef));
|
|
553
|
+
if (!takeover) {
|
|
554
|
+
throw new DeclarativeControlCompilationError('ROUTE_RESERVED', `routeClaims[${index}].pathTemplate`, `Route ${normalizedPath} is reserved by ${routeSpace.routeSpaceId}.`);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
const conflict = compiled.find((candidate) => (0, exports.sameRevisionRef)(candidate.routeSpaceRevisionRef, claim.routeSpaceRevisionRef) &&
|
|
558
|
+
(0, exports.compiledRouteClaimsOverlap)(candidate, compiledClaim));
|
|
559
|
+
if (conflict)
|
|
560
|
+
throw new DeclarativeControlCompilationError('ROUTE_CONFLICT', `routeClaims[${index}].pathTemplate`, `Route ${normalizedPath} overlaps another active claim pattern.`);
|
|
561
|
+
compiled.push(compiledClaim);
|
|
289
562
|
});
|
|
290
563
|
if (!compiled.some((claim) => claim.kind === 'canonical')) {
|
|
291
564
|
throw new DeclarativeControlCompilationError('ROUTE_CONFLICT', 'routeClaims', 'At least one canonical route claim is required.');
|
|
@@ -293,7 +566,81 @@ const compileRouteClaims = (input) => {
|
|
|
293
566
|
return Object.freeze(compiled);
|
|
294
567
|
};
|
|
295
568
|
exports.compileRouteClaims = compileRouteClaims;
|
|
296
|
-
|
|
569
|
+
/**
|
|
570
|
+
* Matches an application-relative request path using only the policy frozen into
|
|
571
|
+
* a CompiledRouteClaim. Runtime consumers must not reconstruct RouteSpace policy
|
|
572
|
+
* from product ids or deployment configuration.
|
|
573
|
+
*/
|
|
574
|
+
const matchCompiledRouteClaim = (claimInput, pathInput) => {
|
|
575
|
+
const claim = declarative_control_1.CompiledRouteClaimSchema.parse(claimInput);
|
|
576
|
+
const rawPath = String(pathInput || '').trim();
|
|
577
|
+
if (!rawPath.startsWith('/') ||
|
|
578
|
+
rawPath.includes('?') ||
|
|
579
|
+
rawPath.includes('#') ||
|
|
580
|
+
rawPath.includes('\\') ||
|
|
581
|
+
rawPath.includes('://')) {
|
|
582
|
+
return { matched: false, parameters: {} };
|
|
583
|
+
}
|
|
584
|
+
const rawSegments = rawPath.split('/');
|
|
585
|
+
if (rawSegments.some((segment) => segment === '.' || segment === '..'))
|
|
586
|
+
return { matched: false, parameters: {} };
|
|
587
|
+
const requestHasTrailingSlash = rawPath.length > 1 && rawPath.endsWith('/');
|
|
588
|
+
if (claim.matcher.trailingSlash === 'require' && !requestHasTrailingSlash)
|
|
589
|
+
return { matched: false, parameters: {} };
|
|
590
|
+
if (claim.matcher.trailingSlash === 'preserve' &&
|
|
591
|
+
requestHasTrailingSlash !== (claim.normalizedPath.length > 1 && claim.normalizedPath.endsWith('/'))) {
|
|
592
|
+
return { matched: false, parameters: {} };
|
|
593
|
+
}
|
|
594
|
+
const normalizeTrailing = (value) => {
|
|
595
|
+
if (claim.matcher.trailingSlash === 'remove' && value.length > 1)
|
|
596
|
+
return value.replace(/\/+$/, '');
|
|
597
|
+
if (claim.matcher.trailingSlash === 'require' && value.length > 1 && !value.endsWith('/'))
|
|
598
|
+
return `${value}/`;
|
|
599
|
+
return value;
|
|
600
|
+
};
|
|
601
|
+
const requestPath = normalizeTrailing(rawPath);
|
|
602
|
+
const templatePath = normalizeTrailing(claim.normalizedPath);
|
|
603
|
+
const requestSegments = requestPath.split('/').filter(Boolean);
|
|
604
|
+
const templateSegments = templatePath.split('/').filter(Boolean);
|
|
605
|
+
if (requestSegments.length !== templateSegments.length)
|
|
606
|
+
return { matched: false, parameters: {} };
|
|
607
|
+
const parameterDefinitions = new Map(claim.matcher.parameters.map((parameter) => [parameter.name, parameter]));
|
|
608
|
+
const parameters = {};
|
|
609
|
+
const normalizedSegments = [];
|
|
610
|
+
for (let index = 0; index < templateSegments.length; index += 1) {
|
|
611
|
+
const template = templateSegments[index];
|
|
612
|
+
const rawValue = requestSegments[index];
|
|
613
|
+
const match = template.match(/^[:$]([A-Za-z][A-Za-z0-9_-]*)$/);
|
|
614
|
+
if (!match) {
|
|
615
|
+
if ((claim.matcher.caseSensitive ? template : template.toLowerCase()) !==
|
|
616
|
+
(claim.matcher.caseSensitive ? rawValue : rawValue.toLowerCase())) {
|
|
617
|
+
return { matched: false, parameters: {} };
|
|
618
|
+
}
|
|
619
|
+
normalizedSegments.push(template);
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
const definition = parameterDefinitions.get(match[1]);
|
|
623
|
+
let value;
|
|
624
|
+
try {
|
|
625
|
+
value = decodeURIComponent(rawValue);
|
|
626
|
+
}
|
|
627
|
+
catch {
|
|
628
|
+
return { matched: false, parameters: {} };
|
|
629
|
+
}
|
|
630
|
+
if (!definition || !routeParameterPattern(definition.type).test(value))
|
|
631
|
+
return { matched: false, parameters: {} };
|
|
632
|
+
parameters[definition.name] = value;
|
|
633
|
+
normalizedSegments.push(rawValue);
|
|
634
|
+
}
|
|
635
|
+
const canonicalPath = normalizeTrailing(`/${normalizedSegments.join('/')}` || '/');
|
|
636
|
+
return {
|
|
637
|
+
matched: true,
|
|
638
|
+
normalizedPath: canonicalPath,
|
|
639
|
+
parameters: Object.freeze(parameters),
|
|
640
|
+
};
|
|
641
|
+
};
|
|
642
|
+
exports.matchCompiledRouteClaim = matchCompiledRouteClaim;
|
|
643
|
+
function routeParameterPattern(type) {
|
|
297
644
|
if (type === 'integer')
|
|
298
645
|
return /^-?\d+$/;
|
|
299
646
|
if (type === 'uuid')
|
|
@@ -301,7 +648,7 @@ const routeParameterPattern = (type) => {
|
|
|
301
648
|
if (type === 'slug')
|
|
302
649
|
return /^[A-Za-z0-9]+(?:[._-][A-Za-z0-9]+)*$/;
|
|
303
650
|
return /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
304
|
-
}
|
|
651
|
+
}
|
|
305
652
|
/**
|
|
306
653
|
* Materializes the browser URL owned by a RouteSpace from an application-relative
|
|
307
654
|
* compiled route. Declarations and runtime resolution remain application-relative;
|
|
@@ -339,7 +686,12 @@ const renderTreeDepth = (tree) => {
|
|
|
339
686
|
tree.nodes.forEach((node) => {
|
|
340
687
|
let depth = 1;
|
|
341
688
|
let parentId = node.parentNodeId;
|
|
689
|
+
const ancestors = new Set([node.nodeId]);
|
|
342
690
|
while (parentId) {
|
|
691
|
+
if (ancestors.has(parentId)) {
|
|
692
|
+
throw new DeclarativeControlCompilationError('RENDER_TREE_INVALID', 'page.renderTree.nodes', `RenderTree contains a parent cycle at ${parentId}.`);
|
|
693
|
+
}
|
|
694
|
+
ancestors.add(parentId);
|
|
343
695
|
depth += 1;
|
|
344
696
|
parentId = byId.get(parentId)?.parentNodeId;
|
|
345
697
|
}
|
|
@@ -347,38 +699,138 @@ const renderTreeDepth = (tree) => {
|
|
|
347
699
|
});
|
|
348
700
|
return maximum;
|
|
349
701
|
};
|
|
350
|
-
const compareLegacyEntityRef = (reference, revision) => reference.kind === revision.kind
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
702
|
+
const compareLegacyEntityRef = (reference, revision) => reference.kind === revision.kind &&
|
|
703
|
+
reference.id === revision.id &&
|
|
704
|
+
String(reference.version) === String(revision.revision) &&
|
|
705
|
+
reference.ownerRepo === revision.ownerRepo;
|
|
354
706
|
const pageDependencies = (page, compilerRevisionRef) => [
|
|
355
|
-
...page.routeClaims.map((claim) => ({
|
|
707
|
+
...page.routeClaims.map((claim) => ({
|
|
708
|
+
role: 'route-space',
|
|
709
|
+
revisionRef: claim.routeSpaceRevisionRef,
|
|
710
|
+
})),
|
|
356
711
|
{ role: 'shell', revisionRef: page.shellRevisionRef },
|
|
357
712
|
...page.capabilityInstances.flatMap((instance) => [
|
|
358
|
-
{
|
|
713
|
+
{
|
|
714
|
+
role: 'capability',
|
|
715
|
+
revisionRef: instance.capabilityRevisionRef,
|
|
716
|
+
},
|
|
359
717
|
{ role: 'provider', revisionRef: instance.providerRevisionRef },
|
|
360
|
-
{ role: 'schema', revisionRef:
|
|
718
|
+
...(instance.eventEffects ?? []).map((effect) => ({ role: 'schema', revisionRef: effect.sourceIntentSchemaRevisionRef })),
|
|
719
|
+
{
|
|
720
|
+
role: 'schema',
|
|
721
|
+
revisionRef: instance.propertySchemaRevisionRef,
|
|
722
|
+
},
|
|
361
723
|
]),
|
|
724
|
+
...(page.stateDefinitions ?? []).map((state) => ({
|
|
725
|
+
role: 'schema',
|
|
726
|
+
revisionRef: state.schemaRevisionRef,
|
|
727
|
+
})),
|
|
728
|
+
...(page.interactionBindings ?? []).map((binding) => ({
|
|
729
|
+
role: 'schema',
|
|
730
|
+
revisionRef: binding.sourceIntentSchemaRevisionRef,
|
|
731
|
+
})),
|
|
362
732
|
...page.ontologyBindings.flatMap((binding) => [
|
|
363
|
-
{
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
733
|
+
{
|
|
734
|
+
role: 'ontology-definition',
|
|
735
|
+
revisionRef: binding.ontologyDefinitionRevisionRef,
|
|
736
|
+
},
|
|
737
|
+
{ role: 'view', revisionRef: binding.viewRevisionRef },
|
|
738
|
+
{
|
|
739
|
+
role: 'view',
|
|
740
|
+
revisionRef: binding.canonicalDataViewRevisionRef,
|
|
741
|
+
},
|
|
742
|
+
{
|
|
743
|
+
role: 'schema',
|
|
744
|
+
revisionRef: binding.renderModelSchemaRevisionRef,
|
|
745
|
+
},
|
|
746
|
+
...(binding.cursorWindow
|
|
747
|
+
? [
|
|
748
|
+
{
|
|
749
|
+
role: 'schema',
|
|
750
|
+
revisionRef: binding.cursorWindow.pageChangeIntentSchemaRevisionRef,
|
|
751
|
+
},
|
|
752
|
+
]
|
|
753
|
+
: []),
|
|
754
|
+
]),
|
|
755
|
+
...(page.queryBindings ?? []).flatMap((binding) => [
|
|
756
|
+
{
|
|
757
|
+
role: 'query-definition',
|
|
758
|
+
revisionRef: binding.queryDefinitionRevisionRef,
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
role: 'schema',
|
|
762
|
+
revisionRef: binding.renderModelSchemaRevisionRef,
|
|
763
|
+
},
|
|
764
|
+
...(binding.targetProjection ? [{ role: 'schema', revisionRef: binding.targetProjection.schemaRevisionRef }] : []),
|
|
765
|
+
...(binding.streamTargetProjection ? [{ role: 'schema', revisionRef: binding.streamTargetProjection.schemaRevisionRef }] : []),
|
|
766
|
+
...(binding.cursorWindow
|
|
767
|
+
? [
|
|
768
|
+
{
|
|
769
|
+
role: 'schema',
|
|
770
|
+
revisionRef: binding.cursorWindow.pageChangeIntentSchemaRevisionRef,
|
|
771
|
+
},
|
|
772
|
+
]
|
|
773
|
+
: []),
|
|
367
774
|
]),
|
|
368
775
|
...page.actionBindings.flatMap((binding) => [
|
|
369
776
|
{ role: 'action', revisionRef: binding.commandRevisionRef },
|
|
370
|
-
{
|
|
777
|
+
{
|
|
778
|
+
role: 'schema',
|
|
779
|
+
revisionRef: binding.sourceIntentSchemaRevisionRef,
|
|
780
|
+
},
|
|
371
781
|
{ role: 'schema', revisionRef: binding.inputSchemaRevisionRef },
|
|
372
782
|
{ role: 'schema', revisionRef: binding.resultSchemaRevisionRef },
|
|
373
|
-
...(binding.compensationCommandRevisionRef
|
|
783
|
+
...(binding.compensationCommandRevisionRef
|
|
784
|
+
? [
|
|
785
|
+
{
|
|
786
|
+
role: 'action',
|
|
787
|
+
revisionRef: binding.compensationCommandRevisionRef,
|
|
788
|
+
},
|
|
789
|
+
]
|
|
790
|
+
: []),
|
|
374
791
|
]),
|
|
375
|
-
...page.tokenRevisionRefs.map((revisionRef) => ({
|
|
792
|
+
...page.tokenRevisionRefs.map((revisionRef) => ({
|
|
793
|
+
role: 'token',
|
|
794
|
+
revisionRef,
|
|
795
|
+
})),
|
|
376
796
|
{ role: 'performance-budget', revisionRef: page.performanceBudgetRef },
|
|
377
|
-
{
|
|
797
|
+
{
|
|
798
|
+
role: 'observation-policy',
|
|
799
|
+
revisionRef: page.observationPolicyRevisionRef,
|
|
800
|
+
},
|
|
378
801
|
{ role: 'compiler', revisionRef: compilerRevisionRef },
|
|
379
802
|
];
|
|
803
|
+
const domainQueryDependencies = (definition) => [
|
|
804
|
+
...(definition.ontologyDefinitionRevisionRef
|
|
805
|
+
? [
|
|
806
|
+
{
|
|
807
|
+
role: 'ontology-definition',
|
|
808
|
+
revisionRef: definition.ontologyDefinitionRevisionRef,
|
|
809
|
+
},
|
|
810
|
+
]
|
|
811
|
+
: []),
|
|
812
|
+
...(definition.viewRevisionRef ? [{ role: 'view', revisionRef: definition.viewRevisionRef }] : []),
|
|
813
|
+
...(definition.canonicalDataViewRevisionRef
|
|
814
|
+
? [
|
|
815
|
+
{
|
|
816
|
+
role: 'view',
|
|
817
|
+
revisionRef: definition.canonicalDataViewRevisionRef,
|
|
818
|
+
},
|
|
819
|
+
]
|
|
820
|
+
: []),
|
|
821
|
+
{ role: 'schema', revisionRef: definition.inputSchemaRevisionRef },
|
|
822
|
+
{ role: 'schema', revisionRef: definition.resultSchemaRevisionRef },
|
|
823
|
+
];
|
|
380
824
|
const compilePageRuntimeBundle = (input) => {
|
|
381
|
-
const
|
|
825
|
+
const parsedPage = declarative_control_1.PageSchema.parse(input.page);
|
|
826
|
+
const page = {
|
|
827
|
+
...parsedPage,
|
|
828
|
+
routeStatePresentations: parsedPage.routeStatePresentations ?? [],
|
|
829
|
+
stateDefinitions: parsedPage.stateDefinitions ?? [],
|
|
830
|
+
entryTransitions: parsedPage.entryTransitions ?? [],
|
|
831
|
+
interactionBindings: parsedPage.interactionBindings ?? [],
|
|
832
|
+
queryBindings: parsedPage.queryBindings ?? [],
|
|
833
|
+
};
|
|
382
834
|
const pageRevisionRef = declarative_control_1.RevisionRefSchema.parse(input.pageRevisionRef);
|
|
383
835
|
const release = declarative_control_1.PageReleaseSchema.parse(input.release);
|
|
384
836
|
const releaseRevisionRef = declarative_control_1.RevisionRefSchema.parse(input.releaseRevisionRef);
|
|
@@ -393,6 +845,61 @@ const compilePageRuntimeBundle = (input) => {
|
|
|
393
845
|
requireReleaseReady(release);
|
|
394
846
|
requireDependencies(release.dependencySnapshot, pageDependencies(page, compilerRevisionRef));
|
|
395
847
|
assertDependencyScopes(release.dependencySnapshot, scope);
|
|
848
|
+
const queryRegistrations = (input.domainQueryRegistry ?? []).map((registration, index) => {
|
|
849
|
+
const definitionRevisionRef = declarative_control_1.RevisionRefSchema.parse(registration.definitionRevisionRef);
|
|
850
|
+
const definition = declarative_control_1.DomainQueryDefinitionSchema.parse(registration.definition);
|
|
851
|
+
assertSameTenantScope(definition.tenantScope, scope, `domainQueryRegistry[${index}].definition.tenantScope`);
|
|
852
|
+
assertRevisionIdentity(definitionRevisionRef, 'domain-query-definition', definition.queryId, scope, `domainQueryRegistry[${index}].definitionRevisionRef`);
|
|
853
|
+
if (definitionRevisionRef.contentHash !== (0, exports.canonicalContentHash)(definition)) {
|
|
854
|
+
throw new DeclarativeControlCompilationError('QUERY_DEFINITION_MISMATCH', `domainQueryRegistry[${index}].definitionRevisionRef.contentHash`, 'Domain Query registry entry does not match its exact definition content hash.');
|
|
855
|
+
}
|
|
856
|
+
return { definitionRevisionRef, definition };
|
|
857
|
+
});
|
|
858
|
+
assertUniqueRegistryKeys(queryRegistrations.map((registration) => (0, exports.revisionRefKey)(registration.definitionRevisionRef)), 'domainQueryRegistry');
|
|
859
|
+
const queryDefinitionsByRevision = new Map(queryRegistrations.map((registration) => [
|
|
860
|
+
(0, exports.revisionRefKey)(registration.definitionRevisionRef),
|
|
861
|
+
registration.definition,
|
|
862
|
+
]));
|
|
863
|
+
page.queryBindings.forEach((binding, index) => {
|
|
864
|
+
const definition = queryDefinitionsByRevision.get((0, exports.revisionRefKey)(binding.queryDefinitionRevisionRef));
|
|
865
|
+
if (!definition) {
|
|
866
|
+
throw new DeclarativeControlCompilationError('QUERY_DEFINITION_MISMATCH', `queryBindings[${index}].queryDefinitionRevisionRef`, 'Query binding does not resolve to one exact governed Domain Query definition.');
|
|
867
|
+
}
|
|
868
|
+
if (!(0, exports.sameRevisionRef)(definition.resultSchemaRevisionRef, binding.renderModelSchemaRevisionRef)) {
|
|
869
|
+
throw new DeclarativeControlCompilationError('QUERY_DEFINITION_MISMATCH', `queryBindings[${index}].renderModelSchemaRevisionRef`, 'Query binding render model does not match the exact Domain Query result schema.');
|
|
870
|
+
}
|
|
871
|
+
if (!(0, exports.accessPolicyChainImplies)([page.pageAccessPolicy], definition.accessPolicy) &&
|
|
872
|
+
binding.accessFailure !== 'render-forbidden') {
|
|
873
|
+
throw new DeclarativeControlCompilationError('AUDIENCE_WIDER_THAN_TARGET', `queryBindings[${index}]`, 'Page access is wider than the governed Domain Query audience.');
|
|
874
|
+
}
|
|
875
|
+
const sourceKind = definition.dataSource?.kind ?? 'exact-view';
|
|
876
|
+
if (binding.execution === 'local-state' && sourceKind !== 'page-state') {
|
|
877
|
+
throw new DeclarativeControlCompilationError('QUERY_DEFINITION_MISMATCH', `queryBindings[${index}].execution`, 'A local-state binding must resolve to one page-state Domain Query definition.');
|
|
878
|
+
}
|
|
879
|
+
if (binding.execution === 'server' && sourceKind === 'page-state') {
|
|
880
|
+
throw new DeclarativeControlCompilationError('QUERY_DEFINITION_MISMATCH', `queryBindings[${index}].execution`, 'A page-state Domain Query cannot execute on the Server.');
|
|
881
|
+
}
|
|
882
|
+
requireDependencies(release.dependencySnapshot, domainQueryDependencies(definition));
|
|
883
|
+
});
|
|
884
|
+
const shellRegistration = declarative_control_http_1.DeclarativeProductResourceRegistrationSchema.parse(input.shellRegistration);
|
|
885
|
+
if (shellRegistration.resourceKind !== 'shell' ||
|
|
886
|
+
!(0, exports.sameRevisionRef)(shellRegistration.resourceRevisionRef, page.shellRevisionRef) ||
|
|
887
|
+
(0, exports.declarativeProductResourceRevisionHash)(shellRegistration) !== shellRegistration.resourceRevisionRef.contentHash ||
|
|
888
|
+
(0, exports.declarativeProductResourceSourceHash)(shellRegistration.document) !== shellRegistration.sourceContentHash) {
|
|
889
|
+
throw new DeclarativeControlCompilationError('SHELL_REVISION_MISMATCH', 'shellRegistration', 'The active Shell registration does not match the Page exact Shell revision.');
|
|
890
|
+
}
|
|
891
|
+
if (!shellRegistration.supportedSurfaces.includes(release.target.surface)) {
|
|
892
|
+
throw new DeclarativeControlCompilationError('SHELL_SURFACE_MISMATCH', 'shellRegistration.supportedSurfaces', 'The active Shell registration does not support the release surface.');
|
|
893
|
+
}
|
|
894
|
+
const shellDocument = declarative_control_http_1.DeclarativeShellResourceDocumentSchema.parse(shellRegistration.document);
|
|
895
|
+
const shellChrome = shellDocument.surfaceChrome.find((entry) => entry.surface === release.target.surface);
|
|
896
|
+
if (!shellChrome) {
|
|
897
|
+
throw new DeclarativeControlCompilationError('SHELL_CHROME_UNAVAILABLE', 'shellRegistration.document.surfaceChrome', 'The active Shell does not declare chrome for the release surface.');
|
|
898
|
+
}
|
|
899
|
+
const shellDescriptor = {
|
|
900
|
+
shellRevisionRef: page.shellRevisionRef,
|
|
901
|
+
header: shellChrome.header,
|
|
902
|
+
};
|
|
396
903
|
if (page.renderTree.nodes.length > input.limits.maxRenderNodes)
|
|
397
904
|
throw new DeclarativeControlCompilationError('RENDER_NODE_LIMIT_EXCEEDED', 'page.renderTree.nodes', 'RenderTree exceeds the caller-approved node limit.');
|
|
398
905
|
if (renderTreeDepth(page.renderTree) > input.limits.maxRenderDepth)
|
|
@@ -425,43 +932,187 @@ const compilePageRuntimeBundle = (input) => {
|
|
|
425
932
|
]));
|
|
426
933
|
page.capabilityInstances.forEach((instance, index) => {
|
|
427
934
|
const node = renderTree.nodes.find((candidate) => candidate.nodeId === instance.nodeId);
|
|
428
|
-
if (!node ||
|
|
429
|
-
|
|
430
|
-
|
|
935
|
+
if (!node ||
|
|
936
|
+
!compareLegacyEntityRef(node.capabilityRef, instance.capabilityRevisionRef) ||
|
|
937
|
+
!node.providerRef ||
|
|
938
|
+
!compareLegacyEntityRef(node.providerRef, instance.providerRevisionRef) ||
|
|
939
|
+
node.pageRef.id !== page.pageId) {
|
|
431
940
|
throw new DeclarativeControlCompilationError('CAPABILITY_BINDING_MISMATCH', `capabilityInstances[${index}]`, 'RenderTree node identity does not match the declared capability/provider instance.');
|
|
432
941
|
}
|
|
433
942
|
const registration = registrationsByPair.get(`${(0, exports.revisionRefKey)(instance.capabilityRevisionRef)}:${(0, exports.revisionRefKey)(instance.providerRevisionRef)}`);
|
|
434
|
-
if (!registration
|
|
435
|
-
throw new DeclarativeControlCompilationError('
|
|
943
|
+
if (!registration) {
|
|
944
|
+
throw new DeclarativeControlCompilationError('CAPABILITY_BINDING_MISMATCH', `capabilityInstances[${index}]`, 'Capability/provider pair has no exact governed Design registration.');
|
|
436
945
|
}
|
|
437
946
|
if (instance.allowedSideEffects.some((sideEffect) => !registration.allowedSideEffects.includes(sideEffect))) {
|
|
438
947
|
throw new DeclarativeControlCompilationError('CAPABILITY_BINDING_MISMATCH', `capabilityInstances[${index}].allowedSideEffects`, 'Page requests undeclared provider side effects.');
|
|
439
948
|
}
|
|
949
|
+
if (!(0, exports.sameRevisionRef)(instance.propertySchemaRevisionRef, registration.propertySchemaRevisionRef)) {
|
|
950
|
+
throw new DeclarativeControlCompilationError('CAPABILITY_BINDING_MISMATCH', `capabilityInstances[${index}].propertySchemaRevisionRef`, 'Capability properties do not pin the exact schema registered by the active Design catalog.');
|
|
951
|
+
}
|
|
952
|
+
if (!(0, exports.accessPolicyChainImplies)([page.pageAccessPolicy, ...(instance.accessPolicy ? [instance.accessPolicy] : [])], registration.accessPolicy)) {
|
|
953
|
+
throw new DeclarativeControlCompilationError('AUDIENCE_WIDER_THAN_TARGET', `capabilityInstances[${index}]`, 'Page access is wider than the governed capability audience.');
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
if (instancesByNode.size !== page.capabilityInstances.length) {
|
|
957
|
+
throw new DeclarativeControlCompilationError('CAPABILITY_BINDING_MISMATCH', 'capabilityInstances', 'Each executable RenderTree node must be governed by at most one capability instance.');
|
|
958
|
+
}
|
|
959
|
+
renderTree.nodes.forEach((node, index) => {
|
|
960
|
+
if (!node.providerRef)
|
|
961
|
+
return;
|
|
962
|
+
if (!instancesByNode.has(node.nodeId)) {
|
|
963
|
+
throw new DeclarativeControlCompilationError('CAPABILITY_BINDING_MISMATCH', `renderTree.nodes[${index}]`, 'Every provider-backed RenderTree node must be governed by one capability instance.');
|
|
964
|
+
}
|
|
440
965
|
});
|
|
441
966
|
page.ontologyBindings.forEach((binding, index) => {
|
|
442
967
|
const instance = page.capabilityInstances.find((candidate) => candidate.instanceId === binding.target.capabilityInstanceId);
|
|
443
|
-
const registration = instance &&
|
|
968
|
+
const registration = instance &&
|
|
969
|
+
registrationsByPair.get(`${(0, exports.revisionRefKey)(instance.capabilityRevisionRef)}:${(0, exports.revisionRefKey)(instance.providerRevisionRef)}`);
|
|
444
970
|
const port = registration?.inputPorts.find((candidate) => candidate.name === binding.target.port);
|
|
445
971
|
if (!port || !(0, exports.sameRevisionRef)(port.schemaRevisionRef, binding.renderModelSchemaRevisionRef)) {
|
|
446
972
|
throw new DeclarativeControlCompilationError('PORT_TYPE_MISMATCH', `ontologyBindings[${index}].target.port`, 'Ontology render model does not match the registered capability input port.');
|
|
447
973
|
}
|
|
974
|
+
if (binding.cursorWindow) {
|
|
975
|
+
const sourceInstance = page.capabilityInstances.find(candidate => candidate.instanceId === (binding.cursorWindow.sourceCapabilityInstanceId ?? binding.target.capabilityInstanceId));
|
|
976
|
+
const sourceRegistration = sourceInstance && registrationsByPair.get(`${(0, exports.revisionRefKey)(sourceInstance.capabilityRevisionRef)}:${(0, exports.revisionRefKey)(sourceInstance.providerRevisionRef)}`);
|
|
977
|
+
const pageChangePort = sourceRegistration?.outputPorts.find((candidate) => candidate.name === binding.cursorWindow.pageChangePort);
|
|
978
|
+
if (!pageChangePort ||
|
|
979
|
+
!(0, exports.sameRevisionRef)(pageChangePort.schemaRevisionRef, binding.cursorWindow.pageChangeIntentSchemaRevisionRef)) {
|
|
980
|
+
throw new DeclarativeControlCompilationError('PORT_TYPE_MISMATCH', `ontologyBindings[${index}].cursorWindow.pageChangePort`, 'Cursor-window page-change intent does not match the registered capability output port.');
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
});
|
|
984
|
+
page.queryBindings.forEach((binding, index) => {
|
|
985
|
+
const instance = page.capabilityInstances.find((candidate) => candidate.instanceId === binding.target.capabilityInstanceId);
|
|
986
|
+
const registration = instance &&
|
|
987
|
+
registrationsByPair.get(`${(0, exports.revisionRefKey)(instance.capabilityRevisionRef)}:${(0, exports.revisionRefKey)(instance.providerRevisionRef)}`);
|
|
988
|
+
const port = registration?.inputPorts.find((candidate) => candidate.name === binding.target.port);
|
|
989
|
+
if (!port || !(0, exports.sameRevisionRef)(port.schemaRevisionRef, (binding.targetProjection?.schemaRevisionRef ?? binding.renderModelSchemaRevisionRef))) {
|
|
990
|
+
throw new DeclarativeControlCompilationError('PORT_TYPE_MISMATCH', `queryBindings[${index}].target.port`, 'Domain Query render model does not match the registered capability input port.');
|
|
991
|
+
}
|
|
992
|
+
if (binding.streamTargetProjection && (!port || !(0, exports.sameRevisionRef)(port.schemaRevisionRef, binding.streamTargetProjection.schemaRevisionRef))) {
|
|
993
|
+
throw new DeclarativeControlCompilationError('PORT_TYPE_MISMATCH', `queryBindings[${index}].streamTargetProjection`, 'Stream render model does not match the registered capability input port.');
|
|
994
|
+
}
|
|
995
|
+
if (binding.cursorWindow) {
|
|
996
|
+
const sourceInstance = page.capabilityInstances.find(candidate => candidate.instanceId === (binding.cursorWindow.sourceCapabilityInstanceId ?? binding.target.capabilityInstanceId));
|
|
997
|
+
const sourceRegistration = sourceInstance && registrationsByPair.get(`${(0, exports.revisionRefKey)(sourceInstance.capabilityRevisionRef)}:${(0, exports.revisionRefKey)(sourceInstance.providerRevisionRef)}`);
|
|
998
|
+
const pageChangePort = sourceRegistration?.outputPorts.find((candidate) => candidate.name === binding.cursorWindow.pageChangePort);
|
|
999
|
+
if (!pageChangePort ||
|
|
1000
|
+
!(0, exports.sameRevisionRef)(pageChangePort.schemaRevisionRef, binding.cursorWindow.pageChangeIntentSchemaRevisionRef)) {
|
|
1001
|
+
throw new DeclarativeControlCompilationError('PORT_TYPE_MISMATCH', `queryBindings[${index}].cursorWindow.pageChangePort`, 'Cursor-window page-change intent does not match the registered capability output port.');
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
page.capabilityInstances.forEach((instance, index) => {
|
|
1006
|
+
const registration = registrationsByPair.get(`${(0, exports.revisionRefKey)(instance.capabilityRevisionRef)}:${(0, exports.revisionRefKey)(instance.providerRevisionRef)}`);
|
|
1007
|
+
instance.eventPayloadBindings?.forEach((binding, bindingIndex) => {
|
|
1008
|
+
if (!registration?.outputPorts.some((port) => port.name === binding.port))
|
|
1009
|
+
throw new DeclarativeControlCompilationError('PORT_TYPE_MISMATCH', `capabilityInstances[${index}].eventPayloadBindings[${bindingIndex}]`, 'Event payload projection must reference a registered output port.');
|
|
1010
|
+
});
|
|
1011
|
+
instance.eventEffects?.forEach((effect, effectIndex) => {
|
|
1012
|
+
const port = registration?.outputPorts.find((candidate) => candidate.name === effect.sourcePort);
|
|
1013
|
+
if (!port || !(0, exports.sameRevisionRef)(port.schemaRevisionRef, effect.sourceIntentSchemaRevisionRef))
|
|
1014
|
+
throw new DeclarativeControlCompilationError('PORT_TYPE_MISMATCH', `capabilityInstances[${index}].eventEffects[${effectIndex}]`, 'Event effect source must match an exact registered output port schema.');
|
|
1015
|
+
});
|
|
1016
|
+
});
|
|
1017
|
+
page.interactionBindings.forEach((binding, index) => {
|
|
1018
|
+
const instance = page.capabilityInstances.find((candidate) => candidate.instanceId === binding.source.capabilityInstanceId);
|
|
1019
|
+
const registration = instance &&
|
|
1020
|
+
registrationsByPair.get(`${(0, exports.revisionRefKey)(instance.capabilityRevisionRef)}:${(0, exports.revisionRefKey)(instance.providerRevisionRef)}`);
|
|
1021
|
+
const port = registration?.outputPorts.find((candidate) => candidate.name === binding.source.port);
|
|
1022
|
+
if (!port || !(0, exports.sameRevisionRef)(port.schemaRevisionRef, binding.sourceIntentSchemaRevisionRef)) {
|
|
1023
|
+
throw new DeclarativeControlCompilationError('PORT_TYPE_MISMATCH', `interactionBindings[${index}].sourceIntentSchemaRevisionRef`, 'Interaction source intent does not match the registered capability output port.');
|
|
1024
|
+
}
|
|
448
1025
|
});
|
|
449
1026
|
page.actionBindings.forEach((binding, index) => {
|
|
450
1027
|
const instance = page.capabilityInstances.find((candidate) => candidate.instanceId === binding.source.capabilityInstanceId);
|
|
451
|
-
const registration = instance &&
|
|
1028
|
+
const registration = instance &&
|
|
1029
|
+
registrationsByPair.get(`${(0, exports.revisionRefKey)(instance.capabilityRevisionRef)}:${(0, exports.revisionRefKey)(instance.providerRevisionRef)}`);
|
|
452
1030
|
const port = registration?.outputPorts.find((candidate) => candidate.name === binding.source.port);
|
|
453
1031
|
if (!port || !(0, exports.sameRevisionRef)(port.schemaRevisionRef, binding.sourceIntentSchemaRevisionRef)) {
|
|
454
1032
|
throw new DeclarativeControlCompilationError('PORT_TYPE_MISMATCH', `actionBindings[${index}].sourceIntentSchemaRevisionRef`, 'Action source intent does not match the registered capability output port.');
|
|
455
1033
|
}
|
|
456
1034
|
});
|
|
457
|
-
const routeClaims = (0, exports.compileRouteClaims)({
|
|
1035
|
+
const routeClaims = (0, exports.compileRouteClaims)({
|
|
1036
|
+
claims: page.routeClaims,
|
|
1037
|
+
routeSpaces: input.routeSpaces,
|
|
1038
|
+
surface: release.target.surface,
|
|
1039
|
+
legacyRouteTakeoverAuthorizations: release.target.legacyRouteTakeoverAuthorization
|
|
1040
|
+
? [release.target.legacyRouteTakeoverAuthorization]
|
|
1041
|
+
: [],
|
|
1042
|
+
});
|
|
458
1043
|
const releaseRoute = routeClaims.find((claim) => claim.kind === 'canonical' && claim.normalizedPath === release.target.normalizedPath);
|
|
459
1044
|
if (!releaseRoute || !(0, exports.sameRevisionRef)(releaseRoute.routeSpaceRevisionRef, release.target.routeSpaceRevisionRef)) {
|
|
460
|
-
throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', 'release.target', 'Release target does not match
|
|
1045
|
+
throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', 'release.target', 'Release target does not match an exact Page route claim.');
|
|
461
1046
|
}
|
|
462
1047
|
if (!page.supportedSurfaces.includes(release.target.surface)) {
|
|
463
1048
|
throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', 'release.target.surface', 'Page does not support the release surface.');
|
|
464
1049
|
}
|
|
1050
|
+
const routeTargets = (input.targetRegistry ?? []).map((registration, index) => ({
|
|
1051
|
+
...registration,
|
|
1052
|
+
stableTargetRef: declarative_control_1.StableRefSchema.parse(registration.stableTargetRef),
|
|
1053
|
+
targetRevisionRef: declarative_control_1.RevisionRefSchema.parse(registration.targetRevisionRef),
|
|
1054
|
+
...(registration.releaseRevisionRef
|
|
1055
|
+
? {
|
|
1056
|
+
releaseRevisionRef: declarative_control_1.RevisionRefSchema.parse(registration.releaseRevisionRef),
|
|
1057
|
+
}
|
|
1058
|
+
: {}),
|
|
1059
|
+
accessPolicy: declarative_control_1.AccessPolicySchema.parse(registration.accessPolicy),
|
|
1060
|
+
routeClaim: declarative_control_1.CompiledRouteClaimSchema.parse(registration.routeClaim),
|
|
1061
|
+
sourceIndex: index,
|
|
1062
|
+
}));
|
|
1063
|
+
assertUniqueRegistryKeys(routeTargets.map((registration) => (0, exports.stableRefKey)(registration.stableTargetRef)), 'targetRegistry');
|
|
1064
|
+
const entryTransitions = page.entryTransitions.map((transition, index) => {
|
|
1065
|
+
const matches = routeTargets.filter((registration) => registration.kind === 'route' &&
|
|
1066
|
+
(0, exports.sameStableRef)(registration.stableTargetRef, transition.targetRef) &&
|
|
1067
|
+
registration.surface === release.target.surface);
|
|
1068
|
+
if (matches.length !== 1) {
|
|
1069
|
+
throw new DeclarativeControlCompilationError('PAGE_ENTRY_TARGET_UNRELEASED', `entryTransitions[${index}].targetRef`, 'Entry transition target must resolve to one exact active route registration on the same surface.');
|
|
1070
|
+
}
|
|
1071
|
+
const target = matches[0];
|
|
1072
|
+
if (target.releaseRevisionRef && !['page-release', 'workbench-release'].includes(target.releaseRevisionRef.kind)) {
|
|
1073
|
+
throw new DeclarativeControlCompilationError('PAGE_ENTRY_TARGET_UNRELEASED', `entryTransitions[${index}].targetRef`, 'Entry transition Release provenance must identify a Page or Workbench Release.');
|
|
1074
|
+
}
|
|
1075
|
+
if (target.routeClaim.kind !== 'canonical') {
|
|
1076
|
+
throw new DeclarativeControlCompilationError('PAGE_ENTRY_TARGET_UNRELEASED', `entryTransitions[${index}].targetRef`, 'Entry transition targets must expose one canonical route claim.');
|
|
1077
|
+
}
|
|
1078
|
+
if (!(0, exports.sameStableRef)(target.stableTargetRef, target.targetRevisionRef)) {
|
|
1079
|
+
throw new DeclarativeControlCompilationError('PAGE_ENTRY_TARGET_UNRELEASED', `targetRegistry[${target.sourceIndex}]`, 'Entry transition target registration identity is not exact.');
|
|
1080
|
+
}
|
|
1081
|
+
// Entry transitions may narrow into a separately protected route. The target
|
|
1082
|
+
// route remains authoritative and re-evaluates its own access policy after
|
|
1083
|
+
// navigation, so a source Page must not inherit the target's permissions.
|
|
1084
|
+
const requiredPathParameters = [...target.routeClaim.normalizedPath.matchAll(/:([A-Za-z][A-Za-z0-9_-]*)/g)].map((match) => match[1]);
|
|
1085
|
+
const mappedPathParameters = Object.keys(transition.pathParameters);
|
|
1086
|
+
const missing = requiredPathParameters.find((name) => !mappedPathParameters.includes(name));
|
|
1087
|
+
const unknown = mappedPathParameters.find((name) => !requiredPathParameters.includes(name));
|
|
1088
|
+
if (missing || unknown) {
|
|
1089
|
+
throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', `entryTransitions[${index}].pathParameters`, missing
|
|
1090
|
+
? `Entry transition does not resolve target route parameter ${missing}.`
|
|
1091
|
+
: `Entry transition maps unknown target route parameter ${unknown}.`);
|
|
1092
|
+
}
|
|
1093
|
+
requireDependencies(release.dependencySnapshot, [
|
|
1094
|
+
{
|
|
1095
|
+
role: target.targetRevisionRef.kind,
|
|
1096
|
+
revisionRef: target.targetRevisionRef,
|
|
1097
|
+
},
|
|
1098
|
+
...(target.releaseRevisionRef
|
|
1099
|
+
? [
|
|
1100
|
+
{
|
|
1101
|
+
role: target.releaseRevisionRef.kind,
|
|
1102
|
+
revisionRef: target.releaseRevisionRef,
|
|
1103
|
+
},
|
|
1104
|
+
]
|
|
1105
|
+
: []),
|
|
1106
|
+
]);
|
|
1107
|
+
return {
|
|
1108
|
+
...transition,
|
|
1109
|
+
browsingContext: transition.browsingContext ?? 'same',
|
|
1110
|
+
targetRevisionRef: target.targetRevisionRef,
|
|
1111
|
+
...(target.releaseRevisionRef ? { targetReleaseRevisionRef: target.releaseRevisionRef } : {}),
|
|
1112
|
+
targetAccessPolicy: target.accessPolicy,
|
|
1113
|
+
targetRouteClaim: target.routeClaim,
|
|
1114
|
+
};
|
|
1115
|
+
});
|
|
465
1116
|
const unsigned = {
|
|
466
1117
|
contract: 'PageRuntimeBundle',
|
|
467
1118
|
schemaVersion: 1,
|
|
@@ -476,10 +1127,17 @@ const compilePageRuntimeBundle = (input) => {
|
|
|
476
1127
|
pageRevisionRef,
|
|
477
1128
|
surface: release.target.surface,
|
|
478
1129
|
routeClaims,
|
|
1130
|
+
routeStatePresentations: page.routeStatePresentations.filter((presentation) => presentation.surface === release.target.surface),
|
|
479
1131
|
shellRevisionRef: page.shellRevisionRef,
|
|
1132
|
+
shellDescriptor,
|
|
480
1133
|
renderTree,
|
|
481
1134
|
capabilityInstances: page.capabilityInstances,
|
|
1135
|
+
deniedCapabilityInstanceIds: [],
|
|
1136
|
+
stateDefinitions: page.stateDefinitions,
|
|
1137
|
+
entryTransitions,
|
|
1138
|
+
interactionBindings: page.interactionBindings,
|
|
482
1139
|
ontologyBindings: page.ontologyBindings,
|
|
1140
|
+
queryBindings: page.queryBindings,
|
|
483
1141
|
actionBindings: page.actionBindings,
|
|
484
1142
|
pageAccessPolicy: page.pageAccessPolicy,
|
|
485
1143
|
tokenRevisionRefs: page.tokenRevisionRefs,
|
|
@@ -487,32 +1145,59 @@ const compilePageRuntimeBundle = (input) => {
|
|
|
487
1145
|
observationPolicyRevisionRef: page.observationPolicyRevisionRef,
|
|
488
1146
|
privacyClassification: page.privacyClassification,
|
|
489
1147
|
};
|
|
490
|
-
return deepFreeze(declarative_control_1.PageRuntimeBundleSchema.parse({
|
|
1148
|
+
return deepFreeze(declarative_control_1.PageRuntimeBundleSchema.parse({
|
|
1149
|
+
...unsigned,
|
|
1150
|
+
contentHash: (0, exports.canonicalContentHash)(unsigned),
|
|
1151
|
+
}));
|
|
491
1152
|
};
|
|
492
1153
|
exports.compilePageRuntimeBundle = compilePageRuntimeBundle;
|
|
493
1154
|
const workbenchDependencyRole = (kind) => {
|
|
494
1155
|
switch (kind) {
|
|
495
|
-
case 'workflow':
|
|
496
|
-
|
|
497
|
-
case '
|
|
498
|
-
|
|
499
|
-
case '
|
|
500
|
-
|
|
1156
|
+
case 'workflow':
|
|
1157
|
+
return 'workflow';
|
|
1158
|
+
case 'agent':
|
|
1159
|
+
return 'agent';
|
|
1160
|
+
case 'capability':
|
|
1161
|
+
return 'capability';
|
|
1162
|
+
case 'design':
|
|
1163
|
+
return 'design';
|
|
1164
|
+
case 'built-in-application':
|
|
1165
|
+
return 'built-in-application';
|
|
1166
|
+
default:
|
|
1167
|
+
return 'workflow';
|
|
501
1168
|
}
|
|
502
1169
|
};
|
|
503
1170
|
const workbenchDependencies = (workbench, compilerRevisionRef) => [
|
|
504
|
-
...workbench.routeClaims.map((claim) => ({
|
|
1171
|
+
...workbench.routeClaims.map((claim) => ({
|
|
1172
|
+
role: 'route-space',
|
|
1173
|
+
revisionRef: claim.routeSpaceRevisionRef,
|
|
1174
|
+
})),
|
|
505
1175
|
...workbench.appInstances.flatMap((instance) => [
|
|
506
|
-
{
|
|
1176
|
+
{
|
|
1177
|
+
role: workbenchDependencyRole(instance.targetRevisionRef.kind),
|
|
1178
|
+
revisionRef: instance.targetRevisionRef,
|
|
1179
|
+
},
|
|
507
1180
|
{ role: 'provider', revisionRef: instance.providerRevisionRef },
|
|
508
1181
|
{ role: 'schema', revisionRef: instance.inputSchemaRevisionRef },
|
|
509
1182
|
]),
|
|
510
|
-
{
|
|
1183
|
+
{
|
|
1184
|
+
role: 'capability',
|
|
1185
|
+
revisionRef: workbench.layout.hostCapabilityRevisionRef,
|
|
1186
|
+
},
|
|
511
1187
|
{ role: 'provider', revisionRef: workbench.layout.hostProviderRevisionRef },
|
|
512
|
-
{
|
|
513
|
-
|
|
1188
|
+
{
|
|
1189
|
+
role: 'layout-policy',
|
|
1190
|
+
revisionRef: workbench.layout.layoutPolicyRevisionRef,
|
|
1191
|
+
},
|
|
1192
|
+
...workbench.layout.tokenRevisionRefs.map((revisionRef) => ({
|
|
1193
|
+
role: 'token',
|
|
1194
|
+
revisionRef,
|
|
1195
|
+
})),
|
|
514
1196
|
{ role: 'performance-budget', revisionRef: workbench.performanceBudgetRef },
|
|
515
|
-
{
|
|
1197
|
+
{
|
|
1198
|
+
role: 'observation-policy',
|
|
1199
|
+
revisionRef: workbench.observationPolicyRevisionRef,
|
|
1200
|
+
},
|
|
516
1201
|
{ role: 'compiler', revisionRef: compilerRevisionRef },
|
|
517
1202
|
];
|
|
518
1203
|
const compileWorkbenchRuntimeBundle = (input) => {
|
|
@@ -525,7 +1210,8 @@ const compileWorkbenchRuntimeBundle = (input) => {
|
|
|
525
1210
|
assertSameTenantScope(release.tenantScope, scope, 'release.tenantScope');
|
|
526
1211
|
if (workbench.purpose === 'template')
|
|
527
1212
|
throw new DeclarativeControlCompilationError('WORKBENCH_TEMPLATE_UNRELEASABLE', 'workbench.purpose', 'Workbench templates cannot be activated.');
|
|
528
|
-
if (workbench.groups.length > input.limits.maxWorkbenchGroups ||
|
|
1213
|
+
if (workbench.groups.length > input.limits.maxWorkbenchGroups ||
|
|
1214
|
+
workbench.appInstances.length > input.limits.maxWorkbenchInstances) {
|
|
529
1215
|
throw new DeclarativeControlCompilationError('WORKBENCH_INSTANCE_LIMIT_EXCEEDED', 'workbench', 'Workbench exceeds caller-approved compilation limits.');
|
|
530
1216
|
}
|
|
531
1217
|
assertRevisionIdentity(workbenchRevisionRef, 'workbench', workbench.workbenchId, scope, 'workbenchRevisionRef');
|
|
@@ -538,10 +1224,17 @@ const compileWorkbenchRuntimeBundle = (input) => {
|
|
|
538
1224
|
requireReleaseReady(release);
|
|
539
1225
|
requireDependencies(release.dependencySnapshot, workbenchDependencies(workbench, compilerRevisionRef));
|
|
540
1226
|
assertDependencyScopes(release.dependencySnapshot, scope);
|
|
541
|
-
const routeClaims = (0, exports.compileRouteClaims)({
|
|
1227
|
+
const routeClaims = (0, exports.compileRouteClaims)({
|
|
1228
|
+
claims: workbench.routeClaims,
|
|
1229
|
+
routeSpaces: input.routeSpaces,
|
|
1230
|
+
surface: release.target.surface,
|
|
1231
|
+
legacyRouteTakeoverAuthorizations: release.target.legacyRouteTakeoverAuthorization
|
|
1232
|
+
? [release.target.legacyRouteTakeoverAuthorization]
|
|
1233
|
+
: [],
|
|
1234
|
+
});
|
|
542
1235
|
const releaseRoute = routeClaims.find((claim) => claim.kind === 'canonical' && claim.normalizedPath === release.target.normalizedPath);
|
|
543
1236
|
if (!releaseRoute || !(0, exports.sameRevisionRef)(releaseRoute.routeSpaceRevisionRef, release.target.routeSpaceRevisionRef)) {
|
|
544
|
-
throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', 'release.target', 'Release target does not match
|
|
1237
|
+
throw new DeclarativeControlCompilationError('ROUTE_SPACE_MISMATCH', 'release.target', 'Release target does not match an exact Workbench route claim.');
|
|
545
1238
|
}
|
|
546
1239
|
const targetRegistry = input.targetRegistry.map((registration) => ({
|
|
547
1240
|
stableTargetRef: declarative_control_1.StableRefSchema.parse(registration.stableTargetRef),
|
|
@@ -560,13 +1253,18 @@ const compileWorkbenchRuntimeBundle = (input) => {
|
|
|
560
1253
|
...(instance.targetRevisionRef.tenantScope ? { tenantScope: instance.targetRevisionRef.tenantScope } : {}),
|
|
561
1254
|
});
|
|
562
1255
|
const registration = targetsByStableRef.get((0, exports.stableRefKey)(stableTarget));
|
|
563
|
-
if (!registration ||
|
|
564
|
-
|
|
1256
|
+
if (!registration ||
|
|
1257
|
+
!(0, exports.sameStableRef)(registration.stableTargetRef, stableFromRevision(registration.targetRevisionRef)) ||
|
|
1258
|
+
!(0, exports.sameRevisionRef)(registration.targetRevisionRef, instance.targetRevisionRef)) {
|
|
565
1259
|
throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', `appInstances[${index}].targetRevisionRef`, 'Workbench app target is not present at the exact registered revision.');
|
|
566
1260
|
}
|
|
567
1261
|
assertTenantCompatible(instance.targetRevisionRef, scope, `appInstances[${index}].targetRevisionRef`);
|
|
568
1262
|
const group = groupsById.get(instance.groupId);
|
|
569
|
-
const chain = [
|
|
1263
|
+
const chain = [
|
|
1264
|
+
workbench.workbenchAccessPolicy,
|
|
1265
|
+
...(group?.accessPolicy ? [group.accessPolicy] : []),
|
|
1266
|
+
instance.accessPolicy,
|
|
1267
|
+
];
|
|
570
1268
|
if (!(0, exports.accessPolicyChainImplies)(chain, registration.accessPolicy)) {
|
|
571
1269
|
throw new DeclarativeControlCompilationError('AUDIENCE_WIDER_THAN_TARGET', `appInstances[${index}].accessPolicy`, 'Workbench and instance audience is wider than the target audience.');
|
|
572
1270
|
}
|
|
@@ -584,6 +1282,10 @@ const compileWorkbenchRuntimeBundle = (input) => {
|
|
|
584
1282
|
diagnostics: [],
|
|
585
1283
|
workbenchId: workbench.workbenchId,
|
|
586
1284
|
workbenchRevisionRef,
|
|
1285
|
+
identity: {
|
|
1286
|
+
name: workbench.identity.name,
|
|
1287
|
+
...(workbench.identity.description ? { description: workbench.identity.description } : {}),
|
|
1288
|
+
},
|
|
587
1289
|
surface: release.target.surface,
|
|
588
1290
|
routeClaims,
|
|
589
1291
|
groups: workbench.groups,
|
|
@@ -597,7 +1299,10 @@ const compileWorkbenchRuntimeBundle = (input) => {
|
|
|
597
1299
|
observationPolicyRevisionRef: workbench.observationPolicyRevisionRef,
|
|
598
1300
|
privacyClassification: workbench.privacyClassification,
|
|
599
1301
|
};
|
|
600
|
-
return deepFreeze(declarative_control_1.WorkbenchRuntimeBundleSchema.parse({
|
|
1302
|
+
return deepFreeze(declarative_control_1.WorkbenchRuntimeBundleSchema.parse({
|
|
1303
|
+
...unsigned,
|
|
1304
|
+
contentHash: (0, exports.canonicalContentHash)(unsigned),
|
|
1305
|
+
}));
|
|
601
1306
|
};
|
|
602
1307
|
exports.compileWorkbenchRuntimeBundle = compileWorkbenchRuntimeBundle;
|
|
603
1308
|
const navigationDepth = (navigation) => {
|
|
@@ -634,11 +1339,26 @@ const orderedNavigationNodes = (navigation) => {
|
|
|
634
1339
|
};
|
|
635
1340
|
const navigationDependencies = (navigation, release, compilerRevisionRef) => [
|
|
636
1341
|
...release.resolvedTargets.flatMap((target) => [
|
|
637
|
-
{
|
|
638
|
-
|
|
1342
|
+
{
|
|
1343
|
+
role: target.targetRevisionRef.kind === 'domain-command'
|
|
1344
|
+
? 'action'
|
|
1345
|
+
: target.targetRevisionRef.kind,
|
|
1346
|
+
revisionRef: target.targetRevisionRef,
|
|
1347
|
+
},
|
|
1348
|
+
...(target.releaseRevisionRef
|
|
1349
|
+
? [
|
|
1350
|
+
{
|
|
1351
|
+
role: target.releaseRevisionRef.kind,
|
|
1352
|
+
revisionRef: target.releaseRevisionRef,
|
|
1353
|
+
},
|
|
1354
|
+
]
|
|
1355
|
+
: []),
|
|
639
1356
|
]),
|
|
640
1357
|
{ role: 'performance-budget', revisionRef: navigation.performanceBudgetRef },
|
|
641
|
-
{
|
|
1358
|
+
{
|
|
1359
|
+
role: 'observation-policy',
|
|
1360
|
+
revisionRef: navigation.observationPolicyRevisionRef,
|
|
1361
|
+
},
|
|
642
1362
|
{ role: 'compiler', revisionRef: compilerRevisionRef },
|
|
643
1363
|
];
|
|
644
1364
|
const compileNavigationRuntimeBundle = (input) => {
|
|
@@ -658,8 +1378,8 @@ const compileNavigationRuntimeBundle = (input) => {
|
|
|
658
1378
|
if (!(0, exports.sameRevisionRef)(navigationRevisionRef, release.navigationRevisionRef))
|
|
659
1379
|
throw new DeclarativeControlCompilationError('REVISION_MISMATCH', 'release.navigationRevisionRef', 'Release does not pin the supplied Navigation revision.');
|
|
660
1380
|
assertRevisionIdentity(releaseRevisionRef, 'navigation-release', release.releaseSlotId, scope, 'releaseRevisionRef');
|
|
661
|
-
if (release.target.surface !== navigation.supportedSurfaces.find((surface) => surface === release.target.surface)
|
|
662
|
-
|
|
1381
|
+
if (release.target.surface !== navigation.supportedSurfaces.find((surface) => surface === release.target.surface) ||
|
|
1382
|
+
!navigation.placements.includes(release.target.placement)) {
|
|
663
1383
|
throw new DeclarativeControlCompilationError('REVISION_MISMATCH', 'release.target', 'Navigation release target is not declared by the Navigation record.');
|
|
664
1384
|
}
|
|
665
1385
|
requireReleaseReady(release);
|
|
@@ -680,19 +1400,30 @@ const compileNavigationRuntimeBundle = (input) => {
|
|
|
680
1400
|
return {
|
|
681
1401
|
...common,
|
|
682
1402
|
kind: 'route',
|
|
683
|
-
releaseRevisionRef: registration.releaseRevisionRef
|
|
1403
|
+
releaseRevisionRef: registration.releaseRevisionRef
|
|
1404
|
+
? declarative_control_1.RevisionRefSchema.parse(registration.releaseRevisionRef)
|
|
1405
|
+
: undefined,
|
|
684
1406
|
routeClaim,
|
|
685
1407
|
};
|
|
686
1408
|
}
|
|
687
1409
|
if (registration.kind === 'registered-menu-action') {
|
|
688
1410
|
const sourceCatalogRevisionRef = declarative_control_1.RevisionRefSchema.parse(registration.sourceCatalogRevisionRef);
|
|
689
|
-
if (sourceCatalogRevisionRef.kind !== 'application-menu-catalog' ||
|
|
1411
|
+
if (sourceCatalogRevisionRef.kind !== 'application-menu-catalog' ||
|
|
1412
|
+
registration.targetRevisionRef.kind !== 'menu-action') {
|
|
690
1413
|
throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', 'targetRegistry', 'Registered Menu Actions require exact menu-action and application-menu-catalog revisions.');
|
|
691
1414
|
}
|
|
692
1415
|
if (registration.inputSchemaRef && !registration.validateInput) {
|
|
693
1416
|
throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', 'targetRegistry', 'Registered Menu Actions with input schemas require the active catalog validator.');
|
|
694
1417
|
}
|
|
695
|
-
return {
|
|
1418
|
+
return {
|
|
1419
|
+
...common,
|
|
1420
|
+
kind: 'registered-menu-action',
|
|
1421
|
+
applicationId: registration.applicationId,
|
|
1422
|
+
actionRef: registration.actionRef,
|
|
1423
|
+
inputSchemaRef: registration.inputSchemaRef,
|
|
1424
|
+
validateInput: registration.validateInput,
|
|
1425
|
+
sourceCatalogRevisionRef,
|
|
1426
|
+
};
|
|
696
1427
|
}
|
|
697
1428
|
if (registration.targetRevisionRef.kind !== 'domain-command') {
|
|
698
1429
|
throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', 'targetRegistry', 'Governed DomainCommand actions require an exact domain-command revision.');
|
|
@@ -701,10 +1432,16 @@ const compileNavigationRuntimeBundle = (input) => {
|
|
|
701
1432
|
const resultSchemaRevisionRef = registration.resultSchemaRevisionRef
|
|
702
1433
|
? declarative_control_1.RevisionRefSchema.parse(registration.resultSchemaRevisionRef)
|
|
703
1434
|
: undefined;
|
|
704
|
-
if (inputSchemaRevisionRef.kind !== 'schema' ||
|
|
1435
|
+
if (inputSchemaRevisionRef.kind !== 'schema' ||
|
|
1436
|
+
(resultSchemaRevisionRef && resultSchemaRevisionRef.kind !== 'schema')) {
|
|
705
1437
|
throw new DeclarativeControlCompilationError('NAV_TARGET_UNRELEASED', 'targetRegistry', 'Governed DomainCommand actions require exact input and output Schema revisions.');
|
|
706
1438
|
}
|
|
707
|
-
return {
|
|
1439
|
+
return {
|
|
1440
|
+
...common,
|
|
1441
|
+
kind: 'governed-domain-command',
|
|
1442
|
+
inputSchemaRevisionRef,
|
|
1443
|
+
resultSchemaRevisionRef,
|
|
1444
|
+
};
|
|
708
1445
|
});
|
|
709
1446
|
assertUniqueRegistryKeys(targetRegistry.map((registration) => (0, exports.stableRefKey)(registration.stableTargetRef)), 'targetRegistry');
|
|
710
1447
|
const targetsByStableRef = new Map(targetRegistry.map((registration) => [(0, exports.stableRefKey)(registration.stableTargetRef), registration]));
|
|
@@ -775,7 +1512,12 @@ const compileNavigationRuntimeBundle = (input) => {
|
|
|
775
1512
|
}));
|
|
776
1513
|
let resolvedTarget;
|
|
777
1514
|
if (registration.kind === 'route') {
|
|
778
|
-
resolvedTarget = {
|
|
1515
|
+
resolvedTarget = {
|
|
1516
|
+
...released,
|
|
1517
|
+
kind: 'route',
|
|
1518
|
+
accessPolicy: registration.accessPolicy,
|
|
1519
|
+
routeClaim: registration.routeClaim,
|
|
1520
|
+
};
|
|
779
1521
|
}
|
|
780
1522
|
else if (registration.kind === 'registered-menu-action') {
|
|
781
1523
|
if (!registration.inputSchemaRef && Object.keys(mappedInput).length > 0) {
|
|
@@ -788,7 +1530,8 @@ const compileNavigationRuntimeBundle = (input) => {
|
|
|
788
1530
|
catch (error) {
|
|
789
1531
|
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)}`);
|
|
790
1532
|
}
|
|
791
|
-
const sourceDependency = release.dependencySnapshot.find((dependency) => dependency.role === 'application-menu-catalog' &&
|
|
1533
|
+
const sourceDependency = release.dependencySnapshot.find((dependency) => dependency.role === 'application-menu-catalog' &&
|
|
1534
|
+
(0, exports.sameRevisionRef)(dependency.revisionRef, registration.sourceCatalogRevisionRef));
|
|
792
1535
|
if (!sourceDependency)
|
|
793
1536
|
throw new DeclarativeControlCompilationError('DEPENDENCY_MISSING', `nodes[${index}].targetRef`, 'Registered Menu Action source catalog is not pinned by NavigationRelease.');
|
|
794
1537
|
resolvedTarget = {
|
|
@@ -806,7 +1549,8 @@ const compileNavigationRuntimeBundle = (input) => {
|
|
|
806
1549
|
else {
|
|
807
1550
|
const inputDependency = release.dependencySnapshot.find((dependency) => dependency.role === 'schema' && (0, exports.sameRevisionRef)(dependency.revisionRef, registration.inputSchemaRevisionRef));
|
|
808
1551
|
const resultDependency = registration.resultSchemaRevisionRef
|
|
809
|
-
? release.dependencySnapshot.find((dependency) => dependency.role === 'schema' &&
|
|
1552
|
+
? release.dependencySnapshot.find((dependency) => dependency.role === 'schema' &&
|
|
1553
|
+
(0, exports.sameRevisionRef)(dependency.revisionRef, registration.resultSchemaRevisionRef))
|
|
810
1554
|
: undefined;
|
|
811
1555
|
if (!inputDependency || (registration.resultSchemaRevisionRef && !resultDependency)) {
|
|
812
1556
|
throw new DeclarativeControlCompilationError('DEPENDENCY_MISSING', `nodes[${index}].targetRef`, 'Governed DomainCommand schemas are not pinned by NavigationRelease.');
|
|
@@ -818,7 +1562,9 @@ const compileNavigationRuntimeBundle = (input) => {
|
|
|
818
1562
|
execution: 'server',
|
|
819
1563
|
commandRevisionRef: registration.targetRevisionRef,
|
|
820
1564
|
inputSchemaRevisionRef: registration.inputSchemaRevisionRef,
|
|
821
|
-
...(registration.resultSchemaRevisionRef
|
|
1565
|
+
...(registration.resultSchemaRevisionRef
|
|
1566
|
+
? { resultSchemaRevisionRef: registration.resultSchemaRevisionRef }
|
|
1567
|
+
: {}),
|
|
822
1568
|
input: common_1.JsonObjectSchema.parse(mappedInput),
|
|
823
1569
|
};
|
|
824
1570
|
}
|
|
@@ -846,7 +1592,10 @@ const compileNavigationRuntimeBundle = (input) => {
|
|
|
846
1592
|
performanceBudgetRef: navigation.performanceBudgetRef,
|
|
847
1593
|
observationPolicyRevisionRef: navigation.observationPolicyRevisionRef,
|
|
848
1594
|
};
|
|
849
|
-
return deepFreeze(declarative_control_1.NavigationRuntimeBundleSchema.parse({
|
|
1595
|
+
return deepFreeze(declarative_control_1.NavigationRuntimeBundleSchema.parse({
|
|
1596
|
+
...unsigned,
|
|
1597
|
+
contentHash: (0, exports.canonicalContentHash)(unsigned),
|
|
1598
|
+
}));
|
|
850
1599
|
};
|
|
851
1600
|
exports.compileNavigationRuntimeBundle = compileNavigationRuntimeBundle;
|
|
852
1601
|
const validateWorkbenchRuntimeSet = (bundleInputs) => {
|
|
@@ -859,9 +1608,9 @@ const validateWorkbenchRuntimeSet = (bundleInputs) => {
|
|
|
859
1608
|
const seenOrders = new Set();
|
|
860
1609
|
let defaultCount = 0;
|
|
861
1610
|
bundles.forEach((bundle, index) => {
|
|
862
|
-
if (scopeKey(bundle.tenantScope) !== scopeKey(first.tenantScope)
|
|
863
|
-
|
|
864
|
-
|
|
1611
|
+
if (scopeKey(bundle.tenantScope) !== scopeKey(first.tenantScope) ||
|
|
1612
|
+
bundle.surface !== first.surface ||
|
|
1613
|
+
!(0, exports.sameStableRef)(bundle.target.environmentRef, first.target.environmentRef)) {
|
|
865
1614
|
throw new DeclarativeControlCompilationError('WORKBENCH_RELEASE_SET_INVALID', `bundles[${index}]`, 'Workbench release set entries must share tenant, environment, and surface.');
|
|
866
1615
|
}
|
|
867
1616
|
if (seenIds.has(bundle.workbenchId))
|
|
@@ -894,7 +1643,11 @@ const resolveWorkbenchEntry = (input) => {
|
|
|
894
1643
|
if (defaultBundle)
|
|
895
1644
|
return { status: 'resolved', bundle: defaultBundle, source: 'default' };
|
|
896
1645
|
if (allowed[0])
|
|
897
|
-
return {
|
|
1646
|
+
return {
|
|
1647
|
+
status: 'resolved',
|
|
1648
|
+
bundle: allowed[0],
|
|
1649
|
+
source: 'first-accessible',
|
|
1650
|
+
};
|
|
898
1651
|
return { status: 'forbidden', workbenchId: '' };
|
|
899
1652
|
};
|
|
900
1653
|
exports.resolveWorkbenchEntry = resolveWorkbenchEntry;
|