@arcote.tech/arc-adapter-db-sqlite 0.8.4 → 0.8.6

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.
Files changed (2) hide show
  1. package/dist/index.js +104 -48
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1353,9 +1353,74 @@ function apply(state, patches, applyOptions) {
1353
1353
  var constructorString = Object.prototype.constructor.toString();
1354
1354
 
1355
1355
  // ../../../core/dist/index.js
1356
- var TOKEN_PREFIX = "arc:token:";
1357
- function hasLocalStorage() {
1358
- return typeof localStorage !== "undefined";
1356
+ var COOKIE_PREFIX = "arc_token";
1357
+ var TOKEN_BUMP_KEY = "arc:token-bump";
1358
+ function hasDocument() {
1359
+ return typeof document !== "undefined";
1360
+ }
1361
+ function signalCrossTabChange() {
1362
+ if (typeof localStorage === "undefined")
1363
+ return;
1364
+ try {
1365
+ localStorage.setItem(TOKEN_BUMP_KEY, String(Date.now()));
1366
+ } catch {}
1367
+ }
1368
+ function isSecureContext() {
1369
+ return typeof location !== "undefined" && location.protocol === "https:";
1370
+ }
1371
+ function tokenCookieName(scopeKey) {
1372
+ return scopeKey === "default" ? COOKIE_PREFIX : `${COOKIE_PREFIX}_${scopeKey.replace(/:/g, ".")}`;
1373
+ }
1374
+ function scopeKeyFromCookieName(name) {
1375
+ if (name === COOKIE_PREFIX)
1376
+ return "default";
1377
+ if (!name.startsWith(`${COOKIE_PREFIX}_`))
1378
+ return null;
1379
+ return name.slice(COOKIE_PREFIX.length + 1).replace(/\./g, ":");
1380
+ }
1381
+ function maxAgeFromExp(exp) {
1382
+ const THIRTY_DAYS = 30 * 24 * 60 * 60;
1383
+ if (typeof exp !== "number" || !Number.isFinite(exp))
1384
+ return THIRTY_DAYS;
1385
+ const expMs = exp > 1000000000000 ? exp : exp * 1000;
1386
+ const secs = Math.floor((expMs - Date.now()) / 1000);
1387
+ return secs > 0 ? secs : THIRTY_DAYS;
1388
+ }
1389
+ function writeTokenCookie(scopeKey, jwt, exp) {
1390
+ if (!hasDocument())
1391
+ return;
1392
+ const attrs = [
1393
+ "Path=/",
1394
+ "SameSite=Lax",
1395
+ `Max-Age=${maxAgeFromExp(exp)}`
1396
+ ];
1397
+ if (isSecureContext())
1398
+ attrs.push("Secure");
1399
+ document.cookie = `${tokenCookieName(scopeKey)}=${encodeURIComponent(jwt)}; ${attrs.join("; ")}`;
1400
+ signalCrossTabChange();
1401
+ }
1402
+ function removeTokenCookie(scopeKey) {
1403
+ if (!hasDocument())
1404
+ return;
1405
+ document.cookie = `${tokenCookieName(scopeKey)}=; Path=/; SameSite=Lax; Max-Age=0`;
1406
+ signalCrossTabChange();
1407
+ }
1408
+ function readAllTokenCookies() {
1409
+ if (!hasDocument() || !document.cookie)
1410
+ return [];
1411
+ const out = [];
1412
+ for (const part of document.cookie.split(";")) {
1413
+ const eq = part.indexOf("=");
1414
+ if (eq < 0)
1415
+ continue;
1416
+ const scopeKey = scopeKeyFromCookieName(part.slice(0, eq).trim());
1417
+ if (scopeKey === null)
1418
+ continue;
1419
+ const jwt = decodeURIComponent(part.slice(eq + 1).trim());
1420
+ if (jwt)
1421
+ out.push({ scopeKey, jwt });
1422
+ }
1423
+ return out;
1359
1424
  }
1360
1425
  function notifyTokenChange(scope) {
1361
1426
  if (typeof window !== "undefined") {
@@ -1371,24 +1436,21 @@ class AuthAdapter {
1371
1436
  constructor(options) {
1372
1437
  this.namespace = options?.storageNamespace || undefined;
1373
1438
  }
1374
- storageKey(scope) {
1375
- return this.namespace ? `${TOKEN_PREFIX}${this.namespace}:${scope}` : TOKEN_PREFIX + scope;
1439
+ scopeKey(scope) {
1440
+ return this.namespace ? `${this.namespace}:${scope}` : scope;
1376
1441
  }
1377
1442
  setToken(token, scope = "default") {
1378
1443
  if (!token) {
1379
1444
  this.scopes.delete(scope);
1380
- if (hasLocalStorage()) {
1381
- localStorage.removeItem(this.storageKey(scope));
1382
- notifyTokenChange(scope);
1383
- }
1445
+ removeTokenCookie(this.scopeKey(scope));
1446
+ notifyTokenChange(scope);
1384
1447
  return;
1385
1448
  }
1386
1449
  try {
1387
1450
  const parts = token.split(".");
1388
1451
  if (parts.length !== 3) {
1389
1452
  this.scopes.delete(scope);
1390
- if (hasLocalStorage())
1391
- localStorage.removeItem(this.storageKey(scope));
1453
+ removeTokenCookie(this.scopeKey(scope));
1392
1454
  return;
1393
1455
  }
1394
1456
  const payload = JSON.parse(atob(parts[1]));
@@ -1401,49 +1463,45 @@ class AuthAdapter {
1401
1463
  exp: payload.exp
1402
1464
  }
1403
1465
  });
1404
- if (hasLocalStorage()) {
1405
- localStorage.setItem(this.storageKey(scope), token);
1406
- notifyTokenChange(scope);
1407
- }
1466
+ writeTokenCookie(this.scopeKey(scope), token, payload.exp);
1467
+ notifyTokenChange(scope);
1408
1468
  } catch {
1409
1469
  this.scopes.delete(scope);
1410
- if (hasLocalStorage())
1411
- localStorage.removeItem(this.storageKey(scope));
1470
+ removeTokenCookie(this.scopeKey(scope));
1412
1471
  }
1413
1472
  }
1414
1473
  setDecoded(decoded, scope = "default") {
1415
1474
  this.scopes.set(scope, { raw: "", decoded });
1416
1475
  }
1417
1476
  loadPersisted() {
1418
- if (!hasLocalStorage())
1419
- return;
1420
- const prefix = this.namespace ? `${TOKEN_PREFIX}${this.namespace}:` : TOKEN_PREFIX;
1421
- for (let i = 0;i < localStorage.length; i++) {
1422
- const key = localStorage.key(i);
1423
- if (key?.startsWith(prefix)) {
1424
- const scope = key.slice(prefix.length);
1425
- if (!this.namespace && scope.includes(":"))
1477
+ const nsPrefix = this.namespace ? `${this.namespace}:` : "";
1478
+ for (const { scopeKey, jwt } of readAllTokenCookies()) {
1479
+ let scope;
1480
+ if (this.namespace) {
1481
+ if (!scopeKey.startsWith(nsPrefix))
1426
1482
  continue;
1427
- const raw = localStorage.getItem(key);
1428
- if (raw) {
1429
- try {
1430
- const parts = raw.split(".");
1431
- if (parts.length !== 3)
1432
- continue;
1433
- const payload = JSON.parse(atob(parts[1]));
1434
- this.scopes.set(scope, {
1435
- raw,
1436
- decoded: {
1437
- tokenName: payload.tokenName,
1438
- params: payload.params || {},
1439
- iat: payload.iat,
1440
- exp: payload.exp
1441
- }
1442
- });
1443
- } catch {
1444
- localStorage.removeItem(key);
1483
+ scope = scopeKey.slice(nsPrefix.length);
1484
+ } else {
1485
+ if (scopeKey.includes(":"))
1486
+ continue;
1487
+ scope = scopeKey;
1488
+ }
1489
+ try {
1490
+ const parts = jwt.split(".");
1491
+ if (parts.length !== 3)
1492
+ continue;
1493
+ const payload = JSON.parse(atob(parts[1]));
1494
+ this.scopes.set(scope, {
1495
+ raw: jwt,
1496
+ decoded: {
1497
+ tokenName: payload.tokenName,
1498
+ params: payload.params || {},
1499
+ iat: payload.iat,
1500
+ exp: payload.exp
1445
1501
  }
1446
- }
1502
+ });
1503
+ } catch {
1504
+ removeTokenCookie(scopeKey);
1447
1505
  }
1448
1506
  }
1449
1507
  }
@@ -1475,10 +1533,8 @@ class AuthAdapter {
1475
1533
  return Array.from(this.scopes.keys());
1476
1534
  }
1477
1535
  clear() {
1478
- if (hasLocalStorage()) {
1479
- for (const scope of this.scopes.keys()) {
1480
- localStorage.removeItem(this.storageKey(scope));
1481
- }
1536
+ for (const scope of this.scopes.keys()) {
1537
+ removeTokenCookie(this.scopeKey(scope));
1482
1538
  }
1483
1539
  this.scopes.clear();
1484
1540
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcote.tech/arc-adapter-db-sqlite",
3
- "version": "0.8.4",
3
+ "version": "0.8.6",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -20,7 +20,7 @@
20
20
  "test": "bun test"
21
21
  },
22
22
  "peerDependencies": {
23
- "@arcote.tech/arc": "^0.8.4"
23
+ "@arcote.tech/arc": "^0.8.6"
24
24
  },
25
25
  "devDependencies": {
26
26
  "typescript": "^5.0.0"