@xnetjs/react 0.2.0 → 0.4.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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useNodeStore
3
- } from "./chunk-IHTMVTTE.js";
3
+ } from "./chunk-RIN2MXZK.js";
4
4
 
5
5
  // src/hooks/useUndoScope.ts
6
6
  import { UndoManager } from "@xnetjs/history";
@@ -7,7 +7,7 @@ import {
7
7
  useDataBridge,
8
8
  useTelemetryReporter,
9
9
  useTracingReporter
10
- } from "./chunk-IHTMVTTE.js";
10
+ } from "./chunk-RIN2MXZK.js";
11
11
 
12
12
  // src/utils/flattenNode.ts
13
13
  function flattenNode(node, options) {
@@ -2,7 +2,7 @@ import {
2
2
  flattenNode,
3
3
  useQuery,
4
4
  useSyncManager
5
- } from "./chunk-6VOICQZ3.js";
5
+ } from "./chunk-EJEGIEIC.js";
6
6
  import {
7
7
  useInstrumentation
8
8
  } from "./chunk-JCOFKBOB.js";
@@ -11,7 +11,7 @@ import {
11
11
  useNodeStore,
12
12
  useXNet,
13
13
  useXNetInternal
14
- } from "./chunk-IHTMVTTE.js";
14
+ } from "./chunk-RIN2MXZK.js";
15
15
 
16
16
  // src/hooks/useInfiniteQuery.ts
17
17
  import { createQueryDescriptor, serializeQueryDescriptor } from "@xnetjs/data-bridge";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  useMutate,
3
3
  useQuery
4
- } from "./chunk-6VOICQZ3.js";
4
+ } from "./chunk-EJEGIEIC.js";
5
5
  import {
6
6
  XNetContext,
7
7
  downloadBackup,
@@ -9,7 +9,7 @@ import {
9
9
  useNodeStore,
10
10
  useSecurityContext,
11
11
  useXNet
12
- } from "./chunk-IHTMVTTE.js";
12
+ } from "./chunk-RIN2MXZK.js";
13
13
 
14
14
  // src/hooks/useTaskProjectionSync.ts
15
15
  import { ExternalReferenceSchema, TaskSchema, isCompletedTaskStatus } from "@xnetjs/data";
@@ -227,153 +227,11 @@ function createRuntimeStatus(runtime, overrides = {}) {
227
227
  }
228
228
 
229
229
  // src/context.ts
230
- import { MemoryNodeStorageAdapter, NodeStore } from "@xnetjs/data";
231
- import {
232
- createDataBridge,
233
- createMainThreadBridge,
234
- MainThreadBridge,
235
- WorkerBridge
236
- } from "@xnetjs/data-bridge";
237
230
  import { UndoManager } from "@xnetjs/history";
238
- import { createUCAN } from "@xnetjs/identity";
239
231
  import { PluginRegistry } from "@xnetjs/plugins";
240
- import React, {
241
- createContext as createContext5,
242
- useCallback,
243
- useContext as useContext5,
244
- useEffect as useEffect3,
245
- useMemo as useMemo2,
246
- useRef,
247
- useState as useState3
248
- } from "react";
249
-
250
- // src/hub/auto-backup.ts
251
- import * as Y from "yjs";
252
- var AutoBackup = class {
253
- constructor(upload, options) {
254
- this.upload = upload;
255
- this.debounceMs = options?.debounceMs ?? 5e3;
256
- this.isEnabled = options?.isEnabled ?? (() => true);
257
- }
258
- timers = /* @__PURE__ */ new Map();
259
- debounceMs;
260
- isEnabled;
261
- handleDocUpdate(docId, doc) {
262
- this.scheduleBackup(docId, doc, this.debounceMs);
263
- }
264
- handleDocEvict(docId, doc) {
265
- this.scheduleBackup(docId, doc, 0);
266
- }
267
- scheduleBackup(docId, doc, delay) {
268
- const existing = this.timers.get(docId);
269
- if (existing) {
270
- clearTimeout(existing);
271
- }
272
- const run = async () => {
273
- this.timers.delete(docId);
274
- if (!this.isEnabled()) return;
275
- try {
276
- const state = Y.encodeStateAsUpdate(doc);
277
- await this.upload(docId, state);
278
- } catch (err) {
279
- console.warn(`[auto-backup] Failed for ${docId}:`, err);
280
- }
281
- };
282
- if (delay <= 0) {
283
- void run();
284
- return;
285
- }
286
- this.timers.set(
287
- docId,
288
- setTimeout(() => void run(), delay)
289
- );
290
- }
291
- async flush() {
292
- for (const timer of this.timers.values()) {
293
- clearTimeout(timer);
294
- }
295
- this.timers.clear();
296
- }
297
- destroy() {
298
- void this.flush();
299
- }
300
- };
301
-
302
- // src/hub/backup.ts
303
- import { concatBytes, decrypt, encrypt, NONCE_SIZE } from "@xnetjs/crypto";
304
- var toHttpUrl = (hubUrl) => {
305
- try {
306
- const url = new URL(hubUrl);
307
- if (url.protocol === "ws:") url.protocol = "http:";
308
- if (url.protocol === "wss:") url.protocol = "https:";
309
- return url.toString().replace(/\/$/, "");
310
- } catch {
311
- return hubUrl;
312
- }
313
- };
314
- var encodeEncrypted = (encrypted) => concatBytes(encrypted.nonce, encrypted.ciphertext);
315
- var decodeEncrypted = (payload) => {
316
- const nonce = payload.slice(0, NONCE_SIZE);
317
- const ciphertext = payload.slice(NONCE_SIZE);
318
- return { nonce, ciphertext };
319
- };
320
- var resolveFetch = (fetchFn) => {
321
- if (fetchFn) return fetchFn;
322
- if (typeof fetch === "undefined") {
323
- throw new Error("fetch is not available in this environment");
324
- }
325
- return fetch;
326
- };
327
- var buildAuthHeader = async (getAuthToken) => {
328
- if (!getAuthToken) return null;
329
- const token = await getAuthToken();
330
- if (!token) return null;
331
- return `Bearer ${token}`;
332
- };
333
- async function uploadBackup(config, docId, plaintext) {
334
- const encrypted = encrypt(plaintext, config.encryptionKey);
335
- const payload = encodeEncrypted(encrypted);
336
- return uploadEncryptedBackup(config, docId, payload);
337
- }
338
- async function uploadEncryptedBackup(config, docId, payload) {
339
- const httpUrl = toHttpUrl(config.hubUrl);
340
- const fetcher = resolveFetch(config.fetchFn);
341
- const authHeader = await buildAuthHeader(config.getAuthToken);
342
- const res = await fetcher(`${httpUrl}/backup/${encodeURIComponent(docId)}`, {
343
- method: "PUT",
344
- headers: {
345
- ...authHeader ? { Authorization: authHeader } : {},
346
- "Content-Type": "application/octet-stream"
347
- },
348
- body: payload
349
- });
350
- if (!res.ok) {
351
- throw new Error(`Backup upload failed: ${res.status} ${res.statusText}`);
352
- }
353
- return res.json();
354
- }
355
- async function downloadBackup(config, docId) {
356
- const payload = await downloadEncryptedBackup(config, docId);
357
- if (!payload) return null;
358
- const encrypted = decodeEncrypted(payload);
359
- return decrypt(encrypted, config.encryptionKey);
360
- }
361
- async function downloadEncryptedBackup(config, docId) {
362
- const httpUrl = toHttpUrl(config.hubUrl);
363
- const fetcher = resolveFetch(config.fetchFn);
364
- const authHeader = await buildAuthHeader(config.getAuthToken);
365
- const res = await fetcher(`${httpUrl}/backup/${encodeURIComponent(docId)}`, {
366
- headers: authHeader ? { Authorization: authHeader } : void 0
367
- });
368
- if (res.status === 404) return null;
369
- if (!res.ok) {
370
- throw new Error(`Backup download failed: ${res.status} ${res.statusText}`);
371
- }
372
- return new Uint8Array(await res.arrayBuffer());
373
- }
232
+ import React, { createContext as createContext5, useContext as useContext5, useEffect as useEffect6, useMemo as useMemo2, useState as useState5 } from "react";
374
233
 
