@aventara/core 0.1.0-pilot.4 → 1.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/CHANGELOG.md +338 -0
  2. package/README.md +100 -3
  3. package/dist/adapters/adapter-model.d.ts +8 -0
  4. package/dist/adapters/adapter.interface.d.ts +6 -2
  5. package/dist/compiler/contract-compiler-diagnostic.d.ts +6 -0
  6. package/dist/compiler/contract.compiler.js +67 -0
  7. package/dist/config/config.resolver.d.ts +3 -0
  8. package/dist/config/config.resolver.js +1 -0
  9. package/dist/config/config.validator.js +6 -0
  10. package/dist/config/define-fields.d.ts +10 -3
  11. package/dist/config/framework-config.d.ts +4 -1
  12. package/dist/config/framework-fields-config.d.ts +6 -0
  13. package/dist/contracts/client-contract-structure.validator.d.ts +21 -1
  14. package/dist/contracts/client-contract-structure.validator.js +99 -2
  15. package/dist/contracts/contract-canonicalizer.js +32 -0
  16. package/dist/contracts/contract.d.ts +7 -0
  17. package/dist/contracts/field.d.ts +10 -0
  18. package/dist/contracts/json-shape.d.ts +65 -0
  19. package/dist/contracts/json-shape.js +1 -0
  20. package/dist/contracts/reference-write-limit.d.ts +7 -0
  21. package/dist/contracts/reference-write-limit.js +1 -0
  22. package/dist/contracts/scalar-value-type.d.ts +12 -1
  23. package/dist/framework/contract-view.d.ts +126 -21
  24. package/dist/framework/framework.d.ts +5 -3
  25. package/dist/framework/framework.factory.js +56 -13
  26. package/dist/index.d.ts +8 -40
  27. package/dist/index.js +0 -20
  28. package/dist/internal.d.ts +35 -0
  29. package/dist/internal.js +16 -0
  30. package/dist/json/avz.d.ts +96 -0
  31. package/dist/json/avz.js +212 -0
  32. package/dist/json/index.d.ts +6 -0
  33. package/dist/json/index.js +1 -0
  34. package/dist/json/json-shape.registry.d.ts +22 -0
  35. package/dist/json/json-shape.registry.js +16 -0
  36. package/dist/json/zod-issue.translator.d.ts +51 -0
  37. package/dist/json/zod-issue.translator.js +142 -0
  38. package/dist/operations/operation-arguments.d.ts +151 -101
  39. package/dist/operations/operation-identity.d.ts +2 -0
  40. package/dist/operations/operation-identity.js +3 -0
  41. package/dist/operations/operation-validator-core.d.ts +1 -1
  42. package/dist/operations/operation-validator-core.js +28 -10
  43. package/dist/operations/operation-validator.d.ts +20 -5
  44. package/dist/operations/operation-validator.js +26 -10
  45. package/dist/operations/projection-scope.resolver.d.ts +1 -1
  46. package/dist/operations/structural-limits.walker.d.ts +19 -0
  47. package/dist/operations/structural-limits.walker.js +344 -0
  48. package/dist/protocol/absent-route.responder.d.ts +2 -1
  49. package/dist/protocol/absent-route.responder.js +32 -6
  50. package/dist/protocol/http-request.decoder.d.ts +6 -0
  51. package/dist/protocol/http-request.decoder.js +11 -3
  52. package/dist/protocol/protocol.binder.d.ts +4 -2
  53. package/dist/protocol/protocol.binder.js +3 -1
  54. package/dist/protocol/protocol.handler.d.ts +6 -2
  55. package/dist/protocol/protocol.handler.js +14 -4
  56. package/dist/protocol/unmounted-route.error.d.ts +19 -0
  57. package/dist/protocol/unmounted-route.error.js +10 -0
  58. package/dist/runtime/caller-data.copier.d.ts +59 -0
  59. package/dist/runtime/caller-data.copier.js +470 -0
  60. package/dist/runtime/caller-data.door.d.ts +56 -0
  61. package/dist/runtime/caller-data.door.js +65 -0
  62. package/dist/runtime/computed-read-runtime.js +3 -10
  63. package/dist/runtime/computed-value.error.d.ts +13 -0
  64. package/dist/runtime/computed-value.error.js +9 -0
  65. package/dist/runtime/create-requirement.d.ts +43 -7
  66. package/dist/runtime/create-requirement.js +89 -9
  67. package/dist/runtime/diagnostics-reporter.d.ts +20 -4
  68. package/dist/runtime/diagnostics-reporter.js +11 -4
  69. package/dist/runtime/error-boundary.d.ts +8 -0
  70. package/dist/runtime/error-boundary.js +65 -35
  71. package/dist/runtime/field-behavior.d.ts +2 -2
  72. package/dist/runtime/framework-error.d.ts +12 -0
  73. package/dist/runtime/misuse-reporter.d.ts +32 -0
  74. package/dist/runtime/misuse-reporter.js +19 -0
  75. package/dist/runtime/mutation-planner.js +13 -11
  76. package/dist/runtime/operation-request.d.ts +4 -11
  77. package/dist/runtime/operation-runtime.d.ts +14 -7
  78. package/dist/runtime/operation-runtime.js +37 -18
  79. package/dist/runtime/outcome-mapper.js +12 -2
  80. package/dist/runtime/output-validator.d.ts +10 -0
  81. package/dist/runtime/output-validator.js +11 -0
  82. package/dist/runtime/owned-execution.registry.d.ts +13 -0
  83. package/dist/runtime/owned-execution.registry.js +7 -0
  84. package/dist/runtime/pipeline.d.ts +19 -7
  85. package/dist/runtime/referential-action.d.ts +7 -0
  86. package/dist/runtime/request-envelope.validator.d.ts +5 -0
  87. package/dist/runtime/request-envelope.validator.js +118 -0
  88. package/dist/runtime/scalar-runtime.d.ts +30 -2
  89. package/dist/runtime/scalar-runtime.js +162 -79
  90. package/dist/transactions/transaction-plan-assembler.d.ts +5 -1
  91. package/dist/transactions/transaction-plan-assembler.js +74 -75
  92. package/dist/transactions/transaction-plan-validator.d.ts +30 -7
  93. package/dist/transactions/transaction-plan-validator.js +204 -153
  94. package/dist/transactions/transaction-reference-collector.d.ts +30 -0
  95. package/dist/transactions/transaction-reference-collector.js +204 -0
  96. package/dist/transactions/transaction-reference-resolver.js +10 -5
  97. package/dist/transactions/transaction-reference-validator.js +24 -17
  98. package/dist/transactions/transaction-reference.d.ts +23 -51
  99. package/dist/transactions/transaction-request.d.ts +3 -3
  100. package/dist/transactions/transaction-response.d.ts +6 -1
  101. package/dist/transactions/transaction-response.js +24 -1
  102. package/dist/transactions/transaction-runtime.d.ts +4 -2
  103. package/dist/transactions/transaction-runtime.js +4 -3
  104. package/package.json +17 -3
  105. package/dist/operations/operation-boolean-nodes.d.ts +0 -11
  106. package/dist/operations/operation-boolean-nodes.js +0 -283
  107. package/dist/operations/operation-nesting.d.ts +0 -8
  108. package/dist/operations/operation-nesting.js +0 -307
