@base44-preview/sdk 0.8.48-pr.282.b3c4c1e → 0.8.48-pr.282.d56486f
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 +59 -40
- package/dist/modules/actors.d.ts +2 -3
- package/dist/utils/embed-session.d.ts +2 -6
- package/dist/utils/embed-session.js +15 -7
- package/package.json +1 -1
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, takeEmbedTokenFromUrl, } from "./utils/embed-session.js";
|
|
8
|
+
import { exchangeEmbedToken, frameSession, isFramed, 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,34 +58,16 @@ 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
|
-
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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;
|
|
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;
|
|
89
71
|
const headers = {
|
|
90
72
|
...optionalHeaders,
|
|
91
73
|
"X-App-Id": String(appId),
|
|
@@ -134,11 +116,14 @@ export function createClient(config) {
|
|
|
134
116
|
baseURL: `${serverUrl}/api`,
|
|
135
117
|
headers,
|
|
136
118
|
});
|
|
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;
|
|
137
122
|
const userAuthModule = createAuthModule(axiosClient, functionsAxiosClient, appId, {
|
|
138
123
|
appBaseUrl: normalizedAppBaseUrl,
|
|
139
124
|
serverUrl,
|
|
140
125
|
token,
|
|
141
|
-
embedded
|
|
126
|
+
embedded,
|
|
142
127
|
// The socket carries its token on the handshake, so an identity change
|
|
143
128
|
// only reaches it by opening a new connection — or, on logout, by
|
|
144
129
|
// dropping the one still running as the user who just left.
|
|
@@ -148,17 +133,34 @@ export function createClient(config) {
|
|
|
148
133
|
// requests during construction (notably analytics, which fires an init
|
|
149
134
|
// event whose flush calls auth.me()). Without this, the first User/me
|
|
150
135
|
// request is built before setToken runs and goes out unauthenticated.
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
if (typeof window !== "undefined" && !embedOtt) {
|
|
136
|
+
// Skipped in a frame: the session comes from the exchange below.
|
|
137
|
+
if (typeof window !== "undefined" && !embedded) {
|
|
154
138
|
const accessToken = token || getAccessToken();
|
|
155
139
|
if (accessToken) {
|
|
156
140
|
userAuthModule.setToken(accessToken);
|
|
157
141
|
}
|
|
158
142
|
}
|
|
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.
|
|
159
161
|
const session = embedOtt
|
|
160
|
-
? exchangeEmbedToken({ serverUrl, appId, ott: embedOtt })
|
|
161
|
-
:
|
|
162
|
+
? frameSession(appId, () => exchangeEmbedToken({ serverUrl, appId, ott: embedOtt }))
|
|
163
|
+
: frameSession(appId);
|
|
162
164
|
// Settles once the exchanged session is applied (memory only); at once
|
|
163
165
|
// otherwise. Never rejects: every request waits on it, so a failure here
|
|
164
166
|
// must not turn into a rejection on each of them.
|
|
@@ -180,6 +182,21 @@ export function createClient(config) {
|
|
|
180
182
|
console.error("Base44: applying the embedded session failed:", e);
|
|
181
183
|
})
|
|
182
184
|
: 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
|
+
};
|
|
183
200
|
if (session) {
|
|
184
201
|
// Requests issued during the exchange wait for it. Registered after createAxiosClient's
|
|
185
202
|
// interceptors so it runs first and the anonymous-visitor header sees the Authorization.
|
|
@@ -247,11 +264,13 @@ export function createClient(config) {
|
|
|
247
264
|
getSocket,
|
|
248
265
|
appId,
|
|
249
266
|
serverUrl,
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
267
|
+
getToken: getTokenNow,
|
|
268
|
+
}),
|
|
269
|
+
aiGateway: createAiGatewayModule({
|
|
270
|
+
serverUrl,
|
|
271
|
+
getToken: getTokenNow,
|
|
272
|
+
appId,
|
|
253
273
|
}),
|
|
254
|
-
aiGateway: createAiGatewayModule({ serverUrl, getToken, appId }),
|
|
255
274
|
appLogs: createAppLogsModule(axiosClient, appId),
|
|
256
275
|
app: createAppModule(axiosClient, appId),
|
|
257
276
|
users: createUsersModule(axiosClient, appId),
|
|
@@ -299,7 +318,7 @@ export function createClient(config) {
|
|
|
299
318
|
// The user's token, as on the user-scoped module: the only thing this is
|
|
300
319
|
// read for is the `?token=` on a channel URL handed to that user, which
|
|
301
320
|
// the app's service credential must never end up in.
|
|
302
|
-
getToken,
|
|
321
|
+
getToken: getTokenNow,
|
|
303
322
|
}),
|
|
304
323
|
aiGateway: createAiGatewayModule({
|
|
305
324
|
serverUrl,
|
package/dist/modules/actors.d.ts
CHANGED
|
@@ -11,9 +11,8 @@ 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
|
-
|
|
16
|
-
getAuthToken(): Promise<string | null | undefined>;
|
|
14
|
+
* anonymous connects omit it. */
|
|
15
|
+
getAuthToken(): string | null | undefined | Promise<string | null | undefined>;
|
|
17
16
|
/** Same semantics as function calls: editors with a non-prod version get the
|
|
18
17
|
* draft actor script; everyone else gets the published one. */
|
|
19
18
|
functionsVersion?: string;
|
|
@@ -7,12 +7,6 @@
|
|
|
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
|
-
*
|
|
16
10
|
* The exchange endpoint is rate limited per app, and its limiter refuses before
|
|
17
11
|
* the one-time token is redeemed — so a 429 leaves the token still valid and is
|
|
18
12
|
* worth retrying once.
|
|
@@ -21,6 +15,8 @@
|
|
|
21
15
|
*/
|
|
22
16
|
export declare const EMBED_TOKEN_PARAM = "ott";
|
|
23
17
|
/** @internal */
|
|
18
|
+
export declare function frameSession(appId: string, start?: () => Promise<string | null>): Promise<string | null> | null;
|
|
19
|
+
/** @internal */
|
|
24
20
|
export declare function takeEmbedTokenFromUrl(): string | null;
|
|
25
21
|
/** @internal */
|
|
26
22
|
export declare function isFramed(): boolean;
|
|
@@ -7,12 +7,6 @@
|
|
|
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
|
-
*
|
|
16
10
|
* The exchange endpoint is rate limited per app, and its limiter refuses before
|
|
17
11
|
* the one-time token is redeemed — so a 429 leaves the token still valid and is
|
|
18
12
|
* worth retrying once.
|
|
@@ -26,6 +20,20 @@ const RATE_LIMITED = 429;
|
|
|
26
20
|
const RATE_LIMIT_RETRY_MS = 1000;
|
|
27
21
|
const EXCHANGE_TIMEOUT_MS = 15000;
|
|
28
22
|
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
|
+
}
|
|
29
37
|
/** @internal */
|
|
30
38
|
export function takeEmbedTokenFromUrl() {
|
|
31
39
|
if (typeof window === "undefined" || !window.location) {
|
|
@@ -44,7 +52,7 @@ export function takeEmbedTokenFromUrl() {
|
|
|
44
52
|
catch (e) {
|
|
45
53
|
console.error("Error retrieving embed token from URL:", e);
|
|
46
54
|
}
|
|
47
|
-
return
|
|
55
|
+
return ott;
|
|
48
56
|
}
|
|
49
57
|
/** @internal */
|
|
50
58
|
export function isFramed() {
|