@fuzdev/fuz_app 0.10.1 → 0.12.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.
Files changed (63) hide show
  1. package/dist/actions/action_bridge.d.ts +8 -8
  2. package/dist/actions/action_bridge.d.ts.map +1 -1
  3. package/dist/actions/action_bridge.js +5 -5
  4. package/dist/actions/action_codegen.d.ts +18 -1
  5. package/dist/actions/action_codegen.d.ts.map +1 -1
  6. package/dist/actions/action_codegen.js +49 -6
  7. package/dist/actions/action_event.d.ts +60 -0
  8. package/dist/actions/action_event.d.ts.map +1 -0
  9. package/dist/actions/action_event.js +367 -0
  10. package/dist/actions/action_event_data.d.ts +639 -0
  11. package/dist/actions/action_event_data.d.ts.map +1 -0
  12. package/dist/actions/action_event_data.js +29 -0
  13. package/dist/actions/action_event_helpers.d.ts +73 -0
  14. package/dist/actions/action_event_helpers.d.ts.map +1 -0
  15. package/dist/actions/action_event_helpers.js +96 -0
  16. package/dist/actions/action_event_types.d.ts +31 -0
  17. package/dist/actions/action_event_types.d.ts.map +1 -0
  18. package/dist/actions/action_event_types.js +38 -0
  19. package/dist/actions/action_peer.d.ts +30 -0
  20. package/dist/actions/action_peer.d.ts.map +1 -0
  21. package/dist/actions/action_peer.js +146 -0
  22. package/dist/actions/action_spec.d.ts +1 -1
  23. package/dist/actions/action_spec.js +1 -1
  24. package/dist/actions/request_tracker.svelte.d.ts +69 -0
  25. package/dist/actions/request_tracker.svelte.d.ts.map +1 -0
  26. package/dist/actions/request_tracker.svelte.js +161 -0
  27. package/dist/actions/rpc_client.d.ts +43 -0
  28. package/dist/actions/rpc_client.d.ts.map +1 -0
  29. package/dist/actions/rpc_client.js +151 -0
  30. package/dist/actions/transports.d.ts +47 -0
  31. package/dist/actions/transports.d.ts.map +1 -0
  32. package/dist/actions/transports.js +108 -0
  33. package/dist/actions/transports_http.d.ts +16 -0
  34. package/dist/actions/transports_http.d.ts.map +1 -0
  35. package/dist/actions/transports_http.js +81 -0
  36. package/dist/actions/transports_ws.d.ts +26 -0
  37. package/dist/actions/transports_ws.d.ts.map +1 -0
  38. package/dist/actions/transports_ws.js +94 -0
  39. package/dist/actions/transports_ws_backend.d.ts +42 -0
  40. package/dist/actions/transports_ws_backend.d.ts.map +1 -0
  41. package/dist/actions/transports_ws_backend.js +133 -0
  42. package/dist/http/jsonrpc_errors.d.ts +2 -0
  43. package/dist/http/jsonrpc_errors.d.ts.map +1 -1
  44. package/dist/http/jsonrpc_errors.js +2 -0
  45. package/dist/http/surface.d.ts +3 -3
  46. package/dist/http/surface.d.ts.map +1 -1
  47. package/dist/realtime/sse.d.ts +3 -3
  48. package/dist/realtime/sse.d.ts.map +1 -1
  49. package/dist/realtime/sse_auth_guard.d.ts +2 -2
  50. package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
  51. package/dist/server/app_server.d.ts +2 -2
  52. package/dist/server/app_server.d.ts.map +1 -1
  53. package/dist/testing/integration_helpers.d.ts +0 -5
  54. package/dist/testing/integration_helpers.d.ts.map +1 -1
  55. package/dist/testing/integration_helpers.js +6 -1
  56. package/dist/testing/stubs.d.ts +2 -2
  57. package/dist/testing/stubs.d.ts.map +1 -1
  58. package/dist/ui/AdminOverview.svelte +1 -0
  59. package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
  60. package/dist/uuid.d.ts +12 -0
  61. package/dist/uuid.d.ts.map +1 -0
  62. package/dist/uuid.js +9 -0
  63. package/package.json +1 -1
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Action event helper functions — type guards, validators, and data creation.
3
+ *
4
+ * @module
5
+ */
6
+ import type { Result } from '@fuzdev/fuz_util/result.js';
7
+ import { type ActionEventStep, type ActionExecutor } from './action_event_types.js';
8
+ import type { ActionEventData, ActionEventRequestResponseData, ActionEventRemoteNotificationData, ActionEventLocalCallData } from './action_event_data.js';
9
+ import type { ActionEventPhase, ActionInitiator, ActionKind } from './action_spec.js';
10
+ import type { JsonrpcErrorObject } from '../http/jsonrpc.js';
11
+ import type { ActionEvent } from './action_event.js';
12
+ export declare const is_request_response: (data: ActionEventData) => data is ActionEventRequestResponseData;
13
+ export declare const is_remote_notification: (data: ActionEventData) => data is ActionEventRemoteNotificationData;
14
+ export declare const is_local_call: (data: ActionEventData) => data is ActionEventLocalCallData;
15
+ export declare const is_send_request: (data: ActionEventData) => data is ActionEventRequestResponseData & {
16
+ phase: "send_request";
17
+ };
18
+ export declare const is_receive_request: (data: ActionEventData) => data is ActionEventRequestResponseData & {
19
+ phase: "receive_request";
20
+ };
21
+ export declare const is_send_response: (data: ActionEventData) => data is ActionEventRequestResponseData & {
22
+ phase: "send_response";
23
+ };
24
+ export declare const is_receive_response: (data: ActionEventData) => data is ActionEventRequestResponseData & {
25
+ phase: "receive_response";
26
+ };
27
+ export declare const is_notification_send: (data: ActionEventData) => data is ActionEventRemoteNotificationData & {
28
+ phase: "send";
29
+ };
30
+ export declare const is_notification_receive: (data: ActionEventData) => data is ActionEventRemoteNotificationData & {
31
+ phase: "receive";
32
+ };
33
+ export declare const is_execute: (data: ActionEventData) => data is ActionEventLocalCallData & {
34
+ phase: "execute";
35
+ };
36
+ export declare const is_initial: (data: ActionEventData) => data is ActionEventData & {
37
+ step: "initial";
38
+ };
39
+ export declare const is_parsed: (data: ActionEventData) => data is ActionEventData & {
40
+ step: "parsed";
41
+ };
42
+ export declare const is_handling: (data: ActionEventData) => data is ActionEventData & {
43
+ step: "handling";
44
+ };
45
+ export declare const is_handled: (data: ActionEventData) => data is ActionEventData & {
46
+ step: "handled";
47
+ };
48
+ export declare const is_failed: (data: ActionEventData) => data is ActionEventData & {
49
+ step: "failed";
50
+ };
51
+ export declare const is_send_request_with_parsed_input: <TMethod extends string = string>(data: ActionEventData) => data is ActionEventRequestResponseData<TMethod> & {
52
+ phase: "send_request";
53
+ step: "parsed" | "handling";
54
+ input: unknown;
55
+ };
56
+ export declare const is_notification_send_with_parsed_input: <TMethod extends string = string>(data: ActionEventData) => data is ActionEventRemoteNotificationData<TMethod> & {
57
+ phase: "send";
58
+ step: "parsed" | "handling";
59
+ input: unknown;
60
+ };
61
+ export declare const validate_step_transition: (from: ActionEventStep, to: ActionEventStep) => void;
62
+ export declare const validate_phase_for_kind: (kind: ActionKind, phase: ActionEventPhase) => void;
63
+ export declare const validate_phase_transition: (from: ActionEventPhase, to: ActionEventPhase) => void;
64
+ export declare const get_initial_phase: (kind: ActionKind, initiator: ActionInitiator, executor: ActionExecutor) => ActionEventPhase | null;
65
+ export declare const should_validate_output: (kind: ActionKind, phase: ActionEventPhase) => boolean;
66
+ export declare const is_action_complete: (data: ActionEventData) => boolean;
67
+ export declare const create_initial_data: (kind: ActionKind, phase: ActionEventPhase, method: string, executor: ActionExecutor, input: unknown) => ActionEventData;
68
+ export declare const extract_action_result: (event: ActionEvent) => Result<{
69
+ value: ActionEventData["output"];
70
+ }, {
71
+ error: JsonrpcErrorObject;
72
+ }>;
73
+ //# sourceMappingURL=action_event_helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action_event_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_event_helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,4BAA4B,CAAC;AAEvD,OAAO,EACN,KAAK,eAAe,EACpB,KAAK,cAAc,EAInB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EACX,eAAe,EACf,8BAA8B,EAC9B,iCAAiC,EACjC,wBAAwB,EACxB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAC,gBAAgB,EAAE,eAAe,EAAE,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACpF,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAGnD,eAAO,MAAM,mBAAmB,GAC/B,MAAM,eAAe,KACnB,IAAI,IAAI,8BAAkE,CAAC;AAE9E,eAAO,MAAM,sBAAsB,GAClC,MAAM,eAAe,KACnB,IAAI,IAAI,iCAAwE,CAAC;AAEpF,eAAO,MAAM,aAAa,GAAI,MAAM,eAAe,KAAG,IAAI,IAAI,wBACnC,CAAC;AAG5B,eAAO,MAAM,eAAe,GAC3B,MAAM,eAAe,KACnB,IAAI,IAAI,8BAA8B,GAAG;IAAC,KAAK,EAAE,cAAc,CAAA;CACA,CAAC;AAEnE,eAAO,MAAM,kBAAkB,GAC9B,MAAM,eAAe,KACnB,IAAI,IAAI,8BAA8B,GAAG;IAAC,KAAK,EAAE,iBAAiB,CAAA;CACA,CAAC;AAEtE,eAAO,MAAM,gBAAgB,GAC5B,MAAM,eAAe,KACnB,IAAI,IAAI,8BAA8B,GAAG;IAAC,KAAK,EAAE,eAAe,CAAA;CACA,CAAC;AAEpE,eAAO,MAAM,mBAAmB,GAC/B,MAAM,eAAe,KACnB,IAAI,IAAI,8BAA8B,GAAG;IAAC,KAAK,EAAE,kBAAkB,CAAA;CACA,CAAC;AAEvE,eAAO,MAAM,oBAAoB,GAChC,MAAM,eAAe,KACnB,IAAI,IAAI,iCAAiC,GAAG;IAAC,KAAK,EAAE,MAAM,CAAA;CACA,CAAC;AAE9D,eAAO,MAAM,uBAAuB,GACnC,MAAM,eAAe,KACnB,IAAI,IAAI,iCAAiC,GAAG;IAAC,KAAK,EAAE,SAAS,CAAA;CACA,CAAC;AAEjE,eAAO,MAAM,UAAU,GACtB,MAAM,eAAe,KACnB,IAAI,IAAI,wBAAwB,GAAG;IAAC,KAAK,EAAE,SAAS,CAAA;CACA,CAAC;AAGxD,eAAO,MAAM,UAAU,GAAI,MAAM,eAAe,KAAG,IAAI,IAAI,eAAe,GAAG;IAAC,IAAI,EAAE,SAAS,CAAA;CACrE,CAAC;AAEzB,eAAO,MAAM,SAAS,GAAI,MAAM,eAAe,KAAG,IAAI,IAAI,eAAe,GAAG;IAAC,IAAI,EAAE,QAAQ,CAAA;CACpE,CAAC;AAExB,eAAO,MAAM,WAAW,GAAI,MAAM,eAAe,KAAG,IAAI,IAAI,eAAe,GAAG;IAAC,IAAI,EAAE,UAAU,CAAA;CACtE,CAAC;AAE1B,eAAO,MAAM,UAAU,GAAI,MAAM,eAAe,KAAG,IAAI,IAAI,eAAe,GAAG;IAAC,IAAI,EAAE,SAAS,CAAA;CACrE,CAAC;AAEzB,eAAO,MAAM,SAAS,GAAI,MAAM,eAAe,KAAG,IAAI,IAAI,eAAe,GAAG;IAAC,IAAI,EAAE,QAAQ,CAAA;CACpE,CAAC;AAKxB,eAAO,MAAM,iCAAiC,GAAI,OAAO,SAAS,MAAM,GAAG,MAAM,EAChF,MAAM,eAAe,KACnB,IAAI,IAAI,8BAA8B,CAAC,OAAO,CAAC,GAAG;IACpD,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC;CACkE,CAAC;AAEnF,eAAO,MAAM,sCAAsC,GAAI,OAAO,SAAS,MAAM,GAAG,MAAM,EACrF,MAAM,eAAe,KACnB,IAAI,IAAI,iCAAiC,CAAC,OAAO,CAAC,GAAG;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC;CACuE,CAAC;AAGxF,eAAO,MAAM,wBAAwB,GAAI,MAAM,eAAe,EAAE,IAAI,eAAe,KAAG,IAKrF,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,MAAM,UAAU,EAAE,OAAO,gBAAgB,KAAG,IAKnF,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,MAAM,gBAAgB,EAAE,IAAI,gBAAgB,KAAG,IAKxF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC7B,MAAM,UAAU,EAChB,WAAW,eAAe,EAC1B,UAAU,cAAc,KACtB,gBAAgB,GAAG,IAWrB,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,MAAM,UAAU,EAAE,OAAO,gBAAgB,KAAG,OAEpC,CAAC;AAEhD,eAAO,MAAM,kBAAkB,GAAI,MAAM,eAAe,KAAG,OAO1D,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC/B,MAAM,UAAU,EAChB,OAAO,gBAAgB,EACvB,QAAQ,MAAM,EACd,UAAU,cAAc,EACxB,OAAO,OAAO,KACZ,eAaD,CAAC;AAEH,eAAO,MAAM,qBAAqB,GACjC,OAAO,WAAW,KAChB,MAAM,CAAC;IAAC,KAAK,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAA;CAAC,EAAE;IAAC,KAAK,EAAE,kBAAkB,CAAA;CAAC,CAaxE,CAAC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Action event helper functions — type guards, validators, and data creation.
3
+ *
4
+ * @module
5
+ */
6
+ import { ACTION_EVENT_STEP_TRANSITIONS, ACTION_EVENT_PHASE_BY_KIND, ACTION_EVENT_PHASE_TRANSITIONS, } from './action_event_types.js';
7
+ // Type guards for action kinds
8
+ export const is_request_response = (data) => data.kind === 'request_response';
9
+ export const is_remote_notification = (data) => data.kind === 'remote_notification';
10
+ export const is_local_call = (data) => data.kind === 'local_call';
11
+ // Type guards for specific states
12
+ export const is_send_request = (data) => data.kind === 'request_response' && data.phase === 'send_request';
13
+ export const is_receive_request = (data) => data.kind === 'request_response' && data.phase === 'receive_request';
14
+ export const is_send_response = (data) => data.kind === 'request_response' && data.phase === 'send_response';
15
+ export const is_receive_response = (data) => data.kind === 'request_response' && data.phase === 'receive_response';
16
+ export const is_notification_send = (data) => data.kind === 'remote_notification' && data.phase === 'send';
17
+ export const is_notification_receive = (data) => data.kind === 'remote_notification' && data.phase === 'receive';
18
+ export const is_execute = (data) => data.kind === 'local_call' && data.phase === 'execute';
19
+ // Step state guards
20
+ export const is_initial = (data) => data.step === 'initial';
21
+ export const is_parsed = (data) => data.step === 'parsed';
22
+ export const is_handling = (data) => data.step === 'handling';
23
+ export const is_handled = (data) => data.step === 'handled';
24
+ export const is_failed = (data) => data.step === 'failed';
25
+ // Combined type guards for specific states with parsed input
26
+ // These check for 'parsed' or 'handling' steps since protocol messages
27
+ // are created when transitioning from 'parsed' to 'handling'
28
+ export const is_send_request_with_parsed_input = (data) => is_send_request(data) && (data.step === 'parsed' || data.step === 'handling');
29
+ export const is_notification_send_with_parsed_input = (data) => is_notification_send(data) && (data.step === 'parsed' || data.step === 'handling');
30
+ // Validation helpers
31
+ export const validate_step_transition = (from, to) => {
32
+ const valid_transitions = ACTION_EVENT_STEP_TRANSITIONS[from];
33
+ if (!valid_transitions.includes(to)) {
34
+ throw new Error(`Invalid step transition from '${from}' to '${to}'`);
35
+ }
36
+ };
37
+ export const validate_phase_for_kind = (kind, phase) => {
38
+ const valid_phases = ACTION_EVENT_PHASE_BY_KIND[kind];
39
+ if (!valid_phases.includes(phase)) {
40
+ throw new Error(`Invalid phase '${phase}' for ${kind} action`);
41
+ }
42
+ };
43
+ export const validate_phase_transition = (from, to) => {
44
+ const expected = ACTION_EVENT_PHASE_TRANSITIONS[from];
45
+ if (expected !== to) {
46
+ throw new Error(`Invalid phase transition from '${from}' to '${to}'`);
47
+ }
48
+ };
49
+ export const get_initial_phase = (kind, initiator, executor) => {
50
+ if (initiator !== 'both' && initiator !== executor)
51
+ return null;
52
+ switch (kind) {
53
+ case 'request_response':
54
+ return 'send_request';
55
+ case 'remote_notification':
56
+ return 'send';
57
+ case 'local_call':
58
+ return 'execute';
59
+ }
60
+ };
61
+ export const should_validate_output = (kind, phase) => (kind === 'request_response' && (phase === 'receive_request' || phase === 'receive_response')) ||
62
+ (kind === 'local_call' && phase === 'execute');
63
+ export const is_action_complete = (data) => {
64
+ if (data.step === 'failed')
65
+ return true;
66
+ if (data.step !== 'handled')
67
+ return false;
68
+ // Check if in terminal phase
69
+ const next_phase = ACTION_EVENT_PHASE_TRANSITIONS[data.phase];
70
+ return next_phase === null;
71
+ };
72
+ export const create_initial_data = (kind, phase, method, executor, input) => ({
73
+ kind,
74
+ phase,
75
+ step: 'initial',
76
+ method,
77
+ executor,
78
+ input,
79
+ output: null,
80
+ error: null,
81
+ progress: null,
82
+ request: null,
83
+ response: null,
84
+ notification: null,
85
+ });
86
+ export const extract_action_result = (event) => {
87
+ const { data } = event;
88
+ if (data.step === 'handled') {
89
+ return { ok: true, value: data.output };
90
+ }
91
+ if (data.step === 'failed') {
92
+ return { ok: false, error: data.error };
93
+ }
94
+ // Programming error - event not in terminal state
95
+ throw new Error(`cannot extract result: event in non-terminal state (step: ${data.step})`);
96
+ };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Action event type definitions — state machine constants and environment interface.
3
+ *
4
+ * @module
5
+ */
6
+ import { z } from 'zod';
7
+ import type { Logger } from '@fuzdev/fuz_util/log.js';
8
+ import type { ActionEventPhase, ActionKind, ActionSpecUnion } from './action_spec.js';
9
+ export declare const ActionExecutor: z.ZodEnum<{
10
+ frontend: "frontend";
11
+ backend: "backend";
12
+ }>;
13
+ export type ActionExecutor = z.infer<typeof ActionExecutor>;
14
+ export declare const ActionEventStep: z.ZodEnum<{
15
+ initial: "initial";
16
+ parsed: "parsed";
17
+ handling: "handling";
18
+ handled: "handled";
19
+ failed: "failed";
20
+ }>;
21
+ export type ActionEventStep = z.infer<typeof ActionEventStep>;
22
+ export declare const ACTION_EVENT_STEP_TRANSITIONS: Record<ActionEventStep, ReadonlyArray<ActionEventStep>>;
23
+ export declare const ACTION_EVENT_PHASE_BY_KIND: Record<ActionKind, ReadonlyArray<ActionEventPhase>>;
24
+ export declare const ACTION_EVENT_PHASE_TRANSITIONS: Record<ActionEventPhase, ActionEventPhase | null>;
25
+ export interface ActionEventEnvironment {
26
+ readonly executor: ActionExecutor;
27
+ lookup_action_handler: (method: string, phase: ActionEventPhase) => ((event: any) => any) | undefined;
28
+ lookup_action_spec: (method: string) => ActionSpecUnion | undefined;
29
+ readonly log?: Logger | null;
30
+ }
31
+ //# sourceMappingURL=action_event_types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action_event_types.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_event_types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,gBAAgB,EAAE,UAAU,EAAE,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEpF,eAAO,MAAM,cAAc;;;EAAkC,CAAC;AAC9D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,eAAO,MAAM,eAAe;;;;;;EAAiE,CAAC;AAC9F,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,eAAO,MAAM,6BAA6B,EAMrC,MAAM,CAAC,eAAe,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC;AAE7D,eAAO,MAAM,0BAA0B,EAWlC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAEzD,eAAO,MAAM,8BAA8B,EAUtC,MAAM,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC,CAAC;AAEvD,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,qBAAqB,EAAE,CACtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,gBAAgB,KACnB,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,CAAC,GAAG,SAAS,CAAC;IACvC,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,eAAe,GAAG,SAAS,CAAC;IACpE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Action event type definitions — state machine constants and environment interface.
3
+ *
4
+ * @module
5
+ */
6
+ import { z } from 'zod';
7
+ export const ActionExecutor = z.enum(['frontend', 'backend']);
8
+ export const ActionEventStep = z.enum(['initial', 'parsed', 'handling', 'handled', 'failed']);
9
+ export const ACTION_EVENT_STEP_TRANSITIONS = {
10
+ initial: ['parsed', 'failed'],
11
+ parsed: ['handling', 'failed'],
12
+ handling: ['handled', 'failed'],
13
+ handled: [],
14
+ failed: [],
15
+ };
16
+ export const ACTION_EVENT_PHASE_BY_KIND = {
17
+ request_response: [
18
+ 'send_request',
19
+ 'receive_request',
20
+ 'send_response',
21
+ 'receive_response',
22
+ 'send_error',
23
+ 'receive_error',
24
+ ],
25
+ remote_notification: ['send', 'receive'],
26
+ local_call: ['execute'],
27
+ };
28
+ export const ACTION_EVENT_PHASE_TRANSITIONS = {
29
+ send_request: 'receive_response',
30
+ receive_request: 'send_response',
31
+ send_response: null,
32
+ receive_response: null,
33
+ send_error: null,
34
+ receive_error: null,
35
+ send: null,
36
+ receive: null,
37
+ execute: null,
38
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * ActionPeer — symmetric send/receive for JSON-RPC actions.
3
+ *
4
+ * Wraps a `Transports` registry and `ActionEventEnvironment` to provide
5
+ * bidirectional action dispatch via JSON-RPC 2.0.
6
+ *
7
+ * @module
8
+ */
9
+ import { JsonrpcMessageFromServerToClient, JsonrpcNotification, JsonrpcRequest, JsonrpcResponseOrError, JsonrpcErrorResponse } from '../http/jsonrpc.js';
10
+ import { Transports, type TransportName } from './transports.js';
11
+ import type { ActionEventEnvironment } from './action_event_types.js';
12
+ export interface ActionPeerSendOptions {
13
+ transport_name?: TransportName;
14
+ }
15
+ export interface ActionPeerOptions {
16
+ environment: ActionEventEnvironment;
17
+ transports?: Transports;
18
+ default_send_options?: Partial<ActionPeerSendOptions>;
19
+ }
20
+ export declare class ActionPeer {
21
+ #private;
22
+ readonly environment: ActionEventEnvironment;
23
+ readonly transports: Transports;
24
+ default_send_options: ActionPeerSendOptions;
25
+ constructor(options: ActionPeerOptions);
26
+ send(message: JsonrpcRequest, options?: ActionPeerSendOptions): Promise<JsonrpcResponseOrError>;
27
+ send(message: JsonrpcNotification, options?: ActionPeerSendOptions): Promise<JsonrpcErrorResponse | null>;
28
+ receive(message: unknown): Promise<JsonrpcMessageFromServerToClient | null>;
29
+ }
30
+ //# sourceMappingURL=action_peer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action_peer.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_peer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAEN,gCAAgC,EAChC,mBAAmB,EACnB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,MAAM,oBAAoB,CAAC;AAU5B,OAAO,EAAC,UAAU,EAAE,KAAK,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC/D,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yBAAyB,CAAC;AAOpE,MAAM,WAAW,qBAAqB;IACrC,cAAc,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IACjC,WAAW,EAAE,sBAAsB,CAAC;IAGpC,UAAU,CAAC,EAAE,UAAU,CAAC;IAGxB,oBAAoB,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACtD;AAED,qBAAa,UAAU;;IACtB,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAMhC,oBAAoB,EAAE,qBAAqB,CAAC;gBAEhC,OAAO,EAAE,iBAAiB;IAOhC,IAAI,CACT,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,sBAAsB,CAAC;IAC5B,IAAI,CACT,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IA2CjC,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,gCAAgC,GAAG,IAAI,CAAC;CAyIjF"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * ActionPeer — symmetric send/receive for JSON-RPC actions.
3
+ *
4
+ * Wraps a `Transports` registry and `ActionEventEnvironment` to provide
5
+ * bidirectional action dispatch via JSON-RPC 2.0.
6
+ *
7
+ * @module
8
+ */
9
+ import { JsonrpcMessageFromClientToServer, JsonrpcMessageFromServerToClient, JsonrpcNotification, JsonrpcRequest, JsonrpcResponseOrError, JsonrpcErrorResponse, } from '../http/jsonrpc.js';
10
+ import { create_jsonrpc_error_response, create_jsonrpc_error_response_from_thrown, to_jsonrpc_message_id, is_jsonrpc_request, is_jsonrpc_notification, } from '../http/jsonrpc_helpers.js';
11
+ import { jsonrpc_error_messages } from '../http/jsonrpc_errors.js';
12
+ import { create_action_event } from './action_event.js';
13
+ import { Transports } from './transports.js';
14
+ export class ActionPeer {
15
+ environment;
16
+ transports;
17
+ // TODO maybe expand the pattern of using `transports` in send, so what's used in receive?
18
+ // It seems abstracting that out would make this class much simpler and generic, but too much so?
19
+ // What deps should it actually know about, and what gains could we have by making it more decoupled?
20
+ // e.g. don't just decouple for the sake of imagined flexibility!
21
+ default_send_options;
22
+ constructor(options) {
23
+ this.environment = options.environment;
24
+ this.transports = options.transports ?? new Transports();
25
+ this.default_send_options = options.default_send_options ?? {};
26
+ }
27
+ async send(message, options) {
28
+ try {
29
+ const transport = this.transports.get_transport(options?.transport_name ?? this.default_send_options.transport_name);
30
+ if (!transport) {
31
+ this.environment.log?.error('[peer] send failed: no transport available');
32
+ return create_jsonrpc_error_response(to_jsonrpc_message_id(message), jsonrpc_error_messages.service_unavailable('no transport available'));
33
+ }
34
+ const message_type = is_jsonrpc_request(message) ? 'request' : 'notification';
35
+ this.environment.log?.debug(`[peer] send ${message_type}:`, message.method, `via ${transport.transport_name}`);
36
+ const result = await transport.send(message);
37
+ if (result && 'error' in result) {
38
+ this.environment.log?.error(`[peer] send ${message_type} failed:`, message.method, result.error.message);
39
+ }
40
+ return result;
41
+ }
42
+ catch (error) {
43
+ // TODO add retry handling here?
44
+ this.environment.log?.error('[peer] send unexpected error:', error);
45
+ return create_jsonrpc_error_response_from_thrown(to_jsonrpc_message_id(message), error);
46
+ } // TODO finally?
47
+ }
48
+ async receive(message) {
49
+ try {
50
+ const result = await this.#receive_message(message);
51
+ return result;
52
+ }
53
+ catch (error) {
54
+ this.environment.log?.error('[peer] receive unexpected error:', error);
55
+ // Return appropriate error response based on the message
56
+ return create_jsonrpc_error_response_from_thrown(to_jsonrpc_message_id(message), error);
57
+ } // TODO finally?
58
+ }
59
+ /**
60
+ * Processes a single JSON-RPC message, returning a response message if any.
61
+ */
62
+ async #receive_message(message) {
63
+ if (is_jsonrpc_request(message)) {
64
+ return this.#receive_request(message);
65
+ }
66
+ else if (is_jsonrpc_notification(message)) {
67
+ await this.#receive_notification(message);
68
+ return null;
69
+ }
70
+ else {
71
+ return create_jsonrpc_error_response(to_jsonrpc_message_id(message), jsonrpc_error_messages.invalid_request());
72
+ }
73
+ }
74
+ /**
75
+ * Processes a JSON-RPC request. Returns the response message.
76
+ */
77
+ async #receive_request(request) {
78
+ const spec = this.environment.lookup_action_spec(request.method);
79
+ if (!spec) {
80
+ this.environment.log?.warn(`[peer] receive request: method not found:`, request.method);
81
+ return create_jsonrpc_error_response(request.id, jsonrpc_error_messages.method_not_found(request.method));
82
+ }
83
+ this.environment.log?.debug(`[peer] receive request:`, request.method);
84
+ try {
85
+ // Create action event in receive_request phase
86
+ const event = create_action_event(this.environment, spec, request.params, 'receive_request');
87
+ event.set_request(request);
88
+ // Parse and handle
89
+ await event.parse().handle_async();
90
+ // Check if we successfully handled the request
91
+ if (event.data.step === 'handled') {
92
+ // Transition to send_response phase
93
+ event.transition('send_response');
94
+ await event.parse().handle_async();
95
+ // TODO doesn't seem exactly right, shouldn't need the guard, or needs some other tweaks
96
+ // Return the response if any
97
+ if (event.data.response) {
98
+ return event.data.response;
99
+ }
100
+ }
101
+ // Check for terminal failure
102
+ if (event.data.step === 'failed') {
103
+ this.environment.log?.error(`[peer] receive request failed:`, request.method, event.data.error);
104
+ return create_jsonrpc_error_response(request.id, event.data.error);
105
+ }
106
+ // Check if transitioned to error phase (send_error)
107
+ if (event.data.phase === 'send_error') {
108
+ // Error handler may exist - try to handle it (already parsed)
109
+ await event.handle_async();
110
+ // Return error response (handler may have modified/logged it)
111
+ return create_jsonrpc_error_response(request.id, event.data.error);
112
+ }
113
+ // Fallback for unexpected states
114
+ this.environment.log?.error(`[peer] receive request: unexpected state:`, request.method, event.data);
115
+ return create_jsonrpc_error_response(request.id, jsonrpc_error_messages.internal_error('unknown error'));
116
+ }
117
+ catch (error) {
118
+ this.environment.log?.error(`[peer] receive request exception:`, request.method, error);
119
+ return create_jsonrpc_error_response_from_thrown(request.id, error);
120
+ }
121
+ }
122
+ /**
123
+ * Processes a JSON-RPC notification. Returns nothing, no response exists.
124
+ */
125
+ async #receive_notification(notification) {
126
+ const spec = this.environment.lookup_action_spec(notification.method);
127
+ if (!spec) {
128
+ this.environment.log?.warn(`[peer] receive notification: method not found:`, notification.method);
129
+ return;
130
+ }
131
+ this.environment.log?.debug(`[peer] receive notification:`, notification.method);
132
+ try {
133
+ // Create action event in receive phase
134
+ const event = create_action_event(this.environment, spec, notification.params, 'receive');
135
+ event.set_notification(notification);
136
+ // Parse and handle
137
+ await event.parse().handle_async();
138
+ if (event.data.step === 'failed') {
139
+ this.environment.log?.error(`[peer] receive notification failed:`, notification.method, event.data.error);
140
+ }
141
+ }
142
+ catch (error) {
143
+ this.environment.log?.error(`[peer] receive notification exception:`, notification.method, error);
144
+ }
145
+ }
146
+ }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Extracted from zzz's action system. Action specs define method, kind,
5
5
  * auth, side effects, and input/output schemas. Bridge functions in
