@aventara/core 0.1.0-pilot.3 → 1.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +338 -0
- package/README.md +100 -3
- package/dist/adapters/adapter-discovery-diagnostic.d.ts +2 -0
- package/dist/adapters/adapter-field.d.ts +3 -26
- package/dist/adapters/adapter-identifier.d.ts +1 -11
- package/dist/adapters/adapter-model.d.ts +12 -0
- package/dist/adapters/adapter-operation-executor.interface.d.ts +5 -1
- package/dist/adapters/adapter-resource.d.ts +7 -28
- package/dist/adapters/adapter.interface.d.ts +25 -26
- package/dist/compiler/contract-compiler-diagnostic.d.ts +8 -0
- package/dist/compiler/contract.compiler.d.ts +11 -22
- package/dist/compiler/contract.compiler.js +67 -0
- package/dist/config/any-framework-config.d.ts +5 -26
- package/dist/config/config-diagnostic.d.ts +2 -0
- package/dist/config/config-layer.d.ts +6 -19
- package/dist/config/config.resolver.d.ts +9 -14
- package/dist/config/config.resolver.js +1 -0
- package/dist/config/config.validator.d.ts +6 -3
- package/dist/config/config.validator.js +6 -0
- package/dist/config/define-fields.d.ts +15 -48
- package/dist/config/effective-fields.d.ts +6 -29
- package/dist/config/entrypoint.normalizer.d.ts +6 -18
- package/dist/config/framework-behaviors-config.d.ts +11 -10
- package/dist/config/framework-config.d.ts +19 -16
- package/dist/config/framework-fields-config.d.ts +20 -7
- package/dist/config/framework-restrictions-config.d.ts +41 -61
- package/dist/config/pipeline-config.d.ts +7 -17
- package/dist/contracts/capability.d.ts +13 -49
- package/dist/contracts/client-contract-structure.validator.d.ts +28 -54
- package/dist/contracts/client-contract-structure.validator.js +99 -2
- package/dist/contracts/contract-canonicalizer.d.ts +4 -6
- package/dist/contracts/contract-canonicalizer.js +32 -0
- package/dist/contracts/contract-hash.d.ts +3 -2
- package/dist/contracts/contract-limits.d.ts +7 -1
- package/dist/contracts/contract-protocol.d.ts +7 -8
- package/dist/contracts/contract.d.ts +20 -4
- package/dist/contracts/enum-definition.d.ts +2 -0
- package/dist/contracts/field.d.ts +40 -167
- package/dist/contracts/identifier.d.ts +1 -16
- package/dist/contracts/json-shape.d.ts +65 -0
- package/dist/contracts/json-shape.js +1 -0
- package/dist/contracts/lifecycle-trait.d.ts +4 -3
- package/dist/contracts/reference-write-limit.d.ts +7 -0
- package/dist/contracts/reference-write-limit.js +1 -0
- package/dist/contracts/resource-operations.d.ts +2 -62
- package/dist/contracts/resource.d.ts +2 -0
- package/dist/contracts/scalar-value-type.d.ts +28 -48
- package/dist/contracts/scalar.d.ts +4 -3
- package/dist/contracts/transaction-capability.d.ts +2 -0
- package/dist/contracts/wire-scalar-format.d.ts +6 -21
- package/dist/framework/contract-view.d.ts +152 -130
- package/dist/framework/framework-construction.error.d.ts +6 -1
- package/dist/framework/framework.d.ts +33 -46
- package/dist/framework/framework.factory.d.ts +3 -17
- package/dist/framework/framework.factory.js +56 -13
- package/dist/framework/operation-facade.d.ts +3 -7
- package/dist/index.d.ts +8 -40
- package/dist/index.js +0 -20
- package/dist/internal.d.ts +35 -0
- package/dist/internal.js +16 -0
- package/dist/json/avz.d.ts +96 -0
- package/dist/json/avz.js +212 -0
- package/dist/json/index.d.ts +6 -0
- package/dist/json/index.js +1 -0
- package/dist/json/json-shape.registry.d.ts +22 -0
- package/dist/json/json-shape.registry.js +16 -0
- package/dist/json/zod-issue.translator.d.ts +51 -0
- package/dist/json/zod-issue.translator.js +142 -0
- package/dist/operations/operation-arguments.d.ts +198 -303
- package/dist/operations/operation-call.d.ts +13 -15
- package/dist/operations/operation-identity.d.ts +6 -2
- package/dist/operations/operation-identity.js +3 -0
- package/dist/operations/operation-result.d.ts +15 -61
- package/dist/operations/operation-validator-core.d.ts +6 -5
- package/dist/operations/operation-validator-core.js +28 -10
- package/dist/operations/operation-validator.d.ts +22 -9
- package/dist/operations/operation-validator.js +26 -10
- package/dist/operations/projection-scope.resolver.d.ts +1 -11
- package/dist/operations/structural-limits.walker.d.ts +19 -0
- package/dist/operations/structural-limits.walker.js +344 -0
- package/dist/operations/validation-code.d.ts +5 -17
- package/dist/operations/write-scope.resolver.d.ts +3 -28
- package/dist/protocol/absent-route.responder.d.ts +25 -39
- package/dist/protocol/absent-route.responder.js +32 -6
- package/dist/protocol/av-protocol.d.ts +2 -8
- package/dist/protocol/contract-document.responder.d.ts +5 -18
- package/dist/protocol/http-request.decoder.d.ts +18 -59
- package/dist/protocol/http-request.decoder.js +11 -3
- package/dist/protocol/http-request.reader.d.ts +5 -5
- package/dist/protocol/http-response.encoder.d.ts +14 -20
- package/dist/protocol/http-status.table.d.ts +0 -8
- package/dist/protocol/index.d.ts +2 -7
- package/dist/protocol/operation-response.guard.d.ts +0 -15
- package/dist/protocol/protocol-failure.d.ts +8 -27
- package/dist/protocol/protocol-headers.d.ts +15 -42
- package/dist/protocol/protocol-surface.d.ts +0 -22
- package/dist/protocol/protocol.binder.d.ts +19 -27
- package/dist/protocol/protocol.binder.js +3 -1
- package/dist/protocol/protocol.handler.d.ts +19 -23
- package/dist/protocol/protocol.handler.js +14 -4
- package/dist/protocol/unmounted-route.error.d.ts +19 -0
- package/dist/protocol/unmounted-route.error.js +10 -0
- package/dist/runtime/caller-data.copier.d.ts +59 -0
- package/dist/runtime/caller-data.copier.js +470 -0
- package/dist/runtime/caller-data.door.d.ts +56 -0
- package/dist/runtime/caller-data.door.js +65 -0
- package/dist/runtime/computed-read-runtime.js +3 -10
- package/dist/runtime/computed-value.error.d.ts +13 -0
- package/dist/runtime/computed-value.error.js +9 -0
- package/dist/runtime/create-requirement.d.ts +43 -7
- package/dist/runtime/create-requirement.js +89 -9
- package/dist/runtime/decimal.d.ts +5 -3
- package/dist/runtime/diagnostics-reporter.d.ts +33 -37
- package/dist/runtime/diagnostics-reporter.js +11 -4
- package/dist/runtime/error-boundary.d.ts +14 -10
- package/dist/runtime/error-boundary.js +65 -35
- package/dist/runtime/execution-options.d.ts +3 -7
- package/dist/runtime/field-behavior.d.ts +14 -21
- package/dist/runtime/framework-error.d.ts +14 -2
- package/dist/runtime/json-value.d.ts +7 -15
- package/dist/runtime/misuse-reporter.d.ts +32 -0
- package/dist/runtime/misuse-reporter.js +19 -0
- package/dist/runtime/mutation-planner.d.ts +6 -12
- package/dist/runtime/mutation-planner.js +13 -11
- package/dist/runtime/operation-request.d.ts +11 -11
- package/dist/runtime/operation-response.d.ts +18 -23
- package/dist/runtime/operation-runtime.d.ts +25 -33
- package/dist/runtime/operation-runtime.js +37 -18
- package/dist/runtime/outcome-mapper.js +12 -2
- package/dist/runtime/output-validator.d.ts +10 -0
- package/dist/runtime/output-validator.js +11 -0
- package/dist/runtime/owned-execution.registry.d.ts +13 -0
- package/dist/runtime/owned-execution.registry.js +7 -0
- package/dist/runtime/pipeline.d.ts +33 -36
- package/dist/runtime/referential-action.d.ts +8 -26
- package/dist/runtime/request-envelope.validator.d.ts +5 -0
- package/dist/runtime/request-envelope.validator.js +118 -0
- package/dist/runtime/request-id.d.ts +3 -10
- package/dist/runtime/scalar-runtime.d.ts +42 -14
- package/dist/runtime/scalar-runtime.js +162 -79
- package/dist/transactions/deferred-operation.d.ts +10 -21
- package/dist/transactions/operation-arguments-encoder.d.ts +1 -0
- package/dist/transactions/operation-fingerprint.d.ts +3 -1
- package/dist/transactions/transaction-envelope.d.ts +2 -4
- package/dist/transactions/transaction-integrity-error.d.ts +4 -15
- package/dist/transactions/transaction-plan-assembler.d.ts +6 -1
- package/dist/transactions/transaction-plan-assembler.js +74 -75
- package/dist/transactions/transaction-plan-validator.d.ts +33 -24
- package/dist/transactions/transaction-plan-validator.js +204 -153
- package/dist/transactions/transaction-reference-collector.d.ts +30 -0
- package/dist/transactions/transaction-reference-collector.js +204 -0
- package/dist/transactions/transaction-reference-resolver.d.ts +9 -12
- package/dist/transactions/transaction-reference-resolver.js +10 -5
- package/dist/transactions/transaction-reference-validator.js +24 -17
- package/dist/transactions/transaction-reference.d.ts +31 -64
- package/dist/transactions/transaction-request.d.ts +6 -8
- package/dist/transactions/transaction-response.d.ts +10 -7
- package/dist/transactions/transaction-response.js +24 -1
- package/dist/transactions/transaction-runtime.d.ts +7 -5
- package/dist/transactions/transaction-runtime.js +4 -3
- package/dist/transactions/transaction-slot-path-error.d.ts +5 -15
- package/dist/transactions/transaction-slot-writer.d.ts +3 -13
- package/package.json +17 -3
- package/dist/operations/operation-boolean-nodes.d.ts +0 -11
- package/dist/operations/operation-boolean-nodes.js +0 -283
- package/dist/operations/operation-nesting.d.ts +0 -8
- package/dist/operations/operation-nesting.js +0 -307
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
|
|
2
|
+
import { advertisedDirectives, holdsAt, } from "../contracts/field.js";
|
|
3
|
+
import { NESTED_PROJECTION_SCOPE, resolveProjectionScope, } from "./projection-scope.resolver.js";
|
|
4
|
+
const UNTRACKED = [];
|
|
5
|
+
const RELATION_FILTER_OPERATORS = ["some", "every", "none"];
|
|
6
|
+
const DIRECTIVE_PAYLOADS = new Map([
|
|
7
|
+
["$connectOrCreate", [["create", "create"]]],
|
|
8
|
+
["$update", [["data", "update"]]],
|
|
9
|
+
[
|
|
10
|
+
"$upsert",
|
|
11
|
+
[
|
|
12
|
+
["create", "create"],
|
|
13
|
+
["update", "update"],
|
|
14
|
+
],
|
|
15
|
+
],
|
|
16
|
+
]);
|
|
17
|
+
const NO_PAYLOADS = [];
|
|
18
|
+
function isRecord(value) {
|
|
19
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20
|
+
}
|
|
21
|
+
function extend(state, path, segment) {
|
|
22
|
+
return state.tracking ? [...path, segment] : UNTRACKED;
|
|
23
|
+
}
|
|
24
|
+
function nestingExceeded(state) {
|
|
25
|
+
state.nesting = {
|
|
26
|
+
path: ["arguments", state.rootKey],
|
|
27
|
+
code: "V1013",
|
|
28
|
+
message: `Request nesting exceeds maxNestingDepth (${state.nestingLimit}).`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function countBooleanNode(state, path, key) {
|
|
32
|
+
if (state.booleanExceeded) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
state.booleanCount += 1;
|
|
36
|
+
if (state.booleanCount > state.booleanLimit) {
|
|
37
|
+
state.booleanExceeded = true;
|
|
38
|
+
if (state.tracking) {
|
|
39
|
+
state.booleanNodes = {
|
|
40
|
+
path: [...path, key],
|
|
41
|
+
code: "V1015",
|
|
42
|
+
message: `Boolean/filter node count exceeds maxBooleanNodes (${state.booleanLimit}).`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function walkWhere(state, resourceName, value, depth, path, counting) {
|
|
48
|
+
if (depth > state.nestingLimit) {
|
|
49
|
+
nestingExceeded(state);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const resource = lookupResource(state.contract, resourceName);
|
|
53
|
+
if (!isRecord(value) || resource === undefined) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
for (const key of Object.keys(value)) {
|
|
57
|
+
if (counting) {
|
|
58
|
+
countBooleanNode(state, path, key);
|
|
59
|
+
}
|
|
60
|
+
const child = value[key];
|
|
61
|
+
if (key === "AND" || key === "OR") {
|
|
62
|
+
if (Array.isArray(child)) {
|
|
63
|
+
for (let index = 0; index < child.length; index += 1) {
|
|
64
|
+
walkWhere(state, resourceName, child[index], depth + 1, state.tracking ? [...path, key, index] : UNTRACKED, counting);
|
|
65
|
+
if (state.nesting !== undefined) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (key === "NOT") {
|
|
73
|
+
walkWhere(state, resourceName, child, depth + 1, extend(state, path, key), counting);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
const field = lookupField(resource, key);
|
|
77
|
+
if (field?.kind !== "relation") {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (field.cardinality === "one") {
|
|
81
|
+
walkWhere(state, field.target, child, depth + 1, extend(state, path, key), counting);
|
|
82
|
+
}
|
|
83
|
+
else if (isRecord(child)) {
|
|
84
|
+
for (const operator of RELATION_FILTER_OPERATORS) {
|
|
85
|
+
if (!(operator in child)) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
walkWhere(state, field.target, child[operator], depth + 1, state.tracking ? [...path, key, operator] : UNTRACKED, counting);
|
|
89
|
+
if (state.nesting !== undefined) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (state.nesting !== undefined) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function walkOrderBy(state, resourceName, value, depth) {
|
|
101
|
+
const resource = lookupResource(state.contract, resourceName);
|
|
102
|
+
if (resource === undefined) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const entries = Array.isArray(value) ? value : [value];
|
|
106
|
+
for (let index = 0; index < entries.length; index += 1) {
|
|
107
|
+
const entry = entries[index];
|
|
108
|
+
if (!isRecord(entry)) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
for (const fieldName of Object.keys(entry)) {
|
|
112
|
+
const field = lookupField(resource, fieldName);
|
|
113
|
+
if (field?.kind !== "relation" || field.cardinality === "many") {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const relationDepth = depth + 1;
|
|
117
|
+
if (relationDepth > state.nestingLimit) {
|
|
118
|
+
nestingExceeded(state);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
walkOrderBy(state, field.target, entry[fieldName], relationDepth);
|
|
122
|
+
if (state.nesting !== undefined) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function soleKey(record) {
|
|
129
|
+
const keys = Object.keys(record);
|
|
130
|
+
return keys.length === 1 ? keys[0] : undefined;
|
|
131
|
+
}
|
|
132
|
+
function walkProjection(state, resourceName, value, depth, path, mode, scope) {
|
|
133
|
+
const resource = lookupResource(state.contract, resourceName);
|
|
134
|
+
if (!Array.isArray(value) || resource === undefined) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
138
|
+
const entry = value[index];
|
|
139
|
+
const relationName = isRecord(entry) ? soleKey(entry) : undefined;
|
|
140
|
+
const edge = relationName === undefined
|
|
141
|
+
? undefined
|
|
142
|
+
: lookupField(resource, relationName);
|
|
143
|
+
if (relationName === undefined || edge?.kind !== "relation") {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const relationDepth = depth + 1;
|
|
147
|
+
if (relationDepth > state.nestingLimit) {
|
|
148
|
+
nestingExceeded(state);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const projection = entry[relationName];
|
|
152
|
+
if (!isRecord(projection)) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const relationPath = state.tracking
|
|
156
|
+
? [...path, index, relationName]
|
|
157
|
+
: UNTRACKED;
|
|
158
|
+
const counted = scope !== undefined &&
|
|
159
|
+
holdsAt(mode === "select"
|
|
160
|
+
? edge.capabilities.select
|
|
161
|
+
: edge.capabilities.include, scope);
|
|
162
|
+
if ("where" in projection) {
|
|
163
|
+
walkWhere(state, edge.target, projection.where, relationDepth, extend(state, relationPath, "where"), counted && edge.capabilities.filter?.includes("nested") === true);
|
|
164
|
+
if (state.nesting !== undefined) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if ("orderBy" in projection) {
|
|
169
|
+
walkOrderBy(state, edge.target, projection.orderBy, relationDepth);
|
|
170
|
+
if (state.nesting !== undefined) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
for (const nestedMode of ["select", "include"]) {
|
|
175
|
+
if (!(nestedMode in projection)) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
walkProjection(state, edge.target, projection[nestedMode], relationDepth, extend(state, relationPath, nestedMode), nestedMode, counted ? NESTED_PROJECTION_SCOPE : undefined);
|
|
179
|
+
if (state.nesting !== undefined) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function walkMutationData(state, resourceName, value, depth, path, stage, counting) {
|
|
186
|
+
if (depth > state.nestingLimit) {
|
|
187
|
+
nestingExceeded(state);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const resource = lookupResource(state.contract, resourceName);
|
|
191
|
+
if (!isRecord(value) || resource === undefined) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
for (const fieldName of Object.keys(value)) {
|
|
195
|
+
const edge = lookupField(resource, fieldName);
|
|
196
|
+
const directives = value[fieldName];
|
|
197
|
+
if (edge?.kind !== "relation" || !isRecord(directives)) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
walkRelationDirectives(state, edge, directives, depth + 1, extend(state, path, fieldName), stage, counting);
|
|
201
|
+
if (state.nesting !== undefined) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function walkRelationDirectives(state, edge, directives, relationDepth, path, stage, counting) {
|
|
207
|
+
const supported = advertisedDirectives(edge.capabilities[stage]);
|
|
208
|
+
for (const directive of Object.keys(directives)) {
|
|
209
|
+
if (relationDepth > state.nestingLimit) {
|
|
210
|
+
nestingExceeded(state);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const directivePath = extend(state, path, directive);
|
|
214
|
+
const directiveCounting = counting && supported?.includes(directive) === true;
|
|
215
|
+
const directiveValue = directives[directive];
|
|
216
|
+
if (Array.isArray(directiveValue)) {
|
|
217
|
+
for (let index = 0; index < directiveValue.length; index += 1) {
|
|
218
|
+
walkDirectiveEntry(state, edge.target, directive, directiveValue[index], relationDepth, extend(state, directivePath, index), directiveCounting);
|
|
219
|
+
if (state.nesting !== undefined) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
walkDirectiveEntry(state, edge.target, directive, directiveValue, relationDepth, directivePath, directiveCounting);
|
|
226
|
+
if (state.nesting !== undefined) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
function walkDirectiveEntry(state, target, directive, entry, relationDepth, path, counting) {
|
|
233
|
+
if (directive === "$create") {
|
|
234
|
+
walkMutationData(state, target, entry, relationDepth, path, "create", counting);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (!isRecord(entry)) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if ((directive === "$update" || directive === "$delete") &&
|
|
241
|
+
"where" in entry) {
|
|
242
|
+
walkWhere(state, target, entry.where, relationDepth, extend(state, path, "where"), counting);
|
|
243
|
+
if (state.nesting !== undefined) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
for (const [key, stage] of DIRECTIVE_PAYLOADS.get(directive) ?? NO_PAYLOADS) {
|
|
248
|
+
if (!(key in entry)) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
walkMutationData(state, target, entry[key], relationDepth, extend(state, path, key), stage, counting);
|
|
252
|
+
if (state.nesting !== undefined) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function isUniqueOperation(request) {
|
|
258
|
+
return (request.variant === "unique" &&
|
|
259
|
+
(request.family === "find" ||
|
|
260
|
+
request.family === "update" ||
|
|
261
|
+
request.family === "delete" ||
|
|
262
|
+
request.family === "upsert"));
|
|
263
|
+
}
|
|
264
|
+
function walkArguments(state, request, args) {
|
|
265
|
+
const resource = request.resource;
|
|
266
|
+
const rootPath = (key) => {
|
|
267
|
+
state.rootKey = key;
|
|
268
|
+
return state.tracking ? ["arguments", key] : UNTRACKED;
|
|
269
|
+
};
|
|
270
|
+
if ("where" in args) {
|
|
271
|
+
walkWhere(state, resource, args.where, 1, rootPath("where"), !isUniqueOperation(request));
|
|
272
|
+
if (state.nesting !== undefined) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if ("orderBy" in args) {
|
|
277
|
+
rootPath("orderBy");
|
|
278
|
+
walkOrderBy(state, resource, args.orderBy, 0);
|
|
279
|
+
if (state.nesting !== undefined) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
for (const mode of ["select", "include"]) {
|
|
284
|
+
if (!(mode in args)) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
walkProjection(state, resource, args[mode], 0, rootPath(mode), mode, resolveProjectionScope(lookupResource(state.contract, resource), request));
|
|
288
|
+
if (state.nesting !== undefined) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if ("data" in args) {
|
|
293
|
+
const path = rootPath("data");
|
|
294
|
+
const data = args.data;
|
|
295
|
+
if (Array.isArray(data)) {
|
|
296
|
+
for (let index = 0; index < data.length; index += 1) {
|
|
297
|
+
walkMutationData(state, resource, data[index], 0, extend(state, path, index), "create", request.family === "create");
|
|
298
|
+
if (state.nesting !== undefined) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
walkMutationData(state, resource, data, 0, path, request.family === "update" ? "update" : "create", request.family === "create" || request.family === "update");
|
|
305
|
+
if (state.nesting !== undefined) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
for (const branch of ["create", "update"]) {
|
|
311
|
+
if (!(branch in args)) {
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
walkMutationData(state, resource, args[branch], 0, rootPath(branch), branch, request.family === "upsert");
|
|
315
|
+
if (state.nesting !== undefined) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function walk(contract, request, args, tracking) {
|
|
321
|
+
const state = {
|
|
322
|
+
contract,
|
|
323
|
+
nestingLimit: contract.limits.maxNestingDepth,
|
|
324
|
+
booleanLimit: contract.limits.maxBooleanNodes,
|
|
325
|
+
tracking,
|
|
326
|
+
rootKey: "",
|
|
327
|
+
booleanCount: 0,
|
|
328
|
+
nesting: undefined,
|
|
329
|
+
booleanNodes: undefined,
|
|
330
|
+
booleanExceeded: false,
|
|
331
|
+
};
|
|
332
|
+
walkArguments(state, request, args);
|
|
333
|
+
return state;
|
|
334
|
+
}
|
|
335
|
+
export function findStructuralLimitIssues(contract, request, args) {
|
|
336
|
+
const untracked = walk(contract, request, args, false);
|
|
337
|
+
if (untracked.nesting !== undefined || !untracked.booleanExceeded) {
|
|
338
|
+
return { nesting: untracked.nesting, booleanNodes: undefined };
|
|
339
|
+
}
|
|
340
|
+
return {
|
|
341
|
+
nesting: undefined,
|
|
342
|
+
booleanNodes: walk(contract, request, args, true).booleanNodes,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
@@ -1,26 +1,14 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* It is a runtime array for the same reason `OPERATION_CODES` is one: the union
|
|
3
|
-
* below is the compiler's view of the set, and the response boundary needs the set
|
|
4
|
-
* itself to test a thrower-supplied code by identity before emitting it.
|
|
5
|
-
*/
|
|
1
|
+
/** The set of allocated Validation codes, as a runtime array. */
|
|
6
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
|
+
/** A validation code (`V1000` and up), one per kind of argument problem. */
|
|
7
4
|
export type ValidationCode = (typeof VALIDATION_CODES)[number];
|
|
8
|
-
/**
|
|
9
|
-
* This is the text the response boundary emits in place of a thrower-supplied
|
|
10
|
-
* issue message, which is untrusted and may carry provider text that specification
|
|
11
|
-
* 13.5 forbids in `cause`.
|
|
12
|
-
*
|
|
13
|
-
* It is deliberately not the only message a `V` code may ever carry. A framework
|
|
14
|
-
* producer knows the offending field, limit or reference and says so; those issues
|
|
15
|
-
* are built here and mapped straight to their envelope by `mapValidationOutcome`,
|
|
16
|
-
* never through the sanitization boundary. This table is the floor for an issue
|
|
17
|
-
* the framework did not author, not a ceiling on the ones it did.
|
|
18
|
-
*/
|
|
5
|
+
/** The framework's message for each validation code. */
|
|
19
6
|
export declare const VALIDATION_CODE_MESSAGES: Readonly<Record<ValidationCode, string>>;
|
|
7
|
+
/** One validation problem: its code, message and the argument path it is at. */
|
|
20
8
|
export type ValidationIssue = {
|
|
21
9
|
readonly path?: readonly (string | number)[];
|
|
22
10
|
readonly code: ValidationCode;
|
|
23
11
|
readonly message: string;
|
|
24
12
|
};
|
|
25
|
-
/** Builds one
|
|
13
|
+
/** Builds one validation issue at its path. */
|
|
26
14
|
export declare function validationIssue(code: ValidationCode, path: readonly (string | number)[], message: string): ValidationIssue;
|
|
@@ -3,38 +3,13 @@ import type { Contract } from "../contracts/contract.js";
|
|
|
3
3
|
import type { Resource } from "../contracts/resource.js";
|
|
4
4
|
import type { OperationIdentity } from "./operation-identity.js";
|
|
5
5
|
/**
|
|
6
|
-
* Which write position one request's
|
|
7
|
-
* argument sits in, read off the variant the Resource advertises.
|
|
8
|
-
*
|
|
9
|
-
* The write mirror of `resolveProjectionScope`, and a separate function for the
|
|
10
|
-
* reason `resource-operations.ts` gives for `projectionScopeOf`/`writeScopeOf`
|
|
11
|
-
* being two: the axes are measured and consulted independently — the flat-bulk
|
|
12
|
-
* write scope covers four variants where the bulk-returning projection scope
|
|
13
|
-
* covers two — and a caller that needs one position should not be handed the other
|
|
14
|
-
* to discard.
|
|
15
|
-
*
|
|
16
|
-
* `"nested"` is the answer wherever nothing narrower is stated — an absent
|
|
17
|
-
* Resource, an unadvertised variant, `true`, or a descriptor that qualifies only
|
|
18
|
-
* its projection argument. Availability is **not** decided here: an unadvertised
|
|
19
|
-
* operation is refused by `operation-validator.ts` before the mutation walk runs,
|
|
20
|
-
* and answering `"nested"` for one keeps this function a write question rather than
|
|
21
|
-
* a second, weaker copy of the availability gate.
|
|
6
|
+
* Which write position one request's top-level `data` (or `create`/`update`)
|
|
7
|
+
* argument sits in, read off the variant the Resource advertises. `"nested"`
|
|
8
|
+
* wherever nothing narrower is stated.
|
|
22
9
|
*/
|
|
23
10
|
export declare function resolveWriteScope(resource: Resource<Contract> | undefined, request: OperationIdentity): WriteScope;
|
|
24
11
|
/**
|
|
25
12
|
* The position a write NESTED beneath an admitted relation directive sits in: the
|
|
26
13
|
* unrestricted one, at every depth, under every top-level scope.
|
|
27
|
-
*
|
|
28
|
-
* It is a constant and not a parameter the recursion threads, because there is no
|
|
29
|
-
* depth at which the answer differs. A relation write reached through `$create`,
|
|
30
|
-
* `$connectOrCreate.create`, `$update.data` or `$upsert`'s two branches lands in
|
|
31
|
-
* the unrestricted write input on both pilot engines, whatever the top-level
|
|
32
|
-
* argument was. The measurement behind that is the flat bulk write inputs carrying
|
|
33
|
-
* **no relation member at all**, so a nested write is only ever reachable
|
|
34
|
-
* *through* a relation the top-level scope already admitted — and past that point
|
|
35
|
-
* the full write surface returns.
|
|
36
|
-
*
|
|
37
|
-
* Naming it is the point, exactly as `NESTED_PROJECTION_SCOPE` names the same
|
|
38
|
-
* decision on the read axis.
|
|
39
14
|
*/
|
|
40
15
|
export declare const NESTED_WRITE_SCOPE: WriteScope;
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import type { FrameworkContracts } from "../compiler/contract.compiler.js";
|
|
2
2
|
import { type OperationIdentity } from "../operations/operation-identity.js";
|
|
3
|
+
import { type FrameworkDiagnosticsSink } from "../runtime/diagnostics-reporter.js";
|
|
3
4
|
import type { ClientProtocolIdentity } from "../runtime/operation-request.js";
|
|
4
5
|
import { type OperationFailureResponse } from "../runtime/operation-response.js";
|
|
5
6
|
import type { AvProtocolRequest } from "./http-request.decoder.js";
|
|
6
7
|
import { type ReadRequest } from "./http-request.reader.js";
|
|
7
8
|
import { type AvProtocolResponse } from "./http-response.encoder.js";
|
|
8
9
|
/**
|
|
9
|
-
*
|
|
10
|
-
* `
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* The absence answers: the checks a framework route makes before it reads a body, runs
|
|
11
|
+
* a pipeline or reaches an Adapter — the protocol version (`A2006`), the
|
|
12
|
+
* ClientContract hash (`A2005`), then whether the ClientContract advertises the route
|
|
13
|
+
* at all (`A2001`, `A2002`). Every envelope is the one the Framework Validation Layer
|
|
14
|
+
* answers for the same request, so a caller cannot tell which layer answered. Reads
|
|
15
|
+
* the compiled Contracts only.
|
|
14
16
|
*/
|
|
15
17
|
/** A route's three decoded segments, still untrusted strings. */
|
|
16
18
|
export type OperationRouteSegments = {
|
|
@@ -28,18 +30,18 @@ export type OperationRouteResolution = {
|
|
|
28
30
|
};
|
|
29
31
|
/**
|
|
30
32
|
* An operation route `/_resources/<resource>/<family>/<variant>` under one client
|
|
31
|
-
* protocol identity: version → hash → Resource → operation. A Resource key is
|
|
32
|
-
*
|
|
33
|
-
*
|
|
33
|
+
* protocol identity: version → hash → Resource → operation. A Resource key is matched
|
|
34
|
+
* exactly and only as the ClientContract's own key; a family/variant pair only when it
|
|
35
|
+
* is a standard operation the Resource advertises, read through
|
|
34
36
|
* `isOperationVariantAvailable` alone.
|
|
35
37
|
*/
|
|
36
38
|
export declare function resolveOperationRoute(contracts: FrameworkContracts, protocol: ClientProtocolIdentity, route: OperationRouteSegments): OperationRouteResolution;
|
|
37
39
|
/**
|
|
38
|
-
* The `/_transactions` route under one client protocol identity: version → hash →
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
40
|
+
* The `/_transactions` route under one client protocol identity: version → hash → the
|
|
41
|
+
* ClientContract's transaction capability. The route exists only when that capability
|
|
42
|
+
* is `"interactive"` — tested against the value itself, as `protocol.surface()` tests
|
|
43
|
+
* it — and is otherwise absent with core's own refusal of a plan. `undefined` when the
|
|
44
|
+
* route is there.
|
|
43
45
|
*/
|
|
44
46
|
export declare function transactionsRouteFailure(contracts: FrameworkContracts, protocol: ClientProtocolIdentity): OperationFailureResponse | undefined;
|
|
45
47
|
/**
|
|
@@ -54,12 +56,12 @@ type RouteCheck<Route> = ({
|
|
|
54
56
|
readonly response: AvProtocolResponse;
|
|
55
57
|
};
|
|
56
58
|
/**
|
|
57
|
-
* An operation route's checks before its body (decoder steps 2–4): the path
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
59
|
+
* An operation route's checks before its body (decoder steps 2–4): the path (`A2000`
|
|
60
|
+
* unless `/_resources/<r>/<f>/<v>`, each segment decodable and none empty), the
|
|
61
|
+
* identity headers' presence (`A2000`), then {@link resolveOperationRoute} — version,
|
|
62
|
+
* hash, Resource, operation — and the method (`A2012`, `Allow: POST`). One sequence
|
|
63
|
+
* for both route styles: `decodeOperation` reads the body only after it passes,
|
|
64
|
+
* `answerAbsent` never.
|
|
63
65
|
*/
|
|
64
66
|
export declare function checkOperationRoute(contracts: FrameworkContracts, read: ReadRequest): RouteCheck<{
|
|
65
67
|
readonly resource: string;
|
|
@@ -74,25 +76,9 @@ export declare function checkOperationRoute(contracts: FrameworkContracts, read:
|
|
|
74
76
|
export declare function checkTransactionsRoute(contracts: FrameworkContracts, read: ReadRequest): RouteCheck<object>;
|
|
75
77
|
/**
|
|
76
78
|
* `protocol.answerAbsent(request)` — the fallback a host that mounts one route per
|
|
77
|
-
* `protocol.surface()` entry mounts for every path it did not. Never a catch-all
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* 1. a value that is not an `AvProtocolRequest` → `400 A2000`, minted id;
|
|
82
|
-
* 2. a path outside the protocol's underscore namespace → `undefined`: the host
|
|
83
|
-
* answers it itself — `/favicon.ico` is not the framework's;
|
|
84
|
-
* 3. `/_contract`: any method but `GET` → `405 A2012` with `Allow: GET`; no
|
|
85
|
-
* identity header is read;
|
|
86
|
-
* 4. `/_transactions`, or else an operation route: exactly what the catch-all
|
|
87
|
-
* host's decoder answers before its body — path syntax and identity presence
|
|
88
|
-
* (`A2000`), version (`A2006`), hash (`A2005`), Resource (`A2001`), operation
|
|
89
|
-
* or the `"none"` capability (`A2002`), method (`A2012`, `Allow: POST`) — each
|
|
90
|
-
* core's own envelope;
|
|
91
|
-
* 5. a route that EXISTS, reached with its own method — the host mounted only part
|
|
92
|
-
* of the surface — → `500 A3000`: a host wiring bug made visible, never a
|
|
93
|
-
* silent 404.
|
|
94
|
-
*
|
|
95
|
-
* Every framework answer echoes `Aventara-Request-Id`.
|
|
79
|
+
* `protocol.surface()` entry mounts for every path it did not. Never a catch-all into
|
|
80
|
+
* framework handling: it reads no body, runs no pipeline, calls no Adapter, and takes
|
|
81
|
+
* only the compiled Contracts. In order:
|
|
96
82
|
*/
|
|
97
|
-
export declare function answerAbsentRequest(contracts: FrameworkContracts, received: AvProtocolRequest): AvProtocolResponse | undefined;
|
|
83
|
+
export declare function answerAbsentRequest(contracts: FrameworkContracts, received: AvProtocolRequest, sink?: FrameworkDiagnosticsSink): AvProtocolResponse | undefined;
|
|
98
84
|
export {};
|
|
@@ -3,6 +3,7 @@ import { isOperationVariantAvailable, } from "../contracts/resource-operations.j
|
|
|
3
3
|
import { parseOperationIdentity, } from "../operations/operation-identity.js";
|
|
4
4
|
import { operationUnavailableIssue } from "../operations/operation-validator.js";
|
|
5
5
|
import { resourceUnavailableIssue } from "../operations/operation-validator-core.js";
|
|
6
|
+
import { createReporter, } from "../runtime/diagnostics-reporter.js";
|
|
6
7
|
import { INTERNAL_FAILURE_MESSAGE, operationFailure, } from "../runtime/operation-response.js";
|
|
7
8
|
import { protocolIdentityFailure } from "../runtime/operation-runtime.js";
|
|
8
9
|
import { mapValidationOutcome } from "../runtime/outcome-mapper.js";
|
|
@@ -11,6 +12,7 @@ import { CONTRACT_ROUTE, GET_ONLY, isProtocolPath, operationRouteSegments, POST_
|
|
|
11
12
|
import { encodeOperationResponse, } from "./http-response.encoder.js";
|
|
12
13
|
import { identityHeadersMissing, transportFailure, } from "./protocol-failure.js";
|
|
13
14
|
import { missingIdentityHeaders } from "./protocol-headers.js";
|
|
15
|
+
import { UnmountedRouteError } from "./unmounted-route.error.js";
|
|
14
16
|
export function resolveOperationRoute(contracts, protocol, route) {
|
|
15
17
|
const identityFailure = protocolIdentityFailure(contracts, protocol);
|
|
16
18
|
if (identityFailure !== undefined) {
|
|
@@ -29,7 +31,9 @@ export function resolveOperationRoute(contracts, protocol, route) {
|
|
|
29
31
|
!isOperationVariantAvailable(lookupOwn(lookupOwn(advertised, route.family), route.variant))) {
|
|
30
32
|
return {
|
|
31
33
|
ok: false,
|
|
32
|
-
failure: mapValidationOutcome([
|
|
34
|
+
failure: mapValidationOutcome([
|
|
35
|
+
operationUnavailableIssue(contracts.client, route),
|
|
36
|
+
]),
|
|
33
37
|
};
|
|
34
38
|
}
|
|
35
39
|
return { ok: true, operation };
|
|
@@ -82,7 +86,7 @@ function identityFailureOf(read) {
|
|
|
82
86
|
function refusedWith(response) {
|
|
83
87
|
return { ok: false, response };
|
|
84
88
|
}
|
|
85
|
-
export function answerAbsentRequest(contracts, received) {
|
|
89
|
+
export function answerAbsentRequest(contracts, received, sink) {
|
|
86
90
|
const read = readRequest(received);
|
|
87
91
|
if (!read.ok) {
|
|
88
92
|
return read.response;
|
|
@@ -96,10 +100,32 @@ export function answerAbsentRequest(contracts, received) {
|
|
|
96
100
|
? unmounted(read.requestId)
|
|
97
101
|
: transportFailure("A2012", read.requestId, GET_ONLY);
|
|
98
102
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
if (path === TRANSACTIONS_ROUTE) {
|
|
104
|
+
const route = checkTransactionsRoute(contracts, read);
|
|
105
|
+
if (!route.ok) {
|
|
106
|
+
return route.response;
|
|
107
|
+
}
|
|
108
|
+
createReporter(sink, {
|
|
109
|
+
kind: "transaction",
|
|
110
|
+
origin: "client",
|
|
111
|
+
requestId: read.requestId,
|
|
112
|
+
})(new UnmountedRouteError("transactions", `POST ${TRANSACTIONS_ROUTE}`), "A3000");
|
|
113
|
+
return unmounted(read.requestId);
|
|
114
|
+
}
|
|
115
|
+
const route = checkOperationRoute(contracts, read);
|
|
116
|
+
if (!route.ok) {
|
|
117
|
+
return route.response;
|
|
118
|
+
}
|
|
119
|
+
const { family, variant } = route.operation;
|
|
120
|
+
createReporter(sink, {
|
|
121
|
+
kind: "operation",
|
|
122
|
+
origin: "client",
|
|
123
|
+
resource: route.resource,
|
|
124
|
+
family,
|
|
125
|
+
variant,
|
|
126
|
+
requestId: read.requestId,
|
|
127
|
+
})(new UnmountedRouteError(`${route.resource}.${family}.${variant}`, `POST ${path}`), "A3000");
|
|
128
|
+
return unmounted(read.requestId);
|
|
103
129
|
}
|
|
104
130
|
function unmounted(requestId) {
|
|
105
131
|
return encodeOperationResponse(operationFailure("A3000", { message: INTERNAL_FAILURE_MESSAGE }), requestId);
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
3
|
-
*
|
|
4
|
-
* language freezes a module namespace, and a bundler drops the members a consumer
|
|
5
|
-
* does not read.
|
|
6
|
-
*
|
|
7
|
-
* Re-exports only — no logic lives here. Every member is pinned, by name and by
|
|
8
|
-
* type, in `./index.test-d.ts`, whose exact `keyof` set fails when a member is
|
|
9
|
-
* added or removed without a row.
|
|
2
|
+
* The HTTP protocol: pure functions and data a host uses to serve a Framework.
|
|
3
|
+
* Start with `AvProtocol.bind(framework)`.
|
|
10
4
|
*/
|
|
11
5
|
export { normalizeEntrypoint } from "../config/entrypoint.normalizer.js";
|
|
12
6
|
export { scalarFormats } from "../contracts/wire-scalar-format.js";
|
|
@@ -2,9 +2,9 @@ import type { ClientContract } 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
|
/**
|
|
5
|
-
* The served ClientContract, written once per binding: its JCS-canonical bytes and
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* The served ClientContract, written once per binding: its JCS-canonical bytes and its
|
|
6
|
+
* entity tag, the quoted contract hash. The bytes include `protocol.hash`, although
|
|
7
|
+
* the hash's own input excludes it.
|
|
8
8
|
*/
|
|
9
9
|
export type ContractDocument = {
|
|
10
10
|
readonly body: string;
|
|
@@ -13,20 +13,7 @@ export type ContractDocument = {
|
|
|
13
13
|
/** The bound ClientContract as the document `_contract` serves. */
|
|
14
14
|
export declare function contractDocumentOf(client: ClientContract): ContractDocument;
|
|
15
15
|
/**
|
|
16
|
-
* `protocol.encodeContract(request)`: the `GET <entrypoint>/_contract` responder.
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* 1. a value that is not an `AvProtocolRequest` → `400 A2000` under a minted id
|
|
20
|
-
* (as the decoders answer it);
|
|
21
|
-
* 3. a path other than `/_contract` → `400 A2000` (path syntax this route cannot
|
|
22
|
-
* read, as a decoder answers one);
|
|
23
|
-
* 4. a method other than `GET` → `405 A2012` with `Allow: GET`;
|
|
24
|
-
* 5. `If-None-Match` matching the document's entity tag — RFC 9110 §13.1.2's weak
|
|
25
|
-
* comparison, over a comma-separated list, or `*` — → `304 Not Modified`, no
|
|
26
|
-
* body, still carrying `ETag` and `Cache-Control`; otherwise `200` with the
|
|
27
|
-
* canonical bytes, `ETag`, `Cache-Control: no-cache` and `Content-Type:
|
|
28
|
-
* application/json`.
|
|
29
|
-
*
|
|
30
|
-
* No identity header is required or read, and the body is never read.
|
|
16
|
+
* `protocol.encodeContract(request)`: the `GET <entrypoint>/_contract` responder. In
|
|
17
|
+
* order:
|
|
31
18
|
*/
|
|
32
19
|
export declare function encodeContractRequest(document: ContractDocument, received: AvProtocolRequest): AvProtocolResponse;
|