@palbase/web 7.2.2 → 7.3.0

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-DLfnVVwL.d.ts → analytics-facade-BER0EyYT.d.ts} +8 -3
  2. package/dist/{analytics-facade-jyXv7Cu4.d.cts → analytics-facade-CQXCQSoF.d.cts} +8 -3
  3. package/dist/{chunk-IREKQSHT.js → chunk-YBURINUN.js} +60 -14
  4. package/dist/chunk-YBURINUN.js.map +1 -0
  5. package/dist/gen/cli.cjs +6 -12
  6. package/dist/gen/cli.cjs.map +1 -1
  7. package/dist/gen/cli.js +6 -12
  8. package/dist/gen/cli.js.map +1 -1
  9. package/dist/index.cjs +51 -4
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +3 -3
  12. package/dist/index.d.ts +3 -3
  13. package/dist/index.js +1 -1
  14. package/dist/internal.cjs +59 -13
  15. package/dist/internal.cjs.map +1 -1
  16. package/dist/internal.d.cts +3 -3
  17. package/dist/internal.d.ts +3 -3
  18. package/dist/internal.js +1 -1
  19. package/dist/next/client.cjs +67 -21
  20. package/dist/next/client.cjs.map +1 -1
  21. package/dist/next/client.js +5 -3
  22. package/dist/next/client.js.map +1 -1
  23. package/dist/next/index.cjs +73 -27
  24. package/dist/next/index.cjs.map +1 -1
  25. package/dist/next/index.d.cts +2 -22
  26. package/dist/next/index.d.ts +2 -22
  27. package/dist/next/index.js +5 -4
  28. package/dist/next/index.js.map +1 -1
  29. package/dist/{pb-DdzpEkPY.d.ts → pb-BRlmBIAm.d.ts} +1 -1
  30. package/dist/{pb-CfYQGEn0.d.cts → pb-WAQvwCfM.d.cts} +1 -1
  31. package/dist/react/index.cjs +50 -3
  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 +1 -1
  36. package/package.json +13 -13
  37. package/LICENSE +0 -21
  38. package/dist/chunk-IREKQSHT.js.map +0 -1
@@ -6,9 +6,11 @@ import {
6
6
  import {
7
7
  __configure,
8
8
  getRuntime
9
- } from "../chunk-IREKQSHT.js";
9
+ } from "../chunk-YBURINUN.js";
10
10
  import "../chunk-ACCJV6FV.js";
11
- import "../chunk-CFDU23TB.js";
11
+ import {
12
+ environmentRefFromPublishableApiKey
13
+ } from "../chunk-CFDU23TB.js";
12
14
  import "../chunk-PZ5AY32C.js";
13
15
 
14
16
  // src/next/client.ts
@@ -70,7 +72,7 @@ function setupPalbeNext() {
70
72
  const config = getRuntime().config;
71
73
  __configure({
72
74
  ...config,
73
- storage: cookieSessionStorage(config.environmentRef)
75
+ storage: cookieSessionStorage(environmentRefFromPublishableApiKey(config.apiKey))
74
76
  });
75
77
  }
