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

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,35 @@
1
1
  # @aventara/testing
2
2
 
3
+ ## 1.0.0-rc.12
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [fdeee8a]
8
+ - @aventara/core@1.0.0-rc.12
9
+
10
+ ## 1.0.0-rc.11
11
+
12
+ ### Patch Changes
13
+
14
+ - 67551ca: The protocol corpus covers rc.11's Operation Sets and cached reads. `POST /_all` rows: a mix of reads and writes answered
15
+ `200 A1000` with each key's own envelope, hostile keys, the streamed NDJSON answer, and the whole-request refusals
16
+ (`limits.maxAll`, an empty set, a bad key or member, a stale hash, `GET`). Cached-read rows run against a fourth corpus
17
+ ClientContract with `cache` stages, named by their query's `v`: each `for` audience's headers, the compressed `q`,
18
+ `ETag` and `304`, the `no-store` refusals, and the `405`s. `runAvProtocolConformance` and `AvProtocolCorpus.framework`
19
+ pick a `GET` row's contract by its `v`, and `fixtures/protocol-v1.json` lists the fourth contract.
20
+ - 186bc29: The corpus Contracts' hashes and `fixtures/protocol-v1.json` move once, because every Client Contract's limits now
21
+ include `maxAll` and `maxAllConcurrency`.
22
+ - Updated dependencies [6197c08]
23
+ - Updated dependencies [e0e89c1]
24
+ - Updated dependencies [186bc29]
25
+ - Updated dependencies [33b5f83]
26
+ - Updated dependencies [6d8b589]
27
+ - Updated dependencies [11ece49]
28
+ - Updated dependencies [92fd093]
29
+ - Updated dependencies [e5e98e6]
30
+ - Updated dependencies [a05d970]
31
+ - @aventara/core@1.0.0-rc.11
32
+
3
33
  ## 1.0.0-rc.10
4
34
 
5
35
  ### Patch Changes
package/README.md CHANGED
@@ -36,8 +36,10 @@ const framework = await AvProtocolCorpus.framework();
36
36
  ```
37
37
 
38
38
  - `framework(contractHash?)`: a fresh corpus `AvFramework`, backed by an in-memory adapter whose answers every row
39
- states. Pass a row's `Aventara-Contract-Hash` to get the contract that row targets: a few rows target a second
40
- contract without transactions, and every other hash (a stale one included) gets the main contract.
39
+ states. Pass a row's `Aventara-Contract-Hash` to get the contract that row targets (a cached read's `GET` sends no
40
+ such header: pass its query's `v`). A few rows target a contract without transactions, the `/_access/can` rows one
41
+ with `access`, and the cached-read rows one with `cache` stages; every other hash (a stale one included) gets the
42
+ main contract.
41
43
  - `entrypoint`: where the corpus is mounted; every row's `path` is relative to it.
42
44
  - `clientContractHash`: the main ClientContract's hash. A client generated against it sends this hash, and
43
45
  `GET /_contract` names it.
@@ -63,8 +65,11 @@ or host written in another language can be held to the same answers:
63
65
  ```
64
66
 
65
67
  - `contracts`: each ClientContract a row targets: its hash and its exact `GET /_contract` bytes (`document`, a
66
- string). The first is the main contract, `clientContractHash`; a row targets the other by sending its hash.
67
- - `rows`: as `AvProtocolFixture` describes them. One body is too large to write out (one byte over the 1 MiB request
68
+ string). The first is the main contract, `clientContractHash`; a row targets another by sending its hash (a cached
69
+ read's `GET` as its query's `v`).
70
+ - `rows`: as `AvProtocolFixture` describes them. A cached read's `request` carries its `query` (without the `?`). A
71
+ streamed `POST /_all` answer (`Accept: application/x-ndjson`) is no envelope: its row's `code` is `null` and its
72
+ `bodyBytes` are the lines in order. One body is too large to write out (one byte over the 1 MiB request
68
73
  limit): its `request.body.content` is a recipe, `{ "prefix": "…", "repeat": "x", "times": 1048567, "suffix": "…" }`,
69
74
  standing for `prefix` + `repeat` repeated `times` times + `suffix`. Every other `content` is the body's text.
70
75
 
@@ -1,285 +1,5 @@
1
1
  import type { AvAdapterModel, AvContext, AvFramework, AvPrebuiltContracts } from "@aventara/core";
