@palbase/web 4.0.1 → 4.0.2

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 (38) hide show
  1. package/dist/{analytics-facade-DwOtlXPP.d.cts → analytics-facade-CaluA4bW.d.cts} +26 -1
  2. package/dist/{analytics-facade-Nk6J9Ncm.d.ts → analytics-facade-Cp3d4QI-.d.ts} +26 -1
  3. package/dist/{chunk-NXEPAEF5.js → chunk-CFDU23TB.js} +3 -3
  4. package/dist/chunk-CFDU23TB.js.map +1 -0
  5. package/dist/{chunk-TGDS6VMT.js → chunk-TW6YN354.js} +58 -6
  6. package/dist/chunk-TW6YN354.js.map +1 -0
  7. package/dist/gen/cli.cjs +5 -5
  8. package/dist/gen/cli.cjs.map +1 -1
  9. package/dist/gen/cli.js +5 -5
  10. package/dist/gen/cli.js.map +1 -1
  11. package/dist/index.cjs +55 -3
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +3 -3
  14. package/dist/index.d.ts +3 -3
  15. package/dist/index.js +2 -2
  16. package/dist/internal.cjs +57 -5
  17. package/dist/internal.cjs.map +1 -1
  18. package/dist/internal.d.cts +3 -3
  19. package/dist/internal.d.ts +3 -3
  20. package/dist/internal.js +2 -2
  21. package/dist/next/client.cjs +57 -5
  22. package/dist/next/client.cjs.map +1 -1
  23. package/dist/next/client.js +2 -2
  24. package/dist/next/index.cjs +58 -6
  25. package/dist/next/index.cjs.map +1 -1
  26. package/dist/next/index.d.cts +2 -2
  27. package/dist/next/index.d.ts +2 -2
  28. package/dist/next/index.js +2 -2
  29. package/dist/{pb-FG_nV7NR.d.ts → pb-DUK5qy81.d.ts} +1 -1
  30. package/dist/{pb-C9v5dEO6.d.cts → pb-DvV6ftmf.d.cts} +1 -1
  31. package/dist/react/index.cjs +10 -2
  32. package/dist/react/index.cjs.map +1 -1
  33. package/dist/react/index.d.cts +1 -1
  34. package/dist/react/index.d.ts +1 -1
  35. package/dist/react/index.js +2 -2
  36. package/package.json +2 -2
  37. package/dist/chunk-NXEPAEF5.js.map +0 -1
  38. package/dist/chunk-TGDS6VMT.js.map +0 -1
@@ -1663,7 +1663,13 @@ type AuthChangeEvent = {
1663
1663
  user: AuthUser;
1664
1664
  } | {
1665
1665
  type: 'signedOut';
1666
- reason: 'userInitiated' | 'sessionExpired';
1666
+ /**
1667
+ * `userInitiated` — pb.auth.signOut(); `sessionExpired` — a refresh
1668
+ * ultimately failed; `accountDeleted` — this device ran deleteAccount();
1669
+ * `sessionInvalid` — a server-side session kill (erased/revoked subject)
1670
+ * was observed on a request and the client tore down reactively.
1671
+ */
1672
+ reason: 'userInitiated' | 'sessionExpired' | 'accountDeleted' | 'sessionInvalid';
1667
1673
  } | {
1668
1674
  type: 'tokenRefreshed';
1669
1675
  };
@@ -1672,6 +1678,7 @@ declare class PalbeAuth {
1672
1678
  private readonly rt;
1673
1679
  private cachedUser;
1674
1680
  private signingOut;
1681
+ private nextSignOutReason;
1675
1682
  private signingIn;
1676
1683
  private signedInState;
1677
1684
  private hydratingUser;
@@ -1690,6 +1697,24 @@ declare class PalbeAuth {
1690
1697
  password: string;
1691
1698
  }): Promise<AuthSuccess>;
1692
1699
  signOut(): Promise<void>;
1700
+ /**
1701
+ * Self-service account erasure ("right to be forgotten"). Calls palauth
1702
+ * `DELETE /auth/user` (session-authed + fresh re-auth): password users pass
1703
+ * `{ password }`; passwordless/OAuth users rely on a freshly stepped-up
1704
+ * session. On 202 the erasure workflow is durably queued AND every session is
1705
+ * already revoked server-side — so we tear down local state (mirroring
1706
+ * `signOut()`'s clear, minus the pointless `/logout`) and emit
1707
+ * `signedOut{reason:'accountDeleted'}`.
1708
+ *
1709
+ * On 401 `reauth_required` / 503 `not_configured` (or `erasure_unavailable`)
1710
+ * the request throws BEFORE the teardown line, so the local session is left
1711
+ * fully intact — the deletion did not happen and the user is still signed in.
1712
+ */
1713
+ deleteAccount(params?: {
1714
+ password?: string;
1715
+ }): Promise<{
1716
+ erasureId: string;
1717
+ }>;
1693
1718
  getUser(): Promise<AuthUser>;
