@aventara/testing 1.0.0-rc.1 → 1.0.0-rc.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,119 @@
1
1
  # @aventara/testing
2
2
 
3
+ ## 1.0.0-rc.10
4
+
5
+ ### Patch Changes
6
+
7
+ - 04bb39a: `engines.node` is now `^22.23.4 || >=24.22.1`, the Node security releases of 2026-10-20 (CVE-2026-105481,
8
+ CVE-2026-105482, CVE-2026-105483, CVE-2026-106069, CVE-2026-106072, CVE-2026-106073, CVE-2026-106074,
9
+ CVE-2026-111497). The bins refuse an older Node in one sentence naming that range.
10
+ - 587dd01: The protocol corpus covers `POST /_access/can`: its answers and refusals, driven against a third corpus Client
11
+ Contract built with `access`. `AvProtocolCorpus.framework(hash)` serves that Contract for its hash, and
12
+ `fixtures/protocol-v1.json` carries it beside the other two.
13
+ - Updated dependencies [587dd01]
14
+ - Updated dependencies [d7e7369]
15
+ - Updated dependencies [7ee547b]
16
+ - Updated dependencies [f52c499]
17
+ - Updated dependencies [2907484]
18
+ - Updated dependencies [a6bbdf0]
19
+ - Updated dependencies [3e26549]
20
+ - Updated dependencies [a6bbdf0]
21
+ - Updated dependencies [6f3f6f6]
22
+ - Updated dependencies [04bb39a]
23
+ - Updated dependencies [3fb3333]
24
+ - Updated dependencies [827ccb6]
25
+ - Updated dependencies [7f5abc3]
26
+ - Updated dependencies [88263a1]
27
+ - Updated dependencies [10341d5]
28
+ - Updated dependencies [8129844]
29
+ - Updated dependencies [88263a1]
30
+ - Updated dependencies [3020b5c]
31
+ - Updated dependencies [88263a1]
32
+ - Updated dependencies [88263a1]
33
+ - @aventara/core@1.0.0-rc.10
34
+
35
+ ## 1.0.0-rc.9
36
+
37
+ ### Patch Changes
38
+
39
+ - Updated dependencies [205a379]
40
+ - Updated dependencies [a0bb05e]
41
+ - Updated dependencies [86ab319]
42
+ - Updated dependencies [fdf52e6]
43
+ - @aventara/core@1.0.0-rc.9
44
+
45
+ ## 1.0.0-rc.8
46
+
47
+ 1.0.0-rc.5, rc.6 and rc.7 were tagged but never published; 1.0.0-rc.8 contains everything listed under them and the changes below.
48
+
49
+ ### Patch Changes
50
+
51
+ - Updated dependencies [1c8e4ee]
52
+ - @aventara/core@1.0.0-rc.8
53
+
54
+ ## 1.0.0-rc.7
55
+
56
+ 1.0.0-rc.5 and 1.0.0-rc.6 were tagged but never published; 1.0.0-rc.7 contains everything listed under them and the changes below.
57
+
58
+ ### Patch Changes
59
+
60
+ - Updated dependencies [f917c1c]
61
+ - @aventara/core@1.0.0-rc.7
62
+
63
+ ## 1.0.0-rc.6
64
+
65
+ 1.0.0-rc.5 was tagged but never published. 1.0.0-rc.6 contains everything listed under 1.0.0-rc.5 and the fix below.
66
+
67
+ ### Patch Changes
68
+
69
+ - Updated dependencies [1cf72e0]
70
+ - @aventara/core@1.0.0-rc.6
71
+
72
+ ## 1.0.0-rc.5
73
+
74
+ ### Patch Changes
75
+
76
+ - Updated dependencies [4795ff1]
77
+ - Updated dependencies [9e178ca]
78
+ - @aventara/core@1.0.0-rc.5
79
+
80
+ ## 1.0.0-rc.4
81
+
82
+ ### Patch Changes
83
+
84
+ - Updated dependencies [e3d03a7]
85
+ - Updated dependencies [d10639a]
86
+ - Updated dependencies [f67e68c]
87
+ - Updated dependencies [708556c]
88
+ - Updated dependencies [3a0dfca]
89
+ - Updated dependencies [99169d2]
90
+ - Updated dependencies [0fd2608]
91
+ - Updated dependencies [154e440]
92
+ - Updated dependencies [2fcffdb]
93
+ - @aventara/core@1.0.0-rc.4
94
+
95
+ ## 1.0.0-rc.3
96
+
97
+ ### Patch Changes
98
+
99
+ - Updated dependencies [b38034d]
100
+ - Updated dependencies [b38034d]
101
+ - Updated dependencies [b38034d]
102
+ - Updated dependencies [b38034d]
103
+ - Updated dependencies [b38034d]
104
+ - Updated dependencies [b38034d]
105
+ - @aventara/core@1.0.0-rc.3
106
+
107
+ ## 1.0.0-rc.2
108
+
109
+ ### Patch Changes
110
+
111
+ - Updated dependencies [9366e16]
112
+ - Updated dependencies [9366e16]
113
+ - Updated dependencies [9366e16]
114
+ - Updated dependencies [9366e16]
115
+ - @aventara/core@1.0.0-rc.2
116
+
3
117
  ## 1.0.0-rc.1
4
118
 
5
119
  ### Patch Changes
@@ -465,7 +579,7 @@
465
579
  `framework.transaction`, `framework.executeTransaction` and `POST /_transactions` alike. A single call is unchanged
466
580
  (`["arguments", …]`). If your code reads `issue.path` from a transaction's answer, drop the `"operations", i, "args"`
467
581
  prefix to get the path inside that step's arguments. `@aventara/testing`'s protocol corpus row "a client-hidden
468
- field — /_transactions" and `fixtures/protocol-v1.json` carry the new path.
582
+ field — /\_transactions" and `fixtures/protocol-v1.json` carry the new path.
469
583
  - 032f792: **Behaviour changes, transactions:** an error about a transaction step itself — rather than its arguments — now
470
584
  names the step too, so every path in a transaction's answer is a path through the request you sent: an unknown or
471
585
  hidden Resource is at `["operations", i, "resource"]`, a fingerprint that does not match at
package/README.md CHANGED
@@ -20,7 +20,7 @@ It depends on `@aventara/core` only.
20
20
  npm install --save-dev @aventara/testing@rc
