@lovrozagar/oat 0.6.0 → 0.6.2
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 +21 -7
- package/dist/cli.js +4 -0
- package/dist/runtime/async.d.ts +19 -4
- package/dist/runtime/async.d.ts.map +1 -1
- package/dist/runtime/async.js +55 -6
- package/dist/runtime/async.js.map +1 -1
- package/dist/runtime/checks.d.ts.map +1 -1
- package/dist/runtime/checks.js +90 -21
- package/dist/runtime/checks.js.map +1 -1
- package/dist/runtime/client.d.ts +2 -2
- package/dist/runtime/client.d.ts.map +1 -1
- package/dist/runtime/client.js +36 -14
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/fixture.d.ts.map +1 -1
- package/dist/runtime/fixture.js +86 -21
- package/dist/runtime/fixture.js.map +1 -1
- package/dist/runtime/rate-limit.d.ts +40 -2
- package/dist/runtime/rate-limit.d.ts.map +1 -1
- package/dist/runtime/rate-limit.js +115 -4
- package/dist/runtime/rate-limit.js.map +1 -1
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +23 -18
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/sse.d.ts +17 -0
- package/dist/runtime/sse.d.ts.map +1 -0
- package/dist/runtime/sse.js +62 -0
- package/dist/runtime/sse.js.map +1 -0
- package/dist/runtime/world.d.ts +16 -0
- package/dist/runtime/world.d.ts.map +1 -1
- package/dist/runtime/world.js +89 -0
- package/dist/runtime/world.js.map +1 -1
- package/dist/spec/collection.d.ts +2 -0
- package/dist/spec/collection.d.ts.map +1 -1
- package/dist/spec/collection.js +16 -0
- package/dist/spec/collection.js.map +1 -1
- package/dist/spec/graph.d.ts +2 -0
- package/dist/spec/graph.d.ts.map +1 -1
- package/dist/spec/graph.js +2 -1
- package/dist/spec/graph.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -807,7 +807,7 @@ Numbers use the ladder `1, 2, 5, 10, 20, 50, 100` so **lexical order ≠ numeric
|
|
|
807
807
|
|
|
808
808
|
Empty schemas (`{}`, `true`, `additionalProperties: {}`) and cyclic `$ref`s after inlining stop the walk — they become a scalar or `{}`, never another object descent. A `RangeError` during generation is a `COVERAGE_GAP` on that entity naming the operationId and JSON pointer (`fixture generation overflow on table.create (/)`), not `blocked by unknown`.
|
|
809
809
|
|
|
810
|
-
String fields honour `format` and `
|
|
810
|
+
String fields honour `format`, `pattern`, and `minLength` together: `email` → `oat-{variant}-{index}@example.test`, `uri` / `url` → `https://example.test/...`, `uuid` → a fixed-shape UUID, `pattern` → a string that matches (or the field is omitted / the entity is a gap). A generated string is padded to `minLength` (repeat the last character) without breaking `pattern`. `"Quarterly Report N"` is only used when the document does not constrain the string. `minLength` greater than `maxLength` omits an optional field and records `missingRequired` on a required one.
|
|
811
811
|
|
|
812
812
|
An operation with `x-invite` is not `entity.create`. oat does not POST a generated invitee. The invite check sends `granteeField` = the peer's `inviteAs`. Missing `inviteAs` is a coverage gap naming the tag.
|
|
813
813
|
|
|
@@ -817,6 +817,10 @@ Parent path parameters are created first (depth-first through the owning entity'
|
|
|
817
817
|
|
|
818
818
|
A create that returns `>= 300` on the first variant fails the entity (downstream checks `BLOCKED`). Later variants that fail just shorten the cohort — a partial cohort is still used.
|
|
819
819
|
|
|
820
|
+
HTTP 429 is retried first — `Retry-After` or exponential backoff, up to five times — on seed, checks, and teardown, whether or not the operation declared `x-rate-limit`. The first 429 is never a seed failure. A leftover 429 after those retries is a gap, not a backend defect.
|
|
821
|
+
|
|
822
|
+
A 402 / plan-limit (`payment_required`, `*_plan_limit`) on create is not a backend defect when the same-tenant list already has a row — typically an earlier `x-effects` create that filled a free-plan quota. oat reuses that id so children (a `row` after extract created a `table`) can still seed. It does not invent records. Write-path checks on the adopted entity stand down.
|
|
823
|
+
|
|
820
824
|
A documented feature-gate 403 is the exception: if create declares `x-feature-gate` and the body is `vars.type: feature_gate` (and `vars.feature` matches the tag when present), oat records a `COVERAGE_GAP` naming the tag rather than a seed defect. See [`x-feature-gate`](#x-feature-gate).
|
|
821
825
|
|
|
822
826
|
`--seed` / `seed` makes the bodies identical across runs. It does not make server-assigned ids identical.
|
|
@@ -894,7 +898,7 @@ Collection shape is derived from the success JSON schema, not from hardcoded wra
|
|
|
894
898
|
| page | `page`, `pageNumber`, `page_number`, `offset` |
|
|
895
899
|
| limit | `limit`, `perPage`, `per_page`, `pageSize`, `page_size` |
|
|
896
900
|
|
|
897
|
-
Success schema is the first JSON media type on responses `200`, `201`, `202`, `2XX`, or `default`. Request schema is taken from `requestBody` preferring `multipart/form-data`, then `application/x-www-form-urlencoded`, then JSON. A
|
|
901
|
+
Success schema is the first JSON media type on responses `200`, `201`, `202`, `2XX`, or `default`. Request schema is taken from `requestBody` preferring `multipart/form-data`, then `application/x-www-form-urlencoded`, then JSON. A success response that lists `text/event-stream` is a stream: oat consumes it to the end and does not treat the raw body as a JSON schema defect. Media type is the stream tag — there is no `x-stream`.
|
|
898
902
|
|
|
899
903
|
## OpenAPI meta tags
|
|
900
904
|
|
|
@@ -973,6 +977,8 @@ An invite operation is **not** the entity's fixture create, even when it is `POS
|
|
|
973
977
|
|
|
974
978
|
Timeline asserted: cannot read → invite → still cannot → accept → can → revoke → cannot.
|
|
975
979
|
|
|
980
|
+
Accept and revoke send the documented JSON request body when the operation declares one, filled from the invite token / grant id (and other known scope values). A path-only accept (`POST /invites/{token}` with no body) stays path-only — oat does not invent a body.
|
|
981
|
+
|
|
976
982
|
**Fallback:** the check does not run.
|
|
977
983
|
|
|
978
984
|
### `x-query`
|
|
@@ -1007,11 +1013,17 @@ x-async:
|
|
|
1007
1013
|
pollIntervalMs: 2000
|
|
1008
1014
|
```
|
|
1009
1015
|
|
|
1010
|
-
|
|
1016
|
+
`x-async` means **POST is a receipt, then poll**. It is not how you mark a stream. A stream is a success response that lists `text/event-stream`.
|
|
1017
|
+
|
|
1018
|
+
When the start response is JSON, oat polls `poll` until `until` matches, then treats that payload as the result. `poll` may be an operationId or `"GET /path/{id}"`. Defaults: `timeoutMs: 120000`, `pollIntervalMs: 2000`.
|
|
1019
|
+
|
|
1020
|
+
When the start response is `text/event-stream`, oat parses `event:` / `data:` frames. `data` is JSON when it starts with `{` / `[`. `idFrom` is resolved against **each event's JSON `data`**, first hit wins — `$.batch_id` on `event: batch` data `{ "batch_id": "…" }` works. A frame named `complete` / `error`, or one whose `data` matches `until`, is the terminal record; `successWhen` is applied to it and oat does **not** GET the poll route. Poll only if the stream ended without a terminal frame **and** `idFrom` resolved.
|
|
1021
|
+
|
|
1022
|
+
A spec may leave both `x-async` and `text/event-stream` on the same operation. The stream is still the result; `x-async` only supplies `idFrom` / `until` / the poll fallback.
|
|
1011
1023
|
|
|
1012
1024
|
`until` / `successWhen` use the same `field.op.value` predicates as filters (`eq`, `in`, …).
|
|
1013
1025
|
|
|
1014
|
-
**Fallback:** treated as synchronous; async checks are `COVERAGE_GAP`.
|
|
1026
|
+
**Fallback:** treated as synchronous; async checks are `COVERAGE_GAP`. A 2xx stream without `x-async` is consumed and recorded; async checks do not run.
|
|
1015
1027
|
|
|
1016
1028
|
### `x-effects`
|
|
1017
1029
|
|
|
@@ -1164,7 +1176,9 @@ x-rate-limit: { category: ai, rps: 3 }
|
|
|
1164
1176
|
|
|
1165
1177
|
Groups operations sharing one throughput budget (`category`) and optionally the rate itself (`rps`). Without this, oat's matrix can hammer a `login` or paid-inference route past its real limit, collect 429s, and report them as backend defects — exactly the false-positive class that erodes trust fastest. With it, requests to that category are paced through a token bucket before they fire.
|
|
1166
1178
|
|
|
1167
|
-
|
|
1179
|
+
Tags are the **proactive** path. HTTP 429 is the **reactive** path and is honoured even when the operation has no `x-rate-limit` at all (untagged JWT writes, teardown DELETEs). oat reads `Retry-After` (delta-seconds or HTTP-date), otherwise backs off 1s, 2s, 4s… capped at 30s, and retries the same request up to five times. The wait is fed into the matching bucket, or into an implicit `untagged-write` bucket so the next call does not immediately re-trip.
|
|
1180
|
+
|
|
1181
|
+
A 429 is only ever reported when the request that drew it was demonstrably under the _declared_ rate — oat's own bucket had a free token, so it did not have to wait for one. A 429 that arrived only after oat's bucket made the request wait means oat's own rate model was too generous, which is paced around, never reported. A 429 against a config-supplied or implicit rate is never a finding.
|
|
1168
1182
|
|
|
1169
1183
|
`config.rateLimits` is checked first and needs no tag at all — it is what keeps oat usable against a backend that has not adopted `x-rate-limit` yet, or against an environment (staging, usually) whose real limit differs from what the document claims for production. A 429 against a config-supplied rate is never a finding: it is the operator's own belief about the environment, not a claim the API made.
|
|
1170
1184
|
|
|
@@ -1235,8 +1249,8 @@ Order is fixed (foundations first) so cascade suppression has a cause to point a
|
|
|
1235
1249
|
| `softdelete.absent-from-default-list` | a soft-deleted row is gone from the default list | `x-soft-delete` | `list.read-after-write` |
|
|
1236
1250
|
| `invalidation.declared-route-changes` | after a write, the other entity's listed route actually changes | `x-invalidate` naming another entity | list, persist |
|
|
1237
1251
|
| `effects.declared-effect-occurs` | `x-effects` cardinality delta is observed on the named list | `x-effects` | `list.read-after-write` |
|
|
1238
|
-
| `async.reaches-terminal-state` |
|
|
1239
|
-
| `async.receipt-identifies-the-job` | `idFrom` on the receipt resolves to a pollable job
|
|
1252
|
+
| `async.reaches-terminal-state` | `x-async` reaches `until` (poll, or a terminal SSE frame) before `timeoutMs` | `x-async` | — |
|
|
1253
|
+
| `async.receipt-identifies-the-job` | `idFrom` on the receipt (JSON object or SSE event JSON) resolves to a pollable job | `x-async` + `idFrom` | — |
|
|
1240
1254
|
| `patch.minimality` | PATCH `{ name }` does not clear other writable fields | update + item route | — |
|
|
1241
1255
|
| `idempotency.replay-does-not-duplicate` | same Idempotency-Key + same body does not create a second row | create + documented Idempotency-Key header | list, persist |
|
|
1242
1256
|
| `delete.absent-record-returns-404` | DELETE of a missing id is 404, not 200 | delete | — |
|
package/dist/cli.js
CHANGED
|
@@ -236,6 +236,7 @@ export async function main() {
|
|
|
236
236
|
if (command === "conformance") {
|
|
237
237
|
const { postgresAvailable, renderParserSuite, renderSuite, runExampleSpecSuite, runTagUnlockSuite, runParserSuite, runPayloadCatalogSuite, runCoverageReportSuite, runSeedContractSuite, runTenantScopeSuite, runSuite, sqliteAvailable, d1Available, } = await import("./conformance/suite.js");
|
|
238
238
|
const { runFeatureGateSuite } = await import("./conformance/feature-gate.js");
|
|
239
|
+
const { runRateLimitSuite } = await import("./conformance/rate-limit.js");
|
|
239
240
|
const parser = renderParserSuite(runParserSuite());
|
|
240
241
|
process.stdout.write(parser.text);
|
|
241
242
|
/* The documented example is checked in the same breath: it is the only place a reader
|
|
@@ -256,6 +257,9 @@ export async function main() {
|
|
|
256
257
|
const featureGate = renderParserSuite(await runFeatureGateSuite());
|
|
257
258
|
process.stdout.write(featureGate.text);
|
|
258
259
|
parser.failures += featureGate.failures;
|
|
260
|
+
const rateLimit = renderParserSuite(await runRateLimitSuite());
|
|
261
|
+
process.stdout.write(rateLimit.text);
|
|
262
|
+
parser.failures += rateLimit.failures;
|
|
259
263
|
const seedContract = renderParserSuite(await runSeedContractSuite());
|
|
260
264
|
process.stdout.write(seedContract.text);
|
|
261
265
|
parser.failures += seedContract.failures;
|
package/dist/runtime/async.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Async operation support.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* most of the surface.
|
|
4
|
+
* `x-async` means the HTTP response is a receipt, then oat polls. A `text/event-stream` body is
|
|
5
|
+
* the result itself — parse events, do not `JSON.parse` the raw string. Poll only when the
|
|
6
|
+
* stream ends without a terminal frame and `idFrom` resolved.
|
|
8
7
|
*/
|
|
9
8
|
import type { AsyncSpec } from "../spec/extensions.ts";
|
|
10
9
|
import type { Client, Exchange } from "./client.ts";
|
|
10
|
+
import { type SseEvent } from "./sse.ts";
|
|
11
11
|
export interface AsyncOutcome {
|
|
12
12
|
/** Terminal state reached, or null on timeout. */
|
|
13
13
|
terminal: Record<string, unknown> | null;
|
|
@@ -23,6 +23,21 @@ export interface AsyncOutcome {
|
|
|
23
23
|
* language as the filter grammar rather than inventing a second one.
|
|
24
24
|
*/
|
|
25
25
|
export declare function matchesPredicate(record: Record<string, unknown>, expression: string): boolean;
|
|
26
|
+
export declare function readPath(body: unknown, path: string): unknown;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve `idFrom` against a JSON receipt, or against each SSE event's JSON `data` (first hit).
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveAsyncId(receipt: unknown, idFrom: string): unknown;
|
|
31
|
+
export interface StreamAsyncView {
|
|
32
|
+
id: unknown;
|
|
33
|
+
/** Event data that carried `idFrom`, for binding the poll path. */
|
|
34
|
+
idRecord: Record<string, unknown> | null;
|
|
35
|
+
/** `complete` / `error` frame, or a frame whose `data` matches `until`. */
|
|
36
|
+
terminal: Record<string, unknown> | null;
|
|
37
|
+
events: SseEvent[];
|
|
38
|
+
}
|
|
39
|
+
/** Read job id and terminal state from SSE frames. `null` when the body is not a stream. */
|
|
40
|
+
export declare function inspectStreamAsync(receipt: unknown, spec: AsyncSpec): StreamAsyncView | null;
|
|
26
41
|
/**
|
|
27
42
|
* Polls until `until` matches, the timeout expires, or the poll route stops responding.
|
|
28
43
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"async.d.ts","sourceRoot":"","sources":["../../src/runtime/async.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"async.d.ts","sourceRoot":"","sources":["../../src/runtime/async.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,KAAK,QAAQ,EAAa,MAAM,UAAU,CAAA;AAGnD,MAAM,WAAW,YAAY;IAC5B,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACxC,SAAS,EAAE,QAAQ,EAAE,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,2FAA2F;IAC3F,SAAS,EAAE,OAAO,CAAA;CAClB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CA0B7F;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAU7D;AAOD;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAYxE;AAED,MAAM,WAAW,eAAe;IAC/B,EAAE,EAAE,OAAO,CAAA;IACX,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACxC,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACxC,MAAM,EAAE,QAAQ,EAAE,CAAA;CAClB;AAED,4FAA4F;AAC5F,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,eAAe,GAAG,IAAI,CAsB5F;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC/B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC7B,OAAO,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACrC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GACjD,OAAO,CAAC,YAAY,CAAC,CA4EvB"}
|
package/dist/runtime/async.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Async operation support.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* most of the surface.
|
|
4
|
+
* `x-async` means the HTTP response is a receipt, then oat polls. A `text/event-stream` body is
|
|
5
|
+
* the result itself — parse events, do not `JSON.parse` the raw string. Poll only when the
|
|
6
|
+
* stream ends without a terminal frame and `idFrom` resolved.
|
|
8
7
|
*/
|
|
8
|
+
import { sseEvents } from "./sse.js";
|
|
9
9
|
import { fillPath } from "./world.js";
|
|
10
10
|
/**
|
|
11
11
|
* A single PostgREST-style predicate, reused here so `until`/`successWhen` speak the same
|
|
@@ -41,7 +41,7 @@ export function matchesPredicate(record, expression) {
|
|
|
41
41
|
return false;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
function readPath(body, path) {
|
|
44
|
+
export function readPath(body, path) {
|
|
45
45
|
let node = body;
|
|
46
46
|
for (const segment of path
|
|
47
47
|
.replace(/^\$\.?/, "")
|
|
@@ -53,6 +53,55 @@ function readPath(body, path) {
|
|
|
53
53
|
}
|
|
54
54
|
return node;
|
|
55
55
|
}
|
|
56
|
+
function recordOf(data) {
|
|
57
|
+
if (data === null || typeof data !== "object" || Array.isArray(data))
|
|
58
|
+
return null;
|
|
59
|
+
return data;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Resolve `idFrom` against a JSON receipt, or against each SSE event's JSON `data` (first hit).
|
|
63
|
+
*/
|
|
64
|
+
export function resolveAsyncId(receipt, idFrom) {
|
|
65
|
+
const events = sseEvents(receipt);
|
|
66
|
+
if (events !== null) {
|
|
67
|
+
for (const ev of events) {
|
|
68
|
+
const record = recordOf(ev.data);
|
|
69
|
+
if (record === null)
|
|
70
|
+
continue;
|
|
71
|
+
const found = readPath(record, idFrom);
|
|
72
|
+
if (found !== undefined && found !== null)
|
|
73
|
+
return found;
|
|
74
|
+
}
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
return readPath(receipt, idFrom);
|
|
78
|
+
}
|
|
79
|
+
/** Read job id and terminal state from SSE frames. `null` when the body is not a stream. */
|
|
80
|
+
export function inspectStreamAsync(receipt, spec) {
|
|
81
|
+
const events = sseEvents(receipt);
|
|
82
|
+
if (events === null)
|
|
83
|
+
return null;
|
|
84
|
+
let id;
|
|
85
|
+
let idRecord = null;
|
|
86
|
+
let terminal = null;
|
|
87
|
+
for (const ev of events) {
|
|
88
|
+
const record = recordOf(ev.data);
|
|
89
|
+
if (record === null)
|
|
90
|
+
continue;
|
|
91
|
+
if (id === undefined && spec.idFrom !== undefined) {
|
|
92
|
+
const found = readPath(record, spec.idFrom);
|
|
93
|
+
if (found !== undefined && found !== null) {
|
|
94
|
+
id = found;
|
|
95
|
+
idRecord = record;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const named = ev.event === "complete" || ev.event === "error";
|
|
99
|
+
const untilHit = spec.until !== undefined && matchesPredicate(record, spec.until);
|
|
100
|
+
if (named || untilHit)
|
|
101
|
+
terminal = record;
|
|
102
|
+
}
|
|
103
|
+
return { events, id, idRecord, terminal };
|
|
104
|
+
}
|
|
56
105
|
/**
|
|
57
106
|
* Polls until `until` matches, the timeout expires, or the poll route stops responding.
|
|
58
107
|
*
|
|
@@ -65,7 +114,7 @@ export async function driveAsync(client, spec, receipt, scope, headers, refreshI
|
|
|
65
114
|
const began = performance.now();
|
|
66
115
|
const pollScope = { ...scope };
|
|
67
116
|
if (spec.idFrom !== undefined) {
|
|
68
|
-
const id =
|
|
117
|
+
const id = resolveAsyncId(receipt, spec.idFrom);
|
|
69
118
|
if (id !== undefined && id !== null) {
|
|
70
119
|
/* The receipt names the job; bind it to whichever poll-path parameter is unresolved. */
|
|
71
120
|
const parameters = [...spec.poll.matchAll(/\{([^}]+)\}/g)].map((m) => m[1] ?? "");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"async.js","sourceRoot":"","sources":["../../src/runtime/async.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"async.js","sourceRoot":"","sources":["../../src/runtime/async.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../../src/runtime/checks.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../../src/runtime/checks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAE5D,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAIjE,OAAO,KAAK,EAAE,MAAM,EAA4B,MAAM,aAAa,CAAA;AAGnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAGpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,EAAE,KAAK,OAAO,EAAY,MAAM,YAAY,CAAA;AAEnD,kGAAkG;AAClG,MAAM,WAAW,KAAK;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACxB,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,iEAAiE;IACjE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;CAC5B;AAED,MAAM,WAAW,YAAY;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,SAAS,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,MAAM,EAAE,cAAc,CAAA;IACtB,MAAM,EAAE,cAAc,GAAG,SAAS,CAAA;IAClC,QAAQ,EAAE,cAAc,GAAG,SAAS,CAAA;IACpC,QAAQ,EAAE,cAAc,GAAG,SAAS,CAAA;IACpC,QAAQ,EAAE,cAAc,GAAG,SAAS,CAAA;IACpC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,OAAO,EAAE,OAAO,EAAE,CAAA;IAClB,KAAK,EAAE,eAAe,GAAG,IAAI,CAAA;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,MAAM,EAAE,UAAU,GAAG,IAAI,CAAA;IACzB,IAAI,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,uFAAuF;IACvF,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACnD;;;OAGG;IACH,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,6FAA6F;IAC7F,OAAO,EAAE,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;IACnD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;IAC5C,SAAS,EAAE,eAAe,GAAG,SAAS,CAAA;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,wDAAwD;IACxD,OAAO,EAAE,aAAa,CAAA;IACtB,8DAA8D;IAC9D,QAAQ,EAAE,cAAc,EAAE,CAAA;IAC1B,0DAA0D;IAC1D,SAAS,EAAE,cAAc,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,KAAK;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,8EAA8E;IAC9E,UAAU,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAA;IAC1C;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,GAAG,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACzC;AA+jJD,eAAO,MAAM,MAAM,EAAE,SAAS,KAAK,EA8ElC,CAAA"}
|
package/dist/runtime/checks.js
CHANGED
|
@@ -11,7 +11,7 @@ import { pathTemplateMatches } from "../spec/load.js";
|
|
|
11
11
|
import { encodeForOperation } from "./body.js";
|
|
12
12
|
import { STRING_PAYLOADS, payloadFits } from "./payloads.js";
|
|
13
13
|
import { describeFeatureGate, isDocumentedFeatureGateDenial, reportFeatureGateSchemaDrift } from "./feature-gate.js";
|
|
14
|
-
import { driveAsync } from "./async.js";
|
|
14
|
+
import { driveAsync, inspectStreamAsync, matchesPredicate, resolveAsyncId } from "./async.js";
|
|
15
15
|
import { buildCohort } from "./fixture.js";
|
|
16
16
|
import { fillPath } from "./world.js";
|
|
17
17
|
/* ------------------------------------------------------------------- helpers */
|
|
@@ -33,6 +33,16 @@ function standDownForFeatureGate(ctx, op, exchange, check) {
|
|
|
33
33
|
"down rather than treat the documented 403 as a defect.");
|
|
34
34
|
return true;
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* A 429 that survived Client retries is the bucket, not the backend. The check that needed a
|
|
38
|
+
* 2xx stands down; it is not a defect and it is not a concurrency conclusion.
|
|
39
|
+
*/
|
|
40
|
+
function standDownForRateLimit(ctx, exchange, check) {
|
|
41
|
+
if (exchange.status !== 429)
|
|
42
|
+
return false;
|
|
43
|
+
ctx.findings.unresolved(check, ctx.entityName, "the request was rate-limited (429) after retries, so this check could not complete");
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
36
46
|
/** The list endpoint's derived conventions — parameter roles and envelope spellings. */
|
|
37
47
|
function conv(ctx) {
|
|
38
48
|
return ctx.listOp.conventions;
|
|
@@ -2607,8 +2617,14 @@ const inviteGrantsThenRevokes = {
|
|
|
2607
2617
|
if (token === undefined) {
|
|
2608
2618
|
return ctx.findings.unresolved(this.id, ctx.entityName, `invite response has no token at ${spec.tokenPointer}`);
|
|
2609
2619
|
}
|
|
2610
|
-
const
|
|
2611
|
-
|
|
2620
|
+
const acceptScope = { ...resource, token };
|
|
2621
|
+
const acceptBody = documentedJsonBody(ctx, acceptOp, acceptScope);
|
|
2622
|
+
const accepted = await ctx.client.request(acceptOp.method, fillPath(acceptOp.path, acceptScope), {
|
|
2623
|
+
...(acceptBody === undefined ? {} : { body: acceptBody }),
|
|
2624
|
+
headers: {
|
|
2625
|
+
...delegate.headers(),
|
|
2626
|
+
...(acceptBody === undefined ? {} : { "content-type": "application/json" }),
|
|
2627
|
+
},
|
|
2612
2628
|
});
|
|
2613
2629
|
if (standDownForFeatureGate(ctx, acceptOp, accepted, this.id))
|
|
2614
2630
|
return;
|
|
@@ -2623,7 +2639,15 @@ const inviteGrantsThenRevokes = {
|
|
|
2623
2639
|
if (grantId === undefined) {
|
|
2624
2640
|
return ctx.findings.unresolved(this.id, ctx.entityName, `invite response has no grant id at ${spec.grantPointer}, so revoke cannot be expressed`);
|
|
2625
2641
|
}
|
|
2626
|
-
const
|
|
2642
|
+
const revokeScope = { ...resource, grant_id: grantId, token };
|
|
2643
|
+
const revokeBody = documentedJsonBody(ctx, revokeOp, revokeScope);
|
|
2644
|
+
const revoked = await ctx.client.request(revokeOp.method, fillPath(revokeOp.path, revokeScope), {
|
|
2645
|
+
...(revokeBody === undefined ? {} : { body: revokeBody }),
|
|
2646
|
+
headers: {
|
|
2647
|
+
...owner.headers(),
|
|
2648
|
+
...(revokeBody === undefined ? {} : { "content-type": "application/json" }),
|
|
2649
|
+
},
|
|
2650
|
+
});
|
|
2627
2651
|
if (standDownForFeatureGate(ctx, revokeOp, revoked, this.id))
|
|
2628
2652
|
return;
|
|
2629
2653
|
if (revoked.status >= 300) {
|
|
@@ -2978,7 +3002,7 @@ const successSchemaHonoured = {
|
|
|
2978
3002
|
const exchange = createExchange(ctx);
|
|
2979
3003
|
if (exchange === undefined)
|
|
2980
3004
|
return;
|
|
2981
|
-
if (isEventStream(exchange))
|
|
3005
|
+
if (isEventStream(exchange, createOp))
|
|
2982
3006
|
return;
|
|
2983
3007
|
if (!validator.documents(raw, exchange.status)) {
|
|
2984
3008
|
return ctx.findings.unresolved(this.id, ctx.entityName, `create returned ${exchange.status}, which the document declares no schema for — ` +
|
|
@@ -3039,10 +3063,41 @@ function submittedFields(body) {
|
|
|
3039
3063
|
return body;
|
|
3040
3064
|
return {};
|
|
3041
3065
|
}
|
|
3042
|
-
|
|
3066
|
+
/** Document first, then the live `Content-Type`. Media type is the stream tag — not `x-async`. */
|
|
3067
|
+
function isEventStream(exchange, op) {
|
|
3068
|
+
if (op?.eventStream === true)
|
|
3069
|
+
return true;
|
|
3043
3070
|
const type = exchange.responseHeaders["content-type"] ?? "";
|
|
3044
3071
|
return type.includes("text/event-stream");
|
|
3045
3072
|
}
|
|
3073
|
+
/**
|
|
3074
|
+
* JSON request body declared on the operation, filled from known flow values.
|
|
3075
|
+
*
|
|
3076
|
+
* Path-only accept/revoke (`POST /invites/{token}` with no body) stay path-only.
|
|
3077
|
+
*/
|
|
3078
|
+
function documentedJsonBody(ctx, op, fields) {
|
|
3079
|
+
const raw = ctx.model.rawOperations.get(op.operationId);
|
|
3080
|
+
const picked = raw === undefined ? null : requestContent(raw);
|
|
3081
|
+
if (picked === null || !picked.mediaType.includes("json"))
|
|
3082
|
+
return undefined;
|
|
3083
|
+
const properties = picked.schema.properties;
|
|
3084
|
+
if (properties !== null && typeof properties === "object") {
|
|
3085
|
+
const names = Object.keys(properties);
|
|
3086
|
+
if (names.length > 0) {
|
|
3087
|
+
const body = {};
|
|
3088
|
+
for (const name of names) {
|
|
3089
|
+
if (fields[name] !== undefined)
|
|
3090
|
+
body[name] = fields[name];
|
|
3091
|
+
}
|
|
3092
|
+
return body;
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
if (fields.token !== undefined)
|
|
3096
|
+
return { token: fields.token };
|
|
3097
|
+
if (fields.grant_id !== undefined)
|
|
3098
|
+
return { grant_id: fields.grant_id };
|
|
3099
|
+
return { ...fields };
|
|
3100
|
+
}
|
|
3046
3101
|
function findConstrained(schema, predicate) {
|
|
3047
3102
|
const props = schema.properties;
|
|
3048
3103
|
if (props === null || typeof props !== "object")
|
|
@@ -3201,6 +3256,10 @@ const noLostUpdate = {
|
|
|
3201
3256
|
return;
|
|
3202
3257
|
if (standDownForFeatureGate(ctx, ctx.updateOp, secondWrite, this.id))
|
|
3203
3258
|
return;
|
|
3259
|
+
if (standDownForRateLimit(ctx, firstWrite, this.id))
|
|
3260
|
+
return;
|
|
3261
|
+
if (standDownForRateLimit(ctx, secondWrite, this.id))
|
|
3262
|
+
return;
|
|
3204
3263
|
if (firstWrite.status >= 300 || secondWrite.status >= 300) {
|
|
3205
3264
|
return ctx.findings.unresolved(this.id, ctx.entityName, `a concurrent PATCH was rejected (${firstWrite.status}, ${secondWrite.status}), so no ` +
|
|
3206
3265
|
"race actually took place");
|
|
@@ -3298,6 +3357,8 @@ const declaredEffectsOccur = {
|
|
|
3298
3357
|
});
|
|
3299
3358
|
if (standDownForFeatureGate(ctx, op, invoked, this.id))
|
|
3300
3359
|
continue;
|
|
3360
|
+
if (standDownForRateLimit(ctx, invoked, this.id))
|
|
3361
|
+
continue;
|
|
3301
3362
|
if (invoked.status >= 400) {
|
|
3302
3363
|
ctx.findings.gap(this.id, ctx.entityName, `${op.operationId} could not be invoked`, `returned ${invoked.status}; its declared effects are unverified`);
|
|
3303
3364
|
continue;
|
|
@@ -3374,7 +3435,21 @@ const asyncReachesTerminalState = {
|
|
|
3374
3435
|
ctx.findings.gap(this.id, ctx.entityName, `${op.operationId} could not be started`, `returned ${start.status}; the async lifecycle after it is untested`);
|
|
3375
3436
|
continue;
|
|
3376
3437
|
}
|
|
3377
|
-
const
|
|
3438
|
+
const streamed = isEventStream(start, op);
|
|
3439
|
+
const fromStream = streamed ? inspectStreamAsync(start.responseBody, spec) : null;
|
|
3440
|
+
if (fromStream?.terminal !== null && fromStream?.terminal !== undefined) {
|
|
3441
|
+
if (spec.successWhen !== undefined && !matchesPredicate(fromStream.terminal, spec.successWhen)) {
|
|
3442
|
+
ctx.findings.gap(this.id, ctx.entityName, `${op.operationId} reached a non-success terminal state`, `terminal state did not satisfy "${spec.successWhen}"; downstream effects of ` +
|
|
3443
|
+
"this operation are untested");
|
|
3444
|
+
}
|
|
3445
|
+
continue;
|
|
3446
|
+
}
|
|
3447
|
+
const receipt = fromStream?.idRecord !== null && fromStream?.idRecord !== undefined ? fromStream.idRecord : start.responseBody;
|
|
3448
|
+
if (streamed && fromStream !== null && (fromStream.id === undefined || fromStream.id === null)) {
|
|
3449
|
+
ctx.findings.backend(this.id, ctx.entityName, `${op.operationId} job disappeared before completing`, "the stream ended without a terminal frame and without a job id, so the poll route cannot be named.", [start]);
|
|
3450
|
+
continue;
|
|
3451
|
+
}
|
|
3452
|
+
const outcome = await driveAsync(ctx.client, spec, receipt, ctx.scope, ctx.auth, ctx.refreshIfStale);
|
|
3378
3453
|
if (outcome.timedOut) {
|
|
3379
3454
|
ctx.findings.backend(this.id, ctx.entityName, `${op.operationId} never reached a terminal state`, `polled ${spec.poll} ${outcome.polls} time(s) over ${Math.round(outcome.elapsedMs)}ms ` +
|
|
3380
3455
|
`without satisfying "${spec.until ?? "any terminal state"}". A job that neither ` +
|
|
@@ -3414,19 +3489,7 @@ const asyncReceiptIsResolvable = {
|
|
|
3414
3489
|
const started = ctx.client.transcript.find((e) => e.method === op.method && e.status < 300 && new URL(e.url).pathname === resolved);
|
|
3415
3490
|
if (started === undefined)
|
|
3416
3491
|
continue;
|
|
3417
|
-
const
|
|
3418
|
-
const path = spec.idFrom
|
|
3419
|
-
.replace(/^\$\.?/, "")
|
|
3420
|
-
.split(".")
|
|
3421
|
-
.filter(Boolean);
|
|
3422
|
-
let node = body;
|
|
3423
|
-
for (const segment of path) {
|
|
3424
|
-
if (node === null || typeof node !== "object") {
|
|
3425
|
-
node = undefined;
|
|
3426
|
-
break;
|
|
3427
|
-
}
|
|
3428
|
-
node = node[segment];
|
|
3429
|
-
}
|
|
3492
|
+
const node = resolveAsyncId(started.responseBody, spec.idFrom);
|
|
3430
3493
|
if (node !== undefined && node !== null)
|
|
3431
3494
|
continue;
|
|
3432
3495
|
ctx.findings.spec(this.id, ctx.entityName, `${op.operationId} response does not carry the job identifier it declares`, `x-async names "${spec.idFrom}" as the job id, but the response has no such value. ` +
|
|
@@ -3543,6 +3606,8 @@ const stringPayloadSurvives = {
|
|
|
3543
3606
|
const control = await writeField(ASCII_PAYLOAD_PROBE, id);
|
|
3544
3607
|
if (standDownForFeatureGate(ctx, writeOp, control, this.id))
|
|
3545
3608
|
return;
|
|
3609
|
+
if (standDownForRateLimit(ctx, control, this.id))
|
|
3610
|
+
return;
|
|
3546
3611
|
if (control.status === 401 || control.status === 403) {
|
|
3547
3612
|
return ctx.findings.unresolved(this.id, ctx.entityName, `the ASCII control write returned ${control.status}, so later refusals cannot be attributed to the payload`);
|
|
3548
3613
|
}
|
|
@@ -3585,7 +3650,9 @@ const stringPayloadSurvives = {
|
|
|
3585
3650
|
evidence.push(written);
|
|
3586
3651
|
continue;
|
|
3587
3652
|
}
|
|
3588
|
-
if (
|
|
3653
|
+
if (standDownForRateLimit(ctx, written, this.id))
|
|
3654
|
+
return;
|
|
3655
|
+
if (written.status === 404 || written.status === 409 || written.status === 415) {
|
|
3589
3656
|
continue;
|
|
3590
3657
|
}
|
|
3591
3658
|
if (written.status >= 400 && written.status < 500) {
|
|
@@ -3684,6 +3751,8 @@ const documentedStatusHonoured = {
|
|
|
3684
3751
|
continue;
|
|
3685
3752
|
if (isDocumentedFeatureGateDenial(op, exchange.status, exchange.responseBody))
|
|
3686
3753
|
continue;
|
|
3754
|
+
if (exchange.status === 429)
|
|
3755
|
+
continue;
|
|
3687
3756
|
const raw = ctx.model.rawOperations.get(op.operationId);
|
|
3688
3757
|
if (!declaresConcreteStatuses(raw))
|
|
3689
3758
|
continue;
|