@neetru/sdk 3.4.1 → 3.4.2

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/react.mjs CHANGED
@@ -1,7 +1,566 @@
1
- import * as React from 'react';
1
+ import * as React2 from 'react';
2
2
 
3
3
  // src/react.ts
4
4
 
5
+ // src/types.ts
6
+ var DEFAULT_BASE_URL = "https://api.neetru.com";
7
+
8
+ // src/account-bar.ts
9
+ var h = React2.createElement;
10
+ var DEFAULT_LABELS = {
11
+ accountButton: "Abrir menu da conta",
12
+ appsButton: "Seus produtos Neetru",
13
+ appsTitle: "Trocar de produto",
14
+ myAccount: "Minha conta Neetru",
15
+ accountSettings: "Configura\xE7\xF5es da conta",
16
+ signOut: "Sair",
17
+ currentBadge: "Atual",
18
+ emptyProducts: "Nenhum outro produto dispon\xEDvel."
19
+ };
20
+ async function fetchNeetruAccountBar(client) {
21
+ const auth = client.auth;
22
+ const idToken = typeof auth?.getIdToken === "function" ? auth.getIdToken() : null;
23
+ if (!idToken) return null;
24
+ const config = client.config;
25
+ const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
26
+ const fetchFn = config.fetch ?? globalThis.fetch;
27
+ const url = `${baseUrl}/api/sdk/v1/account/bar`;
28
+ try {
29
+ const res = await fetchFn(url, {
30
+ headers: { authorization: `Bearer ${idToken}`, accept: "application/json" }
31
+ });
32
+ if (!res.ok) return null;
33
+ const body = await res.json();
34
+ if (!body || typeof body !== "object" || !body.account) return null;
35
+ return {
36
+ account: {
37
+ displayName: String(body.account.displayName ?? ""),
38
+ email: String(body.account.email ?? ""),
39
+ photoUrl: body.account.photoUrl ?? null
40
+ },
41
+ accountUrl: String(body.accountUrl ?? "https://minhaconta.neetru.com"),
42
+ products: Array.isArray(body.products) ? body.products.filter(
43
+ (p) => !!p && typeof p.slug === "string" && typeof p.url === "string"
44
+ ) : []
45
+ };
46
+ } catch {
47
+ return null;
48
+ }
49
+ }
50
+ function initialsFrom(nameOrEmail) {
51
+ const s = (nameOrEmail ?? "").trim();
52
+ if (!s) return "?";
53
+ const local = s.includes("@") ? s.split("@")[0] : s;
54
+ const parts = local.split(/[\s._-]+/).filter(Boolean);
55
+ if (parts.length === 0) return local.slice(0, 1).toUpperCase();
56
+ if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
57
+ return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
58
+ }
59
+ var C = {
60
+ bg: "#ffffff",
61
+ bgHover: "#f5f5f5",
62
+ fg: "#0a0a0a",
63
+ muted: "#666666",
64
+ border: "#0a0a0a",
65
+ borderSoft: "#e5e5e5"
66
+ };
67
+ var SQUARE = 0;
68
+ function WaffleIcon({ size = 18, color = C.fg }) {
69
+ const dots = [0, 1, 2].flatMap((r) => [0, 1, 2].map((c) => ({ r, c })));
70
+ const gap = size / 3;
71
+ const dot = Math.max(2, size / 7);
72
+ return h(
73
+ "svg",
74
+ { width: size, height: size, viewBox: `0 0 ${size} ${size}`, "aria-hidden": true, style: { display: "block" } },
75
+ dots.map(
76
+ ({ r, c }) => h("rect", {
77
+ key: `${r}-${c}`,
78
+ x: c * gap + (gap - dot) / 2,
79
+ y: r * gap + (gap - dot) / 2,
80
+ width: dot,
81
+ height: dot,
82
+ fill: color
83
+ })
84
+ )
85
+ );
86
+ }
87
+ function focusables(container) {
88
+ if (!container) return [];
89
+ return Array.from(
90
+ container.querySelectorAll(
91
+ 'a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])'
92
+ )
93
+ ).filter((el) => el.offsetParent !== null || el === document.activeElement);
94
+ }
95
+ function NeetruAccountBar({
96
+ client,
97
+ currentProductSlug,
98
+ settingsUrl,
99
+ onSignOut,
100
+ fetchBar,
101
+ labels,
102
+ className
103
+ }) {
104
+ const L = { ...DEFAULT_LABELS, ...labels };
105
+ const seedAccount = React2.useMemo(() => {
106
+ try {
107
+ const u = client.auth.getUser();
108
+ if (!u) return null;
109
+ return {
110
+ displayName: u.displayName || u.email || "",
111
+ email: u.email || "",
112
+ photoUrl: u.photoURL ?? null
113
+ };
114
+ } catch {
115
+ return null;
116
+ }
117
+ }, [client]);
118
+ const [data, setData] = React2.useState(null);
119
+ const [open, setOpen] = React2.useState(null);
120
+ const [signingOut, setSigningOut] = React2.useState(false);
121
+ const containerRef = React2.useRef(null);
122
+ const accountBtnRef = React2.useRef(null);
123
+ const appsBtnRef = React2.useRef(null);
124
+ const popoverRef = React2.useRef(null);
125
+ React2.useEffect(() => {
126
+ let cancelled = false;
127
+ const run = fetchBar ?? fetchNeetruAccountBar;
128
+ Promise.resolve(run(client)).then((res) => {
129
+ if (!cancelled && res) setData(res);
130
+ }).catch(() => {
131
+ });
132
+ return () => {
133
+ cancelled = true;
134
+ };
135
+ }, [client, fetchBar]);
136
+ const account = data?.account ?? seedAccount;
137
+ const accountUrl = data?.accountUrl ?? "https://minhaconta.neetru.com";
138
+ const products = data?.products ?? [];
139
+ const closeAndRefocus = React2.useCallback((which) => {
140
+ setOpen(null);
141
+ const trigger = which === "apps" ? appsBtnRef.current : accountBtnRef.current;
142
+ trigger?.focus();
143
+ }, []);
144
+ React2.useEffect(() => {
145
+ if (!open) return;
146
+ const first = focusables(popoverRef.current)[0];
147
+ first?.focus();
148
+ const onDocMouseDown = (e) => {
149
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
150
+ setOpen(null);
151
+ }
152
+ };
153
+ document.addEventListener("mousedown", onDocMouseDown);
154
+ return () => document.removeEventListener("mousedown", onDocMouseDown);
155
+ }, [open]);
156
+ const onPopoverKeyDown = React2.useCallback(
157
+ (e) => {
158
+ if (e.key === "Escape") {
159
+ e.stopPropagation();
160
+ closeAndRefocus(open);
161
+ return;
162
+ }
163
+ const items = focusables(popoverRef.current);
164
+ if (items.length === 0) return;
165
+ const idx = items.indexOf(document.activeElement);
166
+ if (e.key === "Tab") {
167
+ if (e.shiftKey && idx <= 0) {
168
+ e.preventDefault();
169
+ items[items.length - 1].focus();
170
+ } else if (!e.shiftKey && idx === items.length - 1) {
171
+ e.preventDefault();
172
+ items[0].focus();
173
+ }
174
+ } else if (e.key === "ArrowDown") {
175
+ e.preventDefault();
176
+ items[(idx + 1) % items.length].focus();
177
+ } else if (e.key === "ArrowUp") {
178
+ e.preventDefault();
179
+ items[(idx - 1 + items.length) % items.length].focus();
180
+ }
181
+ },
182
+ [open, closeAndRefocus]
183
+ );
184
+ const handleSignOut = React2.useCallback(async () => {
185
+ if (signingOut) return;
186
+ setSigningOut(true);
187
+ try {
188
+ await client.auth.signOut();
189
+ } catch {
190
+ } finally {
191
+ setSigningOut(false);
192
+ setOpen(null);
193
+ onSignOut?.();
194
+ }
195
+ }, [client, signingOut, onSignOut]);
196
+ if (!account) return null;
197
+ const initials = initialsFrom(account.displayName || account.email);
198
+ const avatarInner = account.photoUrl ? h("img", {
199
+ src: account.photoUrl,
200
+ alt: "",
201
+ width: 32,
202
+ height: 32,
203
+ style: { width: 32, height: 32, objectFit: "cover", display: "block" }
204
+ }) : h(
205
+ "span",
206
+ {
207
+ "aria-hidden": true,
208
+ style: {
209
+ width: 32,
210
+ height: 32,
211
+ display: "inline-flex",
212
+ alignItems: "center",
213
+ justifyContent: "center",
214
+ backgroundColor: C.fg,
215
+ color: "#ffffff",
216
+ fontSize: 13,
217
+ fontWeight: 700,
218
+ letterSpacing: "0.02em"
219
+ }
220
+ },
221
+ initials
222
+ );
223
+ const iconBtnStyle = (active) => ({
224
+ display: "inline-flex",
225
+ alignItems: "center",
226
+ justifyContent: "center",
227
+ width: 36,
228
+ height: 36,
229
+ padding: 0,
230
+ borderRadius: SQUARE,
231
+ border: `1px solid ${active ? C.border : C.borderSoft}`,
232
+ backgroundColor: active ? C.bgHover : C.bg,
233
+ color: C.fg,
234
+ cursor: "pointer",
235
+ boxSizing: "border-box",
236
+ fontFamily: "inherit",
237
+ overflow: "hidden"
238
+ });
239
+ const appsButton = h(
240
+ "button",
241
+ {
242
+ type: "button",
243
+ ref: appsBtnRef,
244
+ "aria-label": L.appsButton,
245
+ "aria-haspopup": "menu",
246
+ "aria-expanded": open === "apps",
247
+ "data-neetru-appswitcher-button": "true",
248
+ onClick: () => setOpen((o) => o === "apps" ? null : "apps"),
249
+ style: iconBtnStyle(open === "apps")
250
+ },
251
+ h(WaffleIcon, {})
252
+ );
253
+ const accountButton = h(
254
+ "button",
255
+ {
256
+ type: "button",
257
+ ref: accountBtnRef,
258
+ "aria-label": `${L.accountButton}${account.displayName ? ` (${account.displayName})` : ""}`,
259
+ "aria-haspopup": "menu",
260
+ "aria-expanded": open === "account",
261
+ "data-neetru-account-button": "true",
262
+ onClick: () => setOpen((o) => o === "account" ? null : "account"),
263
+ style: { ...iconBtnStyle(open === "account"), width: 36, height: 36 }
264
+ },
265
+ avatarInner
266
+ );
267
+ const popoverStyle = {
268
+ position: "absolute",
269
+ top: "calc(100% + 6px)",
270
+ right: 0,
271
+ minWidth: 260,
272
+ maxWidth: 320,
273
+ backgroundColor: C.bg,
274
+ border: `1px solid ${C.border}`,
275
+ borderRadius: SQUARE,
276
+ zIndex: 1e3,
277
+ color: C.fg,
278
+ fontFamily: "inherit"
279
+ // BMW: sem sombra/glassmorphism — borda sólida define o recorte.
280
+ };
281
+ const menuItemStyle = {
282
+ display: "flex",
283
+ alignItems: "center",
284
+ gap: 10,
285
+ width: "100%",
286
+ padding: "10px 14px",
287
+ background: "transparent",
288
+ border: "none",
289
+ borderTop: `1px solid ${C.borderSoft}`,
290
+ color: C.fg,
291
+ fontSize: 14,
292
+ fontWeight: 400,
293
+ textAlign: "left",
294
+ textDecoration: "none",
295
+ cursor: "pointer",
296
+ boxSizing: "border-box",
297
+ fontFamily: "inherit"
298
+ };
299
+ const hoverHandlers = {
300
+ onMouseEnter: (e) => {
301
+ e.currentTarget.style.backgroundColor = C.bgHover;
302
+ },
303
+ onMouseLeave: (e) => {
304
+ e.currentTarget.style.backgroundColor = "transparent";
305
+ }
306
+ };
307
+ const accountPopover = open === "account" ? h(
308
+ "div",
309
+ {
310
+ ref: popoverRef,
311
+ role: "menu",
312
+ "aria-label": L.accountButton,
313
+ "data-neetru-account-menu": "true",
314
+ onKeyDown: onPopoverKeyDown,
315
+ style: popoverStyle
316
+ },
317
+ // Header identidade
318
+ h(
319
+ "div",
320
+ { style: { display: "flex", gap: 12, alignItems: "center", padding: 14 } },
321
+ h(
322
+ "span",
323
+ {
324
+ "aria-hidden": true,
325
+ style: {
326
+ width: 40,
327
+ height: 40,
328
+ flexShrink: 0,
329
+ display: "inline-flex",
330
+ alignItems: "center",
331
+ justifyContent: "center",
332
+ overflow: "hidden",
333
+ backgroundColor: account.photoUrl ? "transparent" : C.fg,
334
+ color: "#ffffff",
335
+ fontSize: 15,
336
+ fontWeight: 700
337
+ }
338
+ },
339
+ account.photoUrl ? h("img", {
340
+ src: account.photoUrl,
341
+ alt: "",
342
+ width: 40,
343
+ height: 40,
344
+ style: { width: 40, height: 40, objectFit: "cover", display: "block" }
345
+ }) : initials
346
+ ),
347
+ h(
348
+ "span",
349
+ { style: { display: "flex", flexDirection: "column", minWidth: 0 } },
350
+ h(
351
+ "span",
352
+ {
353
+ style: {
354
+ fontWeight: 700,
355
+ fontSize: 14,
356
+ whiteSpace: "nowrap",
357
+ overflow: "hidden",
358
+ textOverflow: "ellipsis"
359
+ }
360
+ },
361
+ account.displayName || account.email
362
+ ),
363
+ account.email ? h(
364
+ "span",
365
+ {
366
+ style: {
367
+ color: C.muted,
368
+ fontSize: 12,
369
+ whiteSpace: "nowrap",
370
+ overflow: "hidden",
371
+ textOverflow: "ellipsis"
372
+ }
373
+ },
374
+ account.email
375
+ ) : null
376
+ )
377
+ ),
378
+ // Minha conta Neetru
379
+ h(
380
+ "a",
381
+ {
382
+ role: "menuitem",
383
+ href: accountUrl,
384
+ target: "_blank",
385
+ rel: "noopener noreferrer",
386
+ style: menuItemStyle,
387
+ ...hoverHandlers
388
+ },
389
+ L.myAccount
390
+ ),
391
+ // Configurações da conta (deste produto)
392
+ settingsUrl ? h(
393
+ "a",
394
+ { role: "menuitem", href: settingsUrl, style: menuItemStyle, ...hoverHandlers },
395
+ L.accountSettings
396
+ ) : null,
397
+ // Sair
398
+ h(
399
+ "button",
400
+ {
401
+ type: "button",
402
+ role: "menuitem",
403
+ onClick: handleSignOut,
404
+ disabled: signingOut,
405
+ "data-neetru-signout": "true",
406
+ style: { ...menuItemStyle, cursor: signingOut ? "not-allowed" : "pointer" },
407
+ ...hoverHandlers
408
+ },
409
+ signingOut ? `${L.signOut}\u2026` : L.signOut
410
+ )
411
+ ) : null;
412
+ const appsPopover = open === "apps" ? h(
413
+ "div",
414
+ {
415
+ ref: popoverRef,
416
+ role: "menu",
417
+ "aria-label": L.appsTitle,
418
+ "data-neetru-appswitcher-menu": "true",
419
+ onKeyDown: onPopoverKeyDown,
420
+ style: { ...popoverStyle, minWidth: 280 }
421
+ },
422
+ h(
423
+ "div",
424
+ {
425
+ style: {
426
+ padding: "12px 14px 8px",
427
+ fontSize: 11,
428
+ fontWeight: 700,
429
+ letterSpacing: "0.08em",
430
+ textTransform: "uppercase",
431
+ color: C.muted
432
+ }
433
+ },
434
+ L.appsTitle
435
+ ),
436
+ products.length === 0 ? h(
437
+ "div",
438
+ { style: { padding: "4px 14px 16px", fontSize: 13, color: C.muted } },
439
+ L.emptyProducts
440
+ ) : h(
441
+ "div",
442
+ {
443
+ style: {
444
+ display: "grid",
445
+ gridTemplateColumns: "1fr 1fr",
446
+ gap: 1,
447
+ padding: 1,
448
+ backgroundColor: C.borderSoft
449
+ }
450
+ },
451
+ products.map((p) => {
452
+ const isCurrent = !!currentProductSlug && p.slug === currentProductSlug;
453
+ return h(
454
+ "a",
455
+ {
456
+ key: p.slug,
457
+ role: "menuitem",
458
+ href: p.url,
459
+ "aria-current": isCurrent ? "true" : void 0,
460
+ "data-neetru-product": p.slug,
461
+ "data-current": isCurrent ? "true" : void 0,
462
+ title: p.name,
463
+ style: {
464
+ display: "flex",
465
+ flexDirection: "column",
466
+ alignItems: "center",
467
+ gap: 6,
468
+ padding: "14px 8px",
469
+ textDecoration: "none",
470
+ color: C.fg,
471
+ backgroundColor: isCurrent ? C.bgHover : C.bg,
472
+ cursor: "pointer",
473
+ boxSizing: "border-box"
474
+ },
475
+ onMouseEnter: (e) => {
476
+ e.currentTarget.style.backgroundColor = C.bgHover;
477
+ },
478
+ onMouseLeave: (e) => {
479
+ e.currentTarget.style.backgroundColor = isCurrent ? C.bgHover : C.bg;
480
+ }
481
+ },
482
+ // Tile/ícone
483
+ p.iconUrl ? h("img", {
484
+ src: p.iconUrl,
485
+ alt: "",
486
+ width: 32,
487
+ height: 32,
488
+ style: { width: 32, height: 32, objectFit: "cover", display: "block" }
489
+ }) : h(
490
+ "span",
491
+ {
492
+ "aria-hidden": true,
493
+ style: {
494
+ width: 32,
495
+ height: 32,
496
+ display: "inline-flex",
497
+ alignItems: "center",
498
+ justifyContent: "center",
499
+ backgroundColor: C.fg,
500
+ color: "#ffffff",
501
+ fontSize: 13,
502
+ fontWeight: 700
503
+ }
504
+ },
505
+ initialsFrom(p.name)
506
+ ),
507
+ h(
508
+ "span",
509
+ {
510
+ style: {
511
+ fontSize: 12,
512
+ fontWeight: isCurrent ? 700 : 400,
513
+ textAlign: "center",
514
+ lineHeight: 1.2,
515
+ maxWidth: "100%",
516
+ overflow: "hidden",
517
+ textOverflow: "ellipsis",
518
+ whiteSpace: "nowrap",
519
+ width: "100%"
520
+ }
521
+ },
522
+ p.name
523
+ ),
524
+ isCurrent ? h(
525
+ "span",
526
+ {
527
+ style: {
528
+ fontSize: 9,
529
+ fontWeight: 700,
530
+ letterSpacing: "0.08em",
531
+ textTransform: "uppercase",
532
+ color: C.muted
533
+ }
534
+ },
535
+ L.currentBadge
536
+ ) : null
537
+ );
538
+ })
539
+ )
540
+ ) : null;
541
+ return h(
542
+ "div",
543
+ {
544
+ ref: containerRef,
545
+ className,
546
+ "data-neetru-account-bar": "true",
547
+ style: {
548
+ position: "relative",
549
+ display: "inline-flex",
550
+ alignItems: "center",
551
+ gap: 8,
552
+ // Superfície de cliente = sempre claro (dark é staff-only).
553
+ colorScheme: "light",
554
+ fontFamily: "inherit"
555
+ }
556
+ },
557
+ appsButton,
558
+ accountButton,
559
+ accountPopover,
560
+ appsPopover
561
+ );
562
+ }
563
+
5
564
  // src/firestore-compat.ts