@@ -1,17 +1,67 @@
1
1
  import { CanonicalJsonError } from "../contracts/contract-canonicalizer.js";
2
- import { lookupField, lookupOwn, lookupResource, } from "../contracts/contract-lookup.js";
2
+ import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
3
3
  import { parseOperationIdentity } from "../operations/operation-identity.js";
4
+ import { findOperationAvailabilityIssue, unavailableOperationKey, } from "../operations/operation-validator.js";
4
5
  import { VALIDATION_CODE_MESSAGES, validationIssue, } from "../operations/validation-code.js";
6
+ import { CallerDataError, locateCallerDataError, } from "../runtime/caller-data.copier.js";
7
+ import { copyAtDoor, misuseIdentityOf, refuseCallerData, } from "../runtime/caller-data.door.js";
5
8
  import { planReadOperation, } from "../runtime/computed-read-runtime.js";
6
- import { OPERATION_ARGUMENTS_PATH, planOperationArgumentsPath, } from "../runtime/error-boundary.js";
9
+ import { planOperationArgumentsPath, planStepPath, } from "../runtime/error-boundary.js";
10
+ import { createMisuseReporter } from "../runtime/misuse-reporter.js";
7
11
  import { operationFailure } from "../runtime/operation-response.js";
8
12
  import { activeContract, validateOperationRequest, validateProtocolIdentity, } from "../runtime/operation-runtime.js";
