lemma-sdk 0.2.21 → 0.2.22

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/auth.d.ts CHANGED
@@ -102,6 +102,13 @@ export declare class AuthManager {
102
102
  private setState;
103
103
  private assertBrowserContext;
104
104
  private getCookie;
105
+ private getCookieDomainCandidates;
106
+ private expireCookie;
107
+ /**
108
+ * Defensive cleanup for stale SuperTokens frontend marker cookies/storage.
109
+ * This helps recover when signout/session-expiry paths leave local markers behind.
110
+ */
111
+ private clearFrontendSessionMarkers;
105
112
  private clearInjectedToken;
106
113
  private rawSignOutViaBackend;
107
114
  /**
package/dist/auth.js CHANGED
@@ -18,6 +18,14 @@
18
18
  import Session from "supertokens-web-js/recipe/session";
19
19
  import { ensureCookieSessionSupport } from "./supertokens.js";
20
20
  const DEFAULT_BLOCKED_REDIRECT_PATHS = ["/login", "/signup", "/auth"];
21
+ const SUPERTOKENS_FRONTEND_MARKER_KEYS = [
22
+ "sFrontToken",
23
+ "st-last-access-token-update",
24
+ "sIRTFrontend",
25
+ "sAntiCsrf",
26
+ "st-access-token",
27
+ "st-refresh-token",
28
+ ];
21
29
  const LOCALSTORAGE_TOKEN_KEY = "lemma_token";
22
30
  function readStorageToken() {
23
31
  if (typeof window === "undefined")
@@ -214,6 +222,62 @@ export class AuthManager {
214
222
  const match = document.cookie.match(new RegExp(`(?:^|; )${escaped}=([^;]*)`));
215
223
  return match ? decodeURIComponent(match[1]) : undefined;
216
224
  }
225
+ getCookieDomainCandidates() {
226
+ if (typeof window === "undefined") {
227
+ return [undefined];
228
+ }
229
+ const host = window.location.hostname;
230
+ const isIpv4 = /^\d{1,3}(?:\.\d{1,3}){3}$/.test(host);
231
+ const isIpv6 = host.includes(":");
232
+ if (!host || host === "localhost" || isIpv4 || isIpv6) {
233
+ return [undefined];
234
+ }
235
+ const domains = new Set();
236
+ const parts = host.split(".").filter(Boolean);
237
+ for (let i = 0; i < parts.length - 1; i += 1) {
238
+ const candidate = parts.slice(i).join(".");
239
+ if (!candidate)
240
+ continue;
241
+ domains.add(candidate);
242
+ domains.add(`.${candidate}`);
243
+ }
244
+ return [undefined, ...domains];
245
+ }
246
+ expireCookie(name, domain) {
247
+ if (typeof document === "undefined")
248
+ return;
249
+ const domainPart = domain ? `;domain=${domain}` : "";
250
+ document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;max-age=0;path=/${domainPart};samesite=lax`;
251
+ document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;max-age=0;path=/${domainPart}`;
252
+ }
253
+ /**
254
+ * Defensive cleanup for stale SuperTokens frontend marker cookies/storage.
255
+ * This helps recover when signout/session-expiry paths leave local markers behind.
256
+ */
257
+ clearFrontendSessionMarkers() {
258
+ if (typeof window === "undefined")
259
+ return;
260
+ for (const key of SUPERTOKENS_FRONTEND_MARKER_KEYS) {
261
+ try {
262
+ window.localStorage.removeItem(key);
263
+ }
264
+ catch {
265
+ // ignore storage errors
266
+ }
267
+ try {
268
+ window.sessionStorage.removeItem(key);
269
+ }
270
+ catch {
271
+ // ignore storage errors
272
+ }
273
+ }
274
+ const domains = this.getCookieDomainCandidates();
275
+ for (const key of SUPERTOKENS_FRONTEND_MARKER_KEYS) {
276
+ for (const domain of domains) {
277
+ this.expireCookie(key, domain);
278
+ }
279
+ }
280
+ }
217
281
  clearInjectedToken() {
218
282
  this.injectedToken = null;
219
283
  clearTestingToken();
@@ -322,6 +386,7 @@ export class AuthManager {
322
386
  const response = await fetch(`${this.apiUrl}/users/me`, this.getRequestInit({ method: "GET" }));
323
387
  // Only 401 means not authenticated — 403 means authenticated but forbidden
324
388
  if (response.status === 401) {
389
+ this.clearFrontendSessionMarkers();
325
390
  const next = { status: "unauthenticated", user: null };
326
391
  this.setState(next);
327
392
  return next;
@@ -348,6 +413,7 @@ export class AuthManager {
348
413
  * Does NOT redirect — call redirectToAuth() explicitly if desired.
349
414
  */
350
415
  markUnauthenticated() {
416
+ this.clearFrontendSessionMarkers();
351
417
  this.setState({ status: "unauthenticated", user: null });
352
418
  }
353
419
  /**
@@ -204,6 +204,14 @@ exports.resolveSafeRedirectUri = resolveSafeRedirectUri;
204
204
  const session_1 = require("supertokens-web-js/recipe/session");
205
205
  const supertokens_js_1 = require("./supertokens.js");
206
206
  const DEFAULT_BLOCKED_REDIRECT_PATHS = ["/login", "/signup", "/auth"];
207
+ const SUPERTOKENS_FRONTEND_MARKER_KEYS = [
208
+ "sFrontToken",
209
+ "st-last-access-token-update",
210
+ "sIRTFrontend",
211
+ "sAntiCsrf",
212
+ "st-access-token",
213
+ "st-refresh-token",
214
+ ];
207
215
  const LOCALSTORAGE_TOKEN_KEY = "lemma_token";
208
216
  function readStorageToken() {
209
217
  if (typeof window === "undefined")
@@ -397,6 +405,62 @@ class AuthManager {
397
405
  const match = document.cookie.match(new RegExp(`(?:^|; )${escaped}=([^;]*)`));
398
406
  return match ? decodeURIComponent(match[1]) : undefined;
399
407
  }
408
+ getCookieDomainCandidates() {
409
+ if (typeof window === "undefined") {
410
+ return [undefined];
411
+ }
412
+ const host = window.location.hostname;
413
+ const isIpv4 = /^\d{1,3}(?:\.\d{1,3}){3}$/.test(host);
414
+ const isIpv6 = host.includes(":");
415
+ if (!host || host === "localhost" || isIpv4 || isIpv6) {
416
+ return [undefined];
417
+ }
418
+ const domains = new Set();
419
+ const parts = host.split(".").filter(Boolean);
420
+ for (let i = 0; i < parts.length - 1; i += 1) {
421
+ const candidate = parts.slice(i).join(".");
422
+ if (!candidate)
423
+ continue;
424
+ domains.add(candidate);
425
+ domains.add(`.${candidate}`);
426
+ }
427
+ return [undefined, ...domains];
428
+ }
429
+ expireCookie(name, domain) {
430
+ if (typeof document === "undefined")
431
+ return;
432
+ const domainPart = domain ? `;domain=${domain}` : "";
433
+ document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;max-age=0;path=/${domainPart};samesite=lax`;
434
+ document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;max-age=0;path=/${domainPart}`;
435
+ }
436
+ /**
437
+ * Defensive cleanup for stale SuperTokens frontend marker cookies/storage.
438
+ * This helps recover when signout/session-expiry paths leave local markers behind.
439
+ */
440
+ clearFrontendSessionMarkers() {
441
+ if (typeof window === "undefined")
442
+ return;
443
+ for (const key of SUPERTOKENS_FRONTEND_MARKER_KEYS) {
444
+ try {
445
+ window.localStorage.removeItem(key);
446
+ }
447
+ catch {
448
+ // ignore storage errors
449
+ }
450
+ try {
451
+ window.sessionStorage.removeItem(key);
452
+ }
453
+ catch {
454
+ // ignore storage errors
455
+ }
456
+ }
457
+ const domains = this.getCookieDomainCandidates();
458
+ for (const key of SUPERTOKENS_FRONTEND_MARKER_KEYS) {
459
+ for (const domain of domains) {
460
+ this.expireCookie(key, domain);
461
+ }
462
+ }
463
+ }
400
464
  clearInjectedToken() {
401
465
  this.injectedToken = null;
402
466
  clearTestingToken();
@@ -505,6 +569,7 @@ class AuthManager {
505
569
  const response = await fetch(`${this.apiUrl}/users/me`, this.getRequestInit({ method: "GET" }));
506
570
  // Only 401 means not authenticated — 403 means authenticated but forbidden
507
571
  if (response.status === 401) {
572
+ this.clearFrontendSessionMarkers();
508
573
  const next = { status: "unauthenticated", user: null };
509
574
  this.setState(next);
510
575
  return next;
@@ -531,6 +596,7 @@ class AuthManager {
531
596
  * Does NOT redirect — call redirectToAuth() explicitly if desired.
532
597
  */
533
598
  markUnauthenticated() {
599
+ this.clearFrontendSessionMarkers();
534
600
  this.setState({ status: "unauthenticated", user: null });
535
601
  }
536
602
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lemma-sdk",
3
- "version": "0.2.21",
3
+ "version": "0.2.22",
4
4
  "description": "Official TypeScript SDK for Lemma pod-scoped APIs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",