@lovrozagar/oat 0.9.1 → 0.11.0
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/README.md +26 -1936
- package/dist/cli.js +326 -60
- package/dist/config/define-config.d.ts +15 -1
- package/dist/config/define-config.d.ts.map +1 -1
- package/dist/config/define-config.js.map +1 -1
- package/dist/config/validate.d.ts +12 -0
- package/dist/config/validate.d.ts.map +1 -0
- package/dist/config/validate.js +86 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/conformance/effects.d.ts +9 -0
- package/dist/conformance/effects.d.ts.map +1 -0
- package/dist/conformance/effects.js +276 -0
- package/dist/conformance/effects.js.map +1 -0
- package/dist/conformance/expected-failures.d.ts +18 -0
- package/dist/conformance/expected-failures.d.ts.map +1 -0
- package/dist/conformance/expected-failures.js +48 -0
- package/dist/conformance/expected-failures.js.map +1 -0
- package/dist/conformance/feature-gate.d.ts +7 -0
- package/dist/conformance/feature-gate.d.ts.map +1 -0
- package/dist/conformance/feature-gate.js +428 -0
- package/dist/conformance/feature-gate.js.map +1 -0
- package/dist/conformance/fuzz.d.ts +108 -0
- package/dist/conformance/fuzz.d.ts.map +1 -0
- package/dist/conformance/fuzz.js +246 -0
- package/dist/conformance/fuzz.js.map +1 -0
- package/dist/conformance/leaks.d.ts +10 -0
- package/dist/conformance/leaks.d.ts.map +1 -0
- package/dist/conformance/leaks.js +23 -0
- package/dist/conformance/leaks.js.map +1 -0
- package/dist/conformance/pool.d.ts +49 -0
- package/dist/conformance/pool.d.ts.map +1 -0
- package/dist/conformance/pool.js +75 -0
- package/dist/conformance/pool.js.map +1 -0
- package/dist/conformance/rate-limit.d.ts +7 -0
- package/dist/conformance/rate-limit.d.ts.map +1 -0
- package/dist/conformance/rate-limit.js +372 -0
- package/dist/conformance/rate-limit.js.map +1 -0
- package/dist/conformance/scope.d.ts +15 -0
- package/dist/conformance/scope.d.ts.map +1 -0
- package/dist/conformance/scope.js +78 -0
- package/dist/conformance/scope.js.map +1 -0
- package/dist/conformance/seed-contract.d.ts +11 -0
- package/dist/conformance/seed-contract.d.ts.map +1 -0
- package/dist/conformance/seed-contract.js +680 -0
- package/dist/conformance/seed-contract.js.map +1 -0
- package/dist/conformance/shapes.d.ts +35 -0
- package/dist/conformance/shapes.d.ts.map +1 -0
- package/dist/conformance/shapes.js +162 -0
- package/dist/conformance/shapes.js.map +1 -0
- package/dist/conformance/specs.d.ts +21 -0
- package/dist/conformance/specs.d.ts.map +1 -0
- package/dist/conformance/specs.js +306 -0
- package/dist/conformance/specs.js.map +1 -0
- package/dist/conformance/suite.d.ts +209 -0
- package/dist/conformance/suite.d.ts.map +1 -0
- package/dist/conformance/suite.js +1538 -0
- package/dist/conformance/suite.js.map +1 -0
- package/dist/conformance/unique.d.ts +7 -0
- package/dist/conformance/unique.d.ts.map +1 -0
- package/dist/conformance/unique.js +586 -0
- package/dist/conformance/unique.js.map +1 -0
- package/dist/conformance/worker.d.ts +3 -0
- package/dist/conformance/worker.d.ts.map +1 -0
- package/dist/conformance/worker.js +27 -0
- package/dist/conformance/worker.js.map +1 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.js +6 -2
- package/dist/reference/defects.d.ts +71 -1
- package/dist/reference/defects.d.ts.map +1 -1
- package/dist/reference/defects.js +74 -8
- package/dist/reference/defects.js.map +1 -1
- package/dist/reference/dialect.d.ts +6 -4
- package/dist/reference/dialect.d.ts.map +1 -1
- package/dist/reference/dialect.js +1 -0
- package/dist/reference/dialect.js.map +1 -1
- package/dist/reference/http.d.ts +17 -25
- package/dist/reference/http.d.ts.map +1 -1
- package/dist/reference/http.js +574 -224
- package/dist/reference/http.js.map +1 -1
- package/dist/reference/listing.d.ts +51 -0
- package/dist/reference/listing.d.ts.map +1 -0
- package/dist/reference/listing.js +256 -0
- package/dist/reference/listing.js.map +1 -0
- package/dist/reference/model.d.ts +35 -1
- package/dist/reference/model.d.ts.map +1 -1
- package/dist/reference/model.js +42 -0
- package/dist/reference/model.js.map +1 -1
- package/dist/reference/query.d.ts +132 -43
- package/dist/reference/query.d.ts.map +1 -1
- package/dist/reference/query.js +397 -315
- package/dist/reference/query.js.map +1 -1
- package/dist/reference/shapes.d.ts +60 -0
- package/dist/reference/shapes.d.ts.map +1 -0
- package/dist/reference/shapes.js +142 -0
- package/dist/reference/shapes.js.map +1 -0
- package/dist/reference/spec.d.ts +9 -2
- package/dist/reference/spec.d.ts.map +1 -1
- package/dist/reference/spec.js +291 -71
- package/dist/reference/spec.js.map +1 -1
- package/dist/reference/store-api.d.ts +14 -43
- package/dist/reference/store-api.d.ts.map +1 -1
- package/dist/reference/store-api.js +8 -58
- package/dist/reference/store-api.js.map +1 -1
- package/dist/reference/stores/memory.d.ts +12 -15
- package/dist/reference/stores/memory.d.ts.map +1 -1
- package/dist/reference/stores/memory.js +22 -70
- package/dist/reference/stores/memory.js.map +1 -1
- package/dist/reference/stores/postgres.d.ts +11 -23
- package/dist/reference/stores/postgres.d.ts.map +1 -1
- package/dist/reference/stores/postgres.js +53 -334
- package/dist/reference/stores/postgres.js.map +1 -1
- package/dist/reference/stores/sql-compile.d.ts +36 -0
- package/dist/reference/stores/sql-compile.d.ts.map +1 -0
- package/dist/reference/stores/sql-compile.js +95 -0
- package/dist/reference/stores/sql-compile.js.map +1 -0
- package/dist/reference/stores/sqlite.d.ts +12 -27
- package/dist/reference/stores/sqlite.d.ts.map +1 -1
- package/dist/reference/stores/sqlite.js +54 -355
- package/dist/reference/stores/sqlite.js.map +1 -1
- package/dist/report/console.d.ts +2 -1
- package/dist/report/console.d.ts.map +1 -1
- package/dist/report/console.js +56 -10
- package/dist/report/console.js.map +1 -1
- package/dist/report/matrix.d.ts +10 -13
- package/dist/report/matrix.d.ts.map +1 -1
- package/dist/report/matrix.js +82 -18
- package/dist/report/matrix.js.map +1 -1
- package/dist/report/render.d.ts +18 -1
- package/dist/report/render.d.ts.map +1 -1
- package/dist/report/render.js +169 -14
- package/dist/report/render.js.map +1 -1
- package/dist/runtime/async.d.ts +16 -3
- package/dist/runtime/async.d.ts.map +1 -1
- package/dist/runtime/async.js +24 -19
- package/dist/runtime/async.js.map +1 -1
- package/dist/runtime/auth.d.ts +2 -9
- package/dist/runtime/auth.d.ts.map +1 -1
- package/dist/runtime/auth.js +38 -62
- package/dist/runtime/auth.js.map +1 -1
- package/dist/runtime/body.d.ts +15 -3
- package/dist/runtime/body.d.ts.map +1 -1
- package/dist/runtime/body.js +61 -12
- package/dist/runtime/body.js.map +1 -1
- package/dist/runtime/check-costs.d.ts +15 -0
- package/dist/runtime/check-costs.d.ts.map +1 -0
- package/dist/runtime/check-costs.js +114 -0
- package/dist/runtime/check-costs.js.map +1 -0
- package/dist/runtime/check-ids.d.ts +15 -0
- package/dist/runtime/check-ids.d.ts.map +1 -0
- package/dist/runtime/check-ids.js +140 -0
- package/dist/runtime/check-ids.js.map +1 -0
- package/dist/runtime/checks.d.ts +122 -18
- package/dist/runtime/checks.d.ts.map +1 -1
- package/dist/runtime/checks.js +3437 -1933
- package/dist/runtime/checks.js.map +1 -1
- package/dist/runtime/client.d.ts +112 -0
- package/dist/runtime/client.d.ts.map +1 -1
- package/dist/runtime/client.js +271 -39
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/cookies.d.ts +16 -2
- package/dist/runtime/cookies.d.ts.map +1 -1
- package/dist/runtime/cookies.js +83 -22
- package/dist/runtime/cookies.js.map +1 -1
- package/dist/runtime/exchanges.d.ts +4 -5
- package/dist/runtime/exchanges.d.ts.map +1 -1
- package/dist/runtime/exchanges.js +33 -55
- package/dist/runtime/exchanges.js.map +1 -1
- package/dist/runtime/exit.d.ts +40 -0
- package/dist/runtime/exit.d.ts.map +1 -0
- package/dist/runtime/exit.js +48 -0
- package/dist/runtime/exit.js.map +1 -0
- package/dist/runtime/feature-gate.d.ts +0 -9
- package/dist/runtime/feature-gate.d.ts.map +1 -1
- package/dist/runtime/feature-gate.js +0 -21
- package/dist/runtime/feature-gate.js.map +1 -1
- package/dist/runtime/finding.d.ts +61 -7
- package/dist/runtime/finding.d.ts.map +1 -1
- package/dist/runtime/finding.js +74 -12
- package/dist/runtime/finding.js.map +1 -1
- package/dist/runtime/fixture.d.ts +35 -28
- package/dist/runtime/fixture.d.ts.map +1 -1
- package/dist/runtime/fixture.js +92 -731
- package/dist/runtime/fixture.js.map +1 -1
- package/dist/runtime/generate.d.ts +63 -0
- package/dist/runtime/generate.d.ts.map +1 -0
- package/dist/runtime/generate.js +635 -0
- package/dist/runtime/generate.js.map +1 -0
- package/dist/runtime/headers.d.ts +6 -0
- package/dist/runtime/headers.d.ts.map +1 -0
- package/dist/runtime/headers.js +16 -0
- package/dist/runtime/headers.js.map +1 -0
- package/dist/runtime/path.d.ts +7 -0
- package/dist/runtime/path.d.ts.map +1 -0
- package/dist/runtime/path.js +44 -0
- package/dist/runtime/path.js.map +1 -0
- package/dist/runtime/payloads.d.ts +2 -0
- package/dist/runtime/payloads.d.ts.map +1 -1
- package/dist/runtime/payloads.js +2 -1
- package/dist/runtime/payloads.js.map +1 -1
- package/dist/runtime/rate-limit.d.ts +6 -4
- package/dist/runtime/rate-limit.d.ts.map +1 -1
- package/dist/runtime/rate-limit.js +22 -33
- package/dist/runtime/rate-limit.js.map +1 -1
- package/dist/runtime/redact.d.ts +24 -0
- package/dist/runtime/redact.d.ts.map +1 -0
- package/dist/runtime/redact.js +98 -0
- package/dist/runtime/redact.js.map +1 -0
- package/dist/runtime/run.d.ts +51 -2
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +463 -195
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/runs.d.ts +5 -0
- package/dist/runtime/runs.d.ts.map +1 -1
- package/dist/runtime/runs.js +7 -1
- package/dist/runtime/runs.js.map +1 -1
- package/dist/runtime/scope.d.ts +163 -0
- package/dist/runtime/scope.d.ts.map +1 -0
- package/dist/runtime/scope.js +423 -0
- package/dist/runtime/scope.js.map +1 -0
- package/dist/runtime/teardown.d.ts +17 -4
- package/dist/runtime/teardown.d.ts.map +1 -1
- package/dist/runtime/teardown.js +49 -16
- package/dist/runtime/teardown.js.map +1 -1
- package/dist/runtime/transcript.d.ts +34 -2
- package/dist/runtime/transcript.d.ts.map +1 -1
- package/dist/runtime/transcript.js +119 -24
- package/dist/runtime/transcript.js.map +1 -1
- package/dist/runtime/unique.d.ts +2 -11
- package/dist/runtime/unique.d.ts.map +1 -1
- package/dist/runtime/unique.js +27 -53
- package/dist/runtime/unique.js.map +1 -1
- package/dist/runtime/validate.d.ts +13 -2
- package/dist/runtime/validate.d.ts.map +1 -1
- package/dist/runtime/validate.js +51 -31
- package/dist/runtime/validate.js.map +1 -1
- package/dist/runtime/wait.d.ts +2 -1
- package/dist/runtime/wait.d.ts.map +1 -1
- package/dist/runtime/wait.js +2 -36
- package/dist/runtime/wait.js.map +1 -1
- package/dist/runtime/world.d.ts +31 -3
- package/dist/runtime/world.d.ts.map +1 -1
- package/dist/runtime/world.js +113 -32
- package/dist/runtime/world.js.map +1 -1
- package/dist/spec/collection.d.ts +8 -2
- package/dist/spec/collection.d.ts.map +1 -1
- package/dist/spec/collection.js +47 -7
- package/dist/spec/collection.js.map +1 -1
- package/dist/spec/extensions.d.ts +5 -1
- package/dist/spec/extensions.d.ts.map +1 -1
- package/dist/spec/extensions.js +9 -2
- package/dist/spec/extensions.js.map +1 -1
- package/dist/spec/graph.d.ts +46 -0
- package/dist/spec/graph.d.ts.map +1 -1
- package/dist/spec/graph.js +175 -11
- package/dist/spec/graph.js.map +1 -1
- package/dist/spec/load.d.ts +25 -5
- package/dist/spec/load.d.ts.map +1 -1
- package/dist/spec/load.js +160 -59
- package/dist/spec/load.js.map +1 -1
- package/dist/spec/query-capabilities.d.ts +4 -0
- package/dist/spec/query-capabilities.d.ts.map +1 -1
- package/dist/spec/query-capabilities.js +6 -0
- package/dist/spec/query-capabilities.js.map +1 -1
- package/dist/spec/schema.d.ts +20 -0
- package/dist/spec/schema.d.ts.map +1 -0
- package/dist/spec/schema.js +118 -0
- package/dist/spec/schema.js.map +1 -0
- package/dist/spec/tag-schema.d.ts +12 -0
- package/dist/spec/tag-schema.d.ts.map +1 -0
- package/dist/spec/tag-schema.js +143 -0
- package/dist/spec/tag-schema.js.map +1 -0
- package/dist/spec/types.js +17 -1
- package/dist/spec/types.js.map +1 -1
- package/docs/api.md +59 -0
- package/docs/assumptions.md +99 -0
- package/docs/checks.md +183 -0
- package/docs/commands.md +214 -0
- package/docs/configuration.md +650 -0
- package/docs/model.md +184 -0
- package/docs/reference-defects.md +94 -0
- package/docs/reports.md +211 -0
- package/docs/tags.md +400 -0
- package/package.json +3 -1
package/dist/runtime/validate.js
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import ajvModule from "ajv/dist/2020.js";
|
|
9
9
|
import formatsModule from "ajv-formats";
|
|
10
|
+
import { DEFS_ID } from "../spec/load.js";
|
|
11
|
+
import { normalizeSchema } from "../spec/schema.js";
|
|
10
12
|
const OK = { errors: [], ok: true };
|
|
11
13
|
/* Both packages ship CJS with an interop default, so the callable lives on `.default` under
|
|
12
14
|
* NodeNext resolution — but only at runtime, hence the cast. */
|
|
@@ -15,7 +17,8 @@ const addFormats = (formatsModule.default ?? formatsModule);
|
|
|
15
17
|
export class SchemaValidator {
|
|
16
18
|
ajv;
|
|
17
19
|
cache = new Map();
|
|
18
|
-
|
|
20
|
+
/** `defs`: the recursive schemas a dereferenced document refers to (see `dereference`). */
|
|
21
|
+
constructor(defs = {}) {
|
|
19
22
|
this.ajv = new Ajv2020({
|
|
20
23
|
allErrors: true,
|
|
21
24
|
/* Specs in the wild carry annotations AJV does not know; refusing to compile over a
|
|
@@ -24,6 +27,12 @@ export class SchemaValidator {
|
|
|
24
27
|
validateFormats: true,
|
|
25
28
|
});
|
|
26
29
|
addFormats(this.ajv);
|
|
30
|
+
/* Recursive schemas are referenced as `oat-defs#/$defs/<name>`, so they are registered
|
|
31
|
+
* once under that id and every compiled schema can reach them. */
|
|
32
|
+
const $defs = {};
|
|
33
|
+
for (const [name, def] of Object.entries(defs))
|
|
34
|
+
$defs[name] = normalizeSchema(def, { direction: "response" });
|
|
35
|
+
this.ajv.addSchema({ $defs, $id: DEFS_ID });
|
|
27
36
|
}
|
|
28
37
|
/** Compiles the schema documented for this operation and status, if there is one. */
|
|
29
38
|
compile(op, key, status) {
|
|
@@ -36,21 +45,24 @@ export class SchemaValidator {
|
|
|
36
45
|
return null;
|
|
37
46
|
}
|
|
38
47
|
try {
|
|
39
|
-
const validate = this.ajv.compile(
|
|
48
|
+
const validate = this.ajv.compile(normalizeSchema(schema, { direction: "response" }));
|
|
40
49
|
this.cache.set(key, validate);
|
|
41
50
|
return validate;
|
|
42
51
|
}
|
|
43
|
-
catch {
|
|
52
|
+
catch (error) {
|
|
44
53
|
/* An uncompilable schema is a spec defect, surfaced by the caller as a gap rather than
|
|
45
|
-
* crashing the run. */
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
* crashing the run — and never as a pass. */
|
|
55
|
+
const failed = { failed: error instanceof Error ? error.message : String(error) };
|
|
56
|
+
this.cache.set(key, failed);
|
|
57
|
+
return failed;
|
|
48
58
|
}
|
|
49
59
|
}
|
|
50
60
|
validate(operationId, op, status, body) {
|
|
51
61
|
const validate = this.compile(op, `${operationId}:${status}`, status);
|
|
52
62
|
if (validate === null)
|
|
53
63
|
return OK;
|
|
64
|
+
if ("failed" in validate)
|
|
65
|
+
return { errors: [], ok: true, unchecked: validate.failed };
|
|
54
66
|
if (validate(body) === true)
|
|
55
67
|
return OK;
|
|
56
68
|
const errors = (validate.errors ?? []).map((error) => {
|
|
@@ -78,34 +90,42 @@ function schemaFor(op, status) {
|
|
|
78
90
|
}
|
|
79
91
|
return null;
|
|
80
92
|
}
|
|
93
|
+
/* One AJV per set of definitions: each registers them under `oat-defs`, as the document names them. */
|
|
94
|
+
const instanceAjvs = new WeakMap();
|
|
95
|
+
const NO_DEFS = {};
|
|
96
|
+
const instanceCache = new WeakMap();
|
|
97
|
+
function ajvFor(defs) {
|
|
98
|
+
const existing = instanceAjvs.get(defs);
|
|
99
|
+
if (existing !== undefined)
|
|
100
|
+
return existing;
|
|
101
|
+
const ajv = new Ajv2020({ allErrors: true, strict: false, validateFormats: true });
|
|
102
|
+
addFormats(ajv);
|
|
103
|
+
const $defs = {};
|
|
104
|
+
for (const [name, def] of Object.entries(defs))
|
|
105
|
+
$defs[name] = normalizeSchema(def, { direction: "request" });
|
|
106
|
+
ajv.addSchema({ $defs, $id: DEFS_ID });
|
|
107
|
+
instanceAjvs.set(defs, ajv);
|
|
108
|
+
return ajv;
|
|
109
|
+
}
|
|
81
110
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* keys that collide with the `examples` keyword in draft 2020-12.
|
|
111
|
+
* Whether `value` satisfies an already-normalized `schema` — the self-check every generated body
|
|
112
|
+
* passes before it is sent. Returns AJV's complaints, or `[]`.
|
|
85
113
|
*/
|
|
86
|
-
function
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return node;
|
|
92
|
-
const out = {};
|
|
93
|
-
for (const [key, value] of Object.entries(node)) {
|
|
94
|
-
if (key === "nullable")
|
|
95
|
-
continue;
|
|
96
|
-
if (key === "example")
|
|
97
|
-
continue;
|
|
98
|
-
if (key === "discriminator")
|
|
99
|
-
continue;
|
|
100
|
-
out[key] = walk(value);
|
|
114
|
+
export function instanceErrors(schema, value, defs = NO_DEFS) {
|
|
115
|
+
let compiled = instanceCache.get(schema);
|
|
116
|
+
if (compiled === undefined) {
|
|
117
|
+
try {
|
|
118
|
+
compiled = ajvFor(defs).compile(schema);
|
|
101
119
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (original.nullable === true && typeof original.type === "string") {
|
|
105
|
-
out.type = [original.type, "null"];
|
|
120
|
+
catch (error) {
|
|
121
|
+
compiled = { failed: error instanceof Error ? error.message : String(error) };
|
|
106
122
|
}
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
123
|
+
instanceCache.set(schema, compiled);
|
|
124
|
+
}
|
|
125
|
+
if ("failed" in compiled)
|
|
126
|
+
return [`schema cannot be compiled: ${compiled.failed}`];
|
|
127
|
+
if (compiled(value) === true)
|
|
128
|
+
return [];
|
|
129
|
+
return (compiled.errors ?? []).map((error) => `${error.instancePath || "(root)"} ${error.message ?? "is invalid"}`);
|
|
110
130
|
}
|
|
111
131
|
//# sourceMappingURL=validate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/runtime/validate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,SAAS,MAAM,kBAAkB,CAAA;AACxC,OAAO,aAAa,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/runtime/validate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,SAAS,MAAM,kBAAkB,CAAA;AACxC,OAAO,aAAa,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AA0BnD,MAAM,EAAE,GAAqB,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;AAErD;gEACgE;AAChE,MAAM,OAAO,GAAG,CAAE,SAAmC,CAAC,OAAO,IAAI,SAAS,CAAmB,CAAA;AAC7F,MAAM,UAAU,GAAG,CAAE,aAAuC,CAAC,OAAO,IAAI,aAAa,CAA2B,CAAA;AAEhH,MAAM,OAAO,eAAe;IACV,GAAG,CAAS;IACZ,KAAK,GAAG,IAAI,GAAG,EAAwD,CAAA;IAExF,2FAA2F;IAC3F,YAAY,OAAqC,EAAE;QAClD,IAAI,CAAC,GAAG,GAAG,IAAI,OAAO,CAAC;YACtB,SAAS,EAAE,IAAI;YACf;8EACkE;YAClE,MAAM,EAAE,KAAK;YACb,eAAe,EAAE,IAAI;SACrB,CAAC,CAAA;QACF,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACpB;0EACkE;QAClE,MAAM,KAAK,GAAiC,EAAE,CAAA;QAC9C,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAA;QAC7G,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAA;IAC5C,CAAC;IAED,qFAAqF;IAC7E,OAAO,CAAC,EAAmB,EAAE,GAAW,EAAE,MAAc;QAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAClC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAA;QAEvC,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;QACpC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACrB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;YACzB,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC,CAAA;YACrF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;YAC7B,OAAO,QAAQ,CAAA;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB;yDAC6C;YAC7C,MAAM,MAAM,GAAG,EAAE,MAAM,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAA;YACjF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YAC3B,OAAO,MAAM,CAAA;QACd,CAAC;IACF,CAAC;IAED,QAAQ,CAAC,WAAmB,EAAE,EAAmB,EAAE,MAAc,EAAE,IAAa;QAC/E,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,WAAW,IAAI,MAAM,EAAE,EAAE,MAAM,CAAC,CAAA;QACrE,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,EAAE,CAAA;QAChC,IAAI,QAAQ,IAAI,QAAQ;YAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAA;QACrF,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI;YAAE,OAAO,EAAE,CAAA;QACtC,MAAM,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACpD,MAAM,EAAE,GAAG,KAAK,CAAC,YAAY,KAAK,SAAS,IAAI,KAAK,CAAC,YAAY,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAA;YACxG,OAAO,GAAG,EAAE,IAAI,KAAK,CAAC,OAAO,IAAI,YAAY,EAAE,CAAA;QAChD,CAAC,CAAC,CAAA;QACF,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAA;IAChE,CAAC;IAED,gFAAgF;IAChF,SAAS,CAAC,EAAmB,EAAE,MAAc;QAC5C,OAAO,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,KAAK,IAAI,CAAA;IACtC,CAAC;CACD;AAED,SAAS,SAAS,CAAC,EAAmB,EAAE,MAAc;IACrD,MAAM,SAAS,GAAG,EAAE,CAAC,SAAS,IAAI,EAAE,CAAA;IACpC,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;IAC/E,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;QACxC,IAAI,OAAO,KAAK,SAAS;YAAE,SAAQ;QACnC,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1D,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC,MAAM,CAAA;QAClF,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAA;AACZ,CAAC;AAED,uGAAuG;AACvG,MAAM,YAAY,GAAG,IAAI,OAAO,EAAmB,CAAA;AACnD,MAAM,OAAO,GAAiC,EAAE,CAAA;AAChD,MAAM,aAAa,GAAG,IAAI,OAAO,EAAiD,CAAA;AAElF,SAAS,MAAM,CAAC,IAAkC;IACjD,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACvC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAA;IAC3C,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAA;IAClF,UAAU,CAAC,GAAG,CAAC,CAAA;IACf,MAAM,KAAK,GAAiC,EAAE,CAAA;IAC9C,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAA;IAC5G,GAAG,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAA;IACtC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAC3B,OAAO,GAAG,CAAA;AACX,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC7B,MAAoB,EACpB,KAAc,EACd,OAAqC,OAAO;IAE5C,IAAI,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACxC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC;YACJ,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,QAAQ,GAAG,EAAE,MAAM,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAA;QAC9E,CAAC;QACD,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IACpC,CAAC;IACD,IAAI,QAAQ,IAAI,QAAQ;QAAE,OAAO,CAAC,8BAA8B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;IAClF,IAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,IAAI;QAAE,OAAO,EAAE,CAAA;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,YAAY,IAAI,QAAQ,IAAI,KAAK,CAAC,OAAO,IAAI,YAAY,EAAE,CAAC,CAAA;AACpH,CAAC"}
|
package/dist/runtime/wait.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { Hooks } from "../config/define-config.ts";
|
|
|
8
8
|
import type { WaitSpec } from "../spec/extensions.ts";
|
|
9
9
|
import type { OperationModel } from "../spec/graph.ts";
|
|
10
10
|
import type { Client, Exchange } from "./client.ts";
|
|
11
|
-
|
|
11
|
+
import { readPath as readPointer } from "./path.ts";
|
|
12
12
|
/** Present enough to stop polling: not null, not "", not []. */
|
|
13
13
|
export declare function pointerIsOccupied(value: unknown): boolean;
|
|
14
14
|
export interface WaitOutcome {
|
|
@@ -29,4 +29,5 @@ export declare function driveWait(options: {
|
|
|
29
29
|
awaitSideEffect?: Hooks["awaitSideEffect"];
|
|
30
30
|
refreshIfStale?: (force?: boolean) => Promise<void>;
|
|
31
31
|
}): Promise<WaitOutcome>;
|
|
32
|
+
export { readPointer };
|
|
32
33
|
//# sourceMappingURL=wait.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wait.d.ts","sourceRoot":"","sources":["../../src/runtime/wait.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"wait.d.ts","sourceRoot":"","sources":["../../src/runtime/wait.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,QAAQ,IAAI,WAAW,EAAE,MAAM,WAAW,CAAA;AAInD,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIzD;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAA;IACrB,OAAO,EAAE,OAAO,CAAA;CAChB;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE;IACxC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,cAAc,CAAA;IACtB,IAAI,EAAE,QAAQ,CAAA;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,OAAO,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;IACf,eAAe,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,CAAA;IAC1C,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACnD,GAAG,OAAO,CAAC,WAAW,CAAC,CAuEvB;AAED,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
package/dist/runtime/wait.js
CHANGED
|
@@ -4,44 +4,9 @@
|
|
|
4
4
|
* Queue consumers and webhook inboxes are not the same request. Timeout is a finding, not a
|
|
5
5
|
* coverage gap — the document claimed the side effect would appear.
|
|
6
6
|
*/
|
|
7
|
+
import { readPath as readPointer } from "./path.js";
|
|
7
8
|
import { sleep } from "./poll.js";
|
|
8
9
|
import { fillPath } from "./world.js";
|
|
9
|
-
export function readPointer(body, pointer) {
|
|
10
|
-
if (pointer.startsWith("/"))
|
|
11
|
-
return readJsonPointer(body, pointer);
|
|
12
|
-
let node = body;
|
|
13
|
-
for (const segment of pointer
|
|
14
|
-
.replace(/^\$\.?/, "")
|
|
15
|
-
.split(".")
|
|
16
|
-
.filter(Boolean)) {
|
|
17
|
-
if (node === null || typeof node !== "object")
|
|
18
|
-
return undefined;
|
|
19
|
-
const index = Number.parseInt(segment, 10);
|
|
20
|
-
node = Array.isArray(node)
|
|
21
|
-
? Number.isNaN(index)
|
|
22
|
-
? undefined
|
|
23
|
-
: node[index]
|
|
24
|
-
: node[segment];
|
|
25
|
-
}
|
|
26
|
-
return node;
|
|
27
|
-
}
|
|
28
|
-
function readJsonPointer(body, pointer) {
|
|
29
|
-
if (pointer === "/")
|
|
30
|
-
return body;
|
|
31
|
-
let node = body;
|
|
32
|
-
for (const raw of pointer.slice(1).split("/")) {
|
|
33
|
-
const segment = raw.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
34
|
-
if (node === null || typeof node !== "object")
|
|
35
|
-
return undefined;
|
|
36
|
-
const index = Number.parseInt(segment, 10);
|
|
37
|
-
node = Array.isArray(node)
|
|
38
|
-
? Number.isNaN(index)
|
|
39
|
-
? undefined
|
|
40
|
-
: node[index]
|
|
41
|
-
: node[segment];
|
|
42
|
-
}
|
|
43
|
-
return node;
|
|
44
|
-
}
|
|
45
10
|
/** Present enough to stop polling: not null, not "", not []. */
|
|
46
11
|
export function pointerIsOccupied(value) {
|
|
47
12
|
if (value === undefined || value === null || value === "")
|
|
@@ -122,4 +87,5 @@ export async function driveWait(options) {
|
|
|
122
87
|
timedOut: true,
|
|
123
88
|
};
|
|
124
89
|
}
|
|
90
|
+
export { readPointer };
|
|
125
91
|
//# sourceMappingURL=wait.js.map
|
package/dist/runtime/wait.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wait.js","sourceRoot":"","sources":["../../src/runtime/wait.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"wait.js","sourceRoot":"","sources":["../../src/runtime/wait.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/world.d.ts
CHANGED
|
@@ -24,9 +24,14 @@ export declare class SeedError extends Error {
|
|
|
24
24
|
readonly cause_: string;
|
|
25
25
|
/** Status the failing request returned, when the failure was an HTTP response. */
|
|
26
26
|
readonly status?: number | undefined;
|
|
27
|
+
/** The create that failed, when the failure was one — a parent's, not always the entity's own. */
|
|
28
|
+
readonly operationId?: string | undefined;
|
|
29
|
+
readonly exchange?: Exchange | undefined;
|
|
27
30
|
constructor(cause_: string, message: string,
|
|
28
31
|
/** Status the failing request returned, when the failure was an HTTP response. */
|
|
29
|
-
status?: number | undefined
|
|
32
|
+
status?: number | undefined,
|
|
33
|
+
/** The create that failed, when the failure was one — a parent's, not always the entity's own. */
|
|
34
|
+
operationId?: string | undefined, exchange?: Exchange | undefined);
|
|
30
35
|
}
|
|
31
36
|
export declare function fillPath(template: string, values: Record<string, string>): string;
|
|
32
37
|
/**
|
|
@@ -39,19 +44,33 @@ export declare function isPlanLimitResponse(status: number, body: unknown): bool
|
|
|
39
44
|
/** Pulls the collection out of a list body the same way seed fallback and effect checks do. */
|
|
40
45
|
export declare function recordsFromList(body: unknown, collectionKey: string | null): Record_[];
|
|
41
46
|
/** Same-tenant records the list route already returns. Empty when the route cannot be resolved. */
|
|
42
|
-
export declare function listExisting(listOp: OperationModel, client: Client, headers: Record<string, string> | (() => Record<string, string>), values: Record<string, string>): Promise<Record_[]>;
|
|
47
|
+
export declare function listExisting(listOp: OperationModel, model: SpecModel, client: Client, headers: Record<string, string> | (() => Record<string, string>), values: Record<string, string>): Promise<Record_[]>;
|
|
43
48
|
export interface WorldOptions {
|
|
44
49
|
roots: Record<string, string>;
|
|
45
50
|
seed: number;
|
|
51
|
+
/**
|
|
52
|
+
* Per-run token mixed into every value that must not collide with an earlier run's records —
|
|
53
|
+
* unique columns, above all. A seed alone repeats exactly, which is its job.
|
|
54
|
+
*/
|
|
55
|
+
nonce?: string;
|
|
46
56
|
cohortSize?: number;
|
|
47
57
|
authHeaders: () => Record<string, string>;
|
|
48
58
|
uploads?: UploadContext;
|
|
59
|
+
/**
|
|
60
|
+
* Called the moment a record exists, before anything else can fail. A record learned about
|
|
61
|
+
* only after the step that made it returns is dropped whenever a later step throws.
|
|
62
|
+
*/
|
|
63
|
+
onCreate?: (entity: string, id: string, scope: Record<string, string>) => void;
|
|
64
|
+
/** Who is creating — keys the ancestor cache, since one principal's parent is not another's. */
|
|
65
|
+
principal?: string;
|
|
66
|
+
/** Ancestors already made in this run, by principal, operation and parent path. */
|
|
67
|
+
ancestors?: Map<string, string>;
|
|
49
68
|
}
|
|
50
69
|
/**
|
|
51
70
|
* Resolves every path parameter an operation needs. Roots come from config; everything else is
|
|
52
71
|
* created through the owning entity's create operation, depth-first.
|
|
53
72
|
*/
|
|
54
|
-
export declare function
|
|
73
|
+
export declare function resolvePathScope(op: OperationModel, model: SpecModel, client: Client, options: WorldOptions, scope?: Scope): Promise<Scope>;
|
|
55
74
|
export declare function requestSchemaOf(op: OperationModel, model: SpecModel): Record<string, unknown> | null;
|
|
56
75
|
export interface SeededCohort {
|
|
57
76
|
members: CohortMember[];
|
|
@@ -80,6 +99,15 @@ export interface SeededCohort {
|
|
|
80
99
|
uniqueAdopted?: boolean;
|
|
81
100
|
/** Set when extra cohort variants were dropped because unique values could not differ. */
|
|
82
101
|
uniqueGap?: string;
|
|
102
|
+
/**
|
|
103
|
+
* Variants after the first whose create failed. The cohort carries on without them, and the
|
|
104
|
+
* run reports each: a 5xx is the backend's failure, a 4xx a variant the document permits and
|
|
105
|
+
* the backend refused.
|
|
106
|
+
*/
|
|
107
|
+
failedVariants?: Array<{
|
|
108
|
+
variant: string;
|
|
109
|
+
exchange: Exchange;
|
|
110
|
+
}>;
|
|
83
111
|
}
|
|
84
112
|
/** Creates the cohort and returns the server's view of each instance. */
|
|
85
113
|
export declare function seedCohort(createOp: OperationModel, model: SpecModel, client: Client, options: WorldOptions, scope: Scope): Promise<SeededCohort>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"world.d.ts","sourceRoot":"","sources":["../../src/runtime/world.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAKjE,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,KAAK,YAAY,EAA0E,MAAM,cAAc,CAAA;AAGxH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAE7C,MAAM,WAAW,KAAK;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,+FAA+F;IAC/F,OAAO,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC5D;AAED,qBAAa,SAAU,SAAQ,KAAK;IAElC,QAAQ,CAAC,MAAM,EAAE,MAAM;IAEvB,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"world.d.ts","sourceRoot":"","sources":["../../src/runtime/world.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAKjE,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,KAAK,YAAY,EAA0E,MAAM,cAAc,CAAA;AAGxH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAE7C,MAAM,WAAW,KAAK;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,+FAA+F;IAC/F,OAAO,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC5D;AAED,qBAAa,SAAU,SAAQ,KAAK;IAElC,QAAQ,CAAC,MAAM,EAAE,MAAM;IAEvB,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IACxB,kGAAkG;IAClG,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ;gBANnB,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM;IACf,kFAAkF;IACzE,MAAM,CAAC,EAAE,MAAM,YAAA;IACxB,kGAAkG;IACzF,WAAW,CAAC,EAAE,MAAM,YAAA,EACpB,QAAQ,CAAC,EAAE,QAAQ,YAAA;CAI7B;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAMjF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAI1E;AAqBD,+FAA+F;AAC/F,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,EAAE,CAOtF;AAED,mGAAmG;AACnG,wBAAsB,YAAY,CACjC,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAChE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,OAAO,CAAC,OAAO,EAAE,CAAC,CAcpB;AAED,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAA;IAC9E,gGAAgG;IAChG,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mFAAmF;IACnF,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACrC,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,YAAY,EACrB,KAAK,GAAE,KAAmC,GACxC,OAAO,CAAC,KAAK,CAAC,CAiEhB;AAmGD,wBAAgB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAIpG;AAED,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,OAAO,EAAE,OAAO,EAAE,CAAA;IAClB;;;;;OAKG;IACH,WAAW,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAA;IACvE;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,0FAA0F;IAC1F,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAA;CAC/D;AAED,yEAAyE;AACzE,wBAAsB,UAAU,CAC/B,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,KAAK,GACV,OAAO,CAAC,YAAY,CAAC,CAwJvB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAe1D"}
|
package/dist/runtime/world.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* reported as BLOCKED against that single cause.
|
|
8
8
|
*/
|
|
9
9
|
import { requestContent } from "../spec/collection.js";
|
|
10
|
-
import { owningEntityName } from "../spec/graph.js";
|
|
10
|
+
import { largestPageQuery, owningEntityName } from "../spec/graph.js";
|
|
11
11
|
import { encodeForOperation } from "./body.js";
|
|
12
12
|
import { forEachInvocation } from "./upload-each.js";
|
|
13
13
|
import { buildCohort, ensureDistinctUniqueValues, isOverflowError, overflowFrom } from "./fixture.js";
|
|
@@ -16,12 +16,18 @@ import { describeFeatureGate, isDocumentedFeatureGateDenial } from "./feature-ga
|
|
|
16
16
|
export class SeedError extends Error {
|
|
17
17
|
cause_;
|
|
18
18
|
status;
|
|
19
|
+
operationId;
|
|
20
|
+
exchange;
|
|
19
21
|
constructor(cause_, message,
|
|
20
22
|
/** Status the failing request returned, when the failure was an HTTP response. */
|
|
21
|
-
status
|
|
23
|
+
status,
|
|
24
|
+
/** The create that failed, when the failure was one — a parent's, not always the entity's own. */
|
|
25
|
+
operationId, exchange) {
|
|
22
26
|
super(message);
|
|
23
27
|
this.cause_ = cause_;
|
|
24
28
|
this.status = status;
|
|
29
|
+
this.operationId = operationId;
|
|
30
|
+
this.exchange = exchange;
|
|
25
31
|
}
|
|
26
32
|
}
|
|
27
33
|
export function fillPath(template, values) {
|
|
@@ -76,13 +82,16 @@ export function recordsFromList(body, collectionKey) {
|
|
|
76
82
|
return [];
|
|
77
83
|
}
|
|
78
84
|
/** Same-tenant records the list route already returns. Empty when the route cannot be resolved. */
|
|
79
|
-
export async function listExisting(listOp, client, headers, values) {
|
|
85
|
+
export async function listExisting(listOp, model, client, headers, values) {
|
|
80
86
|
for (const param of listOp.pathParams) {
|
|
81
87
|
if (values[param] === undefined)
|
|
82
88
|
return [];
|
|
83
89
|
}
|
|
84
90
|
try {
|
|
85
|
-
const exchange = await client.get(fillPath(listOp.path, values), {
|
|
91
|
+
const exchange = await client.get(fillPath(listOp.path, values), {
|
|
92
|
+
headers,
|
|
93
|
+
query: largestPageQuery(model, listOp),
|
|
94
|
+
});
|
|
86
95
|
if (exchange.status >= 300)
|
|
87
96
|
return [];
|
|
88
97
|
return recordsFromList(exchange.responseBody, listOp.collection?.key ?? null);
|
|
@@ -95,7 +104,7 @@ export async function listExisting(listOp, client, headers, values) {
|
|
|
95
104
|
* Resolves every path parameter an operation needs. Roots come from config; everything else is
|
|
96
105
|
* created through the owning entity's create operation, depth-first.
|
|
97
106
|
*/
|
|
98
|
-
export async function
|
|
107
|
+
export async function resolvePathScope(op, model, client, options, scope = { created: [], values: {} }) {
|
|
99
108
|
for (const param of op.pathParams) {
|
|
100
109
|
if (scope.values[param] !== undefined)
|
|
101
110
|
continue;
|
|
@@ -115,28 +124,72 @@ export async function resolveScope(op, model, client, options, scope = { created
|
|
|
115
124
|
const createOp = model.byOperationId.get(entity.create);
|
|
116
125
|
if (createOp === undefined)
|
|
117
126
|
throw new SeedError(param, `missing operation ${entity.create}`);
|
|
118
|
-
await
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
127
|
+
await resolvePathScope(createOp, model, client, options, scope);
|
|
128
|
+
/* One ancestor per principal and parent path: a row and its siblings share the table oat
|
|
129
|
+
* made for the first of them, instead of each leaving another table behind. */
|
|
130
|
+
const cacheKey = `${options.principal ?? ""}\u0000${createOp.operationId}\u0000${fillPath(createOp.path, scope.values)}`;
|
|
131
|
+
const cached = options.ancestors?.get(cacheKey);
|
|
132
|
+
if (cached !== undefined) {
|
|
133
|
+
scope.values[param] = cached;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
/* Entities in parallel lanes can reach the same missing ancestor at once; the second
|
|
137
|
+
* waits for the first's create rather than making a twin. */
|
|
138
|
+
const pending = options.ancestors === undefined ? undefined : inflightAncestors(options.ancestors).get(cacheKey);
|
|
139
|
+
if (pending !== undefined) {
|
|
140
|
+
scope.values[param] = await pending;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const creating = (async () => {
|
|
144
|
+
const { record: created, adopted } = await createOne(createOp, model, client, options, scope);
|
|
145
|
+
const identity = entity.identity ?? "id";
|
|
146
|
+
const id = created[identity];
|
|
147
|
+
if (typeof id !== "string" && typeof id !== "number") {
|
|
148
|
+
throw new SeedError(param, `create for "${owner}" returned no usable "${identity}"`);
|
|
149
|
+
}
|
|
150
|
+
/* Adopted, not created: somebody else's record, never oat's to remove. */
|
|
151
|
+
if (!adopted)
|
|
152
|
+
options.onCreate?.(owner, String(id), { ...scope.values });
|
|
153
|
+
options.ancestors?.set(cacheKey, String(id));
|
|
154
|
+
return String(id);
|
|
155
|
+
})();
|
|
156
|
+
if (options.ancestors !== undefined)
|
|
157
|
+
inflightAncestors(options.ancestors).set(cacheKey, creating);
|
|
158
|
+
try {
|
|
159
|
+
scope.values[param] = await creating;
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
if (options.ancestors !== undefined)
|
|
163
|
+
inflightAncestors(options.ancestors).delete(cacheKey);
|
|
124
164
|
}
|
|
125
|
-
scope.values[param] = String(id);
|
|
126
165
|
scope.created.push({
|
|
127
166
|
entity: owner,
|
|
128
|
-
id:
|
|
167
|
+
id: scope.values[param],
|
|
129
168
|
path: fillPath(createOp.path, scope.values),
|
|
130
169
|
});
|
|
131
170
|
}
|
|
132
171
|
return scope;
|
|
133
172
|
}
|
|
173
|
+
/** Ancestor creates under way, per ancestor cache. */
|
|
174
|
+
const INFLIGHT = new WeakMap();
|
|
175
|
+
function inflightAncestors(cache) {
|
|
176
|
+
let pending = INFLIGHT.get(cache);
|
|
177
|
+
if (pending === undefined) {
|
|
178
|
+
pending = new Map();
|
|
179
|
+
INFLIGHT.set(cache, pending);
|
|
180
|
+
}
|
|
181
|
+
return pending;
|
|
182
|
+
}
|
|
134
183
|
async function createOne(createOp, model, client, options, scope) {
|
|
135
184
|
const schema = requestSchemaOf(createOp, model);
|
|
136
185
|
let member;
|
|
137
186
|
try {
|
|
138
187
|
;
|
|
139
|
-
[member] = buildCohort(schema ?? {}, options.seed, ["baseline"], createOp.operationId
|
|
188
|
+
[member] = buildCohort(schema ?? {}, options.seed, ["baseline"], createOp.operationId, {
|
|
189
|
+
defs: model.defs,
|
|
190
|
+
distinct: new Set((createOp.unique ?? []).flat()),
|
|
191
|
+
...(options.nonce === undefined ? {} : { nonce: options.nonce }),
|
|
192
|
+
});
|
|
140
193
|
}
|
|
141
194
|
catch (error) {
|
|
142
195
|
if (isOverflowError(error))
|
|
@@ -147,7 +200,7 @@ async function createOne(createOp, model, client, options, scope) {
|
|
|
147
200
|
if ((createOp.unique?.length ?? 0) > 0) {
|
|
148
201
|
/* Ancestor creates share the entity seed with the entity's own cohort; unique columns
|
|
149
202
|
* must not collide with a later seed of the same collection. */
|
|
150
|
-
body = uniquifyProbeBody(body, createOp.unique ?? [], schema, `anc${options.seed}`);
|
|
203
|
+
body = uniquifyProbeBody(body, createOp.unique ?? [], schema, `anc${options.seed}-${options.nonce ?? ""}`);
|
|
151
204
|
}
|
|
152
205
|
const encoded = await encodeForOperation(createOp, model, body, uploadContext(options), member?.variant ?? "baseline", 0);
|
|
153
206
|
const exchange = await client.request("POST", fillPath(createOp.path, scope.values), {
|
|
@@ -162,16 +215,16 @@ async function createOne(createOp, model, client, options, scope) {
|
|
|
162
215
|
if (isPlanLimitResponse(exchange.status, exchange.responseBody)) {
|
|
163
216
|
const reused = await adoptExisting(createOp, model, client, options, scope);
|
|
164
217
|
if (reused !== null)
|
|
165
|
-
return reused;
|
|
218
|
+
return { adopted: true, record: reused };
|
|
166
219
|
}
|
|
167
220
|
if (isUniqueConflictResponse(createOp, exchange.status)) {
|
|
168
221
|
const reused = await adoptExisting(createOp, model, client, options, scope);
|
|
169
222
|
if (reused !== null)
|
|
170
|
-
return reused;
|
|
223
|
+
return { adopted: true, record: reused };
|
|
171
224
|
}
|
|
172
|
-
throw new SeedError(createOp.operationId, `${createOp.operationId} returned ${exchange.status}: ${JSON.stringify(exchange.responseBody).slice(0, 300)}`, exchange.status);
|
|
225
|
+
throw new SeedError(createOp.operationId, `${createOp.operationId} returned ${exchange.status}: ${JSON.stringify(exchange.responseBody).slice(0, 300)}`, exchange.status, createOp.operationId, exchange);
|
|
173
226
|
}
|
|
174
|
-
return (exchange.responseBody ?? {});
|
|
227
|
+
return { adopted: false, record: (exchange.responseBody ?? {}) };
|
|
175
228
|
}
|
|
176
229
|
/** First listed record with a usable identity, or null — never synthesises a row. */
|
|
177
230
|
async function adoptExisting(createOp, model, client, options, scope) {
|
|
@@ -184,7 +237,7 @@ async function adoptExisting(createOp, model, client, options, scope) {
|
|
|
184
237
|
const listOp = model.byOperationId.get(entity.list);
|
|
185
238
|
if (listOp === undefined)
|
|
186
239
|
return null;
|
|
187
|
-
const records = await listExisting(listOp, client, options.authHeaders, { ...options.roots, ...scope.values });
|
|
240
|
+
const records = await listExisting(listOp, model, client, options.authHeaders, { ...options.roots, ...scope.values });
|
|
188
241
|
const identity = entity.identity ?? "id";
|
|
189
242
|
return (records.find((record) => {
|
|
190
243
|
const id = record[identity];
|
|
@@ -205,8 +258,16 @@ export async function seedCohort(createOp, model, client, options, scope) {
|
|
|
205
258
|
let members;
|
|
206
259
|
let uniqueGap;
|
|
207
260
|
try {
|
|
208
|
-
const generated = buildCohort(schema, options.seed, undefined, createOp.operationId
|
|
209
|
-
|
|
261
|
+
const generated = buildCohort(schema, options.seed, undefined, createOp.operationId, {
|
|
262
|
+
defs: model.defs,
|
|
263
|
+
distinct: new Set((createOp.unique ?? []).flat()),
|
|
264
|
+
...(options.nonce === undefined ? {} : { nonce: options.nonce }),
|
|
265
|
+
}).slice(0, options.cohortSize ?? 7);
|
|
266
|
+
const distinct = ensureDistinctUniqueValues(generated, createOp.unique ?? [], schema, {
|
|
267
|
+
defs: model.defs,
|
|
268
|
+
distinct: new Set((createOp.unique ?? []).flat()),
|
|
269
|
+
...(options.nonce === undefined ? {} : { nonce: options.nonce }),
|
|
270
|
+
});
|
|
210
271
|
members = distinct.members;
|
|
211
272
|
if (distinct.gap !== null)
|
|
212
273
|
uniqueGap = distinct.gap;
|
|
@@ -214,12 +275,12 @@ export async function seedCohort(createOp, model, client, options, scope) {
|
|
|
214
275
|
const listOp = entity?.list === undefined ? undefined : model.byOperationId.get(entity.list);
|
|
215
276
|
const existing = listOp === undefined
|
|
216
277
|
? []
|
|
217
|
-
: await listExisting(listOp, client, options.authHeaders, { ...options.roots, ...scope.values });
|
|
278
|
+
: await listExisting(listOp, model, client, options.authHeaders, { ...options.roots, ...scope.values });
|
|
218
279
|
if (existing.length > 0 && (createOp.unique?.length ?? 0) > 0) {
|
|
219
280
|
members = members.map((member, index) => {
|
|
220
281
|
let body = member.body;
|
|
221
282
|
for (let token = 0; token < 8 && uniqueTupleCollides(body, createOp.unique ?? [], existing); token++) {
|
|
222
|
-
body = uniquifyProbeBody(body, createOp.unique ?? [], schema, `ex${index}${token}`);
|
|
283
|
+
body = uniquifyProbeBody(body, createOp.unique ?? [], schema, `ex${index}${token}-${options.nonce ?? ""}`);
|
|
223
284
|
}
|
|
224
285
|
return { ...member, body };
|
|
225
286
|
});
|
|
@@ -234,6 +295,15 @@ export async function seedCohort(createOp, model, client, options, scope) {
|
|
|
234
295
|
const path = fillPath(createOp.path, scope.values);
|
|
235
296
|
const uploads = uploadContext(options);
|
|
236
297
|
const seededMembers = [];
|
|
298
|
+
const identity = (createOp.entity === null ? undefined : model.entities.get(createOp.entity))?.identity ?? "id";
|
|
299
|
+
const created = (exchange) => {
|
|
300
|
+
const record = (exchange.responseBody ?? {});
|
|
301
|
+
const id = record[identity];
|
|
302
|
+
if (createOp.entity !== null && (typeof id === "string" || typeof id === "number")) {
|
|
303
|
+
options.onCreate?.(createOp.entity, String(id), { ...scope.values });
|
|
304
|
+
}
|
|
305
|
+
return record;
|
|
306
|
+
};
|
|
237
307
|
const postMember = async (member, nextUploads) => {
|
|
238
308
|
const encoded = await encodeForOperation(createOp, model, member.body, nextUploads, member.variant, records.length);
|
|
239
309
|
return client.request("POST", path, {
|
|
@@ -244,7 +314,12 @@ export async function seedCohort(createOp, model, client, options, scope) {
|
|
|
244
314
|
...(nextUploads.fixture === undefined ? {} : { fixture: nextUploads.fixture.filename }),
|
|
245
315
|
});
|
|
246
316
|
};
|
|
247
|
-
const
|
|
317
|
+
const failedVariants = [];
|
|
318
|
+
const withGap = (cohort) => ({
|
|
319
|
+
...cohort,
|
|
320
|
+
...(uniqueGap === undefined ? {} : { uniqueGap }),
|
|
321
|
+
...(failedVariants.length === 0 ? {} : { failedVariants }),
|
|
322
|
+
});
|
|
248
323
|
const failOrAdopt = async (member, exchange) => {
|
|
249
324
|
if (records.length > 0)
|
|
250
325
|
return withGap({ featureGate: null, members: seededMembers, records });
|
|
@@ -270,14 +345,14 @@ export async function seedCohort(createOp, model, client, options, scope) {
|
|
|
270
345
|
});
|
|
271
346
|
}
|
|
272
347
|
throw new SeedError(createOp.operationId, `seeding "${member.variant}" returned ${exchange.status}: ` +
|
|
273
|
-
JSON.stringify(exchange.responseBody).slice(0, 300), exchange.status);
|
|
348
|
+
JSON.stringify(exchange.responseBody).slice(0, 300), exchange.status, createOp.operationId, exchange);
|
|
274
349
|
}
|
|
275
350
|
if (isPlanLimitResponse(exchange.status, exchange.responseBody)) {
|
|
276
351
|
const adopted = await adoptExisting(createOp, model, client, options, scope);
|
|
277
352
|
if (adopted !== null)
|
|
278
353
|
return withGap({ adopted: true, featureGate: null, members: seededMembers, records: [adopted] });
|
|
279
354
|
}
|
|
280
|
-
throw new SeedError(createOp.operationId, `seeding "${member.variant}" returned ${exchange.status}: ` + JSON.stringify(exchange.responseBody).slice(0, 300), exchange.status);
|
|
355
|
+
throw new SeedError(createOp.operationId, `seeding "${member.variant}" returned ${exchange.status}: ` + JSON.stringify(exchange.responseBody).slice(0, 300), exchange.status, createOp.operationId, exchange);
|
|
281
356
|
};
|
|
282
357
|
let lastFail;
|
|
283
358
|
const outcomes = await forEachInvocation(createOp.operationId, uploads, async (nextUploads, slot) => {
|
|
@@ -290,15 +365,21 @@ export async function seedCohort(createOp, model, client, options, scope) {
|
|
|
290
365
|
return null;
|
|
291
366
|
}
|
|
292
367
|
seededMembers.push(member);
|
|
293
|
-
records.push((exchange
|
|
368
|
+
records.push(created(exchange));
|
|
294
369
|
return null;
|
|
295
370
|
}
|
|
296
371
|
for (const member of members) {
|
|
297
372
|
const exchange = await postMember(member, nextUploads);
|
|
298
|
-
if (exchange.status >= 300)
|
|
299
|
-
|
|
373
|
+
if (exchange.status >= 300) {
|
|
374
|
+
/* The first create decides whether there is a cohort at all; a later one failing
|
|
375
|
+
* is a variant lost, reported rather than ending the cohort in silence. */
|
|
376
|
+
if (records.length === 0)
|
|
377
|
+
return failOrAdopt(member, exchange);
|
|
378
|
+
failedVariants.push({ exchange, variant: member.variant });
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
300
381
|
seededMembers.push(member);
|
|
301
|
-
records.push((exchange
|
|
382
|
+
records.push(created(exchange));
|
|
302
383
|
}
|
|
303
384
|
return null;
|
|
304
385
|
});
|
|
@@ -325,7 +406,7 @@ export function probeCreateFixtures(model) {
|
|
|
325
406
|
continue;
|
|
326
407
|
const schema = requestSchemaOf(op, model) ?? {};
|
|
327
408
|
try {
|
|
328
|
-
buildCohort(schema, 1, ["baseline"], op.operationId);
|
|
409
|
+
buildCohort(schema, 1, ["baseline"], op.operationId, { defs: model.defs });
|
|
329
410
|
}
|
|
330
411
|
catch (error) {
|
|
331
412
|
if (isOverflowError(error)) {
|