@base44-preview/sdk 0.8.48-pr.282.d771123 → 0.8.48-pr.284.e0a8d2f
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 +21 -82
- package/dist/client.types.d.ts +1 -2
- package/dist/modules/agents.d.ts +1 -1
- package/dist/modules/agents.js +4 -3
- package/dist/modules/agents.types.d.ts +2 -2
- package/dist/modules/ai-gateway.d.ts +1 -1
- package/dist/modules/ai-gateway.js +3 -2
- package/dist/modules/ai-gateway.types.d.ts +2 -2
- package/dist/modules/auth.js +0 -10
- package/dist/modules/auth.types.d.ts +0 -21
- package/dist/utils/auth-utils.d.ts +0 -2
- package/dist/utils/auth-utils.js +0 -11
- package/dist/utils/socket-utils.d.ts +1 -3
- package/dist/utils/socket-utils.js +2 -1
- package/package.json +1 -1
- package/dist/utils/embed-session.d.ts +0 -50
- package/dist/utils/embed-session.js +0 -140
package/dist/client.js
CHANGED
|
@@ -5,7 +5,6 @@ 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";
|
|
9
8
|
import { createFetchWithAuth } from "./utils/fetch-with-auth.js";
|
|
10
9
|
import { createFunctionsModule } from "./modules/functions.js";
|
|
11
10
|
import { createAgentsModule } from "./modules/agents.js";
|
|
@@ -55,30 +54,15 @@ import { createActorsModule, resolveActorsHost, } from "./modules/actors.js";
|
|
|
55
54
|
*/
|
|
56
55
|
export function createClient(config) {
|
|
57
56
|
var _a, _b, _c, _d;
|
|
58
|
-
const { serverUrl = "https://base44.app", appId, analytics, serviceToken, requiresAuth = false, appBaseUrl, options, functionsVersion, headers: optionalHeaders, } = config;
|
|
57
|
+
const { serverUrl = "https://base44.app", appId, analytics, token, serviceToken, requiresAuth = false, appBaseUrl, options, functionsVersion, headers: optionalHeaders, } = config;
|
|
59
58
|
// Normalize appBaseUrl to always be a string (empty if not provided or invalid)
|
|
60
59
|
const normalizedAppBaseUrl = typeof appBaseUrl === "string" ? appBaseUrl : "";
|
|
61
|
-
// A host platform embeds the app with a one-time token on the iframe URL.
|
|
62
|
-
// It comes off the URL here, before any other code can read it; the
|
|
63
|
-
// exchange that turns it into a session runs once the modules exist.
|
|
64
|
-
const embedOtt = takeEmbedTokenFromUrl();
|
|
65
|
-
if (embedOtt) {
|
|
66
|
-
markEmbeddedTab();
|
|
67
|
-
}
|
|
68
|
-
const embedded = Boolean(embedOtt) || isEmbeddedTab();
|
|
69
|
-
// What an app passes as `token` is whatever getAccessToken() returned as the
|
|
70
|
-
// page loaded. In an embedded frame that is the one-time token itself, or a
|
|
71
|
-
// token an earlier visitor left in storage; neither is this session.
|
|
72
|
-
const token = embedded ? undefined : config.token;
|
|
73
|
-
let currentToken = token !== null && token !== void 0 ? token : null;
|
|
74
60
|
const socketConfig = {
|
|
75
61
|
serverUrl,
|
|
76
62
|
mountPath: "/ws-user-apps/socket.io/",
|
|
77
63
|
transports: ["websocket"],
|
|
78
64
|
appId,
|
|
79
|
-
|
|
80
|
-
// platform minted, so the socket must not fall back to a stored token.
|
|
81
|
-
token: embedded ? null : token,
|
|
65
|
+
token,
|
|
82
66
|
};
|
|
83
67
|
let socket = null;
|
|
84
68
|
const getSocket = () => {
|
|
@@ -141,73 +125,26 @@ export function createClient(config) {
|
|
|
141
125
|
appBaseUrl: normalizedAppBaseUrl,
|
|
142
126
|
serverUrl,
|
|
143
127
|
token,
|
|
144
|
-
embedded,
|
|
145
128
|
});
|
|
146
129
|
// Apply the access token before any module that may issue authenticated
|
|
147
130
|
// requests during construction (notably analytics, which fires an init
|
|
148
131
|
// event whose flush calls auth.me()). Without this, the first User/me
|
|
149
132
|
// request is built before setToken runs and goes out unauthenticated.
|
|
150
|
-
|
|
151
|
-
// and a token an earlier visitor left in storage must not become it.
|
|
152
|
-
if (typeof window !== "undefined" && !embedded) {
|
|
133
|
+
if (typeof window !== "undefined") {
|
|
153
134
|
const accessToken = token || getAccessToken();
|
|
154
135
|
if (accessToken) {
|
|
155
|
-
currentToken = accessToken;
|
|
156
136
|
userAuthModule.setToken(accessToken);
|
|
157
137
|
}
|
|
158
138
|
}
|
|
159
|
-
// The one answer every module reads. Follows setToken and logout; outside an
|
|
160
|
-
// embedded frame it still falls back to storage, so a login in another tab is
|
|
161
|
-
// picked up on the next connection, as before.
|
|
162
|
-
const getToken = () => {
|
|
163
|
-
if (userAuthModule.hasToken()) {
|
|
164
|
-
return currentToken;
|
|
165
|
-
}
|
|
166
|
-
return embedded ? null : getAccessToken();
|
|
167
|
-
};
|
|
168
|
-
const applyToken = (newToken, saveToStorage) => {
|
|
169
|
-
userAuthModule.setToken(newToken, saveToStorage);
|
|
170
|
-
currentToken = newToken;
|
|
171
|
-
socketConfig.token = newToken;
|
|
172
|
-
if (socket) {
|
|
173
|
-
socket.updateConfig({ token: newToken });
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
// Resolves once the embedded session is in hand (or known not to be coming);
|
|
177
|
-
// immediately for every other client. The exchanged token is applied without
|
|
178
|
-
// persisting it: the session must not outlive the frame it was minted for.
|
|
179
|
-
const authReady = embedOtt
|
|
180
|
-
? exchangeEmbedToken({ serverUrl, appId, ott: embedOtt }).then((sessionToken) => {
|
|
181
|
-
if (sessionToken) {
|
|
182
|
-
applyToken(sessionToken, false);
|
|
183
|
-
}
|
|
184
|
-
})
|
|
185
|
-
: Promise.resolve();
|
|
186
|
-
if (embedOtt) {
|
|
187
|
-
// Requests issued while the exchange is in flight wait for it and carry the
|
|
188
|
-
// session it produces. Registered after createAxiosClient's interceptors,
|
|
189
|
-
// so it runs first and the anonymous-visitor header sees the Authorization.
|
|
190
|
-
for (const client of [axiosClient, functionsAxiosClient]) {
|
|
191
|
-
client.interceptors.request.use(async (requestConfig) => {
|
|
192
|
-
await authReady;
|
|
193
|
-
const sessionToken = getToken();
|
|
194
|
-
if (sessionToken && !requestConfig.headers.get("Authorization")) {
|
|
195
|
-
requestConfig.headers.set("Authorization", `Bearer ${sessionToken}`);
|
|
196
|
-
}
|
|
197
|
-
return requestConfig;
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
139
|
const actorsModule = createActorsModule({
|
|
202
140
|
appId,
|
|
203
141
|
// serverUrl is often relative/empty (same-origin app); the proxy-fallback
|
|
204
142
|
// URL needs an absolute host, so fall back to the page origin.
|
|
205
143
|
host: resolveActorsHost(serverUrl, typeof window !== "undefined" ? (_a = window.location) === null || _a === void 0 ? void 0 : _a.origin : undefined),
|
|
206
144
|
functionsVersion,
|
|
207
|
-
getAuthToken:
|
|
145
|
+
getAuthToken: () => token || getAccessToken(),
|
|
208
146
|
mintConnectionToken: async (actorName, room, connectionId) => {
|
|
209
|
-
|
|
210
|
-
const authToken = getToken();
|
|
147
|
+
const authToken = token || getAccessToken();
|
|
211
148
|
return await actorsAxiosClient.post(`/apps/${appId}/actors/${encodeURIComponent(actorName)}/connection-token`, { room, connection_id: connectionId }, {
|
|
212
149
|
headers: {
|
|
213
150
|
...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
|
|
@@ -234,9 +171,10 @@ export function createClient(config) {
|
|
|
234
171
|
functions: createFunctionsModule(functionsAxiosClient, appId, {
|
|
235
172
|
getAuthHeaders: () => {
|
|
236
173
|
const headers = {};
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
174
|
+
// Get current token from storage or initial config
|
|
175
|
+
const currentToken = token || getAccessToken();
|
|
176
|
+
if (currentToken) {
|
|
177
|
+
headers["Authorization"] = `Bearer ${currentToken}`;
|
|
240
178
|
}
|
|
241
179
|
return headers;
|
|
242
180
|
},
|
|
@@ -247,9 +185,9 @@ export function createClient(config) {
|
|
|
247
185
|
getSocket,
|
|
248
186
|
appId,
|
|
249
187
|
serverUrl,
|
|
250
|
-
|
|
188
|
+
token,
|
|
251
189
|
}),
|
|
252
|
-
aiGateway: createAiGatewayModule({ serverUrl,
|
|
190
|
+
aiGateway: createAiGatewayModule({ serverUrl, token, appId }),
|
|
253
191
|
appLogs: createAppLogsModule(axiosClient, appId),
|
|
254
192
|
app: createAppModule(axiosClient, appId),
|
|
255
193
|
users: createUsersModule(axiosClient, appId),
|
|
@@ -294,13 +232,9 @@ export function createClient(config) {
|
|
|
294
232
|
getSocket,
|
|
295
233
|
appId,
|
|
296
234
|
serverUrl,
|
|
297
|
-
|
|
298
|
-
}),
|
|
299
|
-
aiGateway: createAiGatewayModule({
|
|
300
|
-
serverUrl,
|
|
301
|
-
getToken: () => serviceToken,
|
|
302
|
-
appId,
|
|
235
|
+
token,
|
|
303
236
|
}),
|
|
237
|
+
aiGateway: createAiGatewayModule({ serverUrl, token: serviceToken, appId }),
|
|
304
238
|
appLogs: createAppLogsModule(serviceRoleAxiosClient, appId),
|
|
305
239
|
cleanup: () => {
|
|
306
240
|
if (socket) {
|
|
@@ -340,7 +274,6 @@ export function createClient(config) {
|
|
|
340
274
|
* Sets a new authentication token for all subsequent requests.
|
|
341
275
|
*
|
|
342
276
|
* @param newToken - The new authentication token
|
|
343
|
-
* @param saveToStorage - Whether to also keep the token in local storage. Defaults to `true`.
|
|
344
277
|
*
|
|
345
278
|
* @example
|
|
346
279
|
* ```typescript
|
|
@@ -352,8 +285,14 @@ export function createClient(config) {
|
|
|
352
285
|
* base44.setToken(access_token);
|
|
353
286
|
* ```
|
|
354
287
|
*/
|
|
355
|
-
setToken(newToken
|
|
356
|
-
|
|
288
|
+
setToken(newToken) {
|
|
289
|
+
userModules.auth.setToken(newToken);
|
|
290
|
+
if (socket) {
|
|
291
|
+
socket.updateConfig({
|
|
292
|
+
token: newToken,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
socketConfig.token = newToken;
|
|
357
296
|
},
|
|
358
297
|
/**
|
|
359
298
|
* Gets the current client configuration.
|
package/dist/client.types.d.ts
CHANGED
|
@@ -200,9 +200,8 @@ export interface Base44Client {
|
|
|
200
200
|
* Updates the token for both HTTP requests and WebSocket connections.
|
|
201
201
|
*
|
|
202
202
|
* @param newToken - The new authentication token.
|
|
203
|
-
* @param saveToStorage - Whether to also keep the token in local storage so it survives a page load. Defaults to `true`.
|
|
204
203
|
*/
|
|
205
|
-
setToken(newToken: string
|
|
204
|
+
setToken(newToken: string): void;
|
|
206
205
|
/**
|
|
207
206
|
* Gets the current client configuration.
|
|
208
207
|
* @internal
|
package/dist/modules/agents.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { AgentsModule, AgentsModuleConfig } from "./agents.types.js";
|
|
2
|
-
export declare function createAgentsModule({ axios, getSocket, appId, serverUrl,
|
|
2
|
+
export declare function createAgentsModule({ axios, getSocket, appId, serverUrl, token, }: AgentsModuleConfig): AgentsModule;
|
package/dist/modules/agents.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { getAccessToken } from "../utils/auth-utils.js";
|
|
2
|
+
export function createAgentsModule({ axios, getSocket, appId, serverUrl, token, }) {
|
|
2
3
|
const baseURL = `/apps/${appId}/agents`;
|
|
3
4
|
// Track active conversations
|
|
4
5
|
const currentConversations = {};
|
|
@@ -55,7 +56,7 @@ export function createAgentsModule({ axios, getSocket, appId, serverUrl, getToke
|
|
|
55
56
|
};
|
|
56
57
|
const getWhatsAppConnectURL = (agentName) => {
|
|
57
58
|
const baseUrl = `${serverUrl}/api/apps/${appId}/agents/${encodeURIComponent(agentName)}/whatsapp`;
|
|
58
|
-
const accessToken =
|
|
59
|
+
const accessToken = token !== null && token !== void 0 ? token : getAccessToken();
|
|
59
60
|
if (accessToken) {
|
|
60
61
|
return `${baseUrl}?token=${accessToken}`;
|
|
61
62
|
}
|
|
@@ -66,7 +67,7 @@ export function createAgentsModule({ axios, getSocket, appId, serverUrl, getToke
|
|
|
66
67
|
};
|
|
67
68
|
const getTelegramConnectURL = (agentName) => {
|
|
68
69
|
const baseUrl = `${serverUrl}/api/apps/${appId}/agents/${encodeURIComponent(agentName)}/telegram`;
|
|
69
|
-
const accessToken =
|
|
70
|
+
const accessToken = token !== null && token !== void 0 ? token : getAccessToken();
|
|
70
71
|
if (accessToken) {
|
|
71
72
|
return `${baseUrl}?token=${accessToken}`;
|
|
72
73
|
}
|
|
@@ -160,8 +160,8 @@ export interface AgentsModuleConfig {
|
|
|
160
160
|
appId: string;
|
|
161
161
|
/** Server URL */
|
|
162
162
|
serverUrl?: string;
|
|
163
|
-
/**
|
|
164
|
-
|
|
163
|
+
/** Authentication token */
|
|
164
|
+
token?: string;
|
|
165
165
|
}
|
|
166
166
|
/**
|
|
167
167
|
* Agents module for managing AI agent conversations.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { AiGatewayModule, AiGatewayModuleConfig } from "./ai-gateway.types.js";
|
|
2
|
-
export declare function createAiGatewayModule({ serverUrl,
|
|
2
|
+
export declare function createAiGatewayModule({ serverUrl, token, appId, }: AiGatewayModuleConfig): AiGatewayModule;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { getAccessToken } from "../utils/auth-utils.js";
|
|
2
|
+
export function createAiGatewayModule({ serverUrl, token, appId, }) {
|
|
2
3
|
const connection = () => {
|
|
3
4
|
var _a;
|
|
4
5
|
return ({
|
|
5
6
|
baseURL: `${serverUrl}/api/apps/${appId}/ai/openai/v1`,
|
|
6
|
-
token: (_a =
|
|
7
|
+
token: (_a = token !== null && token !== void 0 ? token : getAccessToken()) !== null && _a !== void 0 ? _a : "",
|
|
7
8
|
});
|
|
8
9
|
};
|
|
9
10
|
return {
|
|
@@ -17,8 +17,8 @@ export interface AiGatewayConnection {
|
|
|
17
17
|
export interface AiGatewayModuleConfig {
|
|
18
18
|
/** Server URL */
|
|
19
19
|
serverUrl?: string;
|
|
20
|
-
/**
|
|
21
|
-
|
|
20
|
+
/** Authentication token */
|
|
21
|
+
token?: string;
|
|
22
22
|
/** Application ID */
|
|
23
23
|
appId: string;
|
|
24
24
|
}
|
package/dist/modules/auth.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { resetAnalyticsSessionContext } from "./analytics.js";
|
|
2
|
-
import { showEmbedSessionEnded } from "../utils/embed-session.js";
|
|
3
2
|
function isInsideIframe() {
|
|
4
3
|
if (typeof window === "undefined")
|
|
5
4
|
return false;
|
|
@@ -87,9 +86,6 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
87
86
|
hasToken() {
|
|
88
87
|
return hasAccessToken;
|
|
89
88
|
},
|
|
90
|
-
isEmbedded() {
|
|
91
|
-
return Boolean(options.embedded);
|
|
92
|
-
},
|
|
93
89
|
// Get current user information
|
|
94
90
|
async me() {
|
|
95
91
|
const request = pendingMe !== null && pendingMe !== void 0 ? pendingMe : axios.get(`/apps/${appId}/entities/User/me`).finally(() => {
|
|
@@ -113,12 +109,6 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
113
109
|
if (typeof window === "undefined") {
|
|
114
110
|
throw new Error("Login method can only be used in a browser environment");
|
|
115
111
|
}
|
|
116
|
-
// An embedded session can only be renewed by the host platform; the
|
|
117
|
-
// login round trip cannot complete inside its frame.
|
|
118
|
-
if (options.embedded) {
|
|
119
|
-
showEmbedSessionEnded();
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
112
|
// If nextUrl is not provided, use the current URL
|
|
123
113
|
const redirectUrl = nextUrl
|
|
124
114
|
? new URL(nextUrl, window.location.origin).toString()
|
|
@@ -98,11 +98,6 @@ export interface AuthModuleOptions {
|
|
|
98
98
|
* which is how the server-side SDK reports a token it never sets explicitly.
|
|
99
99
|
*/
|
|
100
100
|
token?: string;
|
|
101
|
-
/**
|
|
102
|
-
* Whether this client runs embedded in a host platform's frame, where a
|
|
103
|
-
* session is minted by the platform and cannot be renewed by a login redirect.
|
|
104
|
-
*/
|
|
105
|
-
embedded?: boolean;
|
|
106
101
|
}
|
|
107
102
|
/**
|
|
108
103
|
* Authentication module for managing user authentication and authorization. The module automatically stores tokens in local storage when available and manages authorization headers for API requests.
|
|
@@ -184,22 +179,6 @@ export interface AuthModule {
|
|
|
184
179
|
* ```
|
|
185
180
|
*/
|
|
186
181
|
redirectToLogin(nextUrl: string): void;
|
|
187
|
-
/**
|
|
188
|
-
* Whether the app is running embedded in a host platform.
|
|
189
|
-
*
|
|
190
|
-
* A platform embeds an app in an iframe and signs its user in by minting a one-time token onto the frame's URL; the SDK trades it for a session as the client is created. That session is held in memory only and can be renewed only by the platform, so when it ends there is no login page to send the user to — {@linkcode AuthModule.redirectToLogin | redirectToLogin()} shows a "session ended" notice instead. Use this to render your own notice or to hide sign-in and sign-out controls that cannot work inside the frame.
|
|
191
|
-
*
|
|
192
|
-
* @returns `true` when the app was embedded by a host platform, `false` otherwise.
|
|
193
|
-
*
|
|
194
|
-
* @example
|
|
195
|
-
* ```typescript
|
|
196
|
-
* // Show your own message instead of a login screen
|
|
197
|
-
* if (!user && base44.auth.isEmbedded()) {
|
|
198
|
-
* return <SessionEnded />;
|
|
199
|
-
* }
|
|
200
|
-
* ```
|
|
201
|
-
*/
|
|
202
|
-
isEmbedded(): boolean;
|
|
203
182
|
/**
|
|
204
183
|
* Redirects the user to a third-party authentication provider's login page.
|
|
205
184
|
*
|
|
@@ -5,8 +5,6 @@ import { GetAccessTokenOptions, SaveAccessTokenOptions, RemoveAccessTokenOptions
|
|
|
5
5
|
* Low-level utility for manually retrieving tokens. In most cases, the Base44 client handles
|
|
6
6
|
* token management automatically. This function is useful for custom authentication flows or when you need direct access to stored tokens. Requires a browser environment and can't be used in the backend.
|
|
7
7
|
*
|
|
8
|
-
* When a host platform has embedded the app with a one-time token (`?ott=`), that token is returned as it stands: it is what {@linkcode createClient} trades for the session, so a page that gates on "is there a token?" as it loads sees one. It is neither stored nor removed from the URL here.
|
|
9
|
-
*
|
|
10
8
|
* @internal
|
|
11
9
|
*
|
|
12
10
|
* @param options - Configuration options for token retrieval.
|
package/dist/utils/auth-utils.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import { EMBED_TOKEN_PARAM } from "./embed-session.js";
|
|
2
1
|
/**
|
|
3
2
|
* Retrieves an access token from URL parameters or local storage.
|
|
4
3
|
*
|
|
5
4
|
* Low-level utility for manually retrieving tokens. In most cases, the Base44 client handles
|
|
6
5
|
* token management automatically. This function is useful for custom authentication flows or when you need direct access to stored tokens. Requires a browser environment and can't be used in the backend.
|
|
7
6
|
*
|
|
8
|
-
* When a host platform has embedded the app with a one-time token (`?ott=`), that token is returned as it stands: it is what {@linkcode createClient} trades for the session, so a page that gates on "is there a token?" as it loads sees one. It is neither stored nor removed from the URL here.
|
|
9
|
-
*
|
|
10
7
|
* @internal
|
|
11
8
|
*
|
|
12
9
|
* @param options - Configuration options for token retrieval.
|
|
@@ -59,14 +56,6 @@ export function getAccessToken(options = {}) {
|
|
|
59
56
|
}
|
|
60
57
|
return token;
|
|
61
58
|
}
|
|
62
|
-
// A platform-embedded load carries a one-time token instead. It is not a
|
|
63
|
-
// session yet — createClient takes it off the URL and exchanges it — but
|
|
64
|
-
// it is the identity this load arrives with, and callers that read this
|
|
65
|
-
// once as the page loads must not conclude there is none.
|
|
66
|
-
const embedToken = urlParams.get(EMBED_TOKEN_PARAM);
|
|
67
|
-
if (embedToken) {
|
|
68
|
-
return embedToken;
|
|
69
|
-
}
|
|
70
59
|
}
|
|
71
60
|
catch (e) {
|
|
72
61
|
console.error("Error retrieving token from URL:", e);
|
|
@@ -4,9 +4,7 @@ export interface RoomsSocketConfig {
|
|
|
4
4
|
mountPath: string;
|
|
5
5
|
transports: string[];
|
|
6
6
|
appId: string;
|
|
7
|
-
|
|
8
|
-
* known to be anonymous, so storage is never consulted. */
|
|
9
|
-
token?: string | null;
|
|
7
|
+
token?: string;
|
|
10
8
|
}
|
|
11
9
|
export type TSocketRoom = string;
|
|
12
10
|
export type TJsonStr = string;
|
|
@@ -3,11 +3,12 @@ import { getAccessToken } from "./auth-utils.js";
|
|
|
3
3
|
import { getAnalyticsSessionId } from "../modules/analytics.js";
|
|
4
4
|
const ROOM_LEAVE_GRACE_MS = 250;
|
|
5
5
|
function initializeSocket(config, handlers) {
|
|
6
|
+
var _a;
|
|
6
7
|
// On unauthenticated clients, send a stable anonymous visitor id on the
|
|
7
8
|
// handshake so the backend can verify room access for anonymous agent
|
|
8
9
|
// conversations (mirrors the X-Base44-Anonymous-Id HTTP header). Authenticated
|
|
9
10
|
// clients are identified by their token instead.
|
|
10
|
-
const resolvedToken = config.token
|
|
11
|
+
const resolvedToken = (_a = config.token) !== null && _a !== void 0 ? _a : getAccessToken();
|
|
11
12
|
const query = {
|
|
12
13
|
app_id: config.appId,
|
|
13
14
|
token: resolvedToken,
|
package/package.json
CHANGED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sessions for apps embedded in a host platform.
|
|
3
|
-
*
|
|
4
|
-
* The platform's server mints a one-time token for one of its users and puts
|
|
5
|
-
* it on the iframe URL as `?ott=`. The client takes it off the URL as it is
|
|
6
|
-
* created, trades it for an app-user session through the OAuth token-exchange
|
|
7
|
-
* grant (RFC 8693), and keeps the result in memory only — never in storage — so
|
|
8
|
-
* the session lives and dies with the frame.
|
|
9
|
-
*
|
|
10
|
-
* @internal
|
|
11
|
-
*/
|
|
12
|
-
/** The query parameter a host platform puts the one-time token on. @internal */
|
|
13
|
-
export declare const EMBED_TOKEN_PARAM = "ott";
|
|
14
|
-
/**
|
|
15
|
-
* Reads the one-time token off the current URL and strips it, so it is never
|
|
16
|
-
* left in the address bar, in history, or in a shared link.
|
|
17
|
-
*
|
|
18
|
-
* @internal
|
|
19
|
-
*/
|
|
20
|
-
export declare function takeEmbedTokenFromUrl(): string | null;
|
|
21
|
-
/**
|
|
22
|
-
* Whether this tab previously redeemed an embed token. Counts only inside a
|
|
23
|
-
* frame: a top-level tab that once carried a token must fall back to the
|
|
24
|
-
* regular login, or it could never sign in again.
|
|
25
|
-
*
|
|
26
|
-
* @internal
|
|
27
|
-
*/
|
|
28
|
-
export declare function isEmbeddedTab(): boolean;
|
|
29
|
-
/** @internal */
|
|
30
|
-
export declare function markEmbeddedTab(): void;
|
|
31
|
-
/**
|
|
32
|
-
* Trades a one-time embed token for an app-user session token. Resolves to
|
|
33
|
-
* `null` when the platform refuses the token; never throws.
|
|
34
|
-
*
|
|
35
|
-
* @internal
|
|
36
|
-
*/
|
|
37
|
-
export declare function exchangeEmbedToken({ serverUrl, appId, ott, fetchImpl, }: {
|
|
38
|
-
serverUrl: string;
|
|
39
|
-
appId: string;
|
|
40
|
-
ott: string;
|
|
41
|
-
fetchImpl?: typeof fetch;
|
|
42
|
-
}): Promise<string | null>;
|
|
43
|
-
/**
|
|
44
|
-
* Covers the page with a plain "session ended" notice. An embedded session can
|
|
45
|
-
* only be renewed by the host platform (by reloading its own page), so this
|
|
46
|
-
* stands in for the login redirect, which cannot complete inside a frame.
|
|
47
|
-
*
|
|
48
|
-
* @internal
|
|
49
|
-
*/
|
|
50
|
-
export declare function showEmbedSessionEnded(): void;
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sessions for apps embedded in a host platform.
|
|
3
|
-
*
|
|
4
|
-
* The platform's server mints a one-time token for one of its users and puts
|
|
5
|
-
* it on the iframe URL as `?ott=`. The client takes it off the URL as it is
|
|
6
|
-
* created, trades it for an app-user session through the OAuth token-exchange
|
|
7
|
-
* grant (RFC 8693), and keeps the result in memory only — never in storage — so
|
|
8
|
-
* the session lives and dies with the frame.
|
|
9
|
-
*
|
|
10
|
-
* @internal
|
|
11
|
-
*/
|
|
12
|
-
/** The query parameter a host platform puts the one-time token on. @internal */
|
|
13
|
-
export const EMBED_TOKEN_PARAM = "ott";
|
|
14
|
-
const EMBED_TAB_KEY = "base44_embed_session";
|
|
15
|
-
const GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange";
|
|
16
|
-
const SUBJECT_TOKEN_TYPE = "urn:base44:params:oauth:token-type:embed-ott";
|
|
17
|
-
const RATE_LIMITED = 429;
|
|
18
|
-
const RATE_LIMIT_RETRY_MS = 1000;
|
|
19
|
-
const SESSION_ENDED_ELEMENT_ID = "base44-embed-session-ended";
|
|
20
|
-
/**
|
|
21
|
-
* Reads the one-time token off the current URL and strips it, so it is never
|
|
22
|
-
* left in the address bar, in history, or in a shared link.
|
|
23
|
-
*
|
|
24
|
-
* @internal
|
|
25
|
-
*/
|
|
26
|
-
export function takeEmbedTokenFromUrl() {
|
|
27
|
-
if (typeof window === "undefined" || !window.location) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
try {
|
|
31
|
-
const url = new URL(window.location.href);
|
|
32
|
-
const ott = url.searchParams.get(EMBED_TOKEN_PARAM);
|
|
33
|
-
if (!ott) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
url.searchParams.delete(EMBED_TOKEN_PARAM);
|
|
37
|
-
window.history.replaceState(window.history.state, "", url.toString());
|
|
38
|
-
return ott;
|
|
39
|
-
}
|
|
40
|
-
catch (e) {
|
|
41
|
-
console.error("Error retrieving embed token from URL:", e);
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Whether this tab previously redeemed an embed token. Counts only inside a
|
|
47
|
-
* frame: a top-level tab that once carried a token must fall back to the
|
|
48
|
-
* regular login, or it could never sign in again.
|
|
49
|
-
*
|
|
50
|
-
* @internal
|
|
51
|
-
*/
|
|
52
|
-
export function isEmbeddedTab() {
|
|
53
|
-
if (typeof window === "undefined") {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
// A cross-site frame is third-party storage, which some browsers block
|
|
57
|
-
// outright — every access can throw, and the marker is then unavailable.
|
|
58
|
-
try {
|
|
59
|
-
return (window.self !== window.top &&
|
|
60
|
-
window.sessionStorage.getItem(EMBED_TAB_KEY) === "1");
|
|
61
|
-
}
|
|
62
|
-
catch (_a) {
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
/** @internal */
|
|
67
|
-
export function markEmbeddedTab() {
|
|
68
|
-
try {
|
|
69
|
-
window.sessionStorage.setItem(EMBED_TAB_KEY, "1");
|
|
70
|
-
}
|
|
71
|
-
catch (_a) {
|
|
72
|
-
/* storage blocked */
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Trades a one-time embed token for an app-user session token. Resolves to
|
|
77
|
-
* `null` when the platform refuses the token; never throws.
|
|
78
|
-
*
|
|
79
|
-
* @internal
|
|
80
|
-
*/
|
|
81
|
-
export async function exchangeEmbedToken({ serverUrl, appId, ott, fetchImpl = fetch, }) {
|
|
82
|
-
const post = () => fetchImpl(`${serverUrl}/api/apps/${appId}/auth/embed/token`, {
|
|
83
|
-
method: "POST",
|
|
84
|
-
headers: { "X-App-Id": String(appId) },
|
|
85
|
-
body: new URLSearchParams({
|
|
86
|
-
grant_type: GRANT_TYPE,
|
|
87
|
-
subject_token: ott,
|
|
88
|
-
subject_token_type: SUBJECT_TOKEN_TYPE,
|
|
89
|
-
}),
|
|
90
|
-
});
|
|
91
|
-
try {
|
|
92
|
-
let response = await post();
|
|
93
|
-
// The limiter refuses before the token is redeemed, so it is still valid.
|
|
94
|
-
if (response.status === RATE_LIMITED) {
|
|
95
|
-
await new Promise((resolve) => setTimeout(resolve, RATE_LIMIT_RETRY_MS));
|
|
96
|
-
response = await post();
|
|
97
|
-
}
|
|
98
|
-
if (!response.ok) {
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
const { access_token: token } = (await response.json());
|
|
102
|
-
return token || null;
|
|
103
|
-
}
|
|
104
|
-
catch (e) {
|
|
105
|
-
console.error("Embed token exchange failed:", e);
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Covers the page with a plain "session ended" notice. An embedded session can
|
|
111
|
-
* only be renewed by the host platform (by reloading its own page), so this
|
|
112
|
-
* stands in for the login redirect, which cannot complete inside a frame.
|
|
113
|
-
*
|
|
114
|
-
* @internal
|
|
115
|
-
*/
|
|
116
|
-
export function showEmbedSessionEnded() {
|
|
117
|
-
if (typeof document === "undefined" || !document.body) {
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
if (document.getElementById(SESSION_ENDED_ELEMENT_ID)) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
const overlay = document.createElement("div");
|
|
124
|
-
overlay.id = SESSION_ENDED_ELEMENT_ID;
|
|
125
|
-
overlay.setAttribute("role", "alert");
|
|
126
|
-
overlay.style.cssText =
|
|
127
|
-
"position:fixed;inset:0;z-index:2147483647;display:flex;align-items:center;" +
|
|
128
|
-
"justify-content:center;background:#fff;color:#0f172a;" +
|
|
129
|
-
"font-family:ui-sans-serif,system-ui,sans-serif;text-align:center;padding:2rem;";
|
|
130
|
-
const title = document.createElement("h1");
|
|
131
|
-
title.textContent = "Session ended";
|
|
132
|
-
title.style.cssText = "font-size:1.5rem;font-weight:700;margin:0 0 .75rem;";
|
|
133
|
-
const body = document.createElement("p");
|
|
134
|
-
body.textContent = "Refresh the page to continue.";
|
|
135
|
-
body.style.cssText = "margin:0;color:#475569;";
|
|
136
|
-
const card = document.createElement("div");
|
|
137
|
-
card.append(title, body);
|
|
138
|
-
overlay.append(card);
|
|
139
|
-
document.body.append(overlay);
|
|
140
|
-
}
|