@fuzdev/fuz_app 0.29.0 → 0.31.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 +630 -0
- package/dist/actions/action_rpc.d.ts +29 -0
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +42 -6
- package/dist/actions/action_types.d.ts +2 -2
- package/dist/actions/cancel.d.ts +12 -13
- package/dist/actions/cancel.d.ts.map +1 -1
- package/dist/actions/cancel.js +10 -13
- package/dist/actions/heartbeat.d.ts +8 -13
- package/dist/actions/heartbeat.d.ts.map +1 -1
- package/dist/actions/heartbeat.js +5 -8
- package/dist/actions/register_action_ws.d.ts +3 -3
- package/dist/actions/register_action_ws.js +2 -2
- package/dist/actions/register_ws_endpoint.d.ts +4 -4
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +3 -3
- package/dist/actions/socket.svelte.d.ts +16 -16
- package/dist/actions/socket.svelte.d.ts.map +1 -1
- package/dist/actions/socket.svelte.js +15 -15
- package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.d.ts +15 -0
- package/dist/actions/transports_ws_backend.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.js +17 -0
- package/dist/auth/CLAUDE.md +923 -0
- package/dist/auth/account_action_specs.d.ts +216 -0
- package/dist/auth/account_action_specs.d.ts.map +1 -0
- package/dist/auth/account_action_specs.js +159 -0
- package/dist/auth/account_actions.d.ts +51 -0
- package/dist/auth/account_actions.d.ts.map +1 -0
- package/dist/auth/account_actions.js +119 -0
- package/dist/auth/account_queries.d.ts +6 -2
- package/dist/auth/account_queries.d.ts.map +1 -1
- package/dist/auth/account_queries.js +40 -4
- package/dist/auth/account_routes.d.ts +94 -16
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +108 -180
- package/dist/auth/account_schema.d.ts +85 -30
- package/dist/auth/account_schema.d.ts.map +1 -1
- package/dist/auth/account_schema.js +40 -8
- package/dist/auth/admin_action_specs.d.ts +674 -0
- package/dist/auth/admin_action_specs.d.ts.map +1 -0
- package/dist/auth/admin_action_specs.js +287 -0
- package/dist/auth/admin_actions.d.ts +69 -0
- package/dist/auth/admin_actions.d.ts.map +1 -0
- package/dist/auth/admin_actions.js +256 -0
- package/dist/auth/api_token.d.ts +10 -0
- package/dist/auth/api_token.d.ts.map +1 -1
- package/dist/auth/api_token.js +9 -0
- package/dist/auth/api_token_queries.d.ts +3 -3
- package/dist/auth/api_token_queries.js +3 -3
- package/dist/auth/app_settings_schema.d.ts +4 -3
- package/dist/auth/app_settings_schema.d.ts.map +1 -1
- package/dist/auth/app_settings_schema.js +2 -1
- package/dist/auth/audit_log_routes.d.ts +14 -6
- package/dist/auth/audit_log_routes.d.ts.map +1 -1
- package/dist/auth/audit_log_routes.js +22 -79
- package/dist/auth/audit_log_schema.d.ts +100 -29
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +83 -11
- package/dist/auth/bootstrap_routes.d.ts +14 -0
- package/dist/auth/bootstrap_routes.d.ts.map +1 -1
- package/dist/auth/bootstrap_routes.js +10 -3
- package/dist/auth/cleanup.d.ts +63 -0
- package/dist/auth/cleanup.d.ts.map +1 -0
- package/dist/auth/cleanup.js +80 -0
- package/dist/auth/invite_schema.d.ts +11 -10
- package/dist/auth/invite_schema.d.ts.map +1 -1
- package/dist/auth/invite_schema.js +4 -3
- package/dist/auth/migrations.d.ts +6 -0
- package/dist/auth/migrations.d.ts.map +1 -1
- package/dist/auth/migrations.js +28 -0
- package/dist/auth/permit_offer_action_specs.d.ts +364 -0
- package/dist/auth/permit_offer_action_specs.d.ts.map +1 -0
- package/dist/auth/permit_offer_action_specs.js +216 -0
- package/dist/auth/permit_offer_actions.d.ts +96 -0
- package/dist/auth/permit_offer_actions.d.ts.map +1 -0
- package/dist/auth/permit_offer_actions.js +428 -0
- package/dist/auth/permit_offer_notifications.d.ts +361 -0
- package/dist/auth/permit_offer_notifications.d.ts.map +1 -0
- package/dist/auth/permit_offer_notifications.js +179 -0
- package/dist/auth/permit_offer_queries.d.ts +165 -0
- package/dist/auth/permit_offer_queries.d.ts.map +1 -0
- package/dist/auth/permit_offer_queries.js +390 -0
- package/dist/auth/permit_offer_schema.d.ts +103 -0
- package/dist/auth/permit_offer_schema.d.ts.map +1 -0
- package/dist/auth/permit_offer_schema.js +142 -0
- package/dist/auth/permit_queries.d.ts +77 -14
- package/dist/auth/permit_queries.d.ts.map +1 -1
- package/dist/auth/permit_queries.js +119 -24
- package/dist/auth/session_queries.d.ts +4 -2
- package/dist/auth/session_queries.d.ts.map +1 -1
- package/dist/auth/session_queries.js +4 -2
- package/dist/auth/signup_routes.d.ts +13 -0
- package/dist/auth/signup_routes.d.ts.map +1 -1
- package/dist/auth/signup_routes.js +14 -7
- package/dist/http/CLAUDE.md +584 -0
- package/dist/http/pending_effects.d.ts +29 -0
- package/dist/http/pending_effects.d.ts.map +1 -0
- package/dist/http/pending_effects.js +31 -0
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/route_spec.js +4 -3
- package/dist/rate_limiter.d.ts +30 -0
- package/dist/rate_limiter.d.ts.map +1 -1
- package/dist/rate_limiter.js +25 -2
- package/dist/realtime/sse_auth_guard.d.ts +2 -0
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
- package/dist/realtime/sse_auth_guard.js +5 -3
- package/dist/testing/CLAUDE.md +668 -1
- package/dist/testing/admin_integration.d.ts +10 -7
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +382 -482
- package/dist/testing/app_server.d.ts +7 -6
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/attack_surface.d.ts +9 -3
- package/dist/testing/attack_surface.d.ts.map +1 -1
- package/dist/testing/attack_surface.js +4 -4
- package/dist/testing/audit_completeness.d.ts +6 -0
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +158 -134
- package/dist/testing/auth_apps.d.ts.map +1 -1
- package/dist/testing/auth_apps.js +4 -33
- package/dist/testing/db.d.ts +1 -1
- package/dist/testing/db.d.ts.map +1 -1
- package/dist/testing/db.js +2 -0
- package/dist/testing/entities.d.ts +35 -13
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +17 -0
- package/dist/testing/integration.d.ts +10 -0
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +352 -340
- package/dist/testing/integration_helpers.d.ts +16 -5
- package/dist/testing/integration_helpers.d.ts.map +1 -1
- package/dist/testing/integration_helpers.js +24 -4
- package/dist/testing/rate_limiting.d.ts +7 -0
- package/dist/testing/rate_limiting.d.ts.map +1 -1
- package/dist/testing/rate_limiting.js +41 -10
- package/dist/testing/rpc_helpers.d.ts +153 -1
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +184 -8
- package/dist/testing/sse_round_trip.d.ts +8 -0
- package/dist/testing/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/sse_round_trip.js +10 -3
- package/dist/testing/standard.d.ts +9 -1
- package/dist/testing/standard.d.ts.map +1 -1
- package/dist/testing/standard.js +6 -2
- package/dist/testing/surface_invariants.d.ts +7 -3
- package/dist/testing/surface_invariants.d.ts.map +1 -1
- package/dist/testing/surface_invariants.js +5 -4
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +9 -38
- package/dist/ui/AccountSessions.svelte +8 -4
- package/dist/ui/AccountSessions.svelte.d.ts.map +1 -1
- package/dist/ui/AdminAccounts.svelte +61 -33
- package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
- package/dist/ui/AdminAuditLog.svelte +3 -2
- package/dist/ui/AdminAuditLog.svelte.d.ts.map +1 -1
- package/dist/ui/AdminInvites.svelte +3 -2
- package/dist/ui/AdminInvites.svelte.d.ts.map +1 -1
- package/dist/ui/AdminOverview.svelte +14 -9
- package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
- package/dist/ui/AdminPermitHistory.svelte +3 -2
- package/dist/ui/AdminPermitHistory.svelte.d.ts.map +1 -1
- package/dist/ui/AdminSessions.svelte +29 -25
- package/dist/ui/AdminSessions.svelte.d.ts.map +1 -1
- package/dist/ui/CLAUDE.md +351 -0
- package/dist/ui/OpenSignupToggle.svelte +6 -3
- package/dist/ui/OpenSignupToggle.svelte.d.ts.map +1 -1
- package/dist/ui/PermitOfferForm.svelte +141 -0
- package/dist/ui/PermitOfferForm.svelte.d.ts +14 -0
- package/dist/ui/PermitOfferForm.svelte.d.ts.map +1 -0
- package/dist/ui/PermitOfferHistory.svelte +109 -0
- package/dist/ui/PermitOfferHistory.svelte.d.ts +11 -0
- package/dist/ui/PermitOfferHistory.svelte.d.ts.map +1 -0
- package/dist/ui/PermitOfferInbox.svelte +121 -0
- package/dist/ui/PermitOfferInbox.svelte.d.ts +12 -0
- package/dist/ui/PermitOfferInbox.svelte.d.ts.map +1 -0
- package/dist/ui/account_sessions_state.svelte.d.ts +53 -3
- package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
- package/dist/ui/account_sessions_state.svelte.js +39 -16
- package/dist/ui/admin_accounts_state.svelte.d.ts +118 -2
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.js +99 -23
- package/dist/ui/admin_invites_state.svelte.d.ts +47 -1
- package/dist/ui/admin_invites_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_invites_state.svelte.js +38 -26
- package/dist/ui/admin_sessions_state.svelte.d.ts +26 -0
- package/dist/ui/admin_sessions_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_sessions_state.svelte.js +35 -21
- package/dist/ui/app_settings_state.svelte.d.ts +39 -0
- package/dist/ui/app_settings_state.svelte.d.ts.map +1 -1
- package/dist/ui/app_settings_state.svelte.js +34 -18
- package/dist/ui/audit_log_state.svelte.d.ts +40 -3
- package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
- package/dist/ui/audit_log_state.svelte.js +36 -42
- package/dist/ui/auth_state.svelte.d.ts +4 -3
- package/dist/ui/auth_state.svelte.d.ts.map +1 -1
- package/dist/ui/auth_state.svelte.js +4 -1
- package/dist/ui/permit_offers_state.svelte.d.ts +125 -0
- package/dist/ui/permit_offers_state.svelte.d.ts.map +1 -0
- package/dist/ui/permit_offers_state.svelte.js +197 -0
- package/package.json +3 -3
- package/dist/auth/admin_routes.d.ts +0 -29
- package/dist/auth/admin_routes.d.ts.map +0 -1
- package/dist/auth/admin_routes.js +0 -226
- package/dist/auth/app_settings_routes.d.ts +0 -27
- package/dist/auth/app_settings_routes.d.ts.map +0 -1
- package/dist/auth/app_settings_routes.js +0 -66
- package/dist/auth/invite_routes.d.ts +0 -18
- package/dist/auth/invite_routes.d.ts.map +0 -1
- package/dist/auth/invite_routes.js +0 -129
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @module
|
|
13
13
|
*/
|
|
14
|
+
import { z } from 'zod';
|
|
14
15
|
import type { Logger } from '@fuzdev/fuz_util/log.js';
|
|
15
16
|
import type { RequestResponseActionSpec } from './action_spec.js';
|
|
16
17
|
import { type RouteSpec } from '../http/route_spec.js';
|
|
@@ -35,6 +36,15 @@ export interface ActionContext {
|
|
|
35
36
|
background_db: Db;
|
|
36
37
|
/** Fire-and-forget side effects — push here for post-response flushing. */
|
|
37
38
|
pending_effects: Array<Promise<void>>;
|
|
39
|
+
/**
|
|
40
|
+
* Resolved client IP from the trusted-proxy middleware — `'unknown'` if the
|
|
41
|
+
* middleware wasn't in the stack (e.g. WS dispatch) or couldn't resolve.
|
|
42
|
+
* Thread into `audit_log_fire_and_forget` as `ip: ctx.client_ip` for every
|
|
43
|
+
* user-initiated action so RPC audit rows match the REST convention. Pass
|
|
44
|
+
* `null` only for rows written outside a request (e.g. the
|
|
45
|
+
* `permit_offer_expire` cleanup sweep in `auth/cleanup.ts`).
|
|
46
|
+
*/
|
|
47
|
+
client_ip: string;
|
|
38
48
|
/** Logger instance. */
|
|
39
49
|
log: Logger;
|
|
40
50
|
/**
|
|
@@ -71,6 +81,25 @@ export interface RpcAction {
|
|
|
71
81
|
spec: RequestResponseActionSpec;
|
|
72
82
|
handler: ActionHandler;
|
|
73
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Pair a spec with a handler while preserving per-method input/output types.
|
|
86
|
+
*
|
|
87
|
+
* Constructing `{spec, handler}` literals widens `handler` to
|
|
88
|
+
* `ActionHandler<any, any>`, so spec/handler drift (renamed Zod schema,
|
|
89
|
+
* output field removal, input shape change) slips past the typechecker.
|
|
90
|
+
* `rpc_action(spec, handler)` binds the handler signature to
|
|
91
|
+
* `(input: z.infer<spec.input>, ctx) => z.infer<spec.output>` via the
|
|
92
|
+
* generic spec parameter — drift surfaces at the call site.
|
|
93
|
+
*
|
|
94
|
+
* Fits fuz_app's factory-closure pattern (handlers close over
|
|
95
|
+
* `grantable_roles`, `app_settings` ref, `notification_sender`, etc.).
|
|
96
|
+
* zzz uses a different shape — a codegen-keyed `Record<Method, Handler>`
|
|
97
|
+
* map typed via generated `ActionInputs`/`ActionOutputs` — which works when
|
|
98
|
+
* handlers are pure (no closure state) and specs are codegen-enumerated.
|
|
99
|
+
* fuz_app's admin + permit-offer actions have neither, so per-pair typing
|
|
100
|
+
* at the registration site is the right fit.
|
|
101
|
+
*/
|
|
102
|
+
export declare const rpc_action: <TSpec extends RequestResponseActionSpec>(spec: TSpec, handler: ActionHandler<z.infer<TSpec["input"]>, z.infer<TSpec["output"]>>) => RpcAction;
|
|
74
103
|
/** Options for `create_rpc_endpoint`. */
|
|
75
104
|
export interface CreateRpcEndpointOptions {
|
|
76
105
|
/** Mount path for the endpoint (e.g., `/api/rpc`). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action_rpc.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_rpc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"action_rpc.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_rpc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAExE,OAAO,EAAgC,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE9F,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAEpC,OAAO,EAGN,KAAK,gBAAgB,EAGrB,MAAM,oBAAoB,CAAC;AAW5B;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC7B,+DAA+D;IAC/D,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IAC5B,iDAAiD;IACjD,UAAU,EAAE,gBAAgB,CAAC;IAC7B,8DAA8D;IAC9D,EAAE,EAAE,EAAE,CAAC;IACP,oFAAoF;IACpF,aAAa,EAAE,EAAE,CAAC;IAClB,2EAA2E;IAC3E,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC;;;;;;;OAOG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;OAQG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD;;;;OAIG;IACH,MAAM,EAAE,WAAW,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,CAAC,MAAM,GAAG,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,CACxD,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,aAAa,KACd,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,yBAAyB,CAAC;IAChC,OAAO,EAAE,aAAa,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,SAAS,yBAAyB,EACjE,MAAM,KAAK,EACX,SAAS,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KACvE,SAGD,CAAC;AAEH,yCAAyC;AACzC,MAAM,WAAW,wBAAwB;IACxC,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC1B,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;CACZ;AA4DD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,wBAAwB,KAAG,KAAK,CAAC,SAAS,CAwPtF,CAAC"}
|
|
@@ -14,11 +14,35 @@
|
|
|
14
14
|
import { z } from 'zod';
|
|
15
15
|
import { DEV } from 'esm-env';
|
|
16
16
|
import {} from '../http/route_spec.js';
|
|
17
|
+
import { get_client_ip } from '../http/proxy.js';
|
|
17
18
|
import { get_request_context, has_role } from '../auth/request_context.js';
|
|
18
19
|
import { CREDENTIAL_TYPE_KEY } from '../hono_context.js';
|
|
19
20
|
import { is_null_schema } from '../http/schema_helpers.js';
|
|
20
21
|
import { JSONRPC_VERSION, JsonrpcRequest, } from '../http/jsonrpc.js';
|
|
21
22
|
import { jsonrpc_error_messages, jsonrpc_error_code_to_http_status, JSONRPC_ERROR_CODES, } from '../http/jsonrpc_errors.js';
|
|
23
|
+
import { ERROR_INSUFFICIENT_PERMISSIONS, ERROR_KEEPER_REQUIRES_DAEMON_TOKEN, } from '../http/error_schemas.js';
|
|
24
|
+
/**
|
|
25
|
+
* Pair a spec with a handler while preserving per-method input/output types.
|
|
26
|
+
*
|
|
27
|
+
* Constructing `{spec, handler}` literals widens `handler` to
|
|
28
|
+
* `ActionHandler<any, any>`, so spec/handler drift (renamed Zod schema,
|
|
29
|
+
* output field removal, input shape change) slips past the typechecker.
|
|
30
|
+
* `rpc_action(spec, handler)` binds the handler signature to
|
|
31
|
+
* `(input: z.infer<spec.input>, ctx) => z.infer<spec.output>` via the
|
|
32
|
+
* generic spec parameter — drift surfaces at the call site.
|
|
33
|
+
*
|
|
34
|
+
* Fits fuz_app's factory-closure pattern (handlers close over
|
|
35
|
+
* `grantable_roles`, `app_settings` ref, `notification_sender`, etc.).
|
|
36
|
+
* zzz uses a different shape — a codegen-keyed `Record<Method, Handler>`
|
|
37
|
+
* map typed via generated `ActionInputs`/`ActionOutputs` — which works when
|
|
38
|
+
* handlers are pure (no closure state) and specs are codegen-enumerated.
|
|
39
|
+
* fuz_app's admin + permit-offer actions have neither, so per-pair typing
|
|
40
|
+
* at the registration site is the right fit.
|
|
41
|
+
*/
|
|
42
|
+
export const rpc_action = (spec, handler) => ({
|
|
43
|
+
spec,
|
|
44
|
+
handler: handler,
|
|
45
|
+
});
|
|
22
46
|
/**
|
|
23
47
|
* Format a JSON-RPC error response.
|
|
24
48
|
*
|
|
@@ -49,15 +73,25 @@ const check_action_auth = (auth, request_context, credential_type) => {
|
|
|
49
73
|
if (auth === 'keeper') {
|
|
50
74
|
// keeper requires daemon_token credential type AND the keeper role.
|
|
51
75
|
// API tokens and session cookies cannot access keeper actions even
|
|
52
|
-
// if the account has the keeper permit.
|
|
76
|
+
// if the account has the keeper permit. Attach the credential type
|
|
77
|
+
// under `data` so clients can distinguish "wrong credential shape"
|
|
78
|
+
// from "missing keeper role" — mirrors REST 403 semantics.
|
|
53
79
|
if (credential_type !== 'daemon_token' || !has_role(request_context, 'keeper')) {
|
|
54
|
-
return jsonrpc_error_messages.forbidden(
|
|
80
|
+
return jsonrpc_error_messages.forbidden('forbidden', {
|
|
81
|
+
reason: ERROR_KEEPER_REQUIRES_DAEMON_TOKEN,
|
|
82
|
+
credential_type,
|
|
83
|
+
});
|
|
55
84
|
}
|
|
56
85
|
return null;
|
|
57
86
|
}
|
|
58
|
-
// role check
|
|
87
|
+
// role check — attach `required_role` under `data.required_role` so
|
|
88
|
+
// clients can render targeted copy (matches the former REST `PermissionError`
|
|
89
|
+
// shape that exposed `required_role` as a top-level field).
|
|
59
90
|
if (!has_role(request_context, auth.role)) {
|
|
60
|
-
return jsonrpc_error_messages.forbidden(`requires role: ${auth.role}
|
|
91
|
+
return jsonrpc_error_messages.forbidden(`requires role: ${auth.role}`, {
|
|
92
|
+
reason: ERROR_INSUFFICIENT_PERMISSIONS,
|
|
93
|
+
required_role: auth.role,
|
|
94
|
+
});
|
|
61
95
|
}
|
|
62
96
|
return null;
|
|
63
97
|
};
|
|
@@ -145,6 +179,7 @@ export const create_rpc_endpoint = (options) => {
|
|
|
145
179
|
}
|
|
146
180
|
};
|
|
147
181
|
const signal = c.req.raw.signal;
|
|
182
|
+
const client_ip = get_client_ip(c);
|
|
148
183
|
const execute = async (db) => {
|
|
149
184
|
const action_context = {
|
|
150
185
|
auth: request_context,
|
|
@@ -152,16 +187,17 @@ export const create_rpc_endpoint = (options) => {
|
|
|
152
187
|
db,
|
|
153
188
|
background_db: route.background_db,
|
|
154
189
|
pending_effects: route.pending_effects,
|
|
190
|
+
client_ip,
|
|
155
191
|
log,
|
|
156
192
|
notify,
|
|
157
193
|
signal,
|
|
158
194
|
};
|
|
159
195
|
const output = await action.handler(parse_result.data, action_context);
|
|
160
|
-
// DEV-only output validation
|
|
196
|
+
// DEV-only output validation — logs an error on mismatch, does not throw.
|
|
161
197
|
if (DEV) {
|
|
162
198
|
const output_result = action.spec.output.safeParse(output);
|
|
163
199
|
if (!output_result.success) {
|
|
164
|
-
log.
|
|
200
|
+
log.error(`RPC output schema mismatch: ${method_name}`, output_result.error.issues);
|
|
165
201
|
}
|
|
166
202
|
}
|
|
167
203
|
return c.json({ jsonrpc: JSONRPC_VERSION, id, result: output });
|
|
@@ -54,8 +54,8 @@ export interface BaseHandlerContext {
|
|
|
54
54
|
export type WsActionHandler<TCtx extends BaseHandlerContext = BaseHandlerContext> = (input: unknown, ctx: TCtx) => unknown;
|
|
55
55
|
/**
|
|
56
56
|
* A spec paired with its optional handler — the composable unit passed to
|
|
57
|
-
*
|
|
58
|
-
* both fields; the client reads only
|
|
57
|
+
* `register_action_ws` and `create_rpc_client`. The server uses
|
|
58
|
+
* both fields; the client reads only `spec` (the `handler` is
|
|
59
59
|
* ignored, harmless). Shared fuz_app primitives (e.g. `heartbeat_action`)
|
|
60
60
|
* export a complete tuple so consumers spread them into both sides'
|
|
61
61
|
* `actions` array without inventing per-repo ping plumbing.
|
package/dist/actions/cancel.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Semantics: the client sends `{jsonrpc, method: 'cancel', params:
|
|
6
6
|
* {request_id}}` to abort an in-flight request on the same socket.
|
|
7
|
-
*
|
|
7
|
+
* `register_action_ws` intercepts this notification and aborts the
|
|
8
8
|
* matching pending request's `ctx.signal`. Unknown ids are no-ops by design —
|
|
9
9
|
* races between response arrival and cancel delivery are safe without extra
|
|
10
10
|
* coordination.
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
* The handler field is an empty stub: cancel semantics are dispatcher-owned
|
|
13
13
|
* (the dispatcher has the `{request_id → AbortController}` map, not the
|
|
14
14
|
* handler). The handler exists for symmetry with other composable primitives
|
|
15
|
-
* like
|
|
16
|
-
* spread
|
|
15
|
+
* like `heartbeat_action`; the dispatcher never calls it. Consumers
|
|
16
|
+
* spread `cancel_action` into their server's `actions` array so
|
|
17
17
|
* `spec_by_method` knows about it (enabling input validation on incoming
|
|
18
18
|
* cancels) and so `create_rpc_client` codegen produces `app.api.cancel()`
|
|
19
19
|
* when desired — though `FrontendWebsocketClient.request({signal})` sends
|
|
@@ -29,11 +29,9 @@
|
|
|
29
29
|
*/
|
|
30
30
|
import { z } from 'zod';
|
|
31
31
|
import type { Action } from './action_types.js';
|
|
32
|
-
/** Method name on the wire — shared across every fuz_app consumer. */
|
|
33
|
-
export declare const CANCEL_METHOD = "cancel";
|
|
34
32
|
/**
|
|
35
|
-
* Params for
|
|
36
|
-
*
|
|
33
|
+
* Params for the `cancel` notification. `request_id` is the id of the
|
|
34
|
+
* pending request to abort. Must match the id of a request sent on the
|
|
37
35
|
* same socket; cancels from other sockets (or for unknown ids) are ignored.
|
|
38
36
|
*/
|
|
39
37
|
export declare const CancelNotificationParams: z.ZodObject<{
|
|
@@ -50,19 +48,20 @@ export type CancelNotificationParams = z.infer<typeof CancelNotificationParams>;
|
|
|
50
48
|
*/
|
|
51
49
|
export declare const cancel_action_spec: {
|
|
52
50
|
method: string;
|
|
53
|
-
initiator: "both" | "frontend" | "backend";
|
|
54
|
-
input: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
55
|
-
description: string;
|
|
56
51
|
kind: "remote_notification";
|
|
52
|
+
initiator: "frontend";
|
|
57
53
|
auth: null;
|
|
58
54
|
side_effects: true;
|
|
55
|
+
input: z.ZodObject<{
|
|
56
|
+
request_id: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
57
|
+
}, z.core.$strict>;
|
|
59
58
|
output: z.ZodVoid;
|
|
60
59
|
async: true;
|
|
61
|
-
|
|
60
|
+
description: string;
|
|
62
61
|
};
|
|
63
62
|
/**
|
|
64
|
-
* Placeholder handler — cancel semantics are owned by
|
|
65
|
-
* not invoked per-handler. Exported for symmetry with the
|
|
63
|
+
* Placeholder handler — cancel semantics are owned by `register_action_ws`,
|
|
64
|
+
* not invoked per-handler. Exported for symmetry with the `Action`
|
|
66
65
|
* tuple shape; the dispatcher short-circuits cancel notifications before any
|
|
67
66
|
* handler lookup happens.
|
|
68
67
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cancel.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/cancel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAItB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAC;AAE9C
|
|
1
|
+
{"version":3,"file":"cancel.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/cancel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAItB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAC;AAE9C;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;kBAEnC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;CAWS,CAAC;AAEzC;;;;;GAKG;AACH,eAAO,MAAM,cAAc,QAAO,IAAU,CAAC;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,EAAE,MAG3B,CAAC"}
|
package/dist/actions/cancel.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Semantics: the client sends `{jsonrpc, method: 'cancel', params:
|
|
6
6
|
* {request_id}}` to abort an in-flight request on the same socket.
|
|
7
|
-
*
|
|
7
|
+
* `register_action_ws` intercepts this notification and aborts the
|
|
8
8
|
* matching pending request's `ctx.signal`. Unknown ids are no-ops by design —
|
|
9
9
|
* races between response arrival and cancel delivery are safe without extra
|
|
10
10
|
* coordination.
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
* The handler field is an empty stub: cancel semantics are dispatcher-owned
|
|
13
13
|
* (the dispatcher has the `{request_id → AbortController}` map, not the
|
|
14
14
|
* handler). The handler exists for symmetry with other composable primitives
|
|
15
|
-
* like
|
|
16
|
-
* spread
|
|
15
|
+
* like `heartbeat_action`; the dispatcher never calls it. Consumers
|
|
16
|
+
* spread `cancel_action` into their server's `actions` array so
|
|
17
17
|
* `spec_by_method` knows about it (enabling input validation on incoming
|
|
18
18
|
* cancels) and so `create_rpc_client` codegen produces `app.api.cancel()`
|
|
19
19
|
* when desired — though `FrontendWebsocketClient.request({signal})` sends
|
|
@@ -29,12 +29,9 @@
|
|
|
29
29
|
*/
|
|
30
30
|
import { z } from 'zod';
|
|
31
31
|
import { JsonrpcRequestId } from '../http/jsonrpc.js';
|
|
32
|
-
import { RemoteNotificationActionSpec } from './action_spec.js';
|
|
33
|
-
/** Method name on the wire — shared across every fuz_app consumer. */
|
|
34
|
-
export const CANCEL_METHOD = 'cancel';
|
|
35
32
|
/**
|
|
36
|
-
* Params for
|
|
37
|
-
*
|
|
33
|
+
* Params for the `cancel` notification. `request_id` is the id of the
|
|
34
|
+
* pending request to abort. Must match the id of a request sent on the
|
|
38
35
|
* same socket; cancels from other sockets (or for unknown ids) are ignored.
|
|
39
36
|
*/
|
|
40
37
|
export const CancelNotificationParams = z.strictObject({
|
|
@@ -48,8 +45,8 @@ export const CancelNotificationParams = z.strictObject({
|
|
|
48
45
|
* ownership naturally: a different socket's cancel for the same id misses
|
|
49
46
|
* in its own map.
|
|
50
47
|
*/
|
|
51
|
-
export const cancel_action_spec =
|
|
52
|
-
method:
|
|
48
|
+
export const cancel_action_spec = {
|
|
49
|
+
method: 'cancel',
|
|
53
50
|
kind: 'remote_notification',
|
|
54
51
|
initiator: 'frontend',
|
|
55
52
|
auth: null,
|
|
@@ -58,10 +55,10 @@ export const cancel_action_spec = RemoteNotificationActionSpec.parse({
|
|
|
58
55
|
output: z.void(),
|
|
59
56
|
async: true,
|
|
60
57
|
description: 'Client-initiated cancellation of an in-flight request by id. Dispatcher-handled: aborts the ctx.signal of the matching pending request on the same socket. Unknown or completed ids no-op.',
|
|
61
|
-
}
|
|
58
|
+
};
|
|
62
59
|
/**
|
|
63
|
-
* Placeholder handler — cancel semantics are owned by
|
|
64
|
-
* not invoked per-handler. Exported for symmetry with the
|
|
60
|
+
* Placeholder handler — cancel semantics are owned by `register_action_ws`,
|
|
61
|
+
* not invoked per-handler. Exported for symmetry with the `Action`
|
|
65
62
|
* tuple shape; the dispatcher short-circuits cancel notifications before any
|
|
66
63
|
* handler lookup happens.
|
|
67
64
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared heartbeat action — the first composable fuz_app primitive carrying
|
|
3
3
|
* both a spec and a handler in one tuple. Consumers spread
|
|
4
|
-
*
|
|
4
|
+
* `heartbeat_action` into both the server's and the client's `actions`
|
|
5
5
|
* array so disconnect detection works identically across every repo without
|
|
6
6
|
* per-consumer ping plumbing.
|
|
7
7
|
*
|
|
@@ -12,15 +12,13 @@
|
|
|
12
12
|
* alive without any handler-level state.
|
|
13
13
|
*
|
|
14
14
|
* Nullary input/output today. `{client_ts, server_ts}` fields can be added
|
|
15
|
-
* later if clock-skew telemetry ever matters — the
|
|
15
|
+
* later if clock-skew telemetry ever matters — the `Action` container
|
|
16
16
|
* is open for additions without churning consumer call sites.
|
|
17
17
|
*
|
|
18
18
|
* @module
|
|
19
19
|
*/
|
|
20
20
|
import { z } from 'zod';
|
|
21
21
|
import type { Action } from './action_types.js';
|
|
22
|
-
/** Method name on the wire — shared across every fuz_app consumer. */
|
|
23
|
-
export declare const HEARTBEAT_METHOD = "heartbeat";
|
|
24
22
|
/**
|
|
25
23
|
* `ActionSpec` for the shared heartbeat. `authenticated` auth — upgrade-time
|
|
26
24
|
* auth has already admitted the socket; heartbeats don't need role gating.
|
|
@@ -28,17 +26,14 @@ export declare const HEARTBEAT_METHOD = "heartbeat";
|
|
|
28
26
|
*/
|
|
29
27
|
export declare const heartbeat_action_spec: {
|
|
30
28
|
method: string;
|
|
31
|
-
initiator: "both" | "frontend" | "backend";
|
|
32
|
-
side_effects: boolean;
|
|
33
|
-
input: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
34
|
-
output: z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
35
|
-
description: string;
|
|
36
29
|
kind: "request_response";
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
initiator: "frontend";
|
|
31
|
+
auth: "authenticated";
|
|
32
|
+
side_effects: false;
|
|
33
|
+
input: z.ZodObject<{}, z.core.$strict>;
|
|
34
|
+
output: z.ZodObject<{}, z.core.$strict>;
|
|
40
35
|
async: true;
|
|
41
|
-
|
|
36
|
+
description: string;
|
|
42
37
|
};
|
|
43
38
|
/** Handler — nullary echo. Stateless, suitable for high-frequency pings. */
|
|
44
39
|
export declare const heartbeat_handler: () => Record<string, never>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/heartbeat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAC;AAE9C
|
|
1
|
+
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/heartbeat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAC;AAE9C;;;;GAIG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;CAUG,CAAC;AAEtC,4EAA4E;AAC5E,eAAO,MAAM,iBAAiB,QAAO,MAAM,CAAC,MAAM,EAAE,KAAK,CAAS,CAAC;AAEnE;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAG9B,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared heartbeat action — the first composable fuz_app primitive carrying
|
|
3
3
|
* both a spec and a handler in one tuple. Consumers spread
|
|
4
|
-
*
|
|
4
|
+
* `heartbeat_action` into both the server's and the client's `actions`
|
|
5
5
|
* array so disconnect detection works identically across every repo without
|
|
6
6
|
* per-consumer ping plumbing.
|
|
7
7
|
*
|
|
@@ -12,22 +12,19 @@
|
|
|
12
12
|
* alive without any handler-level state.
|
|
13
13
|
*
|
|
14
14
|
* Nullary input/output today. `{client_ts, server_ts}` fields can be added
|
|
15
|
-
* later if clock-skew telemetry ever matters — the
|
|
15
|
+
* later if clock-skew telemetry ever matters — the `Action` container
|
|
16
16
|
* is open for additions without churning consumer call sites.
|
|
17
17
|
*
|
|
18
18
|
* @module
|
|
19
19
|
*/
|
|
20
20
|
import { z } from 'zod';
|
|
21
|
-
import { RequestResponseActionSpec } from './action_spec.js';
|
|
22
|
-
/** Method name on the wire — shared across every fuz_app consumer. */
|
|
23
|
-
export const HEARTBEAT_METHOD = 'heartbeat';
|
|
24
21
|
/**
|
|
25
22
|
* `ActionSpec` for the shared heartbeat. `authenticated` auth — upgrade-time
|
|
26
23
|
* auth has already admitted the socket; heartbeats don't need role gating.
|
|
27
24
|
* `side_effects: false` keeps it orthogonal to state changes.
|
|
28
25
|
*/
|
|
29
|
-
export const heartbeat_action_spec =
|
|
30
|
-
method:
|
|
26
|
+
export const heartbeat_action_spec = {
|
|
27
|
+
method: 'heartbeat',
|
|
31
28
|
kind: 'request_response',
|
|
32
29
|
initiator: 'frontend',
|
|
33
30
|
auth: 'authenticated',
|
|
@@ -36,7 +33,7 @@ export const heartbeat_action_spec = RequestResponseActionSpec.parse({
|
|
|
36
33
|
output: z.strictObject({}),
|
|
37
34
|
async: true,
|
|
38
35
|
description: 'Shared activity ping — keeps the socket alive and exercises the dispatch path.',
|
|
39
|
-
}
|
|
36
|
+
};
|
|
40
37
|
/** Handler — nullary echo. Stateless, suitable for high-frequency pings. */
|
|
41
38
|
export const heartbeat_handler = () => ({});
|
|
42
39
|
/**
|
|
@@ -79,8 +79,8 @@ export interface SocketCloseContext {
|
|
|
79
79
|
export interface ServerHeartbeatOptions {
|
|
80
80
|
/**
|
|
81
81
|
* Receive-silence (ms) past which the server closes the socket with
|
|
82
|
-
*
|
|
83
|
-
* the counter — chatty clients never trip it. First
|
|
82
|
+
* `WS_CLOSE_SERVER_HEARTBEAT_TIMEOUT`. Any incoming message resets
|
|
83
|
+
* the counter — chatty clients never trip it. First `timeout`
|
|
84
84
|
* window after socket open is exempt (cold-start grace).
|
|
85
85
|
*/
|
|
86
86
|
timeout?: number;
|
|
@@ -97,7 +97,7 @@ export interface RegisterActionWsOptions<TCtx extends BaseHandlerContext> {
|
|
|
97
97
|
* The actions registered on this endpoint — each carries a spec (drives
|
|
98
98
|
* method lookup, per-action auth, input/output validation) and an
|
|
99
99
|
* optional handler (omit for client-only specs like inbound
|
|
100
|
-
* notifications). Include the shared
|
|
100
|
+
* notifications). Include the shared `heartbeat_action` here to
|
|
101
101
|
* complete the disconnect-detection pairing with the frontend client.
|
|
102
102
|
*/
|
|
103
103
|
actions: ReadonlyArray<Action<TCtx>>;
|
|
@@ -39,7 +39,7 @@ import { jsonrpc_error_messages, ThrownJsonrpcError } from '../http/jsonrpc_erro
|
|
|
39
39
|
import { create_jsonrpc_error_response, create_jsonrpc_error_response_from_thrown, create_jsonrpc_notification, to_jsonrpc_message_id, to_jsonrpc_params, is_jsonrpc_request, } from '../http/jsonrpc_helpers.js';
|
|
40
40
|
import { CREDENTIAL_TYPE_KEY, AUTH_API_TOKEN_ID_KEY } from '../hono_context.js';
|
|
41
41
|
import {} from './action_types.js';
|
|
42
|
-
import {
|
|
42
|
+
import { cancel_action_spec, CancelNotificationParams } from './cancel.js';
|
|
43
43
|
import { WS_CLOSE_SERVER_HEARTBEAT_TIMEOUT } from './transports.js';
|
|
44
44
|
import { BackendWebsocketTransport } from './transports_ws_backend.js';
|
|
45
45
|
/** Default inactivity window before the server closes a silent socket. */
|
|
@@ -206,7 +206,7 @@ export const register_action_ws = (options) => {
|
|
|
206
206
|
// are not a feature yet).
|
|
207
207
|
if (!is_jsonrpc_request(json)) {
|
|
208
208
|
if (typeof json === 'object' && json !== null && 'method' in json && !('id' in json)) {
|
|
209
|
-
if (json.method ===
|
|
209
|
+
if (json.method === cancel_action_spec.method) {
|
|
210
210
|
const parsed = CancelNotificationParams.safeParse(json.params);
|
|
211
211
|
if (!parsed.success) {
|
|
212
212
|
log.debug('cancel: invalid params, ignoring', parsed.error.issues);
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* 3. Optional `require_role(required_role)` — for endpoints gated to a
|
|
11
11
|
* specific role.
|
|
12
12
|
*
|
|
13
|
-
* Then delegates to
|
|
13
|
+
* Then delegates to `register_action_ws` for per-message JSON-RPC
|
|
14
14
|
* dispatch.
|
|
15
15
|
*
|
|
16
16
|
* @module
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import type { RoleName } from '../auth/role_schema.js';
|
|
19
19
|
import { type RegisterActionWsOptions, type RegisterActionWsResult } from './register_action_ws.js';
|
|
20
20
|
import type { BaseHandlerContext } from './action_types.js';
|
|
21
|
-
/** Options for
|
|
21
|
+
/** Options for `register_ws_endpoint`. */
|
|
22
22
|
export interface RegisterWsEndpointOptions<TCtx extends BaseHandlerContext> extends RegisterActionWsOptions<TCtx> {
|
|
23
23
|
/**
|
|
24
24
|
* Origin allowlist regexes — typically parsed from the `ALLOWED_ORIGINS`
|
|
@@ -38,8 +38,8 @@ export interface RegisterWsEndpointOptions<TCtx extends BaseHandlerContext> exte
|
|
|
38
38
|
* Mount a WebSocket endpoint with the standard upgrade stack (origin check
|
|
39
39
|
* + auth + optional role) and JSON-RPC dispatch.
|
|
40
40
|
*
|
|
41
|
-
* Returns the
|
|
42
|
-
* created), same as
|
|
41
|
+
* Returns the `BackendWebsocketTransport` (supplied or freshly
|
|
42
|
+
* created), same as `register_action_ws` — retain it to wire
|
|
43
43
|
* `create_ws_auth_guard` on `on_audit_event` or to broadcast.
|
|
44
44
|
*/
|
|
45
45
|
export declare const register_ws_endpoint: <TCtx extends BaseHandlerContext>(options: RegisterWsEndpointOptions<TCtx>) => RegisterActionWsResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register_ws_endpoint.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/register_ws_endpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAEN,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,mBAAmB,CAAC;AAE1D,
|
|
1
|
+
{"version":3,"file":"register_ws_endpoint.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/register_ws_endpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAEN,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,mBAAmB,CAAC;AAE1D,0CAA0C;AAC1C,MAAM,WAAW,yBAAyB,CACzC,IAAI,SAAS,kBAAkB,CAC9B,SAAQ,uBAAuB,CAAC,IAAI,CAAC;IACtC;;;;OAIG;IACH,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,QAAQ,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAI,IAAI,SAAS,kBAAkB,EACnE,SAAS,yBAAyB,CAAC,IAAI,CAAC,KACtC,sBAUF,CAAC"}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* 3. Optional `require_role(required_role)` — for endpoints gated to a
|
|
11
11
|
* specific role.
|
|
12
12
|
*
|
|
13
|
-
* Then delegates to
|
|
13
|
+
* Then delegates to `register_action_ws` for per-message JSON-RPC
|
|
14
14
|
* dispatch.
|
|
15
15
|
*
|
|
16
16
|
* @module
|
|
@@ -23,8 +23,8 @@ import { register_action_ws, } from './register_action_ws.js';
|
|
|
23
23
|
* Mount a WebSocket endpoint with the standard upgrade stack (origin check
|
|
24
24
|
* + auth + optional role) and JSON-RPC dispatch.
|
|
25
25
|
*
|
|
26
|
-
* Returns the
|
|
27
|
-
* created), same as
|
|
26
|
+
* Returns the `BackendWebsocketTransport` (supplied or freshly
|
|
27
|
+
* created), same as `register_action_ws` — retain it to wire
|
|
28
28
|
* `create_ws_auth_guard` on `on_audit_event` or to broadcast.
|
|
29
29
|
*/
|
|
30
30
|
export const register_ws_endpoint = (options) => {
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
* message path so request/response correlation is transport-level rather
|
|
14
14
|
* than re-invented per consumer.
|
|
15
15
|
* - **Durable queue** — `request()` calls made while disconnected buffer up
|
|
16
|
-
* to
|
|
16
|
+
* to `DEFAULT_QUEUE_MAX_SIZE` requests and flush on reopen. Overflow
|
|
17
17
|
* rejects with `queue_overflow`. Raw {@link FrontendWebsocketClient.send}
|
|
18
18
|
* is drop-on-disconnect (fire-and-forget notifications want that).
|
|
19
19
|
* - **Activity-aware heartbeat** — idles fire a shared `heartbeat` request;
|
|
20
|
-
* receive-silence past
|
|
21
|
-
* with
|
|
20
|
+
* receive-silence past `DEFAULT_HEARTBEAT_RECEIVE_TIMEOUT` closes
|
|
21
|
+
* with `WS_CLOSE_CLIENT_HEARTBEAT_TIMEOUT` and lets auto-reconnect
|
|
22
22
|
* pick back up.
|
|
23
23
|
*
|
|
24
24
|
* @module
|
|
@@ -37,7 +37,7 @@ export declare const DEFAULT_RECONNECT_DELAY_MAX = 10000;
|
|
|
37
37
|
export declare const DEFAULT_BACKOFF_FACTOR = 1.5;
|
|
38
38
|
/** Idle interval before sending a heartbeat (ms). */
|
|
39
39
|
export declare const DEFAULT_HEARTBEAT_INTERVAL = 30000;
|
|
40
|
-
/** Max receive silence before closing with
|
|
40
|
+
/** Max receive silence before closing with `WS_CLOSE_CLIENT_HEARTBEAT_TIMEOUT` (ms). */
|
|
41
41
|
export declare const DEFAULT_HEARTBEAT_RECEIVE_TIMEOUT = 60000;
|
|
42
42
|
/** Default bound on buffered requests while disconnected. Overflow rejects. */
|
|
43
43
|
export declare const DEFAULT_QUEUE_MAX_SIZE = 100;
|
|
@@ -66,14 +66,14 @@ export interface FrontendWebsocketHeartbeatOptions {
|
|
|
66
66
|
/**
|
|
67
67
|
* Idle duration (ms) after which a heartbeat is sent. Reset by any send or
|
|
68
68
|
* receive — chatty clients never emit extras. Defaults to
|
|
69
|
-
*
|
|
69
|
+
* `DEFAULT_HEARTBEAT_INTERVAL`.
|
|
70
70
|
*/
|
|
71
71
|
interval?: number;
|
|
72
72
|
/**
|
|
73
73
|
* Receive-silence (ms) after which the client closes the socket with
|
|
74
|
-
*
|
|
75
|
-
* in. Should be a comfortable multiple of
|
|
76
|
-
*
|
|
74
|
+
* `WS_CLOSE_CLIENT_HEARTBEAT_TIMEOUT`, letting auto-reconnect kick
|
|
75
|
+
* in. Should be a comfortable multiple of `interval`. Defaults to
|
|
76
|
+
* `DEFAULT_HEARTBEAT_RECEIVE_TIMEOUT`.
|
|
77
77
|
*/
|
|
78
78
|
receive_timeout?: number;
|
|
79
79
|
}
|
|
@@ -81,7 +81,7 @@ export interface FrontendWebsocketQueueOptions {
|
|
|
81
81
|
/**
|
|
82
82
|
* Maximum number of requests held while the socket is disconnected.
|
|
83
83
|
* Enqueue past this rejects the new call with a `queue_overflow` error.
|
|
84
|
-
* Defaults to
|
|
84
|
+
* Defaults to `DEFAULT_QUEUE_MAX_SIZE`.
|
|
85
85
|
*/
|
|
86
86
|
max_size?: number;
|
|
87
87
|
}
|
|
@@ -138,7 +138,7 @@ export declare class FrontendWebsocketClient implements WebsocketConnection, Dis
|
|
|
138
138
|
* when the underlying `ws.send` throws (e.g., buffer full, serialization
|
|
139
139
|
* error); reset to `null` on the next successful send. Not touched when
|
|
140
140
|
* `send()` short-circuits because the socket is not connected — consult
|
|
141
|
-
*
|
|
141
|
+
* `connected` for that case. Wrappers surfacing per-message failure
|
|
142
142
|
* reasons can read this after a `false` return from `send()`.
|
|
143
143
|
*/
|
|
144
144
|
last_send_error: Error | null;
|
|
@@ -170,7 +170,7 @@ export declare class FrontendWebsocketClient implements WebsocketConnection, Dis
|
|
|
170
170
|
* `null`/omitted restores the defaults, or a config object customizes
|
|
171
171
|
* specific fields (missing fields fall back to defaults, not "keep
|
|
172
172
|
* current" — each call defines the whole policy atomically, same as the
|
|
173
|
-
* constructor and
|
|
173
|
+
* constructor and `set_reconnect`).
|
|
174
174
|
*
|
|
175
175
|
* When connected, the live timer is restarted immediately so the new
|
|
176
176
|
* `interval` / `receive_timeout` take effect without a reconnect; when
|
|
@@ -185,10 +185,10 @@ export declare class FrontendWebsocketClient implements WebsocketConnection, Dis
|
|
|
185
185
|
* pending.
|
|
186
186
|
*
|
|
187
187
|
* Use this when UI state asks "stop trying for now" without the finality
|
|
188
|
-
* of
|
|
188
|
+
* of `disconnect` (which also rejects pending/queued requests and
|
|
189
189
|
* clears heartbeat) or the policy change of `set_reconnect(false)`
|
|
190
190
|
* (which disables future reconnects). The queue stays intact so that
|
|
191
|
-
* calling
|
|
191
|
+
* calling `connect` later flushes buffered work.
|
|
192
192
|
*/
|
|
193
193
|
cancel_reconnect(): void;
|
|
194
194
|
get url(): string;
|
|
@@ -233,7 +233,7 @@ export declare class FrontendWebsocketClient implements WebsocketConnection, Dis
|
|
|
233
233
|
* disconnect-detection slot.
|
|
234
234
|
*
|
|
235
235
|
* On `AbortSignal` fire: rejects the local promise *and* sends the shared
|
|
236
|
-
* `cancel` notification (
|
|
236
|
+
* `cancel` notification (`cancel_action_spec.method`) so the server-side
|
|
237
237
|
* dispatcher can abort the matching handler's `ctx.signal`. Suppressed
|
|
238
238
|
* for queued-but-never-sent (server doesn't know about it) and
|
|
239
239
|
* response-beat-cancel races.
|
|
@@ -259,14 +259,14 @@ export declare class FrontendWebsocketClient implements WebsocketConnection, Dis
|
|
|
259
259
|
add_error_handler(handler: SocketErrorHandler): () => void;
|
|
260
260
|
}
|
|
261
261
|
/**
|
|
262
|
-
* Project
|
|
262
|
+
* Project `SocketStatus` onto fuz_util's `AsyncStatus` — the
|
|
263
263
|
* 5-way → 4-way mapping every consumer re-derives to surface connection state
|
|
264
264
|
* to UI (loading indicators, retry banners). Collapses `reconnecting` into
|
|
265
265
|
* `failure` (UI shows "lost, retrying") and splits `closed` by `revoked` so
|
|
266
266
|
* a terminal session-revocation read as `failure` while a clean client-
|
|
267
267
|
* initiated close reads as `initial` (the "not connected, not trying" state).
|
|
268
268
|
*
|
|
269
|
-
* @param status - the socket's current
|
|
269
|
+
* @param status - the socket's current `SocketStatus`
|
|
270
270
|
* @param revoked - whether the session has been permanently revoked
|
|
271
271
|
* (typically `FrontendWebsocketClient.revoked`)
|
|
272
272
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/socket.svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAyC,KAAK,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAKjG,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,oBAAoB,CAAC;AAE5D,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,OAAO,CAAC;AACvC,kCAAkC;AAClC,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,8DAA8D;AAC9D,eAAO,MAAM,2BAA2B,QAAQ,CAAC;AACjD,qEAAqE;AACrE,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,qDAAqD;AACrD,eAAO,MAAM,0BAA0B,QAAS,CAAC;AACjD,
|
|
1
|
+
{"version":3,"file":"socket.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/socket.svelte.ts"],"names":[],"mappings":"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"}
|