@base44-preview/sdk 0.8.40-pr.212.d742832 → 0.8.40-pr.212.f14d383

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/actor.d.ts CHANGED
@@ -8,6 +8,7 @@
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
+ import type { Base44Client } from "./client";
11
12
  /**
12
13
  * A single client connection. `Send` is the message type this connection accepts
13
14
  * via {@link send} — the actor's *outgoing* (server→client) messages.
@@ -74,4 +75,10 @@ export declare abstract class Actor<Incoming = unknown, Outgoing = unknown> {
74
75
  protected stopLoop(): Promise<void>;
75
76
  protected get instanceId(): string;
76
77
  protected get storage(): Storage;
78
+ /**
79
+ * Anonymous Base44 client scoped to this actor instance — no user or service
80
+ * auth, so entity access is RLS-gated (same as a logged-out visitor).
81
+ * Example: `const rows = await this.client.entities.Score.list();`
82
+ */
83
+ protected get client(): Base44Client;
77
84
  }
package/dist/actor.js CHANGED
@@ -60,4 +60,12 @@ export class Actor {
60
60
  get storage() {
61
61
  throw new Error("Actor.storage is only available inside a deployed actor");
62
62
  }
63
+ /**
64
+ * Anonymous Base44 client scoped to this actor instance — no user or service
65
+ * auth, so entity access is RLS-gated (same as a logged-out visitor).
66
+ * Example: `const rows = await this.client.entities.Score.list();`
67
+ */
68
+ get client() {
69
+ throw new Error("Actor.client is only available inside a deployed actor");
70
+ }
63
71
  }
package/dist/client.js CHANGED
@@ -52,27 +52,9 @@ import { createActorsModule } from "./modules/actors.js";
52
52
  */
