@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
|
@@ -13,10 +13,11 @@ export declare function uniqueMissFailure(operation: AvOperationIdentity, data:
|
|
|
13
13
|
*/
|
|
14
14
|
export declare function mapOperationOutcome(operation: AvOperationIdentity, data: unknown): AvOperationResponse;
|
|
15
15
|
/** The A-codes a set of Framework Validation Layer issues can roll up to. */
|
|
16
|
-
|
|
16
|
+
type ValidationOutcomeCode = "A2001" | "A2002" | "A2004" | "A2007" | "A2009";
|
|
17
17
|
/** The framework's top-level `cause.message` for each validation outcome code. */
|
|
18
18
|
export declare const VALIDATION_OUTCOME_MESSAGES: {
|
|
19
19
|
readonly [K in ValidationOutcomeCode]: string;
|
|
20
20
|
};
|
|
21
21
|
/** Maps framework validation issues to their stable failure envelope. */
|
|
22
22
|
export declare function mapValidationOutcome(issues: readonly AvValidationIssue[]): AvOperationFailureResponse;
|
|
23
|
+
export {};
|
|
@@ -2,7 +2,7 @@ import type { AvContract } from "../contracts/contract.js";
|
|
|
2
2
|
import type { AvOperationIdentity } from "../operations/operation-identity.js";
|
|
3
3
|
import type { AvValidationIssue } from "../operations/validation-code.js";
|
|
4
4
|
import type { ReadProjectionPlan } from "./computed-read-runtime.js";
|
|
5
|
-
|
|
5
|
+
type OutputValidationResult = {
|
|
6
6
|
readonly ok: true;
|
|
7
7
|
} | {
|
|
8
8
|
readonly ok: false;
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
|
|
2
2
|
import { advertisedReducers, } from "../contracts/field.js";
|
|
3
|
+
import { isRecord } from "./record.guard.js";
|
|
3
4
|
import { normalizeScalarFieldValue } from "./scalar-runtime.js";
|
|
4
5
|
function issue(message, path = ["data"]) {
|
|
5
6
|
return { ok: false, issues: [{ path, code: "V1001", message }] };
|
|
6
7
|
}
|
|
7
|
-
function isRecord(value) {
|
|
8
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
9
|
-
}
|
|
10
8
|
function validatesRecordOrNull(value) {
|
|
11
9
|
return value === null || isRecord(value);
|
|
12
10
|
}
|
|
@@ -1,11 +1,41 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RemoteRequestOrigin } from "../config/config-layer.js";
|
|
2
|
+
import type { PolicyCaller } from "../policy/policy-request.js";
|
|
3
|
+
import type { AvAgentTransactionRequest, AvClientTransactionRequest } from "../transactions/transaction-request.js";
|
|
2
4
|
import type { AvTransactionResponse } from "../transactions/transaction-response.js";
|
|
5
|
+
import type { AvCallerDataError } from "./caller-data.copier.js";
|
|
3
6
|
import type { RemoteOperationRequest } from "./operation-request.js";
|
|
4
7
|
import type { AvOperationResponse } from "./operation-response.js";
|
|
5
|
-
|
|
8
|
+
import type { AvState } from "./request-state.js";
|
|
9
|
+
/**
|
|
10
|
+
* The entries that run a request the protocol decoded itself, uncopied, and
|
|
11
|
+
* what an Operation Set reads off the Framework besides.
|
|
12
|
+
*/
|
|
6
13
|
export type OwnedExecution = {
|
|
7
|
-
|
|
8
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Runs `request` uncopied; with `refused`, its arguments are a host's parsed body
|
|
16
|
+
* whose copy at the call failed, answered as the door answers that failure.
|
|
17
|
+
* `member` is an Operation Set entry's: the principal derived once for the
|
|
18
|
+
* set, and the entry's key, which its diagnostics name.
|
|
19
|
+
*/
|
|
20
|
+
readonly execute: (request: RemoteOperationRequest, refused?: AvCallerDataError, member?: {
|
|
21
|
+
readonly caller?: PolicyCaller;
|
|
22
|
+
readonly key?: string;
|
|
23
|
+
}) => Promise<AvOperationResponse>;
|
|
24
|
+
/**
|
|
25
|
+
* The principal a remote request with this state runs as, derived once, or
|
|
26
|
+
* `undefined` when no policy checks it. Throws or rejects as
|
|
27
|
+
* `policy.principal` does.
|
|
28
|
+
*/
|
|
29
|
+
readonly caller: (request: {
|
|
30
|
+
readonly origin: RemoteRequestOrigin;
|
|
31
|
+
readonly state: AvState;
|
|
32
|
+
}) => PolicyCaller | undefined | Promise<PolicyCaller>;
|
|
33
|
+
/**
|
|
34
|
+
* Runs `request` uncopied; with `refused`, its plan is a host's parsed plan taken
|
|
35
|
+
* at the call, and these steps' arguments could not be copied there: each is
|
|
36
|
+
* answered at its turn as the door answers that failure.
|
|
37
|
+
*/
|
|
38
|
+
readonly executeTransaction: (request: AvClientTransactionRequest | AvAgentTransactionRequest, refused?: ReadonlyMap<number, AvCallerDataError>) => Promise<AvTransactionResponse>;
|
|
9
39
|
};
|
|
10
40
|
/** Records `framework`'s owned entries; called once, at construction. */
|
|
11
41
|
export declare function recordOwnedExecution(framework: object, execution: OwnedExecution): void;
|
|
@@ -24,6 +24,8 @@ import type { AvOperationFailureResponse } from "./operation-response.js";
|
|
|
24
24
|
*/
|
|
25
25
|
/** The one text every `A3004` carries on the wire. */
|
|
26
26
|
export declare const PIPE_OUTPUT_FAILURE_MESSAGE = "A server pipeline produced invalid arguments.";
|
|
27
|
+
/** The Contract a stage's output is held to: Core's Resources plus what `active` adds. */
|
|
28
|
+
export declare function serverContractFor(core: AvContractCore, active: AvContract): AvContract;
|
|
27
29
|
/** The error the diagnostics channel receives for a refused pipe output. */
|
|
28
30
|
export declare class AvPipeOutputError extends Error {
|
|
29
31
|
readonly issues: readonly AvValidationIssue[];
|
|
@@ -61,3 +63,11 @@ export declare function refuseStageOutput(contracts: {
|
|
|
61
63
|
}, request: AvOperationIdentity & {
|
|
62
64
|
readonly resource: string;
|
|
63
65
|
}, args: unknown, subject: string, options?: OperationValidationOptions): RefusedStageOutput | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* The `A3004` for a stage output the server's rules raised `issues` against
|
|
68
|
+
* (paths under `["arguments", …]`), the first named in the diagnostic;
|
|
69
|
+
* `undefined` when there are none.
|
|
70
|
+
*/
|
|
71
|
+
export declare function refusedStageOutput(request: AvOperationIdentity & {
|
|
72
|
+
readonly resource: string;
|
|
73
|
+
}, issues: readonly AvValidationIssue[], subject: string): RefusedStageOutput | undefined;
|
|
@@ -19,7 +19,7 @@ function serverContract(core, active) {
|
|
|
19
19
|
return { ...core, resources };
|
|
20
20
|
}
|
|
21
21
|
const SERVER_VIEWS = new WeakMap();
|
|
22
|
-
function serverContractFor(core, active) {
|
|
22
|
+
export function serverContractFor(core, active) {
|
|
23
23
|
let view = SERVER_VIEWS.get(active);
|
|
24
24
|
if (view === undefined) {
|
|
25
25
|
view = serverContract(core, active);
|
|
@@ -64,7 +64,9 @@ export function refusePipeOutput(contracts, request, args, pipe, index, options)
|
|
|
64
64
|
return refuseStageOutput(contracts, request, args, `Pipe ${pipeLabel(pipe, index)}`, options);
|
|
65
65
|
}
|
|
66
66
|
export function refuseStageOutput(contracts, request, args, subject, options) {
|
|
67
|
-
|
|
67
|
+
return refusedStageOutput(request, serverIssues(serverContractFor(contracts.core, contracts.active), request, args, options), subject);
|
|
68
|
+
}
|
|
69
|
+
export function refusedStageOutput(request, issues, subject) {
|
|
68
70
|
const [first] = issues;
|
|
69
71
|
if (first === undefined) {
|
|
70
72
|
return undefined;
|
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
import type { AvAdapterModel } from "../adapters/adapter-model.js";
|
|
2
2
|
import type { AvAdapterSqlValue } from "../adapters/adapter-sql-statement.js";
|
|
3
|
+
import type { AvPreComputeLift } from "../config/computed-fields.js";
|
|
3
4
|
import type { AvRequestOrigin } from "../config/config-layer.js";
|
|
4
5
|
import type { AvConfigResourceKey } from "../config/framework-field-definition.js";
|
|
5
6
|
import type { AvContract } from "../contracts/contract.js";
|
|
6
7
|
import type { AvApplicationScalarForms } from "../contracts/scalar-value-type.js";
|
|
7
|
-
import type { AvContractApplicationView } from "../framework/contract-view.js";
|
|
8
|
+
import type { AvContractApplicationView, RequirementsLessComputed } from "../framework/contract-view.js";
|
|
8
9
|
import type { AvContextOperations } from "../framework/operation-facade.js";
|
|
9
10
|
import type { AvOperationArgumentsFor, AvResourceKey } from "../operations/operation-arguments.js";
|
|
10
11
|
import type { AvOperationFamily, AvOperationIdentity } from "../operations/operation-identity.js";
|
|
11
12
|
import type { AvTransactionReference } from "../transactions/transaction-reference.js";
|
|
12
13
|
import type { AvError } from "./framework-error.js";
|
|
13
|
-
import type { AvDeepReadonly, AvDeepReadonlyLeaf } from "./readonly-value.js";
|
|
14
|
+
import type { ArrayForm, AvDeepReadonly, AvDeepReadonlyLeaf } from "./readonly-value.js";
|
|
14
15
|
import type { AvState } from "./request-state.js";
|
|
15
16
|
/**
|
|
16
17
|
* What a pipeline is told about the HTTP request a client-origin operation arrived on.
|
|
17
18
|
*/
|
|
18
19
|
export type AvTransportContext = {
|
|
19
|
-
|
|
20
|
+
/**
|
|
21
|
+
* `"POST"`, or `"GET"` for a read of a Resource with `cache` (a browser's
|
|
22
|
+
* prefetch or a CDN's refetch is a GET too).
|
|
23
|
+
*/
|
|
24
|
+
readonly method: "POST" | "GET";
|
|
20
25
|
readonly headers: Readonly<Record<string, string>>;
|
|
21
26
|
};
|
|
22
27
|
/** What a pipeline ctx states about the request, whatever the stage. */
|
|
@@ -36,24 +41,38 @@ type AvContextFacts = {
|
|
|
36
41
|
*/
|
|
37
42
|
readonly $state: AvState;
|
|
38
43
|
};
|
|
39
|
-
/**
|
|
40
|
-
* `ctx.$sql`: a developer SQL statement, written only as a tagged template —
|
|
41
|
-
* ``await ctx.$sql<Row>`insert into audit (actor) values (${actorId})` `` — run at
|
|
42
|
-
* once. Every interpolated value is bound as a parameter, never spliced into the
|
|
43
|
-
* text. It runs in the current transaction; outside one, as a plain statement,
|
|
44
|
-
* with no transaction opened around it. Resolves the rows the statement returned.
|
|
45
|
-
*/
|
|
46
|
-
export type AvContextSql = <Row = unknown>(strings: TemplateStringsArray, ...values: readonly AvAdapterSqlValue[]) => Promise<Row[]>;
|
|
47
44
|
/**
|
|
48
45
|
* The arguments a variant-level stage is told: the operation's arguments under
|
|
49
46
|
* the model's Application Contract view, in the application forms, a reference
|
|
50
47
|
* position admitting an unresolved `$ref`. `unknown` for a model whose Resource
|
|
51
48
|
* names are not literal.
|
|
52
49
|
*/
|
|
53
|
-
export type AvStageArguments<M extends AvAdapterModel, R extends string, F extends AvOperationFamily, V extends string> =
|
|
50
|
+
export type AvStageArguments<M extends AvAdapterModel, R extends string, F extends AvOperationFamily, V extends string> = StageArgumentsOf<AvContractApplicationView<M>, R, F, V>;
|
|
51
|
+
/** The arguments of operation `F`.`V` on `R` under the Contract view `C`. */
|
|
52
|
+
type StageArgumentsOf<C extends AvContract, R extends string, F extends AvOperationFamily, V extends string> = string extends R ? unknown : R extends AvResourceKey<C> ? AvOperationArgumentsFor<C, R, Extract<AvOperationIdentity, {
|
|
54
53
|
readonly family: F;
|
|
55
54
|
readonly variant: V;
|
|
56
55
|
}>, AvApplicationScalarForms, AvApplicationScalarForms> : unknown;
|
|
56
|
+
/**
|
|
57
|
+
* The arguments a variant's guards, pipes and filters are told: the operation's
|
|
58
|
+
* arguments before write compute has run, so a create need not hold a field
|
|
59
|
+
* `compute.create` fills (`Lift`, as `"<Resource>.<field>"`; `string`: any).
|
|
60
|
+
*/
|
|
61
|
+
export type AvPreComputeStageArguments<M extends AvAdapterModel, R extends string, F extends AvOperationFamily, V extends string, Lift extends string = AvPreComputeLift<M, "root">> = F extends "find" | "delete" ? AvStageArguments<M, R, F, V> : [Lift] extends [never] ? AvStageArguments<M, R, F, V> : StageArgumentsOf<PreComputeView<AvContractApplicationView<M>, Lift>, R, F, V>;
|
|
62
|
+
/** A Contract view with the create requirements `Lift` names lifted. */
|
|
63
|
+
type PreComputeView<C, Lift extends string> = Extract<{
|
|
64
|
+
readonly [P in keyof C]: P extends "resources" ? string extends Lift ? {
|
|
65
|
+
readonly [R in keyof C[P]]: Omit<C[P][R], "createRequirements">;
|
|
66
|
+
} : {
|
|
67
|
+
readonly [R in keyof C[P]]: LiftedResource<C[P][R], LiftedFieldOf<Lift, R>>;
|
|
68
|
+
} : C[P];
|
|
69
|
+
}, AvContract>;
|
|
70
|
+
/** The fields of Resource `R` that `Lift` names. */
|
|
71
|
+
type LiftedFieldOf<Lift extends string, R> = Lift extends `${R & string}.${infer Field}` ? Field : never;
|
|
72
|
+
/** One Resource with the create requirements on `Fields` lifted; itself when none. */
|
|
73
|
+
type LiftedResource<Resource, Fields> = [Fields] extends [never] ? Resource : {
|
|
74
|
+
readonly [P in keyof Resource]: P extends "createRequirements" ? RequirementsLessComputed<Exclude<Resource[P], undefined>, Fields> : Resource[P];
|
|
75
|
+
};
|
|
57
76
|
/**
|
|
58
77
|
* What a pipeline callback is told about the operation it is wrapping, and the
|
|
59
78
|
* framework's executor: `ctx.<Resource>.<family>.<variant>(args)`, `ctx.$sql` and
|
|
@@ -83,11 +102,20 @@ export type AvContext<M extends AvAdapterModel = AvAdapterModel, R extends strin
|
|
|
83
102
|
* returned them in a pipe, and the validated arguments the operation executes in
|
|
84
103
|
* an interceptor, a hook or a filter. Only a pipe changes them, by returning new
|
|
85
104
|
* ones; writing to them throws a `TypeError`. At a variant, typed as that
|
|
86
|
-
* operation's arguments ({@link AvStageArguments}), deep read-only;
|
|
87
|
-
* `
|
|
105
|
+
* operation's arguments ({@link AvStageArguments}), deep read-only; in a guard or
|
|
106
|
+
* a filter a create may lack the fields `compute.create` fills ({@link
|
|
107
|
+
* AvPreComputeStageArguments}: write compute has not run); above it, `unknown`.
|
|
88
108
|
*/
|
|
89
109
|
readonly $args: AvDeepReadonly<A>;
|
|
90
|
-
|
|
110
|
+
/**
|
|
111
|
+
* A developer SQL statement, written only as a tagged template —
|
|
112
|
+
* ``await ctx.$sql<Row>`insert into audit (actor) values (${actorId})` ``
|
|
113
|
+
* — run at once. Every interpolated value is bound as a parameter, never
|
|
114
|
+
* spliced into the text. It runs in the current transaction; outside one,
|
|
115
|
+
* as a plain statement, with no transaction opened around it. Resolves
|
|
116
|
+
* the rows the statement returned.
|
|
117
|
+
*/
|
|
118
|
+
readonly $sql: <Row = unknown>(strings: TemplateStringsArray, ...values: readonly AvAdapterSqlValue[]) => Promise<Row[]>;
|
|
91
119
|
/**
|
|
92
120
|
* Runs `work` in a transaction, `tx` being this ctx bound to it, and resolves
|
|
93
121
|
* what `work` resolved; a throw rolls it back. Inside an open transaction it
|
|
@@ -103,22 +131,22 @@ export type AvGuard<M extends AvAdapterModel = AvAdapterModel, R extends string
|
|
|
103
131
|
* Transforms the arguments before the validators judge them: the only stage
|
|
104
132
|
* that changes them. `args` is deep-frozen, so a pipe returns new arguments;
|
|
105
133
|
* returning `undefined` keeps them as they are. At a variant, `args` and the
|
|
106
|
-
* return are typed as that operation's arguments
|
|
107
|
-
*
|
|
134
|
+
* return are typed as that operation's arguments before write compute runs
|
|
135
|
+
* ({@link AvPreComputeStageArguments}: a create may lack the fields
|
|
136
|
+
* `compute.create` fills), `args` deep read-only.
|
|
108
137
|
*/
|
|
109
138
|
export type AvPipe<M extends AvAdapterModel = AvAdapterModel, R extends string = AvConfigResourceKey<M>, F extends AvOperationFamily = AvOperationFamily, V extends string = string, A = unknown> = {
|
|
110
|
-
pipe(args: PipeArguments<A>, context: AvContext<M, R, F, V, A>):
|
|
139
|
+
pipe(args: PipeArguments<A>, context: AvContext<M, R, F, V, A>): unknown extends PipeArguments<A> ? any : PipeArguments<A> | undefined | void | Promise<PipeArguments<A> | undefined | void>;
|
|
111
140
|
}["pipe"];
|
|
112
141
|
/**
|
|
113
142
|
* A variant pipe's arguments and return: the operation's arguments, deep
|
|
114
143
|
* read-only, each member closed to inference.
|
|
115
144
|
*/
|
|
116
|
-
type PipeArguments<T> = T extends AvDeepReadonlyLeaf | AvTransactionReference ? T : T extends
|
|
145
|
+
type PipeArguments<T> = T extends AvDeepReadonlyLeaf | AvTransactionReference ? T : T extends readonly unknown[] ? ArrayForm<T> extends "array" ? readonly NoInfer<PipeArguments<Exclude<T[number], undefined>>>[] : {
|
|
146
|
+
readonly [K in keyof T]: NoInfer<PipeArguments<Exclude<T[K], undefined>>>;
|
|
147
|
+
} : T extends object ? {
|
|
117
148
|
readonly [K in keyof T]: NoInfer<PipeArguments<Exclude<T[K], undefined>>>;
|
|
118
149
|
} : T;
|
|
119
|
-
/** What a pipe returns: arguments of type `A`, or `undefined` to keep them. */
|
|
120
|
-
type PipeResult<A> = unknown extends A ? any : // biome-ignore lint/suspicious/noConfusingVoidType: a pipe written as `() => void sideEffect()` keeps the arguments, as `undefined` does
|
|
121
|
-
A | undefined | void | Promise<A | undefined | void>;
|
|
122
150
|
/** Runs just before the operation executes, inside every interceptor; `ctx.$args` is deep-frozen. */
|
|
123
151
|
export type AvBeforeHook<M extends AvAdapterModel = AvAdapterModel, R extends string = AvConfigResourceKey<M>, F extends AvOperationFamily = AvOperationFamily, V extends string = string, A = unknown> = {
|
|
124
152
|
before(context: AvContext<M, R, F, V, A>): void | Promise<void>;
|
|
@@ -180,7 +208,8 @@ export type AvTransactionStep<M extends AvAdapterModel = AvAdapterModel> = {
|
|
|
180
208
|
export type AvTransactionContext<M extends AvAdapterModel = AvAdapterModel> = AvContextOperations<M> & AvContextFacts & {
|
|
181
209
|
/** The plan, in step order, `$ref`s unresolved, deep-frozen. */
|
|
182
210
|
readonly $args: readonly AvTransactionStep<M>[];
|
|
183
|
-
|
|
211
|
+
/** As a stage's `ctx.$sql`: a developer SQL statement, run in this transaction. */
|
|
212
|
+
readonly $sql: <Row = unknown>(strings: TemplateStringsArray, ...values: readonly AvAdapterSqlValue[]) => Promise<Row[]>;
|
|
184
213
|
/** Runs `work` inside this transaction (it opens nothing): `tx` is this ctx. */
|
|
185
214
|
$transaction<T>(work: (tx: AvTransactionContext<M>) => Promise<T>): Promise<T>;
|
|
186
215
|
};
|
|
@@ -1,12 +1,23 @@
|
|
|
1
|
-
import { AvDecimal } from "./decimal.js";
|
|
1
|
+
import { type AvDecimal } from "./decimal.js";
|
|
2
2
|
/** A value `AvDeepReadonly` leaves as it is: a primitive, a function, or a scalar instance. */
|
|
3
3
|
export type AvDeepReadonlyLeaf = string | number | boolean | bigint | symbol | null | undefined | Date | Uint8Array | AvDecimal | ((...args: never[]) => unknown);
|
|
4
|
+
/**
|
|
5
|
+
* Whether array type `T` is an open array (every length: `"array"`) or a tuple
|
|
6
|
+
* (`"tuple"`). A tuple whose only fixed positions are optional ones before a rest
|
|
7
|
+
* element (`[a?, ...b[]]`) has every length too and reads as an array.
|
|
8
|
+
*/
|
|
9
|
+
export type ArrayForm<T extends readonly unknown[]> = T extends readonly [] | readonly [unknown, ...unknown[]] | readonly [...unknown[], unknown] ? "tuple" : T extends {
|
|
10
|
+
readonly length: infer Length;
|
|
11
|
+
} ? number extends Length ? "array" : "tuple" : "tuple";
|
|
4
12
|
/**
|
|
5
13
|
* `T` with every property, element and nested property read-only: what a stage
|
|
6
|
-
* that only reads is told. Arrays become read-only arrays
|
|
7
|
-
* `Uint8Array`, an `AvDecimal` and functions are left as
|
|
14
|
+
* that only reads is told. Arrays become read-only arrays, tuples read-only
|
|
15
|
+
* tuples; a `Date`, a `Uint8Array`, an `AvDecimal` and functions are left as
|
|
16
|
+
* they are.
|
|
8
17
|
*/
|
|
9
|
-
export type AvDeepReadonly<T> = T extends AvDeepReadonlyLeaf ? T : T extends
|
|
18
|
+
export type AvDeepReadonly<T> = T extends AvDeepReadonlyLeaf ? T : T extends readonly unknown[] ? ArrayForm<T> extends "array" ? readonly AvDeepReadonly<T[number]>[] : {
|
|
19
|
+
readonly [K in keyof T]: AvDeepReadonly<T[K]>;
|
|
20
|
+
} : T extends object ? {
|
|
10
21
|
readonly [K in keyof T]: AvDeepReadonly<T[K]>;
|
|
11
22
|
} : T;
|
|
12
23
|
/**
|
|
@@ -21,8 +32,12 @@ export declare function deepFreeze<T>(value: T): T;
|
|
|
21
32
|
* only reads is told — the validated arguments after validation, a result in an
|
|
22
33
|
* after hook — so neither what is written nor the result the caller receives can
|
|
23
34
|
* be changed through it.
|
|
35
|
+
*
|
|
36
|
+
* With `snapshot`, a copied container found to hold no `Date` or `Uint8Array`
|
|
37
|
+
* is remembered as such at once, so a later `frozenCopy` of the copy shares it
|
|
38
|
+
* without walking it: for a copy that is itself copied again for each stage.
|
|
24
39
|
*/
|
|
25
|
-
export declare function frozenCopy<T>(value: T): AvDeepReadonly<T>;
|
|
40
|
+
export declare function frozenCopy<T>(value: T, snapshot?: boolean): AvDeepReadonly<T>;
|
|
26
41
|
/**
|
|
27
42
|
* A read-only view of `value`: reads see the live value, nested plain objects
|
|
28
43
|
* and arrays as views too, and any write, definition or deletion throws a
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isAvDecimal } from "./decimal.js";
|
|
2
2
|
function isContainer(value) {
|
|
3
3
|
if (value === null || typeof value !== "object") {
|
|
4
4
|
return false;
|
|
@@ -6,7 +6,7 @@ function isContainer(value) {
|
|
|
6
6
|
if (Array.isArray(value)) {
|
|
7
7
|
return true;
|
|
8
8
|
}
|
|
9
|
-
if (value
|
|
9
|
+
if (isAvDecimal(value)) {
|
|
10
10
|
return false;
|
|
11
11
|
}
|
|
12
12
|
const prototype = Object.getPrototypeOf(value);
|
|
@@ -36,51 +36,99 @@ function scalarCopy(value) {
|
|
|
36
36
|
}
|
|
37
37
|
return undefined;
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
const SCALAR_FREE = new WeakSet();
|
|
40
|
+
function scalarFree(value) {
|
|
41
|
+
return Object.isFrozen(value) && SCALAR_FREE.has(value);
|
|
42
|
+
}
|
|
43
|
+
const WALKING = Symbol("walking");
|
|
44
|
+
function place(target, key, value, enumerable) {
|
|
45
|
+
if (enumerable && typeof key === "string" && !(key in target)) {
|
|
46
|
+
target[key] = value;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
Object.defineProperty(target, key, {
|
|
50
|
+
value,
|
|
51
|
+
enumerable,
|
|
52
|
+
writable: true,
|
|
53
|
+
configurable: true,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
export function frozenCopy(value, snapshot = false) {
|
|
57
|
+
const scalar = scalarCopy(value);
|
|
58
|
+
if (scalar !== undefined) {
|
|
59
|
+
return scalar;
|
|
60
|
+
}
|
|
61
|
+
if (!isContainer(value) || scalarFree(value)) {
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
40
64
|
const copies = new Map();
|
|
65
|
+
let cycled = false;
|
|
66
|
+
let holdsScalar = false;
|
|
41
67
|
const copy = (current) => {
|
|
68
|
+
if (current === null || typeof current !== "object") {
|
|
69
|
+
return current;
|
|
70
|
+
}
|
|
42
71
|
const scalar = scalarCopy(current);
|
|
43
72
|
if (scalar !== undefined) {
|
|
73
|
+
holdsScalar = true;
|
|
44
74
|
return scalar;
|
|
45
75
|
}
|
|
46
|
-
if (!isContainer(current)) {
|
|
76
|
+
if (!isContainer(current) || scalarFree(current)) {
|
|
47
77
|
return current;
|
|
48
78
|
}
|
|
49
|
-
|
|
50
|
-
|
|
79
|
+
const known = copies.get(current);
|
|
80
|
+
if (known === WALKING) {
|
|
81
|
+
cycled = true;
|
|
82
|
+
return current;
|
|
83
|
+
}
|
|
84
|
+
if (known !== undefined) {
|
|
85
|
+
holdsScalar ||= !scalarFree(known);
|
|
86
|
+
return known;
|
|
51
87
|
}
|
|
52
|
-
copies.set(current,
|
|
53
|
-
const
|
|
54
|
-
|
|
88
|
+
copies.set(current, WALKING);
|
|
89
|
+
const outer = holdsScalar;
|
|
90
|
+
holdsScalar = false;
|
|
91
|
+
let changed = !(Object.isFrozen(current) && DEEP_FROZEN.has(current));
|
|
92
|
+
const array = Array.isArray(current);
|
|
93
|
+
const prototype = Object.getPrototypeOf(current);
|
|
94
|
+
const target = array
|
|
95
|
+
? new Array(current.length)
|
|
96
|
+
: prototype === Object.prototype
|
|
97
|
+
? {}
|
|
98
|
+
: Object.create(prototype);
|
|
55
99
|
for (const key of Reflect.ownKeys(current)) {
|
|
100
|
+
if (array && key === "length") {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
56
103
|
const descriptor = Object.getOwnPropertyDescriptor(current, key);
|
|
57
|
-
if (descriptor === undefined ||
|
|
58
|
-
!("value" in descriptor) ||
|
|
59
|
-
(Array.isArray(current) && key === "length")) {
|
|
104
|
+
if (descriptor === undefined || !("value" in descriptor)) {
|
|
60
105
|
continue;
|
|
61
106
|
}
|
|
62
107
|
const next = copy(descriptor.value);
|
|
63
108
|
changed ||= next !== descriptor.value;
|
|
64
|
-
|
|
109
|
+
place(target, key, next, descriptor.enumerable === true);
|
|
65
110
|
}
|
|
111
|
+
const held = holdsScalar;
|
|
112
|
+
holdsScalar = outer || held;
|
|
66
113
|
if (!changed) {
|
|
67
114
|
copies.set(current, current);
|
|
115
|
+
if (!cycled) {
|
|
116
|
+
SCALAR_FREE.add(current);
|
|
117
|
+
}
|
|
68
118
|
return current;
|
|
69
119
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
|
120
|
+
Object.freeze(target);
|
|
121
|
+
DEEP_FROZEN.add(target);
|
|
122
|
+
if (cycled) {
|
|
123
|
+
for (const key of Reflect.ownKeys(target)) {
|
|
124
|
+
deepFreeze(target[key]);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (snapshot && !held && !cycled) {
|
|
128
|
+
SCALAR_FREE.add(target);
|
|
80
129
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return frozen;
|
|
130
|
+
copies.set(current, target);
|
|
131
|
+
return target;
|
|
84
132
|
};
|
|
85
133
|
return copy(value);
|
|
86
134
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** An object that is not a list: what core reads as a record of named values. */
|
|
2
|
+
export declare function isRecord<T extends Readonly<Record<string, unknown>> = Readonly<Record<string, unknown>>>(value: unknown): value is T;
|
|
3
|
+
/**
|
|
4
|
+
* A **plain** record: an object literal (prototype `Object.prototype` or
|
|
5
|
+
* `null`), not a `Date`, a core `AvDecimal`, a `Uint8Array` or another class
|
|
6
|
+
* instance. The one discriminant between an argument OBJECT and a VALUE wherever
|
|
7
|
+
* a position admits both: a write record, a directive's operand, a filter
|
|
8
|
+
* position above all, where a plain record is an operator object and anything
|
|
9
|
+
* else is a value that equality shorthand holds to the field's scalar. The
|
|
10
|
+
* validator (`operation-validator-core.ts`) reads a filter position through this
|
|
11
|
+
* same answer, and an adapter's filter translation is expected to, so a position
|
|
12
|
+
* cannot be operators to one reader and a value to another.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isPlainRecord<T extends Readonly<Record<string, unknown>> = Readonly<Record<string, unknown>>>(value: unknown): value is T;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function isRecord(value) {
|
|
2
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
export function isPlainRecord(value) {
|
|
5
|
+
if (!isRecord(value)) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
const prototype = Object.getPrototypeOf(value);
|
|
9
|
+
return prototype === Object.prototype || prototype === null;
|
|
10
|
+
}
|
|
@@ -29,7 +29,7 @@ export type ReferentialEdge = {
|
|
|
29
29
|
* relation `field` and any of these names the reference twice and is refused;
|
|
30
30
|
* a required relation may be written through all of them instead.
|
|
31
31
|
*/
|
|
32
|
-
readonly
|
|
32
|
+
readonly referenceFields: readonly string[];
|
|
33
33
|
/** What deleting a `target` row does to rows of the ENCLOSING Resource. */
|
|
34
34
|
readonly onDelete: ReferentialDeleteEffect;
|
|
35
35
|
};
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { isRecord } from "./record.guard.js";
|
|
1
2
|
const ORIGINS = ["application", "client", "agent"];
|
|
2
3
|
const OPERATION_IDENTITY_MEMBERS = ["resource", "family", "variant"];
|
|
3
4
|
export function validateOperationEnvelope(request) {
|
|
4
5
|
if (!isRecord(request)) {
|
|
5
6
|
return [issue([], "V1001", "Operation request must be an object.")];
|
|
6
7
|
}
|
|
7
|
-
const issues = [
|
|
8
|
+
const issues = [
|
|
9
|
+
...originAndIdentityIssues(request, request.family === "find"),
|
|
10
|
+
];
|
|
8
11
|
for (const member of OPERATION_IDENTITY_MEMBERS) {
|
|
9
12
|
const failure = requiredStringIssue(request, member);
|
|
10
13
|
if (failure !== undefined) {
|
|
@@ -17,9 +20,9 @@ export function validateTransactionEnvelope(request) {
|
|
|
17
20
|
if (!isRecord(request)) {
|
|
18
21
|
return [issue([], "V1001", "Transaction request must be an object.")];
|
|
19
22
|
}
|
|
20
|
-
return originAndIdentityIssues(request);
|
|
23
|
+
return originAndIdentityIssues(request, false);
|
|
21
24
|
}
|
|
22
|
-
function originAndIdentityIssues(request) {
|
|
25
|
+
function originAndIdentityIssues(request, readable) {
|
|
23
26
|
const issues = [];
|
|
24
27
|
const origin = request.origin;
|
|
25
28
|
if (origin === undefined) {
|
|
@@ -46,7 +49,7 @@ function originAndIdentityIssues(request) {
|
|
|
46
49
|
if (origin === "client" || origin === "agent") {
|
|
47
50
|
issues.push(...protocolIssues(request.protocol, origin));
|
|
48
51
|
if (request.transport !== undefined) {
|
|
49
|
-
issues.push(...transportIssues(request.transport));
|
|
52
|
+
issues.push(...transportIssues(request.transport, readable));
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
else if (origin === "application") {
|
|
@@ -84,15 +87,18 @@ function protocolIssues(protocol, origin) {
|
|
|
84
87
|
}
|
|
85
88
|
return issues;
|
|
86
89
|
}
|
|
87
|
-
function transportIssues(transport) {
|
|
90
|
+
function transportIssues(transport, readable) {
|
|
88
91
|
if (!isRecord(transport)) {
|
|
89
92
|
return [
|
|
90
93
|
issue(["transport"], "V1001", "Transport metadata must be an object."),
|
|
91
94
|
];
|
|
92
95
|
}
|
|
93
96
|
const issues = [];
|
|
94
|
-
if (transport.method !== "POST"
|
|
95
|
-
|
|
97
|
+
if (transport.method !== "POST" &&
|
|
98
|
+
!(readable && transport.method === "GET")) {
|
|
99
|
+
issues.push(issue(["transport", "method"], "V1001", readable
|
|
100
|
+
? 'Transport method must be "POST" or "GET".'
|
|
101
|
+
: 'Transport method must be "POST".'));
|
|
96
102
|
}
|
|
97
103
|
const headers = transport.headers;
|
|
98
104
|
if (!isRecord(headers)) {
|
|
@@ -115,9 +121,6 @@ function requiredStringIssue(request, member) {
|
|
|
115
121
|
? undefined
|
|
116
122
|
: issue([member], "V1001", `Property "${member}" must be a string.`);
|
|
117
123
|
}
|
|
118
|
-
function isRecord(value) {
|
|
119
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
120
|
-
}
|
|
121
124
|
function issue(path, code, message) {
|
|
122
125
|
return { path, code, message };
|
|
123
126
|
}
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import type { AvRequestOrigin } from "../config/config-layer.js";
|
|
2
|
-
import type { AvScalarFilterOperator } from "../contracts/capability.js";
|
|
3
2
|
import type { AvContract } from "../contracts/contract.js";
|
|
4
3
|
import type { AvScalarField } from "../contracts/field.js";
|
|
5
4
|
import type { AvOperationIdentity } from "../operations/operation-identity.js";
|
|
6
5
|
import type { OperationValidationOptions, SemanticOperationArguments } from "../operations/operation-validator.js";
|
|
7
6
|
import type { AvValidationIssue } from "../operations/validation-code.js";
|
|
8
7
|
import { type TransactionSlotShape } from "../transactions/transaction-reference.js";
|
|
9
|
-
|
|
8
|
+
type ScalarNormalizationResult = {
|
|
10
9
|
readonly ok: true;
|
|
11
10
|
readonly arguments: SemanticOperationArguments;
|
|
12
11
|
} | {
|
|
13
12
|
readonly ok: false;
|
|
14
13
|
readonly issues: readonly AvValidationIssue[];
|
|
15
14
|
};
|
|
16
|
-
|
|
15
|
+
type ScalarValueNormalizationResult = {
|
|
17
16
|
readonly ok: true;
|
|
18
17
|
readonly value: unknown;
|
|
19
18
|
} | {
|
|
@@ -21,16 +20,8 @@ export type ScalarValueNormalizationResult = {
|
|
|
21
20
|
readonly issues: readonly AvValidationIssue[];
|
|
22
21
|
};
|
|
23
22
|
type Path = readonly (string | number)[];
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
-
* admits both — a filter position above all: a **plain** record is an operator object,
|
|
27
|
-
* and anything else — a `Date`, a core `AvDecimal`, a `Uint8Array` — is a value, which
|
|
28
|
-
* equality shorthand then holds to the field's scalar. The validator (`operation-
|
|
29
|
-
* validator-core.ts`) reads a filter position through this same answer, and an
|
|
30
|
-
* adapter's filter translation is expected to, so a position cannot be operators to
|
|
31
|
-
* one reader and a value to another.
|
|
32
|
-
*/
|
|
33
|
-
export declare function isPlainRecord(value: unknown): value is Readonly<Record<string, unknown>>;
|
|
23
|
+
/** The `V1001` of an `undefined` the request reads with. */
|
|
24
|
+
export declare function unsentReadValueIssue(path: Path): AvValidationIssue;
|
|
34
25
|
/**
|
|
35
26
|
* An operation argument's JSON value is bounded by `maxJsonDepth`, which the
|
|
36
27
|
* structural walk enforces before this runs; a `$sql` step's parameter is not
|
|
@@ -71,14 +62,6 @@ export declare function jsonShapeIssues(field: AvScalarField<AvContract>, value:
|
|
|
71
62
|
* its copy.
|
|
72
63
|
*/
|
|
73
64
|
export declare function copyScalarFieldValue(field: AvScalarField<AvContract>, value: unknown): unknown;
|
|
74
|
-
/**
|
|
75
|
-
* The operators of a step's own filter whose operand is a reference position, and
|
|
76
|
-
* the shape each holds — the one table the normalization below and the reference
|
|
77
|
-
* collector (`transaction-reference-collector.ts`) both read. `not` also takes a
|
|
78
|
-
* nested operator object. Not here, so never a reference: `mode`, `isEmpty`, `path`
|
|
79
|
-
* and a `json` field's `string*`/`array*` operators, which take no field value.
|
|
80
|
-
*/
|
|
81
|
-
export declare const REFERENCE_OPERANDS: Readonly<Partial<Record<AvScalarFilterOperator, TransactionSlotShape>>>;
|
|
82
65
|
/** The shape of `operator`'s operand when it is a reference position. */
|
|
83
66
|
export declare function referenceOperandShape(operator: string): TransactionSlotShape | undefined;
|
|
84
67
|
/**
|