@archbase/ssr 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.
package/dist/index.js ADDED
@@ -0,0 +1,655 @@
1
+ import { jsx as w, Fragment as x } from "react/jsx-runtime";
2
+ import y, { createContext as L, useState as v, useEffect as C, useContext as Q, useRef as P } from "react";
3
+ import { ArchbaseDataSource as _ } from "@archbase/data";
4
+ import { QueryClient as q, hydrate as F, QueryClientProvider as N, dehydrate as W } from "@tanstack/react-query";
5
+ const S = typeof window > "u", U = !S, h = () => !!(typeof window < "u" && window.document && window.document.createElement), G = {
6
+ getItem(t) {
7
+ if (!h())
8
+ return null;
9
+ try {
10
+ return localStorage.getItem(t);
11
+ } catch {
12
+ return null;
13
+ }
14
+ },
15
+ setItem(t, e) {
16
+ if (h())
17
+ try {
18
+ localStorage.setItem(t, e);
19
+ } catch {
20
+ }
21
+ },
22
+ removeItem(t) {
23
+ if (h())
24
+ try {
25
+ localStorage.removeItem(t);
26
+ } catch {
27
+ }
28
+ }
29
+ }, X = {
30
+ getItem(t) {
31
+ if (!h())
32
+ return null;
33
+ try {
34
+ return sessionStorage.getItem(t);
35
+ } catch {
36
+ return null;
37
+ }
38
+ },
39
+ setItem(t, e) {
40
+ if (h())
41
+ try {
42
+ sessionStorage.setItem(t, e);
43
+ } catch {
44
+ }
45
+ },
46
+ removeItem(t) {
47
+ if (h())
48
+ try {
49
+ sessionStorage.removeItem(t);
50
+ } catch {
51
+ }
52
+ }
53
+ };
54
+ function O(t) {
55
+ try {
56
+ return JSON.stringify(t, (e, r) => typeof r == "function" || r === void 0 ? null : typeof r == "object" && r !== null && typeof r.toJSON == "function" ? r.toJSON() : r);
57
+ } catch (e) {
58
+ return console.warn("Failed to serialize data for SSR:", e), "null";
59
+ }
60
+ }
61
+ function T(t) {
62
+ try {
63
+ return JSON.parse(t);
64
+ } catch (e) {
65
+ return console.warn("Failed to deserialize SSR data:", e), null;
66
+ }
67
+ }
68
+ let M = 0;
69
+ function Y(t = "archbase") {
70
+ return `${t}-${++M}`;
71
+ }
72
+ function Z() {
73
+ M = 0;
74
+ }
75
+ function ee() {
76
+ return h() ? window : void 0;
77
+ }
78
+ function te() {
79
+ return h() ? document : void 0;
80
+ }
81
+ function re(t) {
82
+ if (!h())
83
+ return !1;
84
+ const r = {
85
+ localStorage: () => "localStorage" in window,
86
+ sessionStorage: () => "sessionStorage" in window,
87
+ indexedDB: () => "indexedDB" in window,
88
+ serviceWorker: () => "serviceWorker" in navigator,
89
+ geolocation: () => "geolocation" in navigator,
90
+ webRTC: () => "RTCPeerConnection" in window,
91
+ websockets: () => "WebSocket" in window,
92
+ fetch: () => "fetch" in window,
93
+ intersectionObserver: () => "IntersectionObserver" in window,
94
+ mutationObserver: () => "MutationObserver" in window,
95
+ resizeObserver: () => "ResizeObserver" in window
96
+ }[t];
97
+ return r ? r() : !1;
98
+ }
99
+ function ne(t, e) {
100
+ if (!h())
101
+ return e;
102
+ try {
103
+ return t();
104
+ } catch {
105
+ return e;
106
+ }
107
+ }
108
+ function se(t) {
109
+ return h() ? t() : void 0;
110
+ }
111
+ function ie(t) {
112
+ return S ? t() : void 0;
113
+ }
114
+ function ae(t, e) {
115
+ return S ? t : e();
116
+ }
117
+ function oe(t) {
118
+ if (!h())
119
+ return { matches: !1, media: t };
120
+ try {
121
+ const e = window.matchMedia(t);
122
+ return {
123
+ matches: e.matches,
124
+ media: e.media
125
+ };
126
+ } catch {
127
+ return { matches: !1, media: t };
128
+ }
129
+ }
130
+ const H = L({
131
+ isSSR: S,
132
+ isHydrated: !1
133
+ });
134
+ function ce({
135
+ children: t,
136
+ serverData: e,
137
+ onHydrated: r,
138
+ fallback: s
139
+ }) {
140
+ const [o, n] = v(!S);
141
+ C(() => {
142
+ !o && h() && (n(!0), r?.());
143
+ }, [o, r]);
144
+ const i = {
145
+ isSSR: S,
146
+ isHydrated: o,
147
+ serverData: e
148
+ };
149
+ return !o && s ? /* @__PURE__ */ w(H.Provider, { value: i, children: s }) : /* @__PURE__ */ w(H.Provider, { value: i, children: t });
150
+ }
151
+ function g() {
152
+ const t = Q(H);
153
+ if (!t)
154
+ throw new Error("useArchbaseSSR must be used within ArchbaseSSRProvider");
155
+ return t;
156
+ }
157
+ function ue(t, e) {
158
+ const { isHydrated: r } = g(), [s, o] = v(t);
159
+ return C(() => {
160
+ if (r) {
161
+ const n = typeof e == "function" ? e() : e;
162
+ o(n);
163
+ }
164
+ }, [r, e]), s;
165
+ }
166
+ function de({ children: t, fallback: e = null }) {
167
+ const { isHydrated: r } = g();
168
+ return r ? /* @__PURE__ */ w(x, { children: t }) : /* @__PURE__ */ w(x, { children: e });
169
+ }
170
+ function le({ children: t }) {
171
+ const { isSSR: e } = g();
172
+ return e ? /* @__PURE__ */ w(x, { children: t }) : null;
173
+ }
174
+ function fe(t, e) {
175
+ const { isHydrated: r } = g();
176
+ C(() => {
177
+ if (r)
178
+ return t();
179
+ }, [r, ...e || []]);
180
+ }
181
+ function he(t, e = !1) {
182
+ const [r, s] = v(e), { isHydrated: o } = g();
183
+ return C(() => {
184
+ if (!o || !h())
185
+ return;
186
+ const n = window.matchMedia(t);
187
+ s(n.matches);
188
+ const i = (a) => {
189
+ s(a.matches);
190
+ };
191
+ return n.addEventListener ? (n.addEventListener("change", i), () => n.removeEventListener("change", i)) : (n.addListener(i), () => n.removeListener(i));
192
+ }, [t, o]), r;
193
+ }
194
+ class E extends _ {
195
+ _ssrData;
196
+ _isHydrating = !1;
197
+ constructor(e, r = {}) {
198
+ super(e, r);
199
+ }
200
+ /**
201
+ * Serialize DataSource state for SSR
202
+ */
203
+ serializeState() {
204
+ const e = {
205
+ records: this.getAllRecords(),
206
+ currentRecord: this.getCurrentRecord(),
207
+ recordIndex: this.getRecordIndex(),
208
+ state: "active",
209
+ // Simplified state
210
+ hasChanges: this.isChanged(),
211
+ filter: this.getFilter(),
212
+ sort: this.getSort(),
213
+ metadata: this.getAllMetadata()
214
+ };
215
+ return O(e);
216
+ }
217
+ /**
218
+ * Restore DataSource state from serialized data
219
+ */
220
+ deserializeState(e) {
221
+ const r = T(e);
222
+ if (!r) {
223
+ console.warn("Failed to deserialize DataSource state");
224
+ return;
225
+ }
226
+ this._isHydrating = !0, this._ssrData = r;
227
+ try {
228
+ r.records.length > 0 && this.setRecords(r.records), r.recordIndex >= 0 && this.gotoRecord(r.recordIndex), r.filter && (this.filter = r.filter), r.sort && (this.sort = r.sort);
229
+ } finally {
230
+ this._isHydrating = !1, this._ssrData = void 0;
231
+ }
232
+ }
233
+ /**
234
+ * Check if DataSource is currently hydrating from SSR
235
+ */
236
+ isHydrating() {
237
+ return this._isHydrating;
238
+ }
239
+ /**
240
+ * Get SSR data if available
241
+ */
242
+ getSSRData() {
243
+ return this._ssrData;
244
+ }
245
+ /**
246
+ * Create a minimal state object for SSR
247
+ * Only includes essential data to reduce payload size
248
+ */
249
+ serializeMinimalState() {
250
+ const e = {
251
+ records: this.getAllRecords().slice(0, 50),
252
+ // Limit records for performance
253
+ currentRecord: this.getCurrentRecord(),
254
+ recordIndex: this.getRecordIndex(),
255
+ state: "active",
256
+ hasChanges: this.isChanged()
257
+ };
258
+ return O(e);
259
+ }
260
+ /**
261
+ * Create a DataSource instance from server data
262
+ */
263
+ static fromServerData(e, r, s = {}) {
264
+ const o = new E(e, s);
265
+ return r && (typeof r == "string" ? o.deserializeState(r) : Array.isArray(r.records) && (o.setRecords(r.records), r.currentIndex >= 0 && o.gotoRecord(r.currentIndex))), o;
266
+ }
267
+ /**
268
+ * Enhanced method to handle SSR-safe operations
269
+ */
270
+ ssrSafeOperation(e, r) {
271
+ if (S)
272
+ try {
273
+ return e();
274
+ } catch (s) {
275
+ return console.warn("SSR operation failed, using fallback:", s), r;
276
+ }
277
+ return e();
278
+ }
279
+ /**
280
+ * Override to handle SSR-safe filtering
281
+ */
282
+ applyFilter(e) {
283
+ this.ssrSafeOperation(
284
+ () => {
285
+ this.filter = e;
286
+ },
287
+ void 0
288
+ );
289
+ }
290
+ /**
291
+ * Override to handle SSR-safe sorting
292
+ */
293
+ applySort(e) {
294
+ this.ssrSafeOperation(
295
+ () => {
296
+ this.sort = e;
297
+ },
298
+ void 0
299
+ );
300
+ }
301
+ /**
302
+ * Get records with SSR safety
303
+ */
304
+ getRecords() {
305
+ return this.ssrSafeOperation(
306
+ () => this.getAllRecords(),
307
+ []
308
+ );
309
+ }
310
+ /**
311
+ * Get current record with SSR safety
312
+ */
313
+ getCurrentRecord() {
314
+ return this.ssrSafeOperation(
315
+ () => super.getCurrentRecord(),
316
+ void 0
317
+ );
318
+ }
319
+ /**
320
+ * Check if we have data available for rendering
321
+ */
322
+ hasData() {
323
+ return this.getRecords().length > 0;
324
+ }
325
+ /**
326
+ * Create a snapshot that can be safely transmitted between server/client
327
+ */
328
+ createSnapshot() {
329
+ return {
330
+ records: this.getAllRecords(),
331
+ currentIndex: this.getRecordIndex(),
332
+ metadata: this.getAllMetadata(),
333
+ timestamp: Date.now()
334
+ };
335
+ }
336
+ /**
337
+ * Restore from a snapshot
338
+ */
339
+ restoreFromSnapshot(e) {
340
+ this._isHydrating = !0;
341
+ try {
342
+ this.setRecords(e.records), e.currentIndex >= 0 && this.gotoRecord(e.currentIndex);
343
+ } finally {
344
+ this._isHydrating = !1;
345
+ }
346
+ }
347
+ /**
348
+ * Helper method to get all metadata
349
+ */
350
+ getAllMetadata() {
351
+ return {};
352
+ }
353
+ /**
354
+ * Get all records from the data source
355
+ */
356
+ getAllRecords() {
357
+ return this.records || [];
358
+ }
359
+ /**
360
+ * Get current record index
361
+ */
362
+ getRecordIndex() {
363
+ return this.recordIndex || 0;
364
+ }
365
+ /**
366
+ * Check if data source has changes
367
+ */
368
+ isChanged() {
369
+ return this.changed || !1;
370
+ }
371
+ /**
372
+ * Get current filter
373
+ */
374
+ getFilter() {
375
+ return this.filter;
376
+ }
377
+ /**
378
+ * Get current sort
379
+ */
380
+ getSort() {
381
+ return this.sort || [];
382
+ }
383
+ /**
384
+ * Get record count
385
+ */
386
+ getRecordCount() {
387
+ return this.getTotalRecords();
388
+ }
389
+ /**
390
+ * Set records with proper DataSource options
391
+ */
392
+ setRecords(e) {
393
+ this.refreshData({
394
+ records: e,
395
+ grandTotalRecords: e.length,
396
+ currentPage: 1,
397
+ totalPages: 1,
398
+ pageSize: e.length
399
+ });
400
+ }
401
+ }
402
+ function J(t, e = {}) {
403
+ const {
404
+ initialRecords: r = [],
405
+ serverDataKey: s,
406
+ autoHydrate: o = !0,
407
+ fallbackRecords: n = [],
408
+ serializer: i
409
+ } = e, { isHydrated: a, serverData: d } = g(), [c] = v(() => {
410
+ const u = new E(t);
411
+ return S && r.length > 0 && u.setRecords(r), u;
412
+ }), [A, m] = v(!1), [f, p] = v(null), I = P(!1);
413
+ return C(() => {
414
+ if (!(!a || I.current || !o)) {
415
+ I.current = !0;
416
+ try {
417
+ m(!0), p(null);
418
+ let u = null;
419
+ if (d && (s ? u = d[s] : u = d), typeof u == "string")
420
+ if (i?.deserialize)
421
+ u = i.deserialize(u);
422
+ else {
423
+ c.deserializeState(u);
424
+ return;
425
+ }
426
+ u && Array.isArray(u.records) ? (c.setRecords(u.records), typeof u.currentIndex == "number" && c.gotoRecord(u.currentIndex)) : n.length > 0 && c.setRecords(n);
427
+ } catch (u) {
428
+ console.error("Failed to hydrate DataSource:", u), p(u instanceof Error ? u : new Error("Hydration failed")), n.length > 0 && c.setRecords(n);
429
+ } finally {
430
+ m(!1);
431
+ }
432
+ }
433
+ }, [a, d, s, o, n, c, i]), {
434
+ dataSource: c,
435
+ isLoading: A,
436
+ error: f,
437
+ isHydrated: a,
438
+ serializeState: () => i?.serialize ? i.serialize(c.createSnapshot()) : c.serializeState(),
439
+ deserializeState: (u) => {
440
+ try {
441
+ if (i?.deserialize) {
442
+ const R = i.deserialize(u);
443
+ c.restoreFromSnapshot(R);
444
+ } else
445
+ c.deserializeState(u);
446
+ } catch (R) {
447
+ console.error("Failed to deserialize DataSource state:", R), p(R instanceof Error ? R : new Error("Deserialization failed"));
448
+ }
449
+ },
450
+ getMinimalState: () => ({
451
+ recordCount: c.getRecordCount(),
452
+ currentIndex: c.getRecordIndex(),
453
+ hasData: c.hasData(),
454
+ isActive: c.isActive()
455
+ }),
456
+ refresh: async (u) => {
457
+ m(!0), p(null);
458
+ try {
459
+ u ? c.setRecords(u) : c.refreshData();
460
+ } catch (R) {
461
+ p(R instanceof Error ? R : new Error("Refresh failed"));
462
+ } finally {
463
+ m(!1);
464
+ }
465
+ },
466
+ // Convenience getters
467
+ records: c.getRecords(),
468
+ currentRecord: c.getCurrentRecord(),
469
+ recordCount: c.getRecordCount(),
470
+ hasData: c.hasData()
471
+ };
472
+ }
473
+ function Se(t) {
474
+ const { isHydrated: e } = g(), [r] = v(() => t.map(({ name: a, options: d }) => ({
475
+ name: a,
476
+ ...J(a, d)
477
+ }))), s = (a) => r.find((d) => d.name === a), o = () => r.reduce((a, d) => (a[d.name] = d.serializeState(), a), {}), n = r.some((a) => a.isLoading), i = r.filter((a) => a.error).map((a) => ({ name: a.name, error: a.error }));
478
+ return {
479
+ sources: r,
480
+ getDataSource: s,
481
+ serializeAll: o,
482
+ isAnyLoading: n,
483
+ errors: i,
484
+ isHydrated: e
485
+ };
486
+ }
487
+ function j({
488
+ children: t,
489
+ queryClient: e,
490
+ dehydratedState: r,
491
+ defaultStaleTime: s = 1e3 * 60 * 5,
492
+ // 5 minutes
493
+ defaultCacheTime: o = 1e3 * 60 * 10
494
+ // 10 minutes
495
+ }) {
496
+ const { isHydrated: n, serverData: i } = g(), [a] = y.useState(() => e || new q({
497
+ defaultOptions: {
498
+ queries: {
499
+ staleTime: s,
500
+ gcTime: o,
501
+ // TanStack Query v5 uses gcTime instead of cacheTime
502
+ refetchOnWindowFocus: !1,
503
+ retry: (d, c) => c?.status >= 400 && c?.status < 500 ? !1 : d < 3
504
+ },
505
+ mutations: {
506
+ retry: 1
507
+ }
508
+ }
509
+ }));
510
+ return y.useEffect(() => {
511
+ if (n && (r || i?.queryState)) {
512
+ const d = r || i.queryState;
513
+ if (typeof d == "string") {
514
+ const c = T(d);
515
+ c && F(a, c);
516
+ } else
517
+ F(a, d);
518
+ }
519
+ }, [n, r, i, a]), /* @__PURE__ */ w(N, { client: a, children: t });
520
+ }
521
+ function ye(t, e, r = {}) {
522
+ const {
523
+ dataSource: s,
524
+ syncWithDataSource: o = !1,
525
+ transformForDataSource: n,
526
+ ssrData: i,
527
+ ssr: a = !0,
528
+ ...d
529
+ } = r, { isHydrated: c, serverData: A } = g(), m = y.useCallback(() => {
530
+ if (a) {
531
+ if (i)
532
+ return i;
533
+ if (A?.queries) {
534
+ const l = Array.isArray(t) ? t.join(":") : String(t);
535
+ return A.queries[l];
536
+ }
537
+ }
538
+ }, [a, i, A, t]);
539
+ y.useMemo(() => ({
540
+ queryKey: Array.isArray(t) ? t : [t],
541
+ queryFn: e,
542
+ enabled: S ? !1 : d.enabled ?? !0,
543
+ initialData: m(),
544
+ ...d
545
+ }), [t, e, d, m]);
546
+ const [f, p] = y.useState(m()), [I, b] = y.useState(!f), [D, z] = y.useState(null);
547
+ return y.useEffect(() => {
548
+ if (!(!o || !s || !f))
549
+ try {
550
+ let l = f;
551
+ n ? l = n(f) : Array.isArray(f) ? l = f : f && typeof f == "object" && "data" in f && (l = f.data), Array.isArray(l) && s.setRecords(l);
552
+ } catch (l) {
553
+ console.error("Failed to sync query data with DataSource:", l);
554
+ }
555
+ }, [f, s, o, n]), {
556
+ data: f,
557
+ isLoading: I,
558
+ error: D,
559
+ isSuccess: !I && !D,
560
+ isError: !!D,
561
+ refetch: async () => {
562
+ b(!0), z(null);
563
+ try {
564
+ const l = await e();
565
+ return p(l), { data: l };
566
+ } catch (l) {
567
+ throw z(l), l;
568
+ } finally {
569
+ b(!1);
570
+ }
571
+ }
572
+ };
573
+ }
574
+ function ge(t) {
575
+ const e = W(t);
576
+ return O(e);
577
+ }
578
+ async function K(t, e) {
579
+ if (!S)
580
+ return;
581
+ const r = e.map(async ({ key: s, fetchFn: o }) => {
582
+ const n = Array.isArray(s) ? s : [s];
583
+ try {
584
+ await t.prefetchQuery({
585
+ queryKey: n,
586
+ queryFn: o,
587
+ staleTime: 1 / 0
588
+ // Don't refetch during SSR
589
+ });
590
+ } catch (i) {
591
+ console.error(`Failed to prefetch query ${JSON.stringify(n)}:`, i);
592
+ }
593
+ });
594
+ await Promise.allSettled(r);
595
+ }
596
+ function me(t, e = {}) {
597
+ const { queryClient: r, prefetchQueries: s } = e;
598
+ function o(n) {
599
+ const [i] = y.useState(
600
+ () => r || new q({
601
+ defaultOptions: {
602
+ queries: {
603
+ staleTime: 3e5,
604
+ // 5 minutes
605
+ gcTime: 6e5
606
+ // 10 minutes
607
+ }
608
+ }
609
+ })
610
+ );
611
+ return y.useEffect(() => {
612
+ if (S && s) {
613
+ const a = s(n);
614
+ K(i, a);
615
+ }
616
+ }, [n]), /* @__PURE__ */ w(j, { queryClient: i, children: /* @__PURE__ */ w(t, { ...n }) });
617
+ }
618
+ return o.displayName = `withArchbaseTanStack(${t.displayName || t.name})`, o;
619
+ }
620
+ const Re = "3.0.0";
621
+ export {
622
+ E as ArchbaseSSRDataSource,
623
+ ce as ArchbaseSSRProvider,
624
+ Re as ArchbaseSSRVersion,
625
+ j as ArchbaseTanStackProvider,
626
+ de as ClientOnly,
627
+ le as ServerOnly,
628
+ h as canUseDOM,
629
+ se as clientOnly,
630
+ ae as createHydrationSafeValue,
631
+ Y as createSSRId,
632
+ T as deserializeFromSSR,
633
+ te as getDocument,
634
+ oe as getMediaQuery,
635
+ ee as getWindow,
636
+ re as hasFeature,
637
+ U as isClient,
638
+ S as isServer,
639
+ K as prepareServerQueries,
640
+ Z as resetSSRIdCounter,
641
+ G as safeLocalStorage,
642
+ X as safeSessionStorage,
643
+ O as serializeForSSR,
644
+ ge as serializeQueryClientState,
645
+ ie as serverOnly,
646
+ ye as useArchbaseQuery,
647
+ g as useArchbaseSSR,
648
+ J as useArchbaseSSRDataSource,
649
+ Se as useArchbaseSSRDataSources,
650
+ fe as useClientEffect,
651
+ ue as useHydrationSafeState,
652
+ he as useSSRSafeMediaQuery,
653
+ me as withArchbaseTanStack,
654
+ ne as withSSRFallback
655
+ };
@@ -0,0 +1,52 @@
1
+ import { default as React, ReactNode } from 'react';
2
+ interface SSRContextValue {
3
+ isSSR: boolean;
4
+ isHydrated: boolean;
5
+ serverData?: any;
6
+ }
7
+ interface ArchbaseSSRProviderProps {
8
+ children: ReactNode;
9
+ serverData?: any;
10
+ /** Custom hydration detection logic */
11
+ onHydrated?: () => void;
12
+ /** Fallback content during hydration */
13
+ fallback?: ReactNode;
14
+ }
15
+ /**
16
+ * Provider for SSR-aware Archbase components
17
+ * Handles hydration state and provides SSR context
18
+ */
19
+ export declare function ArchbaseSSRProvider({ children, serverData, onHydrated, fallback }: ArchbaseSSRProviderProps): import("react/jsx-runtime").JSX.Element;
20
+ /**
21
+ * Hook to access SSR context
22
+ */
23
+ export declare function useArchbaseSSR(): SSRContextValue;
24
+ /**
25
+ * Hook for hydration-safe state
26
+ * Returns a default value during SSR and switches to actual value after hydration
27
+ */
28
+ export declare function useHydrationSafeState<T>(ssrValue: T, clientValue: T | (() => T)): T;
29
+ /**
30
+ * Component that only renders on client side after hydration
31
+ */
32
+ interface ClientOnlyProps {
33
+ children: ReactNode;
34
+ fallback?: ReactNode;
35
+ }
36
+ export declare function ClientOnly({ children, fallback }: ClientOnlyProps): import("react/jsx-runtime").JSX.Element;
37
+ /**
38
+ * Component that only renders on server side
39
+ */
40
+ interface ServerOnlyProps {
41
+ children: ReactNode;
42
+ }
43
+ export declare function ServerOnly({ children }: ServerOnlyProps): import("react/jsx-runtime").JSX.Element | null;
44
+ /**
45
+ * Hook for SSR-safe effects that only run on client
46
+ */
47
+ export declare function useClientEffect(effect: React.EffectCallback, deps?: React.DependencyList): void;
48
+ /**
49
+ * Hook for media queries that work with SSR
50
+ */
51
+ export declare function useSSRSafeMediaQuery(query: string, defaultValue?: boolean): boolean;
52
+ export {};