@firtoz/socka 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +191 -40
- package/dist/{SockaWebSocketSession-Bru8yFcK.d.ts → SockaWebSocketSession-Cza7Fti-.d.ts} +87 -5
- package/dist/bun/index.d.ts +28 -3
- package/dist/bun/index.js +28 -5
- package/dist/bun/index.js.map +1 -1
- package/dist/{chunk-MZCQHJXY.js → chunk-2FNWVCP3.js} +27 -8
- package/dist/chunk-2FNWVCP3.js.map +1 -0
- package/dist/{chunk-AM7PB26G.js → chunk-H3S3435J.js} +125 -3
- package/dist/chunk-H3S3435J.js.map +1 -0
- package/dist/{chunk-45D4T232.js → chunk-JVLUA3Q5.js} +64 -6
- package/dist/chunk-JVLUA3Q5.js.map +1 -0
- package/dist/chunk-KQO5AVKA.js +8 -0
- package/dist/chunk-KQO5AVKA.js.map +1 -0
- package/dist/client/index.d.ts +59 -3
- package/dist/client/index.js +2 -2
- package/dist/core/index.d.ts +5 -1
- package/dist/core/index.js +1 -1
- package/dist/do/index.d.ts +20 -2
- package/dist/do/index.js +35 -2
- package/dist/do/index.js.map +1 -1
- package/dist/hono/cloudflare-workers.d.ts +2 -2
- package/dist/hono/cloudflare-workers.js +4 -3
- package/dist/hono/cloudflare-workers.js.map +1 -1
- package/dist/hono/index.d.ts +20 -4
- package/dist/hono/index.js +5 -3
- package/dist/hono/index.js.map +1 -1
- package/dist/react/index.d.ts +43 -4
- package/dist/react/index.js +103 -9
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.d.ts +17 -4
- package/dist/server/index.js +24 -4
- package/dist/server/index.js.map +1 -1
- package/dist/{socka-report-error-DzFI2Tr7.d.ts → socka-report-error-ixTynx4w.d.ts} +8 -1
- package/dist/test/index.d.ts +11 -0
- package/dist/test/index.js +84 -0
- package/dist/test/index.js.map +1 -0
- package/docs/README.md +15 -6
- package/docs/auth.md +27 -0
- package/docs/backpressure.md +16 -0
- package/docs/client.md +44 -3
- package/docs/comparison.md +1 -1
- package/docs/durable-objects.md +2 -2
- package/docs/getting-started.md +143 -84
- package/docs/history.md +26 -0
- package/docs/internals.md +56 -0
- package/docs/lifecycle.md +3 -3
- package/docs/multi-room.md +10 -8
- package/docs/peers.md +11 -7
- package/docs/presence.md +43 -0
- package/docs/{events.md → pushes.md} +1 -1
- package/docs/recipes.md +78 -0
- package/docs/reconnection.md +44 -0
- package/docs/reference.md +21 -30
- package/docs/server.md +14 -1
- package/docs/testing.md +20 -0
- package/docs/wire-format.md +25 -0
- package/examples/minimal-socka.ts +56 -3
- package/package.json +14 -10
- package/dist/chunk-45D4T232.js.map +0 -1
- package/dist/chunk-AM7PB26G.js.map +0 -1
- package/dist/chunk-MZCQHJXY.js.map +0 -1
package/dist/client/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SockaContract, a as SockaContractConfig, b as SockaWireFormat, n as SockaServerResponseFrame, l as SockaServerErrorFrame, m as SockaServerEventFrame, I as InferSockaSend, g as InferSockaPushPayload, f as InferSockaPushHandlers, y as SockaReportError } from '../socka-report-error-
|
|
2
|
-
export { x as reportSockaError } from '../socka-report-error-
|
|
1
|
+
import { S as SockaContract, a as SockaContractConfig, b as SockaWireFormat, n as SockaServerResponseFrame, l as SockaServerErrorFrame, m as SockaServerEventFrame, I as InferSockaSend, g as InferSockaPushPayload, f as InferSockaPushHandlers, y as SockaReportError } from '../socka-report-error-ixTynx4w.js';
|
|
2
|
+
export { x as reportSockaError } from '../socka-report-error-ixTynx4w.js';
|
|
3
3
|
import '@standard-schema/spec';
|
|
4
4
|
|
|
5
5
|
interface SockaWebSocketClientOptions<TContract extends SockaContract<SockaContractConfig>> {
|
|
@@ -23,7 +23,41 @@ interface SockaWebSocketClientOptions<TContract extends SockaContract<SockaContr
|
|
|
23
23
|
onServerError?: (frame: SockaServerErrorFrame) => void;
|
|
24
24
|
onEvent?: (frame: SockaServerEventFrame) => void;
|
|
25
25
|
onValidationError?: (error: Error, rawMessage: unknown) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Automatic reconnect after an abnormal close. **Disabled by default** when
|
|
28
|
+
* {@link webSocket} is injected (tests); enabled when using {@link url}.
|
|
29
|
+
* Pass `false` to disable.
|
|
30
|
+
*/
|
|
31
|
+
reconnect?: false | SockaReconnectConfig;
|
|
32
|
+
/** Fired before a reconnect attempt is scheduled (after delay is chosen). */
|
|
33
|
+
onReconnecting?: (info: SockaReconnectingInfo) => void;
|
|
34
|
+
/** Fired after a new socket reaches `open` following a reconnect. */
|
|
35
|
+
onReconnected?: (info: SockaReconnectedInfo) => void;
|
|
26
36
|
}
|
|
37
|
+
/** Options for {@link SockaWebSocketClientOptions.reconnect}. */
|
|
38
|
+
type SockaReconnectConfig = {
|
|
39
|
+
/** Default `1000`. */
|
|
40
|
+
initialDelayMs?: number;
|
|
41
|
+
/** Default `30000`. */
|
|
42
|
+
maxDelayMs?: number;
|
|
43
|
+
/** 0–1 fraction of delay to randomize. Default `0.2`. */
|
|
44
|
+
jitter?: number;
|
|
45
|
+
/** Omit for infinite attempts. */
|
|
46
|
+
maxAttempts?: number;
|
|
47
|
+
/**
|
|
48
|
+
* When `true` (default), delay reconnect until `document` is visible again.
|
|
49
|
+
*/
|
|
50
|
+
pauseWhenHidden?: boolean;
|
|
51
|
+
};
|
|
52
|
+
type SockaReconnectingInfo = {
|
|
53
|
+
attempt: number;
|
|
54
|
+
delayMs: number;
|
|
55
|
+
};
|
|
56
|
+
type SockaReconnectedInfo = {
|
|
57
|
+
attempt: number;
|
|
58
|
+
};
|
|
59
|
+
/** High-level connection lifecycle for UI and telemetry. */
|
|
60
|
+
type SockaConnectionStatus = "idle" | "connecting" | "open" | "reconnecting" | "closed";
|
|
27
61
|
/**
|
|
28
62
|
* Browser WebSocket client driven by a socka contract. Sends client request
|
|
29
63
|
* frames and dispatches decoded server frames to callbacks.
|
|
@@ -39,9 +73,27 @@ declare class SockaWebSocketClient<TContract extends SockaContract<SockaContract
|
|
|
39
73
|
private readonly onEventCb?;
|
|
40
74
|
private readonly onValidationError?;
|
|
41
75
|
readonly contract: TContract;
|
|
76
|
+
private manualClose;
|
|
77
|
+
private reconnectAttempt;
|
|
78
|
+
private reconnectTimer;
|
|
79
|
+
private _status;
|
|
80
|
+
private readonly statusListeners;
|
|
42
81
|
constructor(options: SockaWebSocketClientOptions<TContract>);
|
|
82
|
+
private setStatus;
|
|
83
|
+
/** Current connection lifecycle state. */
|
|
84
|
+
get status(): SockaConnectionStatus;
|
|
85
|
+
/**
|
|
86
|
+
* Subscribe to {@link status} changes. The listener is called immediately with the
|
|
87
|
+
* current status, then on every transition. Returns an unsubscribe function.
|
|
88
|
+
*/
|
|
89
|
+
onStatusChange(listener: (status: SockaConnectionStatus) => void): () => void;
|
|
43
90
|
private createSocket;
|
|
44
91
|
private attachSocket;
|
|
92
|
+
private getReconnectEnabled;
|
|
93
|
+
private resolveReconnectConfig;
|
|
94
|
+
private computeReconnectDelayMs;
|
|
95
|
+
private maybeScheduleReconnect;
|
|
96
|
+
private openReplacementSocket;
|
|
45
97
|
private handleMessageEvent;
|
|
46
98
|
/**
|
|
47
99
|
* Creates the WebSocket (when {@link SockaWebSocketClientOptions.autoConnect}
|
|
@@ -106,6 +158,10 @@ declare class SockaSessionBase<TContract extends SockaContract<SockaContractConf
|
|
|
106
158
|
close(code?: number, reason?: string): void;
|
|
107
159
|
/** Opens the WebSocket when using {@link SockaWebSocketClientOptions.autoConnect} `false`. */
|
|
108
160
|
connect(): Promise<void>;
|
|
161
|
+
/** Same as {@link SockaWebSocketClient.status}. */
|
|
162
|
+
get status(): SockaConnectionStatus;
|
|
163
|
+
/** Same as {@link SockaWebSocketClient.onStatusChange}. */
|
|
164
|
+
onStatusChange(listener: (status: SockaConnectionStatus) => void): () => void;
|
|
109
165
|
}
|
|
110
166
|
interface SockaSessionConstructor {
|
|
111
167
|
new <TContract extends SockaContract<SockaContractConfig>>(options: SockaSessionOptions<TContract>): SockaSession<TContract>;
|
|
@@ -116,4 +172,4 @@ type SockaSession<TContract extends SockaContract<SockaContractConfig>> = SockaS
|
|
|
116
172
|
*/
|
|
117
173
|
declare const SockaSession: SockaSessionConstructor;
|
|
118
174
|
|
|
119
|
-
export { SockaReportError, SockaSession, type SockaSessionConstructor, type SockaSessionOptions, type SockaSessionPushWaitOptions, type SockaSessionSubscribeApi, SockaWebSocketClient, type SockaWebSocketClientOptions };
|
|
175
|
+
export { type SockaConnectionStatus, type SockaReconnectConfig, type SockaReconnectedInfo, type SockaReconnectingInfo, SockaReportError, SockaSession, type SockaSessionConstructor, type SockaSessionOptions, type SockaSessionPushWaitOptions, type SockaSessionSubscribeApi, SockaWebSocketClient, type SockaWebSocketClientOptions };
|
package/dist/client/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { SockaSession, SockaWebSocketClient } from '../chunk-
|
|
1
|
+
export { SockaSession, SockaWebSocketClient } from '../chunk-H3S3435J.js';
|
|
2
2
|
import '../chunk-YMT4HAH7.js';
|
|
3
|
-
export { reportSockaError } from '../chunk-
|
|
3
|
+
export { reportSockaError } from '../chunk-2FNWVCP3.js';
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { D as DecodedSockaWire, e as InferSockaHandlers, f as InferSockaPushHandlers, g as InferSockaPushPayload, I as InferSockaSend, R as RESERVED_SOCKA_PROCEDURE_NAMES, h as ReservedSockaProcedureName, i as SOCKA_WIRE_VERSION, k as SockaClientRequestFrame, S as SockaContract, a as SockaContractConfig, c as SockaProcedureDef, y as SockaReportError, l as SockaServerErrorFrame, m as SockaServerEventFrame, n as SockaServerResponseFrame, j as SockaWireError, b as SockaWireFormat, o as SockaWireFrame, V as ValidateSockaCallKeys, p as decodeSockaWire, w as defaultReportError, d as defineSocka, q as encodeClientRequest, s as encodeServerError, t as encodeServerEvent, r as encodeServerResponse, u as encodeSockaWire, v as parseWirePayload, x as reportSockaError } from '../socka-report-error-
|
|
1
|
+
export { D as DecodedSockaWire, e as InferSockaHandlers, f as InferSockaPushHandlers, g as InferSockaPushPayload, I as InferSockaSend, R as RESERVED_SOCKA_PROCEDURE_NAMES, h as ReservedSockaProcedureName, i as SOCKA_WIRE_VERSION, k as SockaClientRequestFrame, S as SockaContract, a as SockaContractConfig, c as SockaProcedureDef, y as SockaReportError, l as SockaServerErrorFrame, m as SockaServerEventFrame, n as SockaServerResponseFrame, j as SockaWireError, b as SockaWireFormat, o as SockaWireFrame, V as ValidateSockaCallKeys, p as decodeSockaWire, w as defaultReportError, d as defineSocka, q as encodeClientRequest, s as encodeServerError, t as encodeServerEvent, r as encodeServerResponse, u as encodeSockaWire, v as parseWirePayload, x as reportSockaError } from '../socka-report-error-ixTynx4w.js';
|
|
2
2
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -14,15 +14,19 @@ declare function parseStandardSchema<T>(schema: StandardSchemaV1<unknown, T>, va
|
|
|
14
14
|
declare class SockaError extends Error {
|
|
15
15
|
readonly requestId?: string;
|
|
16
16
|
readonly code?: string;
|
|
17
|
+
readonly data?: unknown;
|
|
17
18
|
constructor(message: string, options?: {
|
|
18
19
|
requestId?: string;
|
|
19
20
|
code?: string;
|
|
21
|
+
data?: unknown;
|
|
20
22
|
cause?: unknown;
|
|
21
23
|
});
|
|
22
24
|
/** Builds a {@link SockaError} from a standard RPC error envelope. */
|
|
23
25
|
static fromWire(msg: {
|
|
24
26
|
id: string;
|
|
25
27
|
error: string;
|
|
28
|
+
code?: string;
|
|
29
|
+
data?: unknown;
|
|
26
30
|
}): SockaError;
|
|
27
31
|
}
|
|
28
32
|
|
package/dist/core/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { RESERVED_SOCKA_PROCEDURE_NAMES } from '../chunk-YMT4HAH7.js';
|
|
2
|
-
export { SOCKA_WIRE_VERSION, SockaError, SockaWireError, decodeSockaWire, defaultReportError, encodeClientRequest, encodeServerError, encodeServerEvent, encodeServerResponse, encodeSockaWire, parseStandardSchema, parseWirePayload, reportSockaError } from '../chunk-
|
|
2
|
+
export { SOCKA_WIRE_VERSION, SockaError, SockaWireError, decodeSockaWire, defaultReportError, encodeClientRequest, encodeServerError, encodeServerEvent, encodeServerResponse, encodeSockaWire, parseStandardSchema, parseWirePayload, reportSockaError } from '../chunk-2FNWVCP3.js';
|
|
3
3
|
|
|
4
4
|
// src/core/contract.ts
|
|
5
5
|
function defineSocka(config) {
|
package/dist/do/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Context } from 'hono';
|
|
2
2
|
import { BaseSession, SessionEnv, BaseWebSocketDO } from '@firtoz/websocket-do';
|
|
3
|
-
import { S as SockaContract, a as SockaContractConfig, b as SockaWireFormat, e as InferSockaHandlers, y as SockaReportError, g as InferSockaPushPayload } from '../socka-report-error-
|
|
4
|
-
import {
|
|
3
|
+
import { S as SockaContract, a as SockaContractConfig, b as SockaWireFormat, e as InferSockaHandlers, y as SockaReportError, g as InferSockaPushPayload } from '../socka-report-error-ixTynx4w.js';
|
|
4
|
+
import { d as SockaPushSession } from '../SockaWebSocketSession-Cza7Fti-.js';
|
|
5
5
|
import '@standard-schema/spec';
|
|
6
6
|
|
|
7
7
|
/** Session data with no fields — `createData` may be omitted (defaults to `{}`). */
|
|
@@ -52,6 +52,24 @@ declare class SockaDoSession<TContract extends SockaContract<SockaContractConfig
|
|
|
52
52
|
emitWireEvent(event: string, body: unknown): void;
|
|
53
53
|
emitPush<K extends keyof TContract["pushes"] & string>(name: K, body: InferSockaPushPayload<TContract, K>): Promise<void>;
|
|
54
54
|
broadcastPush<K extends keyof TContract["pushes"] & string>(name: K, body: InferSockaPushPayload<TContract, K>, excludeSelf?: boolean): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* {@link SockaWebSocketSession.listPeers} for this Durable Object room.
|
|
57
|
+
*/
|
|
58
|
+
listPeers(options?: {
|
|
59
|
+
excludeSelf?: boolean;
|
|
60
|
+
}): TData[];
|
|
61
|
+
/**
|
|
62
|
+
* Like {@link listPeers} but maps each peer {@link SockaDoSession}.
|
|
63
|
+
*/
|
|
64
|
+
listPeersWith<R>(map: (session: SockaDoSession<TContract, TData, TEnv>) => R, options?: {
|
|
65
|
+
excludeSelf?: boolean;
|
|
66
|
+
}): R[];
|
|
67
|
+
peerCount(options?: {
|
|
68
|
+
excludeSelf?: boolean;
|
|
69
|
+
}): number;
|
|
70
|
+
hasPeers(options?: {
|
|
71
|
+
excludeSelf?: boolean;
|
|
72
|
+
}): boolean;
|
|
55
73
|
}
|
|
56
74
|
|
|
57
75
|
type SockaWebSocketDOOptions<TEnv extends object, TSession extends SockaDoSession<any, any, TEnv>> = {
|
package/dist/do/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { SockaWebSocketSession } from '../chunk-
|
|
2
|
-
import { reportSockaError } from '../chunk-
|
|
1
|
+
import { SockaWebSocketSession } from '../chunk-JVLUA3Q5.js';
|
|
2
|
+
import { reportSockaError } from '../chunk-2FNWVCP3.js';
|
|
3
3
|
import { BaseSession, BaseWebSocketDO } from '@firtoz/websocket-do';
|
|
4
4
|
|
|
5
5
|
function runSockaDoSessionOnAttached(config, session) {
|
|
@@ -91,6 +91,39 @@ var SockaDoSession = class extends BaseSession {
|
|
|
91
91
|
broadcastPush(name, body, excludeSelf = false) {
|
|
92
92
|
return this.socka.broadcastPush(name, body, excludeSelf);
|
|
93
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* {@link SockaWebSocketSession.listPeers} for this Durable Object room.
|
|
96
|
+
*/
|
|
97
|
+
listPeers(options) {
|
|
98
|
+
const out = [];
|
|
99
|
+
for (const [ws, s] of this.sessions) {
|
|
100
|
+
if (options?.excludeSelf && ws === this.websocket) continue;
|
|
101
|
+
out.push(s.data);
|
|
102
|
+
}
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Like {@link listPeers} but maps each peer {@link SockaDoSession}.
|
|
107
|
+
*/
|
|
108
|
+
listPeersWith(map, options) {
|
|
109
|
+
const out = [];
|
|
110
|
+
for (const [ws, s] of this.sessions) {
|
|
111
|
+
if (options?.excludeSelf && ws === this.websocket) continue;
|
|
112
|
+
out.push(map(s));
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
peerCount(options) {
|
|
117
|
+
let n = 0;
|
|
118
|
+
for (const [ws] of this.sessions) {
|
|
119
|
+
if (options?.excludeSelf && ws === this.websocket) continue;
|
|
120
|
+
n += 1;
|
|
121
|
+
}
|
|
122
|
+
return n;
|
|
123
|
+
}
|
|
124
|
+
hasPeers(options) {
|
|
125
|
+
return this.peerCount(options) > 0;
|
|
126
|
+
}
|
|
94
127
|
};
|
|
95
128
|
var SockaWebSocketDO = class extends BaseWebSocketDO {
|
|
96
129
|
constructor(ctx, env, options) {
|
package/dist/do/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/do/SockaDoSession.ts","../../src/do/SockaWebSocketDO.ts","../../src/do/dispatch.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { Context } from \"hono\";\nimport { BaseSession } from \"@firtoz/websocket-do\";\nimport type {\n\tInferSockaPushPayload,\n\tSockaContract,\n\tSockaContractConfig,\n\tInferSockaHandlers,\n} from \"../core/contract\";\nimport {\n\tSockaWebSocketSession,\n\ttype SockaPushSession,\n\ttype SockaWebSocketSessionConfig,\n} from \"../server/SockaWebSocketSession\";\nimport { reportSockaError } from \"../core/socka-report-error\";\nimport type { SockaReportError } from \"../core/socka-report-error\";\nimport type { SockaWireFormat } from \"../core/wire-codec\";\n\n/** Session data with no fields — `createData` may be omitted (defaults to `{}`). */\ntype EmptySockaSessionData = Record<string, never>;\n\ntype SockaDoOuterSession<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTEnv extends object,\n> = import(\"./SockaDoSession\").SockaDoSession<TContract, TData, TEnv>;\n\ntype SockaDoSessionCreateData<TData, TEnv extends object> = [TData] extends [\n\tEmptySockaSessionData,\n]\n\t? {\n\t\t\tcreateData?: (ctx: Context<{ Bindings: TEnv }>) => TData;\n\t\t}\n\t: {\n\t\t\tcreateData: (ctx: Context<{ Bindings: TEnv }>) => TData;\n\t\t};\n\nexport type SockaDoSessionConfig<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTEnv extends object,\n> = {\n\tcontract: TContract;\n\t/** Default `\"json\"`. Use `\"msgpack\"` for binary frames (must match client). */\n\twireFormat?: SockaWireFormat;\n\thandlers: InferSockaHandlers<\n\t\tTContract,\n\t\tSockaDoOuterSession<TContract, TData, TEnv>\n\t>;\n\thandleClose: (\n\t\tsession: SockaDoOuterSession<TContract, TData, TEnv>,\n\t) => Promise<void>;\n\tonHandlerError?: (\n\t\terror: unknown,\n\t\trpcName: string,\n\t\tinput: unknown,\n\t\tsession: SockaDoOuterSession<TContract, TData, TEnv>,\n\t) => void;\n\tonValidationError?: (\n\t\terror: unknown,\n\t\toriginalMessage: unknown,\n\t) => Promise<void>;\n\t/**\n\t * Optional sink for non-RPC failures (e.g. `onAttached`). Defaults to\n\t * `console.error`; see `SockaReportError` in `@firtoz/socka/core`.\n\t */\n\treportError?: (event: SockaReportError) => void;\n\t/**\n\t * Called after this session is registered in the DO `sessions` map (next\n\t * microtask). Use for join broadcasts and other logic that must run only\n\t * when peers can see this connection.\n\t */\n\tonAttached?: (\n\t\tsession: SockaDoOuterSession<TContract, TData, TEnv>,\n\t) => void | Promise<void>;\n\tserializeJson?: (value: unknown) => string;\n\tdeserializeJson?: (raw: string) => unknown;\n} & SockaDoSessionCreateData<TData, TEnv>;\n\nfunction runSockaDoSessionOnAttached<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTEnv extends object,\n>(\n\tconfig: SockaDoSessionConfig<TContract, TData, TEnv>,\n\tsession: SockaDoSession<TContract, TData, TEnv>,\n): void {\n\tconst cb = config.onAttached;\n\tif (!cb) return;\n\ttry {\n\t\tconst result = cb(session);\n\t\tvoid Promise.resolve(result).catch((error: unknown) => {\n\t\t\treportSockaError(config.reportError, {\n\t\t\t\tkind: \"serverOnAttached\",\n\t\t\t\terror,\n\t\t\t});\n\t\t});\n\t} catch (error) {\n\t\treportSockaError(config.reportError, { kind: \"serverOnAttached\", error });\n\t}\n}\n\nfunction wrapHandlersForInnerSockaEngine<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTEnv extends object,\n>(\n\tcontract: TContract,\n\tuserHandlers: InferSockaHandlers<\n\t\tTContract,\n\t\tSockaDoSession<TContract, TData, TEnv>\n\t>,\n\touter: SockaDoSession<TContract, TData, TEnv>,\n): InferSockaHandlers<\n\tTContract,\n\tSockaWebSocketSession<TContract, EmptySockaSessionData>\n> {\n\tconst calls = contract.calls;\n\tconst out: Record<\n\t\tstring,\n\t\t| ((\n\t\t\t\tinput: unknown,\n\t\t\t\tinner: SockaWebSocketSession<TContract, EmptySockaSessionData>,\n\t\t ) => unknown | Promise<unknown>)\n\t\t| ((\n\t\t\t\tinner: SockaWebSocketSession<TContract, EmptySockaSessionData>,\n\t\t ) => unknown | Promise<unknown>)\n\t> = {};\n\n\tfor (const key of Object.keys(calls) as Array<keyof typeof calls & string>) {\n\t\tconst proc = calls[key];\n\t\tconst userFn = userHandlers[key as keyof typeof userHandlers];\n\t\tif (proc.input) {\n\t\t\tout[key] = (\n\t\t\t\tinput,\n\t\t\t\t_inner: SockaWebSocketSession<TContract, EmptySockaSessionData>,\n\t\t\t) =>\n\t\t\t\t(\n\t\t\t\t\tuserFn as (\n\t\t\t\t\t\ti: unknown,\n\t\t\t\t\t\ts: SockaDoSession<TContract, TData, TEnv>,\n\t\t\t\t\t) => unknown | Promise<unknown>\n\t\t\t\t)(input, outer);\n\t\t} else {\n\t\t\tout[key] = (\n\t\t\t\t_inner: SockaWebSocketSession<TContract, EmptySockaSessionData>,\n\t\t\t) =>\n\t\t\t\t(\n\t\t\t\t\tuserFn as (\n\t\t\t\t\t\ts: SockaDoSession<TContract, TData, TEnv>,\n\t\t\t\t\t) => unknown | Promise<unknown>\n\t\t\t\t)(outer);\n\t\t}\n\t}\n\n\treturn out as InferSockaHandlers<\n\t\tTContract,\n\t\tSockaWebSocketSession<TContract, EmptySockaSessionData>\n\t>;\n}\n\n/**\n * Durable Object WebSocket session driven by a socka contract.\n * Dispatches client requests to typed handler functions, validates\n * input/output via Standard Schema, and auto-sends response/error frames.\n */\nexport class SockaDoSession<\n\t\tTContract extends SockaContract<SockaContractConfig>,\n\t\tTData = EmptySockaSessionData,\n\t\tTEnv extends object = Cloudflare.Env,\n\t>\n\textends BaseSession<TData, unknown, unknown, TEnv>\n\timplements SockaPushSession<TContract>\n{\n\tprivate socka!: SockaWebSocketSession<TContract, EmptySockaSessionData>;\n\n\tconstructor(\n\t\twebsocket: WebSocket,\n\t\tsessions: Map<WebSocket, SockaDoSession<TContract, TData, TEnv>>,\n\t\tconfig: SockaDoSessionConfig<TContract, TData, TEnv>,\n\t) {\n\t\tconst wireFormat = config.wireFormat ?? \"json\";\n\t\tsuper(\n\t\t\twebsocket,\n\t\t\tsessions as Map<WebSocket, BaseSession<TData, unknown, unknown, TEnv>>,\n\t\t\t{\n\t\t\t\tcreateData:\n\t\t\t\t\tconfig.createData ??\n\t\t\t\t\t((_ctx: Context<{ Bindings: TEnv }>) => ({}) as TData),\n\t\t\t\thandleMessage: async () => {\n\t\t\t\t\t// Raw message handling goes through handleRawMessage / handleBufferMessage\n\t\t\t\t},\n\t\t\t\thandleBufferMessage: async (message) => {\n\t\t\t\t\tawait this.socka.handleBinaryMessage(message);\n\t\t\t\t},\n\t\t\t\thandleClose: async (baseSession) => {\n\t\t\t\t\tawait config.handleClose(\n\t\t\t\t\t\tbaseSession as SockaDoSession<TContract, TData, TEnv>,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t\tconst sockaConfig: SockaWebSocketSessionConfig<\n\t\t\tTContract,\n\t\t\tEmptySockaSessionData\n\t\t> = {\n\t\t\tcontract: config.contract,\n\t\t\twireFormat,\n\t\t\thandlers: wrapHandlersForInnerSockaEngine(\n\t\t\t\tconfig.contract,\n\t\t\t\tconfig.handlers,\n\t\t\t\tthis,\n\t\t\t),\n\t\t\thandleClose: async () => {\n\t\t\t\t// Outer DO lifecycle uses SockaDoSessionConfig.handleClose; inner engine no-op.\n\t\t\t},\n\t\t\tonHandlerError: config.onHandlerError\n\t\t\t\t? (err, rpcName, input, _inner) => {\n\t\t\t\t\t\tconfig.onHandlerError?.(err, rpcName, input, this);\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tonValidationError: config.onValidationError,\n\t\t\tserializeJson: config.serializeJson,\n\t\t\tdeserializeJson: config.deserializeJson,\n\t\t};\n\t\tthis.socka = new SockaWebSocketSession(\n\t\t\twebsocket,\n\t\t\tsessions as unknown as Map<\n\t\t\t\tWebSocket,\n\t\t\t\tSockaWebSocketSession<TContract, EmptySockaSessionData>\n\t\t\t>,\n\t\t\tsockaConfig,\n\t\t);\n\t\t// Defer past the outer `await createSession()` continuation so\n\t\t// `BaseSession.startFresh` has run and `session.data` exists (single\n\t\t// `queueMicrotask` runs before that continuation).\n\t\tqueueMicrotask(() => {\n\t\t\tqueueMicrotask(() => {\n\t\t\t\trunSockaDoSessionOnAttached(config, this);\n\t\t\t});\n\t\t});\n\t}\n\n\tpublic async handleRawMessage(rawMessage: string): Promise<void> {\n\t\treturn this.socka.handleRawMessage(rawMessage);\n\t}\n\n\tpublic emitWireEvent(event: string, body: unknown): void {\n\t\tthis.socka.emitWireEvent(event, body);\n\t}\n\n\tpublic emitPush<K extends keyof TContract[\"pushes\"] & string>(\n\t\tname: K,\n\t\tbody: InferSockaPushPayload<TContract, K>,\n\t): Promise<void> {\n\t\treturn this.socka.emitPush(name, body);\n\t}\n\n\tpublic broadcastPush<K extends keyof TContract[\"pushes\"] & string>(\n\t\tname: K,\n\t\tbody: InferSockaPushPayload<TContract, K>,\n\t\texcludeSelf = false,\n\t): Promise<void> {\n\t\treturn this.socka.broadcastPush(name, body, excludeSelf);\n\t}\n}\n","import type { Context } from \"hono\";\nimport type { SessionEnv } from \"@firtoz/websocket-do\";\nimport { BaseWebSocketDO } from \"@firtoz/websocket-do\";\nimport type { SockaContract, SockaContractConfig } from \"../core/contract\";\nimport type { SockaDoSession } from \"./SockaDoSession\";\n\nexport type SockaWebSocketDOOptions<\n\tTEnv extends object,\n\t// `any` contract slot: concrete sessions use `defineSocka` contracts that do\n\t// not assign to `SockaContract<SockaContractConfig>` under strict generics.\n\tTSession extends SockaDoSession<\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany,\n\t\tTEnv\n\t>,\n> = {\n\tcreateSockaSession: (\n\t\tctx: Context<{ Bindings: TEnv }> | undefined,\n\t\twebsocket: WebSocket,\n\t) => TSession | Promise<TSession>;\n};\n\n/**\n * Durable Object base class for WebSocket apps using {@link SockaDoSession}\n * (Standard Schema contract-driven).\n */\nexport abstract class SockaWebSocketDO<\n\tTSession extends SockaDoSession<\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany\n\t> = SockaDoSession<\n\t\tSockaContract<SockaContractConfig>,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany\n\t>,\n\tTEnv extends SessionEnv<TSession> = SessionEnv<TSession>,\n> extends BaseWebSocketDO<TSession, TEnv> {\n\tconstructor(\n\t\tctx: DurableObjectState,\n\t\tenv: TEnv,\n\t\toptions: SockaWebSocketDOOptions<TEnv, TSession>,\n\t) {\n\t\tsuper(ctx, env, {\n\t\t\tcreateSession: (sessionCtx, websocket) =>\n\t\t\t\toptions.createSockaSession(sessionCtx, websocket),\n\t\t});\n\t}\n}\n","/**\n * Shared error reply shape for correlate-by-id RPC when the handler throws.\n * Narrow at the call site to your server message union if needed.\n */\nexport function toErrorReply(\n\tid: string,\n\terror: string,\n): {\n\ttype: \"error\";\n\tid: string;\n\terror: string;\n} {\n\treturn { type: \"error\", id, error };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/do/SockaDoSession.ts","../../src/do/SockaWebSocketDO.ts","../../src/do/dispatch.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { Context } from \"hono\";\nimport { BaseSession } from \"@firtoz/websocket-do\";\nimport type {\n\tInferSockaPushPayload,\n\tSockaContract,\n\tSockaContractConfig,\n\tInferSockaHandlers,\n} from \"../core/contract\";\nimport {\n\tSockaWebSocketSession,\n\ttype SockaPushSession,\n\ttype SockaWebSocketSessionConfig,\n} from \"../server/SockaWebSocketSession\";\nimport { reportSockaError } from \"../core/socka-report-error\";\nimport type { SockaReportError } from \"../core/socka-report-error\";\nimport type { SockaWireFormat } from \"../core/wire-codec\";\n\n/** Session data with no fields — `createData` may be omitted (defaults to `{}`). */\ntype EmptySockaSessionData = Record<string, never>;\n\ntype SockaDoOuterSession<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTEnv extends object,\n> = import(\"./SockaDoSession\").SockaDoSession<TContract, TData, TEnv>;\n\ntype SockaDoSessionCreateData<TData, TEnv extends object> = [TData] extends [\n\tEmptySockaSessionData,\n]\n\t? {\n\t\t\tcreateData?: (ctx: Context<{ Bindings: TEnv }>) => TData;\n\t\t}\n\t: {\n\t\t\tcreateData: (ctx: Context<{ Bindings: TEnv }>) => TData;\n\t\t};\n\nexport type SockaDoSessionConfig<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTEnv extends object,\n> = {\n\tcontract: TContract;\n\t/** Default `\"json\"`. Use `\"msgpack\"` for binary frames (must match client). */\n\twireFormat?: SockaWireFormat;\n\thandlers: InferSockaHandlers<\n\t\tTContract,\n\t\tSockaDoOuterSession<TContract, TData, TEnv>\n\t>;\n\thandleClose: (\n\t\tsession: SockaDoOuterSession<TContract, TData, TEnv>,\n\t) => Promise<void>;\n\tonHandlerError?: (\n\t\terror: unknown,\n\t\trpcName: string,\n\t\tinput: unknown,\n\t\tsession: SockaDoOuterSession<TContract, TData, TEnv>,\n\t) => void;\n\tonValidationError?: (\n\t\terror: unknown,\n\t\toriginalMessage: unknown,\n\t) => Promise<void>;\n\t/**\n\t * Optional sink for non-RPC failures (e.g. `onAttached`). Defaults to\n\t * `console.error`; see `SockaReportError` in `@firtoz/socka/core`.\n\t */\n\treportError?: (event: SockaReportError) => void;\n\t/**\n\t * Called after this session is registered in the DO `sessions` map (next\n\t * microtask). Use for join broadcasts and other logic that must run only\n\t * when peers can see this connection.\n\t */\n\tonAttached?: (\n\t\tsession: SockaDoOuterSession<TContract, TData, TEnv>,\n\t) => void | Promise<void>;\n\tserializeJson?: (value: unknown) => string;\n\tdeserializeJson?: (raw: string) => unknown;\n} & SockaDoSessionCreateData<TData, TEnv>;\n\nfunction runSockaDoSessionOnAttached<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTEnv extends object,\n>(\n\tconfig: SockaDoSessionConfig<TContract, TData, TEnv>,\n\tsession: SockaDoSession<TContract, TData, TEnv>,\n): void {\n\tconst cb = config.onAttached;\n\tif (!cb) return;\n\ttry {\n\t\tconst result = cb(session);\n\t\tvoid Promise.resolve(result).catch((error: unknown) => {\n\t\t\treportSockaError(config.reportError, {\n\t\t\t\tkind: \"serverOnAttached\",\n\t\t\t\terror,\n\t\t\t});\n\t\t});\n\t} catch (error) {\n\t\treportSockaError(config.reportError, { kind: \"serverOnAttached\", error });\n\t}\n}\n\nfunction wrapHandlersForInnerSockaEngine<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTEnv extends object,\n>(\n\tcontract: TContract,\n\tuserHandlers: InferSockaHandlers<\n\t\tTContract,\n\t\tSockaDoSession<TContract, TData, TEnv>\n\t>,\n\touter: SockaDoSession<TContract, TData, TEnv>,\n): InferSockaHandlers<\n\tTContract,\n\tSockaWebSocketSession<TContract, EmptySockaSessionData>\n> {\n\tconst calls = contract.calls;\n\tconst out: Record<\n\t\tstring,\n\t\t| ((\n\t\t\t\tinput: unknown,\n\t\t\t\tinner: SockaWebSocketSession<TContract, EmptySockaSessionData>,\n\t\t ) => unknown | Promise<unknown>)\n\t\t| ((\n\t\t\t\tinner: SockaWebSocketSession<TContract, EmptySockaSessionData>,\n\t\t ) => unknown | Promise<unknown>)\n\t> = {};\n\n\tfor (const key of Object.keys(calls) as Array<keyof typeof calls & string>) {\n\t\tconst proc = calls[key];\n\t\tconst userFn = userHandlers[key as keyof typeof userHandlers];\n\t\tif (proc.input) {\n\t\t\tout[key] = (\n\t\t\t\tinput,\n\t\t\t\t_inner: SockaWebSocketSession<TContract, EmptySockaSessionData>,\n\t\t\t) =>\n\t\t\t\t(\n\t\t\t\t\tuserFn as (\n\t\t\t\t\t\ti: unknown,\n\t\t\t\t\t\ts: SockaDoSession<TContract, TData, TEnv>,\n\t\t\t\t\t) => unknown | Promise<unknown>\n\t\t\t\t)(input, outer);\n\t\t} else {\n\t\t\tout[key] = (\n\t\t\t\t_inner: SockaWebSocketSession<TContract, EmptySockaSessionData>,\n\t\t\t) =>\n\t\t\t\t(\n\t\t\t\t\tuserFn as (\n\t\t\t\t\t\ts: SockaDoSession<TContract, TData, TEnv>,\n\t\t\t\t\t) => unknown | Promise<unknown>\n\t\t\t\t)(outer);\n\t\t}\n\t}\n\n\treturn out as InferSockaHandlers<\n\t\tTContract,\n\t\tSockaWebSocketSession<TContract, EmptySockaSessionData>\n\t>;\n}\n\n/**\n * Durable Object WebSocket session driven by a socka contract.\n * Dispatches client requests to typed handler functions, validates\n * input/output via Standard Schema, and auto-sends response/error frames.\n */\nexport class SockaDoSession<\n\t\tTContract extends SockaContract<SockaContractConfig>,\n\t\tTData = EmptySockaSessionData,\n\t\tTEnv extends object = Cloudflare.Env,\n\t>\n\textends BaseSession<TData, unknown, unknown, TEnv>\n\timplements SockaPushSession<TContract>\n{\n\tprivate socka!: SockaWebSocketSession<TContract, EmptySockaSessionData>;\n\n\tconstructor(\n\t\twebsocket: WebSocket,\n\t\tsessions: Map<WebSocket, SockaDoSession<TContract, TData, TEnv>>,\n\t\tconfig: SockaDoSessionConfig<TContract, TData, TEnv>,\n\t) {\n\t\tconst wireFormat = config.wireFormat ?? \"json\";\n\t\tsuper(\n\t\t\twebsocket,\n\t\t\tsessions as Map<WebSocket, BaseSession<TData, unknown, unknown, TEnv>>,\n\t\t\t{\n\t\t\t\tcreateData:\n\t\t\t\t\tconfig.createData ??\n\t\t\t\t\t((_ctx: Context<{ Bindings: TEnv }>) => ({}) as TData),\n\t\t\t\thandleMessage: async () => {\n\t\t\t\t\t// Raw message handling goes through handleRawMessage / handleBufferMessage\n\t\t\t\t},\n\t\t\t\thandleBufferMessage: async (message) => {\n\t\t\t\t\tawait this.socka.handleBinaryMessage(message);\n\t\t\t\t},\n\t\t\t\thandleClose: async (baseSession) => {\n\t\t\t\t\tawait config.handleClose(\n\t\t\t\t\t\tbaseSession as SockaDoSession<TContract, TData, TEnv>,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t\tconst sockaConfig: SockaWebSocketSessionConfig<\n\t\t\tTContract,\n\t\t\tEmptySockaSessionData\n\t\t> = {\n\t\t\tcontract: config.contract,\n\t\t\twireFormat,\n\t\t\thandlers: wrapHandlersForInnerSockaEngine(\n\t\t\t\tconfig.contract,\n\t\t\t\tconfig.handlers,\n\t\t\t\tthis,\n\t\t\t),\n\t\t\thandleClose: async () => {\n\t\t\t\t// Outer DO lifecycle uses SockaDoSessionConfig.handleClose; inner engine no-op.\n\t\t\t},\n\t\t\tonHandlerError: config.onHandlerError\n\t\t\t\t? (err, rpcName, input, _inner) => {\n\t\t\t\t\t\tconfig.onHandlerError?.(err, rpcName, input, this);\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tonValidationError: config.onValidationError,\n\t\t\tserializeJson: config.serializeJson,\n\t\t\tdeserializeJson: config.deserializeJson,\n\t\t};\n\t\tthis.socka = new SockaWebSocketSession(\n\t\t\twebsocket,\n\t\t\tsessions as unknown as Map<\n\t\t\t\tWebSocket,\n\t\t\t\tSockaWebSocketSession<TContract, EmptySockaSessionData>\n\t\t\t>,\n\t\t\tsockaConfig,\n\t\t);\n\t\t// Defer past the outer `await createSession()` continuation so\n\t\t// `BaseSession.startFresh` has run and `session.data` exists (single\n\t\t// `queueMicrotask` runs before that continuation).\n\t\tqueueMicrotask(() => {\n\t\t\tqueueMicrotask(() => {\n\t\t\t\trunSockaDoSessionOnAttached(config, this);\n\t\t\t});\n\t\t});\n\t}\n\n\tpublic async handleRawMessage(rawMessage: string): Promise<void> {\n\t\treturn this.socka.handleRawMessage(rawMessage);\n\t}\n\n\tpublic emitWireEvent(event: string, body: unknown): void {\n\t\tthis.socka.emitWireEvent(event, body);\n\t}\n\n\tpublic emitPush<K extends keyof TContract[\"pushes\"] & string>(\n\t\tname: K,\n\t\tbody: InferSockaPushPayload<TContract, K>,\n\t): Promise<void> {\n\t\treturn this.socka.emitPush(name, body);\n\t}\n\n\tpublic broadcastPush<K extends keyof TContract[\"pushes\"] & string>(\n\t\tname: K,\n\t\tbody: InferSockaPushPayload<TContract, K>,\n\t\texcludeSelf = false,\n\t): Promise<void> {\n\t\treturn this.socka.broadcastPush(name, body, excludeSelf);\n\t}\n\n\t/**\n\t * {@link SockaWebSocketSession.listPeers} for this Durable Object room.\n\t */\n\tpublic listPeers(options?: { excludeSelf?: boolean }): TData[] {\n\t\tconst out: TData[] = [];\n\t\tfor (const [ws, s] of this.sessions) {\n\t\t\tif (options?.excludeSelf && ws === this.websocket) continue;\n\t\t\tout.push(s.data);\n\t\t}\n\t\treturn out;\n\t}\n\n\t/**\n\t * Like {@link listPeers} but maps each peer {@link SockaDoSession}.\n\t */\n\tpublic listPeersWith<R>(\n\t\tmap: (session: SockaDoSession<TContract, TData, TEnv>) => R,\n\t\toptions?: { excludeSelf?: boolean },\n\t): R[] {\n\t\tconst out: R[] = [];\n\t\tfor (const [ws, s] of this.sessions) {\n\t\t\tif (options?.excludeSelf && ws === this.websocket) continue;\n\t\t\tout.push(map(s as SockaDoSession<TContract, TData, TEnv>));\n\t\t}\n\t\treturn out;\n\t}\n\n\tpublic peerCount(options?: { excludeSelf?: boolean }): number {\n\t\tlet n = 0;\n\t\tfor (const [ws] of this.sessions) {\n\t\t\tif (options?.excludeSelf && ws === this.websocket) continue;\n\t\t\tn += 1;\n\t\t}\n\t\treturn n;\n\t}\n\n\tpublic hasPeers(options?: { excludeSelf?: boolean }): boolean {\n\t\treturn this.peerCount(options) > 0;\n\t}\n}\n","import type { Context } from \"hono\";\nimport type { SessionEnv } from \"@firtoz/websocket-do\";\nimport { BaseWebSocketDO } from \"@firtoz/websocket-do\";\nimport type { SockaContract, SockaContractConfig } from \"../core/contract\";\nimport type { SockaDoSession } from \"./SockaDoSession\";\n\nexport type SockaWebSocketDOOptions<\n\tTEnv extends object,\n\t// `any` contract slot: concrete sessions use `defineSocka` contracts that do\n\t// not assign to `SockaContract<SockaContractConfig>` under strict generics.\n\tTSession extends SockaDoSession<\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany,\n\t\tTEnv\n\t>,\n> = {\n\tcreateSockaSession: (\n\t\tctx: Context<{ Bindings: TEnv }> | undefined,\n\t\twebsocket: WebSocket,\n\t) => TSession | Promise<TSession>;\n};\n\n/**\n * Durable Object base class for WebSocket apps using {@link SockaDoSession}\n * (Standard Schema contract-driven).\n */\nexport abstract class SockaWebSocketDO<\n\tTSession extends SockaDoSession<\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany\n\t> = SockaDoSession<\n\t\tSockaContract<SockaContractConfig>,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany,\n\t\t// biome-ignore lint/suspicious/noExplicitAny: session family type erasure\n\t\tany\n\t>,\n\tTEnv extends SessionEnv<TSession> = SessionEnv<TSession>,\n> extends BaseWebSocketDO<TSession, TEnv> {\n\tconstructor(\n\t\tctx: DurableObjectState,\n\t\tenv: TEnv,\n\t\toptions: SockaWebSocketDOOptions<TEnv, TSession>,\n\t) {\n\t\tsuper(ctx, env, {\n\t\t\tcreateSession: (sessionCtx, websocket) =>\n\t\t\t\toptions.createSockaSession(sessionCtx, websocket),\n\t\t});\n\t}\n}\n","/**\n * Shared error reply shape for correlate-by-id RPC when the handler throws.\n * Narrow at the call site to your server message union if needed.\n */\nexport function toErrorReply(\n\tid: string,\n\terror: string,\n): {\n\ttype: \"error\";\n\tid: string;\n\terror: string;\n} {\n\treturn { type: \"error\", id, error };\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Context } from 'hono';
|
|
2
2
|
import { WSEvents } from 'hono/ws';
|
|
3
|
-
import { S as SockaContract, a as SockaContractConfig } from '../socka-report-error-
|
|
4
|
-
import {
|
|
3
|
+
import { S as SockaContract, a as SockaContractConfig } from '../socka-report-error-ixTynx4w.js';
|
|
4
|
+
import { a as SockaWebSocketSession, c as SockaWebSocketInit, b as SockaWebSocketSessionConfig } from '../SockaWebSocketSession-Cza7Fti-.js';
|
|
5
5
|
import '@standard-schema/spec';
|
|
6
6
|
|
|
7
7
|
type SockaHonoCloudflareOptions<TContract extends SockaContract<SockaContractConfig>, TData> = {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { sockaHonoStrictInitFromContext } from '../chunk-KQO5AVKA.js';
|
|
1
2
|
import { dispatchSockaInboundMessage } from '../chunk-5WQTYLIC.js';
|
|
2
|
-
import { SockaWebSocketSession, runSockaSessionOnAttached } from '../chunk-
|
|
3
|
-
import { reportSockaError } from '../chunk-
|
|
3
|
+
import { SockaWebSocketSession, runSockaSessionOnAttached } from '../chunk-JVLUA3Q5.js';
|
|
4
|
+
import { reportSockaError } from '../chunk-2FNWVCP3.js';
|
|
4
5
|
|
|
5
6
|
// src/hono/cloudflare-workers.ts
|
|
6
7
|
function sockaHonoCloudflare(config, options) {
|
|
@@ -16,7 +17,7 @@ function sockaHonoCloudflare(config, options) {
|
|
|
16
17
|
let session = sessions.get(domWs);
|
|
17
18
|
const cfg = scopeConfig;
|
|
18
19
|
if (!session) {
|
|
19
|
-
const init = options?.sockaInit?.(c);
|
|
20
|
+
const init = options?.sockaInit?.(c) ?? sockaHonoStrictInitFromContext(c);
|
|
20
21
|
session = new SockaWebSocketSession(domWs, sessions, cfg, init);
|
|
21
22
|
sessions.set(domWs, session);
|
|
22
23
|
runSockaSessionOnAttached(cfg, session);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hono/cloudflare-workers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/hono/cloudflare-workers.ts"],"names":[],"mappings":";;;;;;AA8BO,SAAS,mBAAA,CAIf,QACA,OAAA,EACsD;AACtD,EAAA,MAAM,cAAA,GACL,OAAA,EAAS,QAAA,oBACT,IAAI,GAAA,EAAwD;AAC7D,EAAA,MAAM,YAAA,GAAe,MAAA;AACrB,EAAA,MAAM,eAAe,OAAA,EAAS,YAAA;AAE9B,EAAA,OAAO,CAAC,CAAA,MAAgB;AAAA,IACvB,SAAA,CAAU,KAAK,KAAA,EAAO;AACrB,MAAA,MAAM,MAAM,KAAA,CAAM,GAAA;AAClB,MAAA,IAAI,CAAC,GAAA,EAAK;AACV,MAAA,MAAM,KAAA,GAAQ,GAAA;AACd,MAAA,MAAM,EAAE,QAAA,EAAU,MAAA,EAAQ,WAAA,EAAY,GAAI,YAAA,GACvC,YAAA,CAAa,CAAC,CAAA,GACd,EAAE,QAAA,EAAU,cAAA,EAAgB,QAAQ,YAAA,EAAa;AACpD,MAAA,IAAI,OAAA,GAAU,QAAA,CAAS,GAAA,CAAI,KAAK,CAAA;AAChC,MAAA,MAAM,GAAA,GAAM,WAAA;AACZ,MAAA,IAAI,CAAC,OAAA,EAAS;AACb,QAAA,MAAM,OACL,OAAA,EAAS,SAAA,GAAY,CAAC,CAAA,IAAK,+BAA+B,CAAC,CAAA;AAC5D,QAAA,OAAA,GAAU,IAAI,qBAAA,CAAsB,KAAA,EAAO,QAAA,EAAU,KAAK,IAAI,CAAA;AAC9D,QAAA,QAAA,CAAS,GAAA,CAAI,OAAO,OAAO,CAAA;AAC3B,QAAA,yBAAA,CAA0B,KAAK,OAAO,CAAA;AAAA,MACvC;AACA,MAAA,MAAM,UAAA,GAA8B,IAAI,UAAA,IAAc,MAAA;AACtD,MAAA,KAAK,2BAAA,CAA4B,OAAA,EAAS,UAAA,EAAY,GAAA,CAAI,IAAI,CAAA,CAAE,KAAA;AAAA,QAC/D,CAAC,KAAA,KAAmB;AACnB,UAAA,gBAAA,CAAiB,IAAI,WAAA,EAAa;AAAA,YACjC,IAAA,EAAM,sBAAA;AAAA,YACN,OAAA,EAAS,MAAA;AAAA,YACT;AAAA,WACA,CAAA;AAAA,QACF;AAAA,OACD;AAAA,IACD,CAAA;AAAA,IACA,OAAA,CAAQ,MAAM,KAAA,EAAO;AACpB,MAAA,MAAM,MAAM,KAAA,CAAM,GAAA;AAClB,MAAA,IAAI,CAAC,GAAA,EAAK;AACV,MAAA,MAAM,KAAA,GAAQ,GAAA;AACd,MAAA,KAAA,CAAM,YAA2B;AAChC,QAAA,MAAM,EAAE,QAAA,EAAU,MAAA,EAAQ,WAAA,EAAY,GAAI,YAAA,GACvC,YAAA,CAAa,CAAC,CAAA,GACd,EAAE,QAAA,EAAU,cAAA,EAAgB,QAAQ,YAAA,EAAa;AACpD,QAAA,MAAM,GAAA,GAAM,WAAA;AAIZ,QAAA,MAAM,OAAA,GAAU,QAAA,CAAS,GAAA,CAAI,KAAK,CAAA;AAClC,QAAA,IAAI;AACH,UAAA,IAAI,OAAA,EAAS;AACZ,YAAA,MAAM,QAAQ,iBAAA,EAAkB;AAAA,UACjC;AAAA,QACD,SAAS,KAAA,EAAO;AACf,UAAA,gBAAA,CAAiB,IAAI,WAAA,EAAa;AAAA,YACjC,IAAA,EAAM,mBAAA;AAAA,YACN;AAAA,WACA,CAAA;AAAA,QACF,CAAA,SAAE;AACD,UAAA,QAAA,CAAS,OAAO,KAAK,CAAA;AAAA,QACtB;AAAA,MACD,CAAA,GAAG,CAAE,KAAA,CAAM,CAAC,KAAA,KAAmB;AAC9B,QAAA,gBAAA,CAAiB,aAAa,WAAA,EAAa;AAAA,UAC1C,IAAA,EAAM,gBAAA;AAAA,UACN,OAAA,EAAS,MAAA;AAAA,UACT;AAAA,SACA,CAAA;AAAA,MACF,CAAC,CAAA;AAAA,IACF;AAAA,GACD,CAAA;AACD","file":"cloudflare-workers.js","sourcesContent":["import type { Context } from \"hono\";\nimport type { WSEvents } from \"hono/ws\";\nimport type { SockaContract, SockaContractConfig } from \"../core/contract\";\nimport { reportSockaError } from \"../core/socka-report-error\";\nimport type { SockaWireFormat } from \"../core/wire-codec\";\nimport { dispatchSockaInboundMessage } from \"../server/dispatchSockaInboundMessage\";\nimport {\n\tSockaWebSocketSession,\n\trunSockaSessionOnAttached,\n\ttype SockaWebSocketInit,\n\ttype SockaWebSocketSessionConfig,\n} from \"../server/SockaWebSocketSession\";\nimport { sockaHonoStrictInitFromContext } from \"./strict-init-context\";\n\nexport type SockaHonoCloudflareOptions<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n> = {\n\tsessions?: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\tsockaInit?: (c: Context) => SockaWebSocketInit | undefined;\n\tresolveScope?: (c: Context) => {\n\t\tsessions: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\t\tconfig: SockaWebSocketSessionConfig<TContract, TData>;\n\t};\n};\n\n/**\n * Callback for `upgradeWebSocket` from `hono/cloudflare-workers` (no `onOpen`;\n * the session is created on first `onMessage`).\n */\nexport function sockaHonoCloudflare<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n>(\n\tconfig: SockaWebSocketSessionConfig<TContract, TData>,\n\toptions?: SockaHonoCloudflareOptions<TContract, TData>,\n): (c: Context) => Omit<WSEvents<WebSocket>, \"onOpen\"> {\n\tconst staticSessions =\n\t\toptions?.sessions ??\n\t\tnew Map<WebSocket, SockaWebSocketSession<TContract, TData>>();\n\tconst staticConfig = config;\n\tconst resolveScope = options?.resolveScope;\n\n\treturn (c: Context) => ({\n\t\tonMessage(evt, wsCtx) {\n\t\t\tconst raw = wsCtx.raw;\n\t\t\tif (!raw) return;\n\t\t\tconst domWs = raw as WebSocket;\n\t\t\tconst { sessions, config: scopeConfig } = resolveScope\n\t\t\t\t? resolveScope(c)\n\t\t\t\t: { sessions: staticSessions, config: staticConfig };\n\t\t\tlet session = sessions.get(domWs);\n\t\t\tconst cfg = scopeConfig as SockaWebSocketSessionConfig<TContract, TData>;\n\t\t\tif (!session) {\n\t\t\t\tconst init: SockaWebSocketInit | undefined =\n\t\t\t\t\toptions?.sockaInit?.(c) ?? sockaHonoStrictInitFromContext(c);\n\t\t\t\tsession = new SockaWebSocketSession(domWs, sessions, cfg, init);\n\t\t\t\tsessions.set(domWs, session);\n\t\t\t\trunSockaSessionOnAttached(cfg, session);\n\t\t\t}\n\t\t\tconst wireFormat: SockaWireFormat = cfg.wireFormat ?? \"json\";\n\t\t\tvoid dispatchSockaInboundMessage(session, wireFormat, evt.data).catch(\n\t\t\t\t(error: unknown) => {\n\t\t\t\t\treportSockaError(cfg.reportError, {\n\t\t\t\t\t\tkind: \"serverInboundMessage\",\n\t\t\t\t\t\tadapter: \"hono\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t\tonClose(_evt, wsCtx) {\n\t\t\tconst raw = wsCtx.raw;\n\t\t\tif (!raw) return;\n\t\t\tconst domWs = raw as WebSocket;\n\t\t\tvoid (async (): Promise<void> => {\n\t\t\t\tconst { sessions, config: scopeConfig } = resolveScope\n\t\t\t\t\t? resolveScope(c)\n\t\t\t\t\t: { sessions: staticSessions, config: staticConfig };\n\t\t\t\tconst cfg = scopeConfig as SockaWebSocketSessionConfig<\n\t\t\t\t\tTContract,\n\t\t\t\t\tTData\n\t\t\t\t>;\n\t\t\t\tconst session = sessions.get(domWs);\n\t\t\t\ttry {\n\t\t\t\t\tif (session) {\n\t\t\t\t\t\tawait session.invokeHandleClose();\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\treportSockaError(cfg.reportError, {\n\t\t\t\t\t\tkind: \"serverHandleClose\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t});\n\t\t\t\t} finally {\n\t\t\t\t\tsessions.delete(domWs);\n\t\t\t\t}\n\t\t\t})().catch((error: unknown) => {\n\t\t\t\treportSockaError(staticConfig.reportError, {\n\t\t\t\t\tkind: \"serverShutdown\",\n\t\t\t\t\tadapter: \"hono\",\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t});\n\t\t},\n\t});\n}\n"]}
|
package/dist/hono/index.d.ts
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import { Context } from 'hono';
|
|
2
|
+
import { S as SockaStrictWebSocketInit, b as SockaWebSocketSessionConfig, a as SockaWebSocketSession, c as SockaWebSocketInit } from '../SockaWebSocketSession-Cza7Fti-.js';
|
|
2
3
|
import { WSEvents } from 'hono/ws';
|
|
3
4
|
import { WebSocket as WebSocket$1 } from 'ws';
|
|
4
|
-
import { S as SockaContract, a as SockaContractConfig } from '../socka-report-error-
|
|
5
|
-
import { a as SockaWebSocketSessionConfig, S as SockaWebSocketSession, b as SockaWebSocketInit } from '../SockaWebSocketSession-Bru8yFcK.js';
|
|
5
|
+
import { S as SockaContract, a as SockaContractConfig } from '../socka-report-error-ixTynx4w.js';
|
|
6
6
|
import '@standard-schema/spec';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Build {@link SockaStrictWebSocketInit} from a Hono {@link Context} by synthesizing a
|
|
10
|
+
* **`Request`** from **`c.req.url`** (method GET; URL matches the incoming upgrade).
|
|
11
|
+
*
|
|
12
|
+
* Used when **`sockaHonoNodeWs` / `sockaHonoCloudflare`** omit a custom **`sockaInit`** and
|
|
13
|
+
* **`strictUpgradeRequest: true`** is set: **`createData`** then always receives
|
|
14
|
+
* **`init.request`** without you writing **`sockaInit: (ctx) => ({ request: new Request(ctx.req.url) })`** by hand.
|
|
15
|
+
*
|
|
16
|
+
* For full fidelity to the original upgrade (headers, method), pass your own **`sockaInit`**
|
|
17
|
+
* that forwards the real **`Request`** from your runtime instead of this helper.
|
|
18
|
+
*/
|
|
19
|
+
declare function sockaHonoStrictInitFromContext(c: Context): SockaStrictWebSocketInit;
|
|
20
|
+
|
|
8
21
|
type SockaHonoNodeWsOptions<TContract extends SockaContract<SockaContractConfig>, TData> = {
|
|
9
22
|
/** Shared map; default is a new `Map`. */
|
|
10
23
|
sessions?: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;
|
|
11
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Per-upgrade init for `createData`. When omitted, defaults to
|
|
26
|
+
* {@link sockaHonoStrictInitFromContext} so `Request` is always available.
|
|
27
|
+
*/
|
|
12
28
|
sockaInit?: (c: Context) => SockaWebSocketInit | undefined;
|
|
13
29
|
/**
|
|
14
30
|
* Resolve the session map and config from this upgrade’s Hono context (e.g. multi-room
|
|
@@ -27,4 +43,4 @@ type SockaHonoNodeWsOptions<TContract extends SockaContract<SockaContractConfig>
|
|
|
27
43
|
*/
|
|
28
44
|
declare function sockaHonoNodeWs<TContract extends SockaContract<SockaContractConfig>, TData>(config: SockaWebSocketSessionConfig<TContract, TData>, options?: SockaHonoNodeWsOptions<TContract, TData>): (c: Context) => WSEvents<WebSocket$1>;
|
|
29
45
|
|
|
30
|
-
export { type SockaHonoNodeWsOptions, sockaHonoNodeWs };
|
|
46
|
+
export { type SockaHonoNodeWsOptions, sockaHonoNodeWs, sockaHonoStrictInitFromContext };
|
package/dist/hono/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { sockaHonoStrictInitFromContext } from '../chunk-KQO5AVKA.js';
|
|
2
|
+
export { sockaHonoStrictInitFromContext } from '../chunk-KQO5AVKA.js';
|
|
1
3
|
import { dispatchSockaInboundMessage } from '../chunk-5WQTYLIC.js';
|
|
2
|
-
import { SockaWebSocketSession, runSockaSessionOnAttached } from '../chunk-
|
|
3
|
-
import { reportSockaError } from '../chunk-
|
|
4
|
+
import { SockaWebSocketSession, runSockaSessionOnAttached } from '../chunk-JVLUA3Q5.js';
|
|
5
|
+
import { reportSockaError } from '../chunk-2FNWVCP3.js';
|
|
4
6
|
|
|
5
7
|
// src/hono/node-ws.ts
|
|
6
8
|
function sockaHonoNodeWs(config, options) {
|
|
@@ -13,7 +15,7 @@ function sockaHonoNodeWs(config, options) {
|
|
|
13
15
|
if (!raw) return;
|
|
14
16
|
const domWs = raw;
|
|
15
17
|
const { sessions, config: scopeConfig } = resolveScope ? resolveScope(c) : { sessions: staticSessions, config: staticConfig };
|
|
16
|
-
const init = options?.sockaInit?.(c);
|
|
18
|
+
const init = options?.sockaInit?.(c) ?? sockaHonoStrictInitFromContext(c);
|
|
17
19
|
const cfg = scopeConfig;
|
|
18
20
|
const session = new SockaWebSocketSession(domWs, sessions, cfg, init);
|
|
19
21
|
sessions.set(domWs, session);
|
package/dist/hono/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hono/node-ws.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/hono/node-ws.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { Context } from \"hono\";\nimport type { WSEvents } from \"hono/ws\";\nimport type { WebSocket as NodeWebSocket } from \"ws\";\nimport type { SockaContract, SockaContractConfig } from \"../core/contract\";\nimport { reportSockaError } from \"../core/socka-report-error\";\nimport type { SockaWireFormat } from \"../core/wire-codec\";\nimport { dispatchSockaInboundMessage } from \"../server/dispatchSockaInboundMessage\";\nimport {\n\tSockaWebSocketSession,\n\trunSockaSessionOnAttached,\n\ttype SockaWebSocketInit,\n\ttype SockaWebSocketSessionConfig,\n} from \"../server/SockaWebSocketSession\";\nimport { sockaHonoStrictInitFromContext } from \"./strict-init-context\";\n\nexport { sockaHonoStrictInitFromContext } from \"./strict-init-context\";\n\nexport type SockaHonoNodeWsOptions<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n> = {\n\t/** Shared map; default is a new `Map`. */\n\tsessions?: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\t/**\n\t * Per-upgrade init for `createData`. When omitted, defaults to\n\t * {@link sockaHonoStrictInitFromContext} so `Request` is always available.\n\t */\n\tsockaInit?: (c: Context) => SockaWebSocketInit | undefined;\n\t/**\n\t * Resolve the session map and config from this upgrade’s Hono context (e.g. multi-room\n\t * from `c.req.param(\"roomId\")`). When set, overrides the outer `config` / static `sessions`\n\t * for each connection.\n\t */\n\tresolveScope?: (c: Context) => {\n\t\tsessions: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\t\tconfig: SockaWebSocketSessionConfig<TContract, TData>;\n\t};\n};\n\n/**\n * Returns the callback passed to `upgradeWebSocket` from\n * {@link https://github.com/honojs/middleware/tree/main/packages/node-ws @hono/node-ws}\n * `createNodeWebSocket({ app }).upgradeWebSocket`.\n */\nexport function sockaHonoNodeWs<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n>(\n\tconfig: SockaWebSocketSessionConfig<TContract, TData>,\n\toptions?: SockaHonoNodeWsOptions<TContract, TData>,\n): (c: Context) => WSEvents<NodeWebSocket> {\n\tconst staticSessions =\n\t\toptions?.sessions ??\n\t\tnew Map<WebSocket, SockaWebSocketSession<TContract, TData>>();\n\tconst staticConfig = config;\n\tconst resolveScope = options?.resolveScope;\n\n\treturn (c: Context) => ({\n\t\tonOpen(_evt, wsCtx) {\n\t\t\tconst raw = wsCtx.raw;\n\t\t\tif (!raw) return;\n\t\t\tconst domWs = raw as unknown as WebSocket;\n\t\t\tconst { sessions, config: scopeConfig } = resolveScope\n\t\t\t\t? resolveScope(c)\n\t\t\t\t: { sessions: staticSessions, config: staticConfig };\n\t\t\tconst init: SockaWebSocketInit | undefined =\n\t\t\t\toptions?.sockaInit?.(c) ?? sockaHonoStrictInitFromContext(c);\n\t\t\tconst cfg = scopeConfig as SockaWebSocketSessionConfig<TContract, TData>;\n\t\t\tconst session = new SockaWebSocketSession(domWs, sessions, cfg, init);\n\t\t\tsessions.set(domWs, session);\n\t\t\trunSockaSessionOnAttached(cfg, session);\n\t\t},\n\t\tonMessage(evt, wsCtx) {\n\t\t\tconst raw = wsCtx.raw;\n\t\t\tif (!raw) return;\n\t\t\tconst domWs = raw as unknown as WebSocket;\n\t\t\tconst { sessions, config: scopeConfig } = resolveScope\n\t\t\t\t? resolveScope(c)\n\t\t\t\t: { sessions: staticSessions, config: staticConfig };\n\t\t\tconst session = sessions.get(domWs);\n\t\t\tif (!session) return;\n\t\t\tconst cfg = scopeConfig as SockaWebSocketSessionConfig<TContract, TData>;\n\t\t\tconst wireFormat: SockaWireFormat = cfg.wireFormat ?? \"json\";\n\t\t\tvoid dispatchSockaInboundMessage(session, wireFormat, evt.data).catch(\n\t\t\t\t(error: unknown) => {\n\t\t\t\t\treportSockaError(cfg.reportError, {\n\t\t\t\t\t\tkind: \"serverInboundMessage\",\n\t\t\t\t\t\tadapter: \"hono\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t\tonClose(_evt, wsCtx) {\n\t\t\tconst raw = wsCtx.raw;\n\t\t\tif (!raw) return;\n\t\t\tconst domWs = raw as unknown as WebSocket;\n\t\t\tvoid (async (): Promise<void> => {\n\t\t\t\tconst { sessions, config: scopeConfig } = resolveScope\n\t\t\t\t\t? resolveScope(c)\n\t\t\t\t\t: { sessions: staticSessions, config: staticConfig };\n\t\t\t\tconst cfg = scopeConfig as SockaWebSocketSessionConfig<\n\t\t\t\t\tTContract,\n\t\t\t\t\tTData\n\t\t\t\t>;\n\t\t\t\tconst session = sessions.get(domWs);\n\t\t\t\ttry {\n\t\t\t\t\tif (session) {\n\t\t\t\t\t\tawait session.invokeHandleClose();\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\treportSockaError(cfg.reportError, {\n\t\t\t\t\t\tkind: \"serverHandleClose\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t});\n\t\t\t\t} finally {\n\t\t\t\t\tsessions.delete(domWs);\n\t\t\t\t}\n\t\t\t})().catch((error: unknown) => {\n\t\t\t\treportSockaError(staticConfig.reportError, {\n\t\t\t\t\tkind: \"serverShutdown\",\n\t\t\t\t\tadapter: \"hono\",\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t});\n\t\t},\n\t});\n}\n"]}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DependencyList, RefObject, ReactNode, ReactElement } from 'react';
|
|
2
|
-
import { S as SockaContract, a as SockaContractConfig, f as InferSockaPushHandlers, I as InferSockaSend } from '../socka-report-error-
|
|
3
|
-
import { SockaSessionOptions, SockaSession } from '../client/index.js';
|
|
2
|
+
import { S as SockaContract, a as SockaContractConfig, f as InferSockaPushHandlers, I as InferSockaSend, g as InferSockaPushPayload } from '../socka-report-error-ixTynx4w.js';
|
|
3
|
+
import { SockaSessionOptions, SockaSession, SockaConnectionStatus } from '../client/index.js';
|
|
4
4
|
import '@standard-schema/spec';
|
|
5
5
|
|
|
6
6
|
/** Options for {@link useSocka}. */
|
|
@@ -12,6 +12,9 @@ type UseSockaOptions<TContract extends SockaContract<SockaContractConfig>> = Soc
|
|
|
12
12
|
declare function useSocka<TContract extends SockaContract<SockaContractConfig>>(options: UseSockaOptions<TContract>, deps: DependencyList): {
|
|
13
13
|
ready: boolean;
|
|
14
14
|
sessionRef: RefObject<SockaSession<TContract> | null>;
|
|
15
|
+
status: SockaConnectionStatus;
|
|
16
|
+
reconnecting: boolean;
|
|
17
|
+
reconnectAttempt: number;
|
|
15
18
|
};
|
|
16
19
|
|
|
17
20
|
type UseSockaSessionOptions<TContract extends SockaContract<SockaContractConfig>> = Omit<UseSockaOptions<TContract>, "contract" | "pushHandlers"> & {
|
|
@@ -25,13 +28,43 @@ declare function createSockaSendProxyFromSession<TContract extends SockaContract
|
|
|
25
28
|
/**
|
|
26
29
|
* ```tsx
|
|
27
30
|
* const { ready, send } = useSockaSession(myContract, { url }, deps);
|
|
28
|
-
* await send.echo({
|
|
31
|
+
* await send.echo({ message: "hi" });
|
|
29
32
|
* ```
|
|
30
33
|
*/
|
|
31
34
|
declare function useSockaSession<TContract extends SockaContract<SockaContractConfig>>(contract: TContract, options: UseSockaSessionOptions<TContract>, deps: DependencyList): {
|
|
32
35
|
ready: boolean;
|
|
33
36
|
send: InferSockaSend<TContract>;
|
|
34
37
|
sessionRef: RefObject<SockaSession<TContract> | null>;
|
|
38
|
+
status: SockaConnectionStatus;
|
|
39
|
+
reconnecting: boolean;
|
|
40
|
+
reconnectAttempt: number;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type SockaPresenceOptions<TContract extends SockaContract<SockaContractConfig>, TUser extends {
|
|
44
|
+
userId: string;
|
|
45
|
+
}, KJoin extends keyof TContract["pushes"] & string, KLeave extends keyof TContract["pushes"] & string> = {
|
|
46
|
+
snapshot: () => Promise<{
|
|
47
|
+
selfUserId: string;
|
|
48
|
+
users: TUser[];
|
|
49
|
+
}>;
|
|
50
|
+
joinPush: KJoin;
|
|
51
|
+
leavePush: KLeave;
|
|
52
|
+
mapJoinUser: (p: InferSockaPushPayload<TContract, KJoin>) => TUser;
|
|
53
|
+
mapLeaveUserId: (p: InferSockaPushPayload<TContract, KLeave>) => string;
|
|
54
|
+
/** Optional display order after each update (e.g. by `displayName`). */
|
|
55
|
+
sortUsers?: (a: TUser, b: TUser) => number;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Loads a presence snapshot RPC once, then merges **`joinPush`** / **`leavePush`** deltas.
|
|
59
|
+
* Pass the same **`deps`** you use for {@link useSocka} when room identity changes.
|
|
60
|
+
* Options are read from a ref so you do not need to memoize the **`options`** object.
|
|
61
|
+
*/
|
|
62
|
+
declare function useSockaPresence<TContract extends SockaContract<SockaContractConfig>, TUser extends {
|
|
63
|
+
userId: string;
|
|
64
|
+
}, KJoin extends keyof TContract["pushes"] & string, KLeave extends keyof TContract["pushes"] & string>(sessionRef: RefObject<SockaSession<TContract> | null>, ready: boolean, options: SockaPresenceOptions<TContract, TUser, KJoin, KLeave>, deps: DependencyList): {
|
|
65
|
+
users: TUser[];
|
|
66
|
+
selfUserId: string | undefined;
|
|
67
|
+
loading: boolean;
|
|
35
68
|
};
|
|
36
69
|
|
|
37
70
|
type AnySockaContract = SockaContract<SockaContractConfig>;
|
|
@@ -44,6 +77,9 @@ type SockaSessionContextValue<TContract extends SockaContract<SockaContractConfi
|
|
|
44
77
|
readonly contract: TContract;
|
|
45
78
|
readonly ready: boolean;
|
|
46
79
|
readonly sessionRef: RefObject<SockaSession<TContract> | null>;
|
|
80
|
+
readonly status: SockaConnectionStatus;
|
|
81
|
+
readonly reconnecting: boolean;
|
|
82
|
+
readonly reconnectAttempt: number;
|
|
47
83
|
};
|
|
48
84
|
type SockaSessionProviderProps<TContract extends SockaContract<SockaContractConfig>> = {
|
|
49
85
|
readonly contract: TContract;
|
|
@@ -67,6 +103,9 @@ declare function useSockaSessionContext<TContract extends SockaContract<SockaCon
|
|
|
67
103
|
ready: boolean;
|
|
68
104
|
send: InferSockaSend<TContract>;
|
|
69
105
|
sessionRef: RefObject<SockaSession<TContract> | null>;
|
|
106
|
+
status: SockaConnectionStatus;
|
|
107
|
+
reconnecting: boolean;
|
|
108
|
+
reconnectAttempt: number;
|
|
70
109
|
};
|
|
71
110
|
|
|
72
|
-
export { type SockaSessionContextValue, SockaSessionProvider, type SockaSessionProviderProps, type UseSockaOptions, type UseSockaSessionOptions, createSockaSendProxyFromSession, useSocka, useSockaSession, useSockaSessionContext };
|
|
111
|
+
export { type SockaPresenceOptions, type SockaSessionContextValue, SockaSessionProvider, type SockaSessionProviderProps, type UseSockaOptions, type UseSockaSessionOptions, createSockaSendProxyFromSession, useSocka, useSockaPresence, useSockaSession, useSockaSessionContext };
|