@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.
Files changed (228) hide show
  1. package/CHANGELOG.md +943 -16
  2. package/ERRORS.md +142 -0
  3. package/README.md +274 -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 +227 -24
  19. package/dist/compiler/managed-elsewhere.projector.d.ts +52 -0
  20. package/dist/compiler/managed-elsewhere.projector.js +179 -0
  21. package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
  22. package/dist/compiler/managed-elsewhere.validator.js +74 -0
  23. package/dist/config/computed-fields.d.ts +62 -0
  24. package/dist/config/computed-fields.js +73 -0
  25. package/dist/config/config-diagnostic.guidance.d.ts +6 -0
  26. package/dist/config/config-diagnostic.guidance.js +32 -0
  27. package/dist/config/config.resolver.d.ts +24 -0
  28. package/dist/config/config.resolver.js +65 -0
  29. package/dist/config/config.validator.js +222 -8
  30. package/dist/config/define-resource.d.ts +1 -5
  31. package/dist/config/entrypoint.normalizer.d.ts +3 -2
  32. package/dist/config/exact-framework-config.d.ts +67 -22
  33. package/dist/config/field-compute.resolver.d.ts +2 -0
  34. package/dist/config/field-compute.resolver.js +8 -0
  35. package/dist/config/framework-config.d.ts +53 -15
  36. package/dist/config/framework-resources-config.d.ts +25 -14
  37. package/dist/config/pipeline-config.d.ts +4 -4
  38. package/dist/config/pipeline-tree.resolver.d.ts +2 -2
  39. package/dist/contracts/access-route.rules.d.ts +10 -0
  40. package/dist/contracts/access-route.rules.js +45 -0
  41. package/dist/contracts/capability.d.ts +26 -1
  42. package/dist/contracts/capability.js +20 -0
  43. package/dist/contracts/client-contract-structure.validator.d.ts +301 -89
  44. package/dist/contracts/client-contract-structure.validator.js +37 -2
  45. package/dist/contracts/contract-access.d.ts +29 -0
  46. package/dist/contracts/contract-access.js +1 -0
  47. package/dist/contracts/contract-canonicalizer.d.ts +9 -1
  48. package/dist/contracts/contract-canonicalizer.js +30 -4
  49. package/dist/contracts/contract-hash.d.ts +0 -1
  50. package/dist/contracts/contract-hash.js +1 -1
  51. package/dist/contracts/contract.d.ts +27 -1
  52. package/dist/contracts/field.d.ts +58 -1
  53. package/dist/contracts/json-schema.projector.d.ts +11 -0
  54. package/dist/contracts/json-schema.projector.js +78 -0
  55. package/dist/contracts/scalar-value-type.d.ts +3 -1
  56. package/dist/framework/access-facade.d.ts +116 -0
  57. package/dist/framework/access-facade.js +120 -0
  58. package/dist/framework/contract-view.d.ts +120 -16
  59. package/dist/framework/framework-construction.error.d.ts +14 -4
  60. package/dist/framework/framework-construction.error.js +18 -2
  61. package/dist/framework/framework.d.ts +26 -5
  62. package/dist/framework/framework.factory.d.ts +1 -1
  63. package/dist/framework/framework.factory.js +115 -23
  64. package/dist/framework/operation-facade.d.ts +80 -13
  65. package/dist/framework/operation-facade.js +2 -1
  66. package/dist/index.d.ts +17 -5
  67. package/dist/index.js +1 -0
  68. package/dist/internal.d.ts +7 -2
  69. package/dist/internal.js +6 -0
  70. package/dist/operations/database-refusal.d.ts +51 -0
  71. package/dist/operations/database-refusal.js +45 -0
  72. package/dist/operations/operation-arguments.d.ts +148 -60
  73. package/dist/operations/operation-call.d.ts +9 -5
  74. package/dist/operations/operation-result.d.ts +6 -4
  75. package/dist/operations/operation-validator-core.js +159 -36
  76. package/dist/operations/operation-validator.d.ts +1 -1
  77. package/dist/operations/structural-limits.walker.d.ts +1 -1
  78. package/dist/operations/validation-code.guidance.d.ts +6 -0
  79. package/dist/operations/validation-code.guidance.js +90 -0
  80. package/dist/operations/write-scope.resolver.d.ts +4 -0
  81. package/dist/operations/write-scope.resolver.js +2 -0
  82. package/dist/policy/access-provider.interface.d.ts +91 -0
  83. package/dist/policy/access-provider.interface.js +1 -0
  84. package/dist/policy/access-provider.registry.d.ts +17 -0
  85. package/dist/policy/access-provider.registry.js +15 -0
  86. package/dist/policy/access-question.d.ts +20 -0
  87. package/dist/policy/access-question.js +1 -0
  88. package/dist/policy/access-question.registry.d.ts +5 -0
  89. package/dist/policy/access-question.registry.js +19 -0
  90. package/dist/policy/access-question.runtime.d.ts +36 -0
  91. package/dist/policy/access-question.runtime.js +297 -0
  92. package/dist/policy/access-verb.table.d.ts +56 -0
  93. package/dist/policy/access-verb.table.js +21 -0
  94. package/dist/policy/access-verbs.d.ts +46 -0
  95. package/dist/policy/access-verbs.js +1 -0
  96. package/dist/policy/policy-admission.d.ts +20 -0
  97. package/dist/policy/policy-admission.js +409 -0
  98. package/dist/policy/policy-after-update.runtime.d.ts +79 -0
  99. package/dist/policy/policy-after-update.runtime.js +208 -0
  100. package/dist/policy/policy-condition.d.ts +15 -0
  101. package/dist/policy/policy-condition.js +36 -0
  102. package/dist/policy/policy-engine.d.ts +205 -0
  103. package/dist/policy/policy-engine.js +1 -0
  104. package/dist/policy/policy-named-rows.d.ts +18 -0
  105. package/dist/policy/policy-named-rows.js +51 -0
  106. package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
  107. package/dist/policy/policy-nested-write.runtime.js +545 -0
  108. package/dist/policy/policy-read.runtime.d.ts +81 -0
  109. package/dist/policy/policy-read.runtime.js +503 -0
  110. package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
  111. package/dist/policy/policy-reference-write.runtime.js +345 -0
  112. package/dist/policy/policy-request.d.ts +41 -0
  113. package/dist/policy/policy-request.js +63 -0
  114. package/dist/policy/policy-session.d.ts +106 -0
  115. package/dist/policy/policy-session.js +295 -0
  116. package/dist/policy/policy-startup.validator.d.ts +10 -0
  117. package/dist/policy/policy-startup.validator.js +112 -0
  118. package/dist/policy/policy-write.runtime.d.ts +39 -0
  119. package/dist/policy/policy-write.runtime.js +532 -0
  120. package/dist/prebuilt/core-version.generated.d.ts +2 -0
  121. package/dist/prebuilt/core-version.generated.js +1 -0
  122. package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
  123. package/dist/prebuilt/prebuilt-changes.js +65 -0
  124. package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
  125. package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
  126. package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
  127. package/dist/prebuilt/prebuilt-contracts.js +1 -0
  128. package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
  129. package/dist/prebuilt/prebuilt-contracts.loader.js +77 -0
  130. package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
  131. package/dist/prebuilt/prebuilt-inputs.fingerprint.js +229 -0
  132. package/dist/protocol/absent-route.responder.d.ts +9 -27
  133. package/dist/protocol/absent-route.responder.js +36 -3
  134. package/dist/protocol/contract-document.responder.d.ts +2 -1
  135. package/dist/protocol/http-request.decoder.d.ts +19 -3
  136. package/dist/protocol/http-request.decoder.js +24 -1
  137. package/dist/protocol/http-request.reader.d.ts +6 -3
  138. package/dist/protocol/http-request.reader.js +1 -0
  139. package/dist/protocol/http-response.encoder.js +2 -2
  140. package/dist/protocol/protocol-headers.d.ts +3 -3
  141. package/dist/protocol/protocol-surface.d.ts +6 -1
  142. package/dist/protocol/protocol-surface.js +7 -0
  143. package/dist/protocol/protocol.binder.d.ts +16 -1
  144. package/dist/protocol/protocol.binder.js +4 -1
  145. package/dist/protocol/protocol.handler.d.ts +12 -1
  146. package/dist/protocol/protocol.handler.js +86 -17
  147. package/dist/runtime/caller-data.copier.d.ts +18 -3
  148. package/dist/runtime/caller-data.copier.js +21 -8
  149. package/dist/runtime/caller-data.door.d.ts +13 -6
  150. package/dist/runtime/computed-read-runtime.d.ts +6 -1
  151. package/dist/runtime/computed-read-runtime.js +232 -45
  152. package/dist/runtime/computed-value.error.d.ts +3 -2
  153. package/dist/runtime/computed-value.error.js +3 -2
  154. package/dist/runtime/context-executor.runtime.d.ts +4 -3
  155. package/dist/runtime/context-executor.runtime.js +4 -2
  156. package/dist/runtime/core-class.brand.d.ts +10 -0
  157. package/dist/runtime/core-class.brand.js +21 -0
  158. package/dist/runtime/create-requirement.d.ts +31 -5
  159. package/dist/runtime/create-requirement.js +129 -21
  160. package/dist/runtime/decimal.d.ts +14 -0
  161. package/dist/runtime/decimal.js +21 -0
  162. package/dist/runtime/diagnostics-reporter.d.ts +44 -9
  163. package/dist/runtime/diagnostics-reporter.js +13 -1
  164. package/dist/runtime/error-boundary.d.ts +9 -2
  165. package/dist/runtime/error-boundary.js +12 -0
  166. package/dist/runtime/error-guidance.d.ts +12 -0
  167. package/dist/runtime/error-guidance.js +1 -0
  168. package/dist/runtime/error.catalog.d.ts +49 -0
  169. package/dist/runtime/error.catalog.js +49 -0
  170. package/dist/runtime/execution-options.d.ts +8 -0
  171. package/dist/runtime/field-check.evaluator.d.ts +0 -2
  172. package/dist/runtime/field-check.evaluator.js +1 -1
  173. package/dist/runtime/field-compute.d.ts +11 -10
  174. package/dist/runtime/field-stage.runtime.d.ts +3 -1
  175. package/dist/runtime/field-stage.runtime.js +8 -4
  176. package/dist/runtime/field-validator.runtime.d.ts +19 -1
  177. package/dist/runtime/field-validator.runtime.js +47 -8
  178. package/dist/runtime/framework-error.js +9 -0
  179. package/dist/runtime/framework-warning.emitter.d.ts +6 -0
  180. package/dist/runtime/framework-warning.emitter.js +8 -0
  181. package/dist/runtime/json-value.d.ts +10 -5
  182. package/dist/runtime/level-lifecycle.runtime.d.ts +4 -3
  183. package/dist/runtime/level-lifecycle.runtime.js +3 -5
  184. package/dist/runtime/mutation-planner.d.ts +1 -6
  185. package/dist/runtime/mutation-planner.js +3 -14
  186. package/dist/runtime/operation-code.guidance.d.ts +6 -0
  187. package/dist/runtime/operation-code.guidance.js +167 -0
  188. package/dist/runtime/operation-request.d.ts +16 -9
  189. package/dist/runtime/operation-runtime.d.ts +35 -17
  190. package/dist/runtime/operation-runtime.js +220 -49
  191. package/dist/runtime/outcome-mapper.d.ts +2 -1
  192. package/dist/runtime/output-validator.d.ts +1 -1
  193. package/dist/runtime/owned-execution.registry.d.ts +13 -3
  194. package/dist/runtime/pipe-output.validator.d.ts +10 -0
  195. package/dist/runtime/pipe-output.validator.js +4 -2
  196. package/dist/runtime/pipeline.d.ts +47 -22
  197. package/dist/runtime/readonly-value.d.ts +20 -5
  198. package/dist/runtime/readonly-value.js +74 -26
  199. package/dist/runtime/referential-action.d.ts +1 -1
  200. package/dist/runtime/scalar-runtime.d.ts +4 -11
  201. package/dist/runtime/scalar-runtime.js +91 -22
  202. package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
  203. package/dist/runtime/unsent-value.normalizer.js +128 -0
  204. package/dist/transactions/operation-arguments-encoder.js +8 -3
  205. package/dist/transactions/operation-fingerprint.js +2 -2
  206. package/dist/transactions/sql-statement.d.ts +10 -2
  207. package/dist/transactions/sql-statement.validator.d.ts +2 -2
  208. package/dist/transactions/sql-statement.validator.js +38 -5
  209. package/dist/transactions/transaction-envelope.d.ts +5 -4
  210. package/dist/transactions/transaction-integrity-error.js +2 -0
  211. package/dist/transactions/transaction-plan-assembler.d.ts +12 -5
  212. package/dist/transactions/transaction-plan-assembler.js +48 -10
  213. package/dist/transactions/transaction-plan-validator.d.ts +23 -7
  214. package/dist/transactions/transaction-plan-validator.js +27 -1
  215. package/dist/transactions/transaction-reference-resolver.d.ts +3 -2
  216. package/dist/transactions/transaction-reference-validator.d.ts +43 -3
  217. package/dist/transactions/transaction-reference-validator.js +83 -57
  218. package/dist/transactions/transaction-reference.d.ts +1 -1
  219. package/dist/transactions/transaction-reference.js +5 -0
  220. package/dist/transactions/transaction-request.d.ts +8 -8
  221. package/dist/transactions/transaction-runtime.d.ts +5 -2
  222. package/dist/transactions/transaction-runtime.js +79 -27
  223. package/dist/transactions/transaction-settlement.runtime.d.ts +4 -3
  224. package/dist/transactions/transaction-slot-path-error.js +2 -0
  225. package/dist/transactions/transaction-stage.runtime.d.ts +5 -3
  226. package/dist/transactions/transaction-stage.runtime.js +7 -4
  227. package/package.json +6 -5
  228. package/src/runtime/field-check.evaluator.ts +1 -1
