@base44-preview/sdk 0.8.48-pr.282.3c9bac2 → 0.8.48-pr.282.520fd69
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 +25 -6
- package/dist/modules/auth.js +5 -3
- package/dist/utils/embed-session.d.ts +11 -2
- package/dist/utils/embed-session.js +32 -8
- 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, isEmbeddedTab, markEmbeddedTab, takeEmbedTokenFromUrl, } from "./utils/embed-session.js";
|
|
8
|
+
import { exchangeEmbedToken, isEmbeddedTab, isFramed, markEmbeddedTab, 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,13 +58,19 @@ 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
|
-
|
|
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;
|
|
62
67
|
if (embedOtt) {
|
|
63
68
|
markEmbeddedTab();
|
|
64
69
|
}
|
|
65
70
|
const embedded = Boolean(embedOtt) || isEmbeddedTab();
|
|
66
|
-
//
|
|
67
|
-
|
|
71
|
+
// The passed token is the OTT itself whenever one came in on the URL, and a
|
|
72
|
+
// stale stored one in a frame. Neither of those is this session.
|
|
73
|
+
const token = urlOtt !== null || embedded ? undefined : config.token;
|
|
68
74
|
const headers = {
|
|
69
75
|
...optionalHeaders,
|
|
70
76
|
"X-App-Id": String(appId),
|
|
@@ -150,12 +156,25 @@ export function createClient(config) {
|
|
|
150
156
|
userAuthModule.setToken(newToken, saveToStorage);
|
|
151
157
|
socket === null || socket === void 0 ? void 0 : socket.reconnect();
|
|
152
158
|
};
|
|
153
|
-
// Settles once the exchanged session is applied (memory only); at once
|
|
159
|
+
// Settles once the exchanged session is applied (memory only); at once
|
|
160
|
+
// otherwise. Never rejects: every request waits on it, so a failure here
|
|
161
|
+
// must not turn into a rejection on each of them.
|
|
154
162
|
const authReady = embedOtt
|
|
155
|
-
? exchangeEmbedToken({ serverUrl, appId, ott: embedOtt })
|
|
163
|
+
? exchangeEmbedToken({ serverUrl, appId, ott: embedOtt })
|
|
164
|
+
.then((sessionToken) => {
|
|
165
|
+
var _a;
|
|
156
166
|
if (sessionToken) {
|
|
157
167
|
applyToken(sessionToken, false);
|
|
168
|
+
return;
|
|
158
169
|
}
|
|
170
|
+
// The app is about to run anonymous. Say why, once, instead of
|
|
171
|
+
// leaving only the 401s that follow.
|
|
172
|
+
const error = new Error("Base44: the embed token was refused, so this app is not signed in.");
|
|
173
|
+
console.error(error.message);
|
|
174
|
+
(_a = options === null || options === void 0 ? void 0 : options.onError) === null || _a === void 0 ? void 0 : _a.call(options, error);
|
|
175
|
+
})
|
|
176
|
+
.catch((e) => {
|
|
177
|
+
console.error("Base44: applying the embedded session failed:", e);
|
|
159
178
|
})
|
|
160
179
|
: Promise.resolve();
|
|
161
180
|
if (embedOtt) {
|
package/dist/modules/auth.js
CHANGED
|
@@ -189,6 +189,10 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
189
189
|
setToken(token, saveToStorage = true) {
|
|
190
190
|
if (!token)
|
|
191
191
|
return;
|
|
192
|
+
// An embedded session belongs to the frame the platform minted it for.
|
|
193
|
+
// Persisting it would let it outlive that frame and be picked up as the
|
|
194
|
+
// identity on a later top-level visit, so storage is refused outright.
|
|
195
|
+
const persist = saveToStorage && !options.embedded;
|
|
192
196
|
// Same reasoning as in `logout`: the identity changes here, so anything
|
|
193
197
|
// resolved for the previous one must not be handed to later callers.
|
|
194
198
|
clearPendingMe();
|
|
@@ -198,9 +202,7 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
198
202
|
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
|
|
199
203
|
functionsAxiosClient.defaults.headers.common["Authorization"] = `Bearer ${token}`;
|
|
200
204
|
// Save token to localStorage if requested
|
|
201
|
-
if (
|
|
202
|
-
typeof window !== "undefined" &&
|
|
203
|
-
window.localStorage) {
|
|
205
|
+
if (persist && typeof window !== "undefined" && window.localStorage) {
|
|
204
206
|
try {
|
|
205
207
|
window.localStorage.setItem("base44_access_token", token);
|
|
206
208
|
// Set "token" that is set by the built-in SDK of platform version 2
|
|
@@ -18,6 +18,14 @@ export declare const EMBED_TOKEN_PARAM = "ott";
|
|
|
18
18
|
* @internal
|
|
19
19
|
*/
|
|
20
20
|
export declare function takeEmbedTokenFromUrl(): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Whether this document is rendered inside a frame. Read at call time, not at
|
|
23
|
+
* import: a module-level answer would be fixed before a host (or a test) has
|
|
24
|
+
* set the window up.
|
|
25
|
+
*
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
export declare function isFramed(): boolean;
|
|
21
29
|
/**
|
|
22
30
|
* Whether this tab previously redeemed an embed token. Counts only inside a
|
|
23
31
|
* frame: a top-level tab that once carried a token must fall back to the
|
|
@@ -42,8 +50,9 @@ export declare function exchangeEmbedToken({ serverUrl, appId, ott, fetchImpl, }
|
|
|
42
50
|
}): Promise<string | null>;
|
|
43
51
|
/**
|
|
44
52
|
* Covers the page with a plain "session ended" notice. An embedded session can
|
|
45
|
-
* only be renewed by the host platform
|
|
46
|
-
*
|
|
53
|
+
* only be renewed by the host platform, so this stands in for the login
|
|
54
|
+
* redirect, which cannot complete inside a frame. The copy points at the host
|
|
55
|
+
* page: reloading the frame itself carries no token and lands here again.
|
|
47
56
|
*
|
|
48
57
|
* @internal
|
|
49
58
|
*/
|
|
@@ -27,19 +27,43 @@ export function takeEmbedTokenFromUrl() {
|
|
|
27
27
|
if (typeof window === "undefined" || !window.location) {
|
|
28
28
|
return null;
|
|
29
29
|
}
|
|
30
|
+
let ott = null;
|
|
30
31
|
try {
|
|
31
32
|
const url = new URL(window.location.href);
|
|
32
|
-
|
|
33
|
+
ott = url.searchParams.get(EMBED_TOKEN_PARAM);
|
|
33
34
|
if (!ott) {
|
|
34
35
|
return null;
|
|
35
36
|
}
|
|
36
37
|
url.searchParams.delete(EMBED_TOKEN_PARAM);
|
|
37
38
|
window.history.replaceState(window.history.state, "", url.toString());
|
|
38
|
-
return ott;
|
|
39
39
|
}
|
|
40
40
|
catch (e) {
|
|
41
|
+
// The token was read but the URL could not be rewritten (history blocked,
|
|
42
|
+
// a sandboxed frame, replaceState rate-limited). Return it anyway: it is
|
|
43
|
+
// this load's identity, and dropping it here would leave `?ott=` on the
|
|
44
|
+
// URL for getAccessToken to hand back as if it were a session token.
|
|
41
45
|
console.error("Error retrieving embed token from URL:", e);
|
|
42
|
-
|
|
46
|
+
}
|
|
47
|
+
return ott;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Whether this document is rendered inside a frame. Read at call time, not at
|
|
51
|
+
* import: a module-level answer would be fixed before a host (or a test) has
|
|
52
|
+
* set the window up.
|
|
53
|
+
*
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
export function isFramed() {
|
|
57
|
+
if (typeof window === "undefined") {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
return window.self !== window.top;
|
|
62
|
+
}
|
|
63
|
+
catch (_a) {
|
|
64
|
+
// Reaching the top window can be refused outright; if we cannot see it,
|
|
65
|
+
// we are certainly not it.
|
|
66
|
+
return true;
|
|
43
67
|
}
|
|
44
68
|
}
|
|
45
69
|
/**
|
|
@@ -56,8 +80,7 @@ export function isEmbeddedTab() {
|
|
|
56
80
|
// A cross-site frame is third-party storage, which some browsers block
|
|
57
81
|
// outright — every access can throw, and the marker is then unavailable.
|
|
58
82
|
try {
|
|
59
|
-
return (
|
|
60
|
-
window.sessionStorage.getItem(EMBED_TAB_KEY) === "1");
|
|
83
|
+
return isFramed() && window.sessionStorage.getItem(EMBED_TAB_KEY) === "1";
|
|
61
84
|
}
|
|
62
85
|
catch (_a) {
|
|
63
86
|
return false;
|
|
@@ -108,8 +131,9 @@ export async function exchangeEmbedToken({ serverUrl, appId, ott, fetchImpl = fe
|
|
|
108
131
|
}
|
|
109
132
|
/**
|
|
110
133
|
* Covers the page with a plain "session ended" notice. An embedded session can
|
|
111
|
-
* only be renewed by the host platform
|
|
112
|
-
*
|
|
134
|
+
* only be renewed by the host platform, so this stands in for the login
|
|
135
|
+
* redirect, which cannot complete inside a frame. The copy points at the host
|
|
136
|
+
* page: reloading the frame itself carries no token and lands here again.
|
|
113
137
|
*
|
|
114
138
|
* @internal
|
|
115
139
|
*/
|
|
@@ -131,7 +155,7 @@ export function showEmbedSessionEnded() {
|
|
|
131
155
|
title.textContent = "Session ended";
|
|
132
156
|
title.style.cssText = "font-size:1.5rem;font-weight:700;margin:0 0 .75rem;";
|
|
133
157
|
const body = document.createElement("p");
|
|
134
|
-
body.textContent = "
|
|
158
|
+
body.textContent = "Reload this page in your browser to start a new session.";
|
|
135
159
|
body.style.cssText = "margin:0;color:#475569;";
|
|
136
160
|
const card = document.createElement("div");
|
|
137
161
|
card.append(title, body);
|