@xnetjs/react 0.0.2 → 0.1.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.d.ts CHANGED
@@ -1,2782 +1,683 @@
1
- import { PropertyBuilder, SchemaIRI, MigrationInfo, InferCreateProps, NodeState, MigratedNodeState, DefinedSchema, ColumnDefinition, ViewConfig, FilterGroup, SortConfig, CellValue, Schema, DatabaseSchemaMetadata, NodeId, NodeStore, NodeStorageAdapter, AuthGrant, NodeChange, NodePayload } from '@xnetjs/data';
2
- export { ColumnConfig, ColumnDefinition, ColumnType, ViewConfig, ViewType } from '@xnetjs/data';
3
- import { DID, ContentId, AuthAction } from '@xnetjs/core';
4
- import { Awareness } from 'y-protocols/awareness';
5
- import * as Y from 'yjs';
6
- import { TimelineEntry, HistoryTarget, HistoricalState, PropertyDiff, UndoManagerOptions, AuditEntry, ActivitySummary, DiffResult, BlameInfo, VerificationOptions, VerificationResult } from '@xnetjs/history';
7
- import * as react from 'react';
8
- import { Component, ReactNode, ErrorInfo } from 'react';
9
- import * as react_jsx_runtime from 'react/jsx-runtime';
10
- import { Identity, KeyBundle, PQKeyRegistry, HybridKeyBundle } from '@xnetjs/identity';
11
- import { SecurityLevel, UnifiedSignature, VerificationResult as VerificationResult$1 } from '@xnetjs/crypto';
12
- import { DataBridge } from '@xnetjs/data-bridge';
13
- import { Platform, PluginRegistry, RegisteredPlugin, ViewContribution, CommandContribution, SlashCommandContribution, SidebarContribution, EditorContribution, PropertyHandlerContribution, BlockContribution, SettingContribution } from '@xnetjs/plugins';
14
- export { I as InstrumentationContext, a as InstrumentationContextValue, Q as QueryTrackerLike, Y as YDocRegistryLike, u as useInstrumentation } from './instrumentation-Cn94kn8-.js';
15
-
16
- /**
17
- * FlatNode utilities - Flatten NodeState properties to top level
18
- *
19
- * This module provides type-safe flattening of Node properties so developers
20
- * can access `node.title` instead of `node.properties.title`.
21
- */
22
-
23
- /**
24
- * Base node fields (always present on any node)
25
- */
26
- interface NodeBase {
27
- /** Unique node identifier */
28
- id: string;
29
- /** Schema IRI this node conforms to */
30
- schemaId: SchemaIRI;
31
- /** Creation timestamp */
32
- createdAt: number;
33
- /** Creator's DID */
34
- createdBy: DID;
35
- /** Last update timestamp */
36
- updatedAt: number;
37
- /** Last updater's DID */
38
- updatedBy: DID;
39
- /** Whether node is soft-deleted */
40
- deleted: boolean;
41
- /**
42
- * True if this node's schema is not registered/known to the current app version.
43
- * The node data is still accessible but may not have proper type information.
44
- * UI should render a generic "Unknown data type" component for these nodes.
45
- */
46
- _unknownSchema?: boolean;
47
- /**
48
- * Properties from future schema versions that aren't known to the current schema.
49
- * Preserved for forward compatibility - can be displayed in a "raw data" view.
50
- */
51
- _unknown?: Record<string, unknown>;
52
- /**
53
- * The schema version that last wrote to this node.
54
- * Useful for detecting when migrations might be needed.
55
- */
56
- _schemaVersion?: string;
57
- /**
58
- * The original schema IRI this node was migrated from.
59
- * Only present if the node was automatically migrated on read.
60
- */
61
- _migratedFrom?: SchemaIRI;
62
- /**
63
- * Full migration info if the node was migrated.
64
- * Includes lossless flag and any warnings about data loss.
65
- */
66
- _migrationInfo?: MigrationInfo;
67
- }
68
- /**
69
- * A flattened node with properties at the top level.
70
- *
71
- * Instead of `node.properties.title`, access `node.title` directly.
72
- * All property types are correctly inferred from the schema.
73
- *
74
- * @example
75
- * ```tsx
76
- * const { data } = useQuery(TaskSchema, id)
77
- * // data is FlatNode<typeof TaskSchema._properties>
78
- *
79
- * console.log(data.title) // string - correctly typed!
80
- * console.log(data.status) // 'todo' | 'done' - union type!
81
- * ```
82
- */
83
- type FlatNode<P extends Record<string, PropertyBuilder>> = NodeBase & InferCreateProps<P>;
84
- /**
85
- * Options for flattenNode function
86
- */
87
- interface FlattenNodeOptions {
88
- /**
89
- * Mark this node as having an unknown schema.
90
- * This happens when the node's schemaId is not registered in the current app version.
91
- */
92
- unknownSchema?: boolean;
93
- /**
94
- * Migration info if the node was migrated from a different schema version.
95
- */
96
- migrationInfo?: MigrationInfo;
97
- }
98
- /**
99
- * Flatten a NodeState by spreading properties to top level.
100
- *
101
- * @param node - The NodeState with nested properties
102
- * @param options - Optional settings for handling unknown schemas
103
- * @returns A new object with properties flattened to top level
104
- *
105
- * @example
106
- * ```ts
107
- * const nodeState = {
108
- * id: '123',
109
- * schemaId: 'xnet://xnet.fyi/Task',
110
- * properties: { title: 'My Task', status: 'todo' },
111
- * // ...
112
- * }
113
- *
114
- * const flat = flattenNode(nodeState)
115
- * // { id: '123', schemaId: '...', title: 'My Task', status: 'todo', ... }
116
- * ```
117
- */
118
- declare function flattenNode<P extends Record<string, PropertyBuilder>>(node: NodeState | MigratedNodeState, options?: FlattenNodeOptions): FlatNode<P>;
119
- /**
120
- * Flatten an array of NodeState objects.
121
- */
122
- declare function flattenNodes<P extends Record<string, PropertyBuilder>>(nodes: (NodeState | MigratedNodeState)[], options?: FlattenNodeOptions): FlatNode<P>[];
123
- /**
124
- * Create a FlatNode with unknown schema flag.
125
- * Use this when displaying nodes whose schema is not registered.
126
- */
127
- declare function flattenUnknownSchemaNode(node: NodeState): FlatNode<Record<string, PropertyBuilder>>;
128
- /**
129
- * Create FlatNodes from an array, marking those with unknown schemas.
130
- *
131
- * @param nodes - Array of NodeState objects
132
- * @param isSchemaKnown - Function to check if a schema is registered
133
- * @returns Array of FlatNodes with _unknownSchema set appropriately
134
- */
135
- declare function flattenNodesWithSchemaCheck<P extends Record<string, PropertyBuilder>>(nodes: NodeState[], isSchemaKnown: (schemaId: string) => boolean): FlatNode<P>[];
136
-
137
- /**
138
- * useQuery - Unified read hook for Nodes via DataBridge
139
- *
140
- * A single hook for all read operations:
141
- * - List all nodes of a schema
142
- * - Get a single node by ID
143
- * - Query with filters
144
- *
145
- * Returns FlatNode with properties at top level for ergonomic access.
146
- *
147
- * Uses DataBridge for off-main-thread data access. The bridge handles
148
- * caching and provides useSyncExternalStore-compatible subscriptions.
149
- *
150
- * @example
151
- * ```tsx
152
- * // List all tasks
153
- * const { data: tasks } = useQuery(TaskSchema)
154
- * tasks.forEach(task => console.log(task.title)) // Direct access!
155
- *
156
- * // Get single task by ID
157
- * const { data: task } = useQuery(TaskSchema, taskId)
158
- * console.log(task?.status) // Typed correctly!
159
- *
160
- * // Query with filters
161
- * const { data: urgent } = useQuery(TaskSchema, {
162
- * where: { status: 'urgent' },
163
- * orderBy: { createdAt: 'desc' }
164
- * })
165
- * ```
166
- */
167
-
168
- /**
169
- * Sort direction
170
- */
171
- type SortDirection = 'asc' | 'desc';
172
- /**
173
- * System fields that can be used for ordering
174
- */
175
- type SystemOrderField = 'createdAt' | 'updatedAt';
176
- /**
177
- * Query filter options
178
- */
179
- interface QueryFilter<P extends Record<string, PropertyBuilder> = Record<string, PropertyBuilder>> {
180
- /** Filter conditions (property: value) */
181
- where?: Partial<InferCreateProps<P>>;
182
- /** Include soft-deleted nodes */
183
- includeDeleted?: boolean;
184
- /** Sort by property or system field (createdAt, updatedAt) */
185
- orderBy?: {
186
- [K in keyof InferCreateProps<P> | SystemOrderField]?: SortDirection;
187
- };
188
- /** Limit results */
189
- limit?: number;
190
- /** Offset for pagination */
191
- offset?: number;
192
- }
193
- /**
194
- * Migration warning info
195
- */
196
- interface MigrationWarning {
197
- /** The node ID that was migrated */
198
- nodeId: string;
199
- /** The original schema IRI */
200
- from: string;
201
- /** The target schema IRI */
202
- to: string;
203
- /** Warning messages about potential data loss */
204
- warnings: string[];
205
- }
206
- /**
207
- * Result when querying a list of nodes
208
- */
209
- interface QueryListResult<P extends Record<string, PropertyBuilder>> {
210
- /** The queried nodes (flattened - access properties directly) */
211
- data: FlatNode<P>[];
212
- /** Whether currently loading */
213
- loading: boolean;
214
- /** Any error that occurred */
215
- error: Error | null;
216
- /** Reload the query */
217
- reload: () => void;
218
- /**
219
- * Migration warnings for nodes that were migrated from different schema versions.
220
- * Only populated if nodes required migration and the migration was lossy.
221
- */
222
- migrationWarnings: MigrationWarning[];
223
- }
224
- /**
225
- * Result when querying a single node
226
- */
227
- interface QuerySingleResult<P extends Record<string, PropertyBuilder>> {
228
- /** The queried node (flattened - access properties directly), null if not found */
229
- data: FlatNode<P> | null;
230
- /** Whether currently loading */
231
- loading: boolean;
232
- /** Any error that occurred */
233
- error: Error | null;
234
- /** Reload the query */
235
- reload: () => void;
236
- /**
237
- * Migration warnings if the node was migrated from a different schema version.
238
- * Only populated if the node required migration and the migration was lossy.
239
- */
240
- migrationWarnings: MigrationWarning[];
241
- }
242
- /**
243
- * Query all nodes of a schema
244
- */
245
- declare function useQuery<P extends Record<string, PropertyBuilder>>(schema: DefinedSchema<P>): QueryListResult<P>;
246
- /**
247
- * Query a single node by ID
248
- */
249
- declare function useQuery<P extends Record<string, PropertyBuilder>>(schema: DefinedSchema<P>, id: string): QuerySingleResult<P>;
250
- /**
251
- * Query nodes with filters
252
- */
253
- declare function useQuery<P extends Record<string, PropertyBuilder>>(schema: DefinedSchema<P>, filter: QueryFilter<P>): QueryListResult<P>;
254
-
255
- /**
256
- * useMutate - Unified write hook for Nodes via DataBridge
257
- *
258
- * A single hook for all write operations:
259
- * - Create nodes (requires schema)
260
- * - Update nodes (requires schema for type safety)
261
- * - Delete nodes (by ID)
262
- * - Atomic transactions (multiple operations)
263
- *
264
- * Uses DataBridge for off-main-thread data access.
265
- *
266
- * Features:
267
- * - Immediate local updates (bridge updates UI subscribers synchronously)
268
- * - Type-safe schema-bound mutations
269
- * - Transaction support for atomic multi-node operations
270
- * - Pending state tracking
271
- *
272
- * @example
273
- * ```tsx
274
- * const { create, update, remove, mutate, isPending } = useMutate()
275
- *
276
- * // Simple operations
277
- * await create(TaskSchema, { title: 'New Task', status: 'todo' })
278
- * await update(TaskSchema, taskId, { status: 'done' }) // Type-safe!
279
- * await remove(taskId)
280
- *
281
- * // Atomic transaction
282
- * await mutate([
283
- * { type: 'create', schema: TaskSchema, data: { title: 'Task 1' } },
284
- * { type: 'update', id: taskId, data: { status: 'done' } },
285
- * { type: 'delete', id: oldTaskId }
286
- * ])
287
- * ```
288
- */
289
-
290
- /**
291
- * Create operation for mutate
292
- */
293
- interface MutateCreate<P extends Record<string, PropertyBuilder> = Record<string, PropertyBuilder>> {
294
- type: 'create';
295
- schema: DefinedSchema<P>;
296
- data: InferCreateProps<P>;
297
- id?: string;
298
- }
299
- /**
300
- * Update operation for mutate
301
- */
302
- interface MutateUpdate {
303
- type: 'update';
304
- id: string;
305
- data: Record<string, unknown>;
306
- }
307
- /**
308
- * Delete operation for mutate
309
- */
310
- interface MutateDelete {
311
- type: 'delete';
312
- id: string;
313
- }
314
- /**
315
- * Restore operation for mutate
316
- */
317
- interface MutateRestore {
318
- type: 'restore';
319
- id: string;
320
- }
321
- /**
322
- * All possible mutate operations
323
- */
324
- type MutateOp = MutateCreate<Record<string, PropertyBuilder>> | MutateUpdate | MutateDelete | MutateRestore;
325
- /**
326
- * Result from a mutate transaction
327
- */
328
- interface MutateResult {
329
- /** Results for each operation (NodeState or null for delete) */
330
- results: (NodeState | null)[];
331
- /** Batch ID when transaction backend is available */
332
- batchId?: string;
333
- /** Temp ID mapping when transaction backend is available */
334
- tempIds?: Record<string, string>;
335
- }
336
- /**
337
- * Result from useMutate hook
338
- */
339
- interface UseMutateResult {
340
- /**
341
- * Create a new node.
342
- * Requires a schema to know what type to create.
343
- * Optionally specify a custom ID (otherwise auto-generated).
344
- *
345
- * @returns The created node (flattened), or null if creation failed
346
- */
347
- create: <P extends Record<string, PropertyBuilder>>(schema: DefinedSchema<P>, data: InferCreateProps<P>, id?: string) => Promise<FlatNode<P> | null>;
348
- /**
349
- * Update an existing node by ID.
350
- * Requires schema for type-safe property checking.
351
- *
352
- * @example
353
- * ```tsx
354
- * await update(TaskSchema, taskId, { status: 'done' }) // OK
355
- * await update(TaskSchema, taskId, { typo: 'x' }) // Type error!
356
- * ```
357
- *
358
- * @returns The updated node (flattened), or null if update failed
359
- */
360
- update: <P extends Record<string, PropertyBuilder>>(schema: DefinedSchema<P>, id: string, data: Partial<InferCreateProps<P>>) => Promise<FlatNode<P> | null>;
361
- /**
362
- * Delete a node by ID (soft delete).
363
- */
364
- remove: (id: string) => Promise<void>;
365
- /**
366
- * Restore a deleted node by ID.
367
- *
368
- * @returns The restored node (flattened), or null if restore failed
369
- */
370
- restore: (id: string) => Promise<FlatNode<Record<string, PropertyBuilder>> | null>;
371
- /**
372
- * Execute multiple operations atomically.
373
- * All operations succeed or fail together.
374
- *
375
- * Note: Transaction support requires MainThreadBridge with direct NodeStore access.
376
- * WorkerBridge executes operations sequentially (not truly atomic).
377
- */
378
- mutate: (ops: MutateOp[]) => Promise<MutateResult | null>;
379
- /**
380
- * Whether any mutation is currently in progress.
381
- */
382
- isPending: boolean;
383
- /**
384
- * Number of pending mutations.
385
- */
386
- pendingCount: number;
387
- }
388
- /**
389
- * Hook for all write operations on Nodes via DataBridge.
390
- *
391
- * Provides both convenience methods (create, update, remove) and
392
- * a full transaction API (mutate) for atomic multi-node operations.
393
- *
394
- * All operations update the local cache immediately, and subscribers
395
- * see changes synchronously. Background sync handles persistence.
396
- */
397
- declare function useMutate(): UseMutateResult;
398
-
399
- /**
400
- * useNode - The unified hook for working with a single Node
401
- *
402
- * This is the primary hook for editing Nodes. It provides:
403
- * - Node properties (flattened for ergonomic access)
404
- * - Y.Doc for collaborative rich text (if schema specifies document: 'yjs')
405
- * - Auto-sync via WebSocket
406
- * - Type-safe mutations (update, remove)
407
- * - Presence awareness (live + hub snapshot)
408
- * - Auto-create with createIfMissing
409
- *
410
- * @example
411
- * ```tsx
412
- * const {
413
- * data, // FlatNode - access data.title directly!
414
- * doc, // Y.Doc for rich text
415
- * update, // Type-safe update function
416
- * remove, // Soft delete
417
- * syncStatus, // 'offline' | 'connecting' | 'connected'
418
- * peerCount, // Number of connected peers
419
- * presence, // Presence list (live + hub snapshot)
420
- * loading,
421
- * error
422
- * } = useNode(PageSchema, pageId, {
423
- * createIfMissing: { title: 'Untitled' }
424
- * })
425
- *
426
- * // Update is type-safe!
427
- * update({ title: 'New Title' }) // OK
428
- * update({ typo: 'x' }) // Type error!
429
- * ```
430
- */
431
-
432
- /**
433
- * Sync connection status
434
- */
435
- type SyncStatus$1 = 'offline' | 'connecting' | 'connected' | 'error';
436
- interface PresenceUser {
437
- did: string;
438
- name?: string;
439
- color?: string;
440
- lastSeen?: number;
441
- isStale?: boolean;
442
- }
443
- /**
444
- * Options for useNode
445
- */
446
- interface UseNodeOptions<P extends Record<string, PropertyBuilder>> {
447
- /** Signaling servers for y-webrtc (default: localhost for dev) */
448
- signalingServers?: string[];
449
- /** Disable auto-sync (default: false) */
450
- disableSync?: boolean;
451
- /** Debounce persistence delay in ms (default: 1000) */
452
- persistDebounce?: number;
453
- /**
454
- * Auto-create the node if it doesn't exist.
455
- * Provide the default properties to use for creation.
456
- */
457
- createIfMissing?: InferCreateProps<P>;
458
- /**
459
- * User's DID for presence/cursors. If provided, broadcasts awareness state.
460
- */
461
- did?: string;
462
- }
463
- /**
464
- * Result from useNode hook
465
- */
466
- interface UseNodeResult<P extends Record<string, PropertyBuilder>> {
467
- /** Node properties (flattened - access directly: data.title) */
468
- data: FlatNode<P> | null;
469
- /** Yjs document instance (null if schema has no document type) */
470
- doc: Y.Doc | null;
471
- /**
472
- * Update node properties (type-safe).
473
- * Only properties defined in the schema are allowed.
474
- */
475
- update: (properties: Partial<InferCreateProps<P>>) => Promise<void>;
476
- /**
477
- * Soft-delete the node.
478
- */
479
- remove: () => Promise<void>;
480
- /** Whether currently loading */
481
- loading: boolean;
482
- /** Any error that occurred */
483
- error: Error | null;
484
- /** Whether document has unsaved changes */
485
- isDirty: boolean;
486
- /** Last persistence timestamp */
487
- lastSavedAt: number | null;
488
- /** Whether the node was auto-created (via createIfMissing) */
489
- wasCreated: boolean;
490
- /** Sync connection status */
491
- syncStatus: SyncStatus$1;
492
- /** Sync error message (if syncStatus is 'error') */
493
- syncError: string | null;
494
- /** Connected peer count */
495
- peerCount: number;
496
- /** Presence list (live awareness + hub snapshot) */
497
- presence: PresenceUser[];
498
- /** Yjs Awareness instance (for TipTap CollaborationCursor) */
499
- awareness: Awareness | null;
500
- /** Manually trigger save */
501
- save: () => Promise<void>;
502
- /** Reload from storage */
503
- reload: () => Promise<void>;
504
- }
505
- /**
506
- * Load a Node with its CRDT document.
507
- *
508
- * This is the primary hook for editing content. It combines:
509
- * - Data loading (with FlatNode for ergonomic access)
510
- * - Y.Doc for collaborative rich text
511
- * - Type-safe mutations
512
- * - Real-time sync and presence
513
- */
514
- declare function useNode<P extends Record<string, PropertyBuilder>>(schema: DefinedSchema<P>, id: string | null, options?: UseNodeOptions<P>): UseNodeResult<P>;
515
-
516
- /**
517
- * useDatabaseDoc - Hook for database column and view operations
518
- *
519
- * Provides reactive access to the database's Y.Doc structure:
520
- * - Column definitions (CRDT-ordered)
521
- * - View configurations
522
- * - Column and view CRUD operations
523
- *
524
- * @example
525
- * ```tsx
526
- * const {
527
- * columns,
528
- * views,
529
- * createColumn,
530
- * updateColumn,
531
- * deleteColumn,
532
- * reorderColumn,
533
- * createView,
534
- * updateView,
535
- * deleteView
536
- * } = useDatabaseDoc(databaseId)
537
- * ```
538
- */
539
-
540
- interface UseDatabaseDocResult {
541
- /** All column definitions (CRDT-ordered) */
542
- columns: ColumnDefinition[];
543
- /** All view configurations */
544
- views: ViewConfig[];
545
- /** Y.Doc for direct access (if needed) */
546
- doc: Y.Doc | null;
547
- /** Whether the doc is loading */
548
- loading: boolean;
549
- /** Any error that occurred */
550
- error: Error | null;
551
- /** Create a new column */
552
- createColumn: (definition: Omit<ColumnDefinition, 'id'>) => string | null;
553
- /** Update a column's properties */
554
- updateColumn: (columnId: string, updates: Partial<Omit<ColumnDefinition, 'id'>>) => void;
555
- /** Delete a column */
556
- deleteColumn: (columnId: string) => void;
557
- /** Reorder a column to a new position */
558
- reorderColumn: (columnId: string, newIndex: number) => void;
559
- /** Duplicate a column */
560
- duplicateColumn: (columnId: string, newName?: string) => string | null;
561
- /** Get a single column by ID */
562
- getColumn: (columnId: string) => ColumnDefinition | null;
563
- /** Create a new view */
564
- createView: (config: Omit<ViewConfig, 'id'>) => string | null;
565
- /** Update a view's properties */
566
- updateView: (viewId: string, updates: Partial<Omit<ViewConfig, 'id'>>) => void;
567
- /** Delete a view */
568
- deleteView: (viewId: string) => void;
569
- /** Duplicate a view */
570
- duplicateView: (viewId: string, newName?: string) => string | null;
571
- /** Get a single view by ID */
572
- getView: (viewId: string) => ViewConfig | null;
573
- }
574
- /**
575
- * Hook for database column and view operations.
576
- *
577
- * Provides reactive access to the database's Y.Doc structure with
578
- * CRDT-based column ordering and real-time schema sync.
579
- */
580
- declare function useDatabaseDoc(databaseId: string): UseDatabaseDocResult;
581
-
582
- /**
583
- * useDatabase - Hook for database row operations with pagination
584
- *
585
- * Provides:
586
- * - Paginated row queries
587
- * - Row CRUD operations
588
- * - Integration with useDatabaseDoc for columns/views
589
- *
590
- * @example
591
- * ```tsx
592
- * const {
593
- * rows,
594
- * columns,
595
- * views,
596
- * loading,
597
- * hasMore,
598
- * loadMore,
599
- * createRow,
600
- * updateRow,
601
- * deleteRow
602
- * } = useDatabase(databaseId)
603
- * ```
604
- */
605
-
606
- interface UseDatabaseOptions {
607
- /** Active view ID (uses first view if not specified) */
608
- view?: string;
609
- /** Override view filters */
610
- filters?: FilterGroup;
611
- /** Override view sorts */
612
- sorts?: SortConfig[];
613
- /** Search query (full-text search) - not yet implemented */
614
- search?: string;
615
- /** Page size (default: 50) */
616
- pageSize?: number;
617
- }
618
- interface DatabaseRow {
619
- /** Row ID */
620
- id: string;
621
- /** Sort key for ordering */
622
- sortKey: string;
623
- /** Cell values keyed by column ID */
624
- cells: Record<string, CellValue>;
625
- /** Creation timestamp */
626
- createdAt: number;
627
- /** Creator DID */
628
- createdBy: string;
629
- }
630
- interface UseDatabaseResult {
631
- /** Column definitions */
632
- columns: ColumnDefinition[];
633
- /** View configurations */
634
- views: ViewConfig[];
635
- /** Loaded rows */
636
- rows: DatabaseRow[];
637
- /** Total row count */
638
- total: number;
639
- /** Whether more rows are available */
640
- hasMore: boolean;
641
- /** Load more rows */
642
- loadMore: () => Promise<void>;
643
- /** Active view configuration */
644
- activeView: ViewConfig | null;
645
- /** Set the active view */
646
- setActiveView: (viewId: string) => void;
647
- /** Create a new row */
648
- createRow: (values?: Record<string, CellValue>) => Promise<string>;
649
- /** Update a row's cell values */
650
- updateRow: (rowId: string, values: Record<string, CellValue>) => Promise<void>;
651
- /** Delete a row */
652
- deleteRow: (rowId: string) => Promise<void>;
653
- /** Reorder a row */
654
- reorderRow: (rowId: string, before?: string, after?: string) => Promise<void>;
655
- /** Delete multiple rows */
656
- deleteRows: (rowIds: string[]) => Promise<void>;
657
- /** Whether initially loading */
658
- loading: boolean;
659
- /** Whether loading more rows */
660
- loadingMore: boolean;
661
- /** Any error that occurred */
662
- error: Error | null;
663
- /** Refetch all rows */
664
- refetch: () => Promise<void>;
665
- }
666
- /**
667
- * Hook for database row operations with pagination.
668
- */
669
- declare function useDatabase(databaseId: string, options?: UseDatabaseOptions): UseDatabaseResult;
670
-
671
- /**
672
- * useDatabaseRow - Hook for single row operations with optimistic updates
673
- *
674
- * Provides:
675
- * - Row data with cell values
676
- * - Y.Doc for rich text cells
677
- * - Optimistic updates
678
- * - Delete operation
679
- *
680
- * @example
681
- * ```tsx
682
- * const {
683
- * row,
684
- * doc,
685
- * update,
686
- * delete: deleteRow,
687
- * loading
688
- * } = useDatabaseRow(rowId)
689
- * ```
690
- */
691
-
692
- interface DatabaseRowData {
693
- /** Row ID */
694
- id: string;
695
- /** Database ID this row belongs to */
696
- databaseId: string;
697
- /** Sort key for ordering */
698
- sortKey: string;
699
- /** Cell values keyed by column ID */
700
- cells: Record<string, CellValue>;
701
- /** Creation timestamp */
702
- createdAt: number;
703
- /** Creator DID */
704
- createdBy: string;
705
- }
706
- interface UseDatabaseRowResult {
707
- /** Row data */
708
- row: DatabaseRowData | null;
709
- /** Y.Doc for rich text cells (if any) */
710
- doc: Y.Doc | null;
711
- /** Update cell values (with optimistic UI) */
712
- update: (values: Record<string, CellValue>) => Promise<void>;
713
- /** Delete this row */
714
- delete: () => Promise<void>;
715
- /** Loading state */
716
- loading: boolean;
717
- /** Error state */
718
- error: Error | null;
719
- }
720
- /**
721
- * Hook for single row operations with optimistic updates.
722
- */
723
- declare function useDatabaseRow(rowId: string): UseDatabaseRowResult;
724
-
725
- /**
726
- * useCell - Hook for individual cell editing with debounced saves
727
- *
728
- * Provides:
729
- * - Cell value with optimistic updates
730
- * - Debounced persistence
731
- * - Clear operation
732
- *
733
- * @example
734
- * ```tsx
735
- * const { value, setValue, saving } = useCell<string>(rowId, 'title')
736
- *
737
- * return (
738
- * <Input
739
- * value={value ?? ''}
740
- * onChange={(e) => setValue(e.target.value)}
741
- * className={saving ? 'opacity-50' : ''}
742
- * />
743
- * )
744
- * ```
745
- */
746
-
747
- interface UseCellResult<T extends CellValue = CellValue> {
748
- /** Cell value */
749
- value: T | null;
750
- /** Update cell value (debounced save) */
751
- setValue: (value: T | null) => void;
752
- /** Clear cell value */
753
- clear: () => void;
754
- /** Whether cell is being saved */
755
- saving: boolean;
756
- /** Error from last save */
757
- error: Error | null;
758
- }
759
- interface UseCellOptions {
760
- /** Debounce delay in ms (default: 300) */
761
- debounce?: number;
762
- }
763
- /**
764
- * Hook for individual cell editing with debounced saves.
765
- */
766
- declare function useCell<T extends CellValue = CellValue>(rowId: string, columnId: string, options?: UseCellOptions): UseCellResult<T>;
767
-
768
- /**
769
- * useRelatedRows - Hook for loading related row data for relation columns
770
- *
771
- * Fetches the row data for a list of row IDs, typically from a relation column.
772
- *
773
- * @example
774
- * ```tsx
775
- * const { rows, loading, error } = useRelatedRows(['row1', 'row2'])
776
- * // rows contains the full row data for display
777
- * ```
778
- */
779
-
780
- interface UseRelatedRowsResult {
781
- /** Loaded row data */
782
- rows: DatabaseRow[];
783
- /** Whether rows are loading */
784
- loading: boolean;
785
- /** Any error that occurred */
786
- error: Error | null;
787
- }
788
- /**
789
- * Hook for loading related row data.
790
- *
791
- * @param rowIds - Array of row IDs to load
792
- * @returns Object containing rows, loading state, and error
793
- */
794
- declare function useRelatedRows(rowIds: string[]): UseRelatedRowsResult;
795
-
796
- /**
797
- * useReverseRelations - Hook for finding rows that link TO a given row
798
- *
799
- * Finds all rows in other databases that have relation columns pointing
800
- * to the specified row. Useful for showing "backlinks" or "linked from" sections.
801
- *
802
- * @example
803
- * ```tsx
804
- * const { relations, loading, error } = useReverseRelations(taskId, tasksDatabaseId)
805
- * // relations contains all rows that link to this task
806
- * ```
807
- */
808
-
809
- interface ReverseRelation {
810
- /** The row that links to the target row */
811
- row: DatabaseRow;
812
- /** The relation column through which it links */
813
- column: ColumnDefinition;
814
- /** ID of the source database */
815
- sourceDatabaseId: string;
816
- /** Title of the source database */
817
- sourceDatabaseTitle: string;
818
- }
819
- interface UseReverseRelationsResult {
820
- /** Found reverse relations */
821
- relations: ReverseRelation[];
822
- /** Whether relations are loading */
823
- loading: boolean;
824
- /** Any error that occurred */
825
- error: Error | null;
826
- /** Refetch the relations */
827
- refetch: () => void;
828
- }
829
- /**
830
- * Hook for finding reverse relations (backlinks) to a row.
831
- *
832
- * @param rowId - The row ID to find links to
833
- * @param databaseId - The database containing the row
834
- * @returns Object containing relations, loading state, and error
835
- */
836
- declare function useReverseRelations(rowId: string, databaseId: string): UseReverseRelationsResult;
837
-
838
- /**
839
- * useDatabaseSchema - Hook for database-defined schema access
840
- *
841
- * Provides reactive access to a database's schema metadata and properties.
842
- * Works with the schema registry to resolve database-defined schemas.
843
- *
844
- * @example
845
- * ```tsx
846
- * const {
847
- * schema,
848
- * metadata,
849
- * loading,
850
- * error
851
- * } = useDatabaseSchema(databaseId)
852
- *
853
- * // Access schema version
854
- * console.log(metadata?.version) // "1.2.0"
855
- *
856
- * // Access schema properties
857
- * schema?.properties.forEach(prop => console.log(prop.name))
858
- * ```
859
- */
860
-
861
- interface UseDatabaseSchemaResult {
862
- /** The resolved Schema object, or null if not loaded */
863
- schema: Schema | null;
864
- /** The schema metadata from the database's Y.Doc */
865
- metadata: DatabaseSchemaMetadata | null;
866
- /** The schema IRI for this database */
867
- schemaIRI: string | null;
868
- /** Whether the schema is loading */
869
- loading: boolean;
870
- /** Any error that occurred */
871
- error: Error | null;
872
- /** Force refresh the schema */
873
- refresh: () => void;
874
- }
875
- /**
876
- * Hook for accessing a database's schema.
877
- *
878
- * Loads the database's Y.Doc, extracts schema metadata and columns,
879
- * builds the Schema object, and registers it with the schema registry.
880
- *
881
- * @param databaseId - The database node ID
882
- * @returns The schema, metadata, and loading state
883
- */
884
- declare function useDatabaseSchema(databaseId: string | undefined): UseDatabaseSchemaResult;
885
-
886
- interface UseCommentsOptions {
887
- /** The Node ID to get comments for (any schema) */
888
- nodeId: string;
889
- /** Optional: filter to specific anchor type */
890
- anchorType?: 'text' | 'cell' | 'row' | 'column' | 'canvas-position' | 'canvas-object' | 'node';
891
- }
892
- interface CommentThread {
893
- /** The root comment (holds anchor data and resolved state) */
894
- root: CommentNode;
895
- /** Replies to this thread (sorted by Lamport time) */
896
- replies: CommentNode[];
897
- }
898
- /** Flattened comment node for easier access */
899
- interface CommentNode {
900
- id: string;
901
- schemaId: string;
902
- createdAt: number;
903
- lamportTime: number;
904
- wallTime: number;
905
- properties: {
906
- target: string;
907
- targetSchema?: string;
908
- inReplyTo?: string;
909
- anchorType: string;
910
- anchorData: string;
911
- content: string;
912
- attachments?: string[];
913
- replyToUser?: string;
914
- replyToCommentId?: string;
915
- resolved: boolean;
916
- resolvedBy?: string;
917
- resolvedAt?: number;
918
- edited: boolean;
919
- editedAt?: number;
920
- createdBy: string;
921
- };
922
- }
923
- interface AddCommentOptions {
924
- /** Comment content (GitHub-flavored markdown) */
925
- content: string;
926
- /** Type of anchor */
927
- anchorType: 'text' | 'cell' | 'row' | 'column' | 'canvas-position' | 'canvas-object' | 'node';
928
- /** JSON-encoded anchor data */
929
- anchorData: string;
930
- /** Schema IRI of the target Node (optimization) */
931
- targetSchema?: string;
932
- }
933
- interface ReplyContext {
934
- /** DID of user being replied to (for "replying to @user" UI) */
935
- replyToUser?: string;
936
- /** Comment ID being referenced (for "in reply to X" display) */
937
- replyToCommentId?: string;
938
- }
939
- interface UseCommentsResult {
940
- /** All comments on the target node */
941
- comments: CommentNode[];
942
- /** Comments grouped into threads (root + replies) */
943
- threads: CommentThread[];
944
- /** Total comment count */
945
- count: number;
946
- /** Count of unresolved threads */
947
- unresolvedCount: number;
948
- /** Whether loading */
949
- loading: boolean;
950
- /** Any error */
951
- error: Error | null;
952
- /** Add a new root comment */
953
- addComment: (options: AddCommentOptions) => Promise<string | null>;
954
- /** Reply to a thread */
955
- replyTo: (rootCommentId: string, content: string, context?: ReplyContext) => Promise<string | null>;
956
- /** Resolve a thread */
957
- resolveThread: (rootCommentId: string) => Promise<void>;
958
- /** Reopen a resolved thread */
959
- reopenThread: (rootCommentId: string) => Promise<void>;
960
- /** Delete a comment (soft delete) */
961
- deleteComment: (commentId: string) => Promise<void>;
962
- /** Delete an entire thread (root + all replies) */
963
- deleteThread: (rootCommentId: string) => Promise<void>;
964
- /** Edit a comment */
965
- editComment: (commentId: string, content: string) => Promise<void>;
966
- /** Reload comments */
967
- reload: () => Promise<void>;
968
- }
969
- /**
970
- * Universal hook for comments on any Node.
971
- */
972
- declare function useComments({ nodeId, anchorType }: UseCommentsOptions): UseCommentsResult;
973
-
974
- /**
975
- * Get the unresolved comment count for a Node.
976
- *
977
- * @param nodeId - The Node ID to get comment count for
978
- * @returns The number of unresolved comment threads
979
- */
980
- declare function useCommentCount(nodeId: string): number;
981
- /**
982
- * Get detailed comment counts for a Node.
983
- *
984
- * @param nodeId - The Node ID to get comment counts for
985
- * @returns Object with total and unresolved counts
986
- */
987
- declare function useCommentCounts(nodeId: string): {
988
- total: number;
989
- unresolved: number;
990
- resolved: number;
991
- };
992
-
993
- /**
994
- * useHistory - React hook for node history / time travel
995
- *
996
- * Provides point-in-time reconstruction, timeline browsing,
997
- * and state materialization for a node.
998
- *
999
- * @example
1000
- * ```tsx
1001
- * const { timeline, materializeAt, diff, changeCount, loading } = useHistory(nodeId)
1002
- *
1003
- * // Get timeline
1004
- * const entries = timeline
1005
- *
1006
- * // Materialize at a specific point
1007
- * const historical = await materializeAt({ type: 'index', index: 5 })
1008
- *
1009
- * // Diff two points
1010
- * const diffs = await diff({ type: 'index', index: 0 }, { type: 'latest' })
1011
- * ```
1012
- */
1013
-
1014
- interface UseHistoryResult {
1015
- /** Full timeline of changes for the node */
1016
- timeline: TimelineEntry[];
1017
- /** Total number of changes */
1018
- changeCount: number;
1019
- /** Reconstruct node state at a target point */
1020
- materializeAt: (target: HistoryTarget) => Promise<HistoricalState | null>;
1021
- /** Diff between two points */
1022
- diff: (from: HistoryTarget, to: HistoryTarget) => Promise<PropertyDiff[]>;
1023
- /** Create a revert payload to restore to a historical point */
1024
- createRevertPayload: (target: HistoryTarget) => Promise<Record<string, unknown> | null>;
1025
- /** Whether the timeline is loading */
1026
- loading: boolean;
1027
- /** Any error */
1028
- error: Error | null;
1029
- /** Reload the timeline */
1030
- reload: () => Promise<void>;
1031
- }
1032
- declare function useHistory(nodeId: NodeId | null): UseHistoryResult;
1033
-
1034
- /**
1035
- * useUndo - React hook for per-node undo/redo
1036
- *
1037
- * Wraps UndoManager to provide undo/redo actions, stack depth,
1038
- * and canUndo/canRedo state for a given node.
1039
- *
1040
- * @example
1041
- * ```tsx
1042
- * const { undo, redo, canUndo, canRedo, undoCount, redoCount } = useUndo(nodeId)
1043
- *
1044
- * // Wire to keyboard shortcuts
1045
- * <button onClick={undo} disabled={!canUndo}>Undo</button>
1046
- * <button onClick={redo} disabled={!canRedo}>Redo</button>
1047
- * ```
1048
- */
1049
-
1050
- interface UseUndoOptions {
1051
- /** The local user's DID (required for undo to work) */
1052
- localDID: DID;
1053
- /** UndoManager configuration overrides */
1054
- options?: Partial<UndoManagerOptions>;
1055
- }
1056
- interface UseUndoResult {
1057
- /** Undo the last change for this node */
1058
- undo: () => Promise<boolean>;
1059
- /** Redo the last undone change for this node */
1060
- redo: () => Promise<boolean>;
1061
- /** Undo all changes in a batch */
1062
- undoBatch: (batchId: string) => Promise<boolean>;
1063
- /** Whether undo is available */
1064
- canUndo: boolean;
1065
- /** Whether redo is available */
1066
- canRedo: boolean;
1067
- /** Number of undo entries */
1068
- undoCount: number;
1069
- /** Number of redo entries */
1070
- redoCount: number;
1071
- /** Clear undo/redo stacks for this node */
1072
- clear: () => void;
1073
- }
1074
- declare function useUndo(nodeId: NodeId | null, opts: UseUndoOptions): UseUndoResult;
1075
-
1076
- /**
1077
- * useAudit - React hook for querying the audit log
1078
- *
1079
- * Provides paginated, filterable access to change audit entries
1080
- * and activity summaries for nodes.
1081
- *
1082
- * @example
1083
- * ```tsx
1084
- * const { entries, activity, loading } = useAudit(nodeId)
1085
- * const { entries: filtered } = useAudit(nodeId, { operations: ['create', 'delete'] })
1086
- * ```
1087
- */
1088
-
1089
- interface UseAuditOptions {
1090
- /** Filter by operations */
1091
- operations?: ('create' | 'update' | 'delete' | 'restore')[];
1092
- /** Filter by author DID */
1093
- author?: string;
1094
- /** Time range filter [from, to] in wall clock ms */
1095
- timeRange?: [number, number];
1096
- /** Max entries to return */
1097
- limit?: number;
1098
- /** Sort order */
1099
- order?: 'asc' | 'desc';
1100
- }
1101
- interface UseAuditResult {
1102
- /** Audit entries matching the query */
1103
- entries: AuditEntry[];
1104
- /** Activity summary for the node */
1105
- activity: ActivitySummary | null;
1106
- /** Whether loading */
1107
- loading: boolean;
1108
- /** Any error */
1109
- error: Error | null;
1110
- /** Reload audit data */
1111
- reload: () => Promise<void>;
1112
- }
1113
- declare function useAudit(nodeId: NodeId | null, options?: UseAuditOptions): UseAuditResult;
1114
-
1115
- /**
1116
- * useDiff - React hook for comparing node state between two points
1117
- *
1118
- * Wraps DiffEngine to provide on-demand diffs between any two
1119
- * HistoryTarget points.
1120
- *
1121
- * @example
1122
- * ```tsx
1123
- * const { diff, result, loading } = useDiff(nodeId)
1124
- *
1125
- * // Compare creation to latest
1126
- * await diff({ type: 'index', index: 0 }, { type: 'latest' })
1127
- *
1128
- * // Show result
1129
- * result?.diffs.forEach(d => console.log(d.property, d.type))
1130
- * ```
1131
- */
1132
-
1133
- interface UseDiffResult {
1134
- /** Compute diff between two points */
1135
- diff: (from: HistoryTarget, to: HistoryTarget) => Promise<void>;
1136
- /** Diff N changes back from current */
1137
- diffFromCurrent: (changesAgo: number) => Promise<void>;
1138
- /** Latest diff result */
1139
- result: DiffResult | null;
1140
- /** Whether diffing */
1141
- loading: boolean;
1142
- /** Any error */
1143
- error: Error | null;
1144
- }
1145
- declare function useDiff(nodeId: NodeId | null): UseDiffResult;
1146
-
1147
- /**
1148
- * useBlame - React hook for per-property attribution
1149
- *
1150
- * Shows who last changed each property, how many times,
1151
- * and the full edit history.
1152
- *
1153
- * @example
1154
- * ```tsx
1155
- * const { blame, loading, reload } = useBlame(nodeId)
1156
- *
1157
- * blame.forEach(b => {
1158
- * console.log(`${b.property}: last changed by ${b.lastChangedBy}, ${b.totalEdits} edits`)
1159
- * })
1160
- * ```
1161
- */
1162
-
1163
- interface UseBlameResult {
1164
- /** Blame info for all properties */
1165
- blame: BlameInfo[];
1166
- /** Whether loading */
1167
- loading: boolean;
1168
- /** Any error */
1169
- error: Error | null;
1170
- /** Reload blame data */
1171
- reload: () => Promise<void>;
1172
- }
1173
- declare function useBlame(nodeId: NodeId | null): UseBlameResult;
1174
-
1175
- /**
1176
- * useVerification - React hook for cryptographic chain verification
1177
- *
1178
- * Runs verification on a node's change history and reports
1179
- * validity, errors, and statistics.
1180
- *
1181
- * @example
1182
- * ```tsx
1183
- * const { verify, result, loading } = useVerification(nodeId)
1184
- *
1185
- * await verify()
1186
- * if (result?.valid) {
1187
- * console.log('Chain is valid!', result.stats)
1188
- * } else {
1189
- * console.log('Errors:', result?.errors)
1190
- * }
1191
- * ```
1192
- */
1193
-
1194
- interface UseVerificationResult {
1195
- /** Run full verification */
1196
- verify: (options?: VerificationOptions) => Promise<void>;
1197
- /** Run quick check (hash + chain only) */
1198
- quickCheck: () => Promise<{
1199
- valid: boolean;
1200
- errors: number;
1201
- } | null>;
1202
- /** Latest verification result */
1203
- result: VerificationResult | null;
1204
- /** Whether verification is running */
1205
- loading: boolean;
1206
- /** Verification progress (0-1) */
1207
- progress: number;
1208
- /** Any error */
1209
- error: Error | null;
1210
- }
1211
- declare function useVerification(nodeId: NodeId | null): UseVerificationResult;
1212
-
1213
- /**
1214
- * Connection Manager - Multiplexed WebSocket connection for all tracked Nodes
1215
- *
1216
- * Instead of one WebSocket per Node (current WebSocketSyncProvider approach),
1217
- * the Connection Manager maintains a single WebSocket subscribed to multiple
1218
- * rooms. This reduces connection count from O(N) to O(1).
1219
- *
1220
- * The signaling protocol supports multi-room subscriptions:
1221
- * { type: "subscribe", topics: ["xnet-doc-abc", "xnet-doc-def"] }
1222
- */
1223
- type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'error';
1224
- interface ConnectionManagerConfig {
1225
- /** Signaling/hub WebSocket URL */
1226
- url: string;
1227
- /** Reconnect delay in ms (default: 2000) */
1228
- reconnectDelay?: number;
1229
- /** Max reconnect attempts (default: Infinity) */
1230
- maxReconnects?: number;
1231
- /** UCAN token for hub auth */
1232
- ucanToken?: string;
1233
- /** Async UCAN token provider (preferred for rotation) */
1234
- getUCANToken?: () => Promise<string>;
1235
- }
1236
- type RoomHandler = (data: Record<string, unknown>) => void;
1237
- type StatusHandler = (status: ConnectionStatus) => void;
1238
- interface RoomJoinResult {
1239
- /** Unsubscribe function */
1240
- unsubscribe: () => void;
1241
- /** Promise that resolves when server confirms subscription */
1242
- ready: Promise<void>;
1243
- }
1244
- interface ConnectionManager {
1245
- /** Current connection status */
1246
- readonly status: ConnectionStatus;
1247
- /** Connect to the signaling server */
1248
- connect(): void;
1249
- /** Disconnect and cleanup */
1250
- disconnect(): void;
1251
- /** Subscribe to a room (returns unsubscribe function) */
1252
- joinRoom(room: string, handler: RoomHandler): () => void;
1253
- /** Subscribe to a room with confirmation (returns cleanup and ready promise) */
1254
- joinRoomAsync(room: string, handler: RoomHandler): RoomJoinResult;
1255
- /** Leave a room */
1256
- leaveRoom(room: string): void;
1257
- /** Publish a message to a room */
1258
- publish(room: string, data: object): void;
1259
- /** Send a raw message on the WebSocket */
1260
- sendRaw(message: object): void;
1261
- /** Listen for non-room messages */
1262
- onMessage(handler: (message: Record<string, unknown>) => void): () => void;
1263
- /** Listen for status changes */
1264
- onStatus(handler: StatusHandler): () => void;
1265
- /** Number of active room subscriptions */
1266
- readonly roomCount: number;
1267
- }
1268
- declare function createConnectionManager(config: ConnectionManagerConfig): ConnectionManager;
1269
-
1270
- /**
1271
- * Blob Sync Provider - Handles blob synchronization between peers.
1272
- *
1273
- * Integrates with the Background Sync Manager's ConnectionManager to send
1274
- * blob have/want/data messages over the same multiplexed WebSocket connection
1275
- * used for Y.Doc sync. Uses a dedicated room for blob sync messages.
1276
- *
1277
- * Protocol:
1278
- * blob-have: Announce available CIDs to peers
1279
- * blob-want: Request missing blobs by CID
1280
- * blob-data: Transfer blob bytes (base64 encoded)
1281
- * blob-not-found: Signal unavailability
1282
- */
1283
-
1284
- /** Minimal blob store interface for sync (satisfied by BlobStore from @xnetjs/storage) */
1285
- interface BlobStoreForSync {
1286
- get(cid: ContentId): Promise<Uint8Array | null>;
1287
- put(data: Uint8Array): Promise<ContentId>;
1288
- has(cid: ContentId): Promise<boolean>;
1289
- }
1290
-
1291
- /**
1292
- * Sync Manager - Top-level orchestrator for Background Sync
1293
- *
1294
- * Wires together Node Pool, Registry, and Connection Manager into a cohesive
1295
- * sync service. Handles the Yjs sync protocol (state vectors, diffs, incremental
1296
- * updates) for each tracked Node.
1297
- *
1298
- * Components acquire Y.Docs via the SyncManager (through useNode). When released,
1299
- * docs stay alive in the pool and continue syncing in the background.
1300
- */
1301
-
1302
- type SyncStatus = ConnectionStatus;
1303
- interface SyncManagerConfig {
1304
- /** NodeStore for meta bridge */
1305
- nodeStore: NodeStore;
1306
- /** Storage adapter for pool persistence (Y.Doc content) */
1307
- storage: NodeStorageAdapter;
1308
- /** Signaling/hub WebSocket URL */
1309
- signalingUrl: string;
1310
- /** Max Y.Docs in memory (default: 50) */
1311
- poolSize?: number;
1312
- /** TTL for tracked Nodes in ms (default: 7 days) */
1313
- trackTTL?: number;
1314
- /** Author DID for awareness */
1315
- authorDID?: string;
1316
- /** Blob store for P2P blob sync (optional — if omitted, blob sync is disabled) */
1317
- blobStore?: BlobStoreForSync;
1318
- /** Optional UCAN token for hub auth */
1319
- ucanToken?: string;
1320
- /** Optional UCAN token provider for hub auth */
1321
- getUCANToken?: () => Promise<string>;
1322
- /** Optional pool update callback */
1323
- onDocUpdate?: (nodeId: string, doc: Y.Doc) => void;
1324
- /** Optional pool eviction callback */
1325
- onDocEvict?: (nodeId: string, doc: Y.Doc) => void;
1326
- /** Optional room for node-change relay (enables NodeStore sync via hub) */
1327
- nodeSyncRoom?: string;
1328
- }
1329
- interface SyncManager {
1330
- /** Start the sync manager (connect, load registry, sync tracked Nodes) */
1331
- start(): Promise<void>;
1332
- /** Stop (disconnect, flush, save registry) */
1333
- stop(): Promise<void>;
1334
- /** Track a Node for background sync */
1335
- track(nodeId: string, schemaId: string): void;
1336
- /** Stop tracking a Node */
1337
- untrack(nodeId: string): void;
1338
- /** Acquire a Y.Doc (used by useNode) */
1339
- acquire(nodeId: string): Promise<Y.Doc>;
1340
- /** Release a Y.Doc (component unmounted) */
1341
- release(nodeId: string): void;
1342
- /** Get awareness for a Node (for cursor presence) */
1343
- getAwareness(nodeId: string): Awareness | null;
1344
- /** Listen for awareness snapshots from the hub */
1345
- onAwarenessSnapshot(nodeId: string, handler: (users: AwarenessSnapshotUser[]) => void): () => void;
1346
- /** Request blobs from peers by CID (no-op if blob sync is disabled) */
1347
- requestBlobs(cids: string[]): Promise<void>;
1348
- /** Announce blob CIDs to peers (no-op if blob sync is disabled) */
1349
- announceBlobs(cids: string[]): void;
1350
- /** Connection status */
1351
- readonly status: SyncStatus;
1352
- /** Pool stats */
1353
- readonly poolSize: number;
1354
- /** Tracked count */
1355
- readonly trackedCount: number;
1356
- /** Offline queue size */
1357
- readonly queueSize: number;
1358
- /** Pending blob requests */
1359
- readonly pendingBlobCount: number;
1360
- /** Listen for events */
1361
- on(event: 'status', handler: (status: SyncStatus) => void): () => void;
1362
- /** Underlying ConnectionManager (if available) */
1363
- readonly connection?: ConnectionManager;
1364
- }
1365
- type AwarenessSnapshotUser = {
1366
- did: string;
1367
- state: {
1368
- user?: {
1369
- name?: string;
1370
- color?: string;
1371
- avatar?: string;
1372
- did?: string;
1373
- };
1374
- cursor?: {
1375
- anchor: number;
1376
- head: number;
1377
- };
1378
- selection?: unknown;
1379
- online?: boolean;
1380
- [key: string]: unknown;
1381
- };
1382
- lastSeen: number;
1383
- isStale: boolean;
1384
- };
1385
- declare function createSyncManager(config: SyncManagerConfig): SyncManager;
1386
-
1387
- /**
1388
- * useHubStatus - Access hub connection status from context.
1389
- */
1390
-
1391
- declare function useHubStatus(): SyncStatus;
1392
-
1393
- /**
1394
- * useCan - Check current user's permissions for a node.
1395
- */
1396
- interface UseCanResult {
1397
- canRead: boolean;
1398
- canWrite: boolean;
1399
- canDelete: boolean;
1400
- canShare: boolean;
1401
- loading: boolean;
1402
- error: Error | null;
1403
- isFresh: boolean;
1404
- evaluatedAt: number;
1405
- }
1406
- declare function useCan(nodeId: string): UseCanResult;
1407
-
1408
- /**
1409
- * useCanEdit - Resolve editor/viewer capabilities for a node.
1410
- */
1411
- type UseCanEditResult = {
1412
- canEdit: boolean;
1413
- canView: boolean;
1414
- loading: boolean;
1415
- error: Error | null;
1416
- roles: string[];
1417
- };
1418
- declare function useCanEdit(nodeId: string): UseCanEditResult;
1419
-
1420
- /**
1421
- * useGrants - Read and mutate grants for a node.
1422
- */
1423
-
1424
- interface GrantInput {
1425
- to: DID;
1426
- actions: AuthAction[];
1427
- resource?: string;
1428
- expiresIn?: string | number;
1429
- parentGrantId?: string;
1430
- }
1431
- interface UseGrantsResult {
1432
- grants: AuthGrant[];
1433
- loading: boolean;
1434
- error: Error | null;
1435
- grant: (input: GrantInput) => Promise<AuthGrant>;
1436
- revoke: (grantId: string) => Promise<void>;
1437
- }
1438
- declare function useGrants(nodeId: string): UseGrantsResult;
1439
-
1440
- interface UseBackupReturn {
1441
- upload: (docId: string, plaintext: Uint8Array) => Promise<void>;
1442
- download: (docId: string) => Promise<Uint8Array | null>;
1443
- uploading: boolean;
1444
- }
1445
- declare function useBackup(): UseBackupReturn;
1446
-
1447
- interface FileRef {
1448
- cid: string;
1449
- name: string;
1450
- mimeType: string;
1451
- size: number;
1452
- }
1453
- interface UseFileUploadReturn {
1454
- upload: (file: File) => Promise<FileRef>;
1455
- uploading: boolean;
1456
- progress: number;
1457
- }
1458
- declare function useFileUpload(): UseFileUploadReturn;
1459
-
1460
- interface HubSearchOptions {
1461
- schemaIri?: string;
1462
- limit?: number;
1463
- offset?: number;
1464
- }
1465
- interface HubSearchResult {
1466
- docId: string;
1467
- title: string;
1468
- schemaIri: string;
1469
- snippet: string;
1470
- rank: number;
1471
- }
1472
- interface HubSearchState {
1473
- search: (query: string, options?: HubSearchOptions) => Promise<HubSearchResult[]>;
1474
- results: HubSearchResult[];
1475
- loading: boolean;
1476
- error: Error | null;
1477
- }
1478
- declare function useHubSearch(): HubSearchState;
1479
-
1480
- /**
1481
- * useRemoteSchema - Hub schema registry fetch hook.
1482
- */
1483
- interface RemoteSchemaDefinition {
1484
- iri: string;
1485
- version: number;
1486
- name: string;
1487
- description: string;
1488
- definition: Record<string, unknown>;
1489
- authorDid: string;
1490
- propertiesCount: number;
1491
- createdAt: number;
1492
- }
1493
- interface RemoteSchemaState {
1494
- schema: RemoteSchemaDefinition | null;
1495
- loading: boolean;
1496
- error: Error | null;
1497
- }
1498
- declare const useRemoteSchema: (iri: string | undefined) => RemoteSchemaState;
1499
-
1500
- /**
1501
- * usePeerDiscovery - hub peer discovery hook.
1502
- */
1503
- interface DiscoveredPeer {
1504
- did: string;
1505
- displayName?: string;
1506
- endpoints: Array<{
1507
- type: string;
1508
- address: string;
1509
- priority?: number;
1510
- }>;
1511
- lastSeen: number;
1512
- isOnline: boolean;
1513
- }
1514
- declare const usePeerDiscovery: () => {
1515
- peers: DiscoveredPeer[];
1516
- resolve: (did: string) => Promise<DiscoveredPeer | null>;
1517
- refresh: () => Promise<void>;
1518
- loading: boolean;
1519
- };
1520
-
1521
- declare function HubStatusIndicator(): JSX.Element;
1522
-
1523
- /**
1524
- * Global error boundary for xNet React apps.
1525
- *
1526
- * Catches unhandled React render errors and displays a recovery UI
1527
- * instead of crashing the entire app tree.
1528
- */
1529
-
1530
- type ErrorBoundaryFallbackProps = {
1531
- error: Error;
1532
- reset: () => void;
1533
- };
1534
- type ErrorBoundaryProps = {
1535
- children: ReactNode;
1536
- /** Custom fallback UI. Receives error + reset function. If omitted, a default error screen is shown. */
1537
- fallback?: ReactNode | ((props: ErrorBoundaryFallbackProps) => ReactNode);
1538
- /** Callback fired when an error is caught. */
1539
- onError?: (error: Error, errorInfo: ErrorInfo) => void;
1540
- /** Change this value to force a reset (e.g. after navigation). */
1541
- resetKey?: string | number;
1542
- };
1543
- type ErrorBoundaryState = {
1544
- hasError: boolean;
1545
- error: Error | null;
1546
- };
1547
- declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
1548
- state: ErrorBoundaryState;
1549
- static getDerivedStateFromError(error: Error): ErrorBoundaryState;
1550
- componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
1551
- private handleReset;
1552
- componentDidUpdate(prevProps: ErrorBoundaryProps): void;
1553
- render(): ReactNode;
1554
- }
1555
-
1556
- /**
1557
- * Skeleton loading placeholder.
1558
- *
1559
- * Shows a pulsing placeholder while content is loading. Supports
1560
- * different shapes (text lines, circles, rectangles).
1561
- */
1562
- type SkeletonProps = {
1563
- /** Width (CSS value). Default: '100%'. */
1564
- width?: string | number;
1565
- /** Height (CSS value). Default: '1em'. */
1566
- height?: string | number;
1567
- /** Border radius. Use '50%' for circles. Default: '4px'. */
1568
- borderRadius?: string | number;
1569
- /** Additional inline styles. */
1570
- style?: React.CSSProperties;
1571
- /** Number of lines to render. Default: 1. */
1572
- lines?: number;
1573
- /** Gap between lines. Default: '0.5rem'. */
1574
- gap?: string;
1575
- };
1576
- declare function Skeleton({ width, height, borderRadius, style, lines, gap }: SkeletonProps): JSX.Element;
1577
- /**
1578
- * Inject the skeleton keyframes into the document head.
1579
- * Call once at app startup, or include the CSS in your stylesheet:
1580
- *
1581
- * ```css
1582
- * @keyframes xnet-skeleton-pulse {
1583
- * 0% { background-position: 200% 0; }
1584
- * 100% { background-position: -200% 0; }
1585
- * }
1586
- * ```
1587
- */
1588
- declare function injectSkeletonStyles(): void;
1589
-
1590
- interface DemoBannerProps {
1591
- /** How many hours until demo data expires */
1592
- evictionHours: number;
1593
- /** Called when banner is dismissed */
1594
- onDismiss?: () => void;
1595
- }
1596
- /**
1597
- * DemoBanner component
1598
- *
1599
- * @example
1600
- * ```tsx
1601
- * <DemoBanner evictionHours={24} />
1602
- * ```
1603
- */
1604
- declare function DemoBanner({ evictionHours, onDismiss }: DemoBannerProps): react_jsx_runtime.JSX.Element | null;
1605
-
1606
- /**
1607
- * DemoQuotaIndicator - Shows storage quota usage for demo mode
1608
- *
1609
- * Displays a progress bar with bytes used / limit.
1610
- * Colors change at warning (80%) and critical (95%) thresholds.
1611
- */
1612
- interface DemoQuotaIndicatorProps {
1613
- /** Bytes currently used */
1614
- usedBytes: number;
1615
- /** Total quota limit in bytes */
1616
- limitBytes: number;
1617
- }
1618
- /**
1619
- * DemoQuotaIndicator component
1620
- *
1621
- * @example
1622
- * ```tsx
1623
- * <DemoQuotaIndicator usedBytes={5242880} limitBytes={10485760} />
1624
- * ```
1625
- */
1626
- declare function DemoQuotaIndicator({ usedBytes, limitBytes }: DemoQuotaIndicatorProps): react_jsx_runtime.JSX.Element;
1627
-
1628
- /**
1629
- * DemoDataExpiredScreen - Full-screen message when demo data is evicted
1630
- *
1631
- * Shown when the user's demo data has been cleaned up after inactivity.
1632
- * Provides options to start fresh or download the desktop app.
1633
- */
1634
- /**
1635
- * DemoDataExpiredScreen component
1636
- *
1637
- * @example
1638
- * ```tsx
1639
- * if (dataExpired) {
1640
- * return <DemoDataExpiredScreen />
1641
- * }
1642
- * ```
1643
- */
1644
- declare function DemoDataExpiredScreen(): react_jsx_runtime.JSX.Element;
1645
-
1646
- /**
1647
- * Demo mode limits (from hub handshake)
1648
- */
1649
- interface DemoLimits {
1650
- /** Storage quota in bytes */
1651
- quotaBytes: number;
1652
- /** Maximum number of documents */
1653
- maxDocs: number;
1654
- /** Eviction time in hours */
1655
- evictionHours: number;
1656
- }
1657
- /**
1658
- * Demo mode usage stats (future: populated from hub)
1659
- */
1660
- interface DemoUsage {
1661
- /** Bytes currently used */
1662
- usedBytes: number;
1663
- /** Number of documents */
1664
- docCount: number;
1665
- }
1666
- /**
1667
- * Demo mode state
1668
- */
1669
- interface DemoModeState {
1670
- /** Whether connected to a demo hub */
1671
- isDemo: boolean;
1672
- /** Demo mode limits (if in demo mode) */
1673
- limits?: DemoLimits;
1674
- /** Current usage (if in demo mode and available) */
1675
- usage?: DemoUsage;
1676
- }
1677
- /**
1678
- * Hook to detect and track demo mode from hub connection
1679
- *
1680
- * Listens for the handshake message from the hub which includes `isDemo`
1681
- * and `demoLimits` fields when connected to a demo hub.
1682
- *
1683
- * @example
1684
- * ```tsx
1685
- * function App() {
1686
- * const { isDemo, limits } = useDemoMode()
1687
- *
1688
- * return (
1689
- * <div>
1690
- * {isDemo && limits && (
1691
- * <DemoBanner evictionHours={limits.evictionHours} />
1692
- * )}
1693
- * <MainContent />
1694
- * </div>
1695
- * )
1696
- * }
1697
- * ```
1698
- */
1699
- declare function useDemoMode(): DemoModeState;
1700
-
1701
- type OfflineIndicatorProps = {
1702
- /** Custom message. Default: 'You are offline. Changes will sync when reconnected.' */
1703
- message?: string;
1704
- /** Additional CSS class. */
1705
- className?: string;
1706
- /** Position. Default: 'bottom'. */
1707
- position?: 'top' | 'bottom';
1708
- };
1709
- /** Returns true when the browser is offline. */
1710
- declare function useIsOffline(): boolean;
1711
- declare function OfflineIndicator({ message, className, position }: OfflineIndicatorProps): JSX.Element | null;
1712
-
1713
- /**
1714
- * WebSocketSyncProvider - Syncs Y.Doc via WebSocket relay
1715
- *
1716
- * Unlike y-webrtc (which uses WebRTC DataChannels for P2P), this provider
1717
- * relays all Yjs updates through the signaling server. This works in all
1718
- * environments (same-machine, different networks, behind NATs) at the cost
1719
- * of server-relayed traffic.
1720
- *
1721
- * Protocol (extends the y-webrtc signaling protocol):
1722
- * - Uses the same subscribe/publish mechanism as y-webrtc signaling
1723
- * - Sync messages are published as JSON with base64-encoded binary data
1724
- * - Message types: 'sync-step1', 'sync-step2', 'sync-update', 'awareness'
1725
- *
1726
- * Sync flow:
1727
- * 1. On connect: subscribe to room, broadcast sync-step1 (state vector)
1728
- * 2. On receiving sync-step1: respond with sync-step2 (diff for their vector)
1729
- * 3. On local update: broadcast sync-update to room
1730
- * 4. On receiving sync-update: apply to local doc
1731
- *
1732
- * Awareness flow:
1733
- * 1. On connect: broadcast local awareness state
1734
- * 2. On awareness change: broadcast updated state
1735
- * 3. On receiving awareness: apply to local awareness instance
1736
- * 4. On disconnect: peers remove the disconnected client's state
1737
- */
1738
-
1739
- interface WebSocketSyncProviderOptions {
1740
- /** WebSocket URL of the signaling/relay server */
1741
- url: string;
1742
- /** Room name (peers in the same room sync together) */
1743
- room: string;
1744
- /** Reconnect delay in ms (default: 2000) */
1745
- reconnectDelay?: number;
1746
- /** Maximum reconnect attempts (default: Infinity) */
1747
- maxReconnectAttempts?: number;
1748
- }
1749
- type SyncEventType = 'status' | 'synced' | 'peers' | 'awareness-snapshot';
1750
- type SyncEventHandler = (event: unknown) => void;
1751
- declare class WebSocketSyncProvider {
1752
- readonly doc: Y.Doc;
1753
- readonly room: string;
1754
- readonly url: string;
1755
- readonly awareness: Awareness;
1756
- private ws;
1757
- private reconnectDelay;
1758
- private maxReconnectAttempts;
1759
- private reconnectAttempts;
1760
- private reconnectTimer;
1761
- private destroyed;
1762
- private connected;
1763
- private synced;
1764
- private peerId;
1765
- private remotePeerIds;
1766
- private eventHandlers;
1767
- constructor(doc: Y.Doc, options: WebSocketSyncProviderOptions);
1768
- get isConnected(): boolean;
1769
- get isSynced(): boolean;
1770
- /** Helper to get XML fragment length for debug logging */
1771
- private _getFragmentLength;
1772
- on(event: SyncEventType, handler: SyncEventHandler): void;
1773
- off(event: SyncEventType, handler: SyncEventHandler): void;
1774
- private emit;
1775
- destroy(): void;
1776
- private _connect;
1777
- private _scheduleReconnect;
1778
- private _send;
1779
- private _publish;
1780
- /** Handle incoming sync messages from other peers */
1781
- private _handleSyncMessage;
1782
- /** Broadcast local doc updates to peers */
1783
- private _onDocUpdate;
1784
- /** Broadcast local awareness changes to peers */
1785
- private _onAwarenessUpdate;
1786
- }
1787
-
1788
- /**
1789
- * useSyncManager - Access the Background Sync Manager from context
1790
- *
1791
- * Returns null if SyncManager is not available (disabled, not initialized,
1792
- * or when running outside XNetProvider).
1793
- */
1794
-
1795
- declare function useSyncManager(): SyncManager | null;
1796
-
1797
- /**
1798
- * Meta Bridge - Unidirectional sync from NodeStore → Y.Doc meta map
1799
- *
1800
- * SECURITY: This bridge is intentionally ONE-WAY. The Y.Doc meta map is a
1801
- * read-only cache for the editor UI. Property changes MUST go through the
1802
- * signed NodeChange pipeline (via mutate()), never through Yjs.
1803
- *
1804
- * Before (VULNERABLE):
1805
- * NodeStore ↔ MetaBridge ↔ Y.Doc meta
1806
- * (Malicious Yjs updates could poison NodeStore!)
1807
- *
1808
- * After (SECURE):
1809
- * NodeStore → MetaBridge → Y.Doc meta (write)
1810
- * Y.Doc meta → Editor UI (read-only display)
1811
- * Editor UI → mutate() → NodeStore (signed writes)
1812
- *
1813
- * See: docs/plans/plan03_4_1YjsSecurity/04-metabridge-isolation.md
1814
- */
1815
-
1816
- /** Transaction origin for MetaBridge writes (for debugging/monitoring) */
1817
- declare const METABRIDGE_ORIGIN = "metabridge";
1818
- declare const METABRIDGE_SEED_ORIGIN = "metabridge-seed";
1819
- interface MetaBridge {
1820
- /**
1821
- * Start observing NodeStore changes for a Node and syncing to Y.Doc meta.
1822
- * Direction: NodeStore → Y.Doc meta map (ONE-WAY)
1823
- *
1824
- * @returns Unsubscribe function
1825
- */
1826
- observe(nodeId: string, doc: Y.Doc): () => void;
1827
- /**
1828
- * Seed the Y.Doc meta map with current NodeStore state.
1829
- * Called on document open to populate editor UI.
1830
- */
1831
- seed(nodeId: string, doc: Y.Doc): Promise<void>;
1832
- /**
1833
- * @deprecated Use seed() instead. applyNow() was the bidirectional API.
1834
- * This is kept for backward compatibility but now just calls seed().
1835
- */
1836
- applyNow(nodeId: string, doc: Y.Doc): Promise<void>;
1837
- }
1838
- /**
1839
- * Create a unidirectional MetaBridge.
1840
- *
1841
- * @param store - NodeStore to observe
1842
- * @param options - Configuration options
1843
- */
1844
- declare function createMetaBridge(store: NodeStore, options?: {
1845
- /** Log warnings for non-MetaBridge meta map changes (default: true) */
1846
- warnOnExternalMetaChanges?: boolean;
1847
- }): MetaBridge;
1848
-
1849
- /**
1850
- * Node Pool - LRU cache of Y.Doc instances with acquire/release semantics
1851
- *
1852
- * Components acquire a Y.Doc when they need it and release it when they unmount.
1853
- * Released Y.Docs stay in the pool (warm state) and continue receiving sync
1854
- * updates via the Connection Manager.
1855
- *
1856
- * States:
1857
- * - Active: refCount > 0, never evicted
1858
- * - Warm: refCount = 0, evictable (LRU)
1859
- * - Cold: evicted, serialized to storage (load on demand)
1860
- */
1861
-
1862
- type PoolEntryState = 'active' | 'warm' | 'cold';
1863
- interface NodePoolConfig {
1864
- /** Storage adapter for persisting Y.Doc state */
1865
- storage: NodeStorageAdapter;
1866
- /** Meta bridge for syncing properties to NodeStore */
1867
- metaBridge: MetaBridge;
1868
- /** Max warm entries before LRU eviction (default: 50) */
1869
- maxWarm?: number;
1870
- /** Debounce delay for persisting dirty docs (default: 2000ms) */
1871
- persistDelay?: number;
1872
- /** Optional callback when a doc is updated */
1873
- onDocUpdate?: (nodeId: string, doc: Y.Doc) => void;
1874
- /** Optional callback before a doc is evicted */
1875
- onDocEvict?: (nodeId: string, doc: Y.Doc) => void;
1876
- }
1877
- interface NodePool {
1878
- /** Acquire a Y.Doc for a Node (load from storage or create new) */
1879
- acquire(nodeId: string): Promise<Y.Doc>;
1880
- /** Release a Y.Doc (component unmounted, doc stays warm) */
1881
- release(nodeId: string): void;
1882
- /** Check if a Node is in the pool */
1883
- has(nodeId: string): boolean;
1884
- /** Get pool entry state */
1885
- getState(nodeId: string): PoolEntryState | null;
1886
- /** Number of entries currently in memory */
1887
- readonly size: number;
1888
- /** Force-persist all dirty docs */
1889
- flushAll(): Promise<void>;
1890
- /** Destroy pool, persist all docs, cleanup */
1891
- destroy(): Promise<void>;
1892
- }
1893
- declare function createNodePool(config: NodePoolConfig): NodePool;
1894
-
1895
- /**
1896
- * NodeStoreSyncProvider - Sync NodeChange events via hub ConnectionManager.
1897
- */
1898
-
1899
- type SerializedNodeChange = {
1900
- id: string;
1901
- type: string;
1902
- hash: string;
1903
- room: string;
1904
- nodeId: string;
1905
- schemaId?: string;
1906
- lamportTime: number;
1907
- lamportAuthor: string;
1908
- authorDid: string;
1909
- wallTime: number;
1910
- parentHash: string | null;
1911
- payload: NodePayload;
1912
- signatureB64: string;
1913
- batchId?: string;
1914
- batchIndex?: number;
1915
- batchSize?: number;
1916
- };
1917
- type NodeSyncResponse = {
1918
- type: 'node-sync-response';
1919
- room: string;
1920
- changes: SerializedNodeChange[];
1921
- highWaterMark: number;
1922
- };
1923
- /**
1924
- * Listener for unknown change type events.
1925
- */
1926
- type UnknownChangeTypeListener = (change: NodeChange, peerId: string) => void;
1927
- declare class NodeStoreSyncProvider {
1928
- private store;
1929
- private room;
1930
- private lastSyncedLamport;
1931
- private connection;
1932
- private roomCleanup;
1933
- private statusCleanup;
1934
- private messageCleanup;
1935
- private storeCleanup;
1936
- private unknownChangeTypeListeners;
1937
- constructor(store: NodeStore, room: string);
1938
- /**
1939
- * Subscribe to unknown change type events.
1940
- * These are changes received from peers with types this version doesn't know how to process.
1941
- * The changes are still stored in the change log for forward compatibility.
1942
- *
1943
- * @param listener - Callback invoked when an unknown change type is received
1944
- * @returns Unsubscribe function
1945
- */
1946
- onUnknownChangeType(listener: UnknownChangeTypeListener): () => void;
1947
- private emitUnknownChangeType;
1948
- attach(connection: ConnectionManager): void;
1949
- detach(): void;
1950
- private handleRoomMessage;
1951
- private handleDirectMessage;
1952
- private requestSync;
1953
- private syncLocalChanges;
1954
- private broadcastChange;
1955
- private handleRemoteChange;
1956
- private handleSyncResponse;
1957
- private serializeChange;
1958
- private deserializeChange;
1959
- }
1960
-
1961
- /**
1962
- * Registry - Persistent tracked-Node set that survives app restarts
1963
- *
1964
- * The Registry maintains the set of Nodes the BSM should keep synced.
1965
- * Nodes are added automatically when opened and expire after a configurable TTL.
1966
- * Pinned Nodes never expire.
1967
- */
1968
- interface TrackedNode {
1969
- nodeId: string;
1970
- schemaId: string;
1971
- /** When the user last opened this Node */
1972
- lastOpened: number;
1973
- /** When sync last completed for this Node */
1974
- lastSynced: number;
1975
- /** Whether explicitly pinned (never expires) */
1976
- pinned: boolean;
1977
- }
1978
- interface RegistryStorage {
1979
- get(key: string): Promise<TrackedNode[] | null>;
1980
- set(key: string, entries: TrackedNode[]): Promise<void>;
1981
- }
1982
- interface RegistryConfig {
1983
- /** Storage adapter for persistence */
1984
- storage: RegistryStorage;
1985
- /** TTL for tracked Nodes in ms (default: 7 days) */
1986
- trackTTL?: number;
1987
- /** Storage key for the tracked set */
1988
- storageKey?: string;
1989
- }
1990
- interface Registry {
1991
- /** Add a Node to the tracked set */
1992
- track(nodeId: string, schemaId: string): void;
1993
- /** Remove a Node from the tracked set */
1994
- untrack(nodeId: string): void;
1995
- /** Pin a Node (never expires) */
1996
- pin(nodeId: string): void;
1997
- /** Unpin a Node (subject to TTL expiry) */
1998
- unpin(nodeId: string): void;
1999
- /** Mark a Node as recently opened (refreshes TTL) */
2000
- touch(nodeId: string): void;
2001
- /** Mark a Node as synced */
2002
- markSynced(nodeId: string): void;
2003
- /** Get all tracked Nodes (excluding expired) */
2004
- getTracked(): TrackedNode[];
2005
- /** Check if a Node is tracked */
2006
- isTracked(nodeId: string): boolean;
2007
- /** Load from storage */
2008
- load(): Promise<void>;
2009
- /** Persist to storage */
2010
- save(): Promise<void>;
2011
- /** Remove expired entries */
2012
- prune(): number;
2013
- }
2014
- declare function createRegistry(config: RegistryConfig): Registry;
2015
-
2016
- /**
2017
- * Offline Queue - Persistent queue for Y.Doc updates made while disconnected
2018
- *
2019
- * When the network is unavailable, local Y.Doc updates are queued in persistent
2020
- * storage. On reconnect, the queue is drained (replayed in order). This ensures
2021
- * no local changes are lost, even across app restarts.
2022
- */
2023
-
2024
- interface QueueEntry {
2025
- /** Node ID this update belongs to */
2026
- nodeId: string;
2027
- /** Serialized Y.Doc update (base64 encoded) */
2028
- update: string;
2029
- /** Timestamp when queued */
2030
- queuedAt: number;
2031
- }
2032
- interface OfflineQueueConfig {
2033
- /** Storage adapter for persistence */
2034
- storage: NodeStorageAdapter;
2035
- /** Storage key for the queue (default: '_xnet_offline_queue') */
2036
- storageKey?: string;
2037
- /** Max queue size before dropping oldest entries (default: 1000) */
2038
- maxSize?: number;
2039
- }
2040
- interface OfflineQueue {
2041
- /** Enqueue an update for later broadcast */
2042
- enqueue(nodeId: string, update: Uint8Array): Promise<void>;
2043
- /** Drain the queue, calling handler for each entry. Returns count drained. */
2044
- drain(handler: (entry: QueueEntry) => Promise<void>): Promise<number>;
2045
- /** Number of entries in the queue */
2046
- readonly size: number;
2047
- /** Load queue from storage */
2048
- load(): Promise<void>;
2049
- /** Persist queue to storage */
2050
- save(): Promise<void>;
2051
- /** Clear all entries */
2052
- clear(): Promise<void>;
1
+ import { Q as QueryFilter, a as QueryStatus, F as FlatNode, b as QueryPlanSummary } from './useQuery-D7ajycrc.js';
2
+ export { i as FlattenNodeOptions, M as MigrationWarning, c as QueryListResult, d as QuerySingleResult, S as SortDirection, f as flattenNode, e as flattenNodes, h as flattenNodesWithSchemaCheck, g as flattenUnknownSchemaNode, u as useQuery } from './useQuery-D7ajycrc.js';
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
+ import { U as UseTaskProjectionSyncResult, T as TaskProjectionInput, a as TaskTreeItem } from './experimental-B2FrBnkV.js';
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';
7
+ export { ColumnConfig, ColumnDefinition, ColumnType, SavedViewFeedDensity, SavedViewFeedLayout, ViewConfig, ViewType } from '@xnetjs/data';
8
+ import { QueryExecutionMode, QuerySourcePreference, QuerySearchFilter, QueryPageInfo, QueryMetadata } from '@xnetjs/data-bridge';
9
+ import { LucideIcon } from 'lucide-react';
10
+ import { ReactNode, JSX } from 'react';
11
+ export { DatabaseRow, DatabaseRowData, ReverseRelation, UseCellOptions, UseCellResult, UseDatabaseDocResult, UseDatabaseOptions, UseDatabaseResult, UseDatabaseRowResult, UseDatabaseSchemaResult, UseRelatedRowsResult, UseReverseRelationsResult, useCell, useDatabase, useDatabaseDoc, useDatabaseRow, useDatabaseSchema, useRelatedRows, useReverseRelations } from './database.js';
12
+ export { u as useNodeStore } from './useNodeStore-DTCSBF51.js';
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
+ 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';
16
+ export { I as InstrumentationContext, a as InstrumentationContextValue, Q as QueryTrackerLike, Y as YDocRegistryLike, u as useInstrumentation } from './instrumentation-CpIuG2y5.js';
17
+ export { a as TelemetryContext, T as TelemetryReporter, u as useTelemetryReporter } from './telemetry-context-B7r6H1KW.js';
18
+ import '@xnetjs/core';
19
+ import 'y-protocols/awareness';
20
+ import 'yjs';
21
+ import '@xnetjs/identity';
22
+ import '@xnetjs/history';
23
+ import 'react/jsx-runtime';
24
+ import '@xnetjs/crypto';
25
+ import '@xnetjs/plugins';
26
+ import '@xnetjs/sync';
27
+
28
+ /**
29
+ * useEffectiveSchema resolve a node type's *effective* schema reactively:
30
+ * the canonical core schema (from the registry) plus any registered extension
31
+ * fields, composed by `buildEffectiveSchema`.
32
+ *
33
+ * This is the keystone for the universal database view: given any schema IRI
34
+ * (a built-in like `Task`/`Contact`, or a database-derived schema), it yields
35
+ * the column set the grid should render — core columns marked `readonly`
36
+ * (structurally locked) and `ext:<authority>/<field>` columns editable.
37
+ *
38
+ * Composition happens at read time (not cached in the registry) because
39
+ * extensions are added/removed live; the two `useQuery` subscriptions keep the
40
+ * effective schema in sync as `SchemaExtension`/`ExtensionField` nodes change.
41
+ */
42
+
43
+ interface UseEffectiveSchemaResult {
44
+ /** The composed effective schema, or null while the core schema loads / can't resolve. */
45
+ schema: Schema | null;
46
+ /** True while the core schema is being resolved. */
47
+ loading: boolean;
2053
48
  }
2054
- declare function createOfflineQueue(config: OfflineQueueConfig): OfflineQueue;
49
+ declare function useEffectiveSchema(schemaId: SchemaIRI | null | undefined): UseEffectiveSchemaResult;
2055
50
 
2056
51
  /**
2057
- * useIdentity hook for identity access
52
+ * useSavedView - Execute persisted SavedView descriptors.
2058
53
  */
2059
54
 
2060
- /**
2061
- * Result from useIdentity hook
2062
- */
2063
- interface UseIdentityResult {
2064
- identity: Identity | null;
2065
- isAuthenticated: boolean;
2066
- did: string | null;
2067
- }
2068
- /**
2069
- * Hook for accessing current identity
2070
- */
2071
- declare function useIdentity(): UseIdentityResult;
55
+ type RegistrySchema = DefinedSchema<Record<string, PropertyBuilder>>;
56
+ type SavedViewSchemaRegistry = readonly RegistrySchema[];
57
+ type SavedViewPrivacySummary = {
58
+ counts: Record<string, number>;
59
+ sensitiveCount: number;
60
+ };
61
+ type SavedViewQueryOverride = {
62
+ search?: string | QuerySearchFilter;
63
+ orderBy?: QueryASTOrderBy[];
64
+ page?: QueryASTPage;
65
+ };
66
+ type UseSavedViewOptions = Pick<QueryFilter<Record<string, PropertyBuilder>>, 'includeDeleted' | 'materializedView'> & {
67
+ mode?: QueryExecutionMode;
68
+ source?: QuerySourcePreference;
69
+ search?: string | QuerySearchFilter;
70
+ includePolicy?: 'ignore' | 'block';
71
+ queryOverrides?: Record<string, SavedViewQueryOverride>;
72
+ };
73
+ type SavedViewQueryResult = {
74
+ queryId: string;
75
+ rowRole: string;
76
+ schemaId: string;
77
+ schemaName: string;
78
+ data: FlatNode<Record<string, PropertyBuilder>>[];
79
+ status: QueryStatus;
80
+ loading: boolean;
81
+ error: Error | null;
82
+ pageInfo: QueryPageInfo;
83
+ totalCount: number | null;
84
+ hasMore: boolean;
85
+ plan: QueryPlanSummary | null;
86
+ metadata: QueryMetadata | null;
87
+ plannerGate: QueryASTPlannerGate;
88
+ blockers: string[];
89
+ warnings: string[];
90
+ canExecute: boolean;
91
+ aggregates: QueryASTAggregateExecution | null;
92
+ privacy: SavedViewPrivacySummary;
93
+ };
94
+ type UseSavedViewResult = {
95
+ descriptor: SavedViewDescriptor | null;
96
+ validation: QueryASTValidationResult;
97
+ kind: 'node' | 'query-set' | 'invalid';
98
+ status: QueryStatus;
99
+ loading: boolean;
100
+ error: Error | null;
101
+ title: string | null;
102
+ description: string | null;
103
+ primaryQueryId: string | null;
104
+ queryIds: string[];
105
+ queries: Record<string, SavedViewQueryResult>;
106
+ primary: SavedViewQueryResult | null;
107
+ blockers: string[];
108
+ warnings: string[];
109
+ privacy: SavedViewPrivacySummary;
110
+ reload: () => void;
111
+ };
112
+ declare function useSavedView(input: SavedViewDescriptor | string | null | undefined, registry: SavedViewSchemaRegistry, options?: UseSavedViewOptions): UseSavedViewResult;
2072
113
 
2073
114
  /**
2074
- * @xnetjs/react/onboarding - State machine for the onboarding flow
2075
- *
2076
- * States:
2077
- * welcome → authenticating → connecting-hub → ready → complete
2078
- * ↓ ↑
2079
- * auth-error ──────── (retry) ────────┘
2080
- * welcome → unsupported-browser (terminal)
2081
- * welcome → import-identity → qr-scan/recovery-phrase → connecting-hub
115
+ * Shared visual-preview derivation for saved view rows.
2082
116
  */
2083
117
 
2084
- type OnboardingState = 'welcome' | 'authenticating' | 'auth-error' | 'unsupported-browser' | 'import-identity' | 'qr-scan' | 'recovery-phrase' | 'connecting-hub' | 'ready' | 'complete';
2085
- type OnboardingEvent = {
2086
- type: 'AUTHENTICATE';
2087
- } | {
2088
- type: 'CREATE_NEW';
2089
- } | {
2090
- type: 'IMPORT_EXISTING';
2091
- } | {
2092
- type: 'PASSKEY_SUCCESS';
2093
- identity: Identity;
2094
- keyBundle: KeyBundle;
2095
- } | {
2096
- type: 'PASSKEY_FAILED';
2097
- error: Error;
2098
- } | {
2099
- type: 'BROWSER_UNSUPPORTED';
2100
- } | {
2101
- type: 'RETRY_AUTH';
2102
- } | {
2103
- type: 'BACK_TO_WELCOME';
118
+ type SavedViewVisualPreviewKind = 'content' | 'actor' | 'interaction' | 'message' | 'collection' | 'reference' | 'record';
119
+ type SavedViewVisualPreviewPrivacy = 'private' | 'shared' | 'public' | 'unknown';
120
+ type SavedViewVisualWorkspaceLayout = {
121
+ kind: 'grid';
122
+ groupBy?: string;
123
+ sortBy?: string;
2104
124
  } | {
2105
- type: 'SCAN_QR';
125
+ kind: 'timeline';
126
+ timeField: string;
127
+ laneBy?: string;
2106
128
  } | {
2107
- type: 'ENTER_PHRASE';
129
+ kind: 'cluster';
130
+ groupBy: string;
131
+ sizeBy?: string;
2108
132
  } | {
2109
- type: 'IDENTITY_IMPORTED';
2110
- identity: Identity;
2111
- keyBundle: KeyBundle;
133
+ kind: 'graph';
134
+ lensId?: string;
135
+ algorithm: 'layered' | 'radial' | 'force' | 'stress';
2112
136
  } | {
2113
- type: 'HUB_CONNECTED';
2114
- } | {
2115
- type: 'HUB_FAILED';
2116
- error: Error;
2117
- } | {
2118
- type: 'CREATE_FIRST_PAGE';
137
+ kind: 'collection-board';
138
+ collectionField: string;
2119
139
  };
2120
- type OnboardingMachineContext = {
2121
- identity: Identity | null;
2122
- keyBundle: KeyBundle | null;
2123
- hubUrl: string | null;
2124
- error: Error | null;
2125
- isDemo: boolean;
140
+ type SavedViewVisualPreviewCreator = {
141
+ id?: string;
142
+ label: string;
143
+ url?: string;
2126
144
  };
2127
- type OnboardingReducerState = {
2128
- state: OnboardingState;
2129
- context: OnboardingMachineContext;
145
+ type SavedViewVisualPreviewRelationship = {
146
+ kind: string;
147
+ targetNodeId: string;
148
+ label?: string;
2130
149
  };
2131
- declare function onboardingReducer(current: OnboardingReducerState, event: OnboardingEvent): OnboardingReducerState;
2132
- declare function createInitialState(hubUrl?: string): OnboardingReducerState;
2133
-
2134
- /**
2135
- * @xnetjs/react/onboarding - React context provider for the onboarding flow
2136
- */
2137
-
2138
- type OnboardingContextValue = {
2139
- state: OnboardingState;
2140
- context: OnboardingMachineContext;
2141
- send: (event: OnboardingEvent) => void;
150
+ type SavedViewVisualPreviewModel = {
151
+ id: string;
152
+ sourceNodeId: string;
153
+ sourceSchemaId: string;
154
+ kind: SavedViewVisualPreviewKind;
155
+ platform: string;
156
+ title: string;
157
+ subtitle?: string;
158
+ description?: string;
159
+ creator?: SavedViewVisualPreviewCreator;
160
+ timestamp?: string;
161
+ timestampMs?: number;
162
+ url?: string;
163
+ thumbnailUrl?: string;
164
+ embedUrl?: string;
165
+ provider?: ExternalReferenceProvider;
166
+ platformContentId?: string;
167
+ privacy: SavedViewVisualPreviewPrivacy;
168
+ metrics: Record<string, number>;
169
+ relationships: SavedViewVisualPreviewRelationship[];
170
+ source: {
171
+ queryId?: string;
172
+ rowRole?: string;
173
+ schemaName?: string;
174
+ sourceRecordId?: string;
175
+ importRunId?: string;
176
+ };
2142
177
  };
2143
- type OnboardingProviderProps = {
2144
- children: ReactNode;
2145
- /** Default hub URL for new users */
2146
- defaultHubUrl?: string;
2147
- /** Called when onboarding completes */
2148
- onComplete?: (identity: Identity, keyBundle: KeyBundle) => void;
178
+ type SavedViewVisualTimelineBucket = {
179
+ key: string;
180
+ label: string;
181
+ startMs: number;
182
+ count: number;
183
+ previews: SavedViewVisualPreviewModel[];
2149
184
  };
2150
- declare function OnboardingProvider({ children, defaultHubUrl, onComplete }: OnboardingProviderProps): JSX.Element;
2151
- /**
2152
- * Access the onboarding state machine from within an OnboardingProvider.
2153
- */
2154
- declare function useOnboarding(): OnboardingContextValue;
2155
-
2156
- type HubConnectScreenProps = {
2157
- /** Optional: attempt hub connection. If not provided, auto-advances. */
2158
- connectToHub?: () => Promise<void>;
185
+ type SavedViewCanvasProjectionNode = {
186
+ id: string;
187
+ schemaId: string;
188
+ kind: 'actor' | 'content' | 'interaction' | 'conversation' | 'message' | 'collection' | 'collection-item' | 'source-record';
189
+ title: string;
190
+ subtitle?: string;
191
+ platform?: string;
192
+ privacyClass?: string;
193
+ groupKey?: string;
2159
194
  };
2160
- declare function HubConnectScreen({ connectToHub }: HubConnectScreenProps): JSX.Element;
195
+ declare function deriveSavedViewVisualPreview(row: Readonly<Record<string, unknown>>, query?: Pick<SavedViewQueryResult, 'queryId' | 'rowRole' | 'schemaId' | 'schemaName'> | null): SavedViewVisualPreviewModel;
196
+ declare function deriveSavedViewVisualPreviews(rows: readonly Readonly<Record<string, unknown>>[], query?: Pick<SavedViewQueryResult, 'queryId' | 'rowRole' | 'schemaId' | 'schemaName'> | null): SavedViewVisualPreviewModel[];
197
+ declare function deriveCachedSavedViewVisualPreviews(input: {
198
+ descriptor?: SavedViewDescriptor | string | null;
199
+ query?: Pick<SavedViewQueryResult, 'queryId' | 'rowRole' | 'schemaId' | 'schemaName'> | null;
200
+ rows: readonly Readonly<Record<string, unknown>>[];
201
+ }): SavedViewVisualPreviewModel[];
202
+ declare function createSavedViewVisualPreviewFingerprint(input: {
203
+ descriptor?: SavedViewDescriptor | string | null;
204
+ query?: Pick<SavedViewQueryResult, 'queryId' | 'schemaId'> | null;
205
+ rows: readonly Readonly<Record<string, unknown>>[];
206
+ }): string;
207
+ declare function deriveSavedViewTimelineBuckets(previews: readonly SavedViewVisualPreviewModel[]): SavedViewVisualTimelineBucket[];
208
+ declare function createSavedViewCanvasProjectionNodes(previews: readonly SavedViewVisualPreviewModel[], options?: {
209
+ limit?: number;
210
+ groupBy?: 'platform' | 'kind' | 'creator' | 'privacy';
211
+ }): SavedViewCanvasProjectionNode[];
212
+ declare function isSavedViewVisualPreviewEmbeddable(preview: SavedViewVisualPreviewModel): boolean;
213
+ declare function hasSavedViewVisualPreviewSensitiveData(preview: SavedViewVisualPreviewModel): boolean;
214
+ declare function savedViewVisualPreviewIsSelfActor(row: Readonly<Record<string, unknown>>): boolean;
2161
215
 
2162
- interface OnboardingFlowProps {
2163
- /** Optional hub connection function */
2164
- connectToHub?: HubConnectScreenProps['connectToHub'];
2165
- /** Render prop for the completed state (app content) */
2166
- children?: React.ReactNode;
2167
- }
2168
216
  /**
2169
- * Renders the correct onboarding screen based on state machine state.
217
+ * @xnetjs/react - Media feed presentation for saved view previews.
2170
218
  *
2171
- * @example
2172
- * <OnboardingProvider onComplete={handleComplete}>
2173
- * <OnboardingFlow>
2174
- * <App />
2175
- * </OnboardingFlow>
2176
- * </OnboardingProvider>
219
+ * Renders content-shaped rows (videos, posts, saves, playlists) as a
220
+ * thumbnail-forward feed with list/grid layouts and a density control.
2177
221
  */
2178
- declare function OnboardingFlow({ connectToHub, children }: OnboardingFlowProps): JSX.Element;
2179
-
2180
- declare function WelcomeScreen(): JSX.Element;
2181
-
2182
- declare function AuthenticatingScreen(): JSX.Element;
2183
-
2184
- declare function AuthErrorScreen(): JSX.Element;
2185
-
2186
- declare function UnsupportedBrowserScreen(): JSX.Element;
2187
-
2188
- declare function ImportIdentityScreen(): JSX.Element;
2189
-
2190
- declare function ReadyScreen(): JSX.Element;
2191
-
2192
- declare function SmartWelcome(): JSX.Element;
2193
222
 
223
+ type SavedViewFeedEnrichmentEntry = {
224
+ title?: string | null;
225
+ description?: string | null;
226
+ authorName?: string | null;
227
+ thumbnailUrl?: string | null;
228
+ };
2194
229
  /**
2195
- * @xnetjs/react/sync - Initial sync manager for new device onboarding
2196
- *
2197
- * Orchestrates the full state sync when a new device connects to the hub
2198
- * with an existing identity. Tracks progress and provides callbacks.
230
+ * Optional overlay that lets the host app merge locally cached metadata
231
+ * (titles, descriptions, thumbnails) over imported preview rows and request
232
+ * fetches for the previews currently on screen.
2199
233
  */
2200
- type SyncPhase = 'connecting' | 'syncing' | 'complete' | 'error';
2201
- type SyncProgress = {
2202
- /** Current phase of the sync process */
2203
- phase: SyncPhase;
2204
- /** Total rooms discovered on the hub */
2205
- roomsTotal: number;
2206
- /** Rooms that have been fully synced */
2207
- roomsSynced: number;
2208
- /** Total bytes received from hub */
2209
- bytesReceived: number;
2210
- /** Error if phase === 'error' */
2211
- error?: Error;
234
+ type SavedViewFeedEnrichmentAdapter = {
235
+ lookup: (preview: SavedViewVisualPreviewModel) => SavedViewFeedEnrichmentEntry | null;
236
+ requestMany?: (previews: readonly SavedViewVisualPreviewModel[]) => void;
237
+ };
238
+ declare function mergeSavedViewFeedEnrichment(preview: SavedViewVisualPreviewModel, entry: SavedViewFeedEnrichmentEntry | null | undefined): SavedViewVisualPreviewModel;
239
+ declare function SavedViewVisualFeed({ previews, layout, density, onSelectLayout, onSelectDensity, selectedSourceNodeId, activeEmbedPreviewId, onSelectPreview, onToggleLiveEmbed, enrichment, wrapItem }: {
240
+ previews: SavedViewVisualPreviewModel[];
241
+ layout: SavedViewFeedLayout;
242
+ density: SavedViewFeedDensity;
243
+ onSelectLayout: (layout: SavedViewFeedLayout) => void;
244
+ onSelectDensity: (density: SavedViewFeedDensity) => void;
245
+ selectedSourceNodeId: string | null;
246
+ activeEmbedPreviewId: string | null;
247
+ onSelectPreview: (preview: SavedViewVisualPreviewModel) => void;
248
+ onToggleLiveEmbed: (preview: SavedViewVisualPreviewModel) => void;
249
+ enrichment?: SavedViewFeedEnrichmentAdapter;
250
+ wrapItem?: (nodeId: string, content: ReactNode) => ReactNode;
251
+ }): JSX.Element;
252
+
253
+ /**
254
+ * @xnetjs/react - Generic saved view execution surface.
255
+ */
256
+
257
+ type SavedViewRunnerProps = {
258
+ descriptor?: SavedViewDescriptor | string | null;
259
+ registry: SavedViewSchemaRegistry;
260
+ title?: string | null;
261
+ description?: string | null;
262
+ fallbackId?: string | null;
263
+ resetKey?: string | null;
264
+ className?: string;
265
+ emptyLabel?: string;
266
+ pageSizes?: readonly number[];
267
+ initialPageSize?: number;
268
+ options?: Omit<UseSavedViewOptions, 'queryOverrides' | 'search'>;
269
+ onSaveLens?: (draft: SavedViewLensDraft) => void | Promise<void>;
270
+ saveLensLabel?: string;
271
+ onOpenVisualCanvasProjection?: (request: SavedViewVisualCanvasProjectionRequest) => void | Promise<void>;
272
+ feedEnrichment?: SavedViewFeedEnrichmentAdapter;
273
+ /**
274
+ * Optional per-item wrapper for the visual renderers (cards mode), keyed by a
275
+ * preview's source node id. The host uses it to route each item through its
276
+ * moderation render gate without this package depending on it. Default: no-op
277
+ * (content rendered unwrapped, exactly as before).
278
+ */
279
+ wrapItem?: (nodeId: string, content: ReactNode) => ReactNode;
2212
280
  };
2213
- type InitialSyncMessage = {
2214
- type: 'initial-sync' | 'node-changes' | 'initial-sync-complete';
2215
- room?: string;
2216
- update?: Uint8Array;
2217
- changes?: unknown[];
2218
- roomCount?: number;
281
+ type SavedViewResultTableProps = {
282
+ query: SavedViewQueryResult | null;
283
+ columns: readonly string[];
284
+ expandedRowId: string | null;
285
+ onToggleRow: (rowId: string) => void;
286
+ loadingLabel?: string;
287
+ emptyLabel?: string;
288
+ formatValue?: (input: {
289
+ column: string;
290
+ value: unknown;
291
+ row: Record<string, unknown>;
292
+ }) => ReactNode;
2219
293
  };
2220
- type ProgressListener = (progress: SyncProgress) => void;
2221
- /**
2222
- * Manages the initial sync process for a new device.
2223
- *
2224
- * Usage:
2225
- * ```ts
2226
- * const manager = createInitialSyncManager()
2227
- * const unsub = manager.onProgress((p) => updateUI(p))
2228
- *
2229
- * // Feed messages from the hub WebSocket:
2230
- * manager.handleMessage({ type: 'initial-sync', room: 'r1', update: ... })
2231
- * manager.handleMessage({ type: 'initial-sync-complete', roomCount: 5 })
2232
- *
2233
- * unsub()
2234
- * ```
2235
- */
2236
- type InitialSyncManager = {
2237
- /** Subscribe to progress updates */
2238
- onProgress(listener: ProgressListener): () => void;
2239
- /** Handle an incoming sync message from the hub */
2240
- handleMessage(msg: InitialSyncMessage): void;
2241
- /** Get current progress snapshot */
2242
- getProgress(): SyncProgress;
2243
- /** Mark sync as started (connecting phase) */
2244
- start(): void;
2245
- /** Mark sync as errored */
2246
- setError(error: Error): void;
2247
- /** Reset to initial state */
2248
- reset(): void;
294
+ type SavedViewFacetSelection = Record<string, readonly string[]>;
295
+ type SavedViewFacetValueSummary = {
296
+ valueKey: string;
297
+ label: string;
298
+ count: number;
2249
299
  };
2250
- declare function createInitialSyncManager(): InitialSyncManager;
2251
-
2252
- /**
2253
- * Sync progress overlay — shown during initial sync on a new device.
2254
- */
2255
-
2256
- interface SyncProgressOverlayProps {
2257
- progress: SyncProgress;
2258
- onComplete: () => void;
2259
- }
2260
- declare function SyncProgressOverlay({ progress, onComplete }: SyncProgressOverlayProps): JSX.Element;
2261
-
2262
- /**
2263
- * @xnetjs/react/onboarding - Quick-start content templates
2264
- */
2265
- interface QuickStartTemplate {
2266
- id: string;
2267
- name: string;
300
+ type SavedViewFacetSummary = {
301
+ field: string;
302
+ values: SavedViewFacetValueSummary[];
303
+ totalValues: number;
304
+ };
305
+ type SavedViewDateBucketInterval = 'day' | 'month' | 'year';
306
+ type SavedViewDateBucketSummary = {
307
+ bucketKey: string;
308
+ label: string;
309
+ startMs: number;
310
+ endMs: number;
311
+ count: number;
312
+ };
313
+ type SavedViewDateBucketFieldSummary = {
314
+ field: string;
315
+ interval: SavedViewDateBucketInterval;
316
+ buckets: SavedViewDateBucketSummary[];
317
+ minMs: number;
318
+ maxMs: number;
319
+ totalRows: number;
320
+ };
321
+ type SavedViewDateBrushSelection = {
322
+ field: string | null;
323
+ bucketKeys: readonly string[];
324
+ };
325
+ type SavedViewInspectorItemKind = 'field' | 'relation' | 'source' | 'import';
326
+ type SavedViewInspectorItem = {
327
+ key: string;
328
+ label: string;
329
+ value: unknown;
330
+ formatted: string;
331
+ kind: SavedViewInspectorItemKind;
332
+ };
333
+ type SavedViewRowInspectorModel = {
334
+ rowId: string;
335
+ schemaId: string;
336
+ rowRole: string | null;
337
+ fields: SavedViewInspectorItem[];
338
+ relations: SavedViewInspectorItem[];
339
+ sourceRecords: SavedViewInspectorItem[];
340
+ importRuns: SavedViewInspectorItem[];
341
+ rawJson: string;
342
+ };
343
+ type SavedViewPrivacyChipTone = 'safe' | 'neutral' | 'warning';
344
+ type SavedViewPrivacyChip = {
345
+ privacyClass: string;
346
+ label: string;
347
+ count: number;
348
+ tone: SavedViewPrivacyChipTone;
349
+ };
350
+ type SavedViewSortDirection = 'asc' | 'desc';
351
+ type SavedViewLensDraft = {
352
+ title: string;
2268
353
  description: string;
2269
- icon: string;
2270
- }
2271
- declare const QUICK_START_TEMPLATES: QuickStartTemplate[];
354
+ descriptor: SavedViewDescriptor;
355
+ queryId: string;
356
+ sourceTitle: string;
357
+ stateSummary: {
358
+ facetFields: string[];
359
+ dateField: string | null;
360
+ dateBucketCount: number;
361
+ sortField: string | null;
362
+ sortDirection: SavedViewSortDirection | null;
363
+ pageSize: number;
364
+ };
365
+ };
366
+ type SavedViewPresentationMode = 'table' | 'cards' | 'timeline' | 'canvas' | 'graph' | 'feed';
2272
367
 
368
+ type SavedViewVisualLayoutId = 'grid' | 'timeline' | 'creator-clusters' | 'platform-lanes' | 'content-type-lanes' | 'date-bands' | 'collection-board' | 'graph';
369
+ type SavedViewVisualLayoutOption = {
370
+ id: SavedViewVisualLayoutId;
371
+ label: string;
372
+ description: string;
373
+ icon: LucideIcon;
374
+ enabled: boolean;
375
+ workspaceLayout: SavedViewVisualWorkspaceLayout;
376
+ projectionGroupBy: 'platform' | 'kind' | 'creator' | 'privacy';
377
+ };
378
+ type SavedViewVisualCanvasProjectionRequest = {
379
+ id: string;
380
+ title: string;
381
+ description?: string | null;
382
+ descriptor?: SavedViewDescriptor | string | null;
383
+ sourceQueryId?: string | null;
384
+ sourceSchemaId?: string | null;
385
+ layout: {
386
+ id: SavedViewVisualLayoutId;
387
+ label: string;
388
+ workspaceLayout: SavedViewVisualWorkspaceLayout;
389
+ projectionGroupBy: SavedViewVisualLayoutOption['projectionGroupBy'];
390
+ };
391
+ nodes: SavedViewCanvasProjectionNode[];
392
+ sourceNodeIds: string[];
393
+ omittedNodeCount: number;
394
+ previewCount: number;
395
+ };
2273
396
  /**
2274
- * @xnetjs/react/onboarding - Helper utilities
2275
- */
2276
- /**
2277
- * Get a human-friendly name for the platform's biometric authenticator.
2278
- */
2279
- declare function getPlatformAuthName(): string;
2280
- /**
2281
- * Truncate a DID for display, showing first and last segments.
2282
- * e.g. "did:key:z6MkhaXg...yz" → "did:key:z6Mkha...xyz"
397
+ * Derive a stable display column list from flattened schema query rows.
2283
398
  */
2284
- declare function truncateDid(did: string, headLen?: number, tailLen?: number): string;
399
+ declare function deriveSavedViewColumns(rows: readonly Record<string, unknown>[]): string[];
2285
400
  /**
2286
- * Copy text to clipboard, returns true on success.
2287
- * Returns false in SSR environments where navigator is unavailable.
401
+ * Format primitive and structured cell values for read-only schema query tables.
2288
402
  */
2289
- declare function copyToClipboard(text: string): Promise<boolean>;
2290
-
403
+ declare function formatSavedViewCellValue(column: string, value: unknown): string;
2291
404
  /**
2292
- * Telemetry context for @xnetjs/react
2293
- *
2294
- * Provides an optional duck-typed TelemetryReporter to the React tree.
2295
- * When present, hooks report performance timing, usage counts, and errors.
2296
- *
2297
- * Uses the same duck-typed interface pattern as other xNet packages to
2298
- * avoid circular dependencies with @xnetjs/telemetry.
405
+ * Compute low-cardinality facets over loaded schema query rows.
2299
406
  */
407
+ declare function deriveSavedViewFacetSummaries(rows: readonly Record<string, unknown>[], columns: readonly string[]): SavedViewFacetSummary[];
2300
408
  /**
2301
- * Duck-typed interface for telemetry reporting.
2302
- * Satisfied by @xnetjs/telemetry's TelemetryCollector or any compatible object.
2303
- *
2304
- * @example
2305
- * ```ts
2306
- * import { TelemetryCollector } from '@xnetjs/telemetry'
2307
- * const telemetry = new TelemetryCollector({ consent })
2308
- * // Pass to XNetProvider via config.telemetry
2309
- * ```
409
+ * Filter loaded schema query rows by facet value keys.
2310
410
  */
2311
- interface TelemetryReporter {
2312
- reportPerformance(metricName: string, durationMs: number): void;
2313
- reportUsage(metricName: string, count: number): void;
2314
- reportCrash(error: Error, context?: Record<string, unknown>): void;
2315
- }
2316
- declare const TelemetryContext: react.Context<TelemetryReporter | null>;
411
+ declare function filterSavedViewRowsByFacets<T extends Record<string, unknown>>(rows: readonly T[], selection: SavedViewFacetSelection): T[];
2317
412
  /**
2318
- * Hook to access the telemetry reporter (null if no telemetry configured).
2319
- * @internal Used by useQuery/useMutate - not part of public API.
413
+ * Compute date buckets over loaded schema query rows.
2320
414
  */
2321
- declare function useTelemetryReporter(): TelemetryReporter | null;
2322
-
415
+ declare function deriveSavedViewDateBucketSummaries(rows: readonly Record<string, unknown>[], columns: readonly string[]): SavedViewDateBucketFieldSummary[];
2323
416
  /**
2324
- * XNet React context provider
2325
- *
2326
- * Provides NodeStore and optional identity to the React tree.
2327
- * All data access happens through useQuery/useMutate/useNode hooks.
417
+ * Filter loaded schema query rows by a selected date bucket brush.
2328
418
  */
2329
-
419
+ declare function filterSavedViewRowsByDateBrush<T extends Record<string, unknown>>(rows: readonly T[], selection: SavedViewDateBrushSelection): T[];
2330
420
  /**
2331
- * XNet configuration
421
+ * Build a generic row inspector model from a flattened saved-view result row.
2332
422
  */
2333
- interface XNetConfig {
2334
- /** Node storage adapter for NodeStore (defaults to MemoryNodeStorageAdapter) */
2335
- nodeStorage?: NodeStorageAdapter;
2336
- /** Author's DID for signing changes */
2337
- authorDID?: DID;
2338
- /** Ed25519 signing key */
2339
- signingKey?: Uint8Array;
2340
- /** User identity */
2341
- identity?: Identity;
2342
- /** Signaling server URLs for sync (default: ['ws://localhost:4444']) */
2343
- signalingServers?: string[];
2344
- /** Hub WebSocket URL for always-on sync (overrides signalingServers[0]) */
2345
- hubUrl?: string;
2346
- /** Hub integration options */
2347
- hubOptions?: {
2348
- /** Auto-generate UCAN for hub auth (default: true) */
2349
- autoAuth?: boolean;
2350
- /** Static UCAN token override for pre-authorized share sessions */
2351
- authToken?: string;
2352
- /** Enable auto-backup on document updates (default: false) */
2353
- autoBackup?: boolean;
2354
- /** Backup debounce delay in ms (default: 5000) */
2355
- backupDebounceMs?: number;
2356
- /** Enable search indexing on NodeStore changes (default: false) */
2357
- enableSearchIndex?: boolean;
2358
- /** Room name for node-change relay (defaults to author DID) */
2359
- nodeSyncRoom?: string;
2360
- };
2361
- /** Encryption key for hub backups (XChaCha20-Poly1305) */
2362
- encryptionKey?: Uint8Array;
2363
- /** Disable Background Sync Manager (default: false) */
2364
- disableSyncManager?: boolean;
2365
- /** Provide an external SyncManager (e.g., IPC-based for Electron desktop).
2366
- * When provided, the internal SyncManager creation is skipped. */
2367
- syncManager?: SyncManager;
2368
- /** Blob store for P2P blob sync (images, files). If provided, the SyncManager
2369
- * will sync blobs alongside Y.Doc state. Typically a BlobStore from @xnetjs/storage. */
2370
- blobStore?: BlobStoreForSync;
2371
- /** Platform for plugin compatibility ('web' | 'electron' | 'mobile'). Defaults to 'web'. */
2372
- platform?: Platform;
2373
- /** Disable plugin system (default: false) */
2374
- disablePlugins?: boolean;
2375
- /**
2376
- * Custom DataBridge instance.
2377
- *
2378
- * When provided, this bridge is used for data access instead of creating
2379
- * a MainThreadBridge. This allows using WorkerBridge or other off-main-thread
2380
- * implementations.
2381
- *
2382
- * The bridge must already be initialized before passing to XNetProvider.
2383
- *
2384
- * Note: When using a custom bridge, NodeStore is still created on the main
2385
- * thread for SyncManager and other integrations. The custom bridge is used
2386
- * only for React hook data access (useQuery, useMutate).
2387
- *
2388
- * @example
2389
- * ```tsx
2390
- * // Using WorkerBridge
2391
- * const bridge = new WorkerBridge(workerUrl)
2392
- * await bridge.initialize({ authorDID, signingKey, dbName: 'xnet' })
2393
- *
2394
- * <XNetProvider config={{ dataBridge: bridge, ... }}>
2395
- * <App />
2396
- * </XNetProvider>
2397
- * ```
2398
- */
2399
- dataBridge?: DataBridge;
2400
- /**
2401
- * Security configuration for multi-level cryptography.
2402
- */
2403
- security?: {
2404
- /** Default security level for new signatures (default: 0 for Ed25519-only) */
2405
- level?: SecurityLevel;
2406
- /** Minimum acceptable level for verification (default: 0) */
2407
- minVerificationLevel?: SecurityLevel;
2408
- /** Verification policy (default: 'strict') */
2409
- verificationPolicy?: 'strict' | 'permissive';
2410
- /** Custom PQ key registry */
2411
- registry?: PQKeyRegistry;
2412
- };
2413
- /**
2414
- * Hybrid key bundle for multi-level cryptography.
2415
- *
2416
- * When provided, enables signing at higher security levels (1, 2).
2417
- * The bundle includes Ed25519 keys and optionally ML-DSA (post-quantum) keys.
2418
- *
2419
- * @example
2420
- * ```tsx
2421
- * const bundle = createKeyBundle({ includePQ: true })
2422
- *
2423
- * <XNetProvider config={{ keyBundle: bundle, ... }}>
2424
- * <App />
2425
- * </XNetProvider>
2426
- * ```
2427
- */
2428
- keyBundle?: HybridKeyBundle;
2429
- /**
2430
- * Optional telemetry reporter for hook instrumentation.
2431
- *
2432
- * When provided, useQuery and useMutate hooks will report:
2433
- * - Query timing (first-load latency)
2434
- * - Cache hit/miss rates
2435
- * - Mutation success/failure rates
2436
- * - Subscription churn (mount/unmount frequency)
2437
- *
2438
- * Uses a duck-typed interface to avoid circular dependencies with @xnetjs/telemetry.
2439
- *
2440
- * @example
2441
- * ```tsx
2442
- * import { TelemetryCollector, ConsentManager } from '@xnetjs/telemetry'
2443
- * const consent = new ConsentManager()
2444
- * const telemetry = new TelemetryCollector({ consent })
2445
- *
2446
- * <XNetProvider config={{ telemetry, ... }}>
2447
- * <App />
2448
- * </XNetProvider>
2449
- * ```
2450
- */
2451
- telemetry?: TelemetryReporter;
2452
- }
423
+ declare function deriveSavedViewRowInspector(row: Record<string, unknown>, query?: SavedViewQueryResult | null): SavedViewRowInspectorModel;
2453
424
  /**
2454
- * XNet context value
425
+ * Derive privacy class chips for the active saved-view result.
2455
426
  */
2456
- interface XNetContextValue {
2457
- /** NodeStore for Node operations */
2458
- nodeStore: NodeStore | null;
2459
- /** Whether NodeStore is initialized */
2460
- nodeStoreReady: boolean;
2461
- /** User identity (if provided) */
2462
- identity?: Identity;
2463
- /** Author DID (resolved from config.authorDID or config.identity.did) */
2464
- authorDID: string | null;
2465
- /** Background Sync Manager (null if disabled or not yet initialized) */
2466
- syncManager: SyncManager | null;
2467
- /** Hub URL (if configured) */
2468
- hubUrl: string | null;
2469
- /** Hub connection status */
2470
- hubStatus: SyncStatus;
2471
- /** Hub connection (shares SyncManager connection when available) */
2472
- hubConnection: ConnectionManager | null;
2473
- /** Hub auth token provider (for HTTP requests) */
2474
- getHubAuthToken?: () => Promise<string>;
2475
- /** Encryption key for hub backups */
2476
- encryptionKey: Uint8Array | null;
2477
- /** Blob store for content-addressed storage (null if not configured) */
2478
- blobStore: BlobStoreForSync | null;
2479
- /** Plugin Registry (null if disabled or not yet initialized) */
2480
- pluginRegistry: PluginRegistry | null;
2481
- }
427
+ declare function deriveSavedViewPrivacyChips(query: SavedViewQueryResult | null): SavedViewPrivacyChip[];
2482
428
  /**
2483
- * XNet provider props
429
+ * Return a user-facing warning when loaded rows contain non-public data.
2484
430
  */
2485
- interface XNetProviderProps {
2486
- config: XNetConfig;
2487
- children: ReactNode;
2488
- }
431
+ declare function getSavedViewSensitiveResultWarning(query: SavedViewQueryResult | null): string | null;
2489
432
  /**
2490
- * XNet provider component
2491
- *
2492
- * Initializes NodeStore and provides it to the React tree.
433
+ * Build a persisted saved-view descriptor from the current table control state.
2493
434
  */
2494
- declare function XNetProvider({ config, children }: XNetProviderProps): JSX.Element;
435
+ declare function createSavedViewLensDraft(input: {
436
+ descriptor: SavedViewDescriptor;
437
+ queryId: string;
438
+ query: SavedViewQueryResult;
439
+ facetSelection: SavedViewFacetSelection;
440
+ dateBrushSelection: SavedViewDateBrushSelection;
441
+ sortField: string;
442
+ sortDirection: SavedViewSortDirection;
443
+ pageSize: number;
444
+ title?: string | null;
445
+ description?: string | null;
446
+ }): SavedViewLensDraft | null;
447
+ declare function SavedViewRunner({ descriptor, registry, title, description, fallbackId, resetKey, className, emptyLabel, pageSizes, initialPageSize, options: baseOptions, onSaveLens, saveLensLabel, onOpenVisualCanvasProjection, feedEnrichment, wrapItem }: SavedViewRunnerProps): JSX.Element;
448
+ declare function createSavedViewVisualCanvasProjectionRequest(input: {
449
+ descriptor?: SavedViewDescriptor | string | null;
450
+ title: string;
451
+ description?: string | null;
452
+ sourceQueryId?: string | null;
453
+ sourceSchemaId?: string | null;
454
+ layout: SavedViewVisualLayoutOption;
455
+ previews: readonly SavedViewVisualPreviewModel[];
456
+ nodes: readonly SavedViewCanvasProjectionNode[];
457
+ }): SavedViewVisualCanvasProjectionRequest;
458
+ declare function SavedViewResultTable({ query, columns, expandedRowId, onToggleRow, loadingLabel, emptyLabel, formatValue }: SavedViewResultTableProps): JSX.Element;
459
+
2495
460
  /**
2496
- * Hook to access XNet context
461
+ * useCanvasTaskSync - Reconcile canvas checklist items with Task nodes.
2497
462
  *
2498
- * @internal Used by useIdentity. Not part of public API.
463
+ * Canvas checklist objects are an editing projection just like page
464
+ * checklists: every item is backed by a canonical Task node (source:
465
+ * 'canvas', `canvas` relation = hosting canvas, anchorBlockId = the
466
+ * checklist object id). Items removed from the canvas archive their nodes;
467
+ * items pasted from elsewhere claim them. Semantics in
468
+ * docs/specs/PAGE_TASK_RECONCILIATION.md.
2499
469
  */
2500
- declare function useXNet(): XNetContextValue;
470
+
471
+ type CanvasTaskInput = TaskProjectionInput;
472
+ interface UseCanvasTaskSyncOptions {
473
+ canvasId: string | null;
474
+ debounceMs?: number;
475
+ }
476
+ type UseCanvasTaskSyncResult = UseTaskProjectionSyncResult;
477
+ declare function useCanvasTaskSync({ canvasId, debounceMs }: UseCanvasTaskSyncOptions): UseCanvasTaskSyncResult;
2501
478
 
2502
479
  /**
2503
- * Security context for multi-level cryptography.
480
+ * useGridDatabase - The V2 database hook (exploration 0159).
481
+ *
482
+ * One subscription path: fields, views, select options, and rows are all
483
+ * nodes read through useQuery (DataBridge → SQLite, with materialized view
484
+ * caching and full-text search). View nodes are the single source of truth
485
+ * for sort/filter/layout — there is no mirrored React state to drift.
2504
486
  *
2505
- * Provides global security configuration and state management for:
2506
- * - Security level selection (0, 1, 2)
2507
- * - Verification policy configuration
2508
- * - PQ key registry access
2509
- * - Key bundle management
487
+ * Replaces the legacy useDatabase/useDatabaseDoc pair (Y.Doc columns/views,
488
+ * 10× over-fetch, client-side pipeline over the whole table).
2510
489
  */
2511
490
 
2512
- /**
2513
- * Security context state.
2514
- */
2515
- interface SecurityContextState {
2516
- /** Current security level for new signatures */
2517
- level: SecurityLevel;
2518
- /** Minimum level to accept during verification */
2519
- minVerificationLevel: SecurityLevel;
2520
- /** Verification policy */
2521
- verificationPolicy: 'strict' | 'permissive';
2522
- /** PQ key registry */
2523
- registry: PQKeyRegistry;
2524
- /** Current key bundle (if available) */
2525
- keyBundle?: HybridKeyBundle;
491
+ interface GridFieldModel {
492
+ id: string;
493
+ name: string;
494
+ type: FieldType;
495
+ config: FieldConfig;
496
+ sortKey: string;
497
+ width: number;
498
+ isTitle?: boolean;
499
+ hidden?: boolean;
500
+ options?: GridOptionModel[];
2526
501
  }
2527
- /**
2528
- * Security context actions.
2529
- */
2530
- interface SecurityContextActions {
2531
- /** Set the signing security level */
2532
- setLevel: (level: SecurityLevel) => void;
2533
- /** Set the minimum verification level */
2534
- setMinVerificationLevel: (level: SecurityLevel) => void;
2535
- /** Set the verification policy */
2536
- setVerificationPolicy: (policy: 'strict' | 'permissive') => void;
2537
- /** Update the key bundle */
2538
- setKeyBundle: (bundle: HybridKeyBundle | undefined) => void;
502
+ interface GridOptionModel {
503
+ id: string;
504
+ field: string;
505
+ name: string;
506
+ color?: string;
507
+ sortKey: string;
2539
508
  }
2540
- /**
2541
- * Combined security context value.
2542
- */
2543
- type SecurityContextValue = SecurityContextState & SecurityContextActions;
2544
- /**
2545
- * Security provider props.
2546
- */
2547
- interface SecurityProviderProps {
2548
- children: ReactNode;
2549
- /** Initial security level (default: 0 for Ed25519-only) */
2550
- level?: SecurityLevel;
2551
- /** Initial minimum verification level (default: 0) */
2552
- minVerificationLevel?: SecurityLevel;
2553
- /** Initial verification policy (default: 'strict') */
2554
- verificationPolicy?: 'strict' | 'permissive';
2555
- /** PQ key registry (default: MemoryPQKeyRegistry) */
2556
- registry?: PQKeyRegistry;
2557
- /** Initial key bundle */
2558
- keyBundle?: HybridKeyBundle;
509
+ interface GridViewModel {
510
+ id: string;
511
+ name: string;
512
+ type: ViewType;
513
+ filters: FilterGroup | null;
514
+ sorts: SortConfig[];
515
+ groupBy: string | null;
516
+ collapsedGroups: string[];
517
+ fieldOrder: Record<string, string>;
518
+ fieldWidths: Record<string, number>;
519
+ hiddenFields: string[];
520
+ rowHeight: RowHeight;
521
+ columnSummaries: Record<string, SummaryFunction>;
522
+ sortKey: string;
523
+ }
524
+ interface GridRowModel {
525
+ id: string;
526
+ sortKey: string;
527
+ cells: Record<string, CellValue>;
528
+ }
529
+ interface UseGridDatabaseOptions {
530
+ /** Active view ID (defaults to the first view) */
531
+ viewId?: string;
532
+ /** Quick-find text (full-text search via SQLite FTS) */
533
+ search?: string;
534
+ /** Row window size (default 500) */
535
+ pageSize?: number;
536
+ }
537
+ interface UseGridDatabaseResult {
538
+ /** Database node (flattened) */
539
+ database: {
540
+ id: string;
541
+ title?: string;
542
+ icon?: string;
543
+ } | null;
544
+ /** All fields, database order */
545
+ fields: GridFieldModel[];
546
+ /** Fields for the active view: order overrides applied, hidden removed */
547
+ visibleFields: GridFieldModel[];
548
+ /** All views, tab order */
549
+ views: GridViewModel[];
550
+ activeView: GridViewModel | null;
551
+ /** Rows: view filters + sorts applied to the fetched window */
552
+ rows: GridRowModel[];
553
+ loading: boolean;
554
+ updateCell: (rowId: string, fieldId: string, value: CellValue) => Promise<void>;
555
+ clearCells: (cells: Array<{
556
+ rowId: string;
557
+ fieldId: string;
558
+ }>) => Promise<void>;
559
+ addRow: (afterRowId?: string, cells?: Record<string, CellValue>) => Promise<string | null>;
560
+ deleteRows: (rowIds: string[]) => Promise<void>;
561
+ moveRowToIndex: (rowId: string, targetIndex: number) => Promise<void>;
562
+ addField: (name: string, type: FieldType, config?: FieldConfig, opts?: {
563
+ isTitle?: boolean;
564
+ width?: number;
565
+ }) => Promise<string | null>;
566
+ renameField: (fieldId: string, name: string) => Promise<void>;
567
+ updateFieldConfig: (fieldId: string, config: FieldConfig) => Promise<void>;
568
+ changeFieldType: (fieldId: string, type: FieldType) => Promise<void>;
569
+ removeField: (fieldId: string) => Promise<void>;
570
+ moveFieldToIndex: (fieldId: string, targetIndex: number) => Promise<void>;
571
+ resizeField: (fieldId: string, width: number) => Promise<void>;
572
+ setFieldHidden: (fieldId: string, hidden: boolean) => Promise<void>;
573
+ createOption: (fieldId: string, name: string) => Promise<string | null>;
574
+ toggleSort: (fieldId: string) => Promise<void>;
575
+ setFilters: (filters: FilterGroup | null) => Promise<void>;
576
+ setGroupBy: (fieldId: string | null) => Promise<void>;
577
+ setRowHeight: (rowHeight: RowHeight) => Promise<void>;
578
+ setColumnSummary: (fieldId: string, fn: SummaryFunction) => Promise<void>;
579
+ addView: (name: string, type: ViewType) => Promise<string | null>;
580
+ renameView: (viewId: string, name: string) => Promise<void>;
581
+ removeView: (viewId: string) => Promise<void>;
582
+ undo: () => Promise<boolean>;
583
+ redo: () => Promise<boolean>;
584
+ canUndo: boolean;
585
+ canRedo: boolean;
2559
586
  }
587
+ declare function useGridDatabase(databaseId: string, options?: UseGridDatabaseOptions): UseGridDatabaseResult;
588
+
2560
589
  /**
2561
- * Security provider component.
2562
- *
2563
- * Wraps the application with security configuration and state.
590
+ * useGlobalUndo - app-wide Cmd+Z (exploration 0179)
2564
591
  *
2565
- * @example
2566
- * ```tsx
2567
- * <SecurityProvider level={1} verificationPolicy="strict">
2568
- * <App />
2569
- * </SecurityProvider>
2570
- * ```
2571
- */
2572
- declare function SecurityProvider({ children, level: initialLevel, minVerificationLevel: initialMinLevel, verificationPolicy: initialPolicy, registry: providedRegistry, keyBundle: initialBundle }: SecurityProviderProps): JSX.Element;
2573
- /**
2574
- * Hook to access security context.
592
+ * Reads the single app-level UndoManager from XNetProvider context and
593
+ * exposes undo/redo backed by undoLatest()/redoLatest(), so one keybinding
594
+ * reverses the most recent action across every node-backed surface —
595
+ * folders, tasks, databases, chat, settings — without the caller caring
596
+ * which surface produced it.
2575
597
  *
2576
- * @throws Error if used outside of SecurityProvider
598
+ * Rich-text editing (TipTap) and the canvas keep their own document-scoped
599
+ * undo and claim Cmd+Z while focused via the command registry's scope
600
+ * stack; this hook is the fallthrough for everything else.
2577
601
  *
2578
602
  * @example
2579
603
  * ```tsx
2580
- * function MyComponent() {
2581
- * const { level, setLevel, registry } = useSecurityContext()
2582
- * // ...
2583
- * }
604
+ * const { undo, redo, canUndo, canRedo } = useGlobalUndo()
605
+ * registry.register({ id: 'edit.undo', key: 'Mod-Z', run: () => void undo() })
2584
606
  * ```
2585
607
  */
2586
- declare function useSecurityContext(): SecurityContextValue;
2587
- /**
2588
- * Hook to optionally access security context.
2589
- *
2590
- * Returns null if used outside of SecurityProvider (no error thrown).
2591
- */
2592
- declare function useSecurityContextOptional(): SecurityContextValue | null;
608
+ interface UseGlobalUndoResult {
609
+ /** Reverse the most recent local action across all node-backed surfaces */
610
+ undo: () => Promise<boolean>;
611
+ /** Re-apply the most recently undone action */
612
+ redo: () => Promise<boolean>;
613
+ /** Whether anything is undoable right now */
614
+ canUndo: boolean;
615
+ /** Whether anything is redoable right now */
616
+ canRedo: boolean;
617
+ }
618
+ declare function useGlobalUndo(): UseGlobalUndoResult;
2593
619
 
2594
620
  /**
2595
- * useSecurity - Hook for security-aware operations.
621
+ * useBilling reactive billing state + checkout, the same shape as `useIdentity`.
622
+ *
623
+ * Reads the caller's own DID-scoped billing from the hub (`GET /billing/me`) and
624
+ * exposes `openCheckout` / `openPortal`, which call the hub (secret key stays
625
+ * server-side) and redirect to the returned hosted URL. The client needs no
626
+ * Stripe secret — only the hub URL it already has. See exploration 0187.
2596
627
  *
2597
- * Provides signing and verification functions that use the current
2598
- * security level from the SecurityContext.
628
+ * Types come from `@xnetjs/billing` as a type-only import, so nothing pulls
629
+ * `node:crypto`/the provider adapters into the browser bundle.
2599
630
  */
2600
631
 
2601
- /**
2602
- * Options for useSecurity hook.
2603
- */
2604
- interface UseSecurityOptions {
2605
- /** Override default security level for this hook instance */
2606
- level?: SecurityLevel;
632
+ interface CheckoutOptions {
633
+ /** `subscription` (default) for recurring, `payment` for one-shot (e.g. Bitcoin). */
634
+ mode?: 'subscription' | 'payment';
635
+ successUrl?: string;
636
+ cancelUrl?: string;
637
+ customerEmail?: string;
2607
638
  }
2608
- /**
2609
- * Return type for useSecurity hook.
2610
- */
2611
- interface UseSecurityResult {
2612
- /** Current security level (from context or override) */
2613
- level: SecurityLevel;
2614
- /** Whether the current key bundle has PQ keys */
2615
- hasPQKeys: boolean;
2616
- /** Maximum level supported by current keys (0 if no PQ keys, 2 if PQ keys present) */
2617
- maxLevel: SecurityLevel;
2618
- /** Sign data at current security level */
2619
- sign: (data: Uint8Array) => UnifiedSignature;
2620
- /** Verify a signature against a DID */
2621
- verify: (data: Uint8Array, signature: UnifiedSignature, did: DID) => Promise<VerificationResult$1>;
2622
- /** Set the global security level */
2623
- setLevel: (level: SecurityLevel) => void;
2624
- /** Check if a level is supported by current keys */
2625
- canSignAt: (level: SecurityLevel) => boolean;
2626
- /** Check if key bundle is available */
2627
- hasKeyBundle: boolean;
639
+ interface UseBillingResult {
640
+ /** The most relevant subscription (active/trialing first), or null. */
641
+ subscription: Subscription | null;
642
+ /** True when the subscription is active or trialing. */
643
+ isActive: boolean;
644
+ /** The active subscription's price/plan ref, or null. */
645
+ plan: string | null;
646
+ status: Subscription['status'] | null;
647
+ customer: Customer | null;
648
+ subscriptions: Subscription[];
649
+ invoices: Invoice[];
650
+ payments: Payment[];
651
+ loading: boolean;
652
+ error: Error | null;
653
+ /** Re-fetch billing state from the hub. */
654
+ reload: () => Promise<void>;
655
+ /** Start hosted checkout for a price/plan and redirect to it. */
656
+ openCheckout: (priceRef: string, options?: CheckoutOptions) => Promise<void>;
657
+ /** Open the provider's customer portal (Stripe) and redirect to it. */
658
+ openPortal: (returnUrl?: string) => Promise<void>;
659
+ /** Stripe publishable key, if configured (for future embedded checkout). */
660
+ publishableKey: string | null;
2628
661
  }
2629
- /**
2630
- * Hook for security-aware operations.
2631
- *
2632
- * Provides signing and verification functions that use the current
2633
- * security level from the SecurityContext.
2634
- *
2635
- * @example
2636
- * ```tsx
2637
- * function SignedMessage() {
2638
- * const { sign, verify, level, hasPQKeys } = useSecurity()
2639
- *
2640
- * const handleSign = async () => {
2641
- * const data = new TextEncoder().encode('Hello')
2642
- * const sig = sign(data)
2643
- * console.log(`Signed at Level ${sig.level}`)
2644
- * }
2645
- *
2646
- * return (
2647
- * <div>
2648
- * <p>Security Level: {level}</p>
2649
- * <p>PQ Keys: {hasPQKeys ? 'Yes' : 'No'}</p>
2650
- * <button onClick={handleSign}>Sign</button>
2651
- * </div>
2652
- * )
2653
- * }
2654
- * ```
2655
- *
2656
- * @example Per-operation level override
2657
- * ```tsx
2658
- * function HighSecurityOperation() {
2659
- * const { sign } = useSecurity({ level: 2 }) // Force Level 2
2660
- *
2661
- * const handleCritical = () => {
2662
- * const data = new TextEncoder().encode('Critical operation')
2663
- * const sig = sign(data) // Signs at Level 2
2664
- * console.log(sig.level) // 2
2665
- * }
2666
- *
2667
- * return <button onClick={handleCritical}>Critical Action</button>
2668
- * }
2669
- * ```
2670
- *
2671
- * @example Fast mode for high-frequency operations
2672
- * ```tsx
2673
- * function CursorUpdates() {
2674
- * const { sign } = useSecurity({ level: 0 }) // Fast Ed25519-only
2675
- *
2676
- * const handleCursor = (position: number) => {
2677
- * const data = new TextEncoder().encode(JSON.stringify({ position }))
2678
- * const sig = sign(data) // Fast signing
2679
- * }
2680
- *
2681
- * return <canvas onMouseMove={(e) => handleCursor(e.clientX)} />
2682
- * }
2683
- * ```
2684
- */
2685
- declare function useSecurity(options?: UseSecurityOptions): UseSecurityResult;
662
+ declare function useBilling(): UseBillingResult;
2686
663
 
2687
664
  /**
2688
- * Plugin registry context
2689
- */
2690
- declare const PluginRegistryContext: react.Context<PluginRegistry | null>;
2691
- /**
2692
- * Access the PluginRegistry instance
2693
- *
2694
- * @example
2695
- * ```tsx
2696
- * const registry = usePluginRegistry()
2697
- * const plugins = registry.getAll()
2698
- * ```
2699
- *
2700
- * @throws Error if used outside of XNetProvider with plugins enabled
2701
- */
2702
- declare function usePluginRegistry(): PluginRegistry;
2703
- /**
2704
- * Safely access the PluginRegistry instance, returns null if not available
2705
- *
2706
- * Use this when you need to optionally access the plugin system without throwing.
2707
- */
2708
- declare function usePluginRegistryOptional(): PluginRegistry | null;
2709
- /**
2710
- * Get all registered plugins with reactive updates
2711
- *
2712
- * @example
2713
- * ```tsx
2714
- * const plugins = usePlugins()
2715
- * // Re-renders when plugins change
2716
- * ```
2717
- */
2718
- declare function usePlugins(): RegisteredPlugin[];
2719
- /**
2720
- * Contribution type to interface mapping
665
+ * @xnetjs/react - Pure helpers for rendering a page's task tree as a
666
+ * flat list of rows. Shared by the in-page task panel and host apps
667
+ * that render page tasks in their own chrome (e.g. the web context
668
+ * panel).
2721
669
  */
2722
- type ContributionTypeMap = {
2723
- views: ViewContribution;
2724
- commands: CommandContribution;
2725
- slashCommands: SlashCommandContribution;
2726
- sidebar: SidebarContribution;
2727
- editor: EditorContribution;
2728
- propertyHandlers: PropertyHandlerContribution;
2729
- blocks: BlockContribution;
2730
- settings: SettingContribution;
670
+
671
+ type RenderableTaskRow = {
672
+ id: string;
673
+ title: string;
674
+ completed: boolean;
675
+ dueDate: number | undefined;
676
+ depth: number;
677
+ assigneeCount: number;
2731
678
  };
2732
- /**
2733
- * Get contributions of a specific type with reactive updates
2734
- *
2735
- * @example
2736
- * ```tsx
2737
- * // Get all registered views
2738
- * const views = useContributions('views')
2739
- *
2740
- * // Get all commands
2741
- * const commands = useContributions('commands')
2742
- * ```
2743
- */
2744
- declare function useContributions<K extends keyof ContributionTypeMap>(type: K): ContributionTypeMap[K][];
2745
- /**
2746
- * Get all registered views
2747
- */
2748
- declare function useViews(): ViewContribution[];
2749
- /**
2750
- * Get all registered commands
2751
- */
2752
- declare function useCommands(): CommandContribution[];
2753
- /**
2754
- * Get all registered slash commands
2755
- */
2756
- declare function useSlashCommands(): SlashCommandContribution[];
2757
- /**
2758
- * Get all registered sidebar items
2759
- */
2760
- declare function useSidebarItems(): SidebarContribution[];
2761
- /**
2762
- * Get all registered editor extensions
2763
- *
2764
- * @throws Error if plugin system is not enabled
2765
- */
2766
- declare function useEditorExtensions(): EditorContribution[];
2767
- /**
2768
- * Get all registered editor extensions, returns empty array if plugin system is not available
2769
- *
2770
- * Safe version that doesn't throw if plugins aren't enabled.
2771
- */
2772
- declare function useEditorExtensionsSafe(): EditorContribution[];
2773
- /**
2774
- * Get a specific view by type
2775
- */
2776
- declare function useView(type: string): ViewContribution | undefined;
2777
- /**
2778
- * Get a specific command by ID
2779
- */
2780
- declare function useCommand(id: string): CommandContribution | undefined;
679
+ declare function flattenTaskTree(items: TaskTreeItem[], depth?: number): RenderableTaskRow[];
680
+ declare function formatTaskDueDate(timestamp: number | undefined): string | null;
681
+ declare function isTaskOverdue(timestamp: number | undefined, completed: boolean): boolean;
2781
682
 
2782
- export { type AddCommentOptions, AuthErrorScreen, AuthenticatingScreen, type BlobStoreForSync, type CommentNode, type CommentThread, type ConnectionManager, type ConnectionManagerConfig, type ConnectionStatus, type DatabaseRow, type DatabaseRowData, DemoBanner, type DemoBannerProps, DemoDataExpiredScreen, type DemoLimits, type DemoModeState, DemoQuotaIndicator, type DemoQuotaIndicatorProps, type DemoUsage, type DiscoveredPeer, ErrorBoundary, type ErrorBoundaryProps, type FileRef, type FlatNode, type FlattenNodeOptions, type GrantInput, HubConnectScreen, type HubSearchOptions, type HubSearchResult, type HubSearchState, HubStatusIndicator, ImportIdentityScreen, type InitialSyncManager, type InitialSyncMessage, METABRIDGE_ORIGIN, METABRIDGE_SEED_ORIGIN, type MetaBridge, type MigrationWarning, type MutateCreate, type MutateDelete, type MutateOp, type MutateRestore, type MutateUpdate, type NodePool, type NodePoolConfig, NodeStoreSyncProvider, type NodeSyncResponse, OfflineIndicator, type OfflineIndicatorProps, type OfflineQueue, type OfflineQueueConfig, type OnboardingContextValue, type OnboardingEvent, OnboardingFlow, type OnboardingFlowProps, type OnboardingMachineContext, OnboardingProvider, type OnboardingProviderProps, type OnboardingReducerState, type OnboardingState, PluginRegistryContext, type PoolEntryState, type PresenceUser, type ProgressListener, QUICK_START_TEMPLATES, type QueryFilter, type QueryListResult, type QuerySingleResult, type QueueEntry, type QuickStartTemplate, ReadyScreen, type Registry, type RegistryConfig, type RegistryStorage, type RemoteSchemaDefinition, type RemoteSchemaState, type ReplyContext, type ReverseRelation, type SecurityContextActions, type SecurityContextState, type SecurityContextValue, SecurityProvider, type SecurityProviderProps, type SerializedNodeChange, Skeleton, type SkeletonProps, SmartWelcome, type SortDirection, type SyncManager, type SyncManagerConfig, type SyncStatus as SyncManagerStatus, type SyncPhase, type SyncProgress, SyncProgressOverlay, type SyncProgressOverlayProps, type SyncStatus$1 as SyncStatus, TelemetryContext, type TelemetryReporter, type TrackedNode, UnsupportedBrowserScreen, type UseAuditOptions, type UseAuditResult, type UseBackupReturn, type UseBlameResult, type UseCanEditResult, type UseCanResult, type UseCellOptions, type UseCellResult, type UseCommentsOptions, type UseCommentsResult, type UseDatabaseDocResult, type UseDatabaseOptions, type UseDatabaseResult, type UseDatabaseRowResult, type UseDatabaseSchemaResult, type UseDiffResult, type UseFileUploadReturn, type UseGrantsResult, type UseHistoryResult, type UseIdentityResult, type UseMutateResult, type UseNodeOptions, type UseNodeResult, type UseRelatedRowsResult, type UseReverseRelationsResult, type UseSecurityOptions, type UseSecurityResult, type UseUndoOptions, type UseUndoResult, type UseVerificationResult, WebSocketSyncProvider, type WebSocketSyncProviderOptions, WelcomeScreen, type XNetConfig, type XNetContextValue, XNetProvider, type XNetProviderProps, copyToClipboard, createConnectionManager, createInitialState, createInitialSyncManager, createMetaBridge, createNodePool, createOfflineQueue, createRegistry, createSyncManager, flattenNode, flattenNodes, flattenNodesWithSchemaCheck, flattenUnknownSchemaNode, getPlatformAuthName, injectSkeletonStyles, onboardingReducer, truncateDid, useAudit, useBackup, useBlame, useCan, useCanEdit, useCell, useCommand, useCommands, useCommentCount, useCommentCounts, useComments, useContributions, useDatabase, useDatabaseDoc, useDatabaseRow, useDatabaseSchema, useDemoMode, useDiff, useEditorExtensions, useEditorExtensionsSafe, useFileUpload, useGrants, useHistory, useHubSearch, useHubStatus, useIdentity, useIsOffline, useMutate, useNode, useOnboarding, usePeerDiscovery, usePluginRegistry, usePluginRegistryOptional, usePlugins, useQuery, useRelatedRows, useRemoteSchema, useReverseRelations, useSecurity, useSecurityContext, useSecurityContextOptional, useSidebarItems, useSlashCommands, useSyncManager, useTelemetryReporter, useUndo, useVerification, useView, useViews, useXNet };
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 };