2
- import { AvDecimal } from "@aventara/core";
3
2
  import type { AvAdapterOperation } from "@aventara/core/internal";
4
- /**
5
- * The corpus's adapter model:
6
- *
7
- * - `authors`: every standard operation; its `secret` field is hidden at
8
- * client scope;
9
- * - `books`: references `authors`, and deleting an author cascades into it
10
- * ({@link CORPUS_REFERENTIAL_ACTIONS}; a plan's `V1019`); the client scope
11
- * defines a computed `label` the client alone sees ({@link CORPUS_RESOURCES});
12
- * - `secrets`: its one operation restricted away at client scope;
13
- * - `hiddenRes`: hidden at client scope;
14
- * - `samples`: one field of each scalar whose wire form is not its runtime
15
- * form (`bigint`, `datetime`, `decimal`, `bytes`).
16
- */
17
- export declare const CORPUS_MODEL: {
18
- readonly transactions: "interactive";
19
- readonly scalars: {
20
- readonly string: {
21
- readonly builtin: true;
22
- };
23
- readonly bigint: {
24
- readonly builtin: true;
25
- };
26
- readonly datetime: {
27
- readonly builtin: true;
28
- };
29
- readonly decimal: {
30
- readonly builtin: true;
31
- };
32
- readonly bytes: {
33
- readonly builtin: true;
34
- };
35
- };
36
- readonly enums: {};
37
- readonly resources: {
38
- readonly authors: {
39
- readonly fields: {
40
- readonly id: {
41
- readonly kind: "scalar";
42
- readonly type: {
43
- readonly scalar: "string";
44
- };
45
- readonly nullable: false;
46
- readonly list: false;
47
- readonly lifecycle: readonly [];
48
- readonly capabilities: {
49
- readonly select: true;
50
- readonly filter: readonly ["equals"];
51
- };
52
- };
53
- readonly name: {
54
- readonly capabilities: {
55
- readonly select: true;
56
- readonly filter: readonly ["equals"];
57
- readonly create: readonly [];
58
- readonly update: readonly [];
59
- };
60
- readonly kind: "scalar";
61
- readonly type: {
62
- readonly scalar: "string";
63
- };
64
- readonly nullable: false;
65
- readonly list: false;
66
- readonly lifecycle: readonly [];
67
- };
68
- readonly secret: {
69
- readonly kind: "scalar";
70
- readonly type: {
71
- readonly scalar: "string";
72
- };
73
- readonly nullable: false;
74
- readonly list: false;
75
- readonly lifecycle: readonly [];
76
- readonly capabilities: {
77
- readonly select: true;
78
- readonly filter: readonly ["equals"];
79
- };
80
- };
81
- };
82
- readonly identifiers: readonly [readonly ["id"]];
83
- readonly operations: {
84
- readonly find: {
85
- readonly first: true;
86
- readonly unique: true;
87
- readonly many: true;
88
- readonly count: true;
89
- };
90
- readonly create: {
91
- readonly one: true;
92
- readonly many: true;
93
- readonly count: true;
94
- };
95
- readonly update: {
96
- readonly first: true;
97
- readonly unique: true;
98
- readonly many: true;
99
- readonly count: true;
100
- };
101
- readonly delete: {
102
- readonly first: true;
103
- readonly unique: true;
104
- readonly many: true;
105
- readonly count: true;
106
- };
107
- readonly upsert: {
108
- readonly unique: true;
109
- };
110
- };
111
- };
112
- readonly books: {
113
- readonly fields: {
114
- readonly id: {
115
- readonly kind: "scalar";
116
- readonly type: {
117
- readonly scalar: "string";
118
- };
119
- readonly nullable: false;
120
- readonly list: false;
121
- readonly lifecycle: readonly [];
122
- readonly capabilities: {
123
- readonly select: true;
124
- readonly filter: readonly ["equals"];
125
- };
126
- };
127
- readonly authorId: {
128
- readonly kind: "scalar";
129
- readonly type: {
130
- readonly scalar: "string";
131
- };
132
- readonly nullable: false;
133
- readonly list: false;
134
- readonly lifecycle: readonly [];
135
- readonly capabilities: {
136
- readonly select: true;
137
- readonly filter: readonly ["equals"];
138
- };
139
- };
140
- };
141
- readonly identifiers: readonly [readonly ["id"]];
142
- readonly operations: {
143
- readonly find: {
144
- readonly many: true;
145
- };
146
- };
147
- };
148
- readonly secrets: {
149
- readonly fields: {
150
- readonly id: {
151
- readonly kind: "scalar";
152
- readonly type: {
153
- readonly scalar: "string";
154
- };
155
- readonly nullable: false;
156
- readonly list: false;
157
- readonly lifecycle: readonly [];
158
- readonly capabilities: {
159
- readonly select: true;
160
- readonly filter: readonly ["equals"];
161
- };
162
- };
163
- };
164
- readonly identifiers: readonly [readonly ["id"]];
165
- readonly operations: {
166
- readonly find: {
167
- readonly many: true;
168
- };
169
- };
170
- };
171
- readonly hiddenRes: {
172
- readonly fields: {
173
- readonly id: {
174
- readonly kind: "scalar";
175
- readonly type: {
176
- readonly scalar: "string";
177
- };
178
- readonly nullable: false;
179
- readonly list: false;
180
- readonly lifecycle: readonly [];
181
- readonly capabilities: {
182
- readonly select: true;
183
- readonly filter: readonly ["equals"];
184
- };
185
- };
186
- };
187
- readonly identifiers: readonly [readonly ["id"]];
188
- readonly operations: {
189
- readonly find: {
190
- readonly many: true;
191
- };
192
- };
193
- };
194
- readonly samples: {
195
- readonly fields: {
196
- readonly id: {
197
- readonly kind: "scalar";
198
- readonly type: {
199
- readonly scalar: "string";
200
- };
201
- readonly nullable: false;
202
- readonly list: false;
203
- readonly lifecycle: readonly [];
204
- readonly capabilities: {
205
- readonly select: true;
206
- readonly filter: readonly ["equals"];
207
- };
208
- };
209
- readonly count: {
210
- readonly kind: "scalar";
211
- readonly type: {
212
- readonly scalar: "bigint" | "datetime" | "decimal" | "bytes";
213
- };
214
- readonly nullable: false;
215
- readonly list: false;
216
- readonly lifecycle: readonly [];
217
- readonly capabilities: {
218
- readonly select: true;
219
- readonly create: readonly [];
220
- };
221
- };
222
- readonly at: {
223
- readonly kind: "scalar";
224
- readonly type: {
225
- readonly scalar: "bigint" | "datetime" | "decimal" | "bytes";
226
- };
227
- readonly nullable: false;
228
- readonly list: false;
229
- readonly lifecycle: readonly [];
230
- readonly capabilities: {
231
- readonly select: true;
232
- readonly create: readonly [];
233
- };
234
- };
235
- readonly amount: {
236
- readonly kind: "scalar";
237
- readonly type: {
238
- readonly scalar: "bigint" | "datetime" | "decimal" | "bytes";
239
- };
240
- readonly nullable: false;
241
- readonly list: false;
242
- readonly lifecycle: readonly [];
243
- readonly capabilities: {
244
- readonly select: true;
245
- readonly create: readonly [];
246
- };
247
- };
248
- readonly blob: {
249
- readonly kind: "scalar";
250
- readonly type: {
251
- readonly scalar: "bigint" | "datetime" | "decimal" | "bytes";
252
- };
253
- readonly nullable: false;
254
- readonly list: false;
255
- readonly lifecycle: readonly [];
256
- readonly capabilities: {
257
- readonly select: true;
258
- readonly create: readonly [];
259
- };
260
- };
261
- };
262
- readonly identifiers: readonly [readonly ["id"]];
263
- readonly operations: {
264
- readonly find: {
265
- readonly unique: true;
266
- };
267
- readonly create: {
268
- readonly one: true;
269
- };
270
- };
271
- };
272
- };
273
- };
274
- /** Deleting an author cascades into its books (an edge under `books`). */
275
- export declare const CORPUS_REFERENTIAL_ACTIONS: {
276
- readonly books: readonly [{
277
- readonly field: "author";
278
- readonly target: "authors";
279
- readonly references: readonly ["authorId"];
280
- readonly onDelete: "cascade";
281
- }];
282
- };
283
3
  /**
284
4
  * The `where.id` a row sends to make the corpus Framework fail one way:
285
5
  *
@@ -314,101 +34,40 @@ declare function corpusGuard(context: AvContext): boolean;
314
34
  * `A3004` trigger, and then adds a filter on a field the server does not have.
315
35
  */
