@mitralab.io/platform-sdk 1.0.9 → 1.1.0-beta.0

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/index.cjs CHANGED
@@ -21,15 +21,53 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  MitraApiError: () => MitraApiError,
24
- createClient: () => createClient
24
+ callIntegrationMitra: () => import_mitra_interactions_sdk14.callIntegrationMitra,
25
+ configureSdkMitra: () => import_mitra_interactions_sdk3.configureSdkMitra,
26
+ createClient: () => createClient,
27
+ createMitraInstance: () => import_mitra_interactions_sdk4.createMitraInstance,
28
+ createRecordMitra: () => import_mitra_interactions_sdk18.createRecordMitra,
29
+ createRecordsBatchMitra: () => import_mitra_interactions_sdk19.createRecordsBatchMitra,
30
+ deleteRecordMitra: () => import_mitra_interactions_sdk22.deleteRecordMitra,
31
+ exchangeSsoCodeMitra: () => exchangeSsoCodeMitra,
32
+ executePublicServerFunctionAsyncMitra: () => import_mitra_interactions_sdk11.executePublicServerFunctionAsyncMitra,
33
+ executePublicServerFunctionMitra: () => import_mitra_interactions_sdk10.executePublicServerFunctionMitra,
34
+ executeServerFunctionAsyncMitra: () => import_mitra_interactions_sdk9.executeServerFunctionAsyncMitra,
35
+ executeServerFunctionMitra: () => import_mitra_interactions_sdk8.executeServerFunctionMitra,
36
+ getAgentTaskMitra: () => import_mitra_interactions_sdk23.getAgentTaskMitra,
37
+ getConfig: () => import_mitra_interactions_sdk5.getConfig,
38
+ getPublicServerFunctionExecutionMitra: () => import_mitra_interactions_sdk12.getPublicServerFunctionExecutionMitra,
39
+ getRecordMitra: () => import_mitra_interactions_sdk17.getRecordMitra,
40
+ listIntegrationsMitra: () => import_mitra_interactions_sdk15.listIntegrationsMitra,
41
+ listRecordsMitra: () => import_mitra_interactions_sdk16.listRecordsMitra,
42
+ loginMitra: () => loginMitra,
43
+ loginWithGoogleMitra: () => loginWithGoogleMitra,
44
+ loginWithMicrosoftMitra: () => loginWithMicrosoftMitra,
45
+ manageAgentChatMitra: () => import_mitra_interactions_sdk24.manageAgentChatMitra,
46
+ manageAgentCredentialMitra: () => import_mitra_interactions_sdk25.manageAgentCredentialMitra,
47
+ patchRecordMitra: () => import_mitra_interactions_sdk21.patchRecordMitra,
48
+ refreshTokenSilently: () => import_mitra_interactions_sdk7.refreshTokenSilently,
49
+ resolveProjectId: () => import_mitra_interactions_sdk6.resolveProjectId,
50
+ stopServerFunctionExecutionMitra: () => import_mitra_interactions_sdk13.stopServerFunctionExecutionMitra,
51
+ updateRecordMitra: () => import_mitra_interactions_sdk20.updateRecordMitra
25
52
  });
26
53
  module.exports = __toCommonJS(index_exports);
27
54
 
55
+ // src/utils/url.ts
56
+ function stripTrailingSlashes(value) {
57
+ let end = value.length;
58
+ while (end > 0 && value.codePointAt(end - 1) === 47) end -= 1;
59
+ return value.slice(0, end);
60
+ }
61
+
28
62
  // src/client.ts
29
- var import_sdk_core6 = require("@mitralab.io/sdk-core");
63
+ var import_sdk_core9 = require("@mitralab.io/sdk-core");
30
64
 
31
65
  // src/utils/http-client.ts
32
66
  var bearerCredentialPattern = /(Bearer\s+)\S+/gi;
