@aventara/core 1.0.0-rc.1 → 1.0.0-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +943 -16
- package/ERRORS.md +142 -0
- package/README.md +274 -16
- package/dist/adapters/adapter-discovery-diagnostic.guidance.d.ts +6 -0
- package/dist/adapters/adapter-discovery-diagnostic.guidance.js +7 -0
- package/dist/adapters/adapter-field.d.ts +22 -0
- package/dist/adapters/adapter-identifier.d.ts +9 -0
- package/dist/adapters/adapter-identifier.js +6 -1
- package/dist/adapters/adapter-model.d.ts +9 -0
- package/dist/adapters/adapter-operation.d.ts +18 -3
- package/dist/adapters/adapter-resource.d.ts +5 -0
- package/dist/adapters/adapter.interface.d.ts +10 -0
- package/dist/avz/avz.d.ts +1 -1
- package/dist/avz/json-shape.registry.d.ts +2 -1
- package/dist/compiler/contract-compiler-diagnostic.guidance.d.ts +6 -0
- package/dist/compiler/contract-compiler-diagnostic.guidance.js +97 -0
- package/dist/compiler/contract.compiler.d.ts +6 -0
- package/dist/compiler/contract.compiler.js +227 -24
- package/dist/compiler/managed-elsewhere.projector.d.ts +52 -0
- package/dist/compiler/managed-elsewhere.projector.js +179 -0
- package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
- package/dist/compiler/managed-elsewhere.validator.js +74 -0
- package/dist/config/computed-fields.d.ts +62 -0
- package/dist/config/computed-fields.js +73 -0
- package/dist/config/config-diagnostic.guidance.d.ts +6 -0
- package/dist/config/config-diagnostic.guidance.js +32 -0
- package/dist/config/config.resolver.d.ts +24 -0
- package/dist/config/config.resolver.js +65 -0
- package/dist/config/config.validator.js +222 -8
- package/dist/config/define-resource.d.ts +1 -5
- package/dist/config/entrypoint.normalizer.d.ts +3 -2
- package/dist/config/exact-framework-config.d.ts +67 -22
- package/dist/config/field-compute.resolver.d.ts +2 -0
- package/dist/config/field-compute.resolver.js +8 -0
- package/dist/config/framework-config.d.ts +53 -15
- package/dist/config/framework-resources-config.d.ts +25 -14
- package/dist/config/pipeline-config.d.ts +4 -4
- package/dist/config/pipeline-tree.resolver.d.ts +2 -2
- package/dist/contracts/access-route.rules.d.ts +10 -0
- package/dist/contracts/access-route.rules.js +45 -0
- package/dist/contracts/capability.d.ts +26 -1
- package/dist/contracts/capability.js +20 -0
- package/dist/contracts/client-contract-structure.validator.d.ts +301 -89
- package/dist/contracts/client-contract-structure.validator.js +37 -2
- package/dist/contracts/contract-access.d.ts +29 -0
- package/dist/contracts/contract-access.js +1 -0
- package/dist/contracts/contract-canonicalizer.d.ts +9 -1
- package/dist/contracts/contract-canonicalizer.js +30 -4
- package/dist/contracts/contract-hash.d.ts +0 -1
- package/dist/contracts/contract-hash.js +1 -1
- package/dist/contracts/contract.d.ts +27 -1
- package/dist/contracts/field.d.ts +58 -1
- package/dist/contracts/json-schema.projector.d.ts +11 -0
- package/dist/contracts/json-schema.projector.js +78 -0
- package/dist/contracts/scalar-value-type.d.ts +3 -1
- package/dist/framework/access-facade.d.ts +116 -0
- package/dist/framework/access-facade.js +120 -0
- package/dist/framework/contract-view.d.ts +120 -16
- package/dist/framework/framework-construction.error.d.ts +14 -4
- package/dist/framework/framework-construction.error.js +18 -2
- package/dist/framework/framework.d.ts +26 -5
- package/dist/framework/framework.factory.d.ts +1 -1
- package/dist/framework/framework.factory.js +115 -23
- package/dist/framework/operation-facade.d.ts +80 -13
- package/dist/framework/operation-facade.js +2 -1
- package/dist/index.d.ts +17 -5
- package/dist/index.js +1 -0
- package/dist/internal.d.ts +7 -2
- package/dist/internal.js +6 -0
- package/dist/operations/database-refusal.d.ts +51 -0
- package/dist/operations/database-refusal.js +45 -0
- package/dist/operations/operation-arguments.d.ts +148 -60
- package/dist/operations/operation-call.d.ts +9 -5
- package/dist/operations/operation-result.d.ts +6 -4
- package/dist/operations/operation-validator-core.js +159 -36
- package/dist/operations/operation-validator.d.ts +1 -1
- package/dist/operations/structural-limits.walker.d.ts +1 -1
- package/dist/operations/validation-code.guidance.d.ts +6 -0
- package/dist/operations/validation-code.guidance.js +90 -0
- package/dist/operations/write-scope.resolver.d.ts +4 -0
- package/dist/operations/write-scope.resolver.js +2 -0
- package/dist/policy/access-provider.interface.d.ts +91 -0
- package/dist/policy/access-provider.interface.js +1 -0
- package/dist/policy/access-provider.registry.d.ts +17 -0
- package/dist/policy/access-provider.registry.js +15 -0
- package/dist/policy/access-question.d.ts +20 -0
- package/dist/policy/access-question.js +1 -0
- package/dist/policy/access-question.registry.d.ts +5 -0
- package/dist/policy/access-question.registry.js +19 -0
- package/dist/policy/access-question.runtime.d.ts +36 -0
- package/dist/policy/access-question.runtime.js +297 -0
- package/dist/policy/access-verb.table.d.ts +56 -0
- package/dist/policy/access-verb.table.js +21 -0
- package/dist/policy/access-verbs.d.ts +46 -0
- package/dist/policy/access-verbs.js +1 -0
- package/dist/policy/policy-admission.d.ts +20 -0
- package/dist/policy/policy-admission.js +409 -0
- package/dist/policy/policy-after-update.runtime.d.ts +79 -0
- package/dist/policy/policy-after-update.runtime.js +208 -0
- package/dist/policy/policy-condition.d.ts +15 -0
- package/dist/policy/policy-condition.js +36 -0
- package/dist/policy/policy-engine.d.ts +205 -0
- package/dist/policy/policy-engine.js +1 -0
- package/dist/policy/policy-named-rows.d.ts +18 -0
- package/dist/policy/policy-named-rows.js +51 -0
- package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
- package/dist/policy/policy-nested-write.runtime.js +545 -0
- package/dist/policy/policy-read.runtime.d.ts +81 -0
- package/dist/policy/policy-read.runtime.js +503 -0
- package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
- package/dist/policy/policy-reference-write.runtime.js +345 -0
- package/dist/policy/policy-request.d.ts +41 -0
- package/dist/policy/policy-request.js +63 -0
- package/dist/policy/policy-session.d.ts +106 -0
- package/dist/policy/policy-session.js +295 -0
- package/dist/policy/policy-startup.validator.d.ts +10 -0
- package/dist/policy/policy-startup.validator.js +112 -0
- package/dist/policy/policy-write.runtime.d.ts +39 -0
- package/dist/policy/policy-write.runtime.js +532 -0
- package/dist/prebuilt/core-version.generated.d.ts +2 -0
- package/dist/prebuilt/core-version.generated.js +1 -0
- package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
- package/dist/prebuilt/prebuilt-changes.js +65 -0
- package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
- package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
- package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
- package/dist/prebuilt/prebuilt-contracts.js +1 -0
- package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
- package/dist/prebuilt/prebuilt-contracts.loader.js +77 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
- package/dist/prebuilt/prebuilt-inputs.fingerprint.js +229 -0
- package/dist/protocol/absent-route.responder.d.ts +9 -27
- package/dist/protocol/absent-route.responder.js +36 -3
- package/dist/protocol/contract-document.responder.d.ts +2 -1
- package/dist/protocol/http-request.decoder.d.ts +19 -3
- package/dist/protocol/http-request.decoder.js +24 -1
- package/dist/protocol/http-request.reader.d.ts +6 -3
- package/dist/protocol/http-request.reader.js +1 -0
- package/dist/protocol/http-response.encoder.js +2 -2
- package/dist/protocol/protocol-headers.d.ts +3 -3
- package/dist/protocol/protocol-surface.d.ts +6 -1
- package/dist/protocol/protocol-surface.js +7 -0
- package/dist/protocol/protocol.binder.d.ts +16 -1
- package/dist/protocol/protocol.binder.js +4 -1
- package/dist/protocol/protocol.handler.d.ts +12 -1
- package/dist/protocol/protocol.handler.js +86 -17
- package/dist/runtime/caller-data.copier.d.ts +18 -3
- package/dist/runtime/caller-data.copier.js +21 -8
- package/dist/runtime/caller-data.door.d.ts +13 -6
- package/dist/runtime/computed-read-runtime.d.ts +6 -1
- package/dist/runtime/computed-read-runtime.js +232 -45
- package/dist/runtime/computed-value.error.d.ts +3 -2
- package/dist/runtime/computed-value.error.js +3 -2
- package/dist/runtime/context-executor.runtime.d.ts +4 -3
- package/dist/runtime/context-executor.runtime.js +4 -2
- package/dist/runtime/core-class.brand.d.ts +10 -0
- package/dist/runtime/core-class.brand.js +21 -0
- package/dist/runtime/create-requirement.d.ts +31 -5
- package/dist/runtime/create-requirement.js +129 -21
- package/dist/runtime/decimal.d.ts +14 -0
- package/dist/runtime/decimal.js +21 -0
- package/dist/runtime/diagnostics-reporter.d.ts +44 -9
- package/dist/runtime/diagnostics-reporter.js +13 -1
- package/dist/runtime/error-boundary.d.ts +9 -2
- package/dist/runtime/error-boundary.js +12 -0
- package/dist/runtime/error-guidance.d.ts +12 -0
- package/dist/runtime/error-guidance.js +1 -0
- package/dist/runtime/error.catalog.d.ts +49 -0
- package/dist/runtime/error.catalog.js +49 -0
- package/dist/runtime/execution-options.d.ts +8 -0
- package/dist/runtime/field-check.evaluator.d.ts +0 -2
- package/dist/runtime/field-check.evaluator.js +1 -1
- package/dist/runtime/field-compute.d.ts +11 -10
- package/dist/runtime/field-stage.runtime.d.ts +3 -1
- package/dist/runtime/field-stage.runtime.js +8 -4
- package/dist/runtime/field-validator.runtime.d.ts +19 -1
- package/dist/runtime/field-validator.runtime.js +47 -8
- package/dist/runtime/framework-error.js +9 -0
- package/dist/runtime/framework-warning.emitter.d.ts +6 -0
- package/dist/runtime/framework-warning.emitter.js +8 -0
- package/dist/runtime/json-value.d.ts +10 -5
- package/dist/runtime/level-lifecycle.runtime.d.ts +4 -3
- package/dist/runtime/level-lifecycle.runtime.js +3 -5
- package/dist/runtime/mutation-planner.d.ts +1 -6
- package/dist/runtime/mutation-planner.js +3 -14
- package/dist/runtime/operation-code.guidance.d.ts +6 -0
- package/dist/runtime/operation-code.guidance.js +167 -0
- package/dist/runtime/operation-request.d.ts +16 -9
- package/dist/runtime/operation-runtime.d.ts +35 -17
- package/dist/runtime/operation-runtime.js +220 -49
- package/dist/runtime/outcome-mapper.d.ts +2 -1
- package/dist/runtime/output-validator.d.ts +1 -1
- package/dist/runtime/owned-execution.registry.d.ts +13 -3
- package/dist/runtime/pipe-output.validator.d.ts +10 -0
- package/dist/runtime/pipe-output.validator.js +4 -2
- package/dist/runtime/pipeline.d.ts +47 -22
- package/dist/runtime/readonly-value.d.ts +20 -5
- package/dist/runtime/readonly-value.js +74 -26
- package/dist/runtime/referential-action.d.ts +1 -1
- package/dist/runtime/scalar-runtime.d.ts +4 -11
- package/dist/runtime/scalar-runtime.js +91 -22
- package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
- package/dist/runtime/unsent-value.normalizer.js +128 -0
- package/dist/transactions/operation-arguments-encoder.js +8 -3
- package/dist/transactions/operation-fingerprint.js +2 -2
- package/dist/transactions/sql-statement.d.ts +10 -2
- package/dist/transactions/sql-statement.validator.d.ts +2 -2
- package/dist/transactions/sql-statement.validator.js +38 -5
- package/dist/transactions/transaction-envelope.d.ts +5 -4
- package/dist/transactions/transaction-integrity-error.js +2 -0
- package/dist/transactions/transaction-plan-assembler.d.ts +12 -5
- package/dist/transactions/transaction-plan-assembler.js +48 -10
- package/dist/transactions/transaction-plan-validator.d.ts +23 -7
- package/dist/transactions/transaction-plan-validator.js +27 -1
- package/dist/transactions/transaction-reference-resolver.d.ts +3 -2
- package/dist/transactions/transaction-reference-validator.d.ts +43 -3
- package/dist/transactions/transaction-reference-validator.js +83 -57
- package/dist/transactions/transaction-reference.d.ts +1 -1
- package/dist/transactions/transaction-reference.js +5 -0
- package/dist/transactions/transaction-request.d.ts +8 -8
- package/dist/transactions/transaction-runtime.d.ts +5 -2
- package/dist/transactions/transaction-runtime.js +79 -27
- package/dist/transactions/transaction-settlement.runtime.d.ts +4 -3
- package/dist/transactions/transaction-slot-path-error.js +2 -0
- package/dist/transactions/transaction-stage.runtime.d.ts +5 -3
- package/dist/transactions/transaction-stage.runtime.js +7 -4
- package/package.json +6 -5
- package/src/runtime/field-check.evaluator.ts +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
|
|
2
2
|
import { advertisedDirectivesAt } from "../contracts/field.js";
|
|
3
|
-
import { NESTED_WRITE_SCOPE, resolveWriteScope, } from "../operations/write-scope.resolver.js";
|
|
3
|
+
import { LOOPBACK_WRITE_SCOPE, NESTED_WRITE_SCOPE, resolveWriteScope, } from "../operations/write-scope.resolver.js";
|
|
4
4
|
import { isRelationMutationDirective, RELATION_MUTATION_RECORD_SITES, } from "./mutation-planner.js";
|
|
5
5
|
function isRecord(value) {
|
|
6
6
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -13,7 +13,7 @@ function edgesOf(table, resource) {
|
|
|
13
13
|
return Array.isArray(listed) ? listed : [];
|
|
14
14
|
}
|
|
15
15
|
function referencesOf(edge) {
|
|
16
|
-
return Array.isArray(edge.
|
|
16
|
+
return Array.isArray(edge.referenceFields) ? edge.referenceFields : [];
|
|
17
17
|
}
|
|
18
18
|
function creatableScalar(contract, resource, field) {
|
|
19
19
|
const found = lookupField(lookupResource(contract, resource), field);
|
|
@@ -63,9 +63,19 @@ function checkCreateRecord(context, resource, record, path, scope, via) {
|
|
|
63
63
|
if (!isRecord(record)) {
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
|
+
if (context.computed !== undefined) {
|
|
67
|
+
computedRequirementGaps(context, resource, record, path, via);
|
|
68
|
+
walkNestedCreates(context, resource, record, path);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
66
71
|
const { contract, issues } = context;
|
|
67
|
-
const
|
|
68
|
-
|
|
72
|
+
const looped = loopbackWrites(context, resource, record, path, via, "create");
|
|
73
|
+
const conflicted = looped.size > 0
|
|
74
|
+
? looped
|
|
75
|
+
: referenceConflicts(context, resource, record, path);
|
|
76
|
+
if (looped.size === 0) {
|
|
77
|
+
mixedReferenceWrites(context, resource, record, path, conflicted);
|
|
78
|
+
}
|
|
69
79
|
const requirements = requirementsOf(contract, resource);
|
|
70
80
|
if (requirements !== undefined) {
|
|
71
81
|
const supplied = suppliedThrough(requirements, via);
|
|
@@ -157,14 +167,93 @@ function mixedReferenceWrites(context, resource, record, path, conflicted) {
|
|
|
157
167
|
});
|
|
158
168
|
}
|
|
159
169
|
}
|
|
160
|
-
function checkUpdateRecord(context, resource, record, path) {
|
|
170
|
+
function checkUpdateRecord(context, resource, record, path, via) {
|
|
161
171
|
if (!isRecord(record)) {
|
|
162
172
|
return;
|
|
163
173
|
}
|
|
164
|
-
|
|
165
|
-
|
|
174
|
+
if (context.computed === undefined &&
|
|
175
|
+
loopbackWrites(context, resource, record, path, via, "update").size === 0) {
|
|
176
|
+
const conflicted = referenceConflicts(context, resource, record, path);
|
|
177
|
+
mixedReferenceWrites(context, resource, record, path, conflicted);
|
|
178
|
+
}
|
|
166
179
|
walkNestedCreates(context, resource, record, path);
|
|
167
180
|
}
|
|
181
|
+
function loopbackWrites(context, resource, record, path, via, stage) {
|
|
182
|
+
const refused = new Set();
|
|
183
|
+
if (via === undefined) {
|
|
184
|
+
return refused;
|
|
185
|
+
}
|
|
186
|
+
const { contract } = context;
|
|
187
|
+
const edge = lookupField(lookupResource(contract, via.resource), via.relation);
|
|
188
|
+
if (edge?.kind !== "relation" || typeof edge.inverse !== "string") {
|
|
189
|
+
return refused;
|
|
190
|
+
}
|
|
191
|
+
const inverse = edge.inverse;
|
|
192
|
+
const other = lookupField(lookupResource(contract, resource), inverse);
|
|
193
|
+
if (other?.kind === "relation" &&
|
|
194
|
+
advertisedDirectivesAt(other.capabilities[stage], LOOPBACK_WRITE_SCOPE) !==
|
|
195
|
+
undefined) {
|
|
196
|
+
return refused;
|
|
197
|
+
}
|
|
198
|
+
const references = edgesOf(context.references, resource).find((candidate) => candidate.field === inverse) ?? undefined;
|
|
199
|
+
for (const field of [
|
|
200
|
+
inverse,
|
|
201
|
+
...(references === undefined ? [] : referencesOf(references)),
|
|
202
|
+
]) {
|
|
203
|
+
if (!written(record, field)) {
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
refused.add(field);
|
|
207
|
+
context.issues.push({
|
|
208
|
+
code: "V1012",
|
|
209
|
+
path: [...path, field],
|
|
210
|
+
message: field === inverse
|
|
211
|
+
? `Relation "${field}" is the relation this ${resource} is written through, from its other end ("${via.resource}.${via.relation}"): the write it sits in supplies it.`
|
|
212
|
+
: `Field "${field}" holds the reference of "${inverse}", the relation this ${resource} is written through ("${via.resource}.${via.relation}"): the write it sits in supplies it.`,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return refused;
|
|
216
|
+
}
|
|
217
|
+
function computedRequirementGaps(context, resource, record, path, via) {
|
|
218
|
+
const reader = context.computed;
|
|
219
|
+
const computed = reader?.computed(resource);
|
|
220
|
+
const stated = reader?.stated(resource);
|
|
221
|
+
if (computed === undefined || computed.size === 0 || stated === undefined) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const supplied = suppliedThrough(stated, via);
|
|
225
|
+
const gap = (field) => {
|
|
226
|
+
context.gaps?.push({
|
|
227
|
+
resource,
|
|
228
|
+
field,
|
|
229
|
+
issue: {
|
|
230
|
+
code: "V1000",
|
|
231
|
+
path: [...path, field],
|
|
232
|
+
message: `compute.create on ${resource}.${field} returned undefined for a required field.`,
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
};
|
|
236
|
+
for (const field of namesOf(stated.required)) {
|
|
237
|
+
if (computed.has(field) &&
|
|
238
|
+
!supplied.has(field) &&
|
|
239
|
+
!written(record, field)) {
|
|
240
|
+
gap(field);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
const groups = Array.isArray(stated.oneOf) ? stated.oneOf : [];
|
|
244
|
+
for (const group of groups) {
|
|
245
|
+
const [relation, ...references] = namesOf(group);
|
|
246
|
+
const left = references.find((field) => computed.has(field) && !written(record, field));
|
|
247
|
+
if (relation === undefined ||
|
|
248
|
+
left === undefined ||
|
|
249
|
+
supplied.has(relation) ||
|
|
250
|
+
references.some((field) => supplied.has(field)) ||
|
|
251
|
+
written(record, relation)) {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
gap(left);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
168
257
|
function walkNestedCreates(context, resource, record, path) {
|
|
169
258
|
if (!isRecord(record)) {
|
|
170
259
|
return;
|
|
@@ -196,7 +285,7 @@ function walkNestedCreates(context, resource, record, path) {
|
|
|
196
285
|
checkCreateRecord(context, field.target, siteRecord, sitePath, NESTED_WRITE_SCOPE, via);
|
|
197
286
|
}
|
|
198
287
|
else {
|
|
199
|
-
checkUpdateRecord(context, field.target, siteRecord, sitePath);
|
|
288
|
+
checkUpdateRecord(context, field.target, siteRecord, sitePath, via);
|
|
200
289
|
}
|
|
201
290
|
}
|
|
202
291
|
}
|
|
@@ -204,17 +293,43 @@ function walkNestedCreates(context, resource, record, path) {
|
|
|
204
293
|
}
|
|
205
294
|
}
|
|
206
295
|
export function recordWriteFactsOf(adapter) {
|
|
207
|
-
|
|
296
|
+
const resources = adapter.model?.resources ?? {};
|
|
297
|
+
return {
|
|
298
|
+
references: adapter.referentialActions ?? {},
|
|
299
|
+
stated: (resource) => {
|
|
300
|
+
const found = Object.hasOwn(resources, resource)
|
|
301
|
+
? resources[resource]
|
|
302
|
+
: undefined;
|
|
303
|
+
const stated = isRecord(found) ? found.createRequirements : undefined;
|
|
304
|
+
return isRecord(stated) ? stated : undefined;
|
|
305
|
+
},
|
|
306
|
+
};
|
|
208
307
|
}
|
|
209
308
|
export function createRequirementIssues(contract, facts, request, args, argumentsPath) {
|
|
210
|
-
if (!isRecord(args)) {
|
|
211
|
-
return [];
|
|
212
|
-
}
|
|
213
309
|
const context = {
|
|
214
310
|
contract,
|
|
215
311
|
references: facts.references,
|
|
216
312
|
issues: [],
|
|
217
313
|
};
|
|
314
|
+
walkOperation(context, request, args, argumentsPath);
|
|
315
|
+
return context.issues;
|
|
316
|
+
}
|
|
317
|
+
export function computedRequirementGapsOf(contract, facts, request, args, argumentsPath, computed) {
|
|
318
|
+
const gaps = [];
|
|
319
|
+
walkOperation({
|
|
320
|
+
contract,
|
|
321
|
+
references: facts.references,
|
|
322
|
+
issues: [],
|
|
323
|
+
computed: { stated: facts.stated, computed },
|
|
324
|
+
gaps,
|
|
325
|
+
}, request, args, argumentsPath);
|
|
326
|
+
return gaps;
|
|
327
|
+
}
|
|
328
|
+
function walkOperation(context, request, args, argumentsPath) {
|
|
329
|
+
if (!isRecord(args)) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const contract = context.contract;
|
|
218
333
|
const scope = resolveWriteScope(lookupResource(contract, request.resource), request);
|
|
219
334
|
if (request.family === "create" && written(args, "data")) {
|
|
220
335
|
const data = args.data;
|
|
@@ -229,16 +344,9 @@ export function createRequirementIssues(contract, facts, request, args, argument
|
|
|
229
344
|
}
|
|
230
345
|
if (request.family === "upsert") {
|
|
231
346
|
checkCreateRecord(context, request.resource, args.create, [...argumentsPath, "create"], scope, undefined);
|
|
232
|
-
checkUpdateRecord(context, request.resource, args.update, [
|
|
233
|
-
...argumentsPath,
|
|
234
|
-
"update",
|
|
235
|
-
]);
|
|
347
|
+
checkUpdateRecord(context, request.resource, args.update, [...argumentsPath, "update"], undefined);
|
|
236
348
|
}
|
|
237
349
|
if (request.family === "update") {
|
|
238
|
-
checkUpdateRecord(context, request.resource, args.data, [
|
|
239
|
-
...argumentsPath,
|
|
240
|
-
"data",
|
|
241
|
-
]);
|
|
350
|
+
checkUpdateRecord(context, request.resource, args.data, [...argumentsPath, "data"], undefined);
|
|
242
351
|
}
|
|
243
|
-
return context.issues;
|
|
244
352
|
}
|
|
@@ -12,3 +12,17 @@ export declare class AvDecimal {
|
|
|
12
12
|
*/
|
|
13
13
|
toJSON(): string;
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Whether `value` is an `AvDecimal`, made by this copy of core or by another of
|
|
17
|
+
* its major: one `in`, for the hot paths that ask about every value.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isAvDecimal(value: unknown): value is AvDecimal;
|
|
20
|
+
/**
|
|
21
|
+
* The digits of `value`, read without running anything the caller could have put
|
|
22
|
+
* on it when this copy made it. Another copy's decimal is read through its own
|
|
23
|
+
* `toString`, which only that copy can answer; what it returns is checked as a
|
|
24
|
+
* decimal string, so the caller's copy keeps the grammar.
|
|
25
|
+
*
|
|
26
|
+
* @throws TypeError when another copy's decimal does not answer a decimal string.
|
|
27
|
+
*/
|
|
28
|
+
export declare function decimalDigitsOf(value: AvDecimal): string;
|
package/dist/runtime/decimal.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { WIRE_SCALAR_PATTERNS } from "../contracts/wire-scalar-format.js";
|
|
2
|
+
import { brandCoreClass, hasCoreBrand } from "./core-class.brand.js";
|
|
3
|
+
let ownDigitsOf;
|
|
2
4
|
export class AvDecimal {
|
|
3
5
|
#value;
|
|
6
|
+
static {
|
|
7
|
+
ownDigitsOf = (value) => (#value in value ? value.#value : undefined);
|
|
8
|
+
}
|
|
4
9
|
constructor(value) {
|
|
5
10
|
if (typeof value !== "string") {
|
|
6
11
|
throw new TypeError("Decimal value must be a string.");
|
|
@@ -17,3 +22,19 @@ export class AvDecimal {
|
|
|
17
22
|
return this.#value;
|
|
18
23
|
}
|
|
19
24
|
}
|
|
25
|
+
const DECIMAL_BRAND = brandCoreClass(AvDecimal, "AvDecimal");
|
|
26
|
+
export function isAvDecimal(value) {
|
|
27
|
+
return hasCoreBrand(value, DECIMAL_BRAND);
|
|
28
|
+
}
|
|
29
|
+
export function decimalDigitsOf(value) {
|
|
30
|
+
const own = ownDigitsOf(value);
|
|
31
|
+
if (own !== undefined) {
|
|
32
|
+
return own;
|
|
33
|
+
}
|
|
34
|
+
const digits = value.toString();
|
|
35
|
+
if (typeof digits !== "string" ||
|
|
36
|
+
!WIRE_SCALAR_PATTERNS.decimal.test(digits)) {
|
|
37
|
+
throw new TypeError("Decimal value must be a valid decimal string.");
|
|
38
|
+
}
|
|
39
|
+
return digits;
|
|
40
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AvRequestOrigin } from "../config/config-layer.js";
|
|
2
2
|
import type { AvOperationFamily } from "../operations/operation-identity.js";
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
3
|
+
import type { AvTransactionRequest } from "../transactions/transaction-request.js";
|
|
4
|
+
import type { AvOperationRequest } from "./operation-request.js";
|
|
5
5
|
import { type AvOperationErrorCode, type AvOperationFailureResponse } from "./operation-response.js";
|
|
6
6
|
/**
|
|
7
7
|
* One unplanned failure of an operation: the raw error, the code the caller
|
|
@@ -47,7 +47,8 @@ export type AvTransactionDiagnostic = {
|
|
|
47
47
|
};
|
|
48
48
|
/**
|
|
49
49
|
* One unplanned failure of the MCP endpoint itself, outside any tool call's
|
|
50
|
-
* operation: the raw error, answered `500` with no detail
|
|
50
|
+
* operation: the raw error, answered `500` with no detail, or `401` when it is
|
|
51
|
+
* the throw of `mcp.authorization.verify`.
|
|
51
52
|
*/
|
|
52
53
|
export type AvMcpDiagnostic = {
|
|
53
54
|
readonly kind: "mcp";
|
|
@@ -62,8 +63,40 @@ export type AvMcpDiagnostic = {
|
|
|
62
63
|
/** Never present: only an operation diagnostic is marked `deliberate`. */
|
|
63
64
|
readonly deliberate?: never;
|
|
64
65
|
};
|
|
65
|
-
/**
|
|
66
|
-
|
|
66
|
+
/**
|
|
67
|
+
* One unplanned failure of a `POST /_access/can` request: the raw error, the
|
|
68
|
+
* code the caller received, and, when one question met it, that question's
|
|
69
|
+
* index (`question`), Resource and action; none of the three when the batch
|
|
70
|
+
* as a whole failed.
|
|
71
|
+
*/
|
|
72
|
+
export type AvCanDiagnostic = {
|
|
73
|
+
readonly kind: "can";
|
|
74
|
+
readonly error: unknown;
|
|
75
|
+
readonly code: AvOperationErrorCode;
|
|
76
|
+
/** The route is the clients': an agent has no `can` route. */
|
|
77
|
+
readonly origin: "client";
|
|
78
|
+
readonly requestId: string;
|
|
79
|
+
/** Never present: no operation of a plan is involved (see `question`). */
|
|
80
|
+
readonly operation?: never;
|
|
81
|
+
/** Never present: only an operation diagnostic is marked `deliberate`. */
|
|
82
|
+
readonly deliberate?: never;
|
|
83
|
+
} & ({
|
|
84
|
+
/** The index of the question in `questions` the failure is blamed on. */
|
|
85
|
+
readonly question: number;
|
|
86
|
+
/** That question's Resource. */
|
|
87
|
+
readonly resource: string;
|
|
88
|
+
/** That question's action. */
|
|
89
|
+
readonly action: "read" | "create" | "update" | "delete";
|
|
90
|
+
} | {
|
|
91
|
+
readonly question?: never;
|
|
92
|
+
readonly resource?: never;
|
|
93
|
+
readonly action?: never;
|
|
94
|
+
});
|
|
95
|
+
/**
|
|
96
|
+
* One diagnostic: of an operation, of a transaction as a whole, of a `can`
|
|
97
|
+
* request, or of the MCP endpoint.
|
|
98
|
+
*/
|
|
99
|
+
export type AvDiagnostic = AvOperationDiagnostic | AvTransactionDiagnostic | AvCanDiagnostic | AvMcpDiagnostic;
|
|
67
100
|
/**
|
|
68
101
|
* Receives a diagnostic for every unplanned failure. Set once, as the root
|
|
69
102
|
* configuration's `diagnostics`.
|
|
@@ -80,8 +113,10 @@ export type DiagnosticMarks = Pick<AvOperationDiagnostic, "deliberate">;
|
|
|
80
113
|
/** The identifying half of a diagnostic, captured once per request. */
|
|
81
114
|
type OperationDiagnosticIdentity = Omit<AvOperationDiagnostic, "error" | "code">;
|
|
82
115
|
type TransactionDiagnosticIdentity = Omit<AvTransactionDiagnostic, "error" | "code">;
|
|
116
|
+
/** A `can` request's identity: its batch's, or one question's. */
|
|
117
|
+
type CanDiagnosticIdentity = AvCanDiagnostic extends infer Diagnostic ? Diagnostic extends unknown ? Omit<Diagnostic, "error" | "code"> : never : never;
|
|
83
118
|
/** The diagnostics channel bound to one diagnostic identity. */
|
|
84
|
-
export declare function createReporter(sink: AvDiagnosticsSink | undefined, identity: OperationDiagnosticIdentity | TransactionDiagnosticIdentity): DiagnosticsReporter;
|
|
119
|
+
export declare function createReporter(sink: AvDiagnosticsSink | undefined, identity: OperationDiagnosticIdentity | TransactionDiagnosticIdentity | CanDiagnosticIdentity): DiagnosticsReporter;
|
|
85
120
|
/**
|
|
86
121
|
* The MCP endpoint's failure channel for `framework`: each call reports one
|
|
87
122
|
* {@link AvMcpDiagnostic} to its configured sink, under a minted request id, and
|
|
@@ -99,14 +134,14 @@ export declare function diagnosticsSinkOf(framework: object): AvDiagnosticsSink
|
|
|
99
134
|
* Binds the configured sink to one operation request. The sink is not awaited,
|
|
100
135
|
* and nothing it throws or rejects with reaches the response.
|
|
101
136
|
*/
|
|
102
|
-
export declare function createDiagnosticsReporter(sink: AvDiagnosticsSink | undefined, request:
|
|
137
|
+
export declare function createDiagnosticsReporter(sink: AvDiagnosticsSink | undefined, request: AvOperationRequest, operation?: number): DiagnosticsReporter;
|
|
103
138
|
/** The diagnostics channel of one transaction request. */
|
|
104
139
|
export type TransactionDiagnosticsChannel = {
|
|
105
140
|
/** A plan-level report; `operation` attributes it to a recorded failing index. */
|
|
106
141
|
readonly transaction: (operation?: number) => DiagnosticsReporter;
|
|
107
142
|
/** A report carrying one plan operation's own identity and index. */
|
|
108
|
-
readonly operation: (request:
|
|
143
|
+
readonly operation: (request: AvOperationRequest, operation: number) => DiagnosticsReporter;
|
|
109
144
|
};
|
|
110
145
|
/** Binds the configured sink to one transaction request and its plan operations. */
|
|
111
|
-
export declare function createTransactionDiagnosticsChannel(sink: AvDiagnosticsSink | undefined, request:
|
|
146
|
+
export declare function createTransactionDiagnosticsChannel(sink: AvDiagnosticsSink | undefined, request: AvTransactionRequest): TransactionDiagnosticsChannel;
|
|
112
147
|
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { coreBrandOf } from "./core-class.brand.js";
|
|
1
2
|
import { internalFailure, } from "./operation-response.js";
|
|
2
3
|
import { requestIdOf } from "./request-id.js";
|
|
3
4
|
const IGNORE_DIAGNOSTIC = () => undefined;
|
|
@@ -31,7 +32,18 @@ export function createReporter(sink, identity) {
|
|
|
31
32
|
}
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
|
-
const CONFIGURED_SINKS =
|
|
35
|
+
const CONFIGURED_SINKS = sharedSinkRegistry();
|
|
36
|
+
function sharedSinkRegistry() {
|
|
37
|
+
const key = coreBrandOf("diagnostics");
|
|
38
|
+
const holder = globalThis;
|
|
39
|
+
const existing = holder[key];
|
|
40
|
+
if (existing instanceof WeakMap) {
|
|
41
|
+
return existing;
|
|
42
|
+
}
|
|
43
|
+
const registry = new WeakMap();
|
|
44
|
+
Object.defineProperty(holder, key, { value: registry });
|
|
45
|
+
return registry;
|
|
46
|
+
}
|
|
35
47
|
export function mcpFailureReporterOf(framework) {
|
|
36
48
|
const sink = CONFIGURED_SINKS.get(framework);
|
|
37
49
|
return (error) => {
|
|
@@ -3,7 +3,7 @@ import { AvError } from "./framework-error.js";
|
|
|
3
3
|
import type { AvCause, AvOperationErrorCode, AvOperationFailureResponse } from "./operation-response.js";
|
|
4
4
|
import type { AvContext } from "./pipeline.js";
|
|
5
5
|
/** Where an unexpected post-validation exception originated. */
|
|
6
|
-
|
|
6
|
+
type FailureOrigin = "adapter" | "runtime";
|
|
7
7
|
/** The one generic Adapter-failure text; every unexpected A3001 carries it. */
|
|
8
8
|
export declare const ADAPTER_FAILURE_MESSAGE = "Adapter execution failed.";
|
|
9
9
|
/** One boundary instance belongs to one operation execution. */
|
|
@@ -50,6 +50,13 @@ type DeliberateOutcome = {
|
|
|
50
50
|
*/
|
|
51
51
|
readonly unvouched: readonly unknown[];
|
|
52
52
|
};
|
|
53
|
+
/**
|
|
54
|
+
* The refusal code `error` deliberately carries, vetted as every boundary vets
|
|
55
|
+
* it ({@link vetDeliberateOutcome}): a recognised error code that is no
|
|
56
|
+
* internal (`A3xxx`) one, with a well-formed cause. `undefined` for anything
|
|
57
|
+
* else, which the caller answers as the defect it is.
|
|
58
|
+
*/
|
|
59
|
+
export declare function deliberateRefusalCode(error: unknown): AvOperationErrorCode | undefined;
|
|
53
60
|
/**
|
|
54
61
|
* Final framework sanitization, shared by every boundary. A deliberate
|
|
55
62
|
* {@link AvError} carries its own stable outcome; anything else is
|
|
@@ -100,7 +107,7 @@ export declare function resolveUnhandledFailure(failure: UnhandledFailure, chain
|
|
|
100
107
|
* A chain of filters and the context they are told, tried in reverse: the first
|
|
101
108
|
* that returns an {@link AvError} handles the error.
|
|
102
109
|
*/
|
|
103
|
-
|
|
110
|
+
type FilterChain = {
|
|
104
111
|
readonly attempt: (error: unknown, view: CallerArgumentsView, boundary: AdapterBoundary) => Promise<FilteredOutcome | undefined>;
|
|
105
112
|
};
|
|
106
113
|
/** The chain of `filters` (stored outer to inner, tried in reverse), told `context`. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isDatabaseRefusalMessage } from "../operations/database-refusal.js";
|
|
1
2
|
import { VALIDATION_CODE_MESSAGES, VALIDATION_CODES, } from "../operations/validation-code.js";
|
|
2
3
|
import { AvError } from "./framework-error.js";
|
|
3
4
|
import { INTERNAL_FAILURE_MESSAGE, internalFailure, OPERATION_CODES, operationFailure, } from "./operation-response.js";
|
|
@@ -164,6 +165,9 @@ function projectIssue(value, unvouched, view, author) {
|
|
|
164
165
|
unvouched.push(supplied);
|
|
165
166
|
}
|
|
166
167
|
}
|
|
168
|
+
else if (isDatabaseRefusalMessage(code, supplied)) {
|
|
169
|
+
message = supplied;
|
|
170
|
+
}
|
|
167
171
|
if (rawPath === undefined) {
|
|
168
172
|
return { code, message };
|
|
169
173
|
}
|
|
@@ -238,6 +242,14 @@ function vetDeliberateOutcome(error, view, author) {
|
|
|
238
242
|
const cause = projectCause(rawCause, unvouched, view, author);
|
|
239
243
|
return cause === undefined ? MALFORMED_OUTCOME : { code, cause, unvouched };
|
|
240
244
|
}
|
|
245
|
+
export function deliberateRefusalCode(error) {
|
|
246
|
+
const outcome = vetDeliberateOutcome(error, { path: [], arguments: undefined }, "developer");
|
|
247
|
+
return outcome === undefined ||
|
|
248
|
+
outcome === MALFORMED_OUTCOME ||
|
|
249
|
+
isInternalCode(outcome.code)
|
|
250
|
+
? undefined
|
|
251
|
+
: outcome.code;
|
|
252
|
+
}
|
|
241
253
|
function reportUnvouched(outcome, report) {
|
|
242
254
|
for (const value of outcome.unvouched) {
|
|
243
255
|
report(value, outcome.code);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Why a code is answered, and what the one who meets it should do. */
|
|
2
|
+
export type ErrorCodeGuidance = {
|
|
3
|
+
/** What typically produced the code, in a sentence or two. */
|
|
4
|
+
readonly cause: string;
|
|
5
|
+
/** What to change so it does not happen again. */
|
|
6
|
+
readonly fix: string;
|
|
7
|
+
};
|
|
8
|
+
/** Guidance for a code whose table holds no message of its own. */
|
|
9
|
+
export type ErrorCodeDescription = ErrorCodeGuidance & {
|
|
10
|
+
/** The code's meaning, in one short sentence. */
|
|
11
|
+
readonly message: string;
|
|
12
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AvAdapterDiscoveryDiagnosticCode } from "../adapters/adapter-discovery-diagnostic.js";
|
|
2
|
+
import type { AvContractCompilerDiagnosticCode } from "../compiler/contract-compiler-diagnostic.js";
|
|
3
|
+
import type { AvConfigDiagnosticCode } from "../config/config-diagnostic.js";
|
|
4
|
+
import type { AvConstructionStage } from "../framework/framework-construction.error.js";
|
|
5
|
+
import { type AvValidationCode } from "../operations/validation-code.js";
|
|
6
|
+
import { type AvOperationCode } from "./operation-response.js";
|
|
7
|
+
/**
|
|
8
|
+
* The documentation page every catalog entry links into. Each code has its own
|
|
9
|
+
* anchor there: the code in lower case (`#a2004`, `#config_required`).
|
|
10
|
+
*/
|
|
11
|
+
export declare const ERROR_CODES_DOCS_URL = "https://aventara-framework.vercel.app/docs/error-codes";
|
|
12
|
+
/**
|
|
13
|
+
* What kind of code an entry is: an outcome code's family (`success` `A1xxx`,
|
|
14
|
+
* `request` `A2xxx`, `internal` `A3xxx`, `auth` `A4xxx`), a `validation` issue
|
|
15
|
+
* code (`V1xxx`), or a startup code, by the construction stage that reports it.
|
|
16
|
+
*/
|
|
17
|
+
export type AvErrorKind = "success" | "request" | "internal" | "auth" | "validation" | AvConstructionStage;
|
|
18
|
+
/** Every code the catalog describes: outcome, validation and startup codes. */
|
|
19
|
+
export type AvErrorCatalogCode = AvOperationCode | AvValidationCode | AvConfigDiagnosticCode | AvAdapterDiscoveryDiagnosticCode | AvContractCompilerDiagnosticCode;
|
|
20
|
+
/** One code: what it means, why it happens, what to do, and where it is documented. */
|
|
21
|
+
export type AvErrorCatalogEntry<C extends AvErrorCatalogCode = AvErrorCatalogCode> = {
|
|
22
|
+
readonly code: C;
|
|
23
|
+
readonly kind: AvErrorKind;
|
|
24
|
+
/** Its meaning in one sentence; for a V-code, the framework's message for it. */
|
|
25
|
+
readonly message: string;
|
|
26
|
+
/** What typically produces it. */
|
|
27
|
+
readonly cause: string;
|
|
28
|
+
/** What to change. */
|
|
29
|
+
readonly fix: string;
|
|
30
|
+
/** Its entry on the error-codes page. */
|
|
31
|
+
readonly docs: string;
|
|
32
|
+
};
|
|
33
|
+
/** The error catalog's type: one entry per code. */
|
|
34
|
+
export type AvErrorCatalog = {
|
|
35
|
+
readonly [C in AvErrorCatalogCode]: AvErrorCatalogEntry<C>;
|
|
36
|
+
};
|
|
37
|
+
/** The documentation URL of one code: the error-codes page at its anchor. */
|
|
38
|
+
export declare function errorDocsUrl(code: AvErrorCatalogCode): string;
|
|
39
|
+
/**
|
|
40
|
+
* Every code Aventara answers or refuses with, by code: its `kind`, `message`,
|
|
41
|
+
* `cause`, `fix` and `docs` URL. An operation's `code`, a validation issue's
|
|
42
|
+
* `code` and a startup diagnostic's `code` are all keys of it:
|
|
43
|
+
*
|
|
44
|
+
* ```ts
|
|
45
|
+
* AvErrorCatalog[error.code].fix;
|
|
46
|
+
* AvErrorCatalog.V1000.docs; // https://aventara-framework.vercel.app/docs/error-codes#v1000
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare const AvErrorCatalog: AvErrorCatalog;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ADAPTER_DISCOVERY_DIAGNOSTIC_GUIDANCE } from "../adapters/adapter-discovery-diagnostic.guidance.js";
|
|
2
|
+
import { CONTRACT_COMPILER_DIAGNOSTIC_GUIDANCE } from "../compiler/contract-compiler-diagnostic.guidance.js";
|
|
3
|
+
import { CONFIG_DIAGNOSTIC_GUIDANCE } from "../config/config-diagnostic.guidance.js";
|
|
4
|
+
import { VALIDATION_CODE_GUIDANCE } from "../operations/validation-code.guidance.js";
|
|
5
|
+
import { VALIDATION_CODE_MESSAGES, VALIDATION_CODES, } from "../operations/validation-code.js";
|
|
6
|
+
import { OPERATION_CODE_GUIDANCE } from "./operation-code.guidance.js";
|
|
7
|
+
import { OPERATION_CODES } from "./operation-response.js";
|
|
8
|
+
export const ERROR_CODES_DOCS_URL = "https://aventara-framework.vercel.app/docs/error-codes";
|
|
9
|
+
export function errorDocsUrl(code) {
|
|
10
|
+
return `${ERROR_CODES_DOCS_URL}#${code.toLowerCase()}`;
|
|
11
|
+
}
|
|
12
|
+
const OUTCOME_KIND = {
|
|
13
|
+
"1": "success",
|
|
14
|
+
"2": "request",
|
|
15
|
+
"3": "internal",
|
|
16
|
+
"4": "auth",
|
|
17
|
+
};
|
|
18
|
+
function entry(code, kind, description) {
|
|
19
|
+
return Object.freeze({
|
|
20
|
+
code,
|
|
21
|
+
kind,
|
|
22
|
+
message: description.message,
|
|
23
|
+
cause: description.cause,
|
|
24
|
+
fix: description.fix,
|
|
25
|
+
docs: errorDocsUrl(code),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function entriesOf(table, kind) {
|
|
29
|
+
return Object.keys(table).map((code) => [
|
|
30
|
+
code,
|
|
31
|
+
entry(code, kind, table[code]),
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
34
|
+
export const AvErrorCatalog = Object.freeze(Object.fromEntries([
|
|
35
|
+
...OPERATION_CODES.map((code) => [
|
|
36
|
+
code,
|
|
37
|
+
entry(code, OUTCOME_KIND[code[1]], OPERATION_CODE_GUIDANCE[code]),
|
|
38
|
+
]),
|
|
39
|
+
...VALIDATION_CODES.map((code) => [
|
|
40
|
+
code,
|
|
41
|
+
entry(code, "validation", {
|
|
42
|
+
message: VALIDATION_CODE_MESSAGES[code],
|
|
43
|
+
...VALIDATION_CODE_GUIDANCE[code],
|
|
44
|
+
}),
|
|
45
|
+
]),
|
|
46
|
+
...entriesOf(CONFIG_DIAGNOSTIC_GUIDANCE, "configuration"),
|
|
47
|
+
...entriesOf(ADAPTER_DISCOVERY_DIAGNOSTIC_GUIDANCE, "discovery"),
|
|
48
|
+
...entriesOf(CONTRACT_COMPILER_DIAGNOSTIC_GUIDANCE, "contract-compilation"),
|
|
49
|
+
]));
|
|
@@ -18,4 +18,12 @@ export type AvExecutionOptions = {
|
|
|
18
18
|
* object), the Framework starts the request with `{}`.
|
|
19
19
|
*/
|
|
20
20
|
readonly state?: AvState & object;
|
|
21
|
+
/**
|
|
22
|
+
* The principal the call or run is checked as by the configuration's
|
|
23
|
+
* `policy`. An application call names one to opt in: left out, it is server
|
|
24
|
+
* code and the policy does not check it. A `framework.client.*` call is
|
|
25
|
+
* checked either way, and `as` replaces the principal `policy.principal`
|
|
26
|
+
* would derive from its state. `null` is the anonymous principal.
|
|
27
|
+
*/
|
|
28
|
+
readonly as?: unknown;
|
|
21
29
|
};
|
|
@@ -24,6 +24,4 @@ export declare function fieldCheckIssue(check: AvFieldCheck, subject: FieldCheck
|
|
|
24
24
|
export declare function fieldCheckIssues(checks: readonly AvFieldCheck[], value: unknown, subject: FieldCheckSubject, path: Path, list: boolean): readonly AvValidationIssue[];
|
|
25
25
|
/** The issues of the checks one value — a whole value, or a list's entry — breaks. */
|
|
26
26
|
export declare function entryCheckIssues(checks: readonly AvFieldCheck[], value: unknown, subject: FieldCheckSubject, path: Path): readonly AvValidationIssue[];
|
|
27
|
-
/** Whether a check judges a list's own length (`AvZ.minItems`/`AvZ.maxItems`). */
|
|
28
|
-
export declare function isListCheck(check: AvFieldCheck): boolean;
|
|
29
27
|
export {};
|
|
@@ -515,7 +515,7 @@ export function entryCheckIssues(checks, value, subject, path) {
|
|
|
515
515
|
}
|
|
516
516
|
return issues;
|
|
517
517
|
}
|
|
518
|
-
|
|
518
|
+
function isListCheck(check) {
|
|
519
519
|
return ((check.check === "max_length" || check.check === "min_length") &&
|
|
520
520
|
check.list === true);
|
|
521
521
|
}
|
|
@@ -17,26 +17,27 @@ export type AvComputeContext<M extends AvAdapterModel = AvAdapterModel> = AvComp
|
|
|
17
17
|
readonly $state: AvDeepReadonly<AvState>;
|
|
18
18
|
};
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* Computes a field's value when a row is created, whether or not the caller sent
|
|
21
|
+
* it. It receives the incoming `data` and returns the value to store; returning
|
|
22
|
+
* `undefined` keeps the current value.
|
|
21
23
|
*/
|
|
22
|
-
type
|
|
24
|
+
export type AvComputeCreate<M extends AvAdapterModel = AvAdapterModel> = (context: {
|
|
23
25
|
readonly field: string;
|
|
24
26
|
readonly value: unknown;
|
|
25
27
|
readonly data: Readonly<Record<string, unknown>>;
|
|
26
28
|
readonly ctx: AvComputeContext<M>;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Computes a field's value when a row is created, whether or not the caller sent
|
|
30
|
-
* it. It receives the incoming `data` and returns the value to store; returning
|
|
31
|
-
* `undefined` keeps the current value.
|
|
32
|
-
*/
|
|
33
|
-
export type AvComputeCreate<M extends AvAdapterModel = AvAdapterModel> = (context: ComputedWriteContext<M>) => unknown | Promise<unknown>;
|
|
29
|
+
}) => unknown | Promise<unknown>;
|
|
34
30
|
/**
|
|
35
31
|
* Computes a field's value when a row is updated, whether or not the caller sent
|
|
36
32
|
* it. It receives the incoming `data` and returns the value to store; returning
|
|
37
33
|
* `undefined` keeps the current value.
|
|
38
34
|
*/
|
|
39
|
-
export type AvComputeUpdate<M extends AvAdapterModel = AvAdapterModel> = (context:
|
|
35
|
+
export type AvComputeUpdate<M extends AvAdapterModel = AvAdapterModel> = (context: {
|
|
36
|
+
readonly field: string;
|
|
37
|
+
readonly value: unknown;
|
|
38
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
39
|
+
readonly ctx: AvComputeContext<M>;
|
|
40
|
+
}) => unknown | Promise<unknown>;
|
|
40
41
|
/**
|
|
41
42
|
* Computes a field's value when a row is read. It receives the stored `record`
|
|
42
43
|
* and returns the value to return; returning `undefined` keeps the current value.
|
|
@@ -6,13 +6,15 @@ export type Path = readonly (string | number)[];
|
|
|
6
6
|
type UnknownRecord = Readonly<Record<string, unknown>>;
|
|
7
7
|
/** A plain object: what a write record, or a directive's operand, is. */
|
|
8
8
|
export declare function isPlainRecord(value: unknown): value is UnknownRecord;
|
|
9
|
+
/** The containers a family writes, by argument key. */
|
|
10
|
+
export declare const WRITE_KEYS: Readonly<Partial<Record<AvOperationFamily, readonly string[]>>>;
|
|
9
11
|
/** The fields of `resource` with stages, in the Resource's field order. */
|
|
10
12
|
export declare function stagedFieldsOf(contract: AvContract, resource: string, stages: Readonly<Record<string, ResolvedFieldStages>>, kind: "pipes" | "guards"): readonly string[];
|
|
11
13
|
/** The value at `path` in `args`, or `undefined` when nothing is there. */
|
|
12
14
|
export declare function valueAt(args: unknown, path: Path): unknown;
|
|
13
15
|
/** `args` with the record at `path` replaced, every container on the way copied. */
|
|
14
16
|
export declare function replaceAt(args: unknown, path: Path, record: UnknownRecord): unknown;
|
|
15
|
-
|
|
17
|
+
type PipedFields = {
|
|
16
18
|
readonly args: unknown;
|
|
17
19
|
/** Whether a field pipe returned a value: the arguments must be held to the server's rules again. */
|
|
18
20
|
readonly changed: boolean;
|