pulse-ui-client 0.1.51 → 0.1.54
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/README.md +115 -8
- package/dist/index.d.ts +122 -60
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -1,15 +1,122 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Pulse JS Client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React client library that renders server-driven VDOM and handles WebSocket communication with the Pulse Python server.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
Client receives VDOM updates via Socket.IO and renders using React. Events are serialized and sent back to server.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ Browser │
|
|
12
|
+
│ ┌──────────────┐ ┌────────────┐ ┌─────────────────────────┐ │
|
|
13
|
+
│ │ PulseProvider│──│ PulseClient│──│ Transport (Socket.IO) │ │
|
|
14
|
+
│ └──────────────┘ └────────────┘ └─────────────────────────┘ │
|
|
15
|
+
│ │ │ │
|
|
16
|
+
│ ▼ ▼ │
|
|
17
|
+
│ ┌──────────────┐ ┌────────────┐ │
|
|
18
|
+
│ │ PulseView │ │ Renderer │ │
|
|
19
|
+
│ │ (per route) │ │ (VDOM→DOM)│ │
|
|
20
|
+
│ └──────────────┘ └────────────┘ │
|
|
21
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
22
|
+
▲ │
|
|
23
|
+
│ VDOM updates │ Events/callbacks
|
|
24
|
+
│ ▼
|
|
25
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
26
|
+
│ Python Server │
|
|
27
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Folder Structure
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
src/
|
|
34
|
+
├── index.ts # Public API exports
|
|
35
|
+
├── pulse.tsx # PulseProvider, PulseView, context
|
|
36
|
+
├── client.tsx # PulseClient - manages connection & views
|
|
37
|
+
├── renderer.tsx # VDOM-to-React rendering
|
|
38
|
+
├── channel.ts # Channel bridge for real-time messaging
|
|
39
|
+
├── transport.ts # Socket.IO transport layer
|
|
40
|
+
├── messages.ts # Client<->server message types
|
|
41
|
+
├── form.tsx # PulseForm component
|
|
42
|
+
├── helpers.ts # Route info extraction utilities
|
|
43
|
+
├── vdom.ts # VDOM types (VDOMNode, VDOMElement)
|
|
44
|
+
├── usePulseChannel.ts # React hook for channels
|
|
45
|
+
│
|
|
46
|
+
└── serialize/ # Data serialization
|
|
47
|
+
├── serializer.ts # Main serialize/deserialize
|
|
48
|
+
├── clean.ts # Data cleaning for wire transfer
|
|
49
|
+
├── elements.ts # Element extraction from refs
|
|
50
|
+
├── events.ts # Event serialization
|
|
51
|
+
└── extractor.ts # Data extraction utilities
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Key Concepts
|
|
55
|
+
|
|
56
|
+
### PulseProvider
|
|
57
|
+
|
|
58
|
+
Root provider establishing server connection:
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { PulseProvider } from "pulse-client";
|
|
62
|
+
|
|
63
|
+
function App() {
|
|
64
|
+
return (
|
|
65
|
+
<PulseProvider config={{ serverUrl: "http://localhost:8000" }}>
|
|
66
|
+
<Routes />
|
|
67
|
+
</PulseProvider>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### PulseView
|
|
73
|
+
|
|
74
|
+
Renders server-driven view for a route:
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
import { PulseView } from "pulse-client";
|
|
78
|
+
|
|
79
|
+
function Dashboard() {
|
|
80
|
+
return <PulseView path="/dashboard" />;
|
|
81
|
+
}
|
|
7
82
|
```
|
|
8
83
|
|
|
9
|
-
|
|
84
|
+
### PulseClient
|
|
85
|
+
|
|
86
|
+
Manages WebSocket connection, route mounting, message handling. Access via `usePulseClient()`.
|
|
87
|
+
|
|
88
|
+
### Renderer
|
|
89
|
+
|
|
90
|
+
Converts VDOM to React:
|
|
91
|
+
- Handles element types (div, span, etc.)
|
|
92
|
+
- Resolves component references
|
|
93
|
+
- Binds event handlers to server
|
|
94
|
+
- Manages refs and lazy loading
|
|
95
|
+
|
|
96
|
+
### Transport
|
|
97
|
+
|
|
98
|
+
Socket.IO transport with automatic reconnection, message queuing, connection status.
|
|
10
99
|
|
|
11
|
-
|
|
12
|
-
|
|
100
|
+
### Channels
|
|
101
|
+
|
|
102
|
+
Real-time messaging:
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
import { usePulseChannel } from "pulse-client";
|
|
106
|
+
|
|
107
|
+
function Chat() {
|
|
108
|
+
const channel = usePulseChannel("chat");
|
|
109
|
+
channel.on("new_message", (msg) => { /* handle */ });
|
|
110
|
+
channel.emit("message", { text: "Hello" });
|
|
111
|
+
}
|
|
13
112
|
```
|
|
14
113
|
|
|
15
|
-
|
|
114
|
+
## Main Exports
|
|
115
|
+
|
|
116
|
+
**Components**: `PulseProvider`, `PulseView`, `PulseForm`, `RenderLazy`
|
|
117
|
+
|
|
118
|
+
**Hooks**: `usePulseClient()`, `usePulseChannel(name)`
|
|
119
|
+
|
|
120
|
+
**Functions**: `serialize`, `deserialize`, `extractServerRouteInfo`, `submitForm`
|
|
121
|
+
|
|
122
|
+
**Types**: `VDOM`, `VDOMNode`, `VDOMElement`, `PulseClient`, `Transport`, `ComponentRegistry`
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react3 from "react";
|
|
2
|
-
import { ComponentPropsWithoutRef,
|
|
3
|
-
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
|
+
import { ComponentPropsWithoutRef, FormEvent, ReactNode } from "react";
|
|
4
3
|
import { LoaderFunctionArgs, NavigateFunction } from "react-router";
|
|
4
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
5
5
|
|
|
6
6
|
//#region src/helpers.d.ts
|
|
7
7
|
interface RouteInfo {
|
|
@@ -29,16 +29,91 @@ declare function extractServerRouteInfo({
|
|
|
29
29
|
};
|
|
30
30
|
//#endregion
|
|
31
31
|
//#region src/vdom.d.ts
|
|
32
|
-
type ComponentRegistry = Record<string,
|
|
32
|
+
type ComponentRegistry = Record<string, unknown>;
|
|
33
|
+
type JsonPrimitive = string | number | boolean | null;
|
|
34
|
+
type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
35
|
+
[k: string]: JsonValue;
|
|
36
|
+
};
|
|
37
|
+
type VDOMExpr = RegistryRefExpr | IdentifierExpr | LiteralExpr | UndefinedExpr | ArrayExpr | ObjectExpr | MemberExpr | SubscriptExpr | CallExpr | UnaryExpr | BinaryExpr | TernaryExpr | TemplateExpr | ArrowExpr | NewExpr;
|
|
38
|
+
interface RegistryRefExpr {
|
|
39
|
+
t: "ref";
|
|
40
|
+
key: string;
|
|
41
|
+
}
|
|
42
|
+
interface IdentifierExpr {
|
|
43
|
+
t: "id";
|
|
44
|
+
name: string;
|
|
45
|
+
}
|
|
46
|
+
interface LiteralExpr {
|
|
47
|
+
t: "lit";
|
|
48
|
+
value: JsonPrimitive;
|
|
49
|
+
}
|
|
50
|
+
interface UndefinedExpr {
|
|
51
|
+
t: "undef";
|
|
52
|
+
}
|
|
53
|
+
interface ArrayExpr {
|
|
54
|
+
t: "array";
|
|
55
|
+
items: VDOMNode[];
|
|
56
|
+
}
|
|
57
|
+
interface ObjectExpr {
|
|
58
|
+
t: "object";
|
|
59
|
+
props: Record<string, VDOMNode>;
|
|
60
|
+
}
|
|
61
|
+
interface MemberExpr {
|
|
62
|
+
t: "member";
|
|
63
|
+
obj: VDOMNode;
|
|
64
|
+
prop: string;
|
|
65
|
+
}
|
|
66
|
+
interface SubscriptExpr {
|
|
67
|
+
t: "sub";
|
|
68
|
+
obj: VDOMNode;
|
|
69
|
+
key: VDOMNode;
|
|
70
|
+
}
|
|
71
|
+
interface CallExpr {
|
|
72
|
+
t: "call";
|
|
73
|
+
callee: VDOMNode;
|
|
74
|
+
args: VDOMNode[];
|
|
75
|
+
}
|
|
76
|
+
interface UnaryExpr {
|
|
77
|
+
t: "unary";
|
|
78
|
+
op: string;
|
|
79
|
+
arg: VDOMNode;
|
|
80
|
+
}
|
|
81
|
+
interface BinaryExpr {
|
|
82
|
+
t: "binary";
|
|
83
|
+
op: string;
|
|
84
|
+
left: VDOMNode;
|
|
85
|
+
right: VDOMNode;
|
|
86
|
+
}
|
|
87
|
+
interface TernaryExpr {
|
|
88
|
+
t: "ternary";
|
|
89
|
+
cond: VDOMNode;
|
|
90
|
+
then: VDOMNode;
|
|
91
|
+
else_: VDOMNode;
|
|
92
|
+
}
|
|
93
|
+
interface TemplateExpr {
|
|
94
|
+
t: "template";
|
|
95
|
+
parts: Array<string | VDOMNode>;
|
|
96
|
+
}
|
|
97
|
+
interface ArrowExpr {
|
|
98
|
+
t: "arrow";
|
|
99
|
+
params: string[];
|
|
100
|
+
body: VDOMNode;
|
|
101
|
+
}
|
|
102
|
+
interface NewExpr {
|
|
103
|
+
t: "new";
|
|
104
|
+
ctor: VDOMNode;
|
|
105
|
+
args: VDOMNode[];
|
|
106
|
+
}
|
|
107
|
+
type CallbackPlaceholder = "$cb";
|
|
108
|
+
type VDOMPropValue = JsonValue | VDOMExpr | VDOMElement | CallbackPlaceholder;
|
|
33
109
|
interface VDOMElement {
|
|
34
110
|
tag: string;
|
|
35
|
-
props?: Record<string, any>;
|
|
36
|
-
children?: VDOMNode[];
|
|
37
111
|
key?: string;
|
|
38
|
-
|
|
112
|
+
props?: Record<string, VDOMPropValue>;
|
|
113
|
+
children?: VDOMNode[];
|
|
114
|
+
eval?: string[];
|
|
39
115
|
}
|
|
40
|
-
type
|
|
41
|
-
type VDOMNode = PrimitiveNode | VDOMElement;
|
|
116
|
+
type VDOMNode = JsonPrimitive | VDOMElement | VDOMExpr;
|
|
42
117
|
type VDOM = VDOMNode;
|
|
43
118
|
interface VDOMUpdateBase {
|
|
44
119
|
type: string;
|
|
@@ -46,13 +121,14 @@ interface VDOMUpdateBase {
|
|
|
46
121
|
}
|
|
47
122
|
interface ReplaceUpdate extends VDOMUpdateBase {
|
|
48
123
|
type: "replace";
|
|
49
|
-
data:
|
|
124
|
+
data: VDOM;
|
|
50
125
|
}
|
|
51
126
|
interface UpdatePropsUpdate extends VDOMUpdateBase {
|
|
52
127
|
type: "update_props";
|
|
53
128
|
data: {
|
|
54
|
-
set?: Record<string,
|
|
129
|
+
set?: Record<string, VDOMPropValue>;
|
|
55
130
|
remove?: string[];
|
|
131
|
+
eval?: string[];
|
|
56
132
|
};
|
|
57
133
|
}
|
|
58
134
|
interface ReconciliationUpdate {
|
|
@@ -62,39 +138,20 @@ interface ReconciliationUpdate {
|
|
|
62
138
|
new: [number[], VDOM[]];
|
|
63
139
|
reuse: [number[], number[]];
|
|
64
140
|
}
|
|
65
|
-
|
|
66
|
-
add?: string[];
|
|
67
|
-
remove?: string[];
|
|
68
|
-
}
|
|
69
|
-
interface UpdateCallbacksUpdate extends VDOMUpdateBase {
|
|
70
|
-
type: "update_callbacks";
|
|
71
|
-
data: PathDelta;
|
|
72
|
-
}
|
|
73
|
-
interface UpdateRenderPropsUpdate extends VDOMUpdateBase {
|
|
74
|
-
type: "update_render_props";
|
|
75
|
-
data: PathDelta;
|
|
76
|
-
}
|
|
77
|
-
interface UpdateJsExprPathsUpdate extends VDOMUpdateBase {
|
|
78
|
-
type: "update_jsexpr_paths";
|
|
79
|
-
data: PathDelta;
|
|
80
|
-
}
|
|
81
|
-
type VDOMUpdate = ReplaceUpdate | UpdatePropsUpdate | ReconciliationUpdate | UpdateCallbacksUpdate | UpdateRenderPropsUpdate | UpdateJsExprPathsUpdate;
|
|
141
|
+
type VDOMUpdate = ReplaceUpdate | UpdatePropsUpdate | ReconciliationUpdate;
|
|
82
142
|
//#endregion
|
|
83
143
|
//#region src/messages.d.ts
|
|
84
144
|
interface ServerInitMessage {
|
|
85
145
|
type: "vdom_init";
|
|
86
146
|
path: string;
|
|
87
147
|
vdom: VDOM;
|
|
88
|
-
callbacks: string[];
|
|
89
|
-
render_props: string[];
|
|
90
|
-
jsexpr_paths: string[];
|
|
91
148
|
}
|
|
92
149
|
interface ServerUpdateMessage {
|
|
93
150
|
type: "vdom_update";
|
|
94
151
|
path: string;
|
|
95
152
|
ops: VDOMUpdate[];
|
|
96
153
|
}
|
|
97
|
-
interface
|
|
154
|
+
interface ServerError {
|
|
98
155
|
message: string;
|
|
99
156
|
stack?: string;
|
|
100
157
|
phase: "render" | "callback" | "mount" | "unmount" | "navigate" | "server";
|
|
@@ -103,7 +160,7 @@ interface ServerErrorInfo {
|
|
|
103
160
|
interface ServerErrorMessage {
|
|
104
161
|
type: "server_error";
|
|
105
162
|
path: string;
|
|
106
|
-
error:
|
|
163
|
+
error: ServerError;
|
|
107
164
|
}
|
|
108
165
|
interface ServerApiCallMessage {
|
|
109
166
|
type: "api_call";
|
|
@@ -143,7 +200,7 @@ interface ServerJsExecMessage {
|
|
|
143
200
|
type: "js_exec";
|
|
144
201
|
path: string;
|
|
145
202
|
id: string;
|
|
146
|
-
|
|
203
|
+
expr: VDOMNode;
|
|
147
204
|
}
|
|
148
205
|
type ServerMessage = ServerInitMessage | ServerUpdateMessage | ServerErrorMessage | ServerApiCallMessage | ServerNavigateToMessage | ServerChannelRequestMessage | ServerChannelResponseMessage | ServerJsExecMessage;
|
|
149
206
|
interface ClientCallbackMessage {
|
|
@@ -152,18 +209,18 @@ interface ClientCallbackMessage {
|
|
|
152
209
|
callback: string;
|
|
153
210
|
args: any[];
|
|
154
211
|
}
|
|
155
|
-
interface
|
|
156
|
-
type: "
|
|
212
|
+
interface ClientAttachMessage {
|
|
213
|
+
type: "attach";
|
|
157
214
|
path: string;
|
|
158
215
|
routeInfo: RouteInfo;
|
|
159
216
|
}
|
|
160
|
-
interface
|
|
161
|
-
type: "
|
|
217
|
+
interface ClientUpdateMessage {
|
|
218
|
+
type: "update";
|
|
162
219
|
path: string;
|
|
163
220
|
routeInfo: RouteInfo;
|
|
164
221
|
}
|
|
165
|
-
interface
|
|
166
|
-
type: "
|
|
222
|
+
interface ClientDetachMessage {
|
|
223
|
+
type: "detach";
|
|
167
224
|
path: string;
|
|
168
225
|
}
|
|
169
226
|
interface ClientApiResultMessage {
|
|
@@ -199,7 +256,7 @@ interface ClientJsResultMessage {
|
|
|
199
256
|
result: any;
|
|
200
257
|
error: string | null;
|
|
201
258
|
}
|
|
202
|
-
type ClientMessage =
|
|
259
|
+
type ClientMessage = ClientAttachMessage | ClientCallbackMessage | ClientUpdateMessage | ClientDetachMessage | ClientApiResultMessage | ClientChannelRequestMessage | ClientChannelResponseMessage | ClientJsResultMessage;
|
|
203
260
|
//#endregion
|
|
204
261
|
//#region src/pulse.d.ts
|
|
205
262
|
interface ConnectionStatusConfig {
|
|
@@ -213,9 +270,6 @@ interface PulseConfig {
|
|
|
213
270
|
}
|
|
214
271
|
type PulsePrerenderView = {
|
|
215
272
|
vdom: VDOM;
|
|
216
|
-
callbacks: string[];
|
|
217
|
-
render_props: string[];
|
|
218
|
-
jsexpr_paths: string[];
|
|
219
273
|
};
|
|
220
274
|
type PulsePrerender = {
|
|
221
275
|
views: Record<string, PulsePrerenderView>;
|
|
@@ -254,20 +308,20 @@ interface MountedView {
|
|
|
254
308
|
routeInfo: RouteInfo;
|
|
255
309
|
onInit: (view: PulsePrerenderView) => void;
|
|
256
310
|
onUpdate: (ops: VDOMUpdate[]) => void;
|
|
257
|
-
onJsExec
|
|
311
|
+
onJsExec: (msg: ServerJsExecMessage) => void;
|
|
312
|
+
onServerError: (error: ServerError) => void;
|
|
258
313
|
}
|
|
259
314
|
type ConnectionStatus = "ok" | "connecting" | "reconnecting" | "error";
|
|
260
315
|
type ConnectionStatusListener = (status: ConnectionStatus) => void;
|
|
261
|
-
type ServerErrorListener = (path: string, error: ServerErrorInfo | null) => void;
|
|
262
316
|
interface PulseClient {
|
|
263
317
|
connect(): Promise<void>;
|
|
264
318
|
disconnect(): void;
|
|
265
319
|
isConnected(): boolean;
|
|
266
320
|
onConnectionChange(listener: ConnectionStatusListener): () => void;
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
321
|
+
updateRoute(path: string, routeInfo: RouteInfo): void;
|
|
322
|
+
invokeCallback(path: string, callback: string, args: any[]): void;
|
|
323
|
+
attach(path: string, view: MountedView): void;
|
|
324
|
+
detach(path: string): void;
|
|
271
325
|
}
|
|
272
326
|
declare class PulseSocketIOClient {
|
|
273
327
|
#private;
|
|
@@ -280,11 +334,10 @@ declare class PulseSocketIOClient {
|
|
|
280
334
|
isConnected(): boolean;
|
|
281
335
|
connect(): Promise<void>;
|
|
282
336
|
onConnectionChange(listener: ConnectionStatusListener): () => void;
|
|
283
|
-
onServerError(listener: ServerErrorListener): () => void;
|
|
284
337
|
sendMessage(payload: ClientMessage): void;
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
338
|
+
attach(path: string, view: MountedView): void;
|
|
339
|
+
updateRoute(path: string, routeInfo: RouteInfo): void;
|
|
340
|
+
detach(path: string): void;
|
|
288
341
|
disconnect(): void;
|
|
289
342
|
invokeCallback(path: string, callback: string, args: any[]): void;
|
|
290
343
|
sendJsResult(id: string, result: any, error: string | null): void;
|
|
@@ -318,6 +371,7 @@ declare class ChannelBridge {
|
|
|
318
371
|
private resolvePending;
|
|
319
372
|
private close;
|
|
320
373
|
}
|
|
374
|
+
declare function usePulseChannel(channelId: string): ChannelBridge;
|
|
321
375
|
//#endregion
|
|
322
376
|
//#region src/form.d.ts
|
|
323
377
|
type PulseFormProps = ComponentPropsWithoutRef<"form"> & {
|
|
@@ -347,9 +401,20 @@ declare function submitForm({
|
|
|
347
401
|
}: SubmitForm): Promise<void>;
|
|
348
402
|
//#endregion
|
|
349
403
|
//#region src/renderer.d.ts
|
|
350
|
-
declare
|
|
351
|
-
|
|
352
|
-
|
|
404
|
+
declare class VDOMRenderer {
|
|
405
|
+
#private;
|
|
406
|
+
constructor(client: PulseSocketIOClient, path: string, registry?: ComponentRegistry);
|
|
407
|
+
getObject(key: string): unknown;
|
|
408
|
+
renderNode(node: VDOMNode, currentPath?: string): ReactNode;
|
|
409
|
+
init(view: PulsePrerenderView & {
|
|
410
|
+
vdom: VDOM;
|
|
411
|
+
}): ReactNode;
|
|
412
|
+
/**
|
|
413
|
+
* Evaluate a VDOMNode expression (for run_js support).
|
|
414
|
+
*/
|
|
415
|
+
evaluateExpr(expr: VDOMNode): unknown;
|
|
416
|
+
applyUpdates(initialTree: ReactNode, updates: VDOMUpdate[]): ReactNode;
|
|
417
|
+
}
|
|
353
418
|
//#endregion
|
|
354
419
|
//#region src/serialize/serializer.d.ts
|
|
355
420
|
type Primitive = number | string | boolean | null | undefined;
|
|
@@ -376,8 +441,5 @@ interface Transport {
|
|
|
376
441
|
onConnectionChange(listener: ConnectionStatusListener$1): () => void;
|
|
377
442
|
}
|
|
378
443
|
//#endregion
|
|
379
|
-
|
|
380
|
-
declare function usePulseChannel(channelId: string): ChannelBridge;
|
|
381
|
-
//#endregion
|
|
382
|
-
export { type ChannelBridge, type ClientApiResultMessage, type ClientCallbackMessage, type ClientChannelMessage, type ClientChannelRequestMessage, type ClientChannelResponseMessage, type ClientMessage, type ClientMountMessage, type ClientNavigateMessage, type ClientUnmountMessage, type ComponentRegistry, type ConnectionStatusListener, type MessageListener, type MountedView, PulseChannelResetError, type PulseClient, type PulseConfig, PulseForm, type PulseFormProps, type PulsePrerender, PulseProvider, type PulseProviderProps, PulseView, RenderLazy, type RouteInfo, type ServerApiCallMessage, type ServerChannelMessage, type ServerChannelRequestMessage, type ServerChannelResponseMessage, type ServerErrorInfo, type ServerErrorListener, type ServerErrorMessage, type ServerInitMessage, type ServerMessage, type ServerNavigateToMessage, type ServerUpdateMessage, type Transport, type VDOM, type VDOMElement, type VDOMNode, type VDOMUpdate, deserialize, extractServerRouteInfo, serialize, submitForm, usePulseChannel, usePulseClient };
|
|
444
|
+
export { type ChannelBridge, type ClientApiResultMessage, type ClientAttachMessage, type ClientCallbackMessage, type ClientChannelMessage, type ClientChannelRequestMessage, type ClientChannelResponseMessage, type ClientDetachMessage, type ClientMessage, type ClientUpdateMessage, type ComponentRegistry, type ComponentRegistry as ComponentRegistry2, type ConnectionStatusListener, type MessageListener, type MountedView, PulseChannelResetError, type PulseClient, type PulseConfig, PulseForm, type PulseFormProps, type PulsePrerender, PulseProvider, type PulseProviderProps, PulseView, type RouteInfo, type ServerApiCallMessage, type ServerChannelMessage, type ServerChannelRequestMessage, type ServerChannelResponseMessage, type ServerError, type ServerErrorMessage, type ServerInitMessage, type ServerMessage, type ServerNavigateToMessage, type ServerUpdateMessage, type Transport, type VDOM, type VDOMElement, type VDOMExpr, type VDOMNode, type VDOMPropValue, VDOMRenderer, type VDOMUpdate, deserialize, extractServerRouteInfo, serialize, submitForm, usePulseChannel, usePulseClient };
|
|
383
445
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Fragment as e,Suspense as t,cloneElement as n,createContext as r,createElement as i,forwardRef as a,isValidElement as o,lazy as s,useCallback as c,useContext as l,useEffect as u,useMemo as d,useRef as f,useState as p}from"react";import{jsx as m,jsxs as h}from"react/jsx-runtime";import{useLocation as g,useNavigate as _,useParams as ee}from"react-router";import{io as v}from"socket.io-client";var y=class extends Error{constructor(e){super(e),this.name=`PulseChannelResetError`}};function te(){return typeof crypto<`u`&&typeof crypto.randomUUID==`function`?crypto.randomUUID().replace(/-/g,``):Math.random().toString(16).slice(2)+Math.random().toString(16).slice(2)}function ne(e){if(e instanceof Error)return e.message;if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return String(e)}}function re(e){return typeof e.responseTo==`string`}function ie(e){return typeof e.event==`string`}var ae=class{handlers=new Map;pending=new Map;backlog=[];closed=!1;constructor(e,t){this.client=e,this.id=t}emit(e,t){this.ensureOpen(),this.client.sendMessage({type:`channel_message`,channel:this.id,event:e,payload:t})}request(e,t){this.ensureOpen();let n=te();return new Promise((r,i)=>{this.pending.set(n,{resolve:r,reject:i}),this.client.sendMessage({type:`channel_message`,channel:this.id,event:e,payload:t,requestId:n})})}on(e,t){this.ensureOpen();let n=this.handlers.get(e);return n||(n=new Set,this.handlers.set(e,n)),n.add(t),this.flushBacklog(e),()=>{let n=this.handlers.get(e);n&&(n.delete(t),n.size===0&&this.handlers.delete(e))}}handleServerMessage(e){return re(e)?(this.resolvePending(e),this.closed):this.closed?!0:ie(e)?e.event===`__close__`?(this.close(new y(`Channel closed by server`)),!0):(e.requestId?this.dispatchRequest(e):this.dispatchEvent(e),this.closed):this.closed}handleDisconnect(e){this.close(e)}dispose(e){this.close(e)}ensureOpen(){if(this.closed)throw new y(`Channel is closed`)}flushBacklog(e){if(this.backlog.length===0)return;let t=[];for(let n of this.backlog)n.event===e?this.dispatchEvent(n):t.push(n);this.backlog=t}dispatchEvent(e){let t=this.handlers.get(e.event);if(!t||t.size===0){this.backlog.push(e);return}for(let n of t)try{let t=n(e.payload);t&&typeof t.then==`function`&&t.catch(e=>{console.error(`Pulse channel handler error`,e)})}catch(e){console.error(`Pulse channel handler error`,e)}}async dispatchRequest(e){let t=this.handlers.get(e.event),n,r;if(t&&t.size>0)for(let i of t)try{let t=i(e.payload);if(n=await Promise.resolve(t),n!==void 0)break}catch(e){r=e;break}if(r){this.client.sendMessage({type:`channel_message`,channel:this.id,event:void 0,responseTo:e.requestId,error:ne(r)});return}this.client.sendMessage({type:`channel_message`,channel:this.id,event:void 0,responseTo:e.requestId,payload:n})}resolvePending(e){let t=e.responseTo?this.pending.get(e.responseTo):void 0;t&&(this.pending.delete(e.responseTo),e.error!==void 0&&e.error!==null?t.reject(new y(String(e.error))):t.resolve(e.payload))}close(e){if(!this.closed){this.closed=!0;for(let t of this.pending.values())t.reject(e);this.pending.clear(),this.handlers.clear(),this.backlog=[]}}};const oe=a(function({onSubmit:e,action:t,...n},r){return m(`form`,{...n,action:t,ref:r,onSubmit:c(n=>b({event:n,action:t,onSubmit:e}),[t,e])})});async function b({event:e,action:t,onSubmit:n,formData:r,force:i}){if(n?.(e),!i&&e.defaultPrevented)return;let a=e.currentTarget;e.preventDefault();let o=e.nativeEvent;r||=new FormData(a,o.submitter);let s=new URL(t,window.location.href);try{await fetch(s,{method:`POST`,credentials:`include`,body:r})}catch(e){if(process.env.NODE_ENV!==`production`)console.error(`[Pulse] Form submission failed`,e);else throw e}}function se({params:e,request:t}){let{"*":n=``,...r}=e,i=new URL(t.url);return{hash:i.hash,pathname:i.pathname,query:i.search,queryParams:Object.fromEntries(i.searchParams.entries()),pathParams:r,catchall:n.length>1?n.split(`/`):[]}}function x(){function e(e,t){return n=>{let r={};for(let t of e)r[t]=n[t];if(t)for(let e in t){let i=t[e];r[e]=i(n)}return r}}return e}const ce=e=>e.tagName.toLowerCase(),le=[`id`,`className`,`tagName`,`localName`,`clientHeight`,`clientLeft`,`clientTop`,`clientWidth`,`scrollHeight`,`scrollLeft`,`scrollTop`,`scrollWidth`,`slot`],ue=[`autofocus`,`tabIndex`,`nonce`],de=[`accessKey`,`accessKeyLabel`,`autocapitalize`,`dir`,`draggable`,`hidden`,`inert`,`lang`,`offsetHeight`,`offsetLeft`,`offsetTop`,`offsetWidth`,`popover`,`spellcheck`,`title`,`translate`,`writingSuggestions`,`contentEditable`,`enterKeyHint`,`isContentEditable`,`inputMode`],S=x()(le,{tagName:ce}),C=x()(ue),fe=x()(de);function w(e){return{...S(e),...C(e),...fe(e)}}function T(e,t){let n=x()(e,t);return e=>({...w(e),...n(e)})}const pe=T([`hash`,`host`,`hostname`,`href`,`origin`,`password`,`pathname`,`port`,`protocol`,`search`,`target`,`download`,`rel`,`hreflang`,`type`,`username`,`ping`,`referrerPolicy`,`text`]),me=T([`alt`,`coords`,`download`,`hash`,`host`,`hostname`,`href`,`origin`,`password`,`pathname`,`port`,`protocol`,`rel`,`search`,`shape`,`target`,`username`,`ping`,`referrerPolicy`]),E=T([`autoplay`,`controls`,`crossOrigin`,`currentSrc`,`currentTime`,`defaultMuted`,`defaultPlaybackRate`,`duration`,`ended`,`loop`,`muted`,`networkState`,`paused`,`playbackRate`,`preload`,`readyState`,`seeking`,`src`,`volume`,`preservesPitch`]),he=e=>E(e),ge=T([`disabled`,`name`,`type`,`value`,`formAction`,`formEnctype`,`formMethod`,`formNoValidate`,`formTarget`,`popoverTargetAction`]),_e=T([`value`]),ve=T([`height`,`src`,`type`,`width`,`align`,`name`]),ye=T([`disabled`,`name`,`type`,`validationMessage`,`willValidate`]),be=T([`acceptCharset`,`action`,`autocomplete`,`encoding`,`enctype`,`length`,`method`,`name`,`noValidate`,`target`,`rel`]),xe=T([`allow`,`allowFullscreen`,`height`,`name`,`referrerPolicy`,`src`,`srcdoc`,`width`,`align`,`frameBorder`,`longDesc`,`marginHeight`,`marginWidth`,`scrolling`,`sandbox`]),Se=T([`alt`,`crossOrigin`,`decoding`,`height`,`isMap`,`loading`,`naturalHeight`,`naturalWidth`,`referrerPolicy`,`sizes`,`src`,`srcset`,`useMap`,`width`,`align`,`border`,`complete`,`hspace`,`longDesc`,`lowsrc`,`name`,`vspace`,`x`,`y`,`fetchPriority`]),Ce=T(`accept.alt.autocomplete.checked.defaultChecked.defaultValue.dirName.disabled.height.indeterminate.max.maxLength.min.minLength.multiple.name.pattern.placeholder.readOnly.required.selectionDirection.selectionEnd.selectionStart.size.src.step.type.value.valueAsNumber.width.align.capture.formAction.formEnctype.formMethod.formNoValidate.formTarget.useMap.validationMessage.willValidate.popoverTargetAction`.split(`.`)),we=T([`htmlFor`]),Te=T([`value`,`type`]),Ee=T([`as`,`crossOrigin`,`disabled`,`fetchPriority`,`href`,`hreflang`,`imageSizes`,`imageSrcset`,`integrity`,`media`,`referrerPolicy`,`rel`,`type`,`charset`,`rev`,`target`,`sizes`]),De=T([`name`]),Oe=T([`high`,`low`,`max`,`min`,`optimum`,`value`]),D=T([`cite`,`dateTime`]),ke=T([`reversed`,`start`,`type`,`compact`]),Ae=T([`data`,`height`,`name`,`type`,`useMap`,`width`,`validationMessage`,`willValidate`,`align`,`archive`,`border`,`code`,`codeBase`,`codeType`,`declare`,`hspace`,`standby`,`vspace`]),je=T([`disabled`,`label`]),Me=T([`defaultSelected`,`disabled`,`index`,`label`,`selected`,`text`,`value`]),Ne=T([`defaultValue`,`name`,`type`,`value`,`htmlFor`,`validationMessage`,`willValidate`]),Pe=T([`max`,`position`,`value`]),O=T([`cite`]),Fe=e=>w(e),Ie=x()([`async`,`crossOrigin`,`defer`,`fetchPriority`,`integrity`,`noModule`,`referrerPolicy`,`src`,`text`,`type`,`charset`],{event:e=>e.event,htmlFor:e=>e.htmlFor}),Le=e=>({...w(e),...Ie(e)}),Re=T([`autocomplete`,`disabled`,`length`,`multiple`,`name`,`required`,`selectedIndex`,`size`,`type`,`value`,`validationMessage`,`willValidate`]),ze=T([`name`]),Be=T([`height`,`media`,`sizes`,`src`,`srcset`,`type`,`width`]),Ve=T([`align`]),k=T([`abbr`,`cellIndex`,`colSpan`,`headers`,`rowSpan`,`scope`,`align`,`axis`,`bgColor`,`ch`,`chOff`,`height`,`noWrap`,`vAlign`,`width`]),A=T([`span`,`align`,`ch`,`chOff`,`vAlign`,`width`]),He=T([`align`,`bgColor`,`border`,`cellPadding`,`cellSpacing`,`frame`,`rules`,`summary`,`width`]),Ue=T([`rowIndex`,`sectionRowIndex`,`align`,`bgColor`,`ch`,`chOff`,`vAlign`]),j=T([`align`,`ch`,`chOff`,`vAlign`]),We=e=>w(e),Ge=T([`autocomplete`,`cols`,`defaultValue`,`dirName`,`disabled`,`maxLength`,`minLength`,`name`,`placeholder`,`readOnly`,`required`,`rows`,`selectionDirection`,`selectionEnd`,`selectionStart`,`value`,`wrap`,`textLength`,`validationMessage`,`willValidate`]),Ke=T([`dateTime`]),qe=T([`default`,`kind`,`label`,`readyState`,`src`,`srclang`]),Je=x()([`height`,`poster`,`videoHeight`,`videoWidth`,`width`,`playsInline`]),Ye=e=>({...E(e),...Je(e)}),Xe=T([`clear`]),Ze=T([`href`,`target`]),Qe=T([`aLink`,`background`,`bgColor`,`link`,`text`,`vLink`]),$e=T([`compact`]),et=T([`open`]),tt=T([`open`,`returnValue`]),nt=T([`align`]),rt=e=>w(e),M=T([`align`]),it=T([`align`,`color`,`noShade`,`size`,`width`]),at=T([`version`]),ot=e=>w(e),st=T([`content`,`httpEquiv`,`name`,`scheme`]),ct=T([`align`]),lt=e=>w(e),ut=T([`width`]),dt=e=>w(e),ft=T([`media`,`type`,`disabled`]),pt=T([`text`]),mt=T([`compact`,`type`]);function N(e){return{...S(e),...C(e)}}function P(e,t){let n=x()(e,t);return e=>({...N(e),...n(e)})}const F={A:pe,AREA:me,AUDIO:he,BASE:Ze,BLOCKQUOTE:O,Q:O,BODY:Qe,BR:Xe,BUTTON:ge,CANVAS:w,CAPTION:Ve,CITE:Fe,COL:A,COLGROUP:A,DATA:_e,DETAILS:et,DIALOG:tt,DIV:nt,DL:$e,EMBED:ve,FIELDSET:ye,FORM:be,H1:M,H2:M,H3:M,H4:M,H5:M,H6:M,HEAD:rt,HR:it,HTML:at,IFRAME:xe,IMG:Se,INPUT:Ce,LABEL:we,LI:Te,LINK:Ee,MAP:De,MENU:ot,META:st,METER:Oe,INS:D,DEL:D,OBJECT:Ae,OL:ke,OPTGROUP:je,OPTION:Me,OUTPUT:Ne,P:ct,PICTURE:lt,PRE:ut,PROGRESS:Pe,SCRIPT:Le,SELECT:Re,SLOT:ze,SOURCE:Be,SPAN:dt,STYLE:ft,TABLE:He,TBODY:j,THEAD:j,TFOOT:j,TD:k,TH:k,TEMPLATE:We,TEXTAREA:Ge,TIME:Ke,TITLE:pt,TR:Ue,TRACK:qe,UL:mt,VIDEO:Ye,SVG:P([`x`,`y`,`width`,`height`,`currentScale`,`currentTranslate`]),CIRCLE:P([`cx`,`cy`,`r`]),ELLIPSE:P([`cx`,`cy`,`rx`,`ry`]),LINE:P([`x1`,`y1`,`x2`,`y2`]),PATH:P([`pathLength`]),RECT:P([`x`,`y`,`width`,`height`,`rx`,`ry`]),POLYGON:P([`points`]),POLYLINE:P([`points`]),TEXT:P([`x`,`y`,`dx`,`dy`,`rotate`,`textLength`,`lengthAdjust`]),TSPAN:P([`x`,`y`,`dx`,`dy`,`rotate`,`textLength`,`lengthAdjust`]),IMAGE:P([`x`,`y`,`width`,`height`,`href`,`preserveAspectRatio`,`crossOrigin`]),USE:P([`x`,`y`,`width`,`height`,`href`]),DEFS:P([]),G:P([]),LINEARGRADIENT:P([`x1`,`y1`,`x2`,`y2`,`gradientUnits`,`gradientTransform`,`spreadMethod`]),RADIALGRADIENT:P([`cx`,`cy`,`r`,`fx`,`fy`,`fr`,`gradientUnits`,`gradientTransform`,`spreadMethod`]),STOP:P([`offset`]),PATTERN:P([`x`,`y`,`width`,`height`,`patternUnits`,`patternContentUnits`,`patternTransform`,`preserveAspectRatio`,`href`]),CLIPPATH:P([`clipPathUnits`]),MASK:P([`x`,`y`,`width`,`height`,`maskUnits`,`maskContentUnits`])};function ht(e){let t=F[e.tagName.toUpperCase()];if(t)return t(e);throw Error(`Unexpected HTML element tag: ${e.tagName} (update .web/custom/serialize.ts)`)}function gt(e){let t=F[e.tagName.toUpperCase()];return t?t(e):N(e)}function I(e){return e instanceof HTMLElement?ht(e):e instanceof SVGElement?gt(e):S(e)}const _t=e=>I(e.target),L=e=>e.relatedTarget?I(e.relatedTarget):null;function R(e,t){return x()(e,{target:_t,...t||{}})}const z=[`target`,`bubbles`,`cancelable`,`defaultPrevented`,`eventPhase`,`isTrusted`,`timeStamp`,`type`],B=[...z,`detail`],V=[...B,`altKey`,`button`,`buttons`,`clientX`,`clientY`,`ctrlKey`,`metaKey`,`movementX`,`movementY`,`pageX`,`pageY`,`screenX`,`screenY`,`shiftKey`],vt=[...V,`pointerId`,`pressure`,`tangentialPressure`,`tiltX`,`tiltY`,`twist`,`width`,`height`,`pointerType`,`isPrimary`],yt=R(z),bt=R(B),xt=R(V,{relatedTarget:L}),St=R(z,{clipboardData:e=>U(e.clipboardData)}),Ct=R([...z,`data`]),wt=R(V,{relatedTarget:L,dataTransfer:e=>U(e.dataTransfer)}),Tt=R(vt,{relatedTarget:L}),Et=R(z,{relatedTarget:L}),Dt=R(z),Ot=R(z),kt=R(z),At=R([...B,`altKey`,`ctrlKey`,`code`,`key`,`locale`,`location`,`metaKey`,`repeat`,`shiftKey`]),jt=R([...B,`altKey`,`ctrlKey`,`metaKey`,`shiftKey`,`changedTouches`,`targetTouches`,`touches`],{changedTouches:e=>H(e.changedTouches),targetTouches:e=>H(e.targetTouches),touches:e=>H(e.touches)}),Mt=R([...V,`deltaMode`,`deltaX`,`deltaY`,`deltaZ`],{relatedTarget:L}),Nt=R([...z,`animationName`,`elapsedTime`,`pseudoElement`]),Pt=R([...z,`oldState`,`newState`]),Ft=R([...z,`elapsedTime`,`propertyName`,`pseudoElement`]);function H(e){return Array.from(e).map(e=>({target:I(e.target),identifier:e.identifier,screenX:e.screenX,screenY:e.screenY,clientX:e.clientX,clientY:e.clientY,pageX:e.pageX,pageY:e.pageY}))}function U(e){if(!e)return null;let t=[];if(e.items)for(let n=0;n<e.items.length;n++){let r=e.items[n];t.push({kind:r.kind,type:r.type})}return{drop_effect:e.dropEffect,effect_allowed:e.effectAllowed,items:t,types:Array.from(e.types||[])}}const W={};function G(e,t,n){for(let r of t)e[r]=n}G(W,[`pointerdown`,`pointermove`,`pointerup`,`pointercancel`,`gotpointercapture`,`lostpointercapture`,`pointerenter`,`pointerleave`,`pointerover`,`pointerout`],Tt),G(W,[`click`,`contextmenu`,`dblclick`,`mousedown`,`mouseenter`,`mouseleave`,`mousemove`,`mouseout`,`mouseover`,`mouseup`],xt),G(W,[`drag`,`dragend`,`dragenter`,`dragexit`,`dragleave`,`dragover`,`dragstart`,`drop`],wt),G(W,[`keydown`,`keypress`,`keyup`],At),G(W,[`focus`,`blur`],Et),G(W,[`change`,`input`],kt),G(W,[`invalid`],Ot),G(W,[`reset`,`submit`],Dt),G(W,[`copy`,`cut`,`paste`],St),G(W,[`compositionend`,`compositionstart`,`compositionupdate`],Ct),G(W,[`touchcancel`,`touchend`,`touchmove`,`touchstart`],jt),G(W,[`scroll`],bt),G(W,[`wheel`],Mt),G(W,[`animationstart`,`animationend`,`animationiteration`],Nt),G(W,[`transitionend`],Ft),G(W,[`toggle`],Pt);function It(e){if(e&&typeof e==`object`&&`nativeEvent`in e&&typeof e.isDefaultPrevented==`function`){let t=e;if(typeof t.type!=`string`)return e;let n=W[t.type.toLowerCase()];return n?n(t):yt(t)}return e}function K(e){let t=new Map,n=[],r=[],i=[],a=[],o=0;function s(e,c){if(e==null||typeof e==`string`||typeof e==`boolean`)return e;if(typeof e==`number`){if(Number.isNaN(e)){let e=c?` in '${c}'`:``;throw Error(`Cannot serialize NaN${e}. NaN and Infinity are not supported because they cannot be serialized to JSON.`)}if(!Number.isFinite(e)){let t=e>0?`Infinity`:`-Infinity`,n=c?` in '${c}'`:``;throw Error(`Cannot serialize ${t}${n}. NaN and Infinity are not supported because they cannot be serialized to JSON.`)}return e}let l=o++,u=t.get(e);if(u!==void 0)return n.push(l),u;if(t.set(e,l),e instanceof Date)return r.push(l),e.getTime();if(Array.isArray(e)){let t=e.length,n=Array(t);for(let r=0;r<t;r++)n[r]=s(e[r],c);return n}if(e instanceof Map){a.push(l);let t={};for(let[n,r]of e.entries())t[String(n)]=s(r,String(n));return t}if(e instanceof Set){i.push(l);let t=e.size,n=Array(t),r=0;for(let t of e)n[r]=s(t,c),r+=1;return n}if(typeof e==`object`){let t={},n=Object.keys(e);for(let r=0;r<n.length;r++){let i=n[r];t[i]=s(e[i],i)}return t}throw Error(`Unsupported value in serialization: ${e}`)}let c=s(e);return[[n,r,i,a],c]}function q(e,t){let[[n,r,i,a],o]=e,s=new Set(n),c=new Set(r),l=new Set(i),u=new Set(a),d=[];function f(e){let n=d.length;if(s.has(n))return d.push(null),d[e];if(c.has(n)){let t=new Date(e);return d.push(t),t}if(e==null||typeof e==`number`||typeof e==`string`||typeof e==`boolean`)return t?.coerceNullsToUndefined?e??void 0:e;if(Array.isArray(e)){if(l.has(n)){let t=new Set;d.push(t);for(let n=0;n<e.length;n++)t.add(f(e[n]));return t}let t=e.length,r=Array(t);d.push(r);for(let n=0;n<t;n++)r[n]=f(e[n]);return r}if(typeof e==`object`){if(u.has(n)){let t=new Map;d.push(t);let n=Object.keys(e);for(let r=0;r<n.length;r++){let i=n[r];t.set(i,f(e[i]))}return t}let t={};d.push(t);let r=Object.keys(e);for(let n=0;n<r.length;n++){let i=r[n];t[i]=f(e[i])}return t}throw Error(`Unsupported value in deserialization: ${e}`)}return f(o)}var Lt=class{#activeViews;#socket=null;#messageQueue;#connectionListeners=new Set;#serverErrors=new Map;#serverErrorListeners=new Set;#channels=new Map;#url;#frameworkNavigate;#directives;#connectionStatusConfig;#hasConnectedOnce=!1;#connectingTimeout=null;#errorTimeout=null;#currentStatus=`ok`;constructor(e,t,n,r){if(this.#url=e,this.#directives=t,this.#frameworkNavigate=n,this.#socket=null,this.#activeViews=new Map,this.#messageQueue=[],this.#connectionStatusConfig=r,typeof window<`u`&&typeof sessionStorage<`u`){let e=sessionStorage.getItem(`__PULSE_DIRECTIVES`);if(e)try{this.#directives=JSON.parse(e)}catch{}}}setDirectives(e){this.#directives=e}isConnected(){return this.#socket?.connected??!1}#clearTimeouts(){this.#connectingTimeout&&=(clearTimeout(this.#connectingTimeout),null),this.#errorTimeout&&=(clearTimeout(this.#errorTimeout),null)}#setStatus(e){this.#clearTimeouts(),this.#currentStatus=e,this.#notifyConnectionListeners(e)}#handleConnected(){this.#hasConnectedOnce=!0,this.#setStatus(`ok`)}#setInitialConnectionStatus(){this.#setStatus(`ok`),this.#connectingTimeout=setTimeout(()=>{this.#setStatus(`connecting`),this.#errorTimeout=setTimeout(()=>{this.#setStatus(`error`)},this.#connectionStatusConfig.initialErrorDelay)},this.#connectionStatusConfig.initialConnectingDelay)}#handleDisconnected(){this.#setStatus(`reconnecting`),this.#errorTimeout=setTimeout(()=>{this.#setStatus(`error`)},this.#connectionStatusConfig.reconnectErrorDelay)}async connect(){if(!this.#socket)return this.#hasConnectedOnce||this.#setInitialConnectionStatus(),new Promise((e,t)=>{let n=v(this.#url,{transports:[`websocket`,`webtransport`],auth:this.#directives.socketio?.auth,extraHeaders:this.#directives.socketio?.headers});this.#socket=n,n.on(`connect`,()=>{console.log(`[SocketIOTransport] Connected:`,this.#socket?.id);for(let[e,t]of this.#activeViews)n.emit(`message`,K({type:`mount`,path:e,routeInfo:t.routeInfo}));for(let e of this.#messageQueue)e.type===`mount`&&this.#activeViews.has(e.path)||e.type!==`navigate`&&n.emit(`message`,K(e));this.#messageQueue=[],this.#handleConnected(),e()}),n.on(`connect_error`,e=>{console.error(`[SocketIOTransport] Connection failed:`,e),this.#handleDisconnected(),t(e)}),n.on(`disconnect`,()=>{console.log(`[SocketIOTransport] Disconnected`),this.#handleTransportDisconnect(),this.#handleDisconnected()}),n.on(`message`,e=>this.#handleServerMessage(q(e,{coerceNullsToUndefined:!0})))})}onConnectionChange(e){return this.#connectionListeners.add(e),e(this.#currentStatus),()=>{this.#connectionListeners.delete(e)}}#notifyConnectionListeners(e){for(let t of this.#connectionListeners)t(e)}onServerError(e){this.#serverErrorListeners.add(e);for(let[t,n]of this.#serverErrors)e(t,n);return()=>{this.#serverErrorListeners.delete(e)}}#notifyServerError(e,t){for(let n of this.#serverErrorListeners)n(e,t)}sendMessage(e){this.isConnected()?this.#socket.emit(`message`,K(e)):this.#messageQueue.push(e)}mountView(e,t){if(this.#activeViews.has(e))throw Error(`Path ${e} is already mounted`);this.#activeViews.set(e,t),this.sendMessage({type:`mount`,path:e,routeInfo:t.routeInfo})}navigate(e,t){this.sendMessage({type:`navigate`,path:e,routeInfo:t})}unmount(e){this.sendMessage({type:`unmount`,path:e}),this.#activeViews.delete(e)}disconnect(){this.#clearTimeouts(),this.#socket?.disconnect(),this.#socket=null,this.#messageQueue=[],this.#connectionListeners.clear(),this.#activeViews.clear(),this.#serverErrors.clear(),this.#serverErrorListeners.clear();for(let{bridge:e}of this.#channels.values())e.dispose(new y(`Client disconnected`));this.#channels.clear(),this.#currentStatus=`ok`,this.#hasConnectedOnce=!1}#handleServerMessage(e){switch(e.type){case`vdom_init`:{let t=this.#activeViews.get(e.path);if(!t)return;t&&t.onInit(e),this.#serverErrors.has(e.path)&&(this.#serverErrors.delete(e.path),this.#notifyServerError(e.path,null));break}case`vdom_update`:{let t=this.#activeViews.get(e.path);if(!t)return;t.onUpdate(e.ops),this.#serverErrors.has(e.path)&&(this.#serverErrors.delete(e.path),this.#notifyServerError(e.path,null));break}case`server_error`:if(!this.#activeViews.has(e.path))return;this.#serverErrors.set(e.path,e.error),this.#notifyServerError(e.path,e.error);break;case`api_call`:this.#performApiCall(e);break;case`navigate_to`:{let t=!!e.replace,n=e.path||``;n.startsWith(`//`)&&(n=`${window.location.protocol}${n}`);let r=()=>t?window.location.replace(n):window.location.assign(n);if(e.hard){r();break}if(!/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(n)){this.#frameworkNavigate(n,{replace:t});break}if(/^https?:\/\//.test(n))try{let e=new URL(n);if(e.origin===window.location.origin){this.#frameworkNavigate(`${e.pathname}${e.search}${e.hash}`,{replace:t});break}}catch{}r();break}case`channel_message`:this.#routeChannelMessage(e);break;case`js_exec`:this.#handleJsExec(e);break;default:console.error(`Unexpected message:`,e)}}async#performApiCall(e){try{let t=await fetch(e.url,{method:e.method||`GET`,headers:{...e.headers||{},...e.body!=null&&!(`content-type`in(e.headers||{}))?{"content-type":`application/json`}:{}},body:e.body==null?void 0:typeof e.body==`string`?e.body:JSON.stringify(e.body),credentials:e.credentials||`include`}),n={};t.headers.forEach((e,t)=>{n[t]=e});let r=null;r=(t.headers.get(`content-type`)||``).includes(`application/json`)?await t.json().catch(()=>null):await t.text().catch(()=>null);let i={type:`api_result`,id:e.id,ok:t.ok,status:t.status,headers:n,body:r};this.sendMessage(i)}catch(t){let n={type:`api_result`,id:e.id,ok:!1,status:0,headers:{},body:{error:String(t)}};this.sendMessage(n)}}invokeCallback(e,t,n){this.sendMessage({type:`callback`,path:e,callback:t,args:n.map(It)})}#handleJsExec(e){let t=this.#activeViews.get(e.path);if(!t?.onJsExec){console.warn(`[Pulse] No onJsExec handler for path: ${e.path}`),this.#sendJsResult(e.id,void 0,`No JS executor registered`);return}t.onJsExec(e)}sendJsResult(e,t,n){this.#sendJsResult(e,t,n)}#sendJsResult(e,t,n){let r={type:`js_result`,id:e,result:t,error:n};this.sendMessage(r)}acquireChannel(e){let t=this.#ensureChannelEntry(e);return t.refCount+=1,t.bridge}releaseChannel(e){let t=this.#channels.get(e);t&&(t.refCount=Math.max(0,t.refCount-1),t.refCount===0&&(t.bridge.dispose(new y(`Channel released`)),this.sendMessage({type:`channel_message`,channel:e,event:`__close__`,payload:{reason:`refcount_zero`}}),this.#channels.delete(e)))}#ensureChannelEntry(e){let t=this.#channels.get(e);return t||(t={bridge:new ae(this,e),refCount:0},this.#channels.set(e,t)),t}#routeChannelMessage(e){let t=this.#ensureChannelEntry(e.channel);t.bridge.handleServerMessage(e)&&t.refCount===0&&this.#channels.delete(e.channel)}#handleTransportDisconnect(){for(let e of this.#channels.values())e.bridge.handleDisconnect(new y(`Connection lost`))}};const J=`$$fragment`;function Rt(e){return typeof e==`object`&&!!e}function zt(e){return typeof e==`object`&&!!e&&e.tag.startsWith(`$$`)&&e.tag!==J}const Y=`$js:`;var Bt=class{#callbacks;#callbackCache;#renderPropKeys;#jsexprPaths;#callbackList;#client;#path;#registry;constructor(e,t,n=[],r=[],i={},a=[]){this.#client=e,this.#path=t,this.#registry=i,this.#callbacks=new Set(n),this.#callbackCache=new Map,this.#renderPropKeys=new Set(r),this.#jsexprPaths=new Set(a),this.#callbackList=[...this.#callbacks].sort()}getObject(e){let t=this.#registry[e];if(t===void 0)throw Error(`[Pulse] Unknown registry key: ${e}`);return t}evaluateJsExpr(e){return Function(`get_object`,`return ${e}`)(e=>this.getObject(e))}hasCallbackPath(e){return this.#callbacks.has(e)}hasRenderPropPath(e){return this.#renderPropKeys.has(e)}hasAnyCallbackUnder(e){if(e===``)return this.#callbackList.length>0;let t=this.#lowerBound(this.#callbackList,e);return t<this.#callbackList.length&&this.#callbackList[t].startsWith(e)}applyCallbackDelta(e){if(e.remove)for(let t of e.remove)this.#callbacks.delete(t),this.#callbackCache.delete(t);if(e.add)for(let t of e.add)this.#callbacks.add(t);this.#callbackList=[...this.#callbacks].sort()}applyRenderPropsDelta(e){if(e.remove)for(let t of e.remove)this.#renderPropKeys.delete(t);if(e.add)for(let t of e.add)this.#renderPropKeys.add(t)}applyJsExprPathsDelta(e){if(e.remove)for(let t of e.remove)this.#jsexprPaths.delete(t);if(e.add)for(let t of e.add)this.#jsexprPaths.add(t)}getCallback(e,t){let n=this.#propPath(e,t),r=this.#callbackCache.get(n);return r||(r=(...e)=>this.#client.invokeCallback(this.#path,n,e),this.#callbackCache.set(n,r)),r}renderNode(t,n=``){if(t==null||typeof t==`boolean`||typeof t==`number`)return t;if(typeof t==`string`){if(t.startsWith(Y)){let e=t.slice(4);return this.evaluateJsExpr(e)}return t}if(Rt(t)){let{tag:r,props:a={},children:o=[]}=t,s={};for(let[e,t]of Object.entries(a))s[e]=this.transformValue(n,e,t);t.key&&(s.key=t.key);let c=[];for(let e=0;e<o.length;e+=1){let t=o[e],r=n?`${n}.${e}`:String(e);c.push(this.renderNode(t,r))}if(zt(t)){let e=t.tag.slice(2),n=this.#registry[e];if(!n)throw Error(`Could not find component ${e}. This is a Pulse internal error.`);return i(n,s,...c)}return i(r===J?e:r,s,...c)}return process.env.NODE_ENV!==`production`&&console.error(`Unknown VDOM node type:`,t),null}#propPath(e,t){return e?`${e}.${t}`:t}transformValue(e,t,n){let r=this.#propPath(e,t);if(this.#callbacks.has(r))return this.getCallback(e,t);if(this.#renderPropKeys.has(r))return this.renderNode(n,r);if(typeof n==`string`&&n.startsWith(Y)){let e=n.slice(4);return this.evaluateJsExpr(e)}return n}init(e){this.#callbacks=new Set(e.callbacks);for(let e of Array.from(this.#callbackCache.keys()))this.#callbacks.has(e)||this.#callbackCache.delete(e);return this.#callbackList=[...this.#callbacks].sort(),this.#renderPropKeys=new Set(e.render_props),this.#jsexprPaths=new Set(e.jsexpr_paths),this.renderNode(e.vdom)}#ensureChildrenArray(e){let t=e.props?.children;return t==null?[]:Array.isArray(t)?t.slice():[t]}applyUpdates(e,t){let r=e;for(let e of t){if(e.type===`update_callbacks`){this.applyCallbackDelta(e.data);continue}if(e.type===`update_render_props`){this.applyRenderPropsDelta(e.data);continue}if(e.type===`update_jsexpr_paths`){this.applyJsExprPathsDelta(e.data);continue}let t=e.path.split(`.`).filter(e=>e.length>0),a=(r,o,s)=>{if(o<t.length){this.#assertIsElement(r,t,o);let e=r,i=t[o],c=+i,l=s?`${s}.${i}`:i;if(Number.isNaN(c)){let t=e.props??{},r=t[i];return n(e,{...t,[i]:a(r,o+1,l)})}else{let t=this.#ensureChildrenArray(e),r=t[c];return t[c]=a(r,o+1,l),n(e,void 0,...t)}}switch(e.type){case`replace`:return this.renderNode(e.data,e.path);case`update_props`:{this.#assertIsElement(r,t,o);let a=r,c={...a.props??{}},l=e.data;if(l.remove&&l.remove.length>0)for(let e of l.remove)e in c&&delete c[e];if(l.set)for(let[e,t]of Object.entries(l.set))c[e]=this.transformValue(s,e,t);return(l.remove?.length??0)>0?(c.key=a.key,c.ref=a.ref,i(a.type,c,...this.#ensureChildrenArray(a))):n(a,c)}case`reconciliation`:{this.#assertIsElement(r,t,o);let i=r,a=this.#ensureChildrenArray(i),c=[],[l,u]=e.new,[d,f]=e.reuse,p=-1,m=-1,h=-1,g=-1;l.length>0&&(p=l[0],h=0),d.length>0&&(m=d[0],g=0);for(let t=0;t<e.N;++t)if(t===p){let e=u[h],n=s?`${s}.${t}`:String(t);c.push(this.renderNode(e,n)),p=h<l.length-1?l[++h]:-1}else if(t===m){let e=a[f[g]],n=s?`${s}.${t}`:String(t);this.hasAnyCallbackUnder(n)&&(e=this.#rebindCallbacksInSubtree(e,n)),c.push(e),m=g<d.length-1?d[++g]:-1}else c.push(a[t]);return n(i,null,...c)}default:throw Error(`[Pulse renderer] Unknown update type: ${e?.type}`)}};r=a(r,0,``)}return r}#assertIsElement(e,t,n){if(process.env.NODE_ENV!==`production`&&!o(e))throw console.error(`Invalid node:`,e),Error(`Invalid node at path ${t.slice(0,n).join(`.`)}`);return!0}#rebindCallbacksInSubtree(e,t){if(!o(e))return e;let r=e,i=r.props??{},a={...i};for(let e of Object.keys(i)){let n=t?`${t}.${e}`:e;this.hasCallbackPath(n)&&(a[e]=this.getCallback(t,e)),this.hasRenderPropPath(n)&&this.hasAnyCallbackUnder(n)&&(a[e]=this.#rebindCallbacksInSubtree(i[e],n))}return n(r,a,...this.#ensureChildrenArray(r).map((e,n)=>{let r=t?`${t}.${n}`:String(n);return this.hasAnyCallbackUnder(r)?this.#rebindCallbacksInSubtree(e,r):e}))}#lowerBound(e,t){let n=0,r=e.length;for(;n<r;){let i=n+r>>>1;e[i]<t?n=i+1:r=i}return n}};function Vt(e,n){let r=s(e);return({children:e,...i})=>m(t,{fallback:n,children:m(r,{...i,children:e})})}const X=r(null),Z=r(null),Q=()=>{let e=l(X);if(!e)throw Error(`usePulseClient must be used within a PulseProvider`);return e},Ht=e=>{let t=l(Z);if(!t)throw Error(`usePulsePrerender must be used within a PulseProvider`);let n=t.views[e];if(!n)throw Error(`No prerender found for '${e}'`);return n},$=typeof window<`u`;function Ut({children:e,config:t,prerender:n}){let[r,i]=p(`ok`),a=_(),{directives:o}=n,s=d(()=>new Lt(t.serverAddress,o,a,t.connectionStatus),[t.serverAddress,a,t.connectionStatus]);u(()=>s.setDirectives(o),[s,o]),u(()=>{if(!$)return;let e=s.onConnectionChange(e=>{i(e)});return s.connect(),()=>{e(),s.disconnect()}},[s]);let c=(()=>{switch(r){case`connecting`:return`Connecting...`;case`reconnecting`:return`Reconnecting...`;case`error`:return`Failed to connect to the server.`;default:return null}})();return m(X.Provider,{value:s,children:h(Z.Provider,{value:n,children:[c&&m(`div`,{style:{position:`fixed`,bottom:`20px`,right:`20px`,backgroundColor:r===`error`?`red`:`#666`,color:`white`,padding:`10px`,borderRadius:`5px`,zIndex:1e3},children:c}),e]})})}function Wt({path:e,registry:t}){let n=Q(),r=Ht(e),i=d(()=>new Bt(n,e,r.callbacks,r.render_props,t,r.jsexpr_paths),[n,e,t]),[a,o]=p(()=>i.init(r)),[s,c]=p(null),l=g(),h=ee(),_=d(()=>{let{"*":e=``,...t}=h,n=new URLSearchParams(l.search);return{hash:l.hash,pathname:l.pathname,query:l.search,queryParams:Object.fromEntries(n.entries()),pathParams:t,catchall:e.length>0?e.split(`/`):[]}},[l.hash,l.pathname,l.search,JSON.stringify(h)]);u(()=>{if($){n.mountView(e,{routeInfo:_,onInit:e=>{o(i.init(e))},onUpdate:e=>{o(t=>t==null?t:i.applyUpdates(t,e))},onJsExec:e=>{let t,r=null;try{t=i.evaluateJsExpr(e.code)}catch(e){r=e instanceof Error?e.message:String(e)}n.sendJsResult(e.id,t,r)}});let t=n.onServerError((t,n)=>{t===e&&c(n)});return()=>{t(),n.unmount(e)}}},[n,i,e]),u(()=>{$&&n.navigate(e,_)},[n,e,_]);let v=f(!1);return u(()=>(v.current?o(i.init(r)):v.current=!0,()=>{v.current=!1}),[r,i]),s?m(Gt,{error:s}):a}function Gt({error:e}){return h(`div`,{style:{padding:16,border:`1px solid #e00`,background:`#fff5f5`,color:`#900`,fontFamily:`ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace`,whiteSpace:`pre-wrap`},children:[h(`div`,{style:{fontWeight:700,marginBottom:8},children:[`Server Error during `,e.phase]}),e.message&&m(`div`,{children:e.message}),e.stack&&h(`details`,{open:!0,style:{marginTop:8},children:[m(`summary`,{children:`Stack trace`}),m(`pre`,{style:{margin:0},children:e.stack})]})]})}function Kt(e){let t=Q(),n=d(()=>{if(!e)throw Error(`usePulseChannel requires a non-empty channelId`);return t.acquireChannel(e)},[t,e]);return u(()=>()=>{t.releaseChannel(e)},[t,e]),n}export{y as PulseChannelResetError,oe as PulseForm,Ut as PulseProvider,Wt as PulseView,Vt as RenderLazy,q as deserialize,se as extractServerRouteInfo,K as serialize,b as submitForm,Kt as usePulseChannel,Q as usePulseClient};
|
|
1
|
+
import{Fragment as e,cloneElement as t,createContext as n,createElement as r,forwardRef as i,isValidElement as a,useCallback as o,useContext as s,useEffect as c,useMemo as l,useRef as u,useState as d}from"react";import{useLocation as f,useNavigate as p,useParams as m}from"react-router";import{io as h}from"socket.io-client";import{jsx as g,jsxs as _}from"react/jsx-runtime";function v(){function e(e,t){return n=>{let r={};for(let t of e)r[t]=n[t];if(t)for(let e in t){let i=t[e];r[e]=i(n)}return r}}return e}const y=e=>e.tagName.toLowerCase(),ee=[`id`,`className`,`tagName`,`localName`,`clientHeight`,`clientLeft`,`clientTop`,`clientWidth`,`scrollHeight`,`scrollLeft`,`scrollTop`,`scrollWidth`,`slot`],te=[`autofocus`,`tabIndex`,`nonce`],ne=[`accessKey`,`accessKeyLabel`,`autocapitalize`,`dir`,`draggable`,`hidden`,`inert`,`lang`,`offsetHeight`,`offsetLeft`,`offsetTop`,`offsetWidth`,`popover`,`spellcheck`,`title`,`translate`,`writingSuggestions`,`contentEditable`,`enterKeyHint`,`isContentEditable`,`inputMode`],b=v()(ee,{tagName:y}),x=v()(te),re=v()(ne);function S(e){return{...b(e),...x(e),...re(e)}}function C(e,t){let n=v()(e,t);return e=>({...S(e),...n(e)})}const ie=C([`hash`,`host`,`hostname`,`href`,`origin`,`password`,`pathname`,`port`,`protocol`,`search`,`target`,`download`,`rel`,`hreflang`,`type`,`username`,`ping`,`referrerPolicy`,`text`]),ae=C([`alt`,`coords`,`download`,`hash`,`host`,`hostname`,`href`,`origin`,`password`,`pathname`,`port`,`protocol`,`rel`,`search`,`shape`,`target`,`username`,`ping`,`referrerPolicy`]),w=C([`autoplay`,`controls`,`crossOrigin`,`currentSrc`,`currentTime`,`defaultMuted`,`defaultPlaybackRate`,`duration`,`ended`,`loop`,`muted`,`networkState`,`paused`,`playbackRate`,`preload`,`readyState`,`seeking`,`src`,`volume`,`preservesPitch`]),oe=e=>w(e),se=C([`disabled`,`name`,`type`,`value`,`formAction`,`formEnctype`,`formMethod`,`formNoValidate`,`formTarget`,`popoverTargetAction`]),ce=C([`value`]),le=C([`height`,`src`,`type`,`width`,`align`,`name`]),ue=C([`disabled`,`name`,`type`,`validationMessage`,`willValidate`]),de=C([`acceptCharset`,`action`,`autocomplete`,`encoding`,`enctype`,`length`,`method`,`name`,`noValidate`,`target`,`rel`]),fe=C([`allow`,`allowFullscreen`,`height`,`name`,`referrerPolicy`,`src`,`srcdoc`,`width`,`align`,`frameBorder`,`longDesc`,`marginHeight`,`marginWidth`,`scrolling`,`sandbox`]),pe=C([`alt`,`crossOrigin`,`decoding`,`height`,`isMap`,`loading`,`naturalHeight`,`naturalWidth`,`referrerPolicy`,`sizes`,`src`,`srcset`,`useMap`,`width`,`align`,`border`,`complete`,`hspace`,`longDesc`,`lowsrc`,`name`,`vspace`,`x`,`y`,`fetchPriority`]),me=C(`accept.alt.autocomplete.checked.defaultChecked.defaultValue.dirName.disabled.height.indeterminate.max.maxLength.min.minLength.multiple.name.pattern.placeholder.readOnly.required.selectionDirection.selectionEnd.selectionStart.size.src.step.type.value.valueAsNumber.width.align.capture.formAction.formEnctype.formMethod.formNoValidate.formTarget.useMap.validationMessage.willValidate.popoverTargetAction`.split(`.`),{valueAsNumber:e=>{let t=e.valueAsNumber;return Number.isFinite(t)?t:null}}),he=C([`htmlFor`]),ge=C([`value`,`type`]),_e=C([`as`,`crossOrigin`,`disabled`,`fetchPriority`,`href`,`hreflang`,`imageSizes`,`imageSrcset`,`integrity`,`media`,`referrerPolicy`,`rel`,`type`,`charset`,`rev`,`target`,`sizes`]),ve=C([`name`]),ye=C([`high`,`low`,`max`,`min`,`optimum`,`value`]),T=C([`cite`,`dateTime`]),be=C([`reversed`,`start`,`type`,`compact`]),xe=C([`data`,`height`,`name`,`type`,`useMap`,`width`,`validationMessage`,`willValidate`,`align`,`archive`,`border`,`code`,`codeBase`,`codeType`,`declare`,`hspace`,`standby`,`vspace`]),Se=C([`disabled`,`label`]),Ce=C([`defaultSelected`,`disabled`,`index`,`label`,`selected`,`text`,`value`]),we=C([`defaultValue`,`name`,`type`,`value`,`htmlFor`,`validationMessage`,`willValidate`]),Te=C([`max`,`position`,`value`]),E=C([`cite`]),Ee=e=>S(e),De=v()([`async`,`crossOrigin`,`defer`,`fetchPriority`,`integrity`,`noModule`,`referrerPolicy`,`src`,`text`,`type`,`charset`],{event:e=>e.event,htmlFor:e=>e.htmlFor}),Oe=e=>({...S(e),...De(e)}),ke=C([`autocomplete`,`disabled`,`length`,`multiple`,`name`,`required`,`selectedIndex`,`size`,`type`,`value`,`validationMessage`,`willValidate`]),Ae=C([`name`]),je=C([`height`,`media`,`sizes`,`src`,`srcset`,`type`,`width`]),Me=C([`align`]),D=C([`abbr`,`cellIndex`,`colSpan`,`headers`,`rowSpan`,`scope`,`align`,`axis`,`bgColor`,`ch`,`chOff`,`height`,`noWrap`,`vAlign`,`width`]),O=C([`span`,`align`,`ch`,`chOff`,`vAlign`,`width`]),Ne=C([`align`,`bgColor`,`border`,`cellPadding`,`cellSpacing`,`frame`,`rules`,`summary`,`width`]),Pe=C([`rowIndex`,`sectionRowIndex`,`align`,`bgColor`,`ch`,`chOff`,`vAlign`]),k=C([`align`,`ch`,`chOff`,`vAlign`]),Fe=e=>S(e),Ie=C([`autocomplete`,`cols`,`defaultValue`,`dirName`,`disabled`,`maxLength`,`minLength`,`name`,`placeholder`,`readOnly`,`required`,`rows`,`selectionDirection`,`selectionEnd`,`selectionStart`,`value`,`wrap`,`textLength`,`validationMessage`,`willValidate`]),Le=C([`dateTime`]),Re=C([`default`,`kind`,`label`,`readyState`,`src`,`srclang`]),ze=v()([`height`,`poster`,`videoHeight`,`videoWidth`,`width`,`playsInline`]),Be=e=>({...w(e),...ze(e)}),Ve=C([`clear`]),He=C([`href`,`target`]),Ue=C([`aLink`,`background`,`bgColor`,`link`,`text`,`vLink`]),We=C([`compact`]),Ge=C([`open`]),Ke=C([`open`,`returnValue`]),qe=C([`align`]),Je=e=>S(e),A=C([`align`]),Ye=C([`align`,`color`,`noShade`,`size`,`width`]),Xe=C([`version`]),Ze=e=>S(e),Qe=C([`content`,`httpEquiv`,`name`,`scheme`]),$e=C([`align`]),et=e=>S(e),tt=C([`width`]),nt=e=>S(e),rt=C([`media`,`type`,`disabled`]),it=C([`text`]),at=C([`compact`,`type`]);function j(e){return{...b(e),...x(e)}}function M(e,t){let n=v()(e,t);return e=>({...j(e),...n(e)})}const N={A:ie,AREA:ae,AUDIO:oe,BASE:He,BLOCKQUOTE:E,Q:E,BODY:Ue,BR:Ve,BUTTON:se,CANVAS:S,CAPTION:Me,CITE:Ee,COL:O,COLGROUP:O,DATA:ce,DETAILS:Ge,DIALOG:Ke,DIV:qe,DL:We,EMBED:le,FIELDSET:ue,FORM:de,H1:A,H2:A,H3:A,H4:A,H5:A,H6:A,HEAD:Je,HR:Ye,HTML:Xe,IFRAME:fe,IMG:pe,INPUT:me,LABEL:he,LI:ge,LINK:_e,MAP:ve,MENU:Ze,META:Qe,METER:ye,INS:T,DEL:T,OBJECT:xe,OL:be,OPTGROUP:Se,OPTION:Ce,OUTPUT:we,P:$e,PICTURE:et,PRE:tt,PROGRESS:Te,SCRIPT:Oe,SELECT:ke,SLOT:Ae,SOURCE:je,SPAN:nt,STYLE:rt,TABLE:Ne,TBODY:k,THEAD:k,TFOOT:k,TD:D,TH:D,TEMPLATE:Fe,TEXTAREA:Ie,TIME:Le,TITLE:it,TR:Pe,TRACK:Re,UL:at,VIDEO:Be,SVG:M([`x`,`y`,`width`,`height`,`currentScale`,`currentTranslate`]),CIRCLE:M([`cx`,`cy`,`r`]),ELLIPSE:M([`cx`,`cy`,`rx`,`ry`]),LINE:M([`x1`,`y1`,`x2`,`y2`]),PATH:M([`pathLength`]),RECT:M([`x`,`y`,`width`,`height`,`rx`,`ry`]),POLYGON:M([`points`]),POLYLINE:M([`points`]),TEXT:M([`x`,`y`,`dx`,`dy`,`rotate`,`textLength`,`lengthAdjust`]),TSPAN:M([`x`,`y`,`dx`,`dy`,`rotate`,`textLength`,`lengthAdjust`]),IMAGE:M([`x`,`y`,`width`,`height`,`href`,`preserveAspectRatio`,`crossOrigin`]),USE:M([`x`,`y`,`width`,`height`,`href`]),DEFS:M([]),G:M([]),LINEARGRADIENT:M([`x1`,`y1`,`x2`,`y2`,`gradientUnits`,`gradientTransform`,`spreadMethod`]),RADIALGRADIENT:M([`cx`,`cy`,`r`,`fx`,`fy`,`fr`,`gradientUnits`,`gradientTransform`,`spreadMethod`]),STOP:M([`offset`]),PATTERN:M([`x`,`y`,`width`,`height`,`patternUnits`,`patternContentUnits`,`patternTransform`,`preserveAspectRatio`,`href`]),CLIPPATH:M([`clipPathUnits`]),MASK:M([`x`,`y`,`width`,`height`,`maskUnits`,`maskContentUnits`])};function ot(e){let t=N[e.tagName.toUpperCase()];if(t)return t(e);throw Error(`Unexpected HTML element tag: ${e.tagName} (update .web/custom/serialize.ts)`)}function st(e){let t=N[e.tagName.toUpperCase()];return t?t(e):j(e)}function P(e){return e instanceof HTMLElement?ot(e):e instanceof SVGElement?st(e):b(e)}const ct=e=>P(e.target),F=e=>e.relatedTarget?P(e.relatedTarget):null;function I(e,t){return v()(e,{target:ct,...t||{}})}const L=[`target`,`bubbles`,`cancelable`,`defaultPrevented`,`eventPhase`,`isTrusted`,`timeStamp`,`type`],R=[...L,`detail`],z=[...R,`altKey`,`button`,`buttons`,`clientX`,`clientY`,`ctrlKey`,`metaKey`,`movementX`,`movementY`,`pageX`,`pageY`,`screenX`,`screenY`,`shiftKey`],lt=[...z,`pointerId`,`pressure`,`tangentialPressure`,`tiltX`,`tiltY`,`twist`,`width`,`height`,`pointerType`,`isPrimary`],ut=I(L),dt=I(R),ft=I(z,{relatedTarget:F}),pt=I(L,{clipboardData:e=>V(e.clipboardData)}),mt=I([...L,`data`]),ht=I(z,{relatedTarget:F,dataTransfer:e=>V(e.dataTransfer)}),gt=I(lt,{relatedTarget:F}),_t=I(L,{relatedTarget:F}),vt=I(L),yt=I(L),bt=I(L),xt=I([...R,`altKey`,`ctrlKey`,`code`,`key`,`locale`,`location`,`metaKey`,`repeat`,`shiftKey`]),St=I([...R,`altKey`,`ctrlKey`,`metaKey`,`shiftKey`,`changedTouches`,`targetTouches`,`touches`],{changedTouches:e=>B(e.changedTouches),targetTouches:e=>B(e.targetTouches),touches:e=>B(e.touches)}),Ct=I([...z,`deltaMode`,`deltaX`,`deltaY`,`deltaZ`],{relatedTarget:F}),wt=I([...L,`animationName`,`elapsedTime`,`pseudoElement`]),Tt=I([...L,`oldState`,`newState`]),Et=I([...L,`elapsedTime`,`propertyName`,`pseudoElement`]);function B(e){return Array.from(e).map(e=>({target:P(e.target),identifier:e.identifier,screenX:e.screenX,screenY:e.screenY,clientX:e.clientX,clientY:e.clientY,pageX:e.pageX,pageY:e.pageY}))}function V(e){if(!e)return null;let t=[];if(e.items)for(let n=0;n<e.items.length;n++){let r=e.items[n];t.push({kind:r.kind,type:r.type})}return{drop_effect:e.dropEffect,effect_allowed:e.effectAllowed,items:t,types:Array.from(e.types||[])}}const H={};function U(e,t,n){for(let r of t)e[r]=n}U(H,[`pointerdown`,`pointermove`,`pointerup`,`pointercancel`,`gotpointercapture`,`lostpointercapture`,`pointerenter`,`pointerleave`,`pointerover`,`pointerout`],gt),U(H,[`click`,`contextmenu`,`dblclick`,`mousedown`,`mouseenter`,`mouseleave`,`mousemove`,`mouseout`,`mouseover`,`mouseup`],ft),U(H,[`drag`,`dragend`,`dragenter`,`dragexit`,`dragleave`,`dragover`,`dragstart`,`drop`],ht),U(H,[`keydown`,`keypress`,`keyup`],xt),U(H,[`focus`,`blur`],_t),U(H,[`change`,`input`],bt),U(H,[`invalid`],yt),U(H,[`reset`,`submit`],vt),U(H,[`copy`,`cut`,`paste`],pt),U(H,[`compositionend`,`compositionstart`,`compositionupdate`],mt),U(H,[`touchcancel`,`touchend`,`touchmove`,`touchstart`],St),U(H,[`scroll`],dt),U(H,[`wheel`],Ct),U(H,[`animationstart`,`animationend`,`animationiteration`],wt),U(H,[`transitionend`],Et),U(H,[`toggle`],Tt);function Dt(e){if(e&&typeof e==`object`&&`nativeEvent`in e&&typeof e.isDefaultPrevented==`function`){let t=e;if(typeof t.type!=`string`)return e;let n=H[t.type.toLowerCase()];return n?n(t):ut(t)}return e}function W(e){let t=new Map,n=[],r=[],i=[],a=[],o=0;function s(e,c){if(e==null||typeof e==`string`||typeof e==`boolean`)return e;if(typeof e==`number`){if(Number.isNaN(e))return null;if(!Number.isFinite(e)){let t=e>0?`Infinity`:`-Infinity`,n=c?` in '${c}'`:``;throw Error(`Cannot serialize ${t}${n}. NaN and Infinity are not supported because they cannot be serialized to JSON.`)}return e}let l=o++,u=t.get(e);if(u!==void 0)return n.push(l),u;if(t.set(e,l),e instanceof Date)return r.push(l),e.getTime();if(Array.isArray(e)){let t=e.length,n=Array(t);for(let r=0;r<t;r++)n[r]=s(e[r],c);return n}if(e instanceof Map){a.push(l);let t={};for(let[n,r]of e.entries())t[String(n)]=s(r,String(n));return t}if(e instanceof Set){i.push(l);let t=e.size,n=Array(t),r=0;for(let t of e)n[r]=s(t,c),r+=1;return n}if(typeof e==`object`){let t={},n=Object.keys(e);for(let r=0;r<n.length;r++){let i=n[r];t[i]=s(e[i],i)}return t}throw Error(`Unsupported value in serialization: ${e}`)}let c=s(e);return[[n,r,i,a],c]}function G(e,t){let[[n,r,i,a],o]=e,s=new Set(n),c=new Set(r),l=new Set(i),u=new Set(a),d=[];function f(e){let n=d.length;if(s.has(n))return d.push(null),d[e];if(c.has(n)){let t=new Date(e);return d.push(t),t}if(e==null||typeof e==`number`||typeof e==`string`||typeof e==`boolean`)return t?.coerceNullsToUndefined?e??void 0:e;if(Array.isArray(e)){if(l.has(n)){let t=new Set;d.push(t);for(let n=0;n<e.length;n++)t.add(f(e[n]));return t}let t=e.length,r=Array(t);d.push(r);for(let n=0;n<t;n++)r[n]=f(e[n]);return r}if(typeof e==`object`){if(u.has(n)){let t=new Map;d.push(t);let n=Object.keys(e);for(let r=0;r<n.length;r++){let i=n[r];t.set(i,f(e[i]))}return t}let t={};d.push(t);let r=Object.keys(e);for(let n=0;n<r.length;n++){let i=r[n];t[i]=f(e[i])}return t}throw Error(`Unsupported value in deserialization: ${e}`)}return f(o)}var Ot=class{#e;#t=null;#n;#r=new Set;#i=new Map;#a;#o;#s;#c;#l=!1;#u=null;#d=null;#f=`ok`;constructor(e,t,n,r){this.#a=e,this.#s=t,this.#o=n,this.#t=null,this.#e=new Map,this.#n=[],this.#c=r}setDirectives(e){this.#s=e}isConnected(){return this.#t?.connected??!1}#p(){this.#u&&=(clearTimeout(this.#u),null),this.#d&&=(clearTimeout(this.#d),null)}#m(e){this.#p(),this.#f=e,this.#v(e)}#h(){this.#l=!0,this.#m(`ok`)}#g(){this.#m(`ok`),this.#u=setTimeout(()=>{this.#m(`connecting`),this.#d=setTimeout(()=>{this.#m(`error`)},this.#c.initialErrorDelay)},this.#c.initialConnectingDelay)}#_(){this.#m(`reconnecting`),this.#d=setTimeout(()=>{this.#m(`error`)},this.#c.reconnectErrorDelay)}async connect(){if(!this.#t)return this.#l||this.#g(),new Promise((e,t)=>{let n=h(this.#a,{transports:[`websocket`,`webtransport`],auth:this.#s.socketio?.auth,extraHeaders:this.#s.socketio?.headers});this.#t=n,n.on(`connect`,()=>{console.log(`[SocketIOTransport] Connected:`,this.#t?.id);for(let[e,t]of this.#e)n.emit(`message`,W({type:`attach`,path:e,routeInfo:t.routeInfo}));for(let e of this.#n)e.type===`attach`&&this.#e.has(e.path)||e.type!==`update`&&n.emit(`message`,W(e));this.#n=[],this.#h(),e()}),n.on(`connect_error`,e=>{console.error(`[SocketIOTransport] Connection failed:`,e),this.#_(),t(e)}),n.on(`disconnect`,()=>{console.log(`[SocketIOTransport] Disconnected`),this.#T(),this.#_()}),n.on(`message`,e=>this.#y(G(e,{coerceNullsToUndefined:!0})))})}onConnectionChange(e){return this.#r.add(e),e(this.#f),()=>{this.#r.delete(e)}}#v(e){for(let t of this.#r)t(e)}sendMessage(e){this.isConnected()?this.#t.emit(`message`,W(e)):this.#n.push(e)}attach(e,t){if(this.#e.has(e))throw Error(`Path ${e} is already attached`);this.#e.set(e,t),this.sendMessage({type:`attach`,path:e,routeInfo:t.routeInfo})}updateRoute(e,t){let n=this.#e.get(e);n&&(n.routeInfo=t,this.sendMessage({type:`update`,path:e,routeInfo:t}))}detach(e){this.sendMessage({type:`detach`,path:e}),this.#e.delete(e)}disconnect(){this.#p(),this.#t?.disconnect(),this.#t=null,this.#n=[],this.#r.clear(),this.#e.clear();for(let{bridge:e}of this.#i.values())e.dispose(new $(`Client disconnected`));this.#i.clear(),this.#f=`ok`,this.#l=!1}#y(e){switch(e.type){case`vdom_init`:{let t=this.#e.get(e.path);if(!t)return;t.onInit(e);break}case`vdom_update`:{let t=this.#e.get(e.path);if(!t)return;t.onUpdate(e.ops);break}case`server_error`:{let t=this.#e.get(e.path);if(!t)return;t.onServerError(e.error);break}case`api_call`:this.#b(e);break;case`navigate_to`:{let t=!!e.replace,n=e.path||``;n.startsWith(`//`)&&(n=`${window.location.protocol}${n}`);let r=()=>t?window.location.replace(n):window.location.assign(n);if(e.hard){r();break}if(!/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(n)){this.#o(n,{replace:t});break}if(/^https?:\/\//.test(n))try{let e=new URL(n);if(e.origin===window.location.origin){this.#o(`${e.pathname}${e.search}${e.hash}`,{replace:t});break}}catch{}r();break}case`channel_message`:this.#w(e);break;case`js_exec`:this.#x(e);break;default:console.error(`Unexpected message:`,e)}}async#b(e){try{let t=await fetch(e.url,{method:e.method||`GET`,headers:{...e.headers||{},...e.body!=null&&!(`content-type`in(e.headers||{}))?{"content-type":`application/json`}:{}},body:e.body==null?void 0:typeof e.body==`string`?e.body:JSON.stringify(e.body),credentials:e.credentials||`include`}),n={};t.headers.forEach((e,t)=>{n[t]=e});let r=null;r=(t.headers.get(`content-type`)||``).includes(`application/json`)?await t.json().catch(()=>null):await t.text().catch(()=>null);let i={type:`api_result`,id:e.id,ok:t.ok,status:t.status,headers:n,body:r};this.sendMessage(i)}catch(t){let n={type:`api_result`,id:e.id,ok:!1,status:0,headers:{},body:{error:String(t)}};this.sendMessage(n)}}invokeCallback(e,t,n){this.sendMessage({type:`callback`,path:e,callback:t,args:n.map(Dt)})}#x(e){let t=this.#e.get(e.path);if(!t){this.#S(e.id,void 0,null);return}t.onJsExec(e)}sendJsResult(e,t,n){this.#S(e,t,n)}#S(e,t,n){let r={type:`js_result`,id:e,result:t,error:n};this.sendMessage(r)}acquireChannel(e){let t=this.#C(e);return t.refCount+=1,t.bridge}releaseChannel(e){let t=this.#i.get(e);t&&(t.refCount=Math.max(0,t.refCount-1),t.refCount===0&&(t.bridge.dispose(new $(`Channel released`)),this.sendMessage({type:`channel_message`,channel:e,event:`__close__`,payload:{reason:`refcount_zero`}}),this.#i.delete(e)))}#C(e){let t=this.#i.get(e);return t||(t={bridge:new zt(this,e),refCount:0},this.#i.set(e,t)),t}#w(e){let t=this.#C(e.channel);t.bridge.handleServerMessage(e)&&t.refCount===0&&this.#i.delete(e.channel)}#T(){for(let e of this.#i.values())e.bridge.handleDisconnect(new $(`Connection lost`))}};function K(e){return typeof e==`object`&&!!e&&`tag`in e}function q(e){return typeof e==`object`&&!!e&&`t`in e}function kt(e){return K(e)&&e.tag.startsWith(`$$`)&&e.tag!==``}function At(e){return e===`$cb`}var J=class{#e;#t;#n;#r;#i;constructor(e,t,n={}){this.#e=e,this.#t=t,this.#n=n,this.#r=new Map,this.#i=new WeakMap}getObject(e){let t=this.#n[e];if(t===void 0)throw Error(`[Pulse] Unknown registry key: ${e}`);return t}#a(e){let t=globalThis[e];if(t===void 0)throw Error(`[Pulse] Unknown identifier in expr: ${e}`);return t}#o(e,t){if(typeof e!=`object`||!e)return e;if(`tag`in e)return this.renderNode(e,``);switch(e.t){case`ref`:return this.getObject(e.key);case`id`:return Object.hasOwn(t,e.name)?t[e.name]:this.#a(e.name);case`lit`:return e.value;case`undef`:return;case`array`:{let n=[];for(let r of e.items)n.push(this.#o(r,t));return n}case`object`:{let n={};for(let[r,i]of Object.entries(e.props))n[r]=this.#o(i,t);return n}case`member`:return this.#o(e.obj,t)?.[e.prop];case`sub`:{let n=this.#o(e.obj,t),r=this.#o(e.key,t);return n?.[r]}case`call`:{let n=this.#o(e.callee,t),r=e.args.map(e=>this.#o(e,t));if(typeof n!=`function`)throw Error(`[Pulse] call callee is not a function`);return n(...r)}case`unary`:{let n=this.#o(e.arg,t);switch(e.op){case`!`:return!n;case`+`:return+n;case`-`:return-n;case`typeof`:return typeof n;case`void`:return;default:throw Error(`[Pulse] Unsupported unary op: ${e.op}`)}}case`binary`:{let n=this.#o(e.left,t),r=this.#o(e.right,t);switch(e.op){case`+`:return n+r;case`-`:return n-r;case`*`:return n*r;case`/`:return n/r;case`%`:return n%r;case`&&`:return n&&r;case`||`:return n||r;case`??`:return n??r;case`**`:return n**r;case`in`:return n in r;case`instanceof`:return n instanceof r;case`===`:return n===r;case`!==`:return n!==r;case`<`:return n<r;case`<=`:return n<=r;case`>`:return n>r;case`>=`:return n>=r;default:throw Error(`[Pulse] Unsupported binary op: ${e.op}`)}}case`ternary`:return this.#o(e.cond,t)?this.#o(e.then,t):this.#o(e.else_,t);case`template`:{let n=``;for(let r of e.parts)typeof r==`string`?n+=r:n+=String(this.#o(r,t));return n}case`arrow`:{let n=e.params;return(...r)=>{let i={...t};for(let e=0;e<n.length;e+=1)i[n[e]]=r[e];return this.#o(e.body,i)}}case`new`:return new(this.#o(e.ctor,t))(...e.args.map(e=>this.#o(e,t)));default:throw Error(`[Pulse] Unknown expr node: ${e.t}`)}}#s(e,t){return e?`${e}.${t}`:t}#c(e,t){let n=this.#s(e,t),r=this.#r.get(n);return r||(r=(...e)=>this.#e.invokeCallback(this.#t,n,e),this.#r.set(n,r)),r}#l(e,t,n){return At(n)?this.#c(e,t):q(n)?this.#o(n,{}):typeof n==`object`&&n&&`tag`in n?this.renderNode(n,this.#s(e,t)):n}#u(e,t){return this.#i.set(e,t),e}renderNode(t,n=``){if(t==null||typeof t==`boolean`||typeof t==`number`||typeof t==`string`)return t;if(q(t))return this.#o(t,{});if(K(t)){let{tag:i,props:a={},children:o=[],eval:s}=t,c,l={},u;if(s){u=new Set(s);for(let[e,t]of Object.entries(a)){if(!u.has(e)){l[e]=t;continue}t===`$cb`&&(c||=new Set,c.add(e)),l[e]=this.#l(n,e,t)}}else for(let[e,t]of Object.entries(a))l[e]=t;t.key&&(l.key=t.key);let d=[];for(let e=0;e<o.length;e+=1){let t=o[e],r=n?`${n}.${e}`:String(e);d.push(this.renderNode(t,r))}if(kt(t)){let e=i.slice(2),t=this.#n[e];if(!t)throw Error(`[Pulse] Missing component for mount point: ${e}`);return this.#u(r(t,l,...d),{eval:u,cbKeys:c})}return this.#u(r(i===``?e:i,l,...d),{eval:u,cbKeys:c})}return process.env.NODE_ENV!==`production`&&console.error(`Unknown VDOM node:`,t),null}init(e){return this.renderNode(e.vdom)}evaluateExpr(e){return this.#o(e,{})}#d(e){let t=e.props?.children;return t==null?[]:Array.isArray(t)?t.slice():[t]}#f(e,t){let n=this.#i.get(e);return n&&this.#i.set(t,n),t}#p(e,n){if(!a(e))return e;let r=e,i=r.props??{},o={...i},s=this.#i.get(r)?.cbKeys;if(s&&s.size>0)for(let e of s)o[e]=this.#c(n,e);for(let e of Object.keys(i)){let t=i[e];a(t)&&(o[e]=this.#p(t,this.#s(n,e)))}let c=this.#d(r).map((e,t)=>{let r=n?`${n}.${t}`:String(t);return this.#p(e,r)});return this.#f(r,t(r,o,...c))}applyUpdates(e,n){let i=e;for(let e of n){let n=e.path.split(`.`).filter(e=>e.length>0),a=(i,o,s)=>{if(o<n.length){this.#m(i,n,o);let e=i,r=n[o],c=+r,l=s?`${s}.${r}`:r;if(Number.isNaN(c)){let n=e.props??{},i=n[r],s={...n,[r]:a(i,o+1,l)};return this.#f(e,t(e,s))}else{let n=this.#d(e),r=n[c];return n[c]=a(r,o+1,l),this.#f(e,t(e,void 0,...n))}}switch(e.type){case`replace`:return this.renderNode(e.data,e.path);case`update_props`:{this.#m(i,n,o);let a=i,c={...a.props??{}},l=this.#i.get(a),u=l?.eval,d=l?.cbKeys,f=e.data.eval,p=f===void 0?u:f.length===0?void 0:new Set(f),m=f!==void 0&&f.length===0,h;if(p){let e=new Set;if(d)for(let t of d)p.has(t)&&e.add(t);h=e}if(m&&d)for(let e of d)delete c[e];if(e.data.remove&&e.data.remove.length>0)for(let t of e.data.remove)delete c[t],h?.delete(t);if(e.data.set)for(let[t,n]of Object.entries(e.data.set)){let e=p?.has(t)===!0;c[t]=e?this.#l(s,t,n):n,h&&(e&&n===`$cb`?h.add(t):h.delete(t))}return h&&h.size===0&&(h=void 0),(e.data.remove?.length??0)>0?(c.key=a.key,c.ref=a.ref,this.#u(r(a.type,c,...this.#d(a)),{eval:p,cbKeys:h})):this.#u(t(a,c),{eval:p,cbKeys:h})}case`reconciliation`:{this.#m(i,n,o);let r=i,a=this.#d(r),c=[],[l,u]=e.new,[d,f]=e.reuse,p=-1,m=-1,h=-1,g=-1;l.length>0&&(p=l[0],h=0),d.length>0&&(m=d[0],g=0);for(let t=0;t<e.N;t+=1)if(t===p){let e=u[h],n=s?`${s}.${t}`:String(t);c.push(this.renderNode(e,n)),p=h<l.length-1?l[++h]:-1}else if(t===m){let e=a[f[g]],n=s?`${s}.${t}`:String(t);e=this.#p(e,n),c.push(e),m=g<d.length-1?d[++g]:-1}else c.push(a[t]);return this.#f(r,t(r,null,...c))}default:throw Error(`[Pulse renderer] Unknown update type: ${e?.type}`)}};i=a(i,0,``)}return i}#m(e,t,n){if(process.env.NODE_ENV!==`production`&&!a(e))throw console.error(`Invalid node:`,e),Error(`Invalid node at path ${t.slice(0,n).join(`.`)}`);return!0}};const Y=n(null),X=n(null),Z=()=>{let e=s(Y);if(!e)throw Error(`usePulseClient must be used within a PulseProvider`);return e},jt=e=>{let t=s(X);if(!t)throw Error(`usePulsePrerender must be used within a PulseProvider`);let n=t.views[e];if(!n)throw Error(`No prerender found for '${e}'`);return n},Q=typeof window<`u`;function Mt({children:e,config:t,prerender:n}){let[r,i]=d(`ok`),a=p(),{directives:o}=n,s=l(()=>new Ot(t.serverAddress,o,a,t.connectionStatus),[t.serverAddress,a,t.connectionStatus]);c(()=>s.setDirectives(o),[s,o]),c(()=>{if(!Q)return;let e=s.onConnectionChange(e=>{i(e)});return s.connect(),()=>{e(),s.disconnect()}},[s]);let u=(()=>{switch(r){case`connecting`:return`Connecting...`;case`reconnecting`:return`Reconnecting...`;case`error`:return`Failed to connect to the server.`;default:return null}})();return g(Y.Provider,{value:s,children:_(X.Provider,{value:n,children:[u&&g(`div`,{style:{position:`fixed`,bottom:`20px`,right:`20px`,backgroundColor:r===`error`?`red`:`#666`,color:`white`,padding:`10px`,borderRadius:`5px`,zIndex:1e3},children:u}),e]})})}function Nt({path:e,registry:t}){let n=Z(),r=jt(e),i=l(()=>new J(n,e,t),[n,e,t]),[a,o]=d(()=>i.init(r)),[s,p]=d(null),h=f(),_=m(),v=l(()=>{let{"*":e=``,...t}=_,n=new URLSearchParams(h.search);return{hash:h.hash,pathname:h.pathname,query:h.search,queryParams:Object.fromEntries(n.entries()),pathParams:t,catchall:e.length>0?e.split(`/`):[]}},[h.hash,h.pathname,h.search,JSON.stringify(_)]);c(()=>{if(Q)return n.attach(e,{routeInfo:v,onInit:e=>{o(i.init(e)),p(null)},onUpdate:e=>{o(t=>t==null?t:i.applyUpdates(t,e)),p(null)},onJsExec:e=>{let t,r=null;try{t=i.evaluateExpr(e.expr)}catch(e){r=e instanceof Error?e.message:String(e)}n.sendJsResult(e.id,t,r)},onServerError:p}),()=>{n.detach(e)}},[n,i,e]),c(()=>{Q&&n.updateRoute(e,v)},[n,e,v]);let y=u(!1);return c(()=>(y.current?o(i.init(r)):y.current=!0,()=>{y.current=!1}),[r,i]),s?g(Pt,{error:s}):a}function Pt({error:e}){return _(`div`,{style:{padding:16,border:`1px solid #e00`,background:`#fff5f5`,color:`#900`,fontFamily:`ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace`,whiteSpace:`pre-wrap`},children:[_(`div`,{style:{fontWeight:700,marginBottom:8},children:[`Server Error during `,e.phase]}),e.message&&g(`div`,{children:e.message}),e.stack&&_(`details`,{open:!0,style:{marginTop:8},children:[g(`summary`,{children:`Stack trace`}),g(`pre`,{style:{margin:0},children:e.stack})]})]})}var $=class extends Error{constructor(e){super(e),this.name=`PulseChannelResetError`}};function Ft(){return typeof crypto<`u`&&typeof crypto.randomUUID==`function`?crypto.randomUUID().replace(/-/g,``):Math.random().toString(16).slice(2)+Math.random().toString(16).slice(2)}function It(e){if(e instanceof Error)return e.message;if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return String(e)}}function Lt(e){return typeof e.responseTo==`string`}function Rt(e){return typeof e.event==`string`}var zt=class{handlers=new Map;pending=new Map;backlog=[];closed=!1;constructor(e,t){this.client=e,this.id=t}emit(e,t){this.ensureOpen(),this.client.sendMessage({type:`channel_message`,channel:this.id,event:e,payload:t})}request(e,t){this.ensureOpen();let n=Ft();return new Promise((r,i)=>{this.pending.set(n,{resolve:r,reject:i}),this.client.sendMessage({type:`channel_message`,channel:this.id,event:e,payload:t,requestId:n})})}on(e,t){this.ensureOpen();let n=this.handlers.get(e);return n||(n=new Set,this.handlers.set(e,n)),n.add(t),this.flushBacklog(e),()=>{let n=this.handlers.get(e);n&&(n.delete(t),n.size===0&&this.handlers.delete(e))}}handleServerMessage(e){return Lt(e)?(this.resolvePending(e),this.closed):this.closed?!0:Rt(e)?e.event===`__close__`?(this.close(new $(`Channel closed by server`)),!0):(e.requestId?this.dispatchRequest(e):this.dispatchEvent(e),this.closed):this.closed}handleDisconnect(e){this.close(e)}dispose(e){this.close(e)}ensureOpen(){if(this.closed)throw new $(`Channel is closed`)}flushBacklog(e){if(this.backlog.length===0)return;let t=[];for(let n of this.backlog)n.event===e?this.dispatchEvent(n):t.push(n);this.backlog=t}dispatchEvent(e){let t=this.handlers.get(e.event);if(!t||t.size===0){this.backlog.push(e);return}for(let n of t)try{let t=n(e.payload);t&&typeof t.then==`function`&&t.catch(e=>{console.error(`Pulse channel handler error`,e)})}catch(e){console.error(`Pulse channel handler error`,e)}}async dispatchRequest(e){let t=this.handlers.get(e.event),n,r;if(t&&t.size>0)for(let i of t)try{let t=i(e.payload);if(n=await Promise.resolve(t),n!==void 0)break}catch(e){r=e;break}if(r){this.client.sendMessage({type:`channel_message`,channel:this.id,event:void 0,responseTo:e.requestId,error:It(r)});return}this.client.sendMessage({type:`channel_message`,channel:this.id,event:void 0,responseTo:e.requestId,payload:n})}resolvePending(e){let t=e.responseTo?this.pending.get(e.responseTo):void 0;t&&(this.pending.delete(e.responseTo),e.error!==void 0&&e.error!==null?t.reject(new $(String(e.error))):t.resolve(e.payload))}close(e){if(!this.closed){this.closed=!0;for(let t of this.pending.values())t.reject(e);this.pending.clear(),this.handlers.clear(),this.backlog=[]}}};function Bt(e){let t=Z(),n=l(()=>{if(!e)throw Error(`usePulseChannel requires a non-empty channelId`);return t.acquireChannel(e)},[t,e]);return c(()=>()=>{t.releaseChannel(e)},[t,e]),n}const Vt=i(function({onSubmit:e,action:t,...n},r){return g(`form`,{...n,action:t,ref:r,onSubmit:o(n=>Ht({event:n,action:t,onSubmit:e}),[t,e])})});async function Ht({event:e,action:t,onSubmit:n,formData:r,force:i}){if(n?.(e),!i&&e.defaultPrevented)return;let a=e.currentTarget;e.preventDefault();let o=e.nativeEvent;r||=new FormData(a,o.submitter);let s=new URL(t,window.location.href);try{await fetch(s,{method:`POST`,credentials:`include`,body:r})}catch(e){if(process.env.NODE_ENV!==`production`)console.error(`[Pulse] Form submission failed`,e);else throw e}}function Ut({params:e,request:t}){let{"*":n=``,...r}=e,i=new URL(t.url);return{hash:i.hash,pathname:i.pathname,query:i.search,queryParams:Object.fromEntries(i.searchParams.entries()),pathParams:r,catchall:n.length>1?n.split(`/`):[]}}export{$ as PulseChannelResetError,Vt as PulseForm,Mt as PulseProvider,Nt as PulseView,J as VDOMRenderer,G as deserialize,Ut as extractServerRouteInfo,W as serialize,Ht as submitForm,Bt as usePulseChannel,Z as usePulseClient};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|