@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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { validationIssue } from "../operations/validation-code.js";
|
|
2
|
+
import { copyAtDoor, refuseCallerData } from "../runtime/caller-data.door.js";
|
|
2
3
|
import { operationFailure } from "../runtime/operation-response.js";
|
|
3
4
|
import { mapValidationOutcome } from "../runtime/outcome-mapper.js";
|
|
4
5
|
import { encodeOperationArgumentsForWire } from "./operation-arguments-encoder.js";
|
|
@@ -11,63 +12,63 @@ function isPlainRecord(value) {
|
|
|
11
12
|
const prototype = Object.getPrototypeOf(value);
|
|
12
13
|
return prototype === Object.prototype || prototype === null;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
case "upsert":
|
|
20
|
-
return ["create", "update"];
|
|
21
|
-
default:
|
|
22
|
-
return [];
|
|
15
|
+
const KEEP = Symbol("keep");
|
|
16
|
+
function rebuildArguments(value, path, leaf, ancestors = new Set()) {
|
|
17
|
+
const replaced = leaf(value, path);
|
|
18
|
+
if (replaced !== KEEP) {
|
|
19
|
+
return replaced;
|
|
23
20
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (!isPlainRecord(args)) {
|
|
27
|
-
return [];
|
|
28
|
-
}
|
|
29
|
-
return referenceKeys(identity).flatMap((key) => {
|
|
30
|
-
const value = args[key];
|
|
31
|
-
if (Array.isArray(value)) {
|
|
32
|
-
return value.flatMap((entry, index) => isPlainRecord(entry) ? [{ path: [key, index], record: entry }] : []);
|
|
33
|
-
}
|
|
34
|
-
return isPlainRecord(value) ? [{ path: [key], record: value }] : [];
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
function replaceContainers(identity, args, rebuild) {
|
|
38
|
-
if (!isPlainRecord(args)) {
|
|
39
|
-
return args;
|
|
21
|
+
if (!Array.isArray(value) && !isPlainRecord(value)) {
|
|
22
|
+
return value;
|
|
40
23
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const value = args[key];
|
|
44
|
-
if (Array.isArray(value)) {
|
|
45
|
-
result[key] = value.map((entry, index) => isPlainRecord(entry)
|
|
46
|
-
? rebuild({ path: [key, index], record: entry })
|
|
47
|
-
: entry);
|
|
48
|
-
}
|
|
49
|
-
else if (isPlainRecord(value)) {
|
|
50
|
-
result[key] = rebuild({ path: [key], record: value });
|
|
51
|
-
}
|
|
24
|
+
if (ancestors.has(value)) {
|
|
25
|
+
return value;
|
|
52
26
|
}
|
|
53
|
-
|
|
27
|
+
ancestors.add(value);
|
|
28
|
+
const rebuilt = Array.isArray(value)
|
|
29
|
+
? value.map((entry, index) => rebuildArguments(entry, [...path, index], leaf, ancestors))
|
|
30
|
+
: Object.fromEntries(Object.entries(value).map(([key, entry]) => [
|
|
31
|
+
key,
|
|
32
|
+
rebuildArguments(entry, [...path, key], leaf, ancestors),
|
|
33
|
+
]));
|
|
34
|
+
ancestors.delete(value);
|
|
35
|
+
return rebuilt;
|
|
54
36
|
}
|
|
55
37
|
function operationEntryFailure(operation, message) {
|
|
56
38
|
return transactionOperationFailure(operationFailure("A2004", {
|
|
57
39
|
message: "Transaction plan failed framework validation.",
|
|
58
|
-
issues: [validationIssue("V1001", [
|
|
40
|
+
issues: [validationIssue("V1001", [], message)],
|
|
59
41
|
}), operation);
|
|
60
42
|
}
|
|
61
43
|
function referenceFailure(issue, operation) {
|
|
62
44
|
return transactionOperationFailure(mapValidationOutcome([issue]), operation);
|
|
63
45
|
}
|
|
64
|
-
export function createTransactionPlanAssembler(contracts, protocol) {
|
|
46
|
+
export function createTransactionPlanAssembler(contracts, protocol, misuse) {
|
|
65
47
|
const handles = new WeakMap();
|
|
66
48
|
const placeholders = new WeakMap();
|
|
67
49
|
const originOf = (origin) => origin === "application"
|
|
68
|
-
? {
|
|
69
|
-
: {
|
|
70
|
-
const snapshot = (
|
|
50
|
+
? { origin: "application" }
|
|
51
|
+
: { origin: "client", protocol };
|
|
52
|
+
const snapshot = (args) => {
|
|
53
|
+
const copy = copyAtDoor(args, {
|
|
54
|
+
keep: (value) => placeholders.has(value),
|
|
55
|
+
});
|
|
56
|
+
return copy.ok ? { args: copy.value } : { args: {}, refused: copy.error };
|
|
57
|
+
};
|
|
58
|
+
const placeholderSites = (args) => {
|
|
59
|
+
const sites = [];
|
|
60
|
+
rebuildArguments(args, [], (value, path) => {
|
|
61
|
+
const placeholder = typeof value === "object" && value !== null
|
|
62
|
+
? placeholders.get(value)
|
|
63
|
+
: undefined;
|
|
64
|
+
if (placeholder === undefined) {
|
|
65
|
+
return KEEP;
|
|
66
|
+
}
|
|
67
|
+
sites.push({ path, object: value, placeholder });
|
|
68
|
+
return value;
|
|
69
|
+
});
|
|
70
|
+
return sites;
|
|
71
|
+
};
|
|
71
72
|
const defer = (origin, resource, identity, args) => {
|
|
72
73
|
const handle = Object.freeze({
|
|
73
74
|
$ref: (field) => {
|
|
@@ -82,11 +83,22 @@ export function createTransactionPlanAssembler(contracts, protocol) {
|
|
|
82
83
|
origin,
|
|
83
84
|
resource,
|
|
84
85
|
identity,
|
|
85
|
-
|
|
86
|
+
...snapshot(args),
|
|
86
87
|
});
|
|
87
88
|
return handle;
|
|
88
89
|
};
|
|
89
|
-
const assemble = async (
|
|
90
|
+
const assemble = async (input) => {
|
|
91
|
+
const list = copyAtDoor(input, { keep: (value) => value !== input });
|
|
92
|
+
if (!list.ok) {
|
|
93
|
+
return {
|
|
94
|
+
ok: false,
|
|
95
|
+
response: operationFailure("A2004", {
|
|
96
|
+
message: "Transaction plan failed framework validation.",
|
|
97
|
+
issues: [refuseCallerData(list.error, ["operations"], {}, misuse)],
|
|
98
|
+
}),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const operations = list.value;
|
|
90
102
|
if (!Array.isArray(operations)) {
|
|
91
103
|
return {
|
|
92
104
|
ok: false,
|
|
@@ -120,17 +132,12 @@ export function createTransactionPlanAssembler(contracts, protocol) {
|
|
|
120
132
|
records.push(record);
|
|
121
133
|
}
|
|
122
134
|
for (const [index, record] of records.entries()) {
|
|
123
|
-
for (const { path,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
:
|
|
128
|
-
|
|
129
|
-
return {
|
|
130
|
-
ok: false,
|
|
131
|
-
response: referenceFailure(validationIssue("V1010", ["operations", index, "args", ...path, field, "$ref"], "Transaction reference names an operation that is not in this transaction."), index),
|
|
132
|
-
};
|
|
133
|
-
}
|
|
135
|
+
for (const { path, placeholder } of placeholderSites(record.args)) {
|
|
136
|
+
if (!positions.has(placeholder.source)) {
|
|
137
|
+
return {
|
|
138
|
+
ok: false,
|
|
139
|
+
response: referenceFailure(validationIssue("V1010", ["operations", index, "args", ...path, "$ref"], "Transaction reference names an operation that is not in this transaction."), index),
|
|
140
|
+
};
|
|
134
141
|
}
|
|
135
142
|
}
|
|
136
143
|
}
|
|
@@ -145,26 +152,17 @@ export function createTransactionPlanAssembler(contracts, protocol) {
|
|
|
145
152
|
};
|
|
146
153
|
const materialize = async (index) => {
|
|
147
154
|
const record = records[index];
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
references.push(nodeAt(operation).then(({ fingerprint }) => {
|
|
160
|
-
bound[field] = {
|
|
161
|
-
$ref: { operation, fingerprint, path: [placeholder.field] },
|
|
162
|
-
};
|
|
163
|
-
}));
|
|
164
|
-
}
|
|
165
|
-
return bound;
|
|
166
|
-
});
|
|
167
|
-
await Promise.all(references);
|
|
155
|
+
const bound = new Map();
|
|
156
|
+
await Promise.all(placeholderSites(record.args).map(async ({ object, placeholder }) => {
|
|
157
|
+
const operation = positions.get(placeholder.source);
|
|
158
|
+
const { fingerprint } = await nodeAt(operation);
|
|
159
|
+
bound.set(object, {
|
|
160
|
+
$ref: { operation, fingerprint, path: [placeholder.field] },
|
|
161
|
+
});
|
|
162
|
+
}));
|
|
163
|
+
const args = rebuildArguments(record.args, [], (value) => typeof value === "object" && value !== null && bound.has(value)
|
|
164
|
+
? bound.get(value)
|
|
165
|
+
: KEEP);
|
|
168
166
|
return {
|
|
169
167
|
resource: record.resource,
|
|
170
168
|
family: record.identity.family,
|
|
@@ -195,6 +193,7 @@ export function createTransactionPlanAssembler(contracts, protocol) {
|
|
|
195
193
|
operations: await Promise.all(records.map((_, index) => nodeAt(index))),
|
|
196
194
|
},
|
|
197
195
|
origins: records.map((record) => originOf(record.origin)),
|
|
196
|
+
refused: new Map(records.flatMap((record, index) => record.refused === undefined ? [] : [[index, record.refused]])),
|
|
198
197
|
};
|
|
199
198
|
};
|
|
200
199
|
return { defer, assemble };
|
|
@@ -2,6 +2,7 @@ import type { AdapterModel } from "../adapters/adapter-model.js";
|
|
|
2
2
|
import type { Contract } from "../contracts/contract.js";
|
|
3
3
|
import type { ScalarField } from "../contracts/field.js";
|
|
4
4
|
import type { SemanticOperationArguments } from "../operations/operation-validator.js";
|
|
5
|
+
import { CallerDataError } from "../runtime/caller-data.copier.js";
|
|
5
6
|
import { type ReadProjectionPlan } from "../runtime/computed-read-runtime.js";
|
|
6
7
|
import type { FrameworkOperationRequest } from "../runtime/operation-request.js";
|
|
7
8
|
import type { OperationFailureResponse } from "../runtime/operation-response.js";
|
|
@@ -9,15 +10,37 @@ import type { OperationPipelineDependencies } from "../runtime/operation-runtime
|
|
|
9
10
|
import type { CascadeClosure } from "../runtime/referential-action.js";
|
|
10
11
|
import type { OperationFingerprint } from "./deferred-operation.js";
|
|
11
12
|
import type { TransactionReference } from "./transaction-reference.js";
|
|
13
|
+
import { type TransactionSlotShape } from "./transaction-reference.js";
|
|
14
|
+
import { type TransactionReferenceCandidateSlot } from "./transaction-reference-collector.js";
|
|
12
15
|
import type { FrameworkTransactionRequest, TransactionOperationOrigin } from "./transaction-request.js";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Where a plan's step arguments came from, so the validator knows whether to copy
|
|
18
|
+
* them at the door (see `ArgumentsSource`):
|
|
19
|
+
*
|
|
20
|
+
* - `"caller"` — `framework.executeTransaction`'s caller's own objects: every step's
|
|
21
|
+
* arguments are copied when the plan is handed in, before the validator's first
|
|
22
|
+
* await, so a step revoked or changed after the call is never read again;
|
|
23
|
+
* - `"owned"` — a plan the protocol decoder parsed, or the typed runner assembled
|
|
24
|
+
* from its builders' copies; `refused` names the steps whose arguments a builder
|
|
25
|
+
* could not copy, answered at their turn.
|
|
26
|
+
*/
|
|
27
|
+
export type PlanArguments = {
|
|
28
|
+
readonly source: "caller";
|
|
29
|
+
} | {
|
|
30
|
+
readonly source: "owned";
|
|
31
|
+
readonly refused?: ReadonlyMap<number, CallerDataError>;
|
|
17
32
|
};
|
|
33
|
+
export type { TransactionReferenceCandidateSlot } from "./transaction-reference-collector.js";
|
|
34
|
+
/** One validated Transaction Slot: where it is, what it holds, and its reference. */
|
|
18
35
|
export type TransactionReferenceSlot = {
|
|
19
36
|
readonly path: readonly (string | number)[];
|
|
37
|
+
/** The destination field. */
|
|
20
38
|
readonly field: ScalarField<Contract>;
|
|
39
|
+
readonly shape: TransactionSlotShape;
|
|
40
|
+
/** The slot is a scalar value of mutation data: what it resolves to is written. */
|
|
41
|
+
readonly written: boolean;
|
|
42
|
+
/** The source field, under its own step's Contract: what the slot receives. */
|
|
43
|
+
readonly source: ScalarField<Contract>;
|
|
21
44
|
readonly reference: TransactionReference;
|
|
22
45
|
};
|
|
23
46
|
export type CandidateTransactionOperation = {
|
|
@@ -48,10 +71,10 @@ export type ValidatedTransactionPlan = {
|
|
|
48
71
|
/**
|
|
49
72
|
* What validating a plan needs beyond one operation's pipeline: the cascade
|
|
50
73
|
* closure over the Adapter's referential actions, resolved once when the
|
|
51
|
-
* Framework is constructed. The
|
|
74
|
+
* Framework is constructed. The record-write facts are not among them: they
|
|
52
75
|
* are checked when each operation runs, after its pipes.
|
|
53
76
|
*/
|
|
54
|
-
export type TransactionPlanDependencies<M extends AdapterModel> = Omit<OperationPipelineDependencies<M>, "
|
|
77
|
+
export type TransactionPlanDependencies<M extends AdapterModel> = Omit<OperationPipelineDependencies<M>, "recordWrites"> & {
|
|
55
78
|
readonly cascades: CascadeClosure;
|
|
56
79
|
};
|
|
57
80
|
export type TransactionPlanValidationResult = {
|
|
@@ -70,4 +93,4 @@ export declare function transactionsUnavailableFailure(): OperationFailureRespon
|
|
|
70
93
|
/**
|
|
71
94
|
* Whole-plan Framework Validation Layer for transaction structure and identity.
|
|
72
95
|
*/
|
|
73
|
-
export declare function validateTransactionPlan<M extends AdapterModel>(dependencies: TransactionPlanDependencies<M>, request: FrameworkTransactionRequest, origins?: readonly TransactionOperationOrigin[]): Promise<TransactionPlanValidationResult>;
|
|
96
|
+
export declare function validateTransactionPlan<M extends AdapterModel>(dependencies: TransactionPlanDependencies<M>, request: FrameworkTransactionRequest, origins?: readonly TransactionOperationOrigin[], planArguments?: PlanArguments): Promise<TransactionPlanValidationResult>;
|