openxiangda-contracts 2.63.0 → 2.69.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/dist/ai.d.ts +1 -1
- package/dist/ai.d.ts.map +1 -1
- package/dist/ai.js +4 -3
- package/dist/ai.js.map +1 -1
- package/dist/browser.d.ts +6 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +6 -0
- package/dist/browser.js.map +1 -1
- package/dist/concurrency.d.ts +1 -1
- package/dist/concurrency.d.ts.map +1 -1
- package/dist/data-field-validation.js +7 -2
- package/dist/data-field-validation.js.map +1 -1
- package/dist/field-value-schemas.d.ts +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/native-compiler/actor-authority.d.ts +11 -0
- package/dist/native-compiler/actor-authority.d.ts.map +1 -0
- package/dist/native-compiler/actor-authority.js +56 -0
- package/dist/native-compiler/actor-authority.js.map +1 -0
- package/dist/native-compiler/artifact-capacity.d.ts +12 -0
- package/dist/native-compiler/artifact-capacity.d.ts.map +1 -0
- package/dist/native-compiler/artifact-capacity.js +34 -0
- package/dist/native-compiler/artifact-capacity.js.map +1 -0
- package/dist/native-compiler/authenticated-public-read.d.ts +18 -0
- package/dist/native-compiler/authenticated-public-read.d.ts.map +1 -0
- package/dist/native-compiler/authenticated-public-read.js +79 -0
- package/dist/native-compiler/authenticated-public-read.js.map +1 -0
- package/dist/native-compiler/compiler.d.ts +2 -21
- package/dist/native-compiler/compiler.d.ts.map +1 -1
- package/dist/native-compiler/compiler.js +203 -46
- package/dist/native-compiler/compiler.js.map +1 -1
- package/dist/native-compiler/data-business-command.d.ts +3 -1
- package/dist/native-compiler/data-business-command.d.ts.map +1 -1
- package/dist/native-compiler/data-business-command.js.map +1 -1
- package/dist/native-compiler/data-capacity.d.ts +14 -3
- package/dist/native-compiler/data-capacity.d.ts.map +1 -1
- package/dist/native-compiler/data-capacity.js +11 -3
- package/dist/native-compiler/data-capacity.js.map +1 -1
- package/dist/native-compiler/data-field.d.ts +22 -0
- package/dist/native-compiler/data-field.d.ts.map +1 -1
- package/dist/native-compiler/data-field.js +19 -2
- package/dist/native-compiler/data-field.js.map +1 -1
- package/dist/native-compiler/date-event-projection.d.ts +13 -0
- package/dist/native-compiler/date-event-projection.d.ts.map +1 -0
- package/dist/native-compiler/date-event-projection.js +71 -0
- package/dist/native-compiler/date-event-projection.js.map +1 -0
- package/dist/native-compiler/declaration-capacity.d.ts +60 -0
- package/dist/native-compiler/declaration-capacity.d.ts.map +1 -0
- package/dist/native-compiler/declaration-capacity.js +32 -0
- package/dist/native-compiler/declaration-capacity.js.map +1 -0
- package/dist/native-compiler/development-backend.d.ts +84 -0
- package/dist/native-compiler/development-backend.d.ts.map +1 -0
- package/dist/native-compiler/development-backend.js +77 -0
- package/dist/native-compiler/development-backend.js.map +1 -0
- package/dist/native-compiler/development-configuration.d.ts +65 -0
- package/dist/native-compiler/development-configuration.d.ts.map +1 -0
- package/dist/native-compiler/development-configuration.js +143 -0
- package/dist/native-compiler/development-configuration.js.map +1 -0
- package/dist/native-compiler/index.cjs +6 -6
- package/dist/native-compiler/index.d.ts +13 -0
- package/dist/native-compiler/index.d.ts.map +1 -1
- package/dist/native-compiler/index.js +6 -6
- package/dist/native-compiler/record-set-guard.d.ts +5 -0
- package/dist/native-compiler/record-set-guard.d.ts.map +1 -0
- package/dist/native-compiler/record-set-guard.js +27 -0
- package/dist/native-compiler/record-set-guard.js.map +1 -0
- package/dist/native-compiler/user-candidates.d.ts +9 -1
- package/dist/native-compiler/user-candidates.d.ts.map +1 -1
- package/dist/native-compiler/user-candidates.js +14 -1
- package/dist/native-compiler/user-candidates.js.map +1 -1
- package/dist/native-compiler/workflow-approved-delegation.d.ts +39 -0
- package/dist/native-compiler/workflow-approved-delegation.d.ts.map +1 -0
- package/dist/native-compiler/workflow-approved-delegation.js +94 -0
- package/dist/native-compiler/workflow-approved-delegation.js.map +1 -0
- package/dist/native-compiler/workflow-business-command.d.ts +2 -2
- package/dist/native-compiler/workflow-business-command.d.ts.map +1 -1
- package/dist/native-compiler/workflow-business-command.js +8 -4
- package/dist/native-compiler/workflow-business-command.js.map +1 -1
- package/dist/native-compiler/workflow-completion-deadline.d.ts +41 -0
- package/dist/native-compiler/workflow-completion-deadline.d.ts.map +1 -0
- package/dist/native-compiler/workflow-completion-deadline.js +40 -0
- package/dist/native-compiler/workflow-completion-deadline.js.map +1 -0
- package/dist/native-compiler/workflow-correction.d.ts +16 -0
- package/dist/native-compiler/workflow-correction.d.ts.map +1 -0
- package/dist/native-compiler/workflow-correction.js +42 -0
- package/dist/native-compiler/workflow-correction.js.map +1 -0
- package/dist/native-compiler/workflow-delegation-administration.d.ts +73 -0
- package/dist/native-compiler/workflow-delegation-administration.d.ts.map +1 -1
- package/dist/native-compiler/workflow-delegation-administration.js +6 -4
- package/dist/native-compiler/workflow-delegation-administration.js.map +1 -1
- package/dist/native-compiler/workflow-graph.d.ts +13 -2
- package/dist/native-compiler/workflow-graph.d.ts.map +1 -1
- package/dist/native-compiler/workflow-graph.js +20 -4
- package/dist/native-compiler/workflow-graph.js.map +1 -1
- package/dist/native-compiler/workflow-initiator-approval.d.ts +5 -1
- package/dist/native-compiler/workflow-initiator-approval.d.ts.map +1 -1
- package/dist/native-compiler/workflow-initiator-approval.js +18 -3
- package/dist/native-compiler/workflow-initiator-approval.js.map +1 -1
- package/dist/native-compiler/workflow-native-stage.d.ts +69 -0
- package/dist/native-compiler/workflow-native-stage.d.ts.map +1 -0
- package/dist/native-compiler/workflow-native-stage.js +42 -0
- package/dist/native-compiler/workflow-native-stage.js.map +1 -0
- package/dist/native-compiler/workflow-node-administration.d.ts +5 -1
- package/dist/native-compiler/workflow-node-administration.d.ts.map +1 -1
- package/dist/native-compiler/workflow-node-administration.js +17 -4
- package/dist/native-compiler/workflow-node-administration.js.map +1 -1
- package/dist/native-compiler/workflow-owned-subject.d.ts +60 -0
- package/dist/native-compiler/workflow-owned-subject.d.ts.map +1 -0
- package/dist/native-compiler/workflow-owned-subject.js +69 -0
- package/dist/native-compiler/workflow-owned-subject.js.map +1 -0
- package/dist/native-compiler/workflow-role-union.d.ts +31 -0
- package/dist/native-compiler/workflow-role-union.d.ts.map +1 -0
- package/dist/native-compiler/workflow-role-union.js +38 -0
- package/dist/native-compiler/workflow-role-union.js.map +1 -0
- package/dist/native-compiler/workflow-task-page.d.ts +10 -3
- package/dist/native-compiler/workflow-task-page.d.ts.map +1 -1
- package/dist/native-compiler/workflow-task-page.js +5 -3
- package/dist/native-compiler/workflow-task-page.js.map +1 -1
- package/dist/native-version.d.ts +20 -0
- package/dist/native-version.d.ts.map +1 -1
- package/dist/native-version.js +20 -0
- package/dist/native-version.js.map +1 -1
- package/dist/native.d.ts +9 -0
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js.map +1 -1
- package/dist/references.d.ts +2 -0
- package/dist/references.d.ts.map +1 -1
- package/dist/schemas.d.ts +1708 -80
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +147 -27
- package/dist/schemas.js.map +1 -1
- package/dist/surface.d.ts +1 -0
- package/dist/surface.d.ts.map +1 -1
- package/dist/surface.js.map +1 -1
- package/dist/types.d.ts +87 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -2
- package/dist/types.js.map +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +26 -0
- package/dist/validation.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { assertWorkflowNativeStagePolicy } from './workflow-native-stage.js';
|
|
2
|
+
import { validateAuthenticatedPublicRead, AuthenticatedPublicReadContractError } from './authenticated-public-read.js';
|
|
3
|
+
import { validateUserCandidateReferences, validateWorkflowUserCandidateBindings, UserCandidateContractError, requiresUserCandidateLaunchScope } from './user-candidates.js';
|
|
2
4
|
import { NativeUniqueKeyContractError, parseNativeUniqueKeys, nativeUniqueKeysContractVersion } from './unique-keys.js';
|
|
3
5
|
import { validateManagedConcurrency, ManagedConcurrencyContractError } from './managed-concurrency.js';
|
|
4
6
|
import { normalizeDecimalReservationEventDeclaration, decimalReservationEventContext } from './decimal-reservation.js';
|
|
@@ -12,16 +14,23 @@ import { validateWorkflowAdministration } from './workflow-node-administration.j
|
|
|
12
14
|
import { validateWorkflowAutomaticCc } from './workflow-automatic-cc.js';
|
|
13
15
|
import { validateWorkflowApprovalEmptyPolicy, workflowBindingAllowsEmptyUsers } from './workflow-approval-empty.js';
|
|
14
16
|
import { validateWorkflowInitiatorApprovalPolicy } from './workflow-initiator-approval.js';
|
|
17
|
+
import { validateWorkflowCompletionDeadlines } from './workflow-completion-deadline.js';
|
|
15
18
|
import { validateWorkflowRejectionNotification } from './workflow-rejection-notification.js';
|
|
16
19
|
import { validateWorkflowCommandHandlers } from './workflow-business-command.js';
|
|
17
20
|
import { validateWorkflowLaunchPreflight } from './workflow-launch-preflight.js';
|
|
21
|
+
import { validateWorkflowApprovedDelegation } from './workflow-approved-delegation.js';
|
|
22
|
+
import { validateWorkflowCorrections } from './workflow-correction.js';
|
|
23
|
+
import { dateEventProjectionFieldsV2 } from './date-event-projection.js';
|
|
18
24
|
import { validateWorkflowTaskPages } from './workflow-task-page.js';
|
|
25
|
+
import { requiresExtendedOwnedSubtableCapacity } from './data-capacity.js';
|
|
19
26
|
import { validateWorkflowBusinessSteps, compileWorkflowBusinessStepHandlers, validateWorkflowBusinessStepSubscriptions, WORKFLOW_BUSINESS_STEP_EVENT, WORKFLOW_BUSINESS_STEP_EVENTS } from './workflow-business-step.js';
|
|
20
27
|
import { validateWorkflowAssignmentRoutingBindings, validateWorkflowAssignmentRoutingPolicy } from './workflow-assignment-routing.js';
|
|
28
|
+
import { requiresWorkflowRoleUnion, validateWorkflowRoleUnion } from './workflow-role-union.js';
|
|
29
|
+
import { assertWorkflowOwnedSubjectCreate, assertWorkflowOwnedSubjectCreateResources } from './workflow-owned-subject.js';
|
|
21
30
|
import * as crypto from 'crypto';
|
|
22
31
|
import { OPENXIANGDA_COMPILER_CONTRACT_VERSION as OPENXIANGDA_V2_COMPILER_CONTRACT_VERSION, PLATFORM_CAPABILITY_CONTRACT_VERSIONS as OPENXIANGDA_V2_PLATFORM_CAPABILITY_CONTRACT_VERSIONS, } from '../native-version.js';
|
|
23
32
|
import { canonicalJson, sha256Digest as sha256Canonical } from '../canonical.js';
|
|
24
|
-
import { NativeDataFieldContractV2Error, nativeFieldRequiresCreateInputV2, parseNativeDataFieldsV2, parseNativeDataResourceInvariantsV2, validateNativeDataResourceReferencesV2, } from './data-field.js';
|
|
33
|
+
import { NativeDataFieldContractV2Error, nativeFieldRequiresCreateInputV2, requiresDateTimeMinutePrecision, requiresOwnedSubtableMinimumRows, parseNativeDataFieldsV2, parseNativeDataResourceInvariantsV2, validateNativeDataResourceReferencesV2, } from './data-field.js';
|
|
25
34
|
import { validateNativeDataResourceSurfaceV2 } from './data-surface.js';
|
|
26
35
|
import { nativeFieldSupportsSortV2 } from './field-query-plan.js';
|
|
27
36
|
import { nativeScopeSourceGrantPathSupportedV2, nativeScopeSourceSubjectPathSupportedV2, resolveNativeScopeSourceFieldPathV2, } from './scope-source-field-path.js';
|
|
@@ -92,11 +101,10 @@ const WORKFLOW_OPERATIONS = new Set([
|
|
|
92
101
|
'admin_override',
|
|
93
102
|
'retry_resolution',
|
|
94
103
|
]);
|
|
95
|
-
const MAX_CONFIG_BYTES =
|
|
96
|
-
const MAX_CONTRACT_BYTES =
|
|
97
|
-
const MAX_DEPTH =
|
|
98
|
-
const
|
|
99
|
-
const MAX_STRING_BYTES = 1024 * 1024;
|
|
104
|
+
const MAX_CONFIG_BYTES = NATIVE_ARTIFACT_CAPACITY_V2.configBytes;
|
|
105
|
+
const MAX_CONTRACT_BYTES = NATIVE_ARTIFACT_CAPACITY_V2.contractBytes;
|
|
106
|
+
const MAX_DEPTH = NATIVE_ARTIFACT_CAPACITY_V2.depth;
|
|
107
|
+
const MAX_STRING_BYTES = NATIVE_ARTIFACT_CAPACITY_V2.stringBytes;
|
|
100
108
|
const EVENT_HANDLER_MANIFEST_SCHEMA = 'openxiangda.event-handler-manifest/v2';
|
|
101
109
|
const ROUTE_MANIFEST_SCHEMA = 'openxiangda.application-route-manifest/v3';
|
|
102
110
|
const EVENT_CAPTURE_FIELD_LIMIT = 64;
|
|
@@ -108,22 +116,10 @@ const EVENT_AUTHORIZATION_SYSTEM_FIELDS = new Set([
|
|
|
108
116
|
'created_at',
|
|
109
117
|
'updated_at',
|
|
110
118
|
]);
|
|
111
|
-
export
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
capabilities: 2000,
|
|
116
|
-
operations: 500,
|
|
117
|
-
eventConsumers: 100,
|
|
118
|
-
eventProducers: 1000,
|
|
119
|
-
eventSchemas: 100,
|
|
120
|
-
eventTypes: 500,
|
|
121
|
-
workflows: 100,
|
|
122
|
-
routes: 500,
|
|
123
|
-
adminPages: 500,
|
|
124
|
-
adminNavigationGroups: 100,
|
|
125
|
-
adminNavigationItems: 500,
|
|
126
|
-
});
|
|
119
|
+
export { NATIVE_CONTRACT_CAPACITY_V2, requiresExtendedDeclarationCapacity, generatedCrudCapabilityOperations } from './declaration-capacity.js';
|
|
120
|
+
import { NATIVE_CONTRACT_CAPACITY_V2, requiresExtendedDeclarationCapacity } from './declaration-capacity.js';
|
|
121
|
+
export { NATIVE_ARTIFACT_CAPACITY_V2, requiresExtendedArtifactCapacity } from './artifact-capacity.js';
|
|
122
|
+
import { NATIVE_ARTIFACT_CAPACITY_V2, requiresExtendedArtifactCapacity } from './artifact-capacity.js';
|
|
127
123
|
export const DATA_EVENT_TYPES_V2 = [
|
|
128
124
|
'openxiangda.data.record.created.v2',
|
|
129
125
|
'openxiangda.data.record.updated.v2',
|
|
@@ -197,8 +193,13 @@ export function compileNativeApplicationConfiguration(input) {
|
|
|
197
193
|
verifyArtifactDigest(contractSource, expectedContractDigest, '/contractBytes', 'NATIVE_CONTRACT_DIGEST_MISMATCH');
|
|
198
194
|
const parsedConfig = parseCanonicalArtifact(configSource, '/configBytes', 'NATIVE_CONFIG_JSON_INVALID', 'NATIVE_CONFIG_NOT_CANONICAL');
|
|
199
195
|
const parsedContract = parseCanonicalArtifact(contractSource, '/contractBytes', 'NATIVE_CONTRACT_JSON_INVALID', 'NATIVE_CONTRACT_NOT_CANONICAL');
|
|
200
|
-
|
|
201
|
-
|
|
196
|
+
// First enforce all global safety bounds before deriving an extension from
|
|
197
|
+
// untrusted input. The sealed configuration alone selects the larger budget.
|
|
198
|
+
inspectJsonBudget(parsedConfig, '/config', NATIVE_ARTIFACT_CAPACITY_V2.extendedNodes);
|
|
199
|
+
inspectJsonBudget(parsedContract, '/contracts', NATIVE_ARTIFACT_CAPACITY_V2.extendedNodes);
|
|
200
|
+
if (!requiresExtendedArtifactCapacity(parsedConfig)) {
|
|
201
|
+
inspectJsonBudget(parsedContract, '/contracts', NATIVE_ARTIFACT_CAPACITY_V2.legacyNodes);
|
|
202
|
+
}
|
|
202
203
|
const config = parsedConfig;
|
|
203
204
|
const contract = parsedContract;
|
|
204
205
|
validateConfigurationEnvelope(config, appCode);
|
|
@@ -287,6 +288,12 @@ export function compileNativeApplicationConfiguration(input) {
|
|
|
287
288
|
* Derives the platform capability usage closure from the normalized, sealed
|
|
288
289
|
* ConfigurationBundleV3. Manifest declarations are deliberately not an input.
|
|
289
290
|
*/
|
|
291
|
+
function workflowUsesOwnedInitialFacts(definition, resources) {
|
|
292
|
+
const subject = definition.subject;
|
|
293
|
+
const resource = resources.find(value => value.code === subject?.resourceCode);
|
|
294
|
+
const projected = new Set(Object.values(subject?.factProjection || {}));
|
|
295
|
+
return Boolean(resource?.schema?.fields?.some((field) => field.type === 'subtable' && projected.has(field.code)));
|
|
296
|
+
}
|
|
290
297
|
export function compileRequiredPlatformCapabilitiesV3(config) {
|
|
291
298
|
const roles = config.authz.roles;
|
|
292
299
|
const resources = config.data.resources;
|
|
@@ -374,6 +381,17 @@ export function compileRequiredPlatformCapabilitiesV3(config) {
|
|
|
374
381
|
},
|
|
375
382
|
};
|
|
376
383
|
const usages = [
|
|
384
|
+
...(requiresExtendedArtifactCapacity(config)
|
|
385
|
+
? [{ code: 'application.extended-artifact-capacity',
|
|
386
|
+
declaration: NATIVE_ARTIFACT_CAPACITY_V2 }] : []),
|
|
387
|
+
...(requiresExtendedDeclarationCapacity(config)
|
|
388
|
+
? [{ code: 'application.extended-declaration-capacity', declaration: {
|
|
389
|
+
resources: config.data.resources.length, policies: config.authz.dataPolicies.length,
|
|
390
|
+
roles: config.authz.roles.length, capabilities: config.authz.capabilities.length,
|
|
391
|
+
definitions: config.workflows.definitions.length, bindings: config.workflows.bindings.length,
|
|
392
|
+
activations: config.workflows.activations.length, routes: config.frontend.routes.length,
|
|
393
|
+
navigationItems: config.frontend.admin.navigation.reduce((count, group) => count + group.items.length, 0),
|
|
394
|
+
} }] : []),
|
|
377
395
|
...(resources.some(resource => resource.uniqueKeys?.length)
|
|
378
396
|
? [{ code: 'data.unique-keys', declaration: resources.filter(resource => resource.uniqueKeys?.length)
|
|
379
397
|
.map(resource => ({ code: resource.code, uniqueKeys: resource.uniqueKeys })) }] : []),
|
|
@@ -387,6 +405,17 @@ export function compileRequiredPlatformCapabilitiesV3(config) {
|
|
|
387
405
|
...(operations.some(operation => operation.platformAccess?.dataCommands)
|
|
388
406
|
? [{ code: 'data.business-commands', declaration: operations.filter(operation => operation.platformAccess?.dataCommands) }]
|
|
389
407
|
: []),
|
|
408
|
+
...(config.authz.dataPolicies.some((policy) => policy.publicRead)
|
|
409
|
+
? [{ code: 'data.authenticated-public-projection',
|
|
410
|
+
declaration: config.authz.dataPolicies.filter((policy) => policy.publicRead) }]
|
|
411
|
+
: []),
|
|
412
|
+
...(operations.some(operation => operation.platformAccess?.roleAssertions?.actorAuthority)
|
|
413
|
+
? [{ code: 'data.transaction-actor-authority',
|
|
414
|
+
declaration: operations.filter(operation => operation.platformAccess?.roleAssertions?.actorAuthority) }]
|
|
415
|
+
: []),
|
|
416
|
+
...(operations.some(operation => operation.platformAccess?.workflowStage)
|
|
417
|
+
? [{ code: 'workflow.native-stage-guard', declaration: operations.filter(operation => operation.platformAccess?.workflowStage) }]
|
|
418
|
+
: []),
|
|
390
419
|
...(operations.some(operation => operation.platformAccess?.recordEdit)
|
|
391
420
|
? [{ code: 'data.record-edit', declaration: operations.filter(operation => operation.platformAccess?.recordEdit) }]
|
|
392
421
|
: []),
|
|
@@ -514,6 +543,9 @@ export function compileRequiredPlatformCapabilitiesV3(config) {
|
|
|
514
543
|
...(config.events.capturePolicies?.length
|
|
515
544
|
? [{ code: 'events.capture-policy', declaration: config.events.capturePolicies }]
|
|
516
545
|
: []),
|
|
546
|
+
...(config.events.dateTriggers.some((trigger) => dateEventProjectionFieldsV2(trigger.resourceCode, config.events.subscriptions.filter((subscription) => subscription.eventTypes.includes(trigger.eventType)), config.data.resources.find((resource) => resource.code === trigger.resourceCode)).length > 0)
|
|
547
|
+
? [{ code: 'events.date-source-projection', declaration: { triggers: config.events.dateTriggers, subscriptions: config.events.subscriptions } }]
|
|
548
|
+
: []),
|
|
517
549
|
...(usesEvents
|
|
518
550
|
? [
|
|
519
551
|
{ code: 'events-v2', declaration: config.events },
|
|
@@ -523,9 +555,23 @@ export function compileRequiredPlatformCapabilitiesV3(config) {
|
|
|
523
555
|
},
|
|
524
556
|
]
|
|
525
557
|
: []),
|
|
558
|
+
...(requiresExtendedOwnedSubtableCapacity(config.data.resources)
|
|
559
|
+
? [{ code: 'data.extended-owned-subtable-capacity', declaration: config.data.resources.filter((resource) => requiresExtendedOwnedSubtableCapacity([resource])) }] : []),
|
|
526
560
|
...(config.data.resources.some((resource) => resource.schema.fields.some((field) => field.userCandidates !== undefined))
|
|
527
561
|
? [{ code: 'data.user-candidates', declaration: config.data.resources.filter((resource) => resource.schema.fields.some((field) => field.userCandidates !== undefined)) }]
|
|
528
562
|
: []),
|
|
563
|
+
...(requiresWorkflowRoleUnion(config.workflows.bindings)
|
|
564
|
+
? [{ code: 'workflow.role-union', declaration: config.workflows.bindings.filter((item) => Object.values(item.binding.bindings).some((entry) => entry.roleCodes !== undefined)) }] : []),
|
|
565
|
+
...(config.backend.operations.some((item) => item.platformAccess?.ownedSubject)
|
|
566
|
+
? [{ code: 'workflow.named-owned-create', declaration: config.backend.operations.filter((item) => item.platformAccess?.ownedSubject) }] : []),
|
|
567
|
+
...(requiresUserCandidateLaunchScope(config.data.resources)
|
|
568
|
+
? [{ code: 'data.user-candidate-launch-scope', declaration: config.data.resources.filter((resource) => requiresUserCandidateLaunchScope([resource])) }]
|
|
569
|
+
: []),
|
|
570
|
+
...(requiresOwnedSubtableMinimumRows(config.data.resources)
|
|
571
|
+
? [{ code: 'data.subtable-minimum-rows', declaration: config.data.resources.filter((resource) => requiresOwnedSubtableMinimumRows([resource])) }] : []),
|
|
572
|
+
...(requiresDateTimeMinutePrecision(config.data.resources)
|
|
573
|
+
? [{ code: 'data.datetime-minute-precision', declaration: config.data.resources.filter((resource) => requiresDateTimeMinutePrecision([resource])) }]
|
|
574
|
+
: []),
|
|
529
575
|
...(config.workflows.activations.length
|
|
530
576
|
? [
|
|
531
577
|
{
|
|
@@ -559,10 +605,23 @@ export function compileRequiredPlatformCapabilitiesV3(config) {
|
|
|
559
605
|
definitions: config.workflows.definitions.filter((item) => item.definition.commandHandlers !== undefined),
|
|
560
606
|
operations: operations.filter(operation => operation.platformAccess?.workflow?.businessCommands),
|
|
561
607
|
} }] : []),
|
|
608
|
+
...(config.workflows.definitions.some((item) => item.definition.commandHandlers?.resubmit) || operations.some(operation => operation.platformAccess?.workflow?.businessCommands?.includes('resubmit'))
|
|
609
|
+
? [{ code: 'workflow.correction-business-command', declaration: {
|
|
610
|
+
definitions: config.workflows.definitions.filter((item) => item.definition.commandHandlers?.resubmit),
|
|
611
|
+
operations: operations.filter(operation => operation.platformAccess?.workflow?.businessCommands?.includes('resubmit')),
|
|
612
|
+
} }] : []),
|
|
562
613
|
...(config.workflows.definitions.some((item) => item.definition.launchPreflight !== undefined)
|
|
563
614
|
? [{ code: 'workflow.launch-preflight', declaration: config.workflows.definitions.filter((item) => item.definition.launchPreflight !== undefined) }] : []),
|
|
615
|
+
...(config.workflows.definitions.some((item) => item.definition.approvedDelegation !== undefined)
|
|
616
|
+
? [{ code: 'workflow.approved-delegation', declaration: config.workflows.definitions.filter((item) => item.definition.approvedDelegation !== undefined) }] : []),
|
|
617
|
+
...(config.workflows.definitions.some((item) => workflowUsesOwnedInitialFacts(item.definition, config.data.resources))
|
|
618
|
+
? [{ code: 'workflow.owned-initial-facts', declaration: config.workflows.definitions.filter((item) => workflowUsesOwnedInitialFacts(item.definition, config.data.resources)) }] : []),
|
|
619
|
+
...(config.workflows.definitions.some((item) => Object.values(item.definition.nodes).some((node) => node.kind === 'correction'))
|
|
620
|
+
? [{ code: 'workflow.initiator-correction', declaration: config.workflows.definitions.filter((item) => Object.values(item.definition.nodes).some((node) => node.kind === 'correction')) }] : []),
|
|
564
621
|
...(config.workflows.definitions.some((item) => Object.values(item.definition.nodes).some((node) => node.operationPolicy?.reject?.commentRequired === false))
|
|
565
622
|
? [{ code: 'workflow.optional-rejection-comment', declaration: config.workflows.definitions.filter((item) => Object.values(item.definition.nodes).some((node) => node.operationPolicy?.reject?.commentRequired === false)) }] : []),
|
|
623
|
+
...(config.workflows.definitions.some((item) => Object.values(item.definition.nodes).some((node) => Object.values(node.operationPolicy || {}).some((policy) => policy.reasonRequired === false)))
|
|
624
|
+
? [{ code: 'workflow.optional-operation-reason', declaration: config.workflows.definitions.filter((item) => Object.values(item.definition.nodes).some((node) => Object.values(node.operationPolicy || {}).some((policy) => policy.reasonRequired === false))) }] : []),
|
|
566
625
|
...(namedInputSourceDefinitions.length
|
|
567
626
|
? [{ code: 'workflow.named-input-sources', declaration: namedInputSourceDefinitions }]
|
|
568
627
|
: []),
|
|
@@ -572,6 +631,9 @@ export function compileRequiredPlatformCapabilitiesV3(config) {
|
|
|
572
631
|
...(config.workflows.definitions.some((item) => Object.values(item.definition.nodes).some((node) => node.kind === 'approval' && node.emptyPolicy !== undefined))
|
|
573
632
|
? [{ code: 'workflow.approval-empty-policy', declaration: config.workflows.definitions.filter((item) => Object.values(item.definition.nodes).some((node) => node.kind === 'approval' && node.emptyPolicy !== undefined)) }]
|
|
574
633
|
: []),
|
|
634
|
+
...(config.workflows.definitions.some((item) => Object.values(item.definition.nodes).some((node) => node.completionDeadline !== undefined))
|
|
635
|
+
? [{ code: 'workflow.completion-deadline', declaration: config.workflows.definitions.filter((item) => Object.values(item.definition.nodes).some((node) => node.completionDeadline !== undefined)) }]
|
|
636
|
+
: []),
|
|
575
637
|
...(config.workflows.definitions.some((item) => Object.values(item.definition.nodes).some((node) => node.initiatorApprovalPolicy !== undefined))
|
|
576
638
|
? [{ code: 'workflow.initiator-approval-policy', declaration: config.workflows.definitions.filter((item) => Object.values(item.definition.nodes).some((node) => node.initiatorApprovalPolicy !== undefined)) }]
|
|
577
639
|
: []),
|
|
@@ -854,13 +916,13 @@ function validateConfigurationEnvelope(config, appCode) {
|
|
|
854
916
|
'dataPolicies',
|
|
855
917
|
'authorizationTransitions',
|
|
856
918
|
], '/config/authz', ['authenticatedUserRoleCode']);
|
|
857
|
-
boundedArray(authz.capabilities, '/config/authz/capabilities',
|
|
858
|
-
boundedArray(authz.roles, '/config/authz/roles',
|
|
919
|
+
boundedArray(authz.capabilities, '/config/authz/capabilities', NATIVE_CONTRACT_CAPACITY_V2.capabilities);
|
|
920
|
+
boundedArray(authz.roles, '/config/authz/roles', NATIVE_CONTRACT_CAPACITY_V2.roles);
|
|
859
921
|
boundedArray(authz.scopeDimensions, '/config/authz/scopeDimensions', 100);
|
|
860
922
|
boundedArray(authz.scopeSources, '/config/authz/scopeSources', 100);
|
|
861
923
|
boundedArray(authz.roleMembershipSources, '/config/authz/roleMembershipSources', 100);
|
|
862
924
|
boundedArray(authz.relationshipGrantSources, '/config/authz/relationshipGrantSources', 100);
|
|
863
|
-
boundedArray(authz.dataPolicies, '/config/authz/dataPolicies',
|
|
925
|
+
boundedArray(authz.dataPolicies, '/config/authz/dataPolicies', NATIVE_CONTRACT_CAPACITY_V2.dataPolicies);
|
|
864
926
|
boundedArray(authz.authorizationTransitions, '/config/authz/authorizationTransitions', 100);
|
|
865
927
|
const backend = object(config.backend, '/config/backend');
|
|
866
928
|
exactKeys(backend, ['secrets', 'operations'], '/config/backend');
|
|
@@ -873,7 +935,7 @@ function validateConfigurationEnvelope(config, appCode) {
|
|
|
873
935
|
'subjectReadSurfaces',
|
|
874
936
|
'concurrency',
|
|
875
937
|
]);
|
|
876
|
-
boundedArray(data.resources, '/config/data/resources',
|
|
938
|
+
boundedArray(data.resources, '/config/data/resources', NATIVE_CONTRACT_CAPACITY_V2.resources);
|
|
877
939
|
if (data.subjectReadSurfaces !== undefined) {
|
|
878
940
|
boundedArray(data.subjectReadSurfaces, '/config/data/subjectReadSurfaces', NATIVE_CONTRACT_CAPACITY_V2.subjectReadSurfaces);
|
|
879
941
|
}
|
|
@@ -894,14 +956,14 @@ function validateConfigurationEnvelope(config, appCode) {
|
|
|
894
956
|
'providers',
|
|
895
957
|
'editableParameters',
|
|
896
958
|
], '/config/workflows');
|
|
897
|
-
boundedArray(workflows.definitions, '/config/workflows/definitions',
|
|
898
|
-
boundedArray(workflows.bindings, '/config/workflows/bindings',
|
|
899
|
-
boundedArray(workflows.activations, '/config/workflows/activations',
|
|
959
|
+
boundedArray(workflows.definitions, '/config/workflows/definitions', NATIVE_CONTRACT_CAPACITY_V2.workflows);
|
|
960
|
+
boundedArray(workflows.bindings, '/config/workflows/bindings', NATIVE_CONTRACT_CAPACITY_V2.workflows);
|
|
961
|
+
boundedArray(workflows.activations, '/config/workflows/activations', NATIVE_CONTRACT_CAPACITY_V2.workflows);
|
|
900
962
|
boundedArray(workflows.providers, '/config/workflows/providers', 100);
|
|
901
963
|
boundedArray(workflows.editableParameters, '/config/workflows/editableParameters', 100);
|
|
902
964
|
const frontend = object(config.frontend, '/config/frontend');
|
|
903
965
|
exactKeys(frontend, ['routes', 'user', 'admin', 'devicePolicy'], '/config/frontend', ['authentication', 'publicAccess']);
|
|
904
|
-
boundedArray(frontend.routes, '/config/frontend/routes',
|
|
966
|
+
boundedArray(frontend.routes, '/config/frontend/routes', NATIVE_CONTRACT_CAPACITY_V2.routes);
|
|
905
967
|
const user = object(frontend.user, '/config/frontend/user');
|
|
906
968
|
exactKeys(user, ['applicationTodoCenter'], '/config/frontend/user');
|
|
907
969
|
boolean(user.applicationTodoCenter, '/config/frontend/user/applicationTodoCenter');
|
|
@@ -1609,6 +1671,12 @@ function compileOperations(config) {
|
|
|
1609
1671
|
const code = stableCode(operation.code, `${pointer}/code`);
|
|
1610
1672
|
validateBackendOperationAi(operation.ai, pointer, code, method, declaredResourceCodes);
|
|
1611
1673
|
const platformAccess = validateOperationPlatformAccess(operation.platformAccess, `${pointer}/platformAccess`, declaredResources, declaredResourceFields, declaredWorkflowCodes, new Set(config.authz.roles.map((role) => String(role.code))));
|
|
1674
|
+
if (platformAccess?.workflowStage) {
|
|
1675
|
+
const stage = platformAccess.workflowStage;
|
|
1676
|
+
const workflow = config.workflows.definitions.find((entry) => entry.definition.code === stage.workflowCode);
|
|
1677
|
+
if (!workflow || workflow.definition.subject?.resourceCode !== stage.resourceCode || stage.runningNodeIds.some((id) => !workflow.definition.nodes[id]))
|
|
1678
|
+
fail('NATIVE_WORKFLOW_STAGE_NODE_INVALID', `${pointer}/platformAccess/workflowStage/runningNodeIds`);
|
|
1679
|
+
}
|
|
1612
1680
|
if (platformAccess?.recordEdit) {
|
|
1613
1681
|
const owner = config.data.resources.find((item) => item.code === platformAccess.recordEdit.resourceCode);
|
|
1614
1682
|
if (owner?.surface?.mutationOwner !== 'action')
|
|
@@ -1814,7 +1882,7 @@ function validateOperationPlatformAccess(value, pointer, declaredResources, decl
|
|
|
1814
1882
|
if (value === undefined)
|
|
1815
1883
|
return null;
|
|
1816
1884
|
const access = object(value, pointer);
|
|
1817
|
-
exactKeys(access, ['directory', 'managedFiles', 'managedFileCopies', 'notification', 'workflow', 'roleAssertions', 'decimalReservation', 'dataCommands', 'recordEdit'], pointer, true);
|
|
1885
|
+
exactKeys(access, ['directory', 'managedFiles', 'managedFileCopies', 'notification', 'workflow', 'roleAssertions', 'decimalReservation', 'dataCommands', 'recordEdit', 'ownedSubject', 'workflowStage'], pointer, true);
|
|
1818
1886
|
if (Object.keys(access).length === 0) {
|
|
1819
1887
|
fail('NATIVE_OPERATION_PLATFORM_ACCESS_EMPTY', pointer);
|
|
1820
1888
|
}
|
|
@@ -1825,6 +1893,19 @@ function validateOperationPlatformAccess(value, pointer, declaredResources, decl
|
|
|
1825
1893
|
equal(commands.mode, 'recoverable-native', `${pointer}/dataCommands/mode`);
|
|
1826
1894
|
result.dataCommands = { mode: 'recoverable-native' };
|
|
1827
1895
|
}
|
|
1896
|
+
if (access.workflowStage !== undefined) {
|
|
1897
|
+
try {
|
|
1898
|
+
assertWorkflowNativeStagePolicy(access.workflowStage);
|
|
1899
|
+
}
|
|
1900
|
+
catch {
|
|
1901
|
+
fail('NATIVE_WORKFLOW_STAGE_DECLARATION_INVALID', `${pointer}/workflowStage`);
|
|
1902
|
+
}
|
|
1903
|
+
const stage = access.workflowStage;
|
|
1904
|
+
if (!result.dataCommands || access.decimalReservation !== undefined || !declaredResources.has(stage.resourceCode) ||
|
|
1905
|
+
!declaredWorkflowCodes.has(stage.workflowCode) || !access.workflow?.codes?.includes(stage.workflowCode))
|
|
1906
|
+
fail('NATIVE_WORKFLOW_STAGE_DECLARATION_INVALID', `${pointer}/workflowStage`);
|
|
1907
|
+
result.workflowStage = { ...stage, runningNodeIds: uniqueSorted([...stage.runningNodeIds]), allowedStatuses: uniqueSorted([...stage.allowedStatuses]) };
|
|
1908
|
+
}
|
|
1828
1909
|
if (access.recordEdit !== undefined) {
|
|
1829
1910
|
const entryPointer = `${pointer}/recordEdit`;
|
|
1830
1911
|
const entry = object(access.recordEdit, entryPointer);
|
|
@@ -1843,7 +1924,9 @@ function validateOperationPlatformAccess(value, pointer, declaredResources, decl
|
|
|
1843
1924
|
}
|
|
1844
1925
|
if (access.roleAssertions !== undefined) {
|
|
1845
1926
|
const assertions = object(access.roleAssertions, `${pointer}/roleAssertions`);
|
|
1846
|
-
exactKeys(assertions, ['roleCodes'], `${pointer}/roleAssertions
|
|
1927
|
+
exactKeys(assertions, ['roleCodes', 'actorAuthority'], `${pointer}/roleAssertions`, true);
|
|
1928
|
+
if (assertions.actorAuthority !== undefined)
|
|
1929
|
+
equal(assertions.actorAuthority, true, `${pointer}/roleAssertions/actorAuthority`);
|
|
1847
1930
|
const codes = uniqueStrings(assertions.roleCodes, `${pointer}/roleAssertions/roleCodes`, 20);
|
|
1848
1931
|
if (!codes.length)
|
|
1849
1932
|
fail('NATIVE_OPERATION_ROLE_ASSERTIONS_REQUIRED', `${pointer}/roleAssertions/roleCodes`);
|
|
@@ -1851,7 +1934,8 @@ function validateOperationPlatformAccess(value, pointer, declaredResources, decl
|
|
|
1851
1934
|
if (!declaredRoleCodes.has(code))
|
|
1852
1935
|
fail('NATIVE_ROLE_REFERENCE_MISSING', `${pointer}/roleAssertions/roleCodes/${index}`);
|
|
1853
1936
|
});
|
|
1854
|
-
result.roleAssertions = { roleCodes: uniqueSorted(codes)
|
|
1937
|
+
result.roleAssertions = { roleCodes: uniqueSorted(codes),
|
|
1938
|
+
...(assertions.actorAuthority === true ? { actorAuthority: true } : {}) };
|
|
1855
1939
|
}
|
|
1856
1940
|
if (access.directory !== undefined) {
|
|
1857
1941
|
const directory = object(access.directory, `${pointer}/directory`);
|
|
@@ -1964,12 +2048,33 @@ function validateOperationPlatformAccess(value, pointer, declaredResources, decl
|
|
|
1964
2048
|
if (!codes.length || codes.some(code => !declaredWorkflowCodes.has(code))) {
|
|
1965
2049
|
fail('NATIVE_OPERATION_WORKFLOW_CODE_INVALID', `${pointer}/workflow/codes`);
|
|
1966
2050
|
}
|
|
1967
|
-
const businessCommands = workflow.businessCommands === undefined ? undefined : uniqueStrings(workflow.businessCommands, `${pointer}/workflow/businessCommands`,
|
|
1968
|
-
if (businessCommands && (!businessCommands.length || businessCommands.some(command => !['approve', 'reject', 'withdraw'].includes(command)))) {
|
|
2051
|
+
const businessCommands = workflow.businessCommands === undefined ? undefined : uniqueStrings(workflow.businessCommands, `${pointer}/workflow/businessCommands`, 4);
|
|
2052
|
+
if (businessCommands && (!businessCommands.length || businessCommands.some(command => !['approve', 'reject', 'withdraw', 'resubmit'].includes(command)))) {
|
|
1969
2053
|
fail('NATIVE_OPERATION_WORKFLOW_BUSINESS_COMMAND_INVALID', `${pointer}/workflow/businessCommands`);
|
|
1970
2054
|
}
|
|
1971
2055
|
result.workflow = { codes: uniqueSorted(codes), ...(businessCommands ? { businessCommands: uniqueSorted(businessCommands) } : {}) };
|
|
1972
2056
|
}
|
|
2057
|
+
if (access.ownedSubject !== undefined) {
|
|
2058
|
+
const entryPointer = `${pointer}/ownedSubject`;
|
|
2059
|
+
const grant = access.ownedSubject;
|
|
2060
|
+
try {
|
|
2061
|
+
assertWorkflowOwnedSubjectCreate(grant);
|
|
2062
|
+
}
|
|
2063
|
+
catch {
|
|
2064
|
+
fail('NATIVE_WORKFLOW_OWNED_SUBJECT_INVALID', entryPointer);
|
|
2065
|
+
}
|
|
2066
|
+
if (!result.workflow || access.decimalReservation !== undefined)
|
|
2067
|
+
fail('NATIVE_WORKFLOW_OWNED_SUBJECT_INVALID', entryPointer);
|
|
2068
|
+
try {
|
|
2069
|
+
assertWorkflowOwnedSubjectCreateResources(grant, declaredResourceFields, result.managedFiles || []);
|
|
2070
|
+
}
|
|
2071
|
+
catch (error) {
|
|
2072
|
+
fail(`NATIVE_${error.message}`, entryPointer);
|
|
2073
|
+
}
|
|
2074
|
+
result.ownedSubject = { mode: 'create', resourceCode: grant.resourceCode, subtables: sorted(grant.subtables.map(table => ({
|
|
2075
|
+
fieldCode: table.fieldCode, fieldCodes: uniqueSorted([...table.fieldCodes]),
|
|
2076
|
+
})), table => table.fieldCode) };
|
|
2077
|
+
}
|
|
1973
2078
|
if (access.decimalReservation !== undefined) {
|
|
1974
2079
|
const reservationPointer = `${pointer}/decimalReservation`;
|
|
1975
2080
|
const reservation = object(access.decimalReservation, reservationPointer);
|
|
@@ -2933,6 +3038,8 @@ function compileAdminNavigation(config) {
|
|
|
2933
3038
|
}
|
|
2934
3039
|
function validateAdminNavigationDeclaration(value, pointer) {
|
|
2935
3040
|
const groups = boundedArray(value, pointer, NATIVE_CONTRACT_CAPACITY_V2.adminNavigationGroups);
|
|
3041
|
+
if (groups.reduce((count, group) => count + (Array.isArray(group?.items) ? group.items.length : 0), 0) > NATIVE_CONTRACT_CAPACITY_V2.adminNavigationItems)
|
|
3042
|
+
fail('NATIVE_ARRAY_LIMIT_EXCEEDED', pointer);
|
|
2936
3043
|
let itemCount = 0;
|
|
2937
3044
|
groups.forEach((rawGroup, groupIndex) => {
|
|
2938
3045
|
const groupPointer = `${pointer}/${groupIndex}`;
|
|
@@ -3073,6 +3180,8 @@ function validateAdminPageContracts(value, pointer) {
|
|
|
3073
3180
|
}
|
|
3074
3181
|
function validateAdminNavigationContracts(value, pointer) {
|
|
3075
3182
|
const groups = boundedArray(value, pointer, NATIVE_CONTRACT_CAPACITY_V2.adminNavigationGroups);
|
|
3183
|
+
if (groups.reduce((count, group) => count + (Array.isArray(group?.items) ? group.items.length : 0), 0) > NATIVE_CONTRACT_CAPACITY_V2.adminNavigationItems)
|
|
3184
|
+
fail('NATIVE_ARRAY_LIMIT_EXCEEDED', pointer);
|
|
3076
3185
|
let itemCount = 0;
|
|
3077
3186
|
groups.forEach((rawGroup, groupIndex) => {
|
|
3078
3187
|
const groupPointer = `${pointer}/${groupIndex}`;
|
|
@@ -3594,6 +3703,9 @@ function compileWorkflowLaunchContract(config, definition, value, pointer, opera
|
|
|
3594
3703
|
const fieldCodes = new Set();
|
|
3595
3704
|
const sourceCounts = new Map();
|
|
3596
3705
|
const normalizedInputs = {};
|
|
3706
|
+
const ownedSubject = operationContract.platformAccess?.ownedSubject;
|
|
3707
|
+
if (ownedSubject && (intentKind !== 'create' || ownedSubject.resourceCode !== subjectResourceCode))
|
|
3708
|
+
fail('NATIVE_WORKFLOW_OWNED_SUBJECT_LAUNCH_MISMATCH', intentPointer);
|
|
3597
3709
|
for (const [inputCode, rawBinding] of inputEntries) {
|
|
3598
3710
|
if (!PROPERTY_CODE_PATTERN.test(inputCode) ||
|
|
3599
3711
|
!Object.prototype.hasOwnProperty.call(requestProperties, inputCode)) {
|
|
@@ -3620,6 +3732,9 @@ function compileWorkflowLaunchContract(config, definition, value, pointer, opera
|
|
|
3620
3732
|
fail('NATIVE_WORKFLOW_NAMED_OPERATION_INPUT_INVALID', `${bindingPointer}/fieldCode`);
|
|
3621
3733
|
}
|
|
3622
3734
|
fieldCodes.add(fieldCode);
|
|
3735
|
+
const field = subjectResource.schema.fields.find((item) => item.code === fieldCode);
|
|
3736
|
+
if (field?.type === 'subtable' && (!ownedSubject || !ownedSubject.subtables.some((table) => table.fieldCode === fieldCode)))
|
|
3737
|
+
fail('NATIVE_WORKFLOW_OWNED_SUBJECT_LAUNCH_REQUIRED', bindingPointer);
|
|
3623
3738
|
normalizedInputs[inputCode] = { source, fieldCode };
|
|
3624
3739
|
}
|
|
3625
3740
|
else {
|
|
@@ -4075,6 +4190,7 @@ function validateDataPolicyReferences(config) {
|
|
|
4075
4190
|
'name',
|
|
4076
4191
|
'resourceCode',
|
|
4077
4192
|
'unrestrictedRoleCodes',
|
|
4193
|
+
'publicRead',
|
|
4078
4194
|
'operations',
|
|
4079
4195
|
'matchMode',
|
|
4080
4196
|
'rules',
|
|
@@ -4106,6 +4222,26 @@ function validateDataPolicyReferences(config) {
|
|
|
4106
4222
|
if (hasReadExpression && !policyFields) {
|
|
4107
4223
|
fail('NATIVE_DATA_POLICY_RESOURCE_MISSING', `${pointer}/resourceCode`);
|
|
4108
4224
|
}
|
|
4225
|
+
if (policy.publicRead !== undefined) {
|
|
4226
|
+
try {
|
|
4227
|
+
const baseline = config.authz.roles.find((role) => role.code === authenticatedUserRoleCode);
|
|
4228
|
+
validateAuthenticatedPublicRead({ policy,
|
|
4229
|
+
resource: config.data.resources.find((resource) => resource.code === policyResourceCode),
|
|
4230
|
+
baselineRoleCode: authenticatedUserRoleCode,
|
|
4231
|
+
baselineCapabilities: baseline?.capabilities || [],
|
|
4232
|
+
baselineDeniedCapabilities: baseline?.deniedCapabilities || [], pointer });
|
|
4233
|
+
}
|
|
4234
|
+
catch (error) {
|
|
4235
|
+
if (!(error instanceof AuthenticatedPublicReadContractError))
|
|
4236
|
+
throw error;
|
|
4237
|
+
fail(error.code, error.pointer);
|
|
4238
|
+
}
|
|
4239
|
+
if (!(policy.unrestrictedRoleCodes || []).includes(authenticatedUserRoleCode))
|
|
4240
|
+
fail('AUTHENTICATED_PUBLIC_READ_CANONICAL_BASELINE_MISSING', `${pointer}/unrestrictedRoleCodes`);
|
|
4241
|
+
}
|
|
4242
|
+
else if (authenticatedUserRoleCode && (policy.unrestrictedRoleCodes || []).includes(authenticatedUserRoleCode)) {
|
|
4243
|
+
fail('NATIVE_DATA_POLICY_BASELINE_UNRESTRICTED', `${pointer}/unrestrictedRoleCodes`);
|
|
4244
|
+
}
|
|
4109
4245
|
const unrestrictedRoleCodes = uniqueStrings(policy.unrestrictedRoleCodes || [], `${pointer}/unrestrictedRoleCodes`, 100);
|
|
4110
4246
|
if (policy.unrestrictedRoleCodes !== undefined &&
|
|
4111
4247
|
unrestrictedRoleCodes.length === 0) {
|
|
@@ -4482,6 +4618,9 @@ function validateWorkflowReferences(config) {
|
|
|
4482
4618
|
const preflightErrors = validateWorkflowLaunchPreflight(definition);
|
|
4483
4619
|
if (preflightErrors.length)
|
|
4484
4620
|
fail(preflightErrors[0], `${pointer}/definition/launchPreflight`);
|
|
4621
|
+
const delegationErrors = validateWorkflowApprovedDelegation(definition);
|
|
4622
|
+
if (delegationErrors.length)
|
|
4623
|
+
fail(delegationErrors[0], `${pointer}/definition/approvedDelegation`);
|
|
4485
4624
|
const businessCommandErrors = validateWorkflowCommandHandlers(definition, config.backend.operations);
|
|
4486
4625
|
if (businessCommandErrors.length)
|
|
4487
4626
|
fail(businessCommandErrors[0], `${pointer}/definition/commandHandlers`);
|
|
@@ -4723,7 +4862,7 @@ function validateWorkflowDefinition(definition, pointer) {
|
|
|
4723
4862
|
'startAt',
|
|
4724
4863
|
'inputSchema',
|
|
4725
4864
|
'nodes',
|
|
4726
|
-
], pointer, ['organizationContext', 'instanceCommands', 'readability', 'taskPages', 'rejectionNotification', 'commandHandlers', 'launchPreflight']);
|
|
4865
|
+
], pointer, ['organizationContext', 'instanceCommands', 'readability', 'taskPages', 'rejectionNotification', 'commandHandlers', 'launchPreflight', 'approvedDelegation']);
|
|
4727
4866
|
equal(definition.schemaVersion, 'openxiangda.workflow-definition/v2', `${pointer}/schemaVersion`);
|
|
4728
4867
|
workflowCodeValue(definition.code, `${pointer}/code`);
|
|
4729
4868
|
requiredString(definition.title, `${pointer}/title`, 255);
|
|
@@ -4748,6 +4887,9 @@ function validateWorkflowDefinition(definition, pointer) {
|
|
|
4748
4887
|
const initiatorPolicyErrors = validateWorkflowInitiatorApprovalPolicy(definition);
|
|
4749
4888
|
if (initiatorPolicyErrors.length)
|
|
4750
4889
|
fail(initiatorPolicyErrors[0], `${pointer}/nodes`);
|
|
4890
|
+
const deadlineErrors = validateWorkflowCompletionDeadlines(definition);
|
|
4891
|
+
if (deadlineErrors.length)
|
|
4892
|
+
fail(deadlineErrors[0], `${pointer}/nodes`);
|
|
4751
4893
|
const rejectionNotificationErrors = validateWorkflowRejectionNotification(definition);
|
|
4752
4894
|
if (rejectionNotificationErrors.length)
|
|
4753
4895
|
fail(rejectionNotificationErrors[0], `${pointer}/rejectionNotification`);
|
|
@@ -4767,7 +4909,7 @@ function validateWorkflowDefinition(definition, pointer) {
|
|
|
4767
4909
|
const nodePointer = `${pointer}/nodes/${nodeId}`;
|
|
4768
4910
|
const node = object(rawNode, nodePointer);
|
|
4769
4911
|
equal(node.id, nodeId, `${nodePointer}/id`);
|
|
4770
|
-
if (!['approval', 'condition', 'end', 'cc', 'action'].includes(node.kind)) {
|
|
4912
|
+
if (!['approval', 'condition', 'end', 'cc', 'action', 'correction'].includes(node.kind)) {
|
|
4771
4913
|
fail('NATIVE_WORKFLOW_NODE_KIND_INVALID', `${nodePointer}/kind`);
|
|
4772
4914
|
}
|
|
4773
4915
|
const targets = [];
|
|
@@ -4789,6 +4931,11 @@ function validateWorkflowDefinition(definition, pointer) {
|
|
|
4789
4931
|
}
|
|
4790
4932
|
}
|
|
4791
4933
|
}
|
|
4934
|
+
else if (node.kind === 'correction') {
|
|
4935
|
+
const errors = validateWorkflowCorrections(definition);
|
|
4936
|
+
if (errors.length)
|
|
4937
|
+
fail(errors[0], nodePointer);
|
|
4938
|
+
}
|
|
4792
4939
|
else if (node.kind === 'action') {
|
|
4793
4940
|
targets.push(requiredString(node.next, `${nodePointer}/next`, 128));
|
|
4794
4941
|
}
|
|
@@ -4833,6 +4980,13 @@ function validateWorkflowDefinition(definition, pointer) {
|
|
|
4833
4980
|
visiting.delete(nodeId);
|
|
4834
4981
|
};
|
|
4835
4982
|
walk(startAt);
|
|
4983
|
+
for (const id of [...reachable]) {
|
|
4984
|
+
const current = nodes[id];
|
|
4985
|
+
if (current?.kind === 'approval')
|
|
4986
|
+
for (const target of current.returnTargets || [])
|
|
4987
|
+
if (nodes[target]?.kind === 'correction')
|
|
4988
|
+
reachable.add(target);
|
|
4989
|
+
}
|
|
4836
4990
|
if (reachable.size !== nodeIds.length) {
|
|
4837
4991
|
fail('NATIVE_WORKFLOW_NODE_UNREACHABLE', `${pointer}/nodes`);
|
|
4838
4992
|
}
|
|
@@ -4879,6 +5033,9 @@ function validateWorkflowBinding(binding, pointer) {
|
|
|
4879
5033
|
for (const [code, raw] of Object.entries(entries)) {
|
|
4880
5034
|
workflowBindingCode(code, `${pointer}/bindings/${code}`);
|
|
4881
5035
|
const entry = object(raw, `${pointer}/bindings/${code}`);
|
|
5036
|
+
const unionErrors = validateWorkflowRoleUnion(entry);
|
|
5037
|
+
if (unionErrors.length)
|
|
5038
|
+
fail(unionErrors[0], `${pointer}/bindings/${code}/roleCodes`);
|
|
4882
5039
|
const provider = requiredString(entry.provider, `${pointer}/bindings/${code}/provider`, 64);
|
|
4883
5040
|
if (![
|
|
4884
5041
|
'fixed_users',
|
|
@@ -4903,7 +5060,7 @@ function validateWorkflowBinding(binding, pointer) {
|
|
|
4903
5060
|
if (['input_users', 'form_field_users'].includes(provider)) {
|
|
4904
5061
|
requiredString(entry.inputPath, `${pointer}/bindings/${code}/inputPath`, 255);
|
|
4905
5062
|
}
|
|
4906
|
-
if (['app_role', 'app_role_in_scope', 'initiator_select'].includes(provider)) {
|
|
5063
|
+
if (['app_role', 'app_role_in_scope', 'initiator_select'].includes(provider) && entry.roleCodes === undefined) {
|
|
4907
5064
|
stableCode(entry.roleCode, `${pointer}/bindings/${code}/roleCode`);
|
|
4908
5065
|
}
|
|
4909
5066
|
if (provider === 'department_supervisor') {
|
|
@@ -4952,13 +5109,13 @@ function mergeUserSurfaceRoutes(expectedContract, contract, config) {
|
|
|
4952
5109
|
const manifest = object(contract.routeManifest, '/contracts/routeManifest');
|
|
4953
5110
|
const expectedManifest = object(expectedContract.routeManifest, '/contracts/routeManifest');
|
|
4954
5111
|
const resources = new Map();
|
|
4955
|
-
for (const raw of boundedArray(config.data?.resources, '/config/data/resources',
|
|
5112
|
+
for (const raw of boundedArray(config.data?.resources, '/config/data/resources', NATIVE_CONTRACT_CAPACITY_V2.resources)) {
|
|
4956
5113
|
const resource = object(raw, '/config/data/resources');
|
|
4957
5114
|
resources.set(String(resource.code || ''), resource);
|
|
4958
5115
|
}
|
|
4959
|
-
const existingCodes = new Set(boundedArray(expectedManifest.routes, '/contracts/routeManifest/routes',
|
|
5116
|
+
const existingCodes = new Set(boundedArray(expectedManifest.routes, '/contracts/routeManifest/routes', NATIVE_CONTRACT_CAPACITY_V2.routes).map(entry => String(object(entry, '/contracts/routeManifest/routes').code || '')));
|
|
4960
5117
|
const accepted = [];
|
|
4961
|
-
for (const rawEntry of boundedArray(manifest.routes, '/contracts/routeManifest/routes',
|
|
5118
|
+
for (const rawEntry of boundedArray(manifest.routes, '/contracts/routeManifest/routes', NATIVE_CONTRACT_CAPACITY_V2.routes)) {
|
|
4962
5119
|
const entry = object(rawEntry, '/contracts/routeManifest/routes');
|
|
4963
5120
|
const kind = String(entry.kind || '');
|
|
4964
5121
|
if (kind !== 'resource-records' && kind !== 'resource-submit')
|
|
@@ -5160,11 +5317,11 @@ function parseCanonicalArtifact(source, pointer, invalidCode, canonicalCode) {
|
|
|
5160
5317
|
fail(canonicalCode, pointer);
|
|
5161
5318
|
return result;
|
|
5162
5319
|
}
|
|
5163
|
-
function inspectJsonBudget(value, pointer) {
|
|
5320
|
+
function inspectJsonBudget(value, pointer, maxNodes) {
|
|
5164
5321
|
let nodes = 0;
|
|
5165
5322
|
const visit = (current, path, depth) => {
|
|
5166
5323
|
nodes += 1;
|
|
5167
|
-
if (nodes >
|
|
5324
|
+
if (nodes > maxNodes)
|
|
5168
5325
|
fail('NATIVE_ARTIFACT_NODE_LIMIT_EXCEEDED', path);
|
|
5169
5326
|
if (depth > MAX_DEPTH)
|
|
5170
5327
|
fail('NATIVE_ARTIFACT_DEPTH_LIMIT_EXCEEDED', path);
|