@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.mjs
CHANGED
|
@@ -192,6 +192,95 @@ var Logger = class {
|
|
|
192
192
|
}
|
|
193
193
|
};
|
|
194
194
|
|
|
195
|
+
// src/lib/token-manager.ts
|
|
196
|
+
var CSRF_TOKEN_COOKIE = "insforge_csrf_token";
|
|
197
|
+
function getCsrfToken() {
|
|
198
|
+
if (typeof document === "undefined") return null;
|
|
199
|
+
const match = document.cookie.split(";").find((c) => c.trim().startsWith(`${CSRF_TOKEN_COOKIE}=`));
|
|
200
|
+
if (!match) return null;
|
|
201
|
+
return match.split("=")[1] || null;
|
|
202
|
+
}
|
|
203
|
+
function setCsrfToken(token) {
|
|
204
|
+
if (typeof document === "undefined") return;
|
|
205
|
+
const maxAge = 7 * 24 * 60 * 60;
|
|
206
|
+
const secure = typeof window !== "undefined" && window.location.protocol === "https:" ? "; Secure" : "";
|
|
207
|
+
document.cookie = `${CSRF_TOKEN_COOKIE}=${encodeURIComponent(token)}; path=/; max-age=${maxAge}; SameSite=Lax${secure}`;
|
|
208
|
+
}
|
|
209
|
+
function clearCsrfToken() {
|
|
210
|
+
if (typeof document === "undefined") return;
|
|
211
|
+
const secure = typeof window !== "undefined" && window.location.protocol === "https:" ? "; Secure" : "";
|
|
212
|
+
document.cookie = `${CSRF_TOKEN_COOKIE}=; path=/; max-age=0; SameSite=Lax${secure}`;
|
|
213
|
+
}
|
|
214
|
+
var TokenManager = class {
|
|
215
|
+
constructor() {
|
|
216
|
+
// In-memory storage
|
|
217
|
+
this.accessToken = null;
|
|
218
|
+
this.user = null;
|
|
219
|
+
// Callback for token changes (used by realtime to reconnect with new token)
|
|
220
|
+
this.onTokenChange = null;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Save session in memory
|
|
224
|
+
*/
|
|
225
|
+
saveSession(session) {
|
|
226
|
+
const tokenChanged = session.accessToken !== this.accessToken;
|
|
227
|
+
this.accessToken = session.accessToken;
|
|
228
|
+
this.user = session.user;
|
|
229
|
+
if (tokenChanged && this.onTokenChange) {
|
|
230
|
+
this.onTokenChange();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Get current session
|
|
235
|
+
*/
|
|
236
|
+
getSession() {
|
|
237
|
+
if (!this.accessToken || !this.user) return null;
|
|
238
|
+
return {
|
|
239
|
+
accessToken: this.accessToken,
|
|
240
|
+
user: this.user
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Get access token
|
|
245
|
+
*/
|
|
246
|
+
getAccessToken() {
|
|
247
|
+
return this.accessToken;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Set access token
|
|
251
|
+
*/
|
|
252
|
+
setAccessToken(token) {
|
|
253
|
+
const tokenChanged = token !== this.accessToken;
|
|
254
|
+
this.accessToken = token;
|
|
255
|
+
if (tokenChanged && this.onTokenChange) {
|
|
256
|
+
this.onTokenChange();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Get user
|
|
261
|
+
*/
|
|
262
|
+
getUser() {
|
|
263
|
+
return this.user;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Set user
|
|
267
|
+
*/
|
|
268
|
+
setUser(user) {
|
|
269
|
+
this.user = user;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Clear in-memory session
|
|
273
|
+
*/
|
|
274
|
+
clearSession() {
|
|
275
|
+
const hadToken = this.accessToken !== null;
|
|
276
|
+
this.accessToken = null;
|
|
277
|
+
this.user = null;
|
|
278
|
+
if (hadToken && this.onTokenChange) {
|
|
279
|
+
this.onTokenChange();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
|
|
195
284
|
// src/lib/http-client.ts
|
|
196
285
|
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([500, 502, 503, 504]);
|
|
197
286
|
var IDEMPOTENT_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
@@ -199,16 +288,23 @@ var HttpClient = class {
|
|
|
199
288
|
/**
|
|
200
289
|
* Creates a new HttpClient instance.
|
|
201
290
|
* @param config - SDK configuration including baseUrl, timeout, retry settings, and fetch implementation.
|
|
291
|
+
* @param tokenManager - Token manager for session persistence.
|
|
202
292
|
* @param logger - Optional logger instance for request/response debugging.
|
|
203
293
|
*/
|
|
204
|
-
constructor(config, logger) {
|
|
294
|
+
constructor(config, tokenManager, logger) {
|
|
205
295
|
this.userToken = null;
|
|
296
|
+
this.autoRefreshToken = true;
|
|
297
|
+
this.isRefreshing = false;
|
|
298
|
+
this.refreshPromise = null;
|
|
299
|
+
this.refreshToken = null;
|
|
206
300
|
this.baseUrl = config.baseUrl || "http://localhost:7130";
|
|
301
|
+
this.autoRefreshToken = config.autoRefreshToken ?? true;
|
|
207
302
|
this.fetch = config.fetch || (globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
|
|
208
303
|
this.anonKey = config.anonKey;
|
|
209
304
|
this.defaultHeaders = {
|
|
210
305
|
...config.headers
|
|
211
306
|
};
|
|
307
|
+
this.tokenManager = tokenManager ?? new TokenManager();
|
|
212
308
|
this.logger = logger || new Logger(false);
|
|
213
309
|
this.timeout = config.timeout ?? 3e4;
|
|
214
310
|
this.retryCount = config.retryCount ?? 3;
|
|
@@ -262,8 +358,14 @@ var HttpClient = class {
|
|
|
262
358
|
* @returns Parsed response data.
|
|
263
359
|
* @throws {InsForgeError} On timeout, network failure, or HTTP error responses.
|
|
264
360
|
*/
|
|
265
|
-
async
|
|
266
|
-
const {
|
|
361
|
+
async handleRequest(method, path, options = {}) {
|
|
362
|
+
const {
|
|
363
|
+
params,
|
|
364
|
+
headers = {},
|
|
365
|
+
body,
|
|
366
|
+
signal: callerSignal,
|
|
367
|
+
...fetchOptions
|
|
368
|
+
} = options;
|
|
267
369
|
const url = this.buildUrl(path, params);
|
|
268
370
|
const startTime = Date.now();
|
|
269
371
|
const canRetry = IDEMPOTENT_METHODS.has(method.toUpperCase()) || options.idempotent === true;
|
|
@@ -302,7 +404,9 @@ var HttpClient = class {
|
|
|
302
404
|
for (let attempt = 0; attempt <= maxAttempts; attempt++) {
|
|
303
405
|
if (attempt > 0) {
|
|
304
406
|
const delay = this.computeRetryDelay(attempt);
|
|
305
|
-
this.logger.warn(
|
|
407
|
+
this.logger.warn(
|
|
408
|
+
`Retry ${attempt}/${maxAttempts} for ${method} ${url} in ${delay}ms`
|
|
409
|
+
);
|
|
306
410
|
if (callerSignal?.aborted) throw callerSignal.reason;
|
|
307
411
|
await new Promise((resolve, reject) => {
|
|
308
412
|
const onAbort = () => {
|
|
@@ -310,7 +414,8 @@ var HttpClient = class {
|
|
|
310
414
|
reject(callerSignal.reason);
|
|
311
415
|
};
|
|
312
416
|
const timer2 = setTimeout(() => {
|
|
313
|
-
if (callerSignal)
|
|
417
|
+
if (callerSignal)
|
|
418
|
+
callerSignal.removeEventListener("abort", onAbort);
|
|
314
419
|
resolve();
|
|
315
420
|
}, delay);
|
|
316
421
|
if (callerSignal) {
|
|
@@ -330,10 +435,16 @@ var HttpClient = class {
|
|
|
330
435
|
controller.abort(callerSignal.reason);
|
|
331
436
|
} else {
|
|
332
437
|
const onCallerAbort = () => controller.abort(callerSignal.reason);
|
|
333
|
-
callerSignal.addEventListener("abort", onCallerAbort, {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
438
|
+
callerSignal.addEventListener("abort", onCallerAbort, {
|
|
439
|
+
once: true
|
|
440
|
+
});
|
|
441
|
+
controller.signal.addEventListener(
|
|
442
|
+
"abort",
|
|
443
|
+
() => {
|
|
444
|
+
callerSignal.removeEventListener("abort", onCallerAbort);
|
|
445
|
+
},
|
|
446
|
+
{ once: true }
|
|
447
|
+
);
|
|
337
448
|
}
|
|
338
449
|
}
|
|
339
450
|
}
|
|
@@ -377,7 +488,13 @@ var HttpClient = class {
|
|
|
377
488
|
}
|
|
378
489
|
if (timer !== void 0) clearTimeout(timer);
|
|
379
490
|
if (!response.ok) {
|
|
380
|
-
this.logger.logResponse(
|
|
491
|
+
this.logger.logResponse(
|
|
492
|
+
method,
|
|
493
|
+
url,
|
|
494
|
+
response.status,
|
|
495
|
+
Date.now() - startTime,
|
|
496
|
+
data
|
|
497
|
+
);
|
|
381
498
|
if (data && typeof data === "object" && "error" in data) {
|
|
382
499
|
if (!data.statusCode && !data.status) {
|
|
383
500
|
data.statusCode = response.status;
|
|
@@ -396,7 +513,13 @@ var HttpClient = class {
|
|
|
396
513
|
"REQUEST_FAILED"
|
|
397
514
|
);
|
|
398
515
|
}
|
|
399
|
-
this.logger.logResponse(
|
|
516
|
+
this.logger.logResponse(
|
|
517
|
+
method,
|
|
518
|
+
url,
|
|
519
|
+
response.status,
|
|
520
|
+
Date.now() - startTime,
|
|
521
|
+
data
|
|
522
|
+
);
|
|
400
523
|
return data;
|
|
401
524
|
} catch (err) {
|
|
402
525
|
if (timer !== void 0) clearTimeout(timer);
|
|
@@ -430,6 +553,33 @@ var HttpClient = class {
|
|
|
430
553
|
"NETWORK_ERROR"
|
|
431
554
|
);
|
|
432
555
|
}
|
|
556
|
+
async request(method, path, options = {}) {
|
|
557
|
+
try {
|
|
558
|
+
return await this.handleRequest(method, path, { ...options });
|
|
559
|
+
} catch (error) {
|
|
560
|
+
if (error instanceof InsForgeError && error.statusCode === 401 && error.error === "INVALID_TOKEN" && this.autoRefreshToken) {
|
|
561
|
+
try {
|
|
562
|
+
const newTokenData = await this.handleTokenRefresh();
|
|
563
|
+
this.setAuthToken(newTokenData.accessToken);
|
|
564
|
+
this.tokenManager.saveSession(newTokenData);
|
|
565
|
+
if (newTokenData.csrfToken) {
|
|
566
|
+
setCsrfToken(newTokenData.csrfToken);
|
|
567
|
+
}
|
|
568
|
+
if (newTokenData.refreshToken) {
|
|
569
|
+
this.setRefreshToken(newTokenData.refreshToken);
|
|
570
|
+
}
|
|
571
|
+
return await this.handleRequest(method, path, { ...options });
|
|
572
|
+
} catch (error2) {
|
|
573
|
+
this.tokenManager.clearSession();
|
|
574
|
+
this.userToken = null;
|
|
575
|
+
this.refreshToken = null;
|
|
576
|
+
clearCsrfToken();
|
|
577
|
+
throw error2;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
throw error;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
433
583
|
/** Performs a GET request. */
|
|
434
584
|
get(path, options) {
|
|
435
585
|
return this.request("GET", path, options);
|
|
@@ -454,6 +604,9 @@ var HttpClient = class {
|
|
|
454
604
|
setAuthToken(token) {
|
|
455
605
|
this.userToken = token;
|
|
456
606
|
}
|
|
607
|
+
setRefreshToken(token) {
|
|
608
|
+
this.refreshToken = token;
|
|
609
|
+
}
|
|
457
610
|
/** Returns the current default headers including the authorization header if set. */
|
|
458
611
|
getHeaders() {
|
|
459
612
|
const headers = { ...this.defaultHeaders };
|
|
@@ -463,94 +616,31 @@ var HttpClient = class {
|
|
|
463
616
|
}
|
|
464
617
|
return headers;
|
|
465
618
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
var CSRF_TOKEN_COOKIE = "insforge_csrf_token";
|
|
470
|
-
function getCsrfToken() {
|
|
471
|
-
if (typeof document === "undefined") return null;
|
|
472
|
-
const match = document.cookie.split(";").find((c) => c.trim().startsWith(`${CSRF_TOKEN_COOKIE}=`));
|
|
473
|
-
if (!match) return null;
|
|
474
|
-
return match.split("=")[1] || null;
|
|
475
|
-
}
|
|
476
|
-
function setCsrfToken(token) {
|
|
477
|
-
if (typeof document === "undefined") return;
|
|
478
|
-
const maxAge = 7 * 24 * 60 * 60;
|
|
479
|
-
const secure = typeof window !== "undefined" && window.location.protocol === "https:" ? "; Secure" : "";
|
|
480
|
-
document.cookie = `${CSRF_TOKEN_COOKIE}=${encodeURIComponent(token)}; path=/; max-age=${maxAge}; SameSite=Lax${secure}`;
|
|
481
|
-
}
|
|
482
|
-
function clearCsrfToken() {
|
|
483
|
-
if (typeof document === "undefined") return;
|
|
484
|
-
const secure = typeof window !== "undefined" && window.location.protocol === "https:" ? "; Secure" : "";
|
|
485
|
-
document.cookie = `${CSRF_TOKEN_COOKIE}=; path=/; max-age=0; SameSite=Lax${secure}`;
|
|
486
|
-
}
|
|
487
|
-
var TokenManager = class {
|
|
488
|
-
constructor() {
|
|
489
|
-
// In-memory storage
|
|
490
|
-
this.accessToken = null;
|
|
491
|
-
this.user = null;
|
|
492
|
-
// Callback for token changes (used by realtime to reconnect with new token)
|
|
493
|
-
this.onTokenChange = null;
|
|
494
|
-
}
|
|
495
|
-
/**
|
|
496
|
-
* Save session in memory
|
|
497
|
-
*/
|
|
498
|
-
saveSession(session) {
|
|
499
|
-
const tokenChanged = session.accessToken !== this.accessToken;
|
|
500
|
-
this.accessToken = session.accessToken;
|
|
501
|
-
this.user = session.user;
|
|
502
|
-
if (tokenChanged && this.onTokenChange) {
|
|
503
|
-
this.onTokenChange();
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
/**
|
|
507
|
-
* Get current session
|
|
508
|
-
*/
|
|
509
|
-
getSession() {
|
|
510
|
-
if (!this.accessToken || !this.user) return null;
|
|
511
|
-
return {
|
|
512
|
-
accessToken: this.accessToken,
|
|
513
|
-
user: this.user
|
|
514
|
-
};
|
|
515
|
-
}
|
|
516
|
-
/**
|
|
517
|
-
* Get access token
|
|
518
|
-
*/
|
|
519
|
-
getAccessToken() {
|
|
520
|
-
return this.accessToken;
|
|
521
|
-
}
|
|
522
|
-
/**
|
|
523
|
-
* Set access token
|
|
524
|
-
*/
|
|
525
|
-
setAccessToken(token) {
|
|
526
|
-
const tokenChanged = token !== this.accessToken;
|
|
527
|
-
this.accessToken = token;
|
|
528
|
-
if (tokenChanged && this.onTokenChange) {
|
|
529
|
-
this.onTokenChange();
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
/**
|
|
533
|
-
* Get user
|
|
534
|
-
*/
|
|
535
|
-
getUser() {
|
|
536
|
-
return this.user;
|
|
537
|
-
}
|
|
538
|
-
/**
|
|
539
|
-
* Set user
|
|
540
|
-
*/
|
|
541
|
-
setUser(user) {
|
|
542
|
-
this.user = user;
|
|
543
|
-
}
|
|
544
|
-
/**
|
|
545
|
-
* Clear in-memory session
|
|
546
|
-
*/
|
|
547
|
-
clearSession() {
|
|
548
|
-
const hadToken = this.accessToken !== null;
|
|
549
|
-
this.accessToken = null;
|
|
550
|
-
this.user = null;
|
|
551
|
-
if (hadToken && this.onTokenChange) {
|
|
552
|
-
this.onTokenChange();
|
|
619
|
+
async handleTokenRefresh() {
|
|
620
|
+
if (this.isRefreshing) {
|
|
621
|
+
return this.refreshPromise;
|
|
553
622
|
}
|
|
623
|
+
this.isRefreshing = true;
|
|
624
|
+
this.refreshPromise = (async () => {
|
|
625
|
+
try {
|
|
626
|
+
const csrfToken = getCsrfToken();
|
|
627
|
+
const body = this.refreshToken ? { refreshToken: this.refreshToken } : void 0;
|
|
628
|
+
const response = await this.handleRequest(
|
|
629
|
+
"POST",
|
|
630
|
+
"/api/auth/sessions/current",
|
|
631
|
+
{
|
|
632
|
+
body,
|
|
633
|
+
headers: csrfToken ? { "X-CSRF-Token": csrfToken } : {},
|
|
634
|
+
credentials: "include"
|
|
635
|
+
}
|
|
636
|
+
);
|
|
637
|
+
return response;
|
|
638
|
+
} finally {
|
|
639
|
+
this.isRefreshing = false;
|
|
640
|
+
this.refreshPromise = null;
|
|
641
|
+
}
|
|
642
|
+
})();
|
|
643
|
+
return this.refreshPromise;
|
|
554
644
|
}
|
|
555
645
|
};
|
|
556
646
|
|
|
@@ -609,6 +699,7 @@ function cleanUrlParams(...params) {
|
|
|
609
699
|
}
|
|
610
700
|
|
|
611
701
|
// src/modules/auth/auth.ts
|
|
702
|
+
import { oAuthProvidersSchema } from "@insforge/shared-schemas";
|
|
612
703
|
var Auth = class {
|
|
613
704
|
constructor(http, tokenManager, options = {}) {
|
|
614
705
|
this.http = http;
|
|
@@ -638,6 +729,7 @@ var Auth = class {
|
|
|
638
729
|
this.tokenManager.saveSession(session);
|
|
639
730
|
}
|
|
640
731
|
this.http.setAuthToken(response.accessToken);
|
|
732
|
+
this.http.setRefreshToken(response.refreshToken ?? null);
|
|
641
733
|
return true;
|
|
642
734
|
}
|
|
643
735
|
// ============================================================================
|
|
@@ -645,7 +737,7 @@ var Auth = class {
|
|
|
645
737
|
// ============================================================================
|
|
646
738
|
/**
|
|
647
739
|
* Detect and handle OAuth callback parameters in URL
|
|
648
|
-
* Supports PKCE flow (insforge_code)
|
|
740
|
+
* Supports PKCE flow (insforge_code)
|
|
649
741
|
*/
|
|
650
742
|
async detectAuthCallback() {
|
|
651
743
|
if (this.isServerMode() || typeof window === "undefined") return;
|
|
@@ -666,31 +758,6 @@ var Auth = class {
|
|
|
666
758
|
}
|
|
667
759
|
return;
|
|
668
760
|
}
|
|
669
|
-
const accessToken = params.get("access_token");
|
|
670
|
-
const userId = params.get("user_id");
|
|
671
|
-
const email = params.get("email");
|
|
672
|
-
if (accessToken && userId && email) {
|
|
673
|
-
const csrfToken = params.get("csrf_token");
|
|
674
|
-
const name = params.get("name");
|
|
675
|
-
if (csrfToken) {
|
|
676
|
-
setCsrfToken(csrfToken);
|
|
677
|
-
}
|
|
678
|
-
const session = {
|
|
679
|
-
accessToken,
|
|
680
|
-
user: {
|
|
681
|
-
id: userId,
|
|
682
|
-
email,
|
|
683
|
-
profile: { name: name || "" },
|
|
684
|
-
metadata: null,
|
|
685
|
-
emailVerified: false,
|
|
686
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
687
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
688
|
-
}
|
|
689
|
-
};
|
|
690
|
-
this.tokenManager.saveSession(session);
|
|
691
|
-
this.http.setAuthToken(accessToken);
|
|
692
|
-
cleanUrlParams("access_token", "user_id", "email", "name", "csrf_token");
|
|
693
|
-
}
|
|
694
761
|
} catch (error) {
|
|
695
762
|
console.debug("OAuth callback detection skipped:", error);
|
|
696
763
|
}
|
|
@@ -708,6 +775,9 @@ var Auth = class {
|
|
|
708
775
|
if (response.accessToken && response.user) {
|
|
709
776
|
this.saveSessionFromResponse(response);
|
|
710
777
|
}
|
|
778
|
+
if (response.refreshToken) {
|
|
779
|
+
this.http.setRefreshToken(response.refreshToken);
|
|
780
|
+
}
|
|
711
781
|
return { data: response, error: null };
|
|
712
782
|
} catch (error) {
|
|
713
783
|
return wrapError(error, "An unexpected error occurred during sign up");
|
|
@@ -721,6 +791,9 @@ var Auth = class {
|
|
|
721
791
|
{ credentials: "include" }
|
|
722
792
|
);
|
|
723
793
|
this.saveSessionFromResponse(response);
|
|
794
|
+
if (response.refreshToken) {
|
|
795
|
+
this.http.setRefreshToken(response.refreshToken);
|
|
796
|
+
}
|
|
724
797
|
return { data: response, error: null };
|
|
725
798
|
} catch (error) {
|
|
726
799
|
return wrapError(error, "An unexpected error occurred during sign in");
|
|
@@ -738,12 +811,15 @@ var Auth = class {
|
|
|
738
811
|
}
|
|
739
812
|
this.tokenManager.clearSession();
|
|
740
813
|
this.http.setAuthToken(null);
|
|
814
|
+
this.http.setRefreshToken(null);
|
|
741
815
|
if (!this.isServerMode()) {
|
|
742
816
|
clearCsrfToken();
|
|
743
817
|
}
|
|
744
818
|
return { error: null };
|
|
745
819
|
} catch {
|
|
746
|
-
return {
|
|
820
|
+
return {
|
|
821
|
+
error: new InsForgeError("Failed to sign out", 500, "SIGNOUT_ERROR")
|
|
822
|
+
};
|
|
747
823
|
}
|
|
748
824
|
}
|
|
749
825
|
// ============================================================================
|
|
@@ -755,18 +831,25 @@ var Auth = class {
|
|
|
755
831
|
async signInWithOAuth(options) {
|
|
756
832
|
try {
|
|
757
833
|
const { provider, redirectTo, skipBrowserRedirect } = options;
|
|
834
|
+
const providerKey = encodeURIComponent(provider.toLowerCase());
|
|
758
835
|
const codeVerifier = generateCodeVerifier();
|
|
759
836
|
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
760
837
|
storePkceVerifier(codeVerifier);
|
|
761
838
|
const params = { code_challenge: codeChallenge };
|
|
762
839
|
if (redirectTo) params.redirect_uri = redirectTo;
|
|
763
|
-
const
|
|
840
|
+
const isBuiltInProvider = oAuthProvidersSchema.options.includes(
|
|
841
|
+
providerKey
|
|
842
|
+
);
|
|
843
|
+
const oauthPath = isBuiltInProvider ? `/api/auth/oauth/${providerKey}` : `/api/auth/oauth/custom/${providerKey}`;
|
|
844
|
+
const response = await this.http.get(oauthPath, {
|
|
845
|
+
params
|
|
846
|
+
});
|
|
764
847
|
if (!this.isServerMode() && typeof window !== "undefined" && !skipBrowserRedirect) {
|
|
765
848
|
window.location.href = response.authUrl;
|
|
766
849
|
return { data: {}, error: null };
|
|
767
850
|
}
|
|
768
851
|
return {
|
|
769
|
-
data: { url: response.authUrl, provider, codeVerifier },
|
|
852
|
+
data: { url: response.authUrl, provider: providerKey, codeVerifier },
|
|
770
853
|
error: null
|
|
771
854
|
};
|
|
772
855
|
} catch (error) {
|
|
@@ -800,7 +883,10 @@ var Auth = class {
|
|
|
800
883
|
)
|
|
801
884
|
};
|
|
802
885
|
}
|
|
803
|
-
const request = {
|
|
886
|
+
const request = {
|
|
887
|
+
code,
|
|
888
|
+
code_verifier: verifier
|
|
889
|
+
};
|
|
804
890
|
const response = await this.http.post(
|
|
805
891
|
this.isServerMode() ? "/api/auth/oauth/exchange?client_type=mobile" : "/api/auth/oauth/exchange",
|
|
806
892
|
request,
|
|
@@ -808,16 +894,14 @@ var Auth = class {
|
|
|
808
894
|
);
|
|
809
895
|
this.saveSessionFromResponse(response);
|
|
810
896
|
return {
|
|
811
|
-
data:
|
|
812
|
-
accessToken: response.accessToken,
|
|
813
|
-
refreshToken: response.refreshToken,
|
|
814
|
-
user: response.user,
|
|
815
|
-
redirectTo: response.redirectTo
|
|
816
|
-
},
|
|
897
|
+
data: response,
|
|
817
898
|
error: null
|
|
818
899
|
};
|
|
819
900
|
} catch (error) {
|
|
820
|
-
return wrapError(
|
|
901
|
+
return wrapError(
|
|
902
|
+
error,
|
|
903
|
+
"An unexpected error occurred during OAuth code exchange"
|
|
904
|
+
);
|
|
821
905
|
}
|
|
822
906
|
}
|
|
823
907
|
/**
|
|
@@ -836,16 +920,18 @@ var Auth = class {
|
|
|
836
920
|
{ credentials: "include" }
|
|
837
921
|
);
|
|
838
922
|
this.saveSessionFromResponse(response);
|
|
923
|
+
if (response.refreshToken) {
|
|
924
|
+
this.http.setRefreshToken(response.refreshToken);
|
|
925
|
+
}
|
|
839
926
|
return {
|
|
840
|
-
data:
|
|
841
|
-
accessToken: response.accessToken,
|
|
842
|
-
refreshToken: response.refreshToken,
|
|
843
|
-
user: response.user
|
|
844
|
-
},
|
|
927
|
+
data: response,
|
|
845
928
|
error: null
|
|
846
929
|
};
|
|
847
930
|
} catch (error) {
|
|
848
|
-
return wrapError(
|
|
931
|
+
return wrapError(
|
|
932
|
+
error,
|
|
933
|
+
"An unexpected error occurred during ID token sign in"
|
|
934
|
+
);
|
|
849
935
|
}
|
|
850
936
|
}
|
|
851
937
|
// ============================================================================
|
|
@@ -886,7 +972,10 @@ var Auth = class {
|
|
|
886
972
|
}
|
|
887
973
|
return { data: response, error: null };
|
|
888
974
|
} catch (error) {
|
|
889
|
-
return wrapError(
|
|
975
|
+
return wrapError(
|
|
976
|
+
error,
|
|
977
|
+
"An unexpected error occurred during session refresh"
|
|
978
|
+
);
|
|
890
979
|
}
|
|
891
980
|
}
|
|
892
981
|
/**
|
|
@@ -899,7 +988,9 @@ var Auth = class {
|
|
|
899
988
|
const accessToken = this.tokenManager.getAccessToken();
|
|
900
989
|
if (!accessToken) return { data: { user: null }, error: null };
|
|
901
990
|
this.http.setAuthToken(accessToken);
|
|
902
|
-
const response = await this.http.get(
|
|
991
|
+
const response = await this.http.get(
|
|
992
|
+
"/api/auth/sessions/current"
|
|
993
|
+
);
|
|
903
994
|
const user = response.user ?? null;
|
|
904
995
|
return { data: { user }, error: null };
|
|
905
996
|
}
|
|
@@ -937,24 +1028,38 @@ var Auth = class {
|
|
|
937
1028
|
// ============================================================================
|
|
938
1029
|
async getProfile(userId) {
|
|
939
1030
|
try {
|
|
940
|
-
const response = await this.http.get(
|
|
1031
|
+
const response = await this.http.get(
|
|
1032
|
+
`/api/auth/profiles/${userId}`
|
|
1033
|
+
);
|
|
941
1034
|
return { data: response, error: null };
|
|
942
1035
|
} catch (error) {
|
|
943
|
-
return wrapError(
|
|
1036
|
+
return wrapError(
|
|
1037
|
+
error,
|
|
1038
|
+
"An unexpected error occurred while fetching user profile"
|
|
1039
|
+
);
|
|
944
1040
|
}
|
|
945
1041
|
}
|
|
946
1042
|
async setProfile(profile) {
|
|
947
1043
|
try {
|
|
948
|
-
const response = await this.http.patch(
|
|
949
|
-
|
|
950
|
-
|
|
1044
|
+
const response = await this.http.patch(
|
|
1045
|
+
"/api/auth/profiles/current",
|
|
1046
|
+
{
|
|
1047
|
+
profile
|
|
1048
|
+
}
|
|
1049
|
+
);
|
|
951
1050
|
const currentUser = this.tokenManager.getUser();
|
|
952
1051
|
if (!this.isServerMode() && currentUser && response.profile !== void 0) {
|
|
953
|
-
this.tokenManager.setUser({
|
|
1052
|
+
this.tokenManager.setUser({
|
|
1053
|
+
...currentUser,
|
|
1054
|
+
profile: response.profile
|
|
1055
|
+
});
|
|
954
1056
|
}
|
|
955
1057
|
return { data: response, error: null };
|
|
956
1058
|
} catch (error) {
|
|
957
|
-
return wrapError(
|
|
1059
|
+
return wrapError(
|
|
1060
|
+
error,
|
|
1061
|
+
"An unexpected error occurred while updating user profile"
|
|
1062
|
+
);
|
|
958
1063
|
}
|
|
959
1064
|
}
|
|
960
1065
|
// ============================================================================
|
|
@@ -962,19 +1067,15 @@ var Auth = class {
|
|
|
962
1067
|
// ============================================================================
|
|
963
1068
|
async resendVerificationEmail(request) {
|
|
964
1069
|
try {
|
|
965
|
-
const response = await this.http.post(
|
|
966
|
-
"/api/auth/email/send-verification",
|
|
967
|
-
request
|
|
968
|
-
);
|
|
1070
|
+
const response = await this.http.post("/api/auth/email/send-verification", request);
|
|
969
1071
|
return { data: response, error: null };
|
|
970
1072
|
} catch (error) {
|
|
971
|
-
return wrapError(
|
|
1073
|
+
return wrapError(
|
|
1074
|
+
error,
|
|
1075
|
+
"An unexpected error occurred while sending verification code"
|
|
1076
|
+
);
|
|
972
1077
|
}
|
|
973
1078
|
}
|
|
974
|
-
/** @deprecated Use `resendVerificationEmail` instead */
|
|
975
|
-
async sendVerificationEmail(request) {
|
|
976
|
-
return this.resendVerificationEmail(request);
|
|
977
|
-
}
|
|
978
1079
|
async verifyEmail(request) {
|
|
979
1080
|
try {
|
|
980
1081
|
const response = await this.http.post(
|
|
@@ -983,9 +1084,15 @@ var Auth = class {
|
|
|
983
1084
|
{ credentials: "include" }
|
|
984
1085
|
);
|
|
985
1086
|
this.saveSessionFromResponse(response);
|
|
1087
|
+
if (response.refreshToken) {
|
|
1088
|
+
this.http.setRefreshToken(response.refreshToken);
|
|
1089
|
+
}
|
|
986
1090
|
return { data: response, error: null };
|
|
987
1091
|
} catch (error) {
|
|
988
|
-
return wrapError(
|
|
1092
|
+
return wrapError(
|
|
1093
|
+
error,
|
|
1094
|
+
"An unexpected error occurred while verifying email"
|
|
1095
|
+
);
|
|
989
1096
|
}
|
|
990
1097
|
}
|
|
991
1098
|
// ============================================================================
|
|
@@ -993,13 +1100,13 @@ var Auth = class {
|
|
|
993
1100
|
// ============================================================================
|
|
994
1101
|
async sendResetPasswordEmail(request) {
|
|
995
1102
|
try {
|
|
996
|
-
const response = await this.http.post(
|
|
997
|
-
"/api/auth/email/send-reset-password",
|
|
998
|
-
request
|
|
999
|
-
);
|
|
1103
|
+
const response = await this.http.post("/api/auth/email/send-reset-password", request);
|
|
1000
1104
|
return { data: response, error: null };
|
|
1001
1105
|
} catch (error) {
|
|
1002
|
-
return wrapError(
|
|
1106
|
+
return wrapError(
|
|
1107
|
+
error,
|
|
1108
|
+
"An unexpected error occurred while sending password reset code"
|
|
1109
|
+
);
|
|
1003
1110
|
}
|
|
1004
1111
|
}
|
|
1005
1112
|
async exchangeResetPasswordToken(request) {
|
|
@@ -1010,7 +1117,10 @@ var Auth = class {
|
|
|
1010
1117
|
);
|
|
1011
1118
|
return { data: response, error: null };
|
|
1012
1119
|
} catch (error) {
|
|
1013
|
-
return wrapError(
|
|
1120
|
+
return wrapError(
|
|
1121
|
+
error,
|
|
1122
|
+
"An unexpected error occurred while verifying reset code"
|
|
1123
|
+
);
|
|
1014
1124
|
}
|
|
1015
1125
|
}
|
|
1016
1126
|
async resetPassword(request) {
|
|
@@ -1021,7 +1131,10 @@ var Auth = class {
|
|
|
1021
1131
|
);
|
|
1022
1132
|
return { data: response, error: null };
|
|
1023
1133
|
} catch (error) {
|
|
1024
|
-
return wrapError(
|
|
1134
|
+
return wrapError(
|
|
1135
|
+
error,
|
|
1136
|
+
"An unexpected error occurred while resetting password"
|
|
1137
|
+
);
|
|
1025
1138
|
}
|
|
1026
1139
|
}
|
|
1027
1140
|
// ============================================================================
|
|
@@ -1029,10 +1142,15 @@ var Auth = class {
|
|
|
1029
1142
|
// ============================================================================
|
|
1030
1143
|
async getPublicAuthConfig() {
|
|
1031
1144
|
try {
|
|
1032
|
-
const response = await this.http.get(
|
|
1145
|
+
const response = await this.http.get(
|
|
1146
|
+
"/api/auth/public-config"
|
|
1147
|
+
);
|
|
1033
1148
|
return { data: response, error: null };
|
|
1034
1149
|
} catch (error) {
|
|
1035
|
-
return wrapError(
|
|
1150
|
+
return wrapError(
|
|
1151
|
+
error,
|
|
1152
|
+
"An unexpected error occurred while fetching auth configuration"
|
|
1153
|
+
);
|
|
1036
1154
|
}
|
|
1037
1155
|
}
|
|
1038
1156
|
};
|
|
@@ -1778,9 +1896,17 @@ var Functions = class _Functions {
|
|
|
1778
1896
|
});
|
|
1779
1897
|
return { data, error: null };
|
|
1780
1898
|
} catch (error) {
|
|
1781
|
-
if (error
|
|
1899
|
+
if (error instanceof Error && error.name === "AbortError") throw error;
|
|
1900
|
+
if (error instanceof InsForgeError && error.statusCode === 404) {
|
|
1782
1901
|
} else {
|
|
1783
|
-
return {
|
|
1902
|
+
return {
|
|
1903
|
+
data: null,
|
|
1904
|
+
error: error instanceof InsForgeError ? error : new InsForgeError(
|
|
1905
|
+
error instanceof Error ? error.message : "Function invocation failed",
|
|
1906
|
+
500,
|
|
1907
|
+
"FUNCTION_ERROR"
|
|
1908
|
+
)
|
|
1909
|
+
};
|
|
1784
1910
|
}
|
|
1785
1911
|
}
|
|
1786
1912
|
}
|
|
@@ -1789,7 +1915,15 @@ var Functions = class _Functions {
|
|
|
1789
1915
|
const data = await this.http.request(method, path, { body, headers });
|
|
1790
1916
|
return { data, error: null };
|
|
1791
1917
|
} catch (error) {
|
|
1792
|
-
|
|
1918
|
+
if (error instanceof Error && error.name === "AbortError") throw error;
|
|
1919
|
+
return {
|
|
1920
|
+
data: null,
|
|
1921
|
+
error: error instanceof InsForgeError ? error : new InsForgeError(
|
|
1922
|
+
error instanceof Error ? error.message : "Function invocation failed",
|
|
1923
|
+
500,
|
|
1924
|
+
"FUNCTION_ERROR"
|
|
1925
|
+
)
|
|
1926
|
+
};
|
|
1793
1927
|
}
|
|
1794
1928
|
}
|
|
1795
1929
|
};
|
|
@@ -2060,8 +2194,15 @@ var Emails = class {
|
|
|
2060
2194
|
);
|
|
2061
2195
|
return { data, error: null };
|
|
2062
2196
|
} catch (error) {
|
|
2063
|
-
|
|
2064
|
-
return {
|
|
2197
|
+
if (error instanceof Error && error.name === "AbortError") throw error;
|
|
2198
|
+
return {
|
|
2199
|
+
data: null,
|
|
2200
|
+
error: error instanceof InsForgeError ? error : new InsForgeError(
|
|
2201
|
+
error instanceof Error ? error.message : "Email send failed",
|
|
2202
|
+
500,
|
|
2203
|
+
"EMAIL_ERROR"
|
|
2204
|
+
)
|
|
2205
|
+
};
|
|
2065
2206
|
}
|
|
2066
2207
|
}
|
|
2067
2208
|
};
|
|
@@ -2070,8 +2211,8 @@ var Emails = class {
|
|
|
2070
2211
|
var InsForgeClient = class {
|
|
2071
2212
|
constructor(config = {}) {
|
|
2072
2213
|
const logger = new Logger(config.debug);
|
|
2073
|
-
this.http = new HttpClient(config, logger);
|
|
2074
2214
|
this.tokenManager = new TokenManager();
|
|
2215
|
+
this.http = new HttpClient(config, this.tokenManager, logger);
|
|
2075
2216
|
if (config.edgeFunctionToken) {
|
|
2076
2217
|
this.http.setAuthToken(config.edgeFunctionToken);
|
|
2077
2218
|
this.tokenManager.setAccessToken(config.edgeFunctionToken);
|
|
@@ -2083,12 +2224,16 @@ var InsForgeClient = class {
|
|
|
2083
2224
|
this.storage = new Storage(this.http);
|
|
2084
2225
|
this.ai = new AI(this.http);
|
|
2085
2226
|
this.functions = new Functions(this.http, config.functionsUrl);
|
|
2086
|
-
this.realtime = new Realtime(
|
|
2227
|
+
this.realtime = new Realtime(
|
|
2228
|
+
this.http.baseUrl,
|
|
2229
|
+
this.tokenManager,
|
|
2230
|
+
config.anonKey
|
|
2231
|
+
);
|
|
2087
2232
|
this.emails = new Emails(this.http);
|
|
2088
2233
|
}
|
|
2089
2234
|
/**
|
|
2090
2235
|
* Get the underlying HTTP client for custom requests
|
|
2091
|
-
*
|
|
2236
|
+
*
|
|
2092
2237
|
* @example
|
|
2093
2238
|
* ```typescript
|
|
2094
2239
|
* const httpClient = client.getHttpClient();
|