@insforge/sdk 1.2.0 → 1.2.1-dev.1
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 +2 -2
- package/dist/index.d.mts +75 -75
- package/dist/index.d.ts +75 -75
- package/dist/index.js +322 -177
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +322 -177
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -232,6 +232,95 @@ var Logger = class {
|
|
|
232
232
|
}
|
|
233
233
|
};
|
|
234
234
|
|
|
235
|
+
// src/lib/token-manager.ts
|
|
236
|
+
var CSRF_TOKEN_COOKIE = "insforge_csrf_token";
|
|
237
|
+
function getCsrfToken() {
|
|
238
|
+
if (typeof document === "undefined") return null;
|
|
239
|
+
const match = document.cookie.split(";").find((c) => c.trim().startsWith(`${CSRF_TOKEN_COOKIE}=`));
|
|
240
|
+
if (!match) return null;
|
|
241
|
+
return match.split("=")[1] || null;
|
|
242
|
+
}
|
|
243
|
+
function setCsrfToken(token) {
|
|
244
|
+
if (typeof document === "undefined") return;
|
|
245
|
+
const maxAge = 7 * 24 * 60 * 60;
|
|
246
|
+
const secure = typeof window !== "undefined" && window.location.protocol === "https:" ? "; Secure" : "";
|
|
247
|
+
document.cookie = `${CSRF_TOKEN_COOKIE}=${encodeURIComponent(token)}; path=/; max-age=${maxAge}; SameSite=Lax${secure}`;
|
|
248
|
+
}
|
|
249
|
+
function clearCsrfToken() {
|
|
250
|
+
if (typeof document === "undefined") return;
|
|
251
|
+
const secure = typeof window !== "undefined" && window.location.protocol === "https:" ? "; Secure" : "";
|
|
252
|
+
document.cookie = `${CSRF_TOKEN_COOKIE}=; path=/; max-age=0; SameSite=Lax${secure}`;
|
|
253
|
+
}
|
|
254
|
+
var TokenManager = class {
|
|
255
|
+
constructor() {
|
|
256
|
+
// In-memory storage
|
|
257
|
+
this.accessToken = null;
|
|
258
|
+
this.user = null;
|
|
259
|
+
// Callback for token changes (used by realtime to reconnect with new token)
|
|
260
|
+
this.onTokenChange = null;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Save session in memory
|
|
264
|
+
*/
|
|
265
|
+
saveSession(session) {
|
|
266
|
+
const tokenChanged = session.accessToken !== this.accessToken;
|
|
267
|
+
this.accessToken = session.accessToken;
|
|
268
|
+
this.user = session.user;
|
|
269
|
+
if (tokenChanged && this.onTokenChange) {
|
|
270
|
+
this.onTokenChange();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Get current session
|
|
275
|
+
*/
|
|
276
|
+
getSession() {
|
|
277
|
+
if (!this.accessToken || !this.user) return null;
|
|
278
|
+
return {
|
|
279
|
+
accessToken: this.accessToken,
|
|
280
|
+
user: this.user
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Get access token
|
|
285
|
+
*/
|
|
286
|
+
getAccessToken() {
|
|
287
|
+
return this.accessToken;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Set access token
|
|
291
|
+
*/
|
|
292
|
+
setAccessToken(token) {
|
|
293
|
+
const tokenChanged = token !== this.accessToken;
|
|
294
|
+
this.accessToken = token;
|
|
295
|
+
if (tokenChanged && this.onTokenChange) {
|
|
296
|
+
this.onTokenChange();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Get user
|
|
301
|
+
*/
|
|
302
|
+
getUser() {
|
|
303
|
+
return this.user;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Set user
|
|
307
|
+
*/
|
|
308
|
+
setUser(user) {
|
|
309
|
+
this.user = user;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Clear in-memory session
|
|
313
|
+
*/
|
|
314
|
+
clearSession() {
|
|
315
|
+
const hadToken = this.accessToken !== null;
|
|
316
|
+
this.accessToken = null;
|
|
317
|
+
this.user = null;
|
|
318
|
+
if (hadToken && this.onTokenChange) {
|
|
319
|
+
this.onTokenChange();
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
|
|
235
324
|
// src/lib/http-client.ts
|
|
236
325
|
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([500, 502, 503, 504]);
|
|
237
326
|
var IDEMPOTENT_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
@@ -239,16 +328,23 @@ var HttpClient = class {
|
|
|
239
328
|
/**
|
|
240
329
|
* Creates a new HttpClient instance.
|
|
241
330
|
* @param config - SDK configuration including baseUrl, timeout, retry settings, and fetch implementation.
|
|
331
|
+
* @param tokenManager - Token manager for session persistence.
|
|
242
332
|
* @param logger - Optional logger instance for request/response debugging.
|
|
243
333
|
*/
|
|
244
|
-
constructor(config, logger) {
|
|
334
|
+
constructor(config, tokenManager, logger) {
|
|
245
335
|
this.userToken = null;
|
|
336
|
+
this.autoRefreshToken = true;
|
|
337
|
+
this.isRefreshing = false;
|
|
338
|
+
this.refreshPromise = null;
|
|
339
|
+
this.refreshToken = null;
|
|
246
340
|
this.baseUrl = config.baseUrl || "http://localhost:7130";
|
|
341
|
+
this.autoRefreshToken = config.autoRefreshToken ?? true;
|
|
247
342
|
this.fetch = config.fetch || (globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
|
|
248
343
|
this.anonKey = config.anonKey;
|
|
249
344
|
this.defaultHeaders = {
|
|
250
345
|
...config.headers
|
|
251
346
|
};
|
|
347
|
+
this.tokenManager = tokenManager ?? new TokenManager();
|
|
252
348
|
this.logger = logger || new Logger(false);
|
|
253
349
|
this.timeout = config.timeout ?? 3e4;
|
|
254
350
|
this.retryCount = config.retryCount ?? 3;
|
|
@@ -302,8 +398,14 @@ var HttpClient = class {
|
|
|
302
398
|
* @returns Parsed response data.
|
|
303
399
|
* @throws {InsForgeError} On timeout, network failure, or HTTP error responses.
|
|
304
400
|
*/
|
|
305
|
-
async
|
|
306
|
-
const {
|
|
401
|
+
async handleRequest(method, path, options = {}) {
|
|
402
|
+
const {
|
|
403
|
+
params,
|
|
404
|
+
headers = {},
|
|
405
|
+
body,
|
|
406
|
+
signal: callerSignal,
|
|
407
|
+
...fetchOptions
|
|
408
|
+
} = options;
|
|
307
409
|
const url = this.buildUrl(path, params);
|
|
308
410
|
const startTime = Date.now();
|
|
309
411
|
const canRetry = IDEMPOTENT_METHODS.has(method.toUpperCase()) || options.idempotent === true;
|
|
@@ -342,7 +444,9 @@ var HttpClient = class {
|
|
|
342
444
|
for (let attempt = 0; attempt <= maxAttempts; attempt++) {
|
|
343
445
|
if (attempt > 0) {
|
|
344
446
|
const delay = this.computeRetryDelay(attempt);
|
|
345
|
-
this.logger.warn(
|
|
447
|
+
this.logger.warn(
|
|
448
|
+
`Retry ${attempt}/${maxAttempts} for ${method} ${url} in ${delay}ms`
|
|
449
|
+
);
|
|
346
450
|
if (callerSignal?.aborted) throw callerSignal.reason;
|
|
347
451
|
await new Promise((resolve, reject) => {
|
|
348
452
|
const onAbort = () => {
|
|
@@ -350,7 +454,8 @@ var HttpClient = class {
|
|
|
350
454
|
reject(callerSignal.reason);
|
|
351
455
|
};
|
|
352
456
|
const timer2 = setTimeout(() => {
|
|
353
|
-
if (callerSignal)
|
|
457
|
+
if (callerSignal)
|
|
458
|
+
callerSignal.removeEventListener("abort", onAbort);
|
|
354
459
|
resolve();
|
|
355
460
|
}, delay);
|
|
356
461
|
if (callerSignal) {
|
|
@@ -370,10 +475,16 @@ var HttpClient = class {
|
|
|
370
475
|
controller.abort(callerSignal.reason);
|
|
371
476
|
} else {
|
|
372
477
|
const onCallerAbort = () => controller.abort(callerSignal.reason);
|
|
373
|
-
callerSignal.addEventListener("abort", onCallerAbort, {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
478
|
+
callerSignal.addEventListener("abort", onCallerAbort, {
|
|
479
|
+
once: true
|
|
480
|
+
});
|
|
481
|
+
controller.signal.addEventListener(
|
|
482
|
+
"abort",
|
|
483
|
+
() => {
|
|
484
|
+
callerSignal.removeEventListener("abort", onCallerAbort);
|
|
485
|
+
},
|
|
486
|
+
{ once: true }
|
|
487
|
+
);
|
|
377
488
|
}
|
|
378
489
|
}
|
|
379
490
|
}
|
|
@@ -417,7 +528,13 @@ var HttpClient = class {
|
|
|
417
528
|
}
|
|
418
529
|
if (timer !== void 0) clearTimeout(timer);
|
|
419
530
|
if (!response.ok) {
|
|
420
|
-
this.logger.logResponse(
|
|
531
|
+
this.logger.logResponse(
|
|
532
|
+
method,
|
|
533
|
+
url,
|
|
534
|
+
response.status,
|
|
535
|
+
Date.now() - startTime,
|
|
536
|
+
data
|
|
537
|
+
);
|
|
421
538
|
if (data && typeof data === "object" && "error" in data) {
|
|
422
539
|
if (!data.statusCode && !data.status) {
|
|
423
540
|
data.statusCode = response.status;
|
|
@@ -436,7 +553,13 @@ var HttpClient = class {
|
|
|
436
553
|
"REQUEST_FAILED"
|
|
437
554
|
);
|
|
438
555
|
}
|
|
439
|
-
this.logger.logResponse(
|
|
556
|
+
this.logger.logResponse(
|
|
557
|
+
method,
|
|
558
|
+
url,
|
|
559
|
+
response.status,
|
|
560
|
+
Date.now() - startTime,
|
|
561
|
+
data
|
|
562
|
+
);
|
|
440
563
|
return data;
|
|
441
564
|
} catch (err) {
|
|
442
565
|
if (timer !== void 0) clearTimeout(timer);
|
|
@@ -470,6 +593,33 @@ var HttpClient = class {
|
|
|
470
593
|
"NETWORK_ERROR"
|
|
471
594
|
);
|
|
472
595
|
}
|
|
596
|
+
async request(method, path, options = {}) {
|
|
597
|
+
try {
|
|
598
|
+
return await this.handleRequest(method, path, { ...options });
|
|
599
|
+
} catch (error) {
|
|
600
|
+
if (error instanceof InsForgeError && error.statusCode === 401 && error.error === "INVALID_TOKEN" && this.autoRefreshToken) {
|
|
601
|
+
try {
|
|
602
|
+
const newTokenData = await this.handleTokenRefresh();
|
|
603
|
+
this.setAuthToken(newTokenData.accessToken);
|
|
604
|
+
this.tokenManager.saveSession(newTokenData);
|
|
605
|
+
if (newTokenData.csrfToken) {
|
|
606
|
+
setCsrfToken(newTokenData.csrfToken);
|
|
607
|
+
}
|
|
608
|
+
if (newTokenData.refreshToken) {
|
|
609
|
+
this.setRefreshToken(newTokenData.refreshToken);
|
|
610
|
+
}
|
|
611
|
+
return await this.handleRequest(method, path, { ...options });
|
|
612
|
+
} catch (error2) {
|
|
613
|
+
this.tokenManager.clearSession();
|
|
614
|
+
this.userToken = null;
|
|
615
|
+
this.refreshToken = null;
|
|
616
|
+
clearCsrfToken();
|
|
617
|
+
throw error2;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
throw error;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
473
623
|
/** Performs a GET request. */
|
|
474
624
|
get(path, options) {
|
|
475
625
|
return this.request("GET", path, options);
|
|
@@ -494,6 +644,9 @@ var HttpClient = class {
|
|
|
494
644
|
setAuthToken(token) {
|
|
495
645
|
this.userToken = token;
|
|
496
646
|
}
|
|
647
|
+
setRefreshToken(token) {
|
|
648
|
+
this.refreshToken = token;
|
|
649
|
+
}
|
|
497
650
|
/** Returns the current default headers including the authorization header if set. */
|
|
498
651
|
getHeaders() {
|
|
499
652
|
const headers = { ...this.defaultHeaders };
|
|
@@ -503,94 +656,31 @@ var HttpClient = class {
|
|
|
503
656
|
}
|
|
504
657
|
return headers;
|
|
505
658
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
var CSRF_TOKEN_COOKIE = "insforge_csrf_token";
|
|
510
|
-
function getCsrfToken() {
|
|
511
|
-
if (typeof document === "undefined") return null;
|
|
512
|
-
const match = document.cookie.split(";").find((c) => c.trim().startsWith(`${CSRF_TOKEN_COOKIE}=`));
|
|
513
|
-
if (!match) return null;
|
|
514
|
-
return match.split("=")[1] || null;
|
|
515
|
-
}
|
|
516
|
-
function setCsrfToken(token) {
|
|
517
|
-
if (typeof document === "undefined") return;
|
|
518
|
-
const maxAge = 7 * 24 * 60 * 60;
|
|
519
|
-
const secure = typeof window !== "undefined" && window.location.protocol === "https:" ? "; Secure" : "";
|
|
520
|
-
document.cookie = `${CSRF_TOKEN_COOKIE}=${encodeURIComponent(token)}; path=/; max-age=${maxAge}; SameSite=Lax${secure}`;
|
|
521
|
-
}
|
|
522
|
-
function clearCsrfToken() {
|
|
523
|
-
if (typeof document === "undefined") return;
|
|
524
|
-
const secure = typeof window !== "undefined" && window.location.protocol === "https:" ? "; Secure" : "";
|
|
525
|
-
document.cookie = `${CSRF_TOKEN_COOKIE}=; path=/; max-age=0; SameSite=Lax${secure}`;
|
|
526
|
-
}
|
|
527
|
-
var TokenManager = class {
|
|
528
|
-
constructor() {
|
|
529
|
-
// In-memory storage
|
|
530
|
-
this.accessToken = null;
|
|
531
|
-
this.user = null;
|
|
532
|
-
// Callback for token changes (used by realtime to reconnect with new token)
|
|
533
|
-
this.onTokenChange = null;
|
|
534
|
-
}
|
|
535
|
-
/**
|
|
536
|
-
* Save session in memory
|
|
537
|
-
*/
|
|
538
|
-
saveSession(session) {
|
|
539
|
-
const tokenChanged = session.accessToken !== this.accessToken;
|
|
540
|
-
this.accessToken = session.accessToken;
|
|
541
|
-
this.user = session.user;
|
|
542
|
-
if (tokenChanged && this.onTokenChange) {
|
|
543
|
-
this.onTokenChange();
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
/**
|
|
547
|
-
* Get current session
|
|
548
|
-
*/
|
|
549
|
-
getSession() {
|
|
550
|
-
if (!this.accessToken || !this.user) return null;
|
|
551
|
-
return {
|
|
552
|
-
accessToken: this.accessToken,
|
|
553
|
-
user: this.user
|
|
554
|
-
};
|
|
555
|
-
}
|
|
556
|
-
/**
|
|
557
|
-
* Get access token
|
|
558
|
-
*/
|
|
559
|
-
getAccessToken() {
|
|
560
|
-
return this.accessToken;
|
|
561
|
-
}
|
|
562
|
-
/**
|
|
563
|
-
* Set access token
|
|
564
|
-
*/
|
|
565
|
-
setAccessToken(token) {
|
|
566
|
-
const tokenChanged = token !== this.accessToken;
|
|
567
|
-
this.accessToken = token;
|
|
568
|
-
if (tokenChanged && this.onTokenChange) {
|
|
569
|
-
this.onTokenChange();
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
/**
|
|
573
|
-
* Get user
|
|
574
|
-
*/
|
|
575
|
-
getUser() {
|
|
576
|
-
return this.user;
|
|
577
|
-
}
|
|
578
|
-
/**
|
|
579
|
-
* Set user
|
|
580
|
-
*/
|
|
581
|
-
setUser(user) {
|
|
582
|
-
this.user = user;
|
|
583
|
-
}
|
|
584
|
-
/**
|
|
585
|
-
* Clear in-memory session
|
|
586
|
-
*/
|
|
587
|
-
clearSession() {
|
|
588
|
-
const hadToken = this.accessToken !== null;
|
|
589
|
-
this.accessToken = null;
|
|
590
|
-
this.user = null;
|
|
591
|
-
if (hadToken && this.onTokenChange) {
|
|
592
|
-
this.onTokenChange();
|
|
659
|
+
async handleTokenRefresh() {
|
|
660
|
+
if (this.isRefreshing) {
|
|
661
|
+
return this.refreshPromise;
|
|
593
662
|
}
|
|
663
|
+
this.isRefreshing = true;
|
|
664
|
+
this.refreshPromise = (async () => {
|
|
665
|
+
try {
|
|
666
|
+
const csrfToken = getCsrfToken();
|
|
667
|
+
const body = this.refreshToken ? { refreshToken: this.refreshToken } : void 0;
|
|
668
|
+
const response = await this.handleRequest(
|
|
669
|
+
"POST",
|
|
670
|
+
"/api/auth/sessions/current",
|
|
671
|
+
{
|
|
672
|
+
body,
|
|
673
|
+
headers: csrfToken ? { "X-CSRF-Token": csrfToken } : {},
|
|
674
|
+
credentials: "include"
|
|
675
|
+
}
|
|
676
|
+
);
|
|
677
|
+
return response;
|
|
678
|
+
} finally {
|
|
679
|
+
this.isRefreshing = false;
|
|
680
|
+
this.refreshPromise = null;
|
|
681
|
+
}
|
|
682
|
+
})();
|
|
683
|
+
return this.refreshPromise;
|
|
594
684
|
}
|
|
595
685
|
};
|
|
596
686
|
|
|
@@ -649,6 +739,7 @@ function cleanUrlParams(...params) {
|
|
|
649
739
|
}
|
|
650
740
|
|
|
651
741
|
// src/modules/auth/auth.ts
|
|
742
|
+
var import_shared_schemas = require("@insforge/shared-schemas");
|
|
652
743
|
var Auth = class {
|
|
653
744
|
constructor(http, tokenManager, options = {}) {
|
|
654
745
|
this.http = http;
|
|
@@ -678,6 +769,7 @@ var Auth = class {
|
|
|
678
769
|
this.tokenManager.saveSession(session);
|
|
679
770
|
}
|
|
680
771
|
this.http.setAuthToken(response.accessToken);
|
|
772
|
+
this.http.setRefreshToken(response.refreshToken ?? null);
|
|
681
773
|
return true;
|
|
682
774
|
}
|
|
683
775
|
// ============================================================================
|
|
@@ -685,7 +777,7 @@ var Auth = class {
|
|
|
685
777
|
// ============================================================================
|
|
686
778
|
/**
|
|
687
779
|
* Detect and handle OAuth callback parameters in URL
|
|
688
|
-
* Supports PKCE flow (insforge_code)
|
|
780
|
+
* Supports PKCE flow (insforge_code)
|
|
689
781
|
*/
|
|
690
782
|
async detectAuthCallback() {
|
|
691
783
|
if (this.isServerMode() || typeof window === "undefined") return;
|
|
@@ -706,31 +798,6 @@ var Auth = class {
|
|
|
706
798
|
}
|
|
707
799
|
return;
|
|
708
800
|
}
|
|
709
|
-
const accessToken = params.get("access_token");
|
|
710
|
-
const userId = params.get("user_id");
|
|
711
|
-
const email = params.get("email");
|
|
712
|
-
if (accessToken && userId && email) {
|
|
713
|
-
const csrfToken = params.get("csrf_token");
|
|
714
|
-
const name = params.get("name");
|
|
715
|
-
if (csrfToken) {
|
|
716
|
-
setCsrfToken(csrfToken);
|
|
717
|
-
}
|
|
718
|
-
const session = {
|
|
719
|
-
accessToken,
|
|
720
|
-
user: {
|
|
721
|
-
id: userId,
|
|
722
|
-
email,
|
|
723
|
-
profile: { name: name || "" },
|
|
724
|
-
metadata: null,
|
|
725
|
-
emailVerified: false,
|
|
726
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
727
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
728
|
-
}
|
|
729
|
-
};
|
|
730
|
-
this.tokenManager.saveSession(session);
|
|
731
|
-
this.http.setAuthToken(accessToken);
|
|
732
|
-
cleanUrlParams("access_token", "user_id", "email", "name", "csrf_token");
|
|
733
|
-
}
|
|
734
801
|
} catch (error) {
|
|
735
802
|
console.debug("OAuth callback detection skipped:", error);
|
|
736
803
|
}
|
|
@@ -748,6 +815,9 @@ var Auth = class {
|
|
|
748
815
|
if (response.accessToken && response.user) {
|
|
749
816
|
this.saveSessionFromResponse(response);
|
|
750
817
|
}
|
|
818
|
+
if (response.refreshToken) {
|
|
819
|
+
this.http.setRefreshToken(response.refreshToken);
|
|
820
|
+
}
|
|
751
821
|
return { data: response, error: null };
|
|
752
822
|
} catch (error) {
|
|
753
823
|
return wrapError(error, "An unexpected error occurred during sign up");
|
|
@@ -761,6 +831,9 @@ var Auth = class {
|
|
|
761
831
|
{ credentials: "include" }
|
|
762
832
|
);
|
|
763
833
|
this.saveSessionFromResponse(response);
|
|
834
|
+
if (response.refreshToken) {
|
|
835
|
+
this.http.setRefreshToken(response.refreshToken);
|
|
836
|
+
}
|
|
764
837
|
return { data: response, error: null };
|
|
765
838
|
} catch (error) {
|
|
766
839
|
return wrapError(error, "An unexpected error occurred during sign in");
|
|
@@ -778,12 +851,15 @@ var Auth = class {
|
|
|
778
851
|
}
|
|
779
852
|
this.tokenManager.clearSession();
|
|
780
853
|
this.http.setAuthToken(null);
|
|
854
|
+
this.http.setRefreshToken(null);
|
|
781
855
|
if (!this.isServerMode()) {
|
|
782
856
|
clearCsrfToken();
|
|
783
857
|
}
|
|
784
858
|
return { error: null };
|
|
785
859
|
} catch {
|
|
786
|
-
return {
|
|
860
|
+
return {
|
|
861
|
+
error: new InsForgeError("Failed to sign out", 500, "SIGNOUT_ERROR")
|
|
862
|
+
};
|
|
787
863
|
}
|
|
788
864
|
}
|
|
789
865
|
// ============================================================================
|
|
@@ -795,18 +871,25 @@ var Auth = class {
|
|
|
795
871
|
async signInWithOAuth(options) {
|
|
796
872
|
try {
|
|
797
873
|
const { provider, redirectTo, skipBrowserRedirect } = options;
|
|
874
|
+
const providerKey = encodeURIComponent(provider.toLowerCase());
|
|
798
875
|
const codeVerifier = generateCodeVerifier();
|
|
799
876
|
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
800
877
|
storePkceVerifier(codeVerifier);
|
|
801
878
|
const params = { code_challenge: codeChallenge };
|
|
802
879
|
if (redirectTo) params.redirect_uri = redirectTo;
|
|
803
|
-
const
|
|
880
|
+
const isBuiltInProvider = import_shared_schemas.oAuthProvidersSchema.options.includes(
|
|
881
|
+
providerKey
|
|
882
|
+
);
|
|
883
|
+
const oauthPath = isBuiltInProvider ? `/api/auth/oauth/${providerKey}` : `/api/auth/oauth/custom/${providerKey}`;
|
|
884
|
+
const response = await this.http.get(oauthPath, {
|
|
885
|
+
params
|
|
886
|
+
});
|
|
804
887
|
if (!this.isServerMode() && typeof window !== "undefined" && !skipBrowserRedirect) {
|
|
805
888
|
window.location.href = response.authUrl;
|
|
806
889
|
return { data: {}, error: null };
|
|
807
890
|
}
|
|
808
891
|
return {
|
|
809
|
-
data: { url: response.authUrl, provider, codeVerifier },
|
|
892
|
+
data: { url: response.authUrl, provider: providerKey, codeVerifier },
|
|
810
893
|
error: null
|
|
811
894
|
};
|
|
812
895
|
} catch (error) {
|
|
@@ -840,7 +923,10 @@ var Auth = class {
|
|
|
840
923
|
)
|
|
841
924
|
};
|
|
842
925
|
}
|
|
843
|
-
const request = {
|
|
926
|
+
const request = {
|
|
927
|
+
code,
|
|
928
|
+
code_verifier: verifier
|
|
929
|
+
};
|
|
844
930
|
const response = await this.http.post(
|
|
845
931
|
this.isServerMode() ? "/api/auth/oauth/exchange?client_type=mobile" : "/api/auth/oauth/exchange",
|
|
846
932
|
request,
|
|
@@ -848,16 +934,14 @@ var Auth = class {
|
|
|
848
934
|
);
|
|
849
935
|
this.saveSessionFromResponse(response);
|
|
850
936
|
return {
|
|
851
|
-
data:
|
|
852
|
-
accessToken: response.accessToken,
|
|
853
|
-
refreshToken: response.refreshToken,
|
|
854
|
-
user: response.user,
|
|
855
|
-
redirectTo: response.redirectTo
|
|
856
|
-
},
|
|
937
|
+
data: response,
|
|
857
938
|
error: null
|
|
858
939
|
};
|
|
859
940
|
} catch (error) {
|
|
860
|
-
return wrapError(
|
|
941
|
+
return wrapError(
|
|
942
|
+
error,
|
|
943
|
+
"An unexpected error occurred during OAuth code exchange"
|
|
944
|
+
);
|
|
861
945
|
}
|
|
862
946
|
}
|
|
863
947
|
/**
|
|
@@ -876,16 +960,18 @@ var Auth = class {
|
|
|
876
960
|
{ credentials: "include" }
|
|
877
961
|
);
|
|
878
962
|
this.saveSessionFromResponse(response);
|
|
963
|
+
if (response.refreshToken) {
|
|
964
|
+
this.http.setRefreshToken(response.refreshToken);
|
|
965
|
+
}
|
|
879
966
|
return {
|
|
880
|
-
data:
|
|
881
|
-
accessToken: response.accessToken,
|
|
882
|
-
refreshToken: response.refreshToken,
|
|
883
|
-
user: response.user
|
|
884
|
-
},
|
|
967
|
+
data: response,
|
|
885
968
|
error: null
|
|
886
969
|
};
|
|
887
970
|
} catch (error) {
|
|
888
|
-
return wrapError(
|
|
971
|
+
return wrapError(
|
|
972
|
+
error,
|
|
973
|
+
"An unexpected error occurred during ID token sign in"
|
|
974
|
+
);
|
|
889
975
|
}
|
|
890
976
|
}
|
|
891
977
|
// ============================================================================
|
|
@@ -926,7 +1012,10 @@ var Auth = class {
|
|
|
926
1012
|
}
|
|
927
1013
|
return { data: response, error: null };
|
|
928
1014
|
} catch (error) {
|
|
929
|
-
return wrapError(
|
|
1015
|
+
return wrapError(
|
|
1016
|
+
error,
|
|
1017
|
+
"An unexpected error occurred during session refresh"
|
|
1018
|
+
);
|
|
930
1019
|
}
|
|
931
1020
|
}
|
|
932
1021
|
/**
|
|
@@ -939,7 +1028,9 @@ var Auth = class {
|
|
|
939
1028
|
const accessToken = this.tokenManager.getAccessToken();
|
|
940
1029
|
if (!accessToken) return { data: { user: null }, error: null };
|
|
941
1030
|
this.http.setAuthToken(accessToken);
|
|
942
|
-
const response = await this.http.get(
|
|
1031
|
+
const response = await this.http.get(
|
|
1032
|
+
"/api/auth/sessions/current"
|
|
1033
|
+
);
|
|
943
1034
|
const user = response.user ?? null;
|
|
944
1035
|
return { data: { user }, error: null };
|
|
945
1036
|
}
|
|
@@ -977,24 +1068,38 @@ var Auth = class {
|
|
|
977
1068
|
// ============================================================================
|
|
978
1069
|
async getProfile(userId) {
|
|
979
1070
|
try {
|
|
980
|
-
const response = await this.http.get(
|
|
1071
|
+
const response = await this.http.get(
|
|
1072
|
+
`/api/auth/profiles/${userId}`
|
|
1073
|
+
);
|
|
981
1074
|
return { data: response, error: null };
|
|
982
1075
|
} catch (error) {
|
|
983
|
-
return wrapError(
|
|
1076
|
+
return wrapError(
|
|
1077
|
+
error,
|
|
1078
|
+
"An unexpected error occurred while fetching user profile"
|
|
1079
|
+
);
|
|
984
1080
|
}
|
|
985
1081
|
}
|
|
986
1082
|
async setProfile(profile) {
|
|
987
1083
|
try {
|
|
988
|
-
const response = await this.http.patch(
|
|
989
|
-
|
|
990
|
-
|
|
1084
|
+
const response = await this.http.patch(
|
|
1085
|
+
"/api/auth/profiles/current",
|
|
1086
|
+
{
|
|
1087
|
+
profile
|
|
1088
|
+
}
|
|
1089
|
+
);
|
|
991
1090
|
const currentUser = this.tokenManager.getUser();
|
|
992
1091
|
if (!this.isServerMode() && currentUser && response.profile !== void 0) {
|
|
993
|
-
this.tokenManager.setUser({
|
|
1092
|
+
this.tokenManager.setUser({
|
|
1093
|
+
...currentUser,
|
|
1094
|
+
profile: response.profile
|
|
1095
|
+
});
|
|
994
1096
|
}
|
|
995
1097
|
return { data: response, error: null };
|
|
996
1098
|
} catch (error) {
|
|
997
|
-
return wrapError(
|
|
1099
|
+
return wrapError(
|
|
1100
|
+
error,
|
|
1101
|
+
"An unexpected error occurred while updating user profile"
|
|
1102
|
+
);
|
|
998
1103
|
}
|
|
999
1104
|
}
|
|
1000
1105
|
// ============================================================================
|
|
@@ -1002,19 +1107,15 @@ var Auth = class {
|
|
|
1002
1107
|
// ============================================================================
|
|
1003
1108
|
async resendVerificationEmail(request) {
|
|
1004
1109
|
try {
|
|
1005
|
-
const response = await this.http.post(
|
|
1006
|
-
"/api/auth/email/send-verification",
|
|
1007
|
-
request
|
|
1008
|
-
);
|
|
1110
|
+
const response = await this.http.post("/api/auth/email/send-verification", request);
|
|
1009
1111
|
return { data: response, error: null };
|
|
1010
1112
|
} catch (error) {
|
|
1011
|
-
return wrapError(
|
|
1113
|
+
return wrapError(
|
|
1114
|
+
error,
|
|
1115
|
+
"An unexpected error occurred while sending verification code"
|
|
1116
|
+
);
|
|
1012
1117
|
}
|
|
1013
1118
|
}
|
|
1014
|
-
/** @deprecated Use `resendVerificationEmail` instead */
|
|
1015
|
-
async sendVerificationEmail(request) {
|
|
1016
|
-
return this.resendVerificationEmail(request);
|
|
1017
|
-
}
|
|
1018
1119
|
async verifyEmail(request) {
|
|
1019
1120
|
try {
|
|
1020
1121
|
const response = await this.http.post(
|
|
@@ -1023,9 +1124,15 @@ var Auth = class {
|
|
|
1023
1124
|
{ credentials: "include" }
|
|
1024
1125
|
);
|
|
1025
1126
|
this.saveSessionFromResponse(response);
|
|
1127
|
+
if (response.refreshToken) {
|
|
1128
|
+
this.http.setRefreshToken(response.refreshToken);
|
|
1129
|
+
}
|
|
1026
1130
|
return { data: response, error: null };
|
|
1027
1131
|
} catch (error) {
|
|
1028
|
-
return wrapError(
|
|
1132
|
+
return wrapError(
|
|
1133
|
+
error,
|
|
1134
|
+
"An unexpected error occurred while verifying email"
|
|
1135
|
+
);
|
|
1029
1136
|
}
|
|
1030
1137
|
}
|
|
1031
1138
|
// ============================================================================
|
|
@@ -1033,13 +1140,13 @@ var Auth = class {
|
|
|
1033
1140
|
// ============================================================================
|
|
1034
1141
|
async sendResetPasswordEmail(request) {
|
|
1035
1142
|
try {
|
|
1036
|
-
const response = await this.http.post(
|
|
1037
|
-
"/api/auth/email/send-reset-password",
|
|
1038
|
-
request
|
|
1039
|
-
);
|
|
1143
|
+
const response = await this.http.post("/api/auth/email/send-reset-password", request);
|
|
1040
1144
|
return { data: response, error: null };
|
|
1041
1145
|
} catch (error) {
|
|
1042
|
-
return wrapError(
|
|
1146
|
+
return wrapError(
|
|
1147
|
+
error,
|
|
1148
|
+
"An unexpected error occurred while sending password reset code"
|
|
1149
|
+
);
|
|
1043
1150
|
}
|
|
1044
1151
|
}
|
|
1045
1152
|
async exchangeResetPasswordToken(request) {
|
|
@@ -1050,7 +1157,10 @@ var Auth = class {
|
|
|
1050
1157
|
);
|
|
1051
1158
|
return { data: response, error: null };
|
|
1052
1159
|
} catch (error) {
|
|
1053
|
-
return wrapError(
|
|
1160
|
+
return wrapError(
|
|
1161
|
+
error,
|
|
1162
|
+
"An unexpected error occurred while verifying reset code"
|
|
1163
|
+
);
|
|
1054
1164
|
}
|
|
1055
1165
|
}
|
|
1056
1166
|
async resetPassword(request) {
|
|
@@ -1061,7 +1171,10 @@ var Auth = class {
|
|
|
1061
1171
|
);
|
|
1062
1172
|
return { data: response, error: null };
|
|
1063
1173
|
} catch (error) {
|
|
1064
|
-
return wrapError(
|
|
1174
|
+
return wrapError(
|
|
1175
|
+
error,
|
|
1176
|
+
"An unexpected error occurred while resetting password"
|
|
1177
|
+
);
|
|
1065
1178
|
}
|
|
1066
1179
|
}
|
|
1067
1180
|
// ============================================================================
|
|
@@ -1069,10 +1182,15 @@ var Auth = class {
|
|
|
1069
1182
|
// ============================================================================
|
|
1070
1183
|
async getPublicAuthConfig() {
|
|
1071
1184
|
try {
|
|
1072
|
-
const response = await this.http.get(
|
|
1185
|
+
const response = await this.http.get(
|
|
1186
|
+
"/api/auth/public-config"
|
|
1187
|
+
);
|
|
1073
1188
|
return { data: response, error: null };
|
|
1074
1189
|
} catch (error) {
|
|
1075
|
-
return wrapError(
|
|
1190
|
+
return wrapError(
|
|
1191
|
+
error,
|
|
1192
|
+
"An unexpected error occurred while fetching auth configuration"
|
|
1193
|
+
);
|
|
1076
1194
|
}
|
|
1077
1195
|
}
|
|
1078
1196
|
};
|
|
@@ -1818,9 +1936,17 @@ var Functions = class _Functions {
|
|
|
1818
1936
|
});
|
|
1819
1937
|
return { data, error: null };
|
|
1820
1938
|
} catch (error) {
|
|
1821
|
-
if (error
|
|
1939
|
+
if (error instanceof Error && error.name === "AbortError") throw error;
|
|
1940
|
+
if (error instanceof InsForgeError && error.statusCode === 404) {
|
|
1822
1941
|
} else {
|
|
1823
|
-
return {
|
|
1942
|
+
return {
|
|
1943
|
+
data: null,
|
|
1944
|
+
error: error instanceof InsForgeError ? error : new InsForgeError(
|
|
1945
|
+
error instanceof Error ? error.message : "Function invocation failed",
|
|
1946
|
+
500,
|
|
1947
|
+
"FUNCTION_ERROR"
|
|
1948
|
+
)
|
|
1949
|
+
};
|
|
1824
1950
|
}
|
|
1825
1951
|
}
|
|
1826
1952
|
}
|
|
@@ -1829,7 +1955,15 @@ var Functions = class _Functions {
|
|
|
1829
1955
|
const data = await this.http.request(method, path, { body, headers });
|
|
1830
1956
|
return { data, error: null };
|
|
1831
1957
|
} catch (error) {
|
|
1832
|
-
|
|
1958
|
+
if (error instanceof Error && error.name === "AbortError") throw error;
|
|
1959
|
+
return {
|
|
1960
|
+
data: null,
|
|
1961
|
+
error: error instanceof InsForgeError ? error : new InsForgeError(
|
|
1962
|
+
error instanceof Error ? error.message : "Function invocation failed",
|
|
1963
|
+
500,
|
|
1964
|
+
"FUNCTION_ERROR"
|
|
1965
|
+
)
|
|
1966
|
+
};
|
|
1833
1967
|
}
|
|
1834
1968
|
}
|
|
1835
1969
|
};
|
|
@@ -2100,8 +2234,15 @@ var Emails = class {
|
|
|
2100
2234
|
);
|
|
2101
2235
|
return { data, error: null };
|
|
2102
2236
|
} catch (error) {
|
|
2103
|
-
|
|
2104
|
-
return {
|
|
2237
|
+
if (error instanceof Error && error.name === "AbortError") throw error;
|
|
2238
|
+
return {
|
|
2239
|
+
data: null,
|
|
2240
|
+
error: error instanceof InsForgeError ? error : new InsForgeError(
|
|
2241
|
+
error instanceof Error ? error.message : "Email send failed",
|
|
2242
|
+
500,
|
|
2243
|
+
"EMAIL_ERROR"
|
|
2244
|
+
)
|
|
2245
|
+
};
|
|
2105
2246
|
}
|
|
2106
2247
|
}
|
|
2107
2248
|
};
|
|
@@ -2110,8 +2251,8 @@ var Emails = class {
|
|
|
2110
2251
|
var InsForgeClient = class {
|
|
2111
2252
|
constructor(config = {}) {
|
|
2112
2253
|
const logger = new Logger(config.debug);
|
|
2113
|
-
this.http = new HttpClient(config, logger);
|
|
2114
2254
|
this.tokenManager = new TokenManager();
|
|
2255
|
+
this.http = new HttpClient(config, this.tokenManager, logger);
|
|
2115
2256
|
if (config.edgeFunctionToken) {
|
|
2116
2257
|
this.http.setAuthToken(config.edgeFunctionToken);
|
|
2117
2258
|
this.tokenManager.setAccessToken(config.edgeFunctionToken);
|
|
@@ -2123,12 +2264,16 @@ var InsForgeClient = class {
|
|
|
2123
2264
|
this.storage = new Storage(this.http);
|
|
2124
2265
|
this.ai = new AI(this.http);
|
|
2125
2266
|
this.functions = new Functions(this.http, config.functionsUrl);
|
|
2126
|
-
this.realtime = new Realtime(
|
|
2267
|
+
this.realtime = new Realtime(
|
|
2268
|
+
this.http.baseUrl,
|
|
2269
|
+
this.tokenManager,
|
|
2270
|
+
config.anonKey
|
|
2271
|
+
);
|
|
2127
2272
|
this.emails = new Emails(this.http);
|
|
2128
2273
|
}
|
|
2129
2274
|
/**
|
|
2130
2275
|
* Get the underlying HTTP client for custom requests
|
|
2131
|
-
*
|
|
2276
|
+
*
|
|
2132
2277
|
* @example
|
|
2133
2278
|
* ```typescript
|
|
2134
2279
|
* const httpClient = client.getHttpClient();
|