@blade-hq/agent-kit 1.0.34 → 1.0.35
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/README.md +95 -2
- package/dist/chunk-6KO3AOJ7.js +251 -0
- package/dist/chunk-6KO3AOJ7.js.map +1 -0
- package/dist/{chunk-FK4CV6R2.js → chunk-C63X3RCM.js} +629 -32
- package/dist/chunk-C63X3RCM.js.map +1 -0
- package/dist/{chunk-BDGMBHYV.js → chunk-DOBX7XP3.js} +5 -5
- package/dist/{chunk-EGGBOVVF.js → chunk-IP7EZVT5.js} +2 -2
- package/dist/{chunk-OICNN4K4.js → chunk-J6H4TMTH.js} +2 -2
- package/dist/{chunk-F4Y7SUBC.js → chunk-SEHOWQVO.js} +2 -2
- package/dist/{chunk-IDVNG3YJ.js → chunk-YJSN44Q4.js} +16 -3
- package/dist/{chunk-IDVNG3YJ.js.map → chunk-YJSN44Q4.js.map} +1 -1
- package/dist/{chunk-E7FQV4IX.js → chunk-ZPPYDQPU.js} +3 -3
- package/dist/client/auth.d.ts +55 -0
- package/dist/client/blade-client.d.ts +19 -3
- package/dist/client/connection.d.ts +41 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.js +11 -3
- package/dist/client/resources/auth.d.ts +1 -26
- package/dist/client/socket.d.ts +1 -0
- package/dist/client/types/rest.d.ts +151 -0
- package/dist/client/types/socket-events.d.ts +4 -0
- package/dist/react/api/published-apps.js +3 -3
- package/dist/react/api/sessions.js +2 -2
- package/dist/react/bootstrap.d.ts +1 -1
- package/dist/react/components/chat/index.js +5 -5
- package/dist/react/components/connection/BladeConnectionButton.d.ts +7 -0
- package/dist/react/components/connection/BladeConnectionPanel.d.ts +7 -0
- package/dist/react/components/connection/index.d.ts +2 -0
- package/dist/react/components/connection/index.js +15 -0
- package/dist/react/components/connection/index.js.map +1 -0
- package/dist/react/components/plan/index.js +4 -4
- package/dist/react/components/session/index.js +3 -3
- package/dist/react/components/workspace/index.js +3 -3
- package/dist/react/hooks/use-blade-connection.d.ts +14 -0
- package/dist/react/index.d.ts +5 -1
- package/dist/react/index.js +20 -22
- package/dist/react/index.js.map +1 -1
- package/dist/react/sockets/event-bridge.d.ts +2 -0
- package/dist/style.css +1 -1
- package/package.json +5 -1
- package/dist/chunk-FK4CV6R2.js.map +0 -1
- /package/dist/{chunk-BDGMBHYV.js.map → chunk-DOBX7XP3.js.map} +0 -0
- /package/dist/{chunk-EGGBOVVF.js.map → chunk-IP7EZVT5.js.map} +0 -0
- /package/dist/{chunk-OICNN4K4.js.map → chunk-J6H4TMTH.js.map} +0 -0
- /package/dist/{chunk-F4Y7SUBC.js.map → chunk-SEHOWQVO.js.map} +0 -0
- /package/dist/{chunk-E7FQV4IX.js.map → chunk-ZPPYDQPU.js.map} +0 -0
|
@@ -95,12 +95,99 @@ var AppDevTemplatesResource = class {
|
|
|
95
95
|
}
|
|
96
96
|
};
|
|
97
97
|
|
|
98
|
-
// src/client/
|
|
98
|
+
// src/client/connection.ts
|
|
99
|
+
var BladeConnectionError = class extends Error {
|
|
100
|
+
code;
|
|
101
|
+
constructor(code, message, options) {
|
|
102
|
+
super(message, options);
|
|
103
|
+
this.name = "BladeConnectionError";
|
|
104
|
+
this.code = code;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
function createMemoryAuthStorage() {
|
|
108
|
+
const values = /* @__PURE__ */ new Map();
|
|
109
|
+
return {
|
|
110
|
+
get: (key) => values.get(key) ?? null,
|
|
111
|
+
set: (key, value) => {
|
|
112
|
+
values.set(key, value);
|
|
113
|
+
},
|
|
114
|
+
remove: (key) => {
|
|
115
|
+
values.delete(key);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function createLocalAuthStorage() {
|
|
120
|
+
return {
|
|
121
|
+
get(key) {
|
|
122
|
+
const raw = window.localStorage.getItem(key);
|
|
123
|
+
if (!raw) return null;
|
|
124
|
+
try {
|
|
125
|
+
const value = JSON.parse(raw);
|
|
126
|
+
if (!value.accessToken || !value.user?.id || !value.user.username) return null;
|
|
127
|
+
return value;
|
|
128
|
+
} catch {
|
|
129
|
+
window.localStorage.removeItem(key);
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
set(key, value) {
|
|
134
|
+
window.localStorage.setItem(key, JSON.stringify(value));
|
|
135
|
+
},
|
|
136
|
+
remove(key) {
|
|
137
|
+
window.localStorage.removeItem(key);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/client/auth.ts
|
|
143
|
+
function buildSocketAuth(options) {
|
|
144
|
+
const token = resolveAuthToken(options);
|
|
145
|
+
return token ? { token } : void 0;
|
|
146
|
+
}
|
|
147
|
+
function resolveAuthToken(options) {
|
|
148
|
+
const token = typeof options.token === "function" ? options.token() : options.token;
|
|
149
|
+
return token ? token : null;
|
|
150
|
+
}
|
|
151
|
+
var DEFAULT_POPUP_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
152
|
+
var DEFAULT_WINDOW_FEATURES = "popup=yes,width=560,height=720,resizable=yes,scrollbars=yes";
|
|
153
|
+
var HEALTH_TIMEOUT_MS = 5e3;
|
|
99
154
|
var AuthResource = class {
|
|
100
155
|
constructor(client) {
|
|
101
156
|
this.client = client;
|
|
157
|
+
const configured = client.options.authStorage;
|
|
158
|
+
if (configured === false) {
|
|
159
|
+
this.storage = this.memoryStorage;
|
|
160
|
+
this.persistent = false;
|
|
161
|
+
} else if (configured) {
|
|
162
|
+
this.storage = configured;
|
|
163
|
+
this.persistent = true;
|
|
164
|
+
} else if (typeof window === "undefined") {
|
|
165
|
+
this.storage = this.memoryStorage;
|
|
166
|
+
this.persistent = false;
|
|
167
|
+
} else {
|
|
168
|
+
this.storage = createLocalAuthStorage();
|
|
169
|
+
this.persistent = true;
|
|
170
|
+
}
|
|
171
|
+
this.snapshot = {
|
|
172
|
+
status: "signed_out",
|
|
173
|
+
baseUrl: client.baseUrl,
|
|
174
|
+
user: null,
|
|
175
|
+
error: null,
|
|
176
|
+
persistent: this.persistent,
|
|
177
|
+
managedBySdk: client.options.token === void 0
|
|
178
|
+
};
|
|
102
179
|
}
|
|
103
180
|
client;
|
|
181
|
+
listeners = /* @__PURE__ */ new Set();
|
|
182
|
+
memoryStorage = createMemoryAuthStorage();
|
|
183
|
+
storage;
|
|
184
|
+
persistent;
|
|
185
|
+
restorePromise = null;
|
|
186
|
+
baseUrlGeneration = 0;
|
|
187
|
+
pendingConnection = null;
|
|
188
|
+
activePopup = null;
|
|
189
|
+
cancelPending = null;
|
|
190
|
+
snapshot;
|
|
104
191
|
getProviders() {
|
|
105
192
|
return this.client.json("GET", "/api/auth/providers");
|
|
106
193
|
}
|
|
@@ -110,7 +197,449 @@ var AuthResource = class {
|
|
|
110
197
|
logout() {
|
|
111
198
|
return this.client.json("POST", "/api/auth/logout");
|
|
112
199
|
}
|
|
200
|
+
getConnectionSnapshot() {
|
|
201
|
+
return this.snapshot;
|
|
202
|
+
}
|
|
203
|
+
subscribe(listener) {
|
|
204
|
+
this.listeners.add(listener);
|
|
205
|
+
return () => this.listeners.delete(listener);
|
|
206
|
+
}
|
|
207
|
+
async probe() {
|
|
208
|
+
this.assertNoMixedContent();
|
|
209
|
+
const controller = new AbortController();
|
|
210
|
+
const timeout = setTimeout(() => controller.abort(), HEALTH_TIMEOUT_MS);
|
|
211
|
+
let response;
|
|
212
|
+
try {
|
|
213
|
+
response = await (this.client.options.fetchImpl ?? fetch)(this.url("/api/health"), {
|
|
214
|
+
method: "GET",
|
|
215
|
+
credentials: "omit",
|
|
216
|
+
signal: controller.signal
|
|
217
|
+
});
|
|
218
|
+
} catch (error) {
|
|
219
|
+
throw new BladeConnectionError(
|
|
220
|
+
"service_unreachable",
|
|
221
|
+
"\u65E0\u6CD5\u8FDE\u63A5\u5230 Blade Agent\uFF0C\u8BF7\u786E\u8BA4\u670D\u52A1\u5730\u5740\u548C\u7F51\u7EDC\u72B6\u6001\u3002",
|
|
222
|
+
{ cause: error }
|
|
223
|
+
);
|
|
224
|
+
} finally {
|
|
225
|
+
clearTimeout(timeout);
|
|
226
|
+
}
|
|
227
|
+
if (!response.ok) {
|
|
228
|
+
throw new BladeConnectionError(
|
|
229
|
+
"service_unreachable",
|
|
230
|
+
`Blade Agent \u670D\u52A1\u8FD4\u56DE\u4E86 ${response.status}\u3002`
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
let data;
|
|
234
|
+
try {
|
|
235
|
+
data = await response.json();
|
|
236
|
+
} catch (error) {
|
|
237
|
+
throw new BladeConnectionError("not_blade_agent", "\u8BE5\u5730\u5740\u4E0D\u662F Blade Agent \u670D\u52A1\u3002", {
|
|
238
|
+
cause: error
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
if (data.service !== "blade-agent") {
|
|
242
|
+
throw new BladeConnectionError("not_blade_agent", "\u8BE5\u5730\u5740\u4E0D\u662F Blade Agent \u670D\u52A1\u3002");
|
|
243
|
+
}
|
|
244
|
+
if (data.sdk_auth_version !== "1") {
|
|
245
|
+
throw new BladeConnectionError(
|
|
246
|
+
"incompatible_server",
|
|
247
|
+
"Blade Agent \u7248\u672C\u8FC7\u4F4E\uFF0C\u8BF7\u5347\u7EA7\u670D\u52A1\u540E\u91CD\u8BD5\u3002"
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
return data;
|
|
251
|
+
}
|
|
252
|
+
restore() {
|
|
253
|
+
if (this.restorePromise) return this.restorePromise;
|
|
254
|
+
if (this.pendingConnection) {
|
|
255
|
+
return this.pendingConnection.then(
|
|
256
|
+
() => this.snapshot,
|
|
257
|
+
() => this.snapshot
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
const promise = this.runRestore().finally(() => {
|
|
261
|
+
if (this.restorePromise === promise) this.restorePromise = null;
|
|
262
|
+
});
|
|
263
|
+
this.restorePromise = promise;
|
|
264
|
+
return promise;
|
|
265
|
+
}
|
|
266
|
+
async runRestore() {
|
|
267
|
+
const generation = this.baseUrlGeneration;
|
|
268
|
+
this.update({ status: "checking_service", user: null, error: null });
|
|
269
|
+
try {
|
|
270
|
+
await this.probe();
|
|
271
|
+
if (generation !== this.baseUrlGeneration) return this.snapshot;
|
|
272
|
+
if (this.client.options.token !== void 0) {
|
|
273
|
+
try {
|
|
274
|
+
const user = await this.getMe();
|
|
275
|
+
if (generation !== this.baseUrlGeneration) return this.snapshot;
|
|
276
|
+
this.update({ status: "connected", user, error: null });
|
|
277
|
+
return this.snapshot;
|
|
278
|
+
} catch (error) {
|
|
279
|
+
if (error instanceof BladeApiError && error.status === 401) {
|
|
280
|
+
this.update({
|
|
281
|
+
status: "expired",
|
|
282
|
+
user: null,
|
|
283
|
+
error: new BladeConnectionError(
|
|
284
|
+
"invalid_credentials",
|
|
285
|
+
"\u63A5\u5165\u65B9\u914D\u7F6E\u7684 Token \u5DF2\u5931\u6548\uFF0C\u8BF7\u66F4\u65B0 Token \u540E\u91CD\u65B0\u68C0\u6D4B\u3002"
|
|
286
|
+
)
|
|
287
|
+
});
|
|
288
|
+
return this.snapshot;
|
|
289
|
+
}
|
|
290
|
+
throw error;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const stored = await this.storageGet();
|
|
294
|
+
if (generation !== this.baseUrlGeneration) return this.snapshot;
|
|
295
|
+
if (!stored) {
|
|
296
|
+
this.client._setManagedToken(null);
|
|
297
|
+
this.update({ status: "signed_out", user: null, error: null });
|
|
298
|
+
return this.snapshot;
|
|
299
|
+
}
|
|
300
|
+
this.client._setManagedToken(stored.accessToken);
|
|
301
|
+
try {
|
|
302
|
+
const user = await this.getMe();
|
|
303
|
+
if (generation !== this.baseUrlGeneration) return this.snapshot;
|
|
304
|
+
this.client._reconnectSocketWithCurrentAuth();
|
|
305
|
+
this.update({ status: "connected", user, error: null });
|
|
306
|
+
return this.snapshot;
|
|
307
|
+
} catch (error) {
|
|
308
|
+
if (error instanceof BladeApiError && error.status === 401) {
|
|
309
|
+
if (generation !== this.baseUrlGeneration) return this.snapshot;
|
|
310
|
+
await this.clearManagedAuth();
|
|
311
|
+
if (generation !== this.baseUrlGeneration) return this.snapshot;
|
|
312
|
+
this.update({ status: "expired", user: null, error: null });
|
|
313
|
+
return this.snapshot;
|
|
314
|
+
}
|
|
315
|
+
throw error;
|
|
316
|
+
}
|
|
317
|
+
} catch (error) {
|
|
318
|
+
const connectionError = this.toConnectionError(error, "service_unreachable");
|
|
319
|
+
this.update({
|
|
320
|
+
status: connectionError.code === "invalid_url" || connectionError.code === "mixed_content" ? "configuration_error" : "service_unavailable",
|
|
321
|
+
user: null,
|
|
322
|
+
error: connectionError
|
|
323
|
+
});
|
|
324
|
+
return this.snapshot;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
retry() {
|
|
328
|
+
return this.restore();
|
|
329
|
+
}
|
|
330
|
+
connectWithPopup(options = {}) {
|
|
331
|
+
if (this.pendingConnection) return this.pendingConnection;
|
|
332
|
+
const promise = this.runPopupFlow(options).finally(() => {
|
|
333
|
+
if (this.pendingConnection === promise) this.pendingConnection = null;
|
|
334
|
+
this.cancelPending = null;
|
|
335
|
+
this.activePopup = null;
|
|
336
|
+
});
|
|
337
|
+
this.pendingConnection = promise;
|
|
338
|
+
return promise;
|
|
339
|
+
}
|
|
340
|
+
async disconnect() {
|
|
341
|
+
if (this.client.options.token !== void 0) {
|
|
342
|
+
throw new BladeConnectionError(
|
|
343
|
+
"token_exchange_failed",
|
|
344
|
+
"\u5F53\u524D Token \u7531\u63A5\u5165\u65B9\u7BA1\u7406\uFF0C\u8BF7\u7531\u63A5\u5165\u65B9\u5B8C\u6210\u65AD\u5F00\u64CD\u4F5C\u3002"
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
const generation = this.baseUrlGeneration;
|
|
348
|
+
await this.clearManagedAuth();
|
|
349
|
+
if (generation !== this.baseUrlGeneration) return;
|
|
350
|
+
this.client._disconnectSocket();
|
|
351
|
+
this.update({ status: "signed_out", user: null, error: null });
|
|
352
|
+
}
|
|
353
|
+
async _handleUnauthorized() {
|
|
354
|
+
if (this.client.options.token !== void 0) return;
|
|
355
|
+
const generation = this.baseUrlGeneration;
|
|
356
|
+
await this.clearManagedAuth();
|
|
357
|
+
if (generation !== this.baseUrlGeneration) return;
|
|
358
|
+
this.client._disconnectSocket();
|
|
359
|
+
this.update({ status: "expired", user: null, error: null });
|
|
360
|
+
}
|
|
361
|
+
async _handleBaseUrlChange() {
|
|
362
|
+
this.baseUrlGeneration += 1;
|
|
363
|
+
const previousRestore = this.restorePromise;
|
|
364
|
+
const previousConnection = this.pendingConnection;
|
|
365
|
+
this.cancelPending?.(
|
|
366
|
+
new BladeConnectionError("invalid_url", "\u670D\u52A1\u5730\u5740\u5DF2\u6539\u53D8\uFF0C\u672C\u6B21\u6388\u6743\u5DF2\u53D6\u6D88\u3002")
|
|
367
|
+
);
|
|
368
|
+
this.activePopup?.close();
|
|
369
|
+
this.client._setManagedToken(null);
|
|
370
|
+
this.update({
|
|
371
|
+
status: "checking_service",
|
|
372
|
+
baseUrl: this.client.baseUrl,
|
|
373
|
+
user: null,
|
|
374
|
+
error: null
|
|
375
|
+
});
|
|
376
|
+
if (previousConnection) {
|
|
377
|
+
try {
|
|
378
|
+
await previousConnection;
|
|
379
|
+
} catch {
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (previousRestore) await previousRestore;
|
|
383
|
+
await this.restore();
|
|
384
|
+
}
|
|
385
|
+
async runPopupFlow(options) {
|
|
386
|
+
if (this.client.options.token !== void 0) {
|
|
387
|
+
throw new BladeConnectionError(
|
|
388
|
+
"token_exchange_failed",
|
|
389
|
+
"\u5DF2\u7ECF\u914D\u7F6E\u663E\u5F0F Token\uFF0C\u65E0\u9700\u518D\u6B21\u6388\u6743\u3002"
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
const generation = this.baseUrlGeneration;
|
|
393
|
+
if (typeof window === "undefined" || !window.location) {
|
|
394
|
+
throw new BladeConnectionError("invalid_url", "\u5F39\u7A97\u6388\u6743\u53EA\u80FD\u5728\u6D4F\u89C8\u5668\u9875\u9762\u4E2D\u4F7F\u7528\u3002");
|
|
395
|
+
}
|
|
396
|
+
try {
|
|
397
|
+
const popup = window.open(
|
|
398
|
+
"",
|
|
399
|
+
"blade-agent-sdk-authorization",
|
|
400
|
+
options.windowFeatures ?? DEFAULT_WINDOW_FEATURES
|
|
401
|
+
);
|
|
402
|
+
if (!popup) {
|
|
403
|
+
throw new BladeConnectionError(
|
|
404
|
+
"popup_blocked",
|
|
405
|
+
"\u6D4F\u89C8\u5668\u963B\u6B62\u4E86\u6388\u6743\u7A97\u53E3\uFF0C\u8BF7\u5141\u8BB8\u5F39\u7A97\u540E\u91CD\u8BD5\u3002"
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
this.activePopup = popup;
|
|
409
|
+
if (this.restorePromise) {
|
|
410
|
+
await this.restorePromise;
|
|
411
|
+
this.assertGeneration(generation);
|
|
412
|
+
if (this.snapshot.status === "connected" && this.snapshot.user) {
|
|
413
|
+
return this.snapshot.user;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
this.update({ status: "checking_service", user: null, error: null });
|
|
417
|
+
await this.probe();
|
|
418
|
+
if (generation !== this.baseUrlGeneration) {
|
|
419
|
+
throw new BladeConnectionError("invalid_url", "\u670D\u52A1\u5730\u5740\u5DF2\u6539\u53D8\uFF0C\u672C\u6B21\u6388\u6743\u5DF2\u53D6\u6D88\u3002");
|
|
420
|
+
}
|
|
421
|
+
const state = createAuthorizationState();
|
|
422
|
+
const clientOrigin = normalizeBrowserOrigin(window.location.origin);
|
|
423
|
+
const authorizeUrl = new URL(this.url("/api/auth/sdk/authorize"));
|
|
424
|
+
authorizeUrl.searchParams.set("client_origin", clientOrigin);
|
|
425
|
+
authorizeUrl.searchParams.set("state", state);
|
|
426
|
+
popup.location.href = authorizeUrl.toString();
|
|
427
|
+
this.update({ status: "waiting_for_authorization", user: null, error: null });
|
|
428
|
+
const message = await this.waitForPopup(
|
|
429
|
+
popup,
|
|
430
|
+
state,
|
|
431
|
+
options.timeoutMs ?? DEFAULT_POPUP_TIMEOUT_MS
|
|
432
|
+
);
|
|
433
|
+
this.assertGeneration(generation);
|
|
434
|
+
if (message.status === "denied") {
|
|
435
|
+
throw new BladeConnectionError("authorization_denied", "\u4F60\u5DF2\u53D6\u6D88\u8FDE\u63A5\u3002");
|
|
436
|
+
}
|
|
437
|
+
if (message.status === "error") {
|
|
438
|
+
if (message.error === "authentication_expired") {
|
|
439
|
+
throw new BladeConnectionError(
|
|
440
|
+
"authorization_expired",
|
|
441
|
+
"Blade Agent \u767B\u5F55\u72B6\u6001\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u8FDE\u63A5\u3002"
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
throw new BladeConnectionError(
|
|
445
|
+
"token_exchange_failed",
|
|
446
|
+
"Blade Agent \u6682\u65F6\u65E0\u6CD5\u521B\u5EFA\u8FDE\u63A5\u51ED\u636E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
if (!message.code) {
|
|
450
|
+
throw new BladeConnectionError(
|
|
451
|
+
"token_exchange_failed",
|
|
452
|
+
"\u6388\u6743\u7ED3\u679C\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u91CD\u65B0\u8FDE\u63A5\u3002"
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
this.update({ status: "connecting", user: null, error: null });
|
|
456
|
+
const issued = await this.client.jsonFromInit("/api/auth/sdk/token", {
|
|
457
|
+
method: "POST",
|
|
458
|
+
credentials: "omit",
|
|
459
|
+
body: JSON.stringify({
|
|
460
|
+
code: message.code,
|
|
461
|
+
state,
|
|
462
|
+
client_origin: clientOrigin
|
|
463
|
+
})
|
|
464
|
+
});
|
|
465
|
+
this.assertGeneration(generation);
|
|
466
|
+
if (!issued.access_token || !issued.user?.id) {
|
|
467
|
+
throw new BladeConnectionError(
|
|
468
|
+
"token_exchange_failed",
|
|
469
|
+
"Blade Agent \u672A\u8FD4\u56DE\u6709\u6548\u7684\u8FDE\u63A5\u51ED\u636E\u3002"
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
this.client._setManagedToken(issued.access_token);
|
|
473
|
+
const verified = await this.getMe();
|
|
474
|
+
this.assertGeneration(generation);
|
|
475
|
+
if (verified.id !== issued.user.id) {
|
|
476
|
+
throw new BladeConnectionError("origin_mismatch", "\u6388\u6743\u8D26\u53F7\u6821\u9A8C\u5931\u8D25\uFF0C\u8BF7\u91CD\u65B0\u8FDE\u63A5\u3002");
|
|
477
|
+
}
|
|
478
|
+
const user = {
|
|
479
|
+
id: verified.id,
|
|
480
|
+
username: verified.username,
|
|
481
|
+
display_name: verified.display_name,
|
|
482
|
+
avatar_url: verified.avatar_url
|
|
483
|
+
};
|
|
484
|
+
await this.storageSet({
|
|
485
|
+
accessToken: issued.access_token,
|
|
486
|
+
user,
|
|
487
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
488
|
+
});
|
|
489
|
+
this.assertGeneration(generation);
|
|
490
|
+
this.update({ status: "connected", user, error: null });
|
|
491
|
+
this.client._reconnectSocketWithCurrentAuth();
|
|
492
|
+
return user;
|
|
493
|
+
} catch (error) {
|
|
494
|
+
if (generation === this.baseUrlGeneration) await this.clearManagedAuth();
|
|
495
|
+
const connectionError = this.toConnectionError(error, "token_exchange_failed");
|
|
496
|
+
if (generation === this.baseUrlGeneration) {
|
|
497
|
+
this.update({
|
|
498
|
+
status: connectionError.code === "authorization_denied" || connectionError.code === "popup_closed" ? "signed_out" : connectionError.code === "mixed_content" || connectionError.code === "invalid_url" ? "configuration_error" : "service_unavailable",
|
|
499
|
+
user: null,
|
|
500
|
+
error: connectionError
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
throw connectionError;
|
|
504
|
+
} finally {
|
|
505
|
+
this.activePopup?.close();
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
waitForPopup(popup, state, timeoutMs) {
|
|
509
|
+
const expectedOrigin = new URL(this.client.baseUrl).origin;
|
|
510
|
+
return new Promise((resolve, reject) => {
|
|
511
|
+
let settled = false;
|
|
512
|
+
const finish = (error, message) => {
|
|
513
|
+
if (settled) return;
|
|
514
|
+
settled = true;
|
|
515
|
+
window.removeEventListener("message", onMessage);
|
|
516
|
+
clearInterval(closedTimer);
|
|
517
|
+
clearTimeout(expiryTimer);
|
|
518
|
+
this.cancelPending = null;
|
|
519
|
+
if (error) reject(error);
|
|
520
|
+
else if (message) resolve(message);
|
|
521
|
+
};
|
|
522
|
+
const onMessage = (event) => {
|
|
523
|
+
const data = event.data;
|
|
524
|
+
if (event.source !== popup || data?.type !== "blade-agent:sdk-auth") return;
|
|
525
|
+
if (event.origin !== expectedOrigin || data.version !== 1 || data.state !== state) {
|
|
526
|
+
finish(
|
|
527
|
+
new BladeConnectionError(
|
|
528
|
+
"origin_mismatch",
|
|
529
|
+
"\u6388\u6743\u7ED3\u679C\u6765\u6E90\u6821\u9A8C\u5931\u8D25\uFF0C\u8BF7\u5173\u95ED\u7A97\u53E3\u540E\u91CD\u65B0\u8FDE\u63A5\u3002"
|
|
530
|
+
)
|
|
531
|
+
);
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
if (data.status !== "success" && data.status !== "denied" && data.status !== "error") {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
finish(void 0, data);
|
|
538
|
+
};
|
|
539
|
+
window.addEventListener("message", onMessage);
|
|
540
|
+
const closedTimer = window.setInterval(() => {
|
|
541
|
+
if (popup.closed) {
|
|
542
|
+
finish(new BladeConnectionError("popup_closed", "\u6388\u6743\u7A97\u53E3\u5DF2\u5173\u95ED\u3002"));
|
|
543
|
+
}
|
|
544
|
+
}, 250);
|
|
545
|
+
const expiryTimer = window.setTimeout(() => {
|
|
546
|
+
finish(
|
|
547
|
+
new BladeConnectionError(
|
|
548
|
+
"authorization_expired",
|
|
549
|
+
"\u6388\u6743\u7B49\u5F85\u65F6\u95F4\u5DF2\u7ED3\u675F\uFF0C\u8BF7\u91CD\u65B0\u8FDE\u63A5\u3002"
|
|
550
|
+
)
|
|
551
|
+
);
|
|
552
|
+
}, timeoutMs);
|
|
553
|
+
this.cancelPending = (error) => finish(error);
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
assertNoMixedContent() {
|
|
557
|
+
if (typeof window !== "undefined" && window.location.protocol === "https:" && new URL(this.client.baseUrl).protocol === "http:") {
|
|
558
|
+
throw new BladeConnectionError(
|
|
559
|
+
"mixed_content",
|
|
560
|
+
"\u5F53\u524D\u9875\u9762\u4F7F\u7528 HTTPS\uFF0CBlade Agent \u4E5F\u9700\u8981\u4F7F\u7528 HTTPS \u5730\u5740\u6216\u901A\u8FC7\u53CD\u5411\u4EE3\u7406\u8BBF\u95EE\u3002"
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
assertGeneration(generation) {
|
|
565
|
+
if (generation !== this.baseUrlGeneration) {
|
|
566
|
+
throw new BladeConnectionError("invalid_url", "\u670D\u52A1\u5730\u5740\u5DF2\u6539\u53D8\uFF0C\u672C\u6B21\u6388\u6743\u5DF2\u53D6\u6D88\u3002");
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
url(path) {
|
|
570
|
+
const base = this.client.baseUrl.endsWith("/") ? this.client.baseUrl : `${this.client.baseUrl}/`;
|
|
571
|
+
return new URL(path.replace(/^\//, ""), base).toString();
|
|
572
|
+
}
|
|
573
|
+
storageKey() {
|
|
574
|
+
return `blade-agent:auth:v1:${encodeURIComponent(this.client.baseUrl)}`;
|
|
575
|
+
}
|
|
576
|
+
async storageGet() {
|
|
577
|
+
try {
|
|
578
|
+
return await this.storage.get(this.storageKey());
|
|
579
|
+
} catch {
|
|
580
|
+
this.useMemoryStorage();
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
async storageSet(value) {
|
|
585
|
+
const generation = this.baseUrlGeneration;
|
|
586
|
+
const key = this.storageKey();
|
|
587
|
+
try {
|
|
588
|
+
await this.storage.set(key, value);
|
|
589
|
+
} catch {
|
|
590
|
+
this.assertGeneration(generation);
|
|
591
|
+
this.useMemoryStorage();
|
|
592
|
+
await this.storage.set(key, value);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
async clearManagedAuth() {
|
|
596
|
+
const generation = this.baseUrlGeneration;
|
|
597
|
+
const key = this.storageKey();
|
|
598
|
+
this.client._setManagedToken(null);
|
|
599
|
+
try {
|
|
600
|
+
await this.storage.remove(key);
|
|
601
|
+
} catch {
|
|
602
|
+
if (generation !== this.baseUrlGeneration) return;
|
|
603
|
+
this.useMemoryStorage();
|
|
604
|
+
await this.storage.remove(key);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
useMemoryStorage() {
|
|
608
|
+
this.storage = this.memoryStorage;
|
|
609
|
+
this.persistent = false;
|
|
610
|
+
this.snapshot = { ...this.snapshot, persistent: false };
|
|
611
|
+
}
|
|
612
|
+
update(next) {
|
|
613
|
+
this.snapshot = {
|
|
614
|
+
...this.snapshot,
|
|
615
|
+
...next,
|
|
616
|
+
baseUrl: next.baseUrl ?? this.client.baseUrl,
|
|
617
|
+
persistent: this.persistent,
|
|
618
|
+
managedBySdk: this.client.options.token === void 0
|
|
619
|
+
};
|
|
620
|
+
for (const listener of this.listeners) listener();
|
|
621
|
+
}
|
|
622
|
+
toConnectionError(error, fallback) {
|
|
623
|
+
if (error instanceof BladeConnectionError) return error;
|
|
624
|
+
return new BladeConnectionError(
|
|
625
|
+
fallback,
|
|
626
|
+
fallback === "service_unreachable" ? "\u65E0\u6CD5\u8FDE\u63A5\u5230 Blade Agent\uFF0C\u8BF7\u68C0\u67E5\u670D\u52A1\u5730\u5740\u540E\u91CD\u8BD5\u3002" : "\u8FDE\u63A5\u6CA1\u6709\u5B8C\u6210\uFF0C\u8BF7\u91CD\u65B0\u6388\u6743\u3002",
|
|
627
|
+
{ cause: error }
|
|
628
|
+
);
|
|
629
|
+
}
|
|
113
630
|
};
|
|
631
|
+
function normalizeBrowserOrigin(value) {
|
|
632
|
+
const url = new URL(value);
|
|
633
|
+
if (!/^https?:$/.test(url.protocol) || url.origin === "null") {
|
|
634
|
+
throw new BladeConnectionError("invalid_url", "\u5F53\u524D\u9875\u9762\u5FC5\u987B\u901A\u8FC7 HTTP \u6216 HTTPS \u6253\u5F00\u3002");
|
|
635
|
+
}
|
|
636
|
+
return url.origin;
|
|
637
|
+
}
|
|
638
|
+
function createAuthorizationState() {
|
|
639
|
+
const bytes = new Uint8Array(24);
|
|
640
|
+
crypto.getRandomValues(bytes);
|
|
641
|
+
return Array.from(bytes, (value) => value.toString(16).padStart(2, "0")).join("");
|
|
642
|
+
}
|
|
114
643
|
|
|
115
644
|
// src/client/resources/env-buckets.ts
|
|
116
645
|
var EnvBucketsResource = class {
|
|
@@ -2590,25 +3119,13 @@ var UserPreferencesResource = class {
|
|
|
2590
3119
|
|
|
2591
3120
|
// src/client/socket.ts
|
|
2592
3121
|
import { io } from "socket.io-client";
|
|
2593
|
-
|
|
2594
|
-
// src/client/auth.ts
|
|
2595
|
-
function buildSocketAuth(options) {
|
|
2596
|
-
const token = resolveAuthToken(options);
|
|
2597
|
-
return token ? { token } : void 0;
|
|
2598
|
-
}
|
|
2599
|
-
function resolveAuthToken(options) {
|
|
2600
|
-
const token = typeof options.token === "function" ? options.token() : options.token;
|
|
2601
|
-
return token ? token : null;
|
|
2602
|
-
}
|
|
2603
|
-
|
|
2604
|
-
// src/client/socket.ts
|
|
2605
3122
|
function createSocket(options) {
|
|
2606
3123
|
const auth = buildSocketAuth(options);
|
|
2607
3124
|
const token = resolveAuthToken(options);
|
|
2608
3125
|
return io(options.baseUrl, {
|
|
2609
3126
|
path: options.path ?? "/socket.io",
|
|
2610
|
-
withCredentials: true,
|
|
2611
|
-
query: token
|
|
3127
|
+
withCredentials: options.withCredentials ?? true,
|
|
3128
|
+
query: typeof options.token === "function" || !token ? void 0 : { token },
|
|
2612
3129
|
auth: typeof options.token === "function" ? (cb) => cb(buildSocketAuth(options) ?? {}) : auth,
|
|
2613
3130
|
autoConnect: false
|
|
2614
3131
|
});
|
|
@@ -2619,6 +3136,8 @@ var REFRESH_PATH = "/api/auth/refresh";
|
|
|
2619
3136
|
var BladeClient = class {
|
|
2620
3137
|
refreshPromise = null;
|
|
2621
3138
|
socketInstance = null;
|
|
3139
|
+
managedToken = null;
|
|
3140
|
+
baseUrlChangeListeners = /* @__PURE__ */ new Set();
|
|
2622
3141
|
storeRestTokenResolver = null;
|
|
2623
3142
|
storeSocketTokenResolver = null;
|
|
2624
3143
|
options;
|
|
@@ -2638,10 +3157,10 @@ var BladeClient = class {
|
|
|
2638
3157
|
skills;
|
|
2639
3158
|
solutions;
|
|
2640
3159
|
userPreferences;
|
|
2641
|
-
constructor(options) {
|
|
3160
|
+
constructor(options = {}) {
|
|
2642
3161
|
this.options = {
|
|
2643
3162
|
...options,
|
|
2644
|
-
baseUrl:
|
|
3163
|
+
baseUrl: resolveBladeBaseUrl(options)
|
|
2645
3164
|
};
|
|
2646
3165
|
this.apiKeys = new ApiKeysResource(this);
|
|
2647
3166
|
this.appDevTemplates = new AppDevTemplatesResource(this);
|
|
@@ -2667,22 +3186,47 @@ var BladeClient = class {
|
|
|
2667
3186
|
this.storeSocketTokenResolver = fn;
|
|
2668
3187
|
}
|
|
2669
3188
|
setBaseUrl(baseUrl) {
|
|
2670
|
-
const nextBaseUrl =
|
|
3189
|
+
const nextBaseUrl = resolveBladeBaseUrl({ baseUrl });
|
|
2671
3190
|
if (nextBaseUrl === this.options.baseUrl) {
|
|
2672
3191
|
return;
|
|
2673
3192
|
}
|
|
2674
3193
|
this.options.baseUrl = nextBaseUrl;
|
|
3194
|
+
this.managedToken = null;
|
|
2675
3195
|
if (this.socketInstance) {
|
|
2676
3196
|
this.socketInstance.removeAllListeners();
|
|
2677
3197
|
this.socketInstance.disconnect();
|
|
2678
3198
|
this.socketInstance = null;
|
|
2679
3199
|
}
|
|
3200
|
+
for (const listener of this.baseUrlChangeListeners) listener();
|
|
3201
|
+
void this.auth._handleBaseUrlChange();
|
|
3202
|
+
}
|
|
3203
|
+
onBaseUrlChange(listener) {
|
|
3204
|
+
this.baseUrlChangeListeners.add(listener);
|
|
3205
|
+
return () => this.baseUrlChangeListeners.delete(listener);
|
|
3206
|
+
}
|
|
3207
|
+
get baseUrl() {
|
|
3208
|
+
return this.options.baseUrl ?? "";
|
|
3209
|
+
}
|
|
3210
|
+
_setManagedToken(token) {
|
|
3211
|
+
this.managedToken = token;
|
|
3212
|
+
}
|
|
3213
|
+
_reconnectSocketWithCurrentAuth() {
|
|
3214
|
+
if (!this.socketInstance) return;
|
|
3215
|
+
this.socketInstance.disconnect();
|
|
3216
|
+
this.socketInstance.io.opts.withCredentials = !this.shouldOmitManagedCredentials(
|
|
3217
|
+
new URL(this.options.baseUrl)
|
|
3218
|
+
);
|
|
3219
|
+
this.socketInstance.connect();
|
|
3220
|
+
}
|
|
3221
|
+
_disconnectSocket() {
|
|
3222
|
+
this.socketInstance?.disconnect();
|
|
2680
3223
|
}
|
|
2681
3224
|
socket() {
|
|
2682
3225
|
if (!this.socketInstance) {
|
|
2683
3226
|
this.socketInstance = createSocket({
|
|
2684
3227
|
baseUrl: this.options.baseUrl,
|
|
2685
|
-
token: () => this.resolveSocketToken()
|
|
3228
|
+
token: () => this.resolveSocketToken(),
|
|
3229
|
+
withCredentials: !this.shouldOmitManagedCredentials(new URL(this.options.baseUrl))
|
|
2686
3230
|
});
|
|
2687
3231
|
}
|
|
2688
3232
|
return this.socketInstance;
|
|
@@ -2743,10 +3287,11 @@ var BladeClient = class {
|
|
|
2743
3287
|
}
|
|
2744
3288
|
async fetch(method, path, init = {}, isRetry = false) {
|
|
2745
3289
|
const url = this.buildUrl(path);
|
|
3290
|
+
const managedTokenAtRequest = this.managedToken;
|
|
2746
3291
|
const response = await (this.options.fetchImpl ?? fetch)(url.toString(), {
|
|
2747
3292
|
method,
|
|
2748
3293
|
body: init.body,
|
|
2749
|
-
credentials: init.credentials ??
|
|
3294
|
+
credentials: init.credentials ?? this.defaultCredentials(url),
|
|
2750
3295
|
headers: this.buildHeaders(url, init.headers),
|
|
2751
3296
|
signal: init.signal
|
|
2752
3297
|
});
|
|
@@ -2756,6 +3301,9 @@ var BladeClient = class {
|
|
|
2756
3301
|
return this.fetch(method, path, init, true);
|
|
2757
3302
|
}
|
|
2758
3303
|
}
|
|
3304
|
+
if (response.status === 401 && managedTokenAtRequest && this.managedToken === managedTokenAtRequest && this.isSameBackendUrl(url)) {
|
|
3305
|
+
void this.auth._handleUnauthorized();
|
|
3306
|
+
}
|
|
2759
3307
|
if (init.expectOk !== false && !response.ok) {
|
|
2760
3308
|
const detail = await extractErrorDetail(response);
|
|
2761
3309
|
throw new BladeApiError(response, detail);
|
|
@@ -2803,7 +3351,13 @@ var BladeClient = class {
|
|
|
2803
3351
|
}
|
|
2804
3352
|
shouldRefreshFor401(url) {
|
|
2805
3353
|
const refreshUrl = this.buildUrl(REFRESH_PATH);
|
|
2806
|
-
return this.isSameBackendUrl(url) && url.pathname !== refreshUrl.pathname && !this.hasExplicitBearerToken();
|
|
3354
|
+
return this.isSameBackendUrl(url) && url.pathname !== refreshUrl.pathname && !this.hasExplicitBearerToken() && !this.managedToken;
|
|
3355
|
+
}
|
|
3356
|
+
defaultCredentials(url) {
|
|
3357
|
+
return this.shouldOmitManagedCredentials(url) ? "omit" : "include";
|
|
3358
|
+
}
|
|
3359
|
+
shouldOmitManagedCredentials(url) {
|
|
3360
|
+
return !!this.managedToken && typeof window !== "undefined" && !!window.location?.origin && url.origin !== window.location.origin;
|
|
2807
3361
|
}
|
|
2808
3362
|
hasExplicitBearerToken() {
|
|
2809
3363
|
return this.options.token !== void 0;
|
|
@@ -2838,7 +3392,7 @@ var BladeClient = class {
|
|
|
2838
3392
|
if (!this.isSameBackendUrl(url)) {
|
|
2839
3393
|
return null;
|
|
2840
3394
|
}
|
|
2841
|
-
return this.
|
|
3395
|
+
return this.resolveConfiguredToken(this.storeRestTokenResolver);
|
|
2842
3396
|
}
|
|
2843
3397
|
resolveRestToken() {
|
|
2844
3398
|
return this.resolveToken(this.storeRestTokenResolver);
|
|
@@ -2847,16 +3401,20 @@ var BladeClient = class {
|
|
|
2847
3401
|
return this.resolveToken(this.storeSocketTokenResolver);
|
|
2848
3402
|
}
|
|
2849
3403
|
resolveToken(resolver) {
|
|
2850
|
-
|
|
2851
|
-
|
|
3404
|
+
return this.resolveConfiguredToken(resolver) || this.managedToken || null;
|
|
3405
|
+
}
|
|
3406
|
+
resolveConfiguredToken(resolver) {
|
|
3407
|
+
const configuredToken = this.options.token === void 0 ? resolver?.() : typeof this.options.token === "function" ? this.options.token() : this.options.token;
|
|
3408
|
+
return configuredToken || null;
|
|
2852
3409
|
}
|
|
2853
3410
|
formDataWithUploadProgress(method, path, form, options, isRetry = false) {
|
|
2854
3411
|
const url = this.buildUrl(path);
|
|
3412
|
+
const managedTokenAtRequest = this.managedToken;
|
|
2855
3413
|
const headers = this.buildHeaders(url);
|
|
2856
3414
|
return new Promise((resolve, reject) => {
|
|
2857
3415
|
const xhr = new XMLHttpRequest();
|
|
2858
3416
|
xhr.open(method, url.toString(), true);
|
|
2859
|
-
xhr.withCredentials =
|
|
3417
|
+
xhr.withCredentials = this.defaultCredentials(url) === "include";
|
|
2860
3418
|
headers.forEach((value, key) => {
|
|
2861
3419
|
xhr.setRequestHeader(key, value);
|
|
2862
3420
|
});
|
|
@@ -2878,6 +3436,9 @@ var BladeClient = class {
|
|
|
2878
3436
|
return;
|
|
2879
3437
|
}
|
|
2880
3438
|
}
|
|
3439
|
+
if (xhr.status === 401 && managedTokenAtRequest && this.managedToken === managedTokenAtRequest && this.isSameBackendUrl(url)) {
|
|
3440
|
+
void this.auth._handleUnauthorized();
|
|
3441
|
+
}
|
|
2881
3442
|
const response = new Response(xhr.responseText, {
|
|
2882
3443
|
status: xhr.status,
|
|
2883
3444
|
statusText: xhr.statusText,
|
|
@@ -2895,12 +3456,44 @@ var BladeClient = class {
|
|
|
2895
3456
|
});
|
|
2896
3457
|
}
|
|
2897
3458
|
};
|
|
2898
|
-
function
|
|
2899
|
-
const
|
|
2900
|
-
if (
|
|
2901
|
-
|
|
3459
|
+
function resolveBladeBaseUrl(options = {}) {
|
|
3460
|
+
const explicit = options.baseUrl?.trim() ?? "";
|
|
3461
|
+
if (explicit && options.port !== void 0) {
|
|
3462
|
+
throw new TypeError("baseUrl and port cannot be configured at the same time");
|
|
3463
|
+
}
|
|
3464
|
+
if (options.port !== void 0 && (!Number.isInteger(options.port) || options.port < 1 || options.port > 65535)) {
|
|
3465
|
+
throw new TypeError("port must be an integer between 1 and 65535");
|
|
3466
|
+
}
|
|
3467
|
+
let candidate = explicit;
|
|
3468
|
+
if (!candidate) {
|
|
3469
|
+
if (typeof window === "undefined" || !window.location?.hostname) {
|
|
3470
|
+
throw new TypeError(
|
|
3471
|
+
"BladeClient requires baseUrl outside a browser, for example new BladeClient({ baseUrl: 'http://127.0.0.1:8020' })"
|
|
3472
|
+
);
|
|
3473
|
+
}
|
|
3474
|
+
const protocol = window.location.protocol;
|
|
3475
|
+
if (protocol !== "http:" && protocol !== "https:") {
|
|
3476
|
+
throw new TypeError("BladeClient automatic baseUrl requires an HTTP(S) page");
|
|
3477
|
+
}
|
|
3478
|
+
const url = new URL(window.location.origin);
|
|
3479
|
+
url.port = String(options.port ?? 8020);
|
|
3480
|
+
url.pathname = "/";
|
|
3481
|
+
url.search = "";
|
|
3482
|
+
url.hash = "";
|
|
3483
|
+
candidate = url.toString();
|
|
3484
|
+
}
|
|
3485
|
+
let parsed;
|
|
3486
|
+
try {
|
|
3487
|
+
parsed = new URL(candidate);
|
|
3488
|
+
} catch (error) {
|
|
3489
|
+
throw new TypeError("baseUrl must be a valid HTTP(S) URL", { cause: error });
|
|
3490
|
+
}
|
|
3491
|
+
if (!/^https?:$/.test(parsed.protocol) || parsed.username || parsed.password || parsed.search || parsed.hash) {
|
|
3492
|
+
throw new TypeError(
|
|
3493
|
+
"baseUrl must be an HTTP(S) URL without embedded credentials, query, or fragment"
|
|
3494
|
+
);
|
|
2902
3495
|
}
|
|
2903
|
-
return
|
|
3496
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
2904
3497
|
}
|
|
2905
3498
|
function isFormData(value) {
|
|
2906
3499
|
return typeof FormData !== "undefined" && value instanceof FormData;
|
|
@@ -2925,6 +3518,9 @@ export {
|
|
|
2925
3518
|
BladeApiError,
|
|
2926
3519
|
ApiKeysResource,
|
|
2927
3520
|
AppDevTemplatesResource,
|
|
3521
|
+
BladeConnectionError,
|
|
3522
|
+
createMemoryAuthStorage,
|
|
3523
|
+
createLocalAuthStorage,
|
|
2928
3524
|
AuthResource,
|
|
2929
3525
|
GisResource,
|
|
2930
3526
|
HeadlessError,
|
|
@@ -2945,6 +3541,7 @@ export {
|
|
|
2945
3541
|
SolutionsResource,
|
|
2946
3542
|
UserPreferencesResource,
|
|
2947
3543
|
createSocket,
|
|
2948
|
-
BladeClient
|
|
3544
|
+
BladeClient,
|
|
3545
|
+
resolveBladeBaseUrl
|
|
2949
3546
|
};
|
|
2950
|
-
//# sourceMappingURL=chunk-
|
|
3547
|
+
//# sourceMappingURL=chunk-C63X3RCM.js.map
|