@palbase/web 4.0.2 → 5.0.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/README.md +20 -3
- package/dist/chunk-BNAGRUIQ.js +381 -0
- package/dist/chunk-BNAGRUIQ.js.map +1 -0
- package/dist/chunk-OWLTZG2V.js +24 -0
- package/dist/chunk-OWLTZG2V.js.map +1 -0
- package/dist/{chunk-TW6YN354.js → chunk-QKFPPZLF.js} +13 -373
- package/dist/chunk-QKFPPZLF.js.map +1 -0
- package/dist/gen/cli.cjs +8 -5
- package/dist/gen/cli.cjs.map +1 -1
- package/dist/gen/cli.js +8 -5
- package/dist/gen/cli.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -3
- package/dist/internal.cjs +1 -1
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.js +2 -1
- package/dist/next/client.cjs +1 -1
- package/dist/next/client.cjs.map +1 -1
- package/dist/next/client.js +2 -1
- package/dist/next/client.js.map +1 -1
- package/dist/next/index.cjs +4 -88
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +2 -62
- package/dist/next/index.d.ts +2 -62
- package/dist/next/index.js +8 -102
- package/dist/next/index.js.map +1 -1
- package/dist/next/middleware.cjs +263 -0
- package/dist/next/middleware.cjs.map +1 -0
- package/dist/next/middleware.d.cts +101 -0
- package/dist/next/middleware.d.ts +101 -0
- package/dist/next/middleware.js +107 -0
- package/dist/next/middleware.js.map +1 -0
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +2 -1
- package/dist/react/index.js.map +1 -1
- package/package.json +11 -1
- package/dist/chunk-TW6YN354.js.map +0 -1
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BackendError,
|
|
3
|
+
HttpClient,
|
|
4
|
+
PalbaseError,
|
|
5
|
+
TokenManager,
|
|
6
|
+
asPalbaseError,
|
|
7
|
+
fromEnvelope,
|
|
8
|
+
fromPalbaseError,
|
|
9
|
+
isBackendError,
|
|
10
|
+
unwrap
|
|
11
|
+
} from "./chunk-BNAGRUIQ.js";
|
|
1
12
|
import {
|
|
2
13
|
environmentRefFromPublishableApiKey
|
|
3
14
|
} from "./chunk-CFDU23TB.js";
|
|
@@ -5,375 +16,6 @@ import {
|
|
|
5
16
|
__export
|
|
6
17
|
} from "./chunk-PZ5AY32C.js";
|
|
7
18
|
|
|
8
|
-
// ../core/dist/index.js
|
|
9
|
-
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
10
|
-
var PalbaseError = class extends Error {
|
|
11
|
-
code;
|
|
12
|
-
status;
|
|
13
|
-
details;
|
|
14
|
-
constructor(code, message, status, details) {
|
|
15
|
-
super(message);
|
|
16
|
-
this.name = "PalbaseError";
|
|
17
|
-
this.code = code;
|
|
18
|
-
this.status = status;
|
|
19
|
-
this.details = details;
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
var PALBASE_DEFAULT_HOST = "api.palbase.studio";
|
|
23
|
-
var API_KEY_RE = /^pb_([a-z0-9]{4,24})_c[A-Za-z0-9]{20}$/;
|
|
24
|
-
function parseEnvironmentRef(apiKey) {
|
|
25
|
-
return API_KEY_RE.exec(apiKey)?.[1] ?? null;
|
|
26
|
-
}
|
|
27
|
-
var MAX_RETRIES = 3;
|
|
28
|
-
var INITIAL_BACKOFF_MS = 200;
|
|
29
|
-
var MAX_RETRY_DELAY_MS = 1e4;
|
|
30
|
-
var HttpClient = class _HttpClient {
|
|
31
|
-
apiKey;
|
|
32
|
-
options;
|
|
33
|
-
tokenManager = null;
|
|
34
|
-
/**
|
|
35
|
-
* Admin JWT used for platform admin endpoints (/admin/*).
|
|
36
|
-
* When set, takes precedence over tokenManager access token in the
|
|
37
|
-
* Authorization header.
|
|
38
|
-
*/
|
|
39
|
-
adminToken = null;
|
|
40
|
-
interceptors = [];
|
|
41
|
-
constructor(apiKey, options) {
|
|
42
|
-
this.apiKey = apiKey;
|
|
43
|
-
this.options = options;
|
|
44
|
-
}
|
|
45
|
-
/** Set (or clear) the admin JWT used on admin endpoints. */
|
|
46
|
-
setAdminToken(token) {
|
|
47
|
-
this.adminToken = token;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Create a scoped HttpClient that adds the given extra headers to every
|
|
51
|
-
* request. The returned client shares the admin token and token manager
|
|
52
|
-
* with the parent at runtime — later changes on the parent propagate to
|
|
53
|
-
* the scope and vice versa.
|
|
54
|
-
*
|
|
55
|
-
* Typical use: adding an Environment-routing header for an admin call.
|
|
56
|
-
*/
|
|
57
|
-
withHeaders(extra) {
|
|
58
|
-
const mergedHeaders = { ...this.options?.headers ?? {}, ...extra };
|
|
59
|
-
const scoped = new _HttpClient(this.apiKey, {
|
|
60
|
-
...this.options,
|
|
61
|
-
headers: mergedHeaders
|
|
62
|
-
});
|
|
63
|
-
scoped.tokenManager = this.tokenManager;
|
|
64
|
-
Object.defineProperty(scoped, "adminToken", {
|
|
65
|
-
get: () => this.adminToken,
|
|
66
|
-
set: (v) => {
|
|
67
|
-
this.adminToken = v;
|
|
68
|
-
},
|
|
69
|
-
configurable: true
|
|
70
|
-
});
|
|
71
|
-
return scoped;
|
|
72
|
-
}
|
|
73
|
-
/** Add a request interceptor. Runs before every request. */
|
|
74
|
-
addInterceptor(interceptor) {
|
|
75
|
-
this.interceptors.push(interceptor);
|
|
76
|
-
}
|
|
77
|
-
async request(method, path, options) {
|
|
78
|
-
if (this.tokenManager?.isExpired() && this.tokenManager.getRefreshToken() && this.tokenManager.refreshFunction) {
|
|
79
|
-
try {
|
|
80
|
-
await this.tokenManager.refreshSession();
|
|
81
|
-
} catch (e) {
|
|
82
|
-
const status = e instanceof PalbaseError ? e.status : 0;
|
|
83
|
-
if (status === 400 || status === 401 || status === 403) {
|
|
84
|
-
this.tokenManager.clearSession();
|
|
85
|
-
} else {
|
|
86
|
-
throw e;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return this.executeWithRetry(method, path, options, 0);
|
|
91
|
-
}
|
|
92
|
-
getBaseUrl() {
|
|
93
|
-
if (this.options?.url) {
|
|
94
|
-
return this.options.url;
|
|
95
|
-
}
|
|
96
|
-
if (this.apiKey && parseEnvironmentRef(this.apiKey) === null) {
|
|
97
|
-
throw new PalbaseError(
|
|
98
|
-
"invalid_api_key",
|
|
99
|
-
'Invalid API key format. Expected pb_{environment_ref}_c{20_base62_chars}. For dev/staging pass `url: "https://api.dev.palbase.studio"` via options.',
|
|
100
|
-
0
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
return `https://${PALBASE_DEFAULT_HOST}`;
|
|
104
|
-
}
|
|
105
|
-
buildHeaders(options) {
|
|
106
|
-
const headers = {
|
|
107
|
-
"Content-Type": "application/json"
|
|
108
|
-
};
|
|
109
|
-
const effectiveKey = this.apiKey;
|
|
110
|
-
if (effectiveKey) {
|
|
111
|
-
headers["apikey"] = effectiveKey;
|
|
112
|
-
}
|
|
113
|
-
const token = this.tokenManager?.getAccessToken();
|
|
114
|
-
if (token) {
|
|
115
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
116
|
-
}
|
|
117
|
-
if (this.adminToken) {
|
|
118
|
-
headers["Authorization"] = `Bearer ${this.adminToken}`;
|
|
119
|
-
}
|
|
120
|
-
if (this.options?.headers) {
|
|
121
|
-
Object.assign(headers, this.options.headers);
|
|
122
|
-
}
|
|
123
|
-
if (options?.headers) {
|
|
124
|
-
Object.assign(headers, options.headers);
|
|
125
|
-
}
|
|
126
|
-
return headers;
|
|
127
|
-
}
|
|
128
|
-
async executeWithRetry(method, path, options, attempt) {
|
|
129
|
-
const url = `${this.getBaseUrl()}${path}`;
|
|
130
|
-
const headers = this.buildHeaders(options);
|
|
131
|
-
for (const interceptor of this.interceptors) {
|
|
132
|
-
await interceptor({ headers, method, path });
|
|
133
|
-
}
|
|
134
|
-
const fetchOptions = {
|
|
135
|
-
method,
|
|
136
|
-
headers,
|
|
137
|
-
signal: options?.signal
|
|
138
|
-
};
|
|
139
|
-
if (options?.body !== void 0) {
|
|
140
|
-
fetchOptions.body = JSON.stringify(options.body);
|
|
141
|
-
}
|
|
142
|
-
let response;
|
|
143
|
-
try {
|
|
144
|
-
response = await fetch(url, fetchOptions);
|
|
145
|
-
} catch (error) {
|
|
146
|
-
if (attempt < MAX_RETRIES - 1) {
|
|
147
|
-
const backoff = INITIAL_BACKOFF_MS * 2 ** attempt;
|
|
148
|
-
await this.delay(backoff);
|
|
149
|
-
return this.executeWithRetry(method, path, options, attempt + 1);
|
|
150
|
-
}
|
|
151
|
-
throw new PalbaseError(
|
|
152
|
-
"network_error",
|
|
153
|
-
error instanceof Error ? error.message : "Network request failed",
|
|
154
|
-
0
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
if (response.status === 429) {
|
|
158
|
-
if (attempt < MAX_RETRIES - 1) {
|
|
159
|
-
const retryAfter = response.headers.get("Retry-After");
|
|
160
|
-
const parsed = retryAfter ? Number.parseInt(retryAfter, 10) : Number.NaN;
|
|
161
|
-
const delayMs = Number.isNaN(parsed) ? INITIAL_BACKOFF_MS * 2 ** attempt : Math.min(parsed * 1e3, MAX_RETRY_DELAY_MS);
|
|
162
|
-
await this.delay(delayMs);
|
|
163
|
-
return this.executeWithRetry(method, path, options, attempt + 1);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
let data = null;
|
|
167
|
-
let errorBody;
|
|
168
|
-
const contentType = response.headers.get("Content-Type");
|
|
169
|
-
if (method !== "HEAD" && contentType?.includes("json")) {
|
|
170
|
-
const body = await response.json();
|
|
171
|
-
if (response.ok) {
|
|
172
|
-
data = body;
|
|
173
|
-
} else {
|
|
174
|
-
errorBody = body;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
if (!response.ok) {
|
|
178
|
-
return {
|
|
179
|
-
data: null,
|
|
180
|
-
error: new PalbaseError(
|
|
181
|
-
errorBody?.error ?? "unknown_error",
|
|
182
|
-
errorBody?.error_description ?? response.statusText,
|
|
183
|
-
response.status,
|
|
184
|
-
errorBody
|
|
185
|
-
),
|
|
186
|
-
status: response.status
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
const contentRange = response.headers.get("Content-Range");
|
|
190
|
-
let count;
|
|
191
|
-
if (contentRange) {
|
|
192
|
-
const slash = contentRange.lastIndexOf("/");
|
|
193
|
-
if (slash >= 0) {
|
|
194
|
-
const totalPart = contentRange.slice(slash + 1);
|
|
195
|
-
if (totalPart !== "*") {
|
|
196
|
-
const parsed = Number.parseInt(totalPart, 10);
|
|
197
|
-
if (!Number.isNaN(parsed)) {
|
|
198
|
-
count = parsed;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
return {
|
|
204
|
-
data,
|
|
205
|
-
error: null,
|
|
206
|
-
status: response.status,
|
|
207
|
-
...count !== void 0 ? { count } : {}
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
delay(ms) {
|
|
211
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
var TokenManager = class {
|
|
215
|
-
session = null;
|
|
216
|
-
listeners = /* @__PURE__ */ new Set();
|
|
217
|
-
refreshPromise = null;
|
|
218
|
-
refreshing = false;
|
|
219
|
-
refreshFunction = null;
|
|
220
|
-
setSession(session) {
|
|
221
|
-
this.session = session;
|
|
222
|
-
this.notify("SESSION_SET", session);
|
|
223
|
-
}
|
|
224
|
-
getAccessToken() {
|
|
225
|
-
return this.session?.accessToken ?? null;
|
|
226
|
-
}
|
|
227
|
-
getRefreshToken() {
|
|
228
|
-
return this.session?.refreshToken ?? null;
|
|
229
|
-
}
|
|
230
|
-
clearSession() {
|
|
231
|
-
this.session = null;
|
|
232
|
-
this.notify("SESSION_CLEARED", null);
|
|
233
|
-
}
|
|
234
|
-
isExpired() {
|
|
235
|
-
if (!this.session) return true;
|
|
236
|
-
return Date.now() >= this.session.expiresAt;
|
|
237
|
-
}
|
|
238
|
-
async refreshSession() {
|
|
239
|
-
if (!this.session?.refreshToken || !this.refreshFunction) {
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
if (this.refreshPromise) {
|
|
243
|
-
return this.refreshPromise;
|
|
244
|
-
}
|
|
245
|
-
if (this.refreshing) {
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
this.refreshing = true;
|
|
249
|
-
this.refreshPromise = this.executeRefresh(this.session.refreshToken);
|
|
250
|
-
try {
|
|
251
|
-
await this.refreshPromise;
|
|
252
|
-
} finally {
|
|
253
|
-
this.refreshPromise = null;
|
|
254
|
-
this.refreshing = false;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
onAuthStateChange(callback) {
|
|
258
|
-
this.listeners.add(callback);
|
|
259
|
-
return () => {
|
|
260
|
-
this.listeners.delete(callback);
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
async executeRefresh(refreshToken) {
|
|
264
|
-
if (!this.refreshFunction) return;
|
|
265
|
-
const newSession = await this.refreshFunction(refreshToken);
|
|
266
|
-
this.setSession(newSession);
|
|
267
|
-
}
|
|
268
|
-
notify(event, session) {
|
|
269
|
-
for (const listener of this.listeners) {
|
|
270
|
-
listener(event, session);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
// src/errors.ts
|
|
276
|
-
var BackendError = class _BackendError extends Error {
|
|
277
|
-
kind;
|
|
278
|
-
code;
|
|
279
|
-
status;
|
|
280
|
-
requestId;
|
|
281
|
-
fields;
|
|
282
|
-
retryAfter;
|
|
283
|
-
data;
|
|
284
|
-
constructor(kind, params) {
|
|
285
|
-
super(params.message);
|
|
286
|
-
this.name = "BackendError";
|
|
287
|
-
this.kind = kind;
|
|
288
|
-
this.code = params.code;
|
|
289
|
-
this.status = params.status ?? 0;
|
|
290
|
-
this.requestId = params.requestId;
|
|
291
|
-
this.fields = params.fields;
|
|
292
|
-
this.retryAfter = params.retryAfter;
|
|
293
|
-
this.data = params.data;
|
|
294
|
-
}
|
|
295
|
-
static notConfigured() {
|
|
296
|
-
return new _BackendError("notConfigured", {
|
|
297
|
-
code: "not_configured",
|
|
298
|
-
message: "Palbe is not configured. Run 'palbase web link' in your project and make sure palbe.gen.ts is imported once at app startup."
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
function isFieldErrorArray(value) {
|
|
303
|
-
return Array.isArray(value) && value.length > 0 && value.every(
|
|
304
|
-
(v) => typeof v === "object" && v !== null && typeof v.field === "string" && typeof v.message === "string"
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
function pickField(value, key) {
|
|
308
|
-
if (typeof value === "object" && value !== null) {
|
|
309
|
-
return value[key];
|
|
310
|
-
}
|
|
311
|
-
return void 0;
|
|
312
|
-
}
|
|
313
|
-
function pickNumber(value, key) {
|
|
314
|
-
const n = pickField(value, key);
|
|
315
|
-
return typeof n === "number" ? n : void 0;
|
|
316
|
-
}
|
|
317
|
-
function pickString(value, key) {
|
|
318
|
-
const s = pickField(value, key);
|
|
319
|
-
return typeof s === "string" ? s : void 0;
|
|
320
|
-
}
|
|
321
|
-
function fromPalbaseError(err) {
|
|
322
|
-
const base = {
|
|
323
|
-
code: err.code,
|
|
324
|
-
message: err.message,
|
|
325
|
-
status: err.status,
|
|
326
|
-
requestId: pickString(err.details, "request_id"),
|
|
327
|
-
data: pickField(err.details, "data")
|
|
328
|
-
};
|
|
329
|
-
if (err.code === "network_error") return new BackendError("network", base);
|
|
330
|
-
if (err.status === 401) return new BackendError("unauthorized", base);
|
|
331
|
-
if (err.status === 429)
|
|
332
|
-
return new BackendError("rateLimited", {
|
|
333
|
-
...base,
|
|
334
|
-
retryAfter: pickNumber(err.details, "retry_after")
|
|
335
|
-
});
|
|
336
|
-
const nested = pickField(err.details, "details");
|
|
337
|
-
if (err.status === 400 && isFieldErrorArray(nested))
|
|
338
|
-
return new BackendError("validation", { ...base, fields: nested });
|
|
339
|
-
return new BackendError("server", base);
|
|
340
|
-
}
|
|
341
|
-
function fromEnvelope(status, body) {
|
|
342
|
-
const code = pickString(body, "error") ?? "http_error";
|
|
343
|
-
const message = pickString(body, "error_description") ?? `HTTP ${status}`;
|
|
344
|
-
const requestId = pickString(body, "request_id");
|
|
345
|
-
const details = pickField(body, "details");
|
|
346
|
-
const params = {
|
|
347
|
-
code,
|
|
348
|
-
message,
|
|
349
|
-
status,
|
|
350
|
-
requestId,
|
|
351
|
-
data: pickField(body, "data")
|
|
352
|
-
};
|
|
353
|
-
if (status === 401) return new BackendError("unauthorized", params);
|
|
354
|
-
if (status === 429)
|
|
355
|
-
return new BackendError("rateLimited", {
|
|
356
|
-
...params,
|
|
357
|
-
// Real 429 wire body has TOP-LEVEL retry_after; nested details is a fallback.
|
|
358
|
-
retryAfter: pickNumber(body, "retry_after") ?? pickNumber(details, "retry_after")
|
|
359
|
-
});
|
|
360
|
-
if (status === 400 && isFieldErrorArray(details))
|
|
361
|
-
return new BackendError("validation", { ...params, fields: details });
|
|
362
|
-
return new BackendError("server", params);
|
|
363
|
-
}
|
|
364
|
-
function isBackendError(e) {
|
|
365
|
-
return e instanceof BackendError || typeof e === "object" && e !== null && e.name === "BackendError" && typeof e.kind === "string";
|
|
366
|
-
}
|
|
367
|
-
function asPalbaseError(e) {
|
|
368
|
-
if (e instanceof PalbaseError) return e;
|
|
369
|
-
if (e instanceof Error && e.name === "PalbaseError") return e;
|
|
370
|
-
return null;
|
|
371
|
-
}
|
|
372
|
-
function unwrap(res) {
|
|
373
|
-
if (res.error) throw fromPalbaseError(res.error);
|
|
374
|
-
return res.data;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
19
|
// src/perf/url-redactor.ts
|
|
378
20
|
var ID_SEGMENT = /^(?:\d+|[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/;
|
|
379
21
|
var EMAIL_SEGMENT = /(?:@|%40)/i;
|
|
@@ -8991,7 +8633,7 @@ function defaultSessionStorage(key) {
|
|
|
8991
8633
|
}
|
|
8992
8634
|
|
|
8993
8635
|
// src/version.ts
|
|
8994
|
-
var VERSION = "
|
|
8636
|
+
var VERSION = "5.0.1";
|
|
8995
8637
|
|
|
8996
8638
|
// src/runtime.ts
|
|
8997
8639
|
function buildRuntime(config) {
|
|
@@ -9395,8 +9037,6 @@ function __reset() {
|
|
|
9395
9037
|
}
|
|
9396
9038
|
|
|
9397
9039
|
export {
|
|
9398
|
-
BackendError,
|
|
9399
|
-
isBackendError,
|
|
9400
9040
|
PalbeAnalytics,
|
|
9401
9041
|
asWireAuthResult,
|
|
9402
9042
|
PalbeAuth,
|
|
@@ -9418,4 +9058,4 @@ export {
|
|
|
9418
9058
|
pb,
|
|
9419
9059
|
createBoundClient
|
|
9420
9060
|
};
|
|
9421
|
-
//# sourceMappingURL=chunk-
|
|
9061
|
+
//# sourceMappingURL=chunk-QKFPPZLF.js.map
|