1694
1719
  refreshUser(): Promise<AuthUser>;
1695
1720
  /**
@@ -1663,7 +1663,13 @@ type AuthChangeEvent = {
1663
1663
  user: AuthUser;
1664
1664
  } | {
1665
1665
  type: 'signedOut';
1666
- reason: 'userInitiated' | 'sessionExpired';
1666
+ /**
1667
+ * `userInitiated` — pb.auth.signOut(); `sessionExpired` — a refresh
1668
+ * ultimately failed; `accountDeleted` — this device ran deleteAccount();
1669
+ * `sessionInvalid` — a server-side session kill (erased/revoked subject)
1670
+ * was observed on a request and the client tore down reactively.
1671
+ */
1672
+ reason: 'userInitiated' | 'sessionExpired' | 'accountDeleted' | 'sessionInvalid';
1667
1673
  } | {
1668
1674
  type: 'tokenRefreshed';
1669
1675
  };
@@ -1672,6 +1678,7 @@ declare class PalbeAuth {
1672
1678
  private readonly rt;
1673
1679
  private cachedUser;
1674
1680
  private signingOut;
1681
+ private nextSignOutReason;
1675
1682
  private signingIn;
1676
1683
  private signedInState;
1677
1684
  private hydratingUser;
@@ -1690,6 +1697,24 @@ declare class PalbeAuth {
1690
1697
  password: string;
1691
1698
  }): Promise<AuthSuccess>;
1692
1699
  signOut(): Promise<void>;
1700
+ /**
1701
+ * Self-service account erasure ("right to be forgotten"). Calls palauth
1702
+ * `DELETE /auth/user` (session-authed + fresh re-auth): password users pass
1703
+ * `{ password }`; passwordless/OAuth users rely on a freshly stepped-up
1704
+ * session. On 202 the erasure workflow is durably queued AND every session is
1705
+ * already revoked server-side — so we tear down local state (mirroring
1706
+ * `signOut()`'s clear, minus the pointless `/logout`) and emit
1707
+ * `signedOut{reason:'accountDeleted'}`.
1708
+ *
1709
+ * On 401 `reauth_required` / 503 `not_configured` (or `erasure_unavailable`)
1710
+ * the request throws BEFORE the teardown line, so the local session is left
1711
+ * fully intact — the deletion did not happen and the user is still signed in.
1712
+ */
1713
+ deleteAccount(params?: {
1714
+ password?: string;
1715
+ }): Promise<{
1716
+ erasureId: string;
1717
+ }>;
1693
1718
  getUser(): Promise<AuthUser>;
1694
1719
  refreshUser(): Promise<AuthUser>;