76
78
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/next/client.ts"],"sourcesContent":["/**\n * '@palbase/web/next/client' — the browser half of the Next.js adapter. This entry\n * must NEVER import 'next' (it runs in plain client bundles); the cookie jar\n * is document.cookie itself, written with the shared codec so the server\n * side (pbServer / middleware / callback) reads the same bytes.\n */\nimport { __configure, getRuntime } from '../internal.js';\nimport type { PersistedSession, SessionStorageAdapter } from '../storage.js';\nimport {\n clearedSessionCookieNames,\n decodeSessionCookies,\n encodeSessionCookies,\n} from './cookie-codec.js';\n\n/** 30 days — the refresh-token TTL (P3 design contract). */\nconst SESSION_MAX_AGE_S = 2_592_000;\n\n// Secure is unconditional, INCLUDING http://localhost: browsers treat\n// localhost as a potentially-trustworthy origin, so document.cookie accepts\n// Secure cookies there — no dev-mode special case needed. KNOWN LIMITATION:\n// plain-http origins OTHER than localhost — e.g. LAN-IP device testing on\n// http://192.168.x.x — are NOT trustworthy, so the browser silently DROPS\n// these Secure cookie writes and the session won't persist; use https (or a\n// localhost tunnel/port-forward) for on-device testing. NOT HttpOnly by\n// design: the browser SDK must read/write the session (Supabase-paradigm\n// tradeoff, documented in the P3 plan).\nconst WRITE_ATTRS = 'Path=/; SameSite=Lax; Secure';\n\n/** Parse document.cookie (\"a=1; b=2\") into a name → raw-value map. */\nfunction cookieJar(): Map<string, string> {\n const jar = new Map<string, string>();\n for (const part of document.cookie.split(';')) {\n const eq = part.indexOf('=');\n if (eq === -1) continue;\n const name = part.slice(0, eq).trim();\n if (name) jar.set(name, part.slice(eq + 1).trim());\n }\n return jar;\n}\n\nfunction deleteCookie(name: string): void {\n // biome-ignore lint/suspicious/noDocumentCookie: SessionStorageAdapter is a SYNC contract; the async Cookie Store API can't back it (and isn't universal).\n document.cookie = `${name}=; ${WRITE_ATTRS}; Max-Age=0`;\n}\n\n/**\n * document.cookie-backed SessionStorageAdapter. `load` returns the EXTENDED\n * PersistedSession (access token + expiry ride along) so hydration adopts\n * the full session without a refresh round-trip.\n */\nexport function cookieSessionStorage(environmentRef: string): SessionStorageAdapter {\n return {\n load(): PersistedSession | null {\n if (typeof document === 'undefined') return null;\n const jar = cookieJar();\n const stored = decodeSessionCookies((name) => jar.get(name), environmentRef);\n if (!stored) return null;\n // A refresh-only save round-trips as a:'' / e:0 — normalize back to\n // the legacy shape so hydration takes the expired-trick path cleanly.\n return stored.accessToken && stored.expiresAt > 0\n ? {\n refreshToken: stored.refreshToken,\n accessToken: stored.accessToken,\n expiresAt: stored.expiresAt,\n }\n : { refreshToken: stored.refreshToken };\n },\n save(session: PersistedSession): void {\n if (typeof document === 'undefined') return;\n const jar = cookieJar();\n // Delete every currently-present session cookie first (stale chunks of\n // a previously-larger session, or a stale base when the new write\n // chunks), then set the new cookie(s).\n for (const name of clearedSessionCookieNames(environmentRef, (n) => jar.has(n))) {\n deleteCookie(name);\n }\n const { set, clear } = encodeSessionCookies(environmentRef, {\n accessToken: session.accessToken ?? '',\n refreshToken: session.refreshToken,\n expiresAt: session.expiresAt ?? 0,\n });\n for (const { name, value } of set) {\n // biome-ignore lint/suspicious/noDocumentCookie: SessionStorageAdapter is a SYNC contract; the async Cookie Store API can't back it (and isn't universal).\n document.cookie = `${name}=${value}; ${WRITE_ATTRS}; Max-Age=${SESSION_MAX_AGE_S}`;\n }\n // Overflow guard (codec contract): delete one-past-the-end so a stale\n // orphan chunk behind a gap can never join a future chunk run.\n for (const name of clear) deleteCookie(name);\n },\n clear(): void {\n if (typeof document === 'undefined') return;\n const jar = cookieJar();\n for (const name of clearedSessionCookieNames(environmentRef, (n) => jar.has(n))) {\n deleteCookie(name);\n }\n },\n };\n}\n\n/**\n * One-liner for a client component/provider: re-configure the already-loaded\n * gen config (palbe.gen.ts must be imported first — throws the guided\n * notConfigured error otherwise) with cookie-backed session storage so the\n * browser and the server share the session. Calling it again simply\n * re-configures (safe, e.g. under fast refresh). When Next evaluates the\n * client component module server-side there is no document — no-op.\n */\nexport function setupPalbeNext(): void {\n if (typeof document === 'undefined') return;\n const config = getRuntime().config;\n __configure({\n ...config,\n storage: cookieSessionStorage(config.environmentRef),\n });\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,IAAM,oBAAoB;AAW1B,IAAM,cAAc;AAGpB,SAAS,YAAiC;AACxC,QAAM,MAAM,oBAAI,IAAoB;AACpC,aAAW,QAAQ,SAAS,OAAO,MAAM,GAAG,GAAG;AAC7C,UAAM,KAAK,KAAK,QAAQ,GAAG;AAC3B,QAAI,OAAO,GAAI;AACf,UAAM,OAAO,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK;AACpC,QAAI,KAAM,KAAI,IAAI,MAAM,KAAK,MAAM,KAAK,CAAC,EAAE,KAAK,CAAC;AAAA,EACnD;AACA,SAAO;AACT;AAEA,SAAS,aAAa,MAAoB;AAExC,WAAS,SAAS,GAAG,IAAI,MAAM,WAAW;AAC5C;AAOO,SAAS,qBAAqB,gBAA+C;AAClF,SAAO;AAAA,IACL,OAAgC;AAC9B,UAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,YAAM,MAAM,UAAU;AACtB,YAAM,SAAS,qBAAqB,CAAC,SAAS,IAAI,IAAI,IAAI,GAAG,cAAc;AAC3E,UAAI,CAAC,OAAQ,QAAO;AAGpB,aAAO,OAAO,eAAe,OAAO,YAAY,IAC5C;AAAA,QACE,cAAc,OAAO;AAAA,QACrB,aAAa,OAAO;AAAA,QACpB,WAAW,OAAO;AAAA,MACpB,IACA,EAAE,cAAc,OAAO,aAAa;AAAA,IAC1C;AAAA,IACA,KAAK,SAAiC;AACpC,UAAI,OAAO,aAAa,YAAa;AACrC,YAAM,MAAM,UAAU;AAItB,iBAAW,QAAQ,0BAA0B,gBAAgB,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,GAAG;AAC/E,qBAAa,IAAI;AAAA,MACnB;AACA,YAAM,EAAE,KAAK,MAAM,IAAI,qBAAqB,gBAAgB;AAAA,QAC1D,aAAa,QAAQ,eAAe;AAAA,QACpC,cAAc,QAAQ;AAAA,QACtB,WAAW,QAAQ,aAAa;AAAA,MAClC,CAAC;AACD,iBAAW,EAAE,MAAM,MAAM,KAAK,KAAK;AAEjC,iBAAS,SAAS,GAAG,IAAI,IAAI,KAAK,KAAK,WAAW,aAAa,iBAAiB;AAAA,MAClF;AAGA,iBAAW,QAAQ,MAAO,cAAa,IAAI;AAAA,IAC7C;AAAA,IACA,QAAc;AACZ,UAAI,OAAO,aAAa,YAAa;AACrC,YAAM,MAAM,UAAU;AACtB,iBAAW,QAAQ,0BAA0B,gBAAgB,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,GAAG;AAC/E,qBAAa,IAAI;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;AAUO,SAAS,iBAAuB;AACrC,MAAI,OAAO,aAAa,YAAa;AACrC,QAAM,SAAS,WAAW,EAAE;AAC5B,cAAY;AAAA,IACV,GAAG;AAAA,IACH,SAAS,qBAAqB,OAAO,cAAc;AAAA,EACrD,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../../src/next/client.ts"],"sourcesContent":["/**\n * '@palbase/web/next/client' — the browser half of the Next.js adapter. This entry\n * must NEVER import 'next' (it runs in plain client bundles); the cookie jar\n * is document.cookie itself, written with the shared codec so the server\n * side (pbServer / middleware / callback) reads the same bytes.\n */\nimport { environmentRefFromPublishableApiKey } from '../api-key.js';\nimport { __configure, getRuntime } from '../internal.js';\nimport type { PersistedSession, SessionStorageAdapter } from '../storage.js';\nimport {\n clearedSessionCookieNames,\n decodeSessionCookies,\n encodeSessionCookies,\n} from './cookie-codec.js';\n\n/** 30 days — the refresh-token TTL (P3 design contract). */\nconst SESSION_MAX_AGE_S = 2_592_000;\n\n// Secure is unconditional, INCLUDING http://localhost: browsers treat\n// localhost as a potentially-trustworthy origin, so document.cookie accepts\n// Secure cookies there — no dev-mode special case needed. KNOWN LIMITATION:\n// plain-http origins OTHER than localhost — e.g. LAN-IP device testing on\n// http://192.168.x.x — are NOT trustworthy, so the browser silently DROPS\n// these Secure cookie writes and the session won't persist; use https (or a\n// localhost tunnel/port-forward) for on-device testing. NOT HttpOnly by\n// design: the browser SDK must read/write the session (Supabase-paradigm\n// tradeoff, documented in the P3 plan).\nconst WRITE_ATTRS = 'Path=/; SameSite=Lax; Secure';\n\n/** Parse document.cookie (\"a=1; b=2\") into a name → raw-value map. */\nfunction cookieJar(): Map<string, string> {\n const jar = new Map<string, string>();\n for (const part of document.cookie.split(';')) {\n const eq = part.indexOf('=');\n if (eq === -1) continue;\n const name = part.slice(0, eq).trim();\n if (name) jar.set(name, part.slice(eq + 1).trim());\n }\n return jar;\n}\n\nfunction deleteCookie(name: string): void {\n // biome-ignore lint/suspicious/noDocumentCookie: SessionStorageAdapter is a SYNC contract; the async Cookie Store API can't back it (and isn't universal).\n document.cookie = `${name}=; ${WRITE_ATTRS}; Max-Age=0`;\n}\n\n/**\n * document.cookie-backed SessionStorageAdapter. `load` returns the EXTENDED\n * PersistedSession (access token + expiry ride along) so hydration adopts\n * the full session without a refresh round-trip.\n */\nexport function cookieSessionStorage(environmentRef: string): SessionStorageAdapter {\n return {\n load(): PersistedSession | null {\n if (typeof document === 'undefined') return null;\n const jar = cookieJar();\n const stored = decodeSessionCookies((name) => jar.get(name), environmentRef);\n if (!stored) return null;\n // A refresh-only save round-trips as a:'' / e:0 — normalize back to\n // the legacy shape so hydration takes the expired-trick path cleanly.\n return stored.accessToken && stored.expiresAt > 0\n ? {\n refreshToken: stored.refreshToken,\n accessToken: stored.accessToken,\n expiresAt: stored.expiresAt,\n }\n : { refreshToken: stored.refreshToken };\n },\n save(session: PersistedSession): void {\n if (typeof document === 'undefined') return;\n const jar = cookieJar();\n // Delete every currently-present session cookie first (stale chunks of\n // a previously-larger session, or a stale base when the new write\n // chunks), then set the new cookie(s).\n for (const name of clearedSessionCookieNames(environmentRef, (n) => jar.has(n))) {\n deleteCookie(name);\n }\n const { set, clear } = encodeSessionCookies(environmentRef, {\n accessToken: session.accessToken ?? '',\n refreshToken: session.refreshToken,\n expiresAt: session.expiresAt ?? 0,\n });\n for (const { name, value } of set) {\n // biome-ignore lint/suspicious/noDocumentCookie: SessionStorageAdapter is a SYNC contract; the async Cookie Store API can't back it (and isn't universal).\n document.cookie = `${name}=${value}; ${WRITE_ATTRS}; Max-Age=${SESSION_MAX_AGE_S}`;\n }\n // Overflow guard (codec contract): delete one-past-the-end so a stale\n // orphan chunk behind a gap can never join a future chunk run.\n for (const name of clear) deleteCookie(name);\n },\n clear(): void {\n if (typeof document === 'undefined') return;\n const jar = cookieJar();\n for (const name of clearedSessionCookieNames(environmentRef, (n) => jar.has(n))) {\n deleteCookie(name);\n }\n },\n };\n}\n\n/**\n * One-liner for a client component/provider: re-configure the already-loaded\n * gen config (palbe.gen.ts must be imported first — throws the guided\n * notConfigured error otherwise) with cookie-backed session storage so the\n * browser and the server share the session. Calling it again simply\n * re-configures (safe, e.g. under fast refresh). When Next evaluates the\n * client component module server-side there is no document — no-op.\n */\nexport function setupPalbeNext(): void {\n if (typeof document === 'undefined') return;\n const config = getRuntime().config;\n __configure({\n ...config,\n storage: cookieSessionStorage(environmentRefFromPublishableApiKey(config.apiKey)),\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,IAAM,oBAAoB;AAW1B,IAAM,cAAc;AAGpB,SAAS,YAAiC;AACxC,QAAM,MAAM,oBAAI,IAAoB;AACpC,aAAW,QAAQ,SAAS,OAAO,MAAM,GAAG,GAAG;AAC7C,UAAM,KAAK,KAAK,QAAQ,GAAG;AAC3B,QAAI,OAAO,GAAI;AACf,UAAM,OAAO,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK;AACpC,QAAI,KAAM,KAAI,IAAI,MAAM,KAAK,MAAM,KAAK,CAAC,EAAE,KAAK,CAAC;AAAA,EACnD;AACA,SAAO;AACT;AAEA,SAAS,aAAa,MAAoB;AAExC,WAAS,SAAS,GAAG,IAAI,MAAM,WAAW;AAC5C;AAOO,SAAS,qBAAqB,gBAA+C;AAClF,SAAO;AAAA,IACL,OAAgC;AAC9B,UAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,YAAM,MAAM,UAAU;AACtB,YAAM,SAAS,qBAAqB,CAAC,SAAS,IAAI,IAAI,IAAI,GAAG,cAAc;AAC3E,UAAI,CAAC,OAAQ,QAAO;AAGpB,aAAO,OAAO,eAAe,OAAO,YAAY,IAC5C;AAAA,QACE,cAAc,OAAO;AAAA,QACrB,aAAa,OAAO;AAAA,QACpB,WAAW,OAAO;AAAA,MACpB,IACA,EAAE,cAAc,OAAO,aAAa;AAAA,IAC1C;AAAA,IACA,KAAK,SAAiC;AACpC,UAAI,OAAO,aAAa,YAAa;AACrC,YAAM,MAAM,UAAU;AAItB,iBAAW,QAAQ,0BAA0B,gBAAgB,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,GAAG;AAC/E,qBAAa,IAAI;AAAA,MACnB;AACA,YAAM,EAAE,KAAK,MAAM,IAAI,qBAAqB,gBAAgB;AAAA,QAC1D,aAAa,QAAQ,eAAe;AAAA,QACpC,cAAc,QAAQ;AAAA,QACtB,WAAW,QAAQ,aAAa;AAAA,MAClC,CAAC;AACD,iBAAW,EAAE,MAAM,MAAM,KAAK,KAAK;AAEjC,iBAAS,SAAS,GAAG,IAAI,IAAI,KAAK,KAAK,WAAW,aAAa,iBAAiB;AAAA,MAClF;AAGA,iBAAW,QAAQ,MAAO,cAAa,IAAI;AAAA,IAC7C;AAAA,IACA,QAAc;AACZ,UAAI,OAAO,aAAa,YAAa;AACrC,YAAM,MAAM,UAAU;AACtB,iBAAW,QAAQ,0BAA0B,gBAAgB,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,GAAG;AAC/E,qBAAa,IAAI;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;AAUO,SAAS,iBAAuB;AACrC,MAAI,OAAO,aAAa,YAAa;AACrC,QAAM,SAAS,WAAW,EAAE;AAC5B,cAAY;AAAA,IACV,GAAG;AAAA,IACH,SAAS,qBAAqB,oCAAoC,OAAO,MAAM,CAAC;AAAA,EAClF,CAAC;AACH;","names":[]}
@@ -42,6 +42,18 @@ __export(next_exports, {
42
42
  });