6
- * `action_bridge.ts` derive `RouteSpec` and `SseEventSpec` from them.
6
+ * `action_bridge.ts` derive `RouteSpec` and `EventSpec` from them.
7
7
  *
8
8
  * TODO @action-system-review The action system (action_spec, action_registry,
9
9
  * action_codegen, action_bridge) will evolve significantly with the saes-rpc quest.
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Extracted from zzz's action system. Action specs define method, kind,
5
5
  * auth, side effects, and input/output schemas. Bridge functions in
6
- * `action_bridge.ts` derive `RouteSpec` and `SseEventSpec` from them.
6
+ * `action_bridge.ts` derive `RouteSpec` and `EventSpec` from them.
7
7
  *
8
8
  * TODO @action-system-review The action system (action_spec, action_registry,
9
9
  * action_codegen, action_bridge) will evolve significantly with the saes-rpc quest.
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Request tracker — manages pending JSON-RPC requests with timeouts.
3
+ *
4
+ * Uses SvelteMap for reactive pending request tracking.
5
+ *
6
+ * @module
7
+ */
8
+ import { type Deferred, type AsyncStatus } from '@fuzdev/fuz_util/async.js';
9
+ import { SvelteMap } from 'svelte/reactivity';
10
+ import { type JsonrpcErrorResponse, type JsonrpcRequestId, type JsonrpcResponseOrError } from '../http/jsonrpc.js';
11
+ /** ISO datetime string for request creation timestamps. */
12
+ type Datetime = string & {
13
+ readonly __brand: 'Datetime';
14
+ };
15
+ /**
16
+ * Represents a pending request with its associated state.
17
+ */
18
+ export declare class RequestTrackerItem {
19
+ readonly id: JsonrpcRequestId;
20
+ readonly deferred: Deferred<JsonrpcResponseOrError>;
21
+ readonly created: Datetime;
22
+ status: AsyncStatus;
23
+ timeout: NodeJS.Timeout | undefined;
24
+ constructor(id: JsonrpcRequestId, deferred: Deferred<JsonrpcResponseOrError>, created: Datetime, status: AsyncStatus, timeout: NodeJS.Timeout | undefined);
25
+ }
26
+ /**
27
+ * Tracks JSON-RPC requests and their responses to manage promises and timeouts.
28
+ * Used by transports to handle the request-response lifecycle.
29
+ */
30
+ export declare class RequestTracker {
31
+ readonly pending_requests: SvelteMap<JsonrpcRequestId, RequestTrackerItem>;
32
+ readonly request_timeout_ms: number;
33
+ constructor(request_timeout_ms?: number);
34
+ /**
35
+ * Track a new request with the given id.
36
+ * @param id - the request id
37
+ * @returns a deferred promise that will be resolved when the response is received
38
+ */
39
+ track_request(id: JsonrpcRequestId): Deferred<JsonrpcResponseOrError>;
40
+ /**
41
+ * Resolve a pending request with the given response data.
42
+ * @param id - the request id
43
+ * @param response - the response data
44
+ */
45
+ resolve_request(id: JsonrpcRequestId, response: JsonrpcResponseOrError): void;
46
+ /**
47
+ * Rejects a pending request with the given error.
48
+ * @param id - the request id
49
+ * @param error_message - the complete `JsonrpcErrorResponse` object
50
+ */
51
+ reject_request(id: JsonrpcRequestId, error_message: JsonrpcErrorResponse): void;
52
+ /**
53
+ * Handles an incoming JSON-RPC message. Resolves or rejects the associated request.
54
+ * Ignores notifications and unknown/invalid messages.
55
+ */
56
+ handle_message(message: any): void;
57
+ /**
58
+ * Cancel a pending request.
59
+ * @param id - the request id
60
+ */
61
+ cancel_request(id: JsonrpcRequestId): void;
62
+ /**
63
+ * Cancel all pending requests.
64
+ * @param reason - optional reason to include in rejection
65
+ */
66
+ cancel_all_requests(reason?: string): void;
67
+ }
68
+ export {};
69
+ //# sourceMappingURL=request_tracker.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request_tracker.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/request_tracker.svelte.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAC,MAAM,2BAA2B,CAAC;AAC3F,OAAO,EAAC,SAAS,EAAC,MAAM,mBAAmB,CAAC;AAE5C,OAAO,EAEN,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,MAAM,oBAAoB,CAAC;AAG5B,2DAA2D;AAC3D,KAAK,QAAQ,GAAG,MAAM,GAAG;IAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;CAAC,CAAC;AAMxD;;GAEG;AACH,qBAAa,kBAAkB;IAC9B,QAAQ,CAAC,EAAE,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC;IACpD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,MAAM,EAAE,WAAW,CAAiB;IACpC,OAAO,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS,CAAgB;gBAGlD,EAAE,EAAE,gBAAgB,EACpB,QAAQ,EAAE,QAAQ,CAAC,sBAAsB,CAAC,EAC1C,OAAO,EAAE,QAAQ,EACjB,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS;CAQpC;AAED;;;GAGG;AACH,qBAAa,cAAc;IAC1B,QAAQ,CAAC,gBAAgB,EAAE,SAAS,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAmB;IAC7F,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;gBAExB,kBAAkB,SAAU;IAIxC;;;;OAIG;IACH,aAAa,CAAC,EAAE,EAAE,gBAAgB,GAAG,QAAQ,CAAC,sBAAsB,CAAC;IA6BrE;;;;OAIG;IACH,eAAe,CAAC,EAAE,EAAE,gBAAgB,EAAE,QAAQ,EAAE,sBAAsB,GAAG,IAAI;IAkB7E;;;;OAIG;IACH,cAAc,CAAC,EAAE,EAAE,gBAAgB,EAAE,aAAa,EAAE,oBAAoB,GAAG,IAAI;IAuB/E;;;OAGG;IACH,cAAc,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI;IAiBlC;;;OAGG;IACH,cAAc,CAAC,EAAE,EAAE,gBAAgB,GAAG,IAAI;IAe1C;;;OAGG;IACH,mBAAmB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;CAiB1C"}