@aventara/core 1.0.0-rc.1 → 1.0.0-rc.11
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 +1022 -16
- package/ERRORS.md +142 -0
- package/README.md +330 -16
- 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 +22 -0
- package/dist/adapters/adapter-identifier.d.ts +9 -0
- package/dist/adapters/adapter-identifier.js +6 -1
- package/dist/adapters/adapter-model.d.ts +9 -0
- package/dist/adapters/adapter-operation.d.ts +18 -3
- package/dist/adapters/adapter-resource.d.ts +5 -0
- package/dist/adapters/adapter.interface.d.ts +10 -0
- package/dist/avz/avz.d.ts +1 -1
- package/dist/avz/json-shape.registry.d.ts +2 -1
- 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 +6 -0
- package/dist/compiler/contract.compiler.js +281 -31
- package/dist/compiler/create-requirements.projector.js +1 -3
- package/dist/compiler/field-validator.compiler.js +1 -3
- package/dist/compiler/managed-elsewhere.projector.d.ts +52 -0
- package/dist/compiler/managed-elsewhere.projector.js +179 -0
- package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
- package/dist/compiler/managed-elsewhere.validator.js +74 -0
- package/dist/config/cache-stage.factory.d.ts +24 -0
- package/dist/config/cache-stage.factory.js +3 -0
- package/dist/config/computed-fields.d.ts +62 -0
- package/dist/config/computed-fields.js +73 -0
- package/dist/config/config-diagnostic.guidance.d.ts +6 -0
- package/dist/config/config-diagnostic.guidance.js +32 -0
- package/dist/config/config.resolver.d.ts +24 -0
- package/dist/config/config.resolver.js +66 -7
- package/dist/config/config.validator.js +283 -21
- package/dist/config/define-resource.d.ts +1 -5
- package/dist/config/entrypoint.normalizer.d.ts +3 -2
- package/dist/config/exact-framework-config.d.ts +73 -22
- package/dist/config/field-compute.resolver.d.ts +2 -0
- package/dist/config/field-compute.resolver.js +9 -3
- package/dist/config/framework-config.d.ts +53 -15
- package/dist/config/framework-resources-config.d.ts +25 -14
- package/dist/config/pipeline-config.d.ts +20 -4
- package/dist/config/pipeline-tree.resolver.d.ts +2 -2
- package/dist/config/pipeline-tree.resolver.js +2 -3
- package/dist/contracts/access-route.rules.d.ts +10 -0
- package/dist/contracts/access-route.rules.js +45 -0
- package/dist/contracts/canonical-json.writer.d.ts +7 -0
- package/dist/contracts/canonical-json.writer.js +55 -0
- package/dist/contracts/capability.d.ts +26 -1
- package/dist/contracts/capability.js +20 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +365 -89
- package/dist/contracts/client-contract-structure.validator.js +49 -2
- package/dist/contracts/contract-access.d.ts +29 -0
- package/dist/contracts/contract-access.js +1 -0
- package/dist/contracts/contract-canonicalizer.d.ts +9 -1
- package/dist/contracts/contract-canonicalizer.js +35 -4
- package/dist/contracts/contract-hash.d.ts +0 -1
- package/dist/contracts/contract-hash.js +1 -1
- package/dist/contracts/contract-limits.d.ts +6 -0
- package/dist/contracts/contract-limits.js +2 -0
- package/dist/contracts/contract.d.ts +42 -1
- package/dist/contracts/field.d.ts +58 -1
- package/dist/contracts/json-schema.projector.d.ts +11 -0
- package/dist/contracts/json-schema.projector.js +76 -0
- package/dist/contracts/scalar-value-type.d.ts +3 -1
- package/dist/framework/access-facade.d.ts +116 -0
- package/dist/framework/access-facade.js +118 -0
- package/dist/framework/contract-view.d.ts +120 -16
- package/dist/framework/framework-construction.error.d.ts +14 -4
- package/dist/framework/framework-construction.error.js +18 -2
- package/dist/framework/framework.d.ts +26 -5
- package/dist/framework/framework.factory.d.ts +1 -1
- package/dist/framework/framework.factory.js +145 -24
- package/dist/framework/operation-facade.d.ts +141 -13
- package/dist/framework/operation-facade.js +9 -1
- package/dist/framework/operation-set.runner.d.ts +47 -0
- package/dist/framework/operation-set.runner.js +168 -0
- package/dist/index.d.ts +19 -5
- package/dist/index.js +3 -0
- package/dist/internal.d.ts +9 -2
- package/dist/internal.js +8 -0
- package/dist/operations/database-refusal.d.ts +51 -0
- package/dist/operations/database-refusal.js +45 -0
- package/dist/operations/operation-arguments.d.ts +148 -60
- package/dist/operations/operation-call.d.ts +9 -5
- package/dist/operations/operation-result.d.ts +6 -4
- package/dist/operations/operation-validator-core.js +160 -39
- package/dist/operations/operation-validator.d.ts +1 -1
- package/dist/operations/structural-limits.walker.d.ts +1 -1
- package/dist/operations/structural-limits.walker.js +1 -3
- package/dist/operations/validation-code.guidance.d.ts +6 -0
- package/dist/operations/validation-code.guidance.js +90 -0
- package/dist/operations/write-scope.resolver.d.ts +4 -0
- package/dist/operations/write-scope.resolver.js +2 -0
- package/dist/policy/access-provider.interface.d.ts +91 -0
- package/dist/policy/access-provider.interface.js +1 -0
- package/dist/policy/access-provider.registry.d.ts +17 -0
- package/dist/policy/access-provider.registry.js +15 -0
- package/dist/policy/access-question.d.ts +20 -0
- package/dist/policy/access-question.js +1 -0
- package/dist/policy/access-question.registry.d.ts +5 -0
- package/dist/policy/access-question.registry.js +19 -0
- package/dist/policy/access-question.runtime.d.ts +36 -0
- package/dist/policy/access-question.runtime.js +295 -0
- package/dist/policy/access-verb.table.d.ts +56 -0
- package/dist/policy/access-verb.table.js +21 -0
- package/dist/policy/access-verbs.d.ts +46 -0
- package/dist/policy/access-verbs.js +1 -0
- package/dist/policy/policy-admission.d.ts +20 -0
- package/dist/policy/policy-admission.js +407 -0
- package/dist/policy/policy-after-update.runtime.d.ts +79 -0
- package/dist/policy/policy-after-update.runtime.js +206 -0
- package/dist/policy/policy-condition.d.ts +15 -0
- package/dist/policy/policy-condition.js +36 -0
- package/dist/policy/policy-engine.d.ts +205 -0
- package/dist/policy/policy-engine.js +1 -0
- package/dist/policy/policy-named-rows.d.ts +18 -0
- package/dist/policy/policy-named-rows.js +51 -0
- package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
- package/dist/policy/policy-nested-write.runtime.js +536 -0
- package/dist/policy/policy-read.runtime.d.ts +81 -0
- package/dist/policy/policy-read.runtime.js +501 -0
- package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
- package/dist/policy/policy-reference-write.runtime.js +336 -0
- package/dist/policy/policy-request.d.ts +72 -0
- package/dist/policy/policy-request.js +115 -0
- package/dist/policy/policy-session.d.ts +106 -0
- package/dist/policy/policy-session.js +293 -0
- package/dist/policy/policy-startup.validator.d.ts +10 -0
- package/dist/policy/policy-startup.validator.js +112 -0
- package/dist/policy/policy-write.runtime.d.ts +39 -0
- package/dist/policy/policy-write.runtime.js +530 -0
- package/dist/prebuilt/core-version.generated.d.ts +2 -0
- package/dist/prebuilt/core-version.generated.js +1 -0
- package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
- package/dist/prebuilt/prebuilt-changes.js +63 -0
- package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
- package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
- package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
- package/dist/prebuilt/prebuilt-contracts.js +1 -0
- package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
- package/dist/prebuilt/prebuilt-contracts.loader.js +75 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.js +227 -0
- package/dist/protocol/absent-route.responder.d.ts +49 -14
- package/dist/protocol/absent-route.responder.js +92 -15
- package/dist/protocol/contract-document.responder.d.ts +9 -1
- package/dist/protocol/contract-document.responder.js +3 -2
- package/dist/protocol/http-request.decoder.d.ts +52 -3
- package/dist/protocol/http-request.decoder.js +45 -6
- package/dist/protocol/http-request.reader.d.ts +10 -3
- package/dist/protocol/http-request.reader.js +12 -2
- package/dist/protocol/http-response.encoder.d.ts +12 -0
- package/dist/protocol/http-response.encoder.js +17 -3
- package/dist/protocol/operation-response.guard.js +1 -3
- package/dist/protocol/operation-set.decoder.d.ts +48 -0
- package/dist/protocol/operation-set.decoder.js +185 -0
- package/dist/protocol/operation-set.handler.d.ts +27 -0
- package/dist/protocol/operation-set.handler.js +179 -0
- package/dist/protocol/protocol-headers.d.ts +12 -3
- package/dist/protocol/protocol-headers.js +12 -5
- package/dist/protocol/protocol-surface.d.ts +16 -3
- package/dist/protocol/protocol-surface.js +41 -1
- package/dist/protocol/protocol.binder.d.ts +52 -1
- package/dist/protocol/protocol.binder.js +6 -1
- package/dist/protocol/protocol.handler.d.ts +45 -1
- package/dist/protocol/protocol.handler.js +164 -19
- package/dist/protocol/read-cache.responder.d.ts +26 -0
- package/dist/protocol/read-cache.responder.js +47 -0
- package/dist/protocol/read-query.codec.d.ts +34 -0
- package/dist/protocol/read-query.codec.js +125 -0
- package/dist/runtime/caller-data.copier.d.ts +18 -3
- package/dist/runtime/caller-data.copier.js +21 -8
- package/dist/runtime/caller-data.door.d.ts +13 -6
- package/dist/runtime/computed-read-runtime.d.ts +6 -1
- package/dist/runtime/computed-read-runtime.js +229 -48
- package/dist/runtime/computed-value.error.d.ts +3 -2
- package/dist/runtime/computed-value.error.js +3 -2
- package/dist/runtime/context-executor.runtime.d.ts +4 -3
- package/dist/runtime/context-executor.runtime.js +4 -2
- package/dist/runtime/core-class.brand.d.ts +10 -0
- package/dist/runtime/core-class.brand.js +21 -0
- package/dist/runtime/create-requirement.d.ts +31 -5
- package/dist/runtime/create-requirement.js +130 -24
- package/dist/runtime/decimal.d.ts +14 -0
- package/dist/runtime/decimal.js +21 -0
- package/dist/runtime/diagnostics-reporter.d.ts +49 -9
- package/dist/runtime/diagnostics-reporter.js +16 -9
- package/dist/runtime/error-boundary.d.ts +9 -2
- package/dist/runtime/error-boundary.js +12 -0
- 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 +8 -0
- package/dist/runtime/field-check.evaluator.d.ts +0 -2
- package/dist/runtime/field-check.evaluator.js +1 -1
- package/dist/runtime/field-compute.d.ts +11 -10
- package/dist/runtime/field-stage.runtime.d.ts +3 -3
- package/dist/runtime/field-stage.runtime.js +9 -11
- package/dist/runtime/field-validator.runtime.d.ts +19 -1
- package/dist/runtime/field-validator.runtime.js +49 -9
- package/dist/runtime/framework-error.js +9 -0
- package/dist/runtime/framework-warning.emitter.d.ts +6 -0
- package/dist/runtime/framework-warning.emitter.js +8 -0
- package/dist/runtime/json-value.d.ts +10 -5
- package/dist/runtime/level-lifecycle.runtime.d.ts +4 -3
- package/dist/runtime/level-lifecycle.runtime.js +3 -5
- package/dist/runtime/mutation-planner.d.ts +1 -6
- package/dist/runtime/mutation-planner.js +4 -17
- package/dist/runtime/nested-write.walker.js +2 -1
- 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 +16 -9
- package/dist/runtime/operation-runtime.d.ts +35 -17
- package/dist/runtime/operation-runtime.js +220 -49
- package/dist/runtime/outcome-mapper.d.ts +2 -1
- package/dist/runtime/output-validator.d.ts +1 -1
- package/dist/runtime/output-validator.js +1 -3
- package/dist/runtime/owned-execution.registry.d.ts +34 -4
- package/dist/runtime/pipe-output.validator.d.ts +10 -0
- package/dist/runtime/pipe-output.validator.js +4 -2
- package/dist/runtime/pipeline.d.ts +52 -23
- package/dist/runtime/readonly-value.d.ts +20 -5
- package/dist/runtime/readonly-value.js +74 -26
- package/dist/runtime/record.guard.d.ts +14 -0
- package/dist/runtime/record.guard.js +10 -0
- package/dist/runtime/referential-action.d.ts +1 -1
- package/dist/runtime/request-envelope.validator.js +13 -10
- package/dist/runtime/scalar-runtime.d.ts +4 -21
- package/dist/runtime/scalar-runtime.js +91 -31
- package/dist/runtime/thenable.guard.d.ts +7 -0
- package/dist/runtime/thenable.guard.js +5 -0
- package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
- package/dist/runtime/unsent-value.normalizer.js +129 -0
- package/dist/transactions/operation-arguments-encoder.js +9 -10
- package/dist/transactions/operation-fingerprint.js +2 -2
- package/dist/transactions/sql-statement.d.ts +10 -2
- package/dist/transactions/sql-statement.validator.d.ts +2 -2
- package/dist/transactions/sql-statement.validator.js +40 -6
- package/dist/transactions/transaction-envelope.d.ts +5 -4
- package/dist/transactions/transaction-integrity-error.js +2 -0
- package/dist/transactions/transaction-plan-assembler.d.ts +12 -5
- package/dist/transactions/transaction-plan-assembler.js +49 -17
- package/dist/transactions/transaction-plan-validator.d.ts +23 -7
- package/dist/transactions/transaction-plan-validator.js +31 -7
- package/dist/transactions/transaction-reference-collector.js +8 -10
- package/dist/transactions/transaction-reference-resolver.d.ts +3 -2
- package/dist/transactions/transaction-reference-resolver.js +1 -3
- package/dist/transactions/transaction-reference-validator.d.ts +43 -3
- package/dist/transactions/transaction-reference-validator.js +83 -57
- package/dist/transactions/transaction-reference.d.ts +1 -1
- package/dist/transactions/transaction-reference.js +5 -0
- package/dist/transactions/transaction-request.d.ts +8 -8
- package/dist/transactions/transaction-runtime.d.ts +5 -2
- package/dist/transactions/transaction-runtime.js +108 -27
- package/dist/transactions/transaction-settlement.runtime.d.ts +4 -3
- package/dist/transactions/transaction-slot-path-error.js +2 -0
- package/dist/transactions/transaction-stage.runtime.d.ts +5 -3
- package/dist/transactions/transaction-stage.runtime.js +8 -7
- package/package.json +6 -5
- package/src/runtime/field-check.evaluator.ts +1 -1
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { lookupOwn, lookupResource } from "../contracts/contract-lookup.js";
|
|
2
|
+
import { AVENTARA_PROTOCOL_VERSION } from "../contracts/contract-protocol.js";
|
|
2
3
|
import { isOperationVariantAvailable, } from "../contracts/resource-operations.js";
|
|
3
4
|
import { parseOperationIdentity, } from "../operations/operation-identity.js";
|
|
4
5
|
import { operationUnavailableIssue } from "../operations/operation-validator.js";
|
|
5
6
|
import { resourceUnavailableIssue } from "../operations/operation-validator-core.js";
|
|
7
|
+
import { validationIssue } from "../operations/validation-code.js";
|
|
6
8
|
import { createReporter, } from "../runtime/diagnostics-reporter.js";
|
|
7
9
|
import { INTERNAL_FAILURE_MESSAGE, operationFailure, } from "../runtime/operation-response.js";
|
|
8
10
|
import { protocolIdentityFailure } from "../runtime/operation-runtime.js";
|
|
9
11
|
import { mapValidationOutcome } from "../runtime/outcome-mapper.js";
|
|
10
12
|
import { transactionsUnavailableFailure } from "../transactions/transaction-plan-validator.js";
|
|
11
|
-
import { CONTRACT_ROUTE, GET_ONLY, isProtocolPath, operationRouteSegments, POST_ONLY, readRequest, TRANSACTIONS_ROUTE, } from "./http-request.reader.js";
|
|
13
|
+
import { ACCESS_CAN_ROUTE, ALL_ROUTE, CONTRACT_ROUTE, GET_AND_POST, GET_ONLY, isProtocolPath, operationRouteSegments, POST_ONLY, readRequest, TRANSACTIONS_ROUTE, } from "./http-request.reader.js";
|
|
12
14
|
import { encodeOperationResponse, } from "./http-response.encoder.js";
|
|
13
15
|
import { identityHeadersMissing, transportFailure, } from "./protocol-failure.js";
|
|
14
|
-
import { missingIdentityHeaders } from "./protocol-headers.js";
|
|
16
|
+
import { missingIdentityHeaders, NO_SNIFF, protocolVersionOf, } from "./protocol-headers.js";
|
|
17
|
+
import { advertisesAnyOperation } from "./protocol-surface.js";
|
|
18
|
+
import { uncachedAnswer } from "./read-cache.responder.js";
|
|
19
|
+
import { readQueryOf } from "./read-query.codec.js";
|
|
15
20
|
import { AvUnmountedRouteError } from "./unmounted-route.error.js";
|
|
16
21
|
export function resolveOperationRoute(contracts, protocol, route, origin = "client") {
|
|
17
22
|
const identityFailure = protocolIdentityFailure(contracts, protocol, origin);
|
|
@@ -38,41 +43,101 @@ export function resolveOperationRoute(contracts, protocol, route, origin = "clie
|
|
|
38
43
|
}
|
|
39
44
|
return { ok: true, operation };
|
|
40
45
|
}
|
|
41
|
-
|
|
46
|
+
function transactionsRouteFailure(contracts, protocol, origin = "client") {
|
|
42
47
|
return (protocolIdentityFailure(contracts, protocol, origin) ??
|
|
43
48
|
(contracts[origin].transactions === "interactive"
|
|
44
49
|
? undefined
|
|
45
50
|
: transactionsUnavailableFailure()));
|
|
46
51
|
}
|
|
52
|
+
function accessCanUnavailableFailure() {
|
|
53
|
+
const message = "Access questions are not available on the active Contract.";
|
|
54
|
+
return operationFailure("A2002", {
|
|
55
|
+
message,
|
|
56
|
+
issues: [validationIssue("V1006", ["questions"], message)],
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function accessCanRouteFailure(contracts, protocol, origin = "client") {
|
|
60
|
+
return (protocolIdentityFailure(contracts, protocol, origin) ??
|
|
61
|
+
(contracts[origin].access === undefined
|
|
62
|
+
? accessCanUnavailableFailure()
|
|
63
|
+
: undefined));
|
|
64
|
+
}
|
|
65
|
+
function allRouteFailure(contracts, protocol, origin = "client") {
|
|
66
|
+
const identityFailure = protocolIdentityFailure(contracts, protocol, origin);
|
|
67
|
+
if (identityFailure !== undefined) {
|
|
68
|
+
return identityFailure;
|
|
69
|
+
}
|
|
70
|
+
if (advertisesAnyOperation(contracts[origin])) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const message = "Operation Sets are not available on the active Contract.";
|
|
74
|
+
return operationFailure("A2002", {
|
|
75
|
+
message,
|
|
76
|
+
issues: [validationIssue("V1006", ["operations"], message)],
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function readIdentityOf(read, query) {
|
|
80
|
+
return {
|
|
81
|
+
version: protocolVersionOf(read.headers) ?? AVENTARA_PROTOCOL_VERSION,
|
|
82
|
+
hash: query.v,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
47
85
|
export function checkOperationRoute(contracts, read, origin = "client") {
|
|
86
|
+
const check = operationRouteCheck(contracts, read, origin);
|
|
87
|
+
return check.ok || read.request.method !== "GET"
|
|
88
|
+
? check
|
|
89
|
+
: refusedWith(uncachedAnswer(check.response));
|
|
90
|
+
}
|
|
91
|
+
function operationRouteCheck(contracts, read, origin) {
|
|
48
92
|
const segments = operationRouteSegments(read.request.path);
|
|
49
93
|
if (segments === undefined) {
|
|
50
94
|
return refusedWith(transportFailure("A2000", read.requestId));
|
|
51
95
|
}
|
|
52
|
-
|
|
96
|
+
const get = read.request.method === "GET";
|
|
97
|
+
const queried = get && read.request.query !== undefined && read.request.query !== "";
|
|
98
|
+
const query = queried ? readQueryOf(read.request.query) : undefined;
|
|
99
|
+
if (queried && query === undefined) {
|
|
100
|
+
return refusedWith(transportFailure("A2000", read.requestId));
|
|
101
|
+
}
|
|
102
|
+
const protocol = query === undefined ? read.protocol : readIdentityOf(read, query);
|
|
103
|
+
if (protocol === undefined) {
|
|
53
104
|
return refusedWith(identityFailureOf(read));
|
|
54
105
|
}
|
|
55
|
-
const route = resolveOperationRoute(contracts,
|
|
106
|
+
const route = resolveOperationRoute(contracts, protocol, segments, origin);
|
|
56
107
|
if (!route.ok) {
|
|
57
108
|
return refusedWith(encodeOperationResponse(route.failure, read.requestId));
|
|
58
109
|
}
|
|
59
|
-
|
|
110
|
+
const { family, variant } = route.operation;
|
|
111
|
+
const marks = family === "find"
|
|
112
|
+
? lookupResource(contracts[origin], segments.resource)?.cache
|
|
113
|
+
: undefined;
|
|
114
|
+
const cache = family === "find"
|
|
115
|
+
? lookupOwn(marks, variant)
|
|
116
|
+
: undefined;
|
|
117
|
+
return read.request.method === "POST" || (get && cache !== undefined)
|
|
60
118
|
? {
|
|
61
119
|
ok: true,
|
|
62
|
-
protocol
|
|
120
|
+
protocol,
|
|
63
121
|
resource: segments.resource,
|
|
64
122
|
operation: route.operation,
|
|
123
|
+
cache,
|
|
124
|
+
query,
|
|
65
125
|
}
|
|
66
|
-
: refusedWith(transportFailure("A2012", read.requestId, POST_ONLY));
|
|
126
|
+
: refusedWith(transportFailure("A2012", read.requestId, cache === undefined ? POST_ONLY : GET_AND_POST));
|
|
67
127
|
}
|
|
68
|
-
|
|
69
|
-
|
|
128
|
+
const POST_ROUTE_FAILURES = {
|
|
129
|
+
[TRANSACTIONS_ROUTE]: transactionsRouteFailure,
|
|
130
|
+
[ACCESS_CAN_ROUTE]: accessCanRouteFailure,
|
|
131
|
+
[ALL_ROUTE]: allRouteFailure,
|
|
132
|
+
};
|
|
133
|
+
export function checkPostRoute(route, contracts, read, origin = "client") {
|
|
134
|
+
if (read.request.path !== route) {
|
|
70
135
|
return refusedWith(transportFailure("A2000", read.requestId));
|
|
71
136
|
}
|
|
72
137
|
if (read.protocol === undefined) {
|
|
73
138
|
return refusedWith(identityFailureOf(read));
|
|
74
139
|
}
|
|
75
|
-
const absent =
|
|
140
|
+
const absent = POST_ROUTE_FAILURES[route](contracts, read.protocol, origin);
|
|
76
141
|
if (absent !== undefined) {
|
|
77
142
|
return refusedWith(encodeOperationResponse(absent, read.requestId));
|
|
78
143
|
}
|
|
@@ -97,11 +162,19 @@ export function answerAbsentRequest(contracts, received, sink, origin = "client"
|
|
|
97
162
|
}
|
|
98
163
|
if (path === CONTRACT_ROUTE) {
|
|
99
164
|
return method === "GET"
|
|
100
|
-
? unmounted(read.requestId)
|
|
165
|
+
? withNoSniff(unmounted(read.requestId))
|
|
101
166
|
: transportFailure("A2012", read.requestId, GET_ONLY);
|
|
102
167
|
}
|
|
168
|
+
if (path === ALL_ROUTE) {
|
|
169
|
+
const route = checkPostRoute(ALL_ROUTE, contracts, read, origin);
|
|
170
|
+
return route.ok ? unmounted(read.requestId) : route.response;
|
|
171
|
+
}
|
|
172
|
+
if (path === ACCESS_CAN_ROUTE) {
|
|
173
|
+
const route = checkPostRoute(ACCESS_CAN_ROUTE, contracts, read, origin);
|
|
174
|
+
return route.ok ? unmounted(read.requestId) : route.response;
|
|
175
|
+
}
|
|
103
176
|
if (path === TRANSACTIONS_ROUTE) {
|
|
104
|
-
const route =
|
|
177
|
+
const route = checkPostRoute(TRANSACTIONS_ROUTE, contracts, read, origin);
|
|
105
178
|
if (!route.ok) {
|
|
106
179
|
return route.response;
|
|
107
180
|
}
|
|
@@ -117,6 +190,7 @@ export function answerAbsentRequest(contracts, received, sink, origin = "client"
|
|
|
117
190
|
return route.response;
|
|
118
191
|
}
|
|
119
192
|
const { family, variant } = route.operation;
|
|
193
|
+
const answer = unmounted(read.requestId);
|
|
120
194
|
createReporter(sink, {
|
|
121
195
|
kind: "operation",
|
|
122
196
|
origin,
|
|
@@ -124,8 +198,11 @@ export function answerAbsentRequest(contracts, received, sink, origin = "client"
|
|
|
124
198
|
family,
|
|
125
199
|
variant,
|
|
126
200
|
requestId: read.requestId,
|
|
127
|
-
})(new AvUnmountedRouteError(`${route.resource}.${family}.${variant}`,
|
|
128
|
-
return
|
|
201
|
+
})(new AvUnmountedRouteError(`${route.resource}.${family}.${variant}`, `${method} ${path}`), "A3000");
|
|
202
|
+
return method === "GET" ? uncachedAnswer(answer) : answer;
|
|
203
|
+
}
|
|
204
|
+
function withNoSniff(response) {
|
|
205
|
+
return { ...response, headers: { ...response.headers, ...NO_SNIFF } };
|
|
129
206
|
}
|
|
130
207
|
function unmounted(requestId) {
|
|
131
208
|
return encodeOperationResponse(operationFailure("A3000", { message: INTERNAL_FAILURE_MESSAGE }), requestId);
|
|
@@ -6,7 +6,7 @@ import type { AvProtocolResponse } from "./http-response.encoder.js";
|
|
|
6
6
|
* entity tag, the quoted contract hash. The bytes include `protocol.hash`, although
|
|
7
7
|
* the hash's own input excludes it.
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
type ContractDocument = {
|
|
10
10
|
readonly body: string;
|
|
11
11
|
readonly etag: string;
|
|
12
12
|
};
|
|
@@ -17,3 +17,11 @@ export declare function contractDocumentOf(client: AvContractClient): ContractDo
|
|
|
17
17
|
* order:
|
|
18
18
|
*/
|
|
19
19
|
export declare function encodeContractRequest(document: ContractDocument, received: AvProtocolRequest): AvProtocolResponse;
|
|
20
|
+
/**
|
|
21
|
+
* Whether `If-None-Match` names the current representation: `*`, or a list holding an
|
|
22
|
+
* entity tag whose opaque tag equals `etag`'s — the WEAK comparison, which `If-None-
|
|
23
|
+
* Match` uses, so a `W/` prefix does not matter. A value that is not a well-formed
|
|
24
|
+
* list matches nothing; an absent header matches nothing.
|
|
25
|
+
*/
|
|
26
|
+
export declare function noneMatchHolds(value: string | undefined, etag: string): boolean;
|
|
27
|
+
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
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
|
-
import { headers, headerValue } from "./protocol-headers.js";
|
|
4
|
+
import { headers, headerValue, NO_SNIFF } from "./protocol-headers.js";
|
|
5
5
|
export function contractDocumentOf(client) {
|
|
6
6
|
return Object.freeze({
|
|
7
7
|
body: canonicalContractTextOf(client),
|
|
@@ -23,6 +23,7 @@ export function encodeContractRequest(document, received) {
|
|
|
23
23
|
const validators = {
|
|
24
24
|
ETag: document.etag,
|
|
25
25
|
"Cache-Control": "no-cache",
|
|
26
|
+
...NO_SNIFF,
|
|
26
27
|
[headers.requestId]: requestId,
|
|
27
28
|
};
|
|
28
29
|
return noneMatchHolds(headerValue(read.headers, "if-none-match"), document.etag)
|
|
@@ -34,7 +35,7 @@ export function encodeContractRequest(document, received) {
|
|
|
34
35
|
};
|
|
35
36
|
}
|
|
36
37
|
const IF_NONE_MATCH_MEMBER = /[ \t]*(?:(?:W\/)?("[\x21\x23-\x7e\x80-\xff]*"))?[ \t]*(,|$)/y;
|
|
37
|
-
function noneMatchHolds(value, etag) {
|
|
38
|
+
export function noneMatchHolds(value, etag) {
|
|
38
39
|
if (value === undefined) {
|
|
39
40
|
return false;
|
|
40
41
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { AvContracts } from "../compiler/contract.compiler.js";
|
|
2
2
|
import type { RemoteRequestOrigin } from "../config/config-layer.js";
|
|
3
|
-
import type { RemoteOperationRequest } from "../runtime/operation-request.js";
|
|
4
|
-
import type {
|
|
3
|
+
import type { AvRequestProtocol, RemoteOperationRequest } from "../runtime/operation-request.js";
|
|
4
|
+
import type { AvTransportContext } from "../runtime/pipeline.js";
|
|
5
|
+
import type { AvAgentTransactionRequest, AvClientTransactionRequest } from "../transactions/transaction-request.js";
|
|
6
|
+
import { type ReadRequest } from "./http-request.reader.js";
|
|
5
7
|
import type { AvProtocolResponse } from "./http-response.encoder.js";
|
|
6
8
|
/** One HTTP request as a host hands it to the protocol. */
|
|
7
9
|
export type AvProtocolRequest = {
|
|
@@ -13,6 +15,12 @@ export type AvProtocolRequest = {
|
|
|
13
15
|
* in the same form as the paths `protocol.surface()` returns.
|
|
14
16
|
*/
|
|
15
17
|
readonly path: string;
|
|
18
|
+
/**
|
|
19
|
+
* The request URL's query, as received (not yet URL-decoded) and without its
|
|
20
|
+
* `?`: `q=…&v=…`. Read only by a cached read's `GET`; omitted or `""` when
|
|
21
|
+
* the URL has none.
|
|
22
|
+
*/
|
|
23
|
+
readonly query?: string;
|
|
16
24
|
/**
|
|
17
25
|
* The request headers as the host received them. Names in any case (they
|
|
18
26
|
* are case-insensitive); a repeated header as its list of values; an entry
|
|
@@ -56,12 +64,14 @@ export type DecodedOperationRequest = Extract<DecodedOperation, {
|
|
|
56
64
|
ok: true;
|
|
57
65
|
}>;
|
|
58
66
|
/** What `protocol.decodeTransaction` answers. */
|
|
59
|
-
export type DecodedTransaction = Decoded<
|
|
67
|
+
export type DecodedTransaction = Decoded<AvClientTransactionRequest | AvAgentTransactionRequest>;
|
|
60
68
|
/**
|
|
61
69
|
* `protocol.decodeOperation(request)` — one operation route's HTTP request as
|
|
62
70
|
* the client-origin request `framework.execute` takes, or its answer.
|
|
63
71
|
*/
|
|
64
72
|
export declare function decodeOperationRequest(contracts: AvContracts, received: AvProtocolRequest, origin?: RemoteRequestOrigin): DecodedOperation;
|
|
73
|
+
/** {@link decodeOperationRequest} over a request already read. */
|
|
74
|
+
export declare function decodeOperationRead(contracts: AvContracts, read: ReadRequest, origin: RemoteRequestOrigin): DecodedOperation;
|
|
65
75
|
/**
|
|
66
76
|
* `protocol.decodeTransaction(request)` — the `/_transactions` request as the client-
|
|
67
77
|
* origin plan request `framework.executeTransaction` takes, or its answer. The same
|
|
@@ -71,10 +81,49 @@ export declare function decodeOperationRequest(contracts: AvContracts, received:
|
|
|
71
81
|
* say otherwise. The body is the plan verbatim.
|
|
72
82
|
*/
|
|
73
83
|
export declare function decodeTransactionRequest(contracts: AvContracts, received: AvProtocolRequest, origin?: RemoteRequestOrigin): DecodedTransaction;
|
|
84
|
+
/** A `/_access/can` request as core answers it: its origin, identity and body. */
|
|
85
|
+
type DecodedCanRequest = {
|
|
86
|
+
readonly origin: RemoteRequestOrigin;
|
|
87
|
+
readonly requestId: string;
|
|
88
|
+
readonly protocol: AvRequestProtocol;
|
|
89
|
+
/** The body, a JSON object: `{ questions }`, read by core. */
|
|
90
|
+
readonly body: object;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* The `/_access/can` request as the request core answers, or its answer: the same
|
|
94
|
+
* steps as {@link decodeTransactionRequest}, with the path exactly `/_access/can`
|
|
95
|
+
* and its absence being a Contract without its `access` section. The body is read
|
|
96
|
+
* as a JSON object and handed to core verbatim; its `questions` are core's to
|
|
97
|
+
* judge.
|
|
98
|
+
*/
|
|
99
|
+
export declare function decodeCanRequest(contracts: AvContracts, received: AvProtocolRequest, origin?: RemoteRequestOrigin): Decoded<DecodedCanRequest>;
|
|
100
|
+
/**
|
|
101
|
+
* A client request's method — `POST`, or `GET` for a cached read — and its
|
|
102
|
+
* headers, in one spelling.
|
|
103
|
+
*/
|
|
104
|
+
export declare function transportOf(read: ReadRequest): AvTransportContext;
|
|
105
|
+
/**
|
|
106
|
+
* Step 5, after the route checks passed: the body as a JSON object, or the answer
|
|
107
|
+
* refusing it. Only the raw arm is measured, typed and parsed.
|
|
108
|
+
*/
|
|
109
|
+
export declare function readBody(read: ReadRequest, contracts: AvContracts, origin: RemoteRequestOrigin): {
|
|
110
|
+
readonly ok: true;
|
|
111
|
+
readonly value: object;
|
|
112
|
+
} | {
|
|
113
|
+
readonly ok: false;
|
|
114
|
+
readonly response: AvProtocolResponse;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Records `value` as a body the protocol parsed itself: a cached read's
|
|
118
|
+
* arguments, `JSON.parse` output of its `q` that nothing else holds.
|
|
119
|
+
*/
|
|
120
|
+
export declare function adoptParsedBody(value: object): void;
|
|
74
121
|
/**
|
|
75
122
|
* Whether `value` is a body this decoder parsed from raw content. Only the protocol's
|
|
76
123
|
* own shortcuts ask, about a request they have just decoded, before any host code
|
|
77
124
|
* could hold it; it is exported from no entry point.
|
|
78
125
|
*/
|
|
79
126
|
export declare function isParsedByDecoder(value: unknown): boolean;
|
|
127
|
+
/** Marks `value`, a part of a body this decoder parsed from raw content, as parsed here. */
|
|
128
|
+
export declare function markParsedByDecoder(value: object): void;
|
|
80
129
|
export {};
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
import { checkOperationRoute,
|
|
2
|
-
import { readRequest } from "./http-request.reader.js";
|
|
1
|
+
import { checkOperationRoute, checkPostRoute, } from "./absent-route.responder.js";
|
|
2
|
+
import { ACCESS_CAN_ROUTE, POST_ONLY, readRequest, TRANSACTIONS_ROUTE, } from "./http-request.reader.js";
|
|
3
3
|
import { transportFailure, } from "./protocol-failure.js";
|
|
4
4
|
import { headerValue } from "./protocol-headers.js";
|
|
5
|
+
import { uncachedAnswer } from "./read-cache.responder.js";
|
|
5
6
|
export function decodeOperationRequest(contracts, received, origin = "client") {
|
|
6
7
|
const read = readRequest(received);
|
|
7
8
|
if (!read.ok) {
|
|
8
9
|
return read;
|
|
9
10
|
}
|
|
11
|
+
return decodeOperationRead(contracts, read, origin);
|
|
12
|
+
}
|
|
13
|
+
export function decodeOperationRead(contracts, read, origin) {
|
|
10
14
|
const route = checkOperationRoute(contracts, read, origin);
|
|
11
15
|
if (!route.ok) {
|
|
12
16
|
return refused(route.response, read.requestId);
|
|
13
17
|
}
|
|
18
|
+
if (read.request.method !== "POST") {
|
|
19
|
+
return refused(uncachedAnswer(transportFailure("A2012", read.requestId, POST_ONLY)), read.requestId);
|
|
20
|
+
}
|
|
14
21
|
const body = readBody(read, contracts, origin);
|
|
15
22
|
return body.ok
|
|
16
23
|
? {
|
|
@@ -33,7 +40,7 @@ export function decodeTransactionRequest(contracts, received, origin = "client")
|
|
|
33
40
|
if (!read.ok) {
|
|
34
41
|
return read;
|
|
35
42
|
}
|
|
36
|
-
const route =
|
|
43
|
+
const route = checkPostRoute(TRANSACTIONS_ROUTE, contracts, read, origin);
|
|
37
44
|
if (!route.ok) {
|
|
38
45
|
return refused(route.response, read.requestId);
|
|
39
46
|
}
|
|
@@ -52,13 +59,39 @@ export function decodeTransactionRequest(contracts, received, origin = "client")
|
|
|
52
59
|
}
|
|
53
60
|
: refused(body.response, read.requestId);
|
|
54
61
|
}
|
|
62
|
+
export function decodeCanRequest(contracts, received, origin = "client") {
|
|
63
|
+
const read = readRequest(received);
|
|
64
|
+
if (!read.ok) {
|
|
65
|
+
return read;
|
|
66
|
+
}
|
|
67
|
+
const route = checkPostRoute(ACCESS_CAN_ROUTE, contracts, read, origin);
|
|
68
|
+
if (!route.ok) {
|
|
69
|
+
return refused(route.response, read.requestId);
|
|
70
|
+
}
|
|
71
|
+
const body = readBody(read, contracts, origin);
|
|
72
|
+
return body.ok
|
|
73
|
+
? {
|
|
74
|
+
ok: true,
|
|
75
|
+
request: {
|
|
76
|
+
origin,
|
|
77
|
+
requestId: read.requestId,
|
|
78
|
+
protocol: route.protocol,
|
|
79
|
+
body: body.value,
|
|
80
|
+
},
|
|
81
|
+
requestId: read.requestId,
|
|
82
|
+
}
|
|
83
|
+
: refused(body.response, read.requestId);
|
|
84
|
+
}
|
|
55
85
|
function refused(response, requestId) {
|
|
56
86
|
return { ok: false, response, requestId };
|
|
57
87
|
}
|
|
58
|
-
function transportOf(read) {
|
|
59
|
-
return {
|
|
88
|
+
export function transportOf(read) {
|
|
89
|
+
return {
|
|
90
|
+
method: read.request.method === "GET" ? "GET" : "POST",
|
|
91
|
+
headers: read.headers,
|
|
92
|
+
};
|
|
60
93
|
}
|
|
61
|
-
function readBody(read, contracts, origin) {
|
|
94
|
+
export function readBody(read, contracts, origin) {
|
|
62
95
|
const code = bodyValue(read.request.body, headerValue(read.headers, "content-type"), contracts[origin].limits.maxRequestBytes);
|
|
63
96
|
return typeof code === "string"
|
|
64
97
|
? { ok: false, response: transportFailure(code, read.requestId) }
|
|
@@ -92,9 +125,15 @@ function bodyValue(body, contentType, maxRequestBytes) {
|
|
|
92
125
|
return { value };
|
|
93
126
|
}
|
|
94
127
|
const PARSED_HERE = new WeakSet();
|
|
128
|
+
export function adoptParsedBody(value) {
|
|
129
|
+
PARSED_HERE.add(value);
|
|
130
|
+
}
|
|
95
131
|
export function isParsedByDecoder(value) {
|
|
96
132
|
return typeof value === "object" && value !== null && PARSED_HERE.has(value);
|
|
97
133
|
}
|
|
134
|
+
export function markParsedByDecoder(value) {
|
|
135
|
+
PARSED_HERE.add(value);
|
|
136
|
+
}
|
|
98
137
|
function isJsonMediaType(contentType) {
|
|
99
138
|
return (contentType
|
|
100
139
|
?.split(";")[0]
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AvRequestProtocol } from "../runtime/operation-request.js";
|
|
2
2
|
import type { OperationRouteSegments } from "./absent-route.responder.js";
|
|
3
3
|
import type { AvProtocolRequest } from "./http-request.decoder.js";
|
|
4
4
|
import type { AvProtocolResponse } from "./http-response.encoder.js";
|
|
5
5
|
/** `POST <api>/_transactions`. */
|
|
6
6
|
export declare const TRANSACTIONS_ROUTE = "/_transactions";
|
|
7
|
+
/** `POST <api>/_access/can`. */
|
|
8
|
+
export declare const ACCESS_CAN_ROUTE = "/_access/can";
|
|
9
|
+
/** `POST <api>/_all`: one Operation Set. */
|
|
10
|
+
export declare const ALL_ROUTE = "/_all";
|
|
7
11
|
/** `GET <api>/_contract`. */
|
|
8
12
|
export declare const CONTRACT_ROUTE = "/_contract";
|
|
9
13
|
/** The methods an operation or `/_transactions` route accepts: `POST`, only. */
|
|
10
14
|
export declare const POST_ONLY: readonly string[];
|
|
15
|
+
/** The methods a cached read's route accepts: `GET` and `POST`. */
|
|
16
|
+
export declare const GET_AND_POST: readonly string[];
|
|
11
17
|
/** The methods the contract route accepts: `GET`, only. */
|
|
12
18
|
export declare const GET_ONLY: readonly string[];
|
|
13
19
|
/**
|
|
@@ -25,10 +31,10 @@ export type ReadRequest = {
|
|
|
25
31
|
/** Adopted from `Aventara-Request-Id`, else minted. */
|
|
26
32
|
readonly requestId: string;
|
|
27
33
|
/** `undefined` when either identity header is absent (`A2000`). */
|
|
28
|
-
readonly protocol:
|
|
34
|
+
readonly protocol: AvRequestProtocol | undefined;
|
|
29
35
|
};
|
|
30
36
|
/** What a value that is not an `AvProtocolRequest` reads as. */
|
|
31
|
-
|
|
37
|
+
type UnreadableRequest = {
|
|
32
38
|
readonly ok: false;
|
|
33
39
|
readonly response: AvProtocolResponse;
|
|
34
40
|
readonly requestId: string;
|
|
@@ -43,3 +49,4 @@ export declare function readRequest(received: unknown): ReadRequest | Unreadable
|
|
|
43
49
|
* `undefined` when it is not one.
|
|
44
50
|
*/
|
|
45
51
|
export declare function operationRouteSegments(path: string): OperationRouteSegments | undefined;
|
|
52
|
+
export {};
|
|
@@ -3,8 +3,11 @@ import { transportFailure } from "./protocol-failure.js";
|
|
|
3
3
|
import { adoptedRequestId, normalizeHeaders, protocolIdentityOf, } from "./protocol-headers.js";
|
|
4
4
|
const OPERATION_ROUTE = /^\/_resources\/([^/]*)\/([^/]*)\/([^/]*)$/;
|
|
5
5
|
export const TRANSACTIONS_ROUTE = "/_transactions";
|
|
6
|
+
export const ACCESS_CAN_ROUTE = "/_access/can";
|
|
7
|
+
export const ALL_ROUTE = "/_all";
|
|
6
8
|
export const CONTRACT_ROUTE = "/_contract";
|
|
7
9
|
export const POST_ONLY = Object.freeze(["POST"]);
|
|
10
|
+
export const GET_AND_POST = Object.freeze(["GET", "POST"]);
|
|
8
11
|
export const GET_ONLY = Object.freeze(["GET"]);
|
|
9
12
|
export function isProtocolPath(path) {
|
|
10
13
|
return path.startsWith("/_");
|
|
@@ -53,14 +56,21 @@ function malformedRequest() {
|
|
|
53
56
|
}
|
|
54
57
|
function wellFormedRequest(received) {
|
|
55
58
|
try {
|
|
56
|
-
const { method, path, headers, body } = received;
|
|
59
|
+
const { method, path, query, headers, body } = received;
|
|
57
60
|
const copied = headerRecord(headers);
|
|
58
61
|
const armed = armedBody(body);
|
|
59
62
|
return typeof method === "string" &&
|
|
60
63
|
typeof path === "string" &&
|
|
64
|
+
(query === undefined || typeof query === "string") &&
|
|
61
65
|
copied !== undefined &&
|
|
62
66
|
armed !== undefined
|
|
63
|
-
? {
|
|
67
|
+
? {
|
|
68
|
+
method,
|
|
69
|
+
path,
|
|
70
|
+
...(query === undefined ? {} : { query }),
|
|
71
|
+
headers: copied,
|
|
72
|
+
body: armed,
|
|
73
|
+
}
|
|
64
74
|
: undefined;
|
|
65
75
|
}
|
|
66
76
|
catch {
|
|
@@ -38,3 +38,15 @@ export declare function encodeOperationResponse(response: AvOperationResponse, r
|
|
|
38
38
|
* as `cause.operation`, as every internal failure inside a plan does.
|
|
39
39
|
*/
|
|
40
40
|
export declare function encodeTransactionResponse(response: AvTransactionResponse, requestId: string, report?: UnencodableReport): AvProtocolResponse;
|
|
41
|
+
/**
|
|
42
|
+
* An Operation Set's answer: `200 A1000`, `data` holding each entry's envelope
|
|
43
|
+
* text under its key, in the order given.
|
|
44
|
+
*/
|
|
45
|
+
export declare function encodeOperationSetResponse(entries: readonly {
|
|
46
|
+
readonly key: string;
|
|
47
|
+
readonly envelope: string;
|
|
48
|
+
}[], requestId: string): AvProtocolResponse;
|
|
49
|
+
/** One line of a streamed Operation Set answer: the entry's key and its envelope text. */
|
|
50
|
+
export declare function operationSetLine(key: string, envelope: string): string;
|
|
51
|
+
/** The headers of a streamed Operation Set answer. */
|
|
52
|
+
export declare function streamedHeaders(requestId: string): Readonly<Record<string, string>>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { encodeBase64, WIRE_SCALAR_PATTERNS, } from "../contracts/wire-scalar-format.js";
|
|
2
|
-
import {
|
|
2
|
+
import { isAvDecimal } from "../runtime/decimal.js";
|
|
3
3
|
import { SERIALIZATION_FAILURE_MESSAGE } from "../runtime/error-boundary.js";
|
|
4
|
-
import { operationFailure, } from "../runtime/operation-response.js";
|
|
4
|
+
import { operationFailure, operationSuccess, } from "../runtime/operation-response.js";
|
|
5
5
|
import { httpStatus } from "./http-status.table.js";
|
|
6
6
|
import { headers } from "./protocol-headers.js";
|
|
7
7
|
export function encodeOperationResponse(response, requestId, report) {
|
|
@@ -37,6 +37,20 @@ export function encodeTransactionResponse(response, requestId, report) {
|
|
|
37
37
|
return written(serializationFailure(step), "null", requestId);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
+
export function encodeOperationSetResponse(entries, requestId) {
|
|
41
|
+
return written(operationSuccess(null, "A1000"), `{${entries.map(({ key, envelope }) => `${JSON.stringify(key)}:${envelope}`).join(",")}}`, requestId);
|
|
42
|
+
}
|
|
43
|
+
export function operationSetLine(key, envelope) {
|
|
44
|
+
return `{"key":${JSON.stringify(key)},"envelope":${envelope}}\n`;
|
|
45
|
+
}
|
|
46
|
+
export function streamedHeaders(requestId) {
|
|
47
|
+
return {
|
|
48
|
+
"Content-Type": "application/x-ndjson",
|
|
49
|
+
"Cache-Control": "no-store",
|
|
50
|
+
"X-Accel-Buffering": "no",
|
|
51
|
+
[headers.requestId]: requestId,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
40
54
|
function serializationFailure(operation) {
|
|
41
55
|
return operationFailure("A3003", {
|
|
42
56
|
message: SERIALIZATION_FAILURE_MESSAGE,
|
|
@@ -161,7 +175,7 @@ function scalarWireText(value) {
|
|
|
161
175
|
}
|
|
162
176
|
return JSON.stringify(wire);
|
|
163
177
|
}
|
|
164
|
-
if (value
|
|
178
|
+
if (isAvDecimal(value)) {
|
|
165
179
|
return JSON.stringify(value.toString());
|
|
166
180
|
}
|
|
167
181
|
if (value instanceof Uint8Array) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { VALIDATION_CODES } from "../operations/validation-code.js";
|
|
2
2
|
import { OPERATION_CODES, } from "../runtime/operation-response.js";
|
|
3
|
+
import { isRecord } from "../runtime/record.guard.js";
|
|
3
4
|
export function isOperationResponse(value) {
|
|
4
5
|
if (!isRecord(value) || !Object.hasOwn(value, "data")) {
|
|
5
6
|
return false;
|
|
@@ -13,9 +14,6 @@ export function isOperationResponse(value) {
|
|
|
13
14
|
}
|
|
14
15
|
return value.data === null && isCause(value.cause);
|
|
15
16
|
}
|
|
16
|
-
function isRecord(value) {
|
|
17
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18
|
-
}
|
|
19
17
|
function isOperationCode(value) {
|
|
20
18
|
return OPERATION_CODES.some((code) => code === value);
|
|
21
19
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { AvContracts } from "../compiler/contract.compiler.js";
|
|
2
|
+
import type { RemoteRequestOrigin } from "../config/config-layer.js";
|
|
3
|
+
import type { AvRequestProtocol } from "../runtime/operation-request.js";
|
|
4
|
+
import type { AvTransportContext } from "../runtime/pipeline.js";
|
|
5
|
+
import { type AvProtocolRequest } from "./http-request.decoder.js";
|
|
6
|
+
import { type AvProtocolResponse } from "./http-response.encoder.js";
|
|
7
|
+
/** One entry of an Operation Set as the decoder read it: its key, the operation it names, and its arguments. */
|
|
8
|
+
export type OperationSetEntry = {
|
|
9
|
+
readonly key: string;
|
|
10
|
+
readonly resource: string;
|
|
11
|
+
readonly family: string;
|
|
12
|
+
readonly variant: string;
|
|
13
|
+
/** A JSON object: the operation's arguments, as its single route's body. */
|
|
14
|
+
readonly args: object;
|
|
15
|
+
};
|
|
16
|
+
/** A decoded `/_all` request: what every entry shares, and the entries in the request's own key order. */
|
|
17
|
+
export type DecodedOperationSet = {
|
|
18
|
+
readonly origin: RemoteRequestOrigin;
|
|
19
|
+
readonly requestId: string;
|
|
20
|
+
readonly protocol: AvRequestProtocol;
|
|
21
|
+
readonly transport: AvTransportContext;
|
|
22
|
+
readonly entries: readonly OperationSetEntry[];
|
|
23
|
+
/** Whether the request asked for the streamed answer (`Accept: application/x-ndjson`). */
|
|
24
|
+
readonly streamed: boolean;
|
|
25
|
+
};
|
|
26
|
+
/** What `decodeAllRequest` answers: the set, or the response that answers the whole request. */
|
|
27
|
+
type DecodedAll = {
|
|
28
|
+
readonly ok: true;
|
|
29
|
+
readonly request: DecodedOperationSet;
|
|
30
|
+
readonly requestId: string;
|
|
31
|
+
} | {
|
|
32
|
+
readonly ok: false;
|
|
33
|
+
readonly response: AvProtocolResponse;
|
|
34
|
+
readonly requestId: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* `POST /_all` — the request as the Operation Set core runs, or the answer that
|
|
38
|
+
* refuses it whole. The same steps as `decodeTransaction` up to the body: request
|
|
39
|
+
* id, path (exactly `/_all`), identity headers, version, hash, the route's
|
|
40
|
+
* presence, method, then size, content type and JSON. Then the body's shape, in
|
|
41
|
+
* order: exactly the `operations` member (`A2004`), an object of entries
|
|
42
|
+
* (`A2004`/`V1001`), at least one (`A2004`/`V1004`), at most `limits.maxAll`
|
|
43
|
+
* (`422 A2009`/`V1014`), every key an identifier (`A2004`/`V1001` at
|
|
44
|
+
* `["operations"]`, the key not echoed), and every entry exactly `resource`,
|
|
45
|
+
* `family` and `variant` strings and an `args` object (`A2004` at its member).
|
|
46
|
+
*/
|
|
47
|
+
export declare function decodeAllRequest(contracts: AvContracts, received: AvProtocolRequest, origin?: RemoteRequestOrigin): DecodedAll;
|
|
48
|
+
export {};
|