@aventara/core 1.0.0-rc.0 → 1.0.0-rc.2
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/CHANGELOG.md +1434 -0
- package/ERRORS.md +142 -0
- package/README.md +247 -57
- package/dist/adapters/adapter-discovery-diagnostic.d.ts +4 -4
- package/dist/adapters/adapter-discovery-diagnostic.guidance.d.ts +6 -0
- package/dist/adapters/adapter-discovery-diagnostic.guidance.js +7 -0
- package/dist/adapters/adapter-field.d.ts +25 -11
- package/dist/adapters/adapter-identifier.d.ts +6 -6
- package/dist/adapters/adapter-model.d.ts +18 -9
- package/dist/adapters/adapter-operation-executor.interface.d.ts +4 -4
- package/dist/adapters/adapter-operation.d.ts +3 -3
- package/dist/adapters/adapter-resource.d.ts +18 -9
- package/dist/adapters/adapter-sql-statement.d.ts +19 -0
- package/dist/adapters/adapter-transaction-executor.interface.d.ts +19 -0
- package/dist/adapters/adapter.interface.d.ts +59 -29
- package/dist/avz/avz-check.factory.d.ts +83 -0
- package/dist/avz/avz-check.factory.js +116 -0
- package/dist/avz/avz-check.registry.d.ts +35 -0
- package/dist/avz/avz-check.registry.js +9 -0
- package/dist/avz/avz.d.ts +203 -0
- package/dist/{json → avz}/avz.js +150 -8
- package/dist/{json → avz}/index.d.ts +2 -1
- package/dist/{json → avz}/json-shape.registry.d.ts +7 -7
- package/dist/{json → avz}/zod-issue.translator.d.ts +8 -2
- package/dist/{json → avz}/zod-issue.translator.js +7 -0
- package/dist/compiler/contract-compiler-diagnostic.d.ts +31 -5
- package/dist/compiler/contract-compiler-diagnostic.guidance.d.ts +6 -0
- package/dist/compiler/contract-compiler-diagnostic.guidance.js +97 -0
- package/dist/compiler/contract.compiler.d.ts +18 -18
- package/dist/compiler/contract.compiler.js +637 -442
- package/dist/compiler/create-requirements.projector.d.ts +49 -0
- package/dist/compiler/create-requirements.projector.js +423 -0
- package/dist/compiler/field-validator.compiler.d.ts +47 -0
- package/dist/compiler/field-validator.compiler.js +238 -0
- package/dist/config/any-framework-config.d.ts +19 -12
- package/dist/config/computed-fields.d.ts +62 -0
- package/dist/config/computed-fields.js +80 -0
- package/dist/config/config-diagnostic.d.ts +11 -4
- package/dist/config/config-diagnostic.guidance.d.ts +6 -0
- package/dist/config/config-diagnostic.guidance.js +32 -0
- package/dist/config/config-layer.d.ts +15 -6
- package/dist/config/config.resolver.d.ts +74 -31
- package/dist/config/config.resolver.js +108 -44
- package/dist/config/config.validator.d.ts +7 -7
- package/dist/config/config.validator.js +581 -72
- package/dist/config/define-resource.d.ts +57 -0
- package/dist/config/define-resource.js +14 -0
- package/dist/config/effective-fields.d.ts +19 -23
- package/dist/config/entrypoint.normalizer.d.ts +1 -1
- package/dist/config/exact-framework-config.d.ts +308 -0
- package/dist/config/field-compute.resolver.d.ts +21 -0
- package/dist/config/field-compute.resolver.js +123 -0
- package/dist/config/field-pipeline-config.d.ts +47 -0
- package/dist/config/forced-operation.validator.d.ts +10 -0
- package/dist/config/forced-operation.validator.js +66 -0
- package/dist/config/framework-config.d.ts +111 -39
- package/dist/config/framework-exemptions-config.d.ts +91 -0
- package/dist/config/framework-exemptions-config.js +1 -0
- package/dist/config/framework-field-definition.d.ts +78 -0
- package/dist/config/framework-field-definition.js +28 -0
- package/dist/config/framework-resources-config.d.ts +122 -0
- package/dist/config/framework-resources-config.js +1 -0
- package/dist/config/pipeline-config.d.ts +56 -20
- package/dist/config/pipeline-tree.resolver.d.ts +79 -0
- package/dist/config/pipeline-tree.resolver.js +220 -0
- package/dist/config/stage-type.eraser.d.ts +65 -0
- package/dist/config/stage-type.eraser.js +1 -0
- package/dist/contracts/capability.d.ts +21 -12
- package/dist/contracts/capability.js +2 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +388 -63
- package/dist/contracts/client-contract-structure.validator.js +156 -10
- package/dist/contracts/contract-canonicalizer.d.ts +26 -3
- package/dist/contracts/contract-canonicalizer.js +156 -29
- package/dist/contracts/contract-hash.d.ts +12 -7
- package/dist/contracts/contract-hash.js +3 -2
- package/dist/contracts/contract-limits.d.ts +4 -1
- package/dist/contracts/contract-limits.js +1 -0
- package/dist/contracts/contract-lookup.d.ts +5 -5
- package/dist/contracts/contract-protocol.d.ts +4 -4
- package/dist/contracts/contract.d.ts +24 -16
- package/dist/contracts/create-requirements.d.ts +35 -0
- package/dist/contracts/create-requirements.js +1 -0
- package/dist/contracts/enum-definition.d.ts +1 -1
- package/dist/contracts/field-check.d.ts +101 -0
- package/dist/contracts/field-check.js +1 -0
- package/dist/contracts/field.d.ts +81 -42
- package/dist/contracts/identifier.d.ts +4 -4
- package/dist/contracts/json-shape.d.ts +12 -1
- package/dist/contracts/lifecycle-trait.d.ts +2 -2
- package/dist/contracts/resource-operations.d.ts +28 -28
- package/dist/contracts/resource.d.ts +15 -9
- package/dist/contracts/scalar-value-type.d.ts +15 -15
- package/dist/contracts/scalar.d.ts +3 -3
- package/dist/contracts/transaction-capability.d.ts +1 -1
- package/dist/contracts/wire-scalar-format.d.ts +4 -4
- package/dist/framework/contract-view.d.ts +213 -147
- package/dist/framework/framework-construction.error.d.ts +19 -10
- package/dist/framework/framework-construction.error.js +7 -3
- package/dist/framework/framework.d.ts +47 -23
- package/dist/framework/framework.factory.d.ts +8 -6
- package/dist/framework/framework.factory.js +49 -22
- package/dist/framework/operation-facade.d.ts +123 -52
- package/dist/framework/operation-facade.js +9 -1
- package/dist/index.d.ts +57 -50
- package/dist/index.js +7 -6
- package/dist/internal.d.ts +17 -10
- package/dist/internal.js +4 -1
- package/dist/operations/database-refusal.d.ts +51 -0
- package/dist/operations/database-refusal.js +45 -0
- package/dist/operations/operation-arguments.d.ts +343 -207
- package/dist/operations/operation-call.d.ts +27 -28
- package/dist/operations/operation-identity.d.ts +10 -10
- package/dist/operations/operation-result.d.ts +21 -21
- package/dist/operations/operation-validator-core.d.ts +6 -6
- package/dist/operations/operation-validator-core.js +99 -6
- package/dist/operations/operation-validator.d.ts +9 -9
- package/dist/operations/projection-scope.resolver.d.ts +6 -6
- package/dist/operations/structural-limits.walker.d.ts +6 -6
- package/dist/operations/structural-limits.walker.js +145 -0
- package/dist/operations/validation-code.d.ts +11 -6
- package/dist/operations/validation-code.guidance.d.ts +6 -0
- package/dist/operations/validation-code.guidance.js +90 -0
- package/dist/operations/validation-code.js +4 -0
- package/dist/operations/write-scope.resolver.d.ts +10 -6
- package/dist/operations/write-scope.resolver.js +2 -0
- package/dist/protocol/absent-route.responder.d.ts +13 -12
- package/dist/protocol/absent-route.responder.js +19 -19
- package/dist/protocol/contract-document.responder.d.ts +3 -3
- package/dist/protocol/contract-document.responder.js +2 -2
- package/dist/protocol/http-request.decoder.d.ts +17 -13
- package/dist/protocol/http-request.decoder.js +10 -10
- package/dist/protocol/http-request.reader.d.ts +3 -3
- package/dist/protocol/http-response.encoder.d.ts +4 -4
- package/dist/protocol/http-response.encoder.js +94 -55
- package/dist/protocol/http-status.table.d.ts +2 -2
- package/dist/protocol/operation-response.guard.d.ts +2 -2
- package/dist/protocol/protocol-surface.d.ts +4 -4
- package/dist/protocol/protocol.binder.d.ts +50 -27
- package/dist/protocol/protocol.binder.js +12 -9
- package/dist/protocol/protocol.handler.d.ts +22 -13
- package/dist/protocol/protocol.handler.js +91 -17
- package/dist/protocol/unmounted-route.error.d.ts +4 -4
- package/dist/protocol/unmounted-route.error.js +2 -2
- package/dist/runtime/caller-data.copier.d.ts +22 -5
- package/dist/runtime/caller-data.copier.js +31 -14
- package/dist/runtime/caller-data.door.d.ts +17 -11
- package/dist/runtime/caller-data.door.js +6 -4
- package/dist/runtime/computed-read-runtime.d.ts +7 -6
- package/dist/runtime/computed-read-runtime.js +76 -50
- package/dist/runtime/computed-value.error.d.ts +7 -6
- package/dist/runtime/computed-value.error.js +5 -4
- package/dist/runtime/context-executor.runtime.d.ts +59 -0
- package/dist/runtime/context-executor.runtime.js +275 -0
- package/dist/runtime/create-requirement.d.ts +44 -79
- package/dist/runtime/create-requirement.js +213 -73
- package/dist/runtime/decimal.d.ts +2 -2
- package/dist/runtime/decimal.js +1 -1
- package/dist/runtime/diagnostics-reporter.d.ts +54 -27
- package/dist/runtime/diagnostics-reporter.js +24 -0
- package/dist/runtime/error-boundary.d.ts +65 -8
- package/dist/runtime/error-boundary.js +49 -19
- package/dist/runtime/error-guidance.d.ts +12 -0
- package/dist/runtime/error-guidance.js +1 -0
- package/dist/runtime/error.catalog.d.ts +49 -0
- package/dist/runtime/error.catalog.js +49 -0
- package/dist/runtime/execution-options.d.ts +10 -2
- package/dist/runtime/field-check.evaluator.d.ts +29 -0
- package/dist/runtime/field-check.evaluator.js +521 -0
- package/dist/runtime/field-compute.d.ts +64 -0
- package/dist/runtime/field-compute.js +1 -0
- package/dist/runtime/field-stage.plan.d.ts +15 -0
- package/dist/runtime/field-stage.plan.js +27 -0
- package/dist/runtime/field-stage.runtime.d.ts +37 -0
- package/dist/runtime/field-stage.runtime.js +147 -0
- package/dist/runtime/field-validator.runtime.d.ts +19 -0
- package/dist/runtime/field-validator.runtime.js +92 -0
- package/dist/runtime/framework-error-class.table.d.ts +33 -0
- package/dist/runtime/framework-error-class.table.js +25 -0
- package/dist/runtime/framework-error.d.ts +68 -8
- package/dist/runtime/framework-error.factory.d.ts +4 -0
- package/dist/runtime/framework-error.factory.js +15 -0
- package/dist/runtime/framework-error.js +23 -2
- package/dist/runtime/interceptor-next.error.d.ts +5 -0
- package/dist/runtime/interceptor-next.error.js +6 -0
- package/dist/runtime/json-value.d.ts +11 -6
- package/dist/runtime/level-lifecycle.runtime.d.ts +25 -0
- package/dist/runtime/level-lifecycle.runtime.js +39 -0
- package/dist/runtime/misuse-reporter.d.ts +12 -12
- package/dist/runtime/mutation-planner.d.ts +19 -10
- package/dist/runtime/mutation-planner.js +48 -35
- package/dist/runtime/nested-write.walker.d.ts +32 -0
- package/dist/runtime/nested-write.walker.js +73 -0
- package/dist/runtime/operation-code.guidance.d.ts +6 -0
- package/dist/runtime/operation-code.guidance.js +167 -0
- package/dist/runtime/operation-request.d.ts +33 -6
- package/dist/runtime/operation-response.d.ts +17 -17
- package/dist/runtime/operation-runtime.d.ts +127 -25
- package/dist/runtime/operation-runtime.js +441 -78
- package/dist/runtime/outcome-mapper.d.ts +16 -5
- package/dist/runtime/outcome-mapper.js +23 -6
- package/dist/runtime/output-validator.d.ts +10 -10
- package/dist/runtime/output-validator.js +3 -3
- package/dist/runtime/owned-execution.registry.d.ts +16 -6
- package/dist/runtime/pipe-output.validator.d.ts +43 -18
- package/dist/runtime/pipe-output.validator.js +15 -13
- package/dist/runtime/pipeline.d.ts +223 -34
- package/dist/runtime/readonly-value.d.ts +43 -0
- package/dist/runtime/readonly-value.js +150 -0
- package/dist/runtime/request-envelope.validator.d.ts +3 -3
- package/dist/runtime/request-envelope.validator.js +12 -7
- package/dist/runtime/request-id.d.ts +1 -1
- package/dist/runtime/request-state.d.ts +14 -0
- package/dist/runtime/request-state.js +1 -0
- package/dist/runtime/request-state.resolver.d.ts +12 -0
- package/dist/runtime/request-state.resolver.js +20 -0
- package/dist/runtime/scalar-runtime.d.ts +35 -16
- package/dist/runtime/scalar-runtime.js +102 -34
- package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
- package/dist/runtime/unsent-value.normalizer.js +128 -0
- package/dist/transactions/deferred-operation.d.ts +35 -20
- package/dist/transactions/operation-arguments-encoder.d.ts +3 -3
- package/dist/transactions/operation-arguments-encoder.js +2 -2
- package/dist/transactions/operation-fingerprint.js +2 -2
- package/dist/transactions/sql-statement.d.ts +85 -0
- package/dist/transactions/sql-statement.js +47 -0
- package/dist/transactions/sql-statement.validator.d.ts +44 -0
- package/dist/transactions/sql-statement.validator.js +167 -0
- package/dist/transactions/transaction-envelope.d.ts +4 -4
- package/dist/transactions/transaction-integrity-error.d.ts +6 -6
- package/dist/transactions/transaction-integrity-error.js +5 -2
- package/dist/transactions/transaction-plan-assembler.d.ts +21 -11
- package/dist/transactions/transaction-plan-assembler.js +169 -32
- package/dist/transactions/transaction-plan-validator.d.ts +45 -20
- package/dist/transactions/transaction-plan-validator.js +96 -38
- package/dist/transactions/transaction-reference-collector.d.ts +5 -5
- package/dist/transactions/transaction-reference-resolver.d.ts +19 -2
- package/dist/transactions/transaction-reference-resolver.js +26 -14
- package/dist/transactions/transaction-reference-validator.d.ts +76 -4
- package/dist/transactions/transaction-reference-validator.js +129 -71
- package/dist/transactions/transaction-reference.d.ts +13 -13
- package/dist/transactions/transaction-reference.js +5 -0
- package/dist/transactions/transaction-request.d.ts +18 -5
- package/dist/transactions/transaction-response.d.ts +6 -6
- package/dist/transactions/transaction-runtime.d.ts +8 -7
- package/dist/transactions/transaction-runtime.js +191 -50
- package/dist/transactions/transaction-settlement.runtime.d.ts +51 -0
- package/dist/transactions/transaction-settlement.runtime.js +120 -0
- package/dist/transactions/transaction-slot-path-error.d.ts +4 -4
- package/dist/transactions/transaction-slot-path-error.js +2 -2
- package/dist/transactions/transaction-slot-writer.js +2 -2
- package/dist/transactions/transaction-stage.runtime.d.ts +82 -0
- package/dist/transactions/transaction-stage.runtime.js +126 -0
- package/package.json +9 -7
- package/src/runtime/field-check.evaluator.ts +720 -0
- package/dist/config/define-fields.d.ts +0 -42
- package/dist/config/define-fields.js +0 -3
- package/dist/config/framework-behaviors-config.d.ts +0 -30
- package/dist/config/framework-fields-config.d.ts +0 -42
- package/dist/config/framework-restrictions-config.d.ts +0 -142
- package/dist/json/avz.d.ts +0 -96
- package/dist/runtime/field-behavior.d.ts +0 -48
- /package/dist/{config/framework-behaviors-config.js → adapters/adapter-sql-statement.js} +0 -0
- /package/dist/{config/framework-fields-config.js → adapters/adapter-transaction-executor.interface.js} +0 -0
- /package/dist/{json → avz}/index.js +0 -0
- /package/dist/{json → avz}/json-shape.registry.js +0 -0
- /package/dist/config/{framework-restrictions-config.js → exact-framework-config.js} +0 -0
- /package/dist/{runtime/field-behavior.js → config/field-pipeline-config.js} +0 -0
|
@@ -28,6 +28,109 @@ function nestingExceeded(state) {
|
|
|
28
28
|
message: `Request nesting exceeds maxNestingDepth (${state.nestingLimit}).`,
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
+
function jsonDepthExceeded(state, fieldPath) {
|
|
32
|
+
state.nestingAtField = true;
|
|
33
|
+
state.nesting = {
|
|
34
|
+
path: state.tracking ? fieldPath : ["arguments", state.rootKey],
|
|
35
|
+
code: "V1021",
|
|
36
|
+
message: `Json value depth exceeds maxJsonDepth (${state.jsonDepthLimit}).`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function isJsonField(field) {
|
|
40
|
+
return "scalar" in field.type && field.type.scalar === "json";
|
|
41
|
+
}
|
|
42
|
+
function jsonValueExceeds(state, value) {
|
|
43
|
+
const deepest = new Map();
|
|
44
|
+
const ancestors = new Set();
|
|
45
|
+
const stack = [{ leave: false, value, level: 0 }];
|
|
46
|
+
while (stack.length > 0) {
|
|
47
|
+
const task = stack.pop();
|
|
48
|
+
if (task.leave) {
|
|
49
|
+
ancestors.delete(task.container);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const current = task.value;
|
|
53
|
+
if (typeof current !== "object" ||
|
|
54
|
+
current === null ||
|
|
55
|
+
ancestors.has(current)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const inner = task.level + 1;
|
|
59
|
+
if (inner > state.jsonDepthLimit) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
const seen = deepest.get(current);
|
|
63
|
+
if (seen !== undefined && seen >= inner) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
deepest.set(current, inner);
|
|
67
|
+
ancestors.add(current);
|
|
68
|
+
stack.push({ leave: true, container: current });
|
|
69
|
+
const entries = Array.isArray(current)
|
|
70
|
+
? current
|
|
71
|
+
: Object.values(current);
|
|
72
|
+
for (const entry of entries) {
|
|
73
|
+
stack.push({ leave: false, value: entry, level: inner });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
function walkJsonWrite(state, field, value, path) {
|
|
79
|
+
const operands = isRecord(value) && Object.keys(value).some((key) => key.startsWith("$"))
|
|
80
|
+
? Object.entries(value)
|
|
81
|
+
.filter(([key]) => key !== "$unset" && key !== "$ref")
|
|
82
|
+
.map(([, operand]) => operand)
|
|
83
|
+
: [value];
|
|
84
|
+
for (const operand of operands) {
|
|
85
|
+
const values = field.list && Array.isArray(operand) ? operand : [operand];
|
|
86
|
+
for (const entry of values) {
|
|
87
|
+
if (jsonValueExceeds(state, entry)) {
|
|
88
|
+
jsonDepthExceeded(state, path);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const JSON_LIST_OPERATORS = new Set(["in", "notIn", "hasEvery", "hasSome"]);
|
|
95
|
+
const JSON_VALUELESS_OPERATORS = new Set(["mode", "isEmpty", "path"]);
|
|
96
|
+
function walkJsonFilter(state, filter, depth, path) {
|
|
97
|
+
let level = depth;
|
|
98
|
+
let current = filter;
|
|
99
|
+
while (isRecord(current)) {
|
|
100
|
+
let next;
|
|
101
|
+
for (const operator of Object.keys(current)) {
|
|
102
|
+
const operand = current[operator];
|
|
103
|
+
if (operator === "not" && isRecord(operand)) {
|
|
104
|
+
next = operand;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (JSON_VALUELESS_OPERATORS.has(operator)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const values = JSON_LIST_OPERATORS.has(operator) && Array.isArray(operand)
|
|
111
|
+
? operand
|
|
112
|
+
: [operand];
|
|
113
|
+
for (const entry of values) {
|
|
114
|
+
if (jsonValueExceeds(state, entry)) {
|
|
115
|
+
jsonDepthExceeded(state, path);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (next === undefined) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
level += 1;
|
|
124
|
+
if (level > state.nestingLimit) {
|
|
125
|
+
nestingExceeded(state);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
current = next;
|
|
129
|
+
}
|
|
130
|
+
if (jsonValueExceeds(state, current)) {
|
|
131
|
+
jsonDepthExceeded(state, path);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
31
134
|
function countBooleanNode(state, path, key) {
|
|
32
135
|
if (state.booleanExceeded) {
|
|
33
136
|
return;
|
|
@@ -74,7 +177,18 @@ function walkWhere(state, resourceName, value, depth, path, counting) {
|
|
|
74
177
|
}
|
|
75
178
|
else {
|
|
76
179
|
const field = lookupField(resource, key);
|
|
180
|
+
if (field?.kind === "scalar") {
|
|
181
|
+
if (isJsonField(field)) {
|
|
182
|
+
walkJsonFilter(state, child, depth, extend(state, path, key));
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
walkScalarNot(state, child, depth);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
77
188
|
if (field?.kind !== "relation") {
|
|
189
|
+
if (state.nesting !== undefined) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
78
192
|
continue;
|
|
79
193
|
}
|
|
80
194
|
if (field.cardinality === "one") {
|
|
@@ -97,6 +211,22 @@ function walkWhere(state, resourceName, value, depth, path, counting) {
|
|
|
97
211
|
}
|
|
98
212
|
}
|
|
99
213
|
}
|
|
214
|
+
function walkScalarNot(state, filter, depth) {
|
|
215
|
+
let level = depth;
|
|
216
|
+
let current = filter;
|
|
217
|
+
while (isRecord(current) && Object.hasOwn(current, "not")) {
|
|
218
|
+
const operand = current.not;
|
|
219
|
+
if (!isRecord(operand)) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
level += 1;
|
|
223
|
+
if (level > state.nestingLimit) {
|
|
224
|
+
nestingExceeded(state);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
current = operand;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
100
230
|
function walkOrderBy(state, resourceName, value, depth) {
|
|
101
231
|
const resource = lookupResource(state.contract, resourceName);
|
|
102
232
|
if (resource === undefined) {
|
|
@@ -194,6 +324,13 @@ function walkMutationData(state, resourceName, value, depth, path, stage, counti
|
|
|
194
324
|
for (const fieldName of Object.keys(value)) {
|
|
195
325
|
const edge = lookupField(resource, fieldName);
|
|
196
326
|
const directives = value[fieldName];
|
|
327
|
+
if (edge?.kind === "scalar" && isJsonField(edge)) {
|
|
328
|
+
walkJsonWrite(state, edge, directives, extend(state, path, fieldName));
|
|
329
|
+
if (state.nesting !== undefined) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
197
334
|
if (edge?.kind !== "relation" || !isRecord(directives)) {
|
|
198
335
|
continue;
|
|
199
336
|
}
|
|
@@ -321,11 +458,13 @@ function walk(contract, request, args, tracking) {
|
|
|
321
458
|
const state = {
|
|
322
459
|
contract,
|
|
323
460
|
nestingLimit: contract.limits.maxNestingDepth,
|
|
461
|
+
jsonDepthLimit: contract.limits.maxJsonDepth,
|
|
324
462
|
booleanLimit: contract.limits.maxBooleanNodes,
|
|
325
463
|
tracking,
|
|
326
464
|
rootKey: "",
|
|
327
465
|
booleanCount: 0,
|
|
328
466
|
nesting: undefined,
|
|
467
|
+
nestingAtField: false,
|
|
329
468
|
booleanNodes: undefined,
|
|
330
469
|
booleanExceeded: false,
|
|
331
470
|
};
|
|
@@ -334,6 +473,12 @@ function walk(contract, request, args, tracking) {
|
|
|
334
473
|
}
|
|
335
474
|
export function findStructuralLimitIssues(contract, request, args) {
|
|
336
475
|
const untracked = walk(contract, request, args, false);
|
|
476
|
+
if (untracked.nestingAtField) {
|
|
477
|
+
return {
|
|
478
|
+
nesting: walk(contract, request, args, true).nesting,
|
|
479
|
+
booleanNodes: undefined,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
337
482
|
if (untracked.nesting !== undefined || !untracked.booleanExceeded) {
|
|
338
483
|
return { nesting: untracked.nesting, booleanNodes: undefined };
|
|
339
484
|
}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
+
import type { AvFieldCheck } from "../contracts/field-check.js";
|
|
1
2
|
/** The set of allocated Validation codes, as a runtime array. */
|
|
2
|
-
export declare const VALIDATION_CODES: readonly ["V1000", "V1001", "V1002", "V1003", "V1004", "V1005", "V1006", "V1007", "V1008", "V1009", "V1010", "V1011", "V1012", "V1013", "V1014", "V1015", "V1016", "V1017", "V1018", "V1019"];
|
|
3
|
+
export declare const VALIDATION_CODES: readonly ["V1000", "V1001", "V1002", "V1003", "V1004", "V1005", "V1006", "V1007", "V1008", "V1009", "V1010", "V1011", "V1012", "V1013", "V1014", "V1015", "V1016", "V1017", "V1018", "V1019", "V1020", "V1021"];
|
|
3
4
|
/** A validation code (`V1000` and up), one per kind of argument problem. */
|
|
4
|
-
export type
|
|
5
|
+
export type AvValidationCode = (typeof VALIDATION_CODES)[number];
|
|
5
6
|
/** The framework's message for each validation code. */
|
|
6
|
-
export declare const VALIDATION_CODE_MESSAGES: Readonly<Record<
|
|
7
|
+
export declare const VALIDATION_CODE_MESSAGES: Readonly<Record<AvValidationCode, string>>;
|
|
7
8
|
/** One validation problem: its code, message and the argument path it is at. */
|
|
8
|
-
export type
|
|
9
|
+
export type AvValidationIssue = {
|
|
9
10
|
readonly path?: readonly (string | number)[];
|
|
10
|
-
readonly code:
|
|
11
|
+
readonly code: AvValidationCode;
|
|
11
12
|
readonly message: string;
|
|
13
|
+
/** The failed field validator's check name (`max_length`, `string_format`, …). */
|
|
14
|
+
readonly check?: AvFieldCheck["check"];
|
|
15
|
+
/** That check's parameters, as the Contract stores them (`{ maximum: 80 }`). */
|
|
16
|
+
readonly params?: Readonly<Record<string, unknown>>;
|
|
12
17
|
};
|
|
13
18
|
/** Builds one validation issue at its path. */
|
|
14
|
-
export declare function validationIssue(code:
|
|
19
|
+
export declare function validationIssue(code: AvValidationCode, path: readonly (string | number)[], message: string): AvValidationIssue;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ErrorCodeGuidance } from "../runtime/error-guidance.js";
|
|
2
|
+
import type { AvValidationCode } from "./validation-code.js";
|
|
3
|
+
/** Cause and fix of every validation code. */
|
|
4
|
+
export declare const VALIDATION_CODE_GUIDANCE: {
|
|
5
|
+
readonly [C in AvValidationCode]: ErrorCodeGuidance;
|
|
6
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export const VALIDATION_CODE_GUIDANCE = {
|
|
2
|
+
V1000: {
|
|
3
|
+
cause: "A required value is absent: a create leaves out a required field that has no database default and no compute.create (the path names the field), a required relation and its reference field are both missing, a typed Json field lacks a required key, or a $ref has no fingerprint.",
|
|
4
|
+
fix: "Send the value at the issue's path. When the server must fill it, give the field a compute.create stage or a database default; a pipe cannot fill it.",
|
|
5
|
+
},
|
|
6
|
+
V1001: {
|
|
7
|
+
cause: "A value of the wrong type: a string where a number is expected, a negative limit, a non-integer id, null given to an operator with no null meaning (gt, contains, in), two directives in one scalar action object (`{ $increment: 1, $decrement: 2 }`), or a server-side value that is not plain data.",
|
|
8
|
+
fix: "Send the type the contract states at that path (the generated client's types say it).",
|
|
9
|
+
},
|
|
10
|
+
V1002: {
|
|
11
|
+
cause: "A value that is not a member of the enum, or outside a typed Json field's AvZ.enum or AvZ.literal.",
|
|
12
|
+
fix: "Send one of the enum's members.",
|
|
13
|
+
},
|
|
14
|
+
V1003: {
|
|
15
|
+
cause: 'A malformed datetime, decimal, base64 or UUID string, or a failed pattern or format validator (`check: "string_format"`).',
|
|
16
|
+
fix: "Send the canonical encoding (ISO-8601 UTC datetime, decimal string, base64 bytes) and satisfy the validator that check and params name.",
|
|
17
|
+
},
|
|
18
|
+
V1004: {
|
|
19
|
+
cause: "A number, length or size outside its range: a failed bound, length or size validator, a BigInt outside signed 64 bits, an AvZ.int() outside the safe integer range, or a transaction with no operations.",
|
|
20
|
+
fix: "Send a value inside the range; check and params name the validator that failed.",
|
|
21
|
+
},
|
|
22
|
+
V1005: {
|
|
23
|
+
cause: "A field that does not exist or is hidden in the caller's layer, an unknown Resource (under A2001), or a key a typed Json field's shape does not declare.",
|
|
24
|
+
fix: "Use a field the caller's contract exposes, expose it through exemptions, or make the call from server code.",
|
|
25
|
+
},
|
|
26
|
+
V1006: {
|
|
27
|
+
cause: "An operator, directive or nested write the field does not offer (at any depth, inside not too; a to-many $update's data takes only what a bulk write takes), a mode it does not offer, or an operation that is not available (under A2002).",
|
|
28
|
+
fix: "Use what the contract lists for that field or Resource, or expose it through exemptions.",
|
|
29
|
+
},
|
|
30
|
+
V1007: {
|
|
31
|
+
cause: "The where of a unique operation is not exactly one complete identifier.",
|
|
32
|
+
fix: "Pass exactly one identifier: the id, or every field of one @unique or @@unique.",
|
|
33
|
+
},
|
|
34
|
+
V1008: {
|
|
35
|
+
cause: "Both select and include, a write-only field selected, or a relation that is not selectable there.",
|
|
36
|
+
fix: "Use select or include, not both, and select only readable fields.",
|
|
37
|
+
},
|
|
38
|
+
V1009: {
|
|
39
|
+
cause: "A cursor without an explicit orderBy, or cursor keys that do not match the ordered fields.",
|
|
40
|
+
fix: "Give an orderBy and a cursor holding exactly its ordered fields.",
|
|
41
|
+
},
|
|
42
|
+
V1010: {
|
|
43
|
+
cause: "A $ref path the earlier step does not return, a $ref to a step that is not in the transaction, or to a step with no single row (a many or count step).",
|
|
44
|
+
fix: "Select the referenced field in the earlier step, and reference a single-row step.",
|
|
45
|
+
},
|
|
46
|
+
V1011: {
|
|
47
|
+
cause: "The referenced value's type does not fit its target, a nullable source where only a non-null value is accepted included.",
|
|
48
|
+
fix: "Reference a field of the target's type, non-null where the target needs it.",
|
|
49
|
+
},
|
|
50
|
+
V1012: {
|
|
51
|
+
cause: "A nested write that does not fit the relation (a list where one record is expected), a reference field set together with its own relation, one record mixing reference fields and relation writes where the adapter cannot run both, or a record written through a relation that writes that relation (or a field holding its reference) back, where the adapter admits no such write.",
|
|
52
|
+
fix: "Write either the relation or its reference field, in the relation's cardinality.",
|
|
53
|
+
},
|
|
54
|
+
V1013: {
|
|
55
|
+
cause: "Nested projections, filters or writes deeper than maxNestingDepth.",
|
|
56
|
+
fix: "Nest less, or raise limits.maxNestingDepth.",
|
|
57
|
+
},
|
|
58
|
+
V1014: {
|
|
59
|
+
cause: "A limit above maxListLimit, or more steps than maxTransactionOperations.",
|
|
60
|
+
fix: "Paginate or split the plan, or raise the limit.",
|
|
61
|
+
},
|
|
62
|
+
V1015: {
|
|
63
|
+
cause: "A where tree with more nodes than maxBooleanNodes.",
|
|
64
|
+
fix: "Simplify the filter (in instead of many OR clauses), or raise limits.maxBooleanNodes.",
|
|
65
|
+
},
|
|
66
|
+
V1016: {
|
|
67
|
+
cause: "A $ref to the referencing step itself or a later one, or to an index no step has.",
|
|
68
|
+
fix: "Reference an earlier step only.",
|
|
69
|
+
},
|
|
70
|
+
V1017: {
|
|
71
|
+
cause: "A hand-written plan whose fingerprint does not match its step.",
|
|
72
|
+
fix: "Let the generated client, framework.appTx or framework.clientTx build the plan.",
|
|
73
|
+
},
|
|
74
|
+
V1018: {
|
|
75
|
+
cause: "The referenced step returned no value at that path, such as a first step that matched no row.",
|
|
76
|
+
fix: "Make sure the earlier step returns a row, or use a unique step, which fails with A2003.",
|
|
77
|
+
},
|
|
78
|
+
V1019: {
|
|
79
|
+
cause: "A later step uses a row that an earlier step's delete removed through a database cascade.",
|
|
80
|
+
fix: "Reorder or drop the dependent step.",
|
|
81
|
+
},
|
|
82
|
+
V1020: {
|
|
83
|
+
cause: "One framework.transaction([...]) list mixes appTx and clientTx steps.",
|
|
84
|
+
fix: "Build every step of a plan from one origin.",
|
|
85
|
+
},
|
|
86
|
+
V1021: {
|
|
87
|
+
cause: "A Json field's value nests deeper than maxJsonDepth.",
|
|
88
|
+
fix: "Flatten the value, or raise limits.maxJsonDepth.",
|
|
89
|
+
},
|
|
90
|
+
};
|
|
@@ -19,6 +19,8 @@ export const VALIDATION_CODES = [
|
|
|
19
19
|
"V1017",
|
|
20
20
|
"V1018",
|
|
21
21
|
"V1019",
|
|
22
|
+
"V1020",
|
|
23
|
+
"V1021",
|
|
22
24
|
];
|
|
23
25
|
export const VALIDATION_CODE_MESSAGES = {
|
|
24
26
|
V1000: "Required value missing.",
|
|
@@ -41,6 +43,8 @@ export const VALIDATION_CODE_MESSAGES = {
|
|
|
41
43
|
V1017: "Transaction fingerprint mismatch.",
|
|
42
44
|
V1018: "Transaction reference resolved to no value.",
|
|
43
45
|
V1019: "Transaction step depends on a row removed by an earlier step's cascade",
|
|
46
|
+
V1020: "Transaction mixes application and client steps.",
|
|
47
|
+
V1021: "Json value depth limit exceeded.",
|
|
44
48
|
};
|
|
45
49
|
export function validationIssue(code, path, message) {
|
|
46
50
|
return { code, path, message };
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
1
|
+
import type { AvWriteScope } from "../contracts/capability.js";
|
|
2
|
+
import type { AvContract } from "../contracts/contract.js";
|
|
3
|
+
import type { AvResource } from "../contracts/resource.js";
|
|
4
|
+
import type { AvOperationIdentity } from "./operation-identity.js";
|
|
5
5
|
/**
|
|
6
6
|
* Which write position one request's top-level `data` (or `create`/`update`)
|
|
7
7
|
* argument sits in, read off the variant the Resource advertises. `"nested"`
|
|
8
8
|
* wherever nothing narrower is stated.
|
|
9
9
|
*/
|
|
10
|
-
export declare function resolveWriteScope(resource:
|
|
10
|
+
export declare function resolveWriteScope(resource: AvResource<AvContract> | undefined, request: AvOperationIdentity): AvWriteScope;
|
|
11
11
|
/**
|
|
12
12
|
* The position a write NESTED beneath an admitted relation directive sits in: the
|
|
13
13
|
* unrestricted one, at every depth, under every top-level scope.
|
|
14
14
|
*/
|
|
15
|
-
export declare const NESTED_WRITE_SCOPE:
|
|
15
|
+
export declare const NESTED_WRITE_SCOPE: AvWriteScope;
|
|
16
|
+
/** The position a to-many `$update`'s `data` sits in: the flat-bulk write position. */
|
|
17
|
+
export declare const TO_MANY_UPDATE_WRITE_SCOPE: AvWriteScope;
|
|
18
|
+
/** The position of a relation's other end inside a record written through it. */
|
|
19
|
+
export declare const LOOPBACK_WRITE_SCOPE: AvWriteScope;
|
|
@@ -5,3 +5,5 @@ export function resolveWriteScope(resource, request) {
|
|
|
5
5
|
return writeScopeOf(lookupOwn(advertised, request.variant));
|
|
6
6
|
}
|
|
7
7
|
export const NESTED_WRITE_SCOPE = "nested";
|
|
8
|
+
export const TO_MANY_UPDATE_WRITE_SCOPE = "bulkWrite";
|
|
9
|
+
export const LOOPBACK_WRITE_SCOPE = "loopback";
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
import { type
|
|
1
|
+
import type { AvContracts } from "../compiler/contract.compiler.js";
|
|
2
|
+
import type { RemoteRequestOrigin } from "../config/config-layer.js";
|
|
3
|
+
import { type AvOperationIdentity } from "../operations/operation-identity.js";
|
|
4
|
+
import { type AvDiagnosticsSink } from "../runtime/diagnostics-reporter.js";
|
|
4
5
|
import type { ClientProtocolIdentity } from "../runtime/operation-request.js";
|
|
5
|
-
import { type
|
|
6
|
+
import { type AvOperationFailureResponse } from "../runtime/operation-response.js";
|
|
6
7
|
import type { AvProtocolRequest } from "./http-request.decoder.js";
|
|
7
8
|
import { type ReadRequest } from "./http-request.reader.js";
|
|
8
9
|
import { type AvProtocolResponse } from "./http-response.encoder.js";
|
|
@@ -23,10 +24,10 @@ export type OperationRouteSegments = {
|
|
|
23
24
|
/** What a route check resolves to: the operation it names, or the answer that refuses it. */
|
|
24
25
|
export type OperationRouteResolution = {
|
|
25
26
|
readonly ok: true;
|
|
26
|
-
readonly operation:
|
|
27
|
+
readonly operation: AvOperationIdentity;
|
|
27
28
|
} | {
|
|
28
29
|
readonly ok: false;
|
|
29
|
-
readonly failure:
|
|
30
|
+
readonly failure: AvOperationFailureResponse;
|
|
30
31
|
};
|
|
31
32
|
/**
|
|
32
33
|
* An operation route `/_resources/<resource>/<family>/<variant>` under one client
|
|
@@ -35,7 +36,7 @@ export type OperationRouteResolution = {
|
|
|
35
36
|
* is a standard operation the Resource advertises, read through
|
|
36
37
|
* `isOperationVariantAvailable` alone.
|
|
37
38
|
*/
|
|
38
|
-
export declare function resolveOperationRoute(contracts:
|
|
39
|
+
export declare function resolveOperationRoute(contracts: AvContracts, protocol: ClientProtocolIdentity, route: OperationRouteSegments, origin?: RemoteRequestOrigin): OperationRouteResolution;
|
|
39
40
|
/**
|
|
40
41
|
* The `/_transactions` route under one client protocol identity: version → hash → the
|
|
41
42
|
* ClientContract's transaction capability. The route exists only when that capability
|
|
@@ -43,7 +44,7 @@ export declare function resolveOperationRoute(contracts: FrameworkContracts, pro
|
|
|
43
44
|
* it — and is otherwise absent with core's own refusal of a plan. `undefined` when the
|
|
44
45
|
* route is there.
|
|
45
46
|
*/
|
|
46
|
-
export declare function transactionsRouteFailure(contracts:
|
|
47
|
+
export declare function transactionsRouteFailure(contracts: AvContracts, protocol: ClientProtocolIdentity, origin?: RemoteRequestOrigin): AvOperationFailureResponse | undefined;
|
|
47
48
|
/**
|
|
48
49
|
* What a route's checks before its body resolve to: the route a request
|
|
49
50
|
* reaches, or the framework response that answers it instead.
|
|
@@ -63,9 +64,9 @@ type RouteCheck<Route> = ({
|
|
|
63
64
|
* for both route styles: `decodeOperation` reads the body only after it passes,
|
|
64
65
|
* `answerAbsent` never.
|
|
65
66
|
*/
|
|
66
|
-
export declare function checkOperationRoute(contracts:
|
|
67
|
+
export declare function checkOperationRoute(contracts: AvContracts, read: ReadRequest, origin?: RemoteRequestOrigin): RouteCheck<{
|
|
67
68
|
readonly resource: string;
|
|
68
|
-
readonly operation:
|
|
69
|
+
readonly operation: AvOperationIdentity;
|
|
69
70
|
}>;
|
|
70
71
|
/**
|
|
71
72
|
* `/_transactions`' checks before its body: the path (`A2000` unless exactly
|
|
@@ -73,12 +74,12 @@ export declare function checkOperationRoute(contracts: FrameworkContracts, read:
|
|
|
73
74
|
* {@link transactionsRouteFailure} — version, hash, `"interactive"` — and the
|
|
74
75
|
* method (`A2012`, `Allow: POST`).
|
|
75
76
|
*/
|
|
76
|
-
export declare function checkTransactionsRoute(contracts:
|
|
77
|
+
export declare function checkTransactionsRoute(contracts: AvContracts, read: ReadRequest, origin?: RemoteRequestOrigin): RouteCheck<object>;
|
|
77
78
|
/**
|
|
78
79
|
* `protocol.answerAbsent(request)` — the fallback a host that mounts one route per
|
|
79
80
|
* `protocol.surface()` entry mounts for every path it did not. Never a catch-all into
|
|
80
81
|
* framework handling: it reads no body, runs no pipeline, calls no Adapter, and takes
|
|
81
82
|
* only the compiled Contracts. In order:
|
|
82
83
|
*/
|
|
83
|
-
export declare function answerAbsentRequest(contracts:
|
|
84
|
+
export declare function answerAbsentRequest(contracts: AvContracts, received: AvProtocolRequest, sink?: AvDiagnosticsSink, origin?: RemoteRequestOrigin): AvProtocolResponse | undefined;
|
|
84
85
|
export {};
|
|
@@ -12,13 +12,13 @@ import { CONTRACT_ROUTE, GET_ONLY, isProtocolPath, operationRouteSegments, POST_
|
|
|
12
12
|
import { encodeOperationResponse, } from "./http-response.encoder.js";
|
|
13
13
|
import { identityHeadersMissing, transportFailure, } from "./protocol-failure.js";
|
|
14
14
|
import { missingIdentityHeaders } from "./protocol-headers.js";
|
|
15
|
-
import {
|
|
16
|
-
export function resolveOperationRoute(contracts, protocol, route) {
|
|
17
|
-
const identityFailure = protocolIdentityFailure(contracts, protocol);
|
|
15
|
+
import { AvUnmountedRouteError } from "./unmounted-route.error.js";
|
|
16
|
+
export function resolveOperationRoute(contracts, protocol, route, origin = "client") {
|
|
17
|
+
const identityFailure = protocolIdentityFailure(contracts, protocol, origin);
|
|
18
18
|
if (identityFailure !== undefined) {
|
|
19
19
|
return { ok: false, failure: identityFailure };
|
|
20
20
|
}
|
|
21
|
-
const resource = lookupResource(contracts
|
|
21
|
+
const resource = lookupResource(contracts[origin], route.resource);
|
|
22
22
|
if (resource === undefined) {
|
|
23
23
|
return {
|
|
24
24
|
ok: false,
|
|
@@ -32,19 +32,19 @@ export function resolveOperationRoute(contracts, protocol, route) {
|
|
|
32
32
|
return {
|
|
33
33
|
ok: false,
|
|
34
34
|
failure: mapValidationOutcome([
|
|
35
|
-
operationUnavailableIssue(contracts
|
|
35
|
+
operationUnavailableIssue(contracts[origin], route),
|
|
36
36
|
]),
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
return { ok: true, operation };
|
|
40
40
|
}
|
|
41
|
-
export function transactionsRouteFailure(contracts, protocol) {
|
|
42
|
-
return (protocolIdentityFailure(contracts, protocol) ??
|
|
43
|
-
(contracts.
|
|
41
|
+
export function transactionsRouteFailure(contracts, protocol, origin = "client") {
|
|
42
|
+
return (protocolIdentityFailure(contracts, protocol, origin) ??
|
|
43
|
+
(contracts[origin].transactions === "interactive"
|
|
44
44
|
? undefined
|
|
45
45
|
: transactionsUnavailableFailure()));
|
|
46
46
|
}
|
|
47
|
-
export function checkOperationRoute(contracts, read) {
|
|
47
|
+
export function checkOperationRoute(contracts, read, origin = "client") {
|
|
48
48
|
const segments = operationRouteSegments(read.request.path);
|
|
49
49
|
if (segments === undefined) {
|
|
50
50
|
return refusedWith(transportFailure("A2000", read.requestId));
|
|
@@ -52,7 +52,7 @@ export function checkOperationRoute(contracts, read) {
|
|
|
52
52
|
if (read.protocol === undefined) {
|
|
53
53
|
return refusedWith(identityFailureOf(read));
|
|
54
54
|
}
|
|
55
|
-
const route = resolveOperationRoute(contracts, read.protocol, segments);
|
|
55
|
+
const route = resolveOperationRoute(contracts, read.protocol, segments, origin);
|
|
56
56
|
if (!route.ok) {
|
|
57
57
|
return refusedWith(encodeOperationResponse(route.failure, read.requestId));
|
|
58
58
|
}
|
|
@@ -65,14 +65,14 @@ export function checkOperationRoute(contracts, read) {
|
|
|
65
65
|
}
|
|
66
66
|
: refusedWith(transportFailure("A2012", read.requestId, POST_ONLY));
|
|
67
67
|
}
|
|
68
|
-
export function checkTransactionsRoute(contracts, read) {
|
|
68
|
+
export function checkTransactionsRoute(contracts, read, origin = "client") {
|
|
69
69
|
if (read.request.path !== TRANSACTIONS_ROUTE) {
|
|
70
70
|
return refusedWith(transportFailure("A2000", read.requestId));
|
|
71
71
|
}
|
|
72
72
|
if (read.protocol === undefined) {
|
|
73
73
|
return refusedWith(identityFailureOf(read));
|
|
74
74
|
}
|
|
75
|
-
const absent = transactionsRouteFailure(contracts, read.protocol);
|
|
75
|
+
const absent = transactionsRouteFailure(contracts, read.protocol, origin);
|
|
76
76
|
if (absent !== undefined) {
|
|
77
77
|
return refusedWith(encodeOperationResponse(absent, read.requestId));
|
|
78
78
|
}
|
|
@@ -86,7 +86,7 @@ function identityFailureOf(read) {
|
|
|
86
86
|
function refusedWith(response) {
|
|
87
87
|
return { ok: false, response };
|
|
88
88
|
}
|
|
89
|
-
export function answerAbsentRequest(contracts, received, sink) {
|
|
89
|
+
export function answerAbsentRequest(contracts, received, sink, origin = "client") {
|
|
90
90
|
const read = readRequest(received);
|
|
91
91
|
if (!read.ok) {
|
|
92
92
|
return read.response;
|
|
@@ -101,30 +101,30 @@ export function answerAbsentRequest(contracts, received, sink) {
|
|
|
101
101
|
: transportFailure("A2012", read.requestId, GET_ONLY);
|
|
102
102
|
}
|
|
103
103
|
if (path === TRANSACTIONS_ROUTE) {
|
|
104
|
-
const route = checkTransactionsRoute(contracts, read);
|
|
104
|
+
const route = checkTransactionsRoute(contracts, read, origin);
|
|
105
105
|
if (!route.ok) {
|
|
106
106
|
return route.response;
|
|
107
107
|
}
|
|
108
108
|
createReporter(sink, {
|
|
109
109
|
kind: "transaction",
|
|
110
|
-
origin
|
|
110
|
+
origin,
|
|
111
111
|
requestId: read.requestId,
|
|
112
|
-
})(new
|
|
112
|
+
})(new AvUnmountedRouteError("transactions", `POST ${TRANSACTIONS_ROUTE}`), "A3000");
|
|
113
113
|
return unmounted(read.requestId);
|
|
114
114
|
}
|
|
115
|
-
const route = checkOperationRoute(contracts, read);
|
|
115
|
+
const route = checkOperationRoute(contracts, read, origin);
|
|
116
116
|
if (!route.ok) {
|
|
117
117
|
return route.response;
|
|
118
118
|
}
|
|
119
119
|
const { family, variant } = route.operation;
|
|
120
120
|
createReporter(sink, {
|
|
121
121
|
kind: "operation",
|
|
122
|
-
origin
|
|
122
|
+
origin,
|
|
123
123
|
resource: route.resource,
|
|
124
124
|
family,
|
|
125
125
|
variant,
|
|
126
126
|
requestId: read.requestId,
|
|
127
|
-
})(new
|
|
127
|
+
})(new AvUnmountedRouteError(`${route.resource}.${family}.${variant}`, `POST ${path}`), "A3000");
|
|
128
128
|
return unmounted(read.requestId);
|
|
129
129
|
}
|
|
130
130
|
function unmounted(requestId) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AvContractClient } from "../contracts/contract.js";
|
|
2
2
|
import type { AvProtocolRequest } from "./http-request.decoder.js";
|
|
3
3
|
import type { AvProtocolResponse } from "./http-response.encoder.js";
|
|
4
4
|
/**
|
|
@@ -11,9 +11,9 @@ export type ContractDocument = {
|
|
|
11
11
|
readonly etag: string;
|
|
12
12
|
};
|
|
13
13
|
/** The bound ClientContract as the document `_contract` serves. */
|
|
14
|
-
export declare function contractDocumentOf(client:
|
|
14
|
+
export declare function contractDocumentOf(client: AvContractClient): ContractDocument;
|
|
15
15
|
/**
|
|
16
|
-
* `protocol.encodeContract(request)`: the `GET <
|
|
16
|
+
* `protocol.encodeContract(request)`: the `GET <api>/_contract` responder. In
|
|
17
17
|
* order:
|
|
18
18
|
*/
|
|
19
19
|
export declare function encodeContractRequest(document: ContractDocument, received: AvProtocolRequest): AvProtocolResponse;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { canonicalContractTextOf } from "../contracts/contract-canonicalizer.js";
|
|
2
2
|
import { CONTRACT_ROUTE, GET_ONLY, readRequest, } from "./http-request.reader.js";
|
|
3
3
|
import { transportFailure } from "./protocol-failure.js";
|
|
4
4
|
import { headers, headerValue } from "./protocol-headers.js";
|
|
5
5
|
export function contractDocumentOf(client) {
|
|
6
6
|
return Object.freeze({
|
|
7
|
-
body:
|
|
7
|
+
body: canonicalContractTextOf(client),
|
|
8
8
|
etag: `"${client.protocol.hash}"`,
|
|
9
9
|
});
|
|
10
10
|
}
|