@base44-preview/sdk 0.8.39-pr.237.783a84a → 0.8.40-pr.212.5212229
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 +77 -0
- package/dist/actor.js +63 -0
- package/dist/client.js +29 -1
- package/dist/client.types.d.ts +25 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/modules/actors.d.ts +15 -0
- package/dist/modules/actors.js +112 -0
- package/dist/modules/actors.types.d.ts +89 -0
- package/dist/modules/actors.types.js +1 -0
- package/dist/modules/sso.d.ts +0 -1
- package/dist/modules/sso.js +5 -1
- package/dist/modules/sso.types.d.ts +27 -3
- package/package.json +3 -2
package/dist/actor.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-only base class for Actors.
|
|
3
|
+
*
|
|
4
|
+
* Import and extend this in your actor files:
|
|
5
|
+
* import { Actor } from "@base44/sdk";
|
|
6
|
+
* export class MyActor extends Actor { ... }
|
|
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
|
+
/**
|
|
12
|
+
* A single client connection. `Send` is the message type this connection accepts
|
|
13
|
+
* via {@link send} — the actor's *outgoing* (server→client) messages.
|
|
14
|
+
*/
|
|
15
|
+
export interface Conn<Send = unknown> {
|
|
16
|
+
/** Unique per-connection id (one per socket/tab), the same value the client
|
|
17
|
+
* receives from `subscribe()`. Use this — not userId — to identify a distinct
|
|
18
|
+
* client, so multiple tabs of the same user are separate connections. */
|
|
19
|
+
id: string;
|
|
20
|
+
userId: string;
|
|
21
|
+
appId: string;
|
|
22
|
+
instanceId: string;
|
|
23
|
+
send(data: Send): void;
|
|
24
|
+
reject(code: number, reason: string): void;
|
|
25
|
+
}
|
|
26
|
+
export interface Storage {
|
|
27
|
+
get<T>(key: string): Promise<T | undefined>;
|
|
28
|
+
put(key: string, value: unknown): Promise<void>;
|
|
29
|
+
delete(key: string): Promise<boolean>;
|
|
30
|
+
/** Wipe the room's entire persisted storage (match-end cleanup). Safe: a
|
|
31
|
+
* later rejoin re-bootstraps exactly like a brand-new room. */
|
|
32
|
+
deleteAll(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Base class for an Actor.
|
|
36
|
+
*
|
|
37
|
+
* @typeParam Incoming - messages this actor *receives* from clients
|
|
38
|
+
* (`handleMessage`'s `msg`) — the schema's `toServer` section.
|
|
39
|
+
* @typeParam Outgoing - messages this actor *sends* to clients
|
|
40
|
+
* (`conn.send`/`broadcast`) — the schema's `toClient` section.
|
|
41
|
+
*
|
|
42
|
+
* With a generated `schema.jsonc`, wire both from the registry so they can't drift
|
|
43
|
+
* from the client's types:
|
|
44
|
+
* ```ts
|
|
45
|
+
* type Reg = ActorRegistry["MyActor"];
|
|
46
|
+
* class MyActor extends Actor<Reg["toServer"], Reg["toClient"]> { ... }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare abstract class Actor<Incoming = unknown, Outgoing = unknown> {
|
|
50
|
+
abstract handleConnect(conn: Conn<Outgoing>): void | Promise<void>;
|
|
51
|
+
abstract handleMessage(conn: Conn<Outgoing>, msg: Incoming): void | Promise<void>;
|
|
52
|
+
abstract handleClose(conn: Conn<Outgoing>): void | Promise<void>;
|
|
53
|
+
abstract handleTick(): void | Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Optional wake hook: runs once when the instance starts, before any
|
|
56
|
+
* connection is handled — safe to load persisted state here.
|
|
57
|
+
*/
|
|
58
|
+
handleStart(): void | Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Managed ticker (opt-in). Override {@link shouldTick} and the platform runs
|
|
61
|
+
* {@link handleTick} on a timer of {@link tickIntervalMs} while it returns true,
|
|
62
|
+
* and stops (letting the Durable Object hibernate — no compute cost) when it
|
|
63
|
+
* returns false. The platform owns scheduling, rescheduling, self-heal, and
|
|
64
|
+
* error-safety — you don't call {@link startLoop}/{@link stopLoop}.
|
|
65
|
+
*
|
|
66
|
+
* Re-evaluated after every connect/message/close and on every tick, so keep it
|
|
67
|
+
* cheap and pure (no async, no side effects). Example: `return this.players >= 2`.
|
|
68
|
+
*/
|
|
69
|
+
protected tickIntervalMs: number;
|
|
70
|
+
protected shouldTick?(): boolean;
|
|
71
|
+
protected broadcast(_data: Outgoing): void;
|
|
72
|
+
protected getConnections(): Conn<Outgoing>[];
|
|
73
|
+
protected startLoop(_ms: number): Promise<void>;
|
|
74
|
+
protected stopLoop(): Promise<void>;
|
|
75
|
+
protected get instanceId(): string;
|
|
76
|
+
protected get storage(): Storage;
|
|
77
|
+
}
|
package/dist/actor.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-only base class for Actors.
|
|
3
|
+
*
|
|
4
|
+
* Import and extend this in your actor files:
|
|
5
|
+
* import { Actor } from "@base44/sdk";
|
|
6
|
+
* export class MyActor extends Actor { ... }
|
|
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
|
+
/**
|
|
12
|
+
* Base class for an Actor.
|
|
13
|
+
*
|
|
14
|
+
* @typeParam Incoming - messages this actor *receives* from clients
|
|
15
|
+
* (`handleMessage`'s `msg`) — the schema's `toServer` section.
|
|
16
|
+
* @typeParam Outgoing - messages this actor *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 = ActorRegistry["MyActor"];
|
|
23
|
+
* class MyActor extends Actor<Reg["toServer"], Reg["toClient"]> { ... }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export class Actor {
|
|
27
|
+
constructor() {
|
|
28
|
+
/**
|
|
29
|
+
* Managed ticker (opt-in). Override {@link shouldTick} and the platform runs
|
|
30
|
+
* {@link handleTick} on a timer of {@link tickIntervalMs} while it returns true,
|
|
31
|
+
* and stops (letting the Durable Object hibernate — no compute cost) when it
|
|
32
|
+
* returns false. The platform owns scheduling, rescheduling, self-heal, and
|
|
33
|
+
* error-safety — you don't call {@link startLoop}/{@link stopLoop}.
|
|
34
|
+
*
|
|
35
|
+
* Re-evaluated after every connect/message/close and on every tick, so keep it
|
|
36
|
+
* cheap and pure (no async, no side effects). Example: `return this.players >= 2`.
|
|
37
|
+
*/
|
|
38
|
+
this.tickIntervalMs = 100;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Optional wake hook: runs once when the instance starts, before any
|
|
42
|
+
* connection is handled — safe to load persisted state here.
|
|
43
|
+
*/
|
|
44
|
+
handleStart() { }
|
|
45
|
+
broadcast(_data) {
|
|
46
|
+
throw new Error("Actor.broadcast() is only available inside a deployed actor");
|
|
47
|
+
}
|
|
48
|
+
getConnections() {
|
|
49
|
+
throw new Error("Actor.getConnections() is only available inside a deployed actor");
|
|
50
|
+
}
|
|
51
|
+
startLoop(_ms) {
|
|
52
|
+
throw new Error("Actor.startLoop() is only available inside a deployed actor");
|
|
53
|
+
}
|
|
54
|
+
stopLoop() {
|
|
55
|
+
throw new Error("Actor.stopLoop() is only available inside a deployed actor");
|
|
56
|
+
}
|
|
57
|
+
get instanceId() {
|
|
58
|
+
throw new Error("Actor.instanceId is only available inside a deployed actor");
|
|
59
|
+
}
|
|
60
|
+
get storage() {
|
|
61
|
+
throw new Error("Actor.storage is only available inside a deployed actor");
|
|
62
|
+
}
|
|
63
|
+
}
|
package/dist/client.js
CHANGED
|
@@ -12,6 +12,7 @@ import { createAppLogsModule } from "./modules/app-logs.js";
|
|
|
12
12
|
import { createUsersModule } from "./modules/users.js";
|
|
13
13
|
import { RoomsSocket } from "./utils/socket-utils.js";
|
|
14
14
|
import { createAnalyticsModule } from "./modules/analytics.js";
|
|
15
|
+
import { createActorsModule } from "./modules/actors.js";
|
|
15
16
|
/**
|
|
16
17
|
* Creates a Base44 client.
|
|
17
18
|
*
|
|
@@ -51,9 +52,27 @@ import { createAnalyticsModule } from "./modules/analytics.js";
|
|
|
51
52
|
*/
|
|
52
53
|
export function createClient(config) {
|
|
53
54
|
var _a, _b;
|
|
54
|
-
const { serverUrl = "https://base44.app", appId, token, serviceToken, requiresAuth = false, appBaseUrl, options, functionsVersion, headers: optionalHeaders, } = config;
|
|
55
|
+
const { serverUrl = "https://base44.app", appId, token, serviceToken, requiresAuth = false, appBaseUrl, options, functionsVersion, headers: optionalHeaders, dispatcherWsUrl, webSocketImpl, } = config;
|
|
55
56
|
// Normalize appBaseUrl to always be a string (empty if not provided or invalid)
|
|
56
57
|
const normalizedAppBaseUrl = typeof appBaseUrl === "string" ? appBaseUrl : "";
|
|
58
|
+
// Derive the dispatcher 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 resolvedDispatcherWsUrl = (() => {
|
|
65
|
+
var _a, _b;
|
|
66
|
+
if (dispatcherWsUrl)
|
|
67
|
+
return dispatcherWsUrl.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
|
+
})();
|
|
57
76
|
const socketConfig = {
|
|
58
77
|
serverUrl,
|
|
59
78
|
mountPath: "/ws-user-apps/socket.io/",
|
|
@@ -160,6 +179,15 @@ export function createClient(config) {
|
|
|
160
179
|
appId,
|
|
161
180
|
userAuthModule,
|
|
162
181
|
}),
|
|
182
|
+
actors: createActorsModule({
|
|
183
|
+
appId,
|
|
184
|
+
dispatcherWsUrl: resolvedDispatcherWsUrl,
|
|
185
|
+
webSocketImpl,
|
|
186
|
+
functionsVersion,
|
|
187
|
+
// Same credential as function calls; the platform proxy authenticates the
|
|
188
|
+
// WS connection with it (anonymous when absent) — no pre-connect token mint.
|
|
189
|
+
getAuthToken: () => token || getAccessToken(),
|
|
190
|
+
}),
|
|
163
191
|
cleanup: () => {
|
|
164
192
|
userModules.analytics.cleanup();
|
|
165
193
|
if (socket) {
|
package/dist/client.types.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { AgentsModule } from "./modules/agents.types.js";
|
|
|
8
8
|
import type { AiGatewayModule } from "./modules/ai-gateway.types.js";
|
|
9
9
|
import type { AppLogsModule } from "./modules/app-logs.types.js";
|
|
10
10
|
import type { AnalyticsModule } from "./modules/analytics.types.js";
|
|
11
|
+
import type { ActorsModule } from "./modules/actors.types.js";
|
|
11
12
|
/**
|
|
12
13
|
* Options for creating a Base44 client.
|
|
13
14
|
*/
|
|
@@ -73,6 +74,28 @@ export interface CreateClientConfig {
|
|
|
73
74
|
* Additional client options.
|
|
74
75
|
*/
|
|
75
76
|
options?: CreateClientOptions;
|
|
77
|
+
/**
|
|
78
|
+
* Base WebSocket URL for the Cloudflare Durable Object dispatcher.
|
|
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 realtime socket is same-origin
|
|
83
|
+
* with the running app, which proxies `/parties` to the backend.
|
|
84
|
+
* Override when the dispatcher lives at a different host than the app.
|
|
85
|
+
*/
|
|
86
|
+
dispatcherWsUrl?: string;
|
|
87
|
+
/**
|
|
88
|
+
* WebSocket implementation for realtime subscriptions in environments
|
|
89
|
+
* without a global `WebSocket` (Node.js < 22). Browsers and Node ≥ 22
|
|
90
|
+
* don't need this.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* import WS from "ws";
|
|
95
|
+
* const base44 = createClient({ appId, webSocketImpl: WS });
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
webSocketImpl?: unknown;
|
|
76
99
|
}
|
|
77
100
|
/**
|
|
78
101
|
* The Base44 client instance.
|
|
@@ -88,6 +111,8 @@ export interface Base44Client {
|
|
|
88
111
|
analytics: AnalyticsModule;
|
|
89
112
|
/** {@link AppLogsModule | App logs module} for tracking app usage. */
|
|
90
113
|
appLogs: AppLogsModule;
|
|
114
|
+
/** {@link ActorsModule | Actors module} for subscribing to and sending messages via Cloudflare Durable Object-backed Actors. */
|
|
115
|
+
actors: ActorsModule;
|
|
91
116
|
/** {@link AuthModule | Auth module} for user authentication and management. */
|
|
92
117
|
auth: AuthModule;
|
|
93
118
|
/** {@link UserConnectorsModule | Connectors module} for app-user OAuth flows. */
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,9 @@ export type { FunctionsModule, FunctionName, FunctionNameRegistry, } from "./mod
|
|
|
11
11
|
export type { AgentsModule, AgentName, AgentNameRegistry, AgentConversation, AgentMessage, AgentMessageReasoning, AgentMessageToolCall, AgentMessageUsage, AgentMessageCustomContext, AgentMessageMetadata, CreateConversationParams, } from "./modules/agents.types.js";
|
|
12
12
|
export type { AiGatewayModule, AiGatewayConnection, } from "./modules/ai-gateway.types.js";
|
|
13
13
|
export type { AppLogsModule } from "./modules/app-logs.types.js";
|
|
14
|
+
export type { ActorsModule, ActorClient, ActorNameRegistry, ActorRegistry, } from "./modules/actors.types.js";
|
|
14
15
|
export type { SsoModule, SsoAccessTokenResponse } from "./modules/sso.types.js";
|
|
16
|
+
export { Actor, type Conn } from "./actor.js";
|
|
15
17
|
export type { ConnectorsModule, UserConnectorsModule, } from "./modules/connectors.types.js";
|
|
16
18
|
export type { CustomIntegrationsModule, CustomIntegrationCallParams, CustomIntegrationCallResponse, } from "./modules/custom-integrations.types.js";
|
|
17
19
|
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 { Actor } from "./actor.js";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ActorRoom } from "./actors.types.js";
|
|
2
|
+
interface ActorsConfig {
|
|
3
|
+
appId: string;
|
|
4
|
+
/** Current user access token, if authenticated. Rides the WS query so the
|
|
5
|
+
* platform proxy can authenticate the connection; anonymous connects omit it. */
|
|
6
|
+
getAuthToken(): string | null | undefined;
|
|
7
|
+
/** Same semantics as function calls: editors with a non-prod version get the
|
|
8
|
+
* draft actor script; everyone else gets the published one. */
|
|
9
|
+
functionsVersion?: string;
|
|
10
|
+
dispatcherWsUrl: string;
|
|
11
|
+
/** WebSocket implementation for runtimes without a global one (Node < 22). */
|
|
12
|
+
webSocketImpl?: unknown;
|
|
13
|
+
}
|
|
14
|
+
export declare function createActorsModule(config: ActorsConfig): Record<string, (instanceId: string) => ActorRoom>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import PartySocket from "partysocket";
|
|
2
|
+
// Heartbeat / half-open detection: PartySocket only reconnects on a close/error
|
|
3
|
+
// event, so ping periodically and force a reconnect if nothing returns in DEAD_MS.
|
|
4
|
+
const PING_MS = 1000;
|
|
5
|
+
const DEAD_MS = 3000;
|
|
6
|
+
class Room {
|
|
7
|
+
constructor(actorName, instanceId, config) {
|
|
8
|
+
this.actorName = actorName;
|
|
9
|
+
this.instanceId = instanceId;
|
|
10
|
+
this.config = config;
|
|
11
|
+
this.ws = null;
|
|
12
|
+
this.listeners = new Set();
|
|
13
|
+
this.heartbeat = null;
|
|
14
|
+
this.connId = null;
|
|
15
|
+
}
|
|
16
|
+
get id() {
|
|
17
|
+
if (!this.connId) {
|
|
18
|
+
throw new Error(`${this.actorName}:${this.instanceId}: connect() before reading id`);
|
|
19
|
+
}
|
|
20
|
+
return this.connId;
|
|
21
|
+
}
|
|
22
|
+
connect(options) {
|
|
23
|
+
var _a;
|
|
24
|
+
if (this.ws)
|
|
25
|
+
return this;
|
|
26
|
+
// The client picks its own conn id; it becomes _pk → the actor's conn.id.
|
|
27
|
+
const connId = (_a = options === null || options === void 0 ? void 0 : options.id) !== null && _a !== void 0 ? _a : crypto.randomUUID();
|
|
28
|
+
this.connId = connId;
|
|
29
|
+
const ws = new PartySocket({
|
|
30
|
+
host: this.config.dispatcherWsUrl,
|
|
31
|
+
party: this.actorName,
|
|
32
|
+
room: this.instanceId,
|
|
33
|
+
id: connId,
|
|
34
|
+
...(this.config.webSocketImpl ? { WebSocket: this.config.webSocketImpl } : {}),
|
|
35
|
+
// Re-read on every (re)connect so a login/logout is picked up.
|
|
36
|
+
query: () => {
|
|
37
|
+
const token = this.config.getAuthToken();
|
|
38
|
+
return {
|
|
39
|
+
app_id: this.config.appId,
|
|
40
|
+
handler: this.actorName,
|
|
41
|
+
...(token ? { token } : {}),
|
|
42
|
+
...(this.config.functionsVersion ? { fv: this.config.functionsVersion } : {}),
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
this.ws = ws;
|
|
47
|
+
let lastMsg = Date.now();
|
|
48
|
+
const bumpAlive = () => { lastMsg = Date.now(); };
|
|
49
|
+
ws.addEventListener("open", bumpAlive);
|
|
50
|
+
ws.addEventListener("message", (ev) => {
|
|
51
|
+
bumpAlive();
|
|
52
|
+
let data;
|
|
53
|
+
try {
|
|
54
|
+
data = JSON.parse(ev.data);
|
|
55
|
+
}
|
|
56
|
+
catch (_a) {
|
|
57
|
+
return; // ignore malformed
|
|
58
|
+
}
|
|
59
|
+
const msgType = data && typeof data === "object" ? data.type : undefined;
|
|
60
|
+
if (msgType === "__pong")
|
|
61
|
+
return; // platform message — never surface it
|
|
62
|
+
for (const listener of this.listeners)
|
|
63
|
+
listener(data);
|
|
64
|
+
});
|
|
65
|
+
this.heartbeat = setInterval(() => {
|
|
66
|
+
if (Date.now() - lastMsg > DEAD_MS) {
|
|
67
|
+
bumpAlive(); // avoid a reconnect storm while the new socket comes up
|
|
68
|
+
ws.reconnect();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
ws.send(JSON.stringify({ type: "__ping" }));
|
|
73
|
+
}
|
|
74
|
+
catch (_a) {
|
|
75
|
+
// socket not open; the watchdog above will force a reconnect
|
|
76
|
+
}
|
|
77
|
+
}, PING_MS);
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
subscribe(callback) {
|
|
81
|
+
if (!this.ws) {
|
|
82
|
+
throw new Error(`${this.actorName}:${this.instanceId}: connect() before subscribe()`);
|
|
83
|
+
}
|
|
84
|
+
this.listeners.add(callback);
|
|
85
|
+
return {
|
|
86
|
+
unsubscribe: () => { this.listeners.delete(callback); },
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
send(data) {
|
|
90
|
+
if (!this.ws) {
|
|
91
|
+
throw new Error(`${this.actorName}:${this.instanceId}: connect() before send()`);
|
|
92
|
+
}
|
|
93
|
+
this.ws.send(JSON.stringify(data));
|
|
94
|
+
}
|
|
95
|
+
close() {
|
|
96
|
+
var _a;
|
|
97
|
+
if (this.heartbeat) {
|
|
98
|
+
clearInterval(this.heartbeat);
|
|
99
|
+
this.heartbeat = null;
|
|
100
|
+
}
|
|
101
|
+
this.listeners.clear();
|
|
102
|
+
(_a = this.ws) === null || _a === void 0 ? void 0 : _a.close();
|
|
103
|
+
this.ws = null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export function createActorsModule(config) {
|
|
107
|
+
return new Proxy({}, {
|
|
108
|
+
get(_, actorName) {
|
|
109
|
+
return (instanceId) => new Room(actorName, instanceId, config);
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extend this interface to add typed `subscribe` callbacks and `send` payloads
|
|
3
|
+
* for your deployed Actors.
|
|
4
|
+
*
|
|
5
|
+
* This is separate from {@link ActorNameRegistry} (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 ActorRegistry {
|
|
12
|
+
* ChatRoom: {
|
|
13
|
+
* toClient: { type: "joined" | "left" | "message"; userId?: string; from?: string; text?: string };
|
|
14
|
+
* toServer: { type: "message"; text: string };
|
|
15
|
+
* };
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export interface ActorRegistry {
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Auto-populated by `base44 types generate` with the names of your deployed actors.
|
|
24
|
+
* Do not edit this interface manually — use {@link ActorRegistry} for message types.
|
|
25
|
+
*/
|
|
26
|
+
export interface ActorNameRegistry {
|
|
27
|
+
}
|
|
28
|
+
type AllActorNames = keyof ActorRegistry | keyof ActorNameRegistry;
|
|
29
|
+
type ToClientFor<N extends string> = N extends keyof ActorRegistry ? ActorRegistry[N] extends {
|
|
30
|
+
toClient: infer I;
|
|
31
|
+
} ? I : unknown : unknown;
|
|
32
|
+
type ToServerFor<N extends string> = N extends keyof ActorRegistry ? ActorRegistry[N] extends {
|
|
33
|
+
toServer: infer O;
|
|
34
|
+
} ? O : unknown : unknown;
|
|
35
|
+
/** Options for {@link ActorRoom.connect}. */
|
|
36
|
+
export interface ActorConnectOptions {
|
|
37
|
+
/**
|
|
38
|
+
* The connection id — becomes the actor's `conn.id`. Supply a stable value
|
|
39
|
+
* (e.g. persisted per tab) so a reconnect reuses the same server-side
|
|
40
|
+
* identity; omit for an auto-generated per-connection id.
|
|
41
|
+
*/
|
|
42
|
+
id?: string;
|
|
43
|
+
}
|
|
44
|
+
/** Handle for one listener registered via {@link ActorRoom.subscribe}. */
|
|
45
|
+
export interface ActorSubscription {
|
|
46
|
+
/** Remove this listener; other listeners and the socket stay live. */
|
|
47
|
+
unsubscribe(): void;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A single actor room. Obtained from {@link ActorClient} (`actors.MyActor(id)`)
|
|
51
|
+
* and made live with {@link connect}. The handle IS the connection: one socket,
|
|
52
|
+
* any number of {@link subscribe} listeners.
|
|
53
|
+
*/
|
|
54
|
+
export interface ActorRoom<N extends string = string> {
|
|
55
|
+
/** The connection id (the value the actor sees as `conn.id`). Throws before {@link connect}. */
|
|
56
|
+
readonly id: string;
|
|
57
|
+
/** Open the WebSocket (required before subscribe/send). Idempotent; returns this. */
|
|
58
|
+
connect(options?: ActorConnectOptions): this;
|
|
59
|
+
/** Register a message listener. Multiple are allowed; returns a per-listener unsubscribe. */
|
|
60
|
+
subscribe(callback: (data: ToClientFor<N>) => void): ActorSubscription;
|
|
61
|
+
/** Send a message. Throws before {@link connect}; buffered by the socket until open. */
|
|
62
|
+
send(data: ToServerFor<N>): void;
|
|
63
|
+
/** Tear down the socket, heartbeat, and all listeners. */
|
|
64
|
+
close(): void;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Client for a single named Actor — call it with a room id to get an
|
|
68
|
+
* {@link ActorRoom}. Typed automatically when the actor is registered in
|
|
69
|
+
* {@link ActorRegistry}.
|
|
70
|
+
*/
|
|
71
|
+
export interface ActorClient<N extends string = string> {
|
|
72
|
+
(instanceId: string): ActorRoom<N>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The actors module provides access to Cloudflare Durable Object-backed
|
|
76
|
+
* Actors deployed by the Base44 platform.
|
|
77
|
+
*
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const room = base44.actors.MyActor("room-1").connect();
|
|
80
|
+
* const sub = room.subscribe((msg) => console.log(msg)); // typed via ActorRegistry
|
|
81
|
+
* room.send({ type: "message", text: "hi" });
|
|
82
|
+
* sub.unsubscribe();
|
|
83
|
+
* room.close();
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export type ActorsModule = {
|
|
87
|
+
[K in AllActorNames]: K extends keyof ActorRegistry ? ActorClient<string & K> : ActorClient;
|
|
88
|
+
} & Record<string, ActorClient>;
|
|
89
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/modules/sso.d.ts
CHANGED
package/dist/modules/sso.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @param axios - Axios instance
|
|
5
5
|
* @param appId - Application ID
|
|
6
|
-
* @param userToken - User authentication token
|
|
7
6
|
* @returns SSO module with authentication methods
|
|
8
7
|
* @internal
|
|
9
8
|
*/
|
|
@@ -14,5 +13,10 @@ export function createSsoModule(axios, appId) {
|
|
|
14
13
|
const url = `/apps/${appId}/auth/sso/accesstoken/${userid}`;
|
|
15
14
|
return axios.get(url);
|
|
16
15
|
},
|
|
16
|
+
// Get the stored SSO OIDC ID token for a specific user
|
|
17
|
+
async getIdToken(userid) {
|
|
18
|
+
const url = `/apps/${appId}/auth/sso/idtoken/${userid}`;
|
|
19
|
+
return axios.get(url);
|
|
20
|
+
},
|
|
17
21
|
};
|
|
18
22
|
}
|
|
@@ -8,9 +8,9 @@ export interface SsoAccessTokenResponse {
|
|
|
8
8
|
/**
|
|
9
9
|
* SSO (Single Sign-On) module for managing SSO authentication.
|
|
10
10
|
*
|
|
11
|
-
* This module provides methods for retrieving SSO
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* This module provides methods for retrieving SSO tokens for users. These
|
|
12
|
+
* tokens allow you to authenticate Base44 users with external systems or
|
|
13
|
+
* services.
|
|
14
14
|
*
|
|
15
15
|
* This module is only available to use with a client in service role authentication mode, which means it can only be used in backend environments.
|
|
16
16
|
*
|
|
@@ -41,4 +41,28 @@ export interface SsoModule {
|
|
|
41
41
|
* ```
|
|
42
42
|
*/
|
|
43
43
|
getAccessToken(userid: string): Promise<SsoAccessTokenResponse>;
|
|
44
|
+
/**
|
|
45
|
+
* Gets the stored SSO OIDC ID token for the current app user.
|
|
46
|
+
*
|
|
47
|
+
* The service-role client must include an on-behalf-of token for the same
|
|
48
|
+
* user specified by `userid`. This method returns the stored token as-is and
|
|
49
|
+
* does not refresh it.
|
|
50
|
+
*
|
|
51
|
+
* @param userid - The current app user's ID.
|
|
52
|
+
* @returns Promise resolving to the raw ID-token string.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* import { createClientFromRequest } from 'npm:@base44/sdk';
|
|
57
|
+
*
|
|
58
|
+
* Deno.serve(async (req) => {
|
|
59
|
+
* const base44 = createClientFromRequest(req);
|
|
60
|
+
* const user = await base44.auth.me();
|
|
61
|
+
* const idToken = await base44.asServiceRole.sso.getIdToken(user.id);
|
|
62
|
+
*
|
|
63
|
+
* return Response.json({ idToken });
|
|
64
|
+
* });
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
getIdToken(userid: string): Promise<string>;
|
|
44
68
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@base44-preview/sdk",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.40-pr.212.5212229",
|
|
4
4
|
"description": "JavaScript SDK for Base44 API",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"create-docs:process": "node scripts/mintlify-post-processing/file-processing/file-processing.js"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"axios": "^1.
|
|
29
|
+
"axios": "^1.18.1",
|
|
30
|
+
"partysocket": "^0.0.23",
|
|
30
31
|
"socket.io-client": "^4.8.3",
|
|
31
32
|
"uuid": "^13.0.2"
|
|
32
33
|
},
|