@fuzdev/fuz_app 0.73.0 → 0.75.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/dist/auth/bearer_auth.d.ts +5 -1
- package/dist/auth/bearer_auth.d.ts.map +1 -1
- package/dist/auth/bearer_auth.js +13 -1
- package/dist/http/route_spec.d.ts +15 -0
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/surface.d.ts +6 -0
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +1 -0
- package/dist/runtime/deno.d.ts.map +1 -1
- package/dist/runtime/deno.js +8 -1
- package/dist/runtime/deps.d.ts +38 -1
- package/dist/runtime/deps.d.ts.map +1 -1
- package/dist/runtime/mock.d.ts.map +1 -1
- package/dist/runtime/mock.js +53 -3
- package/dist/runtime/node.d.ts.map +1 -1
- package/dist/runtime/node.js +17 -1
- package/dist/testing/cross_backend/setup.d.ts +33 -0
- package/dist/testing/cross_backend/setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/setup.js +19 -1
- package/dist/testing/cross_backend/standard.d.ts +19 -1
- package/dist/testing/cross_backend/standard.d.ts.map +1 -1
- package/dist/testing/cross_backend/standard.js +2 -0
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +14 -0
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +24 -1
- package/dist/testing/round_trip.d.ts +19 -1
- package/dist/testing/round_trip.d.ts.map +1 -1
- package/dist/testing/round_trip.js +75 -3
- package/dist/testing/rpc_round_trip.d.ts +23 -1
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +26 -1
- package/package.json +8 -7
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
* Bearer tokens are rejected when `Origin` or `Referer` headers are present —
|
|
5
5
|
* browsers must use cookie auth. This reduces attack surface: a stolen token
|
|
6
6
|
* cannot be replayed from a browser context (the browser adds `Origin`
|
|
7
|
-
* automatically).
|
|
7
|
+
* automatically). The discard is silent on the wire (anti-enumeration); in
|
|
8
|
+
* `DEV` only, the middleware adds an `X-Fuz-Auth-Debug:
|
|
9
|
+
* bearer_discarded_browser_context` response header so tests/tooling can tell
|
|
10
|
+
* "token discarded for browser context" apart from "no credential supplied"
|
|
11
|
+
* without weakening production.
|
|
8
12
|
*
|
|
9
13
|
* Token generation and hashing utilities live in `auth/api_token.ts`.
|
|
10
14
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bearer_auth.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bearer_auth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"bearer_auth.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bearer_auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,MAAM,CAAC;AAC5C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAIpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAA+B,KAAK,WAAW,EAAC,MAAM,oBAAoB,CAAC;AAElF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,SAAS,EACf,iBAAiB,WAAW,GAAG,IAAI,EACnC,KAAK,MAAM,KACT,iBAkFF,CAAC"}
|
package/dist/auth/bearer_auth.js
CHANGED
|
@@ -4,12 +4,17 @@
|
|
|
4
4
|
* Bearer tokens are rejected when `Origin` or `Referer` headers are present —
|
|
5
5
|
* browsers must use cookie auth. This reduces attack surface: a stolen token
|
|
6
6
|
* cannot be replayed from a browser context (the browser adds `Origin`
|
|
7
|
-
* automatically).
|
|
7
|
+
* automatically). The discard is silent on the wire (anti-enumeration); in
|
|
8
|
+
* `DEV` only, the middleware adds an `X-Fuz-Auth-Debug:
|
|
9
|
+
* bearer_discarded_browser_context` response header so tests/tooling can tell
|
|
10
|
+
* "token discarded for browser context" apart from "no credential supplied"
|
|
11
|
+
* without weakening production.
|
|
8
12
|
*
|
|
9
13
|
* Token generation and hashing utilities live in `auth/api_token.ts`.
|
|
10
14
|
*
|
|
11
15
|
* @module
|
|
12
16
|
*/
|
|
17
|
+
import { DEV } from 'esm-env';
|
|
13
18
|
import { AUTH_API_TOKEN_ID_KEY, ACCOUNT_ID_KEY, CREDENTIAL_TYPE_KEY } from '../hono_context.js';
|
|
14
19
|
import { query_validate_api_token } from './api_token_queries.js';
|
|
15
20
|
import { get_client_ip } from '../http/proxy.js';
|
|
@@ -65,6 +70,13 @@ export const create_bearer_auth_middleware = (deps, ip_rate_limiter, log) => {
|
|
|
65
70
|
// handle public actions or fall through to cookie auth.
|
|
66
71
|
if (c.req.header('Origin') !== undefined || c.req.header('Referer') !== undefined) {
|
|
67
72
|
log.debug('bearer auth rejected: browser context (Origin/Referer present)');
|
|
73
|
+
// The discard is silent on the wire by design (a stolen-token probe
|
|
74
|
+
// gets an indistinguishable 401, not a "your token was dropped"
|
|
75
|
+
// signal — anti-enumeration). That same silence makes the contract
|
|
76
|
+
// easy to trip over in tests/tooling, so surface the reason in DEV
|
|
77
|
+
// only: production never emits it, so it leaks nothing to an attacker.
|
|
78
|
+
if (DEV)
|
|
79
|
+
c.header('X-Fuz-Auth-Debug', 'bearer_discarded_browser_context');
|
|
68
80
|
await next();
|
|
69
81
|
return;
|
|
70
82
|
}
|
|
@@ -124,6 +124,21 @@ export interface RouteSpec {
|
|
|
124
124
|
input: z.ZodType;
|
|
125
125
|
/** Success response body schema. */
|
|
126
126
|
output: z.ZodType;
|
|
127
|
+
/**
|
|
128
|
+
* Marks a route whose request and/or response carries **raw bytes or a
|
|
129
|
+
* streaming protocol** rather than JSON — git smart-HTTP, file-store
|
|
130
|
+
* binary uploads/downloads, raw internal callbacks. Disambiguates the
|
|
131
|
+
* overloaded `input: z.null()`, which otherwise can't distinguish "no
|
|
132
|
+
* body" (`GET /health`) from "raw bytes" (a binary upload).
|
|
133
|
+
*
|
|
134
|
+
* Purely descriptive metadata — the dispatcher doesn't read it. Its one
|
|
135
|
+
* consumer is the schema-driven round-trip test suite, which auto-skips
|
|
136
|
+
* `raw_body` routes (it can neither synthesize a meaningful body nor
|
|
137
|
+
* assert a JSON output shape), so consumers no longer hand-maintain a
|
|
138
|
+
* `skip_routes` entry per binary route. Also surfaces in `AppSurfaceRoute`
|
|
139
|
+
* so generated docs render "raw" instead of a misleading `null` body.
|
|
140
|
+
*/
|
|
141
|
+
raw_body?: boolean;
|
|
127
142
|
/**
|
|
128
143
|
* Rate limit key type — declares what this route's rate limiter is keyed on.
|
|
129
144
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route_spec.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/route_spec.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"route_spec.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/route_spec.ts"],"names":[],"mappings":"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"}
|
package/dist/http/surface.d.ts
CHANGED
|
@@ -27,6 +27,12 @@ export interface AppSurfaceRoute {
|
|
|
27
27
|
is_mutation: boolean;
|
|
28
28
|
/** Whether this route's handler runs inside a database transaction. */
|
|
29
29
|
transaction: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Whether this route carries raw bytes / a streaming protocol rather than
|
|
32
|
+
* JSON (see `RouteSpec.raw_body`). When `true`, `input_schema` /
|
|
33
|
+
* `output_schema` being `null` means "raw bytes", not "no body".
|
|
34
|
+
*/
|
|
35
|
+
raw_body: boolean;
|
|
30
36
|
/** Rate limit key type declared on the route spec. `null` when not rate-limited. */
|
|
31
37
|
rate_limit_key: RateLimitKey | null;
|
|
32
38
|
/** JSON Schema representation of the URL path params schema. `null` when no params. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/surface.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/surface.ts"],"names":[],"mappings":"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"}
|
package/dist/http/surface.js
CHANGED
|
@@ -119,6 +119,7 @@ export const generate_app_surface = (options) => {
|
|
|
119
119
|
description: r.description,
|
|
120
120
|
is_mutation: r.method !== 'GET',
|
|
121
121
|
transaction: r.transaction ?? r.method !== 'GET',
|
|
122
|
+
raw_body: r.raw_body ?? false,
|
|
122
123
|
rate_limit_key: r.rate_limit ?? null,
|
|
123
124
|
params_schema: r.params ? schema_to_surface(r.params) : null,
|
|
124
125
|
query_schema: r.query ? schema_to_surface(r.query) : null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deno.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/runtime/deno.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,WAAW,EAA4B,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"deno.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/runtime/deno.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,WAAW,EAA4B,MAAM,WAAW,CAAC;AA0DtE;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,aAAa,CAAC,MAAM,CAAC,KAAG,WAmIhE,CAAC"}
|
package/dist/runtime/deno.js
CHANGED
|
@@ -29,7 +29,7 @@ export const create_deno_runtime = (args) => ({
|
|
|
29
29
|
stat: async (path) => {
|
|
30
30
|
try {
|
|
31
31
|
const s = await Deno.stat(path);
|
|
32
|
-
return { is_file: s.isFile, is_directory: s.isDirectory };
|
|
32
|
+
return { is_file: s.isFile, is_directory: s.isDirectory, size: s.size };
|
|
33
33
|
}
|
|
34
34
|
catch {
|
|
35
35
|
return null;
|
|
@@ -38,6 +38,13 @@ export const create_deno_runtime = (args) => ({
|
|
|
38
38
|
mkdir: (path, options) => Deno.mkdir(path, options),
|
|
39
39
|
read_text_file: (path) => Deno.readTextFile(path),
|
|
40
40
|
read_file: (path) => Deno.readFile(path),
|
|
41
|
+
read_file_stream: async (path) => (await Deno.open(path, { read: true })).readable,
|
|
42
|
+
write_file_stream: async (path, data) => {
|
|
43
|
+
const file = await Deno.open(path, { write: true, create: true, truncate: true });
|
|
44
|
+
// `pipeTo` closes the writable (and so the underlying file) on completion
|
|
45
|
+
// and aborts it on error — no manual `close()` needed.
|
|
46
|
+
await data.pipeTo(file.writable);
|
|
47
|
+
},
|
|
41
48
|
read_text_from_offset: async (path, offset) => {
|
|
42
49
|
const s = await Deno.stat(path);
|
|
43
50
|
const file_size = s.size;
|
package/dist/runtime/deps.d.ts
CHANGED
|
@@ -13,6 +13,17 @@
|
|
|
13
13
|
export interface StatResult {
|
|
14
14
|
is_file: boolean;
|
|
15
15
|
is_directory: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Byte length of a regular file. Meaningful only when `is_file` is true; for
|
|
18
|
+
* directories it is runtime-defined (real OS `stat` reports the directory
|
|
19
|
+
* entry's on-disk size, not 0 — only `create_mock_runtime` reports 0).
|
|
20
|
+
* Populated by every runtime factory (`create_node_runtime` /
|
|
21
|
+
* `create_deno_runtime` / `create_mock_runtime`); optional so loose test
|
|
22
|
+
* stubs that only assert `is_file` / `is_directory` don't have to supply it.
|
|
23
|
+
* Callers that need an exact size (e.g. a streaming upload's
|
|
24
|
+
* `Content-Length`) read it from a real runtime, where it is always present.
|
|
25
|
+
*/
|
|
26
|
+
size?: number;
|
|
16
27
|
}
|
|
17
28
|
/**
|
|
18
29
|
* Result of executing a command.
|
|
@@ -95,6 +106,32 @@ export interface FsWriteDeps {
|
|
|
95
106
|
/** Rename (move) a file. */
|
|
96
107
|
rename: (old_path: string, new_path: string) => Promise<void>;
|
|
97
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Streaming file I/O — read a file as a byte stream, or write a byte stream to
|
|
111
|
+
* a file, both bounded in memory (peak ≈ one chunk, not the whole file).
|
|
112
|
+
*
|
|
113
|
+
* Kept separate from `FsReadDeps` / `FsWriteDeps` so the whole-buffer
|
|
114
|
+
* `read_file` / `write_file` consumers and their partial test stubs are
|
|
115
|
+
* unaffected; only the full runtime factories implement these. Used for
|
|
116
|
+
* GB-scale artifact transfer (the `fuzf file get` / `put` path) where buffering
|
|
117
|
+
* the whole file would OOM the client.
|
|
118
|
+
*/
|
|
119
|
+
export interface FsStreamDeps {
|
|
120
|
+
/**
|
|
121
|
+
* Open a file as a `ReadableStream` of its bytes — read incrementally, so
|
|
122
|
+
* peak memory is one chunk rather than the whole file. Throws if the file
|
|
123
|
+
* does not exist. Use as a streaming upload body or for an incremental hash
|
|
124
|
+
* pass over a large file.
|
|
125
|
+
*/
|
|
126
|
+
read_file_stream: (path: string) => Promise<ReadableStream<Uint8Array>>;
|
|
127
|
+
/**
|
|
128
|
+
* Write a `ReadableStream` of bytes to a file, consuming it with
|
|
129
|
+
* backpressure (peak memory is one chunk). Creates or truncates `path`.
|
|
130
|
+
* Throws on any I/O error; a partially-written file may remain, so callers
|
|
131
|
+
* needing atomicity write to a temp path then `rename`.
|
|
132
|
+
*/
|
|
133
|
+
write_file_stream: (path: string, data: ReadableStream<Uint8Array>) => Promise<void>;
|
|
134
|
+
}
|
|
98
135
|
/**
|
|
99
136
|
* File system remove operations.
|
|
100
137
|
*/
|
|
@@ -155,7 +192,7 @@ export interface ProcessDeps {
|
|
|
155
192
|
* Functions should accept narrow `*Deps` interfaces, not this full type —
|
|
156
193
|
* this type is for the wiring layer that creates and passes the runtime.
|
|
157
194
|
*/
|
|
158
|
-
export interface RuntimeDeps extends EnvDeps, FsReadDeps, FsWriteDeps, FsRemoveDeps, CommandDeps, FetchDeps, TerminalDeps, ProcessDeps, LogDeps {
|
|
195
|
+
export interface RuntimeDeps extends EnvDeps, FsReadDeps, FsWriteDeps, FsStreamDeps, FsRemoveDeps, CommandDeps, FetchDeps, TerminalDeps, ProcessDeps, LogDeps {
|
|
159
196
|
/** Get all environment variables. */
|
|
160
197
|
env_all: () => Record<string, string>;
|
|
161
198
|
/** CLI arguments passed to the program. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deps.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/runtime/deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"deps.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/runtime/deps.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/runtime/mock.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAc,aAAa,EAAE,iBAAiB,EAAC,MAAM,WAAW,CAAC;AAIzF;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC/C,kCAAkC;IAClC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,0CAA0C;IAC1C,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,+CAA+C;IAC/C,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvC,mCAAmC;IACnC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,wCAAwC;IACxC,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,gGAAgG;IAChG,aAAa,EAAE,KAAK,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAAC,OAAO,CAAC,EAAE,iBAAiB,CAAA;KAAC,CAAC,CAAC;IACtF,sCAAsC;IACtC,qBAAqB,EAAE,KAAK,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;KAAC,CAAC,CAAC;IACjE,8BAA8B;IAC9B,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,4CAA4C;IAC5C,oBAAoB,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACjD,yCAAyC;IACzC,YAAY,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,4BAA4B;IAC5B,WAAW,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,WAAW,CAAA;KAAC,CAAC,CAAC;IACxE,wDAAwD;IACxD,oBAAoB,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CAC5C;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAM,KAAK,CAAC,MAAM,CAAM,KAAG,
|
|
1
|
+
{"version":3,"file":"mock.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/runtime/mock.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAc,aAAa,EAAE,iBAAiB,EAAC,MAAM,WAAW,CAAC;AAIzF;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC/C,kCAAkC;IAClC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,0CAA0C;IAC1C,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,+CAA+C;IAC/C,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvC,mCAAmC;IACnC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,wCAAwC;IACxC,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,gGAAgG;IAChG,aAAa,EAAE,KAAK,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAAC,OAAO,CAAC,EAAE,iBAAiB,CAAA;KAAC,CAAC,CAAC;IACtF,sCAAsC;IACtC,qBAAqB,EAAE,KAAK,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;KAAC,CAAC,CAAC;IACjE,8BAA8B;IAC9B,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,4CAA4C;IAC5C,oBAAoB,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACjD,yCAAyC;IACzC,YAAY,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,4BAA4B;IAC5B,WAAW,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,WAAW,CAAA;KAAC,CAAC,CAAC;IACxE,wDAAwD;IACxD,oBAAoB,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CAC5C;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAM,KAAK,CAAC,MAAM,CAAM,KAAG,WAoR9D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,WAAW,KAAG,IAazD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,SAAS,WAAW,EAAE,OAAO,MAAM,KAAG,IAEpE,CAAC;AAEF;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM;CAKxB"}
|
package/dist/runtime/mock.js
CHANGED
|
@@ -74,11 +74,16 @@ export const create_mock_runtime = (args = []) => {
|
|
|
74
74
|
},
|
|
75
75
|
// === Local File System ===
|
|
76
76
|
stat: async (path) => {
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
const bytes = mock_fs_bytes.get(path);
|
|
78
|
+
if (bytes !== undefined) {
|
|
79
|
+
return { is_file: true, is_directory: false, size: bytes.length };
|
|
80
|
+
}
|
|
81
|
+
const text = mock_fs.get(path);
|
|
82
|
+
if (text !== undefined) {
|
|
83
|
+
return { is_file: true, is_directory: false, size: new TextEncoder().encode(text).length };
|
|
79
84
|
}
|
|
80
85
|
if (mock_dirs.has(path)) {
|
|
81
|
-
return { is_file: false, is_directory: true };
|
|
86
|
+
return { is_file: false, is_directory: true, size: 0 };
|
|
82
87
|
}
|
|
83
88
|
return null;
|
|
84
89
|
},
|
|
@@ -117,6 +122,28 @@ export const create_mock_runtime = (args = []) => {
|
|
|
117
122
|
error.code = 'ENOENT';
|
|
118
123
|
throw error;
|
|
119
124
|
},
|
|
125
|
+
read_file_stream: async (path) => {
|
|
126
|
+
let bytes = mock_fs_bytes.get(path);
|
|
127
|
+
if (bytes === undefined) {
|
|
128
|
+
const content = mock_fs.get(path);
|
|
129
|
+
if (content !== undefined)
|
|
130
|
+
bytes = new TextEncoder().encode(content);
|
|
131
|
+
}
|
|
132
|
+
if (bytes === undefined) {
|
|
133
|
+
const error = new Error(`ENOENT: no such file or directory: ${path}`);
|
|
134
|
+
error.code = 'ENOENT';
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
// Single-chunk stream — the mock buffers in memory (fine for tests);
|
|
138
|
+
// real runtimes stream incrementally.
|
|
139
|
+
const data = bytes;
|
|
140
|
+
return new ReadableStream({
|
|
141
|
+
start(controller) {
|
|
142
|
+
controller.enqueue(data);
|
|
143
|
+
controller.close();
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
},
|
|
120
147
|
read_text_from_offset: async (path, offset) => {
|
|
121
148
|
let bytes;
|
|
122
149
|
const stored_bytes = mock_fs_bytes.get(path);
|
|
@@ -172,6 +199,29 @@ export const create_mock_runtime = (args = []) => {
|
|
|
172
199
|
write_file: async (path, data) => {
|
|
173
200
|
mock_fs_bytes.set(path, data);
|
|
174
201
|
},
|
|
202
|
+
write_file_stream: async (path, data) => {
|
|
203
|
+
// Drain the stream into one buffer (the mock has no real disk;
|
|
204
|
+
// real runtimes write incrementally with backpressure).
|
|
205
|
+
const chunks = [];
|
|
206
|
+
let total = 0;
|
|
207
|
+
const reader = data.getReader();
|
|
208
|
+
for (;;) {
|
|
209
|
+
const { done, value } = await reader.read();
|
|
210
|
+
if (done)
|
|
211
|
+
break;
|
|
212
|
+
if (value) {
|
|
213
|
+
chunks.push(value);
|
|
214
|
+
total += value.length;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const merged = new Uint8Array(total);
|
|
218
|
+
let offset = 0;
|
|
219
|
+
for (const chunk of chunks) {
|
|
220
|
+
merged.set(chunk, offset);
|
|
221
|
+
offset += chunk.length;
|
|
222
|
+
}
|
|
223
|
+
mock_fs_bytes.set(path, merged);
|
|
224
|
+
},
|
|
175
225
|
rename: async (old_path, new_path) => {
|
|
176
226
|
const content = mock_fs.get(old_path);
|
|
177
227
|
if (content !== undefined) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/runtime/node.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/runtime/node.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,OAAO,KAAK,EAAC,WAAW,EAA4B,MAAM,WAAW,CAAC;AAEtE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAC/B,OAAM,aAAa,CAAC,MAAM,CAAyB,KACjD,WAmLD,CAAC"}
|
package/dist/runtime/node.js
CHANGED
|
@@ -8,8 +8,11 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { Buffer } from 'node:buffer';
|
|
10
10
|
import { spawn } from 'node:child_process';
|
|
11
|
+
import { createReadStream, createWriteStream } from 'node:fs';
|
|
11
12
|
import { stat, mkdir, readFile, readdir, writeFile, rename, rm, open } from 'node:fs/promises';
|
|
12
13
|
import process from 'node:process';
|
|
14
|
+
import { Readable } from 'node:stream';
|
|
15
|
+
import { pipeline } from 'node:stream/promises';
|
|
13
16
|
/**
|
|
14
17
|
* Create a `RuntimeDeps` backed by Node.js APIs.
|
|
15
18
|
*
|
|
@@ -31,7 +34,7 @@ export const create_node_runtime = (args = process.argv.slice(2)) => ({
|
|
|
31
34
|
stat: async (path) => {
|
|
32
35
|
try {
|
|
33
36
|
const s = await stat(path);
|
|
34
|
-
return { is_file: s.isFile(), is_directory: s.isDirectory() };
|
|
37
|
+
return { is_file: s.isFile(), is_directory: s.isDirectory(), size: s.size };
|
|
35
38
|
}
|
|
36
39
|
catch {
|
|
37
40
|
return null;
|
|
@@ -42,6 +45,19 @@ export const create_node_runtime = (args = process.argv.slice(2)) => ({
|
|
|
42
45
|
},
|
|
43
46
|
read_text_file: (path) => readFile(path, 'utf-8'),
|
|
44
47
|
read_file: (path) => readFile(path).then((buf) => new Uint8Array(buf)),
|
|
48
|
+
// `Readable.toWeb` / `fromWeb` bridge Node streams to the web stream shape
|
|
49
|
+
// the interface speaks. The casts cross Node's `stream/web` ReadableStream
|
|
50
|
+
// and the global DOM `ReadableStream` (structurally identical here).
|
|
51
|
+
read_file_stream: async (path) => {
|
|
52
|
+
// `createReadStream` is lazy — a missing file surfaces as a stream `error`
|
|
53
|
+
// event at consume time, not at the call. `stat` first so we honor the
|
|
54
|
+
// interface's eager-throw contract (matching Deno/mock).
|
|
55
|
+
await stat(path);
|
|
56
|
+
return Readable.toWeb(createReadStream(path));
|
|
57
|
+
},
|
|
58
|
+
write_file_stream: async (path, data) => {
|
|
59
|
+
await pipeline(Readable.fromWeb(data), createWriteStream(path));
|
|
60
|
+
},
|
|
45
61
|
read_text_from_offset: async (path, offset) => {
|
|
46
62
|
const s = await stat(path);
|
|
47
63
|
const file_size = s.size;
|
|
@@ -140,6 +140,19 @@ export interface TestFixtureBase {
|
|
|
140
140
|
* for suites that don't declare any.
|
|
141
141
|
*/
|
|
142
142
|
readonly extra_accounts: Readonly<Record<string, ExtraAccountFixture>>;
|
|
143
|
+
/**
|
|
144
|
+
* Additional actors seeded on the **keeper** account (beyond its single
|
|
145
|
+
* bootstrap `actor`), in declaration order. Populated from the
|
|
146
|
+
* `extra_actors` option. Empty unless a suite declares any. Use to drive
|
|
147
|
+
* the multi-actor `acting`-selector branches: with `extra_actors` non-empty
|
|
148
|
+
* the keeper has >1 actor, so a keeper request omitting `acting` resolves
|
|
149
|
+
* to `actor_required` with these ids in its `available[]` list. Each id is
|
|
150
|
+
* a valid `acting` value the keeper can supply explicitly.
|
|
151
|
+
*/
|
|
152
|
+
readonly extra_actors: ReadonlyArray<{
|
|
153
|
+
readonly id: Uuid;
|
|
154
|
+
readonly name: string;
|
|
155
|
+
}>;
|
|
143
156
|
/**
|
|
144
157
|
* Forge an *expired server-side session* for the keeper account and
|
|
145
158
|
* return the ready-to-send `Cookie` header value (`name=value`). The
|
|
@@ -187,6 +200,13 @@ export interface InProcessSetupOptions extends CreateTestAppOptions {
|
|
|
187
200
|
* `describe_standard_admin_integration_tests`) is the primary user.
|
|
188
201
|
*/
|
|
189
202
|
readonly extra_accounts?: ReadonlyArray<ExtraAccountSpec>;
|
|
203
|
+
/**
|
|
204
|
+
* Additional actor names to seed on the bootstrapped keeper — exposed on
|
|
205
|
+
* `fixture.extra_actors`. See `CrossProcessSetupOptions.extra_actors` /
|
|
206
|
+
* `TestFixtureBase.extra_actors`. Seeded directly against the live backend
|
|
207
|
+
* DB (in-process has no wire hop).
|
|
208
|
+
*/
|
|
209
|
+
readonly extra_actors?: ReadonlyArray<string>;
|
|
190
210
|
}
|
|
191
211
|
/**
|
|
192
212
|
* Build a `SetupTest` that creates a fresh `TestApp` per call via
|
|
@@ -321,6 +341,14 @@ export interface CrossProcessSetupOptions {
|
|
|
321
341
|
* transaction as the keeper.
|
|
322
342
|
*/
|
|
323
343
|
readonly extra_accounts?: ReadonlyArray<ExtraAccountSpec>;
|
|
344
|
+
/**
|
|
345
|
+
* Additional actor names to seed on the keeper account, beyond its
|
|
346
|
+
* single bootstrap actor — exposed on `fixture.extra_actors`. Declare
|
|
347
|
+
* to put the keeper into a multi-actor state so the `actor_required` /
|
|
348
|
+
* explicit-`acting` branches are reachable cross-process. See
|
|
349
|
+
* `TestFixtureBase.extra_actors`.
|
|
350
|
+
*/
|
|
351
|
+
readonly extra_actors?: ReadonlyArray<string>;
|
|
324
352
|
}
|
|
325
353
|
/**
|
|
326
354
|
* Capture a backend's schema snapshot over the `_testing_schema_snapshot`
|
|
@@ -399,6 +427,11 @@ export interface DefaultInProcessSuiteOptions {
|
|
|
399
427
|
* transport.
|
|
400
428
|
*/
|
|
401
429
|
extra_accounts?: ReadonlyArray<ExtraAccountSpec>;
|
|
430
|
+
/**
|
|
431
|
+
* Additional actor names to seed on the bootstrapped keeper — exposed on
|
|
432
|
+
* `fixture.extra_actors`. See `TestFixtureBase.extra_actors`.
|
|
433
|
+
*/
|
|
434
|
+
extra_actors?: ReadonlyArray<string>;
|
|
402
435
|
/**
|
|
403
436
|
* Pre-built `AppSurfaceSpec` — overrides the default which calls
|
|
404
437
|
* `create_test_app_surface_spec` against the same factory inputs.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/setup.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAuB9B,OAAO,EAAC,IAAI,EAAC,MAAM,wBAAwB,CAAC;AAE5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAC,gBAAgB,EAAE,sBAAsB,EAAC,MAAM,4BAA4B,CAAC;AACzF,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,6 +21,7 @@ import '../assert_dev_env.js';
|
|
|
21
21
|
import { z } from 'zod';
|
|
22
22
|
import { Uuid } from '@fuzdev/fuz_util/id.js';
|
|
23
23
|
import { ROLE_KEEPER } from '../../auth/role_schema.js';
|
|
24
|
+
import { query_create_actor } from '../../auth/account_queries.js';
|
|
24
25
|
import { DAEMON_TOKEN_HEADER } from '../../auth/daemon_token.js';
|
|
25
26
|
import { USERNAME_LENGTH_MAX } from '../../primitive_schemas.js';
|
|
26
27
|
import { create_test_app, create_test_account_with_credentials, mint_test_session, DEFAULT_TEST_PASSWORD, } from '../app_server.js';
|
|
@@ -109,6 +110,15 @@ export const default_in_process_setup = (options) => async () => {
|
|
|
109
110
|
});
|
|
110
111
|
extra_accounts[spec.username] = build_extra_account_fixture(seeded, cookie_name);
|
|
111
112
|
}
|
|
113
|
+
// Seed additional keeper actors directly against the same DB. Mirrors
|
|
114
|
+
// the cross-process `_testing_reset` `extra_actors` path; no production
|
|
115
|
+
// wire mints a second actor, so this bootstrap-cradle insert is the
|
|
116
|
+
// only way into a multi-actor keeper state.
|
|
117
|
+
const extra_actors = [];
|
|
118
|
+
for (const name of options.extra_actors ?? []) {
|
|
119
|
+
const seeded_actor = await query_create_actor({ db: test_app.backend.deps.db }, test_app.backend.account.id, name);
|
|
120
|
+
extra_actors.push({ id: seeded_actor.id, name: seeded_actor.name });
|
|
121
|
+
}
|
|
112
122
|
return {
|
|
113
123
|
transport: in_process_fetch_transport(test_app.app),
|
|
114
124
|
// In-process the wrapper is stateless and never auto-adds Origin —
|
|
@@ -122,6 +132,7 @@ export const default_in_process_setup = (options) => async () => {
|
|
|
122
132
|
create_daemon_token_headers: test_app.create_daemon_token_headers,
|
|
123
133
|
create_account: test_app.create_account,
|
|
124
134
|
extra_accounts,
|
|
135
|
+
extra_actors,
|
|
125
136
|
// Forge directly against the live backend's DB + keyring — no wire
|
|
126
137
|
// hop needed in-process.
|
|
127
138
|
mint_expired_session: async () => {
|
|
@@ -270,6 +281,7 @@ const TestingResetResponseShape = z.object({
|
|
|
270
281
|
api_token: z.string(),
|
|
271
282
|
session_cookie: z.string(),
|
|
272
283
|
})),
|
|
284
|
+
extra_actors: z.array(z.object({ id: Uuid, name: z.string() })),
|
|
273
285
|
});
|
|
274
286
|
/**
|
|
275
287
|
* Fire the `_testing_reset` RPC action over the keeper's daemon-token
|
|
@@ -286,6 +298,7 @@ const fire_testing_reset = async (handle, options) => {
|
|
|
286
298
|
...(spec.password_value !== undefined && { password_value: spec.password_value }),
|
|
287
299
|
roles: [...spec.roles],
|
|
288
300
|
})),
|
|
301
|
+
extra_actors: [...(options.extra_actors ?? [])],
|
|
289
302
|
}, handle.config.name, { [DAEMON_TOKEN_HEADER]: handle.daemon_token });
|
|
290
303
|
const parsed = TestingResetResponseShape.safeParse(raw);
|
|
291
304
|
if (!parsed.success) {
|
|
@@ -299,6 +312,7 @@ const fire_testing_reset = async (handle, options) => {
|
|
|
299
312
|
session_cookie: parsed.data.session_cookie,
|
|
300
313
|
},
|
|
301
314
|
extra_accounts: parsed.data.extra_accounts,
|
|
315
|
+
extra_actors: parsed.data.extra_actors,
|
|
302
316
|
};
|
|
303
317
|
};
|
|
304
318
|
/**
|
|
@@ -463,11 +477,13 @@ const create_keeper_transport = (handle, cookie_name, session_cookie) => create_
|
|
|
463
477
|
export const default_cross_process_setup = (handle, options) => {
|
|
464
478
|
const extra_keeper_roles = options?.extra_keeper_roles ?? [];
|
|
465
479
|
const extra_account_specs = options?.extra_accounts ?? [];
|
|
480
|
+
const extra_actor_names = options?.extra_actors ?? [];
|
|
466
481
|
const { cookie_name } = handle.config;
|
|
467
482
|
return async () => {
|
|
468
|
-
const { keeper, extra_accounts: seeded_extras } = await fire_testing_reset(handle, {
|
|
483
|
+
const { keeper, extra_accounts: seeded_extras, extra_actors, } = await fire_testing_reset(handle, {
|
|
469
484
|
extra_keeper_roles,
|
|
470
485
|
extra_accounts: extra_account_specs,
|
|
486
|
+
extra_actors: extra_actor_names,
|
|
471
487
|
});
|
|
472
488
|
// Rebuild the keeper transport with the new session cookie — the
|
|
473
489
|
// reset action wiped the `globalSetup` keeper's auth_session row,
|
|
@@ -550,6 +566,7 @@ export const default_cross_process_setup = (handle, options) => {
|
|
|
550
566
|
create_daemon_token_headers,
|
|
551
567
|
create_account,
|
|
552
568
|
extra_accounts,
|
|
569
|
+
extra_actors,
|
|
553
570
|
// Forge over the wire — the cross-process driver has no keyring,
|
|
554
571
|
// so `_testing_mint_session` mints the backdated row + signs the
|
|
555
572
|
// cookie server-side over the keeper's daemon-token channel.
|
|
@@ -613,6 +630,7 @@ export const default_in_process_suite_options = (options) => ({
|
|
|
613
630
|
app_options: options.app_options,
|
|
614
631
|
roles: [ROLE_KEEPER, ...(options.extra_keeper_roles ?? [])],
|
|
615
632
|
extra_accounts: options.extra_accounts,
|
|
633
|
+
extra_actors: options.extra_actors,
|
|
616
634
|
}),
|
|
617
635
|
surface_source: options.surface_source ??
|
|
618
636
|
create_test_app_surface_spec({
|
|
@@ -43,7 +43,7 @@ import type { RoleSchemaResult } from '../../auth/role_schema.js';
|
|
|
43
43
|
import type { AppSurfaceSpec } from '../../http/surface.js';
|
|
44
44
|
import type { RpcEndpointsSuiteOption } from '../rpc_helpers.js';
|
|
45
45
|
import type { BackendCapabilities } from './capabilities.js';
|
|
46
|
-
import type { SetupTest } from './setup.js';
|
|
46
|
+
import type { SetupTest, TestFixture } from './setup.js';
|
|
47
47
|
/**
|
|
48
48
|
* Configuration for `describe_standard_cross_process_tests`.
|
|
49
49
|
*
|
|
@@ -94,6 +94,24 @@ export interface StandardCrossProcessTestOptions {
|
|
|
94
94
|
* / `info/refs`) which stream git protocol bytes.
|
|
95
95
|
*/
|
|
96
96
|
round_trip_skip_routes?: Array<string>;
|
|
97
|
+
/**
|
|
98
|
+
* Forwarded to `describe_rpc_round_trip_tests` as `success_fixtures`
|
|
99
|
+
* (method name → async params factory). Drives a populated **success**
|
|
100
|
+
* body for referential RPC reads (`*_get`, `*_log`) the nil-id round-trip
|
|
101
|
+
* can only ever error on, and validates it against the method's `output`
|
|
102
|
+
* schema on each backend — the success-shape parity check. See
|
|
103
|
+
* `RpcRoundTripTestOptions.success_fixtures`.
|
|
104
|
+
*/
|
|
105
|
+
rpc_success_fixtures?: Map<string, (fixture: TestFixture) => Promise<Record<string, unknown>>>;
|
|
106
|
+
/**
|
|
107
|
+
* Forwarded to `describe_round_trip_validation` as `success_fixtures`
|
|
108
|
+
* (`'METHOD /path'` → async `{url?, body?}` factory) for referential REST
|
|
109
|
+
* routes. See `RoundTripTestOptions.success_fixtures`.
|
|
110
|
+
*/
|
|
111
|
+
rest_success_fixtures?: Map<string, (fixture: TestFixture) => Promise<{
|
|
112
|
+
url?: string;
|
|
113
|
+
body?: Record<string, unknown>;
|
|
114
|
+
}>>;
|
|
97
115
|
}
|
|
98
116
|
/**
|
|
99
117
|
* Run the cross-process standard test bundle — integration, admin (when
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"standard.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/standard.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAM1D,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"standard.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/standard.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAM1D,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAC,SAAS,EAAE,WAAW,EAAC,MAAM,YAAY,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,WAAW,+BAA+B;IAC/C,2CAA2C;IAC3C,UAAU,EAAE,SAAS,CAAC;IACtB;;;OAGG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uCAAuC;IACvC,YAAY,EAAE,mBAAmB,CAAC;IAClC,uFAAuF;IACvF,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;OAGG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACvC;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/F;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,GAAG,CAC1B,MAAM,EACN,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAC,CAAC,CACjF,CAAC;CACF;AAED;;;;GAIG;AACH,eAAO,MAAM,qCAAqC,GACjD,SAAS,+BAA+B,KACtC,IAwCF,CAAC"}
|
|
@@ -23,6 +23,7 @@ export const describe_standard_cross_process_tests = (options) => {
|
|
|
23
23
|
surface_source: options.surface_source,
|
|
24
24
|
capabilities: options.capabilities,
|
|
25
25
|
skip_routes: options.round_trip_skip_routes,
|
|
26
|
+
success_fixtures: options.rest_success_fixtures,
|
|
26
27
|
});
|
|
27
28
|
describe_rpc_round_trip_tests({
|
|
28
29
|
setup_test: options.setup_test,
|
|
@@ -30,6 +31,7 @@ export const describe_standard_cross_process_tests = (options) => {
|
|
|
30
31
|
capabilities: options.capabilities,
|
|
31
32
|
session_options: options.session_options,
|
|
32
33
|
rpc_endpoints: options.rpc_endpoints,
|
|
34
|
+
success_fixtures: options.rpc_success_fixtures,
|
|
33
35
|
});
|
|
34
36
|
describe_data_exposure_tests({
|
|
35
37
|
setup_test: options.setup_test,
|
|
@@ -106,6 +106,16 @@ export declare const testing_reset_action_spec: {
|
|
|
106
106
|
password_value: z.ZodOptional<z.ZodString>;
|
|
107
107
|
roles: z.ZodArray<z.ZodString>;
|
|
108
108
|
}, z.core.$strict>>>;
|
|
109
|
+
/**
|
|
110
|
+
* Additional actor names to seed on the **keeper** account, beyond
|
|
111
|
+
* its single bootstrap actor. Drives the multi-actor `acting`
|
|
112
|
+
* selector branches (omitted `acting` + >1 actor ⇒ `actor_required`
|
|
113
|
+
* with the `available[]` list) that are otherwise unreachable
|
|
114
|
+
* cross-process — account creation only ever mints one actor, and no
|
|
115
|
+
* production wire path adds a second. Bootstrap-cradle seeding, same
|
|
116
|
+
* rationale as `extra_accounts`.
|
|
117
|
+
*/
|
|
118
|
+
extra_actors: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
109
119
|
}, z.core.$strict>;
|
|
110
120
|
readonly output: z.ZodObject<{
|
|
111
121
|
account: z.ZodObject<{
|
|
@@ -128,6 +138,10 @@ export declare const testing_reset_action_spec: {
|
|
|
128
138
|
api_token: z.ZodString;
|
|
129
139
|
session_cookie: z.ZodString;
|
|
130
140
|
}, z.core.$strict>>;
|
|
141
|
+
extra_actors: z.ZodArray<z.ZodObject<{
|
|
142
|
+
id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
143
|
+
name: z.ZodString;
|
|
144
|
+
}, z.core.$strict>>;
|
|
131
145
|
}, z.core.$strict>;
|
|
132
146
|
readonly async: true;
|
|
133
147
|
readonly description: "Test-binary only — wipe auth tables, re-bootstrap a fresh keeper (+ optional extras), fire the domain-state reset.";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing_reset_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_reset_actions.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAEvE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"testing_reset_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_reset_actions.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAEvE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,gBAAgB,CAAC;AAmBvC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;QAiBpC;;;;;;;;WAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWyC,CAAC;AAE/C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;CAWA,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;CAeC,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,QAAO,SACiB,CAAC;AAEzE;;;;;;;;;GASG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWF,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,qCAAqC,QAAO,SAGvD,CAAC;AAEH,4CAA4C;AAC5C,MAAM,WAAW,2BAA2B;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;IAC9C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxD;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,OAAO,EACb,SAAS,2BAA2B,KAClC,KAAK,CAAC,SAAS,CAsHjB,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,0BAA0B,UAAmC,CAAC"}
|
|
@@ -64,6 +64,7 @@ import { rpc_action } from '../../actions/action_rpc.js';
|
|
|
64
64
|
import { ROLE_ADMIN, ROLE_KEEPER } from '../../auth/role_schema.js';
|
|
65
65
|
import { auth_integration_truncate_tables } from '../db.js';
|
|
66
66
|
import { query_schema_snapshot, SchemaSnapshot } from '../schema_introspect.js';
|
|
67
|
+
import { query_create_actor } from '../../auth/account_queries.js';
|
|
67
68
|
import { create_test_account_with_credentials, mint_test_session, DEFAULT_TEST_PASSWORD, } from '../app_server.js';
|
|
68
69
|
/** Output shape for an individual seeded account (keeper or extra). */
|
|
69
70
|
const SeededAccountShape = z.strictObject({
|
|
@@ -112,9 +113,21 @@ export const testing_reset_action_spec = {
|
|
|
112
113
|
roles: z.array(z.string()),
|
|
113
114
|
}))
|
|
114
115
|
.optional(),
|
|
116
|
+
/**
|
|
117
|
+
* Additional actor names to seed on the **keeper** account, beyond
|
|
118
|
+
* its single bootstrap actor. Drives the multi-actor `acting`
|
|
119
|
+
* selector branches (omitted `acting` + >1 actor ⇒ `actor_required`
|
|
120
|
+
* with the `available[]` list) that are otherwise unreachable
|
|
121
|
+
* cross-process — account creation only ever mints one actor, and no
|
|
122
|
+
* production wire path adds a second. Bootstrap-cradle seeding, same
|
|
123
|
+
* rationale as `extra_accounts`.
|
|
124
|
+
*/
|
|
125
|
+
extra_actors: z.array(z.string()).optional(),
|
|
115
126
|
}),
|
|
116
127
|
output: SeededAccountShape.extend({
|
|
117
128
|
extra_accounts: z.array(SeededAccountShape),
|
|
129
|
+
/** The keeper's additional actors (from input `extra_actors`), in order. */
|
|
130
|
+
extra_actors: z.array(z.strictObject({ id: Uuid, name: z.string() })),
|
|
118
131
|
}),
|
|
119
132
|
async: true,
|
|
120
133
|
description: 'Test-binary only — wipe auth tables, re-bootstrap a fresh keeper (+ optional extras), fire the domain-state reset.',
|
|
@@ -301,6 +314,16 @@ export const create_testing_actions = (deps, options) => {
|
|
|
301
314
|
});
|
|
302
315
|
extras.push(seeded);
|
|
303
316
|
}
|
|
317
|
+
// 5b. Seed any additional keeper actors. Same bootstrap-cradle
|
|
318
|
+
// bypass as extra_accounts — no production wire path mints a
|
|
319
|
+
// second actor, so the multi-actor `acting` branches need this
|
|
320
|
+
// direct insert. Order-preserving so the fixture can address
|
|
321
|
+
// them positionally.
|
|
322
|
+
const extra_actors = [];
|
|
323
|
+
for (const name of input.extra_actors ?? []) {
|
|
324
|
+
const seeded_actor = await query_create_actor({ db: ctx.db }, keeper.account.id, name);
|
|
325
|
+
extra_actors.push({ id: seeded_actor.id, name: seeded_actor.name });
|
|
326
|
+
}
|
|
304
327
|
// 6. Refresh the daemon-token cache so subsequent daemon-token
|
|
305
328
|
// requests resolve to the freshly seeded keeper. The
|
|
306
329
|
// middleware's lazy-refresh path only fires when the cached
|
|
@@ -314,7 +337,7 @@ export const create_testing_actions = (deps, options) => {
|
|
|
314
337
|
// against this open transaction under PGlite.
|
|
315
338
|
if (reset_state)
|
|
316
339
|
await reset_state(ctx.db);
|
|
317
|
-
return { ...keeper, extra_accounts: extras };
|
|
340
|
+
return { ...keeper, extra_accounts: extras, extra_actors };
|
|
318
341
|
}),
|
|
319
342
|
rpc_action(testing_mint_session_action_spec, async (input, ctx) => {
|
|
320
343
|
const { session_cookie } = await mint_test_session({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import './assert_dev_env.js';
|
|
2
2
|
import type { BackendCapabilities } from './cross_backend/capabilities.js';
|
|
3
|
-
import type { SetupTest } from './cross_backend/setup.js';
|
|
3
|
+
import type { SetupTest, TestFixture } from './cross_backend/setup.js';
|
|
4
4
|
import type { AppSurfaceSpec } from '../http/surface.js';
|
|
5
5
|
/** Options for `describe_round_trip_validation`. */
|
|
6
6
|
export interface RoundTripTestOptions {
|
|
@@ -22,6 +22,24 @@ export interface RoundTripTestOptions {
|
|
|
22
22
|
skip_routes?: Array<string>;
|
|
23
23
|
/** Override generated bodies for specific routes (`'METHOD /path'` → body). */
|
|
24
24
|
input_overrides?: Map<string, Record<string, unknown>>;
|
|
25
|
+
/**
|
|
26
|
+
* Success-case fixtures for routes whose **populated success body** the
|
|
27
|
+
* generic nil-id input can't reach — referential REST routes whose path
|
|
28
|
+
* params / body must point at existing rows. Maps `'METHOD /path'` to an
|
|
29
|
+
* async factory that receives the per-test `fixture` (so it can seed the
|
|
30
|
+
* referenced state) and returns `{url?, body?}`: an explicit resolved `url`
|
|
31
|
+
* (when the factory built it from the ids it just seeded) and/or a request
|
|
32
|
+
* `body`. Omit `url` to fall back to the generated valid path.
|
|
33
|
+
*
|
|
34
|
+
* Distinct from `input_overrides` (body-only, accepts a valid error
|
|
35
|
+
* envelope): a `success_fixtures` entry **asserts a 2xx response** and
|
|
36
|
+
* validates it against the route's `output` schema — the success-shape
|
|
37
|
+
* parity check the nil-id round-trip can't perform.
|
|
38
|
+
*/
|
|
39
|
+
success_fixtures?: Map<string, (fixture: TestFixture) => Promise<{
|
|
40
|
+
url?: string;
|
|
41
|
+
body?: Record<string, unknown>;
|
|
42
|
+
}>>;
|
|
25
43
|
}
|
|
26
44
|
/**
|
|
27
45
|
* Run schema-driven round-trip validation tests.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA2B7B,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAE,WAAW,EAAC,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAGvD,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACpC;;;;;OAKG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;OAGG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,6EAA6E;IAC7E,YAAY,EAAE,mBAAmB,CAAC;IAClC,kDAAkD;IAClD,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5B,+EAA+E;IAC/E,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD;;;;;;;;;;;;;OAaG;IACH,gBAAgB,CAAC,EAAE,GAAG,CACrB,MAAM,EACN,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAC,CAAC,CACjF,CAAC;CACF;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,8BAA8B,GAAI,SAAS,oBAAoB,KAAG,IAyI9E,CAAC"}
|
|
@@ -16,8 +16,9 @@ import './assert_dev_env.js';
|
|
|
16
16
|
*
|
|
17
17
|
* @module
|
|
18
18
|
*/
|
|
19
|
-
import { describe, test, beforeAll } from 'vitest';
|
|
19
|
+
import { describe, test, beforeAll, assert } from 'vitest';
|
|
20
20
|
import { ROLE_ADMIN } from '../auth/role_schema.js';
|
|
21
|
+
import { is_public_auth, needs_actor, input_schema_declares_acting } from '../http/auth_shape.js';
|
|
21
22
|
import { assert_response_matches_spec, pick_auth_headers } from './integration_helpers.js';
|
|
22
23
|
import { resolve_valid_path, generate_valid_body } from './schema_generators.js';
|
|
23
24
|
/**
|
|
@@ -54,14 +55,51 @@ export const describe_round_trip_validation = (options) => {
|
|
|
54
55
|
roles: [ROLE_ADMIN],
|
|
55
56
|
});
|
|
56
57
|
});
|
|
58
|
+
// Mirror `pick_auth_headers`' account selection to recover the actor id
|
|
59
|
+
// of whichever account it authed as — so an `actor: 'required'` route
|
|
60
|
+
// that declares `acting?: ActingActor` gets the matching actor supplied
|
|
61
|
+
// explicitly (its sole actor, here), rather than relying on implicit
|
|
62
|
+
// single-actor resolution. Keeps such routes drivable without a
|
|
63
|
+
// consumer skip-list entry. Returns `null` for public routes.
|
|
64
|
+
const pick_acting_actor_id = (spec) => {
|
|
65
|
+
const { auth } = spec;
|
|
66
|
+
if (is_public_auth(auth))
|
|
67
|
+
return null;
|
|
68
|
+
if (auth.credential_types?.includes('daemon_token'))
|
|
69
|
+
return fixture.actor.id;
|
|
70
|
+
if (auth.roles?.length) {
|
|
71
|
+
return auth.roles.includes(ROLE_ADMIN) ? admin_account.actor.id : fixture.actor.id;
|
|
72
|
+
}
|
|
73
|
+
return authed_account.actor.id;
|
|
74
|
+
};
|
|
57
75
|
test.each(describe_time_specs)('$method $path produces schema-valid response', async (spec) => {
|
|
58
76
|
const route_key = `${spec.method} ${spec.path}`;
|
|
59
77
|
if (skip_set.has(route_key))
|
|
60
78
|
return;
|
|
79
|
+
// Raw-byte / streaming routes (git smart-HTTP, binary upload/download)
|
|
80
|
+
// can't be round-tripped — no meaningful body to synthesize, no JSON
|
|
81
|
+
// shape to assert. Auto-skip by the spec marker rather than making
|
|
82
|
+
// every consumer hand-list them in `skip_routes`.
|
|
83
|
+
if (spec.raw_body)
|
|
84
|
+
return;
|
|
61
85
|
const url = resolve_valid_path(spec.path, spec.params);
|
|
62
86
|
const override = options.input_overrides?.get(route_key);
|
|
63
|
-
|
|
87
|
+
let body = override ?? generate_valid_body(spec.input);
|
|
64
88
|
const headers = pick_auth_headers(spec, fixture, authed_account, admin_account);
|
|
89
|
+
// Auto-supply `acting` for actor-required routes that declare it. The
|
|
90
|
+
// `actor !== 'none' ⟺ acting declared` registry invariant means a
|
|
91
|
+
// route either declares `acting` in `query` (REST GET/body-less) or
|
|
92
|
+
// `input` — supply the picked account's actor in the matching channel.
|
|
93
|
+
let request_url = url;
|
|
94
|
+
const acting_id = needs_actor(spec.auth) ? pick_acting_actor_id(spec) : null;
|
|
95
|
+
if (acting_id !== null) {
|
|
96
|
+
if (spec.query && input_schema_declares_acting(spec.query)) {
|
|
97
|
+
request_url = `${url}${url.includes('?') ? '&' : '?'}acting=${acting_id}`;
|
|
98
|
+
}
|
|
99
|
+
else if (input_schema_declares_acting(spec.input) && body) {
|
|
100
|
+
body = { ...body, acting: acting_id };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
65
103
|
const request_init = {
|
|
66
104
|
method: spec.method,
|
|
67
105
|
headers: {
|
|
@@ -70,7 +108,7 @@ export const describe_round_trip_validation = (options) => {
|
|
|
70
108
|
},
|
|
71
109
|
...(body ? { body: JSON.stringify(body) } : {}),
|
|
72
110
|
};
|
|
73
|
-
const res = await fixture.transport(
|
|
111
|
+
const res = await fixture.transport(request_url, request_init);
|
|
74
112
|
if (res.headers.get('Content-Type')?.includes('text/event-stream')) {
|
|
75
113
|
await res.body?.cancel();
|
|
76
114
|
return;
|
|
@@ -82,5 +120,39 @@ export const describe_round_trip_validation = (options) => {
|
|
|
82
120
|
throw new Error(`Round-trip validation failed for ${route_key} (status ${res.status}): ${e.message}`);
|
|
83
121
|
}
|
|
84
122
|
});
|
|
123
|
+
test('declared success fixtures produce schema-valid success bodies', async () => {
|
|
124
|
+
const success_fixtures = options.success_fixtures;
|
|
125
|
+
if (!success_fixtures || success_fixtures.size === 0)
|
|
126
|
+
return;
|
|
127
|
+
for (const [route_key, build] of success_fixtures) {
|
|
128
|
+
const space = route_key.indexOf(' ');
|
|
129
|
+
const method = route_key.slice(0, space);
|
|
130
|
+
const path = route_key.slice(space + 1);
|
|
131
|
+
const spec = describe_time_specs.find((s) => s.method === method && s.path === path);
|
|
132
|
+
assert.ok(spec, `success_fixtures references unknown route '${route_key}'`);
|
|
133
|
+
const seeded = await build(fixture);
|
|
134
|
+
const url = seeded.url ?? resolve_valid_path(spec.path, spec.params);
|
|
135
|
+
const body = seeded.body;
|
|
136
|
+
const headers = pick_auth_headers(spec, fixture, authed_account, admin_account);
|
|
137
|
+
const res = await fixture.transport(url, {
|
|
138
|
+
method: spec.method,
|
|
139
|
+
headers: {
|
|
140
|
+
...headers,
|
|
141
|
+
...(body ? { 'content-type': 'application/json' } : {}),
|
|
142
|
+
},
|
|
143
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
144
|
+
});
|
|
145
|
+
try {
|
|
146
|
+
assert.ok(res.ok, `success fixture expected a 2xx response, got status ${res.status}: ${await res
|
|
147
|
+
.clone()
|
|
148
|
+
.text()
|
|
149
|
+
.catch(() => '<unreadable>')}`);
|
|
150
|
+
await assert_response_matches_spec(describe_time_specs, spec.method, url, res);
|
|
151
|
+
}
|
|
152
|
+
catch (e) {
|
|
153
|
+
throw new Error(`Round-trip success-fixture failed for ${route_key} (status ${res.status}): ${e.message}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
85
157
|
});
|
|
86
158
|
};
|
|
@@ -2,7 +2,7 @@ import './assert_dev_env.js';
|
|
|
2
2
|
import type { AppSurfaceSpec } from '../http/surface.js';
|
|
3
3
|
import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
|
|
4
4
|
import type { BackendCapabilities } from './cross_backend/capabilities.js';
|
|
5
|
-
import type { SetupTest } from './cross_backend/setup.js';
|
|
5
|
+
import type { SetupTest, TestFixture } from './cross_backend/setup.js';
|
|
6
6
|
import type { SessionOptions } from '../auth/session_cookie.js';
|
|
7
7
|
/** Options for `describe_rpc_round_trip_tests`. */
|
|
8
8
|
export interface RpcRoundTripTestOptions {
|
|
@@ -34,6 +34,28 @@ export interface RpcRoundTripTestOptions {
|
|
|
34
34
|
skip_methods?: Array<string>;
|
|
35
35
|
/** Override generated params for specific methods (method name → params). */
|
|
36
36
|
input_overrides?: Map<string, Record<string, unknown>>;
|
|
37
|
+
/**
|
|
38
|
+
* Success-case fixtures for methods whose **populated success body** the
|
|
39
|
+
* generic nil-id input can't reach — referential reads (`*_get`, `*_log`)
|
|
40
|
+
* whose required ids must point at existing rows. Maps method name to an
|
|
41
|
+
* async factory that receives the per-test `fixture` (so it can seed the
|
|
42
|
+
* referenced state — e.g. create a repo via `fixture.transport` +
|
|
43
|
+
* `fixture.create_session_headers()`) and returns the params that drive a
|
|
44
|
+
* **success** response.
|
|
45
|
+
*
|
|
46
|
+
* Distinct from `input_overrides`, which only swaps the request params; the
|
|
47
|
+
* response may still be a valid *error* envelope (missing-row `not_found`),
|
|
48
|
+
* which the generic loop accepts. A `success_fixtures` entry **asserts the
|
|
49
|
+
* response is `ok`** and validates `result` against the method's `output`
|
|
50
|
+
* schema — so a backend that drops a field, or errors where the other
|
|
51
|
+
* backend succeeds, fails loud. This is the success-shape parity check the
|
|
52
|
+
* nil-id round-trip structurally cannot perform (it only ever sees error
|
|
53
|
+
* envelopes for referential methods).
|
|
54
|
+
*
|
|
55
|
+
* Fired as POST. The factory runs against the shared per-describe fixture,
|
|
56
|
+
* so it must not assume a clean slate between entries (seed unique state).
|
|
57
|
+
*/
|
|
58
|
+
success_fixtures?: Map<string, (fixture: TestFixture) => Promise<Record<string, unknown>>>;
|
|
37
59
|
}
|
|
38
60
|
/**
|
|
39
61
|
* Run schema-driven round-trip validation for RPC endpoints.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAyB7B,OAAO,KAAK,EAAC,cAAc,EAAsB,MAAM,oBAAoB,CAAC;AAE5E,OAAO,
|
|
1
|
+
{"version":3,"file":"rpc_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAyB7B,OAAO,KAAK,EAAC,cAAc,EAAsB,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAQN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAE,WAAW,EAAC,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAE9D,mDAAmD;AACnD,MAAM,WAAW,uBAAuB;IACvC,kEAAkE;IAClE,UAAU,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uCAAuC;IACvC,YAAY,EAAE,mBAAmB,CAAC;IAClC;;;;;OAKG;IACH,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,qDAAqD;IACrD,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;CAC3F;AAoDD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,6BAA6B,GAAI,SAAS,uBAAuB,KAAG,IAwJhF,CAAC"}
|
|
@@ -20,7 +20,7 @@ import { ROLE_ADMIN } from '../auth/role_schema.js';
|
|
|
20
20
|
import { JSONRPC_METHOD_NOT_FOUND, JsonrpcErrorResponse } from '../http/jsonrpc.js';
|
|
21
21
|
import { generate_valid_body } from './schema_generators.js';
|
|
22
22
|
import { is_public_auth } from '../http/auth_shape.js';
|
|
23
|
-
import { create_rpc_post_init, create_rpc_get_url, assert_jsonrpc_error_response, assert_jsonrpc_success_response, resolve_rpc_endpoints_for_setup, } from './rpc_helpers.js';
|
|
23
|
+
import { create_rpc_post_init, create_rpc_get_url, assert_jsonrpc_error_response, assert_jsonrpc_success_response, resolve_rpc_endpoints_for_setup, find_rpc_action, find_rpc_method, } from './rpc_helpers.js';
|
|
24
24
|
/**
|
|
25
25
|
* Pick auth headers matching an RPC method's auth requirement. Accepts
|
|
26
26
|
* any `KeeperHeaderProvider` — both `TestApp` (in-process) and
|
|
@@ -170,5 +170,30 @@ export const describe_rpc_round_trip_tests = (options) => {
|
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
});
|
|
173
|
+
test('declared success fixtures produce schema-valid success bodies', async () => {
|
|
174
|
+
const success_fixtures = options.success_fixtures;
|
|
175
|
+
if (!success_fixtures || success_fixtures.size === 0)
|
|
176
|
+
return;
|
|
177
|
+
for (const [method, build] of success_fixtures) {
|
|
178
|
+
const located = find_rpc_action(rpc_endpoints_for_setup, method);
|
|
179
|
+
assert.ok(located, `success_fixtures references unknown RPC method '${method}'`);
|
|
180
|
+
const surface = find_rpc_method(surface_rpc_endpoints, method);
|
|
181
|
+
assert.ok(surface, `success_fixtures method '${method}' missing from generated surface`);
|
|
182
|
+
const params = await build(fixture);
|
|
183
|
+
const headers = pick_rpc_auth_headers(surface.method_spec, fixture, authed_account, admin_account);
|
|
184
|
+
const init = create_rpc_post_init(method, params);
|
|
185
|
+
Object.assign(init.headers, headers);
|
|
186
|
+
const res = await fixture.transport(located.path, init);
|
|
187
|
+
const body = await res.json();
|
|
188
|
+
try {
|
|
189
|
+
assert_method_implemented(method, body);
|
|
190
|
+
assert.ok(res.ok, `success fixture expected a success response, got status ${res.status}: ${JSON.stringify(body)}`);
|
|
191
|
+
assert_jsonrpc_success_response(body, located.action.spec.output);
|
|
192
|
+
}
|
|
193
|
+
catch (e) {
|
|
194
|
+
throw new Error(`RPC success-fixture failed for ${method} (status ${res.status}): ${e.message}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
173
198
|
});
|
|
174
199
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fuzdev/fuz_app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.75.0",
|
|
4
4
|
"description": "fullstack app library",
|
|
5
5
|
"glyph": "🗝",
|
|
6
6
|
"logo": "logo.svg",
|
|
@@ -65,10 +65,10 @@
|
|
|
65
65
|
"@electric-sql/pglite": "^0.4.5",
|
|
66
66
|
"@fuzdev/blake3_wasm": "^0.1.0",
|
|
67
67
|
"@fuzdev/fuz_code": "^0.45.1",
|
|
68
|
-
"@fuzdev/fuz_css": "^0.
|
|
69
|
-
"@fuzdev/fuz_ui": "^0.
|
|
70
|
-
"@fuzdev/fuz_util": "^0.
|
|
71
|
-
"@fuzdev/gro": "^0.
|
|
68
|
+
"@fuzdev/fuz_css": "^0.60.0",
|
|
69
|
+
"@fuzdev/fuz_ui": "^0.195.1",
|
|
70
|
+
"@fuzdev/fuz_util": "^0.63.0",
|
|
71
|
+
"@fuzdev/gro": "^0.200.0",
|
|
72
72
|
"@hono/node-server": "^1.19.14",
|
|
73
73
|
"@hono/node-ws": "^1.3.1",
|
|
74
74
|
"@jridgewell/trace-mapping": "^0.3.31",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"@ryanatkn/eslint-config": "^0.12.1",
|
|
77
77
|
"@sveltejs/acorn-typescript": "^1.0.9",
|
|
78
78
|
"@sveltejs/adapter-static": "^3.0.10",
|
|
79
|
-
"@sveltejs/kit": "^2.
|
|
79
|
+
"@sveltejs/kit": "^2.61.1",
|
|
80
80
|
"@sveltejs/package": "^2.5.7",
|
|
81
81
|
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
|
82
82
|
"@types/estree": "^1.0.8",
|
|
@@ -92,8 +92,9 @@
|
|
|
92
92
|
"pg": "^8.20.0",
|
|
93
93
|
"prettier": "^3.7.4",
|
|
94
94
|
"prettier-plugin-svelte": "^3.5.1",
|
|
95
|
-
"svelte": "^5.
|
|
95
|
+
"svelte": "^5.56.0",
|
|
96
96
|
"svelte-check": "^4.4.5",
|
|
97
|
+
"svelte-docinfo": "^0.2.0",
|
|
97
98
|
"svelte2tsx": "^0.7.52",
|
|
98
99
|
"tslib": "^2.8.1",
|
|
99
100
|
"typescript": "^5.9.3",
|