@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 +30 -0
- package/README.md +9 -4
- package/dist/protocol/corpus-contract.fixture.d.ts +14 -403
- package/dist/protocol/corpus-contract.fixture.js +37 -13
- package/dist/protocol/in-process.driver.d.ts +3 -0
- package/dist/protocol/in-process.driver.js +12 -0
- package/dist/protocol/per-route.driver.d.ts +1 -1
- package/dist/protocol/per-route.driver.js +3 -0
- package/dist/protocol/protocol-conformance.d.ts +3 -2
- package/dist/protocol/protocol-conformance.js +5 -1
- package/dist/protocol/protocol-corpus.d.ts +3 -2
- package/dist/protocol/protocol-fixtures.js +339 -1
- package/dist/protocol/protocol-fixtures.json-codec.js +5 -1
- package/fixtures/protocol-v1.json +141 -113
- package/package.json +2 -2
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
|
|
40
|
-
|
|
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
|
|
67
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
175
|
-
export const CORPUS_CLIENT_CONTRACT_DOCUMENT = '{"enums":{},"limits":{"maxBooleanNodes":50,"maxJsonDepth":64,"maxListLimit":250,"maxNestingDepth":12,"maxRequestBytes":1048576,"maxTransactionOperations":20},"protocol":{"hash":"sha256:
|
|
176
|
-
export const CORPUS_NONE_CLIENT_CONTRACT_HASH = "sha256:
|
|
177
|
-
export const CORPUS_ACCESS_CLIENT_CONTRACT_HASH = "sha256:
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|