67
+ var sensitiveDetailKeyPattern = /token|authorization|password|secret|api.?key|credential|private.?key/i;
68
+ function isSensitiveDetailKey(key) {
69
+ return sensitiveDetailKeyPattern.test(key);
70
+ }
33
71
  function redactText(value, currentToken) {
34
72
  const withoutBearerCredentials = value.replace(bearerCredentialPattern, "$1[REDACTED]");
35
73
  return currentToken ? withoutBearerCredentials.split(currentToken).join("[REDACTED]") : withoutBearerCredentials;
@@ -39,10 +77,13 @@ function redactDetails(value, currentToken) {
39
77
  if (Array.isArray(value)) return value.map((item) => redactDetails(item, currentToken));
40
78
  if (value && typeof value === "object") {
41
79
  return Object.fromEntries(
42
- Object.entries(value).map(([key, entry]) => [
43
- redactText(key, currentToken),
44
- redactDetails(entry, currentToken)
45
- ])
80
+ Object.entries(value).map(([key, entry]) => {
81
+ const redactedKey = redactText(key, currentToken);
82
+ return [
83
+ redactedKey,
84
+ isSensitiveDetailKey(redactedKey) ? "[REDACTED]" : redactDetails(entry, currentToken)
85
+ ];
86
+ })
46
87
  );
47
88
  }
48
89
  return value;
@@ -67,12 +108,14 @@ function buildRequestUrl(baseUrl, path, params) {
67
108
  var HttpClient = class {
68
109
  baseUrl;
69
110
  tokenGetter;
111
+ beforeAuthenticatedRequest;
70
112
  onUnauthorized;
71
113
  onError;
72
114
  defaultHeaders;
73
115
  constructor(config) {
74
116
  this.baseUrl = config.baseUrl.replace(/\/$/, "");
75
117
  this.tokenGetter = config.getToken ?? (() => null);
118
+ this.beforeAuthenticatedRequest = config.beforeAuthenticatedRequest;
76
119
  this.onUnauthorized = config.onUnauthorized;
77
120
  this.onError = config.onError;
78
121
  this.defaultHeaders = config.defaultHeaders ?? {};
@@ -103,6 +146,9 @@ var HttpClient = class {
103
146
  async request(path, options = {}) {
104
147
  const { method = "GET", body, headers = {}, params, isRetry } = options;
105
148
  const url = buildRequestUrl(this.baseUrl, path, params);
149
+ if (!isRetry && this.tokenGetter() && this.beforeAuthenticatedRequest) {
150
+ await this.beforeAuthenticatedRequest();
151
+ }
106
152
  const requestHeaders = {
107
153
  "Content-Type": "application/json",
108
154
  ...this.defaultHeaders,
@@ -129,27 +175,50 @@ var HttpClient = class {
129
175
  }
130
176
  if (!response.ok) {
131
177
  if (response.status === 401 && !isRetry && this.onUnauthorized) {
132
- const refreshed = await this.onUnauthorized();
178
+ const refreshed = await this.onUnauthorized(token);
133
179
  if (refreshed) {
134
180
  return this.request(path, { ...options, isRetry: true });
135
181
  }
136
182
  }
137
- const errorBody = await response.json().catch(() => ({}));
138
- const errorPayload = asErrorPayload(errorBody);
139
- const rawMessage = optionalString(errorPayload.message);
140
- const rawCode = optionalString(errorPayload.error_code);
141
- const error = new MitraApiError(
142
- redactText(rawMessage || `Request failed with status ${response.status}`, token),
143
- response.status,
144
- rawCode === void 0 ? void 0 : redactText(rawCode, token),
145
- redactDetails(errorBody, token)
146
- );
183
+ const error = await this.errorFromResponse(response, token);
147
184
  this.onError?.(error);
148
185
  throw error;
149
186
  }
187
+ return this.parseResponseBody(response, path);
188
+ }
189
+ async errorFromResponse(response, token) {
190
+ const errorBody = await response.json().catch(() => ({}));
191
+ const errorPayload = asErrorPayload(errorBody);
192
+ const rawMessage = optionalString(errorPayload.message);
193
+ const rawCode = optionalString(errorPayload.error_code);
194
+ return new MitraApiError(
195
+ redactText(rawMessage || `Request failed with status ${response.status}`, token),
196
+ response.status,
197
+ rawCode === void 0 ? void 0 : redactText(rawCode, token),
198
+ redactDetails(errorBody, token)
199
+ );
200
+ }
201
+ async parseResponseBody(response, path) {
150
202
  if (response.status === 204) {
151
203
  return void 0;
152
204
  }
205
+ if (typeof response.text === "function") {
206
+ const responseText = await response.text();
207
+ if (responseText.length === 0) {
208
+ return void 0;
209
+ }
210
+ try {
211
+ return JSON.parse(responseText);
212
+ } catch {
213
+ const error = new MitraApiError(
214
+ `Response from ${path} is not valid JSON`,
215
+ response.status,
216
+ "INVALID_RESPONSE"
217
+ );
218
+ this.onError?.(error);
219
+ throw error;
220
+ }
221
+ }
153
222
  return response.json();
154
223
  }
155
224
  /**
@@ -229,26 +298,447 @@ var coreErrors = {
229
298
  invalidResponse: (message) => new MitraApiError(message, 200, "INVALID_RESPONSE")
230
299
  };
231
300
 
301
+ // src/legacy/bridge.ts
302
+ var import_mitra_interactions_sdk = require("mitra-interactions-sdk");
303
+
304
+ // src/modules/auth-page-url.ts
305
+ function resolveAuthPageUrl(apiUrl, configuredAuthPageUrl, browserWindow = globalThis.window) {
306
+ const injectedAuthPageUrl = browserWindow?.__mitraEnv?.authPageUrl;
307
+ try {
308
+ const candidate = configuredAuthPageUrl ?? (typeof injectedAuthPageUrl === "string" && injectedAuthPageUrl.trim() ? injectedAuthPageUrl : new URL("/sdk-auth.html", apiUrl).toString());
309
+ const url = new URL(candidate);
310
+ if (url.protocol !== "https:" && url.protocol !== "http:")
311
+ throw new Error("authPageUrl must be an absolute HTTP or HTTPS URL.");
312
+ return url;
313
+ } catch {
314
+ throw new Error("authPageUrl must be an absolute HTTP or HTTPS URL.");
315
+ }
316
+ }
317
+
318
+ // src/legacy/bridge.ts
319
+ function stripBearer(token) {
320
+ return token.replace(/^\s*(?:bearer\s+)+/i, "").trim();
321
+ }
322
+ var LegacySessionBridge = class {
323
+ auth;
324
+ appId;
325
+ apiUrl;
326
+ configuredAuthPageUrl;
327
+ legacyUrl;
328
+ unsubscribeFromAuth = null;
329
+ constructor(auth, appId, apiUrl, authPageUrl) {
330
+ this.auth = auth;
331
+ this.appId = appId;
332
+ this.apiUrl = apiUrl;
333
+ this.configuredAuthPageUrl = authPageUrl;
334
+ const gatewayUrl = stripTrailingSlashes(apiUrl);
335
+ this.legacyUrl = gatewayUrl ? `${gatewayUrl}/legacy` : "";
336
+ }
337
+ /**
338
+ * Configures the legacy SDK and hands it the session this SDK already holds.
339
+ *
340
+ * Called once per client. Failures are swallowed: an unusable legacy SDK must
341
+ * not stop the new client from being created.
342
+ */
343
+ connect() {
344
+ this.disconnect();
345
+ this.syncToLegacy(this.auth.readSessionTokens());
346
+ this.unsubscribeFromAuth = this.auth.onSessionChange((session) => {
347
+ this.syncToLegacy(session);
348
+ });
349
+ }
350
+ /** Stops this bridge from changing the process-wide legacy SDK singleton. */
351
+ disconnect() {
352
+ this.unsubscribeFromAuth?.();
353
+ this.unsubscribeFromAuth = null;
354
+ }
355
+ syncToLegacy(session) {
356
+ try {
357
+ const authPageUrl = resolveAuthPageUrl(
358
+ this.apiUrl,
359
+ this.configuredAuthPageUrl
360
+ ).toString();
361
+ (0, import_mitra_interactions_sdk.configureSdkMitra)({
362
+ baseURL: this.legacyUrl,
363
+ authUrl: this.legacyUrl,
364
+ authPageUrl,
365
+ projectId: this.appId,
366
+ onTokenRefresh: (session2) => this.adopt(session2),
367
+ ...session.token ? { token: session.token } : {},
368
+ ...session.refreshToken ? { refreshToken: session.refreshToken } : {}
369
+ });
370
+ const legacyConfig = (0, import_mitra_interactions_sdk.getConfig)();
371
+ if (!session.token) delete legacyConfig.token;
372
+ if (!session.refreshToken) delete legacyConfig.refreshToken;
373
+ } catch {
374
+ }
375
+ }
376
+ /**
377
+ * Stores a session produced by the legacy SDK. The AuthModule subscription
378
+ * then writes that session back to the process-wide legacy config and
379
+ * reinstates the refresh hook removed by legacy login.
380
+ */
381
+ adopt(session) {
382
+ const adopted = this.auth.adoptSession({
383
+ token: stripBearer(session.token),
384
+ refreshToken: session.refreshToken ?? null
385
+ });
386
+ if (!adopted) this.syncToLegacy(this.auth.readSessionTokens());
387
+ }
388
+ };
389
+ var activeBridge = null;
390
+ function setActiveBridge(bridge) {
391
+ activeBridge?.disconnect();
392
+ activeBridge = bridge;
393
+ }
394
+ function adoptLegacySession(session) {
395
+ activeBridge?.adopt(session);
396
+ }
397
+
232
398
  // src/modules/auth.ts
399
+ var import_sdk_core2 = require("@mitralab.io/sdk-core");
400
+
401
+ // src/modules/google-auth.ts
233
402
  var import_sdk_core = require("@mitralab.io/sdk-core");
403
+ var RESULT_TYPE = "mitra-oauth-result";
404
+ var PROVIDER_LABELS = {
405
+ google: "Google",
406
+ microsoft: "Microsoft"
407
+ };
408
+ var POPUP_WIDTH = 480;
409
+ var POPUP_HEIGHT = 600;
410
+ var POPUP_TIMEOUT_MS = 5 * 60 * 1e3;
411
+ var POPUP_CLOSED_POLL_MS = 500;
412
+ function expectAuthTokenResponse(value) {
413
+ const response = (0, import_sdk_core.expectObject)(
414
+ value,
415
+ "Authentication token response",
416
+ coreErrors
417
+ );
418
+ for (const field of ["accessToken", "refreshToken", "tokenType"]) {
419
+ if (typeof response[field] !== "string" || !response[field].trim()) {
420
+ throw coreErrors.invalidResponse(
421
+ `Authentication token response has an invalid ${field} field`
422
+ );
423
+ }
424
+ }
425
+ return {
426
+ accessToken: response.accessToken,
427
+ refreshToken: response.refreshToken,
428
+ tokenType: response.tokenType
429
+ };
430
+ }
431
+ var GoogleAuthFlow = class {
432
+ appId;
433
+ apiUrl;
434
+ configuredAuthPageUrl;
435
+ client;
436
+ provider;
437
+ providerLabel;
438
+ redirectStorageKey;
439
+ popupPromise = null;
440
+ constructor(config) {
441
+ this.appId = config.appId;
442
+ this.apiUrl = stripTrailingSlashes(config.apiUrl);
443
+ this.configuredAuthPageUrl = config.authPageUrl;
444
+ this.client = config.client;
445
+ this.provider = config.provider ?? "google";
446
+ this.providerLabel = PROVIDER_LABELS[this.provider];
447
+ this.redirectStorageKey = `mitra_${this.provider}_redirect_${config.appId}`;
448
+ }
449
+ signIn(options = {}) {
450
+ const browserWindow = this.requireBrowser();
451
+ if (options.mode === "redirect") {
452
+ return this.startRedirect(browserWindow);
453
+ }
454
+ if (options.mode !== void 0 && options.mode !== "popup") {
455
+ return Promise.reject(new Error(`Unsupported ${this.providerLabel} sign-in mode: ${String(options.mode)}`));
456
+ }
457
+ if (this.popupPromise) return this.popupPromise;
458
+ this.popupPromise = this.startPopup(browserWindow).finally(() => {
459
+ this.popupPromise = null;
460
+ });
461
+ return this.popupPromise;
462
+ }
463
+ async completeRedirect() {
464
+ const browserWindow = this.requireBrowser();
465
+ const params = new URLSearchParams(browserWindow.location.hash.replace(/^#/, ""));
466
+ const code = params.get("codeMitra");
467
+ const state = params.get("stateMitra");
468
+ const error = params.get("errorMitra");
469
+ if (code === null && state === null && error === null) return null;
470
+ const context = this.readRedirectContext(browserWindow);
471
+ if (!state?.trim()) {
472
+ throw new Error(`${this.providerLabel} sign-in redirect is missing state.`);
473
+ }
474
+ if (context?.state !== state) {
475
+ throw new Error(`Invalid ${this.providerLabel} sign-in state (possible CSRF).`);
476
+ }
477
+ const expectedRedirectUri = this.getRedirectUri(
478
+ resolveAuthPageUrl(this.apiUrl, this.configuredAuthPageUrl, browserWindow)
479
+ );
480
+ if (context.redirectUri !== expectedRedirectUri) {
481
+ throw new Error(`${this.providerLabel} sign-in redirect context is invalid.`);
482
+ }
483
+ this.cleanRedirectFragment(browserWindow);
484
+ this.clearRedirectContext(browserWindow);
485
+ if (code === "error" || error !== null) {
486
+ throw new Error(error || `${this.providerLabel} sign-in failed.`);
487
+ }
488
+ if (!code?.trim()) {
489
+ throw new Error(`${this.providerLabel} sign-in redirect is missing code.`);
490
+ }
491
+ return this.exchangeCode(code, context.redirectUri);
492
+ }
493
+ async startPopup(browserWindow) {
494
+ const state = this.generateState();
495
+ const authPageUrl = resolveAuthPageUrl(
496
+ this.apiUrl,
497
+ this.configuredAuthPageUrl,
498
+ browserWindow
499
+ );
500
+ const popup = this.openPopup(browserWindow, this.buildStartUrl(browserWindow, authPageUrl, state));
501
+ const result = await this.waitForPopupResult(browserWindow, popup, authPageUrl.origin, state);
502
+ if (result.code) return this.exchangeCode(result.code, this.getRedirectUri(authPageUrl));
503
+ return expectAuthTokenResponse(result.token);
504
+ }
505
+ startRedirect(browserWindow) {
506
+ const state = this.generateState();
507
+ const authPageUrl = resolveAuthPageUrl(
508
+ this.apiUrl,
509
+ this.configuredAuthPageUrl,
510
+ browserWindow
511
+ );
512
+ const context = {
513
+ state,
514
+ redirectUri: this.getRedirectUri(authPageUrl)
515
+ };
516
+ this.persistRedirectContext(browserWindow, context);
517
+ const startUrl = this.buildStartUrl(browserWindow, authPageUrl, state);
518
+ browserWindow.location.assign(startUrl.toString());
519
+ return new Promise(() => void 0);
520
+ }
521
+ async exchangeCode(code, redirectUri) {
522
+ const response = await this.client.post(`/api/v1/auth/${this.provider}`, {
523
+ appId: this.appId,
524
+ code,
525
+ redirectUri
526
+ });
527
+ return expectAuthTokenResponse(response);
528
+ }
529
+ buildStartUrl(browserWindow, authPageUrl, state) {
530
+ const startUrl = new URL(authPageUrl);
531
+ startUrl.searchParams.set("provider", this.provider);
532
+ startUrl.searchParams.set("state", state);
533
+ startUrl.searchParams.set("appId", this.appId);
534
+ startUrl.searchParams.set("apiUrl", this.apiUrl);
535
+ startUrl.searchParams.set("origin", browserWindow.location.origin);
536
+ startUrl.searchParams.set("responseType", "code");
537
+ return startUrl;
538
+ }
539
+ getRedirectUri(authPageUrl) {
540
+ return `${authPageUrl.origin}${authPageUrl.pathname}`;
541
+ }
542
+ generateState() {
543
+ if (!globalThis.crypto?.getRandomValues) {
544
+ throw new Error(`${this.providerLabel} sign-in requires crypto.getRandomValues.`);
545
+ }
546
+ const bytes = new Uint8Array(16);
547
+ globalThis.crypto.getRandomValues(bytes);
548
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
549
+ }
550
+ openPopup(browserWindow, url) {
551
+ const outerWidth = browserWindow.outerWidth || browserWindow.screen.width;
552
+ const outerHeight = browserWindow.outerHeight || browserWindow.screen.height;
553
+ const left = Math.max(0, (browserWindow.screenX || 0) + (outerWidth - POPUP_WIDTH) / 2);
554
+ const top = Math.max(0, (browserWindow.screenY || 0) + (outerHeight - POPUP_HEIGHT) / 2);
555
+ const popup = browserWindow.open(
556
+ url.toString(),
557
+ "mitra-google-oauth",
558
+ `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top},menubar=no,toolbar=no,status=no`
559
+ );
560
+ if (!popup) {
561
+ throw new Error(`${this.providerLabel} sign-in popup was blocked by the browser.`);
562
+ }
563
+ return popup;
564
+ }
565
+ waitForPopupResult(browserWindow, popup, expectedOrigin, expectedState) {
566
+ return new Promise((resolve, reject) => {
567
+ const timeout = globalThis.setTimeout(() => {
568
+ cleanup();
569
+ reject(new Error(`${this.providerLabel} sign-in timed out.`));
570
+ }, POPUP_TIMEOUT_MS);
571
+ const closedPoll = globalThis.setInterval(() => {
572
+ if (popup.closed) {
573
+ cleanup();
574
+ reject(new Error(`${this.providerLabel} sign-in was cancelled.`));
575
+ }
576
+ }, POPUP_CLOSED_POLL_MS);
577
+ const onMessage = (event) => {
578
+ if (event.origin !== expectedOrigin || event.source !== popup) return;
579
+ if (!event.data || typeof event.data !== "object") return;
580
+ const data = event.data;
581
+ if (data.type !== RESULT_TYPE) return;
582
+ if (data.state !== expectedState) {
583
+ cleanup();
584
+ reject(new Error(`Invalid ${this.providerLabel} sign-in state (possible CSRF).`));
585
+ return;
586
+ }
587
+ if (data.success !== true) {
588
+ cleanup();
589
+ reject(new Error(typeof data.error === "string" && data.error.trim() ? data.error : `${this.providerLabel} sign-in failed.`));
590
+ return;
591
+ }
592
+ const code = typeof data.code === "string" && data.code.trim() ? data.code : void 0;
593
+ if (!code && data.token === void 0) {
594
+ cleanup();
595
+ reject(new Error("Google auth page returned neither code nor token."));
596
+ return;
597
+ }
598
+ cleanup();
599
+ resolve({ ...code ? { code } : {}, ...data.token !== void 0 ? { token: data.token } : {} });
600
+ };
601
+ const cleanup = () => {
602
+ globalThis.clearTimeout(timeout);
603
+ globalThis.clearInterval(closedPoll);
604
+ browserWindow.removeEventListener("message", onMessage);
605
+ if (!popup.closed) popup.close();
606
+ };
607
+ browserWindow.addEventListener("message", onMessage);
608
+ });
609
+ }
610
+ persistRedirectContext(browserWindow, context) {
611
+ try {
612
+ browserWindow.sessionStorage.setItem(this.redirectStorageKey, JSON.stringify(context));
613
+ } catch {
614
+ throw new Error(`${this.providerLabel} sign-in redirect requires sessionStorage.`);
615
+ }
616
+ }
617
+ readRedirectContext(browserWindow) {
618
+ try {
619
+ const raw = browserWindow.sessionStorage.getItem(this.redirectStorageKey);
620
+ if (!raw) return null;
621
+ const value = JSON.parse(raw);
622
+ if (typeof value.state !== "string" || typeof value.redirectUri !== "string") return null;
623
+ return {
624
+ state: value.state,
625
+ redirectUri: value.redirectUri
626
+ };
627
+ } catch {
628
+ return null;
629
+ }
630
+ }
631
+ clearRedirectContext(browserWindow) {
632
+ try {
633
+ browserWindow.sessionStorage.removeItem(this.redirectStorageKey);
634
+ } catch {
635
+ }
636
+ }
637
+ cleanRedirectFragment(browserWindow) {
638
+ browserWindow.history.replaceState(
639
+ {},
640
+ "",
641
+ `${browserWindow.location.pathname}${browserWindow.location.search}`
642
+ );
643
+ }
644
+ requireBrowser() {
645
+ if (globalThis.window === void 0) {
646
+ throw new Error(`${this.providerLabel} sign-in is only available in a browser.`);
647
+ }
648
+ return globalThis.window;
649
+ }
650
+ };
651
+
652
+ // src/modules/auth.ts
653
+ var DEFAULT_TOKEN_VALIDITY_MS = 3e4;
654
+ var sessionPorts = /* @__PURE__ */ new WeakMap();
655
+ function getAuthSessionPort(auth) {
656
+ const port = sessionPorts.get(auth);
657
+ if (!port) throw new Error("Auth session port is unavailable.");
658
+ return port;
659
+ }
660
+ function decodeJwtPayload(token) {
661
+ try {
662
+ const part = token.replace(/^Bearer\s+/i, "").split(".")[1];
663
+ if (!part || typeof globalThis.atob !== "function") return null;
664
+ const base64 = part.replaceAll("-", "+").replaceAll("_", "/");
665
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
666
+ const value = JSON.parse(globalThis.atob(padded));
667
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
668
+ return value;
669
+ } catch {
670
+ return null;
671
+ }
672
+ }
673
+ function belongsToApp(token, appId) {
674
+ const payload = decodeJwtPayload(token);
675
+ if (!payload) return true;
676
+ return payload.app_id === appId;
677
+ }
678
+ function isTokenExpiring(token, minValidityMs) {
679
+ const exp = decodeJwtPayload(token)?.exp;
680
+ if (typeof exp !== "number" || !Number.isFinite(exp)) return false;
681
+ return exp * 1e3 - Date.now() < minValidityMs;
682
+ }
683
+ function isDefinitiveRefreshFailure(error) {
684
+ return error instanceof MitraApiError && error.status >= 400 && error.status < 500 && error.status !== 408 && error.status !== 429;
685
+ }
234
686
  var AuthModule = class {
235
687
  appId;
236
688
  _currentUser = null;
237
689
  #accessToken = null;
238
690
  #refreshToken = null;
239
- refreshPromise = null;
691
+ sessionGeneration = 0;
692
+ refreshFlight = null;
693
+ transientRefreshFailureGeneration = null;
240
694
  listeners = /* @__PURE__ */ new Set();
695
+ sessionListeners = /* @__PURE__ */ new Set();
241
696
  storageKey;
242
697
  publicClient;
243
698
  authedClient;
244
699
  currentUserApi;
245
- constructor(appId, iamBaseUrl) {
700
+ googleAuth;
701
+ microsoftAuth;
702
+ constructor(appId, iamBaseUrl, options = {}) {
246
703
  this.appId = appId;
704
+ const trimmedIamBaseUrl = stripTrailingSlashes(iamBaseUrl);
705
+ const apiUrl = stripTrailingSlashes(
706
+ options.apiUrl ?? (trimmedIamBaseUrl.endsWith("/iam") ? trimmedIamBaseUrl.slice(0, -"/iam".length) : trimmedIamBaseUrl)
707
+ );
247
708
  this.storageKey = `mitra_auth_${appId}`;
248
709
  this.publicClient = new HttpClient({ baseUrl: iamBaseUrl, getToken: () => null });
249
- this.authedClient = new HttpClient({ baseUrl: iamBaseUrl, getToken: () => this.#accessToken });
250
- this.currentUserApi = (0, import_sdk_core.createAuthModule)(this.authedClient, coreErrors);
710
+ this.authedClient = new HttpClient({
711
+ baseUrl: iamBaseUrl,
712
+ getToken: () => this.#accessToken,
713
+ beforeAuthenticatedRequest: () => this.ensureFreshSession().then(() => void 0),
714
+ onUnauthorized: (requestToken) => this.handleUnauthorized(requestToken)
715
+ });
716
+ this.currentUserApi = (0, import_sdk_core2.createAuthModule)(this.authedClient, coreErrors);
717
+ this.googleAuth = new GoogleAuthFlow({
718
+ appId,
719
+ apiUrl,
720
+ authPageUrl: options.authPageUrl,
721
+ client: this.publicClient
722
+ });
723
+ this.microsoftAuth = new GoogleAuthFlow({
724
+ appId,
725
+ apiUrl,
726
+ authPageUrl: options.authPageUrl,
727
+ client: this.publicClient,
728
+ provider: "microsoft"
729
+ });
251
730
  this.loadFromStorage();
731
+ const readAccessToken = () => this.#accessToken;
732
+ sessionPorts.set(this, {
733
+ get accessToken() {
734
+ return readAccessToken();
735
+ },
736
+ ensureFreshSession: (minValidityMs) => this.ensureFreshSession(minValidityMs),
737
+ handleUnauthorized: (requestToken) => this.handleUnauthorized(requestToken),
738
+ readSessionTokens: () => this.readSessionTokens(),
739
+ onSessionChange: (callback) => this.onSessionChange(callback),
740
+ adoptSession: (session) => this.adoptSession(session)
741
+ });
252
742
  }
253
743
  /** The currently authenticated user, or null. */
254
744
  get currentUser() {
@@ -262,57 +752,94 @@ var AuthModule = class {
262
752
  get isAuthenticated() {
263
753
  return this._currentUser !== null && this.#accessToken !== null;
264
754
  }
755
+ /** @deprecated Email/password authentication is not implemented by IAM. Use Google or Microsoft SSO. */
756
+ async signIn(_credentials) {
757
+ throw new MitraApiError(
758
+ "Email/password authentication is not available. Use signInWithGoogle() or signInWithMicrosoft().",
759
+ 0,
760
+ "UNSUPPORTED_AUTH_METHOD"
761
+ );
762
+ }
265
763
  /**
266
- * Signs in a user with email and password.
764
+ * Signs in with Google SSO.
267
765
  *
268
- * On success, stores access token, refresh token, and user data.
269
- * Subsequent API requests use the token automatically.
766
+ * Popup mode is used by default. Redirect mode stores a one-time CSRF context
767
+ * in `sessionStorage` and navigates to the configured `sdk-auth.html` page.
768
+ * Call {@link completeGoogleSignInRedirect} during application startup to
769
+ * finish a redirect response.
270
770
  *
271
- * @param credentials - Email and password.
272
- * @returns The authenticated user.
273
- * @throws {MitraApiError} On invalid credentials (401).
771
+ * The auth page is resolved from `createClient({ authPageUrl })`, then
772
+ * `window.__mitraEnv.authPageUrl`, and finally `/sdk-auth.html` on the API
773
+ * gateway origin.
774
+ *
775
+ * @param options - Popup or redirect mode.
776
+ * @returns The authenticated and hydrated user in popup mode.
777
+ * @throws {MitraApiError} When IAM rejects the authorization code.
778
+ * @throws {Error} When the browser blocks or cancels the popup, the flow times
779
+ * out, or the OAuth response fails origin, source, state, or shape validation.
274
780
  *
275
781
  * @example
276
782
  * ```typescript
277
- * const user = await mitra.auth.signIn({
278
- * email: 'user@example.com',
279
- * password: 'password123',
280
- * });
783
+ * const user = await mitra.auth.signInWithGoogle();
784
+ * ```
785
+ *
786
+ * @example
787
+ * ```typescript
788
+ * await mitra.auth.signInWithGoogle({ mode: 'redirect' });
281
789
  * ```
282
790
  */
283
- async signIn(credentials) {
284
- const tokenResponse = await this.publicClient.post(
285
- "/api/v1/auth/login",
286
- { ...credentials, appId: this.appId }
287
- );
288
- this.#accessToken = tokenResponse.accessToken;
289
- this.#refreshToken = tokenResponse.refreshToken;
290
- const user = await this.getCurrentUser();
291
- this.setAuthState(user, tokenResponse.accessToken, tokenResponse.refreshToken);
292
- return user;
791
+ async signInWithGoogle(options = {}) {
792
+ return this.establishSession(await this.googleAuth.signIn(options));
293
793
  }
294
794
  /**
295
- * Registers a new user and signs them in automatically.
795
+ * Completes a Google redirect response from `#codeMitra` and `#stateMitra`.
796
+ *
797
+ * The method consumes and clears the fragment and stored CSRF context, sends
798
+ * the single-use code directly to IAM, persists both tokens, calls `auth.me()`,
799
+ * and notifies auth-state listeners. It returns `null` when the current URL is
800
+ * not a Google SSO redirect. Redirect errors must carry the same `stateMitra`
801
+ * stored at the start of the flow before their message is exposed or consumed.
296
802
  *
297
- * @param data - Email, password, and optional name.
298
- * @returns The newly created and authenticated user.
299
- * @throws {MitraApiError} On duplicate email (409) or validation error (400).
803
+ * @returns The authenticated user, or `null` when no redirect result is present.
300
804
  *
301
805
  * @example
302
806
  * ```typescript
303
- * const user = await mitra.auth.signUp({
304
- * email: 'new@example.com',
305
- * password: 'securepassword',
306
- * name: 'Jane Doe',
307
- * });
807
+ * const redirectedUser = await mitra.auth.completeGoogleSignInRedirect();
808
+ * if (redirectedUser) console.log(redirectedUser.email);
308
809
  * ```
309
810
  */
310
- async signUp(data) {
311
- await this.publicClient.post("/api/v1/auth/register", {
312
- ...data,
313
- appId: this.appId
314
- });
315
- return this.signIn({ email: data.email, password: data.password });
811
+ async completeGoogleSignInRedirect() {
812
+ const tokenResponse = await this.googleAuth.completeRedirect();
813
+ return tokenResponse ? this.establishSession(tokenResponse) : null;
814
+ }
815
+ /**
816
+ * Signs in with Microsoft SSO: the same auth-page handshake as Google, exchanged
817
+ * at IAM's `/auth/microsoft`. Popup by default; redirect mode navigates away.
818
+ *
819
+ * @example
820
+ * ```typescript
821
+ * const user = await mitra.auth.signInWithMicrosoft();
822
+ * ```
823
+ */
824
+ async signInWithMicrosoft(options = {}) {
825
+ return this.establishSession(await this.microsoftAuth.signIn(options));
826
+ }
827
+ /**
828
+ * Completes a Microsoft redirect response from `#codeMitra` and `#stateMitra`.
829
+ * Mirrors {@link completeGoogleSignInRedirect}; returns `null` when the current
830
+ * URL is not a Microsoft SSO redirect.
831
+ */
832
+ async completeMicrosoftSignInRedirect() {
833
+ const tokenResponse = await this.microsoftAuth.completeRedirect();
834
+ return tokenResponse ? this.establishSession(tokenResponse) : null;
835
+ }
836
+ /** @deprecated Email/password registration is not implemented by IAM. Use Google or Microsoft SSO. */
837
+ async signUp(_data) {
838
+ throw new MitraApiError(
839
+ "Email/password registration is not available. Use signInWithGoogle() or signInWithMicrosoft().",
840
+ 0,
841
+ "UNSUPPORTED_AUTH_METHOD"
842
+ );
316
843
  }
317
844
  /**
318
845
  * Signs out the current user, clearing all auth state and localStorage.
@@ -334,9 +861,9 @@ var AuthModule = class {
334
861
  /**
335
862
  * Refreshes the session using the stored refresh token.
336
863
  *
337
- * Called automatically by the SDK on 401 responses. Can also be called
338
- * manually. Multiple concurrent calls are deduplicated (only one refresh
339
- * request is made).
864
+ * Called automatically before requests whose JWT is close to expiry and on
865
+ * `401` responses. Can also be called manually. Multiple proactive, reactive,
866
+ * and manual calls are deduplicated into one refresh request.
340
867
  *
341
868
  * @returns `true` if refresh succeeded, `false` otherwise.
342
869
  *
@@ -348,19 +875,50 @@ var AuthModule = class {
348
875
  */
349
876
  async refreshSession() {
350
877
  if (!this.#refreshToken) return false;
351
- if (this.refreshPromise) return this.refreshPromise;
352
- this.refreshPromise = this.doRefresh();
878
+ if (!this.hasValidAppIdentity()) {
879
+ this.clearAuthState();
880
+ return false;
881
+ }
882
+ const generation = this.sessionGeneration;
883
+ if (this.refreshFlight?.generation === generation) {
884
+ return this.refreshFlight.promise;
885
+ }
886
+ this.transientRefreshFailureGeneration = null;
887
+ const flight = {
888
+ generation,
889
+ promise: this.doRefresh(generation, this.#refreshToken)
890
+ };
891
+ this.refreshFlight = flight;
353
892
  try {
354
- return await this.refreshPromise;
893
+ return await flight.promise;
355
894
  } finally {
356
- this.refreshPromise = null;
895
+ if (this.refreshFlight === flight) {
896
+ this.refreshFlight = null;
897
+ }
357
898
  }
358
899
  }
900
+ /**
901
+ * Resolves a 401 against the credential that actually reached the server.
902
+ * A newer session is retried as-is instead of being refreshed because of an
903
+ * older request. A signed-out session is neither refreshed nor retried.
904
+ *
905
+ * @param requestToken - Access token attached to the rejected request.
906
+ * @returns Whether the request should be retried once with the current token.
907
+ *
908
+ * @internal
909
+ */
910
+ async handleUnauthorized(requestToken) {
911
+ const currentToken = this.#accessToken;
912
+ if (!currentToken) return false;
913
+ if (currentToken !== requestToken) return true;
914
+ return this.refreshSession();
915
+ }
359
916
  /**
360
917
  * Fetches the current user from the server and updates local state.
361
918
  *
362
- * Only clears auth state on 401 (expired/invalid token).
363
- * Transient errors (500, network) return null without clearing the session.
919
+ * Clears auth state on a definitive 401. When the request reaches 401 after
920
+ * IAM refresh failed due to a network error, 408, 429, or 5xx response, the
921
+ * retained session is preserved and this method returns null.
364
922
  *
365
923
  * @returns The user if authenticated, `null` otherwise.
366
924
  *
@@ -372,14 +930,17 @@ var AuthModule = class {
372
930
  */
373
931
  async me() {
374
932
  if (!this.#accessToken) return null;
933
+ const generation = this.sessionGeneration;
375
934
  try {
376
935
  const user = await this.getCurrentUser();
936
+ if (generation !== this.sessionGeneration) return null;
377
937
  this._currentUser = user;
938
+ this.transientRefreshFailureGeneration = null;
378
939
  this.saveToStorage();
379
940
  this.notifyListeners();
380
941
  return user;
381
942
  } catch (error) {
382
- if (error instanceof MitraApiError && error.status === 401) {
943
+ if (error instanceof MitraApiError && error.status === 401 && this.#accessToken && generation === this.sessionGeneration && this.transientRefreshFailureGeneration !== this.sessionGeneration) {
383
944
  this.clearAuthState();
384
945
  }
385
946
  return null;
@@ -414,10 +975,110 @@ var AuthModule = class {
414
975
  * ```
415
976
  */
416
977
  setToken(token, saveToStorage = true) {
978
+ if (!this.belongsToConfiguredApp(token)) {
979
+ this.clearAuthState();
980
+ return;
981
+ }
982
+ this.invalidatePendingRefreshes();
417
983
  this.#accessToken = token;
418
984
  if (saveToStorage) {
419
985
  this.saveToStorage();
420
986
  }
987
+ this.notifySessionListeners();
988
+ }
989
+ /**
990
+ * Reads the tokens currently held by this module.
991
+ *
992
+ * Used by the legacy session bridge to hand a session persisted by this SDK
993
+ * over to `mitra-interactions-sdk` on startup.
994
+ *
995
+ * @returns The access and refresh tokens, each `null` when absent.
996
+ *
997
+ * @internal
998
+ */
999
+ readSessionTokens() {
1000
+ return { token: this.#accessToken, refreshToken: this.#refreshToken };
1001
+ }
1002
+ /**
1003
+ * Adopts an app-scoped session received from a trusted platform boundary.
1004
+ *
1005
+ * This preserves the access and refresh tokens together so the normal refresh
1006
+ * lifecycle continues after an embedded preview hands its session to the app.
1007
+ * Call {@link checkAuth} afterward to validate the token and hydrate the user.
1008
+ */
1009
+ setSession(session) {
1010
+ return this.adoptSession({
1011
+ token: session.accessToken,
1012
+ refreshToken: session.refreshToken ?? null
1013
+ });
1014
+ }
1015
+ /**
1016
+ * Ensures the current access token has enough remaining validity.
1017
+ *
1018
+ * JWT decoding is used only as a scheduling heuristic. Opaque tokens and JWTs
1019
+ * without a numeric `exp` claim proceed unchanged and remain server-authoritative.
1020
+ * Multiple proactive and reactive callers share the same refresh request.
1021
+ * Transient refresh failures preserve the current session so the caller can
1022
+ * continue and rely on the normal one-time `401` refresh fallback.
1023
+ *
1024
+ * This method is suitable for authenticated HTTP, WebSocket, and Server-Sent
1025
+ * Events boundaries that need a fresh token before connecting.
1026
+ *
1027
+ * @param minValidityMs - Minimum remaining token lifetime. Defaults to 30 seconds.
1028
+ * @returns `true` when no refresh is needed or refresh succeeds. Returns
1029
+ * `false` when a required refresh fails, even when a transient failure keeps
1030
+ * the current session available for a reactive server-authoritative fallback.
1031
+ */
1032
+ async ensureFreshSession(minValidityMs = DEFAULT_TOKEN_VALIDITY_MS) {
1033
+ if (!Number.isFinite(minValidityMs) || minValidityMs < 0) {
1034
+ throw new RangeError("minValidityMs must be a finite non-negative number");
1035
+ }
1036
+ if (!this.#accessToken) return false;
1037
+ if (!this.hasValidAppIdentity()) {
1038
+ this.clearAuthState();
1039
+ return false;
1040
+ }
1041
+ if (!isTokenExpiring(this.#accessToken, minValidityMs)) return true;
1042
+ return this.refreshSession();
1043
+ }
1044
+ /**
1045
+ * Subscribes an internal boundary to token changes without triggering login
1046
+ * or refresh. Unlike auth-state listeners, this callback is not invoked
1047
+ * immediately and does not depend on the user being hydrated.
1048
+ *
1049
+ * @param callback - Receives the current access and refresh tokens.
1050
+ * @returns A function that removes the callback.
1051
+ *
1052
+ * @internal
1053
+ */
1054
+ onSessionChange(callback) {
1055
+ this.sessionListeners.add(callback);
1056
+ return () => this.sessionListeners.delete(callback);
1057
+ }
1058
+ /**
1059
+ * Adopts a session produced outside this module, such as a legacy SSO login.
1060
+ *
1061
+ * Replaces the in-memory tokens and persists them under the same storage key
1062
+ * the rest of the module uses. The current user is left untouched because the
1063
+ * legacy SDK does not return one; call `me()` to hydrate it.
1064
+ *
1065
+ * @param session - Access token and, when the issuer returned one, refresh token.
1066
+ *
1067
+ * @internal
1068
+ */
1069
+ adoptSession(session) {
1070
+ if (!this.belongsToConfiguredApp(session.token) || typeof session.refreshToken === "string" && !this.belongsToConfiguredApp(session.refreshToken)) {
1071
+ this.clearAuthState();
1072
+ return false;
1073
+ }
1074
+ this.invalidatePendingRefreshes();
1075
+ this.#accessToken = session.token;
1076
+ if (session.refreshToken !== void 0) {
1077
+ this.#refreshToken = session.refreshToken;
1078
+ }
1079
+ this.saveToStorage();
1080
+ this.notifySessionListeners();
1081
+ return true;
421
1082
  }
422
1083
  /**
423
1084
  * Redirects to `/login?returnUrl=...` for unauthenticated users.
@@ -461,27 +1122,65 @@ var AuthModule = class {
461
1122
  this.listeners.delete(callback);
462
1123
  };
463
1124
  }
464
- async doRefresh() {
1125
+ async doRefresh(generation, refreshToken) {
1126
+ let tokenResponse;
465
1127
  try {
466
- const tokenResponse = await this.publicClient.post(
467
- "/api/v1/auth/refresh-token",
468
- { refreshToken: this.#refreshToken }
1128
+ tokenResponse = expectAuthTokenResponse(
1129
+ await this.publicClient.post(
1130
+ "/api/v1/auth/refresh-token",
1131
+ { refreshToken }
1132
+ )
469
1133
  );
470
- this.#accessToken = tokenResponse.accessToken;
471
- this.#refreshToken = tokenResponse.refreshToken;
472
- const user = await this.getCurrentUser();
473
- this.setAuthState(user, tokenResponse.accessToken, tokenResponse.refreshToken);
474
- return true;
475
- } catch {
1134
+ } catch (error) {
1135
+ if (generation !== this.sessionGeneration) return false;
1136
+ if (isDefinitiveRefreshFailure(error)) {
1137
+ this.clearAuthState();
1138
+ } else {
1139
+ this.transientRefreshFailureGeneration = generation;
1140
+ }
1141
+ return false;
1142
+ }
1143
+ if (generation !== this.sessionGeneration) return false;
1144
+ if (!this.belongsToConfiguredApp(tokenResponse.accessToken) || !this.belongsToConfiguredApp(tokenResponse.refreshToken)) {
476
1145
  this.clearAuthState();
477
1146
  return false;
478
1147
  }
1148
+ this.#accessToken = tokenResponse.accessToken;
1149
+ this.#refreshToken = tokenResponse.refreshToken;
1150
+ this.transientRefreshFailureGeneration = null;
1151
+ this.saveToStorage();
1152
+ this.notifySessionListeners();
1153
+ return true;
1154
+ }
1155
+ async establishSession(tokenResponse) {
1156
+ if (!this.belongsToConfiguredApp(tokenResponse.accessToken) || !this.belongsToConfiguredApp(tokenResponse.refreshToken)) {
1157
+ this.clearAuthState();
1158
+ throw coreErrors.invalidResponse("Authentication returned a token for a different app");
1159
+ }
1160
+ this.invalidatePendingRefreshes();
1161
+ const generation = this.sessionGeneration;
1162
+ this.#accessToken = tokenResponse.accessToken;
1163
+ this.#refreshToken = tokenResponse.refreshToken;
1164
+ try {
1165
+ const user = await this.getCurrentUser();
1166
+ if (generation !== this.sessionGeneration) {
1167
+ throw new Error("Authentication session was superseded");
1168
+ }
1169
+ this.setAuthState(user, this.#accessToken, this.#refreshToken);
1170
+ return user;
1171
+ } catch (error) {
1172
+ if (generation === this.sessionGeneration) {
1173
+ this.clearAuthState();
1174
+ }
1175
+ throw error;
1176
+ }
479
1177
  }
480
1178
  setAuthState(user, token, refreshToken) {
481
1179
  this._currentUser = user;
482
1180
  this.#accessToken = token;
483
1181
  this.#refreshToken = refreshToken;
484
1182
  this.saveToStorage();
1183
+ this.notifySessionListeners();
485
1184
  this.notifyListeners();
486
1185
  }
487
1186
  async getCurrentUser() {
@@ -489,11 +1188,35 @@ var AuthModule = class {
489
1188
  return { ...user, tenantId: user.tenant.id };
490
1189
  }
491
1190
  clearAuthState() {
1191
+ const hadAuthState = this._currentUser !== null || this.#accessToken !== null || this.#refreshToken !== null;
1192
+ this.invalidatePendingRefreshes();
492
1193
  this._currentUser = null;
493
1194
  this.#accessToken = null;
494
1195
  this.#refreshToken = null;
495
1196
  this.removeFromStorage();
496
- this.notifyListeners();
1197
+ if (hadAuthState) {
1198
+ this.notifySessionListeners();
1199
+ this.notifyListeners();
1200
+ }
1201
+ }
1202
+ invalidatePendingRefreshes() {
1203
+ this.sessionGeneration += 1;
1204
+ this.transientRefreshFailureGeneration = null;
1205
+ }
1206
+ hasValidAppIdentity() {
1207
+ return (!this.#accessToken || this.belongsToConfiguredApp(this.#accessToken)) && (!this.#refreshToken || this.belongsToConfiguredApp(this.#refreshToken));
1208
+ }
1209
+ belongsToConfiguredApp(token) {
1210
+ return belongsToApp(token, this.appId);
1211
+ }
1212
+ notifySessionListeners() {
1213
+ const session = this.readSessionTokens();
1214
+ this.sessionListeners.forEach((callback) => {
1215
+ try {
1216
+ callback(session);
1217
+ } catch {
1218
+ }
1219
+ });
497
1220
  }
498
1221
  notifyListeners() {
499
1222
  this.listeners.forEach((callback) => {
@@ -524,9 +1247,14 @@ var AuthModule = class {
524
1247
  const stored = localStorage.getItem(this.storageKey);
525
1248
  if (stored) {
526
1249
  const { user, token, refreshToken } = JSON.parse(stored);
1250
+ if (typeof token !== "string" || refreshToken !== null && refreshToken !== void 0 && typeof refreshToken !== "string" || !this.belongsToConfiguredApp(token) || typeof refreshToken === "string" && !this.belongsToConfiguredApp(refreshToken)) {
1251
+ this.clearAuthState();
1252
+ return;
1253
+ }
527
1254
  this._currentUser = user;
528
1255
  this.#accessToken = token;
529
1256
  this.#refreshToken = refreshToken ?? null;
1257
+ this.invalidatePendingRefreshes();
530
1258
  }
531
1259
  } catch {
532
1260
  this.removeFromStorage();
@@ -542,11 +1270,11 @@ var AuthModule = class {
542
1270
  };
543
1271
 
544
1272
  // src/modules/entities.ts
545
- var import_sdk_core2 = require("@mitralab.io/sdk-core");
1273
+ var import_sdk_core3 = require("@mitralab.io/sdk-core");
546
1274
  var EntitiesModule = class _EntitiesModule {
547
1275
  constructor(httpClient, _dataSourceId) {
548
1276
  this.httpClient = httpClient;
549
- this.core = (0, import_sdk_core2.createEntitiesModule)(httpClient, coreErrors);
1277
+ this.core = (0, import_sdk_core3.createEntitiesModule)(httpClient, coreErrors);
550
1278
  }
551
1279
  core;
552
1280
  static createProxy(httpClient, dataSourceId) {
@@ -565,7 +1293,7 @@ var EntitiesModule = class _EntitiesModule {
565
1293
  * Records now resolve the app from authenticated context instead of a data source path.
566
1294
  */
567
1295
  setDataSourceId(_dataSourceId) {
568
- this.core = (0, import_sdk_core2.createEntitiesModule)(this.httpClient, coreErrors);
1296
+ this.core = (0, import_sdk_core3.createEntitiesModule)(this.httpClient, coreErrors);
569
1297
  }
570
1298
  getTable(tableName) {
571
1299
  return this.core.getTable(tableName);
@@ -573,33 +1301,48 @@ var EntitiesModule = class _EntitiesModule {
573
1301
  };
574
1302
 
575
1303
  // src/modules/functions.ts
576
- var import_sdk_core3 = require("@mitralab.io/sdk-core");
1304
+ var import_sdk_core4 = require("@mitralab.io/sdk-core");
577
1305
  var FunctionsModule = class {
578
1306
  core;
579
1307
  constructor(httpClient) {
580
- this.core = (0, import_sdk_core3.createFunctionsModule)(httpClient, { emptyInput: "omit-body" }, coreErrors);
1308
+ this.core = (0, import_sdk_core4.createFunctionsModule)(
1309
+ httpClient,
1310
+ { emptyInput: "omit-body", executeInvocationType: "sync" },
1311
+ coreErrors
1312
+ );
581
1313
  }
582
1314
  /**
583
- * Executes a Function using the Platform SDK 1.x server-default invocation semantics.
584
- * The runtime SDK uses an explicit invocation header instead.
1315
+ * Executes a Function synchronously and waits for its terminal result.
585
1316
  */
586
1317
  async execute(functionId, input) {
587
- const execution = await this.core.execute(functionId, input);
588
- if (execution.input === null) {
589
- throw coreErrors.invalidResponse(
590
- "Function execution response has an invalid input field"
591
- );
592
- }
593
- return { ...execution, input: execution.input };
1318
+ return this.core.execute(functionId, input);
1319
+ }
1320
+ /** Queues a Function and returns its initial execution record. */
1321
+ async executeAsync(functionId, input) {
1322
+ return this.core.executeAsync(functionId, input);
1323
+ }
1324
+ /** Reads the current state of an asynchronous Function execution. */
1325
+ async getExecution(executionId) {
1326
+ return this.core.getExecution(executionId);
1327
+ }
1328
+ /** Requests cancellation of a queued or running Function execution. */
1329
+ cancelExecution(executionId) {
1330
+ return this.core.cancelExecution(executionId);
594
1331
  }
595
1332
  };
596
1333
 
597
1334
  // src/modules/integration.ts
598
- var import_sdk_core4 = require("@mitralab.io/sdk-core");
1335
+ var import_sdk_core5 = require("@mitralab.io/sdk-core");
599
1336
  var IntegrationModule = class {
600
1337
  core;
1338
+ configs;
601
1339
  constructor(httpClient) {
602
- this.core = (0, import_sdk_core4.createIntegrationModule)(httpClient, coreErrors);
1340
+ this.core = (0, import_sdk_core5.createIntegrationModule)(httpClient, coreErrors);
1341
+ this.configs = (0, import_sdk_core5.createIntegrationAdminModule)(httpClient, coreErrors);
1342
+ }
1343
+ /** Lists the current app's integration configs without exposing admin mutations. */
1344
+ list(options) {
1345
+ return this.configs.list(options);
603
1346
  }
604
1347
  executeResource(resourceId, params) {
605
1348
  return this.core.executeResource(resourceId, params);
@@ -607,34 +1350,299 @@ var IntegrationModule = class {
607
1350
  execute(configId, request) {
608
1351
  return this.core.execute(configId, request);
609
1352
  }
1353
+ /** Executes a saved integration config selected by its app-scoped alias. */
1354
+ executeByAlias(alias, request) {
1355
+ return this.core.executeByAlias(alias, request);
1356
+ }
610
1357
  };
611
1358
 
612
1359
  // src/modules/queries.ts
613
- var import_sdk_core5 = require("@mitralab.io/sdk-core");
1360
+ var import_sdk_core6 = require("@mitralab.io/sdk-core");
614
1361
  var QueriesModule = class {
615
- dataSourceId = "";
616
1362
  core;
617
1363
  constructor(httpClient) {
618
- this.core = (0, import_sdk_core5.createQueriesModule)(httpClient, () => this.dataSourceId, coreErrors);
1364
+ this.core = (0, import_sdk_core6.createQueriesModule)(httpClient, coreErrors);
619
1365
  }
620
- /** Called by `client.init()` to set the app's resolved data source. */
621
- setDataSourceId(dataSourceId) {
622
- this.dataSourceId = dataSourceId;
1366
+ /**
1367
+ * @deprecated Preserved for Platform SDK 1.x source compatibility. Data Manager now resolves
1368
+ * the Data Source from the authenticated app.
1369
+ */
1370
+ setDataSourceId(_dataSourceId) {
623
1371
  }
624
1372
  async execute(id, parameters) {
625
- const result = await this.core.execute(id, parameters);
626
- return { ...result, affectedRows: result.affectedRows ?? null };
1373
+ return this.core.execute(id, parameters);
1374
+ }
1375
+ };
1376
+
1377
+ // src/modules/agent-tasks.ts
1378
+ var import_sdk_core7 = require("@mitralab.io/sdk-core");
1379
+
1380
+ // src/modules/agent-session.ts
1381
+ var CONNECT_TIMEOUT_MS = 15e3;
1382
+ function stripBearer2(token) {
1383
+ return token.replace(/^Bearer\s+/i, "");
1384
+ }
1385
+ function asObject(value) {
1386
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
1387
+ }
1388
+ function expectEvent(value) {
1389
+ const event = asObject(value);
1390
+ if (!event || typeof event.type !== "string" || !event.type) return null;
1391
+ if (typeof event.timestamp !== "number" || !Number.isFinite(event.timestamp)) return null;
1392
+ if (event.sequence !== void 0 && (typeof event.sequence !== "number" || !Number.isSafeInteger(event.sequence) || event.sequence < 0)) return null;
1393
+ return {
1394
+ type: event.type,
1395
+ payload: event.payload,
1396
+ timestamp: event.timestamp,
1397
+ ...typeof event.sequence === "number" ? { sequence: event.sequence } : {}
1398
+ };
1399
+ }
1400
+ function parseEvent(raw) {
1401
+ if (typeof raw !== "string") return expectEvent(raw);
1402
+ try {
1403
+ return expectEvent(JSON.parse(raw));
1404
+ } catch {
1405
+ return null;
1406
+ }
1407
+ }
1408
+ function isNormalClose(event) {
1409
+ return event.code === 1e3 || event.code === 4409;
1410
+ }
1411
+ var BrowserAgentTaskEventSource = class {
1412
+ constructor(auth, apiUrl) {
1413
+ this.auth = auth;
1414
+ this.apiUrl = stripTrailingSlashes(apiUrl);
1415
+ }
1416
+ apiUrl;
1417
+ sseFallbackTasks = /* @__PURE__ */ new Set();
1418
+ async open(taskId, observer, signal, transport = "auto") {
1419
+ if (transport === "http") return this.openSse(taskId, observer, signal);
1420
+ if (transport === "websocket") return this.openWebSocket(taskId, observer, signal);
1421
+ if (this.sseFallbackTasks.has(taskId)) {
1422
+ return this.wrapAutoConnection(taskId, await this.openSse(taskId, observer, signal));
1423
+ }
1424
+ try {
1425
+ const connection = await this.openWebSocket(taskId, {
1426
+ ...observer,
1427
+ onDisconnect: (error) => {
1428
+ this.sseFallbackTasks.add(taskId);
1429
+ observer.onDisconnect(error);
1430
+ }
1431
+ }, signal);
1432
+ return this.wrapAutoConnection(taskId, connection);
1433
+ } catch {
1434
+ this.sseFallbackTasks.add(taskId);
1435
+ return this.wrapAutoConnection(taskId, await this.openSse(taskId, observer, signal));
1436
+ }
1437
+ }
1438
+ wrapAutoConnection(taskId, connection) {
1439
+ return {
1440
+ close: () => {
1441
+ this.sseFallbackTasks.delete(taskId);
1442
+ connection.close();
1443
+ }
1444
+ };
1445
+ }
1446
+ async requireFreshToken() {
1447
+ const fresh = await this.auth.ensureFreshSession();
1448
+ const token = this.auth.accessToken;
1449
+ if (!fresh || !token) {
1450
+ throw new Error("A fresh authenticated app session is required for Agent streaming.");
1451
+ }
1452
+ return token;
1453
+ }
1454
+ async openWebSocket(taskId, observer, signal) {
1455
+ if (typeof globalThis.WebSocket !== "function") {
1456
+ throw new TypeError("WebSocket is not available.");
1457
+ }
1458
+ if (signal?.aborted) throw signal.reason ?? new Error("Agent WebSocket connection aborted.");
1459
+ const token = await this.requireFreshToken();
1460
+ const url = `${this.apiUrl.replace(/^http/i, "ws")}/copilot/ws/tasks/${encodeURIComponent(taskId)}?token=${encodeURIComponent(stripBearer2(token))}`;
1461
+ return new Promise((resolve, reject) => {
1462
+ const socket = new globalThis.WebSocket(url);
1463
+ let opened = false;
1464
+ let intentionalClose = false;
1465
+ let settled = false;
1466
+ const removeAbortListener = () => signal?.removeEventListener("abort", onAbort);
1467
+ const clearHandshake = () => {
1468
+ globalThis.clearTimeout(timer);
1469
+ removeAbortListener();
1470
+ };
1471
+ const rejectHandshake = (error) => {
1472
+ if (settled) return;
1473
+ settled = true;
1474
+ intentionalClose = true;
1475
+ clearHandshake();
1476
+ socket.close();
1477
+ reject(error);
1478
+ };
1479
+ const close = () => {
1480
+ if (intentionalClose) return;
1481
+ intentionalClose = true;
1482
+ removeAbortListener();
1483
+ socket.close(1e3, "Client closed");
1484
+ };
1485
+ const onAbort = () => {
1486
+ if (!opened) {
1487
+ rejectHandshake(signal?.reason instanceof Error ? signal.reason : new Error("Agent WebSocket connection aborted."));
1488
+ return;
1489
+ }
1490
+ close();
1491
+ };
1492
+ const timer = globalThis.setTimeout(() => {
1493
+ rejectHandshake(new Error("Timed out connecting to the Agent WebSocket."));
1494
+ }, CONNECT_TIMEOUT_MS);
1495
+ signal?.addEventListener("abort", onAbort, { once: true });
1496
+ socket.onopen = () => {
1497
+ if (settled) return;
1498
+ opened = true;
1499
+ settled = true;
1500
+ globalThis.clearTimeout(timer);
1501
+ resolve({ close });
1502
+ };
1503
+ socket.onerror = () => {
1504
+ if (!opened) rejectHandshake(new Error("Failed to connect to the Agent WebSocket."));
1505
+ };
1506
+ socket.onmessage = (message) => {
1507
+ const event = parseEvent(message.data);
1508
+ if (event) observer.onEvent(event);
1509
+ };
1510
+ socket.onclose = (event) => {
1511
+ globalThis.clearTimeout(timer);
1512
+ removeAbortListener();
1513
+ if (!opened) {
1514
+ rejectHandshake(new Error(`Agent WebSocket closed during handshake (${event.code}).`));
1515
+ return;
1516
+ }
1517
+ if (!intentionalClose && !isNormalClose(event)) {
1518
+ observer.onDisconnect(new Error(`Agent WebSocket disconnected (${event.code}).`));
1519
+ }
1520
+ };
1521
+ });
1522
+ }
1523
+ async openSse(taskId, observer, signal) {
1524
+ if (signal?.aborted) throw signal.reason ?? new Error("Agent SSE connection aborted.");
1525
+ const requestToken = await this.requireFreshToken();
1526
+ const abort = new AbortController();
1527
+ let intentionalClose = false;
1528
+ let disconnected = false;
1529
+ const url = `${this.apiUrl}/copilot/api/v1/tasks/${encodeURIComponent(taskId)}/events`;
1530
+ const request = (token) => globalThis.fetch(url, {
1531
+ headers: { Accept: "text/event-stream", Authorization: `Bearer ${stripBearer2(token)}` },
1532
+ signal: abort.signal
1533
+ });
1534
+ const onAbort = () => {
1535
+ intentionalClose = true;
1536
+ abort.abort(signal?.reason);
1537
+ };
1538
+ signal?.addEventListener("abort", onAbort, { once: true });
1539
+ let response = await request(requestToken);
1540
+ if (response.status === 401 && await this.auth.handleUnauthorized(requestToken)) {
1541
+ const currentToken = this.auth.accessToken;
1542
+ if (currentToken) response = await request(currentToken);
1543
+ }
1544
+ if (!response.ok || !response.body) {
1545
+ signal?.removeEventListener("abort", onAbort);
1546
+ abort.abort();
1547
+ throw new Error(`Agent SSE connection failed (${response.status}).`);
1548
+ }
1549
+ const disconnect = (error) => {
1550
+ if (disconnected || intentionalClose || signal?.aborted) return;
1551
+ disconnected = true;
1552
+ observer.onDisconnect(error);
1553
+ };
1554
+ void this.readSse(response.body, observer, abort.signal).then(() => disconnect()).catch((error) => disconnect(error)).finally(() => signal?.removeEventListener("abort", onAbort));
1555
+ return {
1556
+ close: () => {
1557
+ if (intentionalClose) return;
1558
+ intentionalClose = true;
1559
+ signal?.removeEventListener("abort", onAbort);
1560
+ abort.abort();
1561
+ }
1562
+ };
1563
+ }
1564
+ async readSse(body, observer, signal) {
1565
+ const reader = body.getReader();
1566
+ const decoder = new TextDecoder();
1567
+ let buffer = "";
1568
+ try {
1569
+ while (!signal.aborted) {
1570
+ const { done, value } = await reader.read();
1571
+ if (done) break;
1572
+ buffer += decoder.decode(value, { stream: true });
1573
+ let separator = /\r?\n\r?\n/.exec(buffer);
1574
+ while (separator?.index !== void 0) {
1575
+ const block = buffer.slice(0, separator.index);
1576
+ buffer = buffer.slice(separator.index + separator[0].length);
1577
+ const data = block.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
1578
+ const event = data ? parseEvent(data) : null;
1579
+ if (event) observer.onEvent(event);
1580
+ separator = /\r?\n\r?\n/.exec(buffer);
1581
+ }
1582
+ }
1583
+ } finally {
1584
+ reader.releaseLock();
1585
+ }
627
1586
  }
628
1587
  };
629
1588
 
1589
+ // src/modules/agent-tasks.ts
1590
+ function createBrowserAgentTasksModule(httpClient, auth, apiUrl) {
1591
+ const tasks = (0, import_sdk_core7.createAgentTasksModule)(httpClient, coreErrors);
1592
+ const manager = (0, import_sdk_core7.createAgentTaskSessionManager)({
1593
+ tasks,
1594
+ eventSource: new BrowserAgentTaskEventSource(auth, apiUrl)
1595
+ });
1596
+ return (0, import_sdk_core7.withAgentTaskSessions)(tasks, manager);
1597
+ }
1598
+
1599
+ // src/modules/agent-credentials.ts
1600
+ var import_sdk_core8 = require("@mitralab.io/sdk-core");
1601
+ function requireProvider(provider, allowed, flow) {
1602
+ if (!allowed.includes(provider)) {
1603
+ throw new TypeError(`${flow} does not support provider ${provider}.`);
1604
+ }
1605
+ }
1606
+ function createBrowserAgentCredentialsModule(httpClient) {
1607
+ const core = (0, import_sdk_core8.createAgentCredentialsModule)(httpClient, coreErrors);
1608
+ return {
1609
+ list: () => core.list(),
1610
+ listModels: (agentId) => core.listModels(agentId),
1611
+ saveApiKey: (provider, apiKey) => {
1612
+ requireProvider(provider, ["ANTHROPIC", "OPENAI"], "API key authentication");
1613
+ return core.saveApiKey(provider, apiKey);
1614
+ },
1615
+ remove: (provider) => {
1616
+ requireProvider(provider, ["ANTHROPIC", "OPENAI"], "Credential removal");
1617
+ return core.remove(provider);
1618
+ },
1619
+ startOAuth: (provider) => {
1620
+ requireProvider(provider, ["ANTHROPIC"], "OAuth");
1621
+ return core.startOAuth(provider);
1622
+ },
1623
+ exchangeOAuth: (provider, input) => {
1624
+ requireProvider(provider, ["ANTHROPIC"], "OAuth");
1625
+ return core.exchangeOAuth(provider, input);
1626
+ },
1627
+ startDeviceAuthorization: (provider) => {
1628
+ requireProvider(provider, ["OPENAI"], "Device authorization");
1629
+ return core.startDeviceAuthorization(provider);
1630
+ },
1631
+ pollDeviceAuthorization: (provider, deviceAuthId) => {
1632
+ requireProvider(provider, ["OPENAI"], "Device authorization");
1633
+ return core.pollDeviceAuthorization(provider, deviceAuthId);
1634
+ }
1635
+ };
1636
+ }
1637
+
630
1638
  // src/client.ts
631
1639
  function expectAppInfoResponse(value) {
632
- const response = (0, import_sdk_core6.expectObject)(
1640
+ const response = (0, import_sdk_core9.expectObject)(
633
1641
  value,
634
1642
  "App info response",
635
1643
  coreErrors
636
1644
  );
637
- if (typeof response.dataSourceId !== "string" || !response.dataSourceId.trim()) {
1645
+ if (response.dataSourceId !== null && (typeof response.dataSourceId !== "string" || !response.dataSourceId.trim())) {
638
1646
  throw coreErrors.invalidResponse(
639
1647
  "App info response has an invalid dataSourceId field"
640
1648
  );
@@ -650,18 +1658,23 @@ function expectAppInfoResponse(value) {
650
1658
  };
651
1659
  }
652
1660
  function createClient(config) {
653
- const { appId, apiUrl, onError } = config;
654
- const iamUrl = `${apiUrl}/iam`;
655
- const dataManagerUrl = `${apiUrl}/data-manager`;
656
- const functionsUrl = `${apiUrl}/functions`;
657
- const integrationUrl = `${apiUrl}/integration`;
658
- const codeStudioUrl = `${apiUrl}/code-studio`;
659
- const authModule = new AuthModule(appId, iamUrl);
660
- const onUnauthorized = () => authModule.refreshSession();
1661
+ const { appId, apiUrl, authPageUrl, onError } = config;
1662
+ const gatewayUrl = stripTrailingSlashes(apiUrl);
1663
+ const iamUrl = `${gatewayUrl}/iam`;
1664
+ const dataManagerUrl = `${gatewayUrl}/data-manager`;
1665
+ const functionsUrl = `${gatewayUrl}/functions`;
1666
+ const integrationUrl = `${gatewayUrl}/integration`;
1667
+ const codeStudioUrl = `${gatewayUrl}/code-studio`;
1668
+ const copilotUrl = `${gatewayUrl}/copilot`;
1669
+ const authModule = new AuthModule(appId, iamUrl, { apiUrl: gatewayUrl, authPageUrl });
1670
+ const authSession = getAuthSessionPort(authModule);
1671
+ const onUnauthorized = (requestToken) => authSession.handleUnauthorized(requestToken);
1672
+ const beforeAuthenticatedRequest = () => authModule.ensureFreshSession().then(() => void 0);
661
1673
  const defaultHeaders = { "X-App-Id": appId };
662
1674
  const httpClient = new HttpClient({
663
1675
  baseUrl: dataManagerUrl,
664
1676
  getToken: () => authModule.accessToken,
1677
+ beforeAuthenticatedRequest,
665
1678
  onUnauthorized,
666
1679
  onError,
667
1680
  defaultHeaders
@@ -670,20 +1683,43 @@ function createClient(config) {
670
1683
  const functionsHttpClient = new HttpClient({
671
1684
  baseUrl: functionsUrl,
672
1685
  getToken: () => authModule.accessToken,
1686
+ beforeAuthenticatedRequest,
673
1687
  onUnauthorized,
674
1688
  onError,
675
1689
  defaultHeaders
676
1690
  });
677
1691
  const functionsModule = new FunctionsModule(functionsHttpClient);
1692
+ const publicFunctionsModule = (0, import_sdk_core9.createPublicFunctionsModule)(
1693
+ new HttpClient({ baseUrl: functionsUrl, getToken: () => null }),
1694
+ coreErrors
1695
+ );
1696
+ const copilotHttpClient = new HttpClient({
1697
+ baseUrl: copilotUrl,
1698
+ getToken: () => authModule.accessToken,
1699
+ beforeAuthenticatedRequest,
1700
+ onUnauthorized,
1701
+ onError,
1702
+ defaultHeaders
1703
+ });
1704
+ const agentTasksModule = createBrowserAgentTasksModule(
1705
+ copilotHttpClient,
1706
+ authSession,
1707
+ gatewayUrl
1708
+ );
1709
+ const agentCredentialsModule = createBrowserAgentCredentialsModule(copilotHttpClient);
678
1710
  const integrationHttpClient = new HttpClient({
679
1711
  baseUrl: integrationUrl,
680
1712
  getToken: () => authModule.accessToken,
1713
+ beforeAuthenticatedRequest,
681
1714
  onUnauthorized,
682
1715
  onError,
683
1716
  defaultHeaders
684
1717
  });
685
1718
  const integrationModule = new IntegrationModule(integrationHttpClient);
686
1719
  const queriesModule = new QueriesModule(httpClient);
1720
+ const legacyBridge = new LegacySessionBridge(authSession, appId, apiUrl, authPageUrl);
1721
+ setActiveBridge(legacyBridge);
1722
+ legacyBridge.connect();
687
1723
  let initialized = false;
688
1724
  let allowSignup = true;
689
1725
  async function init() {
@@ -694,11 +1730,12 @@ function createClient(config) {
694
1730
  });
695
1731
  const appInfo = expectAppInfoResponse(
696
1732
  await publicClient.get(
697
- `/api/v1/apps/${(0, import_sdk_core6.encodePathSegment)(appId, "appId", coreErrors)}/info`
1733
+ `/api/v1/apps/${(0, import_sdk_core9.encodePathSegment)(appId, "appId", coreErrors)}/info`
698
1734
  )
699
1735
  );
700
- entitiesModule.setDataSourceId(appInfo.dataSourceId);
701
- queriesModule.setDataSourceId(appInfo.dataSourceId);
1736
+ if (appInfo.dataSourceId) {
1737
+ entitiesModule.setDataSourceId(appInfo.dataSourceId);
1738
+ }
702
1739
  allowSignup = appInfo.allowSignup;
703
1740
  initialized = true;
704
1741
  }
@@ -707,6 +1744,9 @@ function createClient(config) {
707
1744
  auth: authModule,
708
1745
  entities: entitiesModule,
709
1746
  functions: functionsModule,
1747
+ publicFunctions: publicFunctionsModule,
1748
+ agentTasks: agentTasksModule,
1749
+ agentCredentials: agentCredentialsModule,
710
1750
  integration: integrationModule,
711
1751
  queries: queriesModule,
712
1752
  get allowSignup() {
@@ -715,8 +1755,81 @@ function createClient(config) {
715
1755
  config
716
1756
  };
717
1757
  }
1758
+
1759
+ // src/legacy/index.ts
1760
+ var import_mitra_interactions_sdk2 = require("mitra-interactions-sdk");
1761
+ var import_mitra_interactions_sdk3 = require("mitra-interactions-sdk");
1762
+ var import_mitra_interactions_sdk4 = require("mitra-interactions-sdk");
1763
+ var import_mitra_interactions_sdk5 = require("mitra-interactions-sdk");
1764
+ var import_mitra_interactions_sdk6 = require("mitra-interactions-sdk");
1765
+ var import_mitra_interactions_sdk7 = require("mitra-interactions-sdk");
1766
+ var import_mitra_interactions_sdk8 = require("mitra-interactions-sdk");
1767
+ var import_mitra_interactions_sdk9 = require("mitra-interactions-sdk");
1768
+ var import_mitra_interactions_sdk10 = require("mitra-interactions-sdk");
1769
+ var import_mitra_interactions_sdk11 = require("mitra-interactions-sdk");
1770
+ var import_mitra_interactions_sdk12 = require("mitra-interactions-sdk");
1771
+ var import_mitra_interactions_sdk13 = require("mitra-interactions-sdk");
1772
+ var import_mitra_interactions_sdk14 = require("mitra-interactions-sdk");
1773
+ var import_mitra_interactions_sdk15 = require("mitra-interactions-sdk");
1774
+ var import_mitra_interactions_sdk16 = require("mitra-interactions-sdk");
1775
+ var import_mitra_interactions_sdk17 = require("mitra-interactions-sdk");
1776
+ var import_mitra_interactions_sdk18 = require("mitra-interactions-sdk");
1777
+ var import_mitra_interactions_sdk19 = require("mitra-interactions-sdk");
1778
+ var import_mitra_interactions_sdk20 = require("mitra-interactions-sdk");
1779
+ var import_mitra_interactions_sdk21 = require("mitra-interactions-sdk");
1780
+ var import_mitra_interactions_sdk22 = require("mitra-interactions-sdk");
1781
+ var import_mitra_interactions_sdk23 = require("mitra-interactions-sdk");
1782
+ var import_mitra_interactions_sdk24 = require("mitra-interactions-sdk");
1783
+ var import_mitra_interactions_sdk25 = require("mitra-interactions-sdk");
1784
+ var loginMitra = async (method, options) => {
1785
+ const session = await (0, import_mitra_interactions_sdk2.loginMitra)(method, options);
1786
+ adoptLegacySession(session);
1787
+ return session;
1788
+ };
1789
+ var loginWithGoogleMitra = async (options) => {
1790
+ const session = await (0, import_mitra_interactions_sdk2.loginWithGoogleMitra)(options);
1791
+ adoptLegacySession(session);
1792
+ return session;
1793
+ };
1794
+ var loginWithMicrosoftMitra = async (options) => {
1795
+ const session = await (0, import_mitra_interactions_sdk2.loginWithMicrosoftMitra)(options);
1796
+ adoptLegacySession(session);
1797
+ return session;
1798
+ };
1799
+ var exchangeSsoCodeMitra = async (options) => {
1800
+ const session = await (0, import_mitra_interactions_sdk2.exchangeSsoCodeMitra)(options);
1801
+ adoptLegacySession(session);
1802
+ return session;
1803
+ };
718
1804
  // Annotate the CommonJS export names for ESM import in node:
719
1805
  0 && (module.exports = {
720
1806
  MitraApiError,
721
- createClient
1807
+ callIntegrationMitra,
1808
+ configureSdkMitra,
1809
+ createClient,
1810
+ createMitraInstance,
1811
+ createRecordMitra,
1812
+ createRecordsBatchMitra,
1813
+ deleteRecordMitra,
1814
+ exchangeSsoCodeMitra,
1815
+ executePublicServerFunctionAsyncMitra,
1816
+ executePublicServerFunctionMitra,
1817
+ executeServerFunctionAsyncMitra,
1818
+ executeServerFunctionMitra,
1819
+ getAgentTaskMitra,
1820
+ getConfig,
1821
+ getPublicServerFunctionExecutionMitra,
1822
+ getRecordMitra,
1823
+ listIntegrationsMitra,
1824
+ listRecordsMitra,
1825
+ loginMitra,
1826
+ loginWithGoogleMitra,
1827
+ loginWithMicrosoftMitra,
1828
+ manageAgentChatMitra,
1829
+ manageAgentCredentialMitra,
1830
+ patchRecordMitra,
1831
+ refreshTokenSilently,
1832
+ resolveProjectId,
1833
+ stopServerFunctionExecutionMitra,
1834
+ updateRecordMitra
722
1835
  });