@datafn/client 0.0.1

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/README.md ADDED
@@ -0,0 +1,199 @@
1
+ # @datafn/client
2
+
3
+ A comprehensive, offline-first client for DataFn with reactive signals, event bus, and synchronization support.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @datafn/client @datafn/core
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - **Fluent Table API**: Ergonomic interface for querying and mutating specific resources.
14
+ - **Reactive Signals**: Subscribable data sources that automatically update on changes (perfect for UI binding).
15
+ - **Offline Storage**: Built-in support for persistent storage (IndexedDB, Memory) with hydration.
16
+ - **Synchronization**: Integrated `clone`, `pull`, and `push` mechanisms that automatically update local storage.
17
+ - **Event Bus**: Global event system for mutations, sync lifecycle, and error handling.
18
+ - **Transaction Support**: Atomic operations across multiple resources.
19
+ - **Plugins**: Extensible architecture for custom behavior.
20
+ - **Type-Safe**: Built with TypeScript for full type inference.
21
+
22
+ ## Quick Start
23
+
24
+ ```typescript
25
+ import { createDatafnClient, IndexedDbStorageAdapter } from "@datafn/client";
26
+
27
+ // 1. Configure the client
28
+ const client = createDatafnClient({
29
+ clientId: "device-uuid-123", // Required for offline/sync
30
+ schema: mySchema, // Your DataFn schema definition
31
+ storage: new IndexedDbStorageAdapter("my-app-db"), // Persist data locally
32
+ remote: {
33
+ // Your network layer (fetch, axios, etc.) to talk to DataFn server
34
+ async query(q) { /* ... */ },
35
+ async mutation(m) { /* ... */ },
36
+ async pull(p) { /* ... */ },
37
+ // ... other methods
38
+ },
39
+ });
40
+
41
+ // 2. Work with a specific table (Resource)
42
+ const tasks = client.table("task");
43
+
44
+ // 3. Create a reactive signal (Auto-updates when data changes)
45
+ const activeTasksSignal = tasks.signal({
46
+ select: ["id", "title"],
47
+ filters: { completed: false }
48
+ });
49
+
50
+ // Subscribe to changes
51
+ const unsubscribe = activeTasksSignal.subscribe((data) => {
52
+ console.log("Active tasks:", data);
53
+ });
54
+
55
+ // 4. Mutate data (Optimistic updates & Event emission)
56
+ await tasks.mutate({
57
+ operation: "insert",
58
+ record: { title: "New Task", completed: false }
59
+ });
60
+ // -> activeTasksSignal listeners are automatically notified!
61
+ ```
62
+
63
+ ## Core Concepts
64
+
65
+ ### 1. The Client Instance
66
+
67
+ The client is the central hub. It coordinates the **Schema**, **Storage**, **Remote** adapter, and **Event Bus**.
68
+
69
+ ```typescript
70
+ const client = createDatafnClient({
71
+ schema: DatafnSchema;
72
+ remote: DatafnRemoteAdapter;
73
+ storage?: DatafnStorageAdapter; // Optional: Enable offline mode
74
+ plugins?: DatafnPlugin[]; // Optional: Custom logic
75
+ clientId?: string; // Optional: Unique ID for this client
76
+ });
77
+ ```
78
+
79
+ ### 2. Table API
80
+
81
+ The `client.table(name)` method provides a scoped interface for a specific resource defined in your schema. It delegates to the main client but automatically handles resource naming and versioning.
82
+
83
+ ```typescript
84
+ const users = client.table("user");
85
+
86
+ // Query
87
+ const allUsers = await users.query({ select: ["id", "name"] });
88
+
89
+ // Mutate
90
+ await users.mutate({
91
+ operation: "merge",
92
+ id: "user:123",
93
+ record: { name: "New Name" }
94
+ });
95
+
96
+ // Subscribe to events for this table only
97
+ users.subscribe(event => console.log("User changed:", event));
98
+ ```
99
+
100
+ ### 3. Reactive Signals
101
+
102
+ Signals are the bridge between your data and your UI. A signal represents a live query. When data changes (locally or via sync), signals automatically re-run and notify subscribers.
103
+
104
+ ```typescript
105
+ const query = { select: ["id"], filters: { status: "active" } };
106
+ const signal = client.table("todo").signal(query);
107
+
108
+ // Get current value
109
+ console.log(signal.get());
110
+
111
+ // Subscribe
112
+ const unsub = signal.subscribe(newValue => {
113
+ // Update UI efficiently
114
+ });
115
+ ```
116
+
117
+ ### 4. Offline & Storage
118
+
119
+ Pass a `storage` adapter to enable offline capabilities. The client will automatically:
120
+ - Hydrate signals from local storage on load.
121
+ - Apply `clone` and `pull` results to local storage.
122
+ - (Future) Queue mutations when offline.
123
+
124
+ **Available Adapters:**
125
+ - `MemoryStorageAdapter`: Transient, in-memory storage (great for testing).
126
+ - `IndexedDbStorageAdapter`: Persistent browser storage.
127
+
128
+ ```typescript
129
+ import { IndexedDbStorageAdapter } from "@datafn/client";
130
+
131
+ const storage = new IndexedDbStorageAdapter("my-db");
132
+ ```
133
+
134
+ ### 5. Synchronization
135
+
136
+ The `client.sync` facade manages data consistency with the server.
137
+
138
+ ```typescript
139
+ // Initial data load
140
+ await client.sync.clone({ ... });
141
+
142
+ // Fetch incremental updates
143
+ await client.sync.pull({ ... });
144
+
145
+ // Push local changes (if using offline queue)
146
+ await client.sync.push({ ... });
147
+ ```
148
+
149
+ If `storage` is configured, `clone` and `pull` operations automatically update the local database, which in turn triggers all relevant reactive signals.
150
+
151
+ ### 6. Event Bus
152
+
153
+ Listen to global or scoped events.
154
+
155
+ ```typescript
156
+ client.subscribe((event) => {
157
+ if (event.type === "mutation_applied") {
158
+ console.log(`Resource ${event.resource} updated!`);
159
+ }
160
+ });
161
+ ```
162
+
163
+ ## API Reference
164
+
165
+ ### `DatafnClient`
166
+
167
+ - `table(name: string): DatafnTable` - Get a table handle.
168
+ - `query(q: unknown): Promise<unknown>` - Execute a raw query.
169
+ - `mutate(m: unknown): Promise<unknown>` - Execute a raw mutation.
170
+ - `transact(t: unknown): Promise<unknown>` - Execute a transaction.
171
+ - `sync`: Sync facade (`clone`, `pull`, `push`, `seed`).
172
+ - `subscribe(handler, filter?)`: Global event subscription.
173
+
174
+ ### `DatafnTable`
175
+
176
+ - `query(fragment)`: Execute query for this resource.
177
+ - `mutate(fragment)`: Execute mutation for this resource.
178
+ - `signal(fragment)`: Create a reactive signal.
179
+ - `subscribe(handler)`: Subscribe to events for this resource.
180
+
181
+ ### `DatafnRemoteAdapter`
182
+
183
+ Interface for your network layer. You must implement this to connect `datafn/client` to your backend.
184
+
185
+ ```typescript
186
+ interface DatafnRemoteAdapter {
187
+ query(q: unknown): Promise<unknown>;
188
+ mutation(m: unknown): Promise<unknown>;
189
+ transact(t: unknown): Promise<unknown>;
190
+ seed(p: unknown): Promise<unknown>;
191
+ clone(p: unknown): Promise<unknown>;
192
+ pull(p: unknown): Promise<unknown>;
193
+ push(p: unknown): Promise<unknown>;
194
+ }
195
+ ```
196
+
197
+ ## License
198
+
199
+ MIT