@aventara/core 1.0.0-rc.10 → 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 +79 -0
- package/ERRORS.md +82 -82
- package/README.md +57 -1
- package/dist/compiler/contract-compiler-diagnostic.guidance.js +1 -1
- package/dist/compiler/contract.compiler.js +56 -9
- package/dist/compiler/create-requirements.projector.js +1 -3
- package/dist/compiler/field-validator.compiler.js +1 -3
- package/dist/compiler/managed-elsewhere.projector.js +5 -5
- package/dist/config/cache-stage.factory.d.ts +24 -0
- package/dist/config/cache-stage.factory.js +3 -0
- package/dist/config/config.resolver.js +1 -7
- package/dist/config/config.validator.js +61 -13
- package/dist/config/exact-framework-config.d.ts +6 -0
- package/dist/config/field-compute.resolver.js +1 -3
- package/dist/config/pipeline-config.d.ts +16 -0
- package/dist/config/pipeline-tree.resolver.js +2 -3
- package/dist/contracts/canonical-json.writer.d.ts +7 -0
- package/dist/contracts/canonical-json.writer.js +55 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +64 -0
- package/dist/contracts/client-contract-structure.validator.js +12 -0
- package/dist/contracts/contract-canonicalizer.js +5 -0
- package/dist/contracts/contract-limits.d.ts +6 -0
- package/dist/contracts/contract-limits.js +2 -0
- package/dist/contracts/contract.d.ts +15 -0
- package/dist/contracts/json-schema.projector.js +1 -3
- package/dist/framework/access-facade.js +1 -3
- package/dist/framework/framework.factory.js +42 -13
- package/dist/framework/operation-facade.d.ts +67 -6
- package/dist/framework/operation-facade.js +7 -0
- package/dist/framework/operation-set.runner.d.ts +47 -0
- package/dist/framework/operation-set.runner.js +168 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/internal.d.ts +2 -0
- package/dist/internal.js +2 -0
- package/dist/operations/operation-validator-core.js +2 -4
- package/dist/operations/structural-limits.walker.js +1 -3
- package/dist/policy/access-question.runtime.js +1 -3
- package/dist/policy/policy-admission.js +1 -3
- package/dist/policy/policy-after-update.runtime.js +1 -3
- package/dist/policy/policy-nested-write.runtime.js +3 -12
- package/dist/policy/policy-read.runtime.js +1 -3
- package/dist/policy/policy-reference-write.runtime.js +2 -11
- package/dist/policy/policy-request.d.ts +31 -0
- package/dist/policy/policy-request.js +69 -17
- package/dist/policy/policy-session.js +1 -3
- package/dist/policy/policy-write.runtime.js +1 -3
- package/dist/prebuilt/core-version.generated.d.ts +1 -1
- package/dist/prebuilt/core-version.generated.js +1 -1
- package/dist/prebuilt/prebuilt-changes.js +1 -3
- package/dist/prebuilt/prebuilt-contracts.loader.js +1 -3
- package/dist/prebuilt/prebuilt-inputs.fingerprint.js +1 -3
- package/dist/protocol/absent-route.responder.d.ts +69 -16
- package/dist/protocol/absent-route.responder.js +75 -31
- package/dist/protocol/contract-document.responder.d.ts +7 -0
- package/dist/protocol/contract-document.responder.js +3 -2
- package/dist/protocol/http-request.decoder.d.ts +33 -0
- package/dist/protocol/http-request.decoder.js +23 -7
- package/dist/protocol/http-request.reader.d.ts +4 -0
- package/dist/protocol/http-request.reader.js +11 -2
- package/dist/protocol/http-response.encoder.d.ts +12 -0
- package/dist/protocol/http-response.encoder.js +15 -1
- 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 +9 -0
- package/dist/protocol/protocol-headers.js +12 -5
- package/dist/protocol/protocol-surface.d.ts +12 -4
- package/dist/protocol/protocol-surface.js +34 -1
- package/dist/protocol/protocol.binder.d.ts +37 -1
- package/dist/protocol/protocol.binder.js +2 -0
- package/dist/protocol/protocol.handler.d.ts +35 -2
- package/dist/protocol/protocol.handler.js +84 -8
- 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/computed-read-runtime.js +2 -8
- package/dist/runtime/create-requirement.js +1 -3
- package/dist/runtime/diagnostics-reporter.d.ts +6 -1
- package/dist/runtime/diagnostics-reporter.js +3 -8
- package/dist/runtime/error.catalog.d.ts +2 -2
- package/dist/runtime/error.catalog.js +1 -1
- package/dist/runtime/field-stage.runtime.d.ts +0 -2
- package/dist/runtime/field-stage.runtime.js +1 -7
- package/dist/runtime/field-validator.runtime.js +2 -1
- package/dist/runtime/mutation-planner.js +1 -3
- package/dist/runtime/nested-write.walker.js +2 -1
- package/dist/runtime/output-validator.js +1 -3
- package/dist/runtime/owned-execution.registry.d.ts +22 -2
- package/dist/runtime/pipeline.d.ts +5 -1
- package/dist/runtime/record.guard.d.ts +14 -0
- package/dist/runtime/record.guard.js +10 -0
- package/dist/runtime/request-envelope.validator.js +13 -10
- package/dist/runtime/scalar-runtime.d.ts +0 -10
- package/dist/runtime/scalar-runtime.js +1 -10
- package/dist/runtime/thenable.guard.d.ts +7 -0
- package/dist/runtime/thenable.guard.js +5 -0
- package/dist/runtime/unsent-value.normalizer.js +2 -1
- package/dist/transactions/operation-arguments-encoder.js +1 -7
- package/dist/transactions/sql-statement.validator.js +2 -1
- package/dist/transactions/transaction-plan-assembler.js +1 -7
- package/dist/transactions/transaction-plan-validator.js +4 -6
- package/dist/transactions/transaction-reference-collector.js +8 -10
- package/dist/transactions/transaction-reference-resolver.js +1 -3
- package/dist/transactions/transaction-runtime.js +31 -2
- package/dist/transactions/transaction-stage.runtime.js +1 -3
- package/package.json +1 -1
|
@@ -12,6 +12,10 @@ export type AvContractLimits = {
|
|
|
12
12
|
readonly maxBooleanNodes: number;
|
|
13
13
|
/** How deeply a `json` field's value may nest: its arrays and objects, counted from the value. */
|
|
14
14
|
readonly maxJsonDepth: number;
|
|
15
|
+
/** The most operations one Operation Set (`POST /_all`) may hold. */
|
|
16
|
+
readonly maxAll: number;
|
|
17
|
+
/** The most entries of one Operation Set that run at once; at least 1. */
|
|
18
|
+
readonly maxAllConcurrency: number;
|
|
15
19
|
};
|
|
16
20
|
/** The limits in force when the configuration sets none. */
|
|
17
21
|
export declare const DEFAULT_CONTRACT_LIMITS: {
|
|
@@ -21,4 +25,6 @@ export declare const DEFAULT_CONTRACT_LIMITS: {
|
|
|
21
25
|
readonly maxTransactionOperations: 20;
|
|
22
26
|
readonly maxBooleanNodes: 50;
|
|
23
27
|
readonly maxJsonDepth: 64;
|
|
28
|
+
readonly maxAll: 10;
|
|
29
|
+
readonly maxAllConcurrency: 4;
|
|
24
30
|
};
|
|
@@ -56,6 +56,21 @@ export interface AvContractApplication extends AvContract {
|
|
|
56
56
|
* identified by its hash.
|
|
57
57
|
*/
|
|
58
58
|
export interface AvContractClient extends AvContract {
|
|
59
|
+
/**
|
|
60
|
+
* The Resources, by name. One with a cached read carries `cache`, by `find`
|
|
61
|
+
* variant: that read is also served as
|
|
62
|
+
* `GET /_resources/<resource>/find/<variant>?q=…&v=…`, which a browser
|
|
63
|
+
* (`for: "user"`), a CDN for anonymous callers (`"anonymous"`) or a CDN for
|
|
64
|
+
* everyone (`"everyone"`) may keep for `maxAge` seconds.
|
|
65
|
+
*/
|
|
66
|
+
readonly resources: Readonly<Record<string, AvResource<this> & {
|
|
67
|
+
readonly cache?: {
|
|
68
|
+
readonly [variant in "first" | "unique" | "many" | "count"]?: {
|
|
69
|
+
readonly for: "user" | "anonymous" | "everyone";
|
|
70
|
+
readonly maxAge: number;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}>>;
|
|
59
74
|
/** The protocol version and this Contract's hash. */
|
|
60
75
|
readonly protocol: AvContractClientProtocol;
|
|
61
76
|
/**
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3
|
-
}
|
|
1
|
+
import { isRecord } from "../runtime/record.guard.js";
|
|
4
2
|
function memberSchema(schema) {
|
|
5
3
|
if (!isRecord(schema)) {
|
|
6
4
|
throw new TypeError("the schema is not one of the forms a ClientContract states");
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { projectJsonValue } from "../contracts/json-schema.projector.js";
|
|
2
2
|
import { ACCESS_VERB_NAMES, ACCESS_VERBS, providerVerb, } from "../policy/access-verb.table.js";
|
|
3
3
|
import { copyAtDoor } from "../runtime/caller-data.door.js";
|
|
4
|
+
import { isRecord } from "../runtime/record.guard.js";
|
|
4
5
|
import { requestIdOf } from "../runtime/request-id.js";
|
|
5
6
|
import { stateOptionOf } from "../runtime/request-state.resolver.js";
|
|
6
7
|
import { encodeOperationArgumentsForWire } from "../transactions/operation-arguments-encoder.js";
|
|
@@ -63,9 +64,6 @@ function stateOf(options) {
|
|
|
63
64
|
const state = stateOptionOf(options);
|
|
64
65
|
return state === undefined ? {} : { state };
|
|
65
66
|
}
|
|
66
|
-
function isRecord(value) {
|
|
67
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
68
|
-
}
|
|
69
67
|
function wireQuestions(contract, questions) {
|
|
70
68
|
const copy = copyAtDoor({ questions });
|
|
71
69
|
if (!copy.ok) {
|
|
@@ -9,7 +9,7 @@ import { recordAccessProvider } from "../policy/access-provider.registry.js";
|
|
|
9
9
|
import { recordAccessQuestions } from "../policy/access-question.registry.js";
|
|
10
10
|
import { createAccessQuestionAnswerer } from "../policy/access-question.runtime.js";
|
|
11
11
|
import { heldTargetsOf } from "../policy/policy-reference-write.runtime.js";
|
|
12
|
-
import { callerOf } from "../policy/policy-request.js";
|
|
12
|
+
import { callerOf, derivePolicyCaller, } from "../policy/policy-request.js";
|
|
13
13
|
import { policyStartupDiagnostics } from "../policy/policy-startup.validator.js";
|
|
14
14
|
import { loadPrebuiltContracts, warnStalePrebuilt, } from "../prebuilt/prebuilt-contracts.loader.js";
|
|
15
15
|
import { copyAtDoor, copyEnvelopeAtDoor, refuseCallerData, } from "../runtime/caller-data.door.js";
|
|
@@ -26,7 +26,8 @@ import { createTransactionPlanAssembler } from "../transactions/transaction-plan
|
|
|
26
26
|
import { createTransactionRuntime } from "../transactions/transaction-runtime.js";
|
|
27
27
|
import { createServerClientAccess } from "./access-facade.js";
|
|
28
28
|
import { AvConstructionError } from "./framework-construction.error.js";
|
|
29
|
-
import { createOperationFacade, createOperationTree, settleOperation, } from "./operation-facade.js";
|
|
29
|
+
import { createAbortableOperationFacade, createOperationFacade, createOperationTree, settleOperation, } from "./operation-facade.js";
|
|
30
|
+
import { runOperationSet } from "./operation-set.runner.js";
|
|
30
31
|
const APPLICATION_SQL_BUILDER = "$sql";
|
|
31
32
|
export async function createFramework(config) {
|
|
32
33
|
const configDiagnostics = validateFrameworkConfig(config);
|
|
@@ -55,6 +56,10 @@ export async function createFramework(config) {
|
|
|
55
56
|
if (!compilation.ok) {
|
|
56
57
|
throw new AvConstructionError("contract-compilation", compilation.diagnostics);
|
|
57
58
|
}
|
|
59
|
+
const clashes = serverClientClashes(compilation.contracts);
|
|
60
|
+
if (clashes.length > 0) {
|
|
61
|
+
throw new AvConstructionError("contract-compilation", clashes);
|
|
62
|
+
}
|
|
58
63
|
const forcing = validateForcedOperations(config, compilation.contracts);
|
|
59
64
|
if (forcing.length > 0) {
|
|
60
65
|
throw new AvConstructionError("configuration", forcing);
|
|
@@ -79,7 +84,7 @@ export async function createFramework(config) {
|
|
|
79
84
|
const executeTransaction = createTransactionRuntime(runtimeDependencies, pipelineDependencies);
|
|
80
85
|
const misuse = createMisuseReporter(resolvedConfig.misuse);
|
|
81
86
|
const executeOperation = (request, caller) => executeTotally(execute, request, resolvedConfig.diagnostics, "caller", caller);
|
|
82
|
-
const
|
|
87
|
+
const prepareApplicationValues = (request, caller) => ((copy) => () => executeTotally(encodingApplicationValues(execute, compilation.contracts.client, copy), request, resolvedConfig.diagnostics, "caller", caller))(copyArgumentsNow(request.arguments));
|
|
83
88
|
const protocol = {
|
|
84
89
|
version: AVENTARA_PROTOCOL_VERSION,
|
|
85
90
|
hash: compilation.contracts.client.protocol.hash,
|
|
@@ -116,7 +121,7 @@ export async function createFramework(config) {
|
|
|
116
121
|
arguments: args,
|
|
117
122
|
}), executeOperation),
|
|
118
123
|
client: createOperationFacade(model, clientRequest, executeOperation),
|
|
119
|
-
serverClient:
|
|
124
|
+
serverClient: withServerClientMembers(createAbortableOperationFacade(model, clientRequest, prepareApplicationValues), (entries, options) => runOperationSet(entries, options, compilation.contracts.client.limits), accessAnswerer === undefined
|
|
120
125
|
? undefined
|
|
121
126
|
: createServerClientAccess({
|
|
122
127
|
contract: compilation.contracts.client,
|
|
@@ -140,7 +145,8 @@ export async function createFramework(config) {
|
|
|
140
145
|
recordAccessQuestions(framework, accessAnswerer);
|
|
141
146
|
}
|
|
142
147
|
recordOwnedExecution(framework, {
|
|
143
|
-
execute: (request, refused) => executeTotally(execute, request, resolvedConfig.diagnostics, refused === undefined ? "owned" : { refused }),
|
|
148
|
+
execute: (request, refused, member) => executeTotally(execute, request, resolvedConfig.diagnostics, refused === undefined ? "owned" : { refused }, member?.caller, member?.key),
|
|
149
|
+
caller: (request) => derivePolicyCaller(resolvedConfig.policy, request),
|
|
144
150
|
executeTransaction: (request, refused) => executeTransactionTotally(executeTransaction, request, resolvedConfig.diagnostics, undefined, refused === undefined
|
|
145
151
|
? { source: "owned" }
|
|
146
152
|
: { source: "owned", refused }),
|
|
@@ -169,9 +175,19 @@ async function prebuiltCompilation(prebuilt, model, config, resolved) {
|
|
|
169
175
|
}
|
|
170
176
|
return { ok: true, contracts: loaded.contracts };
|
|
171
177
|
}
|
|
172
|
-
function
|
|
178
|
+
function copyArgumentsNow(args) {
|
|
179
|
+
try {
|
|
180
|
+
return copyAtDoor(args);
|
|
181
|
+
}
|
|
182
|
+
catch (thrown) {
|
|
183
|
+
return { thrown };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function encodingApplicationValues(execute, contract, copy) {
|
|
173
187
|
return (request, report, _source, caller) => {
|
|
174
|
-
|
|
188
|
+
if ("thrown" in copy) {
|
|
189
|
+
throw copy.thrown;
|
|
190
|
+
}
|
|
175
191
|
if (!copy.ok) {
|
|
176
192
|
return execute(request, report, { refused: copy.error }, caller);
|
|
177
193
|
}
|
|
@@ -181,8 +197,8 @@ function encodingApplicationValues(execute, contract) {
|
|
|
181
197
|
}, report, "owned", caller);
|
|
182
198
|
};
|
|
183
199
|
}
|
|
184
|
-
async function executeTotally(execute, request, diagnostics, source, caller) {
|
|
185
|
-
const report = createDiagnosticsReporter(diagnostics, request);
|
|
200
|
+
async function executeTotally(execute, request, diagnostics, source, caller, key) {
|
|
201
|
+
const report = createDiagnosticsReporter(diagnostics, request, undefined, key);
|
|
186
202
|
try {
|
|
187
203
|
return await execute(request, report, source, caller);
|
|
188
204
|
}
|
|
@@ -263,8 +279,21 @@ async function runTransactionTotally(execute, assembler, operations, requestId,
|
|
|
263
279
|
statements: assembled.statements,
|
|
264
280
|
}, caller);
|
|
265
281
|
}
|
|
266
|
-
function
|
|
267
|
-
return
|
|
268
|
-
|
|
269
|
-
|
|
282
|
+
function withServerClientMembers(facade, all, access) {
|
|
283
|
+
return Object.freeze({
|
|
284
|
+
...facade,
|
|
285
|
+
all,
|
|
286
|
+
...(access === undefined ? {} : { $access: access }),
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
function serverClientClashes(contracts) {
|
|
290
|
+
return Object.hasOwn(contracts.client.resources, "all")
|
|
291
|
+
? [
|
|
292
|
+
{
|
|
293
|
+
code: "COMPILER_RESERVED_RESOURCE_NAME",
|
|
294
|
+
path: "adapter.model.resources.all",
|
|
295
|
+
message: 'resource "all" clashes with serverClient.all; rename the Resource or expose it under another name',
|
|
296
|
+
},
|
|
297
|
+
]
|
|
298
|
+
: [];
|
|
270
299
|
}
|
|
@@ -39,13 +39,29 @@ export type AvAppTxPlainCall<in out C extends AvContract, in out R extends AvRes
|
|
|
39
39
|
export type AvClientTxProjectingCall<in out C extends AvContract, in out R extends AvResourceKey<C>, in out I extends AvOperationIdentity> = DeferredProjectingCall<C, R, I, DeferredArguments<C, R, I, AvWireScalarForms, AvApplicationScalarForms>, AvApplicationScalarForms, "client">;
|
|
40
40
|
/** `framework.clientTx.<Resource>.<family>.<variant>` when it does not. */
|
|
41
41
|
export type AvClientTxPlainCall<in out C extends AvContract, in out R extends AvResourceKey<C>, in out I extends AvOperationIdentity> = DeferredPlainCall<C, R, I, DeferredArguments<C, R, I, AvWireScalarForms, AvApplicationScalarForms>, AvApplicationScalarForms, "client">;
|
|
42
|
+
/** A `serverClient` call's options: {@link AvExecutionOptions}, and the call's own abort signal. */
|
|
43
|
+
type AvServerClientCallOptions = AvExecutionOptions & {
|
|
44
|
+
/**
|
|
45
|
+
* Aborts this call only. Aborted before the call runs, it never runs;
|
|
46
|
+
* while it runs, it rejects with the signal's reason at once, and the
|
|
47
|
+
* database finishes what it started. Any platform's `AbortSignal` is one.
|
|
48
|
+
*/
|
|
49
|
+
readonly signal?: {
|
|
50
|
+
readonly aborted: boolean;
|
|
51
|
+
readonly reason: unknown;
|
|
52
|
+
addEventListener(type: "abort", listener: () => void, options?: {
|
|
53
|
+
readonly once?: boolean;
|
|
54
|
+
}): void;
|
|
55
|
+
removeEventListener(type: "abort", listener: () => void): void;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
42
58
|
/**
|
|
43
59
|
* `framework.serverClient.<Resource>.<family>.<variant>` when the variant takes a `select` or `include`:
|
|
44
60
|
* the Client Contract's view, application forms in.
|
|
45
61
|
*/
|
|
46
|
-
export type AvServerClientProjectingCall<in out C extends AvContract, in out R extends AvResourceKey<C>, in out I extends AvOperationIdentity> = ProjectingCall<C, R, I, AvOperationArgumentsFor<C, R, I, AvApplicationScalarForms>, AvApplicationScalarForms,
|
|
62
|
+
export type AvServerClientProjectingCall<in out C extends AvContract, in out R extends AvResourceKey<C>, in out I extends AvOperationIdentity> = ProjectingCall<C, R, I, AvOperationArgumentsFor<C, R, I, AvApplicationScalarForms>, AvApplicationScalarForms, AvServerClientCallOptions>;
|
|
47
63
|
/** `framework.serverClient.<Resource>.<family>.<variant>` when it does not. */
|
|
48
|
-
export type AvServerClientPlainCall<in out C extends AvContract, in out R extends AvResourceKey<C>, in out I extends AvOperationIdentity> = PlainCall<C, R, I, AvOperationArgumentsFor<C, R, I, AvApplicationScalarForms>, AvApplicationScalarForms,
|
|
64
|
+
export type AvServerClientPlainCall<in out C extends AvContract, in out R extends AvResourceKey<C>, in out I extends AvOperationIdentity> = PlainCall<C, R, I, AvOperationArgumentsFor<C, R, I, AvApplicationScalarForms>, AvApplicationScalarForms, AvServerClientCallOptions>;
|
|
49
65
|
/**
|
|
50
66
|
* `framework.serverClientTx.<Resource>.<family>.<variant>` when the variant takes a `select` or `include`:
|
|
51
67
|
* the Client Contract's view, application forms in, a client-origin handle out.
|
|
@@ -117,13 +133,50 @@ export type AvApplicationFacade<C extends AvContract> = {
|
|
|
117
133
|
export type AvClientFacade<C extends AvContract> = {
|
|
118
134
|
readonly [R in AvResourceKey<C>]: AvClientResourceFacade<C, R>;
|
|
119
135
|
};
|
|
136
|
+
/** `framework.serverClient.all`: its own member beside the Resources. */
|
|
137
|
+
type ServerClientAll = {
|
|
138
|
+
/**
|
|
139
|
+
* Awaits an object of calls together, in process (any number of them:
|
|
140
|
+
* `limits.maxAll` guards the HTTP door only), and resolves one value per key. A call already runs when it is made;
|
|
141
|
+
* an `avLazy(() => call)` entry is started by `all`, at most
|
|
142
|
+
* `limits.maxAllConcurrency` at once. Strict: the first failure rejects it
|
|
143
|
+
* and its `avLazy` entries not yet started never start (fail-fast, not
|
|
144
|
+
* atomic: what already ran stays done). With `settle: true` every key settles as `{ status, value }`
|
|
145
|
+
* or `{ status, reason }`. Its `signal` aborts each of its calls and no other.
|
|
146
|
+
*/
|
|
147
|
+
readonly all: <E extends {
|
|
148
|
+
readonly [key: string]: PromiseLike<unknown>;
|
|
149
|
+
}, S extends boolean = false>(entries: E, options?: {
|
|
150
|
+
/** Aborts every call of this `all`, and no other. Any platform's `AbortSignal` is one. */
|
|
151
|
+
readonly signal?: {
|
|
152
|
+
readonly aborted: boolean;
|
|
153
|
+
readonly reason: unknown;
|
|
154
|
+
addEventListener(type: "abort", listener: () => void, options?: {
|
|
155
|
+
readonly once?: boolean;
|
|
156
|
+
}): void;
|
|
157
|
+
removeEventListener(type: "abort", listener: () => void): void;
|
|
158
|
+
};
|
|
159
|
+
/** true settles every key on its own and never rejects for one; strict otherwise. */
|
|
160
|
+
readonly settle?: S;
|
|
161
|
+
}) => Promise<S extends true ? {
|
|
162
|
+
-readonly [K in keyof E]: {
|
|
163
|
+
readonly status: "fulfilled";
|
|
164
|
+
readonly value: Awaited<E[K]>;
|
|
165
|
+
} | {
|
|
166
|
+
readonly status: "rejected";
|
|
167
|
+
readonly reason: unknown;
|
|
168
|
+
};
|
|
169
|
+
} : {
|
|
170
|
+
-readonly [K in keyof E]: Awaited<E[K]>;
|
|
171
|
+
}>;
|
|
172
|
+
};
|
|
120
173
|
/**
|
|
121
174
|
* `framework.serverClient`: one {@link AvServerClientResourceFacade} per Resource
|
|
122
|
-
* of `C`, the Client Contract's view, taking application forms
|
|
175
|
+
* of `C`, the Client Contract's view, taking application forms, and `all`.
|
|
123
176
|
*/
|
|
124
177
|
export type AvServerClientFacade<C extends AvContract> = {
|
|
125
178
|
readonly [R in AvResourceKey<C>]: AvServerClientResourceFacade<C, R>;
|
|
126
|
-
};
|
|
179
|
+
} & ServerClientAll;
|
|
127
180
|
/** `framework.appTx.$sql`: the developer SQL step only an application transaction has. */
|
|
128
181
|
type ApplicationSqlStep = {
|
|
129
182
|
/**
|
|
@@ -156,7 +209,7 @@ export type AvServerClientTxFacade<C extends AvContract> = {
|
|
|
156
209
|
};
|
|
157
210
|
type ApplicationSurface<C> = C extends AvContract ? string extends AvResourceKey<C> ? OpaqueSurface : AvApplicationFacade<C> : never;
|
|
158
211
|
type ClientSurface<C> = C extends AvContract ? string extends AvResourceKey<C> ? OpaqueSurface : AvClientFacade<C> : never;
|
|
159
|
-
type ServerClientSurface<C> = C extends AvContract ? string extends AvResourceKey<C> ? OpaqueSurface : AvServerClientFacade<C> : never;
|
|
212
|
+
type ServerClientSurface<C> = C extends AvContract ? string extends AvResourceKey<C> ? OpaqueSurface & ServerClientAll : AvServerClientFacade<C> : never;
|
|
160
213
|
type ApplicationDeferredSurface<C> = C extends AvContract ? string extends AvResourceKey<C> ? OpaqueSurface & ApplicationSqlStep : AvAppTxFacade<C> : never;
|
|
161
214
|
type ClientDeferredSurface<C> = C extends AvContract ? string extends AvResourceKey<C> ? OpaqueSurface : AvClientTxFacade<C> : never;
|
|
162
215
|
type ServerClientDeferredSurface<C> = C extends AvContract ? string extends AvResourceKey<C> ? OpaqueSurface : AvServerClientTxFacade<C> : never;
|
|
@@ -164,7 +217,7 @@ type ServerClientDeferredSurface<C> = C extends AvContract ? string extends AvRe
|
|
|
164
217
|
export type ApplicationOperations<M extends AvAdapterModel, Cfg> = ApplicationSurface<AvContractApplicationView<M, Cfg>>;
|
|
165
218
|
/** `framework.client`'s type: {@link AvClientFacade}, or opaque. */
|
|
166
219
|
export type ClientOperations<M extends AvAdapterModel, Cfg> = ClientSurface<ClientContractView<M, Cfg>>;
|
|
167
|
-
/** `framework.serverClient`'s type: {@link AvServerClientFacade}, or opaque
|
|
220
|
+
/** `framework.serverClient`'s type: {@link AvServerClientFacade}, or opaque with `all`, and `$access`. */
|
|
168
221
|
export type ServerClientOperations<M extends AvAdapterModel, Cfg> = ServerClientSurface<ClientContractView<M, Cfg>> & ServerClientAccess<ClientContractView<M, Cfg>, AccessProviderOf<Cfg>>;
|
|
169
222
|
/** `framework.appTx`'s type: {@link AvAppTxFacade}, or opaque with `$sql`. */
|
|
170
223
|
export type ApplicationTransactionBuilders<M extends AvAdapterModel, Cfg> = ApplicationDeferredSurface<AvContractApplicationView<M, Cfg>>;
|
|
@@ -217,6 +270,14 @@ export declare function createOperationFacade<Facade>(model: AvAdapterModel, req
|
|
|
217
270
|
* the response's data, or its failure thrown.
|
|
218
271
|
*/
|
|
219
272
|
export declare function settleOperation(response: AvOperationResponse | AvTransactionResponse): unknown;
|
|
273
|
+
/** Prepares one call's run: its arguments are read when the call is made. */
|
|
274
|
+
type FacadePreparer = (request: AvOperationRequest, caller: PolicyCaller | undefined) => () => Promise<AvOperationResponse>;
|
|
275
|
+
/**
|
|
276
|
+
* {@link createOperationFacade}'s twin for `framework.serverClient`: a call
|
|
277
|
+
* builds its request and runs at once, and the caller's `signal` aborts it
|
|
278
|
+
* (already aborted, it never runs; aborted while it runs, it rejects at once).
|
|
279
|
+
*/
|
|
280
|
+
export declare function createAbortableOperationFacade<Facade>(model: AvAdapterModel, request: FacadeRequest, prepare: FacadePreparer): Facade;
|
|
220
281
|
/**
|
|
221
282
|
* One leaf of an operation tree: the callable for one advertised variant. The
|
|
222
283
|
* second parameter is a façade call's options; a builder leaf ignores it.
|
|
@@ -4,6 +4,7 @@ import { callerOf } from "../policy/policy-request.js";
|
|
|
4
4
|
import { thrownFailure } from "../runtime/framework-error.factory.js";
|
|
5
5
|
import { requestIdOf } from "../runtime/request-id.js";
|
|
6
6
|
import { stateOptionOf } from "../runtime/request-state.resolver.js";
|
|
7
|
+
import { runAbortable, signalOptionOf } from "./operation-set.runner.js";
|
|
7
8
|
export function createOperationFacade(model, request, execute) {
|
|
8
9
|
return createOperationTree(model, (resource, identity) => async (args, options) => settleOperation(await execute(request(resource, identity, args === undefined ? {} : args, requestIdOf(options), stateOptionOf(options)), callerOf(options))));
|
|
9
10
|
}
|
|
@@ -13,6 +14,12 @@ export function settleOperation(response) {
|
|
|
13
14
|
}
|
|
14
15
|
return response.data;
|
|
15
16
|
}
|
|
17
|
+
export function createAbortableOperationFacade(model, request, prepare) {
|
|
18
|
+
return createOperationTree(model, (resource, identity) => (args, options) => {
|
|
19
|
+
const run = prepare(request(resource, identity, args === undefined ? {} : args, requestIdOf(options), stateOptionOf(options)), callerOf(options));
|
|
20
|
+
return runAbortable(async () => settleOperation(await run()), signalOptionOf(options));
|
|
21
|
+
});
|
|
22
|
+
}
|
|
16
23
|
export function createOperationTree(model, leaf) {
|
|
17
24
|
const resources = Object.entries(model.resources).map(([resource, { operations }]) => {
|
|
18
25
|
const families = Object.entries(operations).map(([family, variants]) => [family, variantLeaves(leaf, resource, family, variants)]);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { AvContractLimits } from "../contracts/contract-limits.js";
|
|
2
|
+
/**
|
|
3
|
+
* What core reads of an abort signal: the platform's `AbortSignal` (DOM's,
|
|
4
|
+
* Node's, any runtime's) is one, structurally. Core runs in any JS runtime, so
|
|
5
|
+
* its declarations name no platform global (rc.11): a consumer with neither
|
|
6
|
+
* DOM's lib nor Node's types type-checks them. The public signatures spell this
|
|
7
|
+
* shape inline (`serverClient` calls, `serverClient.all`, the protocol's
|
|
8
|
+
* `handleAll`): no new public name.
|
|
9
|
+
*/
|
|
10
|
+
export type AbortSignalShape = {
|
|
11
|
+
readonly aborted: boolean;
|
|
12
|
+
readonly reason: unknown;
|
|
13
|
+
addEventListener(type: "abort", listener: () => void, options?: {
|
|
14
|
+
readonly once?: boolean;
|
|
15
|
+
}): void;
|
|
16
|
+
removeEventListener(type: "abort", listener: () => void): void;
|
|
17
|
+
};
|
|
18
|
+
/** `options.signal` when it is an abort signal; anything else is ignored. */
|
|
19
|
+
export declare function signalOptionOf(options: unknown): AbortSignalShape | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Runs `run` now under `signal`: an eager call's own abort. Already aborted, it
|
|
22
|
+
* never runs; aborted while it runs, it rejects at once with the signal's reason.
|
|
23
|
+
*/
|
|
24
|
+
export declare function runAbortable(run: () => Promise<unknown>, signal: AbortSignalShape | undefined): Promise<unknown>;
|
|
25
|
+
/**
|
|
26
|
+
* A call made later: `avLazy(() => avClient.Post.find.many(args))` makes the
|
|
27
|
+
* call on each `then`, `catch` or `finally`, never before the first, and
|
|
28
|
+
* answers what that call answers. It keeps no answer: awaited again (by another
|
|
29
|
+
* request, say), it makes the call again, in the context awaiting it. Given to
|
|
30
|
+
* `all`, it is started by `all`, at most `limits.maxAllConcurrency` at once,
|
|
31
|
+
* and never when `all` has already failed (strict) or been aborted.
|
|
32
|
+
*/
|
|
33
|
+
export declare function avLazy<T>(make: () => PromiseLike<T>): Promise<T>;
|
|
34
|
+
/**
|
|
35
|
+
* The Contract's `limits.maxAllConcurrency`, for `all` here and for `POST /_all`
|
|
36
|
+
* (`protocol/operation-set.handler.ts`). A compiled Contract always holds a
|
|
37
|
+
* whole number of at least 1; a hand-built one that does not runs its entries
|
|
38
|
+
* one at a time, never none.
|
|
39
|
+
*/
|
|
40
|
+
export declare function maxAllConcurrencyOf(limits: AvContractLimits): number;
|
|
41
|
+
/**
|
|
42
|
+
* `all(entries, options?)` over `limits` (the Client Contract's): see the module
|
|
43
|
+
* comment. Rejects with a `TypeError`, before anything runs, when `entries` is not
|
|
44
|
+
* an object whose every value is a promise. Any number of entries is accepted:
|
|
45
|
+
* `limits.maxAll` guards the HTTP door only.
|
|
46
|
+
*/
|
|
47
|
+
export declare function runOperationSet(entries: unknown, options: unknown, limits: AvContractLimits): Promise<unknown>;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { isThenable } from "../runtime/thenable.guard.js";
|
|
2
|
+
const LAZY_CALLS = new WeakMap();
|
|
3
|
+
const ignore = () => undefined;
|
|
4
|
+
export function signalOptionOf(options) {
|
|
5
|
+
if (typeof options !== "object" || options === null) {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
const signal = options.signal;
|
|
9
|
+
return typeof signal === "object" &&
|
|
10
|
+
signal !== null &&
|
|
11
|
+
typeof signal.aborted === "boolean" &&
|
|
12
|
+
typeof signal.addEventListener === "function"
|
|
13
|
+
? signal
|
|
14
|
+
: undefined;
|
|
15
|
+
}
|
|
16
|
+
function start(run, signal) {
|
|
17
|
+
if (signal?.aborted === true) {
|
|
18
|
+
return { result: Promise.reject(signal.reason), done: Promise.resolve() };
|
|
19
|
+
}
|
|
20
|
+
let running;
|
|
21
|
+
try {
|
|
22
|
+
running = run();
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
running = Promise.reject(error);
|
|
26
|
+
}
|
|
27
|
+
const done = running.then(ignore, ignore);
|
|
28
|
+
if (signal === undefined) {
|
|
29
|
+
return { result: running, done };
|
|
30
|
+
}
|
|
31
|
+
const result = new Promise((resolve, reject) => {
|
|
32
|
+
const aborted = () => reject(signal.reason);
|
|
33
|
+
signal.addEventListener("abort", aborted, { once: true });
|
|
34
|
+
running.then((value) => {
|
|
35
|
+
signal.removeEventListener("abort", aborted);
|
|
36
|
+
resolve(value);
|
|
37
|
+
}, (error) => {
|
|
38
|
+
signal.removeEventListener("abort", aborted);
|
|
39
|
+
reject(error);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
return { result, done };
|
|
43
|
+
}
|
|
44
|
+
export function runAbortable(run, signal) {
|
|
45
|
+
return start(run, signal).result;
|
|
46
|
+
}
|
|
47
|
+
export function avLazy(make) {
|
|
48
|
+
const run = () => Promise.resolve(make());
|
|
49
|
+
const record = {
|
|
50
|
+
begin: (signal) => start(run, signal),
|
|
51
|
+
};
|
|
52
|
+
const result = () => record.begin().result;
|
|
53
|
+
const lazy = Object.freeze({
|
|
54
|
+
then: (onFulfilled, onRejected) => result().then(onFulfilled, onRejected),
|
|
55
|
+
catch: (onRejected) => result().catch(onRejected),
|
|
56
|
+
finally: (onFinally) => result().finally(onFinally),
|
|
57
|
+
[Symbol.toStringTag]: "Promise",
|
|
58
|
+
});
|
|
59
|
+
LAZY_CALLS.set(lazy, record);
|
|
60
|
+
return lazy;
|
|
61
|
+
}
|
|
62
|
+
export function maxAllConcurrencyOf(limits) {
|
|
63
|
+
const limit = limits.maxAllConcurrency;
|
|
64
|
+
return typeof limit === "number" && Number.isSafeInteger(limit) && limit >= 1
|
|
65
|
+
? limit
|
|
66
|
+
: 1;
|
|
67
|
+
}
|
|
68
|
+
export function runOperationSet(entries, options, limits) {
|
|
69
|
+
if (typeof entries !== "object" ||
|
|
70
|
+
entries === null ||
|
|
71
|
+
Array.isArray(entries)) {
|
|
72
|
+
return Promise.reject(new TypeError("all takes an object of calls: { key: avClient.Resource.find.many(…), … }."));
|
|
73
|
+
}
|
|
74
|
+
const keyed = [];
|
|
75
|
+
for (const key of Object.keys(entries)) {
|
|
76
|
+
const value = entries[key];
|
|
77
|
+
if (!isThenable(value)) {
|
|
78
|
+
return Promise.reject(new TypeError(`all's entry ${JSON.stringify(key)} is not a call.`));
|
|
79
|
+
}
|
|
80
|
+
keyed.push([key, value]);
|
|
81
|
+
}
|
|
82
|
+
const settle = typeof options === "object" &&
|
|
83
|
+
options !== null &&
|
|
84
|
+
options.settle === true;
|
|
85
|
+
const outer = signalOptionOf(options);
|
|
86
|
+
const group = new AbortController();
|
|
87
|
+
const forward = () => {
|
|
88
|
+
group.abort(outer?.reason);
|
|
89
|
+
};
|
|
90
|
+
if (outer?.aborted === true) {
|
|
91
|
+
forward();
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
outer?.addEventListener("abort", forward, { once: true });
|
|
95
|
+
}
|
|
96
|
+
const list = keyed.map(([key, value]) => {
|
|
97
|
+
const record = LAZY_CALLS.get(value);
|
|
98
|
+
let resolve = ignore;
|
|
99
|
+
let reject = ignore;
|
|
100
|
+
const outcome = new Promise((onResolve, onReject) => {
|
|
101
|
+
resolve = onResolve;
|
|
102
|
+
reject = onReject;
|
|
103
|
+
});
|
|
104
|
+
return {
|
|
105
|
+
key,
|
|
106
|
+
value,
|
|
107
|
+
record,
|
|
108
|
+
outcome,
|
|
109
|
+
resolve,
|
|
110
|
+
reject,
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
const answer = (entry, result) => {
|
|
114
|
+
result.then((value) => entry.resolve(value), (reason) => {
|
|
115
|
+
entry.reject(reason);
|
|
116
|
+
if (!settle) {
|
|
117
|
+
group.abort();
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
const follow = (entry, result) => {
|
|
122
|
+
const aborted = () => entry.reject(group.signal.reason);
|
|
123
|
+
if (group.signal.aborted) {
|
|
124
|
+
aborted();
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
group.signal.addEventListener("abort", aborted, { once: true });
|
|
128
|
+
}
|
|
129
|
+
answer(entry, result);
|
|
130
|
+
};
|
|
131
|
+
for (const entry of list) {
|
|
132
|
+
if (entry.record === undefined) {
|
|
133
|
+
follow(entry, entry.value);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const queued = list.filter((entry) => entry.record !== undefined);
|
|
137
|
+
const cap = maxAllConcurrencyOf(limits);
|
|
138
|
+
let next = 0;
|
|
139
|
+
let running = 0;
|
|
140
|
+
const launch = () => {
|
|
141
|
+
while (next < queued.length && (running < cap || group.signal.aborted)) {
|
|
142
|
+
const entry = queued[next];
|
|
143
|
+
const record = entry.record;
|
|
144
|
+
next += 1;
|
|
145
|
+
const call = record.begin(group.signal);
|
|
146
|
+
running += 1;
|
|
147
|
+
answer(entry, call.result);
|
|
148
|
+
void Promise.all([call.done, entry.outcome.then(ignore, ignore)]).then(() => {
|
|
149
|
+
running -= 1;
|
|
150
|
+
launch();
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
group.signal.addEventListener("abort", launch, { once: true });
|
|
155
|
+
launch();
|
|
156
|
+
const done = (result) => {
|
|
157
|
+
outer?.removeEventListener("abort", forward);
|
|
158
|
+
return result;
|
|
159
|
+
};
|
|
160
|
+
const byKey = (values) => Object.fromEntries(list.map(({ key }, index) => [key, values[index]]));
|
|
161
|
+
if (settle) {
|
|
162
|
+
return Promise.all(list.map(({ outcome }) => outcome.then((value) => ({ status: "fulfilled", value }), (reason) => ({ status: "rejected", reason })))).then((settled) => done(byKey(settled)));
|
|
163
|
+
}
|
|
164
|
+
return Promise.all(list.map(({ outcome }) => outcome)).then((values) => done(byKey(values)), (error) => {
|
|
165
|
+
group.abort();
|
|
166
|
+
throw done(error);
|
|
167
|
+
});
|
|
168
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export type { AvAdapterDiscoveryDiagnostic, AvAdapterDiscoveryDiagnosticCode, }
|
|
|
3
3
|
export type { AvAdapterModel } from "./adapters/adapter-model.js";
|
|
4
4
|
export type { AvContracts } from "./compiler/contract.compiler.js";
|
|
5
5
|
export type { AvContractCompilerDiagnostic, AvContractCompilerDiagnosticCode, } from "./compiler/contract-compiler-diagnostic.js";
|
|
6
|
+
export { cache } from "./config/cache-stage.factory.js";
|
|
6
7
|
export type { AvConfigComputedFields } from "./config/computed-fields.js";
|
|
7
8
|
export type { AvMcpEndpoint } from "./config/config.resolver.js";
|
|
8
9
|
export type { AvConfigDiagnostic, AvConfigDiagnosticCode, } from "./config/config-diagnostic.js";
|
|
@@ -34,6 +35,7 @@ export type { AvFramework } from "./framework/framework.js";
|
|
|
34
35
|
export type { AvConstructionDiagnostic, AvConstructionStage, } from "./framework/framework-construction.error.js";
|
|
35
36
|
export { AvConstructionError } from "./framework/framework-construction.error.js";
|
|
36
37
|
export type { AvApplicationFacade, AvApplicationFamilyFacade, AvApplicationPlainCall, AvApplicationProjectingCall, AvApplicationResourceFacade, AvAppTxFacade, AvAppTxFamilyFacade, AvAppTxPlainCall, AvAppTxProjectingCall, AvAppTxResourceFacade, AvClientFacade, AvClientFamilyFacade, AvClientPlainCall, AvClientProjectingCall, AvClientResourceFacade, AvClientTxFacade, AvClientTxFamilyFacade, AvClientTxPlainCall, AvClientTxProjectingCall, AvClientTxResourceFacade, AvServerClientFacade, AvServerClientFamilyFacade, AvServerClientPlainCall, AvServerClientProjectingCall, AvServerClientResourceFacade, AvServerClientTxFacade, AvServerClientTxFamilyFacade, AvServerClientTxPlainCall, AvServerClientTxProjectingCall, AvServerClientTxResourceFacade, } from "./framework/operation-facade.js";
|
|
38
|
+
export { avLazy } from "./framework/operation-set.runner.js";
|
|
37
39
|
export type { AvCreateDataInput, AvCursorInput, AvFieldKey, AvIncludeInput, AvNoAdvertisedMember, AvNullsOrder, AvOperationArgumentMap, AvOperationArgumentsFor, AvOrderByEntry, AvOrderByInput, AvProjectionEntry, AvRelationProjectionInput, AvResourceKey, AvScalarFilterOperands, AvScalarOrderInput, AvScalarWhereInput, AvSelectInput, AvSortDirection, AvUniqueWhereInput, AvUpdateDataInput, AvWhereInput, } from "./operations/operation-arguments.js";
|
|
38
40
|
export type { AvDeferredOperationCall, AvOperationCall, AvOperationGrammar, AvOperationSlot, } from "./operations/operation-call.js";
|
|
39
41
|
export type { AvOperationFamily, AvOperationIdentity, AvOperationVariant, } from "./operations/operation-identity.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
export { cache } from "./config/cache-stage.factory.js";
|
|
1
2
|
export { defineResource, } from "./config/define-resource.js";
|
|
2
3
|
export { createFramework } from "./framework/framework.factory.js";
|
|
3
4
|
export { AvConstructionError } from "./framework/framework-construction.error.js";
|
|
5
|
+
export { avLazy } from "./framework/operation-set.runner.js";
|
|
4
6
|
export { AvDecimal } from "./runtime/decimal.js";
|
|
5
7
|
export { AvErrorCatalog, } from "./runtime/error.catalog.js";
|
|
6
8
|
export { AvAuthError, AvConflictError, AvContractMismatchError, AvError, AvInternalError, AvNotFoundError, AvProtocolError, AvValidationError, } from "./runtime/framework-error.js";
|
package/dist/internal.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type { AvAdapterSqlStatement, AvAdapterSqlValue, } from "./adapters/adapt
|
|
|
15
15
|
export type { AvAdapterTransactionExecutor } from "./adapters/adapter-transaction-executor.interface.js";
|
|
16
16
|
export { compileContracts } from "./compiler/contract.compiler.js";
|
|
17
17
|
export { resolveFrameworkConfig } from "./config/config.resolver.js";
|
|
18
|
+
export { canonicalJson } from "./contracts/canonical-json.writer.js";
|
|
18
19
|
export { PROJECTION_SCOPES, WRITE_SCOPES } from "./contracts/capability.js";
|
|
19
20
|
export { validateClientContractStructure } from "./contracts/client-contract-structure.validator.js";
|
|
20
21
|
export { AvCanonicalJsonError, canonicalizeContract, canonicalizeJson, } from "./contracts/contract-canonicalizer.js";
|
|
@@ -35,6 +36,7 @@ export type { SemanticOperationArguments } from "./operations/operation-validato
|
|
|
35
36
|
export { VALIDATION_CODES } from "./operations/validation-code.js";
|
|
36
37
|
export { accessProviderOf } from "./policy/access-provider.registry.js";
|
|
37
38
|
export { ACCESS_VERB_NAMES, ACCESS_VERBS, providerVerb, } from "./policy/access-verb.table.js";
|
|
39
|
+
export { holdRequestPrincipal } from "./policy/policy-request.js";
|
|
38
40
|
export { prebuiltFileChanges } from "./prebuilt/prebuilt-changes.js";
|
|
39
41
|
export { emitPrebuiltContracts, prebuiltContractsOf, } from "./prebuilt/prebuilt-contracts.emitter.js";
|
|
40
42
|
export { mcpFailureReporterOf } from "./runtime/diagnostics-reporter.js";
|
package/dist/internal.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { compileContracts } from "./compiler/contract.compiler.js";
|
|
2
2
|
export { resolveFrameworkConfig } from "./config/config.resolver.js";
|
|
3
|
+
export { canonicalJson } from "./contracts/canonical-json.writer.js";
|
|
3
4
|
export { PROJECTION_SCOPES, WRITE_SCOPES } from "./contracts/capability.js";
|
|
4
5
|
export { validateClientContractStructure } from "./contracts/client-contract-structure.validator.js";
|
|
5
6
|
export { AvCanonicalJsonError, canonicalizeContract, canonicalizeJson, } from "./contracts/contract-canonicalizer.js";
|
|
@@ -16,6 +17,7 @@ export { DATABASE_REFUSALS } from "./operations/database-refusal.js";
|
|
|
16
17
|
export { VALIDATION_CODES } from "./operations/validation-code.js";
|
|
17
18
|
export { accessProviderOf } from "./policy/access-provider.registry.js";
|
|
18
19
|
export { ACCESS_VERB_NAMES, ACCESS_VERBS, providerVerb, } from "./policy/access-verb.table.js";
|
|
20
|
+
export { holdRequestPrincipal } from "./policy/policy-request.js";
|
|
19
21
|
export { prebuiltFileChanges } from "./prebuilt/prebuilt-changes.js";
|
|
20
22
|
export { emitPrebuiltContracts, prebuiltContractsOf, } from "./prebuilt/prebuilt-contracts.emitter.js";
|
|
21
23
|
export { mcpFailureReporterOf } from "./runtime/diagnostics-reporter.js";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { FILTER_MODES, toOneRelinkWithRewrite, } from "../contracts/capability.js";
|
|
2
2
|
import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
|
|
3
3
|
import { advertisedDirectivesAt, advertisedReducers, advertisedReducersAt, holdsAt, } from "../contracts/field.js";
|
|
4
|
-
import { isPlainRecord,
|
|
4
|
+
import { isPlainRecord, isRecord } from "../runtime/record.guard.js";
|
|
5
|
+
import { unsentReadValueIssue } from "../runtime/scalar-runtime.js";
|
|
5
6
|
import { routeTransactionReferenceCandidate } from "../transactions/transaction-reference.js";
|
|
6
7
|
import { isOperationFamily, } from "./operation-identity.js";
|
|
7
8
|
import { NESTED_PROJECTION_SCOPE, resolveProjectionScope, } from "./projection-scope.resolver.js";
|
|
@@ -96,9 +97,6 @@ const OPERATION_ARGUMENT_RULES = {
|
|
|
96
97
|
projection: true,
|
|
97
98
|
},
|
|
98
99
|
};
|
|
99
|
-
function isRecord(value) {
|
|
100
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
101
|
-
}
|
|
102
100
|
function includes(values, value) {
|
|
103
101
|
return values?.includes(value) ?? false;
|
|
104
102
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
|
|
2
2
|
import { advertisedDirectives, holdsAt, } from "../contracts/field.js";
|
|
3
|
+
import { isRecord } from "../runtime/record.guard.js";
|
|
3
4
|
import { NESTED_PROJECTION_SCOPE, resolveProjectionScope, } from "./projection-scope.resolver.js";
|
|
4
5
|
const UNTRACKED = [];
|
|
5
6
|
const RELATION_FILTER_OPERATORS = ["some", "every", "none"];
|
|
@@ -15,9 +16,6 @@ const DIRECTIVE_PAYLOADS = new Map([
|
|
|
15
16
|
],
|
|
16
17
|
]);
|
|
17
18
|
const NO_PAYLOADS = [];
|
|
18
|
-
function isRecord(value) {
|
|
19
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20
|
-
}
|
|
21
19
|
function extend(state, path, segment) {
|
|
22
20
|
return state.tracking ? [...path, segment] : UNTRACKED;
|
|
23
21
|
}
|