43
43
  module.exports = __toCommonJS(next_exports);
44
44
 
45
+ // src/api-key.ts
46
+ var API_KEY_RE = /^pb_([a-z0-9]{4,24})_[cs][A-Za-z0-9]{20}$/;
47
+ var PUBLISHABLE_API_KEY_RE = /^pb_([a-z0-9]{4,24})_c[A-Za-z0-9]{20}$/;
48
+ function environmentRefFromApiKey(apiKey) {
49
+ const m = API_KEY_RE.exec(apiKey);
50
+ return m ? m[1] ?? "" : "";
51
+ }
52
+ function environmentRefFromPublishableApiKey(apiKey) {
53
+ const match = PUBLISHABLE_API_KEY_RE.exec(apiKey);
54
+ return match ? match[1] ?? "" : "";
55
+ }
56
+
45
57
  // src/auth-wire.ts
46
58
  function asWireAuthResult(raw) {
47
59
  if (typeof raw !== "object" || raw === null) return null;
@@ -55,18 +67,6 @@ function asWireAuthResult(raw) {
55
67
  return raw;
56
68
  }
57
69
 
58
- // src/api-key.ts
59
- var API_KEY_RE = /^pb_([a-z0-9]{4,24})_[cs][A-Za-z0-9]{20}$/;
60
- var PUBLISHABLE_API_KEY_RE = /^pb_([a-z0-9]{4,24})_c[A-Za-z0-9]{20}$/;
61
- function environmentRefFromApiKey(apiKey) {
62
- const m = API_KEY_RE.exec(apiKey);
63
- return m ? m[1] ?? "" : "";
64
- }
65
- function environmentRefFromPublishableApiKey(apiKey) {
66
- const match = PUBLISHABLE_API_KEY_RE.exec(apiKey);
67
- return match ? match[1] ?? "" : "";
68
- }
69
-
70
70
  // src/next/cookie-codec.ts
71
71
  var MAX_COOKIE_VALUE = 3500;
72
72
  var SESSION_COOKIE_ATTRS = {
@@ -568,6 +568,47 @@ function redactUrl(rawUrl) {
568
568
  return path.split("/").map((seg2) => isSensitiveSegment(seg2) ? ":id" : seg2).join("/");
569
569
  }
570
570
 
571
+ // src/pow.ts
572
+ var POW_CHALLENGE_ID_HEADER = "X-PoW-Challenge-ID";
573
+ var POW_NONCE_HEADER = "X-PoW-Nonce";
574
+ function asPowChallenge(details) {
575
+ if (typeof details !== "object" || details === null) return null;
576
+ const env = details;
577
+ if (env.error !== "pow_required") return null;
578
+ const c = env.challenge;
579
+ if (typeof c !== "object" || c === null) return null;
580
+ const { id, prefix, difficulty } = c;
581
+ if (typeof id !== "string" || typeof prefix !== "string") return null;
582
+ if (typeof difficulty !== "number" || !Number.isInteger(difficulty) || difficulty < 0) return null;
583
+ return { id, prefix, difficulty };
584
+ }
585
+ var encoder = new TextEncoder();
586
+ function leadingZeroBits(hash) {
587
+ let bits = 0;
588
+ for (const byte of hash) {
589
+ if (byte === 0) {
590
+ bits += 8;
591
+ continue;
592
+ }
593
+ return bits + Math.clz32(byte) - 24;
594
+ }
595
+ return bits;
596
+ }
597
+ async function solvePowChallenge(challenge, maxIterations = 1 << 24) {
598
+ for (let nonce = 0; nonce < maxIterations; nonce++) {
599
+ const digest = await crypto.subtle.digest("SHA-256", encoder.encode(challenge.prefix + nonce));
600
+ if (leadingZeroBits(new Uint8Array(digest)) >= challenge.difficulty) {
601
+ return {
602
+ [POW_CHALLENGE_ID_HEADER]: challenge.id,
603
+ [POW_NONCE_HEADER]: String(nonce)
604
+ };
605
+ }
606
+ }
607
+ throw new Error(
608
+ `proof-of-work: no nonce found for difficulty ${challenge.difficulty} within ${maxIterations} attempts`
609
+ );
610
+ }
611
+
571
612
  // src/request.ts
572
613
  var MUTATING = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
573
614
  var PERF_EXCLUDED_PREFIX = "/v1/analytics/";
@@ -591,11 +632,11 @@ async function palbeRequest(rt, method, path, spec = {}) {
591
632
  if (MUTATING.has(method) && !callerHasKey) {
592
633
  headers["Idempotency-Key"] = crypto.randomUUID();
593
634
  }
594
- const attempt = async () => {
635
+ const attempt = async (extra) => {
595
636
  try {
596
637
  return await rt.http.request(method, path, {
597
638
  body: spec.body,
598
- headers,
639
+ headers: extra ? { ...headers, ...extra } : headers,
599
640
  signal: spec.signal
600
641
  });
601
642
  } catch (e) {
@@ -630,6 +671,12 @@ async function palbeRequest(rt, method, path, spec = {}) {
630
671
  }
631
672
  res = await attempt();
632
673
  }
674
+ if (res.error?.status === 403 && res.error.code === "pow_required") {
675
+ const challenge = asPowChallenge(res.error.details);
676
+ if (challenge) {
677
+ res = await attempt(await solvePowChallenge(challenge));
678
+ }
679
+ }
633
680
  } catch (e) {
634
681
  if (!isAbort(e)) record(asPalbaseError(e)?.status ?? 0);
635
682
  throw e;
@@ -1287,7 +1334,7 @@ var AnalyticsState = class {
1287
1334
  idKey;
1288
1335
  optOutKey;
1289
1336
  constructor(rt) {
1290
- const ref = rt.config.environmentRef;
1337
+ const ref = rt.projectRef;
1291
1338
  this.idKey = ref ? `palbe.analytics.id.${ref}` : "palbe.analytics.id";
1292
1339
  this.optOutKey = ref ? `palbe.analytics.optout.${ref}` : "palbe.analytics.optout";
1293
1340
  rt.auth.onAuthEvent((event) => {
@@ -2908,7 +2955,7 @@ var PalbeFlags = class {
2908
2955
  constructor(rt) {
2909
2956
  this.transport = new FlagsClient(rt.http);
2910
2957
  const browser = typeof document !== "undefined";
2911
- const ref = rt.config.environmentRef;
2958
+ const ref = rt.projectRef;
2912
2959
  const options = {
2913
2960
  auth: palbeAuthAdapter(rt.auth),
2914
2961
  ...ref ? { storageKey: `palbe.flags.${ref}` } : {},
@@ -9307,15 +9354,13 @@ function defaultSessionStorage(key) {
9307
9354
  }
9308
9355
 
9309
9356
  // src/version.ts
9310
- var VERSION = "7.2.2";
9357
+ var VERSION = "7.3.0";
9311
9358
 
9312
9359
  // src/runtime.ts
9313
9360
  function buildRuntime(config) {
9314
- const keyEnvironmentRef = environmentRefFromPublishableApiKey(config.apiKey);
9315
- if (keyEnvironmentRef === "") {
9316
- throw new Error("PalbeConfig.apiKey does not contain a valid publishable Environment identity");
9317
- } else if (config.environmentRef !== keyEnvironmentRef) {
9318
- throw new Error("PalbeConfig.environmentRef must match the Environment identity in apiKey");
9361
+ const projectRef = environmentRefFromPublishableApiKey(config.apiKey);
9362
+ if (projectRef === "") {
9363
+ throw new Error("PalbeConfig.apiKey does not contain a valid publishable project identity");
9319
9364
  }
9320
9365
  let runtimeURL;
9321
9366
  try {
@@ -9323,8 +9368,8 @@ function buildRuntime(config) {
9323
9368
  } catch {
9324
9369
  throw new Error("PalbeConfig.url must be a valid URL");
9325
9370
  }
9326
- if (runtimeURL.hostname.endsWith(".palbase.studio") && runtimeURL.hostname.split(".")[0] !== config.environmentRef) {
9327
- throw new Error("PalbeConfig.url must match environmentRef for palbase.studio");
9371
+ if (runtimeURL.hostname.endsWith(".palbase.studio") && runtimeURL.hostname.split(".")[0] !== projectRef) {
9372
+ throw new Error("PalbeConfig.url must match the project identity in apiKey for palbase.studio");
9328
9373
  }
9329
9374
  const http = new HttpClient(config.apiKey, {
9330
9375
  url: config.url,
@@ -9334,7 +9379,7 @@ function buildRuntime(config) {
9334
9379
  const tokenManager = new TokenManager();
9335
9380
  http.tokenManager = tokenManager;
9336
9381
  const authClient = new AuthClient(http, tokenManager);
9337
- const ref = config.environmentRef;
9382
+ const ref = projectRef;
9338
9383
  const storage = config.storage ?? defaultSessionStorage(ref ? `palbe.session.${ref}` : void 0);
9339
9384
  const persisted = storage.load();
9340
9385
  if (persisted) {
@@ -9379,6 +9424,7 @@ function buildRuntime(config) {
9379
9424
  let perf;
9380
9425
  const rt = {
9381
9426
  config,
9427
+ projectRef,
9382
9428
  http,
9383
9429
  tokenManager,
9384
9430
  authClient,
@@ -9790,7 +9836,7 @@ function handleAuthCallback(opts) {
9790
9836
  const wire = asWireAuthResult(raw);
9791
9837
  if (!wire) return redirect(fallback, { auth_error: "oauth_exchange_failed" });
9792
9838
  const response = redirect(safeNextPath(params.get("next"), request.nextUrl.origin) ?? fallback);
9793
- const write = encodeSessionCookiesDecoded(config.environmentRef, {
9839
+ const write = encodeSessionCookiesDecoded(environmentRefFromPublishableApiKey(config.apiKey), {
9794
9840
  accessToken: wire.access_token,
9795
9841
  refreshToken: wire.refresh_token,
9796
9842
  expiresAt: Date.now() + wire.expires_in * 1e3
@@ -9881,7 +9927,7 @@ async function pbServer(opts) {
9881
9927
  "import the generated palbe.gen.ts once in app/layout.tsx \u2014 the root-layout import configures Server Components and Route Handlers too."
9882
9928
  );
9883
9929
  const store = opts?.cookies ?? await nextCookieStore();
9884
- const ref = config.environmentRef;
9930
+ const ref = environmentRefFromPublishableApiKey(config.apiKey);
9885
9931
  const rt = buildRuntime({ ...config, storage: serverCookieAdapter(store, ref) });
9886
9932
  return createBoundClient(rt);
9887
9933
  }