316
36
  declare function corpusPipe(args: unknown): unknown;
317
- /**
318
- * The corpus's root `resources` tree: `books.label`, a VIRTUAL field computed on
319
- * read from `id`.
320
- */
321
- export declare const CORPUS_RESOURCES: {
322
- readonly books: {
323
- readonly fields: {
324
- readonly label: {
325
- readonly definition: {
326
- readonly type: {
327
- readonly scalar: "string";
328
- };
329
- readonly nullable: false;
330
- readonly list: false;
331
- readonly lifecycle: readonly ["VIRTUAL"];
332
- };
333
- readonly pipelines: {
334
- readonly compute: {
335
- readonly read: {
336
- readonly dependsOn: readonly ["id"];
337
- readonly compute: ({ record, }: {
338
- readonly record: Readonly<Record<string, unknown>>;
339
- }) => string;
340
- };
341
- };
342
- };
343
- };
344
- };
345
- };
346
- };
347
- /** The corpus's application layer: `books.label` is the client's only. */
348
- export declare const CORPUS_APPLICATION_CONFIG: {
349
- readonly exposed: true;
350
- readonly exemptions: {
351
- readonly resources: {
352
- readonly books: {
353
- readonly fields: {
354
- readonly label: true;
355
- };
356
- };
357
- };
358
- };
359
- };
360
- /**
361
- * The corpus's client layer: what the ClientContract hides or restricts, and
362
- * the client's own guard and pipe.
363
- */
364
- export declare const CORPUS_CLIENT_CONFIG: {
365
- readonly pipelines: {
366
- readonly guards: readonly [typeof corpusGuard];
367
- readonly pipes: readonly [typeof corpusPipe];
368
- };
369
- readonly exposed: true;
370
- readonly exemptions: {
371
- readonly resources: {
372
- readonly authors: {
373
- readonly fields: {
374
- readonly secret: true;
375
- };
376
- };
377
- readonly secrets: {
378
- readonly operations: {
379
- readonly find: readonly ["many"];
380
- };
381
- };
382
- readonly hiddenRes: true;
383
- };
384
- };
385
- };
386
37
  /** The corpus Framework's mount point; every row's path is relative to it. */
