@astrale-os/kernel-dsl 1.0.0-beta.2 → 1.0.0-beta.20
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/v1/addressing/class-key.js +3 -3
- package/dist/v1/addressing/definition-ref.js +21 -37
- package/dist/v1/addressing/domain-dependency.d.ts +0 -6
- package/dist/v1/addressing/domain-dependency.js +1 -6
- package/dist/v1/addressing/key.d.ts +4 -1
- package/dist/v1/addressing/key.js +23 -3
- package/dist/v1/addressing/ordering.d.ts +2 -0
- package/dist/v1/addressing/ordering.js +4 -0
- package/dist/v1/addressing/patterns.d.ts +1 -1
- package/dist/v1/addressing/patterns.js +2 -6
- package/dist/v1/builder/callable/authoring.d.ts +11 -5
- package/dist/v1/builder/callable/authoring.js +2 -0
- package/dist/v1/builder/class/authoring.d.ts +94 -224
- package/dist/v1/builder/class/authoring.js +31 -33
- package/dist/v1/builder/class/handle.d.ts +27 -0
- package/dist/v1/builder/class/handle.js +1 -0
- package/dist/v1/builder/class/input.d.ts +159 -0
- package/dist/v1/builder/class/projection.d.ts +129 -0
- package/dist/v1/builder/class/projection.js +1 -0
- package/dist/v1/builder/class/property.d.ts +3 -9
- package/dist/v1/builder/class/property.js +1 -0
- package/dist/v1/builder/core/authoring.d.ts +1 -1
- package/dist/v1/builder/index.d.ts +5 -2
- package/dist/v1/builder/lowering/callable.js +1 -0
- package/dist/v1/builder/lowering/class.d.ts +9 -1
- package/dist/v1/builder/lowering/class.js +62 -17
- package/dist/v1/builder/lowering/policy.js +2 -0
- package/dist/v1/builder/lowering/property-keys.d.ts +27 -0
- package/dist/v1/builder/lowering/property-keys.js +108 -0
- package/dist/v1/builder/lowering/schema/compile.js +11 -6
- package/dist/v1/builder/lowering/schema/context.d.ts +9 -1
- package/dist/v1/builder/lowering/schema/context.js +36 -4
- package/dist/v1/builder/lowering/schema/lifetime.d.ts +11 -0
- package/dist/v1/builder/lowering/schema/lifetime.js +55 -0
- package/dist/v1/builder/lowering/value/path.d.ts +1 -1
- package/dist/v1/builder/lowering/value/path.js +2 -4
- package/dist/v1/builder/lowering/value/zod.js +1 -3
- package/dist/v1/builder/policy/authoring.d.ts +85 -5
- package/dist/v1/builder/policy/authoring.js +107 -68
- package/dist/v1/builder/schema/define.d.ts +0 -1
- package/dist/v1/builder/schema/diagnostic.d.ts +3 -2
- package/dist/v1/builder/schema/diagnostic.js +5 -10
- package/dist/v1/builder/schema/input.d.ts +1 -1
- package/dist/v1/builder/schema/projection/callable.d.ts +7 -5
- package/dist/v1/builder/schema/projection/class.d.ts +118 -15
- package/dist/v1/builder/schema/projection/core-input.d.ts +2 -1
- package/dist/v1/builder/schema/projection/identity.d.ts +2 -1
- package/dist/v1/builder/schema/projection/model.d.ts +4 -2
- package/dist/v1/builder/schema/projection/property.d.ts +1 -1
- package/dist/v1/builder/schema/projection/resolved-class.d.ts +2 -1
- package/dist/v1/builder/schema/projection.d.ts +1 -1
- package/dist/v1/builder/value/full-match.d.ts +0 -1
- package/dist/v1/builder/value/full-match.js +0 -1
- package/dist/v1/builder/value/path-metadata.d.ts +1 -1
- package/dist/v1/builder/value/path.d.ts +1 -1
- package/dist/v1/bundle/codec.js +11 -13
- package/dist/v1/bundle/diagnostic.d.ts +2 -0
- package/dist/v1/bundle/diagnostic.js +9 -7
- package/dist/v1/bundle/model.js +1 -1
- package/dist/v1/bundle/structure.js +4 -6
- package/dist/v1/compiled/admission/accept.js +4 -10
- package/dist/v1/compiled/admission/closure.js +2 -2
- package/dist/v1/compiled/admission/diagnostic.d.ts +1 -1
- package/dist/v1/compiled/admission/diagnostic.js +1 -3
- package/dist/v1/compiled/admission/revision.d.ts +9 -1
- package/dist/v1/compiled/admission/revision.js +6 -3
- package/dist/v1/compiled/admission/semantics/class.d.ts +4 -1
- package/dist/v1/compiled/admission/semantics/class.js +37 -12
- package/dist/v1/compiled/admission/semantics/core.d.ts +1 -24
- package/dist/v1/compiled/admission/semantics/core.js +56 -24
- package/dist/v1/compiled/admission/semantics/edge.d.ts +2 -4
- package/dist/v1/compiled/admission/semantics/edge.js +6 -65
- package/dist/v1/compiled/admission/semantics/policy/callable.js +0 -2
- package/dist/v1/compiled/admission/semantics/policy/contracts.d.ts +5 -20
- package/dist/v1/compiled/admission/semantics/policy/contracts.js +8 -21
- package/dist/v1/compiled/admission/semantics/policy/parity.js +40 -43
- package/dist/v1/compiled/admission/semantics/policy/pattern.d.ts +4 -1
- package/dist/v1/compiled/admission/semantics/policy/pattern.js +4 -16
- package/dist/v1/compiled/admission/semantics/policy/typing.d.ts +2 -24
- package/dist/v1/compiled/admission/semantics/policy/typing.js +19 -201
- package/dist/v1/compiled/admission/wire/callable.js +11 -1
- package/dist/v1/compiled/admission/wire/class.js +73 -21
- package/dist/v1/compiled/admission/wire/policy.d.ts +4 -3
- package/dist/v1/compiled/admission/wire/policy.js +8 -7
- package/dist/v1/compiled/compiler/compile.js +8 -8
- package/dist/v1/compiled/diagnostic.js +2 -3
- package/dist/v1/compiled/loader/load.d.ts +3 -2
- package/dist/v1/compiled/loader/load.js +11 -45
- package/dist/v1/domain/create.js +5 -6
- package/dist/v1/domain/model/domain.d.ts +2 -7
- package/dist/v1/domain/model/input.d.ts +2 -1
- package/dist/v1/domain/namespace/member-collection.js +4 -6
- package/dist/v1/domain/projection/classes.js +4 -1
- package/dist/v1/domain/validation/create.d.ts +6 -3
- package/dist/v1/domain/validation/create.js +21 -69
- package/dist/v1/index.d.ts +2 -1
- package/dist/v1/language/.spec/schemas/draft-2020-12.schema.json +462 -0
- package/dist/v1/language/.spec/schemas/value-schema.schema.json +22 -0
- package/dist/v1/language/callable/admission.d.ts +15 -0
- package/dist/v1/language/callable/admission.js +43 -0
- package/dist/v1/language/callable/model/callable.d.ts +10 -0
- package/dist/v1/language/callable/resolved.d.ts +16 -3
- package/dist/v1/language/class/inheritance.d.ts +36 -5
- package/dist/v1/language/class/inheritance.js +87 -1
- package/dist/v1/language/class/lifetime.d.ts +50 -11
- package/dist/v1/language/class/lifetime.js +89 -20
- package/dist/v1/language/class/model/class.d.ts +45 -9
- package/dist/v1/language/class/model/edge.d.ts +31 -2
- package/dist/v1/language/class/model/property.d.ts +16 -7
- package/dist/v1/language/class/property-values.js +2 -4
- package/dist/v1/language/class/unique.d.ts +143 -0
- package/dist/v1/language/class/unique.js +264 -0
- package/dist/v1/language/core/facts.d.ts +85 -0
- package/dist/v1/language/core/facts.js +116 -0
- package/dist/v1/language/definition/metadata.d.ts +5 -0
- package/dist/v1/language/definition/metadata.js +7 -0
- package/dist/v1/language/freeze.d.ts +5 -0
- package/dist/v1/{schema/canonical → language}/freeze.js +4 -0
- package/dist/v1/language/index.d.ts +7 -2
- package/dist/v1/language/index.js +5 -1
- package/dist/v1/language/limits.d.ts +64 -0
- package/dist/v1/language/limits.js +60 -0
- package/dist/v1/language/policy/analysis/branches.d.ts +8 -0
- package/dist/v1/language/policy/analysis/branches.js +2 -1
- package/dist/v1/language/policy/analysis/budgets.d.ts +45 -12
- package/dist/v1/language/policy/analysis/budgets.js +133 -19
- package/dist/v1/language/policy/analysis/checks.js +3 -2
- package/dist/v1/language/policy/analysis/typing.d.ts +51 -0
- package/dist/v1/language/policy/analysis/typing.js +455 -0
- package/dist/v1/language/policy/model/policy.d.ts +49 -9
- package/dist/v1/language/policy/model/policy.js +14 -0
- package/dist/v1/language/policy/normalization/normalize.d.ts +6 -6
- package/dist/v1/language/policy/normalization/normalize.js +22 -21
- package/dist/v1/language/validation/diagnostic.d.ts +15 -1
- package/dist/v1/language/validation/diagnostic.js +21 -0
- package/dist/v1/language/validation/rule.d.ts +45 -0
- package/dist/v1/language/validation/rule.js +109 -0
- package/dist/v1/language/value/compile/fields.js +4 -8
- package/dist/v1/language/value/evaluate/program.d.ts +2 -1
- package/dist/v1/language/value/evaluate/program.js +2 -2
- package/dist/v1/language/value/evaluate/validate.d.ts +2 -2
- package/dist/v1/language/value/evaluate/validate.js +6 -2
- package/dist/v1/language/value/evaluate/validity.optimization.d.ts +14 -0
- package/dist/v1/language/value/evaluate/validity.optimization.js +342 -0
- package/dist/v1/language/value/inclusion/arrays.d.ts +3 -0
- package/dist/v1/language/value/inclusion/arrays.js +85 -0
- package/dist/v1/language/value/inclusion/assertions.d.ts +18 -0
- package/dist/v1/language/value/inclusion/assertions.js +29 -0
- package/dist/v1/language/value/inclusion/combinators.d.ts +3 -0
- package/dist/v1/language/value/inclusion/combinators.js +67 -0
- package/dist/v1/language/value/inclusion/equivalence.d.ts +4 -0
- package/dist/v1/language/value/inclusion/equivalence.js +74 -0
- package/dist/v1/language/value/inclusion/evidence.d.ts +34 -0
- package/dist/v1/language/value/inclusion/evidence.js +138 -0
- package/dist/v1/language/value/inclusion/includes.d.ts +17 -0
- package/dist/v1/language/value/inclusion/includes.js +25 -719
- package/dist/v1/language/value/inclusion/keywords.d.ts +5 -0
- package/dist/v1/language/value/inclusion/keywords.js +31 -0
- package/dist/v1/language/value/inclusion/kinds.d.ts +17 -0
- package/dist/v1/language/value/inclusion/kinds.js +57 -0
- package/dist/v1/language/value/inclusion/location.d.ts +24 -0
- package/dist/v1/language/value/inclusion/location.js +63 -0
- package/dist/v1/language/value/inclusion/numbers.d.ts +3 -0
- package/dist/v1/language/value/inclusion/numbers.js +41 -0
- package/dist/v1/language/value/inclusion/objects.d.ts +3 -0
- package/dist/v1/language/value/inclusion/objects.js +190 -0
- package/dist/v1/language/value/inclusion/strings.d.ts +3 -0
- package/dist/v1/language/value/inclusion/strings.js +29 -0
- package/dist/v1/language/value/inclusion/types.d.ts +3 -0
- package/dist/v1/language/value/inclusion/types.js +11 -0
- package/dist/v1/language/value/ordering.d.ts +14 -0
- package/dist/v1/language/value/ordering.js +86 -9
- package/dist/v1/language/value/profile/canonicalize.js +6 -5
- package/dist/v1/language/value/profile/json.validate.d.ts +3 -1
- package/dist/v1/language/value/profile/json.validate.js +3 -2
- package/dist/v1/language/value/profile/meta-schema.compiled.js +4 -1
- package/dist/v1/language/value/profile/rules.js +17 -43
- package/dist/v1/language/value/profile/validate.js +1 -10
- package/dist/v1/language/value/profile/vocabulary.d.ts +35 -2
- package/dist/v1/language/value/profile/vocabulary.js +52 -5
- package/dist/v1/language/value/reference/closure.js +3 -4
- package/dist/v1/language/value/reference/recursion.js +2 -22
- package/dist/v1/language/value/reference/registry.index.d.ts +2 -0
- package/dist/v1/language/value/reference/registry.index.js +33 -16
- package/dist/v1/language/value/regexp/ast.js +6 -7
- package/dist/v1/language/value/regexp/compile.d.ts +5 -11
- package/dist/v1/language/value/regexp/compile.js +14 -12
- package/dist/v1/language/value/regexp/syntax.js +3 -2
- package/dist/v1/language/value/syntax/keywords.d.ts +3 -3
- package/dist/v1/language/value/syntax/keywords.js +4 -20
- package/dist/v1/language/value/syntax/node-path/validate.js +2 -3
- package/dist/v1/language/value/syntax/pointer.d.ts +2 -0
- package/dist/v1/language/value/syntax/pointer.js +5 -2
- package/dist/v1/language/value/syntax/walk.d.ts +2 -0
- package/dist/v1/language/value/syntax/walk.js +19 -20
- package/dist/v1/schema/.spec/schemas/domain-schema.schema.json +2519 -0
- package/dist/v1/schema/admission/accept.js +3 -14
- package/dist/v1/schema/admission/callable.d.ts +21 -0
- package/dist/v1/schema/admission/callable.js +96 -0
- package/dist/v1/schema/analysis/class.js +33 -15
- package/dist/v1/schema/canonical/revision.js +4 -4
- package/dist/v1/schema/compatibility/api.d.ts +2 -1
- package/dist/v1/schema/compatibility/api.js +1 -0
- package/dist/v1/schema/compatibility/comparators/callables.js +1 -1
- package/dist/v1/schema/compatibility/comparators/classes.d.ts +9 -4
- package/dist/v1/schema/compatibility/comparators/classes.js +29 -8
- package/dist/v1/schema/compatibility/comparators/index.d.ts +1 -1
- package/dist/v1/schema/compatibility/comparators/members.js +1 -1
- package/dist/v1/schema/compatibility/comparators/values.js +2 -2
- package/dist/v1/schema/compatibility/coordinate.js +3 -3
- package/dist/v1/schema/compatibility/diff.js +2 -4
- package/dist/v1/schema/compatibility/extension.d.ts +11 -0
- package/dist/v1/schema/compatibility/extension.js +22 -0
- package/dist/v1/schema/compatibility/fields.d.ts +20 -4
- package/dist/v1/schema/compatibility/fields.js +13 -3
- package/dist/v1/schema/compatibility/meaning/footprint.js +16 -50
- package/dist/v1/schema/compatibility/model.d.ts +17 -5
- package/dist/v1/schema/compatibility/report.js +1 -1
- package/dist/v1/schema/compatibility/scope.d.ts +2 -0
- package/dist/v1/schema/compatibility/scope.js +4 -1
- package/dist/v1/schema/compatibility/structure/index.js +6 -4
- package/dist/v1/schema/compatibility/structure/requirements.js +57 -58
- package/dist/v1/schema/compatibility/versioning/index.js +1 -1
- package/dist/v1/schema/compatibility/versioning/surface.d.ts +1 -1
- package/dist/v1/schema/compatibility/versioning/surface.js +30 -2
- package/dist/v1/schema/compatibility/walk.d.ts +17 -0
- package/dist/v1/schema/compatibility/walk.js +41 -0
- package/dist/v1/schema/diagnostic.d.ts +17 -3
- package/dist/v1/schema/diagnostic.js +14 -11
- package/dist/v1/schema/index.d.ts +10 -1
- package/dist/v1/schema/index.js +4 -0
- package/dist/v1/schema/model/schema.d.ts +20 -1
- package/dist/v1/schema/model/schema.js +1 -1
- package/dist/v1/schema/normalization/domain.d.ts +2 -0
- package/dist/v1/schema/normalization/domain.js +29 -9
- package/dist/v1/schema/resolution/closure.js +2 -1
- package/dist/v1/schema/resolution/context.js +13 -13
- package/dist/v1/schema/resolution/domain.d.ts +5 -0
- package/dist/v1/schema/resolution/domain.js +2 -2
- package/dist/v1/schema/resolution/origins.js +3 -2
- package/dist/v1/schema/rule.d.ts +26 -0
- package/dist/v1/schema/rule.js +440 -0
- package/dist/v1/schema/validation/callable.d.ts +35 -2
- package/dist/v1/schema/validation/callable.js +65 -9
- package/dist/v1/schema/validation/class.d.ts +6 -2
- package/dist/v1/schema/validation/class.js +127 -104
- package/dist/v1/schema/validation/core.js +90 -168
- package/dist/v1/schema/validation/domain.js +4 -13
- package/dist/v1/schema/validation/domain.json-schema.d.ts +15 -0
- package/dist/v1/schema/validation/domain.json-schema.js +197 -0
- package/dist/v1/schema/validation/domain.route.d.ts +6 -1
- package/dist/v1/schema/validation/domain.route.js +18 -0
- package/dist/v1/schema/validation/domain.structure.d.ts +7780 -0
- package/dist/v1/schema/validation/domain.structure.js +398 -147
- package/dist/v1/schema/validation/json.json-schema.d.ts +40 -0
- package/dist/v1/schema/validation/json.json-schema.js +46 -0
- package/dist/v1/schema/validation/policy/budgets.d.ts +33 -2
- package/dist/v1/schema/validation/policy/budgets.js +87 -121
- package/dist/v1/schema/validation/policy/context.d.ts +6 -5
- package/dist/v1/schema/validation/policy/context.js +7 -10
- package/dist/v1/schema/validation/policy/objects.d.ts +1 -1
- package/dist/v1/schema/validation/policy/objects.js +6 -14
- package/dist/v1/schema/validation/policy/references.js +11 -27
- package/dist/v1/schema/validation/policy/typing.d.ts +3 -18
- package/dist/v1/schema/validation/policy/typing.js +22 -356
- package/dist/v1/schema/validation/policy/uses.d.ts +40 -3
- package/dist/v1/schema/validation/policy/uses.js +66 -89
- package/dist/v1/schema/validation/policy/validate.js +5 -5
- package/dist/v1/schema/validation/value-api.d.ts +22 -0
- package/dist/v1/schema/validation/value-api.js +34 -1
- package/dist/v1/schema/validation/value.d.ts +3 -0
- package/dist/v1/schema/validation/value.js +9 -17
- package/dist/v1/schema/validation/value.json-schema.d.ts +49 -0
- package/dist/v1/schema/validation/value.json-schema.js +137 -0
- package/dist/v1/schema/validation/view.js +4 -8
- package/dist/value/canonical.d.ts +6 -0
- package/dist/value/canonical.js +36 -0
- package/dist/value/decode.d.ts +7 -0
- package/dist/value/decode.js +159 -9
- package/dist/value/index.d.ts +1 -1
- package/dist/value/json.d.ts +2 -2
- package/dist/value/json.js +2 -2
- package/dist/value/types.d.ts +6 -0
- package/dist/value/unicode.d.ts +2 -1
- package/dist/value/unicode.js +2 -0
- package/package.json +8 -1
- package/dist/v1/builder/lowering/core-properties.d.ts +0 -10
- package/dist/v1/builder/lowering/core-properties.js +0 -76
- package/dist/v1/compiled/admission/semantics/cardinality.d.ts +0 -5
- package/dist/v1/compiled/admission/semantics/cardinality.js +0 -113
- package/dist/v1/compiled/admission/semantics/policy/equality.d.ts +0 -8
- package/dist/v1/compiled/admission/semantics/policy/equality.js +0 -27
- package/dist/v1/compiled/admission/semantics/policy/measure.d.ts +0 -9
- package/dist/v1/compiled/admission/semantics/policy/measure.js +0 -81
- package/dist/v1/compiled/admission/semantics/policy/variants.d.ts +0 -10
- package/dist/v1/compiled/admission/semantics/policy/variants.js +0 -65
- package/dist/v1/language/class/index.d.ts +0 -8
- package/dist/v1/language/class/index.js +0 -1
- package/dist/v1/language/core/index.d.ts +0 -2
- package/dist/v1/language/value/index.d.ts +0 -11
- package/dist/v1/language/value/index.js +0 -8
- package/dist/v1/schema/canonical/domain.d.ts +0 -3
- package/dist/v1/schema/canonical/domain.digest.d.ts +0 -3
- package/dist/v1/schema/canonical/domain.digest.js +0 -5
- package/dist/v1/schema/canonical/domain.js +0 -5
- package/dist/v1/schema/canonical/freeze.d.ts +0 -1
- /package/dist/v1/{language/core/index.js → builder/class/input.js} +0 -0
|
@@ -1,61 +1,156 @@
|
|
|
1
|
-
import { array, boolean, custom, discriminatedUnion, enum as enumeration, lazy, literal, null as nullSchema, number, record, strictObject, string, tuple, union, } from 'zod';
|
|
1
|
+
import { array, boolean, custom, discriminatedUnion, enum as enumeration, lazy, literal, null as nullSchema, number, record, registry, strictObject, string, tuple, union, } from 'zod';
|
|
2
2
|
import { PropertyKey as SemanticPropertyKey } from '../../addressing/index.js';
|
|
3
|
-
import { CORE_SLUG_PATTERN, DEPENDENCY_ALIAS_PATTERN, DOMAIN_ORIGIN_PATTERN, DOMAIN_REVISION_PATTERN, MEMBER_NAME_PATTERN, } from '../../addressing/patterns.js';
|
|
3
|
+
import { CORE_SLUG_PATTERN, DEPENDENCY_ALIAS_PATTERN, DOMAIN_ORIGIN_PATTERN, DOMAIN_REVISION_PATTERN, MEMBER_NAME_PATTERN, PROPERTY_KEY_PATTERN, } from '../../addressing/patterns.js';
|
|
4
4
|
import { MEDIA_TYPE_PATTERN } from '../../language/class/model/data.js';
|
|
5
5
|
import * as metadata from '../../language/definition/metadata.js';
|
|
6
|
-
import {
|
|
6
|
+
import { limits } from '../../language/limits.js';
|
|
7
|
+
import { BLOB_VALUE_KIND, isBlobValueSchema } from '../../language/value/model/blob.js';
|
|
8
|
+
import { escapePointerToken } from '../../language/value/syntax/pointer.js';
|
|
9
|
+
import { SchemaError, diagnostic, } from '../diagnostic.js';
|
|
7
10
|
import { DOMAIN_FORMAT, DOMAIN_VERSION } from '../model/format.js';
|
|
8
|
-
const
|
|
9
|
-
|
|
11
|
+
export const documentJsonSchema = registry();
|
|
12
|
+
/**
|
|
13
|
+
* The checks of the structure JSON Schema cannot state. The published document names each with the
|
|
14
|
+
* positions it constrains, so that a validator of the document knows what it leaves to the Kernel.
|
|
15
|
+
*/
|
|
16
|
+
export const structureRules = {
|
|
17
|
+
'unique-tuple-set': {
|
|
18
|
+
code: 'STRUCTURE_DUPLICATE_ITEM',
|
|
19
|
+
statement: 'A unique tuple is a set of fields: two tuples naming the same fields in another order are one tuple, repeated.',
|
|
20
|
+
},
|
|
21
|
+
'length-in-utf16-code-units': {
|
|
22
|
+
code: 'STRUCTURE_MAXIMUM',
|
|
23
|
+
statement: 'A maxLength counts UTF-16 code units, where JSON Schema counts code points: a string within the bound in code points and beyond it in code units is refused.',
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
// The pattern refuses `__proto__`, which zod skips before any key check (`lostProtoKeys`).
|
|
27
|
+
const RESERVED_DEPENDENCY_ALIASES = ['prototype', 'constructor'];
|
|
28
|
+
const originSchema = string()
|
|
29
|
+
.min(3)
|
|
30
|
+
.max(253)
|
|
31
|
+
.regex(DOMAIN_ORIGIN_PATTERN)
|
|
32
|
+
.register(documentJsonSchema, { id: 'origin' });
|
|
33
|
+
const memberNameSchema = string()
|
|
34
|
+
.regex(MEMBER_NAME_PATTERN)
|
|
35
|
+
.register(documentJsonSchema, { id: 'name' });
|
|
10
36
|
const dependencyAliasSchema = string()
|
|
11
37
|
.regex(DEPENDENCY_ALIAS_PATTERN)
|
|
12
|
-
.refine((value) => value
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
38
|
+
.refine((value) => !RESERVED_DEPENDENCY_ALIASES.includes(value), {
|
|
39
|
+
message: 'Expected a non-reserved dependency alias.',
|
|
40
|
+
params: { structureCode: 'STRUCTURE_DEPENDENCY_ALIAS' },
|
|
41
|
+
})
|
|
42
|
+
.register(documentJsonSchema, {
|
|
43
|
+
id: 'dependency-alias',
|
|
44
|
+
not: { enum: [...RESERVED_DEPENDENCY_ALIASES] },
|
|
45
|
+
});
|
|
46
|
+
const propertyKeySchema = string()
|
|
47
|
+
.refine(SemanticPropertyKey.is, {
|
|
48
|
+
message: 'Expected a canonical PropertyKey.',
|
|
49
|
+
params: { structureCode: 'STRUCTURE_PROPERTY_KEY' },
|
|
50
|
+
})
|
|
51
|
+
.register(documentJsonSchema, { id: 'property-key', pattern: PROPERTY_KEY_PATTERN.source });
|
|
52
|
+
const coreSlugSchema = string()
|
|
53
|
+
.min(1)
|
|
54
|
+
.max(100)
|
|
55
|
+
.regex(CORE_SLUG_PATTERN)
|
|
56
|
+
.register(documentJsonSchema, { id: 'core-slug' });
|
|
57
|
+
const revisionSchema = string()
|
|
58
|
+
.regex(DOMAIN_REVISION_PATTERN)
|
|
59
|
+
.register(documentJsonSchema, { id: 'revision' });
|
|
16
60
|
const descriptionSchema = string()
|
|
17
61
|
.min(metadata.description.minLength)
|
|
18
|
-
.max(metadata.description.maxLength)
|
|
19
|
-
|
|
62
|
+
.max(metadata.description.maxLength)
|
|
63
|
+
.register(documentJsonSchema, { id: 'description' });
|
|
64
|
+
const iconSchema = string()
|
|
65
|
+
.min(metadata.icon.minLength)
|
|
66
|
+
.max(metadata.icon.maxLength)
|
|
67
|
+
.register(documentJsonSchema, { id: 'icon' });
|
|
20
68
|
const domainNameSchema = string()
|
|
21
69
|
.min(metadata.name.minLength)
|
|
22
70
|
.max(metadata.name.maxLength)
|
|
23
|
-
.refine(metadata.isDomainNameText,
|
|
71
|
+
.refine(metadata.isDomainNameText, {
|
|
72
|
+
message: 'Expected one trimmed line of text.',
|
|
73
|
+
params: { structureCode: 'STRUCTURE_DOMAIN_NAME' },
|
|
74
|
+
})
|
|
75
|
+
.register(documentJsonSchema, {
|
|
76
|
+
id: 'domain-name',
|
|
77
|
+
description: 'The display name of the Domain: one trimmed line of text.',
|
|
78
|
+
pattern: metadata.DOMAIN_NAME_TEXT_PATTERN.source,
|
|
79
|
+
});
|
|
80
|
+
// Zod skips a `__proto__` member, which the structure therefore refuses (`lostProtoKeys`). The JSON
|
|
81
|
+
// Schema refuses it by the fields of a closed object and the pattern of a record's names; a record
|
|
82
|
+
// of any string states it here, by its property names.
|
|
83
|
+
const PROTO_KEY = '__proto__';
|
|
84
|
+
const anyKeyRecord = { propertyNames: { not: { const: PROTO_KEY } } };
|
|
24
85
|
const jsonValueSchema = lazy(() => union([
|
|
25
86
|
nullSchema(),
|
|
26
87
|
boolean(),
|
|
27
88
|
number(),
|
|
28
89
|
string(),
|
|
29
90
|
array(jsonValueSchema),
|
|
30
|
-
record(string(), jsonValueSchema),
|
|
31
|
-
]));
|
|
32
|
-
const jsonObjectSchema = record(string(), jsonValueSchema);
|
|
33
|
-
const jsonSchemaSchema = union([boolean(), jsonObjectSchema])
|
|
91
|
+
record(string(), jsonValueSchema).register(documentJsonSchema, anyKeyRecord),
|
|
92
|
+
])).register(documentJsonSchema, { id: 'json-value' });
|
|
93
|
+
const jsonObjectSchema = record(string(), jsonValueSchema).register(documentJsonSchema, anyKeyRecord);
|
|
94
|
+
const jsonSchemaSchema = union([boolean(), jsonObjectSchema]).register(documentJsonSchema, {
|
|
95
|
+
id: 'value-schema',
|
|
96
|
+
description: 'A value schema of the dialect https://schemas.astrale.ai/dsl/v1/value-schema. The structure admits any boolean or object; the language admits its keywords.',
|
|
97
|
+
});
|
|
34
98
|
const dataDeclarationSchema = strictObject({
|
|
35
|
-
mediaType: string().regex(MEDIA_TYPE_PATTERN),
|
|
99
|
+
mediaType: string().regex(MEDIA_TYPE_PATTERN).register(documentJsonSchema, { id: 'media-type' }),
|
|
36
100
|
});
|
|
37
101
|
const stateNameSchema = string().min(1);
|
|
38
|
-
|
|
102
|
+
// A custom check reads the relation in place: a record would copy it and drop a `__proto__` state.
|
|
103
|
+
const stateTransitionsSchema = custom(isStateTransitions, {
|
|
104
|
+
message: 'Expected each non-empty state to map non-empty events to non-empty states.',
|
|
105
|
+
params: { structureCode: 'STRUCTURE_STATE_TRANSITIONS' },
|
|
106
|
+
}).register(documentJsonSchema, {
|
|
107
|
+
type: 'object',
|
|
108
|
+
propertyNames: { type: 'string', minLength: 1 },
|
|
109
|
+
additionalProperties: {
|
|
110
|
+
type: 'object',
|
|
111
|
+
propertyNames: { type: 'string', minLength: 1 },
|
|
112
|
+
additionalProperties: { type: 'string', minLength: 1 },
|
|
113
|
+
},
|
|
114
|
+
});
|
|
39
115
|
const stateTopologySchema = strictObject({
|
|
40
116
|
initial: stateNameSchema,
|
|
41
117
|
transitions: stateTransitionsSchema,
|
|
42
|
-
});
|
|
43
|
-
const
|
|
118
|
+
}).register(documentJsonSchema, { id: 'state-topology' });
|
|
119
|
+
const propertyShape = {
|
|
44
120
|
schema: jsonSchemaSchema,
|
|
45
121
|
required: boolean(),
|
|
46
122
|
auto: strictObject({
|
|
47
|
-
on: uniqueArray(enumeration(['create', 'update']))
|
|
123
|
+
on: nonEmpty(uniqueArray(enumeration(['create', 'update']))),
|
|
48
124
|
set: literal('instant'),
|
|
49
|
-
})
|
|
125
|
+
})
|
|
126
|
+
.register(documentJsonSchema, { id: 'auto' })
|
|
127
|
+
.optional(),
|
|
50
128
|
immutable: enumeration(['create', 'once']).optional(),
|
|
51
129
|
description: descriptionSchema.optional(),
|
|
52
|
-
|
|
130
|
+
};
|
|
131
|
+
const nodePropertyRecordSchema = record(memberNameSchema, strictObject({ ...propertyShape, state: stateTopologySchema.optional() }).register(documentJsonSchema, { id: 'node-property-definition' })).register(documentJsonSchema, { id: 'node-property-record' });
|
|
132
|
+
// An Edge has no State Property, and only a Node holds Blob contents.
|
|
133
|
+
const BLOB_KIND_KEYWORD = 'x-astrale-value-kind';
|
|
134
|
+
const edgePropertySchema = jsonSchemaSchema
|
|
135
|
+
.refine((value) => !isBlobValueSchema(value), {
|
|
136
|
+
message: 'Blob values are held only by Node Properties.',
|
|
137
|
+
path: [BLOB_KIND_KEYWORD],
|
|
138
|
+
params: { structureCode: 'STRUCTURE_EDGE_BLOB' },
|
|
139
|
+
})
|
|
140
|
+
.register(documentJsonSchema, {
|
|
141
|
+
not: {
|
|
142
|
+
type: 'object',
|
|
143
|
+
required: [BLOB_KIND_KEYWORD],
|
|
144
|
+
properties: { [BLOB_KIND_KEYWORD]: { const: BLOB_VALUE_KIND } },
|
|
145
|
+
},
|
|
53
146
|
});
|
|
54
|
-
const
|
|
147
|
+
const edgePropertyRecordSchema = record(memberNameSchema, strictObject({ ...propertyShape, schema: edgePropertySchema }).register(documentJsonSchema, {
|
|
148
|
+
id: 'edge-property-definition',
|
|
149
|
+
})).register(documentJsonSchema, { id: 'edge-property-record' });
|
|
55
150
|
const domainDependencySchema = strictObject({
|
|
56
151
|
origin: originSchema,
|
|
57
152
|
revision: revisionSchema,
|
|
58
|
-
});
|
|
153
|
+
}).register(documentJsonSchema, { id: 'dependency' });
|
|
59
154
|
const classRefSchema = absoluteRefSchema('class');
|
|
60
155
|
const functionRefSchema = absoluteRefSchema('function');
|
|
61
156
|
const policyRefSchema = absoluteRefSchema('policy');
|
|
@@ -64,40 +159,67 @@ const coreRefSchema = strictObject({
|
|
|
64
159
|
origin: originSchema,
|
|
65
160
|
kind: literal('core'),
|
|
66
161
|
name: coreSlugSchema,
|
|
162
|
+
}).register(documentJsonSchema, { id: 'core-ref' });
|
|
163
|
+
const domainRefSchema = strictObject({ kind: literal('domain') }).register(documentJsonSchema, {
|
|
164
|
+
id: 'domain-endpoint',
|
|
67
165
|
});
|
|
68
|
-
const domainRefSchema = strictObject({ kind: literal('domain') });
|
|
69
166
|
/** Every Definition whose installed projection resolves through one exact member Path. */
|
|
70
167
|
const projectedMemberRefOptions = [
|
|
71
|
-
strictObject({
|
|
168
|
+
strictObject({
|
|
169
|
+
kind: literal('method'),
|
|
170
|
+
owner: classRefSchema,
|
|
171
|
+
name: memberNameSchema,
|
|
172
|
+
}).register(documentJsonSchema, { id: 'method-address' }),
|
|
72
173
|
classRefSchema,
|
|
73
174
|
functionRefSchema,
|
|
74
175
|
policyRefSchema,
|
|
75
176
|
viewRefSchema,
|
|
76
177
|
coreRefSchema,
|
|
77
178
|
];
|
|
78
|
-
const policyObjectRefSchema = discriminatedUnion('kind', projectedMemberRefOptions);
|
|
179
|
+
const policyObjectRefSchema = discriminatedUnion('kind', projectedMemberRefOptions).register(documentJsonSchema, { id: 'projected-member-ref' });
|
|
79
180
|
const coreEndpointRefSchema = discriminatedUnion('kind', [
|
|
80
181
|
...projectedMemberRefOptions,
|
|
81
182
|
domainRefSchema,
|
|
82
|
-
]);
|
|
183
|
+
]).register(documentJsonSchema, { id: 'core-endpoint' });
|
|
83
184
|
const edgeEndpointBaseShape = {
|
|
84
185
|
role: memberNameSchema,
|
|
85
|
-
accepts: uniqueArray(classRefSchema)
|
|
186
|
+
accepts: nonEmpty(uniqueArray(classRefSchema)),
|
|
187
|
+
onDelete: enumeration(['restrict', 'detach'])
|
|
188
|
+
.register(documentJsonSchema, { id: 'edge-lifetime' })
|
|
189
|
+
.optional(),
|
|
86
190
|
};
|
|
87
|
-
const edgeCountSchema = enumeration(['0..*', '1..*', '0..1', '1'])
|
|
88
|
-
|
|
89
|
-
source: strictObject({ ...edgeEndpointBaseShape, outgoing: edgeCountSchema }),
|
|
90
|
-
target: strictObject({ ...edgeEndpointBaseShape, incoming: edgeCountSchema }),
|
|
191
|
+
const edgeCountSchema = enumeration(['0..*', '1..*', '0..1', '1']).register(documentJsonSchema, {
|
|
192
|
+
id: 'edge-count',
|
|
91
193
|
});
|
|
194
|
+
const directedEdgeEndpointsSchema = strictObject({
|
|
195
|
+
source: strictObject({ ...edgeEndpointBaseShape, outgoing: edgeCountSchema }).register(documentJsonSchema, { id: 'directed-source-endpoint' }),
|
|
196
|
+
target: strictObject({ ...edgeEndpointBaseShape, incoming: edgeCountSchema }).register(documentJsonSchema, { id: 'directed-target-endpoint' }),
|
|
197
|
+
}).register(documentJsonSchema, { id: 'directed-endpoints' });
|
|
92
198
|
const incidentEndpointSchema = strictObject({
|
|
93
199
|
...edgeEndpointBaseShape,
|
|
94
200
|
incident: edgeCountSchema,
|
|
95
|
-
});
|
|
96
|
-
const undirectedEdgeEndpointsSchema = tuple([
|
|
201
|
+
}).register(documentJsonSchema, { id: 'incident-endpoint' });
|
|
202
|
+
const undirectedEdgeEndpointsSchema = tuple([
|
|
203
|
+
incidentEndpointSchema,
|
|
204
|
+
incidentEndpointSchema,
|
|
205
|
+
]).register(documentJsonSchema, { id: 'undirected-endpoints' });
|
|
97
206
|
const edgeConstraintsSchema = strictObject({
|
|
98
207
|
noSelf: literal(true).optional(),
|
|
99
208
|
acyclic: literal(true).optional(),
|
|
100
|
-
});
|
|
209
|
+
}).register(documentJsonSchema, { id: 'edge-constraints' });
|
|
210
|
+
// A tuple names distinct fields: endpoints, the slug and Properties by key. Normalization puts
|
|
211
|
+
// them, and the tuples, in canonical order (`compareEdgeUniqueFields`). No tuple is spelled by the
|
|
212
|
+
// absence of the field, never by an empty list: one spelling per meaning, one revision.
|
|
213
|
+
const edgeUniqueFieldSchema = union([
|
|
214
|
+
literal('source'),
|
|
215
|
+
literal('target'),
|
|
216
|
+
literal('slug'),
|
|
217
|
+
strictObject({ property: propertyKeySchema }),
|
|
218
|
+
]).register(documentJsonSchema, { id: 'edge-unique-field' });
|
|
219
|
+
const edgeUniqueSchema = nonEmpty(uniqueTupleSet(nonEmpty(uniqueArray(edgeUniqueFieldSchema))));
|
|
220
|
+
// A Node tuple names distinct Properties by key, which normalization puts in code-point order, as
|
|
221
|
+
// it does the tuples (`compareNodeUniqueTuples`). Two orders of one set of keys are one tuple.
|
|
222
|
+
const nodeUniqueSchema = nonEmpty(uniqueTupleSet(nonEmpty(uniqueArray(propertyKeySchema))));
|
|
101
223
|
const policyPatternSubjectSchema = strictObject({ kind: literal('subject') });
|
|
102
224
|
const policyPatternObjectSchema = strictObject({ kind: literal('object') });
|
|
103
225
|
const policyPatternSourceSchema = strictObject({ kind: literal('source') });
|
|
@@ -105,7 +227,7 @@ const policyPatternTargetSchema = strictObject({ kind: literal('target') });
|
|
|
105
227
|
const policyPatternVariableSchema = strictObject({
|
|
106
228
|
kind: literal('variable'),
|
|
107
229
|
id: number().int().min(0),
|
|
108
|
-
});
|
|
230
|
+
}).register(documentJsonSchema, { id: 'policy-pattern-variable' });
|
|
109
231
|
const policyPatternNodeSchema = discriminatedUnion('kind', [
|
|
110
232
|
policyPatternSubjectSchema,
|
|
111
233
|
policyPatternObjectSchema,
|
|
@@ -113,19 +235,19 @@ const policyPatternNodeSchema = discriminatedUnion('kind', [
|
|
|
113
235
|
policyPatternTargetSchema,
|
|
114
236
|
policyPatternVariableSchema,
|
|
115
237
|
strictObject({ kind: literal('ref'), ref: policyObjectRefSchema }),
|
|
116
|
-
]);
|
|
238
|
+
]).register(documentJsonSchema, { id: 'policy-pattern-node' });
|
|
117
239
|
const policyVariableSelectorSchema = discriminatedUnion('kind', [
|
|
118
240
|
strictObject({ kind: literal('any') }),
|
|
119
241
|
strictObject({ kind: literal('satisfies'), class: classRefSchema }),
|
|
120
|
-
]);
|
|
242
|
+
]).register(documentJsonSchema, { id: 'policy-variable-selector' });
|
|
121
243
|
const policyVariableSchema = union([
|
|
122
244
|
strictObject({ variable: policyPatternVariableSchema, class: classRefSchema }),
|
|
123
245
|
strictObject({ variable: policyPatternVariableSchema, selector: policyVariableSelectorSchema }),
|
|
124
|
-
]);
|
|
246
|
+
]).register(documentJsonSchema, { id: 'policy-variable' });
|
|
125
247
|
const policyRepeatSchema = strictObject({
|
|
126
|
-
min: number().int().min(0).max(
|
|
127
|
-
max: number().int().min(0).max(
|
|
128
|
-
});
|
|
248
|
+
min: number().int().min(0).max(limits.policy.repetition),
|
|
249
|
+
max: number().int().min(0).max(limits.policy.repetition),
|
|
250
|
+
}).register(documentJsonSchema, { id: 'policy-repeat' });
|
|
129
251
|
const policyPatternExpressionSchema = lazy(() => union([
|
|
130
252
|
strictObject({
|
|
131
253
|
sameNode: strictObject({ left: policyPatternNodeSchema, right: policyPatternNodeSchema }),
|
|
@@ -138,17 +260,13 @@ const policyPatternExpressionSchema = lazy(() => union([
|
|
|
138
260
|
}),
|
|
139
261
|
strictObject({
|
|
140
262
|
exists: strictObject({
|
|
141
|
-
nodes: array(policyVariableSchema).
|
|
263
|
+
nodes: nonEmpty(array(policyVariableSchema).max(limits.policy.variablesPerExists)),
|
|
142
264
|
where: policyPatternExpressionSchema,
|
|
143
265
|
}),
|
|
144
266
|
}),
|
|
145
|
-
strictObject({
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
strictObject({
|
|
149
|
-
anyOf: array(policyPatternExpressionSchema).min(1),
|
|
150
|
-
}),
|
|
151
|
-
]));
|
|
267
|
+
strictObject({ allOf: nonEmpty(array(policyPatternExpressionSchema)) }),
|
|
268
|
+
strictObject({ anyOf: nonEmpty(array(policyPatternExpressionSchema)) }),
|
|
269
|
+
])).register(documentJsonSchema, { id: 'policy-pattern-expr' });
|
|
152
270
|
const selfObjectSchema = strictObject({ kind: literal('self') });
|
|
153
271
|
const refObjectSchema = strictObject({ kind: literal('ref'), ref: policyObjectRefSchema });
|
|
154
272
|
const policyCheckObjectSchema = discriminatedUnion('kind', [
|
|
@@ -158,21 +276,26 @@ const policyCheckObjectSchema = discriminatedUnion('kind', [
|
|
|
158
276
|
field: memberNameSchema,
|
|
159
277
|
}),
|
|
160
278
|
refObjectSchema,
|
|
161
|
-
]);
|
|
162
|
-
/** A
|
|
163
|
-
const classRuleObjectSchema = discriminatedUnion('kind', [
|
|
279
|
+
]).register(documentJsonSchema, { id: 'policy-check-object' });
|
|
280
|
+
/** A Class rule checks the observed or written instance or one exact member: it has no input. */
|
|
281
|
+
const classRuleObjectSchema = discriminatedUnion('kind', [
|
|
282
|
+
selfObjectSchema,
|
|
283
|
+
refObjectSchema,
|
|
284
|
+
]).register(documentJsonSchema, { id: 'class-rule-object' });
|
|
164
285
|
/** The recursive Policy check grammar, over the objects one use site admits. */
|
|
165
|
-
function policyChecksSchema(objectSchema) {
|
|
286
|
+
function policyChecksSchema(objectSchema, id) {
|
|
166
287
|
const checks = lazy(() => union([
|
|
167
288
|
strictObject({ sameNode: strictObject({ left: objectSchema, right: objectSchema }) }),
|
|
168
289
|
strictObject({ check: policyRefSchema, object: objectSchema }),
|
|
169
|
-
strictObject({ allOf: array(checks)
|
|
170
|
-
strictObject({ anyOf: array(checks)
|
|
171
|
-
]));
|
|
290
|
+
strictObject({ allOf: nonEmpty(array(checks)) }),
|
|
291
|
+
strictObject({ anyOf: nonEmpty(array(checks)) }),
|
|
292
|
+
])).register(documentJsonSchema, { id });
|
|
172
293
|
return checks;
|
|
173
294
|
}
|
|
174
|
-
const policyCheckExpressionSchema = policyChecksSchema(policyCheckObjectSchema);
|
|
175
|
-
const classRuleChecksSchema = policyChecksSchema(classRuleObjectSchema);
|
|
295
|
+
const policyCheckExpressionSchema = policyChecksSchema(policyCheckObjectSchema, 'policy-check-expr');
|
|
296
|
+
const classRuleChecksSchema = policyChecksSchema(classRuleObjectSchema, 'class-rule-check-expr');
|
|
297
|
+
/** A Node create rule has no Node to check yet: its objects are exact members only. */
|
|
298
|
+
const createRuleChecksSchema = policyChecksSchema(refObjectSchema, 'create-rule-check-expr');
|
|
176
299
|
const callableOutputSchema = discriminatedUnion('mode', [
|
|
177
300
|
strictObject({
|
|
178
301
|
mode: literal('value'),
|
|
@@ -185,139 +308,191 @@ const callableOutputSchema = discriminatedUnion('mode', [
|
|
|
185
308
|
strictObject({
|
|
186
309
|
mode: literal('binary'),
|
|
187
310
|
}),
|
|
188
|
-
]);
|
|
311
|
+
]).register(documentJsonSchema, { id: 'callable-output' });
|
|
189
312
|
const binaryInputSchema = strictObject({
|
|
190
313
|
mode: literal('binary'),
|
|
191
314
|
metadata: jsonSchemaSchema,
|
|
192
315
|
maximumBytes: number().int().min(1).max(Number.MAX_SAFE_INTEGER),
|
|
316
|
+
}).register(documentJsonSchema, { id: 'binary-input' });
|
|
317
|
+
const valueFunctionInputSchema = jsonSchemaSchema
|
|
318
|
+
.refine((value) => typeof value !== 'object' || value === null || value.mode !== 'binary', {
|
|
319
|
+
message: 'Binary input must declare metadata and maximumBytes.',
|
|
320
|
+
params: { structureCode: 'STRUCTURE_BINARY_INPUT' },
|
|
321
|
+
})
|
|
322
|
+
.register(documentJsonSchema, {
|
|
323
|
+
not: { type: 'object', required: ['mode'], properties: { mode: { const: 'binary' } } },
|
|
193
324
|
});
|
|
194
|
-
const valueFunctionInputSchema = jsonSchemaSchema.refine((value) => typeof value !== 'object' || value === null || value.mode !== 'binary', 'Binary input must declare metadata and maximumBytes.');
|
|
195
325
|
const callableExecutionSchema = strictObject({
|
|
196
326
|
durable: boolean(),
|
|
197
|
-
});
|
|
327
|
+
}).register(documentJsonSchema, { id: 'callable-execution' });
|
|
328
|
+
// Its range is language meaning, refused by callable validation with DV_CALLABLE_ADMISSION.
|
|
329
|
+
const callableAdmissionSchema = strictObject({
|
|
330
|
+
maxAge: number(),
|
|
331
|
+
}).register(documentJsonSchema, { id: 'callable-admission' });
|
|
198
332
|
const callableShape = {
|
|
199
333
|
description: descriptionSchema.optional(),
|
|
200
334
|
input: jsonSchemaSchema,
|
|
201
335
|
output: callableOutputSchema,
|
|
202
336
|
execution: callableExecutionSchema.optional(),
|
|
337
|
+
admission: callableAdmissionSchema.optional(),
|
|
203
338
|
auth: enumeration(['anonymous', 'authenticated', 'authorized']),
|
|
204
|
-
policy: union([literal(true), policyCheckExpressionSchema])
|
|
339
|
+
policy: union([literal(true), policyCheckExpressionSchema])
|
|
340
|
+
.register(documentJsonSchema, { id: 'callable-policy' })
|
|
341
|
+
.optional(),
|
|
342
|
+
};
|
|
343
|
+
const authorizedPolicy = {
|
|
344
|
+
if: { properties: { auth: { enum: ['anonymous', 'authenticated'] } }, required: ['auth'] },
|
|
345
|
+
// oxlint-disable-next-line unicorn/no-thenable -- the JSON Schema keyword
|
|
346
|
+
then: { properties: { policy: false } },
|
|
205
347
|
};
|
|
206
348
|
const methodDeclarationSchema = strictObject({
|
|
207
349
|
...callableShape,
|
|
208
350
|
static: boolean(),
|
|
209
351
|
abstract: boolean(),
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
message: 'Only an authorized method may declare a policy.',
|
|
216
|
-
params: { structureCode: 'STRUCTURE_CALLABLE_POLICY_AUTH' },
|
|
217
|
-
});
|
|
218
|
-
}
|
|
352
|
+
})
|
|
353
|
+
.refine((method) => method.auth === 'authorized' || method.policy === undefined, callablePolicyIssue('method'))
|
|
354
|
+
.register(documentJsonSchema, { id: 'method-definition', ...authorizedPolicy });
|
|
355
|
+
const methodRecordSchema = record(memberNameSchema, methodDeclarationSchema).register(documentJsonSchema, {
|
|
356
|
+
id: 'method-record',
|
|
219
357
|
});
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
|
|
358
|
+
// Each slot spells one constant: the other one is what its absence already means.
|
|
359
|
+
const observationPolicySchema = union([
|
|
360
|
+
literal(false),
|
|
361
|
+
policyRefSchema,
|
|
362
|
+
classRuleChecksSchema,
|
|
363
|
+
]).register(documentJsonSchema, { id: 'observation-policy' });
|
|
364
|
+
const writePolicySchema = union([literal(true), policyRefSchema, classRuleChecksSchema]).register(documentJsonSchema, { id: 'write-policy' });
|
|
365
|
+
const createPolicySchema = union([literal(true), createRuleChecksSchema]).register(documentJsonSchema, { id: 'create-policy' });
|
|
223
366
|
const nodeClassPoliciesSchema = strictObject({
|
|
224
|
-
read:
|
|
225
|
-
traverse:
|
|
367
|
+
read: observationPolicySchema.optional(),
|
|
368
|
+
traverse: observationPolicySchema.optional(),
|
|
369
|
+
create: createPolicySchema.optional(),
|
|
370
|
+
update: writePolicySchema.optional(),
|
|
371
|
+
delete: writePolicySchema.optional(),
|
|
226
372
|
});
|
|
227
373
|
const edgeClassPoliciesSchema = strictObject({
|
|
228
|
-
read:
|
|
229
|
-
traverse:
|
|
374
|
+
read: observationPolicySchema.optional(),
|
|
375
|
+
traverse: observationPolicySchema.optional(),
|
|
376
|
+
create: writePolicySchema.optional(),
|
|
377
|
+
update: writePolicySchema.optional(),
|
|
378
|
+
delete: writePolicySchema.optional(),
|
|
230
379
|
});
|
|
380
|
+
// The default `'internal'` is the absence of the field: one spelling per meaning, one revision.
|
|
381
|
+
const inheritanceSchema = enumeration(['open', 'final']);
|
|
231
382
|
const nodeClassSchema = strictObject({
|
|
232
383
|
ref: classRefSchema,
|
|
233
384
|
kind: literal('node'),
|
|
234
385
|
abstract: boolean(),
|
|
386
|
+
inheritance: inheritanceSchema.optional(),
|
|
235
387
|
description: descriptionSchema.optional(),
|
|
236
388
|
extends: uniqueArray(classRefSchema),
|
|
237
|
-
properties:
|
|
389
|
+
properties: nodePropertyRecordSchema,
|
|
238
390
|
methods: methodRecordSchema,
|
|
239
391
|
data: dataDeclarationSchema.optional(),
|
|
240
392
|
icon: iconSchema.optional(),
|
|
241
393
|
policies: nodeClassPoliciesSchema,
|
|
242
|
-
|
|
243
|
-
|
|
394
|
+
unique: nodeUniqueSchema.optional(),
|
|
395
|
+
}).register(documentJsonSchema, { id: 'node-class' });
|
|
396
|
+
const orientationIssue = { params: { structureCode: 'STRUCTURE_EDGE_ORIENTATION' } };
|
|
397
|
+
const edgeClassSchema = strictObject({
|
|
244
398
|
ref: classRefSchema,
|
|
245
399
|
kind: literal('edge'),
|
|
246
400
|
abstract: boolean(),
|
|
401
|
+
inheritance: inheritanceSchema.optional(),
|
|
247
402
|
description: descriptionSchema.optional(),
|
|
248
403
|
extends: uniqueArray(classRefSchema),
|
|
249
|
-
properties:
|
|
404
|
+
properties: edgePropertyRecordSchema,
|
|
250
405
|
constraints: edgeConstraintsSchema,
|
|
251
|
-
|
|
252
|
-
const edgeClassSchema = strictObject({
|
|
253
|
-
...edgeClassShape,
|
|
406
|
+
unique: edgeUniqueSchema.optional(),
|
|
254
407
|
orientation: enumeration(['directed', 'undirected']),
|
|
255
408
|
endpoints: union([directedEdgeEndpointsSchema, undirectedEdgeEndpointsSchema]),
|
|
256
409
|
policies: edgeClassPoliciesSchema,
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
410
|
+
})
|
|
411
|
+
.refine((edge) => (edge.orientation === 'undirected') === Array.isArray(edge.endpoints), {
|
|
412
|
+
...orientationIssue,
|
|
413
|
+
path: ['endpoints'],
|
|
414
|
+
error: 'Edge endpoints do not have the structural shape of its orientation.',
|
|
415
|
+
})
|
|
416
|
+
.refine((edge) => edge.orientation === 'directed' || edge.unique === undefined, {
|
|
417
|
+
...orientationIssue,
|
|
418
|
+
path: ['unique'],
|
|
419
|
+
error: 'Only a directed Edge Class declares unique tuples.',
|
|
420
|
+
})
|
|
421
|
+
.refine((edge) => edge.orientation === 'directed' || edge.constraints.acyclic === undefined, {
|
|
422
|
+
...orientationIssue,
|
|
423
|
+
path: ['constraints', 'acyclic'],
|
|
424
|
+
error: 'Only a directed Edge Class is acyclic.',
|
|
425
|
+
})
|
|
426
|
+
.register(documentJsonSchema, {
|
|
427
|
+
id: 'edge-class',
|
|
428
|
+
if: { properties: { orientation: { const: 'undirected' } }, required: ['orientation'] },
|
|
429
|
+
// oxlint-disable-next-line unicorn/no-thenable -- the JSON Schema keyword
|
|
430
|
+
then: {
|
|
431
|
+
properties: {
|
|
432
|
+
endpoints: { type: 'array' },
|
|
433
|
+
unique: false,
|
|
434
|
+
constraints: { type: 'object', properties: { acyclic: false } },
|
|
435
|
+
},
|
|
436
|
+
},
|
|
437
|
+
else: { properties: { endpoints: { type: 'object' } } },
|
|
438
|
+
});
|
|
439
|
+
const classDeclarationSchema = discriminatedUnion('kind', [
|
|
440
|
+
nodeClassSchema,
|
|
441
|
+
edgeClassSchema,
|
|
442
|
+
]).register(documentJsonSchema, { id: 'class-definition' });
|
|
443
|
+
const functionContractShape = {
|
|
271
444
|
...callableShape,
|
|
272
445
|
input: union([binaryInputSchema, valueFunctionInputSchema]),
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
});
|
|
446
|
+
};
|
|
447
|
+
const functionDefinitionSchema = strictObject({
|
|
448
|
+
ref: functionRefSchema,
|
|
449
|
+
...functionContractShape,
|
|
450
|
+
})
|
|
451
|
+
.refine((callable) => callable.auth === 'authorized' || callable.policy === undefined, callablePolicyIssue('function'))
|
|
452
|
+
.register(documentJsonSchema, { id: 'function-definition', ...authorizedPolicy });
|
|
453
|
+
// A callable contract has the structure of a Function declaration without its ref, wherever it is.
|
|
454
|
+
const callableContractSchema = strictObject(functionContractShape).refine((callable) => callable.auth === 'authorized' || callable.policy === undefined, callablePolicyIssue('function'));
|
|
283
455
|
const policyExpressionSchema = union([
|
|
284
456
|
strictObject({
|
|
285
457
|
match: policyPatternExpressionSchema,
|
|
286
458
|
}),
|
|
287
|
-
strictObject({
|
|
288
|
-
|
|
289
|
-
}),
|
|
290
|
-
strictObject({
|
|
291
|
-
anyOf: array(policyRefSchema).min(1),
|
|
292
|
-
}),
|
|
459
|
+
strictObject({ allOf: nonEmpty(array(policyRefSchema)) }),
|
|
460
|
+
strictObject({ anyOf: nonEmpty(array(policyRefSchema)) }),
|
|
293
461
|
]);
|
|
294
462
|
const policyDefinitionSchema = strictObject({
|
|
295
463
|
ref: policyRefSchema,
|
|
296
464
|
expression: policyExpressionSchema,
|
|
297
465
|
description: descriptionSchema.optional(),
|
|
466
|
+
}).register(documentJsonSchema, { id: 'policy-definition' });
|
|
467
|
+
const viewTargetSchema = strictObject({ kind: literal('domain') }).register(documentJsonSchema, {
|
|
468
|
+
id: 'view-target',
|
|
469
|
+
description: 'Every View targets its owning Domain.',
|
|
298
470
|
});
|
|
299
|
-
const viewTargetSchema = strictObject({ kind: literal('domain') });
|
|
300
471
|
const viewDefinitionSchema = strictObject({
|
|
301
472
|
ref: viewRefSchema,
|
|
302
473
|
description: descriptionSchema.optional(),
|
|
303
474
|
target: viewTargetSchema,
|
|
475
|
+
}).register(documentJsonSchema, { id: 'view-definition' });
|
|
476
|
+
const propertyValuesSchema = record(propertyKeySchema, jsonValueSchema).register(documentJsonSchema, {
|
|
477
|
+
id: 'property-values',
|
|
304
478
|
});
|
|
305
479
|
const coreNodeSchema = strictObject({
|
|
306
480
|
ref: coreRefSchema,
|
|
307
481
|
class: classRefSchema,
|
|
308
|
-
properties:
|
|
309
|
-
});
|
|
482
|
+
properties: propertyValuesSchema,
|
|
483
|
+
}).register(documentJsonSchema, { id: 'core-definition' });
|
|
310
484
|
const coreEdgeSchema = strictObject({
|
|
311
485
|
class: classRefSchema,
|
|
312
486
|
source: coreEndpointRefSchema,
|
|
313
487
|
target: coreEndpointRefSchema,
|
|
314
|
-
properties:
|
|
315
|
-
});
|
|
488
|
+
properties: propertyValuesSchema,
|
|
489
|
+
}).register(documentJsonSchema, { id: 'core-edge' });
|
|
316
490
|
const coreSchema = strictObject({
|
|
317
491
|
nodes: record(coreSlugSchema, coreNodeSchema),
|
|
318
492
|
edges: array(coreEdgeSchema),
|
|
319
|
-
});
|
|
320
|
-
|
|
493
|
+
}).register(documentJsonSchema, { id: 'core' });
|
|
494
|
+
/** The structure of an authored Domain schema document, the single source of its JSON Schema. */
|
|
495
|
+
export const domainSchemaStructure = strictObject({
|
|
321
496
|
format: literal(DOMAIN_FORMAT),
|
|
322
497
|
version: literal(DOMAIN_VERSION),
|
|
323
498
|
origin: originSchema,
|
|
@@ -330,19 +505,65 @@ const structuralSchema = strictObject({
|
|
|
330
505
|
views: record(memberNameSchema, viewDefinitionSchema),
|
|
331
506
|
core: coreSchema,
|
|
332
507
|
});
|
|
333
|
-
const domainSchemaStructuralSchema = structuralSchema;
|
|
334
508
|
export function parseDomainSchemaStructure(input) {
|
|
335
|
-
const result =
|
|
336
|
-
if (result.success)
|
|
337
|
-
|
|
338
|
-
|
|
509
|
+
const result = domainSchemaStructure.safeParse(input);
|
|
510
|
+
if (!result.success) {
|
|
511
|
+
throw new SchemaError(result.error.issues.flatMap((issue) => diagnosticsForIssue(issue, input)));
|
|
512
|
+
}
|
|
513
|
+
const lost = lostProtoKeys(input, result.data, []);
|
|
514
|
+
if (lost.length > 0)
|
|
515
|
+
throw new SchemaError(lost);
|
|
516
|
+
return modelOf(result.data);
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Each `__proto__` member of the input that the parsed document lost. Zod skips that member in an
|
|
520
|
+
* object or a record, so the structure would accept the document without it; it refuses the
|
|
521
|
+
* document instead. A State's transitions are read in place and keep the member.
|
|
522
|
+
*/
|
|
523
|
+
function lostProtoKeys(input, parsed, path) {
|
|
524
|
+
if (!isObject(input) || !isObject(parsed))
|
|
525
|
+
return [];
|
|
526
|
+
const lost = Object.hasOwn(input, PROTO_KEY) && !Object.hasOwn(parsed, PROTO_KEY)
|
|
527
|
+
? [
|
|
528
|
+
diagnostic('STRUCTURE_PROTO_KEY', pointer([...path, PROTO_KEY]), 'A member named __proto__ is refused: the parsed document cannot keep it.'),
|
|
529
|
+
]
|
|
530
|
+
: [];
|
|
531
|
+
return [
|
|
532
|
+
...lost,
|
|
533
|
+
...Object.keys(parsed).flatMap((key) => lostProtoKeys(Reflect.get(input, key), Reflect.get(parsed, key), [...path, key])),
|
|
534
|
+
];
|
|
535
|
+
}
|
|
536
|
+
/** Parse the structure of one callable contract: a Function declaration without its ref. */
|
|
537
|
+
export function parseCallableContract(input) {
|
|
538
|
+
const result = callableContractSchema.safeParse(input);
|
|
539
|
+
if (!result.success) {
|
|
540
|
+
throw new SchemaError(result.error.issues.flatMap((issue) => diagnosticsForIssue(issue, input)));
|
|
541
|
+
}
|
|
542
|
+
const lost = lostProtoKeys(input, result.data, []);
|
|
543
|
+
if (lost.length > 0)
|
|
544
|
+
throw new SchemaError(lost);
|
|
545
|
+
return result.data;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* The structure admits the document the model types: this parameter checks one direction, and
|
|
549
|
+
* `domain.structure.typecheck.ts` both. The brands are the model's own proofs from here on.
|
|
550
|
+
*/
|
|
551
|
+
function modelOf(document) {
|
|
552
|
+
return document;
|
|
339
553
|
}
|
|
340
554
|
function absoluteRefSchema(kind) {
|
|
341
555
|
return strictObject({
|
|
342
556
|
origin: originSchema,
|
|
343
557
|
kind: literal(kind),
|
|
344
558
|
name: memberNameSchema,
|
|
345
|
-
});
|
|
559
|
+
}).register(documentJsonSchema, { id: `${kind}-ref` });
|
|
560
|
+
}
|
|
561
|
+
function callablePolicyIssue(owner) {
|
|
562
|
+
return {
|
|
563
|
+
path: ['policy'],
|
|
564
|
+
params: { structureCode: 'STRUCTURE_CALLABLE_POLICY_AUTH' },
|
|
565
|
+
error: `Only an authorized ${owner} may declare a policy.`,
|
|
566
|
+
};
|
|
346
567
|
}
|
|
347
568
|
function isStateTransitions(input) {
|
|
348
569
|
if (!isRecord(input))
|
|
@@ -366,13 +587,31 @@ function isStateTransitions(input) {
|
|
|
366
587
|
return true;
|
|
367
588
|
}
|
|
368
589
|
function isRecord(input) {
|
|
369
|
-
return input
|
|
590
|
+
return isObject(input) && !Array.isArray(input);
|
|
591
|
+
}
|
|
592
|
+
function isObject(input) {
|
|
593
|
+
return input !== null && typeof input === 'object';
|
|
594
|
+
}
|
|
595
|
+
/** At least one item, which `min(1)` proves: the output is typed as the non-empty tuple it is. */
|
|
596
|
+
function nonEmpty(list) {
|
|
597
|
+
return list.min(1);
|
|
370
598
|
}
|
|
599
|
+
/** Items distinct by JSON equality, which JSON Schema states as `uniqueItems`. */
|
|
371
600
|
function uniqueArray(element) {
|
|
601
|
+
return distinctArray(element, canonicalJson).register(documentJsonSchema, { uniqueItems: true });
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Tuples distinct as sets of fields. JSON Schema states their JSON equality, `uniqueItems`; the
|
|
605
|
+
* rule `unique-tuple-set` names the rest.
|
|
606
|
+
*/
|
|
607
|
+
function uniqueTupleSet(tuple) {
|
|
608
|
+
return distinctArray(tuple, (fields) => JSON.stringify(fields.map(canonicalJson).sort())).register(documentJsonSchema, { uniqueItems: true, 'x-astrale-rule': 'unique-tuple-set' });
|
|
609
|
+
}
|
|
610
|
+
function distinctArray(element, keyOf) {
|
|
372
611
|
return array(element).superRefine((values, context) => {
|
|
373
612
|
const firstIndexByValue = new Map();
|
|
374
613
|
values.forEach((value, index) => {
|
|
375
|
-
const key =
|
|
614
|
+
const key = keyOf(value);
|
|
376
615
|
const firstIndex = firstIndexByValue.get(key);
|
|
377
616
|
if (firstIndex === undefined) {
|
|
378
617
|
firstIndexByValue.set(key, index);
|
|
@@ -401,24 +640,40 @@ function diagnosticsForIssue(issue, input) {
|
|
|
401
640
|
if (issue.code === 'unrecognized_keys') {
|
|
402
641
|
return issue.keys.map((key) => diagnostic('STRUCTURE_UNKNOWN_FIELD', pointer([...issue.path, key]), `Unknown field ${JSON.stringify(key)}.`));
|
|
403
642
|
}
|
|
404
|
-
|
|
643
|
+
// A record key refused by a refinement reports that refinement, at the key.
|
|
644
|
+
const refinement = issue.code === 'invalid_key' ? issue.issues.find(isRefinement) : undefined;
|
|
645
|
+
if (refinement !== undefined) {
|
|
646
|
+
return [diagnostic(refinementCode(refinement), pointer(issue.path), refinement.message)];
|
|
647
|
+
}
|
|
405
648
|
return [
|
|
406
|
-
diagnostic(
|
|
649
|
+
diagnostic(structureCode(issue, input), pointer(issue.path), structureMessage(issue, input)),
|
|
407
650
|
];
|
|
408
651
|
}
|
|
409
|
-
function
|
|
410
|
-
|
|
411
|
-
|
|
652
|
+
function isRefinement(issue) {
|
|
653
|
+
return issue.code === 'custom';
|
|
654
|
+
}
|
|
655
|
+
/** Every refinement of the structure names its own code. */
|
|
656
|
+
function refinementCode(issue) {
|
|
657
|
+
const code = issue.params?.structureCode;
|
|
658
|
+
switch (code) {
|
|
659
|
+
case 'STRUCTURE_BINARY_INPUT':
|
|
412
660
|
case 'STRUCTURE_CALLABLE_POLICY_AUTH':
|
|
661
|
+
case 'STRUCTURE_DEPENDENCY_ALIAS':
|
|
662
|
+
case 'STRUCTURE_DOMAIN_NAME':
|
|
413
663
|
case 'STRUCTURE_DUPLICATE_ITEM':
|
|
664
|
+
case 'STRUCTURE_EDGE_BLOB':
|
|
414
665
|
case 'STRUCTURE_EDGE_ORIENTATION':
|
|
415
|
-
|
|
666
|
+
case 'STRUCTURE_PROPERTY_KEY':
|
|
667
|
+
case 'STRUCTURE_STATE_TRANSITIONS':
|
|
668
|
+
return code;
|
|
416
669
|
default:
|
|
417
|
-
|
|
670
|
+
throw new TypeError(`A structure refinement names no Schema code: ${String(code)}.`);
|
|
418
671
|
}
|
|
419
672
|
}
|
|
420
673
|
function structureCode(issue, input) {
|
|
421
674
|
switch (issue.code) {
|
|
675
|
+
case 'custom':
|
|
676
|
+
return refinementCode(issue);
|
|
422
677
|
case 'invalid_type':
|
|
423
678
|
return valueAtPath(input, issue.path) === undefined ? 'STRUCTURE_REQUIRED' : 'STRUCTURE_TYPE';
|
|
424
679
|
case 'invalid_value':
|
|
@@ -433,10 +688,9 @@ function structureCode(issue, input) {
|
|
|
433
688
|
return 'STRUCTURE_MINIMUM';
|
|
434
689
|
case 'too_big':
|
|
435
690
|
return 'STRUCTURE_MAXIMUM';
|
|
436
|
-
case 'not_multiple_of':
|
|
437
|
-
return 'STRUCTURE_MULTIPLE';
|
|
438
691
|
default:
|
|
439
|
-
|
|
692
|
+
// The structure declares no multipleOf, Map or Set.
|
|
693
|
+
throw new TypeError(`The structure raised a ${issue.code} issue it declares no check for.`);
|
|
440
694
|
}
|
|
441
695
|
}
|
|
442
696
|
function structureMessage(issue, input) {
|
|
@@ -463,8 +717,5 @@ function valueAtPath(input, path) {
|
|
|
463
717
|
function pointer(path) {
|
|
464
718
|
if (path.length === 0)
|
|
465
719
|
return '';
|
|
466
|
-
return `/${path.map((segment) =>
|
|
467
|
-
}
|
|
468
|
-
function escapePointerSegment(segment) {
|
|
469
|
-
return segment.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
720
|
+
return `/${path.map((segment) => escapePointerToken(String(segment))).join('/')}`;
|
|
470
721
|
}
|