375
- // src/context.ts
376
- import { createSyncManager } from "@xnetjs/runtime";
234
+ // src/provider/debug.ts
377
235
  function log(...args) {
378
236
  if (typeof localStorage !== "undefined" && localStorage.getItem("xnet:sync:debug") === "true") {
379
237
  console.log("[XNetProvider]", ...args);
@@ -385,16 +243,10 @@ function scheduleIdle(fn) {
385
243
  if (typeof ric === "function") ric(fn);
386
244
  else setTimeout(fn, 1e3);
387
245
  }
388
- function resolveConfiguredSignalingUrls(hubUrl, signalingServers) {
389
- const seen = /* @__PURE__ */ new Set();
390
- const configured = hubUrl ? [hubUrl, ...signalingServers ?? []] : signalingServers ?? [];
391
- const urls = configured.map((url) => url.trim()).filter((url) => {
392
- if (!url || seen.has(url)) return false;
393
- seen.add(url);
394
- return true;
395
- });
396
- return urls;
397
- }
246
+
247
+ // src/provider/use-hub-auth-token.ts
248
+ import { createUCAN } from "@xnetjs/identity";
249
+ import { useCallback } from "react";
398
250
  var HUB_CAPABILITIES = [
399
251
  { with: "*", can: "hub/*" },
400
252
  { with: "*", can: "backup/*" },
@@ -403,7 +255,112 @@ var HUB_CAPABILITIES = [
403
255
  { with: "*", can: "index/*" }
404
256
  ];
405
257
  var HUB_TOKEN_TTL_SECONDS = 60 * 60 * 24;
258
+ function useHubAuthToken(input) {
259
+ const { authorDID, signingKey, hubUrl, autoAuth, staticHubAuthToken } = input;
260
+ return useCallback(async () => {
261
+ if (staticHubAuthToken) return staticHubAuthToken;
262
+ if (!hubUrl || !autoAuth) return "";
263
+ if (!authorDID || !signingKey) {
264
+ throw new Error("Missing authorDID/signingKey for hub auth");
265
+ }
266
+ return createUCAN({
267
+ issuer: authorDID,
268
+ issuerKey: signingKey,
269
+ audience: hubUrl,
270
+ capabilities: HUB_CAPABILITIES,
271
+ expiration: Math.floor(Date.now() / 1e3) + HUB_TOKEN_TTL_SECONDS
272
+ });
273
+ }, [authorDID, autoAuth, signingKey, hubUrl, staticHubAuthToken]);
274
+ }
275
+
276
+ // src/provider/use-hub-search-index.ts
277
+ import { useEffect as useEffect3 } from "react";
406
278
  var HUB_INDEX_DEBOUNCE_MS = 2e3;
279
+ async function resolveTagSearchText(store, tagIds) {
280
+ const names = await Promise.all(
281
+ tagIds.map(async (id) => {
282
+ const tag = await store.get(id).catch(() => null);
283
+ const name = tag?.properties?.name;
284
+ return typeof name === "string" && name ? `#${name}` : null;
285
+ })
286
+ );
287
+ const present = names.filter((entry) => entry !== null);
288
+ return present.length > 0 ? present.join(" ") : void 0;
289
+ }
290
+ function useHubSearchIndex(input) {
291
+ const { nodeStore, syncManager, hubUrl, enableSearchIndex } = input;
292
+ useEffect3(() => {
293
+ if (!nodeStore || !syncManager || !hubUrl || !enableSearchIndex) return;
294
+ const connection = syncManager.connection;
295
+ if (!connection) return;
296
+ const timers = /* @__PURE__ */ new Map();
297
+ const pending = /* @__PURE__ */ new Map();
298
+ const schedule = (docId, payload) => {
299
+ pending.set(docId, payload);
300
+ const existing = timers.get(docId);
301
+ if (existing) clearTimeout(existing);
302
+ timers.set(
303
+ docId,
304
+ setTimeout(() => {
305
+ timers.delete(docId);
306
+ const next = pending.get(docId);
307
+ pending.delete(docId);
308
+ if (!next) return;
309
+ if (connection.status !== "connected") return;
310
+ if (next.type === "remove") {
311
+ connection.sendRaw({ type: "index-remove", docId });
312
+ return;
313
+ }
314
+ connection.sendRaw({
315
+ type: "index-update",
316
+ docId,
317
+ meta: next.meta,
318
+ ...next.text !== void 0 ? { text: next.text } : {}
319
+ });
320
+ }, HUB_INDEX_DEBOUNCE_MS)
321
+ );
322
+ };
323
+ const handleChange = (event) => {
324
+ const node = event.node;
325
+ if (!node || node.deleted) {
326
+ schedule(event.change.payload.nodeId, { type: "remove" });
327
+ return;
328
+ }
329
+ if (!node.schemaId) return;
330
+ const title = typeof node.properties.title === "string" ? node.properties.title : typeof node.properties.name === "string" ? node.properties.name : "";
331
+ const meta = { schemaIri: node.schemaId, title, properties: node.properties };
332
+ const tagIds = Array.isArray(node.properties.tags) ? node.properties.tags.filter((id) => typeof id === "string") : [];
333
+ if (tagIds.length === 0) {
334
+ schedule(node.id, { type: "update", meta });
335
+ return;
336
+ }
337
+ void resolveTagSearchText(nodeStore, tagIds).then((text) => {
338
+ schedule(node.id, { type: "update", meta, ...text ? { text } : {} });
339
+ });
340
+ };
341
+ const unsubscribe = nodeStore.subscribe(handleChange);
342
+ return () => {
343
+ unsubscribe();
344
+ for (const timer of timers.values()) {
345
+ clearTimeout(timer);
346
+ }
347
+ timers.clear();
348
+ pending.clear();
349
+ };
350
+ }, [enableSearchIndex, hubUrl, nodeStore, syncManager]);
351
+ }
352
+
353
+ // src/provider/use-node-store-runtime.ts
354
+ import { MemoryNodeStorageAdapter, NodeStore } from "@xnetjs/data";
355
+ import { useEffect as useEffect4, useRef, useState as useState3 } from "react";
356
+
357
+ // src/provider/runtime-resolution.ts
358
+ import {
359
+ createDataBridge,
360
+ createMainThreadBridge,
361
+ MainThreadBridge,
362
+ WorkerBridge
363
+ } from "@xnetjs/data-bridge";
407
364
  function getRuntimeErrorMessage(err) {
408
365
  return err instanceof Error ? err.message : String(err);
409
366
  }
@@ -433,17 +390,6 @@ function logRuntimeStatus(runtime, status) {
433
390
  }
434
391
  console.info("[XNetProvider] Runtime ready:", status);
435
392
  }
436
- async function resolveTagSearchText(store, tagIds) {
437
- const names = await Promise.all(
438
- tagIds.map(async (id) => {
439
- const tag = await store.get(id).catch(() => null);
440
- const name = tag?.properties?.name;
441
- return typeof name === "string" && name ? `#${name}` : null;
442
- })
443
- );
444
- const present = names.filter((entry) => entry !== null);
445
- return present.length > 0 ? present.join(" ") : void 0;
446
- }
447
393
  function resolveRuntimeFailure(runtime, nodeStore, reason, bridgeOptions) {
448
394
  if (runtime.fallback === "main-thread") {
449
395
  return {
@@ -568,79 +514,33 @@ async function resolveRuntimeBridge(input) {
568
514
  })
569
515
  };
570
516
  }
571
- var XNetContext = createContext5(null);
572
- var XNetInternalContext = createContext5({
573
- authorDID: null,
574
- signingKey: null,
575
- sync: void 0
576
- });
577
- var DataBridgeContext = createContext5(null);
578
- function useDataBridge() {
579
- return useContext5(DataBridgeContext);
580
- }
581
- function XNetProvider({ config, children }) {
517
+
518
+ // src/provider/use-node-store-runtime.ts
519
+ function useNodeStoreRuntime(input) {
520
+ const {
521
+ authorDID,
522
+ signingKey,
523
+ nodeStorage,
524
+ dataBridge: configDataBridge,
525
+ remoteNodeQueryClient,
526
+ remoteNodeQueryRouting,
527
+ syncManager: configSyncManager,
528
+ telemetry,
529
+ hubUrl,
530
+ signalingUrls,
531
+ runtimeConfig,
532
+ runtimeWorkerUrlKey
533
+ } = input;
582
534
  const [nodeStore, setNodeStore] = useState3(null);
583
535
  const [nodeStoreReady, setNodeStoreReady] = useState3(false);
584
- const [undoManager, setUndoManager] = useState3(null);
585
536
  const [dataBridge, setDataBridge] = useState3(null);
586
- const [syncManager, setSyncManager] = useState3(null);
587
- const [hubStatus, setHubStatus] = useState3("disconnected");
588
- const [pluginRegistry, setPluginRegistry] = useState3(null);
589
537
  const nodeStorageRef = useRef(null);
590
- const platform = config.platform ?? "web";
591
- const authorDID = config.authorDID ?? config.identity?.did;
592
- const hubUrl = config.hubUrl ?? null;
593
- const signalingServersKey = (config.signalingServers ?? []).join("\n");
594
- const signalingServers = useMemo2(
595
- () => signalingServersKey ? signalingServersKey.split("\n") : [],
596
- [signalingServersKey]
597
- );
598
- const signalingUrls = useMemo2(
599
- () => resolveConfiguredSignalingUrls(hubUrl, signalingServers),
600
- [hubUrl, signalingServers]
601
- );
602
- const hubOptions = config.hubOptions;
603
- const autoAuth = hubOptions?.autoAuth ?? true;
604
- const staticHubAuthToken = hubOptions?.authToken?.trim() ?? "";
605
- const autoBackup = hubOptions?.autoBackup ?? false;
606
- const backupDebounceMs = hubOptions?.backupDebounceMs ?? 5e3;
607
- const enableSearchIndex = hubOptions?.enableSearchIndex ?? false;
608
- const nodeSyncRoom = hubOptions?.nodeSyncRoom ?? authorDID ?? "default";
609
- const encryptionKey = config.encryptionKey ?? null;
610
- const runtimeWorkerUrlKey = config.runtime?.worker?.url ? String(config.runtime.worker.url) : "";
611
- const runtimeConfig = useMemo2(
612
- () => resolveRuntimeConfig(config.runtime, platform),
613
- [
614
- config.runtime?.mode,
615
- config.runtime?.fallback,
616
- config.runtime?.diagnostics,
617
- config.runtime?.worker?.dbName,
618
- config.runtime?.worker?.signalingUrl,
619
- runtimeWorkerUrlKey,
620
- platform
621
- ]
622
- );
623
538
  const [runtimeStatus, setRuntimeStatus] = useState3(
624
539
  () => createRuntimeStatus(runtimeConfig)
625
540
  );
626
- const getHubAuthToken = useCallback(async () => {
627
- if (staticHubAuthToken) return staticHubAuthToken;
628
- if (!hubUrl || !autoAuth) return "";
629
- if (!authorDID || !config.signingKey) {
630
- throw new Error("Missing authorDID/signingKey for hub auth");
631
- }
632
- return createUCAN({
633
- issuer: authorDID,
634
- issuerKey: config.signingKey,
635
- audience: hubUrl,
636
- capabilities: HUB_CAPABILITIES,
637
- expiration: Math.floor(Date.now() / 1e3) + HUB_TOKEN_TTL_SECONDS
638
- });
639
- }, [authorDID, autoAuth, config.signingKey, hubUrl, staticHubAuthToken]);
640
- useEffect3(() => {
641
- const nodeStorageAdapter = config.nodeStorage ?? new MemoryNodeStorageAdapter();
541
+ useEffect4(() => {
542
+ const nodeStorageAdapter = nodeStorage ?? new MemoryNodeStorageAdapter();
642
543
  nodeStorageRef.current = nodeStorageAdapter;
643
- const signingKey = config.signingKey;
644
544
  setRuntimeStatus(createRuntimeStatus(runtimeConfig));
645
545
  if (!authorDID || !signingKey) {
646
546
  console.warn(
@@ -673,10 +573,10 @@ function XNetProvider({ config, children }) {
673
573
  authorDID,
674
574
  signingKey,
675
575
  signalingUrl: signalingUrls[0],
676
- dataBridge: config.dataBridge,
677
- remoteNodeQueryClient: config.remoteNodeQueryClient,
678
- remoteNodeQueryRouting: config.remoteNodeQueryRouting,
679
- syncManager: config.syncManager
576
+ dataBridge: configDataBridge,
577
+ remoteNodeQueryClient,
578
+ remoteNodeQueryRouting,
579
+ syncManager: configSyncManager
680
580
  });
681
581
  if (cancelled) {
682
582
  if (resolvedRuntime.createdInternally && resolvedRuntime.bridge) {
@@ -685,16 +585,13 @@ function XNetProvider({ config, children }) {
685
585
  return;
686
586
  }
687
587
  setRuntimeStatus(resolvedRuntime.status);
688
- reportRuntimeStatus(config.telemetry, resolvedRuntime.status);
588
+ reportRuntimeStatus(telemetry, resolvedRuntime.status);
689
589
  logRuntimeStatus(runtimeConfig, resolvedRuntime.status);
690
590
  if (resolvedRuntime.status.phase !== "ready" || !resolvedRuntime.bridge) {
691
- config.telemetry?.reportCrash(
692
- new Error(resolvedRuntime.status.reason ?? "Runtime failed"),
693
- {
694
- codeNamespace: "react.runtime.initialize",
695
- requestedMode: resolvedRuntime.status.requestedMode
696
- }
697
- );
591
+ telemetry?.reportCrash(new Error(resolvedRuntime.status.reason ?? "Runtime failed"), {
592
+ codeNamespace: "react.runtime.initialize",
593
+ requestedMode: resolvedRuntime.status.requestedMode
594
+ });
698
595
  setNodeStore(null);
699
596
  setNodeStoreReady(false);
700
597
  setDataBridge(null);
@@ -732,43 +629,197 @@ function XNetProvider({ config, children }) {
732
629
  };
733
630
  }, [
734
631
  authorDID,
735
- config.nodeStorage,
736
- config.signingKey,
737
- config.dataBridge,
632
+ nodeStorage,
633
+ signingKey,
634
+ configDataBridge,
738
635
  signalingUrls,
739
- config.syncManager,
740
- config.remoteNodeQueryClient,
741
- config.remoteNodeQueryRouting,
742
- config.telemetry,
636
+ configSyncManager,
637
+ remoteNodeQueryClient,
638
+ remoteNodeQueryRouting,
639
+ telemetry,
743
640
  hubUrl,
744
641
  runtimeConfig,
745
642
  runtimeWorkerUrlKey
746
643
  ]);
747
- useEffect3(() => {
748
- if (config.syncManager) {
749
- setSyncManager(config.syncManager);
750
- const sm2 = config.syncManager;
751
- if (sm2.setIdentity && authorDID && config.signingKey) {
752
- sm2.setIdentity(authorDID, config.signingKey);
644
+ return { nodeStore, nodeStoreReady, dataBridge, runtimeStatus, nodeStorageRef };
645
+ }
646
+
647
+ // src/provider/use-sync-manager.ts
648
+ import { createSyncManager } from "@xnetjs/runtime";
649
+ import { useEffect as useEffect5, useState as useState4 } from "react";
650
+
651
+ // src/hub/auto-backup.ts
652
+ import * as Y from "yjs";
653
+ var AutoBackup = class {
654
+ constructor(upload, options) {
655
+ this.upload = upload;
656
+ this.debounceMs = options?.debounceMs ?? 5e3;
657
+ this.isEnabled = options?.isEnabled ?? (() => true);
658
+ }
659
+ timers = /* @__PURE__ */ new Map();
660
+ debounceMs;
661
+ isEnabled;
662
+ handleDocUpdate(docId, doc) {
663
+ this.scheduleBackup(docId, doc, this.debounceMs);
664
+ }
665
+ handleDocEvict(docId, doc) {
666
+ this.scheduleBackup(docId, doc, 0);
667
+ }
668
+ scheduleBackup(docId, doc, delay) {
669
+ const existing = this.timers.get(docId);
670
+ if (existing) {
671
+ clearTimeout(existing);
672
+ }
673
+ const run = async () => {
674
+ this.timers.delete(docId);
675
+ if (!this.isEnabled()) return;
676
+ try {
677
+ const state = Y.encodeStateAsUpdate(doc);
678
+ await this.upload(docId, state);
679
+ } catch (err) {
680
+ console.warn(`[auto-backup] Failed for ${docId}:`, err);
681
+ }
682
+ };
683
+ if (delay <= 0) {
684
+ void run();
685
+ return;
686
+ }
687
+ this.timers.set(
688
+ docId,
689
+ setTimeout(() => void run(), delay)
690
+ );
691
+ }
692
+ async flush() {
693
+ for (const timer of this.timers.values()) {
694
+ clearTimeout(timer);
695
+ }
696
+ this.timers.clear();
697
+ }
698
+ destroy() {
699
+ void this.flush();
700
+ }
701
+ };
702
+
703
+ // src/hub/backup.ts
704
+ import { concatBytes, decrypt, encrypt, NONCE_SIZE } from "@xnetjs/crypto";
705
+ var toHttpUrl = (hubUrl) => {
706
+ try {
707
+ const url = new URL(hubUrl);
708
+ if (url.protocol === "ws:") url.protocol = "http:";
709
+ if (url.protocol === "wss:") url.protocol = "https:";
710
+ return url.toString().replace(/\/$/, "");
711
+ } catch {
712
+ return hubUrl;
713
+ }
714
+ };
715
+ var encodeEncrypted = (encrypted) => concatBytes(encrypted.nonce, encrypted.ciphertext);
716
+ var decodeEncrypted = (payload) => {
717
+ const nonce = payload.slice(0, NONCE_SIZE);
718
+ const ciphertext = payload.slice(NONCE_SIZE);
719
+ return { nonce, ciphertext };
720
+ };
721
+ var resolveFetch = (fetchFn) => {
722
+ if (fetchFn) return fetchFn;
723
+ if (typeof fetch === "undefined") {
724
+ throw new Error("fetch is not available in this environment");
725
+ }
726
+ return fetch;
727
+ };
728
+ var buildAuthHeader = async (getAuthToken) => {
729
+ if (!getAuthToken) return null;
730
+ const token = await getAuthToken();
731
+ if (!token) return null;
732
+ return `Bearer ${token}`;
733
+ };
734
+ async function uploadBackup(config, docId, plaintext) {
735
+ const encrypted = encrypt(plaintext, config.encryptionKey);
736
+ const payload = encodeEncrypted(encrypted);
737
+ return uploadEncryptedBackup(config, docId, payload);
738
+ }
739
+ async function uploadEncryptedBackup(config, docId, payload) {
740
+ const httpUrl = toHttpUrl(config.hubUrl);
741
+ const fetcher = resolveFetch(config.fetchFn);
742
+ const authHeader = await buildAuthHeader(config.getAuthToken);
743
+ const res = await fetcher(`${httpUrl}/backup/${encodeURIComponent(docId)}`, {
744
+ method: "PUT",
745
+ headers: {
746
+ ...authHeader ? { Authorization: authHeader } : {},
747
+ "Content-Type": "application/octet-stream"
748
+ },
749
+ body: payload
750
+ });
751
+ if (!res.ok) {
752
+ throw new Error(`Backup upload failed: ${res.status} ${res.statusText}`);
753
+ }
754
+ return res.json();
755
+ }
756
+ async function downloadBackup(config, docId) {
757
+ const payload = await downloadEncryptedBackup(config, docId);
758
+ if (!payload) return null;
759
+ const encrypted = decodeEncrypted(payload);
760
+ return decrypt(encrypted, config.encryptionKey);
761
+ }
762
+ async function downloadEncryptedBackup(config, docId) {
763
+ const httpUrl = toHttpUrl(config.hubUrl);
764
+ const fetcher = resolveFetch(config.fetchFn);
765
+ const authHeader = await buildAuthHeader(config.getAuthToken);
766
+ const res = await fetcher(`${httpUrl}/backup/${encodeURIComponent(docId)}`, {
767
+ headers: authHeader ? { Authorization: authHeader } : void 0
768
+ });
769
+ if (res.status === 404) return null;
770
+ if (!res.ok) {
771
+ throw new Error(`Backup download failed: ${res.status} ${res.statusText}`);
772
+ }
773
+ return new Uint8Array(await res.arrayBuffer());
774
+ }
775
+
776
+ // src/provider/use-sync-manager.ts
777
+ function useSyncManagerLifecycle(input) {
778
+ const {
779
+ nodeStore,
780
+ nodeStoreReady,
781
+ nodeStorageRef,
782
+ externalSyncManager,
783
+ disableSyncManager,
784
+ signalingUrls,
785
+ authorDID,
786
+ signingKey,
787
+ sync,
788
+ blobStore,
789
+ hubUrl,
790
+ nodeSyncRoom,
791
+ autoAuth,
792
+ autoBackup,
793
+ backupDebounceMs,
794
+ encryptionKey,
795
+ getHubAuthToken
796
+ } = input;
797
+ const [syncManager, setSyncManager] = useState4(null);
798
+ useEffect5(() => {
799
+ if (externalSyncManager) {
800
+ setSyncManager(externalSyncManager);
801
+ const sm2 = externalSyncManager;
802
+ if (sm2.setIdentity && authorDID && signingKey) {
803
+ sm2.setIdentity(authorDID, signingKey);
753
804
  }
754
805
  if (sm2.configureReplication) {
755
- sm2.configureReplication(config.sync);
806
+ sm2.configureReplication(sync);
756
807
  }
757
- config.syncManager.start().catch((err) => {
808
+ externalSyncManager.start().catch((err) => {
758
809
  console.warn("[XNetProvider] External SyncManager failed to start:", err);
759
810
  });
760
811
  return () => {
761
- config.syncManager.stop().catch((err) => {
812
+ externalSyncManager.stop().catch((err) => {
762
813
  console.warn("[XNetProvider] External SyncManager failed to stop:", err);
763
814
  });
764
815
  setSyncManager(null);
765
816
  };
766
817
  }
767
- if (!nodeStore || !nodeStoreReady || config.disableSyncManager) {
818
+ if (!nodeStore || !nodeStoreReady || disableSyncManager) {
768
819
  log("SyncManager disabled or NodeStore not ready", {
769
820
  nodeStore: !!nodeStore,
770
821
  nodeStoreReady,
771
- disableSyncManager: config.disableSyncManager
822
+ disableSyncManager
772
823
  });
773
824
  setSyncManager(null);
774
825
  return;
@@ -779,7 +830,7 @@ function XNetProvider({ config, children }) {
779
830
  return;
780
831
  }
781
832
  const signalingUrl = signalingUrls[0] ?? "";
782
- if (autoAuth && hubUrl && (!authorDID || !config.signingKey)) {
833
+ if (autoAuth && hubUrl && (!authorDID || !signingKey)) {
783
834
  console.warn("[XNetProvider] Hub auth enabled but authorDID/signingKey missing");
784
835
  }
785
836
  if (autoBackup && (!hubUrl || !encryptionKey)) {
@@ -795,9 +846,9 @@ function XNetProvider({ config, children }) {
795
846
  signalingUrl,
796
847
  signalingUrls,
797
848
  authorDID,
798
- signingKey: config.signingKey,
799
- replication: config.sync,
800
- blobStore: config.blobStore,
849
+ signingKey,
850
+ replication: sync,
851
+ blobStore,
801
852
  nodeSyncRoom: hubUrl ? nodeSyncRoom : void 0,
802
853
  getUCANToken: hubUrl ? getHubAuthToken : void 0,
803
854
  onDocUpdate: enableAutoBackup ? (nodeId, doc) => {
@@ -845,11 +896,11 @@ function XNetProvider({ config, children }) {
845
896
  }, [
846
897
  nodeStore,
847
898
  nodeStoreReady,
848
- config.disableSyncManager,
849
- config.syncManager,
899
+ disableSyncManager,
900
+ externalSyncManager,
850
901
  signalingUrls,
851
- config.blobStore,
852
- config.sync,
902
+ blobStore,
903
+ sync,
853
904
  authorDID,
854
905
  autoAuth,
855
906
  autoBackup,
@@ -857,9 +908,14 @@ function XNetProvider({ config, children }) {
857
908
  encryptionKey,
858
909
  getHubAuthToken,
859
910
  hubUrl,
860
- nodeSyncRoom
911
+ nodeSyncRoom,
912
+ nodeStorageRef,
913
+ signingKey
861
914
  ]);
862
- useEffect3(() => {
915
+ return syncManager;
916
+ }
917
+ function useBridgeSyncWiring(dataBridge, syncManager) {
918
+ useEffect5(() => {
863
919
  if (!dataBridge || !syncManager) return;
864
920
  const bridge = dataBridge;
865
921
  if (typeof bridge.setSyncManager === "function") {
@@ -872,7 +928,10 @@ function XNetProvider({ config, children }) {
872
928
  }
873
929
  };
874
930
  }, [dataBridge, syncManager]);
875
- useEffect3(() => {
931
+ }
932
+ function useHubStatus(syncManager) {
933
+ const [hubStatus, setHubStatus] = useState4("disconnected");
934
+ useEffect5(() => {
876
935
  if (!syncManager) {
877
936
  setHubStatus("disconnected");
878
937
  return;
@@ -882,66 +941,110 @@ function XNetProvider({ config, children }) {
882
941
  setHubStatus(status);
883
942
  });
884
943
  }, [syncManager]);
885
- useEffect3(() => {
886
- if (!nodeStore || !syncManager || !hubUrl || !enableSearchIndex) return;
887
- const connection = syncManager.connection;
888
- if (!connection) return;
889
- const timers = /* @__PURE__ */ new Map();
890
- const pending = /* @__PURE__ */ new Map();
891
- const schedule = (docId, payload) => {
892
- pending.set(docId, payload);
893
- const existing = timers.get(docId);
894
- if (existing) clearTimeout(existing);
895
- timers.set(
896
- docId,
897
- setTimeout(() => {
898
- timers.delete(docId);
899
- const next = pending.get(docId);
900
- pending.delete(docId);
901
- if (!next) return;
902
- if (connection.status !== "connected") return;
903
- if (next.type === "remove") {
904
- connection.sendRaw({ type: "index-remove", docId });
905
- return;
906
- }
907
- connection.sendRaw({
908
- type: "index-update",
909
- docId,
910
- meta: next.meta,
911
- ...next.text !== void 0 ? { text: next.text } : {}
912
- });
913
- }, HUB_INDEX_DEBOUNCE_MS)
914
- );
915
- };
916
- const handleChange = (event) => {
917
- const node = event.node;
918
- if (!node || node.deleted) {
919
- schedule(event.change.payload.nodeId, { type: "remove" });
920
- return;
921
- }
922
- if (!node.schemaId) return;
923
- const title = typeof node.properties.title === "string" ? node.properties.title : typeof node.properties.name === "string" ? node.properties.name : "";
924
- const meta = { schemaIri: node.schemaId, title, properties: node.properties };
925
- const tagIds = Array.isArray(node.properties.tags) ? node.properties.tags.filter((id) => typeof id === "string") : [];
926
- if (tagIds.length === 0) {
927
- schedule(node.id, { type: "update", meta });
928
- return;
929
- }
930
- void resolveTagSearchText(nodeStore, tagIds).then((text) => {
931
- schedule(node.id, { type: "update", meta, ...text ? { text } : {} });
932
- });
933
- };
934
- const unsubscribe = nodeStore.subscribe(handleChange);
935
- return () => {
936
- unsubscribe();
937
- for (const timer of timers.values()) {
938
- clearTimeout(timer);
939
- }
940
- timers.clear();
941
- pending.clear();
942
- };
943
- }, [enableSearchIndex, hubUrl, nodeStore, syncManager]);
944
- useEffect3(() => {
944
+ return hubStatus;
945
+ }
946
+
947
+ // src/context.ts
948
+ function resolveConfiguredSignalingUrls(hubUrl, signalingServers) {
949
+ const seen = /* @__PURE__ */ new Set();
950
+ const configured = hubUrl ? [hubUrl, ...signalingServers ?? []] : signalingServers ?? [];
951
+ const urls = configured.map((url) => url.trim()).filter((url) => {
952
+ if (!url || seen.has(url)) return false;
953
+ seen.add(url);
954
+ return true;
955
+ });
956
+ return urls;
957
+ }
958
+ var XNetContext = createContext5(null);
959
+ var XNetInternalContext = createContext5({
960
+ authorDID: null,
961
+ signingKey: null,
962
+ sync: void 0
963
+ });
964
+ var DataBridgeContext = createContext5(null);
965
+ function useDataBridge() {
966
+ return useContext5(DataBridgeContext);
967
+ }
968
+ function XNetProvider({ config, children }) {
969
+ const [undoManager, setUndoManager] = useState5(null);
970
+ const [pluginRegistry, setPluginRegistry] = useState5(null);
971
+ const platform = config.platform ?? "web";
972
+ const authorDID = config.authorDID ?? config.identity?.did;
973
+ const hubUrl = config.hubUrl ?? null;
974
+ const signalingServersKey = (config.signalingServers ?? []).join("\n");
975
+ const signalingServers = useMemo2(
976
+ () => signalingServersKey ? signalingServersKey.split("\n") : [],
977
+ [signalingServersKey]
978
+ );
979
+ const signalingUrls = useMemo2(
980
+ () => resolveConfiguredSignalingUrls(hubUrl, signalingServers),
981
+ [hubUrl, signalingServers]
982
+ );
983
+ const hubOptions = config.hubOptions;
984
+ const autoAuth = hubOptions?.autoAuth ?? true;
985
+ const staticHubAuthToken = hubOptions?.authToken?.trim() ?? "";
986
+ const autoBackup = hubOptions?.autoBackup ?? false;
987
+ const backupDebounceMs = hubOptions?.backupDebounceMs ?? 5e3;
988
+ const enableSearchIndex = hubOptions?.enableSearchIndex ?? false;
989
+ const nodeSyncRoom = hubOptions?.nodeSyncRoom ?? authorDID ?? "default";
990
+ const encryptionKey = config.encryptionKey ?? null;
991
+ const runtimeWorkerUrlKey = config.runtime?.worker?.url ? String(config.runtime.worker.url) : "";
992
+ const runtimeConfig = useMemo2(
993
+ () => resolveRuntimeConfig(config.runtime, platform),
994
+ [
995
+ config.runtime?.mode,
996
+ config.runtime?.fallback,
997
+ config.runtime?.diagnostics,
998
+ config.runtime?.worker?.dbName,
999
+ config.runtime?.worker?.signalingUrl,
1000
+ runtimeWorkerUrlKey,
1001
+ platform
1002
+ ]
1003
+ );
1004
+ const getHubAuthToken = useHubAuthToken({
1005
+ authorDID,
1006
+ signingKey: config.signingKey,
1007
+ hubUrl,
1008
+ autoAuth,
1009
+ staticHubAuthToken
1010
+ });
1011
+ const { nodeStore, nodeStoreReady, dataBridge, runtimeStatus, nodeStorageRef } = useNodeStoreRuntime({
1012
+ authorDID,
1013
+ signingKey: config.signingKey,
1014
+ nodeStorage: config.nodeStorage,
1015
+ dataBridge: config.dataBridge,
1016
+ remoteNodeQueryClient: config.remoteNodeQueryClient,
1017
+ remoteNodeQueryRouting: config.remoteNodeQueryRouting,
1018
+ syncManager: config.syncManager,
1019
+ telemetry: config.telemetry,
1020
+ hubUrl,
1021
+ signalingUrls,
1022
+ runtimeConfig,
1023
+ runtimeWorkerUrlKey
1024
+ });
1025
+ const syncManager = useSyncManagerLifecycle({
1026
+ nodeStore,
1027
+ nodeStoreReady,
1028
+ nodeStorageRef,
1029
+ externalSyncManager: config.syncManager,
1030
+ disableSyncManager: config.disableSyncManager,
1031
+ signalingUrls,
1032
+ authorDID,
1033
+ signingKey: config.signingKey,
1034
+ sync: config.sync,
1035
+ blobStore: config.blobStore,
1036
+ hubUrl,
1037
+ nodeSyncRoom,
1038
+ autoAuth,
1039
+ autoBackup,
1040
+ backupDebounceMs,
1041
+ encryptionKey,
1042
+ getHubAuthToken
1043
+ });
1044
+ useBridgeSyncWiring(dataBridge, syncManager);
1045
+ const hubStatus = useHubStatus(syncManager);
1046
+ useHubSearchIndex({ nodeStore, syncManager, hubUrl, enableSearchIndex });
1047
+ useEffect6(() => {
945
1048
  if (!nodeStore || !nodeStoreReady || config.disablePlugins) {
946
1049
  log("PluginRegistry disabled or NodeStore not ready");
947
1050
  setPluginRegistry(null);
@@ -965,7 +1068,7 @@ function XNetProvider({ config, children }) {
965
1068
  setPluginRegistry(null);
966
1069
  };
967
1070
  }, [nodeStore, nodeStoreReady, config.disablePlugins, config.platform]);
968
- useEffect3(() => {
1071
+ useEffect6(() => {
969
1072
  if (!nodeStore || !nodeStoreReady || !authorDID) {
970
1073
  setUndoManager(null);
971
1074
  return;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useNodeStore
3
- } from "./chunk-IHTMVTTE.js";
3
+ } from "./chunk-RIN2MXZK.js";
4
4
 
5
5
  // src/hooks/useDatabaseDoc.ts
6
6
  import {
package/dist/core.d.ts CHANGED
@@ -5,11 +5,11 @@ import { QueryPageInfo } from '@xnetjs/data-bridge';
5
5
  import { Awareness } from 'y-protocols/awareness';
6
6
  import * as Y from 'yjs';
7
7
  import { Identity } from '@xnetjs/identity';
8
- export { f as XNetConfig, X as XNetContextValue, e as XNetProvider, g as XNetProviderProps, h as XNetRuntimeConfig, i as XNetRuntimeFallback, j as XNetRuntimeMode, k as XNetRuntimePhase, d as XNetRuntimeStatus, l as XNetRuntimeWorkerConfig, a as useXNet } from './context-CFu9i136.js';
8
+ export { f as XNetConfig, X as XNetContextValue, e as XNetProvider, g as XNetProviderProps, h as XNetRuntimeConfig, i as XNetRuntimeFallback, j as XNetRuntimeMode, k as XNetRuntimePhase, d as XNetRuntimeStatus, l as XNetRuntimeWorkerConfig, a as useXNet } from './context-aeFzX2eW.js';
9
9
  import { Component, ReactNode, ErrorInfo } from 'react';
10
10
  import '@xnetjs/core';
11
- import '@xnetjs/runtime';
12
11
  import '@xnetjs/crypto';
12
+ import '@xnetjs/runtime';
13
13
  import '@xnetjs/sync';
14
14
  import '@xnetjs/history';
15
15
  import '@xnetjs/plugins';
package/dist/core.js CHANGED
@@ -5,16 +5,16 @@ import {
5
5
  useInfiniteQuery,
6
6
  useIsOffline,
7
7
  useNode
8
- } from "./chunk-QHNYQVUM.js";
8
+ } from "./chunk-Q3NDLI6Z.js";
9
9
  import {
10
10
  useMutate,
11
11
  useQuery
12
- } from "./chunk-6VOICQZ3.js";
12
+ } from "./chunk-EJEGIEIC.js";
13
13
  import "./chunk-JCOFKBOB.js";
14
14
  import {
15
15
  XNetProvider,
16
16
  useXNet
17
- } from "./chunk-IHTMVTTE.js";
17
+ } from "./chunk-RIN2MXZK.js";
18
18
  export {
19
19
  ErrorBoundary,
20
20
  OfflineIndicator,
package/dist/database.js CHANGED
@@ -6,8 +6,8 @@ import {
6
6
  useDatabaseSchema,
7
7
  useRelatedRows,
8
8
  useReverseRelations
9
- } from "./chunk-KSHTDZ2V.js";
10
- import "./chunk-IHTMVTTE.js";
9
+ } from "./chunk-WL7OCTSM.js";
10
+ import "./chunk-RIN2MXZK.js";
11
11
  export {
12
12
  useCell,
13
13
  useDatabase,
@@ -73,14 +73,14 @@ import {
73
73
  useUndo,
74
74
  useVerification,
75
75
  useVisibleComments
76
- } from "./chunk-7OQXRHEQ.js";
76
+ } from "./chunk-QIX3F46C.js";
77
77
  import {
78
78
  flattenNode,
79
79
  flattenNodes,
80
80
  flattenNodesWithSchemaCheck,
81
81
  flattenUnknownSchemaNode,
82
82
  useSyncManager
83
- } from "./chunk-6VOICQZ3.js";
83
+ } from "./chunk-EJEGIEIC.js";
84
84
  import {
85
85
  InstrumentationContext,
86
86
  useInstrumentation
@@ -104,7 +104,7 @@ import {
104
104
  useTelemetryReporter,
105
105
  useView,
106
106
  useViews
107
- } from "./chunk-IHTMVTTE.js";
107
+ } from "./chunk-RIN2MXZK.js";
108
108
 
109
109
  // src/experimental.ts
110
110
  import { WebSocketSyncProvider } from "@xnetjs/runtime";
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export { i as FlattenNodeOptions, M as MigrationWarning, c as QueryListResult, d
3
3
  export { ErrorBoundary, ErrorBoundaryProps, InfiniteQueryFilter, InfiniteQueryPage, InfiniteQueryResult, MutateCreate, MutateDelete, MutateOp, MutateRestore, MutateUpdate, OfflineIndicator, OfflineIndicatorProps, PresenceUser, SyncStatus, UseIdentityResult, UseMutateResult, UseNodeOptions, UseNodeResult, useIdentity, useInfiniteQuery, useIsOffline, useMutate, useNode } from './core.js';
4
4
  import { U as UseTaskProjectionSyncResult, T as TaskProjectionInput, a as TaskTreeItem } from './experimental-B2FrBnkV.js';
5
5
  export { A as AddCommentOptions, a0 as AddReactionOptions, bm as AuthErrorScreen, aP as AuthTraceSummary, bl as AuthenticatingScreen, r as CommentNode, C as CommentThread, F as CommentVisibility, ad as CreateMessageRequestOptions, b7 as DemoBanner, b8 as DemoBannerProps, bb as DemoDataExpiredScreen, be as DemoLimits, bd as DemoModeState, b9 as DemoQuotaIndicator, ba as DemoQuotaIndicatorProps, bf as DemoUsage, b2 as DiscoveredPeer, aU as FileRef, ae as FirstContactAdmission, af as FirstContactDecision, ag as FirstContactDecisionInput, G as FirstContactMode, ah as FirstContactVisibility, aK as GrantConsentSummary, aL as GrantInput, bp as HubConnectScreen, aX as HubSearchOptions, aY as HubSearchResult, aZ as HubSearchState, b3 as HubStatusIndicator, bo as ImportIdentityScreen, I as InteractionPermission, ai as MessageRequestNode, aj as MessageRequestProperties, ak as MessageRequestStatus, M as ModeratedCommentNode, H as ModeratedCommentThread, J as ModerationFilterOptions, K as ModerationLabelSummary, bA as OnboardingContextValue, bD as OnboardingEvent, bj as OnboardingFlow, bB as OnboardingFlowProps, bE as OnboardingMachineContext, bh as OnboardingProvider, bz as OnboardingProviderProps, bF as OnboardingReducerState, bC as OnboardingState, P as PageTaskInput, e as PageTaskReferenceInput, bI as PageTasksPanel, bJ as PageTasksPanelProps, bW as PluginRegistryContext, L as PublicInteractionMode, N as PublicInteractionPolicySnapshot, O as PublicInteractionSurface, Q as PublicModerationMode, bv as QUICK_START_TEMPLATES, bG as QuickStartTemplate, a1 as ReactionCounterSnapshot, a2 as ReactionNode, a3 as ReactionType, bq as ReadyScreen, a$ as RemoteSchemaDefinition, b0 as RemoteSchemaState, R as ReplyContext, bQ as SecurityContextActions, bP as SecurityContextState, bR as SecurityContextValue, bM as SecurityProvider, bS as SecurityProviderProps, b4 as Skeleton, b6 as SkeletonProps, br as SmartWelcome, bs as SyncProgressOverlay, bH as SyncProgressOverlayProps, bK as TaskCollectionEmbed, bL as TaskCollectionEmbedProps, j as TaskProjectionHost, i as TaskProjectionReferenceInput, bn as UnsupportedBrowserScreen, aw as UseAuditOptions, av as UseAuditResult, aQ as UseAuthTraceResult, aS as UseBackupReturn, aA as UseBlameResult, aH as UseCanEditResult, aF as UseCanResult, p as UseCommentsOptions, q as UseCommentsResult, ay as UseDiffResult, aV as UseFileUploadReturn, b as UseFindOptions, c as UseFindResult, aM as UseGrantsResult, aq as UseHistoryResult, al as UseMessageRequestsOptions, am as UseMessageRequestsResult, S as UseModeratedThreadOptions, f as UsePageTaskSyncOptions, g as UsePageTaskSyncResult, a4 as UsePolicyFilteredReactionCountersOptions, a5 as UsePolicyFilteredReactionCountersResult, bU as UseSecurityOptions, bV as UseSecurityResult, k as UseTaskProjectionSyncOptions, m as UseTasksOptions, n as UseTasksResult, at as UseUndoOptions, as as UseUndoResult, aC as UseVerificationResult, V as UseVisibleCommentsOptions, W as UseVisibleCommentsResult, bk as WelcomeScreen, by as copyToClipboard, a7 as createConversationKey, bu as createInitialState, a8 as createMessageRequestProperties, v as createModerationLabelIndex, Y as createReactionCounterSnapshot, Z as dedupeReactions, aI as describeGrantConsent, w as evaluateCommentModeration, a9 as evaluateFirstContactDecision, x as evaluateInteractionPermission, aa as findLatestMessageRequest, bw as getPlatformAuthName, ab as hasAcceptedContact, b5 as injectSkeletonStyles, _ as isReactionVisible, y as moderateThread, bt as onboardingReducer, z as selectActiveInteractionPolicy, B as selectPublicInteractionMode, aN as summarizeAuthTrace, ac as summarizeMessageRequest, D as summarizeModerationLabel, E as summarizePublicInteractionPolicy, $ as summarizeReactionNode, bx as truncateDid, au as useAudit, aO as useAuthTrace, aR as useBackup, az as useBlame, aE as useCan, aG as useCanEdit, c7 as useCommand, c0 as useCommands, an as useCommentCount, ao as useCommentCounts, o as useComments, b_ as useContributions, bc as useDemoMode, ax as useDiff, c4 as useEditorExtensions, c5 as useEditorExtensionsSafe, aT as useFileUpload, u as useFind, aJ as useGrants, ap as useHistory, aW as useHubSearch, aD as useHubStatus, c3 as useImporters, a6 as useMessageRequests, t as useModeratedThread, bi as useOnboarding, d as usePageTaskSync, b1 as usePeerDiscovery, bX as usePluginRegistry, bY as usePluginRegistryOptional, bZ as usePlugins, X as usePolicyFilteredReactionCounters, a_ as useRemoteSchema, bT as useSecurity, bN as useSecurityContext, bO as useSecurityContextOptional, c2 as useSidebarItems, c1 as useSlashCommands, bg as useSyncManager, h as useTaskProjectionSync, l as useTasks, ar as useUndo, aB as useVerification, c6 as useView, b$ as useViews, s as useVisibleComments } from './experimental-B2FrBnkV.js';
6
- import { SchemaIRI, Schema, SavedViewDescriptor, DefinedSchema, PropertyBuilder, QueryASTOrderBy, QueryASTPage, QueryASTValidationResult, QueryASTPlannerGate, QueryASTAggregateExecution, ExternalReferenceProvider, SavedViewFeedLayout, SavedViewFeedDensity, FieldType, FieldConfig, ViewType, FilterGroup, SortConfig, RowHeight, SummaryFunction, CellValue } from '@xnetjs/data';
6
+ import { SchemaIRI, Schema, SavedViewDescriptor, DefinedSchema, PropertyBuilder, QueryASTOrderBy, QueryASTPage, QueryASTValidationResult, QueryASTPlannerGate, QueryASTAggregateExecution, ExternalReferenceProvider, SavedViewFeedLayout, SavedViewFeedDensity, FieldType, FieldConfig, ViewType, FilterGroup, SortConfig, RowHeight, SummaryFunction, FormViewConfig, FormFieldRule, CellValue, FormSubmissionMeta } from '@xnetjs/data';
7
7
  export { ColumnConfig, ColumnDefinition, ColumnType, SavedViewFeedDensity, SavedViewFeedLayout, ViewConfig, ViewType } from '@xnetjs/data';
8
8
  import { QueryExecutionMode, QuerySourcePreference, QuerySearchFilter, QueryPageInfo, QueryMetadata } from '@xnetjs/data-bridge';
9
9
  import { LucideIcon } from 'lucide-react';
@@ -12,7 +12,7 @@ export { DatabaseRow, DatabaseRowData, ReverseRelation, UseCellOptions, UseCellR
12
12
  export { u as useNodeStore } from './useNodeStore-DTCSBF51.js';
13
13
  export { BlobStoreForSync, ConnectionManager, ConnectionManagerConfig, ConnectionStatus, InitialSyncManager, InitialSyncMessage, METABRIDGE_ORIGIN, METABRIDGE_SEED_ORIGIN, MetaBridge, MultiHubConnectionManagerConfig, NodePool, NodePoolConfig, NodeStoreSyncProvider, NodeSyncResponse, OfflineQueue, OfflineQueueConfig, PoolEntryState, ProgressListener, QueueEntry, Registry, RegistryConfig, RegistryStorage, SerializedNodeChange, SyncManager, SyncManagerConfig, SyncStatus as SyncManagerStatus, SyncPhase, SyncProgress, SyncReconciliationOptions, SyncReconciliationReport, TrackedNode, WebSocketSyncProvider, WebSocketSyncProviderOptions, createConnectionManager, createInitialSyncManager, createMetaBridge, createMultiHubConnectionManager, createNodePool, createOfflineQueue, createRegistry, createSyncManager } from '@xnetjs/runtime';
14
14
  import { Subscription, Customer, Invoice, Payment } from '@xnetjs/billing';
15
- export { n as TRACE_STAGES, s as TracingAttributes, T as TracingContext, p as TracingHandle, o as TracingReporter, r as TracingRootKind, q as TracingSpanInput, f as XNetConfig, X as XNetContextValue, e as XNetProvider, g as XNetProviderProps, h as XNetRuntimeConfig, i as XNetRuntimeFallback, j as XNetRuntimeMode, k as XNetRuntimePhase, d as XNetRuntimeStatus, l as XNetRuntimeWorkerConfig, u as useDataBridge, m as useTracingReporter, a as useXNet } from './context-CFu9i136.js';
15
+ export { n as TRACE_STAGES, s as TracingAttributes, T as TracingContext, p as TracingHandle, o as TracingReporter, r as TracingRootKind, q as TracingSpanInput, f as XNetConfig, X as XNetContextValue, e as XNetProvider, g as XNetProviderProps, h as XNetRuntimeConfig, i as XNetRuntimeFallback, j as XNetRuntimeMode, k as XNetRuntimePhase, d as XNetRuntimeStatus, l as XNetRuntimeWorkerConfig, u as useDataBridge, m as useTracingReporter, a as useXNet } from './context-aeFzX2eW.js';
16
16
  export { I as InstrumentationContext, a as InstrumentationContextValue, Q as QueryTrackerLike, Y as YDocRegistryLike, u as useInstrumentation } from './instrumentation-CpIuG2y5.js';
17
17
  export { a as TelemetryContext, T as TelemetryReporter, u as useTelemetryReporter } from './telemetry-context-B7r6H1KW.js';
18
18
  import '@xnetjs/core';
@@ -520,12 +520,22 @@ interface GridViewModel {
520
520
  rowHeight: RowHeight;
521
521
  columnSummaries: Record<string, SummaryFunction>;
522
522
  sortKey: string;
523
+ formConfig: FormViewConfig | null;
524
+ formRules: Record<string, FormFieldRule>;
525
+ formAccepting: boolean;
523
526
  }
524
527
  interface GridRowModel {
525
528
  id: string;
526
529
  sortKey: string;
527
530
  cells: Record<string, CellValue>;
528
531
  }
532
+ /** Options for `addRow` (exploration 0278: form submissions). */
533
+ interface AddRowOptions {
534
+ /** Explicit node id — deterministic ids make retried submissions upsert. */
535
+ id?: string;
536
+ /** Form-submission provenance stamped on the row. */
537
+ meta?: FormSubmissionMeta;
538
+ }
529
539
  interface UseGridDatabaseOptions {
530
540
  /** Active view ID (defaults to the first view) */
531
541
  viewId?: string;
@@ -556,7 +566,7 @@ interface UseGridDatabaseResult {
556
566
  rowId: string;
557
567
  fieldId: string;
558
568
  }>) => Promise<void>;
559
- addRow: (afterRowId?: string, cells?: Record<string, CellValue>) => Promise<string | null>;
569
+ addRow: (afterRowId?: string, cells?: Record<string, CellValue>, opts?: AddRowOptions) => Promise<string | null>;
560
570
  deleteRows: (rowIds: string[]) => Promise<void>;
561
571
  moveRowToIndex: (rowId: string, targetIndex: number) => Promise<void>;
562
572
  addField: (name: string, type: FieldType, config?: FieldConfig, opts?: {
@@ -576,6 +586,9 @@ interface UseGridDatabaseResult {
576
586
  setGroupBy: (fieldId: string | null) => Promise<void>;
577
587
  setRowHeight: (rowHeight: RowHeight) => Promise<void>;
578
588
  setColumnSummary: (fieldId: string, fn: SummaryFunction) => Promise<void>;
589
+ setFormConfig: (config: FormViewConfig) => Promise<void>;
590
+ setFormRules: (rules: Record<string, FormFieldRule>) => Promise<void>;
591
+ setFormAccepting: (accepting: boolean) => Promise<void>;
579
592
  addView: (name: string, type: ViewType) => Promise<string | null>;
580
593
  renameView: (viewId: string, name: string) => Promise<void>;
581
594
  removeView: (viewId: string) => Promise<void>;
@@ -680,4 +693,4 @@ declare function flattenTaskTree(items: TaskTreeItem[], depth?: number): Rendera
680
693
  declare function formatTaskDueDate(timestamp: number | undefined): string | null;
681
694
  declare function isTaskOverdue(timestamp: number | undefined, completed: boolean): boolean;
682
695
 
683
- export { type CanvasTaskInput, type CheckoutOptions, FlatNode, type GridFieldModel, type GridOptionModel, type GridRowModel, type GridViewModel, QueryFilter, type RenderableTaskRow, type SavedViewCanvasProjectionNode, type SavedViewDateBrushSelection, type SavedViewDateBucketFieldSummary, type SavedViewDateBucketInterval, type SavedViewDateBucketSummary, type SavedViewFacetSelection, type SavedViewFacetSummary, type SavedViewFacetValueSummary, type SavedViewFeedEnrichmentAdapter, type SavedViewFeedEnrichmentEntry, type SavedViewInspectorItem, type SavedViewInspectorItemKind, type SavedViewLensDraft, type SavedViewPresentationMode, type SavedViewPrivacyChip, type SavedViewPrivacyChipTone, type SavedViewPrivacySummary, type SavedViewQueryOverride, type SavedViewQueryResult, SavedViewResultTable, type SavedViewResultTableProps, type SavedViewRowInspectorModel, SavedViewRunner, type SavedViewRunnerProps, type SavedViewSchemaRegistry, type SavedViewSortDirection, type SavedViewVisualCanvasProjectionRequest, SavedViewVisualFeed, type SavedViewVisualLayoutId, type SavedViewVisualLayoutOption, type SavedViewVisualPreviewCreator, type SavedViewVisualPreviewKind, type SavedViewVisualPreviewModel, type SavedViewVisualPreviewPrivacy, type SavedViewVisualPreviewRelationship, type SavedViewVisualTimelineBucket, type SavedViewVisualWorkspaceLayout, TaskProjectionInput, TaskTreeItem, type UseBillingResult, type UseCanvasTaskSyncOptions, type UseCanvasTaskSyncResult, type UseEffectiveSchemaResult, type UseGlobalUndoResult, type UseGridDatabaseOptions, type UseGridDatabaseResult, type UseSavedViewOptions, type UseSavedViewResult, UseTaskProjectionSyncResult, createSavedViewCanvasProjectionNodes, createSavedViewLensDraft, createSavedViewVisualCanvasProjectionRequest, createSavedViewVisualPreviewFingerprint, deriveCachedSavedViewVisualPreviews, deriveSavedViewColumns, deriveSavedViewDateBucketSummaries, deriveSavedViewFacetSummaries, deriveSavedViewPrivacyChips, deriveSavedViewRowInspector, deriveSavedViewTimelineBuckets, deriveSavedViewVisualPreview, deriveSavedViewVisualPreviews, filterSavedViewRowsByDateBrush, filterSavedViewRowsByFacets, flattenTaskTree, formatSavedViewCellValue, formatTaskDueDate, getSavedViewSensitiveResultWarning, hasSavedViewVisualPreviewSensitiveData, isSavedViewVisualPreviewEmbeddable, isTaskOverdue, mergeSavedViewFeedEnrichment, savedViewVisualPreviewIsSelfActor, useBilling, useCanvasTaskSync, useEffectiveSchema, useGlobalUndo, useGridDatabase, useSavedView };
696
+ export { type AddRowOptions, type CanvasTaskInput, type CheckoutOptions, FlatNode, type GridFieldModel, type GridOptionModel, type GridRowModel, type GridViewModel, QueryFilter, type RenderableTaskRow, type SavedViewCanvasProjectionNode, type SavedViewDateBrushSelection, type SavedViewDateBucketFieldSummary, type SavedViewDateBucketInterval, type SavedViewDateBucketSummary, type SavedViewFacetSelection, type SavedViewFacetSummary, type SavedViewFacetValueSummary, type SavedViewFeedEnrichmentAdapter, type SavedViewFeedEnrichmentEntry, type SavedViewInspectorItem, type SavedViewInspectorItemKind, type SavedViewLensDraft, type SavedViewPresentationMode, type SavedViewPrivacyChip, type SavedViewPrivacyChipTone, type SavedViewPrivacySummary, type SavedViewQueryOverride, type SavedViewQueryResult, SavedViewResultTable, type SavedViewResultTableProps, type SavedViewRowInspectorModel, SavedViewRunner, type SavedViewRunnerProps, type SavedViewSchemaRegistry, type SavedViewSortDirection, type SavedViewVisualCanvasProjectionRequest, SavedViewVisualFeed, type SavedViewVisualLayoutId, type SavedViewVisualLayoutOption, type SavedViewVisualPreviewCreator, type SavedViewVisualPreviewKind, type SavedViewVisualPreviewModel, type SavedViewVisualPreviewPrivacy, type SavedViewVisualPreviewRelationship, type SavedViewVisualTimelineBucket, type SavedViewVisualWorkspaceLayout, TaskProjectionInput, TaskTreeItem, type UseBillingResult, type UseCanvasTaskSyncOptions, type UseCanvasTaskSyncResult, type UseEffectiveSchemaResult, type UseGlobalUndoResult, type UseGridDatabaseOptions, type UseGridDatabaseResult, type UseSavedViewOptions, type UseSavedViewResult, UseTaskProjectionSyncResult, createSavedViewCanvasProjectionNodes, createSavedViewLensDraft, createSavedViewVisualCanvasProjectionRequest, createSavedViewVisualPreviewFingerprint, deriveCachedSavedViewVisualPreviews, deriveSavedViewColumns, deriveSavedViewDateBucketSummaries, deriveSavedViewFacetSummaries, deriveSavedViewPrivacyChips, deriveSavedViewRowInspector, deriveSavedViewTimelineBuckets, deriveSavedViewVisualPreview, deriveSavedViewVisualPreviews, filterSavedViewRowsByDateBrush, filterSavedViewRowsByFacets, flattenTaskTree, formatSavedViewCellValue, formatTaskDueDate, getSavedViewSensitiveResultWarning, hasSavedViewVisualPreviewSensitiveData, isSavedViewVisualPreviewEmbeddable, isTaskOverdue, mergeSavedViewFeedEnrichment, savedViewVisualPreviewIsSelfActor, useBilling, useCanvasTaskSync, useEffectiveSchema, useGlobalUndo, useGridDatabase, useSavedView };
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  useInfiniteQuery,
6
6
  useIsOffline,
7
7
  useNode
8
- } from "./chunk-QHNYQVUM.js";
8
+ } from "./chunk-Q3NDLI6Z.js";
9
9
  import {
10
10
  useCell,
11
11
  useDatabase,
@@ -14,7 +14,7 @@ import {
14
14
  useDatabaseSchema,
15
15
  useRelatedRows,
16
16
  useReverseRelations
17
- } from "./chunk-KSHTDZ2V.js";
17
+ } from "./chunk-WL7OCTSM.js";
18
18
  import {
19
19
  AuthErrorScreen,
20
20
  AuthenticatingScreen,
@@ -94,7 +94,7 @@ import {
94
94
  useUndo,
95
95
  useVerification,
96
96
  useVisibleComments
97
- } from "./chunk-7OQXRHEQ.js";
97
+ } from "./chunk-QIX3F46C.js";
98
98
  import {
99
99
  EMPTY_PAGE_INFO,
100
100
  computeFallbackPageInfo,
@@ -106,10 +106,10 @@ import {
106
106
  useMutate,
107
107
  useQuery,
108
108
  useSyncManager
109
- } from "./chunk-6VOICQZ3.js";
109
+ } from "./chunk-EJEGIEIC.js";
110
110
  import {
111
111
  useUndoScope
112
- } from "./chunk-EJ5RW5GI.js";
112
+ } from "./chunk-BDBDZXYS.js";
113
113
  import {
114
114
  InstrumentationContext,
115
115
  useInstrumentation
@@ -142,7 +142,7 @@ import {
142
142
  useView,
143
143
  useViews,
144
144
  useXNet
145
- } from "./chunk-IHTMVTTE.js";
145
+ } from "./chunk-RIN2MXZK.js";
146
146
 
147
147
  // src/hooks/useEffectiveSchema.ts
148
148
  import {
@@ -4264,7 +4264,10 @@ function toViewModel(node) {
4264
4264
  hiddenFields: node.hiddenFields ?? [],
4265
4265
  rowHeight: asRowHeight(node.rowHeight),
4266
4266
  columnSummaries: node.columnSummaries ?? {},
4267
- sortKey: node.sortKey ?? ""
4267
+ sortKey: node.sortKey ?? "",
4268
+ formConfig: node.formConfig ?? null,
4269
+ formRules: node.formRules ?? {},
4270
+ formAccepting: node.formAccepting ?? true
4268
4271
  };
4269
4272
  }
4270
4273
  function fieldsToColumnDefinitions(fields) {
@@ -4533,7 +4536,7 @@ function useGridDatabase(databaseId, options = {}) {
4533
4536
  [updateRowProps]
4534
4537
  );
4535
4538
  const addRow = useCallback2(
4536
- async (afterRowId, cells) => {
4539
+ async (afterRowId, cells, opts) => {
4537
4540
  let sortKey;
4538
4541
  if (afterRowId) {
4539
4542
  const bySortKey = [...rows].sort((a, b) => compareSortKeys(a.sortKey, b.sortKey));
@@ -4553,11 +4556,16 @@ function useGridDatabase(databaseId, options = {}) {
4553
4556
  for (const [fieldId, value] of Object.entries(cells ?? {})) {
4554
4557
  cellProps[cellKey(fieldId)] = value;
4555
4558
  }
4556
- const node = await mutate.create(DatabaseRowSchema, {
4557
- database: databaseId,
4558
- sortKey,
4559
- ...cellProps
4560
- });
4559
+ const node = await mutate.create(
4560
+ DatabaseRowSchema,
4561
+ {
4562
+ database: databaseId,
4563
+ sortKey,
4564
+ ...opts?.meta ? { submissionMeta: opts.meta } : {},
4565
+ ...cellProps
4566
+ },
4567
+ opts?.id
4568
+ );
4561
4569
  return node?.id ?? null;
4562
4570
  },
4563
4571
  [mutate, databaseId, rows, nextAppendKey]
@@ -4750,6 +4758,27 @@ function useGridDatabase(databaseId, options = {}) {
4750
4758
  },
4751
4759
  [mutate, activeView]
4752
4760
  );
4761
+ const setFormConfig = useCallback2(
4762
+ async (config) => {
4763
+ if (!activeView) return;
4764
+ await mutate.update(DatabaseViewSchema, activeView.id, { formConfig: config });
4765
+ },
4766
+ [mutate, activeView]
4767
+ );
4768
+ const setFormRules = useCallback2(
4769
+ async (rules) => {
4770
+ if (!activeView) return;
4771
+ await mutate.update(DatabaseViewSchema, activeView.id, { formRules: rules });
4772
+ },
4773
+ [mutate, activeView]
4774
+ );
4775
+ const setFormAccepting = useCallback2(
4776
+ async (accepting) => {
4777
+ if (!activeView) return;
4778
+ await mutate.update(DatabaseViewSchema, activeView.id, { formAccepting: accepting });
4779
+ },
4780
+ [mutate, activeView]
4781
+ );
4753
4782
  const addView = useCallback2(
4754
4783
  async (name, type) => {
4755
4784
  const node = await mutate.create(DatabaseViewSchema, {
@@ -4801,6 +4830,9 @@ function useGridDatabase(databaseId, options = {}) {
4801
4830
  setGroupBy,
4802
4831
  setRowHeight,
4803
4832
  setColumnSummary,
4833
+ setFormConfig,
4834
+ setFormRules,
4835
+ setFormAccepting,
4804
4836
  addView,
4805
4837
  renameView,
4806
4838
  removeView,
@@ -3,13 +3,13 @@ import { DID } from '@xnetjs/core';
3
3
  import { NodeId } from '@xnetjs/data';
4
4
  import { UndoManagerOptions } from '@xnetjs/history';
5
5
  export { I as InstrumentationContext, a as InstrumentationContextValue, Q as QueryTrackerLike, Y as YDocRegistryLike, u as useInstrumentation } from './instrumentation-CpIuG2y5.js';
6
- export { X as XNetContextValue, c as XNetInternalContextValue, d as XNetRuntimeStatus, u as useDataBridge, a as useXNet, b as useXNetInternal } from './context-CFu9i136.js';
6
+ export { X as XNetContextValue, c as XNetInternalContextValue, d as XNetRuntimeStatus, u as useDataBridge, a as useXNet, b as useXNetInternal } from './context-aeFzX2eW.js';
7
7
  import 'react';
8
8
  import '@xnetjs/data-bridge';
9
9
  import 'yjs';
10
- import '@xnetjs/runtime';
11
10
  import '@xnetjs/crypto';
12
11
  import '@xnetjs/identity';
12
+ import '@xnetjs/runtime';
13
13
  import '@xnetjs/sync';
14
14
  import '@xnetjs/plugins';
15
15
  import './telemetry-context-B7r6H1KW.js';
package/dist/internal.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useUndoScope
3
- } from "./chunk-EJ5RW5GI.js";
3
+ } from "./chunk-BDBDZXYS.js";
4
4
  import {
5
5
  InstrumentationContext,
6
6
  useInstrumentation
@@ -10,7 +10,7 @@ import {
10
10
  useNodeStore,
11
11
  useXNet,
12
12
  useXNetInternal
13
- } from "./chunk-IHTMVTTE.js";
13
+ } from "./chunk-RIN2MXZK.js";
14
14
  export {
15
15
  InstrumentationContext,
16
16
  useDataBridge,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xnetjs/react",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -46,15 +46,15 @@
46
46
  "y-protocols": "^1.0.6",
47
47
  "yjs": "^13.6.24",
48
48
  "@xnetjs/billing": "0.0.2",
49
- "@xnetjs/core": "0.2.0",
50
- "@xnetjs/crypto": "0.2.0",
51
- "@xnetjs/data": "0.2.0",
52
- "@xnetjs/data-bridge": "0.2.0",
53
- "@xnetjs/history": "0.2.0",
54
- "@xnetjs/identity": "0.2.0",
55
- "@xnetjs/plugins": "0.2.0",
56
- "@xnetjs/runtime": "0.1.3",
57
- "@xnetjs/sync": "0.2.0"
49
+ "@xnetjs/core": "0.4.0",
50
+ "@xnetjs/crypto": "0.4.0",
51
+ "@xnetjs/data": "0.4.0",
52
+ "@xnetjs/data-bridge": "0.4.0",
53
+ "@xnetjs/history": "0.4.0",
54
+ "@xnetjs/identity": "0.4.0",
55
+ "@xnetjs/plugins": "0.4.0",
56
+ "@xnetjs/runtime": "0.1.5",
57
+ "@xnetjs/sync": "0.4.0"
58
58
  },
59
59
  "peerDependencies": {
60
60
  "react": "^18.0.0 || ^19.0.0"
@@ -1,8 +1,8 @@
1
- import { SyncManager, BlobStoreForSync, SyncStatus, ConnectionManager } from '@xnetjs/runtime';
2
1
  import { DID } from '@xnetjs/core';
3
2
  import { SecurityLevel } from '@xnetjs/crypto';
4
3
  import { NodeStorageAdapter, NodeStore } from '@xnetjs/data';
5
4
  import { Identity, PQKeyRegistry, HybridKeyBundle } from '@xnetjs/identity';
5
+ import { SyncManager, BlobStoreForSync, SyncStatus, ConnectionManager } from '@xnetjs/runtime';
6
6
  import { SyncReplicationConfig } from '@xnetjs/sync';
7
7
  import * as react from 'react';
8
8
  import { ReactNode } from 'react';