@fuzdev/fuz_app 0.113.0 → 0.114.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/actions/CLAUDE.md +46 -20
- package/dist/actions/action_dispatcher.d.ts +1 -1
- package/dist/actions/action_dispatcher.d.ts.map +1 -1
- package/dist/actions/action_dispatcher.js +22 -16
- package/dist/actions/action_event.d.ts +18 -2
- package/dist/actions/action_event.d.ts.map +1 -1
- package/dist/actions/action_event.js +63 -19
- package/dist/actions/action_event_types.d.ts +22 -0
- package/dist/actions/action_event_types.d.ts.map +1 -1
- package/dist/actions/action_event_types.js +19 -0
- package/dist/actions/compile_action_registry.d.ts +4 -2
- package/dist/actions/compile_action_registry.d.ts.map +1 -1
- package/dist/actions/compile_action_registry.js +8 -3
- package/dist/actions/frontend_rpc_client.d.ts +6 -0
- package/dist/actions/frontend_rpc_client.d.ts.map +1 -1
- package/dist/actions/frontend_rpc_client.js +2 -1
- package/dist/actions/heartbeat.d.ts +8 -4
- package/dist/actions/heartbeat.d.ts.map +1 -1
- package/dist/actions/heartbeat.js +8 -4
- package/dist/actions/peer_ping.d.ts.map +1 -1
- package/dist/actions/peer_ping.js +3 -1
- package/dist/actions/perform_action.d.ts +1 -1
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +6 -4
- package/dist/actions/register_action_ws.d.ts +13 -0
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +23 -2
- package/dist/actions/rpc_client.d.ts +1 -1
- package/dist/actions/rpc_client.d.ts.map +1 -1
- package/dist/actions/rpc_client.js +2 -1
- package/dist/actions/socket.svelte.d.ts +53 -10
- package/dist/actions/socket.svelte.d.ts.map +1 -1
- package/dist/actions/socket.svelte.js +84 -23
- package/dist/actions/transports.d.ts +24 -0
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +30 -0
- package/dist/actions/transports_http.d.ts +11 -4
- package/dist/actions/transports_http.d.ts.map +1 -1
- package/dist/actions/transports_http.js +63 -18
- package/dist/actions/transports_ws.d.ts +28 -3
- package/dist/actions/transports_ws.d.ts.map +1 -1
- package/dist/actions/transports_ws.js +33 -4
- package/dist/actions/ws_endpoint_spec.d.ts +7 -0
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -1
- package/dist/http/CLAUDE.md +7 -3
- package/dist/http/jsonrpc_helpers.d.ts +0 -5
- package/dist/http/jsonrpc_helpers.d.ts.map +1 -1
- package/dist/http/jsonrpc_helpers.js +0 -13
- package/dist/http/schema_helpers.d.ts +56 -0
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +91 -0
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +1 -0
- package/dist/testing/CLAUDE.md +17 -12
- package/dist/testing/cross_backend/peer_ping_ws.d.ts.map +1 -1
- package/dist/testing/cross_backend/peer_ping_ws.js +18 -0
- package/dist/testing/cross_backend/ws_round_trip.d.ts +11 -3
- package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_round_trip.js +74 -12
- package/dist/testing/transports/ws_client.d.ts +6 -0
- package/dist/testing/transports/ws_client.d.ts.map +1 -1
- package/dist/testing/transports/ws_transport.d.ts.map +1 -1
- package/dist/testing/transports/ws_transport.js +6 -1
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +5 -0
- package/dist/ui/form_state.svelte.d.ts +9 -4
- package/dist/ui/form_state.svelte.d.ts.map +1 -1
- package/dist/ui/form_state.svelte.js +28 -8
- package/package.json +2 -2
- package/dist/actions/request_tracker.svelte.d.ts +0 -77
- package/dist/actions/request_tracker.svelte.d.ts.map +0 -1
- package/dist/actions/request_tracker.svelte.js +0 -169
|
@@ -121,6 +121,12 @@ export interface CreateFrontendRpcClientOptions<TApi extends object = object> {
|
|
|
121
121
|
* surface server errors.
|
|
122
122
|
*/
|
|
123
123
|
lookup_action_handler?: ActionEventEnvironment['lookup_action_handler'];
|
|
124
|
+
/**
|
|
125
|
+
* Where dispatch diagnostics go — pure pass-through to
|
|
126
|
+
* `environment.log`. Unset falls back to `console_action_log`; `null`
|
|
127
|
+
* silences them (see `resolve_action_log`).
|
|
128
|
+
*/
|
|
129
|
+
log?: ActionEventEnvironment['log'];
|
|
124
130
|
}
|
|
125
131
|
/** Bundle returned by `create_frontend_rpc_client`. */
|
|
126
132
|
export interface FrontendRpcClient<TApi> {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontend_rpc_client.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/frontend_rpc_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAGN,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,gDAAgD;AAChD,MAAM,WAAW,8BAA8B,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IAC3E;;;;;;;;;;;;;;OAcG;IACH,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IACtC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACtC;;;;;;;;;OASG;IACH,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;IAC1C;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IACpE;;;;;;;;;;;;;;;;OAgBG;IACH,qBAAqB,CAAC,EAAE,sBAAsB,CAAC,uBAAuB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"frontend_rpc_client.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/frontend_rpc_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAGN,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,gDAAgD;AAChD,MAAM,WAAW,8BAA8B,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IAC3E;;;;;;;;;;;;;;OAcG;IACH,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IACtC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACtC;;;;;;;;;OASG;IACH,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;IAC1C;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IACpE;;;;;;;;;;;;;;;;OAgBG;IACH,qBAAqB,CAAC,EAAE,sBAAsB,CAAC,uBAAuB,CAAC,CAAC;IACxE;;;;OAIG;IACH,GAAG,CAAC,EAAE,sBAAsB,CAAC,KAAK,CAAC,CAAC;CACpC;AAED,uDAAuD;AACvD,MAAM,WAAW,iBAAiB,CAAC,IAAI;IACtC;;;;OAIG;IACH,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;IACvB;;;;;OAKG;IACH,UAAU,EAAE,IAAI,CAAC;IACjB,0GAA0G;IAC1G,IAAI,EAAE,gBAAgB,CAAC;IACvB,sHAAsH;IACtH,WAAW,EAAE,sBAAsB,CAAC;CACpC;AAED,sFAAsF;AACtF,eAAO,MAAM,0BAA0B,GAAI,IAAI,SAAS,MAAM,EAC7D,SAAS,8BAA8B,CAAC,IAAI,CAAC,KAC3C,iBAAiB,CAAC,IAAI,CAuBxB,CAAC"}
|
|
@@ -56,7 +56,8 @@ export const create_frontend_rpc_client = (options) => {
|
|
|
56
56
|
const environment = {
|
|
57
57
|
executor: 'frontend',
|
|
58
58
|
lookup_action_spec: (method) => registry.spec_by_method.get(method),
|
|
59
|
-
lookup_action_handler: options.lookup_action_handler ?? (() => undefined)
|
|
59
|
+
lookup_action_handler: options.lookup_action_handler ?? (() => undefined),
|
|
60
|
+
log: options.log
|
|
60
61
|
};
|
|
61
62
|
const transports = new Transports();
|
|
62
63
|
if (options.transports) {
|
|
@@ -11,9 +11,13 @@
|
|
|
11
11
|
* dispatcher tracks receive time, so incoming heartbeats keep the socket
|
|
12
12
|
* alive without any handler-level state.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* Parameterless: the input is `z.void()`, so absent, `null`, and `{}` params
|
|
15
|
+
* are all the no-arg call (`to_void_params`) and anything else is refused —
|
|
16
|
+
* the same shapes the Rust spine's heartbeat admits via
|
|
17
|
+
* `require_void_params`. The output is an empty object. `{client_ts,
|
|
18
|
+
* server_ts}` fields can be added later if clock-skew telemetry ever
|
|
19
|
+
* matters — the `Action` container is open for additions without churning
|
|
20
|
+
* consumer call sites.
|
|
17
21
|
*
|
|
18
22
|
* @module
|
|
19
23
|
*/
|
|
@@ -34,7 +38,7 @@ export declare const heartbeat_action_spec: {
|
|
|
34
38
|
actor: "none";
|
|
35
39
|
};
|
|
36
40
|
side_effects: false;
|
|
37
|
-
input: z.
|
|
41
|
+
input: z.ZodVoid;
|
|
38
42
|
output: z.ZodObject<{}, z.core.$strict>;
|
|
39
43
|
async: true;
|
|
40
44
|
description: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/heartbeat.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/heartbeat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;CAUG,CAAC;AAEtC,4EAA4E;AAC5E,eAAO,MAAM,iBAAiB,QAAO,MAAM,CAAC,MAAM,EAAE,KAAK,CAAS,CAAC;AAEnE;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAG9B,CAAC"}
|
|
@@ -11,9 +11,13 @@
|
|
|
11
11
|
* dispatcher tracks receive time, so incoming heartbeats keep the socket
|
|
12
12
|
* alive without any handler-level state.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* Parameterless: the input is `z.void()`, so absent, `null`, and `{}` params
|
|
15
|
+
* are all the no-arg call (`to_void_params`) and anything else is refused —
|
|
16
|
+
* the same shapes the Rust spine's heartbeat admits via
|
|
17
|
+
* `require_void_params`. The output is an empty object. `{client_ts,
|
|
18
|
+
* server_ts}` fields can be added later if clock-skew telemetry ever
|
|
19
|
+
* matters — the `Action` container is open for additions without churning
|
|
20
|
+
* consumer call sites.
|
|
17
21
|
*
|
|
18
22
|
* @module
|
|
19
23
|
*/
|
|
@@ -30,7 +34,7 @@ export const heartbeat_action_spec = {
|
|
|
30
34
|
initiator: 'frontend',
|
|
31
35
|
auth: { account: 'required', actor: 'none' },
|
|
32
36
|
side_effects: false,
|
|
33
|
-
input: z.
|
|
37
|
+
input: z.void(),
|
|
34
38
|
output: z.strictObject({}),
|
|
35
39
|
async: true,
|
|
36
40
|
description: 'Shared activity ping — keeps the socket alive and exercises the dispatch path.'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peer_ping.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/peer_ping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"peer_ping.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/peer_ping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGhE,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,cAAc,CAAC;AAE5C;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAIvC,kDAAkD;AAClD,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAClD,iDAAiD;AACjD,eAAO,MAAM,2BAA2B,yBAAyB,CAAC;AAClE,iHAAiH;AACjH,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAC5D,sEAAsE;AACtE,eAAO,MAAM,8BAA8B,4BAA4B,CAAC;AACxE,0EAA0E;AAC1E,eAAO,MAAM,8BAA8B,4BAA4B,CAAC;AACxE,qFAAqF;AACrF,eAAO,MAAM,+BAA+B,6BAA6B,CAAC;AAE1E;;;;GAIG;AACH,eAAO,MAAM,eAAe;;;mBAQf,CAAC;AACd,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,6FAA6F;AAC7F,eAAO,MAAM,iBAAiB;;kBAE5B,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,YAAY;;;kBAGvB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAExD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;CAaG,CAAC;AA+BtC;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,GAC7B,OAAO,eAAe,EACtB,KAAK,aAAa,KAChB,OAAO,CAAC,YAAY,CAsCtB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ,OAAO,KAAG,YAGrD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAG9B,CAAC"}
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
*/
|
|
37
37
|
import { z } from 'zod';
|
|
38
38
|
import { ThrownJsonrpcError, JSONRPC_ERROR_CODES } from '../http/jsonrpc_errors.js';
|
|
39
|
+
import { safe_parse_dropping_unknown_keys } from '../http/schema_helpers.js';
|
|
39
40
|
import { DEFAULT_PEER_REQUEST_TIMEOUT } from './peer_request.js';
|
|
40
41
|
/** Wire method name (both directions). Twin of the Rust `PEER_PING_METHOD`. */
|
|
41
42
|
export const PEER_PING_METHOD = 'peer/ping';
|
|
@@ -154,7 +155,8 @@ export const peer_ping_handler = async (input, ctx) => {
|
|
|
154
155
|
const outcome = await ctx.request_client(PEER_PING_METHOD, request_params, { timeout_ms });
|
|
155
156
|
if (!outcome.ok)
|
|
156
157
|
throw peer_request_error_to_jsonrpc(outcome.error);
|
|
157
|
-
|
|
158
|
+
// the reply is remote-authored — a newer client may add fields
|
|
159
|
+
const parsed = safe_parse_dropping_unknown_keys(PingResponse, outcome.value);
|
|
158
160
|
if (!parsed.success) {
|
|
159
161
|
throw new ThrownJsonrpcError(JSONRPC_ERROR_CODES.validation_error, 'peer/ping reply failed validation', { reason: REASON_PEER_PING_INVALID_REPLY });
|
|
160
162
|
}
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* sits behind the authority gates by choice rather than necessity: a
|
|
29
29
|
* caller those gates refuse is answered 403, not 429.
|
|
30
30
|
* 5. **Validate params (400)** — `spec.input.safeParse(raw_params)` with
|
|
31
|
-
* `z.void()` / `?? {}` rules. Runs **after** the authority gates: a
|
|
31
|
+
* `z.void()` / `?? {}` rules (`to_input_params`). Runs **after** the authority gates: a
|
|
32
32
|
* 400 describing the action's input shape to a caller those gates
|
|
33
33
|
* refuse would confirm the method exists and describe how to call it,
|
|
34
34
|
* to a channel that should have learned nothing. Coarse authority
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perform_action.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/perform_action.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAGN,KAAK,cAAc,EACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAGtC,OAAO,EAEN,KAAK,gBAAgB,EAErB,KAAK,kBAAkB,EACvB,MAAM,oBAAoB,CAAC;AAc5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,EAAgC,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAGN,KAAK,UAAU,EACf,MAAM,wBAAwB,CAAC;AAEhC;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAClC,kEAAkE;IAClE,MAAM,EAAE,SAAS,CAAC;IAClB,mGAAmG;IACnG,UAAU,EAAE,OAAO,CAAC;IACpB,sDAAsD;IACtD,UAAU,EAAE,gBAAgB,CAAC;IAC7B,yDAAyD;IACzD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,uEAAuE;IACvE,eAAe,EAAE,cAAc,GAAG,IAAI,CAAC;IACvC;;;;;OAKG;IACH,WAAW,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,oGAAoG;IACpG,MAAM,EAAE,WAAW,CAAC;IACpB,sFAAsF;IACtF,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,uDAAuD;IACvD,aAAa,CAAC,EAAE,IAAI,CAAC;IACrB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC;IAC/B;;;;OAIG;IACH,MAAM,CAAC,EAAE;QAAE,eAAe,EAAE,cAAc,GAAG,IAAI,CAAA;KAAE,CAAC;CACpD;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IACjC,gGAAgG;IAChG,EAAE,EAAE,EAAE,CAAC;IACP;;;OAGG;IACH,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC;;;OAGG;IACH,mBAAmB,EAAE,KAAK,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACvD,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,sBAAsB,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3C,uEAAuE;IACvE,2BAA2B,EAAE,WAAW,GAAG,IAAI,CAAC;CAChD;AAED;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAC9B;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhG;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAC1B,OAAO,kBAAkB,EACzB,MAAM,iBAAiB,KACrB,OAAO,CAAC,mBAAmB,
|
|
1
|
+
{"version":3,"file":"perform_action.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/perform_action.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAGN,KAAK,cAAc,EACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAGtC,OAAO,EAEN,KAAK,gBAAgB,EAErB,KAAK,kBAAkB,EACvB,MAAM,oBAAoB,CAAC;AAc5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,EAAgC,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAGN,KAAK,UAAU,EACf,MAAM,wBAAwB,CAAC;AAEhC;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAClC,kEAAkE;IAClE,MAAM,EAAE,SAAS,CAAC;IAClB,mGAAmG;IACnG,UAAU,EAAE,OAAO,CAAC;IACpB,sDAAsD;IACtD,UAAU,EAAE,gBAAgB,CAAC;IAC7B,yDAAyD;IACzD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,uEAAuE;IACvE,eAAe,EAAE,cAAc,GAAG,IAAI,CAAC;IACvC;;;;;OAKG;IACH,WAAW,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,oGAAoG;IACpG,MAAM,EAAE,WAAW,CAAC;IACpB,sFAAsF;IACtF,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,uDAAuD;IACvD,aAAa,CAAC,EAAE,IAAI,CAAC;IACrB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC;IAC/B;;;;OAIG;IACH,MAAM,CAAC,EAAE;QAAE,eAAe,EAAE,cAAc,GAAG,IAAI,CAAA;KAAE,CAAC;CACpD;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IACjC,gGAAgG;IAChG,EAAE,EAAE,EAAE,CAAC;IACP;;;OAGG;IACH,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC;;;OAGG;IACH,mBAAmB,EAAE,KAAK,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACvD,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,sBAAsB,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3C,uEAAuE;IACvE,2BAA2B,EAAE,WAAW,GAAG,IAAI,CAAC;CAChD;AAED;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAC9B;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhG;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAC1B,OAAO,kBAAkB,EACzB,MAAM,iBAAiB,KACrB,OAAO,CAAC,mBAAmB,CAmL7B,CAAC;AAuHF;;;GAGG;AACH,eAAO,MAAM,iCAAiC,GAC7C,IAAI,gBAAgB,EACpB,QAAQ,mBAAmB,KACzB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,gBAAgB,CAAA;CAAE,GAAG,CAC9C;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,kBAAkB,CAAA;CAAE,CAMnD,CAAC"}
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* sits behind the authority gates by choice rather than necessity: a
|
|
29
29
|
* caller those gates refuse is answered 403, not 429.
|
|
30
30
|
* 5. **Validate params (400)** — `spec.input.safeParse(raw_params)` with
|
|
31
|
-
* `z.void()` / `?? {}` rules. Runs **after** the authority gates: a
|
|
31
|
+
* `z.void()` / `?? {}` rules (`to_input_params`). Runs **after** the authority gates: a
|
|
32
32
|
* 400 describing the action's input shape to a caller those gates
|
|
33
33
|
* refuse would confirm the method exists and describe how to call it,
|
|
34
34
|
* to a channel that should have learned nothing. Coarse authority
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
import { DEV } from 'esm-env';
|
|
58
58
|
import { apply_authorization_phase, has_any_scoped_role } from '../auth/request_context.js';
|
|
59
59
|
import {} from '../hono_context.js';
|
|
60
|
-
import {
|
|
60
|
+
import { to_input_params } from '../http/schema_helpers.js';
|
|
61
61
|
import { dispatch_with_post_commit_rollback } from '../http/pending_effects.js';
|
|
62
62
|
import { JSONRPC_VERSION } from '../http/jsonrpc.js';
|
|
63
63
|
import { jsonrpc_error_messages, jsonrpc_error_code_to_http_status, http_status_to_jsonrpc_error_code, JSONRPC_ERROR_CODES, dev_only } from '../http/jsonrpc_errors.js';
|
|
@@ -143,8 +143,10 @@ export const perform_action = async (input, deps) => {
|
|
|
143
143
|
}
|
|
144
144
|
// step 5: validate params. JSON-RPC 2.0 §4.2 forbids `params: null`;
|
|
145
145
|
// registration sites reject `z.null()` inputs. Empty-body convention
|
|
146
|
-
// (`raw_params ?? {}`) lets all-optional-object methods omit `params
|
|
147
|
-
|
|
146
|
+
// (`raw_params ?? {}`) lets all-optional-object methods omit `params`;
|
|
147
|
+
// a `z.void()` input reads every empty shape as the no-arg call — see
|
|
148
|
+
// `to_input_params`.
|
|
149
|
+
const params = to_input_params(spec.input, raw_params);
|
|
148
150
|
const parse_result = spec.input.safeParse(params);
|
|
149
151
|
if (!parse_result.success) {
|
|
150
152
|
return error_result(jsonrpc_error_messages.invalid_params('invalid params', dev_only({ issues: parse_result.error.issues })));
|
|
@@ -128,6 +128,19 @@ export interface RegisterActionWsOptions {
|
|
|
128
128
|
heartbeat?: boolean | ServerHeartbeatOptions;
|
|
129
129
|
/** Optional per-message delay for testing loading states. Ignored when `0`. */
|
|
130
130
|
artificial_delay?: number;
|
|
131
|
+
/**
|
|
132
|
+
* Cap on one inbound message, in bytes (UTF-8 for text frames). A larger
|
|
133
|
+
* message closes the socket with `WS_CLOSE_MESSAGE_TOO_BIG` before it's
|
|
134
|
+
* parsed — there's no per-message error reply, matching the Rust spine.
|
|
135
|
+
* The cap is checked after the runtime adapter has buffered the message,
|
|
136
|
+
* so it bounds dispatch work, not memory; bound the adapter's own frame
|
|
137
|
+
* limit too (e.g. `ws`'s `maxPayload`) where memory matters. A consumer
|
|
138
|
+
* that raises it passes the same value to the client's
|
|
139
|
+
* `FrontendWebsocketTransportOptions.max_message_bytes`.
|
|
140
|
+
*
|
|
141
|
+
* @default DEFAULT_WS_MAX_MESSAGE_BYTES
|
|
142
|
+
*/
|
|
143
|
+
max_message_bytes?: number;
|
|
131
144
|
/** Optional logger; defaults to `[ws]` namespace. */
|
|
132
145
|
log?: LoggerType;
|
|
133
146
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register_action_ws.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/register_action_ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAE3D,OAAO,EAAU,KAAK,MAAM,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAWnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAyBtD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"register_action_ws.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/register_action_ws.ts"],"names":[],"mappings":"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"}
|
|
@@ -39,7 +39,7 @@ import { CREDENTIAL_TYPE_KEY, TOKEN_SCOPE_KEY, AUTH_API_TOKEN_ID_KEY, TEST_CONTE
|
|
|
39
39
|
import {} from './action_types.js';
|
|
40
40
|
import { compile_action_registry } from './compile_action_registry.js';
|
|
41
41
|
import { cancel_action_spec, CancelNotificationParams } from './cancel.js';
|
|
42
|
-
import { WS_CLOSE_SERVER_HEARTBEAT_TIMEOUT } from './transports.js';
|
|
42
|
+
import { DEFAULT_WS_MAX_MESSAGE_BYTES, WS_CLOSE_MESSAGE_TOO_BIG, WS_CLOSE_SERVER_HEARTBEAT_TIMEOUT, utf8_length_over } from './transports.js';
|
|
43
43
|
import { BackendWebsocketTransport } from './transports_ws_backend.js';
|
|
44
44
|
import { audit_unmatched_peer_response } from './peer_request.js';
|
|
45
45
|
import { perform_action, perform_action_result_to_envelope } from './perform_action.js';
|
|
@@ -103,7 +103,7 @@ const is_peer_response = (json) => {
|
|
|
103
103
|
* in the transport's internal maps via `add_connection` / `remove_connection`
|
|
104
104
|
*/
|
|
105
105
|
export const register_action_ws = (options) => {
|
|
106
|
-
const { path, app, upgradeWebSocket, actions, db, transport = new BackendWebsocketTransport(), heartbeat = true, artificial_delay = 0, log = new Logger('[ws]'), on_socket_open, on_socket_close, action_ip_rate_limiter = null, action_account_rate_limiter = null } = options;
|
|
106
|
+
const { path, app, upgradeWebSocket, actions, db, transport = new BackendWebsocketTransport(), heartbeat = true, artificial_delay = 0, max_message_bytes = DEFAULT_WS_MAX_MESSAGE_BYTES, log = new Logger('[ws]'), on_socket_open, on_socket_close, action_ip_rate_limiter = null, action_account_rate_limiter = null } = options;
|
|
107
107
|
// Build the dispatcher's per-method lookup. Only request_response
|
|
108
108
|
// specs with a handler reach `action_map` — perform_action is the
|
|
109
109
|
// only site that calls handlers, and it requires an `RpcAction`.
|
|
@@ -264,6 +264,12 @@ export const register_action_ws = (options) => {
|
|
|
264
264
|
},
|
|
265
265
|
onMessage: async (event, ws) => {
|
|
266
266
|
last_receive_time = Date.now();
|
|
267
|
+
const size = ws_message_size_over(event.data, max_message_bytes);
|
|
268
|
+
if (size !== null) {
|
|
269
|
+
log.warn(`closing socket: ${size}-byte message exceeds the ${max_message_bytes}-byte cap`);
|
|
270
|
+
ws.close(WS_CLOSE_MESSAGE_TOO_BIG, 'message too big');
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
267
273
|
let json;
|
|
268
274
|
try {
|
|
269
275
|
json = JSON.parse(String(event.data)); // eslint-disable-line @typescript-eslint/no-base-to-string
|
|
@@ -464,3 +470,18 @@ export const register_action_ws = (options) => {
|
|
|
464
470
|
}));
|
|
465
471
|
return { transport };
|
|
466
472
|
};
|
|
473
|
+
/**
|
|
474
|
+
* The byte size of an inbound WebSocket message when it exceeds `max_bytes`,
|
|
475
|
+
* else `null` — UTF-8 bytes for a text frame, the buffer or blob size for a
|
|
476
|
+
* binary one.
|
|
477
|
+
*/
|
|
478
|
+
const ws_message_size_over = (data, max_bytes) => {
|
|
479
|
+
if (typeof data === 'string')
|
|
480
|
+
return utf8_length_over(data, max_bytes);
|
|
481
|
+
let size = null;
|
|
482
|
+
if (data instanceof Blob)
|
|
483
|
+
size = data.size;
|
|
484
|
+
else if (data instanceof ArrayBuffer || ArrayBuffer.isView(data))
|
|
485
|
+
size = data.byteLength;
|
|
486
|
+
return size !== null && size > max_bytes ? size : null;
|
|
487
|
+
};
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* @module
|
|
12
12
|
*/
|
|
13
13
|
import type { Result } from '@fuzdev/fuz_util/result.ts';
|
|
14
|
-
import type
|
|
14
|
+
import { type ActionEventEnvironment } from './action_event_types.js';
|
|
15
15
|
import { type ActionEvent } from './action_event.js';
|
|
16
16
|
import type { ActionDispatcher, ActionDispatcherSendOptions } from './action_dispatcher.js';
|
|
17
17
|
import type { TransportName } from './transports.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc_client.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/rpc_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAQzD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"rpc_client.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/rpc_client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAQzD,OAAO,EAAsB,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAC1F,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAM1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAC5F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAC;AAM/E,uCAAuC;AACvC,MAAM,WAAW,sBAAsB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACnE,IAAI,EAAE,gBAAgB,CAAC;IACvB,WAAW,EAAE,sBAAsB,CAAC;IACpC;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IACpE;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,iBAAiB,GAAI,IAAI,SAAS,MAAM,EACpD,SAAS,sBAAsB,CAAC,IAAI,CAAC,KACnC,IA4BF,CAAC;AAuDF;;;;;GAKG;AACH,MAAM,WAAW,oBAAqB,SAAQ,2BAA2B;CAAG;AA6G5E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,WAAW,CAAC,IAAI,IAAI;KAC9B,CAAC,IAAI,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAClC,GAAG,IAAI,EAAE,MAAM,KAAK,KAChB,OAAO,CAAC,MAAM,CAAC;QAAE,KAAK,EAAE,MAAM,MAAM,CAAA;KAAE,EAAE;QAAE,KAAK,EAAE,kBAAkB,CAAA;KAAE,CAAC,CAAC,GACzE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,CAAC,GACnC,IAAI,CAAC,CAAC,CAAC;CACV,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,mBAAmB,GAAI,IAAI,SAAS,MAAM,EAAE,YAAY,IAAI,KAAG,WAAW,CAAC,IAAI,CA8B3F,CAAC"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @module
|
|
12
12
|
*/
|
|
13
|
+
import { resolve_action_log } from './action_event_types.js';
|
|
13
14
|
import { create_action_event } from './action_event.js';
|
|
14
15
|
import { is_send_request, is_notification_send, extract_action_result } from './action_event_helpers.js';
|
|
15
16
|
import { jsonrpc_error_messages } from '../http/jsonrpc_errors.js';
|
|
@@ -148,7 +149,7 @@ const create_remote_notification_method = (peer, environment, spec, on_action_ev
|
|
|
148
149
|
});
|
|
149
150
|
// Check if notification failed to send
|
|
150
151
|
if (send_result !== null) {
|
|
151
|
-
environment
|
|
152
|
+
resolve_action_log(environment)?.error('notification send failed:', send_result.error);
|
|
152
153
|
return { ok: false, error: send_result.error };
|
|
153
154
|
}
|
|
154
155
|
return { ok: true, value: undefined };
|
|
@@ -16,10 +16,11 @@
|
|
|
16
16
|
* to `DEFAULT_QUEUE_MAX_SIZE` requests and flush on reopen. Overflow
|
|
17
17
|
* rejects with `queue_overflow`. Raw `FrontendWebsocketClient.send`
|
|
18
18
|
* is drop-on-disconnect (fire-and-forget notifications want that).
|
|
19
|
-
* - **Activity-aware heartbeat** —
|
|
20
|
-
* receive-silence past
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* - **Activity-aware heartbeat** — a shared `heartbeat` request fires when
|
|
20
|
+
* either direction has been idle for the interval; receive-silence past
|
|
21
|
+
* the receive timeout (`DEFAULT_HEARTBEAT_RECEIVE_TIMEOUT`, never less
|
|
22
|
+
* than `HEARTBEAT_RECEIVE_TIMEOUT_MIN_FACTOR` × the interval) closes with
|
|
23
|
+
* `WS_CLOSE_CLIENT_HEARTBEAT_TIMEOUT` and lets auto-reconnect pick back up.
|
|
23
24
|
*
|
|
24
25
|
* @module
|
|
25
26
|
*/
|
|
@@ -37,8 +38,31 @@ export declare const DEFAULT_RECONNECT_DELAY_MAX = 10000;
|
|
|
37
38
|
export declare const DEFAULT_BACKOFF_FACTOR = 1.5;
|
|
38
39
|
/** Idle interval before sending a heartbeat (ms). */
|
|
39
40
|
export declare const DEFAULT_HEARTBEAT_INTERVAL = 30000;
|
|
40
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Max receive silence before closing with `WS_CLOSE_CLIENT_HEARTBEAT_TIMEOUT`
|
|
43
|
+
* (ms), for intervals up to half of it — see `resolve_heartbeat_receive_timeout`.
|
|
44
|
+
*/
|
|
41
45
|
export declare const DEFAULT_HEARTBEAT_RECEIVE_TIMEOUT = 60000;
|
|
46
|
+
/**
|
|
47
|
+
* Minimum ratio of the heartbeat receive timeout to the heartbeat interval.
|
|
48
|
+
*
|
|
49
|
+
* A heartbeat goes out once a direction has been idle for `interval`, and the
|
|
50
|
+
* check runs every `interval / 2`, so on an idle socket it can leave up to
|
|
51
|
+
* 1.5 × `interval` after the last receive — and its response needs a round
|
|
52
|
+
* trip on top. A receive timeout under 2 × `interval` can close a healthy
|
|
53
|
+
* idle socket before its heartbeat is answered, so it's clamped up to this.
|
|
54
|
+
*/
|
|
55
|
+
export declare const HEARTBEAT_RECEIVE_TIMEOUT_MIN_FACTOR = 2;
|
|
56
|
+
/**
|
|
57
|
+
* Resolve the effective heartbeat receive timeout for `interval`: the given
|
|
58
|
+
* `receive_timeout` (or `DEFAULT_HEARTBEAT_RECEIVE_TIMEOUT`), raised to at
|
|
59
|
+
* least `HEARTBEAT_RECEIVE_TIMEOUT_MIN_FACTOR` × `interval`.
|
|
60
|
+
*
|
|
61
|
+
* @param interval - heartbeat idle interval in ms
|
|
62
|
+
* @param receive_timeout - requested receive timeout in ms
|
|
63
|
+
* @returns the receive timeout in ms the client enforces
|
|
64
|
+
*/
|
|
65
|
+
export declare const resolve_heartbeat_receive_timeout: (interval: number, receive_timeout?: number) => number;
|
|
42
66
|
/** Default bound on buffered requests while disconnected. Overflow rejects. */
|
|
43
67
|
export declare const DEFAULT_QUEUE_MAX_SIZE = 100;
|
|
44
68
|
/**
|
|
@@ -64,16 +88,20 @@ export interface FrontendWebsocketReconnectOptions {
|
|
|
64
88
|
}
|
|
65
89
|
export interface FrontendWebsocketHeartbeatOptions {
|
|
66
90
|
/**
|
|
67
|
-
* Idle duration (ms) after which a heartbeat is sent
|
|
68
|
-
*
|
|
91
|
+
* Idle duration (ms) after which a heartbeat is sent — when either nothing
|
|
92
|
+
* has been sent or nothing has been received for this long, so both ends'
|
|
93
|
+
* silence detectors stay fed. Traffic in both directions defers it, so
|
|
94
|
+
* chatty connections never emit extras. Defaults to
|
|
69
95
|
* `DEFAULT_HEARTBEAT_INTERVAL`.
|
|
70
96
|
*/
|
|
71
97
|
interval?: number;
|
|
72
98
|
/**
|
|
73
99
|
* Receive-silence (ms) after which the client closes the socket with
|
|
74
100
|
* `WS_CLOSE_CLIENT_HEARTBEAT_TIMEOUT`, letting auto-reconnect kick
|
|
75
|
-
* in.
|
|
76
|
-
* `
|
|
101
|
+
* in. Defaults to `DEFAULT_HEARTBEAT_RECEIVE_TIMEOUT`; either way it's
|
|
102
|
+
* raised to at least `HEARTBEAT_RECEIVE_TIMEOUT_MIN_FACTOR` × `interval`
|
|
103
|
+
* (see `resolve_heartbeat_receive_timeout`), so a long `interval` alone
|
|
104
|
+
* is safe.
|
|
77
105
|
*/
|
|
78
106
|
receive_timeout?: number;
|
|
79
107
|
}
|
|
@@ -132,6 +160,17 @@ export declare class FrontendWebsocketClient implements WebsocketConnection, Dis
|
|
|
132
160
|
last_close_code: number | null;
|
|
133
161
|
/** Reason string from the most recent close event (may be empty). */
|
|
134
162
|
last_close_reason: string | null;
|
|
163
|
+
/**
|
|
164
|
+
* Epoch ms of the most recent frame written to the socket — requests,
|
|
165
|
+
* notifications, heartbeats, and cancels alike. `null` until the first send.
|
|
166
|
+
*/
|
|
167
|
+
last_send_time: number | null;
|
|
168
|
+
/**
|
|
169
|
+
* Epoch ms of the most recent frame received — responses (including ones
|
|
170
|
+
* `request` consumes), notifications, and requests alike. `null` until the
|
|
171
|
+
* first receive.
|
|
172
|
+
*/
|
|
173
|
+
last_receive_time: number | null;
|
|
135
174
|
/**
|
|
136
175
|
* The error thrown by the most recent attempted `send()`, or `null` if the
|
|
137
176
|
* most recent attempt succeeded or none has been attempted yet. Populated
|
|
@@ -239,6 +278,10 @@ export declare class FrontendWebsocketClient implements WebsocketConnection, Dis
|
|
|
239
278
|
* own peer-minted UUID), tracks the pending promise, and resolves when the
|
|
240
279
|
* server sends a matching response.
|
|
241
280
|
*
|
|
281
|
+
* An `undefined` `params` is omitted from the frame rather than sent as
|
|
282
|
+
* `{}` — the absent form is the parameterless call every server admits
|
|
283
|
+
* for a `z.void()` input, including servers that refuse `{}`.
|
|
284
|
+
*
|
|
242
285
|
* Callers supplying an explicit `options.id` are responsible for
|
|
243
286
|
* uniqueness — the pending map is keyed by id, and a duplicate silently
|
|
244
287
|
* overwrites the prior entry. Auto-minted ids are monotonic and never
|
|
@@ -259,7 +302,7 @@ export declare class FrontendWebsocketClient implements WebsocketConnection, Dis
|
|
|
259
302
|
*
|
|
260
303
|
* @mutates this - inserts the new pending entry into `#pending` (or
|
|
261
304
|
* buffers into `#queue` when disconnected) and may bump
|
|
262
|
-
* `#next_request_id`,
|
|
305
|
+
* `#next_request_id`, `last_send_time`, `last_send_error`
|
|
263
306
|
* @throws ThrownJsonrpcError on the returned promise — never thrown
|
|
264
307
|
* synchronously. Rejection codes:
|
|
265
308
|
* - `unauthenticated` — session revoked (entry check or close code)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/socket.svelte.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"socket.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/socket.svelte.ts"],"names":[],"mappings":"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"}
|