@@ -1,10 +1,11 @@
1
+ import { FILTER_MODES, toOneRelinkWithRewrite, } from "../contracts/capability.js";
1
2
  import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
2
3
  import { advertisedDirectivesAt, advertisedReducers, advertisedReducersAt, holdsAt, } from "../contracts/field.js";
3
- import { isPlainRecord } from "../runtime/scalar-runtime.js";
4
+ import { isPlainRecord, unsentReadValueIssue, } from "../runtime/scalar-runtime.js";
4
5
  import { routeTransactionReferenceCandidate } from "../transactions/transaction-reference.js";
5
6
  import { isOperationFamily, } from "./operation-identity.js";
6
7
  import { NESTED_PROJECTION_SCOPE, resolveProjectionScope, } from "./projection-scope.resolver.js";
7
- import { NESTED_WRITE_SCOPE, resolveWriteScope, } from "./write-scope.resolver.js";
8
+ import { NESTED_WRITE_SCOPE, resolveWriteScope, TO_MANY_UPDATE_WRITE_SCOPE, } from "./write-scope.resolver.js";
8
9
  const OPERATION_ARGUMENT_RULES = {
9
10
  "find.first": {
10
11
  allowed: ["where", "orderBy", "select", "include"],
@@ -190,11 +191,16 @@ function validateScalarCondition(contract, fieldName, field, supported, value, p
190
191
  addIssue(state.issues, "V1001", path, `Filter object for field "${fieldName}" must contain an operator.`);
191
192
  return;
192
193
  }
194
+ refuseDanglingQualifiers(fieldName, value, path, state);
193
195
  for (const operator of operators) {
194
196
  if (!includes(supported, operator)) {
195
197
  addIssue(state.issues, "V1006", [...path, operator], `Filter operator "${operator}" is not available on field "${fieldName}".`);
196
198
  continue;
197
199
  }
200
+ if (operator === "mode") {
201
+ refuseUnavailableMode(field, fieldName, value, path, state);
202
+ continue;
203
+ }
198
204
  if (operator === "not") {
199
205
  const operand = value[operator];
200
206
  if (isPlainRecord(operand) && !checkDepth(contract, state, depth + 1)) {
@@ -204,12 +210,55 @@ function validateScalarCondition(contract, fieldName, field, supported, value, p
204
210
  }
205
211
  }
206
212
  }
213
+ function refuseDanglingQualifiers(fieldName, level, path, state) {
214
+ const qualifiers = DANGLING_QUALIFIERS.filter((key) => Object.hasOwn(level, key));
215
+ if (qualifiers.length === 0) {
216
+ return;
217
+ }
218
+ const compares = Object.entries(level).some(([operator, operand]) => !includes(DANGLING_QUALIFIERS, operator) &&
219
+ !(operator === "not" && isNegatedOperatorObject(operand, state)));
220
+ if (compares) {
221
+ return;
222
+ }
223
+ for (const qualifier of qualifiers) {
224
+ addIssue(state.issues, "V1001", [...path, qualifier], `${qualifier} on field "${fieldName}" qualifies no operator: write it next to the operator it applies to (inside "not" to apply to a negated one).`);
225
+ }
226
+ }
227
+ const DANGLING_QUALIFIERS = ["mode", "path"];
228
+ function isNegatedOperatorObject(operand, state) {
229
+ return (isPlainRecord(operand) &&
230
+ !(state.transactionReferences === true &&
231
+ routeTransactionReferenceCandidate(operand).kind !== "ordinary"));
232
+ }
233
+ function refuseUnavailableMode(field, fieldName, level, path, state) {
234
+ const mode = level.mode;
235
+ if (mode === "default" ||
236
+ typeof mode !== "string" ||
237
+ !includes(FILTER_MODES, mode)) {
238
+ return;
239
+ }
240
+ const { filterModes = [], pathFilterModes } = field.capabilities;
241
+ const atPath = Object.hasOwn(level, "path") && pathFilterModes !== undefined;
242
+ if (includes(atPath ? pathFilterModes : filterModes, mode)) {
243
+ return;
244
+ }
245
+ const where = atPath
246
+ ? " at a path"
247
+ : pathFilterModes !== undefined && includes(pathFilterModes, mode)
248
+ ? " without a path"
249
+ : "";
250
+ addIssue(state.issues, "V1006", [...path, "mode"], `Filter mode "${mode}" is not available on field "${fieldName}"${where}.`);
251
+ }
207
252
  function validateRelationFilter(contract, fieldName, field, value, path, state, depth) {
208
253
  const supported = field.capabilities.filter;
209
254
  if (supported === undefined) {
210
255
  addIssue(state.issues, "V1006", path, `Filtering is not available on relation "${fieldName}".`);
211
256
  return;
212
257
  }
258
+ if (value === undefined) {
259
+ state.issues.push(unsentReadValueIssue(path));
260
+ return;
261
+ }
213
262
  if (field.cardinality === "one") {
214
263
  if (value === null) {
215
264
  if (!field.nullable || !includes(supported, "null")) {
@@ -249,10 +298,26 @@ function validateRelationFilter(contract, fieldName, field, value, path, state,
249
298
  validateWhere(contract, field.target, value[operator], [...path, operator], state, depth + 1);
250
299
  }
251
300
  }
301
+ const UNDEFINED_ARGUMENT_MESSAGES = {
302
+ where: "where must not be undefined: leave the key out to mean no filter.",
303
+ limit: "limit must not be undefined: leave the key out to mean no limit.",
304
+ offset: "offset must not be undefined: leave the key out to mean no offset.",
305
+ cursor: "cursor must not be undefined: leave the key out to mean no cursor.",
306
+ };
307
+ const EMPTY_BOOLEAN_NODE_MESSAGE = "A boolean node must hold a condition here: an empty one matches every row, and the write would reach more rows.";
308
+ function isEmptyBooleanNode(value) {
309
+ return Array.isArray(value)
310
+ ? value.length === 0
311
+ : isRecord(value) && Object.keys(value).length === 0;
312
+ }
252
313
  function validateWhere(contract, resourceName, where, path, state, depth) {
253
314
  if (!checkDepth(contract, state, depth)) {
254
315
  return;
255
316
  }
317
+ if (where === undefined) {
318
+ state.issues.push(unsentReadValueIssue(path));
319
+ return;
320
+ }
256
321
  if (!isRecord(where)) {
257
322
  addIssue(state.issues, "V1001", path, "where must be an object.");
258
323
  return;
@@ -263,6 +328,13 @@ function validateWhere(contract, resourceName, where, path, state, depth) {
263
328
  return;
264
329
  }
265
330
  for (const [key, value] of Object.entries(where)) {
331
+ if (state.refuseEmptyNodes === true &&
332
+ (key === "AND" || key === "OR" || key === "NOT") &&
333
+ isEmptyBooleanNode(value)) {
334
+ countFilterNode(contract, state);
335
+ addIssue(state.issues, "V1001", [...path, key], EMPTY_BOOLEAN_NODE_MESSAGE);
336
+ continue;
337
+ }
266
338
  if (key === "AND" || key === "OR") {
267
339
  countFilterNode(contract, state);
268
340
  if (!Array.isArray(value)) {
@@ -270,6 +342,10 @@ function validateWhere(contract, resourceName, where, path, state, depth) {
270
342
  continue;
271
343
  }
272
344
  value.forEach((entry, index) => {
345
+ if (state.refuseEmptyNodes === true && isEmptyBooleanNode(entry)) {
346
+ addIssue(state.issues, "V1001", [...path, key, index], EMPTY_BOOLEAN_NODE_MESSAGE);
347
+ return;
348
+ }
273
349
  validateWhere(contract, resourceName, entry, [...path, key, index], state, depth + 1);
274
350
  });
275
351
  continue;
@@ -366,7 +442,9 @@ function validateOrderBy(contract, resourceName, orderBy, path, issues) {
366
442
  valueKeys[1] !== "sort" ||
367
443
  (value.sort !== "asc" && value.sort !== "desc") ||
368
444
  (value.nulls !== "first" && value.nulls !== "last")) {
369
- addIssue(issues, "V1001", fieldPath, `Extended null ordering for "${fieldName}" must contain sort and nulls.`);
445
+ addIssue(issues, "V1001", fieldPath, Object.hasOwn(value, "$ref")
446
+ ? `A transaction reference cannot stand in orderBy: order "${fieldName}" by "asc", "desc" or { sort, nulls }.`
447
+ : `Null ordering for "${fieldName}" must be exactly { sort: "asc" | "desc", nulls: "first" | "last" }.`);
370
448
  continue;
371
449
  }
372
450
  if (!field.nullable || field.capabilities.orderNulls !== true) {
@@ -393,6 +471,10 @@ function validateOrderBy(contract, resourceName, orderBy, path, issues) {
393
471
  return analysis;
394
472
  }
395
473
  function validatePaginationValue(contract, name, value, path, issues) {
474
+ if (value === undefined) {
475
+ addIssue(issues, "V1001", path, UNDEFINED_ARGUMENT_MESSAGES[name]);
476
+ return;
477
+ }
396
478
  if (!Number.isInteger(value) || typeof value !== "number" || value < 0) {
397
479
  addIssue(issues, "V1001", path, `${name} must be a non-negative integer.`);
398
480
  return;
@@ -402,6 +484,10 @@ function validatePaginationValue(contract, name, value, path, issues) {
402
484
  }
403
485
  }
404
486
  function validateCursor(contract, resourceName, cursor, orderBy, path, issues) {
487
+ if (cursor === undefined) {
488
+ addIssue(issues, "V1009", path, UNDEFINED_ARGUMENT_MESSAGES.cursor);
489
+ return;
490
+ }
405
491
  if (!isRecord(cursor) || orderBy === undefined) {
406
492
  addIssue(issues, "V1009", path, "Cursor pagination requires an object cursor and explicit deterministic orderBy.");
407
493
  return;
@@ -438,6 +524,12 @@ function validateProjection(contract, resourceName, mode, value, scope, path, is
438
524
  }
439
525
  value.forEach((entry, index) => {
440
526
  const entryPath = [...path, index];
527
+ if (entry === "$defaults") {
528
+ if (mode !== "select") {
529
+ addIssue(issues, "V1008", entryPath, "$defaults is a select entry: include already returns the default fields.");
530
+ }
531
+ return;
532
+ }
441
533
  if (entry === "$count") {
442
534
  if (mode !== "select" ||
443
535
  reducerOwner?.edge.cardinality !== "many" ||
@@ -513,6 +605,9 @@ function validateRelationProjection(contract, edge, scope, value, path, issues)
513
605
  if (!includes(edge.capabilities.filter, "nested")) {
514
606
  addIssue(issues, "V1006", [...path, "where"], "Nested returned-relation filtering is not available on this edge.");
515
607
  }
608
+ else if (value.where === undefined) {
609
+ addIssue(issues, "V1001", [...path, "where"], UNDEFINED_ARGUMENT_MESSAGES.where);
610
+ }
516
611
  else {
517
612
  const state = {
518
613
  issues,
@@ -586,11 +681,16 @@ function validateScalarMutation(fieldName, field, value, stage, path, issues, tr
586
681
  addIssue(issues, "V1001", path, "Scalar mutation action objects may contain only $-prefixed directive keys.");
587
682
  return;
588
683
  }
684
+ let unavailable = false;
589
685
  for (const directive of directiveKeys) {
590
686
  if (!includes(directives, directive)) {
687
+ unavailable = true;
591
688
  addIssue(issues, "V1006", [...path, directive], `Mutation directive "${directive}" is not available on field "${fieldName}".`);
592
689
  }
593
690
  }
691
+ if (!unavailable && directiveKeys.length > 1) {
692
+ addIssue(issues, "V1001", path, "Scalar mutation action objects may contain only one directive.");
693
+ }
594
694
  }
595
695
  function validateRelationMutationEntry(contract, edge, directive, value, path, issues, transactionReferences) {
596
696
  const target = edge.target;
@@ -610,8 +710,8 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
610
710
  addIssue(issues, "V1012", path, "To-many $disconnect requires one or more unique identifiers.");
611
711
  return;
612
712
  }
613
- for (const selector of selectors) {
614
- validateUniqueSelector(contract, target, selector, path, issues);
713
+ for (const { entry: selector, at } of entriesOf(edge, value, path)) {
714
+ validateUniqueSelector(contract, target, selector, at, issues);
615
715
  }
616
716
  return;
617
717
  }
@@ -626,82 +726,81 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
626
726
  addIssue(issues, "V1012", path, "To-many $set requires an identifier array.");
627
727
  return;
628
728
  }
629
- for (const selector of value) {
630
- validateUniqueSelector(contract, target, selector, path, issues);
729
+ for (const { entry: selector, at } of entriesOf(edge, value, path)) {
730
+ validateUniqueSelector(contract, target, selector, at, issues);
631
731
  }
632
732
  return;
633
733
  }
634
734
  if (directive === "$connect") {
635
- const selectors = edge.cardinality === "many" && Array.isArray(value) ? value : [value];
636
- for (const selector of selectors) {
637
- validateUniqueSelector(contract, target, selector, path, issues);
735
+ for (const { entry: selector, at } of entriesOf(edge, value, path)) {
736
+ validateUniqueSelector(contract, target, selector, at, issues);
638
737
  }
639
738
  return;
640
739
  }
641
740
  if (directive === "$create") {
642
- const entries = edge.cardinality === "many" && Array.isArray(value) ? value : [value];
643
- for (const entry of entries) {
644
- validateMutationData(contract, target, entry, "create", NESTED_WRITE_SCOPE, path, issues, transactionReferences);
741
+ for (const { entry, at } of entriesOf(edge, value, path)) {
742
+ validateMutationData(contract, target, entry, "create", NESTED_WRITE_SCOPE, at, issues, transactionReferences);
645
743
  }
646
744
  return;
647
745
  }
648
746
  if (directive === "$connectOrCreate") {
649
- const entries = edge.cardinality === "many" && Array.isArray(value) ? value : [value];
650
- for (const entry of entries) {
747
+ for (const { entry, at } of entriesOf(edge, value, path)) {
651
748
  if (!isRecord(entry) || !("where" in entry) || !("create" in entry)) {
652
- addIssue(issues, "V1012", path, "$connectOrCreate requires where and create.");
749
+ addIssue(issues, "V1012", at, "$connectOrCreate requires where and create.");
653
750
  continue;
654
751
  }
655
- validateUniqueSelector(contract, target, entry.where, [...path, "where"], issues);
656
- validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...path, "create"], issues, transactionReferences);
752
+ validateUniqueSelector(contract, target, entry.where, [...at, "where"], issues);
753
+ validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...at, "create"], issues, transactionReferences);
657
754
  }
658
755
  return;
659
756
  }
660
757
  if (directive === "$update") {
661
- const entries = edge.cardinality === "many" && Array.isArray(value) ? value : [value];
662
- for (const entry of entries) {
758
+ for (const { entry, at } of entriesOf(edge, value, path)) {
663
759
  if (!isRecord(entry) || !("data" in entry)) {
664
- addIssue(issues, "V1012", path, "$update requires a data object.");
760
+ addIssue(issues, "V1012", at, "$update requires a data object.");
665
761
  continue;
666
762
  }
667
763
  if (edge.cardinality === "many" && !("where" in entry)) {
668
- addIssue(issues, "V1012", path, "To-many $update requires where.");
764
+ addIssue(issues, "V1012", at, "To-many $update requires where.");
669
765
  continue;
670
766
  }
671
767
  if ("where" in entry) {
672
768
  const state = {
673
769
  issues,
674
- structuralRoot: [...path, "where"],
770
+ structuralRoot: [...at, "where"],
675
771
  transactionReferences,
676
772
  scalarOnly: edge.capabilities.nestedWriteFilter === "scalar",
773
+ ...(edge.cardinality === "many" ? { refuseEmptyNodes: true } : {}),
677
774
  booleanFilterNodes: 0,
678
775
  nestingExceeded: false,
679
776
  booleanNodesExceeded: false,
680
777
  };
681
- validateWhere(contract, target, entry.where, [...path, "where"], state, 1);
778
+ validateWhere(contract, target, entry.where, [...at, "where"], state, 1);
682
779
  }
683
- validateMutationData(contract, target, entry.data, "update", NESTED_WRITE_SCOPE, [...path, "data"], issues, transactionReferences);
780
+ validateMutationData(contract, target, entry.data, "update", edge.cardinality === "many"
781
+ ? TO_MANY_UPDATE_WRITE_SCOPE
782
+ : NESTED_WRITE_SCOPE, [...at, "data"], issues, transactionReferences);
684
783
  }
685
784
  return;
686
785
  }
687
786
  if (directive === "$delete") {
688
- const entries = edge.cardinality === "many" && Array.isArray(value) ? value : [value];
689
- for (const entry of entries) {
787
+ for (const { entry, at } of entriesOf(edge, value, path)) {
690
788
  if (edge.cardinality === "many") {
691
789
  if (!isRecord(entry) || !("where" in entry)) {
692
- addIssue(issues, "V1012", path, "To-many $delete requires where.");
790
+ addIssue(issues, "V1012", at, "To-many $delete requires where.");
693
791
  continue;
694
792
  }
695
793
  const state = {
696
794
  issues,
697
- structuralRoot: [...path, "where"],
795
+ structuralRoot: [...at, "where"],
698
796
  transactionReferences,
699
797
  scalarOnly: edge.capabilities.nestedWriteFilter === "scalar",
798
+ refuseEmptyNodes: true,
700
799
  booleanFilterNodes: 0,
701
800
  nestingExceeded: false,
702
801
  booleanNodesExceeded: false,
703
802
  };
704
- validateWhere(contract, target, entry.where, [...path, "where"], state, 1);
803
+ validateWhere(contract, target, entry.where, [...at, "where"], state, 1);
705
804
  }
706
805
  else if (entry !== true &&
707
806
  (!isRecord(entry) || Object.keys(entry).some((key) => key !== "where"))) {
@@ -723,23 +822,34 @@ function validateRelationMutationEntry(contract, edge, directive, value, path, i
723
822
  return;
724
823
  }
725
824
  if (directive === "$upsert") {
726
- const entries = edge.cardinality === "many" && Array.isArray(value) ? value : [value];
727
- for (const entry of entries) {
825
+ for (const { entry, at } of entriesOf(edge, value, path)) {
728
826
  if (!isRecord(entry) ||
729
827
  !("create" in entry) ||
730
828
  !("update" in entry) ||
731
829
  (edge.cardinality === "many" && !("where" in entry))) {
732
- addIssue(issues, "V1012", path, "$upsert requires create/update and requires where on to-many relations.");
830
+ addIssue(issues, "V1012", at, "$upsert requires create/update and requires where on to-many relations.");
733
831
  continue;
734
832
  }
735
833
  if ("where" in entry) {
736
- validateUniqueSelector(contract, target, entry.where, [...path, "where"], issues);
834
+ validateUniqueSelector(contract, target, entry.where, [...at, "where"], issues);
737
835
  }
738
- validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...path, "create"], issues, transactionReferences);
739
- validateMutationData(contract, target, entry.update, "update", NESTED_WRITE_SCOPE, [...path, "update"], issues, transactionReferences);
836
+ validateMutationData(contract, target, entry.create, "create", NESTED_WRITE_SCOPE, [...at, "create"], issues, transactionReferences);
837
+ validateMutationData(contract, target, entry.update, "update", NESTED_WRITE_SCOPE, [...at, "update"], issues, transactionReferences);
740
838
  }
741
839
  }
742
840
  }
841
+ function entriesOf(edge, value, path) {
842
+ return edge.cardinality === "many" && Array.isArray(value)
843
+ ? value.map((entry, index) => ({ entry, at: [...path, index] }))
844
+ : [{ entry: value, at: path }];
845
+ }
846
+ function refuseToOneRelinkWithRewrite(fieldName, field, value, path, issues) {
847
+ const paired = field.cardinality === "one" ? toOneRelinkWithRewrite(value) : undefined;
848
+ if (paired === undefined) {
849
+ return;
850
+ }
851
+ addIssue(issues, "V1012", path, `To-one relation "${fieldName}" cannot combine ${paired.rewrite.join("/")} with ${paired.relink.join("/")} in one write: the row it would update is the newly linked one. Relink in one write and update in another.`);
852
+ }
743
853
  function validateRelationMutation(contract, fieldName, field, value, stage, scope, path, issues, transactionReferences) {
744
854
  const directives = advertisedDirectivesAt(field.capabilities[stage], scope);
745
855
  if (directives === undefined) {
@@ -750,6 +860,7 @@ function validateRelationMutation(contract, fieldName, field, value, stage, scop
750
860
  addIssue(issues, "V1012", path, `Relation "${fieldName}" mutation value must be a directive object.`);
751
861
  return;
752
862
  }
863
+ refuseToOneRelinkWithRewrite(fieldName, field, value, path, issues);
753
864
  for (const [directive, directiveValue] of Object.entries(value)) {
754
865
  const directivePath = [...path, directive];
755
866
  if (!directive.startsWith("$") || !includes(directives, directive)) {
@@ -817,6 +928,14 @@ function validateMutationArguments(contract, resourceName, request, args, issues
817
928
  }
818
929
  }
819
930
  }
931
+ function emptyNodeRefusalOf(request) {
932
+ return (request.family === "update" || request.family === "delete") &&
933
+ (request.variant === "many" ||
934
+ request.variant === "count" ||
935
+ request.variant === "first")
936
+ ? { refuseEmptyNodes: true }
937
+ : {};
938
+ }
820
939
  function isUniqueOperation(request) {
821
940
  return (request.variant === "unique" &&
822
941
  (request.family === "find" ||
@@ -854,11 +973,15 @@ export function validateOperationArguments(contract, request, options) {
854
973
  if (isUniqueOperation(request)) {
855
974
  validateUniqueSelector(contract, request.resource, request.arguments.where, ["arguments", "where"], issues);
856
975
  }
976
+ else if (request.arguments.where === undefined) {
977
+ addIssue(issues, "V1001", ["arguments", "where"], UNDEFINED_ARGUMENT_MESSAGES.where);
978
+ }
857
979
  else {
858
980
  const state = {
859
981
  issues,
860
982
  structuralRoot: ["arguments", "where"],
861
983
  transactionReferences: options?.transactionReferences === true,
984
+ ...emptyNodeRefusalOf(request),
862
985
  booleanFilterNodes: 0,
863
986
  nestingExceeded: false,
864
987
  booleanNodesExceeded: false,
@@ -2,7 +2,7 @@ import type { AvContract } from "../contracts/contract.js";
2
2
  import { type AvOperationIdentity } from "./operation-identity.js";
3
3
  import { type OperationValidationOptions, type OperationValidationResult } from "./operation-validator-core.js";
4
4
  import type { AvValidationIssue } from "./validation-code.js";
5
- export type { OperationValidationOptions, OperationValidationResult, SemanticOperationArguments, } from "./operation-validator-core.js";
5
+ export type { OperationValidationOptions, SemanticOperationArguments, } from "./operation-validator-core.js";
6
6
  /** The key of a request's operation identity that makes it unavailable. */
7
7
  export declare function unavailableOperationKey(contract: AvContract, request: {
8
8
  readonly resource: string;
@@ -3,7 +3,7 @@ import type { AvOperationIdentity } from "./operation-identity.js";
3
3
  import type { AvValidationIssue } from "./validation-code.js";
4
4
  type Readable = Readonly<Record<string, unknown>>;
5
5
  /** What one walk of an operation's arguments found. */
6
- export type StructuralLimitsFinding = {
6
+ type StructuralLimitsFinding = {
7
7
  /** The nesting issue, which wins over any boolean-node issue. */
8
8
  readonly nesting: AvValidationIssue | undefined;
9
9
  /** The boolean-node issue, when there is no nesting issue. */
@@ -0,0 +1,6 @@
1
+ import type { ErrorCodeGuidance } from "../runtime/error-guidance.js";
2
+ import type { AvValidationCode } from "./validation-code.js";
3
+ /** Cause and fix of every validation code. */
4
+ export declare const VALIDATION_CODE_GUIDANCE: {
5
+ readonly [C in AvValidationCode]: ErrorCodeGuidance;
6
+ };
@@ -0,0 +1,90 @@
1
+ export const VALIDATION_CODE_GUIDANCE = {
2
+ V1000: {
3
+ cause: "A required value is absent: a create leaves out a required field that has no database default and no compute.create (the path names the field), a required relation and its reference field are both missing, a typed Json field lacks a required key, or a $ref has no fingerprint.",
4
+ fix: "Send the value at the issue's path. When the server must fill it, give the field a compute.create stage or a database default; a pipe cannot fill it.",
5
+ },
6
+ V1001: {
7
+ cause: "A value of the wrong type: a string where a number is expected, a negative limit, a non-integer id, null given to an operator with no null meaning (gt, contains, in), two directives in one scalar action object (`{ $increment: 1, $decrement: 2 }`), or a server-side value that is not plain data. Also a value that would make the call reach more rows: `undefined` in a filter, a unique selector or a cursor, an empty boolean node (`NOT: {}`, `AND: []`, `OR: []`) in the where of a write (update or delete many, count or first, a to-many $update or $delete).",
8
+ fix: "Send the type the contract states at that path (the generated client's types say it).",
9
+ },
10
+ V1002: {
11
+ cause: "A value that is not a member of the enum, or outside a typed Json field's AvZ.enum or AvZ.literal.",
12
+ fix: "Send one of the enum's members.",
13
+ },
14
+ V1003: {
15
+ cause: 'A malformed datetime, decimal, base64 or UUID string, or a failed pattern or format validator (`check: "string_format"`).',
16
+ fix: "Send the canonical encoding (ISO-8601 UTC datetime, decimal string, base64 bytes) and satisfy the validator that check and params name.",
17
+ },
18
+ V1004: {
19
+ cause: "A number, length or size outside its range: a failed bound, length or size validator, a BigInt outside signed 64 bits, an AvZ.int() outside the safe integer range, or a transaction with no operations. Under A2004 it is also a value the database refused as too long or out of its range, a BigInt beyond what the data source's driver can bind among them (some bind at most ±(2^53 − 1)).",
20
+ fix: "Send a value inside the range; check and params name the validator that failed.",
21
+ },
22
+ V1005: {
23
+ cause: "A field that does not exist or is hidden in the caller's layer, an unknown Resource (under A2001), or a key a typed Json field's shape does not declare.",
24
+ fix: "Use a field the caller's contract exposes, expose it through exemptions, or make the call from server code.",
25
+ },
26
+ V1006: {
27
+ cause: "An operator, directive or nested write the field does not offer (at any depth, inside not too; a to-many $update's data takes only what a bulk write takes), a mode it does not offer, or an operation that is not available (under A2002).",
28
+ fix: "Use what the contract lists for that field or Resource, or expose it through exemptions.",
29
+ },
30
+ V1007: {
31
+ cause: "The where of a unique operation is not exactly one complete identifier.",
32
+ fix: "Pass exactly one identifier: the id, or every field of one @unique or @@unique.",
33
+ },
34
+ V1008: {
35
+ cause: "Both select and include, a write-only field selected, or a relation that is not selectable there.",
36
+ fix: "Use select or include, not both, and select only readable fields.",
37
+ },
38
+ V1009: {
39
+ cause: "A cursor without an explicit orderBy, or cursor keys that do not match the ordered fields.",
40
+ fix: "Give an orderBy and a cursor holding exactly its ordered fields.",
41
+ },
42
+ V1010: {
43
+ cause: "A $ref path the earlier step does not return, a $ref to a step that is not in the transaction, or to a step with no single row (a many or count step).",
44
+ fix: "Select the referenced field in the earlier step, and reference a single-row step.",
45
+ },
46
+ V1011: {
47
+ cause: "The referenced value's type does not fit its target, a nullable source where only a non-null value is accepted included.",
48
+ fix: "Reference a field of the target's type, non-null where the target needs it.",
49
+ },
50
+ V1012: {
51
+ cause: "A nested write that does not fit the relation (a list where one record is expected), a reference field set together with its own relation, one record mixing reference fields and relation writes where the adapter cannot run both, or a record written through a relation that writes that relation (or a field holding its reference) back, where the adapter admits no such write. Also a to-one $update or $upsert beside $connect, $connectOrCreate, $create, $set or $disconnect on the same relation: the row it would update is the newly linked one.",
52
+ fix: "Write either the relation or its reference field, in the relation's cardinality. Relink a to-one relation in one write and update the linked row in another.",
53
+ },
54
+ V1013: {
55
+ cause: "Nested projections, filters or writes deeper than maxNestingDepth.",
56
+ fix: "Nest less, or raise limits.maxNestingDepth.",
57
+ },
58
+ V1014: {
59
+ cause: "A limit above maxListLimit, or more steps than maxTransactionOperations.",
60
+ fix: "Paginate or split the plan, or raise the limit.",
61
+ },
62
+ V1015: {
63
+ cause: "A where tree with more nodes than maxBooleanNodes.",
64
+ fix: "Simplify the filter (in instead of many OR clauses), or raise limits.maxBooleanNodes.",
65
+ },
66
+ V1016: {
67
+ cause: "A $ref to the referencing step itself or a later one, or to an index no step has.",
68
+ fix: "Reference an earlier step only.",
69
+ },
70
+ V1017: {
71
+ cause: "A hand-written plan whose fingerprint does not match its step.",
72
+ fix: "Let the generated client, framework.appTx or framework.clientTx build the plan.",
73
+ },
74
+ V1018: {
75
+ cause: "The referenced step returned no value at that path, such as a first step that matched no row.",
76
+ fix: "Make sure the earlier step returns a row, or use a unique step, which fails with A2003.",
77
+ },
78
+ V1019: {
79
+ cause: "A later step uses a row that an earlier step's delete removed through a database cascade.",
80
+ fix: "Reorder or drop the dependent step.",
81
+ },
82
+ V1020: {
83
+ cause: "One framework.transaction([...]) list mixes appTx and clientTx steps.",
84
+ fix: "Build every step of a plan from one origin.",
85
+ },
86
+ V1021: {
87
+ cause: "A Json field's value nests deeper than maxJsonDepth.",
88
+ fix: "Flatten the value, or raise limits.maxJsonDepth.",
89
+ },
90
+ };
@@ -13,3 +13,7 @@ export declare function resolveWriteScope(resource: AvResource<AvContract> | und
13
13
  * unrestricted one, at every depth, under every top-level scope.
14
14
  */
15
15
  export declare const NESTED_WRITE_SCOPE: AvWriteScope;
16
+ /** The position a to-many `$update`'s `data` sits in: the flat-bulk write position. */
17
+ export declare const TO_MANY_UPDATE_WRITE_SCOPE: AvWriteScope;
18
+ /** The position of a relation's other end inside a record written through it. */
19
+ export declare const LOOPBACK_WRITE_SCOPE: AvWriteScope;
@@ -5,3 +5,5 @@ export function resolveWriteScope(resource, request) {
5
5
  return writeScopeOf(lookupOwn(advertised, request.variant));
6
6
  }
7
7
  export const NESTED_WRITE_SCOPE = "nested";
8
+ export const TO_MANY_UPDATE_WRITE_SCOPE = "bulkWrite";
9
+ export const LOOPBACK_WRITE_SCOPE = "loopback";
@@ -0,0 +1,91 @@
1
+ import type { AvState } from "../runtime/request-state.js";
2
+ import type { AvPolicyEngine } from "./policy-engine.js";
3
+ /**
4
+ * What the framework's `access` option takes: the policy engine every client
5
+ * and agent request is checked against, and how a request's state is seeded.
6
+ * Aventara Access provides one; one written by hand works the same way.
7
+ *
8
+ * The request's principal is `ctx.$state.me` (`null` when it is absent), so
9
+ * `state` names it as `me`. With `access`, the configuration states no
10
+ * `policy`, and the host no `state` of its own.
11
+ */
12
+ export interface AvAccessProvider {
13
+ /** The policy engine (`AvPolicyEngine`), asked about every client and agent request. */
14
+ readonly policy: AvPolicyEngine;
15
+ /**
16
+ * Seeds a request's `ctx.$state` from its headers (a Web `Headers`): `me`, the principal the
17
+ * policy is asked about (`null` for an anonymous caller), and anything else
18
+ * the stages read. Called once per request by the host. `request` is the
19
+ * host's own request when it has one: Express's `req`, Fastify's
20
+ * `request`, or the Next.js route handler's `Request`. A throw is answered
21
+ * like any developer failure: a thrown `AvError` as its own outcome,
22
+ * anything else as an internal failure.
23
+ */
24
+ state(input: {
25
+ readonly headers: {
26
+ get(name: string): string | null;
27
+ has(name: string): boolean;
28
+ forEach(callback: (value: string, name: string) => void): void;
29
+ };
30
+ readonly request?: unknown;
31
+ }): (AvState & {
32
+ readonly me: unknown;
33
+ }) | Promise<AvState & {
34
+ readonly me: unknown;
35
+ }>;
36
+ /**
37
+ * What the clients' `$access` needs beyond `can`: where the app mounted
38
+ * Aventara Access (`url`), and each verb's route under it, the JSON Schema
39
+ * of its arguments and result, and its server-side `call`. Compiled into
40
+ * the ClientContract's `access` section (its `call`s dropped). Left out,
41
+ * `$access` offers `can` only.
42
+ */
43
+ readonly client?: {
44
+ /** Where the app mounted Access: an absolute `http(s)` URL, or root-relative (`"/api/auth"`). */
45
+ readonly url: string;
46
+ /**
47
+ * The verbs Access offers, each its route, its schemas and its
48
+ * server-side call. A verb left out is no verb of `$access`: a
49
+ * `service` profile, with no cookie sign-in, offers no `signIn` or
50
+ * `signUp`, and only the `kiosk` profile offers `switchUser`, `lock`,
51
+ * `setPin`, `enrollDevice` and `revokeDevice`. Any other name is
52
+ * refused.
53
+ */
54
+ readonly verbs: {
55
+ readonly [Verb in "signIn" | "signUp" | "signOut" | "resetPassword" | "me" | "switchUser" | "lock" | "setPin" | "enrollDevice" | "revokeDevice"]?: {
56
+ /** The route's method. */
57
+ readonly method: "GET" | "POST";
58
+ /** Under `url`: `"/sign-in/email"`. */
59
+ readonly path: string;
60
+ /**
61
+ * The arguments' JSON Schema, in the subset a `json` field's shape
62
+ * uses (absent: the verb takes none).
63
+ */
64
+ readonly args?: {
65
+ readonly [key: string]: unknown;
66
+ };
67
+ /** The result's JSON Schema, in the same subset (`me`: the value when someone is signed in). */
68
+ readonly result: {
69
+ readonly [key: string]: unknown;
70
+ };
71
+ /**
72
+ * The verb run in process, for a server-side client
73
+ * (`framework.serverClient.$access`, Next's `avClient.$access`):
74
+ * Access runs it with the request's headers, and the host's own
75
+ * request and response when the caller hands them (Express's
76
+ * `req`/`res`, Fastify's `request`/`reply`), so a sign-in (or a
77
+ * kiosk's switch, lock or enrollment) sets its cookies as Access
78
+ * sets them: on the response it is handed, or, in a Server Action,
79
+ * through Next's `cookies()`. `me` resolves the token identity, or
80
+ * `null` when no one is signed in.
81
+ */
82
+ call(input: {
83
+ readonly args: unknown;
84
+ readonly headers: Parameters<AvAccessProvider["state"]>[0]["headers"];
85
+ readonly request?: unknown;
86
+ readonly response?: unknown;
87
+ }): Promise<unknown>;
88
+ };
89
+ };
90
+ };
91
+ }
@@ -0,0 +1 @@
1
+ export {};