21
21
  ```
22
22
 
23
- Node `^22.18.0 || >=24.2.0`. ES modules.
23
+ Node `^22.23.4 || >=24.22.1`. ES modules.
24
24
 
25
25
  ## Serving the corpus through your own stack
26
26
 
@@ -1,5 +1,6 @@
1
- import type { AvContext, AvFramework } from "@aventara/core";
1
+ import type { AvAdapterModel, AvContext, AvFramework, AvPrebuiltContracts } from "@aventara/core";
2
2
  import { AvDecimal } from "@aventara/core";
3
+ import type { AvAdapterOperation } from "@aventara/core/internal";
3
4
  /**
4
5
  * The corpus's adapter model:
5
6
  *
@@ -402,6 +403,12 @@ export declare const CORPUS_CLIENT_CONTRACT_DOCUMENT = "{\"enums\":{},\"limits\"
402
403
  * against it would.
403
404
  */
404
405
  export declare const CORPUS_NONE_CLIENT_CONTRACT_HASH = "sha256:5e99809294a2aae922b635e9a44b464b1b6e03359a54d30420292c62676a7ce5";
406
+ /**
407
+ * The hash of the corpus's third ClientContract: the same model and
408
+ * configuration with the framework's `access` option ({@link CORPUS_ACCESS}),
409
+ * so it carries the `access` section and its `POST /_access/can` route.
410
+ */
411
+ export declare const CORPUS_ACCESS_CLIENT_CONTRACT_HASH = "sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23";
405
412
  /** The one record the corpus Adapter knows. */
406
413
  export declare const CORPUS_AUTHOR: {
407
414
  readonly id: "a1";
@@ -421,13 +428,168 @@ export declare const CORPUS_SAMPLE: {
421
428
  readonly blob: Uint8Array<ArrayBuffer>;
422
429
  };
423
430
  /**
424
- * A fresh corpus Framework, and the count of operations its Adapter has been
425
- * handed so far — a row's `adapterCalls` is read from it. `contractHash`
426
- * selects which corpus ClientContract it serves: the `transactions: "none"`
427
- * one when it is {@link CORPUS_NONE_CLIENT_CONTRACT_HASH}, the main one
431
+ * The corpus's access provider, behind {@link CORPUS_ACCESS_CLIENT_CONTRACT_HASH}:
432
+ * every request is anonymous (`me: null`, the same through every host), and its
433
+ * policy answers by the question alone, never by a row. Every operation is
434
+ * allowed, every row is in scope, every field readable, except: no `authors`
435
+ * row is in the delete scope; a question about `books` is refused by an
436
+ * `AvError` the engine throws; and any question about `samples` is the engine's
437
+ * own defect.
438
+ */
439
+ export declare const CORPUS_ACCESS: {
440
+ state: () => {
441
+ me: null;
442
+ };
443
+ policy: {
444
+ can: ({ resource }: {
445
+ readonly principal: unknown;
446
+ readonly origin: import("@aventara/core").AvRequestOrigin;
447
+ readonly resource: string;
448
+ } & {
449
+ readonly action: "read" | "create" | "update" | "delete";
450
+ readonly row?: Readonly<Record<string, unknown>>;
451
+ readonly before?: Readonly<Record<string, unknown>>;
452
+ readonly beforeGrants?: readonly string[];
453
+ readonly exists: (resource: string, where: import("@aventara/core").AvPolicyWhere) => Promise<boolean>;
454
+ }) => true;
455
+ scopeOf: ({ resource, action }: {
456
+ readonly principal: unknown;
457
+ readonly origin: import("@aventara/core").AvRequestOrigin;
458
+ readonly resource: string;
459
+ } & {
460
+ readonly action: "read" | "update" | "delete";
461
+ }) => boolean;
462
+ fieldsOf: () => {
463
+ always: "all";
464
+ perRow: {};
465
+ };
466
+ };
467
+ };
468
+ /**
469
+ * The corpus Framework's configuration, over a fresh corpus Adapter, and the
470
+ * count of operations that Adapter has been handed so far. `contractHash`
471
+ * selects which corpus ClientContract it compiles to: the `transactions:
472
+ * "none"` one when it is {@link CORPUS_NONE_CLIENT_CONTRACT_HASH}, the one with
473
+ * `access` when it is {@link CORPUS_ACCESS_CLIENT_CONTRACT_HASH}, the main one
428
474
  * otherwise (a stale or absent hash included).
429
475
  */
430
- export declare function createCorpusFramework(contractHash?: string): Promise<{
476
+ export declare function corpusConfiguration(contractHash?: string): {
477
+ config: {
478
+ access?: {
479
+ state: () => {
480
+ me: null;
481
+ };
482
+ policy: {
483
+ can: ({ resource }: {
484
+ readonly principal: unknown;
485
+ readonly origin: import("@aventara/core").AvRequestOrigin;
486
+ readonly resource: string;
487
+ } & {
488
+ readonly action: "read" | "create" | "update" | "delete";
489
+ readonly row?: Readonly<Record<string, unknown>>;
490
+ readonly before?: Readonly<Record<string, unknown>>;
491
+ readonly beforeGrants?: readonly string[];
492
+ readonly exists: (resource: string, where: import("@aventara/core").AvPolicyWhere) => Promise<boolean>;
493
+ }) => true;
494
+ scopeOf: ({ resource, action }: {
495
+ readonly principal: unknown;
496
+ readonly origin: import("@aventara/core").AvRequestOrigin;
497
+ readonly resource: string;
498
+ } & {
499
+ readonly action: "read" | "update" | "delete";
500
+ }) => boolean;
501
+ fieldsOf: () => {
502
+ always: "all";
503
+ perRow: {};
504
+ };
505
+ };
506
+ };
507
+ api: string;
508
+ adapter: import("@aventara/core").AvAdapter<AvAdapterModel> & {
509
+ readonly operations: readonly AvAdapterOperation<AvAdapterModel>[];
510
+ readonly transactions: readonly import("../adapters/fake-adapter.js").AvFakeTransactionTrace<AvAdapterModel>[];
511
+ } & {
512
+ transaction?: <T>(work: (executor: import("@aventara/core/internal").AvAdapterTransactionExecutor<AvAdapterModel>) => Promise<T>) => Promise<T>;
513
+ referentialActions: {
514
+ readonly books: readonly [{
515
+ readonly field: "author";
516
+ readonly target: "authors";
517
+ readonly references: readonly ["authorId"];
518
+ readonly onDelete: "cascade";
519
+ }];
520
+ };
521
+ };
522
+ resources: {
523
+ readonly books: {
524
+ readonly fields: {
525
+ readonly label: {
526
+ readonly definition: {
527
+ readonly type: {
528
+ readonly scalar: "string";
529
+ };
530
+ readonly nullable: false;
531
+ readonly list: false;
532
+ readonly lifecycle: readonly ["VIRTUAL"];
533
+ };
534
+ readonly pipelines: {
535
+ readonly compute: {
536
+ readonly read: {
537
+ readonly dependsOn: readonly ["id"];
538
+ readonly compute: ({ record, }: {
539
+ readonly record: Readonly<Record<string, unknown>>;
540
+ }) => string;
541
+ };
542
+ };
543
+ };
544
+ };
545
+ };
546
+ };
547
+ };
548
+ application: {
549
+ readonly exposed: true;
550
+ readonly exemptions: {
551
+ readonly resources: {
552
+ readonly books: {
553
+ readonly fields: {
554
+ readonly label: true;
555
+ };
556
+ };
557
+ };
558
+ };
559
+ };
560
+ client: {
561
+ readonly pipelines: {
562
+ readonly guards: readonly [typeof corpusGuard];
563
+ readonly pipes: readonly [typeof corpusPipe];
564
+ };
565
+ readonly exposed: true;
566
+ readonly exemptions: {
567
+ readonly resources: {
568
+ readonly authors: {
569
+ readonly fields: {
570
+ readonly secret: true;
571
+ };
572
+ };
573
+ readonly secrets: {
574
+ readonly operations: {
575
+ readonly find: readonly ["many"];
576
+ };
577
+ };
578
+ readonly hiddenRes: true;
579
+ };
580
+ };
581
+ };
582
+ };
583
+ adapterCalls: () => number;
584
+ };
585
+ /**
586
+ * A fresh corpus Framework, and the count of operations its Adapter has been
587
+ * handed so far — a row's `adapterCalls` is read from it. `contractHash` selects
588
+ * which corpus ClientContract it serves ({@link corpusConfiguration}). With
589
+ * `prebuilt`, its Contracts are loaded from that file when it matches, as a
590
+ * serverless deployment's would be.
591
+ */
592
+ export declare function createCorpusFramework(contractHash?: string, prebuilt?: AvPrebuiltContracts): Promise<{
431
593
  readonly framework: AvFramework;
432
594
  readonly adapterCalls: () => number;
433
595
  }>;
@@ -174,6 +174,7 @@ export const CORPUS_ENTRYPOINT = "/api";
174
174
  export const CORPUS_CLIENT_CONTRACT_HASH = "sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307";
175
175
  export const CORPUS_CLIENT_CONTRACT_DOCUMENT = '{"enums":{},"limits":{"maxBooleanNodes":50,"maxJsonDepth":64,"maxListLimit":250,"maxNestingDepth":12,"maxRequestBytes":1048576,"maxTransactionOperations":20},"protocol":{"hash":"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307","version":1},"resources":{"authors":{"fields":{"id":{"capabilities":{"filter":["equals"],"select":true},"kind":"scalar","lifecycle":[],"list":false,"nullable":false,"type":{"scalar":"string"}},"name":{"capabilities":{"create":[],"filter":["equals"],"select":true,"update":[]},"kind":"scalar","lifecycle":[],"list":false,"nullable":false,"type":{"scalar":"string"}}},"identifiers":[["id"]],"operations":{"create":{"count":true,"many":true,"one":true},"delete":{"count":true,"first":true,"many":true,"unique":true},"find":{"count":true,"first":true,"many":true,"unique":true},"update":{"count":true,"first":true,"many":true,"unique":true},"upsert":{"unique":true}}},"books":{"fields":{"authorId":{"capabilities":{"filter":["equals"],"select":true},"kind":"scalar","lifecycle":[],"list":false,"nullable":false,"type":{"scalar":"string"}},"id":{"capabilities":{"filter":["equals"],"select":true},"kind":"scalar","lifecycle":[],"list":false,"nullable":false,"type":{"scalar":"string"}},"label":{"capabilities":{"select":true},"kind":"scalar","lifecycle":["COMPUTED_ON_READ","VIRTUAL"],"list":false,"nullable":false,"type":{"scalar":"string"}}},"identifiers":[["id"]],"operations":{"find":{"many":true}}},"samples":{"fields":{"amount":{"capabilities":{"create":[],"select":true},"kind":"scalar","lifecycle":[],"list":false,"nullable":false,"type":{"scalar":"decimal"}},"at":{"capabilities":{"create":[],"select":true},"kind":"scalar","lifecycle":[],"list":false,"nullable":false,"type":{"scalar":"datetime"}},"blob":{"capabilities":{"create":[],"select":true},"kind":"scalar","lifecycle":[],"list":false,"nullable":false,"type":{"scalar":"bytes"}},"count":{"capabilities":{"create":[],"select":true},"kind":"scalar","lifecycle":[],"list":false,"nullable":false,"type":{"scalar":"bigint"}},"id":{"capabilities":{"filter":["equals"],"select":true},"kind":"scalar","lifecycle":[],"list":false,"nullable":false,"type":{"scalar":"string"}}},"identifiers":[["id"]],"operations":{"create":{"one":true},"find":{"unique":true}}},"secrets":{"fields":{"id":{"capabilities":{"filter":["equals"],"select":true},"kind":"scalar","lifecycle":[],"list":false,"nullable":false,"type":{"scalar":"string"}}},"identifiers":[["id"]],"operations":{}}},"scalars":{"bigint":{"builtin":true},"bytes":{"builtin":true},"datetime":{"builtin":true},"decimal":{"builtin":true},"string":{"builtin":true}},"transactions":"interactive"}';
176
176
  export const CORPUS_NONE_CLIENT_CONTRACT_HASH = "sha256:5e99809294a2aae922b635e9a44b464b1b6e03359a54d30420292c62676a7ce5";
177
+ export const CORPUS_ACCESS_CLIENT_CONTRACT_HASH = "sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23";
177
178
  export const CORPUS_AUTHOR = { id: "a1", name: "Ada" };
178
179
  export const CORPUS_NOBODY = "nobody";
179
180
  export const CORPUS_SAMPLE = {
@@ -221,6 +222,22 @@ function corpusAnswer(operation) {
221
222
  }
222
223
  return CORPUS_AUTHOR;
223
224
  }
225
+ export const CORPUS_ACCESS = {
226
+ state: () => ({ me: null }),
227
+ policy: {
228
+ can: ({ resource }) => {
229
+ if (resource === "samples") {
230
+ throw new Error("the corpus policy failed");
231
+ }
232
+ if (resource === "books") {
233
+ throw new AvError("A4002", "The corpus policy refuses books.");
234
+ }
235
+ return true;
236
+ },
237
+ scopeOf: ({ resource, action }) => !(resource === "authors" && action === "delete"),
238
+ fieldsOf: () => ({ always: "all", perRow: {} }),
239
+ },
240
+ };
224
241
  function failingCommit(transaction) {
225
242
  return async (work) => {
226
243
  let doomed = false;
@@ -238,7 +255,7 @@ function failingCommit(transaction) {
238
255
  return result;
239
256
  };
240
257
  }
241
- export async function createCorpusFramework(contractHash) {
258
+ export function corpusConfiguration(contractHash) {
242
259
  const fake = createFakeAdapter({
243
260
  model: contractHash === CORPUS_NONE_CLIENT_CONTRACT_HASH
244
261
  ? { ...CORPUS_MODEL, transactions: "none" }
@@ -251,12 +268,25 @@ export async function createCorpusFramework(contractHash) {
251
268
  ? {}
252
269
  : { transaction: failingCommit(fake.transaction) }),
253
270
  });
271
+ return {
272
+ config: {
273
+ api: CORPUS_ENTRYPOINT,
274
+ adapter,
275
+ resources: CORPUS_RESOURCES,
276
+ application: CORPUS_APPLICATION_CONFIG,
277
+ client: CORPUS_CLIENT_CONFIG,
278
+ ...(contractHash === CORPUS_ACCESS_CLIENT_CONTRACT_HASH
279
+ ? { access: CORPUS_ACCESS }
280
+ : {}),
281
+ },
282
+ adapterCalls: () => adapter.operations.length,
283
+ };
284
+ }
285
+ export async function createCorpusFramework(contractHash, prebuilt) {
286
+ const { config, adapterCalls } = corpusConfiguration(contractHash);
254
287
  const framework = await createFramework({
255
- api: CORPUS_ENTRYPOINT,
256
- adapter,
257
- resources: CORPUS_RESOURCES,
258
- application: CORPUS_APPLICATION_CONFIG,
259
- client: CORPUS_CLIENT_CONFIG,
288
+ ...config,
289
+ ...(prebuilt === undefined ? {} : { prebuilt }),
260
290
  });
261
- return { framework, adapterCalls: () => adapter.operations.length };
291
+ return { framework, adapterCalls };
262
292
  }
@@ -2,7 +2,7 @@ import type { AvProtocolDriver } from "./protocol-driver.js";
2
2
  /**
3
3
  * The protocol hosted in process, with no HTTP stack: `/_contract` goes to
4
4
  * `protocol.encodeContract`, `/_transactions` to `protocol.handleTransaction`,
5
- * every other request to `protocol.handleOperation`, and the answer is written
6
- * back as it is.
5
+ * `/_access/can` to `protocol.handleCan`, every other request to
6
+ * `protocol.handleOperation`, and the answer is written back as it is.
7
7
  */
8
8
  export declare const inProcessDriver: AvProtocolDriver;
@@ -8,6 +8,8 @@ export const inProcessDriver = async (framework) => {
8
8
  return protocol.encodeContract(request);
9
9
  case "/_transactions":
10
10
  return protocol.handleTransaction(request);
11
+ case "/_access/can":
12
+ return protocol.handleCan(request);
11
13
  default:
12
14
  return protocol.handleOperation(request);
13
15
  }
@@ -2,7 +2,8 @@ import type { AvProtocolDriver } from "./protocol-driver.js";
2
2
  /**
3
3
  * The protocol hosted in process as a host that mounts one route per
4
4
  * `protocol.surface()` entry (each operation on `handleOperation`,
5
- * `/_transactions` on `handleTransaction`, `/_contract` on `encodeContract`,
5
+ * `/_transactions` on `handleTransaction`, `/_access/can` on `handleCan`,
6
+ * `/_contract` on `encodeContract`,
6
7
  * matched by method and path) and uses `protocol.answerAbsent` as the fallback
7
8
  * for everything it did not mount. `undefined` from the fallback is a path
8
9
  * outside the protocol, which this host answers with its own bodiless 404.
@@ -14,6 +14,8 @@ export const perRouteDriver = async (framework) => {
14
14
  return protocol.handleOperation(request);
15
15
  case "transactions":
16
16
  return protocol.handleTransaction(request);
17
+ case "can":
18
+ return protocol.handleCan(request);
17
19
  case "contract":
18
20
  return protocol.encodeContract(request);
19
21
  default:
@@ -17,7 +17,9 @@ export declare const AvProtocolCorpus: {
17
17
  * pure function of the operation it is handed. `contractHash` picks which
18
18
  * corpus ClientContract it serves, as a row's `Aventara-Contract-Hash` does:
19
19
  * the corpus's `transactions: "none"` contract for that contract's hash (the
20
- * `/_transactions` absence rows send it), the main one for anything else.
20
+ * `/_transactions` absence rows send it), the one with the framework's
21
+ * `access` option for its hash (the `/_access/can` rows send it), the main one
22
+ * for anything else.
21
23
  */
22
24
  readonly framework: (contractHash?: string) => Promise<AvFramework>;
23
25
  /** Where the corpus Framework is mounted; every row's `path` is relative to it. */
@@ -1,4 +1,4 @@
1
- import { CORPUS_AUTHOR, CORPUS_CLIENT_CONTRACT_DOCUMENT, CORPUS_CLIENT_CONTRACT_HASH, CORPUS_NOBODY, CORPUS_NONE_CLIENT_CONTRACT_HASH, CORPUS_TRIGGER, } from "./corpus-contract.fixture.js";
1
+ import { CORPUS_ACCESS_CLIENT_CONTRACT_HASH, CORPUS_AUTHOR, CORPUS_CLIENT_CONTRACT_DOCUMENT, CORPUS_CLIENT_CONTRACT_HASH, CORPUS_NOBODY, CORPUS_NONE_CLIENT_CONTRACT_HASH, CORPUS_TRIGGER, } from "./corpus-contract.fixture.js";
2
2
  const OPERATION_REQUEST = {
3
3
  method: "POST",
4
4
  path: "/_resources/authors/find/many",
@@ -837,6 +837,146 @@ const CORRELATION = [
837
837
  ["an id with a space", "a b"],
838
838
  ].map(([what, id]) => answered(`correlation: ${what} is not adopted, and never refused → 200 A1000`, corpusRequest("find/many", {}, id), 200, 1, { data: [CORPUS_AUTHOR], code: "A1000", cause: null }, { "Content-Type": "application/json" })),
839
839
  ];
840
+ const canRequest = (requestId, questions, overrides = {}) => {
841
+ const base = corpusRequest("", { questions }, requestId);
842
+ return {
843
+ ...base,
844
+ path: "/_access/can",
845
+ headers: {
846
+ ...base.headers,
847
+ "Aventara-Contract-Hash": CORPUS_ACCESS_CLIENT_CONTRACT_HASH,
848
+ },
849
+ ...overrides,
850
+ };
851
+ };
852
+ const AUTHOR_ROW = { where: { id: CORPUS_AUTHOR.id } };
853
+ const QUESTIONS_INVALID = "Operation arguments failed framework validation.";
854
+ const ACCESS_QUESTIONS = [
855
+ answered("can: three questions in one request, one answer each → 200 A1000", canRequest("corpus-can-three", [
856
+ { resource: "authors", action: "update", ...AUTHOR_ROW },
857
+ { resource: "authors", action: "delete", ...AUTHOR_ROW },
858
+ { resource: "authors", action: "read" },
859
+ ]), 200, 1, { data: [true, false, true], code: "A1000", cause: null }),
860
+ answered("can: a row that does not exist answers false, never A2003", canRequest("corpus-can-missing", [
861
+ {
862
+ resource: "authors",
863
+ action: "update",
864
+ where: { id: CORPUS_NOBODY },
865
+ },
866
+ ]), 200, 1, { data: [false], code: "A1000", cause: null }),
867
+ answered("can: an operation the client is not offered answers false", canRequest("corpus-can-unoffered", [
868
+ { resource: "secrets", action: "read" },
869
+ { resource: "samples", action: "delete" },
870
+ ]), 200, 0, { data: [false, false], code: "A1000", cause: null }),
871
+ answered("can: an AvError the engine throws answers false", canRequest("corpus-can-engine-refuses", [
872
+ { resource: "books", action: "read" },
873
+ { resource: "authors", action: "read" },
874
+ ]), 200, 0, { data: [false, true], code: "A1000", cause: null }),
875
+ answered("can: no questions, no answers → 200 A1000", canRequest("corpus-can-none", []), 200, 0, { data: [], code: "A1000", cause: null }),
876
+ absent('/_access/can without access → 404 A2002 at ["questions"]', {
877
+ ...canRequest("corpus-absent-can", []),
878
+ headers: {
879
+ ...canRequest("corpus-absent-can", []).headers,
880
+ "Aventara-Contract-Hash": CORPUS_CLIENT_CONTRACT_HASH,
881
+ },
882
+ }, 404, "A2002", {
883
+ message: "Access questions are not available on the active Contract.",
884
+ issues: [
885
+ {
886
+ code: "V1006",
887
+ path: ["questions"],
888
+ message: "Access questions are not available on the active Contract.",
889
+ },
890
+ ],
891
+ }),
892
+ refused("method: GET on /_access/can → 405 A2012 with Allow: POST", canRequest("corpus-can-get", [], { method: "GET" }), 405, "A2012", "The HTTP method is not allowed on this framework route.", { Allow: "POST" }),
893
+ answered("can: an unknown and a client-hidden Resource → 404 A2001 for the batch", canRequest("corpus-can-unknown", [
894
+ { resource: "authors", action: "read" },
895
+ { resource: "nope", action: "read" },
896
+ { resource: "hiddenRes", action: "read" },
897
+ ]), 404, 0, {
898
+ data: null,
899
+ code: "A2001",
900
+ cause: {
901
+ message: "The requested Resource is not available.",
902
+ issues: [
903
+ {
904
+ code: "V1005",
905
+ path: ["questions", 1, "resource"],
906
+ message: 'Resource "nope" is not available in the active Contract.',
907
+ },
908
+ {
909
+ code: "V1005",
910
+ path: ["questions", 2, "resource"],
911
+ message: 'Resource "hiddenRes" is not available in the active Contract.',
912
+ },
913
+ ],
914
+ },
915
+ }),
916
+ answered('can: a malformed question → 422 A2004 at ["questions", i, …]', canRequest("corpus-can-malformed", [
917
+ { resource: "authors", action: "refund" },
918
+ { resource: "authors", action: "read", where: { name: "Ada" } },
919
+ { resource: "authors", action: "create", ...AUTHOR_ROW },
920
+ ]), 422, 0, {
921
+ data: null,
922
+ code: "A2004",
923
+ cause: {
924
+ message: QUESTIONS_INVALID,
925
+ issues: [
926
+ {
927
+ code: "V1002",
928
+ path: ["questions", 0, "action"],
929
+ message: 'action must be one of "read", "create", "update" or "delete".',
930
+ },
931
+ {
932
+ code: "V1007",
933
+ path: ["questions", 1, "where"],
934
+ message: 'Unique selector must exactly match one active identifier on Resource "authors".',
935
+ },
936
+ {
937
+ code: "V1001",
938
+ path: ["questions", 2, "where"],
939
+ message: "A create question names no row: it takes no where.",
940
+ },
941
+ ],
942
+ },
943
+ }),
944
+ answered("can: more questions than maxListLimit → 422 A2009", canRequest("corpus-can-over-limit", Array.from({ length: 251 }, () => ({
945
+ resource: "authors",
946
+ action: "read",
947
+ }))), 422, 0, {
948
+ data: null,
949
+ code: "A2009",
950
+ cause: {
951
+ message: QUESTIONS_INVALID,
952
+ issues: [
953
+ {
954
+ code: "V1014",
955
+ path: ["questions"],
956
+ message: "Question count exceeds maxListLimit (250).",
957
+ },
958
+ ],
959
+ },
960
+ }),
961
+ answered("can: the engine throws → 500 A3000", canRequest("corpus-can-engine-throws", [
962
+ { resource: "samples", action: "read" },
963
+ ]), 500, 0, {
964
+ data: null,
965
+ code: "A3000",
966
+ cause: { message: "Internal framework error." },
967
+ }),
968
+ answered("can: the Adapter fails reading the row → 500 A3001", canRequest("corpus-can-adapter-throws", [
969
+ {
970
+ resource: "authors",
971
+ action: "update",
972
+ where: { id: CORPUS_TRIGGER.adapterThrows },
973
+ },
974
+ ]), 500, 1, {
975
+ data: null,
976
+ code: "A3001",
977
+ cause: { message: "Adapter execution failed." },
978
+ }),
979
+ ];
840
980
  export const AvProtocolFixtures = [
841
981
  ...CONTRACT_DISCOVERY,
842
982
  ...SUCCESS_STATUSES,
@@ -849,6 +989,7 @@ export const AvProtocolFixtures = [
849
989
  ...ABSENCE,
850
990
  ...TRANSACTIONS,
851
991
  ...TRANSACTION_REFERENCES,
992
+ ...ACCESS_QUESTIONS,
852
993
  ...INTERNAL,
853
994
  ...CONFLICT,
854
995
  ...WIRE_SCALARS,
@@ -4,7 +4,7 @@ import type { AvProtocolFixture } from "./protocol-fixture.js";
4
4
  * its bytes: `prefix + repeat × times + suffix`. The one oversized-body row
5
5
  * would otherwise be a megabyte of `x`.
6
6
  */
7
- export type ProtocolFixtureContentRecipe = {
7
+ type ProtocolFixtureContentRecipe = {
8
8
  readonly prefix?: string;
9
9
  readonly repeat: string;
10
10
  readonly times: number;
@@ -41,3 +41,4 @@ export declare function expandProtocolFixtureRow(row: ProtocolFixtureJsonRow): A
41
41
  * in corpus order, so a change to the corpus is a change to its own lines.
42
42
  */
43
43
  export declare function protocolFixturesJson(): Promise<string>;
44
+ export {};
@@ -1,6 +1,6 @@
1
1
  import { AVENTARA_PROTOCOL_VERSION } from "@aventara/core/internal";
2
2
  import { AvProtocol } from "@aventara/core/protocol";
3
- import { CORPUS_CLIENT_CONTRACT_HASH, CORPUS_ENTRYPOINT, CORPUS_NONE_CLIENT_CONTRACT_HASH, createCorpusFramework, } from "./corpus-contract.fixture.js";
3
+ import { CORPUS_ACCESS_CLIENT_CONTRACT_HASH, CORPUS_CLIENT_CONTRACT_HASH, CORPUS_ENTRYPOINT, CORPUS_NONE_CLIENT_CONTRACT_HASH, createCorpusFramework, } from "./corpus-contract.fixture.js";
4
4
  import { AvProtocolFixtures } from "./protocol-fixtures.js";
5
5
  const RECIPE_MINIMUM = 1024;
6
6
  function recipeOf(text) {
@@ -78,6 +78,10 @@ export async function protocolFixturesJson() {
78
78
  hash: CORPUS_NONE_CLIENT_CONTRACT_HASH,
79
79
  document: await contractDocument(CORPUS_NONE_CLIENT_CONTRACT_HASH),
80
80
  },
81
+ {
82
+ hash: CORPUS_ACCESS_CLIENT_CONTRACT_HASH,
83
+ document: await contractDocument(CORPUS_ACCESS_CLIENT_CONTRACT_HASH),
84
+ },
81
85
  ];
82
86
  const head = JSON.stringify({
83
87
  protocolVersion: AVENTARA_PROTOCOL_VERSION,
@@ -1,6 +1,7 @@
1
1
  {"protocolVersion":1,"entrypoint":"/api","clientContractHash":"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307","contracts":[
2
2
  {"hash":"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307","document":"{\"enums\":{},\"limits\":{\"maxBooleanNodes\":50,\"maxJsonDepth\":64,\"maxListLimit\":250,\"maxNestingDepth\":12,\"maxRequestBytes\":1048576,\"maxTransactionOperations\":20},\"protocol\":{\"hash\":\"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307\",\"version\":1},\"resources\":{\"authors\":{\"fields\":{\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"name\":{\"capabilities\":{\"create\":[],\"filter\":[\"equals\"],\"select\":true,\"update\":[]},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"create\":{\"count\":true,\"many\":true,\"one\":true},\"delete\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"find\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"update\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"upsert\":{\"unique\":true}}},\"books\":{\"fields\":{\"authorId\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"label\":{\"capabilities\":{\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[\"COMPUTED_ON_READ\",\"VIRTUAL\"],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"find\":{\"many\":true}}},\"samples\":{\"fields\":{\"amount\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"decimal\"}},\"at\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"datetime\"}},\"blob\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"bytes\"}},\"count\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"bigint\"}},\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"create\":{\"one\":true},\"find\":{\"unique\":true}}},\"secrets\":{\"fields\":{\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{}}},\"scalars\":{\"bigint\":{\"builtin\":true},\"bytes\":{\"builtin\":true},\"datetime\":{\"builtin\":true},\"decimal\":{\"builtin\":true},\"string\":{\"builtin\":true}},\"transactions\":\"interactive\"}"},
3
- {"hash":"sha256:5e99809294a2aae922b635e9a44b464b1b6e03359a54d30420292c62676a7ce5","document":"{\"enums\":{},\"limits\":{\"maxBooleanNodes\":50,\"maxJsonDepth\":64,\"maxListLimit\":250,\"maxNestingDepth\":12,\"maxRequestBytes\":1048576,\"maxTransactionOperations\":20},\"protocol\":{\"hash\":\"sha256:5e99809294a2aae922b635e9a44b464b1b6e03359a54d30420292c62676a7ce5\",\"version\":1},\"resources\":{\"authors\":{\"fields\":{\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"name\":{\"capabilities\":{\"create\":[],\"filter\":[\"equals\"],\"select\":true,\"update\":[]},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"create\":{\"count\":true,\"many\":true,\"one\":true},\"delete\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"find\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"update\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"upsert\":{\"unique\":true}}},\"books\":{\"fields\":{\"authorId\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"label\":{\"capabilities\":{\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[\"COMPUTED_ON_READ\",\"VIRTUAL\"],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"find\":{\"many\":true}}},\"samples\":{\"fields\":{\"amount\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"decimal\"}},\"at\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"datetime\"}},\"blob\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"bytes\"}},\"count\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"bigint\"}},\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"create\":{\"one\":true},\"find\":{\"unique\":true}}},\"secrets\":{\"fields\":{\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{}}},\"scalars\":{\"bigint\":{\"builtin\":true},\"bytes\":{\"builtin\":true},\"datetime\":{\"builtin\":true},\"decimal\":{\"builtin\":true},\"string\":{\"builtin\":true}},\"transactions\":\"none\"}"}
3
+ {"hash":"sha256:5e99809294a2aae922b635e9a44b464b1b6e03359a54d30420292c62676a7ce5","document":"{\"enums\":{},\"limits\":{\"maxBooleanNodes\":50,\"maxJsonDepth\":64,\"maxListLimit\":250,\"maxNestingDepth\":12,\"maxRequestBytes\":1048576,\"maxTransactionOperations\":20},\"protocol\":{\"hash\":\"sha256:5e99809294a2aae922b635e9a44b464b1b6e03359a54d30420292c62676a7ce5\",\"version\":1},\"resources\":{\"authors\":{\"fields\":{\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"name\":{\"capabilities\":{\"create\":[],\"filter\":[\"equals\"],\"select\":true,\"update\":[]},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"create\":{\"count\":true,\"many\":true,\"one\":true},\"delete\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"find\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"update\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"upsert\":{\"unique\":true}}},\"books\":{\"fields\":{\"authorId\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"label\":{\"capabilities\":{\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[\"COMPUTED_ON_READ\",\"VIRTUAL\"],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"find\":{\"many\":true}}},\"samples\":{\"fields\":{\"amount\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"decimal\"}},\"at\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"datetime\"}},\"blob\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"bytes\"}},\"count\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"bigint\"}},\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"create\":{\"one\":true},\"find\":{\"unique\":true}}},\"secrets\":{\"fields\":{\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{}}},\"scalars\":{\"bigint\":{\"builtin\":true},\"bytes\":{\"builtin\":true},\"datetime\":{\"builtin\":true},\"decimal\":{\"builtin\":true},\"string\":{\"builtin\":true}},\"transactions\":\"none\"}"},
4
+ {"hash":"sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23","document":"{\"access\":{},\"enums\":{},\"limits\":{\"maxBooleanNodes\":50,\"maxJsonDepth\":64,\"maxListLimit\":250,\"maxNestingDepth\":12,\"maxRequestBytes\":1048576,\"maxTransactionOperations\":20},\"protocol\":{\"hash\":\"sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23\",\"version\":1},\"resources\":{\"authors\":{\"fields\":{\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"name\":{\"capabilities\":{\"create\":[],\"filter\":[\"equals\"],\"select\":true,\"update\":[]},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"create\":{\"count\":true,\"many\":true,\"one\":true},\"delete\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"find\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"update\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"upsert\":{\"unique\":true}}},\"books\":{\"fields\":{\"authorId\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"label\":{\"capabilities\":{\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[\"COMPUTED_ON_READ\",\"VIRTUAL\"],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"find\":{\"many\":true}}},\"samples\":{\"fields\":{\"amount\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"decimal\"}},\"at\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"datetime\"}},\"blob\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"bytes\"}},\"count\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"bigint\"}},\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"create\":{\"one\":true},\"find\":{\"unique\":true}}},\"secrets\":{\"fields\":{\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{}}},\"scalars\":{\"bigint\":{\"builtin\":true},\"bytes\":{\"builtin\":true},\"datetime\":{\"builtin\":true},\"decimal\":{\"builtin\":true},\"string\":{\"builtin\":true}},\"transactions\":\"interactive\"}"}
4
5
  ],"rows":[
5
6
  {"label":"contract: GET → 200 with the JCS bytes, ETag and no-cache","request":{"method":"GET","path":"/_contract","headers":{"Aventara-Request-Id":"corpus-contract"},"body":{"kind":"raw","content":""}},"server":{"status":200,"code":null,"adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-contract","ETag":"\"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307\"","Cache-Control":"no-cache"},"bodyBytes":"{\"enums\":{},\"limits\":{\"maxBooleanNodes\":50,\"maxJsonDepth\":64,\"maxListLimit\":250,\"maxNestingDepth\":12,\"maxRequestBytes\":1048576,\"maxTransactionOperations\":20},\"protocol\":{\"hash\":\"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307\",\"version\":1},\"resources\":{\"authors\":{\"fields\":{\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"name\":{\"capabilities\":{\"create\":[],\"filter\":[\"equals\"],\"select\":true,\"update\":[]},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"create\":{\"count\":true,\"many\":true,\"one\":true},\"delete\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"find\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"update\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"upsert\":{\"unique\":true}}},\"books\":{\"fields\":{\"authorId\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"label\":{\"capabilities\":{\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[\"COMPUTED_ON_READ\",\"VIRTUAL\"],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"find\":{\"many\":true}}},\"samples\":{\"fields\":{\"amount\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"decimal\"}},\"at\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"datetime\"}},\"blob\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"bytes\"}},\"count\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"bigint\"}},\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"create\":{\"one\":true},\"find\":{\"unique\":true}}},\"secrets\":{\"fields\":{\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{}}},\"scalars\":{\"bigint\":{\"builtin\":true},\"bytes\":{\"builtin\":true},\"datetime\":{\"builtin\":true},\"decimal\":{\"builtin\":true},\"string\":{\"builtin\":true}},\"transactions\":\"interactive\"}"},"client":{"outcome":"resolve"}},
6
7
  {"label":"contract: no identity header is required, nor judged when sent","request":{"method":"GET","path":"/_contract","headers":{"Aventara-Request-Id":"corpus-contract-identity","Aventara-Protocol-Version":"2","Aventara-Contract-Hash":"sha256:0000000000000000000000000000000000000000000000000000000000000000"},"body":{"kind":"raw","content":""}},"server":{"status":200,"code":null,"adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-contract-identity","ETag":"\"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307\"","Cache-Control":"no-cache"},"bodyBytes":"{\"enums\":{},\"limits\":{\"maxBooleanNodes\":50,\"maxJsonDepth\":64,\"maxListLimit\":250,\"maxNestingDepth\":12,\"maxRequestBytes\":1048576,\"maxTransactionOperations\":20},\"protocol\":{\"hash\":\"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307\",\"version\":1},\"resources\":{\"authors\":{\"fields\":{\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"name\":{\"capabilities\":{\"create\":[],\"filter\":[\"equals\"],\"select\":true,\"update\":[]},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"create\":{\"count\":true,\"many\":true,\"one\":true},\"delete\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"find\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"update\":{\"count\":true,\"first\":true,\"many\":true,\"unique\":true},\"upsert\":{\"unique\":true}}},\"books\":{\"fields\":{\"authorId\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}},\"label\":{\"capabilities\":{\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[\"COMPUTED_ON_READ\",\"VIRTUAL\"],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"find\":{\"many\":true}}},\"samples\":{\"fields\":{\"amount\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"decimal\"}},\"at\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"datetime\"}},\"blob\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"bytes\"}},\"count\":{\"capabilities\":{\"create\":[],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"bigint\"}},\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{\"create\":{\"one\":true},\"find\":{\"unique\":true}}},\"secrets\":{\"fields\":{\"id\":{\"capabilities\":{\"filter\":[\"equals\"],\"select\":true},\"kind\":\"scalar\",\"lifecycle\":[],\"list\":false,\"nullable\":false,\"type\":{\"scalar\":\"string\"}}},\"identifiers\":[[\"id\"]],\"operations\":{}}},\"scalars\":{\"bigint\":{\"builtin\":true},\"bytes\":{\"builtin\":true},\"datetime\":{\"builtin\":true},\"decimal\":{\"builtin\":true},\"string\":{\"builtin\":true}},\"transactions\":\"interactive\"}"},"client":{"outcome":"resolve"}},
@@ -88,6 +89,18 @@
88
89
  {"label":"method: GET on /_transactions → 405 A2012 with Allow: POST","request":{"method":"GET","path":"/_transactions","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307","Aventara-Request-Id":"corpus-tx-get"},"body":{"kind":"raw","content":"{\"operations\":[{\"resource\":\"authors\",\"family\":\"find\",\"variant\":\"many\",\"args\":{},\"fingerprint\":\"fp1:1aLMnUbKspahv3fbsV7pKg\"}]}"}},"server":{"status":405,"code":"A2012","causeKeys":["message"],"adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-tx-get","Allow":"POST"},"bodyBytes":"{\"data\":null,\"code\":\"A2012\",\"cause\":{\"message\":\"The HTTP method is not allowed on this framework route.\"}}"},"client":{"outcome":"framework-error","code":"A2012"}},
89
90
  {"label":"transaction — a unique where and a filter reference an earlier step's result → 200 A1009","request":{"method":"POST","path":"/_transactions","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307","Aventara-Request-Id":"corpus-tx-ref-where"},"body":{"kind":"raw","content":"{\"operations\":[{\"resource\":\"authors\",\"family\":\"create\",\"variant\":\"one\",\"args\":{\"data\":{\"name\":\"Ada\"},\"select\":[\"id\"]},\"fingerprint\":\"fp1:aMKNYrUwcifOeY8ZYk4pow\"},{\"resource\":\"authors\",\"family\":\"find\",\"variant\":\"unique\",\"args\":{\"where\":{\"id\":{\"$ref\":{\"operation\":0,\"fingerprint\":\"fp1:aMKNYrUwcifOeY8ZYk4pow\",\"path\":[\"id\"]}}}},\"fingerprint\":\"fp1:hKbxzChGakplMZvnpEa1_w\"},{\"resource\":\"authors\",\"family\":\"find\",\"variant\":\"many\",\"args\":{\"where\":{\"OR\":[{\"id\":{\"equals\":{\"$ref\":{\"operation\":0,\"fingerprint\":\"fp1:aMKNYrUwcifOeY8ZYk4pow\",\"path\":[\"id\"]}}}}]}},\"fingerprint\":\"fp1:4LK9l_j8Skjk4iU_wSoRzQ\"}]}"}},"server":{"status":200,"code":"A1009","adapterCalls":3,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-tx-ref-where"},"bodyBytes":"{\"data\":[{\"id\":\"a1\"},{\"id\":\"a1\",\"name\":\"Ada\"},[{\"id\":\"a1\",\"name\":\"Ada\"}]],\"code\":\"A1009\",\"cause\":null}"},"client":{"outcome":"resolve"}},
90
91
  {"label":"argument: a plan reference in a where to an operation index no earlier step has → 422 A2007 / V1016","request":{"method":"POST","path":"/_transactions","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307","Aventara-Request-Id":"corpus-arg-ref-where-index"},"body":{"kind":"raw","content":"{\"operations\":[{\"resource\":\"authors\",\"family\":\"create\",\"variant\":\"one\",\"args\":{\"data\":{\"name\":\"Ada\"},\"select\":[\"id\"]},\"fingerprint\":\"fp1:aMKNYrUwcifOeY8ZYk4pow\"},{\"resource\":\"authors\",\"family\":\"find\",\"variant\":\"unique\",\"args\":{\"where\":{\"id\":{\"$ref\":{\"operation\":5,\"fingerprint\":\"fp1:aMKNYrUwcifOeY8ZYk4pow\",\"path\":[\"id\"]}}}},\"fingerprint\":\"fp1:VS6Zk71avpYzuC90z8qzrQ\"}]}"}},"server":{"status":422,"code":"A2007","causeKeys":["issues","message","operation"],"issues":[{"code":"V1016","path":["operations",1,"args","where","id","$ref","operation"]}],"adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-arg-ref-where-index"},"bodyBytes":"{\"data\":null,\"code\":\"A2007\",\"cause\":{\"message\":\"Operation arguments failed framework validation.\",\"issues\":[{\"code\":\"V1016\",\"path\":[\"operations\",1,\"args\",\"where\",\"id\",\"$ref\",\"operation\"],\"message\":\"Transaction reference operation index is invalid.\"}],\"operation\":1}}"},"client":{"outcome":"framework-error","code":"A2007"}},
92
+ {"label":"can: three questions in one request, one answer each → 200 A1000","request":{"method":"POST","path":"/_access/can","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23","Aventara-Request-Id":"corpus-can-three"},"body":{"kind":"raw","content":"{\"questions\":[{\"resource\":\"authors\",\"action\":\"update\",\"where\":{\"id\":\"a1\"}},{\"resource\":\"authors\",\"action\":\"delete\",\"where\":{\"id\":\"a1\"}},{\"resource\":\"authors\",\"action\":\"read\"}]}"}},"server":{"status":200,"code":"A1000","adapterCalls":1,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-can-three"},"bodyBytes":"{\"data\":[true,false,true],\"code\":\"A1000\",\"cause\":null}"},"client":{"outcome":"resolve"}},
93
+ {"label":"can: a row that does not exist answers false, never A2003","request":{"method":"POST","path":"/_access/can","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23","Aventara-Request-Id":"corpus-can-missing"},"body":{"kind":"raw","content":"{\"questions\":[{\"resource\":\"authors\",\"action\":\"update\",\"where\":{\"id\":\"nobody\"}}]}"}},"server":{"status":200,"code":"A1000","adapterCalls":1,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-can-missing"},"bodyBytes":"{\"data\":[false],\"code\":\"A1000\",\"cause\":null}"},"client":{"outcome":"resolve"}},
94
+ {"label":"can: an operation the client is not offered answers false","request":{"method":"POST","path":"/_access/can","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23","Aventara-Request-Id":"corpus-can-unoffered"},"body":{"kind":"raw","content":"{\"questions\":[{\"resource\":\"secrets\",\"action\":\"read\"},{\"resource\":\"samples\",\"action\":\"delete\"}]}"}},"server":{"status":200,"code":"A1000","adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-can-unoffered"},"bodyBytes":"{\"data\":[false,false],\"code\":\"A1000\",\"cause\":null}"},"client":{"outcome":"resolve"}},
95
+ {"label":"can: an AvError the engine throws answers false","request":{"method":"POST","path":"/_access/can","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23","Aventara-Request-Id":"corpus-can-engine-refuses"},"body":{"kind":"raw","content":"{\"questions\":[{\"resource\":\"books\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"}]}"}},"server":{"status":200,"code":"A1000","adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-can-engine-refuses"},"bodyBytes":"{\"data\":[false,true],\"code\":\"A1000\",\"cause\":null}"},"client":{"outcome":"resolve"}},
96
+ {"label":"can: no questions, no answers → 200 A1000","request":{"method":"POST","path":"/_access/can","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23","Aventara-Request-Id":"corpus-can-none"},"body":{"kind":"raw","content":"{\"questions\":[]}"}},"server":{"status":200,"code":"A1000","adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-can-none"},"bodyBytes":"{\"data\":[],\"code\":\"A1000\",\"cause\":null}"},"client":{"outcome":"resolve"}},
97
+ {"label":"absent: /_access/can without access → 404 A2002 at [\"questions\"]","request":{"method":"POST","path":"/_access/can","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307","Aventara-Request-Id":"corpus-absent-can"},"body":{"kind":"raw","content":"{\"questions\":[]}"}},"server":{"status":404,"code":"A2002","causeKeys":["issues","message"],"issues":[{"code":"V1006","path":["questions"]}],"adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-absent-can"},"bodyBytes":"{\"data\":null,\"code\":\"A2002\",\"cause\":{\"message\":\"Access questions are not available on the active Contract.\",\"issues\":[{\"code\":\"V1006\",\"path\":[\"questions\"],\"message\":\"Access questions are not available on the active Contract.\"}]}}"},"client":{"outcome":"framework-error","code":"A2002"}},
98
+ {"label":"method: GET on /_access/can → 405 A2012 with Allow: POST","request":{"method":"GET","path":"/_access/can","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23","Aventara-Request-Id":"corpus-can-get"},"body":{"kind":"raw","content":"{\"questions\":[]}"}},"server":{"status":405,"code":"A2012","causeKeys":["message"],"adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-can-get","Allow":"POST"},"bodyBytes":"{\"data\":null,\"code\":\"A2012\",\"cause\":{\"message\":\"The HTTP method is not allowed on this framework route.\"}}"},"client":{"outcome":"framework-error","code":"A2012"}},
99
+ {"label":"can: an unknown and a client-hidden Resource → 404 A2001 for the batch","request":{"method":"POST","path":"/_access/can","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23","Aventara-Request-Id":"corpus-can-unknown"},"body":{"kind":"raw","content":"{\"questions\":[{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"nope\",\"action\":\"read\"},{\"resource\":\"hiddenRes\",\"action\":\"read\"}]}"}},"server":{"status":404,"code":"A2001","causeKeys":["issues","message"],"issues":[{"code":"V1005","path":["questions",1,"resource"]},{"code":"V1005","path":["questions",2,"resource"]}],"adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-can-unknown"},"bodyBytes":"{\"data\":null,\"code\":\"A2001\",\"cause\":{\"message\":\"The requested Resource is not available.\",\"issues\":[{\"code\":\"V1005\",\"path\":[\"questions\",1,\"resource\"],\"message\":\"Resource \\\"nope\\\" is not available in the active Contract.\"},{\"code\":\"V1005\",\"path\":[\"questions\",2,\"resource\"],\"message\":\"Resource \\\"hiddenRes\\\" is not available in the active Contract.\"}]}}"},"client":{"outcome":"framework-error","code":"A2001"}},
100
+ {"label":"can: a malformed question → 422 A2004 at [\"questions\", i, …]","request":{"method":"POST","path":"/_access/can","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23","Aventara-Request-Id":"corpus-can-malformed"},"body":{"kind":"raw","content":"{\"questions\":[{\"resource\":\"authors\",\"action\":\"refund\"},{\"resource\":\"authors\",\"action\":\"read\",\"where\":{\"name\":\"Ada\"}},{\"resource\":\"authors\",\"action\":\"create\",\"where\":{\"id\":\"a1\"}}]}"}},"server":{"status":422,"code":"A2004","causeKeys":["issues","message"],"issues":[{"code":"V1002","path":["questions",0,"action"]},{"code":"V1007","path":["questions",1,"where"]},{"code":"V1001","path":["questions",2,"where"]}],"adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-can-malformed"},"bodyBytes":"{\"data\":null,\"code\":\"A2004\",\"cause\":{\"message\":\"Operation arguments failed framework validation.\",\"issues\":[{\"code\":\"V1002\",\"path\":[\"questions\",0,\"action\"],\"message\":\"action must be one of \\\"read\\\", \\\"create\\\", \\\"update\\\" or \\\"delete\\\".\"},{\"code\":\"V1007\",\"path\":[\"questions\",1,\"where\"],\"message\":\"Unique selector must exactly match one active identifier on Resource \\\"authors\\\".\"},{\"code\":\"V1001\",\"path\":[\"questions\",2,\"where\"],\"message\":\"A create question names no row: it takes no where.\"}]}}"},"client":{"outcome":"framework-error","code":"A2004"}},
101
+ {"label":"can: more questions than maxListLimit → 422 A2009","request":{"method":"POST","path":"/_access/can","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23","Aventara-Request-Id":"corpus-can-over-limit"},"body":{"kind":"raw","content":"{\"questions\":[{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"},{\"resource\":\"authors\",\"action\":\"read\"}]}"}},"server":{"status":422,"code":"A2009","causeKeys":["issues","message"],"issues":[{"code":"V1014","path":["questions"]}],"adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-can-over-limit"},"bodyBytes":"{\"data\":null,\"code\":\"A2009\",\"cause\":{\"message\":\"Operation arguments failed framework validation.\",\"issues\":[{\"code\":\"V1014\",\"path\":[\"questions\"],\"message\":\"Question count exceeds maxListLimit (250).\"}]}}"},"client":{"outcome":"framework-error","code":"A2009"}},
102
+ {"label":"can: the engine throws → 500 A3000","request":{"method":"POST","path":"/_access/can","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23","Aventara-Request-Id":"corpus-can-engine-throws"},"body":{"kind":"raw","content":"{\"questions\":[{\"resource\":\"samples\",\"action\":\"read\"}]}"}},"server":{"status":500,"code":"A3000","causeKeys":["message"],"adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-can-engine-throws"},"bodyBytes":"{\"data\":null,\"code\":\"A3000\",\"cause\":{\"message\":\"Internal framework error.\"}}"},"client":{"outcome":"framework-error","code":"A3000"}},
103
+ {"label":"can: the Adapter fails reading the row → 500 A3001","request":{"method":"POST","path":"/_access/can","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23","Aventara-Request-Id":"corpus-can-adapter-throws"},"body":{"kind":"raw","content":"{\"questions\":[{\"resource\":\"authors\",\"action\":\"update\",\"where\":{\"id\":\"A3001\"}}]}"}},"server":{"status":500,"code":"A3001","causeKeys":["message"],"adapterCalls":1,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-can-adapter-throws"},"bodyBytes":"{\"data\":null,\"code\":\"A3001\",\"cause\":{\"message\":\"Adapter execution failed.\"}}"},"client":{"outcome":"framework-error","code":"A3001"}},
91
104
  {"label":"internal: a guard that throws → 500 A3000","request":{"method":"POST","path":"/_resources/authors/find/unique","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307","Aventara-Request-Id":"corpus-internal-a3000"},"body":{"kind":"raw","content":"{\"where\":{\"id\":\"A3000\"}}"}},"server":{"status":500,"code":"A3000","causeKeys":["message"],"adapterCalls":0,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-internal-a3000"},"bodyBytes":"{\"data\":null,\"code\":\"A3000\",\"cause\":{\"message\":\"Internal framework error.\"}}"},"client":{"outcome":"framework-error","code":"A3000"}},
92
105
  {"label":"internal: an Adapter that throws → 500 A3001","request":{"method":"POST","path":"/_resources/authors/find/unique","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307","Aventara-Request-Id":"corpus-internal-a3001"},"body":{"kind":"raw","content":"{\"where\":{\"id\":\"A3001\"}}"}},"server":{"status":500,"code":"A3001","causeKeys":["message"],"adapterCalls":1,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-internal-a3001"},"bodyBytes":"{\"data\":null,\"code\":\"A3001\",\"cause\":{\"message\":\"Adapter execution failed.\"}}"},"client":{"outcome":"framework-error","code":"A3001"}},
93
106
  {"label":"internal: a plan whose commit fails after the work → 500 A3002","request":{"method":"POST","path":"/_transactions","headers":{"Content-Type":"application/json","Aventara-Protocol-Version":"1","Aventara-Contract-Hash":"sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307","Aventara-Request-Id":"corpus-internal-a3002"},"body":{"kind":"raw","content":"{\"operations\":[{\"resource\":\"authors\",\"family\":\"update\",\"variant\":\"unique\",\"args\":{\"where\":{\"id\":\"A3002\"},\"data\":{\"name\":\"Ada\"}},\"fingerprint\":\"fp1:8gs-RmzsqGlD_FFmk6dlQA\"}]}"}},"server":{"status":500,"code":"A3002","causeKeys":["message"],"adapterCalls":1,"responseHeaders":{"Content-Type":"application/json","Aventara-Request-Id":"corpus-internal-a3002"},"bodyBytes":"{\"data\":null,\"code\":\"A3002\",\"cause\":{\"message\":\"Transaction failed.\"}}"},"client":{"outcome":"framework-error","code":"A3002"}},
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@aventara/testing",
3
- "version": "1.0.0-rc.1",
3
+ "version": "1.0.0-rc.10",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "Conformance and extension testing utilities for Aventara.",
6
6
  "type": "module",
7
7
  "engines": {
8
- "node": "^22.18.0 || >=24.2.0"
8
+ "node": "^22.23.4 || >=24.22.1"
9
9
  },
10
10
  "main": "./dist/index.js",
11
11
  "types": "./dist/index.d.ts",
@@ -24,7 +24,7 @@
24
24
  "CHANGELOG.md"
25
25
  ],
26
26
  "dependencies": {
27
- "@aventara/core": "1.0.0-rc.1"
27
+ "@aventara/core": "1.0.0-rc.10"
28
28
  },
29
29
  "publishConfig": {
30
30
  "access": "public"