387
38
  export declare const CORPUS_ENTRYPOINT = "/api";
388
39
  /**
389
40
  * The corpus ClientContract's hash: what a generated client for it sends as
390
41
  * `Aventara-Contract-Hash`. A literal, as a generated client holds it.
391
42
  */
392
- export declare const CORPUS_CLIENT_CONTRACT_HASH = "sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307";
43
+ export declare const CORPUS_CLIENT_CONTRACT_HASH = "sha256:e0f996802a6a8f1ac9954796ae3f48e0892c9d1a2e691b5cd831098f4b78d7f5";
393
44
  /**
394
45
  * The corpus ClientContract as `GET /_contract` serves it: its JCS-canonical
395
46
  * bytes, `protocol.hash` included. A literal, as a host must serve it byte for
396
47
  * byte.
397
48
  */
398
- export declare 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\"}";
49
+ export declare const CORPUS_CLIENT_CONTRACT_DOCUMENT = "{\"enums\":{},\"limits\":{\"maxAll\":10,\"maxAllConcurrency\":4,\"maxBooleanNodes\":50,\"maxJsonDepth\":64,\"maxListLimit\":250,\"maxNestingDepth\":12,\"maxRequestBytes\":1048576,\"maxTransactionOperations\":20},\"protocol\":{\"hash\":\"sha256:e0f996802a6a8f1ac9954796ae3f48e0892c9d1a2e691b5cd831098f4b78d7f5\",\"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\"}";
399
50
  /**
400
51
  * The hash of the corpus's second ClientContract: the same model and
401
52
  * configuration with `transactions: "none"` (the `/_transactions` absence
402
53
  * rows). A row targets it by sending this hash, exactly as a client generated
403
54
  * against it would.
404
55
  */
405
- export declare const CORPUS_NONE_CLIENT_CONTRACT_HASH = "sha256:5e99809294a2aae922b635e9a44b464b1b6e03359a54d30420292c62676a7ce5";
56
+ export declare const CORPUS_NONE_CLIENT_CONTRACT_HASH = "sha256:34a73fd521d186350252a9bf905a9a627465f8267e0051ba4efe0441510e164a";
406
57
  /**
407
58
  * The hash of the corpus's third ClientContract: the same model and
408
59
  * configuration with the framework's `access` option ({@link CORPUS_ACCESS}),
409
60
  * so it carries the `access` section and its `POST /_access/can` route.
410
61
  */