1695
1720
  /**
@@ -1,6 +1,6 @@
1
1
  // src/api-key.ts
2
- var API_KEY_RE = /^pb_([a-z0-9]+)_[cs][A-Za-z0-9]{20}$/;
3
- var PUBLISHABLE_API_KEY_RE = /^pb_([a-z0-9]+)_c[A-Za-z0-9]{20}$/;
2
+ var API_KEY_RE = /^pb_([a-z0-9]{4,24})_[cs][A-Za-z0-9]{20}$/;
3
+ var PUBLISHABLE_API_KEY_RE = /^pb_([a-z0-9]{4,24})_c[A-Za-z0-9]{20}$/;
4
4
  function environmentRefFromApiKey(apiKey) {
5
5
  const m = API_KEY_RE.exec(apiKey);
6
6
  return m ? m[1] ?? "" : "";
@@ -14,4 +14,4 @@ export {
14
14
  environmentRefFromApiKey,
15
15
  environmentRefFromPublishableApiKey
16
16
  };
17
- //# sourceMappingURL=chunk-NXEPAEF5.js.map
17
+ //# sourceMappingURL=chunk-CFDU23TB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api-key.ts"],"sourcesContent":["/**\n * `pb_<environmentRef>_<scope><random>` → environmentRef ('' if malformed).\n * Utility for callers that only have a raw key. App-bound runtime storage and\n * palbe/next cookie naming use the explicit `PalbeConfig.environmentRef` emitted\n * by `palbe-gen`.\n *\n * The key is shape-validated (prefix `pb`, a 4-24 character lowercase ASCII\n * alphanumeric environmentRef, and a `<scope><20-base62-random>` secret segment\n * where scope ∈ {c,s}) before a ref is returned. A structurally-invalid key returns\n * '' so session storage stays\n * UNSCOPED rather than getting bound to a partially-parsed ref — a loose parse\n * (e.g. `pb_victim_cXX`) must not scope persisted sessions to `victim` and\n * hydrate a session belonging to a different, real key. The backend remains the\n * authority that rejects a bad key on the first request; this keeps the client's\n * local session-storage scoping honest. (Audit finding apikey-ref-mismatch.)\n */\nconst API_KEY_RE = /^pb_([a-z0-9]{4,24})_[cs][A-Za-z0-9]{20}$/;\nconst PUBLISHABLE_API_KEY_RE = /^pb_([a-z0-9]{4,24})_c[A-Za-z0-9]{20}$/;\n\nexport function environmentRefFromApiKey(apiKey: string): string {\n const m = API_KEY_RE.exec(apiKey);\n return m ? (m[1] ?? '') : '';\n}\n\n/** Internal app-runtime parser: browser config accepts publishable keys only. */\nexport function environmentRefFromPublishableApiKey(apiKey: string): string {\n const match = PUBLISHABLE_API_KEY_RE.exec(apiKey);\n return match ? (match[1] ?? '') : '';\n}\n"],"mappings":";AAgBA,IAAM,aAAa;AACnB,IAAM,yBAAyB;AAExB,SAAS,yBAAyB,QAAwB;AAC/D,QAAM,IAAI,WAAW,KAAK,MAAM;AAChC,SAAO,IAAK,EAAE,CAAC,KAAK,KAAM;AAC5B;AAGO,SAAS,oCAAoC,QAAwB;AAC1E,QAAM,QAAQ,uBAAuB,KAAK,MAAM;AAChD,SAAO,QAAS,MAAM,CAAC,KAAK,KAAM;AACpC;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  environmentRefFromPublishableApiKey
3
- } from "./chunk-NXEPAEF5.js";
3
+ } from "./chunk-CFDU23TB.js";
4
4
  import {
5
5
  __export
6
6
  } from "./chunk-PZ5AY32C.js";
@@ -20,7 +20,7 @@ var PalbaseError = class extends Error {
20
20
  }
21
21
  };
22
22
  var PALBASE_DEFAULT_HOST = "api.palbase.studio";
23
- var API_KEY_RE = /^pb_([a-z0-9]+)_c[A-Za-z0-9]{20}$/;
23
+ var API_KEY_RE = /^pb_([a-z0-9]{4,24})_c[A-Za-z0-9]{20}$/;
24
24
  function parseEnvironmentRef(apiKey) {
25
25
  return API_KEY_RE.exec(apiKey)?.[1] ?? null;
26
26
  }
@@ -397,6 +397,11 @@ var PERF_EXCLUDED_PREFIX = "/v1/analytics/";
397
397
  function isSelfTraced(path) {
398
398
  return path.startsWith(PERF_EXCLUDED_PREFIX);
399
399
  }
400
+ function isSessionKilled(status, code) {
401
+ if (status === 401) return code === "session_revoked";
402
+ if (status === 403) return code === "subject_fenced" || code === "subject_erased";
403
+ return false;
404
+ }
400
405
  function nowMs() {
401
406
  return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
402
407
  }
