@base44-preview/sdk 0.8.35-pr.212.48756fd → 0.8.35-pr.212.4e8e6d7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js
CHANGED
|
@@ -172,9 +172,11 @@ export function createClient(config) {
|
|
|
172
172
|
realtime: createRealtimeModule({
|
|
173
173
|
appId,
|
|
174
174
|
dispatcherWsUrl: resolvedDispatcherWsUrl,
|
|
175
|
-
getToken: async (handlerName, instanceId) => {
|
|
176
|
-
// axiosClient interceptors unwrap response.data, so the result is the body directly
|
|
177
|
-
|
|
175
|
+
getToken: async (handlerName, instanceId, connId) => {
|
|
176
|
+
// axiosClient interceptors unwrap response.data, so the result is the body directly.
|
|
177
|
+
// conn_id rides inside the signed token (not a WS query param) so it survives
|
|
178
|
+
// proxies that strip params; the dispatcher forwards it as the handler's conn.id.
|
|
179
|
+
const data = await axiosClient.post(`/apps/${appId}/realtime-token`, { handler_name: handlerName, instance_id: instanceId, conn_id: connId });
|
|
178
180
|
return data.token;
|
|
179
181
|
},
|
|
180
182
|
}),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare function createRealtimeModule(config: {
|
|
2
2
|
appId: string;
|
|
3
|
-
getToken(handlerName: string, instanceId: string): Promise<string>;
|
|
3
|
+
getToken(handlerName: string, instanceId: string, connId: string): Promise<string>;
|
|
4
4
|
dispatcherWsUrl: string;
|
|
5
5
|
}): Record<string, RealtimeHandler>;
|
|
6
6
|
/** Handle for an active realtime subscription. */
|
package/dist/modules/realtime.js
CHANGED
|
@@ -9,19 +9,23 @@ export function createRealtimeModule(config) {
|
|
|
9
9
|
get(_, handlerName) {
|
|
10
10
|
return {
|
|
11
11
|
subscribe(instanceId, callback, options) {
|
|
12
|
-
var _a;
|
|
12
|
+
var _a, _b;
|
|
13
13
|
const key = socketKey(handlerName, instanceId);
|
|
14
14
|
// close existing if any
|
|
15
15
|
(_a = activeSockets.get(key)) === null || _a === void 0 ? void 0 : _a.close();
|
|
16
|
+
// Connection id: caller-supplied (stable — reuse across reconnects/tabs as
|
|
17
|
+
// you see fit) or auto-generated per subscription. It travels INSIDE the
|
|
18
|
+
// signed realtime token (never as a WS query param, which proxies strip);
|
|
19
|
+
// the dispatcher forwards the verified claim as partyserver's _pk, so the
|
|
20
|
+
// handler sees this exact value as conn.id. Reconnects re-mint the token
|
|
21
|
+
// with the same id, so conn.id is stable across reconnects.
|
|
22
|
+
const connId = (_b = options === null || options === void 0 ? void 0 : options.id) !== null && _b !== void 0 ? _b : crypto.randomUUID();
|
|
16
23
|
// query as async fn: called on every (re)connect, fetches a fresh token each time
|
|
17
24
|
const ws = new PartySocket({
|
|
18
25
|
host: config.dispatcherWsUrl,
|
|
19
26
|
party: handlerName,
|
|
20
27
|
room: instanceId,
|
|
21
|
-
|
|
22
|
-
// you see fit) or auto-generated per connection. Server sees it as conn.id.
|
|
23
|
-
id: options === null || options === void 0 ? void 0 : options.id,
|
|
24
|
-
query: () => config.getToken(handlerName, instanceId).then((token) => ({ token })),
|
|
28
|
+
query: () => config.getToken(handlerName, instanceId, connId).then((token) => ({ token })),
|
|
25
29
|
});
|
|
26
30
|
activeSockets.set(key, ws);
|
|
27
31
|
// Heartbeat / half-open detection. PartySocket only reconnects on a
|
|
@@ -64,7 +68,7 @@ export function createRealtimeModule(config) {
|
|
|
64
68
|
}
|
|
65
69
|
}, PING_MS);
|
|
66
70
|
return {
|
|
67
|
-
id:
|
|
71
|
+
id: connId, // the connection id (same value the handler sees as conn.id)
|
|
68
72
|
unsubscribe() {
|
|
69
73
|
clearInterval(heartbeat);
|
|
70
74
|
activeSockets.delete(key);
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
* declare module "@base44/sdk" {
|
|
11
11
|
* interface RealtimeHandlerRegistry {
|
|
12
12
|
* ChatRoom: {
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* toClient: { type: "joined" | "left" | "message"; userId?: string; from?: string; text?: string };
|
|
14
|
+
* toServer: { type: "message"; text: string };
|
|
15
15
|
* };
|
|
16
16
|
* }
|
|
17
17
|
* }
|
|
@@ -26,11 +26,11 @@ export interface RealtimeHandlerRegistry {
|
|
|
26
26
|
export interface RealtimeHandlerNameRegistry {
|
|
27
27
|
}
|
|
28
28
|
type AllHandlerNames = keyof RealtimeHandlerRegistry | keyof RealtimeHandlerNameRegistry;
|
|
29
|
-
type
|
|
30
|
-
|
|
29
|
+
type ToClientFor<N extends string> = N extends keyof RealtimeHandlerRegistry ? RealtimeHandlerRegistry[N] extends {
|
|
30
|
+
toClient: infer I;
|
|
31
31
|
} ? I : unknown : unknown;
|
|
32
|
-
type
|
|
33
|
-
|
|
32
|
+
type ToServerFor<N extends string> = N extends keyof RealtimeHandlerRegistry ? RealtimeHandlerRegistry[N] extends {
|
|
33
|
+
toServer: infer O;
|
|
34
34
|
} ? O : unknown : unknown;
|
|
35
35
|
/**
|
|
36
36
|
* Client for a single named RealtimeHandler.
|
|
@@ -45,11 +45,11 @@ export interface RealtimeHandlerClient<N extends string = string> {
|
|
|
45
45
|
* reconnect reuses the same server-side connection); omit it for an auto-generated
|
|
46
46
|
* per-connection id.
|
|
47
47
|
*/
|
|
48
|
-
subscribe(instanceId: string, callback: (data:
|
|
48
|
+
subscribe(instanceId: string, callback: (data: ToClientFor<N>) => void, options?: {
|
|
49
49
|
id?: string;
|
|
50
50
|
}): RealtimeSubscription;
|
|
51
51
|
/** Send a message over the open socket. Throws if not subscribed. */
|
|
52
|
-
send(instanceId: string, data:
|
|
52
|
+
send(instanceId: string, data: ToServerFor<N>): void;
|
|
53
53
|
}
|
|
54
54
|
/** Handle for an active realtime subscription. */
|
|
55
55
|
export interface RealtimeSubscription {
|
|
@@ -9,7 +9,11 @@
|
|
|
9
9
|
* Cloudflare Durable Object implementation — this file provides types only.
|
|
10
10
|
*/
|
|
11
11
|
import type { Base44Client } from "./client.types.js";
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* A single client connection. `Send` is the message type this connection accepts
|
|
14
|
+
* via {@link send} — the handler's *outgoing* (server→client) messages.
|
|
15
|
+
*/
|
|
16
|
+
export interface Conn<Send = unknown> {
|
|
13
17
|
/** Unique per-connection id (one per socket/tab), the same value the client
|
|
14
18
|
* receives from `subscribe()`. Use this — not userId — to identify a distinct
|
|
15
19
|
* client, so multiple tabs of the same user are separate connections. */
|
|
@@ -17,7 +21,7 @@ export interface Conn {
|
|
|
17
21
|
userId: string;
|
|
18
22
|
appId: string;
|
|
19
23
|
instanceId: string;
|
|
20
|
-
send(data:
|
|
24
|
+
send(data: Send): void;
|
|
21
25
|
reject(code: number, reason: string): void;
|
|
22
26
|
}
|
|
23
27
|
export interface Storage {
|
|
@@ -25,10 +29,25 @@ export interface Storage {
|
|
|
25
29
|
put(key: string, value: unknown): Promise<void>;
|
|
26
30
|
delete(key: string): Promise<boolean>;
|
|
27
31
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Base class for a Realtime Handler.
|
|
34
|
+
*
|
|
35
|
+
* @typeParam Incoming - messages this handler *receives* from clients
|
|
36
|
+
* (`handleMessage`'s `msg`) — the schema's `toServer` section.
|
|
37
|
+
* @typeParam Outgoing - messages this handler *sends* to clients
|
|
38
|
+
* (`conn.send`/`broadcast`) — the schema's `toClient` section.
|
|
39
|
+
*
|
|
40
|
+
* With a generated `schema.jsonc`, wire both from the registry so they can't drift
|
|
41
|
+
* from the client's types:
|
|
42
|
+
* ```ts
|
|
43
|
+
* type Reg = RealtimeHandlerRegistry["MyHandler"];
|
|
44
|
+
* class MyHandler extends RealtimeHandler<Reg["toServer"], Reg["toClient"]> { ... }
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare abstract class RealtimeHandler<Incoming = unknown, Outgoing = unknown> {
|
|
48
|
+
abstract handleConnect(conn: Conn<Outgoing>): void | Promise<void>;
|
|
49
|
+
abstract handleMessage(conn: Conn<Outgoing>, msg: Incoming): void | Promise<void>;
|
|
50
|
+
abstract handleClose(conn: Conn<Outgoing>): void | Promise<void>;
|
|
32
51
|
abstract handleTick(): void | Promise<void>;
|
|
33
52
|
onStart(): void | Promise<void>;
|
|
34
53
|
/**
|
|
@@ -43,8 +62,8 @@ export declare abstract class RealtimeHandler<_State = unknown, Message = unknow
|
|
|
43
62
|
*/
|
|
44
63
|
protected tickIntervalMs: number;
|
|
45
64
|
protected shouldTick?(): boolean;
|
|
46
|
-
protected broadcast(_data:
|
|
47
|
-
protected getConnections(): Conn[];
|
|
65
|
+
protected broadcast(_data: Outgoing): void;
|
|
66
|
+
protected getConnections(): Conn<Outgoing>[];
|
|
48
67
|
protected startLoop(_ms: number): Promise<void>;
|
|
49
68
|
protected stopLoop(): Promise<void>;
|
|
50
69
|
protected get instanceId(): string;
|
package/dist/realtime-handler.js
CHANGED
|
@@ -8,6 +8,21 @@
|
|
|
8
8
|
* At deploy time the bundler replaces this import with the compiled
|
|
9
9
|
* Cloudflare Durable Object implementation — this file provides types only.
|
|
10
10
|
*/
|
|
11
|
+
/**
|
|
12
|
+
* Base class for a Realtime Handler.
|
|
13
|
+
*
|
|
14
|
+
* @typeParam Incoming - messages this handler *receives* from clients
|
|
15
|
+
* (`handleMessage`'s `msg`) — the schema's `toServer` section.
|
|
16
|
+
* @typeParam Outgoing - messages this handler *sends* to clients
|
|
17
|
+
* (`conn.send`/`broadcast`) — the schema's `toClient` section.
|
|
18
|
+
*
|
|
19
|
+
* With a generated `schema.jsonc`, wire both from the registry so they can't drift
|
|
20
|
+
* from the client's types:
|
|
21
|
+
* ```ts
|
|
22
|
+
* type Reg = RealtimeHandlerRegistry["MyHandler"];
|
|
23
|
+
* class MyHandler extends RealtimeHandler<Reg["toServer"], Reg["toClient"]> { ... }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
11
26
|
export class RealtimeHandler {
|
|
12
27
|
constructor() {
|
|
13
28
|
/**
|