@byearlybird/starling 0.18.0 → 0.19.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/README.md +58 -92
- package/dist/index.d.ts +63 -181
- package/dist/index.js +336 -569
- package/dist/index.js.map +1 -1
- package/package.json +18 -18
package/README.md
CHANGED
|
@@ -19,20 +19,14 @@ Requires TypeScript 5 or higher.
|
|
|
19
19
|
## Quick Example
|
|
20
20
|
|
|
21
21
|
```typescript
|
|
22
|
-
import { createStore
|
|
23
|
-
import { z } from "zod";
|
|
24
|
-
|
|
25
|
-
const userSchema = z.object({
|
|
26
|
-
id: z.string(),
|
|
27
|
-
name: z.string(),
|
|
28
|
-
});
|
|
22
|
+
import { createStore } from "@byearlybird/starling";
|
|
29
23
|
|
|
30
24
|
const store = createStore({
|
|
31
|
-
users:
|
|
25
|
+
users: (data: { id: string; name: string }) => data.id,
|
|
32
26
|
});
|
|
33
27
|
|
|
34
|
-
store.put(
|
|
35
|
-
const user = store.get("
|
|
28
|
+
store.users.put({ id: "1", name: "Alice" });
|
|
29
|
+
const user = store.users.get("1"); // { id: "1", name: "Alice" }
|
|
36
30
|
```
|
|
37
31
|
|
|
38
32
|
## Features
|
|
@@ -41,7 +35,6 @@ const user = store.get("users", "1"); // { id: "1", name: "Alice" }
|
|
|
41
35
|
- **Fast and synchronous**: All operations are in-memory and synchronous
|
|
42
36
|
- **Framework agnostic**: Works with React, Vue, Svelte, or vanilla JS
|
|
43
37
|
- **Type-safe**: Full TypeScript support with type inference
|
|
44
|
-
- **Schema validation**: Works with Zod, Valibot, ArkType, and more
|
|
45
38
|
- **Merge snapshots**: Sync data between devices or users easily
|
|
46
39
|
- **Change events**: Listen to data changes and integrate with your reactive system
|
|
47
40
|
|
|
@@ -49,28 +42,17 @@ const user = store.get("users", "1"); // { id: "1", name: "Alice" }
|
|
|
49
42
|
|
|
50
43
|
### Creating a Store
|
|
51
44
|
|
|
52
|
-
A store holds one or more collections. Each collection
|
|
45
|
+
A store holds one or more collections. Each collection is defined by a function that extracts the document ID.
|
|
53
46
|
|
|
54
47
|
```typescript
|
|
55
|
-
import { createStore
|
|
56
|
-
|
|
48
|
+
import { createStore } from "@byearlybird/starling";
|
|
49
|
+
|
|
50
|
+
type User = { id: string; name: string; email?: string };
|
|
51
|
+
type Note = { id: string; content: string };
|
|
57
52
|
|
|
58
53
|
const store = createStore({
|
|
59
|
-
users:
|
|
60
|
-
|
|
61
|
-
id: z.string(),
|
|
62
|
-
name: z.string(),
|
|
63
|
-
email: z.string().optional(),
|
|
64
|
-
}),
|
|
65
|
-
(data) => data.id,
|
|
66
|
-
),
|
|
67
|
-
notes: collection(
|
|
68
|
-
z.object({
|
|
69
|
-
id: z.string(),
|
|
70
|
-
content: z.string(),
|
|
71
|
-
}),
|
|
72
|
-
(data) => data.id,
|
|
73
|
-
),
|
|
54
|
+
users: (data: User) => data.id,
|
|
55
|
+
notes: (data: Note) => data.id,
|
|
74
56
|
});
|
|
75
57
|
```
|
|
76
58
|
|
|
@@ -79,7 +61,7 @@ const store = createStore({
|
|
|
79
61
|
Add new items to a collection using `put()`:
|
|
80
62
|
|
|
81
63
|
```typescript
|
|
82
|
-
store.put(
|
|
64
|
+
store.users.put({
|
|
83
65
|
id: "1",
|
|
84
66
|
name: "Alice",
|
|
85
67
|
email: "alice@example.com",
|
|
@@ -90,8 +72,8 @@ Or use `transact()` for atomic multi-collection operations:
|
|
|
90
72
|
|
|
91
73
|
```typescript
|
|
92
74
|
store.transact((tx) => {
|
|
93
|
-
tx.put(
|
|
94
|
-
tx.put(
|
|
75
|
+
tx.users.put({ id: "1", name: "Alice", email: "alice@example.com" });
|
|
76
|
+
tx.notes.put({ id: "n1", content: "Hello" });
|
|
95
77
|
});
|
|
96
78
|
```
|
|
97
79
|
|
|
@@ -100,7 +82,7 @@ store.transact((tx) => {
|
|
|
100
82
|
Update existing items using `patch()`:
|
|
101
83
|
|
|
102
84
|
```typescript
|
|
103
|
-
store.patch("
|
|
85
|
+
store.users.patch("1", {
|
|
104
86
|
email: "newemail@example.com",
|
|
105
87
|
});
|
|
106
88
|
```
|
|
@@ -110,7 +92,7 @@ store.patch("users", "1", {
|
|
|
110
92
|
Remove items using `remove()`:
|
|
111
93
|
|
|
112
94
|
```typescript
|
|
113
|
-
store.remove("
|
|
95
|
+
store.users.remove("1");
|
|
114
96
|
```
|
|
115
97
|
|
|
116
98
|
### Reading Data
|
|
@@ -119,10 +101,13 @@ Read data directly from the store:
|
|
|
119
101
|
|
|
120
102
|
```typescript
|
|
121
103
|
// Get a single item
|
|
122
|
-
const user = store.get("
|
|
104
|
+
const user = store.users.get("1");
|
|
123
105
|
|
|
124
106
|
// Get all items as an array
|
|
125
|
-
const allUsers = store.list(
|
|
107
|
+
const allUsers = store.users.list();
|
|
108
|
+
|
|
109
|
+
// Filter with a where clause
|
|
110
|
+
const admins = store.users.list({ where: (u) => u.role === "admin" });
|
|
126
111
|
|
|
127
112
|
// You can easily derive other operations:
|
|
128
113
|
const userIds = allUsers.map((u) => u.id);
|
|
@@ -134,15 +119,9 @@ const hasUser = allUsers.some((u) => u.id === "1");
|
|
|
134
119
|
Subscribe to changes with `subscribe()`:
|
|
135
120
|
|
|
136
121
|
```typescript
|
|
137
|
-
// Subscribe to
|
|
138
|
-
const unsubscribe = store.subscribe(
|
|
139
|
-
|
|
140
|
-
const allUsers = store.list("users");
|
|
141
|
-
// Update UI, invalidate queries, etc.
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
// Or subscribe to all changes
|
|
145
|
-
store.subscribe((event) => {
|
|
122
|
+
// Subscribe to all changes
|
|
123
|
+
const unsubscribe = store.subscribe((event) => {
|
|
124
|
+
// event is e.g. { users: true } or { users: true, notes: true }
|
|
146
125
|
console.log("Store changed:", event);
|
|
147
126
|
});
|
|
148
127
|
|
|
@@ -183,14 +162,16 @@ function useUsers() {
|
|
|
183
162
|
const queryClient = useQueryClient();
|
|
184
163
|
|
|
185
164
|
useEffect(() => {
|
|
186
|
-
return store.subscribe(
|
|
187
|
-
|
|
165
|
+
return store.subscribe((event) => {
|
|
166
|
+
if ("users" in event) {
|
|
167
|
+
queryClient.invalidateQueries({ queryKey: ["users"] });
|
|
168
|
+
}
|
|
188
169
|
});
|
|
189
170
|
}, []);
|
|
190
171
|
|
|
191
172
|
return useQuery({
|
|
192
173
|
queryKey: ["users"],
|
|
193
|
-
queryFn: () => store.list(
|
|
174
|
+
queryFn: () => store.users.list(),
|
|
194
175
|
});
|
|
195
176
|
}
|
|
196
177
|
```
|
|
@@ -202,8 +183,11 @@ import { useSyncExternalStore } from "react";
|
|
|
202
183
|
|
|
203
184
|
function useUsers() {
|
|
204
185
|
return useSyncExternalStore(
|
|
205
|
-
(callback) =>
|
|
206
|
-
|
|
186
|
+
(callback) =>
|
|
187
|
+
store.subscribe((event) => {
|
|
188
|
+
if ("users" in event) callback();
|
|
189
|
+
}),
|
|
190
|
+
() => store.users.list(),
|
|
207
191
|
);
|
|
208
192
|
}
|
|
209
193
|
```
|
|
@@ -213,9 +197,11 @@ function useUsers() {
|
|
|
213
197
|
```typescript
|
|
214
198
|
import { writable } from "svelte/store";
|
|
215
199
|
|
|
216
|
-
const users = writable(store.list(
|
|
217
|
-
store.subscribe(
|
|
218
|
-
|
|
200
|
+
const users = writable(store.users.list());
|
|
201
|
+
store.subscribe((event) => {
|
|
202
|
+
if ("users" in event) {
|
|
203
|
+
users.set(store.users.list());
|
|
204
|
+
}
|
|
219
205
|
});
|
|
220
206
|
```
|
|
221
207
|
|
|
@@ -224,55 +210,36 @@ store.subscribe(["users"], () => {
|
|
|
224
210
|
```typescript
|
|
225
211
|
import { ref } from "vue";
|
|
226
212
|
|
|
227
|
-
const users = ref(store.list(
|
|
228
|
-
store.subscribe(
|
|
229
|
-
|
|
213
|
+
const users = ref(store.users.list());
|
|
214
|
+
store.subscribe((event) => {
|
|
215
|
+
if ("users" in event) {
|
|
216
|
+
users.value = store.users.list();
|
|
217
|
+
}
|
|
230
218
|
});
|
|
231
219
|
```
|
|
232
220
|
|
|
233
|
-
## Schema Support
|
|
234
|
-
|
|
235
|
-
Starling works with any library that follows the [Standard Schema](https://github.com/standard-schema/spec) specification. This includes:
|
|
236
|
-
|
|
237
|
-
- **Zod** - Most popular schema library
|
|
238
|
-
- **Valibot** - Lightweight alternative
|
|
239
|
-
- **ArkType** - TypeScript-first schemas
|
|
240
|
-
|
|
241
|
-
You can use any of these to define your data shapes. Starling will validate your data and give you full TypeScript types.
|
|
242
|
-
|
|
243
|
-
```typescript
|
|
244
|
-
import { z } from "zod";
|
|
245
|
-
// or
|
|
246
|
-
import * as v from "valibot";
|
|
247
|
-
// or
|
|
248
|
-
import { type } from "arktype";
|
|
249
|
-
|
|
250
|
-
// All of these work the same way
|
|
251
|
-
const schema = z.object({ id: z.string(), name: z.string() });
|
|
252
|
-
// or
|
|
253
|
-
const schema = v.object({ id: v.string(), name: v.string() });
|
|
254
|
-
// or
|
|
255
|
-
const schema = type({ id: "string", name: "string" });
|
|
256
|
-
```
|
|
257
|
-
|
|
258
221
|
## API Overview
|
|
259
222
|
|
|
260
223
|
### Main Export
|
|
261
224
|
|
|
262
225
|
- `createStore(config)` - Creates a new store with collections
|
|
263
226
|
|
|
227
|
+
### Collection Methods
|
|
228
|
+
|
|
229
|
+
Each collection is accessed as a property on the store (e.g., `store.users`):
|
|
230
|
+
|
|
231
|
+
- `store.<collection>.get(id)` - Get a document by ID
|
|
232
|
+
- `store.<collection>.list(options?)` - Get all documents as an array, with optional `where` filter
|
|
233
|
+
- `store.<collection>.put(data)` - Insert or replace a document (upsert, revives tombstoned IDs)
|
|
234
|
+
- `store.<collection>.patch(id, data)` - Partially update an existing document (throws if ID missing)
|
|
235
|
+
- `store.<collection>.remove(id)` - Remove a document
|
|
236
|
+
|
|
264
237
|
### Store Methods
|
|
265
238
|
|
|
266
|
-
- `
|
|
267
|
-
- `
|
|
268
|
-
- `
|
|
269
|
-
- `
|
|
270
|
-
- `remove(collection, id)` - Remove a document
|
|
271
|
-
- `transact(callback)` - Execute operations atomically. Collections are cloned lazily on first access.
|
|
272
|
-
- `subscribe(callback)` - Subscribe to all collection changes
|
|
273
|
-
- `subscribe(collections, callback)` - Subscribe to changes in specific collections
|
|
274
|
-
- `getState()` - Get current store state as a snapshot
|
|
275
|
-
- `merge(snapshot)` - Merge a snapshot into the store
|
|
239
|
+
- `store.transact(callback)` - Execute operations atomically across collections. The `tx` object has the same collection properties (e.g., `tx.users.put(...)`)
|
|
240
|
+
- `store.subscribe(callback)` - Subscribe to all collection changes
|
|
241
|
+
- `store.getState()` - Get current store state as a snapshot
|
|
242
|
+
- `store.merge(snapshot)` - Merge a snapshot into the store
|
|
276
243
|
|
|
277
244
|
For full type definitions, see the TypeScript types exported from the package.
|
|
278
245
|
|
|
@@ -280,7 +247,6 @@ For full type definitions, see the TypeScript types exported from the package.
|
|
|
280
247
|
|
|
281
248
|
- **`lib/core/`** – CRDT primitives: hybrid logical clock, per-field atoms (LWW), tombstones, and document/collection merging.
|
|
282
249
|
- **`lib/store/`** – Store API with collections, batching, queries, and change subscriptions.
|
|
283
|
-
- **`lib/middleware/`** – Optional middleware (e.g. persistence).
|
|
284
250
|
|
|
285
251
|
## Development
|
|
286
252
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,212 +1,94 @@
|
|
|
1
1
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
2
|
|
|
3
|
-
//#region lib/
|
|
3
|
+
//#region lib/clock.d.ts
|
|
4
4
|
type Clock = {
|
|
5
5
|
ms: number;
|
|
6
6
|
seq: number;
|
|
7
7
|
};
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* HLC timestamp.
|
|
10
|
+
* Lexicographically sortable string: `${ms}@${seq}@${deviceId}`.
|
|
11
|
+
* ms and seq are zero-padded hex; deviceId is appended as-is.
|
|
11
12
|
*/
|
|
12
|
-
type Stamp = string
|
|
13
|
-
readonly __brand: "Stamp";
|
|
14
|
-
};
|
|
13
|
+
type Stamp = string;
|
|
15
14
|
declare function advanceClock(current: Clock, next: Clock): Clock;
|
|
16
|
-
declare function makeStamp(ms: number, seq: number): Stamp;
|
|
17
|
-
/**
|
|
18
|
-
* Parse and validate a string as a Stamp. Use when deserializing stored state.
|
|
19
|
-
* Throws if the value is not a valid 24-character hex string.
|
|
20
|
-
*/
|
|
21
|
-
declare function asStamp(value: string): Stamp;
|
|
15
|
+
declare function makeStamp(ms: number, seq: number, deviceId: string): Stamp;
|
|
22
16
|
//#endregion
|
|
23
|
-
//#region lib/
|
|
24
|
-
type Tombstones = Record<string, Stamp>;
|
|
25
|
-
declare function isDeleted(id: string, tombstones: Tombstones): boolean;
|
|
26
|
-
declare function mergeTombstones(target: Tombstones, source: Tombstones): Tombstones;
|
|
27
|
-
//#endregion
|
|
28
|
-
//#region lib/core/types.d.ts
|
|
29
|
-
declare const KEYS: {
|
|
30
|
-
readonly VAL: "~val";
|
|
31
|
-
readonly TS: "~ts";
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* Base constraint for plain document shapes - any object with string keys.
|
|
35
|
-
*/
|
|
17
|
+
//#region lib/crdt.d.ts
|
|
36
18
|
type Document = Record<string, unknown>;
|
|
37
19
|
type Atom<T> = {
|
|
38
|
-
|
|
39
|
-
|
|
20
|
+
"~v": T;
|
|
21
|
+
"~ts": string;
|
|
40
22
|
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Collection of atomized documents with shape T. Map from document ID to AtomizedDocument<T>.
|
|
47
|
-
*/
|
|
48
|
-
type Collection<T extends Document> = Record<string, AtomizedDocument<T>>;
|
|
49
|
-
/**
|
|
50
|
-
* Collection state containing documents and tombstones.
|
|
51
|
-
*/
|
|
52
|
-
type CollectionState<T extends Document> = {
|
|
53
|
-
documents: Collection<T>;
|
|
23
|
+
type AtomizedDocument = Record<string, Atom<unknown>>;
|
|
24
|
+
type Tombstones = Record<string, string>;
|
|
25
|
+
type CollectionState = {
|
|
26
|
+
documents: Record<string, AtomizedDocument>;
|
|
54
27
|
tombstones: Tombstones;
|
|
55
28
|
};
|
|
56
29
|
type StoreState = {
|
|
57
30
|
clock: Clock;
|
|
58
|
-
collections: Record<string, CollectionState
|
|
31
|
+
collections: Record<string, CollectionState>;
|
|
32
|
+
};
|
|
33
|
+
type CollectionChangeEvent = {
|
|
34
|
+
put: string[];
|
|
35
|
+
patch: string[];
|
|
36
|
+
remove: string[];
|
|
59
37
|
};
|
|
60
|
-
/**
|
|
61
|
-
* Type guard to check if a value is an AtomizedDocument.
|
|
62
|
-
* An AtomizedDocument is an object where all values are Atoms.
|
|
63
|
-
*/
|
|
64
|
-
declare function isAtomizedDocument<T extends Document>(value: unknown): value is AtomizedDocument<T>;
|
|
65
|
-
/**
|
|
66
|
-
* Type guard to check if a value is a Collection.
|
|
67
|
-
* A Collection is a Record where all values are AtomizedDocuments.
|
|
68
|
-
*/
|
|
69
|
-
declare function isCollection<T extends Document>(value: unknown): value is Collection<T>;
|
|
70
|
-
/**
|
|
71
|
-
* Type guard to check if a value is a CollectionState.
|
|
72
|
-
* A CollectionState has documents (Collection) and tombstones (Record<string, string>).
|
|
73
|
-
*/
|
|
74
|
-
declare function isCollectionState<T extends Document>(value: unknown): value is CollectionState<T>;
|
|
75
|
-
//#endregion
|
|
76
|
-
//#region lib/core/atomizer.d.ts
|
|
77
|
-
declare function pack<T>(value: T, timestamp: Stamp): Atom<T>;
|
|
78
|
-
declare function unpack<T>(node: unknown): T | undefined;
|
|
79
|
-
declare function isAtom(node: unknown): node is Atom<unknown>;
|
|
80
|
-
declare function atomize<T extends Document>(data: T, timestamp: Stamp): AtomizedDocument<T>;
|
|
81
|
-
//#endregion
|
|
82
|
-
//#region lib/core/lens.d.ts
|
|
83
|
-
declare function createReadLens<T extends Document>(doc: AtomizedDocument<T>): T;
|
|
84
|
-
//#endregion
|
|
85
|
-
//#region lib/core/merge.d.ts
|
|
86
|
-
/** Merges incoming doc fields into local. Adds new keys from incoming; LWW on conflicts. */
|
|
87
|
-
declare function mergeDocs<T extends Document>(local: AtomizedDocument<T>, incoming: Partial<AtomizedDocument<T>>): AtomizedDocument<T>;
|
|
88
|
-
/**
|
|
89
|
-
* Merges two collection states, respecting tombstones.
|
|
90
|
-
* Documents that are tombstoned are excluded from the result.
|
|
91
|
-
* For documents that exist in both collections, fields are merged using LWW semantics.
|
|
92
|
-
*/
|
|
93
|
-
declare function mergeCollections<T extends Document>(local: CollectionState<T>, incoming: CollectionState<T>): CollectionState<T>;
|
|
94
38
|
//#endregion
|
|
95
|
-
//#region lib/
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
* The schema's runtime validation will ensure type safety.
|
|
100
|
-
*/
|
|
101
|
-
declare function validate<T extends StandardSchemaV1>(schema: T, input: unknown): StandardSchemaV1.InferOutput<T>;
|
|
102
|
-
/**
|
|
103
|
-
* Base type constraint for any standard schema object
|
|
104
|
-
*/
|
|
105
|
-
type AnyObject = StandardSchemaV1<Record<string, any>>;
|
|
106
|
-
type Output<T extends AnyObject> = StandardSchemaV1.InferOutput<T>;
|
|
107
|
-
type Input<T extends AnyObject> = StandardSchemaV1.InferInput<T>;
|
|
108
|
-
type CollectionDef<T extends Document = Document, Id extends string = string, S$1 extends AnyObject = AnyObject> = {
|
|
109
|
-
readonly "~docType": T;
|
|
110
|
-
readonly "~idType": Id;
|
|
111
|
-
readonly "~schemaType": S$1;
|
|
112
|
-
schema: AnyObject;
|
|
113
|
-
getId: (data: T) => Id;
|
|
39
|
+
//#region lib/collection.d.ts
|
|
40
|
+
type CollectionDef<Input = unknown, Output extends Document = Document, KeyPath extends keyof Output & string = string> = {
|
|
41
|
+
keyPath: KeyPath;
|
|
42
|
+
schema?: StandardSchemaV1<Input, Output>;
|
|
114
43
|
};
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
* @example
|
|
120
|
-
* ```ts
|
|
121
|
-
* const store = createStore({
|
|
122
|
-
* users: define(userSchema, (data) => data.id),
|
|
123
|
-
* });
|
|
124
|
-
* ```
|
|
125
|
-
*/
|
|
126
|
-
declare function define<S$1 extends AnyObject, Id extends string = string>(schema: S$1, getId: (data: Output<S$1>) => Id): CollectionDef<Output<S$1>, Id, S$1>;
|
|
127
|
-
/**
|
|
128
|
-
* Extract the document type from a CollectionDef
|
|
129
|
-
*/
|
|
130
|
-
type DocType<C extends CollectionDef> = C["~docType"];
|
|
131
|
-
/**
|
|
132
|
-
* Extract the ID type from a CollectionDef
|
|
133
|
-
*/
|
|
134
|
-
type IdType<C extends CollectionDef> = C["~idType"];
|
|
135
|
-
/**
|
|
136
|
-
* Extract the input type from a CollectionDef's schema
|
|
137
|
-
* This allows put() to accept partial data when schemas have defaults
|
|
138
|
-
*/
|
|
139
|
-
type InputType<C extends CollectionDef> = C extends CollectionDef<any, any, infer S> ? Input<S> : never;
|
|
140
|
-
/**
|
|
141
|
-
* Configuration for all collections in a store.
|
|
142
|
-
* All collection definitions must be created using the `collection()` helper.
|
|
143
|
-
*
|
|
144
|
-
* Uses `any` for type parameters to allow any CollectionDef to be stored,
|
|
145
|
-
* while still preserving specific types through inference in createStore.
|
|
146
|
-
*/
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region lib/store.d.ts
|
|
46
|
+
type DocType<C> = C extends CollectionDef<any, infer T, any> ? T : never;
|
|
47
|
+
type InputType<C> = C extends CollectionDef<infer I, any, any> ? I : never;
|
|
147
48
|
type StoreConfig = Record<string, CollectionDef<any, any, any>>;
|
|
148
|
-
/**
|
|
149
|
-
* Valid collection name from a store config
|
|
150
|
-
*/
|
|
151
49
|
type CollectionName<T extends StoreConfig> = keyof T & string;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
type TransactionAPI<T extends StoreConfig> = {
|
|
161
|
-
get<N extends CollectionName<T>>(collection: N, id: IdType<T[N]>): DocType<T[N]> | undefined;
|
|
162
|
-
list<N extends CollectionName<T>>(collection: N, options?: ListOptions<DocType<T[N]>>): DocType<T[N]>[];
|
|
163
|
-
put<N extends CollectionName<T>>(collection: N, data: InputType<T[N]>): DocType<T[N]>;
|
|
164
|
-
patch<N extends CollectionName<T>>(collection: N, id: IdType<T[N]>, data: Partial<DocType<T[N]>>): DocType<T[N]>;
|
|
165
|
-
remove<N extends CollectionName<T>>(collection: N, id: IdType<T[N]>): void;
|
|
50
|
+
type CollectionAPI<C extends CollectionDef> = {
|
|
51
|
+
get(id: string): DocType<C> | undefined;
|
|
52
|
+
list(options?: {
|
|
53
|
+
where?: (doc: DocType<C>) => boolean;
|
|
54
|
+
}): DocType<C>[];
|
|
55
|
+
put(data: InputType<C>): DocType<C>;
|
|
56
|
+
patch(id: string, data: Partial<DocType<C>>): DocType<C>;
|
|
57
|
+
remove(id: string): void;
|
|
166
58
|
};
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
get<N extends CollectionName<T>>(collection: N, id: IdType<T[N]>): DocType<T[N]> | undefined;
|
|
171
|
-
list<N extends CollectionName<T>>(collection: N, options?: ListOptions<DocType<T[N]>>): DocType<T[N]>[];
|
|
172
|
-
put<N extends CollectionName<T>>(collection: N, data: InputType<T[N]>): DocType<T[N]>;
|
|
173
|
-
patch<N extends CollectionName<T>>(collection: N, id: IdType<T[N]>, data: Partial<DocType<T[N]>>): DocType<T[N]>;
|
|
174
|
-
remove<N extends CollectionName<T>>(collection: N, id: IdType<T[N]>): void;
|
|
59
|
+
type StoreChangeEvent<T extends StoreConfig> = { [K in keyof T]?: CollectionChangeEvent };
|
|
60
|
+
type TransactionAPI<T extends StoreConfig> = { [K in CollectionName<T>]: CollectionAPI<T[K]> };
|
|
61
|
+
type Store<T extends StoreConfig> = { [K in CollectionName<T>]: CollectionAPI<T[K]> } & {
|
|
175
62
|
subscribe(callback: (event: StoreChangeEvent<T>) => void): () => void;
|
|
176
63
|
getState(): StoreState;
|
|
177
64
|
merge(snapshot: StoreState): StoreChangeEvent<T>;
|
|
178
65
|
transact<R>(callback: (tx: TransactionAPI<T>) => R): R;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
66
|
+
};
|
|
67
|
+
type StringKeyOf<T> = { [K in keyof T & string]: T[K] extends string ? K : never }[keyof T & string];
|
|
68
|
+
declare function createStore<T extends StoreConfig>(config: {
|
|
69
|
+
deviceId: string;
|
|
70
|
+
collections: T & { [K in keyof T & string]: T[K] extends {
|
|
71
|
+
schema: StandardSchemaV1<any, infer O>;
|
|
72
|
+
} ? {
|
|
73
|
+
keyPath: StringKeyOf<O>;
|
|
74
|
+
} : T[K] };
|
|
75
|
+
}): Store<T>;
|
|
76
|
+
declare function createStore<T extends Record<string, Document & {
|
|
77
|
+
keyPath?: never;
|
|
78
|
+
}>>(config: {
|
|
79
|
+
deviceId: string;
|
|
80
|
+
collections: { [K in keyof T & string]: {
|
|
81
|
+
keyPath: StringKeyOf<T[K]>;
|
|
82
|
+
} };
|
|
83
|
+
}): Store<{ [K in keyof T & string]: CollectionDef<T[K], T[K], string> }>;
|
|
189
84
|
//#endregion
|
|
190
|
-
//#region lib/
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
type PersistenceOptions = {
|
|
196
|
-
key: string;
|
|
197
|
-
storeName?: string;
|
|
198
|
-
debounceMs?: number;
|
|
199
|
-
channelName?: string;
|
|
200
|
-
serialize?: (state: StoreState) => string;
|
|
201
|
-
deserialize?: (serialized: string) => StoreState;
|
|
85
|
+
//#region lib/query.d.ts
|
|
86
|
+
type Query<R> = {
|
|
87
|
+
readonly result: R;
|
|
88
|
+
subscribe(cb: (result: R) => void): () => void;
|
|
89
|
+
dispose(): void;
|
|
202
90
|
};
|
|
203
|
-
declare
|
|
204
|
-
#private;
|
|
205
|
-
constructor(store: Store<T>, options: PersistenceOptions);
|
|
206
|
-
init(): Promise<void>;
|
|
207
|
-
dispose(): Promise<void>;
|
|
208
|
-
subscribe(listener: (serialized: string) => void): () => void;
|
|
209
|
-
}
|
|
91
|
+
declare function createQuery<T extends StoreConfig, R>(store: Store<T>, predicate: (store: Store<T>) => R, dependencies: CollectionName<T>[]): Query<R>;
|
|
210
92
|
//#endregion
|
|
211
|
-
export {
|
|
93
|
+
export { type Clock, type CollectionAPI, type CollectionChangeEvent, type CollectionDef, type CollectionName, type CollectionState, type DocType, type Document, type InputType, type Query, type Store, type StoreChangeEvent, type StoreConfig, type StoreState, type Tombstones, type TransactionAPI, advanceClock, createQuery, createStore, makeStamp };
|
|
212
94
|
//# sourceMappingURL=index.d.ts.map
|