13
+ import { mapValidationOutcome } from "../runtime/outcome-mapper.js";
9
14
  import { encodeOperationArgumentsForWire } from "./operation-arguments-encoder.js";
10
15
  import { computeOperationFingerprint, isOperationFingerprint, } from "./operation-fingerprint.js";
11
16
  import { inspectTransactionEnvelope, inspectTransactionOperationEntry, inspectTransactionOperations, } from "./transaction-envelope.js";
12
- import { routeTransactionReferenceCandidate } from "./transaction-reference.js";
17
+ import { routeTransactionReferenceCandidate, } from "./transaction-reference.js";
18
+ import { collectTransactionReferenceCandidates, } from "./transaction-reference-collector.js";
13
19
  import { validateTransactionReferences } from "./transaction-reference-validator.js";
14
20
  import { transactionOperationFailure } from "./transaction-response.js";
21
+ const CALLER_PLAN = { source: "caller" };
22
+ const STEP_ARGUMENTS_POLICY = {
23
+ mirror: (value) => Object.hasOwn(value, "$ref"),
24
+ };
25
+ function captureSteps(operations, operationCount, planArguments) {
26
+ const steps = [];
27
+ for (let index = 0; index < operationCount; index += 1) {
28
+ const operationEntry = inspectTransactionOperationEntry(operations, index);
29
+ if (!operationEntry.ok) {
30
+ steps.push({
31
+ ok: false,
32
+ response: structuralFailure(operationEntry.issue),
33
+ });
34
+ break;
35
+ }
36
+ const nodeEnvelope = inspectTransactionEnvelope(operationEntry.value, {
37
+ required: OPERATION_KEYS,
38
+ invalidContainerPath: [],
39
+ invalidContainerMessage: "Operation node must be an object.",
40
+ });
41
+ if (!nodeEnvelope.ok) {
42
+ steps.push({
43
+ ok: false,
44
+ response: structuralFailure(nodeEnvelope.issue, index),
45
+ });
46
+ break;
47
+ }
48
+ const node = nodeEnvelope.values;
49
+ const args = node.get("args");
50
+ const refused = planArguments.source === "owned"
51
+ ? planArguments.refused?.get(index)
52
+ : undefined;
53
+ const copy = refused !== undefined
54
+ ? { ok: false, error: refused }
55
+ : planArguments.source === "owned"
56
+ ? { ok: true, value: args }
57
+ : copyAtDoor(args, STEP_ARGUMENTS_POLICY);
58
+ steps.push({ ok: true, node, args: copy });
59
+ if (!copy.ok) {
60
+ break;
61
+ }
62
+ }
63
+ return steps;
64
+ }
15
65
  const PLAN_KEYS = ["operations"];
