@base44-preview/sdk 0.8.48-pr.282.3c9bac2 → 0.8.48-pr.282.8443e7d
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 +48 -21
- package/dist/modules/auth.js +4 -7
- package/dist/modules/auth.types.d.ts +0 -5
- package/dist/utils/socket-utils.d.ts +4 -3
- package/dist/utils/socket-utils.js +10 -5
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -58,13 +58,38 @@ 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
|
+
const inBrowser = typeof window !== "undefined";
|
|
62
|
+
// A host platform embeds the app with a one-time token on the iframe URL.
|
|
63
|
+
// It comes off the URL here, before any other code can read it; the
|
|
64
|
+
// exchange that turns it into a session runs once the modules exist.
|
|
61
65
|
const embedOtt = takeEmbedTokenFromUrl();
|
|
62
66
|
if (embedOtt) {
|
|
63
67
|
markEmbeddedTab();
|
|
64
68
|
}
|
|
65
69
|
const embedded = Boolean(embedOtt) || isEmbeddedTab();
|
|
66
|
-
//
|
|
70
|
+
// What an app passes as `token` is whatever getAccessToken() returned as the
|
|
71
|
+
// page loaded. In an embedded frame that is the one-time token itself, or a
|
|
72
|
+
// token an earlier visitor left in storage; neither is this session.
|
|
67
73
|
const token = embedded ? undefined : config.token;
|
|
74
|
+
let currentToken = token !== null && token !== void 0 ? token : null;
|
|
75
|
+
const socketConfig = {
|
|
76
|
+
serverUrl,
|
|
77
|
+
mountPath: "/ws-user-apps/socket.io/",
|
|
78
|
+
transports: ["websocket"],
|
|
79
|
+
appId,
|
|
80
|
+
// null (not undefined): an embedded frame's only identity is the one the
|
|
81
|
+
// platform minted, so the socket must not fall back to a stored token.
|
|
82
|
+
token: embedded ? null : token,
|
|
83
|
+
};
|
|
84
|
+
let socket = null;
|
|
85
|
+
const getSocket = () => {
|
|
86
|
+
if (!socket) {
|
|
87
|
+
socket = RoomsSocket({
|
|
88
|
+
config: socketConfig,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return socket;
|
|
92
|
+
};
|
|
68
93
|
const headers = {
|
|
69
94
|
...optionalHeaders,
|
|
70
95
|
"X-App-Id": String(appId),
|
|
@@ -123,34 +148,35 @@ export function createClient(config) {
|
|
|
123
148
|
// requests during construction (notably analytics, which fires an init
|
|
124
149
|
// event whose flush calls auth.me()). Without this, the first User/me
|
|
125
150
|
// request is built before setToken runs and goes out unauthenticated.
|
|
126
|
-
//
|
|
127
|
-
|
|
151
|
+
// An embedded load skips this: its session comes from the exchange below,
|
|
152
|
+
// and a token an earlier visitor left in storage must not become it.
|
|
153
|
+
if (inBrowser && !embedded) {
|
|
128
154
|
const accessToken = token || getAccessToken();
|
|
129
155
|
if (accessToken) {
|
|
156
|
+
currentToken = accessToken;
|
|
130
157
|
userAuthModule.setToken(accessToken);
|
|
131
158
|
}
|
|
132
159
|
}
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
appId,
|
|
140
|
-
getToken,
|
|
141
|
-
};
|
|
142
|
-
let socket = null;
|
|
143
|
-
const getSocket = () => {
|
|
144
|
-
if (!socket) {
|
|
145
|
-
socket = RoomsSocket({ config: socketConfig });
|
|
160
|
+
// The one answer every module reads. Follows setToken and logout; outside an
|
|
161
|
+
// embedded frame it still falls back to storage, so a login in another tab is
|
|
162
|
+
// picked up on the next connection, as before.
|
|
163
|
+
const getToken = () => {
|
|
164
|
+
if (userAuthModule.hasToken()) {
|
|
165
|
+
return currentToken;
|
|
146
166
|
}
|
|
147
|
-
return
|
|
167
|
+
return embedded ? null : getAccessToken();
|
|
148
168
|
};
|
|
149
169
|
const applyToken = (newToken, saveToStorage) => {
|
|
150
170
|
userAuthModule.setToken(newToken, saveToStorage);
|
|
151
|
-
|
|
171
|
+
currentToken = newToken;
|
|
172
|
+
socketConfig.token = newToken;
|
|
173
|
+
if (socket) {
|
|
174
|
+
socket.updateConfig({ token: newToken });
|
|
175
|
+
}
|
|
152
176
|
};
|
|
153
|
-
//
|
|
177
|
+
// Resolves once the embedded session is in hand (or known not to be coming);
|
|
178
|
+
// immediately for every other client. The exchanged token is applied without
|
|
179
|
+
// persisting it: the session must not outlive the frame it was minted for.
|
|
154
180
|
const authReady = embedOtt
|
|
155
181
|
? exchangeEmbedToken({ serverUrl, appId, ott: embedOtt }).then((sessionToken) => {
|
|
156
182
|
if (sessionToken) {
|
|
@@ -159,8 +185,9 @@ export function createClient(config) {
|
|
|
159
185
|
})
|
|
160
186
|
: Promise.resolve();
|
|
161
187
|
if (embedOtt) {
|
|
162
|
-
// Requests issued
|
|
163
|
-
//
|
|
188
|
+
// Requests issued while the exchange is in flight wait for it and carry the
|
|
189
|
+
// session it produces. Registered after createAxiosClient's interceptors,
|
|
190
|
+
// so it runs first and the anonymous-visitor header sees the Authorization.
|
|
164
191
|
for (const client of [axiosClient, functionsAxiosClient]) {
|
|
165
192
|
client.interceptors.request.use(async (requestConfig) => {
|
|
166
193
|
await authReady;
|
package/dist/modules/auth.js
CHANGED
|
@@ -82,13 +82,10 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
82
82
|
// Tracked here rather than read off `axios.defaults` so the answer stays tied
|
|
83
83
|
// to the identity transitions below (`setToken`, `logout`) instead of to the
|
|
84
84
|
// header a caller may have set on the instance directly.
|
|
85
|
-
let
|
|
85
|
+
let hasAccessToken = Boolean(options.token);
|
|
86
86
|
return {
|
|
87
87
|
hasToken() {
|
|
88
|
-
return
|
|
89
|
-
},
|
|
90
|
-
getToken() {
|
|
91
|
-
return accessToken;
|
|
88
|
+
return hasAccessToken;
|
|
92
89
|
},
|
|
93
90
|
isEmbedded() {
|
|
94
91
|
return Boolean(options.embedded);
|
|
@@ -164,7 +161,7 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
164
161
|
// flight would otherwise resolve into callers that run after the logout.
|
|
165
162
|
clearPendingMe();
|
|
166
163
|
resetAnalyticsSessionContext();
|
|
167
|
-
|
|
164
|
+
hasAccessToken = false;
|
|
168
165
|
// Only do the rest if in a browser environment
|
|
169
166
|
if (typeof window !== "undefined") {
|
|
170
167
|
// Remove token from localStorage
|
|
@@ -193,7 +190,7 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
193
190
|
// resolved for the previous one must not be handed to later callers.
|
|
194
191
|
clearPendingMe();
|
|
195
192
|
resetAnalyticsSessionContext();
|
|
196
|
-
|
|
193
|
+
hasAccessToken = true;
|
|
197
194
|
// handle token change for axios clients
|
|
198
195
|
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
|
|
199
196
|
functionsAxiosClient.defaults.headers.common["Authorization"] = `Bearer ${token}`;
|
|
@@ -560,9 +560,4 @@ export interface InternalAuthModule extends AuthModule {
|
|
|
560
560
|
* could not succeed without a session, not to decide that one is valid.
|
|
561
561
|
*/
|
|
562
562
|
hasToken(): boolean;
|
|
563
|
-
/**
|
|
564
|
-
* The access token currently set on the client, or `null` when there is none.
|
|
565
|
-
* Follows {@linkcode AuthModule.setToken | setToken} and {@linkcode AuthModule.logout | logout}.
|
|
566
|
-
*/
|
|
567
|
-
getToken(): string | null;
|
|
568
563
|
}
|
|
@@ -4,8 +4,9 @@ export interface RoomsSocketConfig {
|
|
|
4
4
|
mountPath: string;
|
|
5
5
|
transports: string[];
|
|
6
6
|
appId: string;
|
|
7
|
-
/**
|
|
8
|
-
|
|
7
|
+
/** `undefined` means unknown — the socket looks in storage; `null` means
|
|
8
|
+
* known to be anonymous, so storage is never consulted. */
|
|
9
|
+
token?: string | null;
|
|
9
10
|
}
|
|
10
11
|
export type TSocketRoom = string;
|
|
11
12
|
export type TJsonStr = string;
|
|
@@ -41,7 +42,7 @@ export declare function RoomsSocket({ config }: {
|
|
|
41
42
|
leave: (room: string) => void;
|
|
42
43
|
}>;
|
|
43
44
|
subscribeToRoom: (room: TSocketRoom, handlers: Partial<{ [k in TEvent]: THandler<k>; }>) => () => void;
|
|
44
|
-
|
|
45
|
+
updateConfig: (config: Partial<RoomsSocketConfig>) => void;
|
|
45
46
|
updateModel: (room: string, data: any) => Promise<void>;
|
|
46
47
|
disconnect: () => void;
|
|
47
48
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { io } from "socket.io-client";
|
|
2
|
+
import { getAccessToken } from "./auth-utils.js";
|
|
2
3
|
import { getAnalyticsSessionId } from "../modules/analytics.js";
|
|
3
4
|
const ROOM_LEAVE_GRACE_MS = 250;
|
|
4
5
|
function initializeSocket(config, handlers) {
|
|
@@ -6,7 +7,7 @@ function initializeSocket(config, handlers) {
|
|
|
6
7
|
// handshake so the backend can verify room access for anonymous agent
|
|
7
8
|
// conversations (mirrors the X-Base44-Anonymous-Id HTTP header). Authenticated
|
|
8
9
|
// clients are identified by their token instead.
|
|
9
|
-
const resolvedToken = config.
|
|
10
|
+
const resolvedToken = config.token === undefined ? getAccessToken() : config.token;
|
|
10
11
|
const query = {
|
|
11
12
|
app_id: config.appId,
|
|
12
13
|
token: resolvedToken,
|
|
@@ -40,6 +41,7 @@ function initializeSocket(config, handlers) {
|
|
|
40
41
|
return socket;
|
|
41
42
|
}
|
|
42
43
|
export function RoomsSocket({ config }) {
|
|
44
|
+
let currentConfig = { ...config };
|
|
43
45
|
const roomsToListeners = {};
|
|
44
46
|
const pendingRoomLeaves = {};
|
|
45
47
|
const handlers = {
|
|
@@ -81,10 +83,13 @@ export function RoomsSocket({ config }) {
|
|
|
81
83
|
socket.disconnect();
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
|
-
|
|
85
|
-
function reconnect() {
|
|
86
|
+
function updateConfig(config) {
|
|
86
87
|
cleanup();
|
|
87
|
-
|
|
88
|
+
currentConfig = {
|
|
89
|
+
...currentConfig,
|
|
90
|
+
...config,
|
|
91
|
+
};
|
|
92
|
+
socket = initializeSocket(currentConfig, handlers);
|
|
88
93
|
}
|
|
89
94
|
function joinRoom(room) {
|
|
90
95
|
socket.emit("join", room);
|
|
@@ -157,7 +162,7 @@ export function RoomsSocket({ config }) {
|
|
|
157
162
|
return {
|
|
158
163
|
socket,
|
|
159
164
|
subscribeToRoom,
|
|
160
|
-
|
|
165
|
+
updateConfig,
|
|
161
166
|
updateModel,
|
|
162
167
|
disconnect,
|
|
163
168
|
};
|