@palbase/web 2.0.0 → 3.0.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 (47) hide show
  1. package/README.md +11 -9
  2. package/dist/{analytics-facade-ovP0pF2P.d.cts → analytics-facade-BOxQ8IP2.d.cts} +11 -10
  3. package/dist/{analytics-facade-DMtGDGfd.d.ts → analytics-facade-yfMJ69vw.d.ts} +11 -10
  4. package/dist/{chunk-V6VTX65P.js → chunk-3HVTEZ7N.js} +80 -58
  5. package/dist/chunk-3HVTEZ7N.js.map +1 -0
  6. package/dist/{chunk-VJXFABBW.js → chunk-6VGKMNXO.js} +11 -11
  7. package/dist/chunk-6VGKMNXO.js.map +1 -0
  8. package/dist/chunk-S7NAY3MW.js +24 -0
  9. package/dist/chunk-S7NAY3MW.js.map +1 -0
  10. package/dist/gen/cli.cjs +33 -8
  11. package/dist/gen/cli.cjs.map +1 -1
  12. package/dist/gen/cli.js +29 -9
  13. package/dist/gen/cli.js.map +1 -1
  14. package/dist/index.cjs +53 -32
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +4 -4
  17. package/dist/index.d.ts +4 -4
  18. package/dist/index.js +2 -2
  19. package/dist/internal.cjs +83 -54
  20. package/dist/internal.cjs.map +1 -1
  21. package/dist/internal.d.cts +4 -4
  22. package/dist/internal.d.ts +4 -4
  23. package/dist/internal.js +2 -2
  24. package/dist/next/client.cjs +100 -68
  25. package/dist/next/client.cjs.map +1 -1
  26. package/dist/next/client.d.cts +1 -1
  27. package/dist/next/client.d.ts +1 -1
  28. package/dist/next/client.js +12 -10
  29. package/dist/next/client.js.map +1 -1
  30. package/dist/next/index.cjs +103 -69
  31. package/dist/next/index.cjs.map +1 -1
  32. package/dist/next/index.d.cts +11 -11
  33. package/dist/next/index.d.ts +11 -11
  34. package/dist/next/index.js +14 -13
  35. package/dist/next/index.js.map +1 -1
  36. package/dist/{pb-DDM_mCQB.d.cts → pb-B3h3NIPE.d.cts} +1 -1
  37. package/dist/{pb-CvpcQero.d.ts → pb-QRISxPd1.d.ts} +1 -1
  38. package/dist/react/index.cjs +1 -1
  39. package/dist/react/index.cjs.map +1 -1
  40. package/dist/react/index.d.cts +2 -2
  41. package/dist/react/index.d.ts +2 -2
  42. package/dist/react/index.js +2 -2
  43. package/package.json +4 -4
  44. package/dist/chunk-PZ5AY32C.js +0 -10
  45. package/dist/chunk-PZ5AY32C.js.map +0 -1
  46. package/dist/chunk-V6VTX65P.js.map +0 -1
  47. package/dist/chunk-VJXFABBW.js.map +0 -1
@@ -5,7 +5,7 @@ import { S as SessionStorageAdapter } from '../storage-BPaeSG8K.cjs';
5
5
  * PersistedSession (access token + expiry ride along) so hydration adopts
6
6
  * the full session without a refresh round-trip.
7
7
  */
8
- declare function cookieSessionStorage(endpointRef: string): SessionStorageAdapter;
8
+ declare function cookieSessionStorage(environmentRef: string): SessionStorageAdapter;
9
9
  /**
10
10
  * One-liner for a client component/provider: re-configure the already-loaded
11
11
  * gen config (palbe.gen.ts must be imported first — throws the guided
@@ -5,7 +5,7 @@ import { S as SessionStorageAdapter } from '../storage-BPaeSG8K.js';
5
5
  * PersistedSession (access token + expiry ride along) so hydration adopts
6
6
  * the full session without a refresh round-trip.
7
7
  */
