@palbase/web 1.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 (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +292 -0
  3. package/dist/analytics-facade-DkOwkEpi.d.ts +454 -0
  4. package/dist/analytics-facade-t6UrFdn7.d.cts +454 -0
  5. package/dist/chunk-JVT65V4E.js +3384 -0
  6. package/dist/chunk-JVT65V4E.js.map +1 -0
  7. package/dist/chunk-VJXFABBW.js +94 -0
  8. package/dist/chunk-VJXFABBW.js.map +1 -0
  9. package/dist/errors-fDoNdTrJ.d.cts +35 -0
  10. package/dist/errors-fDoNdTrJ.d.ts +35 -0
  11. package/dist/index.cjs +2394 -0
  12. package/dist/index.cjs.map +1 -0
  13. package/dist/index.d.cts +11 -0
  14. package/dist/index.d.ts +11 -0
  15. package/dist/index.js +27 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/internal.cjs +3403 -0
  18. package/dist/internal.cjs.map +1 -0
  19. package/dist/internal.d.cts +49 -0
  20. package/dist/internal.d.ts +49 -0
  21. package/dist/internal.js +19 -0
  22. package/dist/internal.js.map +1 -0
  23. package/dist/next/client.cjs +3131 -0
  24. package/dist/next/client.cjs.map +1 -0
  25. package/dist/next/client.d.cts +19 -0
  26. package/dist/next/client.d.ts +19 -0
  27. package/dist/next/client.js +75 -0
  28. package/dist/next/client.js.map +1 -0
  29. package/dist/next/index.cjs +3680 -0
  30. package/dist/next/index.cjs.map +1 -0
  31. package/dist/next/index.d.cts +238 -0
  32. package/dist/next/index.d.ts +238 -0
  33. package/dist/next/index.js +301 -0
  34. package/dist/next/index.js.map +1 -0
  35. package/dist/pb-BmgkAe97.d.ts +54 -0
  36. package/dist/pb-Cudze7Kb.d.cts +54 -0
  37. package/dist/react/index.cjs +649 -0
  38. package/dist/react/index.cjs.map +1 -0
  39. package/dist/react/index.d.cts +86 -0
  40. package/dist/react/index.d.ts +86 -0
  41. package/dist/react/index.js +156 -0
  42. package/dist/react/index.js.map +1 -0
  43. package/dist/storage-BPaeSG8K.d.cts +21 -0
  44. package/dist/storage-BPaeSG8K.d.ts +21 -0
  45. package/package.json +123 -0
@@ -0,0 +1,649 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/react/index.tsx
22
+ var react_exports = {};
23
+ __export(react_exports, {
24
+ useChannel: () => useChannel,
25
+ useFlag: () => useFlag,
26
+ useFlags: () => useFlags,
27
+ useSession: () => useSession,
28
+ useUser: () => useUser
29
+ });
30
+ module.exports = __toCommonJS(react_exports);
31
+ var import_react = require("react");
32
+
33
+ // ../core/dist/index.js
34
+ var CACHE_TTL_MS = 5 * 60 * 1e3;
35
+ var PalbaseError = class extends Error {
36
+ code;
37
+ status;
38
+ details;
39
+ constructor(code, message, status, details) {
40
+ super(message);
41
+ this.name = "PalbaseError";
42
+ this.code = code;
43
+ this.status = status;
44
+ this.details = details;
45
+ }
46
+ };
47
+
48
+ // src/errors.ts
49
+ var BackendError = class _BackendError extends Error {
50
+ kind;
51
+ code;
52
+ status;
53
+ requestId;
54
+ fields;
55
+ retryAfter;
56
+ data;
57
+ constructor(kind, params) {
58
+ super(params.message);
59
+ this.name = "BackendError";
60
+ this.kind = kind;
61
+ this.code = params.code;
62
+ this.status = params.status ?? 0;
63
+ this.requestId = params.requestId;
64
+ this.fields = params.fields;
65
+ this.retryAfter = params.retryAfter;
66
+ this.data = params.data;
67
+ }
68
+ static notConfigured() {
69
+ return new _BackendError("notConfigured", {
70
+ code: "not_configured",
71
+ message: "Palbe is not configured. Run 'palbase web link' in your project and make sure palbe.gen.ts is imported once at app startup."
72
+ });
73
+ }
74
+ };
75
+ function isFieldErrorArray(value) {
76
+ return Array.isArray(value) && value.length > 0 && value.every(
77
+ (v) => typeof v === "object" && v !== null && typeof v.field === "string" && typeof v.message === "string"
78
+ );
79
+ }
80
+ function pickField(value, key) {
81
+ if (typeof value === "object" && value !== null) {
82
+ return value[key];
83
+ }
84
+ return void 0;
85
+ }
86
+ function pickNumber(value, key) {
87
+ const n = pickField(value, key);
88
+ return typeof n === "number" ? n : void 0;
89
+ }
90
+ function pickString(value, key) {
91
+ const s = pickField(value, key);
92
+ return typeof s === "string" ? s : void 0;
93
+ }
94
+ function fromPalbaseError(err) {
95
+ const base = {
96
+ code: err.code,
97
+ message: err.message,
98
+ status: err.status,
99
+ requestId: pickString(err.details, "request_id"),
100
+ data: pickField(err.details, "data")
101
+ };
102
+ if (err.code === "network_error") return new BackendError("network", base);
103
+ if (err.status === 401) return new BackendError("unauthorized", base);
104
+ if (err.status === 429)
105
+ return new BackendError("rateLimited", {
106
+ ...base,
107
+ retryAfter: pickNumber(err.details, "retry_after")
108
+ });
109
+ const nested = pickField(err.details, "details");
110
+ if (err.status === 400 && isFieldErrorArray(nested))
111
+ return new BackendError("validation", { ...base, fields: nested });
112
+ return new BackendError("server", base);
113
+ }
114
+ function fromEnvelope(status, body) {
115
+ const code = pickString(body, "error") ?? "http_error";
116
+ const message = pickString(body, "error_description") ?? `HTTP ${status}`;
117
+ const requestId = pickString(body, "request_id");
118
+ const details = pickField(body, "details");
119
+ const params = {
120
+ code,
121
+ message,
122
+ status,
123
+ requestId,
124
+ data: pickField(body, "data")
125
+ };
126
+ if (status === 401) return new BackendError("unauthorized", params);
127
+ if (status === 429)
128
+ return new BackendError("rateLimited", {
129
+ ...params,
130
+ // Real 429 wire body has TOP-LEVEL retry_after; nested details is a fallback.
131
+ retryAfter: pickNumber(body, "retry_after") ?? pickNumber(details, "retry_after")
132
+ });
133
+ if (status === 400 && isFieldErrorArray(details))
134
+ return new BackendError("validation", { ...params, fields: details });
135
+ return new BackendError("server", params);
136
+ }
137
+ function isBackendError(e) {
138
+ return e instanceof BackendError || typeof e === "object" && e !== null && e.name === "BackendError" && typeof e.kind === "string";
139
+ }
140
+ function asPalbaseError(e) {
141
+ if (e instanceof PalbaseError) return e;
142
+ if (e instanceof Error && e.name === "PalbaseError") return e;
143
+ return null;
144
+ }
145
+ function unwrap(res) {
146
+ if (res.error) throw fromPalbaseError(res.error);
147
+ return res.data;
148
+ }
149
+
150
+ // src/request.ts
151
+ var MUTATING = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
152
+ async function palbeRequest(rt, method, path, spec = {}) {
153
+ const headers = { ...spec.headers };
154
+ const callerHasKey = Object.keys(headers).some((k) => k.toLowerCase() === "idempotency-key");
155
+ if (MUTATING.has(method) && !callerHasKey) {
156
+ headers["Idempotency-Key"] = crypto.randomUUID();
157
+ }
158
+ const attempt = async () => {
159
+ try {
160
+ return await rt.http.request(method, path, {
161
+ body: spec.body,
162
+ headers,
163
+ signal: spec.signal
164
+ });
165
+ } catch (e) {
166
+ const pe = asPalbaseError(e);
167
+ throw pe ? fromPalbaseError(pe) : e;
168
+ }
169
+ };
170
+ let res = await attempt();
171
+ if (res.error?.status === 401 && rt.tokenManager.getRefreshToken() && rt.tokenManager.refreshFunction) {
172
+ try {
173
+ await rt.tokenManager.refreshSession();
174
+ } catch (refreshErr) {
175
+ const pe = asPalbaseError(refreshErr);
176
+ const status = pe?.status ?? 0;
177
+ if (status === 400 || status === 401 || status === 403) {
178
+ rt.tokenManager.clearSession();
179
+ throw fromPalbaseError(res.error);
180
+ }
181
+ throw pe ? fromPalbaseError(pe) : refreshErr;
182
+ }
183
+ res = await attempt();
184
+ }
185
+ return unwrap(res);
186
+ }
187
+
188
+ // src/state.ts
189
+ var STATE_KEY = /* @__PURE__ */ Symbol.for("palbe.state.v1");
190
+ function palbeState() {
191
+ const g = globalThis;
192
+ let state = g[STATE_KEY];
193
+ if (!state) {
194
+ state = { runtime: null, registry: {}, nsCache: {}, configuredListeners: /* @__PURE__ */ new Set() };
195
+ g[STATE_KEY] = state;
196
+ }
197
+ return state;
198
+ }
199
+
200
+ // src/namespaces.ts
201
+ function isDescriptor(node) {
202
+ return typeof node.path === "string" && typeof node.method === "string";
203
+ }
204
+ function getRegistry() {
205
+ return palbeState().registry;
206
+ }
207
+ function serializeQuery(input) {
208
+ if (input === void 0 || input === null) return "";
209
+ const entries = Object.entries(input).filter(([, v]) => v !== void 0 && v !== null).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
210
+ if (entries.length === 0) return "";
211
+ const parts = entries.map(([k, v]) => {
212
+ if (typeof v !== "string" && typeof v !== "number" && typeof v !== "boolean") {
213
+ throw new BackendError("validation", {
214
+ code: "invalid_query_value",
215
+ message: `Query parameter '${k}' must be a string, number, or boolean.`
216
+ });
217
+ }
218
+ return `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`;
219
+ });
220
+ return `?${parts.join("&")}`;
221
+ }
222
+ async function invokeDescriptor(rt, d, args) {
223
+ const params = d.pathParams ?? [];
224
+ let path = d.path;
225
+ for (let i = 0; i < params.length; i++) {
226
+ const v = args[i];
227
+ if (typeof v !== "string" && typeof v !== "number") {
228
+ throw new BackendError("validation", {
229
+ code: "missing_path_param",
230
+ message: `${d.path}: path parameter '${params[i]}' must be a string or number`
231
+ });
232
+ }
233
+ path = path.replace(`{${params[i]}}`, encodeURIComponent(String(v)));
234
+ }
235
+ if (d.input === "none" && args.length > params.length + 1) {
236
+ throw new BackendError("validation", {
237
+ code: "unexpected_argument",
238
+ message: `${d.path}: endpoint takes no input \u2014 pass only path params and options`
239
+ });
240
+ }
241
+ const input = d.input === "none" ? void 0 : args[params.length];
242
+ const optionsSlot = d.input === "none" ? params.length : params.length + 1;
243
+ const options = args[optionsSlot];
244
+ let body;
245
+ if (d.input === "query") {
246
+ path += serializeQuery(input);
247
+ } else if (d.input !== "none") {
248
+ if (d.method === "GET") {
249
+ if (input !== void 0) {
250
+ throw new BackendError("validation", {
251
+ code: "unsupported_get_input",
252
+ message: `${d.path}: GET endpoints take no body input`
253
+ });
254
+ }
255
+ } else {
256
+ body = input;
257
+ }
258
+ }
259
+ try {
260
+ return await palbeRequest(rt, d.method, path, {
261
+ body,
262
+ headers: options?.headers,
263
+ signal: options?.signal
264
+ });
265
+ } catch (e) {
266
+ if (d.errors && isBackendError(e)) {
267
+ const lift = d.errors[e.code];
268
+ if (lift) throw lift(e);
269
+ }
270
+ throw e;
271
+ }
272
+ }
273
+ function materialize(node, resolveRt) {
274
+ if (isDescriptor(node)) {
275
+ return async (...args) => invokeDescriptor(resolveRt(), node, args);
276
+ }
277
+ const out = {};
278
+ for (const [key, child] of Object.entries(node)) {
279
+ out[key] = materialize(child, resolveRt);
280
+ }
281
+ return out;
282
+ }
283
+ function getNamespace(name) {
284
+ const state = palbeState();
285
+ const cached = state.nsCache[name];
286
+ if (cached !== void 0) return cached;
287
+ const node = state.registry[name];
288
+ if (node === void 0) return void 0;
289
+ const ns = materialize(node, getRuntime);
290
+ state.nsCache[name] = ns;
291
+ return ns;
292
+ }
293
+
294
+ // src/version.ts
295
+ var VERSION = "1.0.0";
296
+
297
+ // src/call.ts
298
+ async function callEndpoint(resolveRt, name, input, options) {
299
+ if (!name || name === "/") {
300
+ throw new BackendError("validation", {
301
+ code: "invalid_endpoint_name",
302
+ message: 'Endpoint name must be a non-empty path like "todos/create"'
303
+ });
304
+ }
305
+ const rt = resolveRt();
306
+ const path = name.startsWith("/") ? name : `/${name}`;
307
+ return palbeRequest(rt, "POST", path, {
308
+ body: input,
309
+ headers: options?.headers,
310
+ signal: options?.signal
311
+ });
312
+ }
313
+
314
+ // src/upload.ts
315
+ function abortError() {
316
+ return new BackendError("network", { code: "aborted", message: "Upload aborted" });
317
+ }
318
+ function checkConstraints(options) {
319
+ const c = options.constraints;
320
+ if (!c) return;
321
+ if (c.maxSize !== void 0 && options.file.size > c.maxSize) {
322
+ const message = `File size ${options.file.size} exceeds max ${c.maxSize} bytes`;
323
+ throw new BackendError("validation", {
324
+ code: "file_too_large",
325
+ message,
326
+ fields: [{ field: "file", message }]
327
+ });
328
+ }
329
+ const effType = options.contentType ?? options.file.type;
330
+ if (c.allowedTypes && c.allowedTypes.length > 0 && !c.allowedTypes.includes(effType)) {
331
+ const message = `File type '${effType}' is not allowed`;
332
+ throw new BackendError("validation", {
333
+ code: "file_type_not_allowed",
334
+ message,
335
+ fields: [{ field: "file", message }]
336
+ });
337
+ }
338
+ }
339
+ async function buildHeaders(rt, extra) {
340
+ if (rt.tokenManager.isExpired() && rt.tokenManager.getRefreshToken() && rt.tokenManager.refreshFunction) {
341
+ try {
342
+ await rt.tokenManager.refreshSession();
343
+ } catch (e) {
344
+ const pe = asPalbaseError(e);
345
+ const status = pe?.status ?? 0;
346
+ if (status === 400 || status === 401 || status === 403) {
347
+ rt.tokenManager.clearSession();
348
+ } else {
349
+ throw pe ? fromPalbaseError(pe) : e;
350
+ }
351
+ }
352
+ }
353
+ const headers = {
354
+ apikey: rt.config.apiKey,
355
+ "X-Client-Info": `palbe-web/${VERSION}`,
356
+ ...rt.config.headers
357
+ };
358
+ const token = rt.tokenManager.getAccessToken();
359
+ if (token) headers.Authorization = `Bearer ${token}`;
360
+ const callerHasKey = Object.keys(extra ?? {}).some((k) => k.toLowerCase() === "idempotency-key");
361
+ if (!callerHasKey) headers["Idempotency-Key"] = crypto.randomUUID();
362
+ return { ...headers, ...extra };
363
+ }
364
+ function buildForm(options) {
365
+ const form = new FormData();
366
+ for (const [k, v] of Object.entries(options.fields ?? {})) form.append(k, v);
367
+ const file = options.contentType && options.file.type !== options.contentType ? new Blob([options.file], { type: options.contentType }) : options.file;
368
+ const filename = options.filename ?? (typeof File !== "undefined" && options.file instanceof File ? options.file.name : "file");
369
+ form.append("file", file, filename);
370
+ return form;
371
+ }
372
+ function decode(status, text) {
373
+ let body;
374
+ try {
375
+ body = text === "" ? null : JSON.parse(text);
376
+ } catch {
377
+ if (status >= 200 && status < 300) {
378
+ throw new BackendError("decode", {
379
+ code: "decode_error",
380
+ message: "Invalid JSON in response",
381
+ status
382
+ });
383
+ }
384
+ body = text;
385
+ }
386
+ if (status < 200 || status >= 300) throw fromEnvelope(status, body);
387
+ return body;
388
+ }
389
+ function uploadViaXHR(url, form, headers, options) {
390
+ return new Promise((resolve, reject) => {
391
+ if (options.signal?.aborted) {
392
+ reject(abortError());
393
+ return;
394
+ }
395
+ const xhr = new XMLHttpRequest();
396
+ xhr.open("POST", url);
397
+ for (const [k, v] of Object.entries(headers)) xhr.setRequestHeader(k, v);
398
+ xhr.upload.onprogress = (e) => {
399
+ if (!e.lengthComputable) return;
400
+ options.onProgress?.({ sent: e.loaded, total: e.total });
401
+ };
402
+ const onAbort = () => xhr.abort();
403
+ const cleanup = () => options.signal?.removeEventListener("abort", onAbort);
404
+ xhr.onload = () => {
405
+ cleanup();
406
+ try {
407
+ resolve(decode(xhr.status, xhr.responseText));
408
+ } catch (err) {
409
+ reject(err);
410
+ }
411
+ };
412
+ xhr.onerror = () => {
413
+ cleanup();
414
+ reject(new BackendError("network", { code: "network_error", message: "Upload failed" }));
415
+ };
416
+ xhr.onabort = () => {
417
+ cleanup();
418
+ reject(abortError());
419
+ };
420
+ options.signal?.addEventListener("abort", onAbort, { once: true });
421
+ xhr.send(form);
422
+ });
423
+ }
424
+ async function uploadViaFetch(url, form, headers, options) {
425
+ let res;
426
+ try {
427
+ res = await fetch(url, { method: "POST", body: form, headers, signal: options.signal });
428
+ } catch (e) {
429
+ if (e instanceof Error && e.name === "AbortError") throw abortError();
430
+ throw new BackendError("network", {
431
+ code: "network_error",
432
+ message: e instanceof Error ? e.message : "Upload failed"
433
+ });
434
+ }
435
+ return decode(res.status, await res.text());
436
+ }
437
+ async function uploadEndpoint(resolveRt, name, options) {
438
+ const rt = resolveRt();
439
+ checkConstraints(options);
440
+ const path = name.startsWith("/") ? name : `/${name}`;
441
+ const url = `${rt.config.url}${path}`;
442
+ const headers = await buildHeaders(rt, options.headers);
443
+ const form = buildForm(options);
444
+ const useXHR = options.onProgress !== void 0 && typeof XMLHttpRequest !== "undefined";
445
+ return useXHR ? uploadViaXHR(url, form, headers, options) : uploadViaFetch(url, form, headers, options);
446
+ }
447
+
448
+ // src/pb.ts
449
+ function createClientProxy(resolveRt, nsAccessor) {
450
+ const base = {
451
+ call(name, input, options) {
452
+ return callEndpoint(resolveRt, name, input, options);
453
+ },
454
+ upload(name, options) {
455
+ return uploadEndpoint(resolveRt, name, options);
456
+ },
457
+ get auth() {
458
+ return resolveRt().auth;
459
+ },
460
+ get flags() {
461
+ return resolveRt().flags;
462
+ },
463
+ get realtime() {
464
+ return resolveRt().realtime;
465
+ },
466
+ get analytics() {
467
+ return resolveRt().analytics;
468
+ }
469
+ };
470
+ return new Proxy(base, {
471
+ get(target, prop, receiver) {
472
+ if (prop in target) return Reflect.get(target, prop, receiver);
473
+ if (prop === "then") return void 0;
474
+ if (typeof prop === "string") {
475
+ const ns = nsAccessor(prop);
476
+ if (ns !== void 0) return ns;
477
+ }
478
+ return void 0;
479
+ },
480
+ has(target, prop) {
481
+ if (prop in target) return true;
482
+ return typeof prop === "string" && prop !== "then" && getRegistry()[prop] !== void 0;
483
+ }
484
+ });
485
+ }
486
+ var pb = createClientProxy(getRuntime, getNamespace);
487
+
488
+ // src/internal.ts
489
+ function onConfigured(cb) {
490
+ const state = palbeState();
491
+ state.configuredListeners.add(cb);
492
+ return () => state.configuredListeners.delete(cb);
493
+ }
494
+ function getRuntime() {
495
+ const rt = palbeState().runtime;
496
+ if (!rt) throw BackendError.notConfigured();
497
+ return rt;
498
+ }
499
+
500
+ // src/react/index.tsx
501
+ var EMPTY_FLAGS = Object.freeze({});
502
+ var SIGNED_OUT = Object.freeze({ signedIn: false, user: null });
503
+ function subscribeWithConfig(getFacadeListener) {
504
+ return (onStoreChange) => {
505
+ let currentFacadeUnsub = null;
506
+ function attachFacade() {
507
+ currentFacadeUnsub?.();
508
+ try {
509
+ currentFacadeUnsub = getFacadeListener(onStoreChange);
510
+ } catch {
511
+ currentFacadeUnsub = null;
512
+ }
513
+ }
514
+ const offConfigured = onConfigured(() => {
515
+ attachFacade();
516
+ onStoreChange();
517
+ });
518
+ attachFacade();
519
+ return () => {
520
+ offConfigured();
521
+ currentFacadeUnsub?.();
522
+ currentFacadeUnsub = null;
523
+ };
524
+ };
525
+ }
526
+ function useUser() {
527
+ return (0, import_react.useSyncExternalStore)(subscribeUserWithConfig, getUserSnapshot, getNullUser);
528
+ }
529
+ var subscribeUserWithConfig = subscribeWithConfig((onStoreChange) => {
530
+ const offState = pb.auth.onAuthStateChange(onStoreChange);
531
+ const offUser = pb.auth.onUserChange(onStoreChange);
532
+ return () => {
533
+ offState();
534
+ offUser();
535
+ };
536
+ });
537
+ function getUserSnapshot() {
538
+ try {
539
+ return pb.auth.currentUser;
540
+ } catch {
541
+ return null;
542
+ }
543
+ }
544
+ function getNullUser() {
545
+ return null;
546
+ }
547
+ function useSession() {
548
+ const lastRef = (0, import_react.useRef)(SIGNED_OUT);
549
+ const getSnapshot = (0, import_react.useCallback)(() => {
550
+ const next = readSession();
551
+ const prev = lastRef.current;
552
+ if (prev.signedIn === next.signedIn && prev.user === next.user) {
553
+ return prev;
554
+ }
555
+ lastRef.current = next;
556
+ return next;
557
+ }, []);
558
+ return (0, import_react.useSyncExternalStore)(subscribeSessionWithConfig, getSnapshot, getSignedOut);
559
+ }
560
+ var subscribeSessionWithConfig = subscribeWithConfig(
561
+ (onStoreChange) => pb.auth.onAuthStateChange(onStoreChange)
562
+ );
563
+ function readSession() {
564
+ try {
565
+ const user = pb.auth.currentUser;
566
+ const signedIn = pb.auth.isSignedIn;
567
+ if (!signedIn && user === null) return SIGNED_OUT;
568
+ return { signedIn, user };
569
+ } catch {
570
+ return SIGNED_OUT;
571
+ }
572
+ }
573
+ function getSignedOut() {
574
+ return SIGNED_OUT;
575
+ }
576
+ function useFlag(key, fallback) {
577
+ const subscribe = (0, import_react.useCallback)(
578
+ subscribeWithConfig((onStoreChange) => pb.flags.subscribeKey(key, onStoreChange)),
579
+ [key]
580
+ );
581
+ const lastRef = (0, import_react.useRef)(fallback);
582
+ const getSnapshot = (0, import_react.useCallback)(() => {
583
+ let next;
584
+ try {
585
+ const value = pb.flags.get(key);
586
+ next = value === void 0 ? fallback : value;
587
+ } catch {
588
+ next = fallback;
589
+ }
590
+ if (!Object.is(next, lastRef.current)) {
591
+ lastRef.current = next;
592
+ }
593
+ return lastRef.current;
594
+ }, [key, fallback]);
595
+ return (0, import_react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
596
+ }
597
+ function useFlags() {
598
+ return (0, import_react.useSyncExternalStore)(subscribeFlagsWithConfig, getFlagsSnapshot, getEmptyFlags);
599
+ }
600
+ var subscribeFlagsWithConfig = subscribeWithConfig(
601
+ (onStoreChange) => pb.flags.onChange(onStoreChange)
602
+ );
603
+ function getFlagsSnapshot() {
604
+ try {
605
+ return pb.flags.all();
606
+ } catch {
607
+ return EMPTY_FLAGS;
608
+ }
609
+ }
610
+ function getEmptyFlags() {
611
+ return EMPTY_FLAGS;
612
+ }
613
+ function useChannel(name, event, handler) {
614
+ const handlerRef = (0, import_react.useRef)(handler);
615
+ (0, import_react.useEffect)(() => {
616
+ handlerRef.current = handler;
617
+ });
618
+ const [status, setStatus] = (0, import_react.useState)("idle");
619
+ const [configEpoch, setConfigEpoch] = (0, import_react.useState)(0);
620
+ (0, import_react.useEffect)(() => {
621
+ return onConfigured(() => setConfigEpoch((n) => n + 1));
622
+ }, []);
623
+ (0, import_react.useEffect)(() => {
624
+ let channel;
625
+ try {
626
+ channel = pb.realtime.channel(name);
627
+ } catch {
628
+ setStatus("unavailable");
629
+ return;
630
+ }
631
+ const sub = channel.on(event, (payload) => handlerRef.current(payload));
632
+ setStatus(pb.realtime.status.state);
633
+ const offStatus = pb.realtime.status.onChange((snapshot) => setStatus(snapshot.state));
634
+ return () => {
635
+ offStatus();
636
+ sub.cancel();
637
+ };
638
+ }, [name, event, configEpoch]);
639
+ return { status };
640
+ }
641
+ // Annotate the CommonJS export names for ESM import in node:
642
+ 0 && (module.exports = {
643
+ useChannel,
644
+ useFlag,
645
+ useFlags,
646
+ useSession,
647
+ useUser
648
+ });
649
+ //# sourceMappingURL=index.cjs.map