@fuzdev/fuz_app 0.72.1 → 0.74.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.
@@ -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;AAwDtE;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,aAAa,CAAC,MAAM,CAAC,KAAG,WA4HhE,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"}
@@ -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;
@@ -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":"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"}
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,WAkO9D,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"}
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"}
@@ -74,11 +74,16 @@ export const create_mock_runtime = (args = []) => {
74
74
  },
75
75
  // === Local File System ===
76
76
  stat: async (path) => {
77
- if (mock_fs.has(path) || mock_fs_bytes.has(path)) {
78
- return { is_file: true, is_directory: false };
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;AAOH,OAAO,KAAK,EAAC,WAAW,EAA4B,MAAM,WAAW,CAAC;AAEtE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAC/B,OAAM,aAAa,CAAC,MAAM,CAAyB,KACjD,WAmKD,CAAC"}
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"}
@@ -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;
@@ -47,7 +47,10 @@ export interface RpcRoundTripTestOptions {
47
47
  *
48
48
  * Error responses (from missing DB state, etc.) are expected and validated
49
49
  * as well-formed JSON-RPC errors. Successful responses are validated against
50
- * `action.spec.output`.
50
+ * `action.spec.output`. A `method not found` (-32601) error is the one
51
+ * exception — it means the backend is missing a method the local surface
52
+ * advertises, so the round-trip fails loud (`assert_method_implemented`)
53
+ * rather than accepting it as a valid error envelope.
51
54
  */
52
55
  export declare const describe_rpc_round_trip_tests: (options: RpcRoundTripTestOptions) => void;
53
56
  //# sourceMappingURL=rpc_round_trip.d.ts.map
@@ -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;AAwB7B,OAAO,KAAK,EAAC,cAAc,EAAsB,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAMN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,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;CACvD;AA6BD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,6BAA6B,GAAI,SAAS,uBAAuB,KAAG,IAkHhF,CAAC"}
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,EAMN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,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;CACvD;AAoDD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,6BAA6B,GAAI,SAAS,uBAAuB,KAAG,IAoHhF,CAAC"}
@@ -15,8 +15,9 @@ import './assert_dev_env.js';
15
15
  *
16
16
  * @module
17
17
  */
18
- import { describe, test, beforeAll } from 'vitest';
18
+ import { describe, test, beforeAll, assert } from 'vitest';
19
19
  import { ROLE_ADMIN } from '../auth/role_schema.js';
20
+ import { JSONRPC_METHOD_NOT_FOUND, JsonrpcErrorResponse } from '../http/jsonrpc.js';
20
21
  import { generate_valid_body } from './schema_generators.js';
21
22
  import { is_public_auth } from '../http/auth_shape.js';
22
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';
@@ -41,6 +42,26 @@ const pick_rpc_auth_headers = (method, keeper, authed_account, admin_account) =>
41
42
  }
42
43
  return authed_account.create_session_headers();
43
44
  };
45
+ /**
46
+ * Guard against silent parity gaps: a method enumerated from the local action
47
+ * surface that the remote backend answers with `method not found` (-32601)
48
+ * means the backend is missing an implementation the local surface advertises.
49
+ * That is a well-formed JSON-RPC error, so the round-trip's
50
+ * `assert_jsonrpc_error_response` branch would otherwise accept it as a pass —
51
+ * masking missing methods across coequal backends. Fail loud instead, before
52
+ * the generic error-envelope acceptance runs.
53
+ *
54
+ * Only `JSONRPC_METHOD_NOT_FOUND` trips this — every other well-formed error
55
+ * (validation, `not_found` from missing DB state, auth denials) stays a valid
56
+ * round-trip outcome.
57
+ */
58
+ const assert_method_implemented = (method, body) => {
59
+ const parsed = JsonrpcErrorResponse.safeParse(body);
60
+ if (parsed.success && parsed.data.error.code === JSONRPC_METHOD_NOT_FOUND) {
61
+ assert.fail(`method '${method}' is registered on the local surface but the backend` +
62
+ ` returned method-not-found — backend is missing this method (parity gap)`);
63
+ }
64
+ };
44
65
  /**
45
66
  * Run schema-driven round-trip validation for RPC endpoints.
46
67
  *
@@ -53,7 +74,10 @@ const pick_rpc_auth_headers = (method, keeper, authed_account, admin_account) =>
53
74
  *
54
75
  * Error responses (from missing DB state, etc.) are expected and validated
55
76
  * as well-formed JSON-RPC errors. Successful responses are validated against
56
- * `action.spec.output`.
77
+ * `action.spec.output`. A `method not found` (-32601) error is the one
78
+ * exception — it means the backend is missing a method the local surface
79
+ * advertises, so the round-trip fails loud (`assert_method_implemented`)
80
+ * rather than accepting it as a valid error envelope.
57
81
  */
58
82
  export const describe_rpc_round_trip_tests = (options) => {
59
83
  const skip_set = new Set(options.skip_methods);
@@ -103,6 +127,7 @@ export const describe_rpc_round_trip_tests = (options) => {
103
127
  assert_jsonrpc_success_response(body, action.spec.output);
104
128
  }
105
129
  else {
130
+ assert_method_implemented(action.spec.method, body);
106
131
  assert_jsonrpc_error_response(body);
107
132
  }
108
133
  }
@@ -135,6 +160,7 @@ export const describe_rpc_round_trip_tests = (options) => {
135
160
  assert_jsonrpc_success_response(body, action.spec.output);
136
161
  }
137
162
  else {
163
+ assert_method_implemented(action.spec.method, body);
138
164
  assert_jsonrpc_error_response(body);
139
165
  }
140
166
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_app",
3
- "version": "0.72.1",
3
+ "version": "0.74.0",
4
4
  "description": "fullstack app library",
5
5
  "glyph": "🗝",
6
6
  "logo": "logo.svg",
@@ -65,9 +65,9 @@
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.59.0",
69
- "@fuzdev/fuz_ui": "^0.192.0",
70
- "@fuzdev/fuz_util": "^0.61.1",
68
+ "@fuzdev/fuz_css": "^0.60.0",
69
+ "@fuzdev/fuz_ui": "^0.195.1",
70
+ "@fuzdev/fuz_util": "^0.62.0",
71
71
  "@fuzdev/gro": "^0.199.1",
72
72
  "@hono/node-server": "^1.19.14",
73
73
  "@hono/node-ws": "^1.3.1",
@@ -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.55.0",
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.54.1",
95
+ "svelte": "^5.56.0",
96
96
  "svelte-check": "^4.4.5",
97
+ "svelte-docinfo": "^0.1.0",
97
98
  "svelte2tsx": "^0.7.52",
98
99
  "tslib": "^2.8.1",
99
100
  "typescript": "^5.9.3",