@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.mjs
CHANGED
|
@@ -21,8 +21,6 @@ var InsForgeError = class _InsForgeError extends Error {
|
|
|
21
21
|
var HttpClient = class {
|
|
22
22
|
constructor(config) {
|
|
23
23
|
this.userToken = null;
|
|
24
|
-
this.isRefreshing = false;
|
|
25
|
-
this.refreshQueue = [];
|
|
26
24
|
this.baseUrl = config.baseUrl || "http://localhost:7130";
|
|
27
25
|
this.fetch = config.fetch || (globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
|
|
28
26
|
this.anonKey = config.anonKey;
|
|
@@ -35,12 +33,6 @@ var HttpClient = class {
|
|
|
35
33
|
);
|
|
36
34
|
}
|
|
37
35
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Set the refresh callback for automatic token refresh on 401
|
|
40
|
-
*/
|
|
41
|
-
setRefreshCallback(callback) {
|
|
42
|
-
this.refreshCallback = callback;
|
|
43
|
-
}
|
|
44
36
|
buildUrl(path, params) {
|
|
45
37
|
const url = new URL(path, this.baseUrl);
|
|
46
38
|
if (params) {
|
|
@@ -57,9 +49,6 @@ var HttpClient = class {
|
|
|
57
49
|
return url.toString();
|
|
58
50
|
}
|
|
59
51
|
async request(method, path, options = {}) {
|
|
60
|
-
return this.performRequest(method, path, options, false);
|
|
61
|
-
}
|
|
62
|
-
async performRequest(method, path, options = {}, isRetry = false) {
|
|
63
52
|
const { params, headers = {}, body, ...fetchOptions } = options;
|
|
64
53
|
const url = this.buildUrl(path, params);
|
|
65
54
|
const requestHeaders = {
|
|
@@ -85,17 +74,9 @@ var HttpClient = class {
|
|
|
85
74
|
method,
|
|
86
75
|
headers: requestHeaders,
|
|
87
76
|
body: processedBody,
|
|
88
|
-
|
|
89
|
-
|
|
77
|
+
credentials: "include",
|
|
78
|
+
...fetchOptions
|
|
90
79
|
});
|
|
91
|
-
const isRefreshEndpoint = path.includes("/api/auth/refresh") || path.includes("/api/auth/logout");
|
|
92
|
-
if (response.status === 401 && !isRetry && !isRefreshEndpoint && this.refreshCallback) {
|
|
93
|
-
const newToken = await this.handleTokenRefresh();
|
|
94
|
-
if (newToken) {
|
|
95
|
-
this.setAuthToken(newToken);
|
|
96
|
-
return this.performRequest(method, path, options, true);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
80
|
if (response.status === 204) {
|
|
100
81
|
return void 0;
|
|
101
82
|
}
|
|
@@ -127,38 +108,6 @@ var HttpClient = class {
|
|
|
127
108
|
}
|
|
128
109
|
return data;
|
|
129
110
|
}
|
|
130
|
-
/**
|
|
131
|
-
* Handle token refresh with queue to prevent duplicate refreshes
|
|
132
|
-
* Multiple concurrent 401s will wait for a single refresh to complete
|
|
133
|
-
*/
|
|
134
|
-
async handleTokenRefresh() {
|
|
135
|
-
if (this.isRefreshing) {
|
|
136
|
-
return new Promise((resolve, reject) => {
|
|
137
|
-
this.refreshQueue.push({ resolve, reject });
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
this.isRefreshing = true;
|
|
141
|
-
try {
|
|
142
|
-
const newToken = await this.refreshCallback?.();
|
|
143
|
-
this.refreshQueue.forEach(({ resolve, reject }) => {
|
|
144
|
-
if (newToken) {
|
|
145
|
-
resolve(newToken);
|
|
146
|
-
} else {
|
|
147
|
-
reject(new Error("Token refresh failed"));
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
this.refreshQueue = [];
|
|
151
|
-
return newToken || null;
|
|
152
|
-
} catch (error) {
|
|
153
|
-
this.refreshQueue.forEach(({ reject }) => {
|
|
154
|
-
reject(error instanceof Error ? error : new Error("Token refresh failed"));
|
|
155
|
-
});
|
|
156
|
-
this.refreshQueue = [];
|
|
157
|
-
return null;
|
|
158
|
-
} finally {
|
|
159
|
-
this.isRefreshing = false;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
111
|
get(path, options) {
|
|
163
112
|
return this.request("GET", path, options);
|
|
164
113
|
}
|
|
@@ -187,58 +136,32 @@ var HttpClient = class {
|
|
|
187
136
|
}
|
|
188
137
|
};
|
|
189
138
|
|
|
190
|
-
// src/lib/
|
|
139
|
+
// src/lib/token-manager.ts
|
|
191
140
|
var TOKEN_KEY = "insforge-auth-token";
|
|
192
141
|
var USER_KEY = "insforge-auth-user";
|
|
193
142
|
var AUTH_FLAG_COOKIE = "isAuthenticated";
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return this.accessToken;
|
|
213
|
-
}
|
|
214
|
-
setAccessToken(token) {
|
|
215
|
-
this.accessToken = token;
|
|
216
|
-
}
|
|
217
|
-
getUser() {
|
|
218
|
-
return this.user;
|
|
219
|
-
}
|
|
220
|
-
setUser(user) {
|
|
221
|
-
this.user = user;
|
|
222
|
-
}
|
|
223
|
-
clearSession() {
|
|
143
|
+
function hasAuthCookie() {
|
|
144
|
+
if (typeof document === "undefined") return false;
|
|
145
|
+
return document.cookie.split(";").some(
|
|
146
|
+
(c) => c.trim().startsWith(`${AUTH_FLAG_COOKIE}=`)
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
function setAuthCookie() {
|
|
150
|
+
if (typeof document === "undefined") return;
|
|
151
|
+
const maxAge = 7 * 24 * 60 * 60;
|
|
152
|
+
document.cookie = `${AUTH_FLAG_COOKIE}=true; path=/; max-age=${maxAge}; SameSite=Lax`;
|
|
153
|
+
}
|
|
154
|
+
function clearAuthCookie() {
|
|
155
|
+
if (typeof document === "undefined") return;
|
|
156
|
+
document.cookie = `${AUTH_FLAG_COOKIE}=; path=/; max-age=0; SameSite=Lax`;
|
|
157
|
+
}
|
|
158
|
+
var TokenManager = class {
|
|
159
|
+
constructor(storage) {
|
|
160
|
+
// In-memory storage
|
|
224
161
|
this.accessToken = null;
|
|
225
162
|
this.user = null;
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if (this.accessToken) return false;
|
|
229
|
-
return this.hasAuthFlag();
|
|
230
|
-
}
|
|
231
|
-
// --- Private: Auth Flag Cookie Detection (SDK-managed on frontend domain) ---
|
|
232
|
-
hasAuthFlag() {
|
|
233
|
-
if (typeof document === "undefined") return false;
|
|
234
|
-
return document.cookie.split(";").some(
|
|
235
|
-
(c) => c.trim().startsWith(`${AUTH_FLAG_COOKIE}=`)
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
var LocalSessionStorage = class {
|
|
240
|
-
constructor(storage) {
|
|
241
|
-
this.strategyId = "local";
|
|
163
|
+
// Mode: 'memory' (new backend) or 'storage' (legacy backend, default)
|
|
164
|
+
this._mode = "storage";
|
|
242
165
|
if (storage) {
|
|
243
166
|
this.storage = storage;
|
|
244
167
|
} else if (typeof window !== "undefined" && window.localStorage) {
|
|
@@ -256,126 +179,111 @@ var LocalSessionStorage = class {
|
|
|
256
179
|
};
|
|
257
180
|
}
|
|
258
181
|
}
|
|
259
|
-
saveSession(session) {
|
|
260
|
-
this.storage.setItem(TOKEN_KEY, session.accessToken);
|
|
261
|
-
this.storage.setItem(USER_KEY, JSON.stringify(session.user));
|
|
262
|
-
}
|
|
263
|
-
getSession() {
|
|
264
|
-
const token = this.storage.getItem(TOKEN_KEY);
|
|
265
|
-
const userStr = this.storage.getItem(USER_KEY);
|
|
266
|
-
if (!token || !userStr) return null;
|
|
267
|
-
try {
|
|
268
|
-
const user = JSON.parse(userStr);
|
|
269
|
-
return { accessToken: token, user };
|
|
270
|
-
} catch {
|
|
271
|
-
this.clearSession();
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
getAccessToken() {
|
|
276
|
-
const token = this.storage.getItem(TOKEN_KEY);
|
|
277
|
-
return typeof token === "string" ? token : null;
|
|
278
|
-
}
|
|
279
|
-
setAccessToken(token) {
|
|
280
|
-
this.storage.setItem(TOKEN_KEY, token);
|
|
281
|
-
}
|
|
282
|
-
getUser() {
|
|
283
|
-
const userStr = this.storage.getItem(USER_KEY);
|
|
284
|
-
if (!userStr) return null;
|
|
285
|
-
try {
|
|
286
|
-
return JSON.parse(userStr);
|
|
287
|
-
} catch {
|
|
288
|
-
return null;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
setUser(user) {
|
|
292
|
-
this.storage.setItem(USER_KEY, JSON.stringify(user));
|
|
293
|
-
}
|
|
294
|
-
clearSession() {
|
|
295
|
-
this.storage.removeItem(TOKEN_KEY);
|
|
296
|
-
this.storage.removeItem(USER_KEY);
|
|
297
|
-
}
|
|
298
|
-
shouldAttemptRefresh() {
|
|
299
|
-
return false;
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
// src/lib/token-manager.ts
|
|
304
|
-
var TokenManager = class {
|
|
305
182
|
/**
|
|
306
|
-
*
|
|
307
|
-
* @param storage - Optional custom storage adapter (used for initial LocalSessionStorage)
|
|
183
|
+
* Get current mode
|
|
308
184
|
*/
|
|
309
|
-
|
|
310
|
-
this.
|
|
185
|
+
get mode() {
|
|
186
|
+
return this._mode;
|
|
311
187
|
}
|
|
312
188
|
/**
|
|
313
|
-
* Set
|
|
314
|
-
* Called after capability discovery to switch to the appropriate strategy
|
|
189
|
+
* Set mode to memory (new backend with cookies + memory)
|
|
315
190
|
*/
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
if (existingSession && previousId !== strategy.strategyId) {
|
|
321
|
-
strategy.saveSession(existingSession);
|
|
191
|
+
setMemoryMode() {
|
|
192
|
+
if (this._mode === "storage") {
|
|
193
|
+
this.storage.removeItem(TOKEN_KEY);
|
|
194
|
+
this.storage.removeItem(USER_KEY);
|
|
322
195
|
}
|
|
196
|
+
this._mode = "memory";
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Set mode to storage (legacy backend with localStorage)
|
|
200
|
+
* Also loads existing session from localStorage
|
|
201
|
+
*/
|
|
202
|
+
setStorageMode() {
|
|
203
|
+
this._mode = "storage";
|
|
204
|
+
this.loadFromStorage();
|
|
323
205
|
}
|
|
324
206
|
/**
|
|
325
|
-
*
|
|
207
|
+
* Load session from localStorage
|
|
326
208
|
*/
|
|
327
|
-
|
|
328
|
-
|
|
209
|
+
loadFromStorage() {
|
|
210
|
+
const token = this.storage.getItem(TOKEN_KEY);
|
|
211
|
+
const userStr = this.storage.getItem(USER_KEY);
|
|
212
|
+
if (token && userStr) {
|
|
213
|
+
try {
|
|
214
|
+
this.accessToken = token;
|
|
215
|
+
this.user = JSON.parse(userStr);
|
|
216
|
+
} catch {
|
|
217
|
+
this.clearSession();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
329
220
|
}
|
|
330
|
-
// --- Delegated Methods ---
|
|
331
221
|
/**
|
|
332
|
-
* Save session
|
|
222
|
+
* Save session (memory always, localStorage only in storage mode)
|
|
333
223
|
*/
|
|
334
224
|
saveSession(session) {
|
|
335
|
-
this.
|
|
225
|
+
this.accessToken = session.accessToken;
|
|
226
|
+
this.user = session.user;
|
|
227
|
+
if (this._mode === "storage") {
|
|
228
|
+
this.storage.setItem(TOKEN_KEY, session.accessToken);
|
|
229
|
+
this.storage.setItem(USER_KEY, JSON.stringify(session.user));
|
|
230
|
+
}
|
|
336
231
|
}
|
|
337
232
|
/**
|
|
338
233
|
* Get current session
|
|
339
234
|
*/
|
|
340
235
|
getSession() {
|
|
341
|
-
|
|
236
|
+
if (!this.accessToken || !this.user) return null;
|
|
237
|
+
return {
|
|
238
|
+
accessToken: this.accessToken,
|
|
239
|
+
user: this.user
|
|
240
|
+
};
|
|
342
241
|
}
|
|
343
242
|
/**
|
|
344
243
|
* Get access token
|
|
345
244
|
*/
|
|
346
245
|
getAccessToken() {
|
|
347
|
-
return this.
|
|
246
|
+
return this.accessToken;
|
|
348
247
|
}
|
|
349
248
|
/**
|
|
350
|
-
*
|
|
249
|
+
* Set access token
|
|
351
250
|
*/
|
|
352
251
|
setAccessToken(token) {
|
|
353
|
-
this.
|
|
252
|
+
this.accessToken = token;
|
|
253
|
+
if (this._mode === "storage") {
|
|
254
|
+
this.storage.setItem(TOKEN_KEY, token);
|
|
255
|
+
}
|
|
354
256
|
}
|
|
355
257
|
/**
|
|
356
|
-
* Get user
|
|
258
|
+
* Get user
|
|
357
259
|
*/
|
|
358
260
|
getUser() {
|
|
359
|
-
return this.
|
|
261
|
+
return this.user;
|
|
360
262
|
}
|
|
361
263
|
/**
|
|
362
|
-
*
|
|
264
|
+
* Set user
|
|
363
265
|
*/
|
|
364
266
|
setUser(user) {
|
|
365
|
-
this.
|
|
267
|
+
this.user = user;
|
|
268
|
+
if (this._mode === "storage") {
|
|
269
|
+
this.storage.setItem(USER_KEY, JSON.stringify(user));
|
|
270
|
+
}
|
|
366
271
|
}
|
|
367
272
|
/**
|
|
368
|
-
* Clear
|
|
273
|
+
* Clear session (both memory and localStorage)
|
|
369
274
|
*/
|
|
370
275
|
clearSession() {
|
|
371
|
-
this.
|
|
276
|
+
this.accessToken = null;
|
|
277
|
+
this.user = null;
|
|
278
|
+
this.storage.removeItem(TOKEN_KEY);
|
|
279
|
+
this.storage.removeItem(USER_KEY);
|
|
372
280
|
}
|
|
373
281
|
/**
|
|
374
|
-
* Check if
|
|
375
|
-
* (e.g., on page reload in secure mode)
|
|
282
|
+
* Check if there's a session in localStorage (for legacy detection)
|
|
376
283
|
*/
|
|
377
|
-
|
|
378
|
-
|
|
284
|
+
hasStoredSession() {
|
|
285
|
+
const token = this.storage.getItem(TOKEN_KEY);
|
|
286
|
+
return !!token;
|
|
379
287
|
}
|
|
380
288
|
};
|
|
381
289
|
|
|
@@ -492,77 +400,75 @@ var Auth = class {
|
|
|
492
400
|
this.detectAuthCallback();
|
|
493
401
|
}
|
|
494
402
|
/**
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
* Called when backend returns sessionMode: 'secure'
|
|
513
|
-
* @internal
|
|
514
|
-
*/
|
|
515
|
-
_switchToSecureStorage() {
|
|
516
|
-
console.log("[InsForge:Auth] _switchToSecureStorage() called, current strategy:", this.tokenManager.getStrategyId());
|
|
517
|
-
if (this.tokenManager.getStrategyId() === "secure") {
|
|
518
|
-
console.log("[InsForge:Auth] _switchToSecureStorage() - already in secure mode, skipping");
|
|
519
|
-
return;
|
|
403
|
+
* Restore session on app initialization
|
|
404
|
+
*
|
|
405
|
+
* @returns Object with isLoggedIn status
|
|
406
|
+
*
|
|
407
|
+
* @example
|
|
408
|
+
* ```typescript
|
|
409
|
+
* const client = new InsForgeClient({ baseUrl: '...' });
|
|
410
|
+
* const { isLoggedIn } = await client.auth.restoreSession();
|
|
411
|
+
*
|
|
412
|
+
* if (isLoggedIn) {
|
|
413
|
+
* const { data } = await client.auth.getCurrentUser();
|
|
414
|
+
* }
|
|
415
|
+
* ```
|
|
416
|
+
*/
|
|
417
|
+
async restoreSession() {
|
|
418
|
+
if (typeof window === "undefined") {
|
|
419
|
+
return { isLoggedIn: false };
|
|
520
420
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
if (typeof localStorage !== "undefined") {
|
|
524
|
-
console.log("[InsForge:Auth] _switchToSecureStorage() - clearing localStorage");
|
|
525
|
-
localStorage.removeItem(TOKEN_KEY);
|
|
526
|
-
localStorage.removeItem(USER_KEY);
|
|
421
|
+
if (this.tokenManager.getAccessToken()) {
|
|
422
|
+
return { isLoggedIn: true };
|
|
527
423
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
424
|
+
if (hasAuthCookie()) {
|
|
425
|
+
try {
|
|
426
|
+
const response = await this.http.post(
|
|
427
|
+
"/api/auth/refresh"
|
|
428
|
+
);
|
|
429
|
+
if (response.accessToken) {
|
|
430
|
+
this.tokenManager.setMemoryMode();
|
|
431
|
+
this.tokenManager.setAccessToken(response.accessToken);
|
|
432
|
+
this.http.setAuthToken(response.accessToken);
|
|
433
|
+
if (response.user) {
|
|
434
|
+
this.tokenManager.setUser(response.user);
|
|
435
|
+
}
|
|
436
|
+
return { isLoggedIn: true };
|
|
437
|
+
}
|
|
438
|
+
} catch (error) {
|
|
439
|
+
if (error instanceof InsForgeError) {
|
|
440
|
+
if (error.statusCode === 404) {
|
|
441
|
+
this.tokenManager.setStorageMode();
|
|
442
|
+
const token = this.tokenManager.getAccessToken();
|
|
443
|
+
if (token) {
|
|
444
|
+
this.http.setAuthToken(token);
|
|
445
|
+
return { isLoggedIn: true };
|
|
446
|
+
}
|
|
447
|
+
return { isLoggedIn: false };
|
|
448
|
+
}
|
|
449
|
+
if (error.statusCode === 401 || error.statusCode === 403) {
|
|
450
|
+
clearAuthCookie();
|
|
451
|
+
return { isLoggedIn: false };
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return { isLoggedIn: false };
|
|
455
|
+
}
|
|
532
456
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
if (this.tokenManager.getStrategyId() === "local") return;
|
|
541
|
-
const currentSession = this.tokenManager.getSession();
|
|
542
|
-
this.tokenManager.setStrategy(new LocalSessionStorage());
|
|
543
|
-
this.clearAuthenticatedCookie();
|
|
544
|
-
if (currentSession) {
|
|
545
|
-
this.tokenManager.saveSession(currentSession);
|
|
457
|
+
if (this.tokenManager.hasStoredSession()) {
|
|
458
|
+
this.tokenManager.setStorageMode();
|
|
459
|
+
const token = this.tokenManager.getAccessToken();
|
|
460
|
+
if (token) {
|
|
461
|
+
this.http.setAuthToken(token);
|
|
462
|
+
return { isLoggedIn: true };
|
|
463
|
+
}
|
|
546
464
|
}
|
|
465
|
+
return { isLoggedIn: false };
|
|
547
466
|
}
|
|
548
467
|
/**
|
|
549
|
-
*
|
|
550
|
-
*
|
|
551
|
-
*
|
|
468
|
+
* Automatically detect and handle OAuth callback parameters in the URL
|
|
469
|
+
* This runs on initialization to seamlessly complete the OAuth flow
|
|
470
|
+
* Matches the backend's OAuth callback response (backend/src/api/routes/auth.ts:540-544)
|
|
552
471
|
*/
|
|
553
|
-
_detectStorageFromResponse(sessionMode) {
|
|
554
|
-
console.log("[InsForge:Auth] _detectStorageFromResponse() - sessionMode:", sessionMode);
|
|
555
|
-
if (sessionMode === "secure") {
|
|
556
|
-
this._switchToSecureStorage();
|
|
557
|
-
} else {
|
|
558
|
-
this._switchToLocalStorage();
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
/**
|
|
562
|
-
* Automatically detect and handle OAuth callback parameters in the URL
|
|
563
|
-
* This runs on initialization to seamlessly complete the OAuth flow
|
|
564
|
-
* Matches the backend's OAuth callback response (backend/src/api/routes/auth.ts:540-544)
|
|
565
|
-
*/
|
|
566
472
|
detectAuthCallback() {
|
|
567
473
|
if (typeof window === "undefined") return;
|
|
568
474
|
try {
|
|
@@ -571,9 +477,7 @@ var Auth = class {
|
|
|
571
477
|
const userId = params.get("user_id");
|
|
572
478
|
const email = params.get("email");
|
|
573
479
|
const name = params.get("name");
|
|
574
|
-
const sessionMode = params.get("session_mode");
|
|
575
480
|
if (accessToken && userId && email) {
|
|
576
|
-
this._detectStorageFromResponse(sessionMode || void 0);
|
|
577
481
|
const session = {
|
|
578
482
|
accessToken,
|
|
579
483
|
user: {
|
|
@@ -587,14 +491,14 @@ var Auth = class {
|
|
|
587
491
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
588
492
|
}
|
|
589
493
|
};
|
|
590
|
-
this.tokenManager.saveSession(session);
|
|
591
494
|
this.http.setAuthToken(accessToken);
|
|
495
|
+
this.tokenManager.saveSession(session);
|
|
496
|
+
setAuthCookie();
|
|
592
497
|
const url = new URL(window.location.href);
|
|
593
498
|
url.searchParams.delete("access_token");
|
|
594
499
|
url.searchParams.delete("user_id");
|
|
595
500
|
url.searchParams.delete("email");
|
|
596
501
|
url.searchParams.delete("name");
|
|
597
|
-
url.searchParams.delete("session_mode");
|
|
598
502
|
if (params.has("error")) {
|
|
599
503
|
url.searchParams.delete("error");
|
|
600
504
|
}
|
|
@@ -610,16 +514,13 @@ var Auth = class {
|
|
|
610
514
|
async signUp(request) {
|
|
611
515
|
try {
|
|
612
516
|
const response = await this.http.post("/api/auth/users", request);
|
|
613
|
-
|
|
614
|
-
this._detectStorageFromResponse(sessionMode);
|
|
615
|
-
if (response.accessToken && response.user) {
|
|
517
|
+
if (response.accessToken && response.user && !isHostedAuthEnvironment()) {
|
|
616
518
|
const session = {
|
|
617
519
|
accessToken: response.accessToken,
|
|
618
520
|
user: response.user
|
|
619
521
|
};
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
}
|
|
522
|
+
this.tokenManager.saveSession(session);
|
|
523
|
+
setAuthCookie();
|
|
623
524
|
this.http.setAuthToken(response.accessToken);
|
|
624
525
|
}
|
|
625
526
|
return {
|
|
@@ -646,23 +547,15 @@ var Auth = class {
|
|
|
646
547
|
async signInWithPassword(request) {
|
|
647
548
|
try {
|
|
648
549
|
const response = await this.http.post("/api/auth/sessions", request);
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
id: "",
|
|
655
|
-
email: "",
|
|
656
|
-
name: "",
|
|
657
|
-
emailVerified: false,
|
|
658
|
-
createdAt: "",
|
|
659
|
-
updatedAt: ""
|
|
660
|
-
}
|
|
661
|
-
};
|
|
662
|
-
if (!isHostedAuthEnvironment()) {
|
|
550
|
+
if (response.accessToken && response.user && !isHostedAuthEnvironment()) {
|
|
551
|
+
const session = {
|
|
552
|
+
accessToken: response.accessToken,
|
|
553
|
+
user: response.user
|
|
554
|
+
};
|
|
663
555
|
this.tokenManager.saveSession(session);
|
|
556
|
+
setAuthCookie();
|
|
557
|
+
this.http.setAuthToken(response.accessToken);
|
|
664
558
|
}
|
|
665
|
-
this.http.setAuthToken(response.accessToken || "");
|
|
666
559
|
return {
|
|
667
560
|
data: response,
|
|
668
561
|
error: null
|
|
@@ -717,28 +610,18 @@ var Auth = class {
|
|
|
717
610
|
}
|
|
718
611
|
/**
|
|
719
612
|
* Sign out the current user
|
|
720
|
-
* In modern mode, also calls backend to clear the refresh token cookie
|
|
721
613
|
*/
|
|
722
614
|
async signOut() {
|
|
723
|
-
console.log("[InsForge:Auth] signOut() called");
|
|
724
|
-
console.log("[InsForge:Auth] signOut() stack trace:", new Error().stack);
|
|
725
615
|
try {
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
await this.http.post("/api/auth/logout");
|
|
730
|
-
console.log("[InsForge:Auth] signOut() - backend logout successful");
|
|
731
|
-
} catch (e) {
|
|
732
|
-
console.log("[InsForge:Auth] signOut() - backend logout failed (ignored):", e);
|
|
733
|
-
}
|
|
616
|
+
try {
|
|
617
|
+
await this.http.post("/api/auth/logout");
|
|
618
|
+
} catch {
|
|
734
619
|
}
|
|
735
620
|
this.tokenManager.clearSession();
|
|
736
621
|
this.http.setAuthToken(null);
|
|
737
|
-
|
|
738
|
-
console.log("[InsForge:Auth] signOut() - completed");
|
|
622
|
+
clearAuthCookie();
|
|
739
623
|
return { error: null };
|
|
740
624
|
} catch (error) {
|
|
741
|
-
console.error("[InsForge:Auth] signOut() - error:", error);
|
|
742
625
|
return {
|
|
743
626
|
error: new InsForgeError(
|
|
744
627
|
"Failed to sign out",
|
|
@@ -748,58 +631,6 @@ var Auth = class {
|
|
|
748
631
|
};
|
|
749
632
|
}
|
|
750
633
|
}
|
|
751
|
-
/**
|
|
752
|
-
* Refresh the access token using the httpOnly refresh token cookie
|
|
753
|
-
* Only works when backend supports secure session storage (httpOnly cookies)
|
|
754
|
-
*
|
|
755
|
-
* @returns New access token or throws an error
|
|
756
|
-
*/
|
|
757
|
-
async refreshToken() {
|
|
758
|
-
console.log("[InsForge:Auth] refreshToken() called");
|
|
759
|
-
try {
|
|
760
|
-
const response = await this.http.post(
|
|
761
|
-
"/api/auth/refresh"
|
|
762
|
-
);
|
|
763
|
-
console.log("[InsForge:Auth] refreshToken() - response received, hasAccessToken:", !!response.accessToken);
|
|
764
|
-
if (response.accessToken) {
|
|
765
|
-
this._detectStorageFromResponse(response.sessionMode);
|
|
766
|
-
this.tokenManager.setAccessToken(response.accessToken);
|
|
767
|
-
this.http.setAuthToken(response.accessToken);
|
|
768
|
-
if (response.user) {
|
|
769
|
-
this.tokenManager.setUser(response.user);
|
|
770
|
-
}
|
|
771
|
-
console.log("[InsForge:Auth] refreshToken() - success");
|
|
772
|
-
return response.accessToken;
|
|
773
|
-
}
|
|
774
|
-
throw new InsForgeError(
|
|
775
|
-
"No access token in refresh response",
|
|
776
|
-
500,
|
|
777
|
-
"REFRESH_FAILED"
|
|
778
|
-
);
|
|
779
|
-
} catch (error) {
|
|
780
|
-
console.error("[InsForge:Auth] refreshToken() - error:", error);
|
|
781
|
-
if (error instanceof InsForgeError) {
|
|
782
|
-
if (error.statusCode === 404) {
|
|
783
|
-
console.log("[InsForge:Auth] refreshToken() - 404 detected, backend does not support refresh endpoint");
|
|
784
|
-
console.log("[InsForge:Auth] refreshToken() - switching to LocalSessionStorage for backward compatibility");
|
|
785
|
-
this._switchToLocalStorage();
|
|
786
|
-
this.clearAuthenticatedCookie();
|
|
787
|
-
}
|
|
788
|
-
if (error.statusCode === 401 || error.statusCode === 403) {
|
|
789
|
-
console.log("[InsForge:Auth] refreshToken() - clearing session due to 401/403");
|
|
790
|
-
this.tokenManager.clearSession();
|
|
791
|
-
this.http.setAuthToken(null);
|
|
792
|
-
this.clearAuthenticatedCookie();
|
|
793
|
-
}
|
|
794
|
-
throw error;
|
|
795
|
-
}
|
|
796
|
-
throw new InsForgeError(
|
|
797
|
-
"Token refresh failed",
|
|
798
|
-
500,
|
|
799
|
-
"REFRESH_FAILED"
|
|
800
|
-
);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
634
|
/**
|
|
804
635
|
* Get all public authentication configuration (OAuth + Email)
|
|
805
636
|
* Returns both OAuth providers and email authentication settings in one request
|
|
@@ -840,40 +671,19 @@ var Auth = class {
|
|
|
840
671
|
/**
|
|
841
672
|
* Get the current user with full profile information
|
|
842
673
|
* Returns both auth info (id, email, role) and profile data (dynamic fields from users table)
|
|
843
|
-
*
|
|
844
|
-
* In secure session mode (httpOnly cookie), this method will automatically attempt
|
|
845
|
-
* to refresh the session if no access token is available (e.g., after page reload).
|
|
846
674
|
*/
|
|
847
675
|
async getCurrentUser() {
|
|
848
|
-
console.log("[InsForge:Auth] getCurrentUser() called");
|
|
849
676
|
try {
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
console.log("[InsForge:Auth] getCurrentUser() - hasAccessToken:", !!accessToken, "shouldAttemptRefresh:", shouldRefresh);
|
|
853
|
-
if (!accessToken && shouldRefresh) {
|
|
854
|
-
console.log("[InsForge:Auth] getCurrentUser() - attempting refresh");
|
|
855
|
-
try {
|
|
856
|
-
accessToken = await this.refreshToken();
|
|
857
|
-
} catch (error) {
|
|
858
|
-
console.log("[InsForge:Auth] getCurrentUser() - refresh failed:", error);
|
|
859
|
-
if (error instanceof InsForgeError && (error.statusCode === 401 || error.statusCode === 403)) {
|
|
860
|
-
return { data: null, error };
|
|
861
|
-
}
|
|
862
|
-
return { data: null, error: error instanceof InsForgeError ? error : new InsForgeError("Token refresh failed", 500, "REFRESH_FAILED") };
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
if (!accessToken) {
|
|
866
|
-
console.log("[InsForge:Auth] getCurrentUser() - no access token, returning null");
|
|
677
|
+
const session = this.tokenManager.getSession();
|
|
678
|
+
if (!session?.accessToken) {
|
|
867
679
|
return { data: null, error: null };
|
|
868
680
|
}
|
|
869
|
-
this.http.setAuthToken(accessToken);
|
|
870
|
-
console.log("[InsForge:Auth] getCurrentUser() - fetching user from API");
|
|
681
|
+
this.http.setAuthToken(session.accessToken);
|
|
871
682
|
const authResponse = await this.http.get("/api/auth/sessions/current");
|
|
872
683
|
const { data: profile, error: profileError } = await this.database.from("users").select("*").eq("id", authResponse.user.id).single();
|
|
873
684
|
if (profileError && profileError.code !== "PGRST116") {
|
|
874
685
|
return { data: null, error: profileError };
|
|
875
686
|
}
|
|
876
|
-
console.log("[InsForge:Auth] getCurrentUser() - success");
|
|
877
687
|
return {
|
|
878
688
|
data: {
|
|
879
689
|
user: authResponse.user,
|
|
@@ -882,12 +692,8 @@ var Auth = class {
|
|
|
882
692
|
error: null
|
|
883
693
|
};
|
|
884
694
|
} catch (error) {
|
|
885
|
-
console.error("[InsForge:Auth] getCurrentUser() - catch error:", error);
|
|
886
695
|
if (error instanceof InsForgeError && error.statusCode === 401) {
|
|
887
|
-
|
|
888
|
-
this.tokenManager.clearSession();
|
|
889
|
-
this.http.setAuthToken(null);
|
|
890
|
-
this.clearAuthenticatedCookie();
|
|
696
|
+
await this.signOut();
|
|
891
697
|
return { data: null, error: null };
|
|
892
698
|
}
|
|
893
699
|
if (error instanceof InsForgeError) {
|
|
@@ -1135,15 +941,14 @@ var Auth = class {
|
|
|
1135
941
|
"/api/auth/email/verify",
|
|
1136
942
|
request
|
|
1137
943
|
);
|
|
1138
|
-
|
|
1139
|
-
this._detectStorageFromResponse(sessionMode);
|
|
1140
|
-
if (response.accessToken) {
|
|
944
|
+
if (response.accessToken && !isHostedAuthEnvironment()) {
|
|
1141
945
|
const session = {
|
|
1142
946
|
accessToken: response.accessToken,
|
|
1143
947
|
user: response.user || {}
|
|
1144
948
|
};
|
|
1145
949
|
this.tokenManager.saveSession(session);
|
|
1146
950
|
this.http.setAuthToken(response.accessToken);
|
|
951
|
+
setAuthCookie();
|
|
1147
952
|
}
|
|
1148
953
|
return {
|
|
1149
954
|
data: response,
|
|
@@ -1687,24 +1492,10 @@ var Functions = class {
|
|
|
1687
1492
|
};
|
|
1688
1493
|
|
|
1689
1494
|
// src/client.ts
|
|
1690
|
-
function hasAuthenticatedCookie() {
|
|
1691
|
-
if (typeof document === "undefined") return false;
|
|
1692
|
-
return document.cookie.split(";").some(
|
|
1693
|
-
(c) => c.trim().startsWith(`${AUTH_FLAG_COOKIE}=`)
|
|
1694
|
-
);
|
|
1695
|
-
}
|
|
1696
1495
|
var InsForgeClient = class {
|
|
1697
1496
|
constructor(config = {}) {
|
|
1698
|
-
console.log("[InsForge:Client] Initializing SDK");
|
|
1699
1497
|
this.http = new HttpClient(config);
|
|
1700
1498
|
this.tokenManager = new TokenManager(config.storage);
|
|
1701
|
-
const hasAuthCookie = hasAuthenticatedCookie();
|
|
1702
|
-
console.log("[InsForge:Client] hasAuthenticatedCookie:", hasAuthCookie);
|
|
1703
|
-
console.log("[InsForge:Client] document.cookie:", typeof document !== "undefined" ? document.cookie : "N/A (SSR)");
|
|
1704
|
-
if (hasAuthCookie) {
|
|
1705
|
-
console.log("[InsForge:Client] Switching to SecureSessionStorage");
|
|
1706
|
-
this.tokenManager.setStrategy(new SecureSessionStorage());
|
|
1707
|
-
}
|
|
1708
1499
|
if (config.edgeFunctionToken) {
|
|
1709
1500
|
this.http.setAuthToken(config.edgeFunctionToken);
|
|
1710
1501
|
this.tokenManager.saveSession({
|
|
@@ -1713,32 +1504,15 @@ var InsForgeClient = class {
|
|
|
1713
1504
|
// Will be populated by getCurrentUser()
|
|
1714
1505
|
});
|
|
1715
1506
|
}
|
|
1716
|
-
this.http.setRefreshCallback(async () => {
|
|
1717
|
-
console.log("[InsForge:Client] HTTP 401 refresh callback triggered");
|
|
1718
|
-
try {
|
|
1719
|
-
return await this.auth.refreshToken();
|
|
1720
|
-
} catch (e) {
|
|
1721
|
-
console.log("[InsForge:Client] Refresh callback failed:", e);
|
|
1722
|
-
if (this.tokenManager.getStrategyId() === "secure") {
|
|
1723
|
-
console.log("[InsForge:Client] Falling back to LocalSessionStorage");
|
|
1724
|
-
this.auth._switchToLocalStorage();
|
|
1725
|
-
}
|
|
1726
|
-
return null;
|
|
1727
|
-
}
|
|
1728
|
-
});
|
|
1729
1507
|
const existingSession = this.tokenManager.getSession();
|
|
1730
|
-
console.log("[InsForge:Client] existingSession:", !!existingSession, "strategyId:", this.tokenManager.getStrategyId());
|
|
1731
1508
|
if (existingSession?.accessToken) {
|
|
1732
1509
|
this.http.setAuthToken(existingSession.accessToken);
|
|
1733
|
-
} else if (this.tokenManager.getStrategyId() === "secure") {
|
|
1734
|
-
console.log("[InsForge:Client] Secure mode, no session in memory - will refresh on first API call");
|
|
1735
1510
|
}
|
|
1736
1511
|
this.auth = new Auth(this.http, this.tokenManager);
|
|
1737
1512
|
this.database = new Database(this.http, this.tokenManager);
|
|
1738
1513
|
this.storage = new Storage(this.http);
|
|
1739
1514
|
this.ai = new AI(this.http);
|
|
1740
1515
|
this.functions = new Functions(this.http);
|
|
1741
|
-
console.log("[InsForge:Client] SDK initialized");
|
|
1742
1516
|
}
|
|
1743
1517
|
/**
|
|
1744
1518
|
* Get the underlying HTTP client for custom requests
|
|
@@ -1752,12 +1526,6 @@ var InsForgeClient = class {
|
|
|
1752
1526
|
getHttpClient() {
|
|
1753
1527
|
return this.http;
|
|
1754
1528
|
}
|
|
1755
|
-
/**
|
|
1756
|
-
* Get the current storage strategy identifier
|
|
1757
|
-
*/
|
|
1758
|
-
getStorageStrategy() {
|
|
1759
|
-
return this.tokenManager.getStrategyId();
|
|
1760
|
-
}
|
|
1761
1529
|
/**
|
|
1762
1530
|
* Future modules will be added here:
|
|
1763
1531
|
* - database: Database operations
|
|
@@ -1781,8 +1549,6 @@ export {
|
|
|
1781
1549
|
HttpClient,
|
|
1782
1550
|
InsForgeClient,
|
|
1783
1551
|
InsForgeError,
|
|
1784
|
-
LocalSessionStorage,
|
|
1785
|
-
SecureSessionStorage,
|
|
1786
1552
|
Storage,
|
|
1787
1553
|
StorageBucket,
|
|
1788
1554
|
TokenManager,
|