@aventara/core 0.1.0-pilot.4 → 1.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +338 -0
- package/README.md +100 -3
- package/dist/adapters/adapter-model.d.ts +8 -0
- package/dist/adapters/adapter.interface.d.ts +6 -2
- package/dist/compiler/contract-compiler-diagnostic.d.ts +6 -0
- package/dist/compiler/contract.compiler.js +67 -0
- package/dist/config/config.resolver.d.ts +3 -0
- package/dist/config/config.resolver.js +1 -0
- package/dist/config/config.validator.js +6 -0
- package/dist/config/define-fields.d.ts +10 -3
- package/dist/config/framework-config.d.ts +4 -1
- package/dist/config/framework-fields-config.d.ts +6 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +21 -1
- package/dist/contracts/client-contract-structure.validator.js +99 -2
- package/dist/contracts/contract-canonicalizer.js +32 -0
- package/dist/contracts/contract.d.ts +7 -0
- package/dist/contracts/field.d.ts +10 -0
- package/dist/contracts/json-shape.d.ts +65 -0
- package/dist/contracts/json-shape.js +1 -0
- package/dist/contracts/reference-write-limit.d.ts +7 -0
- package/dist/contracts/reference-write-limit.js +1 -0
- package/dist/contracts/scalar-value-type.d.ts +12 -1
- package/dist/framework/contract-view.d.ts +126 -21
- package/dist/framework/framework.d.ts +5 -3
- package/dist/framework/framework.factory.js +56 -13
- package/dist/index.d.ts +8 -40
- package/dist/index.js +0 -20
- package/dist/internal.d.ts +35 -0
- package/dist/internal.js +16 -0
- package/dist/json/avz.d.ts +96 -0
- package/dist/json/avz.js +212 -0
- package/dist/json/index.d.ts +6 -0
- package/dist/json/index.js +1 -0
- package/dist/json/json-shape.registry.d.ts +22 -0
- package/dist/json/json-shape.registry.js +16 -0
- package/dist/json/zod-issue.translator.d.ts +51 -0
- package/dist/json/zod-issue.translator.js +142 -0
- package/dist/operations/operation-arguments.d.ts +151 -101
- package/dist/operations/operation-identity.d.ts +2 -0
- package/dist/operations/operation-identity.js +3 -0
- package/dist/operations/operation-validator-core.d.ts +1 -1
- package/dist/operations/operation-validator-core.js +28 -10
- package/dist/operations/operation-validator.d.ts +20 -5
- package/dist/operations/operation-validator.js +26 -10
- package/dist/operations/projection-scope.resolver.d.ts +1 -1
- package/dist/operations/structural-limits.walker.d.ts +19 -0
- package/dist/operations/structural-limits.walker.js +344 -0
- package/dist/protocol/absent-route.responder.d.ts +2 -1
- package/dist/protocol/absent-route.responder.js +32 -6
- package/dist/protocol/http-request.decoder.d.ts +6 -0
- package/dist/protocol/http-request.decoder.js +11 -3
- package/dist/protocol/protocol.binder.d.ts +4 -2
- package/dist/protocol/protocol.binder.js +3 -1
- package/dist/protocol/protocol.handler.d.ts +6 -2
- package/dist/protocol/protocol.handler.js +14 -4
- package/dist/protocol/unmounted-route.error.d.ts +19 -0
- package/dist/protocol/unmounted-route.error.js +10 -0
- package/dist/runtime/caller-data.copier.d.ts +59 -0
- package/dist/runtime/caller-data.copier.js +470 -0
- package/dist/runtime/caller-data.door.d.ts +56 -0
- package/dist/runtime/caller-data.door.js +65 -0
- package/dist/runtime/computed-read-runtime.js +3 -10
- package/dist/runtime/computed-value.error.d.ts +13 -0
- package/dist/runtime/computed-value.error.js +9 -0
- package/dist/runtime/create-requirement.d.ts +43 -7
- package/dist/runtime/create-requirement.js +89 -9
- package/dist/runtime/diagnostics-reporter.d.ts +20 -4
- package/dist/runtime/diagnostics-reporter.js +11 -4
- package/dist/runtime/error-boundary.d.ts +8 -0
- package/dist/runtime/error-boundary.js +65 -35
- package/dist/runtime/field-behavior.d.ts +2 -2
- package/dist/runtime/framework-error.d.ts +12 -0
- package/dist/runtime/misuse-reporter.d.ts +32 -0
- package/dist/runtime/misuse-reporter.js +19 -0
- package/dist/runtime/mutation-planner.js +13 -11
- package/dist/runtime/operation-request.d.ts +4 -11
- package/dist/runtime/operation-runtime.d.ts +14 -7
- package/dist/runtime/operation-runtime.js +37 -18
- package/dist/runtime/outcome-mapper.js +12 -2
- package/dist/runtime/output-validator.d.ts +10 -0
- package/dist/runtime/output-validator.js +11 -0
- package/dist/runtime/owned-execution.registry.d.ts +13 -0
- package/dist/runtime/owned-execution.registry.js +7 -0
- package/dist/runtime/pipeline.d.ts +19 -7
- package/dist/runtime/referential-action.d.ts +7 -0
- package/dist/runtime/request-envelope.validator.d.ts +5 -0
- package/dist/runtime/request-envelope.validator.js +118 -0
- package/dist/runtime/scalar-runtime.d.ts +30 -2
- package/dist/runtime/scalar-runtime.js +162 -79
- package/dist/transactions/transaction-plan-assembler.d.ts +5 -1
- package/dist/transactions/transaction-plan-assembler.js +74 -75
- package/dist/transactions/transaction-plan-validator.d.ts +30 -7
- package/dist/transactions/transaction-plan-validator.js +204 -153
- package/dist/transactions/transaction-reference-collector.d.ts +30 -0
- package/dist/transactions/transaction-reference-collector.js +204 -0
- package/dist/transactions/transaction-reference-resolver.js +10 -5
- package/dist/transactions/transaction-reference-validator.js +24 -17
- package/dist/transactions/transaction-reference.d.ts +23 -51
- package/dist/transactions/transaction-request.d.ts +3 -3
- package/dist/transactions/transaction-response.d.ts +6 -1
- package/dist/transactions/transaction-response.js +24 -1
- package/dist/transactions/transaction-runtime.d.ts +4 -2
- package/dist/transactions/transaction-runtime.js +4 -3
- package/package.json +17 -3
- package/dist/operations/operation-boolean-nodes.d.ts +0 -11
- package/dist/operations/operation-boolean-nodes.js +0 -283
- package/dist/operations/operation-nesting.d.ts +0 -8
- package/dist/operations/operation-nesting.js +0 -307
|
@@ -14,7 +14,7 @@ export type PipelineTransportContext = {
|
|
|
14
14
|
/** What a pipeline callback is told about the operation it is wrapping. */
|
|
15
15
|
export type PipelineContext<M extends AdapterModel = AdapterModel> = {
|
|
16
16
|
readonly contract: Contract;
|
|
17
|
-
readonly
|
|
17
|
+
readonly origin: RequestOrigin;
|
|
18
18
|
readonly resource: FrameworkResourceKey<M>;
|
|
19
19
|
readonly family: OperationFamily;
|
|
20
20
|
readonly variant: string;
|
|
@@ -23,20 +23,32 @@ export type PipelineContext<M extends AdapterModel = AdapterModel> = {
|
|
|
23
23
|
readonly transport?: PipelineTransportContext;
|
|
24
24
|
};
|
|
25
25
|
/** Allows or denies an operation; returning `false` answers `A4001`. */
|
|
26
|
-
export type Guard<M extends AdapterModel = AdapterModel> =
|
|
26
|
+
export type Guard<M extends AdapterModel = AdapterModel> = {
|
|
27
|
+
guard(context: PipelineContext<M>): boolean | undefined | Promise<boolean | undefined>;
|
|
28
|
+
}["guard"];
|
|
27
29
|
/**
|
|
28
30
|
* Transforms the arguments before the operation runs; returning `undefined`
|
|
29
31
|
* keeps them as they are.
|
|
30
32
|
*/
|
|
31
|
-
export type Pipe<M extends AdapterModel = AdapterModel> =
|
|
33
|
+
export type Pipe<M extends AdapterModel = AdapterModel> = {
|
|
34
|
+
pipe(args: unknown, context: PipelineContext<M>): unknown | Promise<unknown>;
|
|
35
|
+
}["pipe"];
|
|
32
36
|
/** Runs just before the operation executes. */
|
|
33
|
-
export type BeforeHook<M extends AdapterModel = AdapterModel> =
|
|
37
|
+
export type BeforeHook<M extends AdapterModel = AdapterModel> = {
|
|
38
|
+
before(context: PipelineContext<M>): void | Promise<void>;
|
|
39
|
+
}["before"];
|
|
34
40
|
/** Runs after the operation succeeds, with its result. */
|
|
35
|
-
export type AfterHook<M extends AdapterModel = AdapterModel> =
|
|
41
|
+
export type AfterHook<M extends AdapterModel = AdapterModel> = {
|
|
42
|
+
after(result: unknown, context: PipelineContext<M>): void | Promise<void>;
|
|
43
|
+
}["after"];
|
|
36
44
|
/** Wraps the operation's execution; call `next()` to run it and get its result. */
|
|
37
|
-
export type Interceptor<M extends AdapterModel = AdapterModel> =
|
|
45
|
+
export type Interceptor<M extends AdapterModel = AdapterModel> = {
|
|
46
|
+
intercept(context: PipelineContext<M>, next: () => Promise<unknown>): Promise<unknown>;
|
|
47
|
+
}["intercept"];
|
|
38
48
|
/**
|
|
39
49
|
* Turns a thrown error into a {@link FrameworkError} to answer with; returning
|
|
40
50
|
* `undefined` passes the error on.
|
|
41
51
|
*/
|
|
42
|
-
export type Filter<M extends AdapterModel = AdapterModel> =
|
|
52
|
+
export type Filter<M extends AdapterModel = AdapterModel> = {
|
|
53
|
+
filter(error: unknown, context: PipelineContext<M>): FrameworkError | undefined | Promise<FrameworkError | undefined>;
|
|
54
|
+
}["filter"];
|
|
@@ -23,6 +23,13 @@ export type ReferentialEdge = {
|
|
|
23
23
|
readonly field: string;
|
|
24
24
|
/** The Resource the edge points AT — the one whose deletion fires `onDelete`. */
|
|
25
25
|
readonly target: string;
|
|
26
|
+
/**
|
|
27
|
+
* The scalar fields of the ENCLOSING Resource that hold the reference, in the
|
|
28
|
+
* order the store pairs them with the `target`'s key. A record that writes the
|
|
29
|
+
* relation `field` and any of these names the reference twice and is refused;
|
|
30
|
+
* a required relation may be written through all of them instead.
|
|
31
|
+
*/
|
|
32
|
+
readonly references: readonly string[];
|
|
26
33
|
/** What deleting a `target` row does to rows of the ENCLOSING Resource. */
|
|
27
34
|
readonly onDelete: ReferentialDeleteEffect;
|
|
28
35
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ValidationIssue } from "../operations/validation-code.js";
|
|
2
|
+
/** The issues of one malformed operation request envelope; empty when well formed. */
|
|
3
|
+
export declare function validateOperationEnvelope(request: unknown): readonly ValidationIssue[];
|
|
4
|
+
/** The issues of one malformed transaction request envelope; empty when well formed. */
|
|
5
|
+
export declare function validateTransactionEnvelope(request: unknown): readonly ValidationIssue[];
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const ORIGINS = ["application", "client"];
|
|
2
|
+
const OPERATION_IDENTITY_MEMBERS = ["resource", "family", "variant"];
|
|
3
|
+
export function validateOperationEnvelope(request) {
|
|
4
|
+
if (!isRecord(request)) {
|
|
5
|
+
return [issue([], "V1001", "Operation request must be an object.")];
|
|
6
|
+
}
|
|
7
|
+
const issues = [...originAndIdentityIssues(request)];
|
|
8
|
+
for (const member of OPERATION_IDENTITY_MEMBERS) {
|
|
9
|
+
const failure = requiredStringIssue(request, member);
|
|
10
|
+
if (failure !== undefined) {
|
|
11
|
+
issues.push(failure);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return issues;
|
|
15
|
+
}
|
|
16
|
+
export function validateTransactionEnvelope(request) {
|
|
17
|
+
if (!isRecord(request)) {
|
|
18
|
+
return [issue([], "V1001", "Transaction request must be an object.")];
|
|
19
|
+
}
|
|
20
|
+
return originAndIdentityIssues(request);
|
|
21
|
+
}
|
|
22
|
+
function originAndIdentityIssues(request) {
|
|
23
|
+
const issues = [];
|
|
24
|
+
const origin = request.origin;
|
|
25
|
+
if (origin === undefined) {
|
|
26
|
+
issues.push(issue(["origin"], "V1000", 'Required property "origin" is missing.'));
|
|
27
|
+
}
|
|
28
|
+
else if (typeof origin !== "string") {
|
|
29
|
+
issues.push(issue(["origin"], "V1001", "Request origin must be a string."));
|
|
30
|
+
}
|
|
31
|
+
else if (!ORIGINS.includes(origin)) {
|
|
32
|
+
issues.push(issue(["origin"], "V1002", 'Request origin must be "application" or "client".'));
|
|
33
|
+
}
|
|
34
|
+
const requestId = request.requestId;
|
|
35
|
+
if (requestId === undefined || requestId === "") {
|
|
36
|
+
issues.push(issue(["requestId"], "V1000", 'Required property "requestId" is missing or empty.'));
|
|
37
|
+
}
|
|
38
|
+
else if (typeof requestId !== "string") {
|
|
39
|
+
issues.push(issue(["requestId"], "V1001", "Request id must be a string."));
|
|
40
|
+
}
|
|
41
|
+
if (origin === "client") {
|
|
42
|
+
issues.push(...protocolIssues(request.protocol));
|
|
43
|
+
if (request.transport !== undefined) {
|
|
44
|
+
issues.push(...transportIssues(request.transport));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else if (origin === "application") {
|
|
48
|
+
for (const member of ["protocol", "transport"]) {
|
|
49
|
+
if (request[member] !== undefined) {
|
|
50
|
+
issues.push(issue([member], "V1005", `Property "${member}" belongs to a client request, not an application one.`));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return issues;
|
|
55
|
+
}
|
|
56
|
+
function protocolIssues(protocol) {
|
|
57
|
+
if (protocol === undefined) {
|
|
58
|
+
return [
|
|
59
|
+
issue(["protocol"], "V1000", 'Required property "protocol" is missing from a client request.'),
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
if (!isRecord(protocol)) {
|
|
63
|
+
return [
|
|
64
|
+
issue(["protocol"], "V1001", "Protocol identity must be an object."),
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
const issues = [];
|
|
68
|
+
if (protocol.version === undefined) {
|
|
69
|
+
issues.push(issue(["protocol", "version"], "V1000", 'Required property "version" is missing.'));
|
|
70
|
+
}
|
|
71
|
+
else if (!Number.isInteger(protocol.version)) {
|
|
72
|
+
issues.push(issue(["protocol", "version"], "V1001", "Protocol version must be an integer."));
|
|
73
|
+
}
|
|
74
|
+
if (protocol.hash === undefined) {
|
|
75
|
+
issues.push(issue(["protocol", "hash"], "V1000", 'Required property "hash" is missing.'));
|
|
76
|
+
}
|
|
77
|
+
else if (typeof protocol.hash !== "string") {
|
|
78
|
+
issues.push(issue(["protocol", "hash"], "V1001", "Protocol hash must be a string."));
|
|
79
|
+
}
|
|
80
|
+
return issues;
|
|
81
|
+
}
|
|
82
|
+
function transportIssues(transport) {
|
|
83
|
+
if (!isRecord(transport)) {
|
|
84
|
+
return [
|
|
85
|
+
issue(["transport"], "V1001", "Transport metadata must be an object."),
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
const issues = [];
|
|
89
|
+
if (transport.method !== "POST") {
|
|
90
|
+
issues.push(issue(["transport", "method"], "V1001", 'Transport method must be "POST".'));
|
|
91
|
+
}
|
|
92
|
+
const headers = transport.headers;
|
|
93
|
+
if (!isRecord(headers)) {
|
|
94
|
+
issues.push(issue(["transport", "headers"], "V1001", "Transport headers must be an object."));
|
|
95
|
+
return issues;
|
|
96
|
+
}
|
|
97
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
98
|
+
if (typeof value !== "string") {
|
|
99
|
+
issues.push(issue(["transport", "headers", name], "V1001", "A transport header value must be a string."));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return issues;
|
|
103
|
+
}
|
|
104
|
+
function requiredStringIssue(request, member) {
|
|
105
|
+
const value = request[member];
|
|
106
|
+
if (value === undefined) {
|
|
107
|
+
return issue([member], "V1000", `Required property "${member}" is missing.`);
|
|
108
|
+
}
|
|
109
|
+
return typeof value === "string"
|
|
110
|
+
? undefined
|
|
111
|
+
: issue([member], "V1001", `Property "${member}" must be a string.`);
|
|
112
|
+
}
|
|
113
|
+
function isRecord(value) {
|
|
114
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
115
|
+
}
|
|
116
|
+
function issue(path, code, message) {
|
|
117
|
+
return { path, code, message };
|
|
118
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { RequestOrigin } from "../config/config-layer.js";
|
|
2
|
+
import type { ScalarFilterOperator } from "../contracts/capability.js";
|
|
2
3
|
import type { Contract } from "../contracts/contract.js";
|
|
3
4
|
import type { ScalarField } from "../contracts/field.js";
|
|
4
5
|
import type { OperationIdentity } from "../operations/operation-identity.js";
|
|
5
6
|
import type { OperationValidationOptions, SemanticOperationArguments } from "../operations/operation-validator.js";
|
|
6
7
|
import type { ValidationIssue } from "../operations/validation-code.js";
|
|
8
|
+
import { type TransactionSlotShape } from "../transactions/transaction-reference.js";
|
|
7
9
|
export type ScalarNormalizationResult = {
|
|
8
10
|
readonly ok: true;
|
|
9
11
|
readonly arguments: SemanticOperationArguments;
|
|
@@ -33,7 +35,17 @@ export declare function isPlainRecord(value: unknown): value is Readonly<Record<
|
|
|
33
35
|
* Normalizes one field value to Aventara's provider-neutral runtime form.
|
|
34
36
|
* `runtime` is used for framework-produced values regardless of request origin.
|
|
35
37
|
*/
|
|
36
|
-
export declare function normalizeScalarFieldValue(contract: Contract, field: ScalarField<Contract>, value: unknown,
|
|
38
|
+
export declare function normalizeScalarFieldValue(contract: Contract, field: ScalarField<Contract>, value: unknown, origin: RequestOrigin | "runtime", path: Path): ScalarValueNormalizationResult;
|
|
39
|
+
/**
|
|
40
|
+
* Every way a normalized value written to `field` does not conform to the field's
|
|
41
|
+
* Json Shape, each at its full path; none for an unshaped field or a `null`.
|
|
42
|
+
* `position` says whether `value` is the field's whole value or one entry of a
|
|
43
|
+
* list field (a `$push` operand).
|
|
44
|
+
*
|
|
45
|
+
* @throws Error when the field carries a shape no checker is bound to — a Contract
|
|
46
|
+
* the Framework did not compile.
|
|
47
|
+
*/
|
|
48
|
+
export declare function jsonShapeIssues(field: ScalarField<Contract>, value: unknown, path: Path, position?: "value" | "entry"): readonly ValidationIssue[];
|
|
37
49
|
/**
|
|
38
50
|
* Copies one validated runtime value of a scalar field into a value the framework
|
|
39
51
|
* owns, per scalar codec: `datetime` → a new `Date`, `bytes` → a sliced `Uint8Array`,
|
|
@@ -44,6 +56,22 @@ export declare function normalizeScalarFieldValue(contract: Contract, field: Sca
|
|
|
44
56
|
* its copy.
|
|
45
57
|
*/
|
|
46
58
|
export declare function copyScalarFieldValue(field: ScalarField<Contract>, value: unknown): unknown;
|
|
59
|
+
/**
|
|
60
|
+
* The operators of a step's own filter whose operand is a reference position, and
|
|
61
|
+
* the shape each holds — the one table the normalization below and the reference
|
|
62
|
+
* collector (`transaction-reference-collector.ts`) both read. `not` also takes a
|
|
63
|
+
* nested operator object. Not here, so never a reference: `mode`, `isEmpty`, `path`
|
|
64
|
+
* and a `json` field's `string*`/`array*` operators, which take no field value.
|
|
65
|
+
*/
|
|
66
|
+
export declare const REFERENCE_OPERANDS: Readonly<Partial<Record<ScalarFilterOperator, TransactionSlotShape>>>;
|
|
67
|
+
/** The shape of `operator`'s operand when it is a reference position. */
|
|
68
|
+
export declare function referenceOperandShape(operator: string): TransactionSlotShape | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Where a normalization writes: `"copy"` leaves the arguments it reads untouched,
|
|
71
|
+
* `"in-place"` writes into them — only for arguments the framework owns and reads
|
|
72
|
+
* nowhere else afterwards: a door's copy, or a body the protocol decoder parsed.
|
|
73
|
+
*/
|
|
74
|
+
export type NormalizationWrite = "copy" | "in-place";
|
|
47
75
|
/**
|
|
48
76
|
* Normalizes every scalar leaf in one structurally valid standard operation.
|
|
49
77
|
* Client wire values are decoded; application values are validated in runtime form.
|
|
@@ -51,5 +79,5 @@ export declare function copyScalarFieldValue(field: ScalarField<Contract>, value
|
|
|
51
79
|
export declare function normalizeOperationScalarValues(contract: Contract, request: OperationIdentity & {
|
|
52
80
|
readonly resource: string;
|
|
53
81
|
readonly arguments: SemanticOperationArguments;
|
|
54
|
-
},
|
|
82
|
+
}, origin: RequestOrigin, options?: OperationValidationOptions, write?: NormalizationWrite): ScalarNormalizationResult;
|
|
55
83
|
export {};
|