@inf-monkeys-tech/monkeys 1.0.72 → 1.1.1
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 +80610 -41684
- package/lib/contracts/declarative-control-http.d.ts.map +1 -1
- package/lib/contracts/declarative-control-http.js +1596 -165
- package/lib/contracts/declarative-control-http.js.map +1 -1
- package/lib/contracts/declarative-control.d.ts +12525 -4613
- package/lib/contracts/declarative-control.d.ts.map +1 -1
- package/lib/contracts/declarative-control.js +3792 -422
- 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 +607 -1
- package/lib/contracts/render.d.ts.map +1 -1
- package/lib/contracts/render.js +332 -133
- 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 +115 -9
- 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/contracts/theme.d.ts +1 -1
- package/lib/esm/contracts/index.mjs +8466 -3114
- package/lib/esm/contracts/index.mjs.map +1 -1
- package/lib/esm/index.mjs +13809 -5067
- package/lib/esm/index.mjs.map +1 -1
- package/lib/esm/runtime/index.mjs +13964 -4515
- package/lib/esm/runtime/index.mjs.map +1 -1
- package/lib/esm/schemas/index.mjs +8779 -2614
- 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 +883 -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 +7334 -1153
- package/lib/json-schema/page-runtime-descriptor.schema.json +34 -0
- package/lib/json-schema/page.schema.json +6329 -6602
- 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 +883 -0
- package/lib/json-schema/render-tree.schema.json +883 -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 +106 -20
- package/lib/runtime/declarative-control-compiler.d.ts.map +1 -1
- package/lib/runtime/declarative-control-compiler.js +1525 -280
- 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 +5969 -2731
- package/lib/schemas/index.d.ts.map +1 -1
- package/lib/schemas/index.js +174 -95
- package/lib/schemas/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.
|
|
3
|
+
exports.CursorWindowBindingSchema = exports.DomainQueryDefinitionSchema = exports.DomainQueryDataSourceSchema = exports.RegisteredServiceDomainQueryDataSourceSchema = exports.GovernedCatalogDomainQueryDataSourceSchema = exports.GovernedCatalogResourceKindSchema = exports.InteractionBindingSchema = exports.PageStateDefinitionSchema = exports.LegacyBrowserPreferenceImportSchema = exports.ResolvedPageEntryTransitionSchema = exports.PageEntryTransitionSchema = exports.PageStateActivationSchema = exports.PageStateConditionSchema = exports.BindingSourceSchema = exports.DeclarativeRouteClaimSchema = exports.LegacyRouteTakeoverAuthorizationSchema = exports.LegacySlotRestorationSchema = exports.WorkbenchIdentitySchema = exports.PublicationPlanSchema = exports.PublicationPlanOperationSchema = exports.ReleaseEvidenceSchema = exports.ReleaseValidationSchema = exports.ReleaseDependencySchema = exports.ReleaseDependencyRoleSchema = exports.ReleaseOperationSchema = exports.CompiledRouteClaimSchema = exports.CompiledRouteMatcherSchema = exports.RouteClaimSchema = exports.LegacyRouteClaimSchema = exports.RouteSpaceSchema = exports.RouteSpaceParameterSchema = exports.RoutePathTemplateSchema = exports.ManagementAccessSchema = exports.PermissionAlternativePolicySchema = exports.AccessPolicySchema = exports.DeclarativeRuntimeShellDescriptorSchema = exports.DeclarativeShellSurfaceChromeSchema = exports.DeclarativeShellHeaderChromeSchema = exports.ProductSurfaceSchema = exports.DeclarativeLifecycleSchema = exports.StableRefAliasMapSchema = exports.StableRefAliasSchema = exports.RevisionRefSchema = exports.StableRefSchema = exports.ReferenceVisibilitySchema = exports.TenantScopeSchema = exports.ScopedIdentityRefSchema = exports.I18nTextSchema = exports.DECLARATIVE_CONTROL_SCHEMA_VERSION = exports.analyzePageBindingDependencies = void 0;
|
|
4
|
+
exports.DeclarativeControlOntologyDefinitionSchema = exports.NavigationRuntimeBundleSchema = exports.CompiledNavigationNodeSchema = exports.CompiledNavigationSeparatorNodeSchema = exports.CompiledNavigationTargetNodeSchema = exports.CompiledNavigationGroupNodeSchema = exports.CompiledNavigationResolvedTargetSchema = exports.CompiledNavigationDomainCommandTargetSchema = exports.CompiledNavigationRegisteredMenuActionTargetSchema = exports.WorkbenchRuntimeBundleSchema = exports.WorkbenchRuntimeIdentitySchema = exports.ResolvedWorkbenchAppInstanceSchema = exports.PageRuntimeBundleSchema = exports.DeclarativeWorkbenchCatalogSchema = exports.DeclarativeWorkbenchCatalogEntrySchema = exports.DeclarativeRouteOwnerIndexSchema = exports.DeclarativeRouteOwnerIndexEntrySchema = exports.NavigationReleaseSchema = exports.UnavailableNavigationTargetSchema = exports.ResolvedNavigationTargetSchema = exports.NavigationSchema = exports.NavigationNodeSchema = exports.NavigationSeparatorNodeSchema = exports.NavigationTargetNodeSchema = exports.NavigationGroupNodeSchema = exports.WorkbenchReleaseSchema = exports.WorkbenchSchema = exports.WorkbenchAppInstanceSchema = exports.WorkbenchGroupSchema = exports.PageReleaseSchema = exports.ResolvedPageSchema = exports.PageSchema = exports.PageNodeSchema = exports.PageActionSchema = exports.PageDataSchema = exports.PageInteractionSchema = exports.PageEntrySchema = exports.PageEntryTargetSchema = exports.PageStateSchema = exports.PageRouteStatePresentationSchema = exports.PageMigrationEquivalenceSchema = exports.PageMigrationEquivalenceDimensionSchema = exports.ActionBindingSchema = exports.ActionResultClipboardEffectSchema = exports.ActionResultBindingEffectSchema = exports.ActionResultBindingEffectSourceSchema = exports.OntologyBindingSchema = exports.CapabilityInstanceSchema = exports.QueryBindingSchema = exports.QueryResultStateBindingSchema = void 0;
|
|
5
|
+
exports.DECLARATIVE_CONTROL_ONTOLOGY_DEFINITIONS = void 0;
|
|
5
6
|
const zod_1 = require("zod");
|
|
6
7
|
const common_1 = require("./common");
|
|
7
8
|
const data_1 = require("./data");
|
|
9
|
+
const legacy_route_1 = require("./legacy-route");
|
|
10
|
+
const file_1 = require("./file");
|
|
8
11
|
const render_1 = require("./render");
|
|
12
|
+
const page_expression_1 = require("./page-expression");
|
|
13
|
+
const page_binding_dependencies_1 = require("./page-binding-dependencies");
|
|
14
|
+
var page_binding_dependencies_2 = require("./page-binding-dependencies");
|
|
15
|
+
Object.defineProperty(exports, "analyzePageBindingDependencies", { enumerable: true, get: function () { return page_binding_dependencies_2.analyzePageBindingDependencies; } });
|
|
9
16
|
exports.DECLARATIVE_CONTROL_SCHEMA_VERSION = 1;
|
|
10
17
|
const uniqueArray = (values, identity) => {
|
|
11
18
|
const seen = new Set();
|
|
@@ -17,6 +24,10 @@ const uniqueArray = (values, identity) => {
|
|
|
17
24
|
}
|
|
18
25
|
return undefined;
|
|
19
26
|
};
|
|
27
|
+
const exactRevisionRef = (left, right) => stableRefIdentity(left) === stableRefIdentity(right) &&
|
|
28
|
+
left.revision === right.revision &&
|
|
29
|
+
left.schemaVersion === right.schemaVersion &&
|
|
30
|
+
left.contentHash === right.contentHash;
|
|
20
31
|
exports.I18nTextSchema = zod_1.z
|
|
21
32
|
.object({
|
|
22
33
|
defaultLocale: common_1.LocaleIdentifierSchema,
|
|
@@ -26,9 +37,9 @@ exports.I18nTextSchema = zod_1.z
|
|
|
26
37
|
.superRefine((value, context) => {
|
|
27
38
|
if (!Object.prototype.hasOwnProperty.call(value.values, value.defaultLocale)) {
|
|
28
39
|
context.addIssue({
|
|
29
|
-
code:
|
|
30
|
-
path: [
|
|
31
|
-
message:
|
|
40
|
+
code: "custom",
|
|
41
|
+
path: ["values", value.defaultLocale],
|
|
42
|
+
message: "I18nText values must contain the default locale.",
|
|
32
43
|
});
|
|
33
44
|
}
|
|
34
45
|
});
|
|
@@ -48,17 +59,21 @@ exports.TenantScopeSchema = zod_1.z
|
|
|
48
59
|
.strict()
|
|
49
60
|
.superRefine((value, context) => {
|
|
50
61
|
const expectedKinds = [
|
|
51
|
-
[
|
|
52
|
-
[
|
|
53
|
-
[
|
|
62
|
+
["tenantRef", value.tenantRef, "tenant"],
|
|
63
|
+
["dataSpaceRef", value.dataSpaceRef, "data-space"],
|
|
64
|
+
["teamRef", value.teamRef, "team"],
|
|
54
65
|
];
|
|
55
66
|
expectedKinds.forEach(([field, reference, expectedKind]) => {
|
|
56
67
|
if (reference && reference.kind !== expectedKind) {
|
|
57
|
-
context.addIssue({
|
|
68
|
+
context.addIssue({
|
|
69
|
+
code: "custom",
|
|
70
|
+
path: [field, "kind"],
|
|
71
|
+
message: `${field} must reference ${expectedKind}.`,
|
|
72
|
+
});
|
|
58
73
|
}
|
|
59
74
|
});
|
|
60
75
|
});
|
|
61
|
-
exports.ReferenceVisibilitySchema = zod_1.z.enum([
|
|
76
|
+
exports.ReferenceVisibilitySchema = zod_1.z.enum(["tenant", "global", "public"]);
|
|
62
77
|
const StableRefShape = {
|
|
63
78
|
kind: common_1.ContractIdentifierSchema,
|
|
64
79
|
id: common_1.ContractIdentifierSchema,
|
|
@@ -67,11 +82,19 @@ const StableRefShape = {
|
|
|
67
82
|
tenantScope: exports.TenantScopeSchema.optional(),
|
|
68
83
|
};
|
|
69
84
|
const validateReferenceScope = (value, context) => {
|
|
70
|
-
if (value.visibility ===
|
|
71
|
-
context.addIssue({
|
|
85
|
+
if (value.visibility === "tenant" && !value.tenantScope) {
|
|
86
|
+
context.addIssue({
|
|
87
|
+
code: "custom",
|
|
88
|
+
path: ["tenantScope"],
|
|
89
|
+
message: "Tenant references require an explicit tenant scope.",
|
|
90
|
+
});
|
|
72
91
|
}
|
|
73
|
-
if (value.visibility !==
|
|
74
|
-
context.addIssue({
|
|
92
|
+
if (value.visibility !== "tenant" && value.tenantScope) {
|
|
93
|
+
context.addIssue({
|
|
94
|
+
code: "custom",
|
|
95
|
+
path: ["tenantScope"],
|
|
96
|
+
message: "Global and public references cannot carry a tenant scope.",
|
|
97
|
+
});
|
|
75
98
|
}
|
|
76
99
|
};
|
|
77
100
|
exports.StableRefSchema = zod_1.z
|
|
@@ -88,12 +111,19 @@ exports.RevisionRefSchema = zod_1.z
|
|
|
88
111
|
.strict()
|
|
89
112
|
.superRefine(validateReferenceScope);
|
|
90
113
|
const scopedIdentityKey = (reference) => `${reference.kind}:${reference.id}:${reference.ownerRepo}`;
|
|
91
|
-
const tenantScopeKey = (scope) => `${scopedIdentityKey(scope.tenantRef)}:${scopedIdentityKey(scope.dataSpaceRef)}:${scope.teamRef ? scopedIdentityKey(scope.teamRef) :
|
|
92
|
-
const stableRefIdentity = (reference) => `${reference.visibility}:${reference.tenantScope ? tenantScopeKey(reference.tenantScope) :
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
114
|
+
const tenantScopeKey = (scope) => `${scopedIdentityKey(scope.tenantRef)}:${scopedIdentityKey(scope.dataSpaceRef)}:${scope.teamRef ? scopedIdentityKey(scope.teamRef) : ""}`;
|
|
115
|
+
const stableRefIdentity = (reference) => `${reference.visibility}:${reference.tenantScope ? tenantScopeKey(reference.tenantScope) : ""}:${reference.kind}:${reference.id}:${reference.ownerRepo}`;
|
|
116
|
+
const validateTenantCompatibleReference = (reference, tenantScope, path, context) => {
|
|
117
|
+
if (reference.visibility === "tenant" &&
|
|
118
|
+
reference.tenantScope &&
|
|
119
|
+
tenantScopeKey(reference.tenantScope) !== tenantScopeKey(tenantScope)) {
|
|
120
|
+
context.addIssue({
|
|
121
|
+
code: "custom",
|
|
122
|
+
path: [...path, "tenantScope"],
|
|
123
|
+
message: "Reference belongs to another tenant scope.",
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
};
|
|
97
127
|
exports.StableRefAliasSchema = zod_1.z
|
|
98
128
|
.object({
|
|
99
129
|
aliasRef: exports.StableRefSchema,
|
|
@@ -105,15 +135,23 @@ exports.StableRefAliasSchema = zod_1.z
|
|
|
105
135
|
.strict()
|
|
106
136
|
.superRefine((value, context) => {
|
|
107
137
|
if (value.aliasRef.kind !== value.canonicalRef.kind) {
|
|
108
|
-
context.addIssue({
|
|
138
|
+
context.addIssue({
|
|
139
|
+
code: "custom",
|
|
140
|
+
path: ["canonicalRef", "kind"],
|
|
141
|
+
message: "Alias and canonical references must have the same kind.",
|
|
142
|
+
});
|
|
109
143
|
}
|
|
110
144
|
if (value.validUntil && value.validUntil <= value.validFrom) {
|
|
111
|
-
context.addIssue({
|
|
145
|
+
context.addIssue({
|
|
146
|
+
code: "custom",
|
|
147
|
+
path: ["validUntil"],
|
|
148
|
+
message: "Alias validUntil must be later than validFrom.",
|
|
149
|
+
});
|
|
112
150
|
}
|
|
113
151
|
});
|
|
114
152
|
exports.StableRefAliasMapSchema = zod_1.z
|
|
115
153
|
.object({
|
|
116
|
-
contract: zod_1.z.literal(
|
|
154
|
+
contract: zod_1.z.literal("StableRefAliasMap"),
|
|
117
155
|
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
118
156
|
tenantScope: exports.TenantScopeSchema,
|
|
119
157
|
aliases: zod_1.z.array(exports.StableRefAliasSchema),
|
|
@@ -123,17 +161,78 @@ exports.StableRefAliasMapSchema = zod_1.z
|
|
|
123
161
|
.superRefine((value, context) => {
|
|
124
162
|
const duplicate = uniqueArray(value.aliases, (entry) => stableRefIdentity(entry.aliasRef));
|
|
125
163
|
if (duplicate)
|
|
126
|
-
context.addIssue({
|
|
164
|
+
context.addIssue({
|
|
165
|
+
code: "custom",
|
|
166
|
+
path: ["aliases"],
|
|
167
|
+
message: `Duplicate alias reference: ${duplicate}`,
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
exports.DeclarativeLifecycleSchema = zod_1.z.enum([
|
|
171
|
+
"active",
|
|
172
|
+
"deprecated",
|
|
173
|
+
"retired",
|
|
174
|
+
]);
|
|
175
|
+
exports.ProductSurfaceSchema = zod_1.z.enum(["studio", "kernel"]);
|
|
176
|
+
exports.DeclarativeShellHeaderChromeSchema = zod_1.z.discriminatedUnion("enabled", [
|
|
177
|
+
zod_1.z.object({ enabled: zod_1.z.literal(false) }).strict(),
|
|
178
|
+
zod_1.z
|
|
179
|
+
.object({
|
|
180
|
+
enabled: zod_1.z.literal(true),
|
|
181
|
+
navigationPlacement: zod_1.z.enum([
|
|
182
|
+
"studio.headbar.primary",
|
|
183
|
+
"kernel.primary",
|
|
184
|
+
]),
|
|
185
|
+
})
|
|
186
|
+
.strict(),
|
|
187
|
+
]);
|
|
188
|
+
exports.DeclarativeShellSurfaceChromeSchema = zod_1.z
|
|
189
|
+
.object({
|
|
190
|
+
surface: exports.ProductSurfaceSchema,
|
|
191
|
+
header: exports.DeclarativeShellHeaderChromeSchema,
|
|
192
|
+
})
|
|
193
|
+
.strict()
|
|
194
|
+
.superRefine((value, context) => {
|
|
195
|
+
if (!value.header.enabled)
|
|
196
|
+
return;
|
|
197
|
+
const expectedPlacement = value.surface === "studio" ? "studio.headbar.primary" : "kernel.primary";
|
|
198
|
+
if (value.header.navigationPlacement !== expectedPlacement) {
|
|
199
|
+
context.addIssue({
|
|
200
|
+
code: "custom",
|
|
201
|
+
path: ["header", "navigationPlacement"],
|
|
202
|
+
message: `The ${value.surface} shell header must use its governed primary Navigation placement.`,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
exports.DeclarativeRuntimeShellDescriptorSchema = zod_1.z
|
|
207
|
+
.object({
|
|
208
|
+
shellRevisionRef: exports.RevisionRefSchema,
|
|
209
|
+
header: exports.DeclarativeShellHeaderChromeSchema,
|
|
210
|
+
})
|
|
211
|
+
.strict()
|
|
212
|
+
.superRefine((value, context) => {
|
|
213
|
+
if (value.shellRevisionRef.kind !== "shell") {
|
|
214
|
+
context.addIssue({
|
|
215
|
+
code: "custom",
|
|
216
|
+
path: ["shellRevisionRef", "kind"],
|
|
217
|
+
message: "Runtime shell descriptors require an exact Shell revision.",
|
|
218
|
+
});
|
|
219
|
+
}
|
|
127
220
|
});
|
|
128
|
-
exports.DeclarativeLifecycleSchema = zod_1.z.enum(['active', 'deprecated', 'retired']);
|
|
129
|
-
exports.ProductSurfaceSchema = zod_1.z.enum(['studio', 'kernel']);
|
|
130
221
|
const GroupRefSchema = exports.StableRefSchema.superRefine((value, context) => {
|
|
131
|
-
if (value.kind !==
|
|
132
|
-
context.addIssue({
|
|
222
|
+
if (value.kind !== "group")
|
|
223
|
+
context.addIssue({
|
|
224
|
+
code: "custom",
|
|
225
|
+
path: ["kind"],
|
|
226
|
+
message: "Access group references must use kind group.",
|
|
227
|
+
});
|
|
133
228
|
});
|
|
134
229
|
const AccessConditionRefSchema = exports.RevisionRefSchema.superRefine((value, context) => {
|
|
135
|
-
if (value.kind !==
|
|
136
|
-
context.addIssue({
|
|
230
|
+
if (value.kind !== "access-condition") {
|
|
231
|
+
context.addIssue({
|
|
232
|
+
code: "custom",
|
|
233
|
+
path: ["kind"],
|
|
234
|
+
message: "Access condition references must use kind access-condition.",
|
|
235
|
+
});
|
|
137
236
|
}
|
|
138
237
|
});
|
|
139
238
|
exports.AccessPolicySchema = zod_1.z
|
|
@@ -148,16 +247,74 @@ exports.AccessPolicySchema = zod_1.z
|
|
|
148
247
|
.strict()
|
|
149
248
|
.superRefine((value, context) => {
|
|
150
249
|
const checks = [
|
|
151
|
-
[
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
250
|
+
[
|
|
251
|
+
"groupAllOf",
|
|
252
|
+
value.groupAllOf,
|
|
253
|
+
(candidate) => stableRefIdentity(candidate),
|
|
254
|
+
],
|
|
255
|
+
[
|
|
256
|
+
"groupAnyOf",
|
|
257
|
+
value.groupAnyOf,
|
|
258
|
+
(candidate) => stableRefIdentity(candidate),
|
|
259
|
+
],
|
|
260
|
+
["permissionAllOf", value.permissionAllOf, String],
|
|
261
|
+
["permissionAnyOf", value.permissionAnyOf, String],
|
|
262
|
+
[
|
|
263
|
+
"conditionAllOf",
|
|
264
|
+
value.conditionAllOf,
|
|
265
|
+
(candidate) => `${stableRefIdentity(candidate)}@${candidate.revision}`,
|
|
266
|
+
],
|
|
156
267
|
];
|
|
157
268
|
checks.forEach(([field, values, identity]) => {
|
|
158
269
|
if (uniqueArray(values, identity))
|
|
159
|
-
context.addIssue({
|
|
270
|
+
context.addIssue({
|
|
271
|
+
code: "custom",
|
|
272
|
+
path: [field],
|
|
273
|
+
message: `${field} entries must be unique.`,
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
/**
|
|
278
|
+
* A finite set of permission conjunctions. An identity is authorized when it
|
|
279
|
+
* satisfies every permission in at least one alternative. This is deliberately
|
|
280
|
+
* separate from AccessPolicy: it models a versioned rollout compatibility
|
|
281
|
+
* bridge such as `new-permission OR (legacy-a AND legacy-b)` without turning
|
|
282
|
+
* individual legacy permissions into broad aliases.
|
|
283
|
+
*/
|
|
284
|
+
exports.PermissionAlternativePolicySchema = zod_1.z
|
|
285
|
+
.object({
|
|
286
|
+
contract: zod_1.z.literal("PermissionAlternativePolicy"),
|
|
287
|
+
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
288
|
+
policyId: common_1.ContractIdentifierSchema,
|
|
289
|
+
alternatives: zod_1.z.array(zod_1.z.array(common_1.ContractIdentifierSchema).min(1)).min(1),
|
|
290
|
+
retirementGate: zod_1.z
|
|
291
|
+
.object({
|
|
292
|
+
capability: common_1.ContractIdentifierSchema,
|
|
293
|
+
notBefore: common_1.IsoDateTimeSchema.optional(),
|
|
294
|
+
})
|
|
295
|
+
.strict()
|
|
296
|
+
.optional(),
|
|
297
|
+
})
|
|
298
|
+
.strict()
|
|
299
|
+
.superRefine((value, context) => {
|
|
300
|
+
const canonical = value.alternatives.map((set) => [...new Set(set)].sort());
|
|
301
|
+
canonical.forEach((set, index) => {
|
|
302
|
+
if (set.length !== value.alternatives[index].length) {
|
|
303
|
+
context.addIssue({
|
|
304
|
+
code: "custom",
|
|
305
|
+
path: ["alternatives", index],
|
|
306
|
+
message: "A permission alternative cannot contain duplicate permissions.",
|
|
307
|
+
});
|
|
308
|
+
}
|
|
160
309
|
});
|
|
310
|
+
const identities = canonical.map((set) => set.join("\0"));
|
|
311
|
+
if (new Set(identities).size !== identities.length) {
|
|
312
|
+
context.addIssue({
|
|
313
|
+
code: "custom",
|
|
314
|
+
path: ["alternatives"],
|
|
315
|
+
message: "Permission alternatives must be unique.",
|
|
316
|
+
});
|
|
317
|
+
}
|
|
161
318
|
});
|
|
162
319
|
exports.ManagementAccessSchema = zod_1.z
|
|
163
320
|
.object({
|
|
@@ -172,81 +329,108 @@ exports.ManagementAccessSchema = zod_1.z
|
|
|
172
329
|
exports.RoutePathTemplateSchema = zod_1.z
|
|
173
330
|
.string()
|
|
174
331
|
.trim()
|
|
175
|
-
.regex(/^\/(?!\/)/,
|
|
332
|
+
.regex(/^\/(?!\/)/, "Expected an application-relative path.")
|
|
176
333
|
.superRefine((value, context) => {
|
|
177
|
-
if (value.includes(
|
|
178
|
-
context.addIssue({
|
|
334
|
+
if (value.includes("?") || value.includes("#") || value.includes("\\")) {
|
|
335
|
+
context.addIssue({
|
|
336
|
+
code: "custom",
|
|
337
|
+
message: "Route paths cannot contain query strings, fragments, or backslashes.",
|
|
338
|
+
});
|
|
179
339
|
}
|
|
180
|
-
if (value.split(
|
|
181
|
-
context.addIssue({
|
|
340
|
+
if (value.split("/").some((segment) => segment === "." || segment === "..")) {
|
|
341
|
+
context.addIssue({
|
|
342
|
+
code: "custom",
|
|
343
|
+
message: "Route paths cannot contain traversal segments.",
|
|
344
|
+
});
|
|
182
345
|
}
|
|
183
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(value) || value.includes(
|
|
184
|
-
context.addIssue({
|
|
346
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(value) || value.includes("://")) {
|
|
347
|
+
context.addIssue({
|
|
348
|
+
code: "custom",
|
|
349
|
+
message: "Route paths cannot contain a scheme or host.",
|
|
350
|
+
});
|
|
185
351
|
}
|
|
186
352
|
});
|
|
187
353
|
exports.RouteSpaceParameterSchema = zod_1.z
|
|
188
354
|
.object({
|
|
189
355
|
name: common_1.ContractIdentifierSchema,
|
|
190
|
-
type: zod_1.z.enum([
|
|
356
|
+
type: zod_1.z.enum(["identifier", "integer", "slug", "uuid"]),
|
|
191
357
|
required: zod_1.z.boolean(),
|
|
192
358
|
})
|
|
193
359
|
.strict();
|
|
194
360
|
exports.RouteSpaceSchema = zod_1.z
|
|
195
361
|
.object({
|
|
196
|
-
contract: zod_1.z.literal(
|
|
362
|
+
contract: zod_1.z.literal("RouteSpace"),
|
|
197
363
|
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
198
364
|
routeSpaceId: common_1.ContractIdentifierSchema,
|
|
199
365
|
supportedSurface: exports.ProductSurfaceSchema,
|
|
200
366
|
basePath: exports.RoutePathTemplateSchema,
|
|
201
367
|
caseSensitive: zod_1.z.boolean(),
|
|
202
|
-
trailingSlash: zod_1.z.enum([
|
|
368
|
+
trailingSlash: zod_1.z.enum(["preserve", "remove", "require"]),
|
|
203
369
|
reservedPaths: zod_1.z.array(exports.RoutePathTemplateSchema),
|
|
204
370
|
parameters: zod_1.z.array(exports.RouteSpaceParameterSchema),
|
|
205
371
|
})
|
|
206
372
|
.strict()
|
|
207
373
|
.superRefine((value, context) => {
|
|
208
374
|
if (uniqueArray(value.parameters, (parameter) => parameter.name)) {
|
|
209
|
-
context.addIssue({
|
|
375
|
+
context.addIssue({
|
|
376
|
+
code: "custom",
|
|
377
|
+
path: ["parameters"],
|
|
378
|
+
message: "RouteSpace parameter names must be unique.",
|
|
379
|
+
});
|
|
210
380
|
}
|
|
211
381
|
if (uniqueArray(value.reservedPaths, (path) => path)) {
|
|
212
|
-
context.addIssue({
|
|
382
|
+
context.addIssue({
|
|
383
|
+
code: "custom",
|
|
384
|
+
path: ["reservedPaths"],
|
|
385
|
+
message: "RouteSpace reserved paths must be unique.",
|
|
386
|
+
});
|
|
213
387
|
}
|
|
214
388
|
});
|
|
215
389
|
const RouteClaimBaseSchema = zod_1.z
|
|
216
390
|
.object({
|
|
217
|
-
kind: zod_1.z.enum([
|
|
391
|
+
kind: zod_1.z.enum(["canonical", "alias", "redirect"]),
|
|
218
392
|
routeSpaceRevisionRef: exports.RevisionRefSchema,
|
|
219
393
|
pathTemplate: exports.RoutePathTemplateSchema,
|
|
220
394
|
redirectTargetRef: exports.StableRefSchema.optional(),
|
|
221
395
|
})
|
|
222
396
|
.strict()
|
|
223
397
|
.superRefine((value, context) => {
|
|
224
|
-
if (value.routeSpaceRevisionRef.kind !==
|
|
225
|
-
context.addIssue({
|
|
398
|
+
if (value.routeSpaceRevisionRef.kind !== "route-space") {
|
|
399
|
+
context.addIssue({
|
|
400
|
+
code: "custom",
|
|
401
|
+
path: ["routeSpaceRevisionRef", "kind"],
|
|
402
|
+
message: "Route claims must reference a route-space revision.",
|
|
403
|
+
});
|
|
226
404
|
}
|
|
227
|
-
if (value.kind ===
|
|
228
|
-
context.addIssue({
|
|
405
|
+
if (value.kind === "redirect" && !value.redirectTargetRef) {
|
|
406
|
+
context.addIssue({
|
|
407
|
+
code: "custom",
|
|
408
|
+
path: ["redirectTargetRef"],
|
|
409
|
+
message: "Redirect claims require a governed target reference.",
|
|
410
|
+
});
|
|
229
411
|
}
|
|
230
|
-
if (value.kind !==
|
|
231
|
-
context.addIssue({
|
|
412
|
+
if (value.kind !== "redirect" && value.redirectTargetRef) {
|
|
413
|
+
context.addIssue({
|
|
414
|
+
code: "custom",
|
|
415
|
+
path: ["redirectTargetRef"],
|
|
416
|
+
message: "Only redirect claims may declare redirectTargetRef.",
|
|
417
|
+
});
|
|
232
418
|
}
|
|
233
419
|
});
|
|
234
420
|
/**
|
|
235
421
|
* Read compatibility for schemaVersion 1 Page and Workbench records written
|
|
236
422
|
* before route claims carried their owning product surface. New declarations
|
|
237
|
-
* must use RouteClaimSchema; compilers
|
|
238
|
-
* exact pinned RouteSpace.
|
|
423
|
+
* must use RouteClaimSchema; compilers materialize this legacy form only from
|
|
424
|
+
* the exact pinned RouteSpace surface.
|
|
239
425
|
*/
|
|
240
426
|
exports.LegacyRouteClaimSchema = RouteClaimBaseSchema;
|
|
241
427
|
exports.RouteClaimSchema = RouteClaimBaseSchema.safeExtend({
|
|
242
428
|
surface: exports.ProductSurfaceSchema,
|
|
243
429
|
}).strict();
|
|
244
|
-
exports.DeclarativeRouteClaimSchema = exports.RouteClaimSchema;
|
|
245
|
-
const LegacyDeclarativeRouteClaimSchema = exports.LegacyRouteClaimSchema;
|
|
246
430
|
const LegacyCompiledRouteMatcherSchema = zod_1.z
|
|
247
431
|
.object({
|
|
248
432
|
caseSensitive: zod_1.z.boolean(),
|
|
249
|
-
trailingSlash: zod_1.z.enum([
|
|
433
|
+
trailingSlash: zod_1.z.enum(["preserve", "remove", "require"]),
|
|
250
434
|
parameters: zod_1.z.array(exports.RouteSpaceParameterSchema),
|
|
251
435
|
})
|
|
252
436
|
.strict();
|
|
@@ -256,90 +440,98 @@ exports.CompiledRouteMatcherSchema = LegacyCompiledRouteMatcherSchema.safeExtend
|
|
|
256
440
|
exports.CompiledRouteClaimSchema = exports.RouteClaimSchema.safeExtend({
|
|
257
441
|
normalizedPath: exports.RoutePathTemplateSchema,
|
|
258
442
|
matcher: exports.CompiledRouteMatcherSchema,
|
|
259
|
-
})
|
|
443
|
+
})
|
|
444
|
+
.strict()
|
|
445
|
+
.superRefine((value, context) => {
|
|
446
|
+
if (value.matcher.surface !== value.surface) {
|
|
447
|
+
context.addIssue({
|
|
448
|
+
code: "custom",
|
|
449
|
+
path: ["matcher", "surface"],
|
|
450
|
+
message: "A compiled route matcher must match its claim surface.",
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
});
|
|
260
454
|
const LegacyCompiledRouteClaimSchema = exports.LegacyRouteClaimSchema.safeExtend({
|
|
261
455
|
normalizedPath: exports.RoutePathTemplateSchema,
|
|
262
456
|
matcher: LegacyCompiledRouteMatcherSchema,
|
|
263
457
|
}).strict();
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
if (
|
|
270
|
-
context.addIssue({ code: 'custom', path: ['routeClaims'], message: 'Route claims must either all declare surface or all omit it for legacy compatibility.' });
|
|
458
|
+
const validateReleaseRouteSurface = (target, context) => {
|
|
459
|
+
const claimSurface = "surface" in target.routeClaim ? target.routeClaim.surface : undefined;
|
|
460
|
+
const matcherSurface = "surface" in target.routeClaim.matcher
|
|
461
|
+
? target.routeClaim.matcher.surface
|
|
462
|
+
: undefined;
|
|
463
|
+
if (claimSurface === undefined && matcherSurface === undefined)
|
|
271
464
|
return;
|
|
272
|
-
|
|
273
|
-
routeClaims.forEach((claim, index) => {
|
|
274
|
-
if ('surface' in claim && !supportedSurfaces.includes(claim.surface)) {
|
|
275
|
-
context.addIssue({ code: 'custom', path: ['routeClaims', index, 'surface'], message: 'Route claim surface must be declared by supportedSurfaces.' });
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
if (explicitClaims.length !== routeClaims.length)
|
|
465
|
+
if (claimSurface === target.surface && matcherSurface === target.surface)
|
|
279
466
|
return;
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
467
|
+
context.addIssue({
|
|
468
|
+
code: "custom",
|
|
469
|
+
path: ["target", "routeClaim"],
|
|
470
|
+
message: "A compiled Release route claim must either be fully legacy or bind both claim and matcher to the target surface.",
|
|
285
471
|
});
|
|
286
472
|
};
|
|
287
|
-
exports.ReleaseOperationSchema = zod_1.z.enum([
|
|
473
|
+
exports.ReleaseOperationSchema = zod_1.z.enum([
|
|
474
|
+
"activate",
|
|
475
|
+
"deactivate",
|
|
476
|
+
"rollback",
|
|
477
|
+
]);
|
|
288
478
|
exports.ReleaseDependencyRoleSchema = zod_1.z.enum([
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
479
|
+
"route-space",
|
|
480
|
+
"shell",
|
|
481
|
+
"page",
|
|
482
|
+
"page-release",
|
|
483
|
+
"workbench",
|
|
484
|
+
"workbench-release",
|
|
485
|
+
"navigation",
|
|
486
|
+
"navigation-release",
|
|
487
|
+
"menu-action",
|
|
488
|
+
"application-menu-catalog",
|
|
489
|
+
"capability",
|
|
490
|
+
"provider",
|
|
491
|
+
"ontology-definition",
|
|
492
|
+
"query-definition",
|
|
493
|
+
"view",
|
|
494
|
+
"projection",
|
|
495
|
+
"action",
|
|
496
|
+
"token",
|
|
497
|
+
"schema",
|
|
498
|
+
"compiler",
|
|
499
|
+
"workflow",
|
|
500
|
+
"agent",
|
|
501
|
+
"built-in-application",
|
|
502
|
+
"design",
|
|
503
|
+
"layout-policy",
|
|
504
|
+
"performance-budget",
|
|
505
|
+
"observation-policy",
|
|
315
506
|
]);
|
|
316
507
|
const DependencyKindByRole = {
|
|
317
|
-
|
|
318
|
-
shell:
|
|
319
|
-
page:
|
|
320
|
-
|
|
321
|
-
workbench:
|
|
322
|
-
|
|
323
|
-
navigation:
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
capability:
|
|
328
|
-
provider:
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
508
|
+
"route-space": "route-space",
|
|
509
|
+
shell: "shell",
|
|
510
|
+
page: "page",
|
|
511
|
+
"page-release": "page-release",
|
|
512
|
+
workbench: "workbench",
|
|
513
|
+
"workbench-release": "workbench-release",
|
|
514
|
+
navigation: "navigation",
|
|
515
|
+
"navigation-release": "navigation-release",
|
|
516
|
+
"menu-action": "menu-action",
|
|
517
|
+
"application-menu-catalog": "application-menu-catalog",
|
|
518
|
+
capability: "capability",
|
|
519
|
+
provider: "view-provider",
|
|
520
|
+
"ontology-definition": "ontology-definition",
|
|
521
|
+
"query-definition": "domain-query-definition",
|
|
522
|
+
view: "view",
|
|
523
|
+
projection: "projection",
|
|
524
|
+
action: "domain-command",
|
|
525
|
+
token: "design-token",
|
|
526
|
+
schema: "schema",
|
|
527
|
+
compiler: "compiler",
|
|
528
|
+
workflow: "workflow",
|
|
529
|
+
agent: "agent",
|
|
530
|
+
"built-in-application": "built-in-application",
|
|
531
|
+
design: "design",
|
|
532
|
+
"layout-policy": "layout-policy",
|
|
533
|
+
"performance-budget": "performance-budget",
|
|
534
|
+
"observation-policy": "observation-policy",
|
|
343
535
|
};
|
|
344
536
|
exports.ReleaseDependencySchema = zod_1.z
|
|
345
537
|
.object({
|
|
@@ -351,15 +543,15 @@ exports.ReleaseDependencySchema = zod_1.z
|
|
|
351
543
|
const expectedKind = DependencyKindByRole[value.role];
|
|
352
544
|
if (value.revisionRef.kind !== expectedKind) {
|
|
353
545
|
context.addIssue({
|
|
354
|
-
code:
|
|
355
|
-
path: [
|
|
546
|
+
code: "custom",
|
|
547
|
+
path: ["revisionRef", "kind"],
|
|
356
548
|
message: `Dependency role ${value.role} requires reference kind ${expectedKind}.`,
|
|
357
549
|
});
|
|
358
550
|
}
|
|
359
551
|
});
|
|
360
552
|
exports.ReleaseValidationSchema = zod_1.z
|
|
361
553
|
.object({
|
|
362
|
-
result: zod_1.z.enum([
|
|
554
|
+
result: zod_1.z.enum(["pass", "fail"]),
|
|
363
555
|
inputHash: common_1.Sha256Schema,
|
|
364
556
|
diagnosticRefs: zod_1.z.array(exports.RevisionRefSchema),
|
|
365
557
|
})
|
|
@@ -380,41 +572,71 @@ exports.ReleaseEvidenceSchema = zod_1.z
|
|
|
380
572
|
.strict()
|
|
381
573
|
.superRefine((value, context) => {
|
|
382
574
|
const expectedKinds = [
|
|
383
|
-
[
|
|
384
|
-
[
|
|
385
|
-
|
|
386
|
-
|
|
575
|
+
["publicationPlanRef", value.publicationPlanRef, "publication-plan"],
|
|
576
|
+
[
|
|
577
|
+
"approvalPolicyRevisionRef",
|
|
578
|
+
value.approvalPolicyRevisionRef,
|
|
579
|
+
"approval-policy",
|
|
580
|
+
],
|
|
581
|
+
[
|
|
582
|
+
"approvalDecisionRevisionRef",
|
|
583
|
+
value.approvalDecisionRevisionRef,
|
|
584
|
+
"approval-decision",
|
|
585
|
+
],
|
|
586
|
+
["actorRef", value.actorRef, "actor"],
|
|
387
587
|
];
|
|
388
588
|
expectedKinds.forEach(([field, reference, expectedKind]) => {
|
|
389
589
|
if (reference.kind !== expectedKind) {
|
|
390
|
-
context.addIssue({
|
|
590
|
+
context.addIssue({
|
|
591
|
+
code: "custom",
|
|
592
|
+
path: [field, "kind"],
|
|
593
|
+
message: `${field} must reference ${expectedKind}.`,
|
|
594
|
+
});
|
|
391
595
|
}
|
|
392
596
|
});
|
|
393
597
|
value.evidenceRefs.forEach((reference, index) => {
|
|
394
|
-
if (reference.kind !==
|
|
395
|
-
context.addIssue({
|
|
598
|
+
if (reference.kind !== "evidence")
|
|
599
|
+
context.addIssue({
|
|
600
|
+
code: "custom",
|
|
601
|
+
path: ["evidenceRefs", index, "kind"],
|
|
602
|
+
message: "Release evidenceRefs must reference evidence revisions.",
|
|
603
|
+
});
|
|
396
604
|
});
|
|
397
605
|
});
|
|
398
606
|
exports.PublicationPlanOperationSchema = zod_1.z
|
|
399
607
|
.object({
|
|
400
|
-
releaseKind: zod_1.z.enum([
|
|
608
|
+
releaseKind: zod_1.z.enum([
|
|
609
|
+
"page-release",
|
|
610
|
+
"workbench-release",
|
|
611
|
+
"navigation-release",
|
|
612
|
+
]),
|
|
401
613
|
releaseSlotId: common_1.ContractIdentifierSchema,
|
|
402
614
|
releaseRevisionRef: exports.RevisionRefSchema,
|
|
403
615
|
expectedHeadRevisionRef: exports.RevisionRefSchema.nullable(),
|
|
404
616
|
})
|
|
405
617
|
.strict()
|
|
406
618
|
.superRefine((value, context) => {
|
|
407
|
-
if (value.releaseRevisionRef.kind !== value.releaseKind ||
|
|
408
|
-
|
|
619
|
+
if (value.releaseRevisionRef.kind !== value.releaseKind ||
|
|
620
|
+
value.releaseRevisionRef.id !== value.releaseSlotId) {
|
|
621
|
+
context.addIssue({
|
|
622
|
+
code: "custom",
|
|
623
|
+
path: ["releaseRevisionRef"],
|
|
624
|
+
message: "Publication Plan operation must pin the exact release slot revision.",
|
|
625
|
+
});
|
|
409
626
|
}
|
|
410
|
-
if (value.expectedHeadRevisionRef
|
|
411
|
-
|
|
412
|
-
|
|
627
|
+
if (value.expectedHeadRevisionRef &&
|
|
628
|
+
(value.expectedHeadRevisionRef.kind !== value.releaseKind ||
|
|
629
|
+
value.expectedHeadRevisionRef.id !== value.releaseSlotId)) {
|
|
630
|
+
context.addIssue({
|
|
631
|
+
code: "custom",
|
|
632
|
+
path: ["expectedHeadRevisionRef"],
|
|
633
|
+
message: "Expected head must identify the same release slot.",
|
|
634
|
+
});
|
|
413
635
|
}
|
|
414
636
|
});
|
|
415
637
|
exports.PublicationPlanSchema = zod_1.z
|
|
416
638
|
.object({
|
|
417
|
-
contract: zod_1.z.literal(
|
|
639
|
+
contract: zod_1.z.literal("PublicationPlan"),
|
|
418
640
|
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
419
641
|
planId: common_1.ContractIdentifierSchema,
|
|
420
642
|
tenantScope: exports.TenantScopeSchema,
|
|
@@ -430,31 +652,66 @@ exports.PublicationPlanSchema = zod_1.z
|
|
|
430
652
|
})
|
|
431
653
|
.strict()
|
|
432
654
|
.superRefine((value, context) => {
|
|
433
|
-
if (value.environmentRef.kind !==
|
|
434
|
-
context.addIssue({
|
|
655
|
+
if (value.environmentRef.kind !== "environment")
|
|
656
|
+
context.addIssue({
|
|
657
|
+
code: "custom",
|
|
658
|
+
path: ["environmentRef", "kind"],
|
|
659
|
+
message: "Publication Plan requires an environment reference.",
|
|
660
|
+
});
|
|
661
|
+
validateTenantCompatibleReference(value.environmentRef, value.tenantScope, ["environmentRef"], context);
|
|
435
662
|
const governedRefs = [
|
|
436
|
-
[
|
|
437
|
-
|
|
438
|
-
|
|
663
|
+
[
|
|
664
|
+
"approvalPolicyRevisionRef",
|
|
665
|
+
value.approvalPolicyRevisionRef,
|
|
666
|
+
"approval-policy",
|
|
667
|
+
],
|
|
668
|
+
[
|
|
669
|
+
"approvalDecisionRevisionRef",
|
|
670
|
+
value.approvalDecisionRevisionRef,
|
|
671
|
+
"approval-decision",
|
|
672
|
+
],
|
|
673
|
+
["actorRef", value.actorRef, "actor"],
|
|
439
674
|
];
|
|
440
675
|
governedRefs.forEach(([field, reference, expectedKind]) => {
|
|
441
676
|
if (reference.kind !== expectedKind)
|
|
442
|
-
context.addIssue({
|
|
677
|
+
context.addIssue({
|
|
678
|
+
code: "custom",
|
|
679
|
+
path: [field, "kind"],
|
|
680
|
+
message: `${field} must reference ${expectedKind}.`,
|
|
681
|
+
});
|
|
682
|
+
validateTenantCompatibleReference(reference, value.tenantScope, [field], context);
|
|
443
683
|
});
|
|
444
684
|
value.operations.forEach((operation, index) => {
|
|
445
685
|
[operation.releaseRevisionRef, operation.expectedHeadRevisionRef].forEach((reference, referenceIndex) => {
|
|
446
|
-
if (reference?.tenantScope &&
|
|
447
|
-
|
|
448
|
-
|
|
686
|
+
if (reference?.tenantScope &&
|
|
687
|
+
tenantScopeKey(reference.tenantScope) !==
|
|
688
|
+
tenantScopeKey(value.tenantScope)) {
|
|
689
|
+
const field = referenceIndex === 0
|
|
690
|
+
? "releaseRevisionRef"
|
|
691
|
+
: "expectedHeadRevisionRef";
|
|
692
|
+
context.addIssue({
|
|
693
|
+
code: "custom",
|
|
694
|
+
path: ["operations", index, field, "tenantScope"],
|
|
695
|
+
message: "Publication Plan operation belongs to another tenant scope.",
|
|
696
|
+
});
|
|
449
697
|
}
|
|
450
698
|
});
|
|
451
699
|
});
|
|
452
700
|
value.evidenceRefs.forEach((reference, index) => {
|
|
453
|
-
if (reference.kind !==
|
|
454
|
-
context.addIssue({
|
|
701
|
+
if (reference.kind !== "evidence")
|
|
702
|
+
context.addIssue({
|
|
703
|
+
code: "custom",
|
|
704
|
+
path: ["evidenceRefs", index, "kind"],
|
|
705
|
+
message: "Publication Plan evidenceRefs must reference evidence revisions.",
|
|
706
|
+
});
|
|
707
|
+
validateTenantCompatibleReference(reference, value.tenantScope, ["evidenceRefs", index], context);
|
|
455
708
|
});
|
|
456
709
|
if (uniqueArray(value.operations, (operation) => `${operation.releaseKind}:${operation.releaseSlotId}`)) {
|
|
457
|
-
context.addIssue({
|
|
710
|
+
context.addIssue({
|
|
711
|
+
code: "custom",
|
|
712
|
+
path: ["operations"],
|
|
713
|
+
message: "Publication Plan release slots must be unique.",
|
|
714
|
+
});
|
|
458
715
|
}
|
|
459
716
|
});
|
|
460
717
|
const IdentitySchema = zod_1.z
|
|
@@ -464,205 +721,2826 @@ const IdentitySchema = zod_1.z
|
|
|
464
721
|
tags: zod_1.z.array(common_1.ContractIdentifierSchema).default([]),
|
|
465
722
|
})
|
|
466
723
|
.strict();
|
|
467
|
-
exports.WorkbenchIdentitySchema = IdentitySchema.extend({
|
|
724
|
+
exports.WorkbenchIdentitySchema = IdentitySchema.extend({
|
|
725
|
+
iconRef: exports.StableRefSchema.optional(),
|
|
726
|
+
}).strict();
|
|
727
|
+
exports.LegacySlotRestorationSchema = zod_1.z
|
|
728
|
+
.object({
|
|
729
|
+
legacyAdapterRevisionRef: exports.RevisionRefSchema,
|
|
730
|
+
sourceRevisionRef: exports.RevisionRefSchema,
|
|
731
|
+
inspectedSourceContentHash: common_1.Sha256Schema,
|
|
732
|
+
})
|
|
733
|
+
.strict()
|
|
734
|
+
.superRefine((value, context) => {
|
|
735
|
+
if (value.sourceRevisionRef.contentHash !== value.inspectedSourceContentHash) {
|
|
736
|
+
context.addIssue({
|
|
737
|
+
code: "custom",
|
|
738
|
+
path: ["inspectedSourceContentHash"],
|
|
739
|
+
message: "Legacy restoration must pin the exact inspected source revision hash.",
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
/**
|
|
744
|
+
* Exact, inspect-produced authority for taking over one predeclared legacy
|
|
745
|
+
* route. It is not a general reserved-route bypass: compiler validation binds
|
|
746
|
+
* it to one canonical claim, one target resource and the exact inspected
|
|
747
|
+
* source/adaptor revisions.
|
|
748
|
+
*/
|
|
749
|
+
exports.LegacyRouteTakeoverAuthorizationSchema = zod_1.z
|
|
750
|
+
.object({
|
|
751
|
+
contract: zod_1.z.literal("LegacyRouteTakeoverAuthorization"),
|
|
752
|
+
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
753
|
+
routeSpaceRevisionRef: exports.RevisionRefSchema,
|
|
754
|
+
normalizedPath: exports.RoutePathTemplateSchema,
|
|
755
|
+
legacyAdapterRevisionRef: exports.RevisionRefSchema,
|
|
756
|
+
sourceRevisionRef: exports.RevisionRefSchema,
|
|
757
|
+
inspectedSourceContentHash: common_1.Sha256Schema,
|
|
758
|
+
targetResourceRef: exports.StableRefSchema,
|
|
759
|
+
workbenchCatalogDefaults: zod_1.z
|
|
760
|
+
.object({ order: zod_1.z.number().int(), isDefaultCandidate: zod_1.z.boolean() })
|
|
761
|
+
.strict()
|
|
762
|
+
.optional(),
|
|
763
|
+
contentHash: common_1.Sha256Schema,
|
|
764
|
+
})
|
|
765
|
+
.strict()
|
|
766
|
+
.superRefine((value, context) => {
|
|
767
|
+
if (value.routeSpaceRevisionRef.kind !== "route-space") {
|
|
768
|
+
context.addIssue({
|
|
769
|
+
code: "custom",
|
|
770
|
+
path: ["routeSpaceRevisionRef", "kind"],
|
|
771
|
+
message: "A route takeover must pin a RouteSpace revision.",
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
if (value.legacyAdapterRevisionRef.kind !== "legacy-route-adapter") {
|
|
775
|
+
context.addIssue({
|
|
776
|
+
code: "custom",
|
|
777
|
+
path: ["legacyAdapterRevisionRef", "kind"],
|
|
778
|
+
message: "A route takeover must pin a legacy-route-adapter revision.",
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
if (!["page", "workbench"].includes(value.targetResourceRef.kind)) {
|
|
782
|
+
context.addIssue({
|
|
783
|
+
code: "custom",
|
|
784
|
+
path: ["targetResourceRef", "kind"],
|
|
785
|
+
message: "A route takeover target must be a Page or Workbench.",
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
if (value.sourceRevisionRef.contentHash !== value.inspectedSourceContentHash) {
|
|
789
|
+
context.addIssue({
|
|
790
|
+
code: "custom",
|
|
791
|
+
path: ["inspectedSourceContentHash"],
|
|
792
|
+
message: "A route takeover must pin the exact inspected legacy source hash.",
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
if (value.targetResourceRef.kind === "workbench" &&
|
|
796
|
+
!value.workbenchCatalogDefaults) {
|
|
797
|
+
context.addIssue({
|
|
798
|
+
code: "custom",
|
|
799
|
+
path: ["workbenchCatalogDefaults"],
|
|
800
|
+
message: "A Workbench takeover must preserve exact legacy catalog order and default semantics.",
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
if (value.targetResourceRef.kind === "page" &&
|
|
804
|
+
value.workbenchCatalogDefaults) {
|
|
805
|
+
context.addIssue({
|
|
806
|
+
code: "custom",
|
|
807
|
+
path: ["workbenchCatalogDefaults"],
|
|
808
|
+
message: "Page takeover provenance cannot carry Workbench catalog defaults.",
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
});
|
|
812
|
+
/** Authoring-only route evidence. Runtime compilation deliberately strips the takeover proof. */
|
|
813
|
+
exports.DeclarativeRouteClaimSchema = exports.RouteClaimSchema.safeExtend({
|
|
814
|
+
legacyRouteTakeoverAuthorization: exports.LegacyRouteTakeoverAuthorizationSchema.optional(),
|
|
815
|
+
}).strict();
|
|
816
|
+
const LegacyDeclarativeRouteClaimSchema = exports.LegacyRouteClaimSchema.safeExtend({
|
|
817
|
+
legacyRouteTakeoverAuthorization: exports.LegacyRouteTakeoverAuthorizationSchema.optional(),
|
|
818
|
+
}).strict();
|
|
819
|
+
const validateDeclaredRouteSurfaces = (supportedSurfaces, routeClaims, context) => {
|
|
820
|
+
if (uniqueArray(supportedSurfaces, (surface) => surface)) {
|
|
821
|
+
context.addIssue({
|
|
822
|
+
code: "custom",
|
|
823
|
+
path: ["supportedSurfaces"],
|
|
824
|
+
message: "Supported surfaces must be unique.",
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
const explicitClaims = routeClaims.filter((claim) => "surface" in claim);
|
|
828
|
+
if (explicitClaims.length > 0 && explicitClaims.length < routeClaims.length) {
|
|
829
|
+
context.addIssue({
|
|
830
|
+
code: "custom",
|
|
831
|
+
path: ["routeClaims"],
|
|
832
|
+
message: "Route claims must either all declare surface or all omit it for legacy compatibility.",
|
|
833
|
+
});
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
routeClaims.forEach((claim, index) => {
|
|
837
|
+
if ("surface" in claim && !supportedSurfaces.includes(claim.surface)) {
|
|
838
|
+
context.addIssue({
|
|
839
|
+
code: "custom",
|
|
840
|
+
path: ["routeClaims", index, "surface"],
|
|
841
|
+
message: "Route claim surface must be declared by supportedSurfaces.",
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
if (explicitClaims.length !== routeClaims.length)
|
|
846
|
+
return;
|
|
847
|
+
supportedSurfaces.forEach((surface) => {
|
|
848
|
+
const canonicalCount = explicitClaims.filter((claim) => claim.surface === surface && claim.kind === "canonical").length;
|
|
849
|
+
if (canonicalCount !== 1) {
|
|
850
|
+
context.addIssue({
|
|
851
|
+
code: "custom",
|
|
852
|
+
path: ["routeClaims"],
|
|
853
|
+
message: `Surface ${surface} requires exactly one canonical route claim.`,
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
};
|
|
468
858
|
const ReleaseBaseShape = {
|
|
469
859
|
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
470
860
|
releaseSlotId: common_1.ContractIdentifierSchema,
|
|
471
861
|
tenantScope: exports.TenantScopeSchema,
|
|
472
862
|
operation: exports.ReleaseOperationSchema,
|
|
863
|
+
legacyRestoration: exports.LegacySlotRestorationSchema.optional(),
|
|
473
864
|
dependencySnapshot: zod_1.z.array(exports.ReleaseDependencySchema),
|
|
474
865
|
evidence: exports.ReleaseEvidenceSchema,
|
|
475
866
|
};
|
|
867
|
+
const validateLegacyRestoration = (value, expectedAdapterKind, context) => {
|
|
868
|
+
if (value.operation === "activate" && value.legacyRestoration) {
|
|
869
|
+
context.addIssue({
|
|
870
|
+
code: "custom",
|
|
871
|
+
path: ["legacyRestoration"],
|
|
872
|
+
message: "An active declarative Release cannot also restore a legacy adapter.",
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
if (value.legacyRestoration?.legacyAdapterRevisionRef.kind !== undefined &&
|
|
876
|
+
value.legacyRestoration.legacyAdapterRevisionRef.kind !==
|
|
877
|
+
expectedAdapterKind) {
|
|
878
|
+
context.addIssue({
|
|
879
|
+
code: "custom",
|
|
880
|
+
path: ["legacyRestoration", "legacyAdapterRevisionRef", "kind"],
|
|
881
|
+
message: `Legacy restoration requires adapter kind ${expectedAdapterKind}.`,
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
};
|
|
476
885
|
const validateDependencySnapshot = (snapshot, context) => {
|
|
477
886
|
const duplicate = uniqueArray(snapshot, (dependency) => `${dependency.role}:${stableRefIdentity(dependency.revisionRef)}@${dependency.revisionRef.revision}`);
|
|
478
887
|
if (duplicate)
|
|
479
|
-
context.addIssue({
|
|
888
|
+
context.addIssue({
|
|
889
|
+
code: "custom",
|
|
890
|
+
path: ["dependencySnapshot"],
|
|
891
|
+
message: `Duplicate dependency: ${duplicate}`,
|
|
892
|
+
});
|
|
480
893
|
};
|
|
481
|
-
const
|
|
894
|
+
const validateReleaseGovernanceScope = (value, expectedKind, context) => {
|
|
482
895
|
const expectedHead = value.evidence.expectedHeadRevisionRef;
|
|
483
|
-
if (expectedHead &&
|
|
484
|
-
|
|
896
|
+
if (expectedHead &&
|
|
897
|
+
(expectedHead.kind !== expectedKind ||
|
|
898
|
+
expectedHead.id !== value.releaseSlotId)) {
|
|
899
|
+
context.addIssue({
|
|
900
|
+
code: "custom",
|
|
901
|
+
path: ["evidence", "expectedHeadRevisionRef"],
|
|
902
|
+
message: "Expected head must identify the same release slot.",
|
|
903
|
+
});
|
|
485
904
|
}
|
|
486
|
-
if (expectedHead?.tenantScope &&
|
|
487
|
-
|
|
905
|
+
if (expectedHead?.tenantScope &&
|
|
906
|
+
tenantScopeKey(expectedHead.tenantScope) !==
|
|
907
|
+
tenantScopeKey(value.tenantScope)) {
|
|
908
|
+
context.addIssue({
|
|
909
|
+
code: "custom",
|
|
910
|
+
path: ["evidence", "expectedHeadRevisionRef", "tenantScope"],
|
|
911
|
+
message: "Expected head belongs to another tenant scope.",
|
|
912
|
+
});
|
|
488
913
|
}
|
|
914
|
+
const governedEvidenceRefs = [
|
|
915
|
+
[["evidence", "publicationPlanRef"], value.evidence.publicationPlanRef],
|
|
916
|
+
[
|
|
917
|
+
["evidence", "approvalPolicyRevisionRef"],
|
|
918
|
+
value.evidence.approvalPolicyRevisionRef,
|
|
919
|
+
],
|
|
920
|
+
[
|
|
921
|
+
["evidence", "approvalDecisionRevisionRef"],
|
|
922
|
+
value.evidence.approvalDecisionRevisionRef,
|
|
923
|
+
],
|
|
924
|
+
[["evidence", "actorRef"], value.evidence.actorRef],
|
|
925
|
+
...value.evidence.validation.diagnosticRefs.map((reference, index) => [
|
|
926
|
+
["evidence", "validation", "diagnosticRefs", index],
|
|
927
|
+
reference,
|
|
928
|
+
]),
|
|
929
|
+
...value.evidence.evidenceRefs.map((reference, index) => [["evidence", "evidenceRefs", index], reference]),
|
|
930
|
+
...(expectedHead
|
|
931
|
+
? [[["evidence", "expectedHeadRevisionRef"], expectedHead]]
|
|
932
|
+
: []),
|
|
933
|
+
...(value.legacyRestoration
|
|
934
|
+
? [
|
|
935
|
+
[
|
|
936
|
+
["legacyRestoration", "legacyAdapterRevisionRef"],
|
|
937
|
+
value.legacyRestoration.legacyAdapterRevisionRef,
|
|
938
|
+
],
|
|
939
|
+
[
|
|
940
|
+
["legacyRestoration", "sourceRevisionRef"],
|
|
941
|
+
value.legacyRestoration.sourceRevisionRef,
|
|
942
|
+
],
|
|
943
|
+
]
|
|
944
|
+
: []),
|
|
945
|
+
];
|
|
946
|
+
governedEvidenceRefs.forEach(([path, reference]) => validateTenantCompatibleReference(reference, value.tenantScope, [...path], context));
|
|
489
947
|
};
|
|
490
|
-
exports.BindingSourceSchema = zod_1.z.discriminatedUnion(
|
|
491
|
-
zod_1.z
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
948
|
+
exports.BindingSourceSchema = zod_1.z.discriminatedUnion("kind", [
|
|
949
|
+
zod_1.z
|
|
950
|
+
.object({
|
|
951
|
+
kind: zod_1.z.literal("scope-field"),
|
|
952
|
+
path: zod_1.z
|
|
953
|
+
.string()
|
|
954
|
+
.trim()
|
|
955
|
+
.min(1)
|
|
956
|
+
.max(4096)
|
|
957
|
+
.regex(/^[A-Za-z0-9_.-]+$/)
|
|
958
|
+
.refine((path) => path.split(".").length <= 16 &&
|
|
959
|
+
path
|
|
960
|
+
.split(".")
|
|
961
|
+
.every((part) => part.length > 0 &&
|
|
962
|
+
!["__proto__", "prototype", "constructor"].includes(part)), "Scope paths require safe own members."),
|
|
963
|
+
})
|
|
964
|
+
.strict(),
|
|
965
|
+
zod_1.z
|
|
966
|
+
.object({
|
|
967
|
+
kind: zod_1.z.literal("binding-field"),
|
|
968
|
+
bindingId: common_1.ContractIdentifierSchema,
|
|
969
|
+
path: zod_1.z
|
|
970
|
+
.string()
|
|
971
|
+
.trim()
|
|
972
|
+
.regex(/^[A-Za-z0-9_.-]+$/),
|
|
973
|
+
})
|
|
974
|
+
.strict(),
|
|
975
|
+
zod_1.z
|
|
976
|
+
.object({
|
|
977
|
+
kind: zod_1.z.literal("constant"),
|
|
978
|
+
value: zod_1.z.union([zod_1.z.string(), zod_1.z.number().finite(), zod_1.z.boolean(), zod_1.z.null()]),
|
|
979
|
+
})
|
|
980
|
+
.strict(),
|
|
981
|
+
zod_1.z
|
|
982
|
+
.object({
|
|
983
|
+
kind: zod_1.z.literal("route-parameter"),
|
|
984
|
+
name: common_1.ContractIdentifierSchema,
|
|
985
|
+
})
|
|
986
|
+
.strict(),
|
|
987
|
+
zod_1.z
|
|
988
|
+
.object({
|
|
989
|
+
kind: zod_1.z.literal("query-parameter"),
|
|
990
|
+
name: common_1.ContractIdentifierSchema,
|
|
991
|
+
})
|
|
992
|
+
.strict(),
|
|
993
|
+
zod_1.z
|
|
994
|
+
.object({
|
|
995
|
+
kind: zod_1.z.literal("identity"),
|
|
996
|
+
name: zod_1.z.enum(["tenantId", "teamId", "userId"]),
|
|
997
|
+
})
|
|
998
|
+
.strict(),
|
|
999
|
+
zod_1.z
|
|
1000
|
+
.object({
|
|
1001
|
+
kind: zod_1.z.literal("intent-field"),
|
|
1002
|
+
path: zod_1.z
|
|
1003
|
+
.string()
|
|
1004
|
+
.trim()
|
|
1005
|
+
.regex(/^[A-Za-z0-9_.-]+$/),
|
|
1006
|
+
})
|
|
1007
|
+
.strict(),
|
|
1008
|
+
zod_1.z
|
|
1009
|
+
.object({
|
|
1010
|
+
kind: zod_1.z.literal("page-state"),
|
|
1011
|
+
stateId: common_1.ContractIdentifierSchema,
|
|
1012
|
+
})
|
|
1013
|
+
.strict(),
|
|
497
1014
|
]);
|
|
498
|
-
|
|
1015
|
+
const ExpressionBindingSourceSchema = zod_1.z
|
|
1016
|
+
.object({ kind: zod_1.z.literal("expression"), expression: page_expression_1.PageExpressionSchema })
|
|
1017
|
+
.strict()
|
|
1018
|
+
.superRefine((value, context) => {
|
|
1019
|
+
if ((0, page_expression_1.collectPageExpressionReads)(value.expression).some((read) => read.root === "actions"))
|
|
1020
|
+
context.addIssue({
|
|
1021
|
+
code: "custom",
|
|
1022
|
+
path: ["expression"],
|
|
1023
|
+
message: "Action runtime state is presentation-only and cannot influence an input or state transition.",
|
|
1024
|
+
});
|
|
1025
|
+
});
|
|
1026
|
+
const FileFieldBindingSourceSchema = zod_1.z
|
|
499
1027
|
.object({
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
providerRevisionRef: exports.RevisionRefSchema,
|
|
504
|
-
propertySchemaRevisionRef: exports.RevisionRefSchema,
|
|
505
|
-
properties: common_1.JsonObjectSchema,
|
|
506
|
-
allowedSideEffects: zod_1.z.array(zod_1.z.enum(['network', 'storage', 'navigation', 'worker', 'websocket'])),
|
|
1028
|
+
kind: zod_1.z.literal("file-field"),
|
|
1029
|
+
fileInputId: common_1.ContractIdentifierSchema,
|
|
1030
|
+
path: zod_1.z.enum(["fileName", "content", "canonicalUri"]),
|
|
507
1031
|
})
|
|
508
1032
|
.strict();
|
|
509
|
-
|
|
1033
|
+
const ActionFileInputSchema = zod_1.z
|
|
510
1034
|
.object({
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
1035
|
+
inputId: common_1.ContractIdentifierSchema,
|
|
1036
|
+
source: zod_1.z.discriminatedUnion("kind", [
|
|
1037
|
+
zod_1.z
|
|
1038
|
+
.object({
|
|
1039
|
+
kind: zod_1.z.literal("page-state"),
|
|
1040
|
+
stateId: common_1.ContractIdentifierSchema,
|
|
1041
|
+
})
|
|
1042
|
+
.strict(),
|
|
1043
|
+
zod_1.z
|
|
1044
|
+
.object({
|
|
1045
|
+
kind: zod_1.z.literal("intent-field"),
|
|
1046
|
+
path: zod_1.z
|
|
1047
|
+
.string()
|
|
1048
|
+
.trim()
|
|
1049
|
+
.regex(/^[A-Za-z0-9_.-]+$/),
|
|
1050
|
+
})
|
|
1051
|
+
.strict(),
|
|
1052
|
+
]),
|
|
1053
|
+
maxBytes: zod_1.z.number().int().min(1).max(5368709120),
|
|
1054
|
+
upload: zod_1.z.object({ purpose: file_1.FilePurposeSchema }).strict().optional(),
|
|
1055
|
+
accept: zod_1.z.string().min(1).max(256).optional(),
|
|
521
1056
|
})
|
|
522
1057
|
.strict()
|
|
523
1058
|
.superRefine((value, context) => {
|
|
524
|
-
if (
|
|
525
|
-
context.addIssue({
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
1059
|
+
if (!value.upload && value.maxBytes > 1048576)
|
|
1060
|
+
context.addIssue({
|
|
1061
|
+
code: "custom",
|
|
1062
|
+
path: ["maxBytes"],
|
|
1063
|
+
message: "Inline text files are limited to one MiB.",
|
|
1064
|
+
});
|
|
530
1065
|
});
|
|
531
|
-
|
|
1066
|
+
const ActionInputBindingSourceSchema = zod_1.z.discriminatedUnion("kind", [
|
|
1067
|
+
...exports.BindingSourceSchema.options,
|
|
1068
|
+
ExpressionBindingSourceSchema,
|
|
1069
|
+
FileFieldBindingSourceSchema,
|
|
1070
|
+
]);
|
|
1071
|
+
const InteractionBindingSourceSchema = zod_1.z.discriminatedUnion("kind", [
|
|
1072
|
+
ExpressionBindingSourceSchema,
|
|
1073
|
+
zod_1.z
|
|
1074
|
+
.object({
|
|
1075
|
+
kind: zod_1.z.literal("constant"),
|
|
1076
|
+
value: zod_1.z.union([zod_1.z.string(), zod_1.z.number().finite(), zod_1.z.boolean(), zod_1.z.null()]),
|
|
1077
|
+
})
|
|
1078
|
+
.strict(),
|
|
1079
|
+
zod_1.z
|
|
1080
|
+
.object({
|
|
1081
|
+
kind: zod_1.z.literal("intent-field"),
|
|
1082
|
+
path: zod_1.z
|
|
1083
|
+
.string()
|
|
1084
|
+
.trim()
|
|
1085
|
+
.regex(/^[A-Za-z0-9_.-]+$/),
|
|
1086
|
+
})
|
|
1087
|
+
.strict(),
|
|
1088
|
+
zod_1.z
|
|
1089
|
+
.object({
|
|
1090
|
+
kind: zod_1.z.literal("result-field"),
|
|
1091
|
+
path: zod_1.z
|
|
1092
|
+
.string()
|
|
1093
|
+
.trim()
|
|
1094
|
+
.regex(/^[A-Za-z0-9_.-]+$/),
|
|
1095
|
+
})
|
|
1096
|
+
.strict(),
|
|
1097
|
+
zod_1.z
|
|
1098
|
+
.object({
|
|
1099
|
+
kind: zod_1.z.literal("page-state"),
|
|
1100
|
+
stateId: common_1.ContractIdentifierSchema,
|
|
1101
|
+
})
|
|
1102
|
+
.strict(),
|
|
1103
|
+
]);
|
|
1104
|
+
const PageStateComparableLiteralSchema = zod_1.z.union([
|
|
1105
|
+
zod_1.z.string(),
|
|
1106
|
+
zod_1.z.number().finite(),
|
|
1107
|
+
zod_1.z.boolean(),
|
|
1108
|
+
zod_1.z.null(),
|
|
1109
|
+
]);
|
|
1110
|
+
exports.PageStateConditionSchema = zod_1.z.discriminatedUnion("predicate", [
|
|
1111
|
+
zod_1.z
|
|
1112
|
+
.object({
|
|
1113
|
+
stateId: common_1.ContractIdentifierSchema,
|
|
1114
|
+
predicate: zod_1.z.literal("equals"),
|
|
1115
|
+
value: PageStateComparableLiteralSchema,
|
|
1116
|
+
})
|
|
1117
|
+
.strict(),
|
|
1118
|
+
zod_1.z
|
|
1119
|
+
.object({
|
|
1120
|
+
stateId: common_1.ContractIdentifierSchema,
|
|
1121
|
+
predicate: zod_1.z.literal("not-equals"),
|
|
1122
|
+
value: PageStateComparableLiteralSchema,
|
|
1123
|
+
})
|
|
1124
|
+
.strict(),
|
|
1125
|
+
zod_1.z
|
|
1126
|
+
.object({
|
|
1127
|
+
stateId: common_1.ContractIdentifierSchema,
|
|
1128
|
+
predicate: zod_1.z.literal("truthy"),
|
|
1129
|
+
})
|
|
1130
|
+
.strict(),
|
|
1131
|
+
]);
|
|
1132
|
+
/**
|
|
1133
|
+
* A recursive boolean expression over governed Page state. Keeping leaf
|
|
1134
|
+
* conditions inside the original `conditions` array preserves the v1 flat
|
|
1135
|
+
* declaration while allowing groups to be nested without a parallel DSL.
|
|
1136
|
+
*/
|
|
1137
|
+
exports.PageStateActivationSchema = zod_1.z.lazy(() => zod_1.z
|
|
532
1138
|
.object({
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
})
|
|
548
|
-
|
|
549
|
-
|
|
1139
|
+
operator: zod_1.z.enum(["all", "any"]),
|
|
1140
|
+
conditions: zod_1.z
|
|
1141
|
+
.array(zod_1.z.union([exports.PageStateConditionSchema, exports.PageStateActivationSchema]))
|
|
1142
|
+
.min(1),
|
|
1143
|
+
})
|
|
1144
|
+
.strict());
|
|
1145
|
+
const forEachPageStateCondition = (activation, visit, path = []) => {
|
|
1146
|
+
activation.conditions.forEach((candidate, index) => {
|
|
1147
|
+
const candidatePath = [...path, "conditions", index];
|
|
1148
|
+
if ("operator" in candidate) {
|
|
1149
|
+
forEachPageStateCondition(candidate, visit, candidatePath);
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
visit(candidate, candidatePath);
|
|
1153
|
+
});
|
|
1154
|
+
};
|
|
1155
|
+
const PageRouteValueSourceSchema = zod_1.z.discriminatedUnion("kind", [
|
|
1156
|
+
zod_1.z
|
|
1157
|
+
.object({
|
|
1158
|
+
kind: zod_1.z.literal("route-parameter"),
|
|
1159
|
+
name: common_1.ContractIdentifierSchema,
|
|
1160
|
+
})
|
|
1161
|
+
.strict(),
|
|
1162
|
+
zod_1.z
|
|
1163
|
+
.object({
|
|
1164
|
+
kind: zod_1.z.literal("constant"),
|
|
1165
|
+
value: zod_1.z.union([zod_1.z.string(), zod_1.z.number().finite(), zod_1.z.boolean()]),
|
|
1166
|
+
})
|
|
1167
|
+
.strict(),
|
|
1168
|
+
zod_1.z
|
|
1169
|
+
.object({
|
|
1170
|
+
kind: zod_1.z.literal("page-state"),
|
|
1171
|
+
stateId: common_1.ContractIdentifierSchema,
|
|
1172
|
+
})
|
|
1173
|
+
.strict(),
|
|
1174
|
+
]);
|
|
1175
|
+
/**
|
|
1176
|
+
* Declares an ordered, state-driven route transition owned by one exact Page
|
|
1177
|
+
* revision. The compiler resolves targetRef to one active governed Release;
|
|
1178
|
+
* raw URLs and application-specific route switches are deliberately excluded.
|
|
1179
|
+
*/
|
|
1180
|
+
exports.PageEntryTransitionSchema = zod_1.z
|
|
1181
|
+
.object({
|
|
1182
|
+
browsingContext: zod_1.z.enum(["same", "new"]).optional(),
|
|
1183
|
+
gestureSource: zod_1.z
|
|
1184
|
+
.object({
|
|
1185
|
+
capabilityInstanceId: common_1.ContractIdentifierSchema,
|
|
1186
|
+
port: common_1.ContractIdentifierSchema,
|
|
1187
|
+
})
|
|
1188
|
+
.strict()
|
|
1189
|
+
.optional(),
|
|
1190
|
+
transitionId: common_1.ContractIdentifierSchema,
|
|
1191
|
+
activation: exports.PageStateActivationSchema,
|
|
1192
|
+
targetRef: exports.StableRefSchema,
|
|
1193
|
+
pathParameters: zod_1.z.record(common_1.ContractIdentifierSchema, PageRouteValueSourceSchema),
|
|
1194
|
+
query: zod_1.z
|
|
1195
|
+
.object({
|
|
1196
|
+
preserve: zod_1.z.boolean(),
|
|
1197
|
+
remove: zod_1.z.array(common_1.ContractIdentifierSchema),
|
|
1198
|
+
set: zod_1.z.record(common_1.ContractIdentifierSchema, PageRouteValueSourceSchema),
|
|
1199
|
+
})
|
|
1200
|
+
.strict(),
|
|
550
1201
|
})
|
|
551
1202
|
.strict()
|
|
552
1203
|
.superRefine((value, context) => {
|
|
553
|
-
if (value.
|
|
554
|
-
context.addIssue({
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
1204
|
+
if ((value.browsingContext === "new") !== Boolean(value.gestureSource)) {
|
|
1205
|
+
context.addIssue({
|
|
1206
|
+
code: "custom",
|
|
1207
|
+
path: ["gestureSource"],
|
|
1208
|
+
message: "New-context entry transitions require an exact gesture source; same-context transitions must omit it.",
|
|
1209
|
+
});
|
|
558
1210
|
}
|
|
559
|
-
if (value.
|
|
560
|
-
context.addIssue({
|
|
1211
|
+
if (!["page", "workbench"].includes(value.targetRef.kind)) {
|
|
1212
|
+
context.addIssue({
|
|
1213
|
+
code: "custom",
|
|
1214
|
+
path: ["targetRef", "kind"],
|
|
1215
|
+
message: "Page entry transitions must reference a governed Page or Workbench.",
|
|
1216
|
+
});
|
|
561
1217
|
}
|
|
562
|
-
if (value.
|
|
563
|
-
context.addIssue({
|
|
1218
|
+
if (new Set(value.query.remove).size !== value.query.remove.length) {
|
|
1219
|
+
context.addIssue({
|
|
1220
|
+
code: "custom",
|
|
1221
|
+
path: ["query", "remove"],
|
|
1222
|
+
message: "Removed query parameter names must be unique.",
|
|
1223
|
+
});
|
|
564
1224
|
}
|
|
565
1225
|
});
|
|
566
|
-
exports.
|
|
1226
|
+
exports.ResolvedPageEntryTransitionSchema = exports.PageEntryTransitionSchema.safeExtend({
|
|
1227
|
+
targetRevisionRef: exports.RevisionRefSchema,
|
|
1228
|
+
targetReleaseRevisionRef: exports.RevisionRefSchema.optional(),
|
|
1229
|
+
targetAccessPolicy: exports.AccessPolicySchema,
|
|
1230
|
+
targetRouteClaim: exports.CompiledRouteClaimSchema,
|
|
1231
|
+
}).strict();
|
|
1232
|
+
exports.LegacyBrowserPreferenceImportSchema = zod_1.z
|
|
567
1233
|
.object({
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
1234
|
+
storageKey: zod_1.z.string().trim().min(1).max(256),
|
|
1235
|
+
jsonPath: zod_1.z
|
|
1236
|
+
.array(zod_1.z.union([
|
|
1237
|
+
zod_1.z.string().trim().min(1).max(128),
|
|
1238
|
+
zod_1.z.object({ stateId: common_1.ContractIdentifierSchema }).strict(),
|
|
1239
|
+
]))
|
|
1240
|
+
.min(1)
|
|
1241
|
+
.max(16)
|
|
1242
|
+
.optional(),
|
|
1243
|
+
valueType: zod_1.z.enum(["string", "number", "boolean-01", "json"]),
|
|
1244
|
+
})
|
|
1245
|
+
.strict();
|
|
1246
|
+
exports.PageStateDefinitionSchema = zod_1.z
|
|
1247
|
+
.object({
|
|
1248
|
+
stateId: common_1.ContractIdentifierSchema,
|
|
1249
|
+
scopeNodeId: common_1.ContractIdentifierSchema.optional(),
|
|
1250
|
+
initialValue: page_expression_1.PageExpressionSchema.optional(),
|
|
1251
|
+
schemaRevisionRef: exports.RevisionRefSchema,
|
|
1252
|
+
defaultValue: common_1.JsonValueSchema.optional(),
|
|
1253
|
+
persistence: zod_1.z.enum([
|
|
1254
|
+
"none",
|
|
1255
|
+
"session",
|
|
1256
|
+
"url",
|
|
1257
|
+
"tenant-preference",
|
|
1258
|
+
"url-with-tenant-preference",
|
|
1259
|
+
]),
|
|
1260
|
+
urlWriteback: zod_1.z.enum(["synchronize", "never"]).optional(),
|
|
1261
|
+
preferencePartitionStateId: common_1.ContractIdentifierSchema.optional(),
|
|
1262
|
+
legacyBrowserPreferenceImport: exports.LegacyBrowserPreferenceImportSchema.optional(),
|
|
587
1263
|
})
|
|
588
1264
|
.strict()
|
|
589
1265
|
.superRefine((value, context) => {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
1266
|
+
if (value.scopeNodeId && value.persistence !== "none")
|
|
1267
|
+
context.addIssue({
|
|
1268
|
+
code: "custom",
|
|
1269
|
+
path: ["persistence"],
|
|
1270
|
+
message: "Repeated instance state must not persist outside its instance.",
|
|
1271
|
+
});
|
|
1272
|
+
if (value.initialValue &&
|
|
1273
|
+
!value.scopeNodeId &&
|
|
1274
|
+
(value.persistence !== "none" ||
|
|
1275
|
+
value.initialValue.kind !== "read" ||
|
|
1276
|
+
value.initialValue.root !== "state" ||
|
|
1277
|
+
value.initialValue.path.length !== 1))
|
|
1278
|
+
context.addIssue({
|
|
1279
|
+
code: "custom",
|
|
1280
|
+
path: ["initialValue"],
|
|
1281
|
+
message: "Root initialization must directly read one persisted Page state into non-persistent state.",
|
|
1282
|
+
});
|
|
1283
|
+
if (value.schemaRevisionRef.kind !== "schema") {
|
|
1284
|
+
context.addIssue({
|
|
1285
|
+
code: "custom",
|
|
1286
|
+
path: ["schemaRevisionRef", "kind"],
|
|
1287
|
+
message: "Page state must pin an exact schema revision.",
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
1290
|
+
if (value.preferencePartitionStateId !== undefined &&
|
|
1291
|
+
value.persistence !== "tenant-preference" &&
|
|
1292
|
+
value.persistence !== "url-with-tenant-preference") {
|
|
1293
|
+
context.addIssue({
|
|
1294
|
+
code: "custom",
|
|
1295
|
+
path: ["preferencePartitionStateId"],
|
|
1296
|
+
message: "Preference partitioning requires tenant preference state.",
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
if (value.urlWriteback !== undefined &&
|
|
1300
|
+
value.persistence !== "url" &&
|
|
1301
|
+
value.persistence !== "url-with-tenant-preference") {
|
|
1302
|
+
context.addIssue({
|
|
1303
|
+
code: "custom",
|
|
1304
|
+
path: ["urlWriteback"],
|
|
1305
|
+
message: "URL writeback is only valid for URL-backed Page state.",
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
});
|
|
1309
|
+
exports.InteractionBindingSchema = zod_1.z
|
|
1310
|
+
.object({
|
|
1311
|
+
bindingId: common_1.ContractIdentifierSchema,
|
|
1312
|
+
source: zod_1.z
|
|
1313
|
+
.object({
|
|
1314
|
+
capabilityInstanceId: common_1.ContractIdentifierSchema,
|
|
1315
|
+
port: common_1.ContractIdentifierSchema,
|
|
1316
|
+
})
|
|
1317
|
+
.strict(),
|
|
1318
|
+
sourceIntentSchemaRevisionRef: exports.RevisionRefSchema,
|
|
1319
|
+
sourceResultSchemaRevisionRef: exports.RevisionRefSchema.optional(),
|
|
1320
|
+
targetStateId: common_1.ContractIdentifierSchema,
|
|
1321
|
+
transition: zod_1.z.enum(["set", "merge", "toggle", "append", "remove", "reset"]),
|
|
1322
|
+
inputMapping: zod_1.z.record(common_1.ContractIdentifierSchema, InteractionBindingSourceSchema),
|
|
1323
|
+
})
|
|
1324
|
+
.strict()
|
|
1325
|
+
.superRefine((value, context) => {
|
|
1326
|
+
if (value.sourceIntentSchemaRevisionRef.kind !== "schema") {
|
|
1327
|
+
context.addIssue({
|
|
1328
|
+
code: "custom",
|
|
1329
|
+
path: ["sourceIntentSchemaRevisionRef", "kind"],
|
|
1330
|
+
message: "Interaction source intents must pin a schema revision.",
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
const mapsResult = Object.values(value.inputMapping).some((source) => source.kind === "result-field" ||
|
|
1334
|
+
(source.kind === "expression" &&
|
|
1335
|
+
(0, page_expression_1.collectPageExpressionReads)(source.expression).some((read) => read.root === "result")));
|
|
1336
|
+
if (mapsResult && !value.sourceResultSchemaRevisionRef) {
|
|
1337
|
+
context.addIssue({
|
|
1338
|
+
code: "custom",
|
|
1339
|
+
path: ["sourceResultSchemaRevisionRef"],
|
|
1340
|
+
message: "Result-field interactions must pin the exact Action result schema revision.",
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
if (value.sourceResultSchemaRevisionRef?.kind !== undefined &&
|
|
1344
|
+
value.sourceResultSchemaRevisionRef.kind !== "schema") {
|
|
1345
|
+
context.addIssue({
|
|
1346
|
+
code: "custom",
|
|
1347
|
+
path: ["sourceResultSchemaRevisionRef", "kind"],
|
|
1348
|
+
message: "Interaction source results must pin a schema revision.",
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
if (!mapsResult && value.sourceResultSchemaRevisionRef) {
|
|
1352
|
+
context.addIssue({
|
|
1353
|
+
code: "custom",
|
|
1354
|
+
path: ["sourceResultSchemaRevisionRef"],
|
|
1355
|
+
message: "Interaction result schemas are only valid when inputMapping declares a result-field source.",
|
|
1356
|
+
});
|
|
1357
|
+
}
|
|
1358
|
+
const mappedInputs = Object.keys(value.inputMapping);
|
|
1359
|
+
if ((value.transition === "toggle" || value.transition === "reset") &&
|
|
1360
|
+
mappedInputs.length > 0) {
|
|
1361
|
+
context.addIssue({
|
|
1362
|
+
code: "custom",
|
|
1363
|
+
path: ["inputMapping"],
|
|
1364
|
+
message: `${value.transition} transitions cannot declare mapped inputs.`,
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1367
|
+
if (value.transition !== "toggle" &&
|
|
1368
|
+
value.transition !== "reset" &&
|
|
1369
|
+
mappedInputs.length === 0) {
|
|
1370
|
+
context.addIssue({
|
|
1371
|
+
code: "custom",
|
|
1372
|
+
path: ["inputMapping"],
|
|
1373
|
+
message: `${value.transition} transitions require at least one mapped input.`,
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
});
|
|
1377
|
+
exports.GovernedCatalogResourceKindSchema = zod_1.z.enum([
|
|
1378
|
+
"tag",
|
|
1379
|
+
"tag-group",
|
|
1380
|
+
"feature-column",
|
|
1381
|
+
]);
|
|
1382
|
+
exports.GovernedCatalogDomainQueryDataSourceSchema = zod_1.z
|
|
1383
|
+
.object({
|
|
1384
|
+
kind: zod_1.z.literal("governed-catalog"),
|
|
1385
|
+
resourceKind: exports.GovernedCatalogResourceKindSchema,
|
|
1386
|
+
})
|
|
1387
|
+
.strict();
|
|
1388
|
+
exports.RegisteredServiceDomainQueryDataSourceSchema = zod_1.z
|
|
1389
|
+
.object({
|
|
1390
|
+
kind: zod_1.z.literal("registered-service"),
|
|
1391
|
+
})
|
|
1392
|
+
.strict();
|
|
1393
|
+
exports.DomainQueryDataSourceSchema = zod_1.z.discriminatedUnion("kind", [
|
|
1394
|
+
zod_1.z.object({ kind: zod_1.z.literal("exact-view") }).strict(),
|
|
1395
|
+
zod_1.z
|
|
1396
|
+
.object({
|
|
1397
|
+
kind: zod_1.z.literal("tenant-catalog"),
|
|
1398
|
+
resource: zod_1.z.enum(["ontology", "view"]),
|
|
1399
|
+
ontologyIdParameter: common_1.ContractIdentifierSchema.optional(),
|
|
1400
|
+
})
|
|
1401
|
+
.strict()
|
|
1402
|
+
.superRefine((source, context) => {
|
|
1403
|
+
if (source.resource === "view" && !source.ontologyIdParameter) {
|
|
1404
|
+
context.addIssue({
|
|
1405
|
+
code: "custom",
|
|
1406
|
+
path: ["ontologyIdParameter"],
|
|
1407
|
+
message: "A tenant View catalog must declare the input parameter that scopes it to one Ontology.",
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
if (source.resource === "ontology" && source.ontologyIdParameter) {
|
|
1411
|
+
context.addIssue({
|
|
1412
|
+
code: "custom",
|
|
1413
|
+
path: ["ontologyIdParameter"],
|
|
1414
|
+
message: "An Ontology catalog cannot be pre-scoped by an Ontology input.",
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
}),
|
|
1418
|
+
zod_1.z
|
|
1419
|
+
.object({
|
|
1420
|
+
kind: zod_1.z.literal("tenant-current-view"),
|
|
1421
|
+
ontologyIdParameter: common_1.ContractIdentifierSchema,
|
|
1422
|
+
viewIdParameter: common_1.ContractIdentifierSchema,
|
|
1423
|
+
})
|
|
1424
|
+
.strict(),
|
|
1425
|
+
zod_1.z.object({ kind: zod_1.z.literal("page-state") }).strict(),
|
|
1426
|
+
exports.GovernedCatalogDomainQueryDataSourceSchema,
|
|
1427
|
+
exports.RegisteredServiceDomainQueryDataSourceSchema,
|
|
1428
|
+
]);
|
|
1429
|
+
exports.DomainQueryDefinitionSchema = zod_1.z
|
|
1430
|
+
.object({
|
|
1431
|
+
contract: zod_1.z.literal("DomainQueryDefinition"),
|
|
1432
|
+
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
1433
|
+
queryId: common_1.ContractIdentifierSchema,
|
|
1434
|
+
tenantScope: exports.TenantScopeSchema,
|
|
1435
|
+
dataSource: exports.DomainQueryDataSourceSchema.optional(),
|
|
1436
|
+
handlerRef: common_1.EntityRefSchema.optional(),
|
|
1437
|
+
ontologyDefinitionRevisionRef: exports.RevisionRefSchema.optional(),
|
|
1438
|
+
viewRevisionRef: exports.RevisionRefSchema.optional(),
|
|
1439
|
+
canonicalDataViewRevisionRef: exports.RevisionRefSchema.optional(),
|
|
1440
|
+
inputSchemaRevisionRef: exports.RevisionRefSchema,
|
|
1441
|
+
resultSchemaRevisionRef: exports.RevisionRefSchema,
|
|
1442
|
+
accessPolicy: exports.AccessPolicySchema,
|
|
1443
|
+
lineageRequired: zod_1.z.literal(true),
|
|
1444
|
+
})
|
|
1445
|
+
.strict()
|
|
1446
|
+
.superRefine((value, context) => {
|
|
1447
|
+
const sourceKind = value.dataSource?.kind ?? "exact-view";
|
|
1448
|
+
const exactDataRefs = [
|
|
1449
|
+
value.ontologyDefinitionRevisionRef,
|
|
1450
|
+
value.viewRevisionRef,
|
|
1451
|
+
value.canonicalDataViewRevisionRef,
|
|
1452
|
+
];
|
|
1453
|
+
if (sourceKind === "exact-view" &&
|
|
1454
|
+
exactDataRefs.some((reference) => !reference)) {
|
|
1455
|
+
context.addIssue({
|
|
1456
|
+
code: "custom",
|
|
1457
|
+
path: ["dataSource"],
|
|
1458
|
+
message: "An exact-view Domain Query must pin Ontology, governed View, and canonical Data View revisions.",
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
if (sourceKind !== "exact-view" && exactDataRefs.some(Boolean)) {
|
|
1462
|
+
context.addIssue({
|
|
1463
|
+
code: "custom",
|
|
1464
|
+
path: ["dataSource"],
|
|
1465
|
+
message: "A non-View Domain Query cannot also pin one fixed View.",
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
if (value.dataSource &&
|
|
1469
|
+
(!value.handlerRef || value.handlerRef.version === undefined)) {
|
|
1470
|
+
context.addIssue({
|
|
1471
|
+
code: "custom",
|
|
1472
|
+
path: ["handlerRef"],
|
|
1473
|
+
message: "A source-aware Domain Query must pin its release-owned handler version.",
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1476
|
+
const refs = [
|
|
1477
|
+
...(sourceKind === "exact-view" && value.ontologyDefinitionRevisionRef
|
|
1478
|
+
? [
|
|
1479
|
+
[
|
|
1480
|
+
"ontologyDefinitionRevisionRef",
|
|
1481
|
+
value.ontologyDefinitionRevisionRef,
|
|
1482
|
+
"ontology-definition",
|
|
1483
|
+
],
|
|
1484
|
+
]
|
|
1485
|
+
: []),
|
|
1486
|
+
...(sourceKind === "exact-view" && value.viewRevisionRef
|
|
1487
|
+
? [["viewRevisionRef", value.viewRevisionRef, "view"]]
|
|
1488
|
+
: []),
|
|
1489
|
+
...(sourceKind === "exact-view" && value.canonicalDataViewRevisionRef
|
|
1490
|
+
? [
|
|
1491
|
+
[
|
|
1492
|
+
"canonicalDataViewRevisionRef",
|
|
1493
|
+
value.canonicalDataViewRevisionRef,
|
|
1494
|
+
"view",
|
|
1495
|
+
],
|
|
1496
|
+
]
|
|
1497
|
+
: []),
|
|
1498
|
+
["inputSchemaRevisionRef", value.inputSchemaRevisionRef, "schema"],
|
|
1499
|
+
["resultSchemaRevisionRef", value.resultSchemaRevisionRef, "schema"],
|
|
1500
|
+
];
|
|
1501
|
+
refs.forEach(([field, reference, expectedKind]) => {
|
|
1502
|
+
if (reference.kind !== expectedKind) {
|
|
1503
|
+
context.addIssue({
|
|
1504
|
+
code: "custom",
|
|
1505
|
+
path: [field, "kind"],
|
|
1506
|
+
message: `${field} must reference ${expectedKind}.`,
|
|
1507
|
+
});
|
|
1508
|
+
}
|
|
1509
|
+
validateTenantCompatibleReference(reference, value.tenantScope, [field], context);
|
|
1510
|
+
});
|
|
1511
|
+
[
|
|
1512
|
+
...value.accessPolicy.groupAllOf,
|
|
1513
|
+
...value.accessPolicy.groupAnyOf,
|
|
1514
|
+
].forEach((reference, index) => validateTenantCompatibleReference(reference, value.tenantScope, ["accessPolicy", "groups", index], context));
|
|
1515
|
+
value.accessPolicy.conditionAllOf.forEach((reference, index) => validateTenantCompatibleReference(reference, value.tenantScope, ["accessPolicy", "conditionAllOf", index], context));
|
|
1516
|
+
if (value.viewRevisionRef &&
|
|
1517
|
+
value.canonicalDataViewRevisionRef &&
|
|
1518
|
+
exactRevisionRef(value.viewRevisionRef, value.canonicalDataViewRevisionRef)) {
|
|
1519
|
+
context.addIssue({
|
|
1520
|
+
code: "custom",
|
|
1521
|
+
path: ["canonicalDataViewRevisionRef"],
|
|
1522
|
+
message: "Governed View adapter and canonical data.view revisions must be distinct.",
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1525
|
+
});
|
|
1526
|
+
exports.CursorWindowBindingSchema = zod_1.z
|
|
1527
|
+
.object({
|
|
1528
|
+
sourceCapabilityInstanceId: common_1.ContractIdentifierSchema.optional(),
|
|
1529
|
+
pageChangePort: common_1.ContractIdentifierSchema,
|
|
1530
|
+
pageChangeIntentSchemaRevisionRef: exports.RevisionRefSchema,
|
|
1531
|
+
})
|
|
1532
|
+
.strict()
|
|
1533
|
+
.superRefine((value, context) => {
|
|
1534
|
+
if (value.pageChangeIntentSchemaRevisionRef.kind !== "schema") {
|
|
1535
|
+
context.addIssue({
|
|
1536
|
+
code: "custom",
|
|
1537
|
+
path: ["pageChangeIntentSchemaRevisionRef", "kind"],
|
|
1538
|
+
message: "Cursor-window page-change intents must pin a schema revision.",
|
|
1539
|
+
});
|
|
1540
|
+
}
|
|
1541
|
+
});
|
|
1542
|
+
exports.QueryResultStateBindingSchema = zod_1.z
|
|
1543
|
+
.object({
|
|
1544
|
+
targetStateId: common_1.ContractIdentifierSchema,
|
|
1545
|
+
targetStateSchemaRevisionRef: exports.RevisionRefSchema,
|
|
1546
|
+
source: zod_1.z
|
|
1547
|
+
.object({ kind: zod_1.z.enum(["page-info-total", "model-total"]) })
|
|
1548
|
+
.strict(),
|
|
1549
|
+
})
|
|
1550
|
+
.strict()
|
|
1551
|
+
.superRefine((value, context) => {
|
|
1552
|
+
if (value.targetStateSchemaRevisionRef.kind !== "schema") {
|
|
1553
|
+
context.addIssue({
|
|
1554
|
+
code: "custom",
|
|
1555
|
+
path: ["targetStateSchemaRevisionRef", "kind"],
|
|
1556
|
+
message: "Query result state bindings must pin a Page-state schema revision.",
|
|
1557
|
+
});
|
|
1558
|
+
}
|
|
1559
|
+
});
|
|
1560
|
+
exports.QueryBindingSchema = zod_1.z
|
|
1561
|
+
.object({
|
|
1562
|
+
bindingId: common_1.ContractIdentifierSchema,
|
|
1563
|
+
queryDefinitionRevisionRef: exports.RevisionRefSchema,
|
|
1564
|
+
parameters: zod_1.z.record(common_1.ContractIdentifierSchema, exports.BindingSourceSchema),
|
|
1565
|
+
target: zod_1.z
|
|
1566
|
+
.object({
|
|
1567
|
+
capabilityInstanceId: common_1.ContractIdentifierSchema,
|
|
1568
|
+
port: common_1.ContractIdentifierSchema,
|
|
1569
|
+
})
|
|
1570
|
+
.strict(),
|
|
1571
|
+
renderModelSchemaRevisionRef: exports.RevisionRefSchema,
|
|
1572
|
+
targetProjection: zod_1.z
|
|
1573
|
+
.object({
|
|
1574
|
+
expression: page_expression_1.PageExpressionSchema,
|
|
1575
|
+
schemaRevisionRef: exports.RevisionRefSchema,
|
|
1576
|
+
})
|
|
1577
|
+
.strict()
|
|
1578
|
+
.optional(),
|
|
1579
|
+
streamTargetProjection: zod_1.z
|
|
1580
|
+
.object({
|
|
1581
|
+
expression: page_expression_1.PageExpressionSchema,
|
|
1582
|
+
schemaRevisionRef: exports.RevisionRefSchema,
|
|
1583
|
+
})
|
|
1584
|
+
.strict()
|
|
1585
|
+
.optional(),
|
|
1586
|
+
stateEffects: zod_1.z
|
|
1587
|
+
.array(zod_1.z
|
|
1588
|
+
.object({
|
|
1589
|
+
targetStateId: common_1.ContractIdentifierSchema,
|
|
1590
|
+
value: page_expression_1.PageExpressionSchema,
|
|
1591
|
+
when: page_expression_1.PageExpressionSchema.optional(),
|
|
1592
|
+
})
|
|
1593
|
+
.strict())
|
|
1594
|
+
.max(32)
|
|
1595
|
+
.optional(),
|
|
1596
|
+
queryWhen: exports.PageStateActivationSchema.optional(),
|
|
1597
|
+
accessFailure: zod_1.z.literal("render-forbidden").optional(),
|
|
1598
|
+
resultStateBindings: zod_1.z
|
|
1599
|
+
.array(exports.QueryResultStateBindingSchema)
|
|
1600
|
+
.max(32)
|
|
1601
|
+
.optional(),
|
|
1602
|
+
execution: zod_1.z.enum(["server", "local-state"]).default("server"),
|
|
1603
|
+
pagination: zod_1.z.enum(["none", "cursor", "offset"]),
|
|
1604
|
+
cursorWindow: exports.CursorWindowBindingSchema.optional(),
|
|
1605
|
+
cache: zod_1.z.enum(["none", "identity-scoped", "tenant-scoped"]),
|
|
1606
|
+
cancelOnChange: zod_1.z.boolean(),
|
|
1607
|
+
refreshPolicy: zod_1.z
|
|
1608
|
+
.object({
|
|
1609
|
+
intervalMs: zod_1.z.number().int().min(1000).max(300000),
|
|
1610
|
+
when: page_expression_1.PageExpressionSchema.optional(),
|
|
1611
|
+
})
|
|
1612
|
+
.strict()
|
|
1613
|
+
.optional(),
|
|
1614
|
+
})
|
|
1615
|
+
.strict()
|
|
1616
|
+
.superRefine((value, context) => {
|
|
1617
|
+
if (value.targetProjection) {
|
|
1618
|
+
if (value.targetProjection.schemaRevisionRef.kind !== "schema")
|
|
1619
|
+
context.addIssue({
|
|
1620
|
+
code: "custom",
|
|
1621
|
+
path: ["targetProjection", "schemaRevisionRef"],
|
|
1622
|
+
message: "Query target projections require an exact target schema revision.",
|
|
1623
|
+
});
|
|
1624
|
+
for (const read of (0, page_expression_1.collectExternalPageExpressionReads)(value.targetProjection.expression))
|
|
1625
|
+
if (read.root !== "model")
|
|
1626
|
+
context.addIssue({
|
|
1627
|
+
code: "custom",
|
|
1628
|
+
path: ["targetProjection", "expression"],
|
|
1629
|
+
message: "Query target projections may read only the validated raw model.",
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1632
|
+
if (value.streamTargetProjection) {
|
|
1633
|
+
const projection = value.streamTargetProjection;
|
|
1634
|
+
if (projection.schemaRevisionRef.kind !== "schema")
|
|
1635
|
+
context.addIssue({
|
|
1636
|
+
code: "custom",
|
|
1637
|
+
path: ["streamTargetProjection", "schemaRevisionRef"],
|
|
1638
|
+
message: "Stream target projections require an exact target schema revision.",
|
|
1639
|
+
});
|
|
1640
|
+
for (const read of (0, page_expression_1.collectExternalPageExpressionReads)(projection.expression))
|
|
1641
|
+
if (read.root !== "model")
|
|
1642
|
+
context.addIssue({
|
|
1643
|
+
code: "custom",
|
|
1644
|
+
path: ["streamTargetProjection", "expression"],
|
|
1645
|
+
message: "Stream target projections may read only the verified query and stream envelope.",
|
|
1646
|
+
});
|
|
1647
|
+
if (value.execution !== "server" || value.pagination !== "none")
|
|
1648
|
+
context.addIssue({
|
|
1649
|
+
code: "custom",
|
|
1650
|
+
path: ["streamTargetProjection"],
|
|
1651
|
+
message: "Stream target projections require a non-paginated Server query.",
|
|
1652
|
+
});
|
|
1653
|
+
}
|
|
1654
|
+
const effects = value.stateEffects ?? [];
|
|
1655
|
+
if (new Set(effects.map((effect) => effect.targetStateId)).size !==
|
|
1656
|
+
effects.length)
|
|
1657
|
+
context.addIssue({
|
|
1658
|
+
code: "custom",
|
|
1659
|
+
path: ["stateEffects"],
|
|
1660
|
+
message: "A query completion may update each state only once.",
|
|
1661
|
+
});
|
|
1662
|
+
for (const [index, effect] of effects.entries())
|
|
1663
|
+
for (const expression of [
|
|
1664
|
+
effect.value,
|
|
1665
|
+
...(effect.when ? [effect.when] : []),
|
|
1666
|
+
]) {
|
|
1667
|
+
for (const read of (0, page_expression_1.collectPageExpressionReads)(expression))
|
|
1668
|
+
if (!["model", "state", "scope"].includes(read.root))
|
|
1669
|
+
context.addIssue({
|
|
1670
|
+
code: "custom",
|
|
1671
|
+
path: ["stateEffects", index],
|
|
1672
|
+
message: "Query state effects may read only model, state, and scope.",
|
|
1673
|
+
});
|
|
1674
|
+
}
|
|
1675
|
+
if (effects.length &&
|
|
1676
|
+
(value.execution !== "server" || value.pagination !== "none"))
|
|
1677
|
+
context.addIssue({
|
|
1678
|
+
code: "custom",
|
|
1679
|
+
path: ["stateEffects"],
|
|
1680
|
+
message: "Query state effects require a non-paginated Server query.",
|
|
1681
|
+
});
|
|
1682
|
+
if (value.refreshPolicy?.when) {
|
|
1683
|
+
for (const read of (0, page_expression_1.collectExternalPageExpressionReads)(value.refreshPolicy.when)) {
|
|
1684
|
+
if (read.root !== "model" &&
|
|
1685
|
+
!(read.root === "actions" &&
|
|
1686
|
+
read.path.length === 2 &&
|
|
1687
|
+
read.path[1] === "pending"))
|
|
1688
|
+
context.addIssue({
|
|
1689
|
+
code: "custom",
|
|
1690
|
+
path: ["refreshPolicy", "when"],
|
|
1691
|
+
message: "Automatic refresh conditions may read only the verified raw model and declared action pending state.",
|
|
1692
|
+
});
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
if (value.refreshPolicy &&
|
|
1696
|
+
(value.execution !== "server" || value.pagination !== "none")) {
|
|
1697
|
+
context.addIssue({
|
|
1698
|
+
code: "custom",
|
|
1699
|
+
path: ["refreshPolicy"],
|
|
1700
|
+
message: "Automatic refresh requires a non-paginated Server query.",
|
|
1701
|
+
});
|
|
1702
|
+
}
|
|
1703
|
+
if (value.queryDefinitionRevisionRef.kind !== "domain-query-definition") {
|
|
1704
|
+
context.addIssue({
|
|
1705
|
+
code: "custom",
|
|
1706
|
+
path: ["queryDefinitionRevisionRef", "kind"],
|
|
1707
|
+
message: "Query bindings must pin a governed domain-query-definition revision.",
|
|
1708
|
+
});
|
|
1709
|
+
}
|
|
1710
|
+
if (value.renderModelSchemaRevisionRef.kind !== "schema") {
|
|
1711
|
+
context.addIssue({
|
|
1712
|
+
code: "custom",
|
|
1713
|
+
path: ["renderModelSchemaRevisionRef", "kind"],
|
|
1714
|
+
message: "Query bindings must pin a render-model schema revision.",
|
|
1715
|
+
});
|
|
1716
|
+
}
|
|
1717
|
+
if (value.execution === "local-state" && value.pagination !== "none") {
|
|
1718
|
+
context.addIssue({
|
|
1719
|
+
code: "custom",
|
|
1720
|
+
path: ["pagination"],
|
|
1721
|
+
message: "Local Page-state queries cannot paginate.",
|
|
1722
|
+
});
|
|
1723
|
+
}
|
|
1724
|
+
if (value.execution === "local-state" && value.accessFailure) {
|
|
1725
|
+
context.addIssue({
|
|
1726
|
+
code: "custom",
|
|
1727
|
+
path: ["accessFailure"],
|
|
1728
|
+
message: "Only a Server query can render an independently governed access failure.",
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
if (value.execution === "local-state" &&
|
|
1732
|
+
(value.resultStateBindings?.length ?? 0) > 0) {
|
|
1733
|
+
context.addIssue({
|
|
1734
|
+
code: "custom",
|
|
1735
|
+
path: ["resultStateBindings"],
|
|
1736
|
+
message: "Only Server queries can project governed result totals into Page state.",
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
const targetStateIds = value.resultStateBindings?.map((binding) => binding.targetStateId) ?? [];
|
|
1740
|
+
if (new Set(targetStateIds).size !== targetStateIds.length) {
|
|
1741
|
+
context.addIssue({
|
|
1742
|
+
code: "custom",
|
|
1743
|
+
path: ["resultStateBindings"],
|
|
1744
|
+
message: "A Query binding can project a governed result total to each Page state at most once.",
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
if (value.cursorWindow && value.pagination !== "cursor") {
|
|
1748
|
+
context.addIssue({
|
|
1749
|
+
code: "custom",
|
|
1750
|
+
path: ["cursorWindow"],
|
|
1751
|
+
message: "Cursor-window navigation requires cursor pagination.",
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
if (value.cursorWindow && value.execution !== "server") {
|
|
1755
|
+
context.addIssue({
|
|
1756
|
+
code: "custom",
|
|
1757
|
+
path: ["cursorWindow"],
|
|
1758
|
+
message: "Cursor-window navigation requires Server query execution.",
|
|
1759
|
+
});
|
|
1760
|
+
}
|
|
1761
|
+
});
|
|
1762
|
+
exports.CapabilityInstanceSchema = zod_1.z
|
|
1763
|
+
.object({
|
|
1764
|
+
instanceId: common_1.ContractIdentifierSchema,
|
|
1765
|
+
nodeId: common_1.ContractIdentifierSchema,
|
|
1766
|
+
capabilityRevisionRef: exports.RevisionRefSchema,
|
|
1767
|
+
providerRevisionRef: exports.RevisionRefSchema,
|
|
1768
|
+
propertySchemaRevisionRef: exports.RevisionRefSchema,
|
|
1769
|
+
properties: common_1.JsonObjectSchema,
|
|
1770
|
+
propertyBindings: zod_1.z.array(page_expression_1.PagePropertyBindingSchema).max(128).optional(),
|
|
1771
|
+
eventPayloadBindings: zod_1.z
|
|
1772
|
+
.array(zod_1.z
|
|
1773
|
+
.object({
|
|
1774
|
+
port: common_1.ContractIdentifierSchema,
|
|
1775
|
+
expression: page_expression_1.PageExpressionSchema,
|
|
1776
|
+
})
|
|
1777
|
+
.strict())
|
|
1778
|
+
.max(32)
|
|
1779
|
+
.optional(),
|
|
1780
|
+
eventEffects: zod_1.z
|
|
1781
|
+
.array(zod_1.z
|
|
1782
|
+
.object({
|
|
1783
|
+
sourcePort: common_1.ContractIdentifierSchema,
|
|
1784
|
+
sourceIntentSchemaRevisionRef: exports.RevisionRefSchema,
|
|
1785
|
+
refreshBindingIds: zod_1.z
|
|
1786
|
+
.array(common_1.ContractIdentifierSchema)
|
|
1787
|
+
.min(1)
|
|
1788
|
+
.max(128),
|
|
1789
|
+
})
|
|
1790
|
+
.strict())
|
|
1791
|
+
.max(32)
|
|
1792
|
+
.optional(),
|
|
1793
|
+
accessPolicy: exports.AccessPolicySchema.optional(),
|
|
1794
|
+
activationWhen: exports.PageStateActivationSchema.optional(),
|
|
1795
|
+
allowedSideEffects: zod_1.z.array(zod_1.z.enum([
|
|
1796
|
+
"network",
|
|
1797
|
+
"storage",
|
|
1798
|
+
"navigation",
|
|
1799
|
+
"clipboard",
|
|
1800
|
+
"worker",
|
|
1801
|
+
"websocket",
|
|
1802
|
+
])),
|
|
1803
|
+
})
|
|
1804
|
+
.strict();
|
|
1805
|
+
exports.OntologyBindingSchema = zod_1.z
|
|
1806
|
+
.object({
|
|
1807
|
+
bindingId: common_1.ContractIdentifierSchema,
|
|
1808
|
+
ontologyDefinitionRevisionRef: exports.RevisionRefSchema,
|
|
1809
|
+
viewRevisionRef: exports.RevisionRefSchema,
|
|
1810
|
+
canonicalDataViewRevisionRef: exports.RevisionRefSchema,
|
|
1811
|
+
parameters: zod_1.z.record(common_1.ContractIdentifierSchema, exports.BindingSourceSchema),
|
|
1812
|
+
target: zod_1.z
|
|
1813
|
+
.object({
|
|
1814
|
+
capabilityInstanceId: common_1.ContractIdentifierSchema,
|
|
1815
|
+
port: common_1.ContractIdentifierSchema,
|
|
1816
|
+
})
|
|
1817
|
+
.strict(),
|
|
1818
|
+
renderModelSchemaRevisionRef: exports.RevisionRefSchema,
|
|
1819
|
+
pagination: zod_1.z.enum(["none", "cursor", "offset"]),
|
|
1820
|
+
cursorWindow: exports.CursorWindowBindingSchema.optional(),
|
|
1821
|
+
cache: zod_1.z.enum(["none", "identity-scoped", "tenant-scoped"]),
|
|
1822
|
+
cancelOnChange: zod_1.z.boolean(),
|
|
1823
|
+
})
|
|
1824
|
+
.strict()
|
|
1825
|
+
.superRefine((value, context) => {
|
|
1826
|
+
if (value.viewRevisionRef.kind !== "view") {
|
|
1827
|
+
context.addIssue({
|
|
1828
|
+
code: "custom",
|
|
1829
|
+
path: ["viewRevisionRef", "kind"],
|
|
1830
|
+
message: "Ontology bindings require an exact governed View revision.",
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
if (value.canonicalDataViewRevisionRef.kind !== "view") {
|
|
1834
|
+
context.addIssue({
|
|
1835
|
+
code: "custom",
|
|
1836
|
+
path: ["canonicalDataViewRevisionRef", "kind"],
|
|
1837
|
+
message: "Ontology bindings require an exact canonical data.view revision.",
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
if (exactRevisionRef(value.viewRevisionRef, value.canonicalDataViewRevisionRef)) {
|
|
1841
|
+
context.addIssue({
|
|
1842
|
+
code: "custom",
|
|
1843
|
+
path: ["canonicalDataViewRevisionRef"],
|
|
1844
|
+
message: "Governed View adapter and canonical data.view revisions must be distinct.",
|
|
1845
|
+
});
|
|
1846
|
+
}
|
|
1847
|
+
if (value.ontologyDefinitionRevisionRef.kind !== "ontology-definition") {
|
|
1848
|
+
context.addIssue({
|
|
1849
|
+
code: "custom",
|
|
1850
|
+
path: ["ontologyDefinitionRevisionRef", "kind"],
|
|
1851
|
+
message: "Expected an ontology-definition revision.",
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1854
|
+
if (value.cursorWindow && value.pagination !== "cursor") {
|
|
1855
|
+
context.addIssue({
|
|
1856
|
+
code: "custom",
|
|
1857
|
+
path: ["cursorWindow"],
|
|
1858
|
+
message: "Cursor-window navigation requires cursor pagination.",
|
|
1859
|
+
});
|
|
1860
|
+
}
|
|
1861
|
+
});
|
|
1862
|
+
exports.ActionResultBindingEffectSourceSchema = zod_1.z.discriminatedUnion("kind", [
|
|
1863
|
+
zod_1.z
|
|
1864
|
+
.object({
|
|
1865
|
+
kind: zod_1.z.literal("result-field"),
|
|
1866
|
+
path: zod_1.z
|
|
1867
|
+
.string()
|
|
1868
|
+
.trim()
|
|
1869
|
+
.regex(/^[A-Za-z0-9_.-]+$/),
|
|
1870
|
+
})
|
|
1871
|
+
.strict(),
|
|
1872
|
+
zod_1.z.object({ kind: zod_1.z.literal("constant"), value: common_1.JsonValueSchema }).strict(),
|
|
1873
|
+
zod_1.z
|
|
1874
|
+
.object({
|
|
1875
|
+
kind: zod_1.z.literal("collection-length"),
|
|
1876
|
+
offset: zod_1.z.number().int().min(-1000).max(1000),
|
|
1877
|
+
})
|
|
1878
|
+
.strict(),
|
|
1879
|
+
]);
|
|
1880
|
+
exports.ActionResultBindingEffectSchema = zod_1.z
|
|
1881
|
+
.object({
|
|
1882
|
+
bindingId: common_1.ContractIdentifierSchema,
|
|
1883
|
+
operation: zod_1.z.enum(["upsert-append", "remove-exact"]),
|
|
1884
|
+
collectionPath: zod_1.z.array(common_1.ContractIdentifierSchema).min(1).max(8),
|
|
1885
|
+
identityPath: zod_1.z.array(common_1.ContractIdentifierSchema).min(1).max(8),
|
|
1886
|
+
mappings: zod_1.z
|
|
1887
|
+
.array(zod_1.z
|
|
1888
|
+
.object({
|
|
1889
|
+
targetPath: zod_1.z.array(common_1.ContractIdentifierSchema).min(1).max(8),
|
|
1890
|
+
source: exports.ActionResultBindingEffectSourceSchema,
|
|
1891
|
+
})
|
|
1892
|
+
.strict())
|
|
1893
|
+
.min(1)
|
|
1894
|
+
.max(64),
|
|
1895
|
+
})
|
|
1896
|
+
.strict()
|
|
1897
|
+
.superRefine((value, context) => {
|
|
1898
|
+
const targetPaths = value.mappings.map(({ targetPath }) => targetPath.join("."));
|
|
1899
|
+
if (new Set(targetPaths).size !== targetPaths.length) {
|
|
1900
|
+
context.addIssue({
|
|
1901
|
+
code: "custom",
|
|
1902
|
+
path: ["mappings"],
|
|
1903
|
+
message: "Result binding effect target paths must be unique.",
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1906
|
+
if (!targetPaths.includes(value.identityPath.join("."))) {
|
|
1907
|
+
context.addIssue({
|
|
1908
|
+
code: "custom",
|
|
1909
|
+
path: ["identityPath"],
|
|
1910
|
+
message: "A result binding effect must map the exact identity path of the projected item.",
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
const identityMapping = value.mappings.find(({ targetPath }) => targetPath.join(".") === value.identityPath.join("."));
|
|
1914
|
+
if (identityMapping?.source.kind === "collection-length") {
|
|
1915
|
+
context.addIssue({
|
|
1916
|
+
code: "custom",
|
|
1917
|
+
path: ["identityPath"],
|
|
1918
|
+
message: "A projected item identity must come from the verified result or a declared constant.",
|
|
1919
|
+
});
|
|
1920
|
+
}
|
|
1921
|
+
if (value.operation === "remove-exact" && value.mappings.length !== 1) {
|
|
1922
|
+
context.addIssue({
|
|
1923
|
+
code: "custom",
|
|
1924
|
+
path: ["mappings"],
|
|
1925
|
+
message: "An exact removal declares only the verified identity mapping used to remove one item.",
|
|
1926
|
+
});
|
|
1927
|
+
}
|
|
1928
|
+
});
|
|
1929
|
+
exports.ActionResultClipboardEffectSchema = zod_1.z
|
|
1930
|
+
.object({
|
|
1931
|
+
source: zod_1.z
|
|
1932
|
+
.object({
|
|
1933
|
+
kind: zod_1.z.literal("result-field"),
|
|
1934
|
+
path: zod_1.z
|
|
1935
|
+
.string()
|
|
1936
|
+
.trim()
|
|
1937
|
+
.regex(/^[A-Za-z0-9_.-]+$/),
|
|
1938
|
+
})
|
|
1939
|
+
.strict(),
|
|
1940
|
+
copiedToast: exports.I18nTextSchema.optional(),
|
|
1941
|
+
fallbackToast: exports.I18nTextSchema.superRefine((value, context) => {
|
|
1942
|
+
for (const [locale, message] of Object.entries(value.values)) {
|
|
1943
|
+
if (!message.includes("{value}")) {
|
|
1944
|
+
context.addIssue({
|
|
1945
|
+
code: "custom",
|
|
1946
|
+
path: ["values", locale],
|
|
1947
|
+
message: "Clipboard fallback feedback must visibly include the exact verified value placeholder.",
|
|
1948
|
+
});
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
}),
|
|
1952
|
+
})
|
|
1953
|
+
.strict();
|
|
1954
|
+
exports.ActionBindingSchema = zod_1.z
|
|
1955
|
+
.object({
|
|
1956
|
+
bindingId: common_1.ContractIdentifierSchema,
|
|
1957
|
+
commandRevisionRef: exports.RevisionRefSchema,
|
|
1958
|
+
source: zod_1.z
|
|
1959
|
+
.object({
|
|
1960
|
+
capabilityInstanceId: common_1.ContractIdentifierSchema,
|
|
1961
|
+
port: common_1.ContractIdentifierSchema,
|
|
1962
|
+
})
|
|
1963
|
+
.strict(),
|
|
1964
|
+
sourceIntentSchemaRevisionRef: exports.RevisionRefSchema,
|
|
1965
|
+
inputSchemaRevisionRef: exports.RevisionRefSchema,
|
|
1966
|
+
when: page_expression_1.PageExpressionSchema.optional(),
|
|
1967
|
+
fileInputs: zod_1.z.array(ActionFileInputSchema).min(1).max(4).optional(),
|
|
1968
|
+
inputMapping: zod_1.z.record(common_1.ContractIdentifierSchema, ActionInputBindingSourceSchema),
|
|
1969
|
+
sensitiveInputPaths: common_1.SensitiveResultPathsSchema.optional(),
|
|
1970
|
+
accessPolicy: exports.AccessPolicySchema,
|
|
1971
|
+
confirmation: exports.I18nTextSchema.optional(),
|
|
1972
|
+
idempotencyKeySource: zod_1.z.enum([
|
|
1973
|
+
"interaction",
|
|
1974
|
+
"record-and-interaction",
|
|
1975
|
+
"caller-provided",
|
|
1976
|
+
]),
|
|
1977
|
+
compensationCommandRevisionRef: exports.RevisionRefSchema.optional(),
|
|
1978
|
+
resultSchemaRevisionRef: exports.RevisionRefSchema,
|
|
1979
|
+
success: zod_1.z
|
|
1980
|
+
.object({
|
|
1981
|
+
download: zod_1.z
|
|
1982
|
+
.discriminatedUnion("kind", [
|
|
1983
|
+
zod_1.z.object({ kind: zod_1.z.literal("native") }).strict(),
|
|
1984
|
+
zod_1.z
|
|
1985
|
+
.object({
|
|
1986
|
+
kind: zod_1.z.literal("text-artifact"),
|
|
1987
|
+
fileNamePath: page_expression_1.PageValuePathSchema.min(1),
|
|
1988
|
+
mimeTypePath: page_expression_1.PageValuePathSchema.min(1),
|
|
1989
|
+
contentPath: page_expression_1.PageValuePathSchema.min(1),
|
|
1990
|
+
maxBytes: zod_1.z.number().int().min(1).max(1048576),
|
|
1991
|
+
})
|
|
1992
|
+
.strict(),
|
|
1993
|
+
])
|
|
1994
|
+
.optional(),
|
|
1995
|
+
refreshBindingIds: zod_1.z.array(common_1.ContractIdentifierSchema),
|
|
1996
|
+
ephemeralResult: zod_1.z
|
|
1997
|
+
.object({
|
|
1998
|
+
kind: zod_1.z.literal("one-time-value"),
|
|
1999
|
+
valuePath: common_1.SensitiveResultPathSchema,
|
|
2000
|
+
labelPath: common_1.SensitiveResultPathSchema,
|
|
2001
|
+
title: exports.I18nTextSchema,
|
|
2002
|
+
description: exports.I18nTextSchema,
|
|
2003
|
+
copySuccessToast: exports.I18nTextSchema,
|
|
2004
|
+
copyFailureToast: exports.I18nTextSchema,
|
|
2005
|
+
})
|
|
2006
|
+
.strict()
|
|
2007
|
+
.optional(),
|
|
2008
|
+
resultBindingEffects: zod_1.z
|
|
2009
|
+
.array(exports.ActionResultBindingEffectSchema)
|
|
2010
|
+
.max(64)
|
|
2011
|
+
.optional(),
|
|
2012
|
+
clipboard: exports.ActionResultClipboardEffectSchema.optional(),
|
|
2013
|
+
navigationTargetRef: exports.StableRefSchema.optional(),
|
|
2014
|
+
toast: exports.I18nTextSchema.optional(),
|
|
2015
|
+
})
|
|
2016
|
+
.strict(),
|
|
2017
|
+
recovery: zod_1.z.enum(["retry-safe", "compensating-command", "manual-review"]),
|
|
2018
|
+
lineageRequired: zod_1.z.literal(true),
|
|
2019
|
+
})
|
|
2020
|
+
.strict()
|
|
2021
|
+
.superRefine((value, context) => {
|
|
2022
|
+
const fileIds = new Set();
|
|
2023
|
+
for (const file of value.fileInputs ?? []) {
|
|
2024
|
+
if (fileIds.has(file.inputId))
|
|
2025
|
+
context.addIssue({
|
|
2026
|
+
code: "custom",
|
|
2027
|
+
path: ["fileInputs"],
|
|
2028
|
+
message: "File input ids must be unique.",
|
|
2029
|
+
});
|
|
2030
|
+
fileIds.add(file.inputId);
|
|
2031
|
+
if (!Object.values(value.inputMapping).some((source) => source.kind === "file-field" && source.fileInputId === file.inputId))
|
|
2032
|
+
context.addIssue({
|
|
2033
|
+
code: "custom",
|
|
2034
|
+
path: ["fileInputs"],
|
|
2035
|
+
message: "File inputs require an explicit governed input mapping.",
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
for (const [name, source] of Object.entries(value.inputMapping))
|
|
2039
|
+
if (source.kind === "file-field") {
|
|
2040
|
+
const file = value.fileInputs?.find((file) => file.inputId === source.fileInputId);
|
|
2041
|
+
if ((source.path === "canonicalUri" && !file?.upload) ||
|
|
2042
|
+
(source.path === "content" && file?.upload))
|
|
2043
|
+
context.addIssue({
|
|
2044
|
+
code: "custom",
|
|
2045
|
+
path: ["inputMapping", name],
|
|
2046
|
+
message: "File field must match its declared transport mode.",
|
|
2047
|
+
});
|
|
2048
|
+
if (!fileIds.has(source.fileInputId))
|
|
2049
|
+
context.addIssue({
|
|
2050
|
+
code: "custom",
|
|
2051
|
+
path: ["inputMapping", name],
|
|
2052
|
+
message: "File fields must reference a declared file input.",
|
|
2053
|
+
});
|
|
2054
|
+
if (source.path === "content" &&
|
|
2055
|
+
!value.sensitiveInputPaths?.includes(`/${name}`))
|
|
2056
|
+
context.addIssue({
|
|
2057
|
+
code: "custom",
|
|
2058
|
+
path: ["sensitiveInputPaths"],
|
|
2059
|
+
message: "File content must be declared as a sensitive command input.",
|
|
2060
|
+
});
|
|
2061
|
+
}
|
|
2062
|
+
if (value.when)
|
|
2063
|
+
for (const read of (0, page_expression_1.collectPageExpressionReads)(value.when)) {
|
|
2064
|
+
if (!["intent", "state", "scope"].includes(read.root))
|
|
2065
|
+
context.addIssue({
|
|
2066
|
+
code: "custom",
|
|
2067
|
+
path: ["when"],
|
|
2068
|
+
message: "Action conditions may read only intent, declared Page state, and instance scope.",
|
|
2069
|
+
});
|
|
2070
|
+
}
|
|
2071
|
+
if (value.success.ephemeralResult) {
|
|
2072
|
+
const { valuePath, labelPath } = value.success.ephemeralResult;
|
|
2073
|
+
const segments = (path) => path.split("/").slice(1);
|
|
2074
|
+
const valueSegments = segments(valuePath);
|
|
2075
|
+
const labelSegments = segments(labelPath);
|
|
2076
|
+
const sharedLength = Math.min(valueSegments.length, labelSegments.length);
|
|
2077
|
+
if (valueSegments
|
|
2078
|
+
.slice(0, sharedLength)
|
|
2079
|
+
.every((segment, index) => segment === labelSegments[index])) {
|
|
2080
|
+
context.addIssue({
|
|
2081
|
+
code: "custom",
|
|
2082
|
+
path: ["success", "ephemeralResult", "labelPath"],
|
|
2083
|
+
message: "One-time result labels cannot overlap the sensitive value path.",
|
|
2084
|
+
});
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
if (value.success.ephemeralResult &&
|
|
2088
|
+
(value.success.resultBindingEffects?.length || 0) > 0) {
|
|
2089
|
+
context.addIssue({
|
|
2090
|
+
code: "custom",
|
|
2091
|
+
path: ["success", "resultBindingEffects"],
|
|
2092
|
+
message: "One-time result presentation cannot share a result with durable binding effects.",
|
|
2093
|
+
});
|
|
2094
|
+
}
|
|
2095
|
+
if (value.commandRevisionRef.kind !== "domain-command") {
|
|
2096
|
+
context.addIssue({
|
|
2097
|
+
code: "custom",
|
|
2098
|
+
path: ["commandRevisionRef", "kind"],
|
|
2099
|
+
message: "Action bindings must reference a domain-command revision.",
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
2102
|
+
if (value.sourceIntentSchemaRevisionRef.kind !== "schema") {
|
|
2103
|
+
context.addIssue({
|
|
2104
|
+
code: "custom",
|
|
2105
|
+
path: ["sourceIntentSchemaRevisionRef", "kind"],
|
|
2106
|
+
message: "Action source intents must pin a schema revision.",
|
|
2107
|
+
});
|
|
2108
|
+
}
|
|
2109
|
+
if (value.inputSchemaRevisionRef.kind !== "schema") {
|
|
2110
|
+
context.addIssue({
|
|
2111
|
+
code: "custom",
|
|
2112
|
+
path: ["inputSchemaRevisionRef", "kind"],
|
|
2113
|
+
message: "Action command inputs must pin a schema revision.",
|
|
2114
|
+
});
|
|
2115
|
+
}
|
|
2116
|
+
if (value.recovery === "compensating-command" &&
|
|
2117
|
+
!value.compensationCommandRevisionRef) {
|
|
2118
|
+
context.addIssue({
|
|
2119
|
+
code: "custom",
|
|
2120
|
+
path: ["compensationCommandRevisionRef"],
|
|
2121
|
+
message: "Compensating recovery requires a compensation command.",
|
|
2122
|
+
});
|
|
2123
|
+
}
|
|
2124
|
+
});
|
|
2125
|
+
exports.PageMigrationEquivalenceDimensionSchema = zod_1.z.enum([
|
|
2126
|
+
"url",
|
|
2127
|
+
"navigation",
|
|
2128
|
+
"access",
|
|
2129
|
+
"deep-link",
|
|
2130
|
+
"layout",
|
|
2131
|
+
"size",
|
|
2132
|
+
"spacing",
|
|
2133
|
+
"design-tokens",
|
|
2134
|
+
"responsive",
|
|
2135
|
+
"view-modes",
|
|
2136
|
+
"search-filter",
|
|
2137
|
+
"editing",
|
|
2138
|
+
"detail",
|
|
2139
|
+
"history",
|
|
2140
|
+
"dialogs",
|
|
2141
|
+
"keyboard",
|
|
2142
|
+
"loading",
|
|
2143
|
+
"empty",
|
|
2144
|
+
"error",
|
|
2145
|
+
"forbidden",
|
|
2146
|
+
]);
|
|
2147
|
+
exports.PageMigrationEquivalenceSchema = zod_1.z
|
|
2148
|
+
.object({
|
|
2149
|
+
contract: zod_1.z.literal("PageMigrationEquivalence"),
|
|
2150
|
+
schemaVersion: zod_1.z.literal(1),
|
|
2151
|
+
policy: zod_1.z.literal("preserve-ui-ux"),
|
|
2152
|
+
baseline: zod_1.z
|
|
2153
|
+
.object({
|
|
2154
|
+
repository: common_1.ContractIdentifierSchema,
|
|
2155
|
+
revision: zod_1.z.string().regex(/^[0-9a-f]{40}$/),
|
|
2156
|
+
pageId: common_1.ContractIdentifierSchema,
|
|
2157
|
+
routePath: exports.RoutePathTemplateSchema,
|
|
2158
|
+
})
|
|
2159
|
+
.strict(),
|
|
2160
|
+
protectedDimensions: zod_1.z
|
|
2161
|
+
.array(exports.PageMigrationEquivalenceDimensionSchema)
|
|
2162
|
+
.min(1),
|
|
2163
|
+
viewports: zod_1.z
|
|
2164
|
+
.array(zod_1.z
|
|
2165
|
+
.object({
|
|
2166
|
+
viewportId: common_1.ContractIdentifierSchema,
|
|
2167
|
+
width: zod_1.z.number().int().min(320).max(7680),
|
|
2168
|
+
height: zod_1.z.number().int().min(480).max(4320),
|
|
2169
|
+
})
|
|
2170
|
+
.strict())
|
|
2171
|
+
.min(2),
|
|
2172
|
+
scenarios: zod_1.z
|
|
2173
|
+
.array(zod_1.z
|
|
2174
|
+
.object({
|
|
2175
|
+
scenarioId: common_1.ContractIdentifierSchema,
|
|
2176
|
+
viewportIds: zod_1.z.array(common_1.ContractIdentifierSchema).min(1),
|
|
2177
|
+
})
|
|
2178
|
+
.strict())
|
|
2179
|
+
.min(1),
|
|
2180
|
+
evidence: zod_1.z
|
|
2181
|
+
.object({
|
|
2182
|
+
sideBySideVisual: zod_1.z.literal(true),
|
|
2183
|
+
domSnapshot: zod_1.z.literal(true),
|
|
2184
|
+
consoleErrors: zod_1.z.literal("none"),
|
|
2185
|
+
})
|
|
2186
|
+
.strict(),
|
|
2187
|
+
allowedDifferences: zod_1.z.array(zod_1.z
|
|
2188
|
+
.object({
|
|
2189
|
+
differenceId: common_1.ContractIdentifierSchema,
|
|
2190
|
+
requirementRevisionRef: exports.RevisionRefSchema,
|
|
2191
|
+
})
|
|
2192
|
+
.strict()),
|
|
2193
|
+
})
|
|
2194
|
+
.strict()
|
|
2195
|
+
.superRefine((value, context) => {
|
|
2196
|
+
if (uniqueArray(value.protectedDimensions, (candidate) => candidate)) {
|
|
2197
|
+
context.addIssue({
|
|
2198
|
+
code: "custom",
|
|
2199
|
+
path: ["protectedDimensions"],
|
|
2200
|
+
message: "Protected UI/UX dimensions must be unique.",
|
|
2201
|
+
});
|
|
2202
|
+
}
|
|
2203
|
+
if (uniqueArray(value.viewports, (candidate) => candidate.viewportId)) {
|
|
2204
|
+
context.addIssue({
|
|
2205
|
+
code: "custom",
|
|
2206
|
+
path: ["viewports"],
|
|
2207
|
+
message: "Migration equivalence viewport identities must be unique.",
|
|
2208
|
+
});
|
|
2209
|
+
}
|
|
2210
|
+
if (uniqueArray(value.scenarios, (candidate) => candidate.scenarioId)) {
|
|
2211
|
+
context.addIssue({
|
|
2212
|
+
code: "custom",
|
|
2213
|
+
path: ["scenarios"],
|
|
2214
|
+
message: "Migration equivalence scenario identities must be unique.",
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
const viewportIds = new Set(value.viewports.map((viewport) => viewport.viewportId));
|
|
2218
|
+
value.scenarios.forEach((scenario, index) => {
|
|
2219
|
+
scenario.viewportIds.forEach((viewportId, viewportIndex) => {
|
|
2220
|
+
if (!viewportIds.has(viewportId)) {
|
|
2221
|
+
context.addIssue({
|
|
2222
|
+
code: "custom",
|
|
2223
|
+
path: ["scenarios", index, "viewportIds", viewportIndex],
|
|
2224
|
+
message: `Migration equivalence scenario references unknown viewport ${viewportId}.`,
|
|
2225
|
+
});
|
|
2226
|
+
}
|
|
2227
|
+
});
|
|
2228
|
+
});
|
|
2229
|
+
});
|
|
2230
|
+
exports.PageRouteStatePresentationSchema = zod_1.z
|
|
2231
|
+
.object({
|
|
2232
|
+
surface: exports.ProductSurfaceSchema,
|
|
2233
|
+
state: zod_1.z.literal("forbidden"),
|
|
2234
|
+
kind: zod_1.z.literal("status"),
|
|
2235
|
+
presentation: zod_1.z.enum(["panel", "page"]),
|
|
2236
|
+
title: exports.I18nTextSchema,
|
|
2237
|
+
description: exports.I18nTextSchema.optional(),
|
|
2238
|
+
})
|
|
2239
|
+
.strict()
|
|
2240
|
+
.superRefine((value, context) => {
|
|
2241
|
+
const localizedFields = [
|
|
2242
|
+
["title", value.title, 160],
|
|
2243
|
+
["description", value.description, 1000],
|
|
2244
|
+
];
|
|
2245
|
+
localizedFields.forEach(([field, copy, maxLength]) => {
|
|
2246
|
+
if (!copy)
|
|
2247
|
+
return;
|
|
2248
|
+
const entries = Object.entries(copy.values);
|
|
2249
|
+
if (entries.length > 16) {
|
|
2250
|
+
context.addIssue({
|
|
2251
|
+
code: "custom",
|
|
2252
|
+
path: [field, "values"],
|
|
2253
|
+
message: "Route-state presentation copy supports at most 16 locales.",
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
entries.forEach(([locale, text]) => {
|
|
2257
|
+
if (text.length > maxLength) {
|
|
2258
|
+
context.addIssue({
|
|
2259
|
+
code: "custom",
|
|
2260
|
+
path: [field, "values", locale],
|
|
2261
|
+
message: `Route-state ${field} copy must contain at most ${maxLength} characters.`,
|
|
2262
|
+
});
|
|
2263
|
+
}
|
|
2264
|
+
});
|
|
2265
|
+
});
|
|
2266
|
+
});
|
|
2267
|
+
exports.PageStateSchema = exports.PageStateDefinitionSchema.omit({
|
|
2268
|
+
schemaRevisionRef: true,
|
|
2269
|
+
})
|
|
2270
|
+
.extend({
|
|
2271
|
+
stateId: common_1.ContractIdentifierSchema,
|
|
2272
|
+
schema: common_1.ContractIdentifierSchema,
|
|
2273
|
+
})
|
|
2274
|
+
.strict();
|
|
2275
|
+
exports.PageEntryTargetSchema = zod_1.z
|
|
2276
|
+
.object({
|
|
2277
|
+
kind: zod_1.z.enum(["page", "workbench"]),
|
|
2278
|
+
id: common_1.ContractIdentifierSchema,
|
|
2279
|
+
})
|
|
2280
|
+
.strict();
|
|
2281
|
+
exports.PageEntrySchema = exports.PageEntryTransitionSchema.omit({
|
|
2282
|
+
targetRef: true,
|
|
2283
|
+
})
|
|
2284
|
+
.extend({
|
|
2285
|
+
target: exports.PageEntryTargetSchema,
|
|
2286
|
+
})
|
|
2287
|
+
.strict();
|
|
2288
|
+
exports.PageInteractionSchema = exports.InteractionBindingSchema.omit({
|
|
2289
|
+
source: true,
|
|
2290
|
+
sourceIntentSchemaRevisionRef: true,
|
|
2291
|
+
sourceResultSchemaRevisionRef: true,
|
|
2292
|
+
})
|
|
2293
|
+
.extend({
|
|
2294
|
+
port: common_1.ContractIdentifierSchema,
|
|
2295
|
+
})
|
|
2296
|
+
.strict();
|
|
2297
|
+
const PageCursorWindowSchema = exports.CursorWindowBindingSchema.omit({
|
|
2298
|
+
pageChangeIntentSchemaRevisionRef: true,
|
|
2299
|
+
}).strict();
|
|
2300
|
+
const PageResultStateBindingSchema = exports.QueryResultStateBindingSchema.omit({
|
|
2301
|
+
targetStateSchemaRevisionRef: true,
|
|
2302
|
+
}).strict();
|
|
2303
|
+
exports.PageDataSchema = exports.QueryBindingSchema.omit({
|
|
2304
|
+
queryDefinitionRevisionRef: true,
|
|
2305
|
+
target: true,
|
|
2306
|
+
renderModelSchemaRevisionRef: true,
|
|
2307
|
+
targetProjection: true,
|
|
2308
|
+
streamTargetProjection: true,
|
|
2309
|
+
cursorWindow: true,
|
|
2310
|
+
resultStateBindings: true,
|
|
2311
|
+
})
|
|
2312
|
+
.extend({
|
|
2313
|
+
query: common_1.ContractIdentifierSchema,
|
|
2314
|
+
port: common_1.ContractIdentifierSchema,
|
|
2315
|
+
targetProjection: zod_1.z
|
|
2316
|
+
.object({ expression: page_expression_1.PageExpressionSchema })
|
|
2317
|
+
.strict()
|
|
2318
|
+
.optional(),
|
|
2319
|
+
streamTargetProjection: zod_1.z
|
|
2320
|
+
.object({ expression: page_expression_1.PageExpressionSchema })
|
|
2321
|
+
.strict()
|
|
2322
|
+
.optional(),
|
|
2323
|
+
cursorWindow: PageCursorWindowSchema.optional(),
|
|
2324
|
+
resultStateBindings: zod_1.z
|
|
2325
|
+
.array(PageResultStateBindingSchema)
|
|
2326
|
+
.max(32)
|
|
2327
|
+
.optional(),
|
|
2328
|
+
})
|
|
2329
|
+
.strict();
|
|
2330
|
+
exports.PageActionSchema = exports.ActionBindingSchema.omit({
|
|
2331
|
+
commandRevisionRef: true,
|
|
2332
|
+
source: true,
|
|
2333
|
+
sourceIntentSchemaRevisionRef: true,
|
|
2334
|
+
inputSchemaRevisionRef: true,
|
|
2335
|
+
compensationCommandRevisionRef: true,
|
|
2336
|
+
resultSchemaRevisionRef: true,
|
|
2337
|
+
})
|
|
2338
|
+
.extend({
|
|
2339
|
+
command: common_1.ContractIdentifierSchema,
|
|
2340
|
+
port: common_1.ContractIdentifierSchema,
|
|
2341
|
+
compensationCommand: common_1.ContractIdentifierSchema.optional(),
|
|
2342
|
+
})
|
|
2343
|
+
.strict();
|
|
2344
|
+
const PageEventEffectSchema = zod_1.z
|
|
2345
|
+
.object({
|
|
2346
|
+
port: common_1.ContractIdentifierSchema,
|
|
2347
|
+
refresh: zod_1.z.array(common_1.ContractIdentifierSchema).min(1).max(128),
|
|
2348
|
+
})
|
|
2349
|
+
.strict();
|
|
2350
|
+
exports.PageNodeSchema = zod_1.z.lazy(() => zod_1.z
|
|
2351
|
+
.object({
|
|
2352
|
+
id: common_1.ContractIdentifierSchema,
|
|
2353
|
+
component: common_1.ContractIdentifierSchema,
|
|
2354
|
+
kind: render_1.RenderNodeKindSchema.optional(),
|
|
2355
|
+
slot: common_1.ContractIdentifierSchema.optional(),
|
|
2356
|
+
props: common_1.JsonObjectSchema.optional(),
|
|
2357
|
+
bindings: zod_1.z.array(page_expression_1.PagePropertyBindingSchema).max(128).optional(),
|
|
2358
|
+
model: common_1.JsonObjectSchema.optional(),
|
|
2359
|
+
style: render_1.RenderStyleSchema.optional(),
|
|
2360
|
+
layout: render_1.RenderLayoutSchema.optional(),
|
|
2361
|
+
responsive: zod_1.z.array(render_1.RenderResponsiveRuleSchema).optional(),
|
|
2362
|
+
surface: render_1.RenderSurfaceSchema.optional(),
|
|
2363
|
+
scroll: render_1.RenderScrollSchema.optional(),
|
|
2364
|
+
activation: render_1.RenderActivationSchema.optional(),
|
|
2365
|
+
lifecycle: render_1.RenderLifecycleSchema.optional(),
|
|
2366
|
+
state: render_1.RenderNodeStateSchema.optional(),
|
|
2367
|
+
access: exports.AccessPolicySchema.optional(),
|
|
2368
|
+
activeWhen: exports.PageStateActivationSchema.optional(),
|
|
2369
|
+
repeat: zod_1.z
|
|
2370
|
+
.object({
|
|
2371
|
+
source: page_expression_1.PageExpressionSchema,
|
|
2372
|
+
keyPath: page_expression_1.PageValuePathSchema.min(1),
|
|
2373
|
+
limit: zod_1.z.number().int().min(1).max(1000).optional(),
|
|
2374
|
+
})
|
|
2375
|
+
.strict()
|
|
2376
|
+
.optional(),
|
|
2377
|
+
data: zod_1.z.array(exports.PageDataSchema).optional(),
|
|
2378
|
+
actions: zod_1.z.array(exports.PageActionSchema).optional(),
|
|
2379
|
+
on: zod_1.z.array(exports.PageInteractionSchema).optional(),
|
|
2380
|
+
effects: zod_1.z.array(PageEventEffectSchema).optional(),
|
|
2381
|
+
eventPayloads: zod_1.z
|
|
2382
|
+
.array(zod_1.z
|
|
2383
|
+
.object({
|
|
2384
|
+
port: common_1.ContractIdentifierSchema,
|
|
2385
|
+
expression: page_expression_1.PageExpressionSchema,
|
|
2386
|
+
})
|
|
2387
|
+
.strict())
|
|
2388
|
+
.optional(),
|
|
2389
|
+
children: zod_1.z.array(exports.PageNodeSchema).optional(),
|
|
2390
|
+
})
|
|
2391
|
+
.strict());
|
|
2392
|
+
exports.PageSchema = zod_1.z
|
|
2393
|
+
.object({
|
|
2394
|
+
contract: zod_1.z.literal("Page"),
|
|
2395
|
+
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
2396
|
+
pageId: common_1.ContractIdentifierSchema,
|
|
2397
|
+
tenantScope: exports.TenantScopeSchema,
|
|
2398
|
+
identity: IdentitySchema,
|
|
2399
|
+
surface: exports.ProductSurfaceSchema,
|
|
2400
|
+
route: exports.RoutePathTemplateSchema,
|
|
2401
|
+
routeSpace: common_1.ContractIdentifierSchema.optional(),
|
|
2402
|
+
lifecycle: exports.DeclarativeLifecycleSchema.default("active"),
|
|
2403
|
+
routeStatePresentations: zod_1.z
|
|
2404
|
+
.array(exports.PageRouteStatePresentationSchema)
|
|
2405
|
+
.max(8)
|
|
2406
|
+
.optional(),
|
|
2407
|
+
shell: common_1.ContractIdentifierSchema.optional(),
|
|
2408
|
+
body: exports.PageNodeSchema,
|
|
2409
|
+
state: zod_1.z.array(exports.PageStateSchema).optional(),
|
|
2410
|
+
entryTransitions: zod_1.z.array(exports.PageEntrySchema).optional(),
|
|
2411
|
+
access: exports.AccessPolicySchema,
|
|
2412
|
+
managementAccess: exports.ManagementAccessSchema,
|
|
2413
|
+
tokens: zod_1.z.array(common_1.ContractIdentifierSchema).optional(),
|
|
2414
|
+
performanceBudget: common_1.ContractIdentifierSchema.optional(),
|
|
2415
|
+
observationPolicy: common_1.ContractIdentifierSchema.optional(),
|
|
2416
|
+
privacyClassification: zod_1.z
|
|
2417
|
+
.enum(["public", "internal", "confidential", "restricted"])
|
|
2418
|
+
.default("internal"),
|
|
2419
|
+
})
|
|
2420
|
+
.strict()
|
|
2421
|
+
.superRefine((page, context) => {
|
|
2422
|
+
const ids = new Set();
|
|
2423
|
+
const dataIds = new Set();
|
|
2424
|
+
const actionIds = new Set();
|
|
2425
|
+
const interactionIds = new Set();
|
|
2426
|
+
const visit = (node, path) => {
|
|
2427
|
+
if (ids.has(node.id))
|
|
2428
|
+
context.addIssue({
|
|
2429
|
+
code: "custom",
|
|
2430
|
+
path: [...path, "id"],
|
|
2431
|
+
message: `Duplicate Page node id ${node.id}.`,
|
|
2432
|
+
});
|
|
2433
|
+
ids.add(node.id);
|
|
2434
|
+
for (const [field, values, target] of [
|
|
2435
|
+
["data", node.data ?? [], dataIds],
|
|
2436
|
+
["actions", node.actions ?? [], actionIds],
|
|
2437
|
+
["on", node.on ?? [], interactionIds],
|
|
2438
|
+
])
|
|
2439
|
+
for (const [index, value] of values.entries()) {
|
|
2440
|
+
if (target.has(value.bindingId))
|
|
2441
|
+
context.addIssue({
|
|
2442
|
+
code: "custom",
|
|
2443
|
+
path: [...path, field, index, "bindingId"],
|
|
2444
|
+
message: `Duplicate Page binding id ${value.bindingId}.`,
|
|
2445
|
+
});
|
|
2446
|
+
target.add(value.bindingId);
|
|
2447
|
+
}
|
|
2448
|
+
(node.children ?? []).forEach((child, index) => visit(child, [...path, "children", index]));
|
|
2449
|
+
};
|
|
2450
|
+
visit(page.body, ["body"]);
|
|
2451
|
+
const stateIds = (page.state ?? []).map((entry) => entry.stateId);
|
|
2452
|
+
if (new Set(stateIds).size !== stateIds.length)
|
|
2453
|
+
context.addIssue({
|
|
2454
|
+
code: "custom",
|
|
2455
|
+
path: ["state"],
|
|
2456
|
+
message: "Page state ids must be unique.",
|
|
2457
|
+
});
|
|
2458
|
+
});
|
|
2459
|
+
exports.ResolvedPageSchema = zod_1.z
|
|
2460
|
+
.object({
|
|
2461
|
+
contract: zod_1.z.literal("Page"),
|
|
2462
|
+
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
2463
|
+
pageId: common_1.ContractIdentifierSchema,
|
|
2464
|
+
tenantScope: exports.TenantScopeSchema,
|
|
2465
|
+
identity: IdentitySchema,
|
|
2466
|
+
supportedSurfaces: zod_1.z.array(exports.ProductSurfaceSchema).min(1),
|
|
2467
|
+
lifecycle: exports.DeclarativeLifecycleSchema,
|
|
2468
|
+
legacyRoutePolicy: legacy_route_1.LegacyRoutePolicySchema.optional(),
|
|
2469
|
+
migrationEquivalence: exports.PageMigrationEquivalenceSchema.optional(),
|
|
2470
|
+
routeStatePresentations: zod_1.z
|
|
2471
|
+
.array(exports.PageRouteStatePresentationSchema)
|
|
2472
|
+
.max(8)
|
|
2473
|
+
.optional(),
|
|
2474
|
+
routeClaims: zod_1.z
|
|
2475
|
+
.array(zod_1.z.union([
|
|
2476
|
+
exports.DeclarativeRouteClaimSchema,
|
|
2477
|
+
LegacyDeclarativeRouteClaimSchema,
|
|
2478
|
+
]))
|
|
2479
|
+
.min(1),
|
|
2480
|
+
shellRevisionRef: exports.RevisionRefSchema,
|
|
2481
|
+
renderTree: render_1.RenderTreeSchema,
|
|
2482
|
+
capabilityInstances: zod_1.z.array(exports.CapabilityInstanceSchema).min(1),
|
|
2483
|
+
stateDefinitions: zod_1.z.array(exports.PageStateDefinitionSchema).optional(),
|
|
2484
|
+
entryTransitions: zod_1.z.array(exports.PageEntryTransitionSchema).optional(),
|
|
2485
|
+
interactionBindings: zod_1.z.array(exports.InteractionBindingSchema).optional(),
|
|
2486
|
+
ontologyBindings: zod_1.z.array(exports.OntologyBindingSchema),
|
|
2487
|
+
queryBindings: zod_1.z.array(exports.QueryBindingSchema).optional(),
|
|
2488
|
+
actionBindings: zod_1.z.array(exports.ActionBindingSchema),
|
|
2489
|
+
pageAccessPolicy: exports.AccessPolicySchema,
|
|
2490
|
+
managementAccess: exports.ManagementAccessSchema,
|
|
2491
|
+
tokenRevisionRefs: zod_1.z.array(exports.RevisionRefSchema).min(1),
|
|
2492
|
+
performanceBudgetRef: exports.RevisionRefSchema,
|
|
2493
|
+
observationPolicyRevisionRef: exports.RevisionRefSchema,
|
|
2494
|
+
privacyClassification: zod_1.z.enum([
|
|
2495
|
+
"public",
|
|
2496
|
+
"internal",
|
|
2497
|
+
"confidential",
|
|
2498
|
+
"restricted",
|
|
2499
|
+
]),
|
|
2500
|
+
})
|
|
2501
|
+
.strict()
|
|
2502
|
+
.superRefine((value, context) => {
|
|
2503
|
+
validateDeclaredRouteSurfaces(value.supportedSurfaces, value.routeClaims, context);
|
|
2504
|
+
const routeStatePresentations = value.routeStatePresentations ?? [];
|
|
2505
|
+
if (uniqueArray(routeStatePresentations, (candidate) => `${candidate.surface}:${candidate.state}`)) {
|
|
2506
|
+
context.addIssue({
|
|
2507
|
+
code: "custom",
|
|
2508
|
+
path: ["routeStatePresentations"],
|
|
2509
|
+
message: "Page route-state presentations must be unique per surface and state.",
|
|
2510
|
+
});
|
|
2511
|
+
}
|
|
2512
|
+
routeStatePresentations.forEach((presentation, index) => {
|
|
2513
|
+
if (!value.supportedSurfaces.includes(presentation.surface)) {
|
|
2514
|
+
context.addIssue({
|
|
2515
|
+
code: "custom",
|
|
2516
|
+
path: ["routeStatePresentations", index, "surface"],
|
|
2517
|
+
message: "Page route-state presentation surface must be declared by supportedSurfaces.",
|
|
2518
|
+
});
|
|
2519
|
+
}
|
|
2520
|
+
});
|
|
2521
|
+
const stateDefinitions = value.stateDefinitions ?? [];
|
|
2522
|
+
const entryTransitions = value.entryTransitions ?? [];
|
|
2523
|
+
const interactionBindings = value.interactionBindings ?? [];
|
|
2524
|
+
const queryBindings = value.queryBindings ?? [];
|
|
2525
|
+
stateDefinitions.forEach((definition, index) => {
|
|
2526
|
+
const partitionStateId = definition.preferencePartitionStateId;
|
|
2527
|
+
const dynamicLegacySegments = definition.legacyBrowserPreferenceImport?.jsonPath?.filter((segment) => typeof segment !== "string") ?? [];
|
|
2528
|
+
if (!partitionStateId) {
|
|
2529
|
+
if (dynamicLegacySegments.length > 0) {
|
|
2530
|
+
context.addIssue({
|
|
2531
|
+
code: "custom",
|
|
2532
|
+
path: [
|
|
2533
|
+
"stateDefinitions",
|
|
2534
|
+
index,
|
|
2535
|
+
"legacyBrowserPreferenceImport",
|
|
2536
|
+
"jsonPath",
|
|
2537
|
+
],
|
|
2538
|
+
message: "A dynamic legacy preference path requires a declared preference partition state.",
|
|
2539
|
+
});
|
|
2540
|
+
}
|
|
2541
|
+
return;
|
|
2542
|
+
}
|
|
2543
|
+
const partitionDefinition = stateDefinitions.find((candidate) => candidate.stateId === partitionStateId);
|
|
2544
|
+
if (partitionStateId === definition.stateId ||
|
|
2545
|
+
!partitionDefinition ||
|
|
2546
|
+
partitionDefinition.preferencePartitionStateId) {
|
|
2547
|
+
context.addIssue({
|
|
2548
|
+
code: "custom",
|
|
2549
|
+
path: ["stateDefinitions", index, "preferencePartitionStateId"],
|
|
2550
|
+
message: "Preference partitioning must reference a distinct, non-partitioned Page state.",
|
|
2551
|
+
});
|
|
2552
|
+
}
|
|
2553
|
+
definition.legacyBrowserPreferenceImport?.jsonPath?.forEach((segment, segmentIndex) => {
|
|
2554
|
+
if (typeof segment !== "string" &&
|
|
2555
|
+
segment.stateId !== partitionStateId) {
|
|
2556
|
+
context.addIssue({
|
|
2557
|
+
code: "custom",
|
|
2558
|
+
path: [
|
|
2559
|
+
"stateDefinitions",
|
|
2560
|
+
index,
|
|
2561
|
+
"legacyBrowserPreferenceImport",
|
|
2562
|
+
"jsonPath",
|
|
2563
|
+
segmentIndex,
|
|
2564
|
+
],
|
|
2565
|
+
message: "A dynamic legacy preference path must use the declared preference partition state.",
|
|
2566
|
+
});
|
|
2567
|
+
}
|
|
2568
|
+
});
|
|
2569
|
+
});
|
|
2570
|
+
const uniqueness = [
|
|
2571
|
+
[
|
|
2572
|
+
"capabilityInstances",
|
|
2573
|
+
value.capabilityInstances,
|
|
2574
|
+
(candidate) => String(candidate.instanceId),
|
|
2575
|
+
],
|
|
2576
|
+
[
|
|
2577
|
+
"stateDefinitions",
|
|
2578
|
+
stateDefinitions,
|
|
2579
|
+
(candidate) => String(candidate.stateId),
|
|
2580
|
+
],
|
|
2581
|
+
[
|
|
2582
|
+
"entryTransitions",
|
|
2583
|
+
entryTransitions,
|
|
2584
|
+
(candidate) => String(candidate.transitionId),
|
|
2585
|
+
],
|
|
2586
|
+
[
|
|
2587
|
+
"interactionBindings",
|
|
2588
|
+
interactionBindings,
|
|
2589
|
+
(candidate) => String(candidate.bindingId),
|
|
2590
|
+
],
|
|
2591
|
+
[
|
|
2592
|
+
"ontologyBindings",
|
|
2593
|
+
value.ontologyBindings,
|
|
2594
|
+
(candidate) => String(candidate.bindingId),
|
|
2595
|
+
],
|
|
2596
|
+
[
|
|
2597
|
+
"queryBindings",
|
|
2598
|
+
queryBindings,
|
|
2599
|
+
(candidate) => String(candidate.bindingId),
|
|
2600
|
+
],
|
|
2601
|
+
[
|
|
2602
|
+
"actionBindings",
|
|
2603
|
+
value.actionBindings,
|
|
2604
|
+
(candidate) => String(candidate.bindingId),
|
|
2605
|
+
],
|
|
2606
|
+
];
|
|
2607
|
+
uniqueness.forEach(([field, values, identity]) => {
|
|
597
2608
|
if (uniqueArray(values, identity))
|
|
598
|
-
context.addIssue({
|
|
2609
|
+
context.addIssue({
|
|
2610
|
+
code: "custom",
|
|
2611
|
+
path: [field],
|
|
2612
|
+
message: `${field} identities must be unique.`,
|
|
2613
|
+
});
|
|
2614
|
+
});
|
|
2615
|
+
const instanceIds = new Set(value.capabilityInstances.map((instance) => instance.instanceId));
|
|
2616
|
+
const stateIds = new Set(stateDefinitions.map((state) => state.stateId));
|
|
2617
|
+
value.capabilityInstances.forEach((instance, index) => {
|
|
2618
|
+
const ports = new Set();
|
|
2619
|
+
const payloadPorts = new Set();
|
|
2620
|
+
instance.eventPayloadBindings?.forEach((binding, bindingIndex) => {
|
|
2621
|
+
const path = [
|
|
2622
|
+
"capabilityInstances",
|
|
2623
|
+
index,
|
|
2624
|
+
"eventPayloadBindings",
|
|
2625
|
+
bindingIndex,
|
|
2626
|
+
];
|
|
2627
|
+
if (payloadPorts.has(binding.port))
|
|
2628
|
+
context.addIssue({
|
|
2629
|
+
code: "custom",
|
|
2630
|
+
path,
|
|
2631
|
+
message: "An event payload can have only one declarative projection.",
|
|
2632
|
+
});
|
|
2633
|
+
payloadPorts.add(binding.port);
|
|
2634
|
+
for (const read of (0, page_expression_1.collectPageExpressionReads)(binding.expression)) {
|
|
2635
|
+
if (read.root === "actions" ||
|
|
2636
|
+
read.root === "result" ||
|
|
2637
|
+
(read.root === "state" && !stateIds.has(read.path[0] ?? "")) ||
|
|
2638
|
+
(read.root === "bindings" &&
|
|
2639
|
+
![...value.ontologyBindings, ...queryBindings].some((candidate) => candidate.bindingId === read.path[0])))
|
|
2640
|
+
context.addIssue({
|
|
2641
|
+
code: "custom",
|
|
2642
|
+
path,
|
|
2643
|
+
message: "Event payload projections require local event, model, scope, declared query results, or declared state.",
|
|
2644
|
+
});
|
|
2645
|
+
}
|
|
2646
|
+
});
|
|
2647
|
+
instance.eventEffects?.forEach((effect, effectIndex) => {
|
|
2648
|
+
const path = [
|
|
2649
|
+
"capabilityInstances",
|
|
2650
|
+
index,
|
|
2651
|
+
"eventEffects",
|
|
2652
|
+
effectIndex,
|
|
2653
|
+
];
|
|
2654
|
+
if (effect.sourceIntentSchemaRevisionRef.kind !== "schema" ||
|
|
2655
|
+
ports.has(effect.sourcePort))
|
|
2656
|
+
context.addIssue({
|
|
2657
|
+
code: "custom",
|
|
2658
|
+
path,
|
|
2659
|
+
message: "Event effects require one exact source schema per output port.",
|
|
2660
|
+
});
|
|
2661
|
+
ports.add(effect.sourcePort);
|
|
2662
|
+
if (value.actionBindings.some((binding) => binding.source.capabilityInstanceId === instance.instanceId &&
|
|
2663
|
+
binding.source.port === effect.sourcePort))
|
|
2664
|
+
context.addIssue({
|
|
2665
|
+
code: "custom",
|
|
2666
|
+
path,
|
|
2667
|
+
message: "An Action output port must declare refresh effects through Action.success.",
|
|
2668
|
+
});
|
|
2669
|
+
for (const id of effect.refreshBindingIds)
|
|
2670
|
+
if (![...value.ontologyBindings, ...queryBindings].some((binding) => binding.bindingId === id))
|
|
2671
|
+
context.addIssue({
|
|
2672
|
+
code: "custom",
|
|
2673
|
+
path,
|
|
2674
|
+
message: "Event effect references an unknown query binding.",
|
|
2675
|
+
});
|
|
2676
|
+
});
|
|
2677
|
+
});
|
|
2678
|
+
const repeatNodes = new Set(value.renderTree.nodes
|
|
2679
|
+
.filter((node) => node.repeat)
|
|
2680
|
+
.map((node) => node.nodeId));
|
|
2681
|
+
stateDefinitions.forEach((definition, index) => {
|
|
2682
|
+
if (definition.scopeNodeId && !repeatNodes.has(definition.scopeNodeId))
|
|
2683
|
+
context.addIssue({
|
|
2684
|
+
code: "custom",
|
|
2685
|
+
path: ["stateDefinitions", index, "scopeNodeId"],
|
|
2686
|
+
message: "Instance state must reference an existing repeated RenderNode.",
|
|
2687
|
+
});
|
|
2688
|
+
if (definition.initialValue && !definition.scopeNodeId) {
|
|
2689
|
+
const expression = definition.initialValue;
|
|
2690
|
+
const source = expression.kind === "read"
|
|
2691
|
+
? stateDefinitions.find((state) => state.stateId === expression.path[0] && !state.scopeNodeId)
|
|
2692
|
+
: undefined;
|
|
2693
|
+
if (!source ||
|
|
2694
|
+
source.initialValue ||
|
|
2695
|
+
!["tenant-preference", "url-with-tenant-preference"].includes(source.persistence))
|
|
2696
|
+
context.addIssue({
|
|
2697
|
+
code: "custom",
|
|
2698
|
+
path: ["stateDefinitions", index, "initialValue"],
|
|
2699
|
+
message: "Root initialization requires an independently hydrated tenant preference; initialization chains are forbidden.",
|
|
2700
|
+
});
|
|
2701
|
+
}
|
|
2702
|
+
if (definition.initialValue) {
|
|
2703
|
+
for (const read of (0, page_expression_1.collectPageExpressionReads)(definition.initialValue)) {
|
|
2704
|
+
if (!["scope", "state"].includes(read.root) ||
|
|
2705
|
+
(read.root === "state" &&
|
|
2706
|
+
!stateDefinitions.some((state) => state.stateId === read.path[0] && !state.scopeNodeId)))
|
|
2707
|
+
context.addIssue({
|
|
2708
|
+
code: "custom",
|
|
2709
|
+
path: ["stateDefinitions", index, "initialValue"],
|
|
2710
|
+
message: "Instance initial values can read only their item scope and declared Page state.",
|
|
2711
|
+
});
|
|
2712
|
+
}
|
|
2713
|
+
}
|
|
2714
|
+
});
|
|
2715
|
+
value.renderTree.nodes.forEach((node, index) => {
|
|
2716
|
+
if (!node.repeat)
|
|
2717
|
+
return;
|
|
2718
|
+
for (const read of (0, page_expression_1.collectPageExpressionReads)(node.repeat.source)) {
|
|
2719
|
+
if (read.root === "actions" ||
|
|
2720
|
+
read.root === "intent" ||
|
|
2721
|
+
read.root === "result" ||
|
|
2722
|
+
read.root === "model" ||
|
|
2723
|
+
(read.root === "state" && !stateIds.has(read.path[0] ?? "")) ||
|
|
2724
|
+
(read.root === "bindings" &&
|
|
2725
|
+
![...value.ontologyBindings, ...queryBindings].some((binding) => binding.bindingId === read.path[0])))
|
|
2726
|
+
context.addIssue({
|
|
2727
|
+
code: "custom",
|
|
2728
|
+
path: ["renderTree", "nodes", index, "repeat", "source"],
|
|
2729
|
+
message: "Repeated nodes require declared Page state, query results, or parent item scope.",
|
|
2730
|
+
});
|
|
2731
|
+
}
|
|
2732
|
+
});
|
|
2733
|
+
// A declaration can consume its own instance or ancestors, never an arbitrary sibling row.
|
|
2734
|
+
const renderNodesById = new Map(value.renderTree.nodes.map((node) => [node.nodeId, node]));
|
|
2735
|
+
const instanceNodes = new Map(value.capabilityInstances.map((instance) => [
|
|
2736
|
+
instance.instanceId,
|
|
2737
|
+
instance.nodeId,
|
|
2738
|
+
]));
|
|
2739
|
+
const scopesForNode = (nodeId) => {
|
|
2740
|
+
const scopes = new Set();
|
|
2741
|
+
const visited = new Set();
|
|
2742
|
+
let node = nodeId ? renderNodesById.get(nodeId) : undefined;
|
|
2743
|
+
while (node && !visited.has(node.nodeId)) {
|
|
2744
|
+
visited.add(node.nodeId);
|
|
2745
|
+
if (node.repeat)
|
|
2746
|
+
scopes.add(node.nodeId);
|
|
2747
|
+
node = node.parentNodeId
|
|
2748
|
+
? renderNodesById.get(node.parentNodeId)
|
|
2749
|
+
: undefined;
|
|
2750
|
+
}
|
|
2751
|
+
return scopes;
|
|
2752
|
+
};
|
|
2753
|
+
const queryOwners = new Map([...value.ontologyBindings, ...queryBindings].map((binding) => [
|
|
2754
|
+
binding.bindingId,
|
|
2755
|
+
[
|
|
2756
|
+
...scopesForNode(instanceNodes.get(binding.target.capabilityInstanceId)),
|
|
2757
|
+
][0],
|
|
2758
|
+
]));
|
|
2759
|
+
const actionScopes = new Map(value.actionBindings.map((binding) => [
|
|
2760
|
+
binding.bindingId,
|
|
2761
|
+
scopesForNode(instanceNodes.get(binding.source.capabilityInstanceId)),
|
|
2762
|
+
]));
|
|
2763
|
+
const actionOwners = new Map([...actionScopes].map(([id, scopes]) => [id, [...scopes][0]]));
|
|
2764
|
+
if (actionOwners.size !== value.actionBindings.length)
|
|
2765
|
+
context.addIssue({
|
|
2766
|
+
code: "custom",
|
|
2767
|
+
path: ["actionBindings"],
|
|
2768
|
+
message: "Action binding identifiers must be unique.",
|
|
2769
|
+
});
|
|
2770
|
+
const checkScopedReads = (reads, scopes, path) => {
|
|
2771
|
+
for (const read of reads) {
|
|
2772
|
+
const owner = read.root === "state"
|
|
2773
|
+
? stateDefinitions.find((state) => state.stateId === read.path[0])
|
|
2774
|
+
?.scopeNodeId
|
|
2775
|
+
: read.root === "bindings"
|
|
2776
|
+
? queryOwners.get(read.path[0])
|
|
2777
|
+
: read.root === "actions"
|
|
2778
|
+
? actionOwners.get(read.path[0])
|
|
2779
|
+
: undefined;
|
|
2780
|
+
// A parent may observe only aggregate pending for its descendant action scopes.
|
|
2781
|
+
// Error codes and individual row state remain scoped; unrelated repeat branches cannot aggregate.
|
|
2782
|
+
const pendingAggregate = read.root === "actions" &&
|
|
2783
|
+
read.path.length === 2 &&
|
|
2784
|
+
read.path[1] === "pending" &&
|
|
2785
|
+
actionScopes.has(read.path[0]) &&
|
|
2786
|
+
[...scopes].every((scope) => actionScopes.get(read.path[0]).has(scope));
|
|
2787
|
+
if (owner && !scopes.has(owner) && !pendingAggregate)
|
|
2788
|
+
context.addIssue({
|
|
2789
|
+
code: "custom",
|
|
2790
|
+
path,
|
|
2791
|
+
message: "A binding cannot read state, query results, or individual action status from a sibling or descendant instance.",
|
|
2792
|
+
});
|
|
2793
|
+
}
|
|
2794
|
+
};
|
|
2795
|
+
const checkScopedSources = (sources, scopes, path) => {
|
|
2796
|
+
Object.entries(sources).forEach(([name, source]) => {
|
|
2797
|
+
if (source.kind === "expression")
|
|
2798
|
+
checkScopedReads((0, page_expression_1.collectPageExpressionReads)(source.expression), scopes, [...path, name]);
|
|
2799
|
+
if (source.kind === "page-state")
|
|
2800
|
+
checkScopedReads([{ kind: "read", root: "state", path: [source.stateId] }], scopes, [...path, name]);
|
|
2801
|
+
if (source.kind === "binding-field")
|
|
2802
|
+
checkScopedReads([{ kind: "read", root: "bindings", path: [source.bindingId] }], scopes, [...path, name]);
|
|
2803
|
+
if (source.kind === "scope-field" && scopes.size === 0)
|
|
2804
|
+
context.addIssue({
|
|
2805
|
+
code: "custom",
|
|
2806
|
+
path: [...path, name],
|
|
2807
|
+
message: "A scope field requires a repeated instance.",
|
|
2808
|
+
});
|
|
2809
|
+
});
|
|
2810
|
+
};
|
|
2811
|
+
value.capabilityInstances.forEach((instance, index) => instance.eventPayloadBindings?.forEach((binding, bindingIndex) => checkScopedReads((0, page_expression_1.collectPageExpressionReads)(binding.expression), scopesForNode(instance.nodeId), ["capabilityInstances", index, "eventPayloadBindings", bindingIndex])));
|
|
2812
|
+
value.capabilityInstances.forEach((instance, index) => instance.propertyBindings?.forEach((binding, bindingIndex) => {
|
|
2813
|
+
checkScopedReads((0, page_expression_1.collectPageExpressionReads)(binding.expression), scopesForNode(instance.nodeId), ["capabilityInstances", index, "propertyBindings", bindingIndex]);
|
|
2814
|
+
}));
|
|
2815
|
+
for (const [collection, bindings] of [
|
|
2816
|
+
["ontologyBindings", value.ontologyBindings],
|
|
2817
|
+
["queryBindings", queryBindings],
|
|
2818
|
+
]) {
|
|
2819
|
+
bindings.forEach((binding, index) => checkScopedSources(binding.parameters, scopesForNode(instanceNodes.get(binding.target.capabilityInstanceId)), [collection, index, "parameters"]));
|
|
2820
|
+
}
|
|
2821
|
+
value.actionBindings.forEach((binding, index) => {
|
|
2822
|
+
const scopes = scopesForNode(instanceNodes.get(binding.source.capabilityInstanceId));
|
|
2823
|
+
checkScopedSources(binding.inputMapping, scopes, [
|
|
2824
|
+
"actionBindings",
|
|
2825
|
+
index,
|
|
2826
|
+
"inputMapping",
|
|
2827
|
+
]);
|
|
2828
|
+
for (const [fileIndex, file] of (binding.fileInputs ?? []).entries()) {
|
|
2829
|
+
if (file.source.kind === "page-state") {
|
|
2830
|
+
const stateId = file.source.stateId;
|
|
2831
|
+
const state = stateDefinitions.find((candidate) => candidate.stateId === stateId);
|
|
2832
|
+
if (!state || state.persistence !== "none")
|
|
2833
|
+
context.addIssue({
|
|
2834
|
+
code: "custom",
|
|
2835
|
+
path: ["actionBindings", index, "fileInputs", fileIndex],
|
|
2836
|
+
message: "File handles require declared nonpersistent Page state.",
|
|
2837
|
+
});
|
|
2838
|
+
checkScopedSources({ file: file.source }, scopes, [
|
|
2839
|
+
"actionBindings",
|
|
2840
|
+
index,
|
|
2841
|
+
"fileInputs",
|
|
2842
|
+
fileIndex,
|
|
2843
|
+
]);
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
if (binding.when) {
|
|
2847
|
+
const reads = (0, page_expression_1.collectPageExpressionReads)(binding.when);
|
|
2848
|
+
checkScopedReads(reads, scopes, ["actionBindings", index, "when"]);
|
|
2849
|
+
for (const read of reads)
|
|
2850
|
+
if (read.root === "state" && !stateIds.has(read.path[0]))
|
|
2851
|
+
context.addIssue({
|
|
2852
|
+
code: "custom",
|
|
2853
|
+
path: ["actionBindings", index, "when"],
|
|
2854
|
+
message: "Action condition references an unknown Page state.",
|
|
2855
|
+
});
|
|
2856
|
+
}
|
|
2857
|
+
});
|
|
2858
|
+
interactionBindings.forEach((binding, index) => {
|
|
2859
|
+
const sourceScopes = scopesForNode(instanceNodes.get(binding.source.capabilityInstanceId));
|
|
2860
|
+
const targetScope = stateDefinitions.find((state) => state.stateId === binding.targetStateId)?.scopeNodeId;
|
|
2861
|
+
if (targetScope && !sourceScopes.has(targetScope))
|
|
2862
|
+
context.addIssue({
|
|
2863
|
+
code: "custom",
|
|
2864
|
+
path: ["interactionBindings", index, "targetStateId"],
|
|
2865
|
+
message: "An interaction must target its own instance or an ancestor.",
|
|
2866
|
+
});
|
|
2867
|
+
checkScopedSources(binding.inputMapping, targetScope ? scopesForNode(targetScope) : new Set(), ["interactionBindings", index, "inputMapping"]);
|
|
2868
|
+
});
|
|
2869
|
+
value.renderTree.nodes.forEach((node, index) => {
|
|
2870
|
+
if (node.repeat)
|
|
2871
|
+
checkScopedReads((0, page_expression_1.collectPageExpressionReads)(node.repeat.source), scopesForNode(node.parentNodeId), ["renderTree", "nodes", index, "repeat", "source"]);
|
|
2872
|
+
});
|
|
2873
|
+
entryTransitions.forEach((transition, transitionIndex) => {
|
|
2874
|
+
if (transition.gestureSource &&
|
|
2875
|
+
(!instanceIds.has(transition.gestureSource.capabilityInstanceId) ||
|
|
2876
|
+
!interactionBindings.some((binding) => binding.source.capabilityInstanceId ===
|
|
2877
|
+
transition.gestureSource.capabilityInstanceId &&
|
|
2878
|
+
binding.source.port === transition.gestureSource.port))) {
|
|
2879
|
+
context.addIssue({
|
|
2880
|
+
code: "custom",
|
|
2881
|
+
path: ["entryTransitions", transitionIndex, "gestureSource"],
|
|
2882
|
+
message: "Entry gesture source must match an existing capability interaction source.",
|
|
2883
|
+
});
|
|
2884
|
+
}
|
|
2885
|
+
if (transition.targetRef.kind === "page" &&
|
|
2886
|
+
transition.targetRef.id === value.pageId) {
|
|
2887
|
+
context.addIssue({
|
|
2888
|
+
code: "custom",
|
|
2889
|
+
path: ["entryTransitions", transitionIndex, "targetRef"],
|
|
2890
|
+
message: "A Page cannot route into itself on entry.",
|
|
2891
|
+
});
|
|
2892
|
+
}
|
|
2893
|
+
forEachPageStateCondition(transition.activation, (condition, conditionPath) => {
|
|
2894
|
+
if (!stateIds.has(condition.stateId)) {
|
|
2895
|
+
context.addIssue({
|
|
2896
|
+
code: "custom",
|
|
2897
|
+
path: [
|
|
2898
|
+
"entryTransitions",
|
|
2899
|
+
transitionIndex,
|
|
2900
|
+
"activation",
|
|
2901
|
+
...conditionPath,
|
|
2902
|
+
"stateId",
|
|
2903
|
+
],
|
|
2904
|
+
message: `Entry transition references unknown Page state ${condition.stateId}.`,
|
|
2905
|
+
});
|
|
2906
|
+
}
|
|
2907
|
+
});
|
|
2908
|
+
const declaredRouteParameters = new Set(value.routeClaims.flatMap((claim) => [...claim.pathTemplate.matchAll(/:([A-Za-z][A-Za-z0-9_-]*)/g)].map((match) => match[1])));
|
|
2909
|
+
for (const source of [
|
|
2910
|
+
...Object.values(transition.pathParameters),
|
|
2911
|
+
...Object.values(transition.query.set),
|
|
2912
|
+
]) {
|
|
2913
|
+
if (source.kind === "route-parameter" &&
|
|
2914
|
+
!declaredRouteParameters.has(source.name)) {
|
|
2915
|
+
context.addIssue({
|
|
2916
|
+
code: "custom",
|
|
2917
|
+
path: ["entryTransitions", transitionIndex],
|
|
2918
|
+
message: `Entry transition references unknown source route parameter ${source.name}.`,
|
|
2919
|
+
});
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
const stateSources = [
|
|
2923
|
+
...Object.values(transition.pathParameters).flatMap((source) => source.kind === "page-state" ? [source.stateId] : []),
|
|
2924
|
+
...Object.values(transition.query.set).flatMap((source) => source.kind === "page-state" ? [source.stateId] : []),
|
|
2925
|
+
];
|
|
2926
|
+
stateSources.forEach((stateId) => {
|
|
2927
|
+
if (!stateIds.has(stateId)) {
|
|
2928
|
+
context.addIssue({
|
|
2929
|
+
code: "custom",
|
|
2930
|
+
path: ["entryTransitions", transitionIndex],
|
|
2931
|
+
message: `Entry transition references unknown Page state ${stateId}.`,
|
|
2932
|
+
});
|
|
2933
|
+
}
|
|
2934
|
+
});
|
|
2935
|
+
});
|
|
2936
|
+
const validatePageStateSources = (sources, path) => {
|
|
2937
|
+
Object.entries(sources).forEach(([name, source]) => {
|
|
2938
|
+
if (source.kind === "expression") {
|
|
2939
|
+
for (const read of (0, page_expression_1.collectPageExpressionReads)(source.expression)) {
|
|
2940
|
+
if ((read.root === "state" &&
|
|
2941
|
+
(!read.path[0] || !stateIds.has(read.path[0]))) ||
|
|
2942
|
+
read.root === "model" ||
|
|
2943
|
+
read.root === "bindings" ||
|
|
2944
|
+
(read.root === "result" && path[0] !== "interactionBindings")) {
|
|
2945
|
+
context.addIssue({
|
|
2946
|
+
code: "custom",
|
|
2947
|
+
path: [...path, name, "expression"],
|
|
2948
|
+
message: "Expression references unavailable context or an undeclared Page state.",
|
|
2949
|
+
});
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
if (source.kind === "page-state" && !stateIds.has(source.stateId)) {
|
|
2954
|
+
context.addIssue({
|
|
2955
|
+
code: "custom",
|
|
2956
|
+
path: [...path, name, "stateId"],
|
|
2957
|
+
message: `Unknown Page state: ${source.stateId}`,
|
|
2958
|
+
});
|
|
2959
|
+
}
|
|
2960
|
+
});
|
|
2961
|
+
};
|
|
2962
|
+
interactionBindings.forEach((binding, index) => {
|
|
2963
|
+
if (!instanceIds.has(binding.source.capabilityInstanceId)) {
|
|
2964
|
+
context.addIssue({
|
|
2965
|
+
code: "custom",
|
|
2966
|
+
path: [
|
|
2967
|
+
"interactionBindings",
|
|
2968
|
+
index,
|
|
2969
|
+
"source",
|
|
2970
|
+
"capabilityInstanceId",
|
|
2971
|
+
],
|
|
2972
|
+
message: "Interaction binding sources an unknown capability instance.",
|
|
2973
|
+
});
|
|
2974
|
+
}
|
|
2975
|
+
if (!stateIds.has(binding.targetStateId)) {
|
|
2976
|
+
context.addIssue({
|
|
2977
|
+
code: "custom",
|
|
2978
|
+
path: ["interactionBindings", index, "targetStateId"],
|
|
2979
|
+
message: "Interaction binding targets an unknown Page state.",
|
|
2980
|
+
});
|
|
2981
|
+
}
|
|
2982
|
+
validatePageStateSources(binding.inputMapping, [
|
|
2983
|
+
"interactionBindings",
|
|
2984
|
+
index,
|
|
2985
|
+
"inputMapping",
|
|
2986
|
+
]);
|
|
2987
|
+
if (Object.values(binding.inputMapping).some((source) => source.kind === "result-field" ||
|
|
2988
|
+
(source.kind === "expression" &&
|
|
2989
|
+
(0, page_expression_1.collectPageExpressionReads)(source.expression).some((read) => read.root === "result")))) {
|
|
2990
|
+
const action = value.actionBindings.find((candidate) => candidate.source.capabilityInstanceId ===
|
|
2991
|
+
binding.source.capabilityInstanceId &&
|
|
2992
|
+
candidate.source.port === binding.source.port);
|
|
2993
|
+
if (!action) {
|
|
2994
|
+
context.addIssue({
|
|
2995
|
+
code: "custom",
|
|
2996
|
+
path: ["interactionBindings", index, "source"],
|
|
2997
|
+
message: "Result-field interactions must source one declared Action binding.",
|
|
2998
|
+
});
|
|
2999
|
+
}
|
|
3000
|
+
else if (!binding.sourceResultSchemaRevisionRef ||
|
|
3001
|
+
!exactRevisionRef(binding.sourceResultSchemaRevisionRef, action.resultSchemaRevisionRef)) {
|
|
3002
|
+
context.addIssue({
|
|
3003
|
+
code: "custom",
|
|
3004
|
+
path: [
|
|
3005
|
+
"interactionBindings",
|
|
3006
|
+
index,
|
|
3007
|
+
"sourceResultSchemaRevisionRef",
|
|
3008
|
+
],
|
|
3009
|
+
message: "Interaction result schema must exactly match the sourced Action result schema.",
|
|
3010
|
+
});
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
});
|
|
3014
|
+
value.capabilityInstances.forEach((instance, index) => {
|
|
3015
|
+
const paths = [];
|
|
3016
|
+
instance.propertyBindings?.forEach((binding, bindingIndex) => {
|
|
3017
|
+
const path = [
|
|
3018
|
+
"capabilityInstances",
|
|
3019
|
+
index,
|
|
3020
|
+
"propertyBindings",
|
|
3021
|
+
bindingIndex,
|
|
3022
|
+
];
|
|
3023
|
+
if (instance.capabilityRevisionRef.id.startsWith("monkeys.design.component.")) {
|
|
3024
|
+
const [group, member, field] = binding.targetPath;
|
|
3025
|
+
const messages = instance.properties.messages;
|
|
3026
|
+
const message = messages && typeof messages === "object" && !Array.isArray(messages)
|
|
3027
|
+
? messages[member]
|
|
3028
|
+
: undefined;
|
|
3029
|
+
const declaredMessage = message && typeof message === "object" && !Array.isArray(message);
|
|
3030
|
+
const allowed = (group === "props" && binding.targetPath.length >= 2) ||
|
|
3031
|
+
(group === "messages" &&
|
|
3032
|
+
declaredMessage &&
|
|
3033
|
+
((field === "values" && binding.targetPath.length >= 3) ||
|
|
3034
|
+
(binding.targetPath.length === 3 &&
|
|
3035
|
+
(field === "key" || field === "textI18n") &&
|
|
3036
|
+
Object.prototype.hasOwnProperty.call(message, field))));
|
|
3037
|
+
if (!allowed)
|
|
3038
|
+
context.addIssue({
|
|
3039
|
+
code: "custom",
|
|
3040
|
+
path: [...path, "targetPath"],
|
|
3041
|
+
message: "Component expressions can update property values or declared message fields, never executable wiring.",
|
|
3042
|
+
});
|
|
3043
|
+
}
|
|
3044
|
+
if (paths.some((previous) => previous
|
|
3045
|
+
.slice(0, Math.min(previous.length, binding.targetPath.length))
|
|
3046
|
+
.every((key, i) => key === binding.targetPath[i]))) {
|
|
3047
|
+
context.addIssue({
|
|
3048
|
+
code: "custom",
|
|
3049
|
+
path: [...path, "targetPath"],
|
|
3050
|
+
message: "Dynamic property targets must not overlap.",
|
|
3051
|
+
});
|
|
3052
|
+
}
|
|
3053
|
+
paths.push(binding.targetPath);
|
|
3054
|
+
(0, page_expression_1.visitPageExpression)(binding.expression, (expression) => {
|
|
3055
|
+
if (expression.kind !== "read")
|
|
3056
|
+
return;
|
|
3057
|
+
if (expression.root === "state" &&
|
|
3058
|
+
(!expression.path[0] || !stateIds.has(expression.path[0]))) {
|
|
3059
|
+
context.addIssue({
|
|
3060
|
+
code: "custom",
|
|
3061
|
+
path: [...path, "expression"],
|
|
3062
|
+
message: "Property expressions must reference a declared Page state.",
|
|
3063
|
+
});
|
|
3064
|
+
}
|
|
3065
|
+
if (expression.root === "bindings" &&
|
|
3066
|
+
![...value.ontologyBindings, ...queryBindings].some((candidate) => candidate.bindingId === expression.path[0])) {
|
|
3067
|
+
context.addIssue({
|
|
3068
|
+
code: "custom",
|
|
3069
|
+
path: [...path, "expression"],
|
|
3070
|
+
message: "Property expressions must reference a declared Page query binding.",
|
|
3071
|
+
});
|
|
3072
|
+
}
|
|
3073
|
+
if (expression.root === "actions" &&
|
|
3074
|
+
(expression.path.length !== 2 ||
|
|
3075
|
+
!actionOwners.has(expression.path[0]) ||
|
|
3076
|
+
!["pending", "errorCode"].includes(expression.path[1]))) {
|
|
3077
|
+
context.addIssue({
|
|
3078
|
+
code: "custom",
|
|
3079
|
+
path: [...path, "expression"],
|
|
3080
|
+
message: "Property expressions may read only pending or errorCode from a declared Action binding.",
|
|
3081
|
+
});
|
|
3082
|
+
}
|
|
3083
|
+
if (expression.root === "intent" || expression.root === "result") {
|
|
3084
|
+
context.addIssue({
|
|
3085
|
+
code: "custom",
|
|
3086
|
+
path: [...path, "expression"],
|
|
3087
|
+
message: "Property expressions cannot read transient event or Action results.",
|
|
3088
|
+
});
|
|
3089
|
+
}
|
|
3090
|
+
});
|
|
3091
|
+
});
|
|
3092
|
+
if (!instance.activationWhen)
|
|
3093
|
+
return;
|
|
3094
|
+
forEachPageStateCondition(instance.activationWhen, (condition, conditionPath) => {
|
|
3095
|
+
if (!stateIds.has(condition.stateId)) {
|
|
3096
|
+
context.addIssue({
|
|
3097
|
+
code: "custom",
|
|
3098
|
+
path: [
|
|
3099
|
+
"capabilityInstances",
|
|
3100
|
+
index,
|
|
3101
|
+
"activationWhen",
|
|
3102
|
+
...conditionPath,
|
|
3103
|
+
"stateId",
|
|
3104
|
+
],
|
|
3105
|
+
message: "Capability activation condition references an unknown Page state.",
|
|
3106
|
+
});
|
|
3107
|
+
}
|
|
3108
|
+
});
|
|
599
3109
|
});
|
|
600
|
-
const instanceIds = new Set(value.capabilityInstances.map((instance) => instance.instanceId));
|
|
601
3110
|
value.ontologyBindings.forEach((binding, index) => {
|
|
602
3111
|
if (!instanceIds.has(binding.target.capabilityInstanceId)) {
|
|
603
|
-
context.addIssue({
|
|
3112
|
+
context.addIssue({
|
|
3113
|
+
code: "custom",
|
|
3114
|
+
path: ["ontologyBindings", index, "target", "capabilityInstanceId"],
|
|
3115
|
+
message: "Ontology binding targets an unknown capability instance.",
|
|
3116
|
+
});
|
|
3117
|
+
}
|
|
3118
|
+
validatePageStateSources(binding.parameters, [
|
|
3119
|
+
"ontologyBindings",
|
|
3120
|
+
index,
|
|
3121
|
+
"parameters",
|
|
3122
|
+
]);
|
|
3123
|
+
});
|
|
3124
|
+
queryBindings.forEach((binding, index) => {
|
|
3125
|
+
if (!instanceIds.has(binding.target.capabilityInstanceId)) {
|
|
3126
|
+
context.addIssue({
|
|
3127
|
+
code: "custom",
|
|
3128
|
+
path: ["queryBindings", index, "target", "capabilityInstanceId"],
|
|
3129
|
+
message: "Query binding targets an unknown capability instance.",
|
|
3130
|
+
});
|
|
3131
|
+
}
|
|
3132
|
+
validatePageStateSources(binding.parameters, [
|
|
3133
|
+
"queryBindings",
|
|
3134
|
+
index,
|
|
3135
|
+
"parameters",
|
|
3136
|
+
]);
|
|
3137
|
+
if (binding.queryWhen) {
|
|
3138
|
+
forEachPageStateCondition(binding.queryWhen, (condition, conditionPath) => {
|
|
3139
|
+
if (!stateIds.has(condition.stateId)) {
|
|
3140
|
+
context.addIssue({
|
|
3141
|
+
code: "custom",
|
|
3142
|
+
path: [
|
|
3143
|
+
"queryBindings",
|
|
3144
|
+
index,
|
|
3145
|
+
"queryWhen",
|
|
3146
|
+
...conditionPath,
|
|
3147
|
+
"stateId",
|
|
3148
|
+
],
|
|
3149
|
+
message: "Query activation condition references an unknown Page state.",
|
|
3150
|
+
});
|
|
3151
|
+
}
|
|
3152
|
+
});
|
|
3153
|
+
}
|
|
3154
|
+
if (binding.refreshPolicy?.when) {
|
|
3155
|
+
const path = ["queryBindings", index, "refreshPolicy", "when"];
|
|
3156
|
+
const reads = (0, page_expression_1.collectExternalPageExpressionReads)(binding.refreshPolicy.when);
|
|
3157
|
+
checkScopedReads(reads, scopesForNode(instanceNodes.get(binding.target.capabilityInstanceId)), path);
|
|
3158
|
+
for (const read of reads)
|
|
3159
|
+
if (read.root === "actions" && !actionScopes.has(read.path[0]))
|
|
3160
|
+
context.addIssue({
|
|
3161
|
+
code: "custom",
|
|
3162
|
+
path,
|
|
3163
|
+
message: "Automatic refresh condition references an unknown action binding.",
|
|
3164
|
+
});
|
|
3165
|
+
}
|
|
3166
|
+
const effectOwners = new Set(binding.stateEffects?.map((effect) => stateDefinitions.find((definition) => definition.stateId === effect.targetStateId)?.scopeNodeId ?? "") ?? []);
|
|
3167
|
+
if (effectOwners.size > 1)
|
|
3168
|
+
context.addIssue({
|
|
3169
|
+
code: "custom",
|
|
3170
|
+
path: ["queryBindings", index, "stateEffects"],
|
|
3171
|
+
message: "A query completion must update a single state owner atomically.",
|
|
3172
|
+
});
|
|
3173
|
+
binding.stateEffects?.forEach((effect, effectIndex) => {
|
|
3174
|
+
const path = ["queryBindings", index, "stateEffects", effectIndex];
|
|
3175
|
+
const state = stateDefinitions.find((definition) => definition.stateId === effect.targetStateId);
|
|
3176
|
+
const scopes = scopesForNode(instanceNodes.get(binding.target.capabilityInstanceId));
|
|
3177
|
+
if (!state || (state.scopeNodeId && !scopes.has(state.scopeNodeId)))
|
|
3178
|
+
context.addIssue({
|
|
3179
|
+
code: "custom",
|
|
3180
|
+
path: [...path, "targetStateId"],
|
|
3181
|
+
message: "A query effect must target declared state in its own scope or an ancestor.",
|
|
3182
|
+
});
|
|
3183
|
+
for (const expression of [
|
|
3184
|
+
effect.value,
|
|
3185
|
+
...(effect.when ? [effect.when] : []),
|
|
3186
|
+
]) {
|
|
3187
|
+
const reads = (0, page_expression_1.collectPageExpressionReads)(expression);
|
|
3188
|
+
checkScopedReads(reads, state?.scopeNodeId ? scopesForNode(state.scopeNodeId) : new Set(), path);
|
|
3189
|
+
for (const read of reads)
|
|
3190
|
+
if (read.root === "state" && !stateIds.has(read.path[0]))
|
|
3191
|
+
context.addIssue({
|
|
3192
|
+
code: "custom",
|
|
3193
|
+
path,
|
|
3194
|
+
message: "Query effect references an unknown Page state.",
|
|
3195
|
+
});
|
|
3196
|
+
}
|
|
3197
|
+
});
|
|
3198
|
+
binding.resultStateBindings?.forEach((resultBinding, resultIndex) => {
|
|
3199
|
+
const stateDefinition = stateDefinitions.find((definition) => definition.stateId === resultBinding.targetStateId);
|
|
3200
|
+
if (!stateDefinition) {
|
|
3201
|
+
context.addIssue({
|
|
3202
|
+
code: "custom",
|
|
3203
|
+
path: [
|
|
3204
|
+
"queryBindings",
|
|
3205
|
+
index,
|
|
3206
|
+
"resultStateBindings",
|
|
3207
|
+
resultIndex,
|
|
3208
|
+
"targetStateId",
|
|
3209
|
+
],
|
|
3210
|
+
message: "Query result binding targets an unknown Page state.",
|
|
3211
|
+
});
|
|
3212
|
+
return;
|
|
3213
|
+
}
|
|
3214
|
+
if (!exactRevisionRef(resultBinding.targetStateSchemaRevisionRef, stateDefinition.schemaRevisionRef)) {
|
|
3215
|
+
context.addIssue({
|
|
3216
|
+
code: "custom",
|
|
3217
|
+
path: [
|
|
3218
|
+
"queryBindings",
|
|
3219
|
+
index,
|
|
3220
|
+
"resultStateBindings",
|
|
3221
|
+
resultIndex,
|
|
3222
|
+
"targetStateSchemaRevisionRef",
|
|
3223
|
+
],
|
|
3224
|
+
message: "Query result binding must pin the exact target Page-state schema revision.",
|
|
3225
|
+
});
|
|
3226
|
+
}
|
|
3227
|
+
if (stateDefinition.persistence !== "none") {
|
|
3228
|
+
context.addIssue({
|
|
3229
|
+
code: "custom",
|
|
3230
|
+
path: [
|
|
3231
|
+
"queryBindings",
|
|
3232
|
+
index,
|
|
3233
|
+
"resultStateBindings",
|
|
3234
|
+
resultIndex,
|
|
3235
|
+
"targetStateId",
|
|
3236
|
+
],
|
|
3237
|
+
message: "Query result state projections must target non-persistent Page state.",
|
|
3238
|
+
});
|
|
3239
|
+
}
|
|
3240
|
+
});
|
|
3241
|
+
});
|
|
3242
|
+
const dependencyBindings = [...value.ontologyBindings, ...queryBindings];
|
|
3243
|
+
(0, page_binding_dependencies_1.analyzePageBindingDependencies)(dependencyBindings).errors.forEach((error) => {
|
|
3244
|
+
const ontologyIndex = value.ontologyBindings.findIndex((binding) => binding.bindingId === error.bindingId);
|
|
3245
|
+
const collection = ontologyIndex >= 0 ? "ontologyBindings" : "queryBindings";
|
|
3246
|
+
const index = ontologyIndex >= 0
|
|
3247
|
+
? ontologyIndex
|
|
3248
|
+
: queryBindings.findIndex((binding) => binding.bindingId === error.bindingId);
|
|
3249
|
+
context.addIssue({
|
|
3250
|
+
code: "custom",
|
|
3251
|
+
path: [collection, index, "parameters"],
|
|
3252
|
+
message: `Page binding dependency ${error.code}: ${error.dependencyId ?? error.bindingId}`,
|
|
3253
|
+
});
|
|
3254
|
+
});
|
|
3255
|
+
const projectedQueryStateIds = new Set();
|
|
3256
|
+
queryBindings.forEach((binding, index) => {
|
|
3257
|
+
binding.resultStateBindings?.forEach((resultBinding, resultIndex) => {
|
|
3258
|
+
if (projectedQueryStateIds.has(resultBinding.targetStateId)) {
|
|
3259
|
+
context.addIssue({
|
|
3260
|
+
code: "custom",
|
|
3261
|
+
path: [
|
|
3262
|
+
"queryBindings",
|
|
3263
|
+
index,
|
|
3264
|
+
"resultStateBindings",
|
|
3265
|
+
resultIndex,
|
|
3266
|
+
"targetStateId",
|
|
3267
|
+
],
|
|
3268
|
+
message: "One Page state can have only one Server Query result owner.",
|
|
3269
|
+
});
|
|
3270
|
+
}
|
|
3271
|
+
projectedQueryStateIds.add(resultBinding.targetStateId);
|
|
3272
|
+
});
|
|
3273
|
+
});
|
|
3274
|
+
queryBindings.forEach((binding, index) => {
|
|
3275
|
+
if (binding.execution !== "server")
|
|
3276
|
+
return;
|
|
3277
|
+
const readStateIds = new Set(Object.values(binding.parameters).flatMap((source) => source.kind === "page-state" ? [source.stateId] : []));
|
|
3278
|
+
if (binding.queryWhen) {
|
|
3279
|
+
forEachPageStateCondition(binding.queryWhen, (condition) => readStateIds.add(condition.stateId));
|
|
3280
|
+
}
|
|
3281
|
+
const feedbackStateId = [...readStateIds].find((stateId) => projectedQueryStateIds.has(stateId));
|
|
3282
|
+
if (feedbackStateId) {
|
|
3283
|
+
context.addIssue({
|
|
3284
|
+
code: "custom",
|
|
3285
|
+
path: ["queryBindings", index],
|
|
3286
|
+
message: `Server Query bindings cannot read projected Query result state: ${feedbackStateId}`,
|
|
3287
|
+
});
|
|
3288
|
+
}
|
|
3289
|
+
});
|
|
3290
|
+
const cursorWindowBindings = [
|
|
3291
|
+
...value.ontologyBindings.map((binding, index) => ({
|
|
3292
|
+
binding,
|
|
3293
|
+
index,
|
|
3294
|
+
collection: "ontologyBindings",
|
|
3295
|
+
})),
|
|
3296
|
+
...queryBindings.map((binding, index) => ({
|
|
3297
|
+
binding,
|
|
3298
|
+
index,
|
|
3299
|
+
collection: "queryBindings",
|
|
3300
|
+
})),
|
|
3301
|
+
].filter((candidate) => candidate.binding.cursorWindow !== undefined);
|
|
3302
|
+
const cursorWindowSources = new Set();
|
|
3303
|
+
cursorWindowBindings.forEach(({ binding, index, collection }) => {
|
|
3304
|
+
const sourceId = binding.cursorWindow.sourceCapabilityInstanceId ??
|
|
3305
|
+
binding.target.capabilityInstanceId;
|
|
3306
|
+
if (!instanceIds.has(sourceId))
|
|
3307
|
+
context.addIssue({
|
|
3308
|
+
code: "custom",
|
|
3309
|
+
path: [
|
|
3310
|
+
collection,
|
|
3311
|
+
index,
|
|
3312
|
+
"cursorWindow",
|
|
3313
|
+
"sourceCapabilityInstanceId",
|
|
3314
|
+
],
|
|
3315
|
+
message: "Cursor-window source must reference a declared capability instance.",
|
|
3316
|
+
});
|
|
3317
|
+
const sourceScopes = [...scopesForNode(instanceNodes.get(sourceId))];
|
|
3318
|
+
const targetScopes = [
|
|
3319
|
+
...scopesForNode(instanceNodes.get(binding.target.capabilityInstanceId)),
|
|
3320
|
+
];
|
|
3321
|
+
if (sourceScopes.length !== targetScopes.length ||
|
|
3322
|
+
sourceScopes.some((id, index) => id !== targetScopes[index]))
|
|
3323
|
+
context.addIssue({
|
|
3324
|
+
code: "custom",
|
|
3325
|
+
path: [
|
|
3326
|
+
collection,
|
|
3327
|
+
index,
|
|
3328
|
+
"cursorWindow",
|
|
3329
|
+
"sourceCapabilityInstanceId",
|
|
3330
|
+
],
|
|
3331
|
+
message: "Cursor-window source and query target must share the same repeated scope.",
|
|
3332
|
+
});
|
|
3333
|
+
const sourceKey = `${sourceId}:${binding.cursorWindow.pageChangePort}`;
|
|
3334
|
+
if (cursorWindowSources.has(sourceKey)) {
|
|
3335
|
+
context.addIssue({
|
|
3336
|
+
code: "custom",
|
|
3337
|
+
path: [collection, index, "cursorWindow", "pageChangePort"],
|
|
3338
|
+
message: "A capability output port can govern at most one cursor-window binding.",
|
|
3339
|
+
});
|
|
3340
|
+
}
|
|
3341
|
+
cursorWindowSources.add(sourceKey);
|
|
3342
|
+
const conflictingInteraction = interactionBindings.some((candidate) => candidate.source.capabilityInstanceId === sourceId &&
|
|
3343
|
+
candidate.source.port === binding.cursorWindow.pageChangePort);
|
|
3344
|
+
const conflictingAction = value.actionBindings.some((candidate) => candidate.source.capabilityInstanceId === sourceId &&
|
|
3345
|
+
candidate.source.port === binding.cursorWindow.pageChangePort);
|
|
3346
|
+
if (conflictingInteraction || conflictingAction) {
|
|
3347
|
+
context.addIssue({
|
|
3348
|
+
code: "custom",
|
|
3349
|
+
path: [collection, index, "cursorWindow", "pageChangePort"],
|
|
3350
|
+
message: "Cursor-window page-change ports cannot also drive Page state or Domain Actions.",
|
|
3351
|
+
});
|
|
604
3352
|
}
|
|
605
3353
|
});
|
|
606
3354
|
value.actionBindings.forEach((binding, index) => {
|
|
607
3355
|
if (!instanceIds.has(binding.source.capabilityInstanceId)) {
|
|
608
|
-
context.addIssue({
|
|
3356
|
+
context.addIssue({
|
|
3357
|
+
code: "custom",
|
|
3358
|
+
path: ["actionBindings", index, "source", "capabilityInstanceId"],
|
|
3359
|
+
message: "Action binding sources an unknown capability instance.",
|
|
3360
|
+
});
|
|
609
3361
|
}
|
|
3362
|
+
validatePageStateSources(binding.inputMapping, [
|
|
3363
|
+
"actionBindings",
|
|
3364
|
+
index,
|
|
3365
|
+
"inputMapping",
|
|
3366
|
+
]);
|
|
610
3367
|
binding.success.refreshBindingIds.forEach((bindingId) => {
|
|
611
|
-
if (!value.ontologyBindings.some((candidate) => candidate.bindingId === bindingId)
|
|
612
|
-
|
|
3368
|
+
if (!value.ontologyBindings.some((candidate) => candidate.bindingId === bindingId) &&
|
|
3369
|
+
!queryBindings.some((candidate) => candidate.bindingId === bindingId)) {
|
|
3370
|
+
context.addIssue({
|
|
3371
|
+
code: "custom",
|
|
3372
|
+
path: ["actionBindings", index, "success", "refreshBindingIds"],
|
|
3373
|
+
message: `Unknown refresh binding: ${bindingId}`,
|
|
3374
|
+
});
|
|
613
3375
|
}
|
|
614
3376
|
});
|
|
3377
|
+
const effectBindingIds = binding.success.resultBindingEffects?.map((effect) => effect.bindingId) ?? [];
|
|
3378
|
+
if (new Set(effectBindingIds).size !== effectBindingIds.length) {
|
|
3379
|
+
context.addIssue({
|
|
3380
|
+
code: "custom",
|
|
3381
|
+
path: ["actionBindings", index, "success", "resultBindingEffects"],
|
|
3382
|
+
message: "An Action can declare at most one result effect for each target binding.",
|
|
3383
|
+
});
|
|
3384
|
+
}
|
|
3385
|
+
binding.success.resultBindingEffects?.forEach((effect, effectIndex) => {
|
|
3386
|
+
if (!value.ontologyBindings.some((candidate) => candidate.bindingId === effect.bindingId) &&
|
|
3387
|
+
!queryBindings.some((candidate) => candidate.bindingId === effect.bindingId)) {
|
|
3388
|
+
context.addIssue({
|
|
3389
|
+
code: "custom",
|
|
3390
|
+
path: [
|
|
3391
|
+
"actionBindings",
|
|
3392
|
+
index,
|
|
3393
|
+
"success",
|
|
3394
|
+
"resultBindingEffects",
|
|
3395
|
+
effectIndex,
|
|
3396
|
+
"bindingId",
|
|
3397
|
+
],
|
|
3398
|
+
message: `Unknown result effect binding: ${effect.bindingId}`,
|
|
3399
|
+
});
|
|
3400
|
+
}
|
|
3401
|
+
if (binding.success.refreshBindingIds.includes(effect.bindingId)) {
|
|
3402
|
+
context.addIssue({
|
|
3403
|
+
code: "custom",
|
|
3404
|
+
path: [
|
|
3405
|
+
"actionBindings",
|
|
3406
|
+
index,
|
|
3407
|
+
"success",
|
|
3408
|
+
"resultBindingEffects",
|
|
3409
|
+
effectIndex,
|
|
3410
|
+
"bindingId",
|
|
3411
|
+
],
|
|
3412
|
+
message: "A result-projected binding cannot also be refreshed by the same Action.",
|
|
3413
|
+
});
|
|
3414
|
+
}
|
|
3415
|
+
});
|
|
3416
|
+
if (binding.success.clipboard) {
|
|
3417
|
+
const sourceInstance = value.capabilityInstances.find((instance) => instance.instanceId === binding.source.capabilityInstanceId);
|
|
3418
|
+
if (!sourceInstance?.allowedSideEffects.includes("clipboard"))
|
|
3419
|
+
context.addIssue({
|
|
3420
|
+
code: "custom",
|
|
3421
|
+
path: ["actionBindings", index, "success", "clipboard"],
|
|
3422
|
+
message: "An Action result clipboard effect requires clipboard permission on its source capability instance.",
|
|
3423
|
+
});
|
|
3424
|
+
}
|
|
615
3425
|
});
|
|
616
|
-
if (value.shellRevisionRef.kind !==
|
|
617
|
-
context.addIssue({
|
|
3426
|
+
if (value.shellRevisionRef.kind !== "shell")
|
|
3427
|
+
context.addIssue({
|
|
3428
|
+
code: "custom",
|
|
3429
|
+
path: ["shellRevisionRef", "kind"],
|
|
3430
|
+
message: "Page shellRevisionRef must reference a shell.",
|
|
3431
|
+
});
|
|
618
3432
|
value.capabilityInstances.forEach((instance, index) => {
|
|
3433
|
+
if (instance.accessPolicy) {
|
|
3434
|
+
[
|
|
3435
|
+
...instance.accessPolicy.groupAllOf,
|
|
3436
|
+
...instance.accessPolicy.groupAnyOf,
|
|
3437
|
+
...instance.accessPolicy.conditionAllOf,
|
|
3438
|
+
].forEach((reference, refIndex) => validateTenantCompatibleReference(reference, value.tenantScope, ["capabilityInstances", index, "accessPolicy", refIndex], context));
|
|
3439
|
+
}
|
|
619
3440
|
const refs = [
|
|
620
|
-
[
|
|
621
|
-
[
|
|
622
|
-
[
|
|
3441
|
+
["capabilityRevisionRef", instance.capabilityRevisionRef, "capability"],
|
|
3442
|
+
["providerRevisionRef", instance.providerRevisionRef, "view-provider"],
|
|
3443
|
+
[
|
|
3444
|
+
"propertySchemaRevisionRef",
|
|
3445
|
+
instance.propertySchemaRevisionRef,
|
|
3446
|
+
"schema",
|
|
3447
|
+
],
|
|
623
3448
|
];
|
|
624
3449
|
refs.forEach(([field, reference, expectedKind]) => {
|
|
625
3450
|
if (reference.kind !== expectedKind)
|
|
626
|
-
context.addIssue({
|
|
3451
|
+
context.addIssue({
|
|
3452
|
+
code: "custom",
|
|
3453
|
+
path: ["capabilityInstances", index, field, "kind"],
|
|
3454
|
+
message: `${field} must reference ${expectedKind}.`,
|
|
3455
|
+
});
|
|
627
3456
|
});
|
|
628
3457
|
});
|
|
629
3458
|
value.tokenRevisionRefs.forEach((reference, index) => {
|
|
630
|
-
if (reference.kind !==
|
|
631
|
-
context.addIssue({
|
|
3459
|
+
if (reference.kind !== "design-token")
|
|
3460
|
+
context.addIssue({
|
|
3461
|
+
code: "custom",
|
|
3462
|
+
path: ["tokenRevisionRefs", index, "kind"],
|
|
3463
|
+
message: "Page token references must use kind design-token.",
|
|
3464
|
+
});
|
|
632
3465
|
});
|
|
633
|
-
if (value.performanceBudgetRef.kind !==
|
|
634
|
-
context.addIssue({
|
|
635
|
-
|
|
636
|
-
|
|
3466
|
+
if (value.performanceBudgetRef.kind !== "performance-budget")
|
|
3467
|
+
context.addIssue({
|
|
3468
|
+
code: "custom",
|
|
3469
|
+
path: ["performanceBudgetRef", "kind"],
|
|
3470
|
+
message: "Page requires a performance-budget revision.",
|
|
3471
|
+
});
|
|
3472
|
+
if (value.observationPolicyRevisionRef.kind !== "observation-policy")
|
|
3473
|
+
context.addIssue({
|
|
3474
|
+
code: "custom",
|
|
3475
|
+
path: ["observationPolicyRevisionRef", "kind"],
|
|
3476
|
+
message: "Page requires an observation-policy revision.",
|
|
3477
|
+
});
|
|
637
3478
|
});
|
|
638
3479
|
exports.PageReleaseSchema = zod_1.z
|
|
639
3480
|
.object({
|
|
640
|
-
contract: zod_1.z.literal(
|
|
3481
|
+
contract: zod_1.z.literal("PageRelease"),
|
|
641
3482
|
...ReleaseBaseShape,
|
|
642
3483
|
pageRevisionRef: exports.RevisionRefSchema,
|
|
643
|
-
target: zod_1.z
|
|
3484
|
+
target: zod_1.z
|
|
3485
|
+
.object({
|
|
644
3486
|
environmentRef: exports.StableRefSchema,
|
|
645
3487
|
surface: exports.ProductSurfaceSchema,
|
|
646
3488
|
routeSpaceRevisionRef: exports.RevisionRefSchema,
|
|
647
3489
|
normalizedPath: exports.RoutePathTemplateSchema,
|
|
648
|
-
routeClaim: zod_1.z.union([
|
|
649
|
-
|
|
3490
|
+
routeClaim: zod_1.z.union([
|
|
3491
|
+
exports.CompiledRouteClaimSchema,
|
|
3492
|
+
LegacyCompiledRouteClaimSchema,
|
|
3493
|
+
]),
|
|
3494
|
+
legacyRouteTakeoverAuthorization: exports.LegacyRouteTakeoverAuthorizationSchema.optional(),
|
|
3495
|
+
})
|
|
3496
|
+
.strict(),
|
|
650
3497
|
})
|
|
651
3498
|
.strict()
|
|
652
3499
|
.superRefine((value, context) => {
|
|
3500
|
+
validateLegacyRestoration(value, "legacy-route-adapter", context);
|
|
653
3501
|
validateDependencySnapshot(value.dependencySnapshot, context);
|
|
654
|
-
|
|
655
|
-
if (value.pageRevisionRef.kind !==
|
|
656
|
-
context.addIssue({
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
if (value.target.
|
|
662
|
-
context.addIssue({
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
3502
|
+
validateReleaseGovernanceScope(value, "page-release", context);
|
|
3503
|
+
if (value.pageRevisionRef.kind !== "page")
|
|
3504
|
+
context.addIssue({
|
|
3505
|
+
code: "custom",
|
|
3506
|
+
path: ["pageRevisionRef", "kind"],
|
|
3507
|
+
message: "Expected a page revision.",
|
|
3508
|
+
});
|
|
3509
|
+
if (value.target.environmentRef.kind !== "environment")
|
|
3510
|
+
context.addIssue({
|
|
3511
|
+
code: "custom",
|
|
3512
|
+
path: ["target", "environmentRef", "kind"],
|
|
3513
|
+
message: "Page release target requires an environment reference.",
|
|
3514
|
+
});
|
|
3515
|
+
if (value.target.routeSpaceRevisionRef.kind !== "route-space")
|
|
3516
|
+
context.addIssue({
|
|
3517
|
+
code: "custom",
|
|
3518
|
+
path: ["target", "routeSpaceRevisionRef", "kind"],
|
|
3519
|
+
message: "Page release target requires a route-space revision.",
|
|
3520
|
+
});
|
|
3521
|
+
validateReleaseRouteSurface(value.target, context);
|
|
3522
|
+
if (value.target.normalizedPath !== value.target.routeClaim.normalizedPath ||
|
|
3523
|
+
!exactRevisionRef(value.target.routeSpaceRevisionRef, value.target.routeClaim.routeSpaceRevisionRef)) {
|
|
3524
|
+
context.addIssue({
|
|
3525
|
+
code: "custom",
|
|
3526
|
+
path: ["target", "routeClaim"],
|
|
3527
|
+
message: "Page Release route authority must pin the exact compiled claim and normalized path.",
|
|
3528
|
+
});
|
|
3529
|
+
}
|
|
3530
|
+
const takeover = value.target.legacyRouteTakeoverAuthorization;
|
|
3531
|
+
if (takeover &&
|
|
3532
|
+
(value.target.routeClaim.kind !== "canonical" ||
|
|
3533
|
+
takeover.normalizedPath !== value.target.normalizedPath ||
|
|
3534
|
+
!exactRevisionRef(takeover.routeSpaceRevisionRef, value.target.routeSpaceRevisionRef) ||
|
|
3535
|
+
takeover.targetResourceRef.kind !== "page" ||
|
|
3536
|
+
takeover.targetResourceRef.id !== value.pageRevisionRef.id ||
|
|
3537
|
+
takeover.targetResourceRef.ownerRepo !==
|
|
3538
|
+
value.pageRevisionRef.ownerRepo)) {
|
|
3539
|
+
context.addIssue({
|
|
3540
|
+
code: "custom",
|
|
3541
|
+
path: ["target", "legacyRouteTakeoverAuthorization"],
|
|
3542
|
+
message: "A Page route takeover must bind the exact canonical claim, RouteSpace and target Page.",
|
|
3543
|
+
});
|
|
666
3544
|
}
|
|
667
3545
|
});
|
|
668
3546
|
exports.WorkbenchGroupSchema = zod_1.z
|
|
@@ -678,130 +3556,253 @@ exports.WorkbenchGroupSchema = zod_1.z
|
|
|
678
3556
|
exports.WorkbenchAppInstanceSchema = zod_1.z
|
|
679
3557
|
.object({
|
|
680
3558
|
instanceId: common_1.ContractIdentifierSchema,
|
|
681
|
-
kind: zod_1.z.enum([
|
|
3559
|
+
kind: zod_1.z.enum([
|
|
3560
|
+
"built-in-application",
|
|
3561
|
+
"workflow-form",
|
|
3562
|
+
"workflow",
|
|
3563
|
+
"agent",
|
|
3564
|
+
"design",
|
|
3565
|
+
"capability",
|
|
3566
|
+
]),
|
|
682
3567
|
targetRevisionRef: exports.RevisionRefSchema,
|
|
683
3568
|
providerRevisionRef: exports.RevisionRefSchema,
|
|
684
3569
|
inputSchemaRevisionRef: exports.RevisionRefSchema,
|
|
685
3570
|
input: common_1.JsonObjectSchema,
|
|
686
3571
|
groupId: common_1.ContractIdentifierSchema,
|
|
687
3572
|
order: zod_1.z.number().int(),
|
|
688
|
-
display: zod_1.z
|
|
3573
|
+
display: zod_1.z
|
|
3574
|
+
.object({
|
|
3575
|
+
name: exports.I18nTextSchema.optional(),
|
|
3576
|
+
iconRef: exports.StableRefSchema.optional(),
|
|
3577
|
+
})
|
|
3578
|
+
.strict(),
|
|
689
3579
|
accessPolicy: exports.AccessPolicySchema,
|
|
690
3580
|
})
|
|
691
3581
|
.strict();
|
|
692
3582
|
exports.WorkbenchSchema = zod_1.z
|
|
693
3583
|
.object({
|
|
694
|
-
contract: zod_1.z.literal(
|
|
3584
|
+
contract: zod_1.z.literal("Workbench"),
|
|
695
3585
|
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
696
3586
|
workbenchId: common_1.ContractIdentifierSchema,
|
|
697
3587
|
tenantScope: exports.TenantScopeSchema,
|
|
698
|
-
purpose: zod_1.z.enum([
|
|
3588
|
+
purpose: zod_1.z.enum(["instance", "template"]),
|
|
699
3589
|
sourceTemplateRevisionRef: exports.RevisionRefSchema.optional(),
|
|
700
3590
|
identity: exports.WorkbenchIdentitySchema,
|
|
701
3591
|
supportedSurfaces: zod_1.z.array(exports.ProductSurfaceSchema).min(1),
|
|
702
3592
|
lifecycle: exports.DeclarativeLifecycleSchema,
|
|
703
|
-
routeClaims: zod_1.z
|
|
3593
|
+
routeClaims: zod_1.z
|
|
3594
|
+
.array(zod_1.z.union([
|
|
3595
|
+
exports.DeclarativeRouteClaimSchema,
|
|
3596
|
+
LegacyDeclarativeRouteClaimSchema,
|
|
3597
|
+
]))
|
|
3598
|
+
.min(1),
|
|
704
3599
|
groups: zod_1.z.array(exports.WorkbenchGroupSchema).min(1),
|
|
705
3600
|
appInstances: zod_1.z.array(exports.WorkbenchAppInstanceSchema).min(1),
|
|
706
|
-
defaultEntry: zod_1.z
|
|
707
|
-
|
|
3601
|
+
defaultEntry: zod_1.z
|
|
3602
|
+
.object({
|
|
3603
|
+
groupId: common_1.ContractIdentifierSchema,
|
|
3604
|
+
instanceId: common_1.ContractIdentifierSchema,
|
|
3605
|
+
showDefaultGroup: zod_1.z.boolean(),
|
|
3606
|
+
})
|
|
3607
|
+
.strict(),
|
|
3608
|
+
layout: zod_1.z
|
|
3609
|
+
.object({
|
|
708
3610
|
hostCapabilityRevisionRef: exports.RevisionRefSchema,
|
|
709
3611
|
hostProviderRevisionRef: exports.RevisionRefSchema,
|
|
710
3612
|
layoutPolicyRevisionRef: exports.RevisionRefSchema,
|
|
711
3613
|
tokenRevisionRefs: zod_1.z.array(exports.RevisionRefSchema).min(1),
|
|
712
|
-
})
|
|
3614
|
+
})
|
|
3615
|
+
.strict(),
|
|
713
3616
|
workbenchAccessPolicy: exports.AccessPolicySchema,
|
|
714
3617
|
managementAccess: exports.ManagementAccessSchema,
|
|
715
|
-
personalPreferencesPolicy: zod_1.z
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
3618
|
+
personalPreferencesPolicy: zod_1.z
|
|
3619
|
+
.object({
|
|
3620
|
+
allowed: zod_1.z.array(zod_1.z.enum(["collapsed-groups", "recent-entry", "layout-density"])),
|
|
3621
|
+
authority: zod_1.z.literal("identity-overlay"),
|
|
3622
|
+
})
|
|
3623
|
+
.strict(),
|
|
719
3624
|
performanceBudgetRef: exports.RevisionRefSchema,
|
|
720
3625
|
observationPolicyRevisionRef: exports.RevisionRefSchema,
|
|
721
|
-
privacyClassification: zod_1.z.enum([
|
|
3626
|
+
privacyClassification: zod_1.z.enum([
|
|
3627
|
+
"public",
|
|
3628
|
+
"internal",
|
|
3629
|
+
"confidential",
|
|
3630
|
+
"restricted",
|
|
3631
|
+
]),
|
|
722
3632
|
})
|
|
723
3633
|
.strict()
|
|
724
3634
|
.superRefine((value, context) => {
|
|
725
3635
|
validateDeclaredRouteSurfaces(value.supportedSurfaces, value.routeClaims, context);
|
|
726
|
-
if (value.purpose ===
|
|
727
|
-
context.addIssue({
|
|
3636
|
+
if (value.purpose === "template" && value.sourceTemplateRevisionRef) {
|
|
3637
|
+
context.addIssue({
|
|
3638
|
+
code: "custom",
|
|
3639
|
+
path: ["sourceTemplateRevisionRef"],
|
|
3640
|
+
message: "Templates cannot derive from another template at runtime.",
|
|
3641
|
+
});
|
|
728
3642
|
}
|
|
729
3643
|
const duplicateGroup = uniqueArray(value.groups, (group) => group.groupId);
|
|
730
3644
|
if (duplicateGroup)
|
|
731
|
-
context.addIssue({
|
|
3645
|
+
context.addIssue({
|
|
3646
|
+
code: "custom",
|
|
3647
|
+
path: ["groups"],
|
|
3648
|
+
message: `Duplicate Workbench group: ${duplicateGroup}`,
|
|
3649
|
+
});
|
|
732
3650
|
const duplicateInstance = uniqueArray(value.appInstances, (instance) => instance.instanceId);
|
|
733
3651
|
if (duplicateInstance)
|
|
734
|
-
context.addIssue({
|
|
3652
|
+
context.addIssue({
|
|
3653
|
+
code: "custom",
|
|
3654
|
+
path: ["appInstances"],
|
|
3655
|
+
message: `Duplicate Workbench instance: ${duplicateInstance}`,
|
|
3656
|
+
});
|
|
735
3657
|
const groupIds = new Set(value.groups.map((group) => group.groupId));
|
|
736
3658
|
value.appInstances.forEach((instance, index) => {
|
|
737
3659
|
if (!groupIds.has(instance.groupId))
|
|
738
|
-
context.addIssue({
|
|
3660
|
+
context.addIssue({
|
|
3661
|
+
code: "custom",
|
|
3662
|
+
path: ["appInstances", index, "groupId"],
|
|
3663
|
+
message: "Workbench app references an unknown group.",
|
|
3664
|
+
});
|
|
739
3665
|
});
|
|
740
3666
|
const defaultInstance = value.appInstances.find((instance) => instance.instanceId === value.defaultEntry.instanceId);
|
|
741
|
-
if (!defaultInstance ||
|
|
742
|
-
|
|
3667
|
+
if (!defaultInstance ||
|
|
3668
|
+
defaultInstance.groupId !== value.defaultEntry.groupId) {
|
|
3669
|
+
context.addIssue({
|
|
3670
|
+
code: "custom",
|
|
3671
|
+
path: ["defaultEntry"],
|
|
3672
|
+
message: "Workbench default entry must reference an app in the declared group.",
|
|
3673
|
+
});
|
|
743
3674
|
}
|
|
744
3675
|
const targetKindByInstanceKind = {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
workflow:
|
|
748
|
-
agent:
|
|
749
|
-
design:
|
|
750
|
-
capability:
|
|
3676
|
+
"built-in-application": "built-in-application",
|
|
3677
|
+
"workflow-form": "workflow",
|
|
3678
|
+
workflow: "workflow",
|
|
3679
|
+
agent: "agent",
|
|
3680
|
+
design: "design",
|
|
3681
|
+
capability: "capability",
|
|
751
3682
|
};
|
|
752
3683
|
value.appInstances.forEach((instance, index) => {
|
|
753
|
-
if (instance.targetRevisionRef.kind !==
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
3684
|
+
if (instance.targetRevisionRef.kind !==
|
|
3685
|
+
targetKindByInstanceKind[instance.kind])
|
|
3686
|
+
context.addIssue({
|
|
3687
|
+
code: "custom",
|
|
3688
|
+
path: ["appInstances", index, "targetRevisionRef", "kind"],
|
|
3689
|
+
message: `Workbench ${instance.kind} target has an incompatible reference kind.`,
|
|
3690
|
+
});
|
|
3691
|
+
if (instance.providerRevisionRef.kind !== "view-provider")
|
|
3692
|
+
context.addIssue({
|
|
3693
|
+
code: "custom",
|
|
3694
|
+
path: ["appInstances", index, "providerRevisionRef", "kind"],
|
|
3695
|
+
message: "Workbench app provider must use kind view-provider.",
|
|
3696
|
+
});
|
|
3697
|
+
if (instance.inputSchemaRevisionRef.kind !== "schema")
|
|
3698
|
+
context.addIssue({
|
|
3699
|
+
code: "custom",
|
|
3700
|
+
path: ["appInstances", index, "inputSchemaRevisionRef", "kind"],
|
|
3701
|
+
message: "Workbench app input must pin a schema revision.",
|
|
3702
|
+
});
|
|
759
3703
|
});
|
|
760
3704
|
const layoutRefs = [
|
|
761
|
-
[
|
|
762
|
-
|
|
763
|
-
|
|
3705
|
+
[
|
|
3706
|
+
"hostCapabilityRevisionRef",
|
|
3707
|
+
value.layout.hostCapabilityRevisionRef,
|
|
3708
|
+
"capability",
|
|
3709
|
+
],
|
|
3710
|
+
[
|
|
3711
|
+
"hostProviderRevisionRef",
|
|
3712
|
+
value.layout.hostProviderRevisionRef,
|
|
3713
|
+
"view-provider",
|
|
3714
|
+
],
|
|
3715
|
+
[
|
|
3716
|
+
"layoutPolicyRevisionRef",
|
|
3717
|
+
value.layout.layoutPolicyRevisionRef,
|
|
3718
|
+
"layout-policy",
|
|
3719
|
+
],
|
|
764
3720
|
];
|
|
765
3721
|
layoutRefs.forEach(([field, reference, expectedKind]) => {
|
|
766
3722
|
if (reference.kind !== expectedKind)
|
|
767
|
-
context.addIssue({
|
|
3723
|
+
context.addIssue({
|
|
3724
|
+
code: "custom",
|
|
3725
|
+
path: ["layout", field, "kind"],
|
|
3726
|
+
message: `${field} must reference ${expectedKind}.`,
|
|
3727
|
+
});
|
|
768
3728
|
});
|
|
769
3729
|
value.layout.tokenRevisionRefs.forEach((reference, index) => {
|
|
770
|
-
if (reference.kind !==
|
|
771
|
-
context.addIssue({
|
|
3730
|
+
if (reference.kind !== "design-token")
|
|
3731
|
+
context.addIssue({
|
|
3732
|
+
code: "custom",
|
|
3733
|
+
path: ["layout", "tokenRevisionRefs", index, "kind"],
|
|
3734
|
+
message: "Workbench token references must use kind design-token.",
|
|
3735
|
+
});
|
|
772
3736
|
});
|
|
773
3737
|
});
|
|
774
3738
|
exports.WorkbenchReleaseSchema = zod_1.z
|
|
775
3739
|
.object({
|
|
776
|
-
contract: zod_1.z.literal(
|
|
3740
|
+
contract: zod_1.z.literal("WorkbenchRelease"),
|
|
777
3741
|
...ReleaseBaseShape,
|
|
778
3742
|
workbenchRevisionRef: exports.RevisionRefSchema,
|
|
779
|
-
target: zod_1.z
|
|
3743
|
+
target: zod_1.z
|
|
3744
|
+
.object({
|
|
780
3745
|
environmentRef: exports.StableRefSchema,
|
|
781
3746
|
surface: exports.ProductSurfaceSchema,
|
|
782
3747
|
workbenchId: common_1.ContractIdentifierSchema,
|
|
783
3748
|
routeSpaceRevisionRef: exports.RevisionRefSchema,
|
|
784
3749
|
normalizedPath: exports.RoutePathTemplateSchema,
|
|
785
|
-
routeClaim: zod_1.z.union([
|
|
3750
|
+
routeClaim: zod_1.z.union([
|
|
3751
|
+
exports.CompiledRouteClaimSchema,
|
|
3752
|
+
LegacyCompiledRouteClaimSchema,
|
|
3753
|
+
]),
|
|
3754
|
+
legacyRouteTakeoverAuthorization: exports.LegacyRouteTakeoverAuthorizationSchema.optional(),
|
|
786
3755
|
order: zod_1.z.number().int(),
|
|
787
3756
|
isDefaultCandidate: zod_1.z.boolean(),
|
|
788
|
-
})
|
|
3757
|
+
})
|
|
3758
|
+
.strict(),
|
|
789
3759
|
})
|
|
790
3760
|
.strict()
|
|
791
3761
|
.superRefine((value, context) => {
|
|
3762
|
+
validateLegacyRestoration(value, "legacy-workbench-adapter", context);
|
|
792
3763
|
validateDependencySnapshot(value.dependencySnapshot, context);
|
|
793
|
-
|
|
794
|
-
if (value.workbenchRevisionRef.kind !==
|
|
795
|
-
context.addIssue({
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
if (value.target.
|
|
801
|
-
context.addIssue({
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
3764
|
+
validateReleaseGovernanceScope(value, "workbench-release", context);
|
|
3765
|
+
if (value.workbenchRevisionRef.kind !== "workbench")
|
|
3766
|
+
context.addIssue({
|
|
3767
|
+
code: "custom",
|
|
3768
|
+
path: ["workbenchRevisionRef", "kind"],
|
|
3769
|
+
message: "Expected a workbench revision.",
|
|
3770
|
+
});
|
|
3771
|
+
if (value.target.environmentRef.kind !== "environment")
|
|
3772
|
+
context.addIssue({
|
|
3773
|
+
code: "custom",
|
|
3774
|
+
path: ["target", "environmentRef", "kind"],
|
|
3775
|
+
message: "Workbench release target requires an environment reference.",
|
|
3776
|
+
});
|
|
3777
|
+
if (value.target.routeSpaceRevisionRef.kind !== "route-space")
|
|
3778
|
+
context.addIssue({
|
|
3779
|
+
code: "custom",
|
|
3780
|
+
path: ["target", "routeSpaceRevisionRef", "kind"],
|
|
3781
|
+
message: "Workbench release target requires a route-space revision.",
|
|
3782
|
+
});
|
|
3783
|
+
validateReleaseRouteSurface(value.target, context);
|
|
3784
|
+
if (value.target.normalizedPath !== value.target.routeClaim.normalizedPath ||
|
|
3785
|
+
!exactRevisionRef(value.target.routeSpaceRevisionRef, value.target.routeClaim.routeSpaceRevisionRef)) {
|
|
3786
|
+
context.addIssue({
|
|
3787
|
+
code: "custom",
|
|
3788
|
+
path: ["target", "routeClaim"],
|
|
3789
|
+
message: "Workbench Release route authority must pin the exact compiled claim and normalized path.",
|
|
3790
|
+
});
|
|
3791
|
+
}
|
|
3792
|
+
const takeover = value.target.legacyRouteTakeoverAuthorization;
|
|
3793
|
+
if (takeover &&
|
|
3794
|
+
(value.target.routeClaim.kind !== "canonical" ||
|
|
3795
|
+
takeover.normalizedPath !== value.target.normalizedPath ||
|
|
3796
|
+
!exactRevisionRef(takeover.routeSpaceRevisionRef, value.target.routeSpaceRevisionRef) ||
|
|
3797
|
+
takeover.targetResourceRef.kind !== "workbench" ||
|
|
3798
|
+
takeover.targetResourceRef.id !== value.workbenchRevisionRef.id ||
|
|
3799
|
+
takeover.targetResourceRef.ownerRepo !==
|
|
3800
|
+
value.workbenchRevisionRef.ownerRepo)) {
|
|
3801
|
+
context.addIssue({
|
|
3802
|
+
code: "custom",
|
|
3803
|
+
path: ["target", "legacyRouteTakeoverAuthorization"],
|
|
3804
|
+
message: "A Workbench route takeover must bind the exact canonical claim, RouteSpace and target Workbench.",
|
|
3805
|
+
});
|
|
805
3806
|
}
|
|
806
3807
|
});
|
|
807
3808
|
const NavigationNodeBaseShape = {
|
|
@@ -810,29 +3811,35 @@ const NavigationNodeBaseShape = {
|
|
|
810
3811
|
order: zod_1.z.number().int(),
|
|
811
3812
|
disabled: zod_1.z.boolean().optional(),
|
|
812
3813
|
};
|
|
813
|
-
exports.NavigationGroupNodeSchema = zod_1.z
|
|
3814
|
+
exports.NavigationGroupNodeSchema = zod_1.z
|
|
3815
|
+
.object({
|
|
814
3816
|
...NavigationNodeBaseShape,
|
|
815
|
-
kind: zod_1.z.literal(
|
|
3817
|
+
kind: zod_1.z.literal("group"),
|
|
816
3818
|
label: exports.I18nTextSchema,
|
|
817
3819
|
iconRef: exports.StableRefSchema.optional(),
|
|
818
3820
|
collapsedByDefault: zod_1.z.boolean(),
|
|
819
3821
|
audience: exports.AccessPolicySchema,
|
|
820
|
-
})
|
|
821
|
-
|
|
3822
|
+
})
|
|
3823
|
+
.strict();
|
|
3824
|
+
exports.NavigationTargetNodeSchema = zod_1.z
|
|
3825
|
+
.object({
|
|
822
3826
|
...NavigationNodeBaseShape,
|
|
823
|
-
kind: zod_1.z.literal(
|
|
3827
|
+
kind: zod_1.z.literal("target"),
|
|
824
3828
|
label: exports.I18nTextSchema,
|
|
825
3829
|
iconRef: exports.StableRefSchema.optional(),
|
|
826
|
-
tone: zod_1.z.enum([
|
|
3830
|
+
tone: zod_1.z.enum(["default", "danger"]).optional(),
|
|
827
3831
|
targetRef: exports.StableRefSchema,
|
|
828
3832
|
parameterMapping: zod_1.z.record(common_1.ContractIdentifierSchema, exports.BindingSourceSchema),
|
|
829
3833
|
audience: exports.AccessPolicySchema,
|
|
830
|
-
})
|
|
831
|
-
|
|
3834
|
+
})
|
|
3835
|
+
.strict();
|
|
3836
|
+
exports.NavigationSeparatorNodeSchema = zod_1.z
|
|
3837
|
+
.object({
|
|
832
3838
|
...NavigationNodeBaseShape,
|
|
833
|
-
kind: zod_1.z.literal(
|
|
834
|
-
})
|
|
835
|
-
|
|
3839
|
+
kind: zod_1.z.literal("separator"),
|
|
3840
|
+
})
|
|
3841
|
+
.strict();
|
|
3842
|
+
exports.NavigationNodeSchema = zod_1.z.discriminatedUnion("kind", [
|
|
836
3843
|
exports.NavigationGroupNodeSchema,
|
|
837
3844
|
exports.NavigationTargetNodeSchema,
|
|
838
3845
|
exports.NavigationSeparatorNodeSchema,
|
|
@@ -841,28 +3848,48 @@ const validateNavigationTree = (nodes, context) => {
|
|
|
841
3848
|
const byId = new Map();
|
|
842
3849
|
nodes.forEach((node, index) => {
|
|
843
3850
|
if (byId.has(node.nodeId))
|
|
844
|
-
context.addIssue({
|
|
3851
|
+
context.addIssue({
|
|
3852
|
+
code: "custom",
|
|
3853
|
+
path: ["nodes", index, "nodeId"],
|
|
3854
|
+
message: `Duplicate Navigation node: ${node.nodeId}`,
|
|
3855
|
+
});
|
|
845
3856
|
else
|
|
846
3857
|
byId.set(node.nodeId, { node, index });
|
|
847
3858
|
});
|
|
848
3859
|
const siblingOrders = new Set();
|
|
849
3860
|
nodes.forEach((node, index) => {
|
|
850
|
-
const orderKey = `${node.parentNodeId ??
|
|
3861
|
+
const orderKey = `${node.parentNodeId ?? ""}:${node.order}`;
|
|
851
3862
|
if (siblingOrders.has(orderKey))
|
|
852
|
-
context.addIssue({
|
|
3863
|
+
context.addIssue({
|
|
3864
|
+
code: "custom",
|
|
3865
|
+
path: ["nodes", index, "order"],
|
|
3866
|
+
message: "Sibling Navigation order values must be unique.",
|
|
3867
|
+
});
|
|
853
3868
|
siblingOrders.add(orderKey);
|
|
854
3869
|
if (node.parentNodeId) {
|
|
855
3870
|
const parent = byId.get(node.parentNodeId)?.node;
|
|
856
3871
|
if (!parent)
|
|
857
|
-
context.addIssue({
|
|
858
|
-
|
|
859
|
-
|
|
3872
|
+
context.addIssue({
|
|
3873
|
+
code: "custom",
|
|
3874
|
+
path: ["nodes", index, "parentNodeId"],
|
|
3875
|
+
message: "Navigation node has an unknown parent.",
|
|
3876
|
+
});
|
|
3877
|
+
else if (parent.kind !== "group")
|
|
3878
|
+
context.addIssue({
|
|
3879
|
+
code: "custom",
|
|
3880
|
+
path: ["nodes", index, "parentNodeId"],
|
|
3881
|
+
message: "Navigation parents must be groups.",
|
|
3882
|
+
});
|
|
860
3883
|
}
|
|
861
3884
|
const ancestors = new Set([node.nodeId]);
|
|
862
3885
|
let parentId = node.parentNodeId;
|
|
863
3886
|
while (parentId) {
|
|
864
3887
|
if (ancestors.has(parentId)) {
|
|
865
|
-
context.addIssue({
|
|
3888
|
+
context.addIssue({
|
|
3889
|
+
code: "custom",
|
|
3890
|
+
path: ["nodes", index, "parentNodeId"],
|
|
3891
|
+
message: `Navigation cycle contains ${node.nodeId}.`,
|
|
3892
|
+
});
|
|
866
3893
|
break;
|
|
867
3894
|
}
|
|
868
3895
|
ancestors.add(parentId);
|
|
@@ -872,7 +3899,7 @@ const validateNavigationTree = (nodes, context) => {
|
|
|
872
3899
|
};
|
|
873
3900
|
exports.NavigationSchema = zod_1.z
|
|
874
3901
|
.object({
|
|
875
|
-
contract: zod_1.z.literal(
|
|
3902
|
+
contract: zod_1.z.literal("Navigation"),
|
|
876
3903
|
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
877
3904
|
navigationId: common_1.ContractIdentifierSchema,
|
|
878
3905
|
tenantScope: exports.TenantScopeSchema,
|
|
@@ -889,8 +3916,13 @@ exports.NavigationSchema = zod_1.z
|
|
|
889
3916
|
.superRefine((value, context) => {
|
|
890
3917
|
validateNavigationTree(value.nodes, context);
|
|
891
3918
|
value.nodes.forEach((node, index) => {
|
|
892
|
-
if (node.kind ===
|
|
893
|
-
|
|
3919
|
+
if (node.kind === "target" &&
|
|
3920
|
+
!["page", "workbench", "menu-action", "domain-command"].includes(node.targetRef.kind)) {
|
|
3921
|
+
context.addIssue({
|
|
3922
|
+
code: "custom",
|
|
3923
|
+
path: ["nodes", index, "targetRef", "kind"],
|
|
3924
|
+
message: "Navigation targets must reference Page, Workbench, registered Menu Action, or DomainCommand identities.",
|
|
3925
|
+
});
|
|
894
3926
|
}
|
|
895
3927
|
});
|
|
896
3928
|
});
|
|
@@ -903,45 +3935,68 @@ exports.ResolvedNavigationTargetSchema = zod_1.z
|
|
|
903
3935
|
})
|
|
904
3936
|
.strict();
|
|
905
3937
|
/** A reviewed missing Page reference is retained without inventing an executable revision. */
|
|
906
|
-
exports.UnavailableNavigationTargetSchema = zod_1.z
|
|
3938
|
+
exports.UnavailableNavigationTargetSchema = zod_1.z
|
|
3939
|
+
.object({
|
|
907
3940
|
nodeId: common_1.ContractIdentifierSchema,
|
|
908
|
-
stableTargetRef: exports.StableRefSchema.refine((reference) => reference.kind ===
|
|
909
|
-
reason: zod_1.z.literal(
|
|
3941
|
+
stableTargetRef: exports.StableRefSchema.refine((reference) => reference.kind === "page", "Only missing Pages can be isolated."),
|
|
3942
|
+
reason: zod_1.z.literal("page-missing"),
|
|
910
3943
|
accessPolicy: exports.AccessPolicySchema.nullable(),
|
|
911
|
-
})
|
|
3944
|
+
})
|
|
3945
|
+
.strict();
|
|
912
3946
|
exports.NavigationReleaseSchema = zod_1.z
|
|
913
3947
|
.object({
|
|
914
|
-
contract: zod_1.z.literal(
|
|
3948
|
+
contract: zod_1.z.literal("NavigationRelease"),
|
|
915
3949
|
...ReleaseBaseShape,
|
|
916
3950
|
navigationRevisionRef: exports.RevisionRefSchema,
|
|
917
|
-
target: zod_1.z
|
|
3951
|
+
target: zod_1.z
|
|
3952
|
+
.object({
|
|
918
3953
|
environmentRef: exports.StableRefSchema,
|
|
919
3954
|
surface: exports.ProductSurfaceSchema,
|
|
920
3955
|
placement: common_1.ContractIdentifierSchema,
|
|
921
|
-
})
|
|
3956
|
+
})
|
|
3957
|
+
.strict(),
|
|
922
3958
|
resolvedTargets: zod_1.z.array(exports.ResolvedNavigationTargetSchema),
|
|
923
3959
|
unavailableTargets: zod_1.z.array(exports.UnavailableNavigationTargetSchema).optional(),
|
|
924
3960
|
})
|
|
925
3961
|
.strict()
|
|
926
3962
|
.superRefine((value, context) => {
|
|
3963
|
+
validateLegacyRestoration(value, "legacy-navigation-adapter", context);
|
|
927
3964
|
validateDependencySnapshot(value.dependencySnapshot, context);
|
|
928
|
-
|
|
929
|
-
if (value.navigationRevisionRef.kind !==
|
|
930
|
-
context.addIssue({
|
|
931
|
-
|
|
932
|
-
|
|
3965
|
+
validateReleaseGovernanceScope(value, "navigation-release", context);
|
|
3966
|
+
if (value.navigationRevisionRef.kind !== "navigation")
|
|
3967
|
+
context.addIssue({
|
|
3968
|
+
code: "custom",
|
|
3969
|
+
path: ["navigationRevisionRef", "kind"],
|
|
3970
|
+
message: "Expected a navigation revision.",
|
|
3971
|
+
});
|
|
3972
|
+
if (value.target.environmentRef.kind !== "environment")
|
|
3973
|
+
context.addIssue({
|
|
3974
|
+
code: "custom",
|
|
3975
|
+
path: ["target", "environmentRef", "kind"],
|
|
3976
|
+
message: "Navigation release target requires an environment reference.",
|
|
3977
|
+
});
|
|
933
3978
|
if (uniqueArray(value.resolvedTargets, (target) => target.nodeId))
|
|
934
|
-
context.addIssue({
|
|
3979
|
+
context.addIssue({
|
|
3980
|
+
code: "custom",
|
|
3981
|
+
path: ["resolvedTargets"],
|
|
3982
|
+
message: "Resolved Navigation node IDs must be unique.",
|
|
3983
|
+
});
|
|
935
3984
|
if (uniqueArray([...value.resolvedTargets, ...(value.unavailableTargets ?? [])], (target) => target.nodeId)) {
|
|
936
|
-
context.addIssue({
|
|
3985
|
+
context.addIssue({
|
|
3986
|
+
code: "custom",
|
|
3987
|
+
path: ["unavailableTargets"],
|
|
3988
|
+
message: "Navigation target resolutions must have unique node IDs.",
|
|
3989
|
+
});
|
|
937
3990
|
}
|
|
938
3991
|
});
|
|
939
|
-
const RuntimeDiagnosticSchema = zod_1.z
|
|
3992
|
+
const RuntimeDiagnosticSchema = zod_1.z
|
|
3993
|
+
.object({
|
|
940
3994
|
code: common_1.ContractIdentifierSchema,
|
|
941
|
-
severity: zod_1.z.enum([
|
|
3995
|
+
severity: zod_1.z.enum(["info", "warning", "error"]),
|
|
942
3996
|
path: zod_1.z.string().trim().min(1),
|
|
943
3997
|
message: zod_1.z.string().trim().min(1),
|
|
944
|
-
})
|
|
3998
|
+
})
|
|
3999
|
+
.strict();
|
|
945
4000
|
const RuntimeBundleBaseShape = {
|
|
946
4001
|
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
947
4002
|
tenantScope: exports.TenantScopeSchema,
|
|
@@ -953,57 +4008,344 @@ const RuntimeBundleBaseShape = {
|
|
|
953
4008
|
rebuildable: zod_1.z.literal(true),
|
|
954
4009
|
diagnostics: zod_1.z.array(RuntimeDiagnosticSchema),
|
|
955
4010
|
};
|
|
956
|
-
|
|
957
|
-
|
|
4011
|
+
const validateRuntimeBundleReference = (reference, tenantScope, path, expectedKind, expectedId, context) => {
|
|
4012
|
+
if (reference.kind !== expectedKind) {
|
|
4013
|
+
context.addIssue({
|
|
4014
|
+
code: "custom",
|
|
4015
|
+
path: [path, "kind"],
|
|
4016
|
+
message: `${path} must reference ${expectedKind}.`,
|
|
4017
|
+
});
|
|
4018
|
+
}
|
|
4019
|
+
if (expectedId !== undefined && reference.id !== expectedId) {
|
|
4020
|
+
context.addIssue({
|
|
4021
|
+
code: "custom",
|
|
4022
|
+
path: [path, "id"],
|
|
4023
|
+
message: `${path} must identify ${expectedId}.`,
|
|
4024
|
+
});
|
|
4025
|
+
}
|
|
4026
|
+
validateTenantCompatibleReference(reference, tenantScope, [path], context);
|
|
4027
|
+
};
|
|
4028
|
+
const validateRuntimeBundleBase = (value, expectedReleaseKind, context) => {
|
|
4029
|
+
validateRuntimeBundleReference(value.releaseRevisionRef, value.tenantScope, "releaseRevisionRef", expectedReleaseKind, undefined, context);
|
|
4030
|
+
validateRuntimeBundleReference(value.compilerRevisionRef, value.tenantScope, "compilerRevisionRef", "compiler", undefined, context);
|
|
4031
|
+
};
|
|
4032
|
+
exports.DeclarativeRouteOwnerIndexEntrySchema = zod_1.z
|
|
4033
|
+
.object({
|
|
4034
|
+
resourceKind: zod_1.z.enum(["page", "workbench"]),
|
|
4035
|
+
releaseSlotId: common_1.ContractIdentifierSchema,
|
|
4036
|
+
activeReleaseRevisionRef: exports.RevisionRefSchema,
|
|
4037
|
+
routeClaim: exports.CompiledRouteClaimSchema,
|
|
4038
|
+
authority: zod_1.z.enum(["declarative", "legacy", "unavailable"]),
|
|
4039
|
+
legacyRestoration: exports.LegacySlotRestorationSchema.optional(),
|
|
4040
|
+
})
|
|
4041
|
+
.strict()
|
|
4042
|
+
.superRefine((value, context) => {
|
|
4043
|
+
if (value.authority === "legacy" && !value.legacyRestoration) {
|
|
4044
|
+
context.addIssue({
|
|
4045
|
+
code: "custom",
|
|
4046
|
+
path: ["legacyRestoration"],
|
|
4047
|
+
message: "A restored legacy route must pin its exact inspected source and adapter revisions.",
|
|
4048
|
+
});
|
|
4049
|
+
}
|
|
4050
|
+
if (value.authority !== "legacy" && value.legacyRestoration) {
|
|
4051
|
+
context.addIssue({
|
|
4052
|
+
code: "custom",
|
|
4053
|
+
path: ["legacyRestoration"],
|
|
4054
|
+
message: "Only a restored legacy route can carry legacy restoration provenance.",
|
|
4055
|
+
});
|
|
4056
|
+
}
|
|
4057
|
+
});
|
|
4058
|
+
exports.DeclarativeRouteOwnerIndexSchema = zod_1.z
|
|
4059
|
+
.object({
|
|
4060
|
+
contract: zod_1.z.literal("DeclarativeRouteOwnerIndex"),
|
|
4061
|
+
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
4062
|
+
tenantScope: exports.TenantScopeSchema,
|
|
4063
|
+
environmentRef: exports.StableRefSchema,
|
|
4064
|
+
surface: exports.ProductSurfaceSchema,
|
|
4065
|
+
generation: zod_1.z.number().int().positive(),
|
|
4066
|
+
entries: zod_1.z.array(exports.DeclarativeRouteOwnerIndexEntrySchema).max(4096),
|
|
4067
|
+
contentHash: common_1.Sha256Schema,
|
|
4068
|
+
rebuildable: zod_1.z.literal(true),
|
|
4069
|
+
})
|
|
4070
|
+
.strict()
|
|
4071
|
+
.superRefine((value, context) => {
|
|
4072
|
+
const identities = value.entries.map((entry) => `${entry.resourceKind}:${entry.releaseSlotId}`);
|
|
4073
|
+
if (new Set(identities).size !== identities.length) {
|
|
4074
|
+
context.addIssue({
|
|
4075
|
+
code: "custom",
|
|
4076
|
+
path: ["entries"],
|
|
4077
|
+
message: "Route owner index entries must be unique by Release slot.",
|
|
4078
|
+
});
|
|
4079
|
+
}
|
|
4080
|
+
if (identities.some((identity, index) => index > 0 && identities[index - 1].localeCompare(identity) > 0)) {
|
|
4081
|
+
context.addIssue({
|
|
4082
|
+
code: "custom",
|
|
4083
|
+
path: ["entries"],
|
|
4084
|
+
message: "Route owner index entries must use deterministic Release-slot order.",
|
|
4085
|
+
});
|
|
4086
|
+
}
|
|
4087
|
+
});
|
|
4088
|
+
exports.DeclarativeWorkbenchCatalogEntrySchema = zod_1.z
|
|
4089
|
+
.object({
|
|
4090
|
+
workbenchId: common_1.ContractIdentifierSchema,
|
|
4091
|
+
authority: zod_1.z.enum(["declarative", "legacy", "unavailable"]),
|
|
4092
|
+
identity: exports.WorkbenchIdentitySchema,
|
|
4093
|
+
order: zod_1.z.number().int(),
|
|
4094
|
+
isDefaultCandidate: zod_1.z.boolean(),
|
|
4095
|
+
activeReleaseRevisionRef: exports.RevisionRefSchema.optional(),
|
|
4096
|
+
legacyAdapterRevisionRef: exports.RevisionRefSchema.optional(),
|
|
4097
|
+
})
|
|
4098
|
+
.strict()
|
|
4099
|
+
.superRefine((value, context) => {
|
|
4100
|
+
if (value.authority === "declarative") {
|
|
4101
|
+
if (value.activeReleaseRevisionRef?.kind !== "workbench-release") {
|
|
4102
|
+
context.addIssue({
|
|
4103
|
+
code: "custom",
|
|
4104
|
+
path: ["activeReleaseRevisionRef"],
|
|
4105
|
+
message: "A declarative Workbench catalog entry requires an exact Workbench Release.",
|
|
4106
|
+
});
|
|
4107
|
+
}
|
|
4108
|
+
if (value.legacyAdapterRevisionRef) {
|
|
4109
|
+
context.addIssue({
|
|
4110
|
+
code: "custom",
|
|
4111
|
+
path: ["legacyAdapterRevisionRef"],
|
|
4112
|
+
message: "A declarative Workbench catalog entry cannot carry a legacy adapter.",
|
|
4113
|
+
});
|
|
4114
|
+
}
|
|
4115
|
+
return;
|
|
4116
|
+
}
|
|
4117
|
+
if (value.activeReleaseRevisionRef) {
|
|
4118
|
+
context.addIssue({
|
|
4119
|
+
code: "custom",
|
|
4120
|
+
path: ["activeReleaseRevisionRef"],
|
|
4121
|
+
message: "A non-declarative Workbench entry cannot expose a Workbench Release.",
|
|
4122
|
+
});
|
|
4123
|
+
}
|
|
4124
|
+
if (value.authority === "legacy" &&
|
|
4125
|
+
value.legacyAdapterRevisionRef?.kind !== "legacy-workbench-adapter") {
|
|
4126
|
+
context.addIssue({
|
|
4127
|
+
code: "custom",
|
|
4128
|
+
path: ["legacyAdapterRevisionRef"],
|
|
4129
|
+
message: "A legacy Workbench entry requires an exact legacy-workbench-adapter revision.",
|
|
4130
|
+
});
|
|
4131
|
+
}
|
|
4132
|
+
if (value.authority === "unavailable" && value.legacyAdapterRevisionRef) {
|
|
4133
|
+
context.addIssue({
|
|
4134
|
+
code: "custom",
|
|
4135
|
+
path: ["legacyAdapterRevisionRef"],
|
|
4136
|
+
message: "An unavailable Workbench entry cannot carry a legacy adapter.",
|
|
4137
|
+
});
|
|
4138
|
+
}
|
|
4139
|
+
});
|
|
4140
|
+
exports.DeclarativeWorkbenchCatalogSchema = zod_1.z
|
|
4141
|
+
.object({
|
|
4142
|
+
contract: zod_1.z.literal("DeclarativeWorkbenchCatalog"),
|
|
4143
|
+
schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
|
|
4144
|
+
tenantScope: exports.TenantScopeSchema,
|
|
4145
|
+
environmentRef: exports.StableRefSchema,
|
|
4146
|
+
surface: exports.ProductSurfaceSchema,
|
|
4147
|
+
generation: zod_1.z.number().int().positive(),
|
|
4148
|
+
entries: zod_1.z.array(exports.DeclarativeWorkbenchCatalogEntrySchema).max(4096),
|
|
4149
|
+
contentHash: common_1.Sha256Schema,
|
|
4150
|
+
rebuildable: zod_1.z.literal(true),
|
|
4151
|
+
})
|
|
4152
|
+
.strict()
|
|
4153
|
+
.superRefine((value, context) => {
|
|
4154
|
+
if (value.environmentRef.kind !== "environment") {
|
|
4155
|
+
context.addIssue({
|
|
4156
|
+
code: "custom",
|
|
4157
|
+
path: ["environmentRef", "kind"],
|
|
4158
|
+
message: "A Workbench catalog requires an Environment reference.",
|
|
4159
|
+
});
|
|
4160
|
+
}
|
|
4161
|
+
const ids = value.entries.map((entry) => entry.workbenchId);
|
|
4162
|
+
if (new Set(ids).size !== ids.length) {
|
|
4163
|
+
context.addIssue({
|
|
4164
|
+
code: "custom",
|
|
4165
|
+
path: ["entries"],
|
|
4166
|
+
message: "Workbench catalog identities must be unique.",
|
|
4167
|
+
});
|
|
4168
|
+
}
|
|
4169
|
+
if (value.entries.filter((entry) => entry.authority !== "unavailable" && entry.isDefaultCandidate).length > 1) {
|
|
4170
|
+
context.addIssue({
|
|
4171
|
+
code: "custom",
|
|
4172
|
+
path: ["entries"],
|
|
4173
|
+
message: "The effective Workbench catalog may have at most one default.",
|
|
4174
|
+
});
|
|
4175
|
+
}
|
|
4176
|
+
const sorted = [...value.entries].sort((left, right) => left.order - right.order ||
|
|
4177
|
+
left.workbenchId.localeCompare(right.workbenchId));
|
|
4178
|
+
if (sorted.some((entry, index) => entry.workbenchId !== value.entries[index]?.workbenchId)) {
|
|
4179
|
+
context.addIssue({
|
|
4180
|
+
code: "custom",
|
|
4181
|
+
path: ["entries"],
|
|
4182
|
+
message: "Workbench catalog entries must use deterministic order plus Workbench identity.",
|
|
4183
|
+
});
|
|
4184
|
+
}
|
|
4185
|
+
});
|
|
4186
|
+
exports.PageRuntimeBundleSchema = zod_1.z
|
|
4187
|
+
.object({
|
|
4188
|
+
contract: zod_1.z.literal("PageRuntimeBundle"),
|
|
958
4189
|
...RuntimeBundleBaseShape,
|
|
959
4190
|
pageId: common_1.ContractIdentifierSchema,
|
|
960
4191
|
pageRevisionRef: exports.RevisionRefSchema,
|
|
961
4192
|
surface: exports.ProductSurfaceSchema,
|
|
962
4193
|
routeClaims: zod_1.z.array(exports.CompiledRouteClaimSchema),
|
|
4194
|
+
routeStatePresentations: zod_1.z
|
|
4195
|
+
.array(exports.PageRouteStatePresentationSchema)
|
|
4196
|
+
.default([]),
|
|
963
4197
|
shellRevisionRef: exports.RevisionRefSchema,
|
|
4198
|
+
shellDescriptor: exports.DeclarativeRuntimeShellDescriptorSchema,
|
|
964
4199
|
renderTree: render_1.RenderTreeSchema,
|
|
965
4200
|
capabilityInstances: zod_1.z.array(exports.CapabilityInstanceSchema),
|
|
4201
|
+
deniedCapabilityInstanceIds: zod_1.z.array(common_1.ContractIdentifierSchema).default([]),
|
|
4202
|
+
capabilityAccessEvaluated: zod_1.z.literal(true).optional(),
|
|
4203
|
+
stateDefinitions: zod_1.z.array(exports.PageStateDefinitionSchema).default([]),
|
|
4204
|
+
entryTransitions: zod_1.z.array(exports.ResolvedPageEntryTransitionSchema).default([]),
|
|
4205
|
+
interactionBindings: zod_1.z.array(exports.InteractionBindingSchema).default([]),
|
|
966
4206
|
ontologyBindings: zod_1.z.array(exports.OntologyBindingSchema),
|
|
4207
|
+
queryBindings: zod_1.z.array(exports.QueryBindingSchema).default([]),
|
|
967
4208
|
actionBindings: zod_1.z.array(exports.ActionBindingSchema),
|
|
968
4209
|
pageAccessPolicy: exports.AccessPolicySchema,
|
|
969
4210
|
tokenRevisionRefs: zod_1.z.array(exports.RevisionRefSchema),
|
|
970
4211
|
performanceBudgetRef: exports.RevisionRefSchema,
|
|
971
4212
|
observationPolicyRevisionRef: exports.RevisionRefSchema,
|
|
972
|
-
privacyClassification: zod_1.z.enum([
|
|
973
|
-
|
|
4213
|
+
privacyClassification: zod_1.z.enum([
|
|
4214
|
+
"public",
|
|
4215
|
+
"internal",
|
|
4216
|
+
"confidential",
|
|
4217
|
+
"restricted",
|
|
4218
|
+
]),
|
|
4219
|
+
})
|
|
4220
|
+
.strict()
|
|
4221
|
+
.superRefine((value, context) => {
|
|
4222
|
+
const instanceIds = new Set(value.capabilityInstances.map((instance) => instance.instanceId));
|
|
4223
|
+
if (new Set(value.deniedCapabilityInstanceIds).size !==
|
|
4224
|
+
value.deniedCapabilityInstanceIds.length ||
|
|
4225
|
+
value.deniedCapabilityInstanceIds.some((id) => !instanceIds.has(id))) {
|
|
4226
|
+
context.addIssue({
|
|
4227
|
+
code: "custom",
|
|
4228
|
+
path: ["deniedCapabilityInstanceIds"],
|
|
4229
|
+
message: "Denied capability identities must be unique declared instances.",
|
|
4230
|
+
});
|
|
4231
|
+
}
|
|
4232
|
+
validateRuntimeBundleBase(value, "page-release", context);
|
|
4233
|
+
value.routeClaims.forEach((claim, index) => {
|
|
4234
|
+
if (claim.surface !== value.surface) {
|
|
4235
|
+
context.addIssue({
|
|
4236
|
+
code: "custom",
|
|
4237
|
+
path: ["routeClaims", index, "surface"],
|
|
4238
|
+
message: "Runtime route claims must match the bundle surface.",
|
|
4239
|
+
});
|
|
4240
|
+
}
|
|
4241
|
+
});
|
|
4242
|
+
validateRuntimeBundleReference(value.pageRevisionRef, value.tenantScope, "pageRevisionRef", "page", value.pageId, context);
|
|
4243
|
+
value.routeStatePresentations.forEach((presentation, index) => {
|
|
4244
|
+
if (presentation.surface !== value.surface) {
|
|
4245
|
+
context.addIssue({
|
|
4246
|
+
code: "custom",
|
|
4247
|
+
path: ["routeStatePresentations", index, "surface"],
|
|
4248
|
+
message: "Runtime route-state presentations must match the compiled Page surface.",
|
|
4249
|
+
});
|
|
4250
|
+
}
|
|
4251
|
+
});
|
|
4252
|
+
});
|
|
974
4253
|
exports.ResolvedWorkbenchAppInstanceSchema = exports.WorkbenchAppInstanceSchema.extend({
|
|
975
4254
|
targetAccessPolicy: exports.AccessPolicySchema,
|
|
976
4255
|
}).strict();
|
|
977
|
-
|
|
4256
|
+
exports.WorkbenchRuntimeIdentitySchema = zod_1.z
|
|
4257
|
+
.object({
|
|
4258
|
+
name: exports.I18nTextSchema,
|
|
4259
|
+
description: exports.I18nTextSchema.optional(),
|
|
4260
|
+
})
|
|
4261
|
+
.strict();
|
|
4262
|
+
const WorkbenchRuntimeTargetSchema = exports.WorkbenchReleaseSchema.shape.target
|
|
4263
|
+
.safeExtend({
|
|
978
4264
|
routeClaim: exports.CompiledRouteClaimSchema,
|
|
979
|
-
})
|
|
980
|
-
|
|
981
|
-
|
|
4265
|
+
})
|
|
4266
|
+
.strict();
|
|
4267
|
+
exports.WorkbenchRuntimeBundleSchema = zod_1.z
|
|
4268
|
+
.object({
|
|
4269
|
+
contract: zod_1.z.literal("WorkbenchRuntimeBundle"),
|
|
982
4270
|
...RuntimeBundleBaseShape,
|
|
983
4271
|
workbenchId: common_1.ContractIdentifierSchema,
|
|
984
4272
|
workbenchRevisionRef: exports.RevisionRefSchema,
|
|
4273
|
+
identity: exports.WorkbenchRuntimeIdentitySchema,
|
|
985
4274
|
surface: exports.ProductSurfaceSchema,
|
|
986
4275
|
routeClaims: zod_1.z.array(exports.CompiledRouteClaimSchema),
|
|
987
4276
|
groups: zod_1.z.array(exports.WorkbenchGroupSchema),
|
|
988
4277
|
appInstances: zod_1.z.array(exports.ResolvedWorkbenchAppInstanceSchema),
|
|
989
|
-
defaultEntry: exports.WorkbenchSchema.shape.defaultEntry,
|
|
4278
|
+
defaultEntry: exports.WorkbenchSchema.shape.defaultEntry.nullable(),
|
|
990
4279
|
layout: exports.WorkbenchSchema.shape.layout,
|
|
991
4280
|
workbenchAccessPolicy: exports.AccessPolicySchema,
|
|
992
4281
|
personalPreferencesPolicy: exports.WorkbenchSchema.shape.personalPreferencesPolicy,
|
|
993
4282
|
target: WorkbenchRuntimeTargetSchema,
|
|
994
4283
|
performanceBudgetRef: exports.RevisionRefSchema,
|
|
995
4284
|
observationPolicyRevisionRef: exports.RevisionRefSchema,
|
|
996
|
-
privacyClassification: zod_1.z.enum([
|
|
997
|
-
|
|
4285
|
+
privacyClassification: zod_1.z.enum([
|
|
4286
|
+
"public",
|
|
4287
|
+
"internal",
|
|
4288
|
+
"confidential",
|
|
4289
|
+
"restricted",
|
|
4290
|
+
]),
|
|
4291
|
+
})
|
|
4292
|
+
.strict()
|
|
4293
|
+
.superRefine((value, context) => {
|
|
4294
|
+
validateRuntimeBundleBase(value, "workbench-release", context);
|
|
4295
|
+
value.routeClaims.forEach((claim, index) => {
|
|
4296
|
+
if (claim.surface !== value.surface) {
|
|
4297
|
+
context.addIssue({
|
|
4298
|
+
code: "custom",
|
|
4299
|
+
path: ["routeClaims", index, "surface"],
|
|
4300
|
+
message: "Runtime route claims must match the bundle surface.",
|
|
4301
|
+
});
|
|
4302
|
+
}
|
|
4303
|
+
});
|
|
4304
|
+
validateRuntimeBundleReference(value.workbenchRevisionRef, value.tenantScope, "workbenchRevisionRef", "workbench", value.workbenchId, context);
|
|
4305
|
+
if (value.appInstances.length === 0) {
|
|
4306
|
+
if (value.defaultEntry !== null) {
|
|
4307
|
+
context.addIssue({
|
|
4308
|
+
code: "custom",
|
|
4309
|
+
path: ["defaultEntry"],
|
|
4310
|
+
message: "An empty Workbench runtime bundle must use a null default entry.",
|
|
4311
|
+
});
|
|
4312
|
+
}
|
|
4313
|
+
return;
|
|
4314
|
+
}
|
|
4315
|
+
if (value.defaultEntry === null) {
|
|
4316
|
+
context.addIssue({
|
|
4317
|
+
code: "custom",
|
|
4318
|
+
path: ["defaultEntry"],
|
|
4319
|
+
message: "A non-empty Workbench runtime bundle requires a default entry.",
|
|
4320
|
+
});
|
|
4321
|
+
return;
|
|
4322
|
+
}
|
|
4323
|
+
const defaultInstance = value.appInstances.find((instance) => instance.instanceId === value.defaultEntry?.instanceId);
|
|
4324
|
+
if (!defaultInstance ||
|
|
4325
|
+
defaultInstance.groupId !== value.defaultEntry.groupId) {
|
|
4326
|
+
context.addIssue({
|
|
4327
|
+
code: "custom",
|
|
4328
|
+
path: ["defaultEntry"],
|
|
4329
|
+
message: "Workbench runtime default entry must reference a visible app in the declared group.",
|
|
4330
|
+
});
|
|
4331
|
+
}
|
|
4332
|
+
if (!value.groups.some((group) => group.groupId === value.defaultEntry?.groupId)) {
|
|
4333
|
+
context.addIssue({
|
|
4334
|
+
code: "custom",
|
|
4335
|
+
path: ["defaultEntry", "groupId"],
|
|
4336
|
+
message: "Workbench runtime default entry must reference a visible group.",
|
|
4337
|
+
});
|
|
4338
|
+
}
|
|
4339
|
+
});
|
|
998
4340
|
const CompiledNavigationTargetSchema = exports.ResolvedNavigationTargetSchema.extend({
|
|
999
|
-
kind: zod_1.z.literal(
|
|
4341
|
+
kind: zod_1.z.literal("route"),
|
|
1000
4342
|
accessPolicy: exports.AccessPolicySchema,
|
|
1001
4343
|
routeClaim: exports.CompiledRouteClaimSchema,
|
|
1002
4344
|
}).strict();
|
|
1003
4345
|
exports.CompiledNavigationRegisteredMenuActionTargetSchema = exports.ResolvedNavigationTargetSchema.extend({
|
|
1004
|
-
kind: zod_1.z.literal(
|
|
4346
|
+
kind: zod_1.z.literal("registered-menu-action"),
|
|
1005
4347
|
accessPolicy: exports.AccessPolicySchema,
|
|
1006
|
-
execution: zod_1.z.literal(
|
|
4348
|
+
execution: zod_1.z.literal("client"),
|
|
1007
4349
|
applicationId: common_1.ContractIdentifierSchema,
|
|
1008
4350
|
actionRef: common_1.ContractIdentifierSchema,
|
|
1009
4351
|
inputSchemaRef: common_1.ContractIdentifierSchema.optional(),
|
|
@@ -1011,19 +4353,21 @@ exports.CompiledNavigationRegisteredMenuActionTargetSchema = exports.ResolvedNav
|
|
|
1011
4353
|
sourceCatalogRevisionRef: exports.RevisionRefSchema,
|
|
1012
4354
|
}).strict();
|
|
1013
4355
|
exports.CompiledNavigationDomainCommandTargetSchema = exports.ResolvedNavigationTargetSchema.extend({
|
|
1014
|
-
kind: zod_1.z.literal(
|
|
4356
|
+
kind: zod_1.z.literal("governed-domain-command"),
|
|
1015
4357
|
accessPolicy: exports.AccessPolicySchema,
|
|
1016
|
-
execution: zod_1.z.literal(
|
|
4358
|
+
execution: zod_1.z.literal("server"),
|
|
1017
4359
|
commandRevisionRef: exports.RevisionRefSchema,
|
|
1018
4360
|
inputSchemaRevisionRef: exports.RevisionRefSchema,
|
|
1019
4361
|
resultSchemaRevisionRef: exports.RevisionRefSchema.optional(),
|
|
1020
4362
|
input: common_1.JsonObjectSchema,
|
|
1021
4363
|
}).strict();
|
|
1022
|
-
exports.CompiledNavigationResolvedTargetSchema = zod_1.z.discriminatedUnion(
|
|
4364
|
+
exports.CompiledNavigationResolvedTargetSchema = zod_1.z.discriminatedUnion("kind", [
|
|
1023
4365
|
CompiledNavigationTargetSchema,
|
|
1024
4366
|
exports.CompiledNavigationRegisteredMenuActionTargetSchema,
|
|
1025
4367
|
exports.CompiledNavigationDomainCommandTargetSchema,
|
|
1026
|
-
exports.UnavailableNavigationTargetSchema.omit({ reason: true })
|
|
4368
|
+
exports.UnavailableNavigationTargetSchema.omit({ reason: true })
|
|
4369
|
+
.extend({ kind: zod_1.z.literal("unavailable") })
|
|
4370
|
+
.strict(),
|
|
1027
4371
|
]);
|
|
1028
4372
|
exports.CompiledNavigationGroupNodeSchema = exports.NavigationGroupNodeSchema.extend({
|
|
1029
4373
|
ancestorAccessPolicies: zod_1.z.array(exports.AccessPolicySchema),
|
|
@@ -1031,24 +4375,39 @@ exports.CompiledNavigationGroupNodeSchema = exports.NavigationGroupNodeSchema.ex
|
|
|
1031
4375
|
exports.CompiledNavigationTargetNodeSchema = exports.NavigationTargetNodeSchema.extend({
|
|
1032
4376
|
ancestorAccessPolicies: zod_1.z.array(exports.AccessPolicySchema),
|
|
1033
4377
|
resolvedTarget: exports.CompiledNavigationResolvedTargetSchema,
|
|
1034
|
-
})
|
|
1035
|
-
|
|
1036
|
-
|
|
4378
|
+
})
|
|
4379
|
+
.strict()
|
|
4380
|
+
.superRefine((node, context) => {
|
|
4381
|
+
if (node.resolvedTarget.nodeId !== node.nodeId ||
|
|
4382
|
+
stableRefIdentity(node.resolvedTarget.stableTargetRef) !==
|
|
4383
|
+
stableRefIdentity(node.targetRef)) {
|
|
4384
|
+
context.addIssue({
|
|
4385
|
+
code: "custom",
|
|
4386
|
+
path: ["resolvedTarget"],
|
|
4387
|
+
message: "Resolved target identity must match the source node.",
|
|
4388
|
+
});
|
|
1037
4389
|
}
|
|
1038
|
-
if (node.resolvedTarget.kind ===
|
|
1039
|
-
|
|
4390
|
+
if (node.resolvedTarget.kind === "unavailable" &&
|
|
4391
|
+
(node.disabled !== true ||
|
|
4392
|
+
Object.keys(node.parameterMapping).length > 0)) {
|
|
4393
|
+
context.addIssue({
|
|
4394
|
+
code: "custom",
|
|
4395
|
+
path: ["resolvedTarget"],
|
|
4396
|
+
message: "Unavailable targets must be disabled and contain no executable input.",
|
|
4397
|
+
});
|
|
1040
4398
|
}
|
|
1041
4399
|
});
|
|
1042
4400
|
exports.CompiledNavigationSeparatorNodeSchema = exports.NavigationSeparatorNodeSchema.extend({
|
|
1043
4401
|
ancestorAccessPolicies: zod_1.z.array(exports.AccessPolicySchema),
|
|
1044
4402
|
}).strict();
|
|
1045
|
-
exports.CompiledNavigationNodeSchema = zod_1.z.discriminatedUnion(
|
|
4403
|
+
exports.CompiledNavigationNodeSchema = zod_1.z.discriminatedUnion("kind", [
|
|
1046
4404
|
exports.CompiledNavigationGroupNodeSchema,
|
|
1047
4405
|
exports.CompiledNavigationTargetNodeSchema,
|
|
1048
4406
|
exports.CompiledNavigationSeparatorNodeSchema,
|
|
1049
4407
|
]);
|
|
1050
|
-
exports.NavigationRuntimeBundleSchema = zod_1.z
|
|
1051
|
-
|
|
4408
|
+
exports.NavigationRuntimeBundleSchema = zod_1.z
|
|
4409
|
+
.object({
|
|
4410
|
+
contract: zod_1.z.literal("NavigationRuntimeBundle"),
|
|
1052
4411
|
...RuntimeBundleBaseShape,
|
|
1053
4412
|
navigationId: common_1.ContractIdentifierSchema,
|
|
1054
4413
|
navigationRevisionRef: exports.RevisionRefSchema,
|
|
@@ -1057,27 +4416,38 @@ exports.NavigationRuntimeBundleSchema = zod_1.z.object({
|
|
|
1057
4416
|
nodes: zod_1.z.array(exports.CompiledNavigationNodeSchema),
|
|
1058
4417
|
performanceBudgetRef: exports.RevisionRefSchema,
|
|
1059
4418
|
observationPolicyRevisionRef: exports.RevisionRefSchema,
|
|
1060
|
-
})
|
|
4419
|
+
})
|
|
4420
|
+
.strict()
|
|
4421
|
+
.superRefine((value, context) => {
|
|
4422
|
+
validateRuntimeBundleBase(value, "navigation-release", context);
|
|
4423
|
+
validateRuntimeBundleReference(value.navigationRevisionRef, value.tenantScope, "navigationRevisionRef", "navigation", value.navigationId, context);
|
|
4424
|
+
});
|
|
1061
4425
|
exports.DeclarativeControlOntologyDefinitionSchema = data_1.OntologyDefinitionSchema.extend({
|
|
1062
|
-
classification: zod_1.z.literal(
|
|
1063
|
-
discovery: zod_1.z
|
|
4426
|
+
classification: zod_1.z.literal("control"),
|
|
4427
|
+
discovery: zod_1.z
|
|
4428
|
+
.object({
|
|
1064
4429
|
ordinaryDataBrowser: zod_1.z.literal(false),
|
|
1065
4430
|
businessSearch: zod_1.z.literal(false),
|
|
1066
4431
|
businessStatistics: zod_1.z.literal(false),
|
|
1067
4432
|
ordinaryExport: zod_1.z.literal(false),
|
|
1068
4433
|
genericWrite: zod_1.z.literal(false),
|
|
1069
|
-
})
|
|
4434
|
+
})
|
|
4435
|
+
.strict(),
|
|
1070
4436
|
}).strict();
|
|
1071
4437
|
const controlDefinition = (ontologyId, bodySchemaRef) => exports.DeclarativeControlOntologyDefinitionSchema.parse({
|
|
1072
|
-
contract:
|
|
4438
|
+
contract: "OntologyDefinition",
|
|
1073
4439
|
ontologyId,
|
|
1074
|
-
dataSpaceId:
|
|
1075
|
-
ownerRepo:
|
|
4440
|
+
dataSpaceId: "monkeys.control",
|
|
4441
|
+
ownerRepo: "monkeys-js-sdk",
|
|
1076
4442
|
bodySchemaRef,
|
|
1077
|
-
authority: {
|
|
4443
|
+
authority: {
|
|
4444
|
+
service: "monkeys-data-server",
|
|
4445
|
+
storage: "domain-record",
|
|
4446
|
+
scope: "tenant",
|
|
4447
|
+
},
|
|
1078
4448
|
relationKinds: [],
|
|
1079
4449
|
metricKinds: [],
|
|
1080
|
-
classification:
|
|
4450
|
+
classification: "control",
|
|
1081
4451
|
discovery: {
|
|
1082
4452
|
ordinaryDataBrowser: false,
|
|
1083
4453
|
businessSearch: false,
|
|
@@ -1087,11 +4457,11 @@ const controlDefinition = (ontologyId, bodySchemaRef) => exports.DeclarativeCont
|
|
|
1087
4457
|
},
|
|
1088
4458
|
});
|
|
1089
4459
|
exports.DECLARATIVE_CONTROL_ONTOLOGY_DEFINITIONS = Object.freeze([
|
|
1090
|
-
controlDefinition(
|
|
1091
|
-
controlDefinition(
|
|
1092
|
-
controlDefinition(
|
|
1093
|
-
controlDefinition(
|
|
1094
|
-
controlDefinition(
|
|
1095
|
-
controlDefinition(
|
|
4460
|
+
controlDefinition("monkeys.system.page", "monkeys.system.page/v1"),
|
|
4461
|
+
controlDefinition("monkeys.system.page-release", "monkeys.system.page-release/v1"),
|
|
4462
|
+
controlDefinition("monkeys.system.workbench", "monkeys.system.workbench/v1"),
|
|
4463
|
+
controlDefinition("monkeys.system.workbench-release", "monkeys.system.workbench-release/v1"),
|
|
4464
|
+
controlDefinition("monkeys.system.navigation", "monkeys.system.navigation/v1"),
|
|
4465
|
+
controlDefinition("monkeys.system.navigation-release", "monkeys.system.navigation-release/v1"),
|
|
1096
4466
|
]);
|
|
1097
4467
|
//# sourceMappingURL=declarative-control.js.map
|