@insforge/sdk 1.0.1-refresh.7 → 1.0.1-refresh.8
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.d.mts +46 -169
- package/dist/index.d.ts +46 -169
- package/dist/index.js +170 -406
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +170 -404
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -27,8 +27,6 @@ __export(index_exports, {
|
|
|
27
27
|
HttpClient: () => HttpClient,
|
|
28
28
|
InsForgeClient: () => InsForgeClient,
|
|
29
29
|
InsForgeError: () => InsForgeError,
|
|
30
|
-
LocalSessionStorage: () => LocalSessionStorage,
|
|
31
|
-
SecureSessionStorage: () => SecureSessionStorage,
|
|
32
30
|
Storage: () => Storage,
|
|
33
31
|
StorageBucket: () => StorageBucket,
|
|
34
32
|
TokenManager: () => TokenManager,
|
|
@@ -60,8 +58,6 @@ var InsForgeError = class _InsForgeError extends Error {
|
|
|
60
58
|
var HttpClient = class {
|
|
61
59
|
constructor(config) {
|
|
62
60
|
this.userToken = null;
|
|
63
|
-
this.isRefreshing = false;
|
|
64
|
-
this.refreshQueue = [];
|
|
65
61
|
this.baseUrl = config.baseUrl || "http://localhost:7130";
|
|
66
62
|
this.fetch = config.fetch || (globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
|
|
67
63
|
this.anonKey = config.anonKey;
|
|
@@ -74,12 +70,6 @@ var HttpClient = class {
|
|
|
74
70
|
);
|
|
75
71
|
}
|
|
76
72
|
}
|
|
77
|
-
/**
|
|
78
|
-
* Set the refresh callback for automatic token refresh on 401
|
|
79
|
-
*/
|
|
80
|
-
setRefreshCallback(callback) {
|
|
81
|
-
this.refreshCallback = callback;
|
|
82
|
-
}
|
|
83
73
|
buildUrl(path, params) {
|
|
84
74
|
const url = new URL(path, this.baseUrl);
|
|
85
75
|
if (params) {
|
|
@@ -96,9 +86,6 @@ var HttpClient = class {
|
|
|
96
86
|
return url.toString();
|
|
97
87
|
}
|
|
98
88
|
async request(method, path, options = {}) {
|
|
99
|
-
return this.performRequest(method, path, options, false);
|
|
100
|
-
}
|
|
101
|
-
async performRequest(method, path, options = {}, isRetry = false) {
|
|
102
89
|
const { params, headers = {}, body, ...fetchOptions } = options;
|
|
103
90
|
const url = this.buildUrl(path, params);
|
|
104
91
|
const requestHeaders = {
|
|
@@ -124,17 +111,9 @@ var HttpClient = class {
|
|
|
124
111
|
method,
|
|
125
112
|
headers: requestHeaders,
|
|
126
113
|
body: processedBody,
|
|
127
|
-
|
|
128
|
-
|
|
114
|
+
credentials: "include",
|
|
115
|
+
...fetchOptions
|
|
129
116
|
});
|
|
130
|
-
const isRefreshEndpoint = path.includes("/api/auth/refresh") || path.includes("/api/auth/logout");
|
|
131
|
-
if (response.status === 401 && !isRetry && !isRefreshEndpoint && this.refreshCallback) {
|
|
132
|
-
const newToken = await this.handleTokenRefresh();
|
|
133
|
-
if (newToken) {
|
|
134
|
-
this.setAuthToken(newToken);
|
|
135
|
-
return this.performRequest(method, path, options, true);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
117
|
if (response.status === 204) {
|
|
139
118
|
return void 0;
|
|
140
119
|
}
|
|
@@ -166,38 +145,6 @@ var HttpClient = class {
|
|
|
166
145
|
}
|
|
167
146
|
return data;
|
|
168
147
|
}
|
|
169
|
-
/**
|
|
170
|
-
* Handle token refresh with queue to prevent duplicate refreshes
|
|
171
|
-
* Multiple concurrent 401s will wait for a single refresh to complete
|
|
172
|
-
*/
|
|
173
|
-
async handleTokenRefresh() {
|
|
174
|
-
if (this.isRefreshing) {
|
|
175
|
-
return new Promise((resolve, reject) => {
|
|
176
|
-
this.refreshQueue.push({ resolve, reject });
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
this.isRefreshing = true;
|
|
180
|
-
try {
|
|
181
|
-
const newToken = await this.refreshCallback?.();
|
|
182
|
-
this.refreshQueue.forEach(({ resolve, reject }) => {
|
|
183
|
-
if (newToken) {
|
|
184
|
-
resolve(newToken);
|
|
185
|
-
} else {
|
|
186
|
-
reject(new Error("Token refresh failed"));
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
this.refreshQueue = [];
|
|
190
|
-
return newToken || null;
|
|
191
|
-
} catch (error) {
|
|
192
|
-
this.refreshQueue.forEach(({ reject }) => {
|
|
193
|
-
reject(error instanceof Error ? error : new Error("Token refresh failed"));
|
|
194
|
-
});
|
|
195
|
-
this.refreshQueue = [];
|
|
196
|
-
return null;
|
|
197
|
-
} finally {
|
|
198
|
-
this.isRefreshing = false;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
148
|
get(path, options) {
|
|
202
149
|
return this.request("GET", path, options);
|
|
203
150
|
}
|
|
@@ -226,58 +173,32 @@ var HttpClient = class {
|
|
|
226
173
|
}
|
|
227
174
|
};
|
|
228
175
|
|
|
229
|
-
// src/lib/
|
|
176
|
+
// src/lib/token-manager.ts
|
|
230
177
|
var TOKEN_KEY = "insforge-auth-token";
|
|
231
178
|
var USER_KEY = "insforge-auth-user";
|
|
232
179
|
var AUTH_FLAG_COOKIE = "isAuthenticated";
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
return this.accessToken;
|
|
252
|
-
}
|
|
253
|
-
setAccessToken(token) {
|
|
254
|
-
this.accessToken = token;
|
|
255
|
-
}
|
|
256
|
-
getUser() {
|
|
257
|
-
return this.user;
|
|
258
|
-
}
|
|
259
|
-
setUser(user) {
|
|
260
|
-
this.user = user;
|
|
261
|
-
}
|
|
262
|
-
clearSession() {
|
|
180
|
+
function hasAuthCookie() {
|
|
181
|
+
if (typeof document === "undefined") return false;
|
|
182
|
+
return document.cookie.split(";").some(
|
|
183
|
+
(c) => c.trim().startsWith(`${AUTH_FLAG_COOKIE}=`)
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
function setAuthCookie() {
|
|
187
|
+
if (typeof document === "undefined") return;
|
|
188
|
+
const maxAge = 7 * 24 * 60 * 60;
|
|
189
|
+
document.cookie = `${AUTH_FLAG_COOKIE}=true; path=/; max-age=${maxAge}; SameSite=Lax`;
|
|
190
|
+
}
|
|
191
|
+
function clearAuthCookie() {
|
|
192
|
+
if (typeof document === "undefined") return;
|
|
193
|
+
document.cookie = `${AUTH_FLAG_COOKIE}=; path=/; max-age=0; SameSite=Lax`;
|
|
194
|
+
}
|
|
195
|
+
var TokenManager = class {
|
|
196
|
+
constructor(storage) {
|
|
197
|
+
// In-memory storage
|
|
263
198
|
this.accessToken = null;
|
|
264
199
|
this.user = null;
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
if (this.accessToken) return false;
|
|
268
|
-
return this.hasAuthFlag();
|
|
269
|
-
}
|
|
270
|
-
// --- Private: Auth Flag Cookie Detection (SDK-managed on frontend domain) ---
|
|
271
|
-
hasAuthFlag() {
|
|
272
|
-
if (typeof document === "undefined") return false;
|
|
273
|
-
return document.cookie.split(";").some(
|
|
274
|
-
(c) => c.trim().startsWith(`${AUTH_FLAG_COOKIE}=`)
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
var LocalSessionStorage = class {
|
|
279
|
-
constructor(storage) {
|
|
280
|
-
this.strategyId = "local";
|
|
200
|
+
// Mode: 'memory' (new backend) or 'storage' (legacy backend, default)
|
|
201
|
+
this._mode = "storage";
|
|
281
202
|
if (storage) {
|
|
282
203
|
this.storage = storage;
|
|
283
204
|
} else if (typeof window !== "undefined" && window.localStorage) {
|
|
@@ -295,126 +216,111 @@ var LocalSessionStorage = class {
|
|
|
295
216
|
};
|
|
296
217
|
}
|
|
297
218
|
}
|
|
298
|
-
saveSession(session) {
|
|
299
|
-
this.storage.setItem(TOKEN_KEY, session.accessToken);
|
|
300
|
-
this.storage.setItem(USER_KEY, JSON.stringify(session.user));
|
|
301
|
-
}
|
|
302
|
-
getSession() {
|
|
303
|
-
const token = this.storage.getItem(TOKEN_KEY);
|
|
304
|
-
const userStr = this.storage.getItem(USER_KEY);
|
|
305
|
-
if (!token || !userStr) return null;
|
|
306
|
-
try {
|
|
307
|
-
const user = JSON.parse(userStr);
|
|
308
|
-
return { accessToken: token, user };
|
|
309
|
-
} catch {
|
|
310
|
-
this.clearSession();
|
|
311
|
-
return null;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
getAccessToken() {
|
|
315
|
-
const token = this.storage.getItem(TOKEN_KEY);
|
|
316
|
-
return typeof token === "string" ? token : null;
|
|
317
|
-
}
|
|
318
|
-
setAccessToken(token) {
|
|
319
|
-
this.storage.setItem(TOKEN_KEY, token);
|
|
320
|
-
}
|
|
321
|
-
getUser() {
|
|
322
|
-
const userStr = this.storage.getItem(USER_KEY);
|
|
323
|
-
if (!userStr) return null;
|
|
324
|
-
try {
|
|
325
|
-
return JSON.parse(userStr);
|
|
326
|
-
} catch {
|
|
327
|
-
return null;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
setUser(user) {
|
|
331
|
-
this.storage.setItem(USER_KEY, JSON.stringify(user));
|
|
332
|
-
}
|
|
333
|
-
clearSession() {
|
|
334
|
-
this.storage.removeItem(TOKEN_KEY);
|
|
335
|
-
this.storage.removeItem(USER_KEY);
|
|
336
|
-
}
|
|
337
|
-
shouldAttemptRefresh() {
|
|
338
|
-
return false;
|
|
339
|
-
}
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
// src/lib/token-manager.ts
|
|
343
|
-
var TokenManager = class {
|
|
344
219
|
/**
|
|
345
|
-
*
|
|
346
|
-
* @param storage - Optional custom storage adapter (used for initial LocalSessionStorage)
|
|
220
|
+
* Get current mode
|
|
347
221
|
*/
|
|
348
|
-
|
|
349
|
-
this.
|
|
222
|
+
get mode() {
|
|
223
|
+
return this._mode;
|
|
350
224
|
}
|
|
351
225
|
/**
|
|
352
|
-
* Set
|
|
353
|
-
* Called after capability discovery to switch to the appropriate strategy
|
|
226
|
+
* Set mode to memory (new backend with cookies + memory)
|
|
354
227
|
*/
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
if (existingSession && previousId !== strategy.strategyId) {
|
|
360
|
-
strategy.saveSession(existingSession);
|
|
228
|
+
setMemoryMode() {
|
|
229
|
+
if (this._mode === "storage") {
|
|
230
|
+
this.storage.removeItem(TOKEN_KEY);
|
|
231
|
+
this.storage.removeItem(USER_KEY);
|
|
361
232
|
}
|
|
233
|
+
this._mode = "memory";
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Set mode to storage (legacy backend with localStorage)
|
|
237
|
+
* Also loads existing session from localStorage
|
|
238
|
+
*/
|
|
239
|
+
setStorageMode() {
|
|
240
|
+
this._mode = "storage";
|
|
241
|
+
this.loadFromStorage();
|
|
362
242
|
}
|
|
363
243
|
/**
|
|
364
|
-
*
|
|
244
|
+
* Load session from localStorage
|
|
365
245
|
*/
|
|
366
|
-
|
|
367
|
-
|
|
246
|
+
loadFromStorage() {
|
|
247
|
+
const token = this.storage.getItem(TOKEN_KEY);
|
|
248
|
+
const userStr = this.storage.getItem(USER_KEY);
|
|
249
|
+
if (token && userStr) {
|
|
250
|
+
try {
|
|
251
|
+
this.accessToken = token;
|
|
252
|
+
this.user = JSON.parse(userStr);
|
|
253
|
+
} catch {
|
|
254
|
+
this.clearSession();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
368
257
|
}
|
|
369
|
-
// --- Delegated Methods ---
|
|
370
258
|
/**
|
|
371
|
-
* Save session
|
|
259
|
+
* Save session (memory always, localStorage only in storage mode)
|
|
372
260
|
*/
|
|
373
261
|
saveSession(session) {
|
|
374
|
-
this.
|
|
262
|
+
this.accessToken = session.accessToken;
|
|
263
|
+
this.user = session.user;
|
|
264
|
+
if (this._mode === "storage") {
|
|
265
|
+
this.storage.setItem(TOKEN_KEY, session.accessToken);
|
|
266
|
+
this.storage.setItem(USER_KEY, JSON.stringify(session.user));
|
|
267
|
+
}
|
|
375
268
|
}
|
|
376
269
|
/**
|
|
377
270
|
* Get current session
|
|
378
271
|
*/
|
|
379
272
|
getSession() {
|
|
380
|
-
|
|
273
|
+
if (!this.accessToken || !this.user) return null;
|
|
274
|
+
return {
|
|
275
|
+
accessToken: this.accessToken,
|
|
276
|
+
user: this.user
|
|
277
|
+
};
|
|
381
278
|
}
|
|
382
279
|
/**
|
|
383
280
|
* Get access token
|
|
384
281
|
*/
|
|
385
282
|
getAccessToken() {
|
|
386
|
-
return this.
|
|
283
|
+
return this.accessToken;
|
|
387
284
|
}
|
|
388
285
|
/**
|
|
389
|
-
*
|
|
286
|
+
* Set access token
|
|
390
287
|
*/
|
|
391
288
|
setAccessToken(token) {
|
|
392
|
-
this.
|
|
289
|
+
this.accessToken = token;
|
|
290
|
+
if (this._mode === "storage") {
|
|
291
|
+
this.storage.setItem(TOKEN_KEY, token);
|
|
292
|
+
}
|
|
393
293
|
}
|
|
394
294
|
/**
|
|
395
|
-
* Get user
|
|
295
|
+
* Get user
|
|
396
296
|
*/
|
|
397
297
|
getUser() {
|
|
398
|
-
return this.
|
|
298
|
+
return this.user;
|
|
399
299
|
}
|
|
400
300
|
/**
|
|
401
|
-
*
|
|
301
|
+
* Set user
|
|
402
302
|
*/
|
|
403
303
|
setUser(user) {
|
|
404
|
-
this.
|
|
304
|
+
this.user = user;
|
|
305
|
+
if (this._mode === "storage") {
|
|
306
|
+
this.storage.setItem(USER_KEY, JSON.stringify(user));
|
|
307
|
+
}
|
|
405
308
|
}
|
|
406
309
|
/**
|
|
407
|
-
* Clear
|
|
310
|
+
* Clear session (both memory and localStorage)
|
|
408
311
|
*/
|
|
409
312
|
clearSession() {
|
|
410
|
-
this.
|
|
313
|
+
this.accessToken = null;
|
|
314
|
+
this.user = null;
|
|
315
|
+
this.storage.removeItem(TOKEN_KEY);
|
|
316
|
+
this.storage.removeItem(USER_KEY);
|
|
411
317
|
}
|
|
412
318
|
/**
|
|
413
|
-
* Check if
|
|
414
|
-
* (e.g., on page reload in secure mode)
|
|
319
|
+
* Check if there's a session in localStorage (for legacy detection)
|
|
415
320
|
*/
|
|
416
|
-
|
|
417
|
-
|
|
321
|
+
hasStoredSession() {
|
|
322
|
+
const token = this.storage.getItem(TOKEN_KEY);
|
|
323
|
+
return !!token;
|
|
418
324
|
}
|
|
419
325
|
};
|
|
420
326
|
|
|
@@ -531,77 +437,75 @@ var Auth = class {
|
|
|
531
437
|
this.detectAuthCallback();
|
|
532
438
|
}
|
|
533
439
|
/**
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
* Called when backend returns sessionMode: 'secure'
|
|
552
|
-
* @internal
|
|
553
|
-
*/
|
|
554
|
-
_switchToSecureStorage() {
|
|
555
|
-
console.log("[InsForge:Auth] _switchToSecureStorage() called, current strategy:", this.tokenManager.getStrategyId());
|
|
556
|
-
if (this.tokenManager.getStrategyId() === "secure") {
|
|
557
|
-
console.log("[InsForge:Auth] _switchToSecureStorage() - already in secure mode, skipping");
|
|
558
|
-
return;
|
|
440
|
+
* Restore session on app initialization
|
|
441
|
+
*
|
|
442
|
+
* @returns Object with isLoggedIn status
|
|
443
|
+
*
|
|
444
|
+
* @example
|
|
445
|
+
* ```typescript
|
|
446
|
+
* const client = new InsForgeClient({ baseUrl: '...' });
|
|
447
|
+
* const { isLoggedIn } = await client.auth.restoreSession();
|
|
448
|
+
*
|
|
449
|
+
* if (isLoggedIn) {
|
|
450
|
+
* const { data } = await client.auth.getCurrentUser();
|
|
451
|
+
* }
|
|
452
|
+
* ```
|
|
453
|
+
*/
|
|
454
|
+
async restoreSession() {
|
|
455
|
+
if (typeof window === "undefined") {
|
|
456
|
+
return { isLoggedIn: false };
|
|
559
457
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
if (typeof localStorage !== "undefined") {
|
|
563
|
-
console.log("[InsForge:Auth] _switchToSecureStorage() - clearing localStorage");
|
|
564
|
-
localStorage.removeItem(TOKEN_KEY);
|
|
565
|
-
localStorage.removeItem(USER_KEY);
|
|
458
|
+
if (this.tokenManager.getAccessToken()) {
|
|
459
|
+
return { isLoggedIn: true };
|
|
566
460
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
461
|
+
if (hasAuthCookie()) {
|
|
462
|
+
try {
|
|
463
|
+
const response = await this.http.post(
|
|
464
|
+
"/api/auth/refresh"
|
|
465
|
+
);
|
|
466
|
+
if (response.accessToken) {
|
|
467
|
+
this.tokenManager.setMemoryMode();
|
|
468
|
+
this.tokenManager.setAccessToken(response.accessToken);
|
|
469
|
+
this.http.setAuthToken(response.accessToken);
|
|
470
|
+
if (response.user) {
|
|
471
|
+
this.tokenManager.setUser(response.user);
|
|
472
|
+
}
|
|
473
|
+
return { isLoggedIn: true };
|
|
474
|
+
}
|
|
475
|
+
} catch (error) {
|
|
476
|
+
if (error instanceof InsForgeError) {
|
|
477
|
+
if (error.statusCode === 404) {
|
|
478
|
+
this.tokenManager.setStorageMode();
|
|
479
|
+
const token = this.tokenManager.getAccessToken();
|
|
480
|
+
if (token) {
|
|
481
|
+
this.http.setAuthToken(token);
|
|
482
|
+
return { isLoggedIn: true };
|
|
483
|
+
}
|
|
484
|
+
return { isLoggedIn: false };
|
|
485
|
+
}
|
|
486
|
+
if (error.statusCode === 401 || error.statusCode === 403) {
|
|
487
|
+
clearAuthCookie();
|
|
488
|
+
return { isLoggedIn: false };
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return { isLoggedIn: false };
|
|
492
|
+
}
|
|
571
493
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
if (this.tokenManager.getStrategyId() === "local") return;
|
|
580
|
-
const currentSession = this.tokenManager.getSession();
|
|
581
|
-
this.tokenManager.setStrategy(new LocalSessionStorage());
|
|
582
|
-
this.clearAuthenticatedCookie();
|
|
583
|
-
if (currentSession) {
|
|
584
|
-
this.tokenManager.saveSession(currentSession);
|
|
494
|
+
if (this.tokenManager.hasStoredSession()) {
|
|
495
|
+
this.tokenManager.setStorageMode();
|
|
496
|
+
const token = this.tokenManager.getAccessToken();
|
|
497
|
+
if (token) {
|
|
498
|
+
this.http.setAuthToken(token);
|
|
499
|
+
return { isLoggedIn: true };
|
|
500
|
+
}
|
|
585
501
|
}
|
|
502
|
+
return { isLoggedIn: false };
|
|
586
503
|
}
|
|
587
504
|
/**
|
|
588
|
-
*
|
|
589
|
-
*
|
|
590
|
-
*
|
|
505
|
+
* Automatically detect and handle OAuth callback parameters in the URL
|
|
506
|
+
* This runs on initialization to seamlessly complete the OAuth flow
|
|
507
|
+
* Matches the backend's OAuth callback response (backend/src/api/routes/auth.ts:540-544)
|
|
591
508
|
*/
|
|
592
|
-
_detectStorageFromResponse(sessionMode) {
|
|
593
|
-
console.log("[InsForge:Auth] _detectStorageFromResponse() - sessionMode:", sessionMode);
|
|
594
|
-
if (sessionMode === "secure") {
|
|
595
|
-
this._switchToSecureStorage();
|
|
596
|
-
} else {
|
|
597
|
-
this._switchToLocalStorage();
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
/**
|
|
601
|
-
* Automatically detect and handle OAuth callback parameters in the URL
|
|
602
|
-
* This runs on initialization to seamlessly complete the OAuth flow
|
|
603
|
-
* Matches the backend's OAuth callback response (backend/src/api/routes/auth.ts:540-544)
|
|
604
|
-
*/
|
|
605
509
|
detectAuthCallback() {
|
|
606
510
|
if (typeof window === "undefined") return;
|
|
607
511
|
try {
|
|
@@ -610,9 +514,7 @@ var Auth = class {
|
|
|
610
514
|
const userId = params.get("user_id");
|
|
611
515
|
const email = params.get("email");
|
|
612
516
|
const name = params.get("name");
|
|
613
|
-
const sessionMode = params.get("session_mode");
|
|
614
517
|
if (accessToken && userId && email) {
|
|
615
|
-
this._detectStorageFromResponse(sessionMode || void 0);
|
|
616
518
|
const session = {
|
|
617
519
|
accessToken,
|
|
618
520
|
user: {
|
|
@@ -626,14 +528,14 @@ var Auth = class {
|
|
|
626
528
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
627
529
|
}
|
|
628
530
|
};
|
|
629
|
-
this.tokenManager.saveSession(session);
|
|
630
531
|
this.http.setAuthToken(accessToken);
|
|
532
|
+
this.tokenManager.saveSession(session);
|
|
533
|
+
setAuthCookie();
|
|
631
534
|
const url = new URL(window.location.href);
|
|
632
535
|
url.searchParams.delete("access_token");
|
|
633
536
|
url.searchParams.delete("user_id");
|
|
634
537
|
url.searchParams.delete("email");
|
|
635
538
|
url.searchParams.delete("name");
|
|
636
|
-
url.searchParams.delete("session_mode");
|
|
637
539
|
if (params.has("error")) {
|
|
638
540
|
url.searchParams.delete("error");
|
|
639
541
|
}
|
|
@@ -649,16 +551,13 @@ var Auth = class {
|
|
|
649
551
|
async signUp(request) {
|
|
650
552
|
try {
|
|
651
553
|
const response = await this.http.post("/api/auth/users", request);
|
|
652
|
-
|
|
653
|
-
this._detectStorageFromResponse(sessionMode);
|
|
654
|
-
if (response.accessToken && response.user) {
|
|
554
|
+
if (response.accessToken && response.user && !isHostedAuthEnvironment()) {
|
|
655
555
|
const session = {
|
|
656
556
|
accessToken: response.accessToken,
|
|
657
557
|
user: response.user
|
|
658
558
|
};
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
559
|
+
this.tokenManager.saveSession(session);
|
|
560
|
+
setAuthCookie();
|
|
662
561
|
this.http.setAuthToken(response.accessToken);
|
|
663
562
|
}
|
|
664
563
|
return {
|
|
@@ -685,23 +584,15 @@ var Auth = class {
|
|
|
685
584
|
async signInWithPassword(request) {
|
|
686
585
|
try {
|
|
687
586
|
const response = await this.http.post("/api/auth/sessions", request);
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
id: "",
|
|
694
|
-
email: "",
|
|
695
|
-
name: "",
|
|
696
|
-
emailVerified: false,
|
|
697
|
-
createdAt: "",
|
|
698
|
-
updatedAt: ""
|
|
699
|
-
}
|
|
700
|
-
};
|
|
701
|
-
if (!isHostedAuthEnvironment()) {
|
|
587
|
+
if (response.accessToken && response.user && !isHostedAuthEnvironment()) {
|
|
588
|
+
const session = {
|
|
589
|
+
accessToken: response.accessToken,
|
|
590
|
+
user: response.user
|
|
591
|
+
};
|
|
702
592
|
this.tokenManager.saveSession(session);
|
|
593
|
+
setAuthCookie();
|
|
594
|
+
this.http.setAuthToken(response.accessToken);
|
|
703
595
|
}
|
|
704
|
-
this.http.setAuthToken(response.accessToken || "");
|
|
705
596
|
return {
|
|
706
597
|
data: response,
|
|
707
598
|
error: null
|
|
@@ -756,28 +647,18 @@ var Auth = class {
|
|
|
756
647
|
}
|
|
757
648
|
/**
|
|
758
649
|
* Sign out the current user
|
|
759
|
-
* In modern mode, also calls backend to clear the refresh token cookie
|
|
760
650
|
*/
|
|
761
651
|
async signOut() {
|
|
762
|
-
console.log("[InsForge:Auth] signOut() called");
|
|
763
|
-
console.log("[InsForge:Auth] signOut() stack trace:", new Error().stack);
|
|
764
652
|
try {
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
await this.http.post("/api/auth/logout");
|
|
769
|
-
console.log("[InsForge:Auth] signOut() - backend logout successful");
|
|
770
|
-
} catch (e) {
|
|
771
|
-
console.log("[InsForge:Auth] signOut() - backend logout failed (ignored):", e);
|
|
772
|
-
}
|
|
653
|
+
try {
|
|
654
|
+
await this.http.post("/api/auth/logout");
|
|
655
|
+
} catch {
|
|
773
656
|
}
|
|
774
657
|
this.tokenManager.clearSession();
|
|
775
658
|
this.http.setAuthToken(null);
|
|
776
|
-
|
|
777
|
-
console.log("[InsForge:Auth] signOut() - completed");
|
|
659
|
+
clearAuthCookie();
|
|
778
660
|
return { error: null };
|
|
779
661
|
} catch (error) {
|
|
780
|
-
console.error("[InsForge:Auth] signOut() - error:", error);
|
|
781
662
|
return {
|
|
782
663
|
error: new InsForgeError(
|
|
783
664
|
"Failed to sign out",
|
|
@@ -787,58 +668,6 @@ var Auth = class {
|
|
|
787
668
|
};
|
|
788
669
|
}
|
|
789
670
|
}
|
|
790
|
-
/**
|
|
791
|
-
* Refresh the access token using the httpOnly refresh token cookie
|
|
792
|
-
* Only works when backend supports secure session storage (httpOnly cookies)
|
|
793
|
-
*
|
|
794
|
-
* @returns New access token or throws an error
|
|
795
|
-
*/
|
|
796
|
-
async refreshToken() {
|
|
797
|
-
console.log("[InsForge:Auth] refreshToken() called");
|
|
798
|
-
try {
|
|
799
|
-
const response = await this.http.post(
|
|
800
|
-
"/api/auth/refresh"
|
|
801
|
-
);
|
|
802
|
-
console.log("[InsForge:Auth] refreshToken() - response received, hasAccessToken:", !!response.accessToken);
|
|
803
|
-
if (response.accessToken) {
|
|
804
|
-
this._detectStorageFromResponse(response.sessionMode);
|
|
805
|
-
this.tokenManager.setAccessToken(response.accessToken);
|
|
806
|
-
this.http.setAuthToken(response.accessToken);
|
|
807
|
-
if (response.user) {
|
|
808
|
-
this.tokenManager.setUser(response.user);
|
|
809
|
-
}
|
|
810
|
-
console.log("[InsForge:Auth] refreshToken() - success");
|
|
811
|
-
return response.accessToken;
|
|
812
|
-
}
|
|
813
|
-
throw new InsForgeError(
|
|
814
|
-
"No access token in refresh response",
|
|
815
|
-
500,
|
|
816
|
-
"REFRESH_FAILED"
|
|
817
|
-
);
|
|
818
|
-
} catch (error) {
|
|
819
|
-
console.error("[InsForge:Auth] refreshToken() - error:", error);
|
|
820
|
-
if (error instanceof InsForgeError) {
|
|
821
|
-
if (error.statusCode === 404) {
|
|
822
|
-
console.log("[InsForge:Auth] refreshToken() - 404 detected, backend does not support refresh endpoint");
|
|
823
|
-
console.log("[InsForge:Auth] refreshToken() - switching to LocalSessionStorage for backward compatibility");
|
|
824
|
-
this._switchToLocalStorage();
|
|
825
|
-
this.clearAuthenticatedCookie();
|
|
826
|
-
}
|
|
827
|
-
if (error.statusCode === 401 || error.statusCode === 403) {
|
|
828
|
-
console.log("[InsForge:Auth] refreshToken() - clearing session due to 401/403");
|
|
829
|
-
this.tokenManager.clearSession();
|
|
830
|
-
this.http.setAuthToken(null);
|
|
831
|
-
this.clearAuthenticatedCookie();
|
|
832
|
-
}
|
|
833
|
-
throw error;
|
|
834
|
-
}
|
|
835
|
-
throw new InsForgeError(
|
|
836
|
-
"Token refresh failed",
|
|
837
|
-
500,
|
|
838
|
-
"REFRESH_FAILED"
|
|
839
|
-
);
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
671
|
/**
|
|
843
672
|
* Get all public authentication configuration (OAuth + Email)
|
|
844
673
|
* Returns both OAuth providers and email authentication settings in one request
|
|
@@ -879,40 +708,19 @@ var Auth = class {
|
|
|
879
708
|
/**
|
|
880
709
|
* Get the current user with full profile information
|
|
881
710
|
* Returns both auth info (id, email, role) and profile data (dynamic fields from users table)
|
|
882
|
-
*
|
|
883
|
-
* In secure session mode (httpOnly cookie), this method will automatically attempt
|
|
884
|
-
* to refresh the session if no access token is available (e.g., after page reload).
|
|
885
711
|
*/
|
|
886
712
|
async getCurrentUser() {
|
|
887
|
-
console.log("[InsForge:Auth] getCurrentUser() called");
|
|
888
713
|
try {
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
console.log("[InsForge:Auth] getCurrentUser() - hasAccessToken:", !!accessToken, "shouldAttemptRefresh:", shouldRefresh);
|
|
892
|
-
if (!accessToken && shouldRefresh) {
|
|
893
|
-
console.log("[InsForge:Auth] getCurrentUser() - attempting refresh");
|
|
894
|
-
try {
|
|
895
|
-
accessToken = await this.refreshToken();
|
|
896
|
-
} catch (error) {
|
|
897
|
-
console.log("[InsForge:Auth] getCurrentUser() - refresh failed:", error);
|
|
898
|
-
if (error instanceof InsForgeError && (error.statusCode === 401 || error.statusCode === 403)) {
|
|
899
|
-
return { data: null, error };
|
|
900
|
-
}
|
|
901
|
-
return { data: null, error: error instanceof InsForgeError ? error : new InsForgeError("Token refresh failed", 500, "REFRESH_FAILED") };
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
if (!accessToken) {
|
|
905
|
-
console.log("[InsForge:Auth] getCurrentUser() - no access token, returning null");
|
|
714
|
+
const session = this.tokenManager.getSession();
|
|
715
|
+
if (!session?.accessToken) {
|
|
906
716
|
return { data: null, error: null };
|
|
907
717
|
}
|
|
908
|
-
this.http.setAuthToken(accessToken);
|
|
909
|
-
console.log("[InsForge:Auth] getCurrentUser() - fetching user from API");
|
|
718
|
+
this.http.setAuthToken(session.accessToken);
|
|
910
719
|
const authResponse = await this.http.get("/api/auth/sessions/current");
|
|
911
720
|
const { data: profile, error: profileError } = await this.database.from("users").select("*").eq("id", authResponse.user.id).single();
|
|
912
721
|
if (profileError && profileError.code !== "PGRST116") {
|
|
913
722
|
return { data: null, error: profileError };
|
|
914
723
|
}
|
|
915
|
-
console.log("[InsForge:Auth] getCurrentUser() - success");
|
|
916
724
|
return {
|
|
917
725
|
data: {
|
|
918
726
|
user: authResponse.user,
|
|
@@ -921,12 +729,8 @@ var Auth = class {
|
|
|
921
729
|
error: null
|
|
922
730
|
};
|
|
923
731
|
} catch (error) {
|
|
924
|
-
console.error("[InsForge:Auth] getCurrentUser() - catch error:", error);
|
|
925
732
|
if (error instanceof InsForgeError && error.statusCode === 401) {
|
|
926
|
-
|
|
927
|
-
this.tokenManager.clearSession();
|
|
928
|
-
this.http.setAuthToken(null);
|
|
929
|
-
this.clearAuthenticatedCookie();
|
|
733
|
+
await this.signOut();
|
|
930
734
|
return { data: null, error: null };
|
|
931
735
|
}
|
|
932
736
|
if (error instanceof InsForgeError) {
|
|
@@ -1174,15 +978,14 @@ var Auth = class {
|
|
|
1174
978
|
"/api/auth/email/verify",
|
|
1175
979
|
request
|
|
1176
980
|
);
|
|
1177
|
-
|
|
1178
|
-
this._detectStorageFromResponse(sessionMode);
|
|
1179
|
-
if (response.accessToken) {
|
|
981
|
+
if (response.accessToken && !isHostedAuthEnvironment()) {
|
|
1180
982
|
const session = {
|
|
1181
983
|
accessToken: response.accessToken,
|
|
1182
984
|
user: response.user || {}
|
|
1183
985
|
};
|
|
1184
986
|
this.tokenManager.saveSession(session);
|
|
1185
987
|
this.http.setAuthToken(response.accessToken);
|
|
988
|
+
setAuthCookie();
|
|
1186
989
|
}
|
|
1187
990
|
return {
|
|
1188
991
|
data: response,
|
|
@@ -1726,24 +1529,10 @@ var Functions = class {
|
|
|
1726
1529
|
};
|
|
1727
1530
|
|
|
1728
1531
|
// src/client.ts
|
|
1729
|
-
function hasAuthenticatedCookie() {
|
|
1730
|
-
if (typeof document === "undefined") return false;
|
|
1731
|
-
return document.cookie.split(";").some(
|
|
1732
|
-
(c) => c.trim().startsWith(`${AUTH_FLAG_COOKIE}=`)
|
|
1733
|
-
);
|
|
1734
|
-
}
|
|
1735
1532
|
var InsForgeClient = class {
|
|
1736
1533
|
constructor(config = {}) {
|
|
1737
|
-
console.log("[InsForge:Client] Initializing SDK");
|
|
1738
1534
|
this.http = new HttpClient(config);
|
|
1739
1535
|
this.tokenManager = new TokenManager(config.storage);
|
|
1740
|
-
const hasAuthCookie = hasAuthenticatedCookie();
|
|
1741
|
-
console.log("[InsForge:Client] hasAuthenticatedCookie:", hasAuthCookie);
|
|
1742
|
-
console.log("[InsForge:Client] document.cookie:", typeof document !== "undefined" ? document.cookie : "N/A (SSR)");
|
|
1743
|
-
if (hasAuthCookie) {
|
|
1744
|
-
console.log("[InsForge:Client] Switching to SecureSessionStorage");
|
|
1745
|
-
this.tokenManager.setStrategy(new SecureSessionStorage());
|
|
1746
|
-
}
|
|
1747
1536
|
if (config.edgeFunctionToken) {
|
|
1748
1537
|
this.http.setAuthToken(config.edgeFunctionToken);
|
|
1749
1538
|
this.tokenManager.saveSession({
|
|
@@ -1752,32 +1541,15 @@ var InsForgeClient = class {
|
|
|
1752
1541
|
// Will be populated by getCurrentUser()
|
|
1753
1542
|
});
|
|
1754
1543
|
}
|
|
1755
|
-
this.http.setRefreshCallback(async () => {
|
|
1756
|
-
console.log("[InsForge:Client] HTTP 401 refresh callback triggered");
|
|
1757
|
-
try {
|
|
1758
|
-
return await this.auth.refreshToken();
|
|
1759
|
-
} catch (e) {
|
|
1760
|
-
console.log("[InsForge:Client] Refresh callback failed:", e);
|
|
1761
|
-
if (this.tokenManager.getStrategyId() === "secure") {
|
|
1762
|
-
console.log("[InsForge:Client] Falling back to LocalSessionStorage");
|
|
1763
|
-
this.auth._switchToLocalStorage();
|
|
1764
|
-
}
|
|
1765
|
-
return null;
|
|
1766
|
-
}
|
|
1767
|
-
});
|
|
1768
1544
|
const existingSession = this.tokenManager.getSession();
|
|
1769
|
-
console.log("[InsForge:Client] existingSession:", !!existingSession, "strategyId:", this.tokenManager.getStrategyId());
|
|
1770
1545
|
if (existingSession?.accessToken) {
|
|
1771
1546
|
this.http.setAuthToken(existingSession.accessToken);
|
|
1772
|
-
} else if (this.tokenManager.getStrategyId() === "secure") {
|
|
1773
|
-
console.log("[InsForge:Client] Secure mode, no session in memory - will refresh on first API call");
|
|
1774
1547
|
}
|
|
1775
1548
|
this.auth = new Auth(this.http, this.tokenManager);
|
|
1776
1549
|
this.database = new Database(this.http, this.tokenManager);
|
|
1777
1550
|
this.storage = new Storage(this.http);
|
|
1778
1551
|
this.ai = new AI(this.http);
|
|
1779
1552
|
this.functions = new Functions(this.http);
|
|
1780
|
-
console.log("[InsForge:Client] SDK initialized");
|
|
1781
1553
|
}
|
|
1782
1554
|
/**
|
|
1783
1555
|
* Get the underlying HTTP client for custom requests
|
|
@@ -1791,12 +1563,6 @@ var InsForgeClient = class {
|
|
|
1791
1563
|
getHttpClient() {
|
|
1792
1564
|
return this.http;
|
|
1793
1565
|
}
|
|
1794
|
-
/**
|
|
1795
|
-
* Get the current storage strategy identifier
|
|
1796
|
-
*/
|
|
1797
|
-
getStorageStrategy() {
|
|
1798
|
-
return this.tokenManager.getStrategyId();
|
|
1799
|
-
}
|
|
1800
1566
|
/**
|
|
1801
1567
|
* Future modules will be added here:
|
|
1802
1568
|
* - database: Database operations
|
|
@@ -1821,8 +1587,6 @@ var index_default = InsForgeClient;
|
|
|
1821
1587
|
HttpClient,
|
|
1822
1588
|
InsForgeClient,
|
|
1823
1589
|
InsForgeError,
|
|
1824
|
-
LocalSessionStorage,
|
|
1825
|
-
SecureSessionStorage,
|
|
1826
1590
|
Storage,
|
|
1827
1591
|
StorageBucket,
|
|
1828
1592
|
TokenManager,
|