6
565
  function toDbQuery(constraints) {
7
566
  const whereFilters = [];
@@ -42,9 +601,9 @@ function CheckoutLink({
42
601
  noAutoRedirect,
43
602
  ...rest
44
603
  }) {
45
- const [submitting, setSubmitting] = React.useState(false);
604
+ const [submitting, setSubmitting] = React2.useState(false);
46
605
  const checkout = client.checkout;
47
- const handleClick = React.useCallback(
606
+ const handleClick = React2.useCallback(
48
607
  async (event) => {
49
608
  event.preventDefault();
50
609
  if (submitting) return;
@@ -71,7 +630,7 @@ function CheckoutLink({
71
630
  },
72
631
  [submitting, checkout, productId, planId, callbackUrl, tenantType, tenantId, noAutoRedirect, onIntentCreated, onError]
73
632
  );
74
- return React.createElement(
633
+ return React2.createElement(
75
634
  "a",
76
635
  {
77
636
  ...rest,
@@ -87,7 +646,7 @@ var NEETRU_FLAME_PATH = "M 281 5.163 C 240.659 26.308, 211.260 52.739, 187.750 8
87
646
  var NEETRU_FLAME_VIEWBOX = "0 0 527 760";
88
647
  var NEETRU_FLAME_ASPECT = 527 / 760;
89
648
  function NeetruFlameIcon({ fill, size = 16 }) {
90
- return React.createElement(
649
+ return React2.createElement(
91
650
  "svg",
92
651
  {
93
652
  viewBox: NEETRU_FLAME_VIEWBOX,
@@ -96,7 +655,7 @@ function NeetruFlameIcon({ fill, size = 16 }) {
96
655
  "aria-hidden": true,
97
656
  style: { flexShrink: 0 }
98
657
  },
99
- React.createElement("path", { d: NEETRU_FLAME_PATH, fill })
658
+ React2.createElement("path", { d: NEETRU_FLAME_PATH, fill })
100
659
  );
101
660
  }
102
661
  var NEETRU_LOGIN_BUTTON_THEME = {
@@ -115,11 +674,11 @@ function NeetruLoginButton({
115
674
  disabled,
116
675
  ...rest
117
676
  }) {
118
- const [isLoading, setIsLoading] = React.useState(false);
119
- const [isHover, setIsHover] = React.useState(false);
677
+ const [isLoading, setIsLoading] = React2.useState(false);
678
+ const [isHover, setIsHover] = React2.useState(false);
120
679
  const colors = NEETRU_LOGIN_BUTTON_THEME[theme];
121
680
  const isDisabled = Boolean(disabled) || isLoading;
122
- const handleClick = React.useCallback(async () => {
681
+ const handleClick = React2.useCallback(async () => {
123
682
  if (isDisabled) return;
124
683
  setIsLoading(true);
125
684
  try {
@@ -131,7 +690,7 @@ function NeetruLoginButton({
131
690
  setIsLoading(false);
132
691
  }
133
692
  }, [client, redirectUri, scope, postLoginRedirect, isDisabled, onError]);
134
- return React.createElement(
693
+ return React2.createElement(
135
694
  "button",
136
695
  {
137
696
  ...rest,
@@ -168,15 +727,15 @@ function NeetruLoginButton({
168
727
  ...style
169
728
  }
170
729
  },
171
- React.createElement(NeetruFlameIcon, { fill: colors.fg }),
172
- React.createElement("span", null, isLoading ? "Entrando\u2026" : label)
730
+ React2.createElement(NeetruFlameIcon, { fill: colors.fg }),
731
+ React2.createElement("span", null, isLoading ? "Entrando\u2026" : label)
173
732
  );
174
733
  }
175
- var EntitlementContext = React.createContext({
734
+ var EntitlementContext = React2.createContext({
176
735
  readonly: false
177
736
  });
178
737
  function useEntitlementContext() {
179
- return React.useContext(EntitlementContext);
738
+ return React2.useContext(EntitlementContext);
180
739
  }
181
740
  function EntitlementGate({
182
741
  client,
@@ -187,12 +746,12 @@ function EntitlementGate({
187
746
  loading,
188
747
  children
189
748
  }) {
190
- const [state, setState] = React.useState({
749
+ const [state, setState] = React2.useState({
191
750
  status: "loading"
192
751
  });
193
752
  const resolvedSlug = productSlug ?? client.config.productId ?? "";
194
753
  const resolvedTenantId = client.config.tenantId;
195
- React.useEffect(() => {
754
+ React2.useEffect(() => {
196
755
  let cancelled = false;
197
756
  const run = async () => {
198
757
  try {
@@ -228,15 +787,15 @@ function EntitlementGate({
228
787
  };
229
788
  }, [client, feature, resolvedSlug, resolvedTenantId]);
230
789
  if (state.status === "loading") {
231
- return React.createElement(React.Fragment, null, loading ?? null);
790
+ return React2.createElement(React2.Fragment, null, loading ?? null);
232
791
  }
233
792
  const result = state.result;
234
793
  const allowed = result?.allowed === true;
235
794
  const isReadonly = !allowed && (mode === "readonly" || result?.behavior === "readonly");
236
795
  if (!allowed && mode === "block" && !isReadonly) {
237
- return React.createElement(React.Fragment, null, fallback ?? null);
796
+ return React2.createElement(React2.Fragment, null, fallback ?? null);
238
797
  }
239
- return React.createElement(
798
+ return React2.createElement(
240
799
  EntitlementContext.Provider,
241
800
  {
242
801
  value: {
@@ -281,17 +840,17 @@ function useCollection(source, options) {
281
840
  const sourceKey = serializeSource(
282
841
  source
283
842
  );
284
- const [state, setState] = React.useState({
843
+ const [state, setState] = React2.useState({
285
844
  data: null,
286
845
  isLoading: sourceKey !== null,
287
846
  error: null,
288
847
  isStale: false,
289
848
  lastUpdated: null
290
849
  });
291
- const mountedRef = React.useRef(true);
292
- const sourceRef = React.useRef(source);
850
+ const mountedRef = React2.useRef(true);
851
+ const sourceRef = React2.useRef(source);
293
852
  sourceRef.current = source;
294
- React.useEffect(() => {
853
+ React2.useEffect(() => {
295
854
  mountedRef.current = true;
296
855
  const current = sourceRef.current;
297
856
  if (!current || sourceKey === null) {
@@ -360,17 +919,17 @@ function useDoc(ref, options) {
360
919
  const intervalMs = options?.intervalMs ?? DEFAULT_INTERVAL_MS;
361
920
  const poll = options?.poll ?? false;
362
921
  const refKey = ref && ref.id ? `${ref.collection}/${ref.id}` : null;
363
- const [state, setState] = React.useState({
922
+ const [state, setState] = React2.useState({
364
923
  data: null,
365
924
  isLoading: refKey !== null,
366
925
  error: null,
367
926
  isStale: false,
368
927
  lastUpdated: null
369
928
  });
370
- const mountedRef = React.useRef(true);
371
- const refRef = React.useRef(ref);
929
+ const mountedRef = React2.useRef(true);
930
+ const refRef = React2.useRef(ref);
372
931
  refRef.current = ref;
373
- React.useEffect(() => {
932
+ React2.useEffect(() => {
374
933
  mountedRef.current = true;
375
934
  const current = refRef.current;
376
935
  if (!current || refKey === null) {
@@ -443,7 +1002,7 @@ function resolveAuth(input) {
443
1002
  function useUser(input, options) {
444
1003
  const timeoutMs = options?.timeoutMs ?? 8e3;
445
1004
  const auth = resolveAuth(input);
446
- const [state, setState] = React.useState(() => {
1005
+ const [state, setState] = React2.useState(() => {
447
1006
  let seeded = null;
448
1007
  try {
449
1008
  seeded = auth.getUser();
@@ -452,8 +1011,8 @@ function useUser(input, options) {
452
1011
  }
453
1012
  return { user: seeded, isLoading: seeded === null, error: null };
454
1013
  });
455
- const mountedRef = React.useRef(true);
456
- React.useEffect(() => {
1014
+ const mountedRef = React2.useRef(true);
1015
+ React2.useEffect(() => {
457
1016
  mountedRef.current = true;
458
1017
  let settled = false;
459
1018
  const timer = setTimeout(() => {
@@ -485,6 +1044,6 @@ function useUser(input, options) {
485
1044
  return state;
486
1045
  }
487
1046
 
488
- export { CheckoutLink, EntitlementGate, NeetruLoginButton, useCollection, useDoc, useEntitlementContext, useUser };
1047
+ export { CheckoutLink, EntitlementGate, NeetruAccountBar, NeetruLoginButton, fetchNeetruAccountBar, initialsFrom, useCollection, useDoc, useEntitlementContext, useUser };
489
1048
  //# sourceMappingURL=react.mjs.map
490
1049
  //# sourceMappingURL=react.mjs.map