@@ -432,7 +437,7 @@ async function palbeRequest(rt, method, path, spec = {}) {
432
437
  let res;
433
438
  try {
434
439
  res = await attempt();
435
- if (res.error?.status === 401 && rt.tokenManager.getRefreshToken() && rt.tokenManager.refreshFunction) {
440
+ if (res.error?.status === 401 && res.error.code !== "session_revoked" && rt.tokenManager.getRefreshToken() && rt.tokenManager.refreshFunction) {
436
441
  try {
437
442
  await rt.tokenManager.refreshSession();
438
443
  } catch (refreshErr) {
@@ -452,6 +457,9 @@ async function palbeRequest(rt, method, path, spec = {}) {
452
457
  if (!isAbort(e)) record(asPalbaseError(e)?.status ?? 0);
453
458
  throw e;
454
459
  }
460
+ if (res.error && isSessionKilled(res.error.status, res.error.code)) {
461
+ rt.auth.reactiveTeardown();
462
+ }
455
463
  record(res.error?.status ?? 200);
456
464
  return unwrap(res);
457
465
  }
@@ -1426,7 +1434,8 @@ var PalbeAuth = class {
1426
1434
  if (!this.signedInState) return;
1427
1435
  this.signedInState = false;
1428
1436
  this.cachedUser = null;
1429
- const reason = this.signingOut ? "userInitiated" : "sessionExpired";
1437
+ const reason = this.nextSignOutReason ?? (this.signingOut ? "userInitiated" : "sessionExpired");
1438
+ this.nextSignOutReason = null;
1430
1439
  this.emitState({ status: "signedOut" });
1431
1440
  this.emitEvent({ type: "signedOut", reason });
1432
1441
  } else if (event === "TOKEN_REFRESHED") {
@@ -1439,6 +1448,10 @@ var PalbeAuth = class {
1439
1448
  rt;
1440
1449
  cachedUser = null;
1441
1450
  signingOut = false;
1451
+ // Explicit signedOut reason pinned for the NEXT session clear (deleteAccount /
1452
+ // reactiveTeardown set it before clearSession; the SIGNED_OUT handler consumes
1453
+ // it exactly once, then resets to null → normal signOut/expiry split resumes).
1454
+ nextSignOutReason = null;
1442
1455
  signingIn = false;
1443
1456
  // suppresses AuthClient's TOKEN_REFRESHED during re-signIn
1444
1457
  signedInState = false;
@@ -1486,6 +1499,45 @@ var PalbeAuth = class {
1486
1499
  this.cachedUser = null;
1487
1500
  }
1488
1501
  }
1502
+ /**
1503
+ * Self-service account erasure ("right to be forgotten"). Calls palauth
1504
+ * `DELETE /auth/user` (session-authed + fresh re-auth): password users pass
1505
+ * `{ password }`; passwordless/OAuth users rely on a freshly stepped-up
1506
+ * session. On 202 the erasure workflow is durably queued AND every session is
1507
+ * already revoked server-side — so we tear down local state (mirroring
1508
+ * `signOut()`'s clear, minus the pointless `/logout`) and emit
1509
+ * `signedOut{reason:'accountDeleted'}`.
1510
+ *
1511
+ * On 401 `reauth_required` / 503 `not_configured` (or `erasure_unavailable`)
1512
+ * the request throws BEFORE the teardown line, so the local session is left
1513
+ * fully intact — the deletion did not happen and the user is still signed in.
1514
+ */
1515
+ async deleteAccount(params = {}) {
1516
+ const res = await palbeRequest(this.rt, "DELETE", "/auth/user", {
1517
+ body: params.password ? { password: params.password } : {}
1518
+ });
1519
+ this.nextSignOutReason = "accountDeleted";
1520
+ this.rt.tokenManager.clearSession();
1521
+ this.rt.storage.clear();
1522
+ this.cachedUser = null;
1523
+ return { erasureId: res.erasure_id };
1524
+ }
1525
+ /**
1526
+ * @internal — invoked by the transport choke point (`request.ts`), not app code.
1527
+ * Reactive teardown when the server reports the session is gone: a 403
1528
+ * `subject_fenced`/`subject_erased` (subject being erased) or a 401
1529
+ * `session_revoked`. Clears local state and emits
1530
+ * `signedOut{reason:'sessionInvalid'}` exactly once (deduped by
1531
+ * `signedInState`). An ordinary 403 authz denial does NOT reach here —
1532
+ * `request.ts` matches only the exact session-kill codes.
1533
+ */
1534
+ reactiveTeardown() {
1535
+ if (!this.signedInState) return;
1536
+ this.nextSignOutReason = "sessionInvalid";
1537
+ this.rt.tokenManager.clearSession();
1538
+ this.rt.storage.clear();
1539
+ this.cachedUser = null;
1540
+ }
1489
1541
  async getUser() {
1490
1542
  const raw = await palbeRequest(this.rt, "GET", "/auth/user");
1491
1543
  return mapWireUser(raw);
@@ -8939,7 +8991,7 @@ function defaultSessionStorage(key) {
8939
8991
  }
8940
8992
 
8941
8993
  // src/version.ts
8942
- var VERSION = "4.0.1";
8994
+ var VERSION = "4.0.2";
8943
8995
 
8944
8996
  // src/runtime.ts
8945
8997
  function buildRuntime(config) {
@@ -9366,4 +9418,4 @@ export {
9366
9418
  pb,
9367
9419
  createBoundClient
9368
9420
  };
9369
- //# sourceMappingURL=chunk-TGDS6VMT.js.map
9421
+ //# sourceMappingURL=chunk-TW6YN354.js.map