411
- export declare const CORPUS_ACCESS_CLIENT_CONTRACT_HASH = "sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23";
62
+ export declare const CORPUS_ACCESS_CLIENT_CONTRACT_HASH = "sha256:ee098756b61a2081f92c7c065816c9f77782561aef572c117d2ee7e18389db0b";
63
+ /**
64
+ * The hash of the corpus's fourth ClientContract: the same model and
65
+ * configuration with `cache` stages on reads ({@link CORPUS_CACHE_RESOURCES}),
66
+ * so it marks them cacheable and serves each a `GET` route. A cached-read row
67
+ * targets it by sending this hash as its query's `v`, exactly as a client
68
+ * generated against it would.
69
+ */
70
+ export declare const CORPUS_CACHE_CLIENT_CONTRACT_HASH = "sha256:d82386747eef41809c28721bc513e70db59884b5bd85ca1535038ce32127fd99";
412
71
  /** The one record the corpus Adapter knows. */
413
72
  export declare const CORPUS_AUTHOR: {
414
73
  readonly id: "a1";
@@ -416,61 +75,13 @@ export declare const CORPUS_AUTHOR: {
416
75
  };
417
76
  /** The `where.id` that matches nothing. */
418
77
  export declare const CORPUS_NOBODY = "nobody";
419
- /**
420
- * The one `samples` record, in runtime forms — what an Adapter hands core, and
421
- * what the HTTP encoders must spell in wire forms.
422
- */
423
- export declare const CORPUS_SAMPLE: {
424
- readonly id: "s1";
425
- readonly count: 9007199254740993n;
426
- readonly at: Date;
427
- readonly amount: AvDecimal;
428
- readonly blob: Uint8Array<ArrayBuffer>;
429
- };
430
- /**
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
78
  /**
469
79
  * The corpus Framework's configuration, over a fresh corpus Adapter, and the
470
80
  * count of operations that Adapter has been handed so far. `contractHash`
471
81
  * selects which corpus ClientContract it compiles to: the `transactions:
472
82
  * "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
83
+ * `access` when it is {@link CORPUS_ACCESS_CLIENT_CONTRACT_HASH}, the one with
84
+ * cached reads when it is {@link CORPUS_CACHE_CLIENT_CONTRACT_HASH}, the main one
474
85
  * otherwise (a stale or absent hash included).
475
86
  */
476
87
  export declare function corpusConfiguration(contractHash?: string): {
@@ -1,4 +1,4 @@
1
- import { AvDecimal, AvError, createFramework } from "@aventara/core";
1
+ import { AvDecimal, AvError, cache, createFramework } from "@aventara/core";
2
2
  import { createFakeAdapter } from "../adapters/fake-adapter.js";
3
3
  const identityString = {
4
4
  kind: "scalar",
@@ -26,7 +26,7 @@ const wired = (scalar) => ({
26
26
  capabilities: { select: true, create: [] },
27
27
  });
28
28
  const findMany = { find: { many: true } };
29
- export const CORPUS_MODEL = {
29
+ const CORPUS_MODEL = {
30
30
  transactions: "interactive",
31
31
  scalars: {
32
32
  string: { builtin: true },
@@ -80,7 +80,7 @@ export const CORPUS_MODEL = {
80
80
  },
81
81
  },
82
82
  };
83
- export const CORPUS_REFERENTIAL_ACTIONS = {
83
+ const CORPUS_REFERENTIAL_ACTIONS = {
84
84
  books: [
85
85
  {
86
86
  field: "author",
@@ -133,7 +133,7 @@ function corpusPipe(args) {
133
133
  const record = args;
134
134
  return { ...record, where: { ...record.where, nope: "x" } };
135
135
  }
136
- export const CORPUS_RESOURCES = {
136
+ const CORPUS_RESOURCES = {
137
137
  books: {
138
138
  fields: {
139
139
  label: {
@@ -155,11 +155,32 @@ export const CORPUS_RESOURCES = {
155
155
  },
156
156
  },
157
157
  };
158
- export const CORPUS_APPLICATION_CONFIG = {
158
+ const CORPUS_CACHE_RESOURCES = {
159
+ ...CORPUS_RESOURCES,
160
+ authors: {
161
+ pipelines: { cache: cache({ for: "user", maxAge: 60 }) },
162
+ operations: {
163
+ find: {
164
+ first: {
165
+ pipelines: { cache: cache({ for: "anonymous", maxAge: 30 }) },
166
+ },
167
+ },
168
+ },
169
+ },
170
+ books: {
171
+ ...CORPUS_RESOURCES.books,
172
+ operations: {
173
+ find: {
174
+ many: { pipelines: { cache: cache({ for: "everyone", maxAge: 300 }) } },
175
+ },
176
+ },
177
+ },
178
+ };
179
+ const CORPUS_APPLICATION_CONFIG = {
159
180
  exposed: true,
160
181
  exemptions: { resources: { books: { fields: { label: true } } } },
161
182
  };
162
- export const CORPUS_CLIENT_CONFIG = {
183
+ const CORPUS_CLIENT_CONFIG = {
163
184
  pipelines: { guards: [corpusGuard], pipes: [corpusPipe] },
164
185
  exposed: true,
165
186
  exemptions: {
@@ -171,13 +192,14 @@ export const CORPUS_CLIENT_CONFIG = {
171
192
  },
172
193
  };
173
194
  export const CORPUS_ENTRYPOINT = "/api";
174
- export const CORPUS_CLIENT_CONTRACT_HASH = "sha256:502530d5b918266c61f45e70035acd7d9637bbf7305c5572106185d5e63ec307";
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
- export const CORPUS_NONE_CLIENT_CONTRACT_HASH = "sha256:5e99809294a2aae922b635e9a44b464b1b6e03359a54d30420292c62676a7ce5";
177
- export const CORPUS_ACCESS_CLIENT_CONTRACT_HASH = "sha256:e45cdbc0c5f27e94058a1e0a1e4b9e532522ebeddcbb68170ac6ec6b45ca0d23";
195
+ export const CORPUS_CLIENT_CONTRACT_HASH = "sha256:e0f996802a6a8f1ac9954796ae3f48e0892c9d1a2e691b5cd831098f4b78d7f5";
196
+ export const CORPUS_CLIENT_CONTRACT_DOCUMENT = '{"enums":{},"limits":{"maxAll":10,"maxAllConcurrency":4,"maxBooleanNodes":50,"maxJsonDepth":64,"maxListLimit":250,"maxNestingDepth":12,"maxRequestBytes":1048576,"maxTransactionOperations":20},"protocol":{"hash":"sha256:e0f996802a6a8f1ac9954796ae3f48e0892c9d1a2e691b5cd831098f4b78d7f5","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"}';
197
+ export const CORPUS_NONE_CLIENT_CONTRACT_HASH = "sha256:34a73fd521d186350252a9bf905a9a627465f8267e0051ba4efe0441510e164a";
198
+ export const CORPUS_ACCESS_CLIENT_CONTRACT_HASH = "sha256:ee098756b61a2081f92c7c065816c9f77782561aef572c117d2ee7e18389db0b";
199
+ export const CORPUS_CACHE_CLIENT_CONTRACT_HASH = "sha256:d82386747eef41809c28721bc513e70db59884b5bd85ca1535038ce32127fd99";
178
200
  export const CORPUS_AUTHOR = { id: "a1", name: "Ada" };
179
201
  export const CORPUS_NOBODY = "nobody";
180
- export const CORPUS_SAMPLE = {
202
+ const CORPUS_SAMPLE = {
181
203
  id: "s1",
182
204
  count: 9007199254740993n,
183
205
  at: new Date("2026-10-05T12:34:56.789Z"),
@@ -222,7 +244,7 @@ function corpusAnswer(operation) {
222
244
  }
223
245
  return CORPUS_AUTHOR;
224
246
  }
225
- export const CORPUS_ACCESS = {
247
+ const CORPUS_ACCESS = {
226
248
  state: () => ({ me: null }),
227
249
  policy: {
228
250
  can: ({ resource }) => {
@@ -272,7 +294,9 @@ export function corpusConfiguration(contractHash) {
272
294
  config: {
273
295
  api: CORPUS_ENTRYPOINT,
274
296
  adapter,
275
- resources: CORPUS_RESOURCES,
297
+ resources: contractHash === CORPUS_CACHE_CLIENT_CONTRACT_HASH
298
+ ? CORPUS_CACHE_RESOURCES
299
+ : CORPUS_RESOURCES,
276
300
  application: CORPUS_APPLICATION_CONFIG,
277
301
  client: CORPUS_CLIENT_CONFIG,
278
302
  ...(contractHash === CORPUS_ACCESS_CLIENT_CONTRACT_HASH