@base44-preview/sdk 0.8.48-pr.282.8f60b80 → 0.8.48-pr.282.b3c4c1e

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
@@ -5,7 +5,7 @@ import { createAuthModule } from "./modules/auth.js";
5
5
  import { createSsoModule } from "./modules/sso.js";
6
6
  import { createConnectorsModule, createUserConnectorsModule, } from "./modules/connectors.js";
7
7
  import { getAccessToken } from "./utils/auth-utils.js";
8
- import { exchangeEmbedToken, frameSession, isFramed, takeEmbedTokenFromUrl, } from "./utils/embed-session.js";
8
+ import { exchangeEmbedToken, takeEmbedTokenFromUrl, } from "./utils/embed-session.js";
9
9
  import { createFetchWithAuth } from "./utils/fetch-with-auth.js";
10
10
  import { createFunctionsModule } from "./modules/functions.js";
11
11
  import { createAgentsModule } from "./modules/agents.js";
@@ -58,16 +58,34 @@ export function createClient(config) {
58
58
  const { serverUrl = "https://base44.app", appId, analytics, serviceToken, requiresAuth = false, appBaseUrl, options, functionsVersion, headers: optionalHeaders, } = config;
59
59
  // Normalize appBaseUrl to always be a string (empty if not provided or invalid)
60
60
  const normalizedAppBaseUrl = typeof appBaseUrl === "string" ? appBaseUrl : "";
61
- // Always taken off the URL, even outside a frame: a one-time token must not
62
- // be left in the address bar, in history, or in a shared link.
63
- const urlOtt = takeEmbedTokenFromUrl();
64
- // Only redeemed inside a frame. Opened as a normal tab, the same URL falls
65
- // back to the app's own login, which works there and cannot work in a frame.
66
- const embedOtt = isFramed() ? urlOtt : null;
67
- const embedded = Boolean(embedOtt);
68
- // The passed token is the OTT itself whenever one came in on the URL. That is
69
- // not this session: it is what the exchange below trades for one.
70
- const token = urlOtt !== null ? undefined : config.token;
61
+ const embedOtt = takeEmbedTokenFromUrl();
62
+ // Asked again on every use, so a session that arrives later — from the
63
+ // exchange, or from a login — reaches the socket and every other module.
64
+ // A declaration, not a const, so this block can stay above the auth module.
65
+ function getToken() {
66
+ var _a;
67
+ return (_a = userAuthModule.getToken()) !== null && _a !== void 0 ? _a : (embedOtt ? null : getAccessToken());
68
+ }
69
+ const socketConfig = {
70
+ serverUrl,
71
+ mountPath: "/ws-user-apps/socket.io/",
72
+ transports: ["websocket"],
73
+ appId,
74
+ getToken,
75
+ };
76
+ let socket = null;
77
+ const getSocket = () => {
78
+ if (!socket) {
79
+ socket = RoomsSocket({
80
+ config: socketConfig,
81
+ });
82
+ }
83
+ return socket;
84
+ };
85
+ // Apps read getAccessToken() as they load and pass the result in as `token`,
86
+ // so on an embedded load this is the OTT: proof of an identity, not one to
87
+ // send as a bearer. The exchange below is what turns it into a session.
88
+ const token = embedOtt ? undefined : config.token;
71
89
  const headers = {
72
90
  ...optionalHeaders,
73
91
  "X-App-Id": String(appId),
@@ -116,14 +134,11 @@ export function createClient(config) {
116
134
  baseURL: `${serverUrl}/api`,
117
135
  headers,
118
136
  });
119
- // Declared before the auth module so `onSessionChange` can reach it; the
120
- // socket itself is still only built on first use, below.
121
- let socket = null;
122
137
  const userAuthModule = createAuthModule(axiosClient, functionsAxiosClient, appId, {
123
138
  appBaseUrl: normalizedAppBaseUrl,
124
139
  serverUrl,
125
140
  token,
126
- embedded,
141
+ embedded: Boolean(embedOtt),
127
142
  // The socket carries its token on the handshake, so an identity change
128
143
  // only reaches it by opening a new connection — or, on logout, by
129
144
  // dropping the one still running as the user who just left.
@@ -133,34 +148,17 @@ export function createClient(config) {
133
148
  // requests during construction (notably analytics, which fires an init
134
149
  // event whose flush calls auth.me()). Without this, the first User/me
135
150
  // request is built before setToken runs and goes out unauthenticated.
136
- // Skipped in a frame: the session comes from the exchange below.
137
- if (typeof window !== "undefined" && !embedded) {
151
+ // Not in a frame: a stored token there belongs to an earlier visitor, not to
152
+ // this session, which only the exchange below can produce.
153
+ if (typeof window !== "undefined" && !embedOtt) {
138
154
  const accessToken = token || getAccessToken();
139
155
  if (accessToken) {
140
156
  userAuthModule.setToken(accessToken);
141
157
  }
142
158
  }
143
- // Live token for every module; outside a frame it still falls back to storage.
144
- const getToken = () => { var _a; return (_a = userAuthModule.getToken()) !== null && _a !== void 0 ? _a : (embedded ? null : getAccessToken()); };
145
- const socketConfig = {
146
- serverUrl,
147
- mountPath: "/ws-user-apps/socket.io/",
148
- transports: ["websocket"],
149
- appId,
150
- getToken,
151
- };
152
- const getSocket = () => {
153
- if (!socket) {
154
- socket = RoomsSocket({ config: socketConfig });
155
- }
156
- return socket;
157
- };
158
- // The exchange belongs to the frame, not to one client: the token is off the
159
- // URL after the first `createClient`, so a second one in the same document
160
- // joins the session already being negotiated rather than going anonymous.
161
159
  const session = embedOtt
162
- ? frameSession(appId, () => exchangeEmbedToken({ serverUrl, appId, ott: embedOtt }))
163
- : frameSession(appId);
160
+ ? exchangeEmbedToken({ serverUrl, appId, ott: embedOtt })
161
+ : null;
164
162
  // Settles once the exchanged session is applied (memory only); at once
165
163
  // otherwise. Never rejects: every request waits on it, so a failure here
166
164
  // must not turn into a rejection on each of them.
@@ -182,21 +180,6 @@ export function createClient(config) {
182
180
  console.error("Base44: applying the embedded session failed:", e);
183
181
  })
184
182
  : Promise.resolve();
185
- // Everything that can wait for the session does. `aiGateway.connection()`
186
- // and the agents connect URLs cannot: they hand back a value, not a promise,
187
- // and a value read now would stay wrong after the session arrives. They warn
188
- // instead of failing quietly.
189
- let warnedEarlyRead = false;
190
- const getTokenNow = () => {
191
- const sessionToken = getToken();
192
- if (sessionToken === null && session && !warnedEarlyRead) {
193
- warnedEarlyRead = true;
194
- console.warn("Base44: read a token before the embedded session was ready, so it is " +
195
- "empty. Await a call such as base44.auth.me() before building a " +
196
- "client or a URL that keeps the token.");
197
- }
198
- return sessionToken;
199
- };
200
183
  if (session) {
201
184
  // Requests issued during the exchange wait for it. Registered after createAxiosClient's
202
185
  // interceptors so it runs first and the anonymous-visitor header sees the Authorization.
@@ -264,13 +247,11 @@ export function createClient(config) {
264
247
  getSocket,
265
248
  appId,
266
249
  serverUrl,
267
- getToken: getTokenNow,
268
- }),
269
- aiGateway: createAiGatewayModule({
270
- serverUrl,
271
- getToken: getTokenNow,
272
- appId,
250
+ // Read synchronously, unlike everything else: these build a URL rather
251
+ // than issue a request, so during the exchange they see no token.
252
+ getToken,
273
253
  }),
254
+ aiGateway: createAiGatewayModule({ serverUrl, getToken, appId }),
274
255
  appLogs: createAppLogsModule(axiosClient, appId),
275
256
  app: createAppModule(axiosClient, appId),
276
257
  users: createUsersModule(axiosClient, appId),
@@ -318,7 +299,7 @@ export function createClient(config) {
318
299
  // The user's token, as on the user-scoped module: the only thing this is
319
300
  // read for is the `?token=` on a channel URL handed to that user, which
320
301
  // the app's service credential must never end up in.
321
- getToken: getTokenNow,
302
+ getToken,
322
303
  }),
323
304
  aiGateway: createAiGatewayModule({
324
305
  serverUrl,
@@ -11,8 +11,9 @@ interface ActorsConfig {
11
11
  appId: string;
12
12
  /** Current user access token, if authenticated. Rides the WS query on the
13
13
  * proxy-fallback path so the platform proxy can authenticate the connection;
14
- * anonymous connects omit it. */
15
- getAuthToken(): string | null | undefined | Promise<string | null | undefined>;
14
+ * anonymous connects omit it. Awaited per dial, so a session still being
15
+ * exchanged is in hand before the URL is built. */
16
+ getAuthToken(): Promise<string | null | undefined>;
16
17
  /** Same semantics as function calls: editors with a non-prod version get the
17
18
  * draft actor script; everyone else gets the published one. */
18
19
  functionsVersion?: string;
@@ -7,6 +7,12 @@
7
7
  * grant (RFC 8693), and keeps the result in memory only — never in storage — so
8
8
  * the session lives and dies with the frame.
9
9
  *
10
+ * Taking the token off the URL is unconditional — a one-time token must not be
11
+ * left in the address bar, in history, or in a shared link — but it is only
12
+ * reported back inside a frame, the only place one is redeemed. It is gone once
13
+ * the first client has taken it, so the session belongs to that client — an app
14
+ * creates one.
15
+ *
10
16
  * The exchange endpoint is rate limited per app, and its limiter refuses before
11
17
  * the one-time token is redeemed — so a 429 leaves the token still valid and is
12
18
  * worth retrying once.
@@ -15,8 +21,6 @@
15
21
  */
16
22
  export declare const EMBED_TOKEN_PARAM = "ott";
17
23
  /** @internal */
18
- export declare function frameSession(appId: string, start?: () => Promise<string | null>): Promise<string | null> | null;
19
- /** @internal */
20
24
  export declare function takeEmbedTokenFromUrl(): string | null;
21
25
  /** @internal */
22
26
  export declare function isFramed(): boolean;
@@ -7,6 +7,12 @@
7
7
  * grant (RFC 8693), and keeps the result in memory only — never in storage — so
8
8
  * the session lives and dies with the frame.
9
9
  *
10
+ * Taking the token off the URL is unconditional — a one-time token must not be
11
+ * left in the address bar, in history, or in a shared link — but it is only
12
+ * reported back inside a frame, the only place one is redeemed. It is gone once
13
+ * the first client has taken it, so the session belongs to that client — an app
14
+ * creates one.
15
+ *
10
16
  * The exchange endpoint is rate limited per app, and its limiter refuses before
11
17
  * the one-time token is redeemed — so a 429 leaves the token still valid and is
12
18
  * worth retrying once.
@@ -20,20 +26,6 @@ const RATE_LIMITED = 429;
20
26
  const RATE_LIMIT_RETRY_MS = 1000;
21
27
  const EXCHANGE_TIMEOUT_MS = 15000;
22
28
  const SESSION_ENDED_ELEMENT_ID = "base44-embed-session-ended";
23
- const FRAME_SESSIONS_KEY = "__base44EmbedSessions";
24
- /** @internal */
25
- export function frameSession(appId, start) {
26
- var _a, _b;
27
- var _c;
28
- if (typeof window === "undefined") {
29
- return start ? start() : null;
30
- }
31
- const sessions = ((_a = (_c = window)[FRAME_SESSIONS_KEY]) !== null && _a !== void 0 ? _a : (_c[FRAME_SESSIONS_KEY] = {}));
32
- if (!sessions[appId] && start) {
33
- sessions[appId] = start();
34
- }
35
- return (_b = sessions[appId]) !== null && _b !== void 0 ? _b : null;
36
- }
37
29
  /** @internal */
38
30
  export function takeEmbedTokenFromUrl() {
39
31
  if (typeof window === "undefined" || !window.location) {
@@ -52,16 +44,11 @@ export function takeEmbedTokenFromUrl() {
52
44
  catch (e) {
53
45
  console.error("Error retrieving embed token from URL:", e);
54
46
  }
55
- return ott;
47
+ return isFramed() ? ott : null;
56
48
  }
57
49
  /** @internal */
58
50
  export function isFramed() {
59
- try {
60
- return typeof window !== "undefined" && window.self !== window.top;
61
- }
62
- catch (_a) {
63
- return true;
64
- }
51
+ return typeof window !== "undefined" && window.self !== window.top;
65
52
  }
66
53
  /** @internal */
67
54
  export async function exchangeEmbedToken({ serverUrl, appId, ott, fetchImpl = fetch, }) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/sdk",
3
- "version": "0.8.48-pr.282.8f60b80",
3
+ "version": "0.8.48-pr.282.b3c4c1e",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",