@aventara/core 1.0.0-rc.1 → 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.
Files changed (261) hide show
  1. package/CHANGELOG.md +1022 -16
  2. package/ERRORS.md +142 -0
  3. package/README.md +330 -16
  4. package/dist/adapters/adapter-discovery-diagnostic.guidance.d.ts +6 -0
  5. package/dist/adapters/adapter-discovery-diagnostic.guidance.js +7 -0
  6. package/dist/adapters/adapter-field.d.ts +22 -0
  7. package/dist/adapters/adapter-identifier.d.ts +9 -0
  8. package/dist/adapters/adapter-identifier.js +6 -1
  9. package/dist/adapters/adapter-model.d.ts +9 -0
  10. package/dist/adapters/adapter-operation.d.ts +18 -3
  11. package/dist/adapters/adapter-resource.d.ts +5 -0
  12. package/dist/adapters/adapter.interface.d.ts +10 -0
  13. package/dist/avz/avz.d.ts +1 -1
  14. package/dist/avz/json-shape.registry.d.ts +2 -1
  15. package/dist/compiler/contract-compiler-diagnostic.guidance.d.ts +6 -0
  16. package/dist/compiler/contract-compiler-diagnostic.guidance.js +97 -0
  17. package/dist/compiler/contract.compiler.d.ts +6 -0
  18. package/dist/compiler/contract.compiler.js +281 -31
  19. package/dist/compiler/create-requirements.projector.js +1 -3
  20. package/dist/compiler/field-validator.compiler.js +1 -3
  21. package/dist/compiler/managed-elsewhere.projector.d.ts +52 -0
  22. package/dist/compiler/managed-elsewhere.projector.js +179 -0
  23. package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
  24. package/dist/compiler/managed-elsewhere.validator.js +74 -0
  25. package/dist/config/cache-stage.factory.d.ts +24 -0
  26. package/dist/config/cache-stage.factory.js +3 -0
  27. package/dist/config/computed-fields.d.ts +62 -0
  28. package/dist/config/computed-fields.js +73 -0
  29. package/dist/config/config-diagnostic.guidance.d.ts +6 -0
  30. package/dist/config/config-diagnostic.guidance.js +32 -0
  31. package/dist/config/config.resolver.d.ts +24 -0
  32. package/dist/config/config.resolver.js +66 -7
  33. package/dist/config/config.validator.js +283 -21
  34. package/dist/config/define-resource.d.ts +1 -5
  35. package/dist/config/entrypoint.normalizer.d.ts +3 -2
  36. package/dist/config/exact-framework-config.d.ts +73 -22
  37. package/dist/config/field-compute.resolver.d.ts +2 -0
  38. package/dist/config/field-compute.resolver.js +9 -3
  39. package/dist/config/framework-config.d.ts +53 -15
  40. package/dist/config/framework-resources-config.d.ts +25 -14
  41. package/dist/config/pipeline-config.d.ts +20 -4
  42. package/dist/config/pipeline-tree.resolver.d.ts +2 -2
  43. package/dist/config/pipeline-tree.resolver.js +2 -3
  44. package/dist/contracts/access-route.rules.d.ts +10 -0
  45. package/dist/contracts/access-route.rules.js +45 -0
  46. package/dist/contracts/canonical-json.writer.d.ts +7 -0
  47. package/dist/contracts/canonical-json.writer.js +55 -0
  48. package/dist/contracts/capability.d.ts +26 -1
  49. package/dist/contracts/capability.js +20 -0
  50. package/dist/contracts/client-contract-structure.validator.d.ts +365 -89
  51. package/dist/contracts/client-contract-structure.validator.js +49 -2
  52. package/dist/contracts/contract-access.d.ts +29 -0
  53. package/dist/contracts/contract-access.js +1 -0
  54. package/dist/contracts/contract-canonicalizer.d.ts +9 -1
  55. package/dist/contracts/contract-canonicalizer.js +35 -4
  56. package/dist/contracts/contract-hash.d.ts +0 -1
  57. package/dist/contracts/contract-hash.js +1 -1
  58. package/dist/contracts/contract-limits.d.ts +6 -0
  59. package/dist/contracts/contract-limits.js +2 -0
  60. package/dist/contracts/contract.d.ts +42 -1
  61. package/dist/contracts/field.d.ts +58 -1
  62. package/dist/contracts/json-schema.projector.d.ts +11 -0
  63. package/dist/contracts/json-schema.projector.js +76 -0
  64. package/dist/contracts/scalar-value-type.d.ts +3 -1
  65. package/dist/framework/access-facade.d.ts +116 -0
  66. package/dist/framework/access-facade.js +118 -0
  67. package/dist/framework/contract-view.d.ts +120 -16
  68. package/dist/framework/framework-construction.error.d.ts +14 -4
  69. package/dist/framework/framework-construction.error.js +18 -2
  70. package/dist/framework/framework.d.ts +26 -5
  71. package/dist/framework/framework.factory.d.ts +1 -1
  72. package/dist/framework/framework.factory.js +145 -24
  73. package/dist/framework/operation-facade.d.ts +141 -13
  74. package/dist/framework/operation-facade.js +9 -1
  75. package/dist/framework/operation-set.runner.d.ts +47 -0
  76. package/dist/framework/operation-set.runner.js +168 -0
  77. package/dist/index.d.ts +19 -5
  78. package/dist/index.js +3 -0
  79. package/dist/internal.d.ts +9 -2
  80. package/dist/internal.js +8 -0
  81. package/dist/operations/database-refusal.d.ts +51 -0
  82. package/dist/operations/database-refusal.js +45 -0
  83. package/dist/operations/operation-arguments.d.ts +148 -60
  84. package/dist/operations/operation-call.d.ts +9 -5
  85. package/dist/operations/operation-result.d.ts +6 -4
  86. package/dist/operations/operation-validator-core.js +160 -39
  87. package/dist/operations/operation-validator.d.ts +1 -1
  88. package/dist/operations/structural-limits.walker.d.ts +1 -1
  89. package/dist/operations/structural-limits.walker.js +1 -3
  90. package/dist/operations/validation-code.guidance.d.ts +6 -0
  91. package/dist/operations/validation-code.guidance.js +90 -0
  92. package/dist/operations/write-scope.resolver.d.ts +4 -0
  93. package/dist/operations/write-scope.resolver.js +2 -0
  94. package/dist/policy/access-provider.interface.d.ts +91 -0
  95. package/dist/policy/access-provider.interface.js +1 -0
  96. package/dist/policy/access-provider.registry.d.ts +17 -0
  97. package/dist/policy/access-provider.registry.js +15 -0
  98. package/dist/policy/access-question.d.ts +20 -0
  99. package/dist/policy/access-question.js +1 -0
  100. package/dist/policy/access-question.registry.d.ts +5 -0
  101. package/dist/policy/access-question.registry.js +19 -0
  102. package/dist/policy/access-question.runtime.d.ts +36 -0
  103. package/dist/policy/access-question.runtime.js +295 -0
  104. package/dist/policy/access-verb.table.d.ts +56 -0
  105. package/dist/policy/access-verb.table.js +21 -0
  106. package/dist/policy/access-verbs.d.ts +46 -0
  107. package/dist/policy/access-verbs.js +1 -0
  108. package/dist/policy/policy-admission.d.ts +20 -0
  109. package/dist/policy/policy-admission.js +407 -0
  110. package/dist/policy/policy-after-update.runtime.d.ts +79 -0
  111. package/dist/policy/policy-after-update.runtime.js +206 -0
  112. package/dist/policy/policy-condition.d.ts +15 -0
  113. package/dist/policy/policy-condition.js +36 -0
  114. package/dist/policy/policy-engine.d.ts +205 -0
  115. package/dist/policy/policy-engine.js +1 -0
  116. package/dist/policy/policy-named-rows.d.ts +18 -0
  117. package/dist/policy/policy-named-rows.js +51 -0
  118. package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
  119. package/dist/policy/policy-nested-write.runtime.js +536 -0
  120. package/dist/policy/policy-read.runtime.d.ts +81 -0
  121. package/dist/policy/policy-read.runtime.js +501 -0
  122. package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
  123. package/dist/policy/policy-reference-write.runtime.js +336 -0
  124. package/dist/policy/policy-request.d.ts +72 -0
  125. package/dist/policy/policy-request.js +115 -0
  126. package/dist/policy/policy-session.d.ts +106 -0
  127. package/dist/policy/policy-session.js +293 -0
  128. package/dist/policy/policy-startup.validator.d.ts +10 -0
  129. package/dist/policy/policy-startup.validator.js +112 -0
  130. package/dist/policy/policy-write.runtime.d.ts +39 -0
  131. package/dist/policy/policy-write.runtime.js +530 -0
  132. package/dist/prebuilt/core-version.generated.d.ts +2 -0
  133. package/dist/prebuilt/core-version.generated.js +1 -0
  134. package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
  135. package/dist/prebuilt/prebuilt-changes.js +63 -0
  136. package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
  137. package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
  138. package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
  139. package/dist/prebuilt/prebuilt-contracts.js +1 -0
  140. package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
  141. package/dist/prebuilt/prebuilt-contracts.loader.js +75 -0
  142. package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
  143. package/dist/prebuilt/prebuilt-inputs.fingerprint.js +227 -0
  144. package/dist/protocol/absent-route.responder.d.ts +49 -14
  145. package/dist/protocol/absent-route.responder.js +92 -15
  146. package/dist/protocol/contract-document.responder.d.ts +9 -1
  147. package/dist/protocol/contract-document.responder.js +3 -2
  148. package/dist/protocol/http-request.decoder.d.ts +52 -3
  149. package/dist/protocol/http-request.decoder.js +45 -6
  150. package/dist/protocol/http-request.reader.d.ts +10 -3
  151. package/dist/protocol/http-request.reader.js +12 -2
  152. package/dist/protocol/http-response.encoder.d.ts +12 -0
  153. package/dist/protocol/http-response.encoder.js +17 -3
  154. package/dist/protocol/operation-response.guard.js +1 -3
  155. package/dist/protocol/operation-set.decoder.d.ts +48 -0
  156. package/dist/protocol/operation-set.decoder.js +185 -0
  157. package/dist/protocol/operation-set.handler.d.ts +27 -0
  158. package/dist/protocol/operation-set.handler.js +179 -0
  159. package/dist/protocol/protocol-headers.d.ts +12 -3
  160. package/dist/protocol/protocol-headers.js +12 -5
  161. package/dist/protocol/protocol-surface.d.ts +16 -3
  162. package/dist/protocol/protocol-surface.js +41 -1
  163. package/dist/protocol/protocol.binder.d.ts +52 -1
  164. package/dist/protocol/protocol.binder.js +6 -1
  165. package/dist/protocol/protocol.handler.d.ts +45 -1
  166. package/dist/protocol/protocol.handler.js +164 -19
  167. package/dist/protocol/read-cache.responder.d.ts +26 -0
  168. package/dist/protocol/read-cache.responder.js +47 -0
  169. package/dist/protocol/read-query.codec.d.ts +34 -0
  170. package/dist/protocol/read-query.codec.js +125 -0
  171. package/dist/runtime/caller-data.copier.d.ts +18 -3
  172. package/dist/runtime/caller-data.copier.js +21 -8
  173. package/dist/runtime/caller-data.door.d.ts +13 -6
  174. package/dist/runtime/computed-read-runtime.d.ts +6 -1
  175. package/dist/runtime/computed-read-runtime.js +229 -48
  176. package/dist/runtime/computed-value.error.d.ts +3 -2
  177. package/dist/runtime/computed-value.error.js +3 -2
  178. package/dist/runtime/context-executor.runtime.d.ts +4 -3
  179. package/dist/runtime/context-executor.runtime.js +4 -2
  180. package/dist/runtime/core-class.brand.d.ts +10 -0
  181. package/dist/runtime/core-class.brand.js +21 -0
  182. package/dist/runtime/create-requirement.d.ts +31 -5
  183. package/dist/runtime/create-requirement.js +130 -24
  184. package/dist/runtime/decimal.d.ts +14 -0
  185. package/dist/runtime/decimal.js +21 -0
  186. package/dist/runtime/diagnostics-reporter.d.ts +49 -9
  187. package/dist/runtime/diagnostics-reporter.js +16 -9
  188. package/dist/runtime/error-boundary.d.ts +9 -2
  189. package/dist/runtime/error-boundary.js +12 -0
  190. package/dist/runtime/error-guidance.d.ts +12 -0
  191. package/dist/runtime/error-guidance.js +1 -0
  192. package/dist/runtime/error.catalog.d.ts +49 -0
  193. package/dist/runtime/error.catalog.js +49 -0
  194. package/dist/runtime/execution-options.d.ts +8 -0
  195. package/dist/runtime/field-check.evaluator.d.ts +0 -2
  196. package/dist/runtime/field-check.evaluator.js +1 -1
  197. package/dist/runtime/field-compute.d.ts +11 -10
  198. package/dist/runtime/field-stage.runtime.d.ts +3 -3
  199. package/dist/runtime/field-stage.runtime.js +9 -11
  200. package/dist/runtime/field-validator.runtime.d.ts +19 -1
  201. package/dist/runtime/field-validator.runtime.js +49 -9
  202. package/dist/runtime/framework-error.js +9 -0
  203. package/dist/runtime/framework-warning.emitter.d.ts +6 -0
  204. package/dist/runtime/framework-warning.emitter.js +8 -0
  205. package/dist/runtime/json-value.d.ts +10 -5
  206. package/dist/runtime/level-lifecycle.runtime.d.ts +4 -3
  207. package/dist/runtime/level-lifecycle.runtime.js +3 -5
  208. package/dist/runtime/mutation-planner.d.ts +1 -6
  209. package/dist/runtime/mutation-planner.js +4 -17
  210. package/dist/runtime/nested-write.walker.js +2 -1
  211. package/dist/runtime/operation-code.guidance.d.ts +6 -0
  212. package/dist/runtime/operation-code.guidance.js +167 -0
  213. package/dist/runtime/operation-request.d.ts +16 -9
  214. package/dist/runtime/operation-runtime.d.ts +35 -17
  215. package/dist/runtime/operation-runtime.js +220 -49
  216. package/dist/runtime/outcome-mapper.d.ts +2 -1
  217. package/dist/runtime/output-validator.d.ts +1 -1
  218. package/dist/runtime/output-validator.js +1 -3
  219. package/dist/runtime/owned-execution.registry.d.ts +34 -4
  220. package/dist/runtime/pipe-output.validator.d.ts +10 -0
  221. package/dist/runtime/pipe-output.validator.js +4 -2
  222. package/dist/runtime/pipeline.d.ts +52 -23
  223. package/dist/runtime/readonly-value.d.ts +20 -5
  224. package/dist/runtime/readonly-value.js +74 -26
  225. package/dist/runtime/record.guard.d.ts +14 -0
  226. package/dist/runtime/record.guard.js +10 -0
  227. package/dist/runtime/referential-action.d.ts +1 -1
  228. package/dist/runtime/request-envelope.validator.js +13 -10
  229. package/dist/runtime/scalar-runtime.d.ts +4 -21
  230. package/dist/runtime/scalar-runtime.js +91 -31
  231. package/dist/runtime/thenable.guard.d.ts +7 -0
  232. package/dist/runtime/thenable.guard.js +5 -0
  233. package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
  234. package/dist/runtime/unsent-value.normalizer.js +129 -0
  235. package/dist/transactions/operation-arguments-encoder.js +9 -10
  236. package/dist/transactions/operation-fingerprint.js +2 -2
  237. package/dist/transactions/sql-statement.d.ts +10 -2
  238. package/dist/transactions/sql-statement.validator.d.ts +2 -2
  239. package/dist/transactions/sql-statement.validator.js +40 -6
  240. package/dist/transactions/transaction-envelope.d.ts +5 -4
  241. package/dist/transactions/transaction-integrity-error.js +2 -0
  242. package/dist/transactions/transaction-plan-assembler.d.ts +12 -5
  243. package/dist/transactions/transaction-plan-assembler.js +49 -17
  244. package/dist/transactions/transaction-plan-validator.d.ts +23 -7
  245. package/dist/transactions/transaction-plan-validator.js +31 -7
  246. package/dist/transactions/transaction-reference-collector.js +8 -10
  247. package/dist/transactions/transaction-reference-resolver.d.ts +3 -2
  248. package/dist/transactions/transaction-reference-resolver.js +1 -3
  249. package/dist/transactions/transaction-reference-validator.d.ts +43 -3
  250. package/dist/transactions/transaction-reference-validator.js +83 -57
  251. package/dist/transactions/transaction-reference.d.ts +1 -1
  252. package/dist/transactions/transaction-reference.js +5 -0
  253. package/dist/transactions/transaction-request.d.ts +8 -8
  254. package/dist/transactions/transaction-runtime.d.ts +5 -2
  255. package/dist/transactions/transaction-runtime.js +108 -27
  256. package/dist/transactions/transaction-settlement.runtime.d.ts +4 -3
  257. package/dist/transactions/transaction-slot-path-error.js +2 -0
  258. package/dist/transactions/transaction-stage.runtime.d.ts +5 -3
  259. package/dist/transactions/transaction-stage.runtime.js +8 -7
  260. package/package.json +6 -5
  261. package/src/runtime/field-check.evaluator.ts +1 -1