16
66
  const OPERATION_KEYS = [
17
67
  "resource",
@@ -23,10 +73,23 @@ const OPERATION_KEYS = [
23
73
  function isObject(value) {
24
74
  return typeof value === "object" && value !== null && !Array.isArray(value);
25
75
  }
76
+ function operationKeyFailure(key, message, operation) {
77
+ return transactionOperationFailure(operationFailure("A2002", {
78
+ message: "Operation arguments failed framework validation.",
79
+ issues: [validationIssue("V1006", [key], message)],
80
+ }), operation);
81
+ }
26
82
  function structuralFailure(rejection, operation) {
27
83
  return operationFailure("A2004", {
28
84
  message: "Transaction plan failed framework validation.",
29
- issues: [rejection],
85
+ issues: [
86
+ operation === undefined || rejection.path === undefined
87
+ ? rejection
88
+ : {
89
+ ...rejection,
90
+ path: [...planStepPath(operation), ...rejection.path],
91
+ },
92
+ ],
30
93
  ...(operation === undefined ? {} : { operation }),
31
94
  });
32
95
  }
@@ -37,11 +100,11 @@ function syntheticRequest(origin, requestId, resource, identity, args) {
37
100
  ...identity,
38
101
  arguments: args,
39
102
  };
40
- return origin.scope === "application"
41
- ? { ...common, scope: "application" }
103
+ return origin.origin === "application"
104
+ ? { ...common, origin: "application" }
42
105
  : {
43
106
  ...common,
44
- scope: "client",
107
+ origin: "client",
45
108
  protocol: origin.protocol,
46
109
  ...(origin.transport === undefined
47
110
  ? {}
@@ -49,10 +112,10 @@ function syntheticRequest(origin, requestId, resource, identity, args) {
49
112
  };
50
113
  }
51
114
  function requestOrigin(request) {
52
- return request.scope === "application"
53
- ? { scope: "application" }
115
+ return request.origin === "application"
116
+ ? { origin: "application" }
54
117
  : {
55
- scope: "client",
118
+ origin: "client",
56
119
  protocol: request.protocol,
57
120
  ...(request.transport === undefined
58
121
  ? {}
@@ -60,55 +123,13 @@ function requestOrigin(request) {
60
123
  };
61
124
  }
62
125
  function originContracts(contracts, origins) {
63
- const layers = new Set(origins.map((origin) => origin.scope));
64
- return [...layers].map((scope) => scope === "application" ? contracts.application : contracts.client);
65
- }
66
- function collectDataCandidates(contract, resourceName, data, path, candidates) {
67
- if (!isObject(data)) {
68
- return;
69
- }
70
- const resource = lookupResource(contract, resourceName);
71
- for (const [fieldName, value] of Object.entries(data)) {
72
- const field = lookupField(resource, fieldName);
73
- const route = routeTransactionReferenceCandidate(value);
74
- if (field?.kind === "scalar" && route.kind !== "ordinary") {
75
- candidates.push({
76
- path: [...path, fieldName],
77
- field,
78
- candidate: route.candidate,
79
- });
80
- }
81
- }
82
- }
83
- function collectCandidates(contract, request, index, args) {
84
- const candidates = [];
85
- const root = planOperationArgumentsPath(index);
86
- if (request.family === "create") {
87
- const data = lookupOwn(args, "data");
88
- if (request.variant === "many" || request.variant === "count") {
89
- if (Array.isArray(data)) {
90
- data.forEach((entry, dataIndex) => {
91
- collectDataCandidates(contract, request.resource, entry, [...root, "data", dataIndex], candidates);
92
- });
93
- }
94
- }
95
- else {
96
- collectDataCandidates(contract, request.resource, data, [...root, "data"], candidates);
97
- }
98
- }
99
- else if (request.family === "update") {
100
- collectDataCandidates(contract, request.resource, lookupOwn(args, "data"), [...root, "data"], candidates);
101
- }
102
- else if (request.family === "upsert") {
103
- for (const stage of ["create", "update"]) {
104
- collectDataCandidates(contract, request.resource, lookupOwn(args, stage), [...root, stage], candidates);
105
- }
106
- }
107
- return candidates;
126
+ const layers = new Set(origins.map(({ origin }) => origin));
127
+ return [...layers].map((origin) => origin === "application" ? contracts.application : contracts.client);
108
128
  }
109
129
  function* relationTraversals(contract, resourceName, value, path) {
110
130
  const resource = lookupResource(contract, resourceName);
111
- if (resource === undefined) {
131
+ if (resource === undefined ||
132
+ routeTransactionReferenceCandidate(value).kind !== "ordinary") {
112
133
  return;
113
134
  }
114
135
  if (Array.isArray(value)) {
@@ -182,7 +203,7 @@ export function transactionsUnavailableFailure() {
182
203
  issues: [validationIssue("V1006", ["operations"], message)],
183
204
  });
184
205
  }
185
- export async function validateTransactionPlan(dependencies, request, origins) {
206
+ export async function validateTransactionPlan(dependencies, request, origins, planArguments = CALLER_PLAN) {
186
207
  const protocolFailure = validateProtocolIdentity(dependencies.contracts, request);
187
208
  if (protocolFailure !== undefined) {
188
209
  return { ok: false, response: protocolFailure };
@@ -229,30 +250,18 @@ export async function validateTransactionPlan(dependencies, request, origins) {
229
250
  }),
230
251
  };
231
252
  }
253
+ const steps = captureSteps(operations, operationCount, planArguments);
254
+ const misuse = createMisuseReporter(dependencies.config.misuse);
232
255
  const validated = [];
233
256
  const cascaded = new Set();
234
257
  for (let index = 0; index < operationCount; index += 1) {
235
- const operationEntry = inspectTransactionOperationEntry(operations, index);
236
- if (!operationEntry.ok) {
237
- return {
238
- ok: false,
239
- response: structuralFailure(operationEntry.issue),
240
- };
241
- }
242
- const nodeEnvelope = inspectTransactionEnvelope(operationEntry.value, {
243
- required: OPERATION_KEYS,
244
- invalidContainerPath: ["operation"],
245
- invalidContainerMessage: "Operation node must be an object.",
246
- });
247
- if (!nodeEnvelope.ok) {
248
- return {
249
- ok: false,
250
- response: structuralFailure(nodeEnvelope.issue, index),
251
- };
258
+ const step = steps[index];
259
+ if (!step.ok) {
260
+ return { ok: false, response: step.response };
252
261
  }
253
- const node = nodeEnvelope.values;
262
+ const node = step.node;
254
263
  const origin = originOf(index);
255
- const contract = origin.scope === "application"
264
+ const contract = origin.origin === "application"
256
265
  ? dependencies.contracts.application
257
266
  : dependencies.contracts.client;
258
267
  const resourceValue = node.get("resource");
@@ -286,100 +295,142 @@ export async function validateTransactionPlan(dependencies, request, origins) {
286
295
  if (identity === undefined) {
287
296
  return {
288
297
  ok: false,
289
- response: transactionOperationFailure(operationFailure("A2002", {
290
- message: "Operation arguments failed framework validation.",
291
- issues: [
292
- validationIssue("V1006", ["operation"], "Operation is not part of the standard operation grammar."),
293
- ],
294
- }), index),
298
+ response: operationKeyFailure(typeof family === "string"
299
+ ? unavailableOperationKey(contract, {
300
+ resource: resourceValue,
301
+ family,
302
+ })
303
+ : "family", "Operation is not part of the standard operation grammar.", index),
295
304
  };
296
305
  }
297
- const operationRequest = syntheticRequest(origin, request.requestId, resourceValue, identity, node.get("args"));
298
- const operationValidation = validateOperationRequest(contract, operationRequest, { transactionReferences: true });
299
- if (!operationValidation.ok) {
306
+ const stepRequest = { resource: resourceValue, ...identity };
307
+ const unavailable = findOperationAvailabilityIssue(contract, stepRequest);
308
+ if (unavailable !== undefined) {
300
309
  return {
301
310
  ok: false,
302
- response: transactionOperationFailure(operationValidation.response, index),
311
+ response: transactionOperationFailure(mapValidationOutcome([unavailable]), index),
303
312
  };
304
313
  }
305
- const candidate = {
306
- index,
307
- request: operationRequest,
308
- arguments: operationValidation.arguments,
309
- projection: planReadOperation(dependencies.contracts.core, contract, (origin.scope === "application"
310
- ? dependencies.config.application
311
- : dependencies.config.client).behaviors, operationRequest, operationValidation.arguments).projection,
312
- declaredFingerprint: node.get("fingerprint"),
313
- candidates: collectCandidates(contract, operationRequest, index, operationValidation.arguments),
314
- };
315
- const referenceValidation = validateTransactionReferences(candidate, validated);
316
- if (!referenceValidation.ok) {
317
- return referenceValidation;
314
+ if (!step.args.ok) {
315
+ return {
316
+ ok: false,
317
+ response: transactionOperationFailure(mapValidationOutcome([
318
+ refuseCallerData(step.args.error, planOperationArgumentsPath(index), {
319
+ ...misuseIdentityOf({
320
+ ...stepRequest,
321
+ origin: origin.origin,
322
+ }),
323
+ operation: index,
324
+ }, misuse),
325
+ ]), index),
326
+ };
318
327
  }
319
- const validatedRequest = {
320
- ...candidate.request,
321
- arguments: referenceValidation.requestArguments,
322
- };
323
- const validatedArguments = referenceValidation.arguments;
324
- const wireArguments = origin.scope === "client"
325
- ? validatedRequest.arguments
326
- : encodeOperationArgumentsForWire(contract, validatedRequest, validatedArguments);
327
- let fingerprint;
328
328
  try {
329
- fingerprint = await computeOperationFingerprint({
330
- resource: validatedRequest.resource,
331
- family: validatedRequest.family,
332
- variant: validatedRequest.variant,
333
- args: wireArguments,
329
+ const operationRequest = syntheticRequest(origin, request.requestId, resourceValue, identity, step.args.value);
330
+ const operationValidation = validateOperationRequest(contract, operationRequest, { transactionReferences: true });
331
+ if (!operationValidation.ok) {
332
+ return {
333
+ ok: false,
334
+ response: transactionOperationFailure(operationValidation.response, index),
335
+ };
336
+ }
337
+ const candidate = {
338
+ index,
339
+ request: operationRequest,
340
+ arguments: operationValidation.arguments,
341
+ projection: planReadOperation(dependencies.contracts.core, contract, (origin.origin === "application"
342
+ ? dependencies.config.application
343
+ : dependencies.config.client).behaviors, operationRequest, operationValidation.arguments).projection,
344
+ declaredFingerprint: node.get("fingerprint"),
345
+ candidates: collectTransactionReferenceCandidates(contract, operationRequest, index, operationValidation.arguments),
346
+ };
347
+ const referenceValidation = validateTransactionReferences(candidate, validated);
348
+ if (!referenceValidation.ok) {
349
+ return referenceValidation;
350
+ }
351
+ const validatedRequest = {
352
+ ...candidate.request,
353
+ arguments: referenceValidation.requestArguments,
354
+ };
355
+ const validatedArguments = referenceValidation.arguments;
356
+ const wireArguments = origin.origin === "client"
357
+ ? validatedRequest.arguments
358
+ : encodeOperationArgumentsForWire(contract, validatedRequest, validatedArguments);
359
+ let fingerprint;
360
+ try {
361
+ fingerprint = await computeOperationFingerprint({
362
+ resource: validatedRequest.resource,
363
+ family: validatedRequest.family,
364
+ variant: validatedRequest.variant,
365
+ args: wireArguments,
366
+ });
367
+ }
368
+ catch (error) {
369
+ if (!(error instanceof CanonicalJsonError)) {
370
+ throw error;
371
+ }
372
+ return {
373
+ ok: false,
374
+ response: structuralFailure(validationIssue("V1001", ["args"], "Invalid runtime/wire type."), index),
375
+ };
376
+ }
377
+ if (!isOperationFingerprint(candidate.declaredFingerprint) ||
378
+ candidate.declaredFingerprint !== fingerprint) {
379
+ return {
380
+ ok: false,
381
+ response: transactionOperationFailure(operationFailure("A2007", {
382
+ message: "Operation fingerprint does not match its arguments.",
383
+ issues: [
384
+ validationIssue("V1017", ["fingerprint"], "Operation fingerprint does not match its arguments."),
385
+ ],
386
+ }), index),
387
+ };
388
+ }
389
+ const dependency = cascadeDependency(contract, validatedRequest, index, cascaded);
390
+ if (dependency !== undefined) {
391
+ return {
392
+ ok: false,
393
+ response: transactionOperationFailure(operationFailure("A2004", {
394
+ message: "Transaction plan failed framework validation.",
395
+ issues: [
396
+ validationIssue("V1019", dependency, VALIDATION_CODE_MESSAGES.V1019),
397
+ ],
398
+ }), index),
399
+ };
400
+ }
401
+ for (const resource of deletedResources(contract, validatedRequest, index)) {
402
+ for (const removed of dependencies.cascades(resource)) {
403
+ cascaded.add(removed);
404
+ }
405
+ }
406
+ validated.push({
407
+ index: candidate.index,
408
+ request: validatedRequest,
409
+ contract,
410
+ arguments: validatedArguments,
411
+ projection: candidate.projection,
412
+ fingerprint,
413
+ references: referenceValidation.references,
334
414
  });
335
415
  }
336
416
  catch (error) {
337
- if (!(error instanceof CanonicalJsonError)) {
417
+ if (!(error instanceof CallerDataError)) {
338
418
  throw error;
339
419
  }
340
420
  return {
341
421
  ok: false,
342
- response: structuralFailure(validationIssue("V1001", OPERATION_ARGUMENTS_PATH, "Invalid runtime/wire type."), index),
422
+ response: transactionOperationFailure(mapValidationOutcome([
423
+ refuseCallerData(locateCallerDataError(error, step.args.value), planOperationArgumentsPath(index), {
424
+ ...misuseIdentityOf({
425
+ resource: resourceValue,
426
+ ...identity,
427
+ origin: origin.origin,
428
+ }),
429
+ operation: index,
430
+ }, misuse),
431
+ ]), index),
343
432
  };
344
433
  }
345
- if (!isOperationFingerprint(candidate.declaredFingerprint) ||
346
- candidate.declaredFingerprint !== fingerprint) {
347
- return {
348
- ok: false,
349
- response: transactionOperationFailure(operationFailure("A2007", {
350
- message: "Operation fingerprint does not match its arguments.",
351
- issues: [
352
- validationIssue("V1017", ["fingerprint"], "Operation fingerprint does not match its arguments."),
353
- ],
354
- }), index),
355
- };
356
- }
357
- const dependency = cascadeDependency(contract, validatedRequest, index, cascaded);
358
- if (dependency !== undefined) {
359
- return {
360
- ok: false,
361
- response: transactionOperationFailure(operationFailure("A2004", {
362
- message: "Transaction plan failed framework validation.",
363
- issues: [
364
- validationIssue("V1019", dependency, VALIDATION_CODE_MESSAGES.V1019),
365
- ],
366
- }), index),
367
- };
368
- }
369
- for (const resource of deletedResources(contract, validatedRequest, index)) {
370
- for (const removed of dependencies.cascades(resource)) {
371
- cascaded.add(removed);
372
- }
373
- }
374
- validated.push({
375
- index: candidate.index,
376
- request: validatedRequest,
377
- contract,
378
- arguments: validatedArguments,
379
- projection: candidate.projection,
380
- fingerprint,
381
- references: referenceValidation.references,
382
- });
383
434
  }
384
435
  return { ok: true, plan: { operations: validated } };
385
436
  }
@@ -0,0 +1,30 @@
1
+ import type { Contract } from "../contracts/contract.js";
2
+ import type { ScalarField } from "../contracts/field.js";
3
+ import type { OperationIdentity } from "../operations/operation-identity.js";
4
+ import type { SemanticOperationArguments } from "../operations/operation-validator.js";
5
+ import { type TransactionSlotShape } from "./transaction-reference.js";
6
+ type Path = readonly (string | number)[];
7
+ /** One `$ref` candidate found at a reference position, before it is validated. */
8
+ export type TransactionReferenceCandidateSlot = {
9
+ readonly path: Path;
10
+ readonly field: ScalarField<Contract>;
11
+ readonly shape: TransactionSlotShape;
12
+ /** The slot is a scalar value of mutation data: what it resolves to is written. */
13
+ readonly written: boolean;
14
+ readonly candidate: unknown;
15
+ };
16
+ /**
17
+ * Every `$ref` candidate at a reference position of one validated operation, with the
18
+ * full wire path, the destination field and the slot's shape. The positions: mutation
19
+ * data (`create`'s `data`, each `data[]` entry of a bulk create, `update`'s `data`,
20
+ * `upsert`'s `create`/`update`) at any depth — its scalar values, the unique keys its
21
+ * relation directives name, the `where` of `$update`/`$delete`/`$upsert`, and the data
22
+ * they nest — the `cursor`, and the step's own `where` at any depth.
23
+ *
24
+ * It reads the validated argument view, whose normalization keeps every key where
25
+ * the caller wrote it, so a slot path names the same member of the wire view.
26
+ */
27
+ export declare function collectTransactionReferenceCandidates(contract: Contract, request: OperationIdentity & {
28
+ readonly resource: string;
29
+ }, index: number, args: SemanticOperationArguments): readonly TransactionReferenceCandidateSlot[];
30
+ export {};