53
53
  export function createClient(config) {
54
54
  var _a, _b;
55
- const { serverUrl = "https://base44.app", appId, token, serviceToken, requiresAuth = false, appBaseUrl, options, functionsVersion, headers: optionalHeaders, actorsWsUrl, } = config;
55
+ const { serverUrl = "https://base44.app", appId, token, serviceToken, requiresAuth = false, appBaseUrl, options, functionsVersion, headers: optionalHeaders, } = config;
56
56
  // Normalize appBaseUrl to always be a string (empty if not provided or invalid)
57
57
  const normalizedAppBaseUrl = typeof appBaseUrl === "string" ? appBaseUrl : "";
58
- // Derive the Actor WebSocket URL if not explicitly provided. Default to
59
- // the app's OWN origin (the app URL proxies /parties to the backend) so the
60
- // socket is same-origin with the running app, not the API host: prefer an
61
- // explicit appBaseUrl, then the browser origin, then fall back to serverUrl
62
- // (Node/SSR, where there's no window). Convert https:// → wss:// (http → ws)
63
- // and strip the trailing slash.
64
- const resolvedActorsWsUrl = (() => {
65
- var _a, _b;
66
- if (actorsWsUrl)
67
- return actorsWsUrl.replace(/\/$/, "");
68
- const appOrigin = normalizedAppBaseUrl ||
69
- // React Native has a bare `window` with no `location`, so guard both.
70
- (typeof window !== "undefined" ? (_b = (_a = window.location) === null || _a === void 0 ? void 0 : _a.origin) !== null && _b !== void 0 ? _b : "" : "");
71
- return (appOrigin || serverUrl)
72
- .replace(/\/$/, "")
73
- .replace(/^https:\/\//, "wss://")
74
- .replace(/^http:\/\//, "ws://");
75
- })();
76
58
  const socketConfig = {
77
59
  serverUrl,
78
60
  mountPath: "/ws-user-apps/socket.io/",
@@ -142,6 +124,12 @@ export function createClient(config) {
142
124
  userAuthModule.setToken(accessToken);
143
125
  }
144
126
  }
127
+ const actorsModule = createActorsModule({
128
+ appId,
129
+ serverUrl,
130
+ functionsVersion,
131
+ getAuthToken: () => token || getAccessToken(),
132
+ });
145
133
  const userModules = {
146
134
  entities: createEntitiesModule({
147
135
  axios: axiosClient,
@@ -179,16 +167,10 @@ export function createClient(config) {
179
167
  appId,
180
168
  userAuthModule,
181
169
  }),
182
- actors: createActorsModule({
183
- appId,
184
- actorsWsUrl: resolvedActorsWsUrl,
185
- functionsVersion,
186
- // Same credential as function calls; the platform proxy authenticates the
187
- // WS connection with it (anonymous when absent) — no pre-connect token mint.
188
- getAuthToken: () => token || getAccessToken(),
189
- }),
170
+ actors: actorsModule.module,
190
171
  cleanup: () => {
191
172
  userModules.analytics.cleanup();
173
+ actorsModule.closeAll();
192
174
  if (socket) {
193
175
  socket.disconnect();
194
176
  }
@@ -74,16 +74,6 @@ export interface CreateClientConfig {
74
74
  * Additional client options.
75
75
  */
76
76
  options?: CreateClientOptions;
77
- /**
78
- * Base WebSocket URL for Actor connections.
79
- *
80
- * Defaults to the app's own origin (`appBaseUrl`, else the browser's
81
- * `window.location.origin`, else `serverUrl`) with `https://` replaced by
82
- * `wss://` (or `http://` by `ws://`) — so the Actor socket is same-origin
83
- * with the running app, which proxies `/parties` to the backend dispatcher.
84
- * Override only when the Actor host differs from the app origin.
85
- */
86
- actorsWsUrl?: string;
87
77
  }
88
78
  /**
89
79
  * The Base44 client instance.
@@ -7,7 +7,12 @@ interface ActorsConfig {
7
7
  /** Same semantics as function calls: editors with a non-prod version get the
8
8
  * draft actor script; everyone else gets the published one. */
9
9
  functionsVersion?: string;
10
- actorsWsUrl: string;
10
+ /** The app's own origin; PartySocket strips the scheme and connects wss (ws
11
+ * for localhost), so the socket is same-origin (the app proxies /parties). */
12
+ serverUrl: string;
11
13
  }
12
- export declare function createActorsModule(config: ActorsConfig): Record<string, (instanceId: string) => ActorRoom>;
14
+ export declare function createActorsModule(config: ActorsConfig): {
15
+ module: Record<string, (instanceId: string) => ActorRoom>;
16
+ closeAll: () => void;
17
+ };
13
18
  export {};
@@ -4,10 +4,11 @@ import PartySocket from "partysocket";
4
4
  const PING_MS = 1000;
5
5
  const DEAD_MS = 3000;
6
6
  class Room {
7
- constructor(actorName, instanceId, config) {
7
+ constructor(actorName, instanceId, config, onClose) {
8
8
  this.actorName = actorName;
9
9
  this.instanceId = instanceId;
10
10
  this.config = config;
11
+ this.onClose = onClose;
11
12
  this.ws = null;
12
13
  this.listeners = new Set();
13
14
  this.heartbeat = null;
@@ -27,7 +28,7 @@ class Room {
27
28
  const connId = (_a = options === null || options === void 0 ? void 0 : options.id) !== null && _a !== void 0 ? _a : crypto.randomUUID();
28
29
  this.connId = connId;
29
30
  const ws = new PartySocket({
30
- host: this.config.actorsWsUrl,
31
+ host: this.config.serverUrl,
31
32
  party: this.actorName,
32
33
  room: this.instanceId,
33
34
  id: connId,
@@ -53,11 +54,11 @@ class Room {
53
54
  data = JSON.parse(ev.data);
54
55
  }
55
56
  catch (_a) {
56
- return; // ignore malformed
57
+ return;
57
58
  }
58
59
  const msgType = data && typeof data === "object" ? data.type : undefined;
59
60
  if (msgType === "__pong")
60
- return; // platform message — never surface it
61
+ return;
61
62
  for (const listener of this.listeners)
62
63
  listener(data);
63
64
  });
@@ -68,13 +69,12 @@ class Room {
68
69
  return;
69
70
  }
70
71
  try {
71
- // Server contract: the deployed Actor shim echoes __ping with __pong
72
- // (see base44-userapp-bundler shim/actor.ts). If that ever stops, an
73
- // idle room's lastMsg goes stale and this watchdog reconnects every DEAD_MS.
72
+ // The deployed shim echoes __ping → __pong (base44-userapp-bundler
73
+ // shim/actor.ts); without that, an idle room reconnects every DEAD_MS.
74
74
  ws.send(JSON.stringify({ type: "__ping" }));
75
75
  }
76
76
  catch (_a) {
77
- // socket not open; the watchdog above will force a reconnect
77
+ // not open; the watchdog above will reconnect
78
78
  }
79
79
  }, PING_MS);
80
80
  return this;
@@ -95,7 +95,7 @@ class Room {
95
95
  this.ws.send(JSON.stringify(data));
96
96
  }
97
97
  close() {
98
- var _a;
98
+ var _a, _b;
99
99
  if (this.heartbeat) {
100
100
  clearInterval(this.heartbeat);
101
101
  this.heartbeat = null;
@@ -103,12 +103,32 @@ class Room {
103
103
  this.listeners.clear();
104
104
  (_a = this.ws) === null || _a === void 0 ? void 0 : _a.close();
105
105
  this.ws = null;
106
+ this.connId = null;
107
+ (_b = this.onClose) === null || _b === void 0 ? void 0 : _b.call(this);
106
108
  }
107
109
  }
108
110
  export function createActorsModule(config) {
109
- return new Proxy({}, {
110
- get(_, actorName) {
111
- return (instanceId) => new Room(actorName, instanceId, config);
111
+ // Live rooms this client opened, so client.cleanup() can reclaim any the app
112
+ // forgot to close() (each room removes itself here on close).
113
+ const rooms = new Set();
114
+ const module = new Proxy({}, {
115
+ get(_, key) {
116
+ // Symbols and `then` resolve to undefined (so the module isn't mistaken
117
+ // for a thenable when awaited); any string key is an actor name.
118
+ if (typeof key !== "string" || key === "then")
119
+ return undefined;
120
+ return (instanceId) => {
121
+ const room = new Room(key, instanceId, config, () => rooms.delete(room));
122
+ rooms.add(room);
123
+ return room;
124
+ };
112
125
  },
113
126
  });
127
+ return {
128
+ module,
129
+ closeAll: () => {
130
+ for (const room of [...rooms])
131
+ room.close();
132
+ },
133
+ };
114
134
  }
@@ -58,7 +58,7 @@ export interface ActorRoom<N extends string = string> {
58
58
  connect(options?: ActorConnectOptions): this;
59
59
  /** Register a message listener. Multiple are allowed; returns a per-listener unsubscribe. */
60
60
  subscribe(callback: (data: ToClientFor<N>) => void): ActorSubscription;
61
- /** Send a message. Throws before {@link connect}; buffered by the socket until open. */
61
+ /** Send a message. Throws before {@link connect}; buffered by the socket once connecting. */
62
62
  send(data: ToServerFor<N>): void;
63
63
  /** Tear down the socket, heartbeat, and all listeners. */
64
64
  close(): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/sdk",
3
- "version": "0.8.40-pr.212.d742832",
3
+ "version": "0.8.40-pr.212.f14d383",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",