8
- declare function cookieSessionStorage(endpointRef: string): SessionStorageAdapter;
8
+ declare function cookieSessionStorage(environmentRef: string): SessionStorageAdapter;
9
9
  /**
10
10
  * One-liner for a client component/provider: re-configure the already-loaded
11
11
  * gen config (palbe.gen.ts must be imported first — throws the guided
@@ -2,13 +2,12 @@ import {
2
2
  clearedSessionCookieNames,
3
3
  decodeSessionCookies,
4
4
  encodeSessionCookies
5
- } from "../chunk-VJXFABBW.js";
5
+ } from "../chunk-6VGKMNXO.js";
6
6
  import {
7
7
  __configure,
8
- endpointRefFromApiKey,
9
8
  getRuntime
10
- } from "../chunk-V6VTX65P.js";
11
- import "../chunk-PZ5AY32C.js";
9
+ } from "../chunk-3HVTEZ7N.js";
10
+ import "../chunk-S7NAY3MW.js";
12
11
 
13
12
  // src/next/client.ts
14
13
  var SESSION_MAX_AGE_S = 2592e3;
@@ -26,12 +25,12 @@ function cookieJar() {
26
25
  function deleteCookie(name) {
27
26
  document.cookie = `${name}=; ${WRITE_ATTRS}; Max-Age=0`;
28
27
  }
29
- function cookieSessionStorage(endpointRef) {
28
+ function cookieSessionStorage(environmentRef) {
30
29
  return {
31
30
  load() {
32
31
  if (typeof document === "undefined") return null;
33
32
  const jar = cookieJar();
34
- const stored = decodeSessionCookies((name) => jar.get(name), endpointRef);
33
+ const stored = decodeSessionCookies((name) => jar.get(name), environmentRef);
35
34
  if (!stored) return null;
36
35
  return stored.accessToken && stored.expiresAt > 0 ? {
37
36
  refreshToken: stored.refreshToken,
@@ -42,10 +41,10 @@ function cookieSessionStorage(endpointRef) {
42
41
  save(session) {
43
42
  if (typeof document === "undefined") return;
44
43
  const jar = cookieJar();
45
- for (const name of clearedSessionCookieNames(endpointRef, (n) => jar.has(n))) {
44
+ for (const name of clearedSessionCookieNames(environmentRef, (n) => jar.has(n))) {
46
45
  deleteCookie(name);
47
46
  }
48
- const { set, clear } = encodeSessionCookies(endpointRef, {
47
+ const { set, clear } = encodeSessionCookies(environmentRef, {
49
48
  accessToken: session.accessToken ?? "",
50
49
  refreshToken: session.refreshToken,
51
50
  expiresAt: session.expiresAt ?? 0
@@ -58,7 +57,7 @@ function cookieSessionStorage(endpointRef) {
58
57
  clear() {
59
58
  if (typeof document === "undefined") return;
60
59
  const jar = cookieJar();
61
- for (const name of clearedSessionCookieNames(endpointRef, (n) => jar.has(n))) {
60
+ for (const name of clearedSessionCookieNames(environmentRef, (n) => jar.has(n))) {
62
61
  deleteCookie(name);
63
62
  }
64
63
  }
@@ -67,7 +66,10 @@ function cookieSessionStorage(endpointRef) {
67
66
  function setupPalbeNext() {
68
67
  if (typeof document === "undefined") return;
69
68
  const config = getRuntime().config;
70
- __configure({ ...config, storage: cookieSessionStorage(endpointRefFromApiKey(config.apiKey)) });
69
+ __configure({
70
+ ...config,
71
+ storage: cookieSessionStorage(config.environmentRef)
72
+ });
71
73
  }
72
74
  export {
73
75
  cookieSessionStorage,
@@ -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 endpointRefFromApiKey,\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(endpointRef: 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), endpointRef);\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(endpointRef, (n) => jar.has(n))) {\n deleteCookie(name);\n }\n const { set, clear } = encodeSessionCookies(endpointRef, {\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(endpointRef, (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({ ...config, storage: cookieSessionStorage(endpointRefFromApiKey(config.apiKey)) });\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,aAA4C;AAC/E,SAAO;AAAA,IACL,OAAgC;AAC9B,UAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,YAAM,MAAM,UAAU;AACtB,YAAM,SAAS,qBAAqB,CAAC,SAAS,IAAI,IAAI,IAAI,GAAG,WAAW;AACxE,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,aAAa,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,GAAG;AAC5E,qBAAa,IAAI;AAAA,MACnB;AACA,YAAM,EAAE,KAAK,MAAM,IAAI,qBAAqB,aAAa;AAAA,QACvD,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,aAAa,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,GAAG;AAC5E,qBAAa,IAAI;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;AAUO,SAAS,iBAAuB;AACrC,MAAI,OAAO,aAAa,YAAa;AACrC,QAAM,SAAS,WAAW,EAAE;AAC5B,cAAY,EAAE,GAAG,QAAQ,SAAS,qBAAqB,sBAAsB,OAAO,MAAM,CAAC,EAAE,CAAC;AAChG;","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 { __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":[]}
@@ -35,7 +35,7 @@ __export(next_exports, {
35
35
  decodeSessionCookies: () => decodeSessionCookies,
36
36
  encodeSessionCookies: () => encodeSessionCookies,
37
37
  encodeSessionCookiesDecoded: () => encodeSessionCookiesDecoded,
38
- endpointRefFromApiKey: () => endpointRefFromApiKey,
38
+ environmentRefFromApiKey: () => environmentRefFromApiKey,
39
39
  handleAuthCallback: () => handleAuthCallback,
40
40
  palbeMiddleware: () => palbeMiddleware,
41
41
  pbServer: () => pbServer,
@@ -57,11 +57,16 @@ function asWireAuthResult(raw) {
57
57
  }
58
58
 
59
59
  // src/api-key.ts
60
- var API_KEY_RE = /^pb_([^_]+)_[cs][A-Za-z0-9]{20}$/;
61
- function endpointRefFromApiKey(apiKey) {
60
+ var API_KEY_RE = /^pb_([a-z0-9]+)_[cs][A-Za-z0-9]{20}$/;
61
+ var PUBLISHABLE_API_KEY_RE = /^pb_([a-z0-9]+)_c[A-Za-z0-9]{20}$/;
62
+ function environmentRefFromApiKey(apiKey) {
62
63
  const m = API_KEY_RE.exec(apiKey);
63
64
  return m ? m[1] ?? "" : "";
64
65
  }
66
+ function environmentRefFromPublishableApiKey(apiKey) {
67
+ const match = PUBLISHABLE_API_KEY_RE.exec(apiKey);
68
+ return match ? match[1] ?? "" : "";
69
+ }
65
70
 
66
71
  // src/next/cookie-codec.ts
67
72
  var MAX_COOKIE_VALUE = 3500;
@@ -71,11 +76,11 @@ var SESSION_COOKIE_ATTRS = {
71
76
  secure: true,
72
77
  maxAge: 2592e3
73
78
  };
74
- function sessionCookieName(endpointRef) {
75
- return `palbe-session-${endpointRef}`;
79
+ function sessionCookieName(environmentRef) {
80
+ return `palbe-session-${environmentRef}`;
76
81
  }
77
- function encodeSessionCookies(endpointRef, session) {
78
- const name = sessionCookieName(endpointRef);
82
+ function encodeSessionCookies(environmentRef, session) {
83
+ const name = sessionCookieName(environmentRef);
79
84
  const value = encodeURIComponent(
80
85
  JSON.stringify({ a: session.accessToken, r: session.refreshToken, e: session.expiresAt })
81
86
  );
@@ -94,15 +99,15 @@ function encodeSessionCookies(endpointRef, session) {
94
99
  }
95
100
  return { set: chunks, clear: [`${name}.${chunks.length}`] };
96
101
  }
97
- function encodeSessionCookiesDecoded(endpointRef, session) {
98
- const { set, clear } = encodeSessionCookies(endpointRef, session);
102
+ function encodeSessionCookiesDecoded(environmentRef, session) {
103
+ const { set, clear } = encodeSessionCookies(environmentRef, session);
99
104
  return {
100
105
  set: set.map(({ name, value }) => ({ name, value: decodeURIComponent(value) })),
101
106
  clear
102
107
  };
103
108
  }
104
- function decodeSessionCookies(get, endpointRef) {
105
- const base = sessionCookieName(endpointRef);
109
+ function decodeSessionCookies(get, environmentRef) {
110
+ const base = sessionCookieName(environmentRef);
106
111
  let encoded = get(base);
107
112
  if (encoded === void 0) {
108
113
  let joined = "";
@@ -136,8 +141,8 @@ function parseStoredSession(json) {
136
141
  return null;
137
142
  }
138
143
  }
139
- function clearedSessionCookieNames(endpointRef, present) {
140
- const base = sessionCookieName(endpointRef);
144
+ function clearedSessionCookieNames(environmentRef, present) {
145
+ const base = sessionCookieName(environmentRef);
141
146
  const names = [];
142
147
  if (present(base)) names.push(base);
143
148
  for (let i = 0; ; i++) {
@@ -163,18 +168,9 @@ var PalbaseError = class extends Error {
163
168
  }
164
169
  };
165
170
  var PALBASE_DEFAULT_HOST = "api.palbase.studio";
166
- var REF_LEN = 8;
167
- var BASE62_RE = /^[0-9A-Za-z]+$/;
168
- function parseProjectRef(apiKey) {
169
- if (apiKey.length < 13) return null;
170
- if (!apiKey.startsWith("pb_")) return null;
171
- if (apiKey[11] !== "_") return null;
172
- const ref = apiKey.slice(3, 11);
173
- if (ref.length !== REF_LEN) return null;
174
- if (!BASE62_RE.test(ref)) return null;
175
- const scope = apiKey[12];
176
- if (scope !== "c") return null;
177
- return ref;
171
+ var API_KEY_RE2 = /^pb_([a-z0-9]+)_c[A-Za-z0-9]{20}$/;
172
+ function parseEnvironmentRef(apiKey) {
173
+ return API_KEY_RE2.exec(apiKey)?.[1] ?? null;
178
174
  }
179
175
  var MAX_RETRIES = 3;
180
176
  var INITIAL_BACKOFF_MS = 200;
@@ -204,8 +200,7 @@ var HttpClient = class _HttpClient {
204
200
  * with the parent at runtime — later changes on the parent propagate to
205
201
  * the scope and vice versa.
206
202
  *
207
- * Typical use: tagging admin calls with `x-palbase-project: <ref>` so the
208
- * gateway can route them to the correct project's data plane.
203
+ * Typical use: adding an Environment-routing header for an admin call.
209
204
  */
