@palbase/web 7.2.2 → 7.3.1
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/{analytics-facade-DLfnVVwL.d.ts → analytics-facade-BER0EyYT.d.ts} +8 -3
- package/dist/{analytics-facade-jyXv7Cu4.d.cts → analytics-facade-CQXCQSoF.d.cts} +8 -3
- package/dist/{chunk-ACCJV6FV.js → chunk-53TN7KYR.js} +58 -5
- package/dist/chunk-53TN7KYR.js.map +1 -0
- package/dist/{chunk-ZC6Q3GPX.js → chunk-CBN3PWNL.js} +2 -2
- package/dist/{chunk-IREKQSHT.js → chunk-RRHJV6YD.js} +22 -15
- package/dist/chunk-RRHJV6YD.js.map +1 -0
- package/dist/gen/cli.cjs +6 -12
- package/dist/gen/cli.cjs.map +1 -1
- package/dist/gen/cli.js +6 -12
- package/dist/gen/cli.js.map +1 -1
- package/dist/index.cjs +49 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/internal.cjs +73 -17
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +3 -3
- package/dist/internal.d.ts +3 -3
- package/dist/internal.js +2 -2
- package/dist/next/client.cjs +81 -25
- package/dist/next/client.cjs.map +1 -1
- package/dist/next/client.js +6 -4
- package/dist/next/client.js.map +1 -1
- package/dist/next/index.cjs +87 -31
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +2 -22
- package/dist/next/index.d.ts +2 -22
- package/dist/next/index.js +7 -6
- package/dist/next/index.js.map +1 -1
- package/dist/next/proxy.js +2 -2
- package/dist/{pb-DdzpEkPY.d.ts → pb-BRlmBIAm.d.ts} +1 -1
- package/dist/{pb-CfYQGEn0.d.cts → pb-WAQvwCfM.d.cts} +1 -1
- package/dist/react/index.cjs +48 -3
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +2 -2
- package/package.json +13 -13
- package/LICENSE +0 -21
- package/dist/chunk-ACCJV6FV.js.map +0 -1
- package/dist/chunk-IREKQSHT.js.map +0 -1
- /package/dist/{chunk-ZC6Q3GPX.js.map → chunk-CBN3PWNL.js.map} +0 -0
package/dist/next/client.js
CHANGED
|
@@ -6,9 +6,11 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
__configure,
|
|
8
8
|
getRuntime
|
|
9
|
-
} from "../chunk-
|
|
10
|
-
import "../chunk-
|
|
11
|
-
import
|
|
9
|
+
} from "../chunk-RRHJV6YD.js";
|
|
10
|
+
import "../chunk-53TN7KYR.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.
|
|
75
|
+
storage: cookieSessionStorage(environmentRefFromPublishableApiKey(config.apiKey))
|
|
74
76
|
});
|
|
75
77
|
}
|
|
76
78
|
export {
|
package/dist/next/client.js.map
CHANGED
|
@@ -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.
|
|
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":[]}
|
package/dist/next/index.cjs
CHANGED
|
@@ -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 = {
|
|
@@ -166,6 +166,45 @@ var PalbaseError = class extends Error {
|
|
|
166
166
|
this.details = details;
|
|
167
167
|
}
|
|
168
168
|
};
|
|
169
|
+
var POW_CHALLENGE_ID_HEADER = "X-PoW-Challenge-ID";
|
|
170
|
+
var POW_NONCE_HEADER = "X-PoW-Nonce";
|
|
171
|
+
function asPowChallenge(details) {
|
|
172
|
+
if (typeof details !== "object" || details === null) return null;
|
|
173
|
+
const env = details;
|
|
174
|
+
if (env.error !== "pow_required") return null;
|
|
175
|
+
const c = env.challenge;
|
|
176
|
+
if (typeof c !== "object" || c === null) return null;
|
|
177
|
+
const { id, prefix, difficulty } = c;
|
|
178
|
+
if (typeof id !== "string" || typeof prefix !== "string") return null;
|
|
179
|
+
if (typeof difficulty !== "number" || !Number.isInteger(difficulty) || difficulty < 0) return null;
|
|
180
|
+
return { id, prefix, difficulty };
|
|
181
|
+
}
|
|
182
|
+
var encoder = new TextEncoder();
|
|
183
|
+
function leadingZeroBits(hash) {
|
|
184
|
+
let bits = 0;
|
|
185
|
+
for (const byte of hash) {
|
|
186
|
+
if (byte === 0) {
|
|
187
|
+
bits += 8;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
return bits + Math.clz32(byte) - 24;
|
|
191
|
+
}
|
|
192
|
+
return bits;
|
|
193
|
+
}
|
|
194
|
+
async function solvePowChallenge(challenge, maxIterations = 1 << 24) {
|
|
195
|
+
for (let nonce = 0; nonce < maxIterations; nonce++) {
|
|
196
|
+
const digest = await crypto.subtle.digest("SHA-256", encoder.encode(challenge.prefix + nonce));
|
|
197
|
+
if (leadingZeroBits(new Uint8Array(digest)) >= challenge.difficulty) {
|
|
198
|
+
return {
|
|
199
|
+
[POW_CHALLENGE_ID_HEADER]: challenge.id,
|
|
200
|
+
[POW_NONCE_HEADER]: String(nonce)
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
throw new Error(
|
|
205
|
+
`proof-of-work: no nonce found for difficulty ${challenge.difficulty} within ${maxIterations} attempts`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
169
208
|
function detectPlatform() {
|
|
170
209
|
if (typeof Deno !== "undefined") {
|
|
171
210
|
return "deno";
|
|
@@ -302,9 +341,9 @@ var HttpClient = class _HttpClient {
|
|
|
302
341
|
}
|
|
303
342
|
return headers;
|
|
304
343
|
}
|
|
305
|
-
async executeWithRetry(method, path, options, attempt) {
|
|
344
|
+
async executeWithRetry(method, path, options, attempt, earned) {
|
|
306
345
|
const url = `${this.getBaseUrl()}${path}`;
|
|
307
|
-
const headers = this.buildHeaders(options);
|
|
346
|
+
const headers = { ...this.buildHeaders(options), ...earned };
|
|
308
347
|
for (const interceptor of this.interceptors) {
|
|
309
348
|
await interceptor({ headers, method, path });
|
|
310
349
|
}
|
|
@@ -323,7 +362,7 @@ var HttpClient = class _HttpClient {
|
|
|
323
362
|
if (attempt < MAX_RETRIES - 1) {
|
|
324
363
|
const backoff = INITIAL_BACKOFF_MS * 2 ** attempt;
|
|
325
364
|
await this.delay(backoff);
|
|
326
|
-
return this.executeWithRetry(method, path, options, attempt + 1);
|
|
365
|
+
return this.executeWithRetry(method, path, options, attempt + 1, earned);
|
|
327
366
|
}
|
|
328
367
|
throw new PalbaseError(
|
|
329
368
|
"network_error",
|
|
@@ -337,7 +376,7 @@ var HttpClient = class _HttpClient {
|
|
|
337
376
|
const parsed = retryAfter ? Number.parseInt(retryAfter, 10) : Number.NaN;
|
|
338
377
|
const delayMs = Number.isNaN(parsed) ? INITIAL_BACKOFF_MS * 2 ** attempt : Math.min(parsed * 1e3, MAX_RETRY_DELAY_MS);
|
|
339
378
|
await this.delay(delayMs);
|
|
340
|
-
return this.executeWithRetry(method, path, options, attempt + 1);
|
|
379
|
+
return this.executeWithRetry(method, path, options, attempt + 1, earned);
|
|
341
380
|
}
|
|
342
381
|
}
|
|
343
382
|
let data = null;
|
|
@@ -351,6 +390,18 @@ var HttpClient = class _HttpClient {
|
|
|
351
390
|
errorBody = body;
|
|
352
391
|
}
|
|
353
392
|
}
|
|
393
|
+
if (response.status === 403 && !earned) {
|
|
394
|
+
const challenge = asPowChallenge(errorBody);
|
|
395
|
+
if (challenge) {
|
|
396
|
+
return this.executeWithRetry(
|
|
397
|
+
method,
|
|
398
|
+
path,
|
|
399
|
+
options,
|
|
400
|
+
attempt,
|
|
401
|
+
await solvePowChallenge(challenge)
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
354
405
|
if (!response.ok) {
|
|
355
406
|
return {
|
|
356
407
|
data: null,
|
|
@@ -591,11 +642,11 @@ async function palbeRequest(rt, method, path, spec = {}) {
|
|
|
591
642
|
if (MUTATING.has(method) && !callerHasKey) {
|
|
592
643
|
headers["Idempotency-Key"] = crypto.randomUUID();
|
|
593
644
|
}
|
|
594
|
-
const attempt = async () => {
|
|
645
|
+
const attempt = async (extra) => {
|
|
595
646
|
try {
|
|
596
647
|
return await rt.http.request(method, path, {
|
|
597
648
|
body: spec.body,
|
|
598
|
-
headers,
|
|
649
|
+
headers: extra ? { ...headers, ...extra } : headers,
|
|
599
650
|
signal: spec.signal
|
|
600
651
|
});
|
|
601
652
|
} catch (e) {
|
|
@@ -630,6 +681,12 @@ async function palbeRequest(rt, method, path, spec = {}) {
|
|
|
630
681
|
}
|
|
631
682
|
res = await attempt();
|
|
632
683
|
}
|
|
684
|
+
if (res.error?.status === 403 && res.error.code === "pow_required") {
|
|
685
|
+
const challenge = asPowChallenge(res.error.details);
|
|
686
|
+
if (challenge) {
|
|
687
|
+
res = await attempt(await solvePowChallenge(challenge));
|
|
688
|
+
}
|
|
689
|
+
}
|
|
633
690
|
} catch (e) {
|
|
634
691
|
if (!isAbort(e)) record(asPalbaseError(e)?.status ?? 0);
|
|
635
692
|
throw e;
|
|
@@ -1287,7 +1344,7 @@ var AnalyticsState = class {
|
|
|
1287
1344
|
idKey;
|
|
1288
1345
|
optOutKey;
|
|
1289
1346
|
constructor(rt) {
|
|
1290
|
-
const ref = rt.
|
|
1347
|
+
const ref = rt.projectRef;
|
|
1291
1348
|
this.idKey = ref ? `palbe.analytics.id.${ref}` : "palbe.analytics.id";
|
|
1292
1349
|
this.optOutKey = ref ? `palbe.analytics.optout.${ref}` : "palbe.analytics.optout";
|
|
1293
1350
|
rt.auth.onAuthEvent((event) => {
|
|
@@ -2908,7 +2965,7 @@ var PalbeFlags = class {
|
|
|
2908
2965
|
constructor(rt) {
|
|
2909
2966
|
this.transport = new FlagsClient(rt.http);
|
|
2910
2967
|
const browser = typeof document !== "undefined";
|
|
2911
|
-
const ref = rt.
|
|
2968
|
+
const ref = rt.projectRef;
|
|
2912
2969
|
const options = {
|
|
2913
2970
|
auth: palbeAuthAdapter(rt.auth),
|
|
2914
2971
|
...ref ? { storageKey: `palbe.flags.${ref}` } : {},
|
|
@@ -9307,15 +9364,13 @@ function defaultSessionStorage(key) {
|
|
|
9307
9364
|
}
|
|
9308
9365
|
|
|
9309
9366
|
// src/version.ts
|
|
9310
|
-
var VERSION = "7.
|
|
9367
|
+
var VERSION = "7.3.1";
|
|
9311
9368
|
|
|
9312
9369
|
// src/runtime.ts
|
|
9313
9370
|
function buildRuntime(config) {
|
|
9314
|
-
const
|
|
9315
|
-
if (
|
|
9316
|
-
throw new Error("PalbeConfig.apiKey does not contain a valid publishable
|
|
9317
|
-
} else if (config.environmentRef !== keyEnvironmentRef) {
|
|
9318
|
-
throw new Error("PalbeConfig.environmentRef must match the Environment identity in apiKey");
|
|
9371
|
+
const projectRef = environmentRefFromPublishableApiKey(config.apiKey);
|
|
9372
|
+
if (projectRef === "") {
|
|
9373
|
+
throw new Error("PalbeConfig.apiKey does not contain a valid publishable project identity");
|
|
9319
9374
|
}
|
|
9320
9375
|
let runtimeURL;
|
|
9321
9376
|
try {
|
|
@@ -9323,8 +9378,8 @@ function buildRuntime(config) {
|
|
|
9323
9378
|
} catch {
|
|
9324
9379
|
throw new Error("PalbeConfig.url must be a valid URL");
|
|
9325
9380
|
}
|
|
9326
|
-
if (runtimeURL.hostname.endsWith(".palbase.studio") && runtimeURL.hostname.split(".")[0] !==
|
|
9327
|
-
throw new Error("PalbeConfig.url must match
|
|
9381
|
+
if (runtimeURL.hostname.endsWith(".palbase.studio") && runtimeURL.hostname.split(".")[0] !== projectRef) {
|
|
9382
|
+
throw new Error("PalbeConfig.url must match the project identity in apiKey for palbase.studio");
|
|
9328
9383
|
}
|
|
9329
9384
|
const http = new HttpClient(config.apiKey, {
|
|
9330
9385
|
url: config.url,
|
|
@@ -9334,7 +9389,7 @@ function buildRuntime(config) {
|
|
|
9334
9389
|
const tokenManager = new TokenManager();
|
|
9335
9390
|
http.tokenManager = tokenManager;
|
|
9336
9391
|
const authClient = new AuthClient(http, tokenManager);
|
|
9337
|
-
const ref =
|
|
9392
|
+
const ref = projectRef;
|
|
9338
9393
|
const storage = config.storage ?? defaultSessionStorage(ref ? `palbe.session.${ref}` : void 0);
|
|
9339
9394
|
const persisted = storage.load();
|
|
9340
9395
|
if (persisted) {
|
|
@@ -9379,6 +9434,7 @@ function buildRuntime(config) {
|
|
|
9379
9434
|
let perf;
|
|
9380
9435
|
const rt = {
|
|
9381
9436
|
config,
|
|
9437
|
+
projectRef,
|
|
9382
9438
|
http,
|
|
9383
9439
|
tokenManager,
|
|
9384
9440
|
authClient,
|
|
@@ -9790,7 +9846,7 @@ function handleAuthCallback(opts) {
|
|
|
9790
9846
|
const wire = asWireAuthResult(raw);
|
|
9791
9847
|
if (!wire) return redirect(fallback, { auth_error: "oauth_exchange_failed" });
|
|
9792
9848
|
const response = redirect(safeNextPath(params.get("next"), request.nextUrl.origin) ?? fallback);
|
|
9793
|
-
const write = encodeSessionCookiesDecoded(config.
|
|
9849
|
+
const write = encodeSessionCookiesDecoded(environmentRefFromPublishableApiKey(config.apiKey), {
|
|
9794
9850
|
accessToken: wire.access_token,
|
|
9795
9851
|
refreshToken: wire.refresh_token,
|
|
9796
9852
|
expiresAt: Date.now() + wire.expires_in * 1e3
|
|
@@ -9881,7 +9937,7 @@ async function pbServer(opts) {
|
|
|
9881
9937
|
"import the generated palbe.gen.ts once in app/layout.tsx \u2014 the root-layout import configures Server Components and Route Handlers too."
|
|
9882
9938
|
);
|
|
9883
9939
|
const store = opts?.cookies ?? await nextCookieStore();
|
|
9884
|
-
const ref = config.
|
|
9940
|
+
const ref = environmentRefFromPublishableApiKey(config.apiKey);
|
|
9885
9941
|
const rt = buildRuntime({ ...config, storage: serverCookieAdapter(store, ref) });
|
|
9886
9942
|
return createBoundClient(rt);
|
|
9887
9943
|
}
|