@aventara/core 1.0.0-rc.1 → 1.0.0-rc.10
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 +943 -16
- package/ERRORS.md +142 -0
- package/README.md +274 -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 +227 -24
- 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/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 +65 -0
- package/dist/config/config.validator.js +222 -8
- 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 +67 -22
- package/dist/config/field-compute.resolver.d.ts +2 -0
- package/dist/config/field-compute.resolver.js +8 -0
- 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 +4 -4
- package/dist/config/pipeline-tree.resolver.d.ts +2 -2
- package/dist/contracts/access-route.rules.d.ts +10 -0
- package/dist/contracts/access-route.rules.js +45 -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 +301 -89
- package/dist/contracts/client-contract-structure.validator.js +37 -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 +30 -4
- package/dist/contracts/contract-hash.d.ts +0 -1
- package/dist/contracts/contract-hash.js +1 -1
- package/dist/contracts/contract.d.ts +27 -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 +78 -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 +120 -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 +115 -23
- package/dist/framework/operation-facade.d.ts +80 -13
- package/dist/framework/operation-facade.js +2 -1
- package/dist/index.d.ts +17 -5
- package/dist/index.js +1 -0
- package/dist/internal.d.ts +7 -2
- package/dist/internal.js +6 -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 +159 -36
- package/dist/operations/operation-validator.d.ts +1 -1
- package/dist/operations/structural-limits.walker.d.ts +1 -1
- 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 +297 -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 +409 -0
- package/dist/policy/policy-after-update.runtime.d.ts +79 -0
- package/dist/policy/policy-after-update.runtime.js +208 -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 +545 -0
- package/dist/policy/policy-read.runtime.d.ts +81 -0
- package/dist/policy/policy-read.runtime.js +503 -0
- package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
- package/dist/policy/policy-reference-write.runtime.js +345 -0
- package/dist/policy/policy-request.d.ts +41 -0
- package/dist/policy/policy-request.js +63 -0
- package/dist/policy/policy-session.d.ts +106 -0
- package/dist/policy/policy-session.js +295 -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 +532 -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 +65 -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 +77 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.js +229 -0
- package/dist/protocol/absent-route.responder.d.ts +9 -27
- package/dist/protocol/absent-route.responder.js +36 -3
- package/dist/protocol/contract-document.responder.d.ts +2 -1
- package/dist/protocol/http-request.decoder.d.ts +19 -3
- package/dist/protocol/http-request.decoder.js +24 -1
- package/dist/protocol/http-request.reader.d.ts +6 -3
- package/dist/protocol/http-request.reader.js +1 -0
- package/dist/protocol/http-response.encoder.js +2 -2
- package/dist/protocol/protocol-headers.d.ts +3 -3
- package/dist/protocol/protocol-surface.d.ts +6 -1
- package/dist/protocol/protocol-surface.js +7 -0
- package/dist/protocol/protocol.binder.d.ts +16 -1
- package/dist/protocol/protocol.binder.js +4 -1
- package/dist/protocol/protocol.handler.d.ts +12 -1
- package/dist/protocol/protocol.handler.js +86 -17
- 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 +232 -45
- 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 +129 -21
- package/dist/runtime/decimal.d.ts +14 -0
- package/dist/runtime/decimal.js +21 -0
- package/dist/runtime/diagnostics-reporter.d.ts +44 -9
- package/dist/runtime/diagnostics-reporter.js +13 -1
- 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 -1
- package/dist/runtime/field-stage.runtime.js +8 -4
- package/dist/runtime/field-validator.runtime.d.ts +19 -1
- package/dist/runtime/field-validator.runtime.js +47 -8
- 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 +3 -14
- 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/owned-execution.registry.d.ts +13 -3
- 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 +47 -22
- package/dist/runtime/readonly-value.d.ts +20 -5
- package/dist/runtime/readonly-value.js +74 -26
- package/dist/runtime/referential-action.d.ts +1 -1
- package/dist/runtime/scalar-runtime.d.ts +4 -11
- package/dist/runtime/scalar-runtime.js +91 -22
- package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
- package/dist/runtime/unsent-value.normalizer.js +128 -0
- package/dist/transactions/operation-arguments-encoder.js +8 -3
- 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 +38 -5
- 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 +48 -10
- package/dist/transactions/transaction-plan-validator.d.ts +23 -7
- package/dist/transactions/transaction-plan-validator.js +27 -1
- package/dist/transactions/transaction-reference-resolver.d.ts +3 -2
- 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 +79 -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 +7 -4
- package/package.json +6 -5
- package/src/runtime/field-check.evaluator.ts +1 -1
|
@@ -1,9 +1,11 @@
|
|
|
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";
|
|
7
9
|
/** `GET <api>/_contract`. */
|
|
8
10
|
export declare const CONTRACT_ROUTE = "/_contract";
|
|
9
11
|
/** The methods an operation or `/_transactions` route accepts: `POST`, only. */
|
|
@@ -25,10 +27,10 @@ export type ReadRequest = {
|
|
|
25
27
|
/** Adopted from `Aventara-Request-Id`, else minted. */
|
|
26
28
|
readonly requestId: string;
|
|
27
29
|
/** `undefined` when either identity header is absent (`A2000`). */
|
|
28
|
-
readonly protocol:
|
|
30
|
+
readonly protocol: AvRequestProtocol | undefined;
|
|
29
31
|
};
|
|
30
32
|
/** What a value that is not an `AvProtocolRequest` reads as. */
|
|
31
|
-
|
|
33
|
+
type UnreadableRequest = {
|
|
32
34
|
readonly ok: false;
|
|
33
35
|
readonly response: AvProtocolResponse;
|
|
34
36
|
readonly requestId: string;
|
|
@@ -43,3 +45,4 @@ export declare function readRequest(received: unknown): ReadRequest | Unreadable
|
|
|
43
45
|
* `undefined` when it is not one.
|
|
44
46
|
*/
|
|
45
47
|
export declare function operationRouteSegments(path: string): OperationRouteSegments | undefined;
|
|
48
|
+
export {};
|
|
@@ -3,6 +3,7 @@ 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";
|
|
6
7
|
export const CONTRACT_ROUTE = "/_contract";
|
|
7
8
|
export const POST_ONLY = Object.freeze(["POST"]);
|
|
8
9
|
export const GET_ONLY = Object.freeze(["GET"]);
|
|
@@ -1,5 +1,5 @@
|
|
|
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
4
|
import { operationFailure, } from "../runtime/operation-response.js";
|
|
5
5
|
import { httpStatus } from "./http-status.table.js";
|
|
@@ -161,7 +161,7 @@ function scalarWireText(value) {
|
|
|
161
161
|
}
|
|
162
162
|
return JSON.stringify(wire);
|
|
163
163
|
}
|
|
164
|
-
if (value
|
|
164
|
+
if (isAvDecimal(value)) {
|
|
165
165
|
return JSON.stringify(value.toString());
|
|
166
166
|
}
|
|
167
167
|
if (value instanceof Uint8Array) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AvRequestProtocol } from "../runtime/operation-request.js";
|
|
2
2
|
/** `AvProtocol.headers` — the header names the protocol owns, as passive data. */
|
|
3
3
|
export declare const headers: Readonly<{
|
|
4
4
|
readonly protocolVersion: "Aventara-Protocol-Version";
|
|
@@ -22,11 +22,11 @@ export declare function normalizeHeaders(received: ReceivedHeaders): Readonly<Re
|
|
|
22
22
|
*/
|
|
23
23
|
export declare function headerValue(normalized: Readonly<Record<string, string>>, name: string): string | undefined;
|
|
24
24
|
/**
|
|
25
|
-
* The identity headers as the `
|
|
25
|
+
* The identity headers as the `AvRequestProtocol` core checks, or `undefined`
|
|
26
26
|
* when either is ABSENT — a request without them is malformed: it does not say which
|
|
27
27
|
* protocol and ClientContract it speaks, so there is nothing to compare.
|
|
28
28
|
*/
|
|
29
|
-
export declare function protocolIdentityOf(normalized: Readonly<Record<string, string>>):
|
|
29
|
+
export declare function protocolIdentityOf(normalized: Readonly<Record<string, string>>): AvRequestProtocol | undefined;
|
|
30
30
|
/**
|
|
31
31
|
* The identity headers a request did not send, in the order the framework sends them —
|
|
32
32
|
* what the `A2000` answering it names. Empty exactly when {@link protocolIdentityOf}
|
|
@@ -17,11 +17,16 @@ export type SurfaceRoute = ({
|
|
|
17
17
|
readonly kind: "transactions";
|
|
18
18
|
readonly method: "POST";
|
|
19
19
|
readonly path: "/_transactions";
|
|
20
|
+
} | {
|
|
21
|
+
readonly kind: "can";
|
|
22
|
+
readonly method: "POST";
|
|
23
|
+
readonly path: "/_access/can";
|
|
20
24
|
};
|
|
21
25
|
/**
|
|
22
26
|
* The route list of one ClientContract: every route a host mounts, from one list,
|
|
23
27
|
* deep-frozen — exactly the advertised operation triples in the Contract's own key
|
|
24
28
|
* order, then `GET /_contract`, then `POST /_transactions` when, and only when,
|
|
25
|
-
* `transactions === "interactive"
|
|
29
|
+
* `transactions === "interactive"`, then `POST /_access/can` when, and only when,
|
|
30
|
+
* the Contract has its `access` section.
|
|
26
31
|
*/
|
|
27
32
|
export declare function surfaceOf(client: AvContractClient): readonly SurfaceRoute[];
|
|
@@ -37,5 +37,12 @@ export function surfaceOf(client) {
|
|
|
37
37
|
path: "/_transactions",
|
|
38
38
|
}));
|
|
39
39
|
}
|
|
40
|
+
if (client.access !== undefined) {
|
|
41
|
+
routes.push(Object.freeze({
|
|
42
|
+
kind: "can",
|
|
43
|
+
method: "POST",
|
|
44
|
+
path: "/_access/can",
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
40
47
|
return Object.freeze(routes);
|
|
41
48
|
}
|
|
@@ -17,7 +17,8 @@ export type AvProtocolBinding = {
|
|
|
17
17
|
* tagged by `kind`: one `POST` `operation` route per `(resource, family, variant)`
|
|
18
18
|
* it advertises and no other, then the `contract` route `GET /_contract`
|
|
19
19
|
* (always), then the `transactions` route `POST /_transactions` exactly when its
|
|
20
|
-
* `transactions` is `"interactive"
|
|
20
|
+
* `transactions` is `"interactive"`, then the `can` route `POST /_access/can`
|
|
21
|
+
* exactly when it has its `access` section. Each path is relative to
|
|
21
22
|
* `framework.api`. Read once at bind time: every call answers the same
|
|
22
23
|
* deep-frozen list, which is passive data a host may serialize.
|
|
23
24
|
*/
|
|
@@ -88,6 +89,20 @@ export type AvProtocolBinding = {
|
|
|
88
89
|
/** Seeds the plan's one `ctx.$state`, as for `handleOperation`. */
|
|
89
90
|
readonly state?: () => AvState | Promise<AvState>;
|
|
90
91
|
}) => Promise<AvProtocolResponse>;
|
|
92
|
+
/**
|
|
93
|
+
* The `POST /_access/can` shortcut: the request decoded, its `ctx.$state`
|
|
94
|
+
* seeded through `options.state`, its `{ questions }` answered by the bound
|
|
95
|
+
* Framework's policy engine under the principal `ctx.$state.me`, and the answer
|
|
96
|
+
* encoded: `200 A1000` with one boolean per question, in order. It only shapes
|
|
97
|
+
* a UI, so it refuses malformed input only, never `403`. Absent (`404 A2002`)
|
|
98
|
+
* unless the bound Contract has its `access` section, which it has exactly when
|
|
99
|
+
* the framework's `access` option is configured. Total over any value, as
|
|
100
|
+
* `handleOperation` is.
|
|
101
|
+
*/
|
|
102
|
+
readonly handleCan: (request: AvProtocolRequest, options?: {
|
|
103
|
+
/** Seeds the request's `ctx.$state`, as for `handleOperation`. */
|
|
104
|
+
readonly state?: () => AvState | Promise<AvState>;
|
|
105
|
+
}) => Promise<AvProtocolResponse>;
|
|
91
106
|
/**
|
|
92
107
|
* The `GET /_contract` responder: the bound ClientContract's JCS-canonical bytes,
|
|
93
108
|
* `ETag` its quoted hash, `Cache-Control: no-cache`, and `304` with no body when
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { accessQuestionsOf } from "../policy/access-question.registry.js";
|
|
1
2
|
import { diagnosticsSinkOf } from "../runtime/diagnostics-reporter.js";
|
|
2
3
|
import { ownedExecutionOf } from "../runtime/owned-execution.registry.js";
|
|
3
4
|
import { answerAbsentRequest } from "./absent-route.responder.js";
|
|
4
5
|
import { contractDocumentOf, encodeContractRequest, } from "./contract-document.responder.js";
|
|
5
6
|
import { decodeOperationRequest, decodeTransactionRequest, } from "./http-request.decoder.js";
|
|
6
7
|
import { encodeOperationResponse, encodeTransactionResponse, } from "./http-response.encoder.js";
|
|
7
|
-
import { handleOperationRequest, handleTransactionRequest, operationUnencodableReport, planUnencodableReport, } from "./protocol.handler.js";
|
|
8
|
+
import { handleCanRequest, handleOperationRequest, handleTransactionRequest, operationUnencodableReport, planUnencodableReport, } from "./protocol.handler.js";
|
|
8
9
|
import { transportFailure } from "./protocol-failure.js";
|
|
9
10
|
import { surfaceOf } from "./protocol-surface.js";
|
|
10
11
|
export function bind(framework, options) {
|
|
@@ -21,6 +22,7 @@ export function bind(framework, options) {
|
|
|
21
22
|
executeTransaction: (request) => framework.executeTransaction(request),
|
|
22
23
|
owned: ownedExecutionOf(framework),
|
|
23
24
|
sink,
|
|
25
|
+
can: accessQuestionsOf(framework),
|
|
24
26
|
};
|
|
25
27
|
return Object.freeze({
|
|
26
28
|
surface: () => surface,
|
|
@@ -33,6 +35,7 @@ export function bind(framework, options) {
|
|
|
33
35
|
failure: transportFailure,
|
|
34
36
|
handleOperation: (request, options) => handleOperationRequest(handler, request, options),
|
|
35
37
|
handleTransaction: (request, options) => handleTransactionRequest(handler, request, options),
|
|
38
|
+
handleCan: (request, options) => handleCanRequest(handler, request, options),
|
|
36
39
|
encodeContract: (request) => encodeContractRequest(document, request),
|
|
37
40
|
answerAbsent: (request) => answerAbsentRequest(contracts, request, sink, origin),
|
|
38
41
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AvContracts } from "../compiler/contract.compiler.js";
|
|
2
2
|
import type { RemoteRequestOrigin } from "../config/config-layer.js";
|
|
3
3
|
import type { AvFramework } from "../framework/framework.js";
|
|
4
|
+
import type { AccessQuestionsAnswerer } from "../policy/access-question.runtime.js";
|
|
4
5
|
import { type AvDiagnosticsSink } from "../runtime/diagnostics-reporter.js";
|
|
5
6
|
import type { RemoteOperationRequest } from "../runtime/operation-request.js";
|
|
6
7
|
import type { OwnedExecution } from "../runtime/owned-execution.registry.js";
|
|
@@ -13,7 +14,7 @@ import { type AvProtocolResponse, type UnencodableReport } from "./http-response
|
|
|
13
14
|
* decoder parsed without copying it again (absent for anything but a
|
|
14
15
|
* constructed Framework) — and its configured diagnostics sink.
|
|
15
16
|
*/
|
|
16
|
-
|
|
17
|
+
type HandlerContext = {
|
|
17
18
|
readonly contracts: AvContracts;
|
|
18
19
|
/** The origin every request the binding decodes runs under. */
|
|
19
20
|
readonly origin: RemoteRequestOrigin;
|
|
@@ -21,6 +22,8 @@ export type HandlerContext = {
|
|
|
21
22
|
readonly executeTransaction: AvFramework["executeTransaction"];
|
|
22
23
|
readonly owned: OwnedExecution | undefined;
|
|
23
24
|
readonly sink: AvDiagnosticsSink | undefined;
|
|
25
|
+
/** The Framework's `can` answerer: absent for one without `access`, or anything `createFramework` did not return. */
|
|
26
|
+
readonly can: AccessQuestionsAnswerer | undefined;
|
|
24
27
|
};
|
|
25
28
|
/** What a host passes beside one protocol request. */
|
|
26
29
|
export type ProtocolCallOptions = {
|
|
@@ -62,3 +65,11 @@ export declare function handleOperationRequest(context: HandlerContext, request:
|
|
|
62
65
|
* planUnencodableReport}.
|
|
63
66
|
*/
|
|
64
67
|
export declare function handleTransactionRequest(context: HandlerContext, request: AvProtocolRequest, options?: ProtocolCallOptions): Promise<AvProtocolResponse>;
|
|
68
|
+
/**
|
|
69
|
+
* `protocol.handleCan(request)`: the `/_access/can` request decoded, its state
|
|
70
|
+
* seeded, its questions answered by the bound Framework, and the answer encoded —
|
|
71
|
+
* `200 A1000` with one boolean per question, in order, or the refusal. Total over
|
|
72
|
+
* any value, as {@link handleOperationRequest} is.
|
|
73
|
+
*/
|
|
74
|
+
export declare function handleCanRequest(context: HandlerContext, request: AvProtocolRequest, options?: ProtocolCallOptions): Promise<AvProtocolResponse>;
|
|
75
|
+
export {};
|
|
@@ -1,16 +1,54 @@
|
|
|
1
|
+
import { copyAtDoor } from "../runtime/caller-data.door.js";
|
|
1
2
|
import { createDiagnosticsReporter, createReporter, } from "../runtime/diagnostics-reporter.js";
|
|
2
3
|
import { sanitizeOperationFailure } from "../runtime/error-boundary.js";
|
|
3
|
-
import {
|
|
4
|
+
import { internalFailure, } from "../runtime/operation-response.js";
|
|
5
|
+
import { capturePlanAtCall } from "../transactions/transaction-plan-validator.js";
|
|
6
|
+
import { decodeCanRequest, decodeOperationRequest, decodeTransactionRequest, isParsedByDecoder, } from "./http-request.decoder.js";
|
|
4
7
|
import { encodeOperationResponse, encodeTransactionResponse, } from "./http-response.encoder.js";
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
: context.execute;
|
|
8
|
+
function admitOperation(context, request) {
|
|
9
|
+
const owned = context.owned;
|
|
10
|
+
if (isParsedByDecoder(request.arguments)) {
|
|
11
|
+
return { request, run: owned?.execute ?? context.execute };
|
|
12
|
+
}
|
|
13
|
+
const copy = copyAtDoor(request.arguments);
|
|
14
|
+
if (owned === undefined) {
|
|
15
|
+
return {
|
|
16
|
+
request: copy.ok ? { ...request, arguments: copy.value } : request,
|
|
17
|
+
run: context.execute,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (copy.ok) {
|
|
21
|
+
return {
|
|
22
|
+
request: { ...request, arguments: copy.value },
|
|
23
|
+
run: (admitted) => owned.execute(admitted),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
request: { ...request, arguments: {} },
|
|
28
|
+
run: (admitted) => owned.execute(admitted, copy.error),
|
|
29
|
+
};
|
|
9
30
|
}
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
31
|
+
function admitTransaction(context, request) {
|
|
32
|
+
const owned = context.owned;
|
|
33
|
+
if (isParsedByDecoder(request.plan)) {
|
|
34
|
+
return {
|
|
35
|
+
request,
|
|
36
|
+
run: owned?.executeTransaction ?? context.executeTransaction,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const captured = capturePlanAtCall(request.plan);
|
|
40
|
+
if (owned === undefined) {
|
|
41
|
+
return {
|
|
42
|
+
request: captured.refused.size === 0
|
|
43
|
+
? { ...request, plan: captured.plan }
|
|
44
|
+
: request,
|
|
45
|
+
run: context.executeTransaction,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
request: { ...request, plan: captured.plan },
|
|
50
|
+
run: (admitted) => owned.executeTransaction(admitted, captured.refused.size === 0 ? undefined : captured.refused),
|
|
51
|
+
};
|
|
14
52
|
}
|
|
15
53
|
async function seededState(options, report, view) {
|
|
16
54
|
if (options?.state === undefined) {
|
|
@@ -48,11 +86,12 @@ export async function handleOperationRequest(context, request, options) {
|
|
|
48
86
|
if (!decoded.ok) {
|
|
49
87
|
return decoded.response;
|
|
50
88
|
}
|
|
51
|
-
const
|
|
89
|
+
const admitted = admitOperation(context, decoded.request);
|
|
90
|
+
const seeded = await seededState(options, createDiagnosticsReporter(context.sink, admitted.request), { path: ["arguments"], arguments: admitted.request.arguments });
|
|
52
91
|
const response = seeded.ok
|
|
53
|
-
? await
|
|
54
|
-
?
|
|
55
|
-
: { ...
|
|
92
|
+
? await admitted.run(seeded.state === undefined
|
|
93
|
+
? admitted.request
|
|
94
|
+
: { ...admitted.request, state: seeded.state })
|
|
56
95
|
: seeded.response;
|
|
57
96
|
return encodeOperationResponse(response, decoded.requestId, operationUnencodableReport(context.sink, decoded.request));
|
|
58
97
|
}
|
|
@@ -61,15 +100,45 @@ export async function handleTransactionRequest(context, request, options) {
|
|
|
61
100
|
if (!decoded.ok) {
|
|
62
101
|
return decoded.response;
|
|
63
102
|
}
|
|
103
|
+
const admitted = admitTransaction(context, decoded.request);
|
|
64
104
|
const seeded = await seededState(options, createReporter(context.sink, {
|
|
65
105
|
kind: "transaction",
|
|
66
106
|
origin: context.origin,
|
|
67
107
|
requestId: decoded.requestId,
|
|
68
|
-
}), { path: ["plan"], arguments:
|
|
108
|
+
}), { path: ["plan"], arguments: admitted.request.plan });
|
|
69
109
|
const response = seeded.ok
|
|
70
|
-
? await
|
|
71
|
-
?
|
|
72
|
-
: { ...
|
|
110
|
+
? await admitted.run(seeded.state === undefined
|
|
111
|
+
? admitted.request
|
|
112
|
+
: { ...admitted.request, state: seeded.state })
|
|
73
113
|
: seeded.response;
|
|
74
114
|
return encodeTransactionResponse(response, decoded.requestId, planUnencodableReport(context.sink, decoded.requestId, context.origin));
|
|
75
115
|
}
|
|
116
|
+
export async function handleCanRequest(context, request, options) {
|
|
117
|
+
const decoded = decodeCanRequest(context.contracts, request, context.origin);
|
|
118
|
+
if (!decoded.ok) {
|
|
119
|
+
return decoded.response;
|
|
120
|
+
}
|
|
121
|
+
const { requestId, body } = decoded.request;
|
|
122
|
+
const report = createReporter(context.sink, {
|
|
123
|
+
kind: "can",
|
|
124
|
+
origin: "client",
|
|
125
|
+
requestId,
|
|
126
|
+
});
|
|
127
|
+
if (context.can === undefined) {
|
|
128
|
+
report(new Error("The bound Framework has no answerer for /_access/can."), "A3000");
|
|
129
|
+
return encodeOperationResponse(internalFailure(), requestId);
|
|
130
|
+
}
|
|
131
|
+
const seeded = await seededState(options, report, {
|
|
132
|
+
path: ["questions"],
|
|
133
|
+
arguments: body,
|
|
134
|
+
});
|
|
135
|
+
const response = seeded.ok
|
|
136
|
+
? await context.can({
|
|
137
|
+
origin: context.origin,
|
|
138
|
+
requestId,
|
|
139
|
+
...(seeded.state === undefined ? {} : { state: seeded.state }),
|
|
140
|
+
body,
|
|
141
|
+
})
|
|
142
|
+
: seeded.response;
|
|
143
|
+
return encodeOperationResponse(response, requestId);
|
|
144
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Why a caller value could not be copied. */
|
|
2
|
-
|
|
2
|
+
type CallerDataFailureKind = "unreadable-value" | "non-plain-value";
|
|
3
3
|
/** A data location inside the copied value, from its root. */
|
|
4
4
|
export type CallerDataPath = readonly (string | number)[];
|
|
5
5
|
/**
|
|
@@ -41,6 +41,22 @@ export type CallerDataPolicy = {
|
|
|
41
41
|
readonly keep?: CallerDataKeep;
|
|
42
42
|
readonly mirror?: CallerDataMirror;
|
|
43
43
|
};
|
|
44
|
+
/** The members a structural mirror copies by value rather than mirroring. */
|
|
45
|
+
type MirrorMembers = {
|
|
46
|
+
/** The policy a member at `path` (from the mirror's root) is copied by, or `undefined`. */
|
|
47
|
+
readonly copyAt: (path: CallerDataPath) => CallerDataPolicy | undefined;
|
|
48
|
+
/** Receives a member whose copy failed; the mirror holds `undefined` for it. */
|
|
49
|
+
readonly refused: (path: CallerDataPath, error: AvCallerDataError) => void;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Mirrors `value` by its descriptors, as a `$ref` control object is mirrored (no
|
|
53
|
+
* getter runs, an accessor stays a tripwire), except the members `members.copyAt`
|
|
54
|
+
* names by their path: each is copied by value under the policy it returns, and one
|
|
55
|
+
* whose copy fails is reported to `members.refused` and held as `undefined`.
|
|
56
|
+
*
|
|
57
|
+
* @throws {@link AvCallerDataError} at `[]` when `value` itself cannot be reflected.
|
|
58
|
+
*/
|
|
59
|
+
export declare function mirrorCallerData(value: object, members: MirrorMembers): unknown;
|
|
44
60
|
/**
|
|
45
61
|
* Places a mirror tripwire's failure in the value the door copied: its path from the
|
|
46
62
|
* copy's root, where `error.path` started from the mirror. A failure that is not a
|
|
@@ -55,5 +71,4 @@ export declare function locateCallerDataError(error: AvCallerDataError, copy: un
|
|
|
55
71
|
* naming its path from `value`.
|
|
56
72
|
*/
|
|
57
73
|
export declare function copyCallerData(value: unknown, policy?: CallerDataPolicy): unknown;
|
|
58
|
-
|
|
59
|
-
export declare function callerDataFailureMessage(kind: CallerDataFailureKind): string;
|
|
74
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AvDecimal } from "./decimal.js";
|
|
1
|
+
import { AvDecimal, decimalDigitsOf, isAvDecimal } from "./decimal.js";
|
|
2
2
|
const FAILURE_MESSAGES = {
|
|
3
3
|
"unreadable-value": "Value could not be read.",
|
|
4
4
|
"non-plain-value": "Value must be plain data.",
|
|
@@ -19,7 +19,6 @@ const NO_POLICY = {};
|
|
|
19
19
|
const OBJECT_PROTOTYPE = Object.prototype;
|
|
20
20
|
const DATE_PROTOTYPE = Date.prototype;
|
|
21
21
|
const dateValueOf = Date.prototype.getTime;
|
|
22
|
-
const decimalValueOf = AvDecimal.prototype.toString;
|
|
23
22
|
const FAST_WALK_DEPTH = 256;
|
|
24
23
|
const SLOW_WALK = Symbol("slow walk");
|
|
25
24
|
class FastWalkFailure {
|
|
@@ -33,8 +32,8 @@ function copyValueType(value, prototype) {
|
|
|
33
32
|
if (prototype === DATE_PROTOTYPE || value instanceof Date) {
|
|
34
33
|
return new Date(dateValueOf.call(value));
|
|
35
34
|
}
|
|
36
|
-
if (value
|
|
37
|
-
return new AvDecimal(
|
|
35
|
+
if (isAvDecimal(value)) {
|
|
36
|
+
return new AvDecimal(decimalDigitsOf(value));
|
|
38
37
|
}
|
|
39
38
|
if (value instanceof Uint8Array) {
|
|
40
39
|
return new Uint8Array(value);
|
|
@@ -268,7 +267,7 @@ function pathSegment(array, key) {
|
|
|
268
267
|
}
|
|
269
268
|
return key;
|
|
270
269
|
}
|
|
271
|
-
function mirrorControlData(value) {
|
|
270
|
+
function mirrorControlData(value, members) {
|
|
272
271
|
const shape = reflectNode(value);
|
|
273
272
|
if (shape === undefined) {
|
|
274
273
|
throw new AvCallerDataError("unreadable-value", []);
|
|
@@ -375,6 +374,20 @@ function mirrorControlData(value) {
|
|
|
375
374
|
continue;
|
|
376
375
|
}
|
|
377
376
|
const memberLink = childLink(link, pathSegment(shape.array, key));
|
|
377
|
+
const byValue = members?.copyAt(pathOf(memberLink));
|
|
378
|
+
if (byValue !== undefined) {
|
|
379
|
+
try {
|
|
380
|
+
store(copyCallerData(member, byValue));
|
|
381
|
+
}
|
|
382
|
+
catch (error) {
|
|
383
|
+
if (!(error instanceof AvCallerDataError)) {
|
|
384
|
+
throw error;
|
|
385
|
+
}
|
|
386
|
+
members?.refused(pathOf(memberLink), error);
|
|
387
|
+
store(undefined);
|
|
388
|
+
}
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
378
391
|
const memberShape = reflectNode(member);
|
|
379
392
|
if (memberShape === undefined) {
|
|
380
393
|
store(UNREADABLE);
|
|
@@ -408,6 +421,9 @@ function mirrorControlData(value) {
|
|
|
408
421
|
}
|
|
409
422
|
return root;
|
|
410
423
|
}
|
|
424
|
+
export function mirrorCallerData(value, members) {
|
|
425
|
+
return mirrorControlData(value, members);
|
|
426
|
+
}
|
|
411
427
|
export function locateCallerDataError(error, copy) {
|
|
412
428
|
const within = error.within;
|
|
413
429
|
if (within === undefined) {
|
|
@@ -465,6 +481,3 @@ export function copyCallerData(value, policy = NO_POLICY) {
|
|
|
465
481
|
}
|
|
466
482
|
return guardNative(() => copyFast(value, 0, policy), (failure) => copySlow(value, policy, failure instanceof FastWalkFailure ? failure.at : undefined));
|
|
467
483
|
}
|
|
468
|
-
export function callerDataFailureMessage(kind) {
|
|
469
|
-
return FAILURE_MESSAGES[kind];
|
|
470
|
-
}
|
|
@@ -6,15 +6,21 @@ import type { AvMisuseEvent, MisuseReporter } from "./misuse-reporter.js";
|
|
|
6
6
|
*
|
|
7
7
|
* - `"caller"`: a server-side caller's own objects — copied at the door.
|
|
8
8
|
* - `"owned"`: data no caller holds a reference to — a body the protocol decoder
|
|
9
|
-
* parsed with `JSON.parse` for this request alone,
|
|
10
|
-
*
|
|
9
|
+
* parsed with `JSON.parse` for this request alone, a host's parsed body the
|
|
10
|
+
* protocol's shortcut copied at the call, or a plan the typed runner assembled
|
|
11
|
+
* from copies its builders took. It is never copied again.
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
13
|
+
* - `{ refused }`: a body the protocol's shortcut copied at the call, whose copy
|
|
14
|
+
* failed — answered at the door as `"caller"` would answer it, never read again.
|
|
15
|
+
*
|
|
16
|
+
* Only core's own modules choose anything but `"caller"`: the public
|
|
17
|
+
* `framework.execute` and `executeTransaction` always pass `"caller"`.
|
|
14
18
|
*/
|
|
15
|
-
export type ArgumentsSource = "caller" | "owned"
|
|
19
|
+
export type ArgumentsSource = "caller" | "owned" | {
|
|
20
|
+
readonly refused: AvCallerDataError;
|
|
21
|
+
};
|
|
16
22
|
/** The operation identity a misuse event may name, as far as it could be read. */
|
|
17
|
-
|
|
23
|
+
type MisuseIdentity = Omit<AvMisuseEvent, "kind" | "path">;
|
|
18
24
|
/**
|
|
19
25
|
* The identity of a request the framework holds a copy of, keeping only what is
|
|
20
26
|
* identity: an origin, a Resource name and a standard operation, each present only
|
|
@@ -54,3 +60,4 @@ export declare function copyAtDoor(value: unknown, policy?: CallerDataPolicy): C
|
|
|
54
60
|
* plan validator inspects and copies step by step.
|
|
55
61
|
*/
|
|
56
62
|
export declare function copyEnvelopeAtDoor(request: unknown, members: readonly string[]): CallerDataCopy;
|
|
63
|
+
export {};
|
|
@@ -21,6 +21,11 @@ export type PlannedReadOperation = {
|
|
|
21
21
|
readonly projection: ReadProjectionPlan | undefined;
|
|
22
22
|
readonly materialize: boolean;
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* The fields a level returns when it states no projection: every scalar of the
|
|
26
|
+
* active Contract whose `select` is `true` and that is not governed.
|
|
27
|
+
*/
|
|
28
|
+
export declare function defaultProjectionFields(active: AvContract, resourceName: string): readonly string[];
|
|
24
29
|
/**
|
|
25
30
|
* Clone the caller projection into the internal Adapter projection: the read
|
|
26
31
|
* set the Adapter is asked for, always explicit for a projecting variant, plus
|
|
@@ -33,5 +38,5 @@ export declare function planReadOperation(core: AvContractCore, model: AvAdapter
|
|
|
33
38
|
* Materialize computed scalar reads and remove internal dependency fields,
|
|
34
39
|
* against `active` — the Contract `planReadOperation` was given as `active`.
|
|
35
40
|
*/
|
|
36
|
-
export declare function materializeReadOperation(active: AvContract, compute: ResolvedComputeConfig | undefined,
|
|
41
|
+
export declare function materializeReadOperation(active: AvContract, compute: ResolvedComputeConfig | undefined, _request: OperationExecutionRequest, plan: PlannedReadOperation, value: unknown, contextFactory: ContextFactory): Promise<unknown>;
|
|
37
42
|
export {};
|