@base44-preview/sdk 0.8.35-pr.212.b15255e → 0.8.35-pr.212.daec52b

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/index.d.ts CHANGED
@@ -10,8 +10,9 @@ export type { IntegrationsModule, IntegrationEndpointFunction, CoreIntegrations,
10
10
  export type { FunctionsModule, FunctionName, FunctionNameRegistry, } from "./modules/functions.types.js";
11
11
  export type { AgentsModule, AgentName, AgentNameRegistry, AgentConversation, AgentMessage, AgentMessageReasoning, AgentMessageToolCall, AgentMessageUsage, AgentMessageCustomContext, AgentMessageMetadata, CreateConversationParams, } from "./modules/agents.types.js";
12
12
  export type { AppLogsModule } from "./modules/app-logs.types.js";
13
- export type { RealtimeModule, RealtimeHandlerClient, RealtimeSubscription, } from "./modules/realtime.types.js";
13
+ export type { RealtimeModule, RealtimeHandlerClient, RealtimeHandlerNameRegistry, RealtimeHandlerRegistry, } from "./modules/realtime.types.js";
14
14
  export type { SsoModule, SsoAccessTokenResponse } from "./modules/sso.types.js";
15
+ export { RealtimeHandler, type Conn } from "./realtime-handler.js";
15
16
  export type { ConnectorsModule, UserConnectorsModule, } from "./modules/connectors.types.js";
16
17
  export type { CustomIntegrationsModule, CustomIntegrationCallParams, CustomIntegrationCallResponse, } from "./modules/custom-integrations.types.js";
17
18
  export type { GetAccessTokenOptions, SaveAccessTokenOptions, RemoveAccessTokenOptions, GetLoginUrlOptions, } from "./utils/auth-utils.types.js";
package/dist/index.js CHANGED
@@ -3,3 +3,4 @@ import { Base44Error } from "./utils/axios-client.js";
3
3
  import { getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, } from "./utils/auth-utils.js";
4
4
  export { createClient, createClientFromRequest, Base44Error, getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, };
5
5
  export * from "./types.js";
6
+ export { RealtimeHandler } from "./realtime-handler.js";
@@ -4,10 +4,7 @@ export declare function createRealtimeModule(config: {
4
4
  dispatcherWsUrl: string;
5
5
  }): Record<string, RealtimeHandler>;
6
6
  interface RealtimeHandler {
7
- subscribe(instanceId: string, callback: (data: unknown) => void): Promise<{
8
- send(data: unknown): void;
9
- close(): void;
10
- }>;
7
+ subscribe(instanceId: string, callback: (data: unknown) => void): () => void;
11
8
  send(instanceId: string, data: unknown): void;
12
9
  }
13
10
  export {};
@@ -4,21 +4,26 @@ const activeSockets = new Map();
4
4
  function socketKey(handlerName, instanceId) {
5
5
  return `${handlerName}:${instanceId}`;
6
6
  }
7
+ // partyserver maps binding names via camelCaseToKebabCase before routing
8
+ function toKebab(str) {
9
+ return str.replace(/[A-Z]/g, (l) => `-${l.toLowerCase()}`).replace(/^-/, "");
10
+ }
7
11
  export function createRealtimeModule(config) {
8
12
  return new Proxy({}, {
9
13
  get(_, handlerName) {
10
14
  return {
11
- async subscribe(instanceId, callback) {
15
+ subscribe(instanceId, callback) {
12
16
  var _a;
13
17
  const key = socketKey(handlerName, instanceId);
14
18
  // close existing if any
15
19
  (_a = activeSockets.get(key)) === null || _a === void 0 ? void 0 : _a.close();
16
- const token = await config.getToken(handlerName, instanceId);
20
+ // query as async fn: called on every (re)connect, fetches a fresh token each time
21
+ // party must be kebab-case: partyserver maps binding names via camelCaseToKebabCase
17
22
  const ws = new PartySocket({
18
23
  host: config.dispatcherWsUrl,
19
- party: handlerName,
24
+ party: toKebab(handlerName),
20
25
  room: instanceId,
21
- query: { token },
26
+ query: () => config.getToken(handlerName, instanceId).then((token) => ({ token })),
22
27
  });
23
28
  activeSockets.set(key, ws);
24
29
  ws.addEventListener("message", (ev) => {
@@ -29,26 +34,9 @@ export function createRealtimeModule(config) {
29
34
  // ignore malformed
30
35
  }
31
36
  });
32
- // Re-fetch token on reconnect
33
- ws.addEventListener("close", async () => {
34
- if (activeSockets.get(key) !== ws)
35
- return; // replaced
36
- try {
37
- const newToken = await config.getToken(handlerName, instanceId);
38
- ws.updateProperties({ query: { token: newToken } });
39
- }
40
- catch (_a) {
41
- // ignore token refresh failure
42
- }
43
- });
44
- return {
45
- send(data) {
46
- ws.send(JSON.stringify(data));
47
- },
48
- close() {
49
- activeSockets.delete(key);
50
- ws.close();
51
- },
37
+ return () => {
38
+ activeSockets.delete(key);
39
+ ws.close();
52
40
  };
53
41
  },
54
42
  send(instanceId, data) {
@@ -1,32 +1,46 @@
1
1
  /**
2
- * A subscription handle returned by {@link RealtimeHandlerClient.subscribe}.
2
+ * Extend this interface to add typed `subscribe` callbacks and `send` payloads
3
+ * for your deployed RealtimeHandlers.
4
+ *
5
+ * This is separate from {@link RealtimeHandlerNameRegistry} (which is auto-generated
6
+ * by `base44 types generate`), so there are no conflicts.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * declare module "@base44/sdk" {
11
+ * interface RealtimeHandlerRegistry {
12
+ * ChatRoom: {
13
+ * inbound: { type: "joined" | "left" | "message"; userId?: string; from?: string; text?: string };
14
+ * outbound: { text: string };
15
+ * };
16
+ * }
17
+ * }
18
+ * ```
19
+ */
20
+ export interface RealtimeHandlerRegistry {
21
+ }
22
+ /**
23
+ * Auto-populated by `base44 types generate` with the names of your deployed handlers.
24
+ * Do not edit this interface manually — use {@link RealtimeHandlerRegistry} for message types.
3
25
  */
4
- export interface RealtimeSubscription {
5
- /** Send a message to all subscribers of this instance. */
6
- send(data: unknown): void;
7
- /** Close the WebSocket connection and remove the subscription. */
8
- close(): void;
26
+ export interface RealtimeHandlerNameRegistry {
9
27
  }
28
+ type AllHandlerNames = keyof RealtimeHandlerRegistry | keyof RealtimeHandlerNameRegistry;
29
+ type InboundFor<N extends string> = N extends keyof RealtimeHandlerRegistry ? RealtimeHandlerRegistry[N] extends {
30
+ inbound: infer I;
31
+ } ? I : unknown : unknown;
32
+ type OutboundFor<N extends string> = N extends keyof RealtimeHandlerRegistry ? RealtimeHandlerRegistry[N] extends {
33
+ outbound: infer O;
34
+ } ? O : unknown : unknown;
10
35
  /**
11
36
  * Client for a single named RealtimeHandler.
37
+ * Typed automatically when the handler is registered in {@link RealtimeHandlerRegistry}.
12
38
  */
13
- export interface RealtimeHandlerClient {
14
- /**
15
- * Subscribe to messages from a specific RealtimeHandler instance.
16
- *
17
- * @param instanceId - The instance ID of the Durable Object.
18
- * @param callback - Called with each parsed message payload.
19
- * @returns A subscription handle with `send` and `close` methods.
20
- */
21
- subscribe(instanceId: string, callback: (data: unknown) => void): Promise<RealtimeSubscription>;
22
- /**
23
- * Send a message to an existing active subscription.
24
- *
25
- * @param instanceId - The instance ID of the Durable Object.
26
- * @param data - The data to send (will be JSON-serialized).
27
- * @throws {Error} When no active subscription exists for this handler/instance pair.
28
- */
29
- send(instanceId: string, data: unknown): void;
39
+ export interface RealtimeHandlerClient<N extends string = string> {
40
+ /** Open a WebSocket subscription. Returns a synchronous unsubscribe function. */
41
+ subscribe(instanceId: string, callback: (data: InboundFor<N>) => void): () => void;
42
+ /** Send a message over the open socket. Throws if not subscribed. */
43
+ send(instanceId: string, data: OutboundFor<N>): void;
30
44
  }
31
45
  /**
32
46
  * The realtime module provides access to Cloudflare Durable Object-backed
@@ -35,10 +49,13 @@ export interface RealtimeHandlerClient {
35
49
  * Handler names are accessed as dynamic properties on this module:
36
50
  * ```typescript
37
51
  * const sub = await base44.realtime.MyHandler.subscribe("room-1", (msg) => {
38
- * console.log(msg);
52
+ * console.log(msg); // typed if MyHandler is in RealtimeHandlerRegistry
39
53
  * });
40
54
  * sub.send({ text: "hello" });
41
55
  * sub.close();
42
56
  * ```
43
57
  */
44
- export type RealtimeModule = Record<string, RealtimeHandlerClient>;
58
+ export type RealtimeModule = {
59
+ [K in AllHandlerNames]: K extends keyof RealtimeHandlerRegistry ? RealtimeHandlerClient<string & K> : RealtimeHandlerClient;
60
+ } & Record<string, RealtimeHandlerClient>;
61
+ export {};
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Type-only base class for Realtime Handlers.
3
+ *
4
+ * Import and extend this in your handler files:
5
+ * import { RealtimeHandler } from "@base44/sdk";
6
+ * export class MyHandler extends RealtimeHandler { ... }
7
+ *
8
+ * At deploy time the bundler replaces this import with the compiled
9
+ * Cloudflare Durable Object implementation — this file provides types only.
10
+ */
11
+ import type { Base44Client } from "./client.types.js";
12
+ export interface Conn {
13
+ userId: string;
14
+ appId: string;
15
+ instanceId: string;
16
+ send(data: unknown): void;
17
+ reject(code: number, reason: string): void;
18
+ }
19
+ export interface Storage {
20
+ get<T>(key: string): Promise<T | undefined>;
21
+ put(key: string, value: unknown): Promise<void>;
22
+ delete(key: string): Promise<boolean>;
23
+ }
24
+ export declare abstract class RealtimeHandler<_State = unknown, Message = unknown> {
25
+ abstract handleConnect(conn: Conn): void | Promise<void>;
26
+ abstract handleMessage(conn: Conn, msg: Message): void | Promise<void>;
27
+ abstract handleClose(conn: Conn): void | Promise<void>;
28
+ abstract handleTick(): void | Promise<void>;
29
+ onStart(): void | Promise<void>;
30
+ protected broadcast(_data: unknown): void;
31
+ protected getConnections(): Conn[];
32
+ protected startLoop(_ms: number): Promise<void>;
33
+ protected stopLoop(): Promise<void>;
34
+ protected get instanceId(): string;
35
+ protected get storage(): Storage;
36
+ protected createServiceClient(): Base44Client;
37
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Type-only base class for Realtime Handlers.
3
+ *
4
+ * Import and extend this in your handler files:
5
+ * import { RealtimeHandler } from "@base44/sdk";
6
+ * export class MyHandler extends RealtimeHandler { ... }
7
+ *
8
+ * At deploy time the bundler replaces this import with the compiled
9
+ * Cloudflare Durable Object implementation — this file provides types only.
10
+ */
11
+ export class RealtimeHandler {
12
+ onStart() { }
13
+ broadcast(_data) {
14
+ throw new Error("RealtimeHandler.broadcast() is only available inside a deployed handler");
15
+ }
16
+ getConnections() {
17
+ throw new Error("RealtimeHandler.getConnections() is only available inside a deployed handler");
18
+ }
19
+ startLoop(_ms) {
20
+ throw new Error("RealtimeHandler.startLoop() is only available inside a deployed handler");
21
+ }
22
+ stopLoop() {
23
+ throw new Error("RealtimeHandler.stopLoop() is only available inside a deployed handler");
24
+ }
25
+ get instanceId() {
26
+ throw new Error("RealtimeHandler.instanceId is only available inside a deployed handler");
27
+ }
28
+ get storage() {
29
+ throw new Error("RealtimeHandler.storage is only available inside a deployed handler");
30
+ }
31
+ createServiceClient() {
32
+ throw new Error("RealtimeHandler.createServiceClient() is only available inside a deployed handler");
33
+ }
34
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/sdk",
3
- "version": "0.8.35-pr.212.b15255e",
3
+ "version": "0.8.35-pr.212.daec52b",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",