@@ -1,22 +1,20 @@
1
1
  import { shapeOfField } from "../avz/json-shape.registry.js";
2
+ import { AVZ_FORMATS } from "../config/framework-field-definition.js";
3
+ import { FILTER_MODES, } from "../contracts/capability.js";
2
4
  import { lookupField, lookupOwn, lookupResource, } from "../contracts/contract-lookup.js";
3
5
  import { decodeBase64, WIRE_SCALAR_PATTERNS, } from "../contracts/wire-scalar-format.js";
4
6
  import { routeTransactionReferenceCandidate, } from "../transactions/transaction-reference.js";
5
- import { AvDecimal } from "./decimal.js";
7
+ import { AvDecimal, isAvDecimal } from "./decimal.js";
8
+ import { fieldCheckIssues } from "./field-check.evaluator.js";
9
+ import { isPlainRecord } from "./record.guard.js";
6
10
  const INT_MIN = -(2 ** 31);
7
11
  const INT_MAX = 2 ** 31 - 1;
8
12
  const BIGINT_MIN = -(2n ** 63n);
9
13
  const BIGINT_MAX = 2n ** 63n - 1n;
10
14
  const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
11
- function isRecord(value) {
12
- return value !== null && typeof value === "object" && !Array.isArray(value);
13
- }
14
- export function isPlainRecord(value) {
15
- if (!isRecord(value)) {
16
- return false;
17
- }
18
- const prototype = Object.getPrototypeOf(value);
19
- return prototype === Object.prototype || prototype === null;
15
+ const NAMED_FORMATS = new Set(AVZ_FORMATS);
16
+ function isNamedFormat(format) {
17
+ return NAMED_FORMATS.has(format);
20
18
  }
21
19
  function issue(code, path, message) {
22
20
  return { code, path, message };
@@ -24,6 +22,10 @@ function issue(code, path, message) {
24
22
  function typeIssue(path, expected) {
25
23
  return issue("V1001", path, `Value must be ${expected}.`);
26
24
  }
25
+ const UNSENT_READ_VALUE_MESSAGE = "Value must not be undefined: it would be left out, and the request would reach more rows.";
26
+ export function unsentReadValueIssue(path) {
27
+ return issue("V1001", path, UNSENT_READ_VALUE_MESSAGE);
28
+ }
27
29
  function formatIssue(path, expected) {
28
30
  return issue("V1003", path, `Value must use ${expected}.`);
29
31
  }
@@ -83,18 +85,14 @@ export function normalizeJsonValue(value, path, seen) {
83
85
  const normalized = [];
84
86
  task.emit(normalized);
85
87
  stack.push({ kind: "leave", container: current });
86
- const entries = [];
87
- current.forEach((entry, index) => {
88
- entries.push([index, entry]);
89
- });
90
- for (let cursor = entries.length - 1; cursor >= 0; cursor -= 1) {
91
- const entry = entries[cursor];
88
+ for (let index = current.length - 1; index >= 0; index -= 1) {
89
+ const entry = current[index];
92
90
  stack.push({
93
91
  kind: "visit",
94
- value: entry[1],
95
- link: { parent: task.link, segment: entry[0] },
92
+ value: entry === undefined ? null : entry,
93
+ link: { parent: task.link, segment: index },
96
94
  emit: (child) => {
97
- normalized.push(child);
95
+ normalized[index] = child;
98
96
  },
99
97
  });
100
98
  }
@@ -112,7 +110,7 @@ export function normalizeJsonValue(value, path, seen) {
112
110
  const normalized = {};
113
111
  task.emit(normalized);
114
112
  stack.push({ kind: "leave", container: current });
115
- const entries = Object.entries(current);
113
+ const entries = Object.entries(current).filter((entry) => entry[1] !== undefined);
116
114
  for (let cursor = entries.length - 1; cursor >= 0; cursor -= 1) {
117
115
  const entry = entries[cursor];
118
116
  stack.push({
@@ -231,10 +229,9 @@ function normalizeScalarAtom(contract, field, value, origin, path, allowNull) {
231
229
  break;
232
230
  case "decimal":
233
231
  if (origin === "application") {
234
- normalized =
235
- value instanceof AvDecimal
236
- ? { ok: true, value }
237
- : { ok: false, issues: [typeIssue(path, "an Aventara Decimal")] };
232
+ normalized = isAvDecimal(value)
233
+ ? { ok: true, value }
234
+ : { ok: false, issues: [typeIssue(path, "an Aventara Decimal")] };
238
235
  }
239
236
  else if (typeof value !== "string") {
240
237
  normalized = {
@@ -359,9 +356,21 @@ export function normalizeScalarFieldValue(contract, field, value, origin, path)
359
356
  });
360
357
  return issues.length > 0
361
358
  ? { ok: false, issues }
362
- : { ok: true, value: normalized };
359
+ : heldToFormat(field, { ok: true, value: normalized }, origin, path);
363
360
  }
364
- return normalizeScalarAtom(contract, field, value, origin === "runtime" ? "application" : origin, path, field.nullable);
361
+ return heldToFormat(field, normalizeScalarAtom(contract, field, value, origin === "runtime" ? "application" : origin, path, field.nullable), origin, path);
362
+ }
363
+ function heldToFormat(field, normalized, origin, path) {
364
+ const format = field.format;
365
+ if (origin !== "runtime" ||
366
+ !normalized.ok ||
367
+ format === undefined ||
368
+ format === "uuid" ||
369
+ !isNamedFormat(format)) {
370
+ return normalized;
371
+ }
372
+ const issues = fieldCheckIssues([{ check: "string_format", format }], normalized.value, "string", path, field.list);
373
+ return issues.length === 0 ? normalized : { ok: false, issues };
365
374
  }
366
375
  export function jsonShapeIssues(field, value, path, position = "value") {
367
376
  if (field.json === undefined || value === null || value === undefined) {
@@ -427,6 +436,11 @@ export function copyScalarFieldValue(field, value) {
427
436
  function normalizeListElement(contract, field, value, origin, path) {
428
437
  return normalizeScalarAtom(contract, field, value, origin, path, false);
429
438
  }
439
+ function normalizeFilterEntry(contract, field, value, origin, path) {
440
+ return value === undefined
441
+ ? { ok: false, issues: [unsentReadValueIssue(path)] }
442
+ : normalizeListElement(contract, field, value, origin, path);
443
+ }
430
444
  function mergeResult(result, issues) {
431
445
  if (result.ok) {
432
446
  return result.value;
@@ -434,7 +448,7 @@ function mergeResult(result, issues) {
434
448
  issues.push(...result.issues);
435
449
  return undefined;
436
450
  }
437
- export const REFERENCE_OPERANDS = Object.freeze({
451
+ const REFERENCE_OPERANDS = Object.freeze({
438
452
  equals: "value",
439
453
  not: "value",
440
454
  lt: "nonNullValue",
@@ -463,10 +477,40 @@ const NULL_OPERAND_OPERATORS = new Set([
463
477
  "arrayStartsWith",
464
478
  "arrayEndsWith",
465
479
  ]);
480
+ const KEYWORD_OPERANDS = Object.freeze({
481
+ mode: (operand, path, issues) => {
482
+ if (!FILTER_MODES.includes(operand)) {
483
+ issues.push(typeIssue(path, '"default", "sensitive" or "insensitive"'));
484
+ }
485
+ },
486
+ isEmpty: (operand, path, issues) => {
487
+ if (typeof operand !== "boolean") {
488
+ issues.push(typeIssue(path, "a boolean"));
489
+ }
490
+ },
491
+ path: (operand, path, issues) => {
492
+ if (!Array.isArray(operand)) {
493
+ issues.push(typeIssue(path, "an array of strings"));
494
+ return;
495
+ }
496
+ for (let index = 0; index < operand.length; index += 1) {
497
+ if (operand[index] === undefined) {
498
+ issues.push(unsentReadValueIssue([...path, index]));
499
+ }
500
+ else if (typeof operand[index] !== "string") {
501
+ issues.push(typeIssue([...path, index], "a string"));
502
+ }
503
+ }
504
+ },
505
+ });
466
506
  function normalizeScalarFilter(contract, field, value, origin, path, issues, references = false) {
467
507
  if (isKeptReference(references, value)) {
468
508
  return value;
469
509
  }
510
+ if (value === undefined) {
511
+ issues.push(unsentReadValueIssue(path));
512
+ return value;
513
+ }
470
514
  if (!isPlainRecord(value)) {
471
515
  return mergeResult(normalizeScalarFieldValue(contract, field, value, origin, path), issues);
472
516
  }
@@ -477,11 +521,17 @@ function normalizeScalarFilter(contract, field, value, origin, path, issues, ref
477
521
  const normalized = cloneRecord(value);
478
522
  for (const [operator, operand] of Object.entries(value)) {
479
523
  const operandPath = [...path, operator];
524
+ if (operand === undefined) {
525
+ issues.push(unsentReadValueIssue(operandPath));
526
+ continue;
527
+ }
480
528
  if (operand === null && !acceptsNullOperand(operator)) {
481
529
  issues.push(typeIssue(operandPath, "non-null"));
482
530
  continue;
483
531
  }
484
- if (operator === "mode" || operator === "isEmpty" || operator === "path") {
532
+ const keyword = lookupOwn(KEYWORD_OPERANDS, operator);
533
+ if (keyword !== undefined) {
534
+ keyword(operand, operandPath, issues);
485
535
  continue;
486
536
  }
487
537
  if (referenceOperandShape(operator) !== undefined &&
@@ -497,14 +547,14 @@ function normalizeScalarFilter(contract, field, value, origin, path, issues, ref
497
547
  issues.push(typeIssue(operandPath, "an array"));
498
548
  continue;
499
549
  }
500
- normalized[operator] = operand.map((entry, index) => mergeResult(normalizeListElement(contract, field, entry, origin, [
550
+ normalized[operator] = operand.map((entry, index) => mergeResult(normalizeFilterEntry(contract, field, entry, origin, [
501
551
  ...operandPath,
502
552
  index,
503
553
  ]), issues));
504
554
  continue;
505
555
  }
506
556
  if (operator === "has") {
507
- normalized[operator] = mergeResult(normalizeListElement(contract, field, operand, origin, operandPath), issues);
557
+ normalized[operator] = mergeResult(normalizeFilterEntry(contract, field, operand, origin, operandPath), issues);
508
558
  continue;
509
559
  }
510
560
  if (operator === "hasEvery" || operator === "hasSome") {
@@ -512,7 +562,7 @@ function normalizeScalarFilter(contract, field, value, origin, path, issues, ref
512
562
  issues.push(typeIssue(operandPath, "an array"));
513
563
  continue;
514
564
  }
515
- normalized[operator] = operand.map((entry, index) => mergeResult(normalizeListElement(contract, field, entry, origin, [
565
+ normalized[operator] = operand.map((entry, index) => mergeResult(normalizeFilterEntry(contract, field, entry, origin, [
516
566
  ...operandPath,
517
567
  index,
518
568
  ]), issues));
@@ -521,6 +571,12 @@ function normalizeScalarFilter(contract, field, value, origin, path, issues, ref
521
571
  if ("scalar" in field.type &&
522
572
  field.type.scalar === "json" &&
523
573
  (operator.startsWith("string") || operator.startsWith("array"))) {
574
+ if (operator.startsWith("string")) {
575
+ if (typeof operand !== "string") {
576
+ issues.push(typeIssue(operandPath, "a string"));
577
+ }
578
+ continue;
579
+ }
524
580
  const jsonResult = normalizeJsonValue(operand, operandPath, new Set());
525
581
  normalized[operator] = mergeResult(jsonResult, issues);
526
582
  continue;
@@ -585,6 +641,10 @@ function normalizeUniqueSelector(contract, resourceName, selector, origin, path,
585
641
  const normalized = cloneRecord(selector);
586
642
  for (const [fieldName, value] of Object.entries(selector)) {
587
643
  const field = lookupField(resource, fieldName);
644
+ if (field?.kind === "scalar" && value === undefined) {
645
+ issues.push(unsentReadValueIssue([...path, fieldName]));
646
+ continue;
647
+ }
588
648
  if (field?.kind === "scalar" && !isKeptReference(references, value)) {
589
649
  normalized[fieldName] = mergeResult(normalizeScalarFieldValue(contract, field, value, origin, [
590
650
  ...path,
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Whether `value` is what `await` waits for rather than answers at once: an
3
+ * object or function whose `then` is a function. Reads `then` once; a `then`
4
+ * getter that throws throws here, so a caller reading an untrusted value guards
5
+ * the call.
6
+ */
7
+ export declare function isThenable(value: unknown): value is PromiseLike<unknown>;
@@ -0,0 +1,5 @@
1
+ export function isThenable(value) {
2
+ return (value !== null &&
3
+ (typeof value === "object" || typeof value === "function") &&
4
+ typeof value.then === "function");
5
+ }
@@ -0,0 +1,15 @@
1
+ import type { AvContract } from "../contracts/contract.js";
2
+ import type { AvOperationFamily } from "../operations/operation-identity.js";
3
+ /**
4
+ * One operation's arguments with every write record's unsent fields removed — a
5
+ * field whose value is `undefined`, at any depth of nested write data the
6
+ * Contract's `maxNestingDepth` admits — and
7
+ * nothing else changed (see the module note): `where`, selectors and every other
8
+ * member are left as they are. The same object when nothing was unsent; otherwise
9
+ * a copy of each container on the way, never a write into `args`. Total over
10
+ * malformed input.
11
+ */
12
+ export declare function withoutUnsentWriteValues(contract: AvContract, request: {
13
+ readonly resource: string;
14
+ readonly family: AvOperationFamily;
15
+ }, args: unknown): unknown;
@@ -0,0 +1,129 @@
1
+ import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
2
+ import { WRITE_KEYS } from "./field-stage.runtime.js";
3
+ import { isRelationMutationDirective, RELATION_MUTATION_RECORD_SITES, } from "./mutation-planner.js";
4
+ import { isPlainRecord } from "./record.guard.js";
5
+ const REMOVE = Symbol("remove");
6
+ const DEPTH_CEILING = 256;
7
+ function rebuilt(record, changes) {
8
+ const copy = Object.getPrototypeOf(record) === null ? Object.create(null) : {};
9
+ for (const key of Object.keys(record)) {
10
+ const value = changes.has(key) ? changes.get(key) : record[key];
11
+ if (value === REMOVE) {
12
+ continue;
13
+ }
14
+ Object.defineProperty(copy, key, {
15
+ value,
16
+ writable: true,
17
+ enumerable: true,
18
+ configurable: true,
19
+ });
20
+ }
21
+ return copy;
22
+ }
23
+ function eachEntry(value, strip) {
24
+ if (!Array.isArray(value)) {
25
+ return strip(value);
26
+ }
27
+ let copy;
28
+ for (let index = 0; index < value.length; index += 1) {
29
+ if (!(index in value)) {
30
+ continue;
31
+ }
32
+ const entry = value[index];
33
+ const stripped = strip(entry);
34
+ if (stripped !== entry) {
35
+ copy ??= value.slice();
36
+ copy[index] = stripped;
37
+ }
38
+ }
39
+ return copy ?? value;
40
+ }
41
+ function stripRecord(walk, resourceName, record, depth) {
42
+ if (depth > walk.depth || !isPlainRecord(record)) {
43
+ return record;
44
+ }
45
+ const resource = lookupResource(walk.contract, resourceName);
46
+ let changes;
47
+ for (const key of Object.keys(record)) {
48
+ const value = record[key];
49
+ if (value === undefined) {
50
+ changes ??= new Map();
51
+ changes.set(key, REMOVE);
52
+ continue;
53
+ }
54
+ const field = lookupField(resource, key);
55
+ if (field?.kind !== "relation") {
56
+ continue;
57
+ }
58
+ const stripped = stripRelationWrite(walk, field.target, value, depth + 1);
59
+ if (stripped !== value) {
60
+ changes ??= new Map();
61
+ changes.set(key, stripped);
62
+ }
63
+ }
64
+ return changes === undefined ? record : rebuilt(record, changes);
65
+ }
66
+ function stripRelationWrite(walk, target, value, depth) {
67
+ if (!isPlainRecord(value)) {
68
+ return value;
69
+ }
70
+ let changes;
71
+ for (const directive of Object.keys(value)) {
72
+ if (!isRelationMutationDirective(directive)) {
73
+ continue;
74
+ }
75
+ const sites = RELATION_MUTATION_RECORD_SITES[directive];
76
+ if (sites.length === 0) {
77
+ continue;
78
+ }
79
+ const operand = value[directive];
80
+ const next = eachEntry(operand, (entry) => {
81
+ let stripped = entry;
82
+ for (const site of sites) {
83
+ if (site.key === undefined) {
84
+ stripped = stripRecord(walk, target, stripped, depth);
85
+ continue;
86
+ }
87
+ if (!isPlainRecord(stripped) || !Object.hasOwn(stripped, site.key)) {
88
+ continue;
89
+ }
90
+ const inner = stripped[site.key];
91
+ const record = stripRecord(walk, target, inner, depth);
92
+ if (record !== inner) {
93
+ stripped = rebuilt(stripped, new Map([[site.key, record]]));
94
+ }
95
+ }
96
+ return stripped;
97
+ });
98
+ if (next !== operand) {
99
+ changes ??= new Map();
100
+ changes.set(directive, next);
101
+ }
102
+ }
103
+ return changes === undefined ? value : rebuilt(value, changes);
104
+ }
105
+ export function withoutUnsentWriteValues(contract, request, args) {
106
+ const keys = Object.hasOwn(WRITE_KEYS, request.family)
107
+ ? WRITE_KEYS[request.family]
108
+ : undefined;
109
+ if (keys === undefined || !isPlainRecord(args)) {
110
+ return args;
111
+ }
112
+ const walk = {
113
+ contract,
114
+ depth: Math.min(contract.limits.maxNestingDepth, DEPTH_CEILING),
115
+ };
116
+ let changes;
117
+ for (const key of keys) {
118
+ if (!Object.hasOwn(args, key)) {
119
+ continue;
120
+ }
121
+ const value = args[key];
122
+ const next = eachEntry(value, (entry) => stripRecord(walk, request.resource, entry, 0));
123
+ if (next !== value) {
124
+ changes ??= new Map();
125
+ changes.set(key, next);
126
+ }
127
+ }
128
+ return changes === undefined ? args : rebuilt(args, changes);
129
+ }
@@ -1,15 +1,9 @@
1
1
  import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
2
2
  import { encodeBase64 } from "../contracts/wire-scalar-format.js";
3
- import { AvDecimal } from "../runtime/decimal.js";
3
+ import { isAvDecimal } from "../runtime/decimal.js";
4
4
  import { isRelationMutationDirective, RELATION_MUTATION_RECORD_SITES, } from "../runtime/mutation-planner.js";
5
+ import { isPlainRecord } from "../runtime/record.guard.js";
5
6
  import { isTransactionReferenceCandidate } from "./transaction-reference.js";
6
- function isPlainRecord(value) {
7
- if (value === null || typeof value !== "object" || Array.isArray(value)) {
8
- return false;
9
- }
10
- const prototype = Object.getPrototypeOf(value);
11
- return prototype === Object.prototype || prototype === null;
12
- }
13
7
  function cloneRecord(value) {
14
8
  return { ...value };
15
9
  }
@@ -27,9 +21,11 @@ function encodeScalarAtom(field, value) {
27
21
  case "bigint":
28
22
  return typeof value === "bigint" ? value.toString(10) : value;
29
23
  case "decimal":
30
- return value instanceof AvDecimal ? value.toString() : value;
24
+ return isAvDecimal(value) ? value.toString() : value;
31
25
  case "datetime":
32
- return value instanceof Date ? value.toISOString() : value;
26
+ return value instanceof Date && !Number.isNaN(value.getTime())
27
+ ? value.toISOString()
28
+ : value;
33
29
  case "bytes":
34
30
  return value instanceof Uint8Array ? encodeBase64(value) : value;
35
31
  default:
@@ -282,6 +278,9 @@ function isUniqueOperation(operation) {
282
278
  operation.family === "upsert"));
283
279
  }
284
280
  export function encodeOperationArgumentsForWire(contract, operation, args) {
281
+ if (!isPlainRecord(args)) {
282
+ return args;
283
+ }
285
284
  const encoded = cloneRecord(args);
286
285
  if (hasOwnWireProperty(args, "where")) {
287
286
  encoded.where = isUniqueOperation(operation)
@@ -1,4 +1,4 @@
1
- import { canonicalizeJson } from "../contracts/contract-canonicalizer.js";
1
+ import { canonicalizeWireJson } from "../contracts/contract-canonicalizer.js";
2
2
  const OPERATION_FINGERPRINT_PATTERN = /^fp1:[A-Za-z0-9_-]{22}$/;
3
3
  function encodeBase64Url(bytes) {
4
4
  let binary = "";
@@ -14,7 +14,7 @@ export function isOperationFingerprint(value) {
14
14
  return typeof value === "string" && OPERATION_FINGERPRINT_PATTERN.test(value);
15
15
  }
16
16
  export async function computeOperationFingerprint(node) {
17
- const canonical = canonicalizeJson({
17
+ const canonical = canonicalizeWireJson({
18
18
  resource: node.resource,
19
19
  family: node.family,
20
20
  variant: node.variant,
@@ -10,7 +10,7 @@ import type { AvTransactionReference } from "./transaction-reference.js";
10
10
  * `${value}::jsonb`), or a `$ref` to an earlier step's field, resolved when the
11
11
  * earlier steps have run and then bound like any other value.
12
12
  */
13
- export type SqlStatementValue = AvAdapterSqlValue | AvTransactionReference;
13
+ export type AvSqlStatementValue = AvAdapterSqlValue | AvTransactionReference;
14
14
  /**
15
15
  * `framework.appTx.$sql`: a developer SQL step, written only as a tagged template —
16
16
  * ``framework.appTx.$sql`select pgmq.send('jobs', jsonb_build_object('id', ${ref}))` ``.
@@ -23,7 +23,7 @@ export type SqlStatementValue = AvAdapterSqlValue | AvTransactionReference;
23
23
  * SQL step's rows. No guard, pipe, hook, interceptor or filter runs around it: it
24
24
  * has no Resource or operation for one to wrap.
25
25
  */
26
- export type SqlStatementBuilder = <Row = unknown>(strings: TemplateStringsArray, ...values: readonly SqlStatementValue[]) => AvOperation<Row[], "application">;
26
+ export type AvSqlStatementBuilder = <Row = unknown>(strings: TemplateStringsArray, ...values: readonly AvSqlStatementValue[]) => AvOperation<Row[], "application">;
27
27
  /** One value of a planned SQL step, as the typed runner bound it. */
28
28
  export type PlannedSqlValue = {
29
29
  readonly kind: "value";
@@ -35,6 +35,14 @@ export type PlannedSqlValue = {
35
35
  readonly operation: number;
36
36
  readonly field: string;
37
37
  }
38
+ /**
39
+ * A whole value that is a `$ref` control object the caller wrote, mirrored at
40
+ * the builder: validated as an operation step's reference is.
41
+ */
42
+ | {
43
+ readonly kind: "candidate";
44
+ readonly candidate: unknown;
45
+ }
38
46
  /** A `$ref` placeholder found inside a value, at `path` within it: refused. */
39
47
  | {
40
48
  readonly kind: "misplaced-reference";
@@ -5,7 +5,7 @@ import type { AvOperationFailureResponse } from "../runtime/operation-response.j
5
5
  import type { PlannedSqlStatement, ValidatedSqlStatement } from "./sql-statement.js";
6
6
  import type { ValidatedTransactionStep } from "./transaction-plan-validator.js";
7
7
  type Path = readonly (string | number)[];
8
- export type SqlStatementValidation = {
8
+ type SqlStatementValidation = {
9
9
  readonly ok: true;
10
10
  readonly statement: ValidatedSqlStatement;
11
11
  } | {
@@ -13,7 +13,7 @@ export type SqlStatementValidation = {
13
13
  readonly response: AvOperationFailureResponse;
14
14
  };
15
15
  /** What validating a SQL step needs from the plan around it. */
16
- export type SqlStatementValidationContext = {
16
+ type SqlStatementValidationContext = {
17
17
  /** The step's position in the plan. */
18
18
  readonly index: number;
19
19
  /** The steps validated before it, by position. */
@@ -1,11 +1,13 @@
1
1
  import { validationIssue } from "../operations/validation-code.js";
2
+ import { AvCallerDataError, locateCallerDataError, } from "../runtime/caller-data.copier.js";
2
3
  import { refuseCallerData } from "../runtime/caller-data.door.js";
3
- import { AvDecimal } from "../runtime/decimal.js";
4
+ import { isAvDecimal } from "../runtime/decimal.js";
4
5
  import { planStepPath } from "../runtime/error-boundary.js";
5
6
  import { operationFailure } from "../runtime/operation-response.js";
6
7
  import { mapValidationOutcome } from "../runtime/outcome-mapper.js";
7
- import { isPlainRecord, normalizeJsonValue, } from "../runtime/scalar-runtime.js";
8
- import { invalidSourceIndexIssue, referenceSourceAt, referenceSourceField, } from "./transaction-reference-validator.js";
8
+ import { isPlainRecord } from "../runtime/record.guard.js";
9
+ import { normalizeJsonValue } from "../runtime/scalar-runtime.js";
10
+ import { inspectReferenceCandidate, invalidSourceIndexIssue, referenceSourceAt, referenceSourceField, } from "./transaction-reference-validator.js";
9
11
  import { transactionOperationFailure } from "./transaction-response.js";
10
12
  function refused(issue, index) {
11
13
  return {
@@ -18,7 +20,7 @@ export function normalizeSqlValue(value, path) {
18
20
  typeof value === "string" ||
19
21
  typeof value === "boolean" ||
20
22
  typeof value === "bigint" ||
21
- value instanceof AvDecimal ||
23
+ isAvDecimal(value) ||
22
24
  value instanceof Uint8Array) {
23
25
  return { ok: true, value };
24
26
  }
@@ -56,7 +58,7 @@ export function normalizeSqlValue(value, path) {
56
58
  };
57
59
  }
58
60
  export function validateSqlStatement(statement, context) {
59
- const { index, earlier } = context;
61
+ const { index } = context;
60
62
  if (!context.available) {
61
63
  const message = "SQL statements are not available on this Adapter.";
62
64
  return {
@@ -73,6 +75,22 @@ export function validateSqlStatement(statement, context) {
73
75
  if (statement.refused !== undefined) {
74
76
  return refused(refuseCallerData(statement.refused, [...planStepPath(index), "values"], { origin: "application", operation: index }, context.misuse), index);
75
77
  }
78
+ try {
79
+ return validateSqlValues(statement, statement.strings, context);
80
+ }
81
+ catch (error) {
82
+ if (!(error instanceof AvCallerDataError)) {
83
+ throw error;
84
+ }
85
+ return refused(refuseCallerData(locateCallerDataError(error, statement.values.map((planned) => planned.kind === "value"
86
+ ? planned.value
87
+ : planned.kind === "candidate"
88
+ ? planned.candidate
89
+ : undefined)), [...planStepPath(index), "values"], { origin: "application", operation: index }, context.misuse), index);
90
+ }
91
+ }
92
+ function validateSqlValues(statement, strings, context) {
93
+ const { index, earlier } = context;
76
94
  const values = [];
77
95
  const issues = [];
78
96
  for (const [position, planned] of statement.values.entries()) {
@@ -80,6 +98,22 @@ export function validateSqlStatement(statement, context) {
80
98
  switch (planned.kind) {
81
99
  case "misplaced-reference":
82
100
  return refused(validationIssue("V1010", [...path, ...planned.path, "$ref"], "A transaction reference in a SQL step must be a whole value."), index);
101
+ case "candidate": {
102
+ const inspection = inspectReferenceCandidate(planned.candidate, path, earlier, index);
103
+ if (!inspection.ok) {
104
+ return refused(inspection.issue, index);
105
+ }
106
+ if (inspection.field.kind !== "scalar" || inspection.field.list) {
107
+ return refused(validationIssue("V1011", inspection.pathPath, "Transaction reference source is not a single scalar field."), index);
108
+ }
109
+ values.push({
110
+ kind: "reference",
111
+ operation: inspection.source.index,
112
+ field: inspection.segment,
113
+ source: inspection.field,
114
+ });
115
+ break;
116
+ }
83
117
  case "reference": {
84
118
  const source = referenceSourceAt(earlier, planned.operation, index);
85
119
  if (source === undefined) {
@@ -127,7 +161,7 @@ export function validateSqlStatement(statement, context) {
127
161
  statement: {
128
162
  kind: "sql",
129
163
  index,
130
- strings: statement.strings,
164
+ strings,
131
165
  values,
132
166
  },
133
167
  };
@@ -1,18 +1,18 @@
1
1
  import type { AvValidationIssue } from "../operations/validation-code.js";
2
- export type TransactionEnvelopeSchema = {
2
+ type TransactionEnvelopeSchema = {
3
3
  readonly required: readonly string[];
4
4
  readonly optional?: readonly string[];
5
5
  readonly invalidContainerPath: readonly (string | number)[];
6
6
  readonly invalidContainerMessage: string;
7
7
  };
8
- export type TransactionEnvelopeInspection = {
8
+ type TransactionEnvelopeInspection = {
9
9
  readonly ok: true;
10
10
  readonly values: ReadonlyMap<string, unknown>;
11
11
  } | {
12
12
  readonly ok: false;
13
13
  readonly issue: AvValidationIssue;
14
14
  };
15
- export type TransactionOperationsInspection = {
15
+ type TransactionOperationsInspection = {
16
16
  readonly ok: true;
17
17
  readonly value: object;
18
18
  readonly length: number;
@@ -20,7 +20,7 @@ export type TransactionOperationsInspection = {
20
20
  readonly ok: false;
21
21
  readonly issue: AvValidationIssue;
22
22
  };
23
- export type TransactionOperationEntryInspection = {
23
+ type TransactionOperationEntryInspection = {
24
24
  readonly ok: true;
25
25
  readonly value: unknown;
26
26
  } | {
@@ -39,3 +39,4 @@ export declare function inspectTransactionOperationEntry(operations: object, ind
39
39
  * Proxies are unsupported; reflection failures are contained as envelope issues.
40
40
  */
41
41
  export declare function inspectTransactionEnvelope(value: unknown, schema: TransactionEnvelopeSchema): TransactionEnvelopeInspection;
42
+ export {};
@@ -1,3 +1,4 @@
1
+ import { brandCoreClass } from "../runtime/core-class.brand.js";
1
2
  const TRANSACTION_INTEGRITY_MESSAGES = {
2
3
  "transaction-unavailable": "Adapter transaction function is unavailable.",
3
4
  "resolved-after-abort": "Adapter transaction resolved after the framework requested rollback.",
@@ -15,3 +16,4 @@ export class AvTransactionIntegrityError extends Error {
15
16
  this.violation = violation;
16
17
  }
17
18
  }
19
+ brandCoreClass(AvTransactionIntegrityError, "AvTransactionIntegrityError");