@base44-preview/sdk 0.8.43-pr.260.d28232f → 0.8.43-pr.261.f8cbcf8
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 +3 -27
- package/dist/client.types.d.ts +0 -12
- package/dist/modules/actors.d.ts +7 -33
- package/dist/modules/actors.js +23 -116
- package/dist/modules/actors.types.d.ts +3 -16
- package/dist/modules/analytics.js +3 -14
- package/dist/modules/connectors.js +13 -11
- package/dist/modules/connectors.types.d.ts +1 -1
- package/dist/utils/axios-client.js +2 -4
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -12,7 +12,7 @@ import { createAppLogsModule } from "./modules/app-logs.js";
|
|
|
12
12
|
import { createUsersModule } from "./modules/users.js";
|
|
13
13
|
import { RoomsSocket } from "./utils/socket-utils.js";
|
|
14
14
|
import { createAnalyticsModule } from "./modules/analytics.js";
|
|
15
|
-
import { createActorsModule, resolveActorsHost
|
|
15
|
+
import { createActorsModule, resolveActorsHost } from "./modules/actors.js";
|
|
16
16
|
/**
|
|
17
17
|
* Creates a Base44 client.
|
|
18
18
|
*
|
|
@@ -110,15 +110,6 @@ export function createClient(config) {
|
|
|
110
110
|
token: serviceToken,
|
|
111
111
|
interceptResponses: false,
|
|
112
112
|
});
|
|
113
|
-
// Dedicated client for actor connection-token mints: no onError (a legacy
|
|
114
|
-
// actor answers every mint with an expected 409 before the proxy fallback,
|
|
115
|
-
// which must not reach the app's error handler — the actors module forwards
|
|
116
|
-
// genuine failures itself via onMintError) and no constructor token
|
|
117
|
-
// (auth is per-request so a login/logout is picked up on every reconnect).
|
|
118
|
-
const actorsAxiosClient = createAxiosClient({
|
|
119
|
-
baseURL: `${serverUrl}/api`,
|
|
120
|
-
headers,
|
|
121
|
-
});
|
|
122
113
|
const userAuthModule = createAuthModule(axiosClient, functionsAxiosClient, appId, {
|
|
123
114
|
appBaseUrl: normalizedAppBaseUrl,
|
|
124
115
|
serverUrl,
|
|
@@ -136,26 +127,11 @@ export function createClient(config) {
|
|
|
136
127
|
}
|
|
137
128
|
const actorsModule = createActorsModule({
|
|
138
129
|
appId,
|
|
139
|
-
// serverUrl is often relative/empty (same-origin app);
|
|
140
|
-
//
|
|
130
|
+
// serverUrl is often relative/empty (same-origin app); PartySocket needs an
|
|
131
|
+
// absolute host, so fall back to the page origin.
|
|
141
132
|
host: resolveActorsHost(serverUrl, typeof window !== "undefined" ? (_a = window.location) === null || _a === void 0 ? void 0 : _a.origin : undefined),
|
|
142
133
|
functionsVersion,
|
|
143
134
|
getAuthToken: () => token || getAccessToken(),
|
|
144
|
-
mintConnectionToken: async (actorName, room, connectionId) => {
|
|
145
|
-
const authToken = token || getAccessToken();
|
|
146
|
-
return await actorsAxiosClient.post(`/apps/${appId}/actors/${encodeURIComponent(actorName)}/connection-token`, { room, connection_id: connectionId }, {
|
|
147
|
-
headers: {
|
|
148
|
-
...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
|
|
149
|
-
// The mint endpoint resolves draft vs published from this header;
|
|
150
|
-
// only the functions axios clients send it by default.
|
|
151
|
-
...(functionsVersion
|
|
152
|
-
? { "Base44-Functions-Version": functionsVersion }
|
|
153
|
-
: {}),
|
|
154
|
-
},
|
|
155
|
-
});
|
|
156
|
-
},
|
|
157
|
-
transport: options === null || options === void 0 ? void 0 : options.actorsTransport,
|
|
158
|
-
onMintError: options === null || options === void 0 ? void 0 : options.onError,
|
|
159
135
|
});
|
|
160
136
|
const userModules = {
|
|
161
137
|
entities: createEntitiesModule({
|
package/dist/client.types.d.ts
CHANGED
|
@@ -15,20 +15,8 @@ import type { ActorsModule } from "./modules/actors.types.js";
|
|
|
15
15
|
export interface CreateClientOptions {
|
|
16
16
|
/**
|
|
17
17
|
* Optional error handler that will be called whenever an API error occurs.
|
|
18
|
-
*
|
|
19
|
-
* Also receives {@link ActorsModule | actors} connection failures. Errors
|
|
20
|
-
* are usually {@linkcode Base44Error} instances — check `error.status`.
|
|
21
18
|
*/
|
|
22
19
|
onError?: (error: Error) => void;
|
|
23
|
-
/**
|
|
24
|
-
* Forces the actors transport. `"auto"` (default) connects directly to the
|
|
25
|
-
* actor and falls back to the platform proxy when the app's actors don't
|
|
26
|
-
* support direct connections; `"proxy"` always uses the platform proxy
|
|
27
|
-
* (ops rollback — no connection-token calls); `"direct"` disables the
|
|
28
|
-
* fallback (validation environments).
|
|
29
|
-
* @internal
|
|
30
|
-
*/
|
|
31
|
-
actorsTransport?: "auto" | "proxy" | "direct";
|
|
32
20
|
}
|
|
33
21
|
/**
|
|
34
22
|
* Configuration for creating a Base44 client.
|
package/dist/modules/actors.d.ts
CHANGED
|
@@ -1,47 +1,21 @@
|
|
|
1
1
|
import type { ActorRef } from "./actors.types.js";
|
|
2
|
-
/** Credentials minted by the platform for one direct actor connection. */
|
|
3
|
-
export interface ActorConnectionCredentials {
|
|
4
|
-
/** Direct actor endpoint, already carrying `?_pk=<connectionId>`. */
|
|
5
|
-
websocket_url: string;
|
|
6
|
-
/** Short-lived JWT bound to (app, actor, room, connectionId); appended to
|
|
7
|
-
* the URL as `token=` since browsers can't set WebSocket headers. */
|
|
8
|
-
token: string;
|
|
9
|
-
}
|
|
10
2
|
interface ActorsConfig {
|
|
11
3
|
appId: string;
|
|
12
|
-
/** Current user access token, if authenticated. Rides the WS query
|
|
13
|
-
*
|
|
14
|
-
* anonymous connects omit it. */
|
|
4
|
+
/** Current user access token, if authenticated. Rides the WS query so the
|
|
5
|
+
* platform proxy can authenticate the connection; anonymous connects omit it. */
|
|
15
6
|
getAuthToken(): string | null | undefined;
|
|
16
7
|
/** Same semantics as function calls: editors with a non-prod version get the
|
|
17
8
|
* draft actor script; everyone else gets the published one. */
|
|
18
9
|
functionsVersion?: string;
|
|
19
|
-
/** Absolute host
|
|
10
|
+
/** Absolute host PartySocket dials (it strips the scheme and connects wss, ws
|
|
20
11
|
* for localhost). Resolved by {@link resolveActorsHost}. */
|
|
21
12
|
host: string;
|
|
22
|
-
/** Mints a direct-connect credential for one (actor, room, connection).
|
|
23
|
-
* Called per connection attempt: the token's expiry is checked at upgrade,
|
|
24
|
-
* so every reconnect needs a fresh one. */
|
|
25
|
-
mintConnectionToken(actorName: string, room: string, connectionId: string): Promise<ActorConnectionCredentials>;
|
|
26
|
-
/** @internal Ops escape hatch: "proxy" never mints (legacy path only),
|
|
27
|
-
* "direct" never falls back. Default "auto". */
|
|
28
|
-
transport?: "auto" | "proxy" | "direct";
|
|
29
|
-
/** Called when a mint fails for a reason other than the expected
|
|
30
|
-
* direct→proxy fallback (which recovers by itself). Wired to the client's
|
|
31
|
-
* `options.onError`. */
|
|
32
|
-
onMintError?: (error: Error) => void;
|
|
33
13
|
}
|
|
34
14
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*/
|
|
40
|
-
export declare function buildProxyActorUrl(rawHost: string, actorName: string, instanceId: string, connectionId: string, appId: string, token: string | null | undefined, functionsVersion?: string): string;
|
|
41
|
-
/**
|
|
42
|
-
* Absolute host for the proxy-fallback actor URL. A relative/empty `serverUrl`
|
|
43
|
-
* can't be dialed (same-origin apps use a relative `/api`, so `serverUrl` is
|
|
44
|
-
* often `""`), so fall back to the page origin.
|
|
15
|
+
* Absolute host for the actor WebSocket. PartySocket needs an absolute host and
|
|
16
|
+
* can't resolve a relative/empty `serverUrl` (same-origin apps use a relative
|
|
17
|
+
* `/api`, so `serverUrl` is often `""`), so fall back to the page origin.
|
|
18
|
+
* PartySocket handles the scheme (https→wss, ws for localhost).
|
|
45
19
|
*/
|
|
46
20
|
export declare function resolveActorsHost(serverUrl: string, browserOrigin?: string): string;
|
|
47
21
|
export declare function createActorsModule(config: ActorsConfig): {
|
package/dist/modules/actors.js
CHANGED
|
@@ -1,32 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
// Heartbeat / half-open detection:
|
|
1
|
+
import PartySocket from "partysocket";
|
|
2
|
+
// Heartbeat / half-open detection: PartySocket only reconnects on a close/error
|
|
3
3
|
// event, so ping periodically and force a reconnect if nothing returns in DEAD_MS.
|
|
4
4
|
const PING_MS = 1000;
|
|
5
5
|
const DEAD_MS = 3000;
|
|
6
|
-
// Mint responses that mean "direct can't serve this connection, the proxy can":
|
|
7
|
-
// 409 = legacy-family actor script, 503 = direct connections not provisioned,
|
|
8
|
-
// 422 = no principal (e.g. anonymous outside a browser) or an id/room only the
|
|
9
|
-
// proxy's looser validation accepts, 405 = a backend that predates the mint
|
|
10
|
-
// endpoint (its actor deploy routes catch the path via `{handler_name:path}`
|
|
11
|
-
// but not the POST method — and the real endpoint never 405s a POST). The
|
|
12
|
-
// proxy serves migrated actors too, so falling back is always safe.
|
|
13
|
-
const PROXY_FALLBACK_STATUSES = new Set([405, 409, 422, 503]);
|
|
14
|
-
// Mint responses no retry can fix (bad request / forbidden / not found): the
|
|
15
|
-
// connection closes instead of re-minting forever; a fresh connect() re-probes.
|
|
16
|
-
// 401 is deliberately absent — the auth token is re-read on every attempt, so a
|
|
17
|
-
// login recovers on the next retry. Disjoint from PROXY_FALLBACK_STATUSES.
|
|
18
|
-
const TERMINAL_MINT_STATUSES = new Set([400, 403, 404]);
|
|
19
|
-
/** The mint's rejection can be anything; a `Base44Error` carries a numeric
|
|
20
|
-
* `.status` (absent for network failures). */
|
|
21
|
-
function mintErrorStatus(err) {
|
|
22
|
-
const status = err && typeof err === "object"
|
|
23
|
-
? err.status
|
|
24
|
-
: undefined;
|
|
25
|
-
return typeof status === "number" ? status : undefined;
|
|
26
|
-
}
|
|
27
|
-
function toError(err) {
|
|
28
|
-
return err instanceof Error ? err : new Error(String(err));
|
|
29
|
-
}
|
|
30
6
|
/**
|
|
31
7
|
* A live connection to an actor instance. Only obtainable from
|
|
32
8
|
* {@link ActorRef.connect}, so `subscribe`/`send` are always valid — the socket
|
|
@@ -38,54 +14,23 @@ class Connection {
|
|
|
38
14
|
this.onClose = onClose;
|
|
39
15
|
this.listeners = new Set();
|
|
40
16
|
this.heartbeat = null;
|
|
41
|
-
this.closed = false;
|
|
42
17
|
this.id = (_a = options === null || options === void 0 ? void 0 : options.id) !== null && _a !== void 0 ? _a : crypto.randomUUID();
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
catch (err) {
|
|
61
|
-
const status = mintErrorStatus(err);
|
|
62
|
-
const isFallback = config.transport !== "direct" &&
|
|
63
|
-
status !== undefined &&
|
|
64
|
-
PROXY_FALLBACK_STATUSES.has(status);
|
|
65
|
-
if (!isFallback) {
|
|
66
|
-
if (status !== undefined && TERMINAL_MINT_STATUSES.has(status)) {
|
|
67
|
-
// close() before notifying: ws.close() stops the redial the
|
|
68
|
-
// rethrow below would otherwise schedule, and a handler that
|
|
69
|
-
// immediately calls connect() gets a clean new connection.
|
|
70
|
-
this.close();
|
|
71
|
-
}
|
|
72
|
-
// Reported from here because the socket's error event only
|
|
73
|
-
// preserves `err.message`, never `.status`.
|
|
74
|
-
try {
|
|
75
|
-
(_a = config.onMintError) === null || _a === void 0 ? void 0 : _a.call(config, toError(err));
|
|
76
|
-
}
|
|
77
|
-
catch (_b) {
|
|
78
|
-
// an app handler must not break the dial loop or mask `err`
|
|
79
|
-
}
|
|
80
|
-
throw err;
|
|
81
|
-
}
|
|
82
|
-
useProxy = true;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
// Rebuilt per attempt so a login/logout is picked up on reconnect.
|
|
86
|
-
return buildProxyActorUrl(config.host, actorName, instanceId, this.id, config.appId, config.getAuthToken(), config.functionsVersion);
|
|
87
|
-
};
|
|
88
|
-
const ws = new ReconnectingWebSocket(urlProvider);
|
|
18
|
+
const ws = new PartySocket({
|
|
19
|
+
host: config.host,
|
|
20
|
+
party: actorName,
|
|
21
|
+
room: instanceId,
|
|
22
|
+
id: this.id,
|
|
23
|
+
// Re-read on every (re)connect so a login/logout is picked up.
|
|
24
|
+
query: () => {
|
|
25
|
+
const token = config.getAuthToken();
|
|
26
|
+
return {
|
|
27
|
+
app_id: config.appId,
|
|
28
|
+
handler: actorName,
|
|
29
|
+
...(token ? { token } : {}),
|
|
30
|
+
...(config.functionsVersion ? { fv: config.functionsVersion } : {}),
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
});
|
|
89
34
|
this.ws = ws;
|
|
90
35
|
let lastMsg = Date.now();
|
|
91
36
|
const bumpAlive = () => { lastMsg = Date.now(); };
|
|
@@ -108,11 +53,7 @@ class Connection {
|
|
|
108
53
|
this.heartbeat = setInterval(() => {
|
|
109
54
|
if (Date.now() - lastMsg > DEAD_MS) {
|
|
110
55
|
bumpAlive(); // avoid a reconnect storm while the new socket comes up
|
|
111
|
-
|
|
112
|
-
// the socket is already redialing with backoff, and reconnect() would
|
|
113
|
-
// reset that backoff into a mint call every DEAD_MS.
|
|
114
|
-
if (ws.readyState === ws.OPEN)
|
|
115
|
-
ws.reconnect();
|
|
56
|
+
ws.reconnect();
|
|
116
57
|
return;
|
|
117
58
|
}
|
|
118
59
|
try {
|
|
@@ -132,15 +73,9 @@ class Connection {
|
|
|
132
73
|
};
|
|
133
74
|
}
|
|
134
75
|
send(data) {
|
|
135
|
-
// after close() the socket would buffer forever (unbounded enqueue)
|
|
136
|
-
if (this.closed)
|
|
137
|
-
return;
|
|
138
76
|
this.ws.send(JSON.stringify(data));
|
|
139
77
|
}
|
|
140
78
|
close() {
|
|
141
|
-
if (this.closed)
|
|
142
|
-
return;
|
|
143
|
-
this.closed = true;
|
|
144
79
|
if (this.heartbeat) {
|
|
145
80
|
clearInterval(this.heartbeat);
|
|
146
81
|
this.heartbeat = null;
|
|
@@ -169,38 +104,10 @@ function makeActorRef(actorName, instanceId, config, connections) {
|
|
|
169
104
|
};
|
|
170
105
|
}
|
|
171
106
|
/**
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*/
|
|
177
|
-
export function buildProxyActorUrl(rawHost, actorName, instanceId, connectionId, appId, token, functionsVersion) {
|
|
178
|
-
let host = rawHost.replace(/^(http|https|ws|wss):\/\//, "");
|
|
179
|
-
if (host.endsWith("/"))
|
|
180
|
-
host = host.slice(0, -1);
|
|
181
|
-
const insecure = host.startsWith("localhost:") ||
|
|
182
|
-
host.startsWith("127.0.0.1:") ||
|
|
183
|
-
host.startsWith("192.168.") ||
|
|
184
|
-
host.startsWith("10.") ||
|
|
185
|
-
(host.startsWith("172.") &&
|
|
186
|
-
host.split(".")[1] >= "16" &&
|
|
187
|
-
host.split(".")[1] <= "31") ||
|
|
188
|
-
host.startsWith("[::ffff:7f00:1]:");
|
|
189
|
-
const query = new URLSearchParams([
|
|
190
|
-
["_pk", connectionId],
|
|
191
|
-
["app_id", appId],
|
|
192
|
-
["handler", actorName],
|
|
193
|
-
]);
|
|
194
|
-
if (token)
|
|
195
|
-
query.append("token", token);
|
|
196
|
-
if (functionsVersion)
|
|
197
|
-
query.append("fv", functionsVersion);
|
|
198
|
-
return `${insecure ? "ws" : "wss"}://${host}/parties/${actorName}/${instanceId}?${query}`;
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Absolute host for the proxy-fallback actor URL. A relative/empty `serverUrl`
|
|
202
|
-
* can't be dialed (same-origin apps use a relative `/api`, so `serverUrl` is
|
|
203
|
-
* often `""`), so fall back to the page origin.
|
|
107
|
+
* Absolute host for the actor WebSocket. PartySocket needs an absolute host and
|
|
108
|
+
* can't resolve a relative/empty `serverUrl` (same-origin apps use a relative
|
|
109
|
+
* `/api`, so `serverUrl` is often `""`), so fall back to the page origin.
|
|
110
|
+
* PartySocket handles the scheme (https→wss, ws for localhost).
|
|
204
111
|
*/
|
|
205
112
|
export function resolveActorsHost(serverUrl, browserOrigin) {
|
|
206
113
|
return serverUrl && !serverUrl.startsWith("/") ? serverUrl : browserOrigin !== null && browserOrigin !== void 0 ? browserOrigin : serverUrl;
|
|
@@ -56,14 +56,9 @@ export interface Connection<N extends string = string> {
|
|
|
56
56
|
readonly id: string;
|
|
57
57
|
/** Register a message listener. Multiple are allowed; returns a per-listener unsubscribe. */
|
|
58
58
|
subscribe(callback: (data: ToClientFor<N>) => void): ActorSubscription;
|
|
59
|
-
/** Send a message. Buffered by the socket until it's open
|
|
60
|
-
* {@link close}. */
|
|
59
|
+
/** Send a message. Buffered by the socket until it's open. */
|
|
61
60
|
send(data: ToServerFor<N>): void;
|
|
62
|
-
/**
|
|
63
|
-
* Tear down the socket, heartbeat, and all listeners. Safe to call more
|
|
64
|
-
* than once. A connection also closes itself when it fails permanently —
|
|
65
|
-
* see {@link ActorRef.connect}.
|
|
66
|
-
*/
|
|
61
|
+
/** Tear down the socket, heartbeat, and all listeners. */
|
|
67
62
|
close(): void;
|
|
68
63
|
}
|
|
69
64
|
/**
|
|
@@ -71,15 +66,7 @@ export interface Connection<N extends string = string> {
|
|
|
71
66
|
* {@link connect} to open the socket and get a {@link Connection}.
|
|
72
67
|
*/
|
|
73
68
|
export interface ActorRef<N extends string = string> {
|
|
74
|
-
/**
|
|
75
|
-
* Open the WebSocket and return the {@link Connection}. Idempotent while the
|
|
76
|
-
* connection is open.
|
|
77
|
-
*
|
|
78
|
-
* A connection that fails permanently (for example, the actor doesn't exist
|
|
79
|
-
* or the caller isn't allowed to connect) closes itself and reports the
|
|
80
|
-
* error to the client's `onError` handler. Call `connect()` again after
|
|
81
|
-
* fixing the cause to get a fresh {@link Connection}, and re-subscribe.
|
|
82
|
-
*/
|
|
69
|
+
/** Open the WebSocket and return the {@link Connection}. Idempotent. */
|
|
83
70
|
connect(options?: ActorConnectOptions): Connection<N>;
|
|
84
71
|
}
|
|
85
72
|
/**
|
|
@@ -25,9 +25,6 @@ const analyticsSharedState = getSharedInstance(ANALYTICS_SHARED_STATE_NAME, () =
|
|
|
25
25
|
wasInitializationTracked: false,
|
|
26
26
|
sessionContext: null,
|
|
27
27
|
sessionStartTime: null,
|
|
28
|
-
// Memoized session id for when `localStorage` can't persist one — see
|
|
29
|
-
// getAnalyticsSessionId.
|
|
30
|
-
fallbackSessionId: null,
|
|
31
28
|
config: {
|
|
32
29
|
...defaultConfiguration,
|
|
33
30
|
...getAnalyticsConfigFromUrlParams(),
|
|
@@ -219,11 +216,9 @@ function trackSessionDurationEvent(track) {
|
|
|
219
216
|
});
|
|
220
217
|
}
|
|
221
218
|
function getEventIntrinsicData() {
|
|
222
|
-
var _a, _b;
|
|
223
219
|
return {
|
|
224
220
|
timestamp: new Date().toISOString(),
|
|
225
|
-
|
|
226
|
-
pageUrl: typeof window !== "undefined" ? (_b = (_a = window.location) === null || _a === void 0 ? void 0 : _a.pathname) !== null && _b !== void 0 ? _b : null : null,
|
|
221
|
+
pageUrl: typeof window !== "undefined" ? window.location.pathname : null,
|
|
227
222
|
};
|
|
228
223
|
}
|
|
229
224
|
function transformEventDataToApiRequestData(sessionContext) {
|
|
@@ -307,15 +302,9 @@ export function getAnalyticsConfigFromUrlParams() {
|
|
|
307
302
|
// return the config object //
|
|
308
303
|
return { enabled: analyticsEnable === "true" };
|
|
309
304
|
}
|
|
310
|
-
// When the id can't be persisted (React Native has no `localStorage`), keep
|
|
311
|
-
// it stable for the process instead of minting a fresh one per call.
|
|
312
|
-
function getFallbackSessionId() {
|
|
313
|
-
var _a;
|
|
314
|
-
return ((_a = analyticsSharedState.fallbackSessionId) !== null && _a !== void 0 ? _a : (analyticsSharedState.fallbackSessionId = generateUuid()));
|
|
315
|
-
}
|
|
316
305
|
export function getAnalyticsSessionId() {
|
|
317
306
|
if (typeof window === "undefined") {
|
|
318
|
-
return
|
|
307
|
+
return generateUuid();
|
|
319
308
|
}
|
|
320
309
|
try {
|
|
321
310
|
const sessionId = localStorage.getItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY);
|
|
@@ -327,6 +316,6 @@ export function getAnalyticsSessionId() {
|
|
|
327
316
|
return sessionId;
|
|
328
317
|
}
|
|
329
318
|
catch (_a) {
|
|
330
|
-
return
|
|
319
|
+
return generateUuid();
|
|
331
320
|
}
|
|
332
321
|
}
|
|
@@ -25,7 +25,7 @@ export function createConnectorsModule(axios, appId) {
|
|
|
25
25
|
if (!integrationType || typeof integrationType !== "string") {
|
|
26
26
|
throw new Error("Integration type is required and must be a string");
|
|
27
27
|
}
|
|
28
|
-
const response = await axios.get(`/apps/${appId}/external-auth/tokens/${integrationType}`);
|
|
28
|
+
const response = await axios.get(`/apps/${appId}/external-auth/tokens/${encodeURIComponent(integrationType)}`);
|
|
29
29
|
// @ts-expect-error
|
|
30
30
|
return response.access_token;
|
|
31
31
|
},
|
|
@@ -34,7 +34,7 @@ export function createConnectorsModule(axios, appId) {
|
|
|
34
34
|
if (!integrationType || typeof integrationType !== "string") {
|
|
35
35
|
throw new Error("Integration type is required and must be a string");
|
|
36
36
|
}
|
|
37
|
-
const response = await axios.get(`/apps/${appId}/external-auth/tokens/${integrationType}`);
|
|
37
|
+
const response = await axios.get(`/apps/${appId}/external-auth/tokens/${encodeURIComponent(integrationType)}`);
|
|
38
38
|
const data = response;
|
|
39
39
|
return {
|
|
40
40
|
accessToken: data.access_token,
|
|
@@ -46,7 +46,7 @@ export function createConnectorsModule(axios, appId) {
|
|
|
46
46
|
if (!connectorId || typeof connectorId !== "string") {
|
|
47
47
|
throw new Error("Connector ID is required and must be a string");
|
|
48
48
|
}
|
|
49
|
-
const response = await axios.get(`/apps/${appId}/external-auth/tokens/connectors/${connectorId}`);
|
|
49
|
+
const response = await axios.get(`/apps/${appId}/external-auth/tokens/connectors/${encodeURIComponent(connectorId)}`);
|
|
50
50
|
const data = response;
|
|
51
51
|
return {
|
|
52
52
|
accessToken: data.access_token,
|
|
@@ -60,7 +60,7 @@ export function createConnectorsModule(axios, appId) {
|
|
|
60
60
|
if (!connectorId || typeof connectorId !== "string") {
|
|
61
61
|
throw new Error("Connector ID is required and must be a string");
|
|
62
62
|
}
|
|
63
|
-
const response = await axios.get(`/apps/${appId}/app-user-auth/connectors/${connectorId}/token`);
|
|
63
|
+
const response = await axios.get(`/apps/${appId}/app-user-auth/connectors/${encodeURIComponent(connectorId)}/token`);
|
|
64
64
|
const data = response;
|
|
65
65
|
return data.access_token;
|
|
66
66
|
},
|
|
@@ -69,7 +69,7 @@ export function createConnectorsModule(axios, appId) {
|
|
|
69
69
|
if (!connectorId || typeof connectorId !== "string") {
|
|
70
70
|
throw new Error("Connector ID is required and must be a string");
|
|
71
71
|
}
|
|
72
|
-
const response = await axios.get(`/apps/${appId}/app-user-auth/connectors/${connectorId}/token`);
|
|
72
|
+
const response = await axios.get(`/apps/${appId}/app-user-auth/connectors/${encodeURIComponent(connectorId)}/token`);
|
|
73
73
|
const data = response;
|
|
74
74
|
return {
|
|
75
75
|
accessToken: data.access_token,
|
|
@@ -78,7 +78,9 @@ export function createConnectorsModule(axios, appId) {
|
|
|
78
78
|
},
|
|
79
79
|
async callApi(integrationType, request) {
|
|
80
80
|
assertNonEmptyString(integrationType, "Integration type");
|
|
81
|
-
|
|
81
|
+
// Encoded so a runtime-built identifier can only ever select a
|
|
82
|
+
// connector, never re-target another route under this token.
|
|
83
|
+
return proxyCall(axios, `/apps/${appId}/connectors/${encodeURIComponent(integrationType)}/call`, request);
|
|
82
84
|
},
|
|
83
85
|
};
|
|
84
86
|
}
|
|
@@ -108,9 +110,9 @@ async function proxyCall(axios, url, request) {
|
|
|
108
110
|
}
|
|
109
111
|
const response = await axios.post(url, {
|
|
110
112
|
method,
|
|
111
|
-
// Omitted
|
|
112
|
-
// declared default host.
|
|
113
|
-
...(request.host
|
|
113
|
+
// Omitted when unset (undefined or null, since untyped callers write
|
|
114
|
+
// either) so the proxy applies the connector's declared default host.
|
|
115
|
+
...(request.host == null ? {} : { host: request.host }),
|
|
114
116
|
path: request.path,
|
|
115
117
|
query: (_b = request.query) !== null && _b !== void 0 ? _b : {},
|
|
116
118
|
headers: (_c = request.headers) !== null && _c !== void 0 ? _c : {},
|
|
@@ -142,7 +144,7 @@ export function createUserConnectorsModule(axios, appId) {
|
|
|
142
144
|
if (!connectorId || typeof connectorId !== "string") {
|
|
143
145
|
throw new Error("Connector ID is required and must be a string");
|
|
144
146
|
}
|
|
145
|
-
const response = await axios.post(`/apps/${appId}/app-user-auth/connectors/${connectorId}/initiate`);
|
|
147
|
+
const response = await axios.post(`/apps/${appId}/app-user-auth/connectors/${encodeURIComponent(connectorId)}/initiate`);
|
|
146
148
|
const data = response;
|
|
147
149
|
return data.redirect_url;
|
|
148
150
|
},
|
|
@@ -150,7 +152,7 @@ export function createUserConnectorsModule(axios, appId) {
|
|
|
150
152
|
if (!connectorId || typeof connectorId !== "string") {
|
|
151
153
|
throw new Error("Connector ID is required and must be a string");
|
|
152
154
|
}
|
|
153
|
-
await axios.delete(`/apps/${appId}/app-user-auth/connectors/${connectorId}`);
|
|
155
|
+
await axios.delete(`/apps/${appId}/app-user-auth/connectors/${encodeURIComponent(connectorId)}`);
|
|
154
156
|
},
|
|
155
157
|
};
|
|
156
158
|
}
|
|
@@ -89,7 +89,7 @@ export interface ConnectorApiResponse<T = unknown> {
|
|
|
89
89
|
* The parsed upstream response body, or proxy error details when no response
|
|
90
90
|
* was received. `null` when the response was binary — see {@link dataBase64}.
|
|
91
91
|
*/
|
|
92
|
-
data: T;
|
|
92
|
+
data: T | null;
|
|
93
93
|
/**
|
|
94
94
|
* The response body base64-encoded, for the media types the connector declares
|
|
95
95
|
* as binary (images, PDFs). Set instead of {@link data}, never alongside it.
|
|
@@ -132,10 +132,8 @@ export function createAxiosClient({ baseURL, headers = {}, token, interceptRespo
|
|
|
132
132
|
client.interceptors.request.use((config) => {
|
|
133
133
|
// `window.location` is absent on React Native (where `window` still exists),
|
|
134
134
|
// so guard on it before reading `.href`.
|
|
135
|
-
if (typeof window !== "undefined") {
|
|
136
|
-
|
|
137
|
-
config.headers.set("X-Origin-URL", window.location.href);
|
|
138
|
-
}
|
|
135
|
+
if (typeof window !== "undefined" && window.location) {
|
|
136
|
+
config.headers.set("X-Origin-URL", window.location.href);
|
|
139
137
|
// On unauthenticated requests, attach a stable anonymous visitor id so the
|
|
140
138
|
// backend can support anonymous agent access (conversation grouping + ownership).
|
|
141
139
|
// Authenticated requests are identified by their Authorization header instead.
|