210
205
  withHeaders(extra) {
211
206
  const mergedHeaders = { ...this.options?.headers ?? {}, ...extra };
@@ -246,10 +241,10 @@ var HttpClient = class _HttpClient {
246
241
  if (this.options?.url) {
247
242
  return this.options.url;
248
243
  }
249
- if (this.apiKey && parseProjectRef(this.apiKey) === null) {
244
+ if (this.apiKey && parseEnvironmentRef(this.apiKey) === null) {
250
245
  throw new PalbaseError(
251
246
  "invalid_api_key",
252
- 'Invalid API key format. Expected pb_{ref}_{scope}{random}. For dev/staging pass `url: "https://api.dev.palbase.studio"` via options.',
247
+ 'Invalid API key format. Expected pb_{environment_ref}_c{20_base62_chars}. For dev/staging pass `url: "https://api.dev.palbase.studio"` via options.',
253
248
  0
254
249
  );
255
250
  }
@@ -262,10 +257,6 @@ var HttpClient = class _HttpClient {
262
257
  const effectiveKey = this.apiKey;
263
258
  if (effectiveKey) {
264
259
  headers["apikey"] = effectiveKey;
265
- const ref = parseProjectRef(effectiveKey);
266
- if (ref) {
267
- headers["X-Project-Ref"] = ref;
268
- }
269
260
  }
270
261
  const token = this.tokenManager?.getAccessToken();
271
262
  if (token) {
@@ -1245,7 +1236,7 @@ var AnalyticsState = class {
1245
1236
  idKey;
1246
1237
  optOutKey;
1247
1238
  constructor(rt) {
1248
- const ref = endpointRefFromApiKey(rt.config.apiKey);
1239
+ const ref = rt.config.environmentRef;
1249
1240
  this.idKey = ref ? `palbe.analytics.id.${ref}` : "palbe.analytics.id";
1250
1241
  this.optOutKey = ref ? `palbe.analytics.optout.${ref}` : "palbe.analytics.optout";
1251
1242
  rt.auth.onAuthEvent((event) => {
@@ -2007,6 +1998,19 @@ var PalbeCalls = class {
2007
1998
 
2008
1999
  // ../modules/flags/dist/index.js
2009
2000
  var FLAG_NAME_RE = /^[a-zA-Z0-9_-]+$/;
2001
+ function flagEnabled(value) {
2002
+ if (typeof value === "boolean") return value;
2003
+ return value != null && value !== 0 && value !== "";
2004
+ }
2005
+ function flagVariant(value) {
2006
+ return typeof value === "string" ? { name: value } : null;
2007
+ }
2008
+ function mapResponse(res, fn) {
2009
+ if (res.error || res.data == null) {
2010
+ return { ...res, data: null };
2011
+ }
2012
+ return { ...res, data: fn(res.data) };
2013
+ }
2010
2014
  var FlagsClient = class {
2011
2015
  httpClient;
2012
2016
  getCurrentUserId;
@@ -2026,10 +2030,11 @@ var FlagsClient = class {
2026
2030
  `Invalid flag name: "${flagName}". Flag names must match ${FLAG_NAME_RE.source}`
2027
2031
  );
2028
2032
  }
2029
- const params = this.buildContextParams(context);
2030
- const query = params.toString();
2031
- const path = `/v1/flags/${flagName}/enabled${query ? `?${query}` : ""}`;
2032
- return this.httpClient.request("GET", path);
2033
+ const res = await this.httpClient.request(
2034
+ "GET",
2035
+ this.mergedPath(context)
2036
+ );
2037
+ return mapResponse(res, (snap) => flagEnabled(snap.values?.[flagName]));
2033
2038
  }
2034
2039
  async getVariant(flagName, context) {
2035
2040
  if (!FLAG_NAME_RE.test(flagName)) {
@@ -2037,16 +2042,29 @@ var FlagsClient = class {
2037
2042
  `Invalid flag name: "${flagName}". Flag names must match ${FLAG_NAME_RE.source}`
2038
2043
  );
2039
2044
  }
2040
- const params = this.buildContextParams(context);
2041
- const query = params.toString();
2042
- const path = `/v1/flags/${flagName}/variant${query ? `?${query}` : ""}`;
2043
- return this.httpClient.request("GET", path);
2045
+ const res = await this.httpClient.request(
2046
+ "GET",
2047
+ this.mergedPath(context)
2048
+ );
2049
+ if (res.error || res.data == null) {
2050
+ return { ...res, data: null };
2051
+ }
2052
+ return { ...res, data: flagVariant(res.data.values?.[flagName]) };
2044
2053
  }
2045
2054
  async getAll(context) {
2046
- const params = this.buildContextParams(context);
2047
- const query = params.toString();
2048
- const path = `/v1/flags${query ? `?${query}` : ""}`;
2049
- return this.httpClient.request("GET", path);
2055
+ const res = await this.httpClient.request(
2056
+ "GET",
2057
+ this.mergedPath(context)
2058
+ );
2059
+ return mapResponse(res, (snap) => {
2060
+ const values = snap.values ?? {};
2061
+ return Object.keys(values).map((name) => {
2062
+ const value = values[name];
2063
+ const flag = { name, enabled: flagEnabled(value) };
2064
+ if (typeof value === "string") flag.variant = { name: value };
2065
+ return flag;
2066
+ });
2067
+ });
2050
2068
  }
2051
2069
  /**
2052
2070
  * Cold-start read: the full merged flag set for the current auth identity.
@@ -2145,15 +2163,16 @@ var FlagsClient = class {
2145
2163
  }
2146
2164
  };
2147
2165
  }
2148
- buildContextParams(context) {
2149
- const params = new URLSearchParams();
2150
- if (context?.userId) {
2151
- params.set("userId", context.userId);
2152
- }
2153
- if (context?.properties) {
2154
- params.set("properties", JSON.stringify(context.properties));
2155
- }
2156
- return params;
2166
+ /**
2167
+ * Resolve the merged-read path for a context. With `context.userId` present the
2168
+ * read targets that specific user's merged view (`/v1/user-flags/users/{id}`, a
2169
+ * privileged cross-user read); otherwise the current auth user's view
2170
+ * (`/v1/user-flags`). `context.properties` has no server-side targeting support
2171
+ * in the user-flags module and is ignored.
2172
+ */
2173
+ mergedPath(context) {
2174
+ const uid = context?.userId;
2175
+ return uid ? `/v1/user-flags/users/${encodeURIComponent(uid)}` : "/v1/user-flags";
2157
2176
  }
2158
2177
  };
2159
2178
  var DEFAULT_POLL_MS = 3e4;
@@ -2558,7 +2577,7 @@ var PalbeFlags = class {
2558
2577
  constructor(rt) {
2559
2578
  this.transport = new FlagsClient(rt.http);
2560
2579
  const browser = typeof document !== "undefined";
2561
- const ref = endpointRefFromApiKey(rt.config.apiKey);
2580
+ const ref = rt.config.environmentRef;
2562
2581
  const options = {
2563
2582
  auth: palbeAuthAdapter(rt.auth),
2564
2583
  ...ref ? { storageKey: `palbe.flags.${ref}` } : {},
@@ -2615,7 +2634,7 @@ var PalbeFlags = class {
2615
2634
  *
2616
2635
  * DEVIATION from iOS sync-cache parity: the platform does not propagate
2617
2636
  * variant metadata into the user-flags snapshot/delta cache, so this is an
2618
- * ASYNC transport read (`GET /v1/flags/{key}/variant`), not a cache lookup.
2637
+ * ASYNC transport read (derived from `GET /v1/user-flags`), not a cache lookup.
2619
2638
  */
2620
2639
  async getVariant(key) {
2621
2640
  let res;
@@ -8298,7 +8317,7 @@ var AnonTokenProvider = class {
8298
8317
  }
8299
8318
  /**
8300
8319
  * Raw fetch, deliberately NOT through HttpClient/palbeRequest: the mint
8301
- * must carry the project apikey and NEVER a Bearer (iOS keeps
8320
+ * must carry the Environment API key and NEVER a Bearer (iOS keeps
8302
8321
  * `/auth/anonymous` on the unauthenticated-path list), and HttpClient's
8303
8322
  * pre-flight would try to refresh a stale session before an anon mint —
8304
8323
  * exactly the entanglement this provider exists to avoid.
@@ -8955,10 +8974,25 @@ function defaultSessionStorage(key) {
8955
8974
  }
8956
8975
 
8957
8976
  // src/version.ts
8958
- var VERSION = "2.0.0";
8977
+ var VERSION = "3.0.0";
8959
8978
 
8960
8979
  // src/runtime.ts
8961
8980
  function buildRuntime(config) {
8981
+ const keyEnvironmentRef = environmentRefFromPublishableApiKey(config.apiKey);
8982
+ if (keyEnvironmentRef === "") {
8983
+ throw new Error("PalbeConfig.apiKey does not contain a valid publishable Environment identity");
8984
+ } else if (config.environmentRef !== keyEnvironmentRef) {
8985
+ throw new Error("PalbeConfig.environmentRef must match the Environment identity in apiKey");
8986
+ }
8987
+ let runtimeURL;
8988
+ try {
8989
+ runtimeURL = new URL(config.url);
8990
+ } catch {
8991
+ throw new Error("PalbeConfig.url must be a valid URL");
8992
+ }
8993
+ if (runtimeURL.hostname.endsWith(".palbase.studio") && runtimeURL.hostname.split(".")[0] !== config.environmentRef) {
8994
+ throw new Error("PalbeConfig.url must match environmentRef for palbase.studio");
8995
+ }
8962
8996
  const http = new HttpClient(config.apiKey, {
8963
8997
  url: config.url,
8964
8998
  headers: { "X-Client-Info": `palbe-web/${VERSION}`, ...config.headers }
@@ -8967,7 +9001,7 @@ function buildRuntime(config) {
8967
9001
  const tokenManager = new TokenManager();
8968
9002
  http.tokenManager = tokenManager;
8969
9003
  const authClient = new AuthClient(http, tokenManager);
8970
- const ref = endpointRefFromApiKey(config.apiKey);
9004
+ const ref = config.environmentRef;
8971
9005
  const storage = config.storage ?? defaultSessionStorage(ref ? `palbe.session.${ref}` : void 0);
8972
9006
  const persisted = storage.load();
8973
9007
  if (persisted) {
@@ -9421,7 +9455,7 @@ function handleAuthCallback(opts) {
9421
9455
  const wire = asWireAuthResult(raw);
9422
9456
  if (!wire) return redirect(fallback, { auth_error: "oauth_exchange_failed" });
9423
9457
  const response = redirect(safeNextPath(params.get("next"), request.nextUrl.origin) ?? fallback);
9424
- const write = encodeSessionCookiesDecoded(endpointRefFromApiKey(config.apiKey), {
9458
+ const write = encodeSessionCookiesDecoded(config.environmentRef, {
9425
9459
  accessToken: wire.access_token,
9426
9460
  refreshToken: wire.refresh_token,
9427
9461
  expiresAt: Date.now() + wire.expires_in * 1e3
@@ -9484,7 +9518,7 @@ async function palbeMiddleware(request, opts) {
9484
9518
  );
9485
9519
  const { NextResponse } = await importNextServer("palbeMiddleware");
9486
9520
  const passThrough = () => opts?.response ?? NextResponse.next({ request });
9487
- const ref = endpointRefFromApiKey(config.apiKey);
9521
+ const ref = config.environmentRef;
9488
9522
  const session = decodeSessionCookies((name) => request.cookies.get(name)?.value, ref);
9489
9523
  if (!session) return passThrough();
9490
9524
  if (session.expiresAt - Date.now() > (opts?.refreshMarginMs ?? DEFAULT_REFRESH_MARGIN_MS)) {
@@ -9554,11 +9588,11 @@ function removeCookie(store, name) {
9554
9588
  } catch {
9555
9589
  }
9556
9590
  }
9557
- function serverCookieAdapter(store, endpointRef) {
9591
+ function serverCookieAdapter(store, environmentRef) {
9558
9592
  const present = (name) => store.get(name) !== void 0;
9559
9593
  return {
9560
9594
  load() {
9561
- const stored = decodeSessionCookies((name) => store.get(name)?.value, endpointRef);
9595
+ const stored = decodeSessionCookies((name) => store.get(name)?.value, environmentRef);
9562
9596
  if (!stored) return null;
9563
9597
  return stored.accessToken && stored.expiresAt > 0 ? {
9564
9598
  refreshToken: stored.refreshToken,
@@ -9568,10 +9602,10 @@ function serverCookieAdapter(store, endpointRef) {
9568
9602
  },
9569
9603
  save(session) {
9570
9604
  if (!session.accessToken || !session.expiresAt) return;
9571
- for (const name of clearedSessionCookieNames(endpointRef, present)) {
9605
+ for (const name of clearedSessionCookieNames(environmentRef, present)) {
9572
9606
  removeCookie(store, name);
9573
9607
  }
9574
- const { set, clear } = encodeSessionCookiesDecoded(endpointRef, {
9608
+ const { set, clear } = encodeSessionCookiesDecoded(environmentRef, {
9575
9609
  accessToken: session.accessToken,
9576
9610
  refreshToken: session.refreshToken,
9577
9611
  expiresAt: session.expiresAt
@@ -9585,7 +9619,7 @@ function serverCookieAdapter(store, endpointRef) {
9585
9619
  for (const name of clear) removeCookie(store, name);
9586
9620
  },
9587
9621
  clear() {
9588
- for (const name of clearedSessionCookieNames(endpointRef, present)) {
9622
+ for (const name of clearedSessionCookieNames(environmentRef, present)) {
9589
9623
  removeCookie(store, name);
9590
9624
  }
9591
9625
  }
@@ -9596,7 +9630,7 @@ async function pbServer(opts) {
9596
9630
  "import the generated palbe.gen.ts once in app/layout.tsx \u2014 the root-layout import configures Server Components and Route Handlers too."
9597
9631
  );
9598
9632
  const store = opts?.cookies ?? await nextCookieStore();
9599
- const ref = endpointRefFromApiKey(config.apiKey);
9633
+ const ref = config.environmentRef;
9600
9634
  const rt = buildRuntime({ ...config, storage: serverCookieAdapter(store, ref) });
9601
9635
  return createBoundClient(rt);
9602
9636
  }
@@ -9607,7 +9641,7 @@ async function pbServer(opts) {
9607
9641
  decodeSessionCookies,
9608
9642
  encodeSessionCookies,
9609
9643
  encodeSessionCookiesDecoded,
9610
- endpointRefFromApiKey,
9644
+ environmentRefFromApiKey,
9611
9645
  handleAuthCallback,
9612
9646
  palbeMiddleware,
9613
9647
  pbServer,