@live-state/sync 0.0.6 → 0.0.7-canary-2
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/chunk-LSAVBBUS.js +1 -0
- package/dist/chunk-NKM6VWL7.js +1 -0
- package/dist/chunk-RSSRYEM3.js +1 -0
- package/dist/client.d.ts +2 -2
- package/dist/client.js +1 -1
- package/dist/fetch-client.d.ts +2 -2
- package/dist/fetch-client.js +1 -1
- package/dist/index-CLkafi56.d.ts +1016 -0
- package/dist/index-hO1iQ-VU.d.cts +608 -0
- package/dist/index-hO1iQ-VU.d.ts +608 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/optimistic-client.d.ts +3 -0
- package/dist/optimistic-client.js +1 -0
- package/dist/server.cjs +10 -4
- package/dist/server.d.cts +262 -86
- package/dist/server.d.ts +262 -86
- package/dist/server.js +8 -2
- package/package.json +6 -1
- package/dist/chunk-AHF6GNMI.js +0 -1
- package/dist/chunk-IT5UC7TA.js +0 -1
- package/dist/index-BtsKDfTE.d.cts +0 -282
- package/dist/index-BtsKDfTE.d.ts +0 -282
- package/dist/index-P-s1Yf1S.d.ts +0 -520
|
@@ -0,0 +1,1016 @@
|
|
|
1
|
+
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
/** biome-ignore-all lint/complexity/noBannedTypes: false positive */
|
|
5
|
+
/**
|
|
6
|
+
* Base metadata type for live types.
|
|
7
|
+
* All metadata types must extend this base.
|
|
8
|
+
*/
|
|
9
|
+
type BaseMeta = {};
|
|
10
|
+
/**
|
|
11
|
+
* Metadata type for atomic live types with timestamp for LWW conflict resolution.
|
|
12
|
+
*/
|
|
13
|
+
type AtomicMeta = {
|
|
14
|
+
timestamp: string | null;
|
|
15
|
+
} & BaseMeta;
|
|
16
|
+
type MutationType = "set";
|
|
17
|
+
/**
|
|
18
|
+
* Describes the storage field type for database mapping.
|
|
19
|
+
*/
|
|
20
|
+
type StorageFieldType = {
|
|
21
|
+
type: string;
|
|
22
|
+
nullable: boolean;
|
|
23
|
+
default?: any;
|
|
24
|
+
unique?: boolean;
|
|
25
|
+
index?: boolean;
|
|
26
|
+
primary?: boolean;
|
|
27
|
+
references?: string;
|
|
28
|
+
enumValues?: readonly string[];
|
|
29
|
+
enumName?: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Materialized representation of a LiveType value with metadata.
|
|
33
|
+
* Used internally for storage and sync operations.
|
|
34
|
+
*/
|
|
35
|
+
type MaterializedLiveType<T extends LiveTypeAny> = {
|
|
36
|
+
value: T["_value"] extends Record<string, LiveTypeAny> ? {
|
|
37
|
+
[K in keyof T["_value"]]: MaterializedLiveType<T["_value"][K]>;
|
|
38
|
+
} : T["_value"];
|
|
39
|
+
_meta: T["_meta"];
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Abstract base class for all live types.
|
|
43
|
+
*
|
|
44
|
+
* @template Value - The actual TypeScript value type
|
|
45
|
+
* @template Meta - Metadata type for sync resolution (defaults to BaseMeta)
|
|
46
|
+
* @template EncodeInput - Type accepted during mutations
|
|
47
|
+
* @template DecodeInput - Type returned after encoding
|
|
48
|
+
*/
|
|
49
|
+
declare abstract class LiveType<Value = any, Meta extends BaseMeta = BaseMeta, EncodeInput = Partial<Value> | Value, DecodeInput = {
|
|
50
|
+
value: Value;
|
|
51
|
+
_meta: keyof Meta extends never ? never : Meta;
|
|
52
|
+
}> {
|
|
53
|
+
readonly _value: Value;
|
|
54
|
+
readonly _meta: Meta;
|
|
55
|
+
readonly _encodeInput: EncodeInput;
|
|
56
|
+
readonly _decodeInput: DecodeInput;
|
|
57
|
+
abstract encodeMutation(mutationType: MutationType, input: EncodeInput, timestamp: string): DecodeInput;
|
|
58
|
+
/**
|
|
59
|
+
* Merges the materialized shape with the encoded mutation
|
|
60
|
+
* @param mutationType The type of mutation
|
|
61
|
+
* @param encodedMutation The encoded mutation
|
|
62
|
+
* @param materializedShape The materialized shape
|
|
63
|
+
* @returns A tuple of the new materialized shape and the accepted diff
|
|
64
|
+
*/
|
|
65
|
+
abstract mergeMutation(mutationType: MutationType, encodedMutation: DecodeInput, materializedShape?: MaterializedLiveType<LiveType<Value, Meta>>): [MaterializedLiveType<LiveType<Value, Meta>>, DecodeInput | null];
|
|
66
|
+
abstract getStorageFieldType(): StorageFieldType;
|
|
67
|
+
}
|
|
68
|
+
type LiveTypeAny = LiveType<any, BaseMeta, any, any>;
|
|
69
|
+
/**
|
|
70
|
+
* Extracts the TypeScript value type from a LiveType.
|
|
71
|
+
*/
|
|
72
|
+
type InferLiveType<T extends LiveTypeAny> = T["_value"] extends Record<string, LiveTypeAny> ? {
|
|
73
|
+
[K in keyof T["_value"]]: InferLiveType<T["_value"][K]>;
|
|
74
|
+
} : T["_value"];
|
|
75
|
+
type InferIndex<T extends LiveTypeAny> = string;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Helper type to extract Value type from LiveAtomicType
|
|
79
|
+
*/
|
|
80
|
+
type ExtractValue<T> = T extends LiveAtomicType<infer V, any, any> ? V : never;
|
|
81
|
+
/**
|
|
82
|
+
* Helper type to extract Meta type from LiveAtomicType
|
|
83
|
+
*/
|
|
84
|
+
type ExtractMeta<T> = T extends LiveAtomicType<any, any, infer M> ? M : AtomicMeta;
|
|
85
|
+
/**
|
|
86
|
+
* Wraps a LiveAtomicType to allow null values.
|
|
87
|
+
* Supports chainable modifiers like `.default()`, `.unique()`, `.index()`, `.primary()`.
|
|
88
|
+
*/
|
|
89
|
+
declare class NullableLiveType<T extends LiveAtomicType<any, any, any>> extends LiveType<T["_value"] | null, T["_meta"], T["_encodeInput"] | null, T["_decodeInput"]> {
|
|
90
|
+
readonly inner: T;
|
|
91
|
+
constructor(inner: T);
|
|
92
|
+
encodeMutation(mutationType: MutationType, input: T["_value"] | null, timestamp: string): T["_decodeInput"];
|
|
93
|
+
mergeMutation(mutationType: MutationType, encodedMutation: T["_decodeInput"], materializedShape?: MaterializedLiveType<LiveType<T["_value"] | null, T["_meta"], T["_value"] | Partial<T["_value"] | null>, T["_decodeInput"]>> | undefined): [
|
|
94
|
+
MaterializedLiveType<LiveType<T["_value"] | null, T["_meta"], T["_value"] | Partial<T["_value"] | null>, T["_decodeInput"]>>,
|
|
95
|
+
T["_decodeInput"] | null
|
|
96
|
+
];
|
|
97
|
+
getStorageFieldType(): StorageFieldType;
|
|
98
|
+
/**
|
|
99
|
+
* Returns a new nullable type with a unique constraint.
|
|
100
|
+
*/
|
|
101
|
+
unique(): NullableLiveType<LiveAtomicType<ExtractValue<T>, undefined, ExtractMeta<T>>>;
|
|
102
|
+
/**
|
|
103
|
+
* Returns a new nullable type with an index.
|
|
104
|
+
*/
|
|
105
|
+
index(): NullableLiveType<LiveAtomicType<ExtractValue<T>, undefined, ExtractMeta<T>>>;
|
|
106
|
+
/**
|
|
107
|
+
* Returns a new nullable type with a default value.
|
|
108
|
+
* Can be the value type or null.
|
|
109
|
+
*/
|
|
110
|
+
default(value: ExtractValue<T> | null): NullableLiveType<LiveAtomicType<ExtractValue<T>, ExtractValue<T> | null, ExtractMeta<T>>>;
|
|
111
|
+
/**
|
|
112
|
+
* Returns a new nullable type marked as primary key.
|
|
113
|
+
*/
|
|
114
|
+
primary(): NullableLiveType<LiveAtomicType<ExtractValue<T>, undefined, ExtractMeta<T>>>;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Base class for atomic (scalar) live types.
|
|
118
|
+
*
|
|
119
|
+
* @template Value - The value type (string, number, boolean, Date)
|
|
120
|
+
* @template DefaultValue - The default value type (undefined if no default)
|
|
121
|
+
* @template Meta - Metadata type for sync resolution
|
|
122
|
+
*/
|
|
123
|
+
declare class LiveAtomicType<Value, DefaultValue = undefined, Meta extends AtomicMeta = AtomicMeta> extends LiveType<Value, Meta, Value, {
|
|
124
|
+
value: Value;
|
|
125
|
+
_meta: Meta;
|
|
126
|
+
}> {
|
|
127
|
+
readonly storageType: string;
|
|
128
|
+
readonly convertFunc?: (value: any) => Value;
|
|
129
|
+
readonly isIndex: boolean;
|
|
130
|
+
readonly isUnique: boolean;
|
|
131
|
+
readonly defaultValue: DefaultValue;
|
|
132
|
+
readonly foreignReference?: string;
|
|
133
|
+
readonly isPrimary: boolean;
|
|
134
|
+
constructor(storageType: string, convertFunc?: (value: any) => Value, index?: boolean, unique?: boolean, defaultValue?: DefaultValue, references?: string, primary?: boolean);
|
|
135
|
+
encodeMutation(mutationType: MutationType, input: Value, timestamp: string): {
|
|
136
|
+
value: Value;
|
|
137
|
+
_meta: Meta;
|
|
138
|
+
};
|
|
139
|
+
mergeMutation(mutationType: MutationType, encodedMutation: {
|
|
140
|
+
value: Value;
|
|
141
|
+
_meta: Meta;
|
|
142
|
+
}, materializedShape?: MaterializedLiveType<LiveType<Value, Meta, Value | Partial<Value>, {
|
|
143
|
+
value: Value;
|
|
144
|
+
_meta: Meta;
|
|
145
|
+
}>>): [
|
|
146
|
+
MaterializedLiveType<LiveType<Value, Meta, Value | Partial<Value>, {
|
|
147
|
+
value: Value;
|
|
148
|
+
_meta: Meta;
|
|
149
|
+
}>>,
|
|
150
|
+
{
|
|
151
|
+
value: Value;
|
|
152
|
+
_meta: Meta;
|
|
153
|
+
} | null
|
|
154
|
+
];
|
|
155
|
+
getStorageFieldType(): StorageFieldType;
|
|
156
|
+
/**
|
|
157
|
+
* Returns a new atomic type with a unique constraint.
|
|
158
|
+
*/
|
|
159
|
+
unique(): LiveAtomicType<Value, undefined, Meta>;
|
|
160
|
+
/**
|
|
161
|
+
* Returns a new atomic type with an index.
|
|
162
|
+
*/
|
|
163
|
+
index(): LiveAtomicType<Value, undefined, Meta>;
|
|
164
|
+
/**
|
|
165
|
+
* Returns a new atomic type with a default value.
|
|
166
|
+
*/
|
|
167
|
+
default(value: Value): LiveAtomicType<Value, Value, Meta>;
|
|
168
|
+
/**
|
|
169
|
+
* Returns a new atomic type marked as primary key.
|
|
170
|
+
*/
|
|
171
|
+
primary(): LiveAtomicType<Value, undefined, Meta>;
|
|
172
|
+
/**
|
|
173
|
+
* Returns a nullable version of this type.
|
|
174
|
+
* If no default value was set, defaults to null.
|
|
175
|
+
*/
|
|
176
|
+
nullable(): NullableLiveType<LiveAtomicType<Value, DefaultValue extends undefined ? null : DefaultValue, Meta>>;
|
|
177
|
+
/**
|
|
178
|
+
* Returns a new atomic type with custom metadata type for advanced sync strategies.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* type VectorClockMeta = AtomicMeta & { vectorClock: Record<string, number> };
|
|
183
|
+
* const content = string().withMeta<VectorClockMeta>();
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
withMeta<TMeta extends AtomicMeta>(): LiveAtomicType<Value, DefaultValue, TMeta>;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Live string type.
|
|
190
|
+
*/
|
|
191
|
+
declare class LiveString extends LiveAtomicType<string> {
|
|
192
|
+
private constructor();
|
|
193
|
+
static create(): LiveString;
|
|
194
|
+
static createId(): LiveAtomicType<string, undefined, {
|
|
195
|
+
timestamp: string | null;
|
|
196
|
+
}>;
|
|
197
|
+
static createReference(foreignField: `${string}.${string}`): LiveString;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Forward declaration for LiveCollection to avoid circular dependency.
|
|
202
|
+
* The actual type is defined in collection.ts
|
|
203
|
+
*/
|
|
204
|
+
interface LiveCollectionAny$1 {
|
|
205
|
+
readonly name: string;
|
|
206
|
+
readonly fields: Record<string, LiveTypeAny>;
|
|
207
|
+
readonly relations: Record<string, RelationAny>;
|
|
208
|
+
setRelations<TRelations extends Record<string, RelationAny>>(relations: TRelations): LiveCollectionAny$1;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Represents a relation between two collections.
|
|
212
|
+
*
|
|
213
|
+
* @template TEntity - The target collection
|
|
214
|
+
* @template TSourceEntity - The source collection
|
|
215
|
+
* @template TType - "one" for many-to-one, "many" for one-to-many
|
|
216
|
+
* @template TRelationalColumn - The FK column on source (for "one" relations)
|
|
217
|
+
* @template TForeignColumn - The FK column on target (for "many" relations)
|
|
218
|
+
* @template TRequired - Whether the relation is required
|
|
219
|
+
*/
|
|
220
|
+
declare class Relation<TEntity extends LiveCollectionAny$1, TSourceEntity extends LiveCollectionAny$1, TType extends "one" | "many", TRelationalColumn extends keyof TSourceEntity["fields"], TForeignColumn extends keyof TEntity["fields"], TRequired extends boolean> extends LiveType<InferIndex<TEntity extends LiveTypeAny ? TEntity : LiveTypeAny>, {
|
|
221
|
+
timestamp: string | null;
|
|
222
|
+
} & BaseMeta> {
|
|
223
|
+
readonly entity: TEntity;
|
|
224
|
+
readonly type: TType;
|
|
225
|
+
readonly required: TRequired;
|
|
226
|
+
readonly relationalColumn?: TRelationalColumn;
|
|
227
|
+
readonly foreignColumn?: TForeignColumn;
|
|
228
|
+
readonly sourceEntity: TSourceEntity;
|
|
229
|
+
private constructor();
|
|
230
|
+
encodeMutation(mutationType: MutationType, input: string, timestamp: string): {
|
|
231
|
+
value: string;
|
|
232
|
+
_meta: {
|
|
233
|
+
timestamp: string;
|
|
234
|
+
};
|
|
235
|
+
};
|
|
236
|
+
mergeMutation(mutationType: MutationType, encodedMutation: {
|
|
237
|
+
value: string;
|
|
238
|
+
_meta: {
|
|
239
|
+
timestamp: string;
|
|
240
|
+
};
|
|
241
|
+
}, materializedShape?: MaterializedLiveType<LiveString> | undefined): [
|
|
242
|
+
MaterializedLiveType<LiveString>,
|
|
243
|
+
{
|
|
244
|
+
value: string;
|
|
245
|
+
_meta: {
|
|
246
|
+
timestamp: string;
|
|
247
|
+
};
|
|
248
|
+
} | null
|
|
249
|
+
];
|
|
250
|
+
getStorageFieldType(): StorageFieldType;
|
|
251
|
+
toJSON(): {
|
|
252
|
+
entityName: string;
|
|
253
|
+
type: TType;
|
|
254
|
+
required: TRequired;
|
|
255
|
+
relationalColumn: TRelationalColumn | undefined;
|
|
256
|
+
foreignColumn: TForeignColumn | undefined;
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* Creates a factory for many-to-one relations.
|
|
260
|
+
*/
|
|
261
|
+
static createOneFactory<TOriginEntity extends LiveCollectionAny$1>(): <TEntity extends LiveCollectionAny$1, TColumn extends keyof TOriginEntity["fields"], TRequired extends boolean = false>(entity: TEntity, column: TColumn, required?: TRequired) => Relation<TEntity, TOriginEntity, "one", TColumn, never, TRequired>;
|
|
262
|
+
/**
|
|
263
|
+
* Creates a factory for one-to-many relations.
|
|
264
|
+
*/
|
|
265
|
+
static createManyFactory<TOriginEntity extends LiveCollectionAny$1>(): <TEntity extends LiveCollectionAny$1, TColumn extends keyof TEntity["fields"], TRequired extends boolean = false>(entity: TEntity, foreignColumn: TColumn, required?: TRequired) => Relation<TEntity, TOriginEntity, "many", never, TColumn, TRequired>;
|
|
266
|
+
}
|
|
267
|
+
type RelationAny = Relation<LiveCollectionAny$1, LiveCollectionAny$1, any, any, any, any>;
|
|
268
|
+
/**
|
|
269
|
+
* Connectors for defining relations.
|
|
270
|
+
*/
|
|
271
|
+
type RelationConnectors<TSourceEntity extends LiveCollectionAny$1> = {
|
|
272
|
+
one: ReturnType<typeof Relation.createOneFactory<TSourceEntity>>;
|
|
273
|
+
many: ReturnType<typeof Relation.createManyFactory<TSourceEntity>>;
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* Declaration type for relations defined separately from collections.
|
|
277
|
+
*/
|
|
278
|
+
type RelationsDecl<TCollectionName extends string = string, TRelations extends Record<string, RelationAny> = Record<string, RelationAny>> = {
|
|
279
|
+
$type: "relations";
|
|
280
|
+
collectionName: TCollectionName;
|
|
281
|
+
/** @deprecated Use `collectionName` instead */
|
|
282
|
+
objectName: TCollectionName;
|
|
283
|
+
relations: TRelations;
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Mutation input type for collections.
|
|
288
|
+
*/
|
|
289
|
+
type LiveCollectionMutationInput<TSchema extends LiveCollectionAny> = Partial<{
|
|
290
|
+
[K in keyof TSchema["fields"]]: TSchema["fields"][K]["_value"];
|
|
291
|
+
}>;
|
|
292
|
+
/**
|
|
293
|
+
* Configuration object for creating a collection with inline relations.
|
|
294
|
+
*/
|
|
295
|
+
type CollectionConfig<TName extends string, TFields extends Record<string, LiveTypeAny>, TRelations extends Record<string, RelationAny> = Record<string, never>> = {
|
|
296
|
+
fields: TFields;
|
|
297
|
+
relations?: (connectors: RelationConnectors<LiveCollection<TName, TFields, any>>) => TRelations;
|
|
298
|
+
};
|
|
299
|
+
/**
|
|
300
|
+
* Represents a collection of entities with fields and relations.
|
|
301
|
+
*
|
|
302
|
+
* @template TName - The collection name (used as resource identifier)
|
|
303
|
+
* @template TFields - The field schema
|
|
304
|
+
* @template TRelations - The relations schema
|
|
305
|
+
*/
|
|
306
|
+
declare class LiveCollection<TName extends string, TFields extends Record<string, LiveTypeAny>, TRelations extends Record<string, RelationAny>> extends LiveType<TFields, BaseMeta, LiveCollectionMutationInput<any>, Record<string, MaterializedLiveType<LiveTypeAny>>> {
|
|
307
|
+
readonly name: TName;
|
|
308
|
+
readonly fields: TFields;
|
|
309
|
+
readonly relations: TRelations;
|
|
310
|
+
constructor(name: TName, fields: TFields, relations?: TRelations);
|
|
311
|
+
encodeMutation(_mutationType: MutationType, input: LiveCollectionMutationInput<this>, timestamp: string): Record<string, any>;
|
|
312
|
+
mergeMutation(mutationType: MutationType, encodedMutations: Record<string, MaterializedLiveType<LiveTypeAny>>, materializedShape?: MaterializedLiveType<this> | undefined): [MaterializedLiveType<this>, Record<string, any> | null];
|
|
313
|
+
/**
|
|
314
|
+
* Returns a new collection with the given relations attached.
|
|
315
|
+
*/
|
|
316
|
+
setRelations<TNewRelations extends Record<string, RelationAny>>(relations: TNewRelations): LiveCollection<this["name"], this["fields"], TNewRelations>;
|
|
317
|
+
getStorageFieldType(): StorageFieldType;
|
|
318
|
+
/**
|
|
319
|
+
* Creates a new collection with fields only.
|
|
320
|
+
*/
|
|
321
|
+
static create<TName extends string, TFields extends Record<string, LiveTypeAny>>(name: TName, fields: TFields): LiveCollection<TName, TFields, Record<string, never>>;
|
|
322
|
+
/**
|
|
323
|
+
* Creates a new collection with fields and inline relations.
|
|
324
|
+
*/
|
|
325
|
+
static create<TName extends string, TFields extends Record<string, LiveTypeAny>, TRelations extends Record<string, RelationAny>>(name: TName, config: CollectionConfig<TName, TFields, TRelations>): LiveCollection<TName, TFields, TRelations>;
|
|
326
|
+
}
|
|
327
|
+
type LiveCollectionAny = LiveCollection<string, Record<string, LiveTypeAny>, any>;
|
|
328
|
+
/** @deprecated Use `LiveCollectionAny` instead */
|
|
329
|
+
type LiveObjectAny = LiveCollectionAny;
|
|
330
|
+
|
|
331
|
+
/** biome-ignore-all lint/complexity/noBannedTypes: false positive */
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Where clause for filtering collections.
|
|
335
|
+
* Supports field comparisons, operators, and nested relation queries.
|
|
336
|
+
*/
|
|
337
|
+
type WhereClause<T extends LiveCollectionAny> = ({
|
|
338
|
+
[K in keyof T["fields"]]?: InferLiveType<T["fields"][K]> | ({
|
|
339
|
+
$eq?: InferLiveType<T["fields"][K]>;
|
|
340
|
+
$in?: InferLiveType<T["fields"][K]>[];
|
|
341
|
+
$not?: InferLiveType<T["fields"][K]> | {
|
|
342
|
+
$in?: InferLiveType<T["fields"][K]>[];
|
|
343
|
+
$eq?: InferLiveType<T["fields"][K]>;
|
|
344
|
+
};
|
|
345
|
+
} & (Exclude<InferLiveType<T["fields"][K]>, null | undefined> extends number | Date ? {
|
|
346
|
+
$gt?: InferLiveType<T["fields"][K]>;
|
|
347
|
+
$gte?: InferLiveType<T["fields"][K]>;
|
|
348
|
+
$lt?: InferLiveType<T["fields"][K]>;
|
|
349
|
+
$lte?: InferLiveType<T["fields"][K]>;
|
|
350
|
+
} : {}));
|
|
351
|
+
} & {
|
|
352
|
+
[K in keyof T["relations"]]?: WhereClause<T["relations"][K]["entity"]>;
|
|
353
|
+
}) | {
|
|
354
|
+
$and?: WhereClause<T>[];
|
|
355
|
+
$or?: WhereClause<T>[];
|
|
356
|
+
};
|
|
357
|
+
/**
|
|
358
|
+
* Sub-query options for nested includes.
|
|
359
|
+
* Allows filtering, sorting, and pagination of related collections.
|
|
360
|
+
*/
|
|
361
|
+
type SubQueryInclude<T extends LiveCollectionAny> = {
|
|
362
|
+
where?: WhereClause<T>;
|
|
363
|
+
limit?: number;
|
|
364
|
+
orderBy?: {
|
|
365
|
+
key: keyof T["fields"] & string;
|
|
366
|
+
direction: "asc" | "desc";
|
|
367
|
+
}[];
|
|
368
|
+
include?: IncludeClause<T>;
|
|
369
|
+
};
|
|
370
|
+
/**
|
|
371
|
+
* Include clause for specifying which relations to fetch.
|
|
372
|
+
* Can be a boolean or a sub-query for fine-grained control.
|
|
373
|
+
*/
|
|
374
|
+
type IncludeClause<T extends LiveCollectionAny> = {
|
|
375
|
+
[K in keyof T["relations"]]?: boolean | SubQueryInclude<T["relations"][K]["entity"]>;
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
type Simplify<T> = T extends object ? {
|
|
379
|
+
[K in keyof T]: T[K];
|
|
380
|
+
} : T;
|
|
381
|
+
declare const LogLevel: {
|
|
382
|
+
readonly CRITICAL: 0;
|
|
383
|
+
readonly ERROR: 1;
|
|
384
|
+
readonly WARN: 2;
|
|
385
|
+
readonly INFO: 3;
|
|
386
|
+
readonly DEBUG: 4;
|
|
387
|
+
};
|
|
388
|
+
type LogLevel = (typeof LogLevel)[keyof typeof LogLevel];
|
|
389
|
+
/**
|
|
390
|
+
* Logger configuration options
|
|
391
|
+
*/
|
|
392
|
+
interface LoggerOptions {
|
|
393
|
+
/**
|
|
394
|
+
* Minimum log level to display. Anything below this level will be muted.
|
|
395
|
+
* @default LogLevel.INFO
|
|
396
|
+
*/
|
|
397
|
+
level?: LogLevel;
|
|
398
|
+
/**
|
|
399
|
+
* Optional prefix to add to all log messages
|
|
400
|
+
*/
|
|
401
|
+
prefix?: string;
|
|
402
|
+
}
|
|
403
|
+
declare class Logger {
|
|
404
|
+
private level;
|
|
405
|
+
private prefix;
|
|
406
|
+
constructor(options?: LoggerOptions);
|
|
407
|
+
critical(...args: any[]): void;
|
|
408
|
+
error(...args: any[]): void;
|
|
409
|
+
warn(...args: any[]): void;
|
|
410
|
+
info(...args: any[]): void;
|
|
411
|
+
debug(...args: any[]): void;
|
|
412
|
+
setLevel(level: LogLevel): void;
|
|
413
|
+
getLevel(): LogLevel;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Infers the TypeScript type of a collection without relations.
|
|
418
|
+
*/
|
|
419
|
+
type InferLiveCollectionWithoutRelations<T extends LiveCollectionAny> = {
|
|
420
|
+
[K in keyof T["fields"]]: InferLiveType<T["fields"][K]>;
|
|
421
|
+
};
|
|
422
|
+
/**
|
|
423
|
+
* Infers the full TypeScript type of a collection with optional relations.
|
|
424
|
+
*
|
|
425
|
+
* @template T - The collection type
|
|
426
|
+
* @template Include - The include clause specifying which relations to include
|
|
427
|
+
*/
|
|
428
|
+
type InferLiveCollection<T extends LiveCollectionAny, Include extends IncludeClause<T> | undefined = undefined> = Simplify<InferLiveCollectionWithoutRelations<T> & (Include extends IncludeClause<T> ? {
|
|
429
|
+
[K in keyof T["relations"] as Include[K] extends true | SubQueryInclude<T["relations"][K]["entity"]> ? K : never]: Include[K] extends true ? T["relations"][K]["type"] extends "one" ? T["fields"][Exclude<T["relations"][K]["relationalColumn"], undefined>] extends NullableLiveType<any> ? InferLiveCollection<T["relations"][K]["entity"]> | null : InferLiveCollection<T["relations"][K]["entity"]> : InferLiveCollection<T["relations"][K]["entity"]>[] : Include[K] extends SubQueryInclude<T["relations"][K]["entity"]> ? T["relations"][K]["type"] extends "one" ? T["fields"][Exclude<T["relations"][K]["relationalColumn"], undefined>] extends NullableLiveType<any> ? InferLiveCollection<T["relations"][K]["entity"], Include[K]["include"]> | null : InferLiveCollection<T["relations"][K]["entity"], Include[K]["include"]> : InferLiveCollection<T["relations"][K]["entity"], Include[K]["include"]>[] : never;
|
|
430
|
+
} : object)>;
|
|
431
|
+
type GetFieldType<T> = T extends NullableLiveType<any> ? T["inner"] : T;
|
|
432
|
+
type HasDefaultValue<T> = T extends {
|
|
433
|
+
defaultValue: undefined;
|
|
434
|
+
} ? false : true;
|
|
435
|
+
/**
|
|
436
|
+
* Infers the insert type for a collection.
|
|
437
|
+
* Fields without defaults are required, fields with defaults are optional.
|
|
438
|
+
*/
|
|
439
|
+
type InferInsert<T extends LiveCollectionAny> = Simplify<{
|
|
440
|
+
[K in keyof T["fields"] as HasDefaultValue<GetFieldType<T["fields"][K]>> extends true ? never : K]: InferLiveType<T["fields"][K]>;
|
|
441
|
+
} & {
|
|
442
|
+
[K in keyof T["fields"] as HasDefaultValue<GetFieldType<T["fields"][K]>> extends false ? never : K]?: InferLiveType<T["fields"][K]>;
|
|
443
|
+
}>;
|
|
444
|
+
/**
|
|
445
|
+
* Infers the update type for a collection.
|
|
446
|
+
* All fields are optional except id which is excluded.
|
|
447
|
+
*/
|
|
448
|
+
type InferUpdate<T extends LiveCollectionAny> = Simplify<Omit<LiveCollectionMutationInput<T>, "id">>;
|
|
449
|
+
/** @deprecated Use `InferLiveCollection` instead */
|
|
450
|
+
type InferLiveObject<T extends LiveCollectionAny, Include extends IncludeClause<T> | undefined = undefined> = InferLiveCollection<T, Include>;
|
|
451
|
+
|
|
452
|
+
type ExtractObjectValues<T> = T[keyof T];
|
|
453
|
+
type ParseRelationsFromSchema<TRawSchema extends RawSchema, TCollectionName extends string> = ExtractObjectValues<{
|
|
454
|
+
[K in keyof TRawSchema]: TRawSchema[K] extends RelationsDecl<infer TCollectionName_, any> ? TCollectionName_ extends TCollectionName ? {
|
|
455
|
+
[K2 in keyof TRawSchema[K]["relations"]]: Relation<ParseCollectionFromSchema<TRawSchema, TRawSchema[K]["relations"][K2]["entity"]["name"]>, TRawSchema[K]["relations"][K2]["sourceEntity"], TRawSchema[K]["relations"][K2]["type"], Exclude<TRawSchema[K]["relations"][K2]["relationalColumn"], undefined>, Exclude<TRawSchema[K]["relations"][K2]["foreignColumn"], undefined>, TRawSchema[K]["relations"][K2]["required"]>;
|
|
456
|
+
} : never : never;
|
|
457
|
+
}>;
|
|
458
|
+
type ParseCollectionFromSchema<TRawSchema extends RawSchema, TCollectionName extends string> = ExtractObjectValues<{
|
|
459
|
+
[K in keyof TRawSchema]: TRawSchema[K] extends LiveCollectionAny ? TRawSchema[K]["name"] extends TCollectionName ? LiveCollection<TRawSchema[K]["name"], TRawSchema[K]["fields"], ParseRelationsFromSchema<TRawSchema, TRawSchema[K]["name"]>> : never : never;
|
|
460
|
+
}>;
|
|
461
|
+
type RawSchema = Record<string, LiveCollectionAny | RelationsDecl>;
|
|
462
|
+
/**
|
|
463
|
+
* The final schema type with all collections and their relations resolved.
|
|
464
|
+
*/
|
|
465
|
+
type Schema<TRawSchema extends RawSchema> = {
|
|
466
|
+
[K in keyof TRawSchema as TRawSchema[K] extends LiveCollectionAny ? TRawSchema[K]["name"] : never]: TRawSchema[K] extends LiveCollectionAny ? ParseCollectionFromSchema<TRawSchema, TRawSchema[K]["name"]> : never;
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
type Promisify<T> = T extends Promise<unknown> ? T : Promise<T>;
|
|
470
|
+
type ConditionalPromise<T, P extends boolean> = P extends true ? Promise<T> : T;
|
|
471
|
+
type PromiseOrSync<T> = T | Promise<T>;
|
|
472
|
+
type Generatable<T, Arg = never> = T | ((arg: Arg) => T);
|
|
473
|
+
|
|
474
|
+
declare const querySchema: z.ZodObject<{
|
|
475
|
+
resource: z.ZodString;
|
|
476
|
+
where: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
477
|
+
include: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
478
|
+
lastSyncedAt: z.ZodOptional<z.ZodString>;
|
|
479
|
+
limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
480
|
+
sort: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
481
|
+
key: z.ZodString;
|
|
482
|
+
direction: z.ZodEnum<{
|
|
483
|
+
asc: "asc";
|
|
484
|
+
desc: "desc";
|
|
485
|
+
}>;
|
|
486
|
+
}, z.core.$strip>>>;
|
|
487
|
+
}, z.core.$strip>;
|
|
488
|
+
type RawQueryRequest = z.infer<typeof querySchema>;
|
|
489
|
+
declare const customQuerySchema: z.ZodObject<{
|
|
490
|
+
resource: z.ZodString;
|
|
491
|
+
procedure: z.ZodString;
|
|
492
|
+
input: z.ZodOptional<z.ZodAny>;
|
|
493
|
+
}, z.core.$strip>;
|
|
494
|
+
type CustomQueryRequest = z.infer<typeof customQuerySchema>;
|
|
495
|
+
|
|
496
|
+
/** biome-ignore-all lint/complexity/noBannedTypes: <explanation> */
|
|
497
|
+
|
|
498
|
+
type InferQueryResult<TCollection extends LiveObjectAny, TInclude extends IncludeClause<TCollection>, TSingle extends boolean = false> = TSingle extends true ? Simplify<InferLiveObject<TCollection, TInclude>> | undefined : Simplify<InferLiveObject<TCollection, TInclude>>[];
|
|
499
|
+
declare class QueryBuilder<TCollection extends LiveObjectAny, TInclude extends IncludeClause<TCollection> = {}, TSingle extends boolean = false, TShouldAwait extends boolean = false> {
|
|
500
|
+
private _collection;
|
|
501
|
+
private _client;
|
|
502
|
+
private _where;
|
|
503
|
+
private _include;
|
|
504
|
+
private _limit?;
|
|
505
|
+
private _single?;
|
|
506
|
+
private _sort?;
|
|
507
|
+
private _shouldAwait?;
|
|
508
|
+
private constructor();
|
|
509
|
+
where(where: WhereClause<TCollection>): QueryBuilder<TCollection, TInclude, TSingle, TShouldAwait>;
|
|
510
|
+
include<TNewInclude extends IncludeClause<TCollection>>(include: TNewInclude): QueryBuilder<TCollection, TInclude & TNewInclude, TSingle, TShouldAwait>;
|
|
511
|
+
limit(limit: number): QueryBuilder<TCollection, TInclude, TSingle, TShouldAwait>;
|
|
512
|
+
one(id: string): QueryBuilder<TCollection, TInclude, true, TShouldAwait>;
|
|
513
|
+
first(where?: WhereClause<TCollection>): QueryBuilder<TCollection, TInclude, true, TShouldAwait>;
|
|
514
|
+
orderBy(key: keyof TCollection["fields"], direction?: "asc" | "desc"): QueryBuilder<TCollection, TInclude, TSingle, TShouldAwait>;
|
|
515
|
+
toJSON(): {
|
|
516
|
+
resource: string;
|
|
517
|
+
where: WhereClause<TCollection>;
|
|
518
|
+
include: TInclude;
|
|
519
|
+
limit: number | undefined;
|
|
520
|
+
sort: {
|
|
521
|
+
key: string;
|
|
522
|
+
direction: "asc" | "desc";
|
|
523
|
+
}[] | undefined;
|
|
524
|
+
};
|
|
525
|
+
buildQueryRequest(): RawQueryRequest;
|
|
526
|
+
get(): ConditionalPromise<InferQueryResult<TCollection, TInclude, TSingle>, TShouldAwait>;
|
|
527
|
+
subscribe(callback: (value: InferQueryResult<TCollection, TInclude, TSingle>) => void): () => void;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Extracts the output type from a Standard Schema validator.
|
|
532
|
+
* Supports Standard Schema (via ~standard property) and Zod schemas (via _output property for backward compatibility).
|
|
533
|
+
*/
|
|
534
|
+
type InferSchema$1<T> = T extends {
|
|
535
|
+
"~standard": {
|
|
536
|
+
types?: {
|
|
537
|
+
output: infer U;
|
|
538
|
+
};
|
|
539
|
+
};
|
|
540
|
+
} ? U : T extends StandardSchemaV1<any, any> ? StandardSchemaV1.InferOutput<T> : T extends {
|
|
541
|
+
_output: infer U;
|
|
542
|
+
} ? U : never;
|
|
543
|
+
/**
|
|
544
|
+
* Helper type for custom mutation functions.
|
|
545
|
+
* When the input type is `never` or `undefined`, the function has no parameters.
|
|
546
|
+
*/
|
|
547
|
+
type CustomMutationFunction<TInput, TOutput> = [TInput] extends [never] | [undefined] ? () => Promisify<TOutput> : (input: TInput) => Promisify<TOutput>;
|
|
548
|
+
/**
|
|
549
|
+
* Helper type for custom query functions.
|
|
550
|
+
* When the input type is `never` or `undefined`, the function has no parameters.
|
|
551
|
+
*/
|
|
552
|
+
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
|
|
553
|
+
type CustomQueryLoadable<TOutput> = PromiseLike<TOutput> & {
|
|
554
|
+
buildQueryRequest: () => CustomQueryRequest;
|
|
555
|
+
};
|
|
556
|
+
type CustomQueryResult<TOutput, TShouldAwait extends boolean = false> = UnwrapPromise<TOutput> extends QueryBuilder<infer TCollection, infer TInclude, infer TSingle, any> ? TShouldAwait extends true ? TSingle extends true ? Promise<Simplify<InferLiveObject<TCollection, TInclude>> | undefined> : Promise<Simplify<InferLiveObject<TCollection, TInclude>>[]> : TSingle extends true ? CustomQueryLoadable<Simplify<InferLiveObject<TCollection, TInclude>> | undefined> : CustomQueryLoadable<Simplify<InferLiveObject<TCollection, TInclude>>[]> : Promisify<UnwrapPromise<TOutput>>;
|
|
557
|
+
type CustomQueryFunction<TInput, TOutput, TShouldAwait extends boolean = false> = [TInput] extends [never] | [undefined] ? () => CustomQueryResult<TOutput, TShouldAwait> : (input: TInput) => CustomQueryResult<TOutput, TShouldAwait>;
|
|
558
|
+
/**
|
|
559
|
+
* Simplified router constraint for client-side usage.
|
|
560
|
+
* This avoids importing server-internal types like Storage and Hooks,
|
|
561
|
+
* which can cause type incompatibilities when the package is bundled.
|
|
562
|
+
*/
|
|
563
|
+
type ClientRouterConstraint = {
|
|
564
|
+
routes: Record<string, {
|
|
565
|
+
resourceSchema: LiveObjectAny | undefined;
|
|
566
|
+
customMutations: Record<string, {
|
|
567
|
+
_type: "mutation";
|
|
568
|
+
inputValidator: StandardSchemaV1<any, any>;
|
|
569
|
+
handler: (...args: any[]) => any;
|
|
570
|
+
}>;
|
|
571
|
+
customQueries: Record<string, {
|
|
572
|
+
_type: "query";
|
|
573
|
+
inputValidator: StandardSchemaV1<any, any>;
|
|
574
|
+
handler: (...args: any[]) => any;
|
|
575
|
+
}>;
|
|
576
|
+
}>;
|
|
577
|
+
};
|
|
578
|
+
type CollectionQueryType<TRoute extends ClientRouterConstraint["routes"][string], TShouldAwait extends boolean> = TRoute["resourceSchema"] extends LiveObjectAny ? QueryBuilder<TRoute["resourceSchema"], {}, false, TShouldAwait> & {
|
|
579
|
+
[K2 in keyof TRoute["customQueries"]]: CustomQueryFunction<InferSchema$1<TRoute["customQueries"][K2]["inputValidator"]>, ReturnType<TRoute["customQueries"][K2]["handler"]>, TShouldAwait>;
|
|
580
|
+
} : {
|
|
581
|
+
[K2 in keyof TRoute["customQueries"]]: CustomQueryFunction<InferSchema$1<TRoute["customQueries"][K2]["inputValidator"]>, ReturnType<TRoute["customQueries"][K2]["handler"]>, TShouldAwait>;
|
|
582
|
+
};
|
|
583
|
+
type CollectionMutateType<TRoute extends ClientRouterConstraint["routes"][string], TShouldAwait extends boolean> = TRoute["resourceSchema"] extends LiveObjectAny ? {
|
|
584
|
+
insert: (input: Simplify<InferInsert<TRoute["resourceSchema"]>>) => ConditionalPromise<void, TShouldAwait>;
|
|
585
|
+
update: (id: string, value: Simplify<InferUpdate<TRoute["resourceSchema"]>>) => ConditionalPromise<void, TShouldAwait>;
|
|
586
|
+
} & {
|
|
587
|
+
[K2 in keyof TRoute["customMutations"]]: CustomMutationFunction<InferSchema$1<TRoute["customMutations"][K2]["inputValidator"]>, ReturnType<TRoute["customMutations"][K2]["handler"]>>;
|
|
588
|
+
} : {
|
|
589
|
+
[K2 in keyof TRoute["customMutations"]]: CustomMutationFunction<InferSchema$1<TRoute["customMutations"][K2]["inputValidator"]>, ReturnType<TRoute["customMutations"][K2]["handler"]>>;
|
|
590
|
+
};
|
|
591
|
+
type Client$1<TRouter extends ClientRouterConstraint, TShouldAwait extends boolean = false> = {
|
|
592
|
+
query: {
|
|
593
|
+
[K in keyof TRouter["routes"]]: CollectionQueryType<TRouter["routes"][K], TShouldAwait>;
|
|
594
|
+
};
|
|
595
|
+
mutate: {
|
|
596
|
+
[K in keyof TRouter["routes"]]: CollectionMutateType<TRouter["routes"][K], TShouldAwait>;
|
|
597
|
+
};
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Extracts the output type from a Standard Schema validator.
|
|
602
|
+
*/
|
|
603
|
+
type InferSchema<T> = T extends {
|
|
604
|
+
"~standard": {
|
|
605
|
+
types?: {
|
|
606
|
+
output: infer U;
|
|
607
|
+
};
|
|
608
|
+
};
|
|
609
|
+
} ? U : T extends StandardSchemaV1<any, any> ? StandardSchemaV1.InferOutput<T> : T extends {
|
|
610
|
+
_output: infer U;
|
|
611
|
+
} ? U : never;
|
|
612
|
+
/**
|
|
613
|
+
* Operation types for optimistic mutations.
|
|
614
|
+
*/
|
|
615
|
+
type OptimisticInsertOperation<T extends LiveCollectionAny> = {
|
|
616
|
+
type: "insert";
|
|
617
|
+
resource: string;
|
|
618
|
+
id: string;
|
|
619
|
+
data: Simplify<InferInsert<T>>;
|
|
620
|
+
};
|
|
621
|
+
type OptimisticUpdateOperation<T extends LiveCollectionAny> = {
|
|
622
|
+
type: "update";
|
|
623
|
+
resource: string;
|
|
624
|
+
id: string;
|
|
625
|
+
data: Simplify<InferUpdate<T>>;
|
|
626
|
+
};
|
|
627
|
+
type OptimisticOperation<T extends LiveCollectionAny = LiveCollectionAny> = OptimisticInsertOperation<T> | OptimisticUpdateOperation<T>;
|
|
628
|
+
/**
|
|
629
|
+
* Query builder type for the storage proxy (read-only operations).
|
|
630
|
+
*/
|
|
631
|
+
type OptimisticQueryBuilder<T extends LiveCollectionAny> = {
|
|
632
|
+
one: (id: string) => {
|
|
633
|
+
get: () => Simplify<InferLiveCollection<T>> | undefined;
|
|
634
|
+
include: <TInclude extends Record<string, boolean | object>>(include: TInclude) => {
|
|
635
|
+
get: () => Simplify<InferLiveCollection<T, TInclude>> | undefined;
|
|
636
|
+
};
|
|
637
|
+
};
|
|
638
|
+
where: (where: Record<string, unknown>) => {
|
|
639
|
+
get: () => Simplify<InferLiveCollection<T>>[];
|
|
640
|
+
include: <TInclude extends Record<string, boolean | object>>(include: TInclude) => {
|
|
641
|
+
get: () => Simplify<InferLiveCollection<T, TInclude>>[];
|
|
642
|
+
};
|
|
643
|
+
};
|
|
644
|
+
get: () => Simplify<InferLiveCollection<T>>[];
|
|
645
|
+
include: <TInclude extends Record<string, boolean | object>>(include: TInclude) => {
|
|
646
|
+
get: () => Simplify<InferLiveCollection<T, TInclude>>[];
|
|
647
|
+
};
|
|
648
|
+
};
|
|
649
|
+
/**
|
|
650
|
+
* Mutation methods for the storage proxy (write operations).
|
|
651
|
+
*/
|
|
652
|
+
type OptimisticMutationMethods<T extends LiveCollectionAny> = {
|
|
653
|
+
insert: (data: Simplify<InferInsert<T>> & {
|
|
654
|
+
id: string;
|
|
655
|
+
}) => void;
|
|
656
|
+
update: (id: string, data: Simplify<InferUpdate<T>>) => void;
|
|
657
|
+
};
|
|
658
|
+
/**
|
|
659
|
+
* Combined storage proxy type with both query and mutation capabilities.
|
|
660
|
+
*/
|
|
661
|
+
type OptimisticStorageProxy<TSchema extends Schema<any>> = {
|
|
662
|
+
[K in keyof TSchema]: OptimisticQueryBuilder<TSchema[K]> & OptimisticMutationMethods<TSchema[K]>;
|
|
663
|
+
};
|
|
664
|
+
/**
|
|
665
|
+
* Context passed to optimistic mutation handlers.
|
|
666
|
+
*/
|
|
667
|
+
type OptimisticHandlerContext<TSchema extends Schema<any>, TInput> = {
|
|
668
|
+
input: TInput;
|
|
669
|
+
storage: OptimisticStorageProxy<TSchema>;
|
|
670
|
+
};
|
|
671
|
+
/**
|
|
672
|
+
* Type for a single optimistic mutation handler.
|
|
673
|
+
*/
|
|
674
|
+
type OptimisticMutationHandler<TSchema extends Schema<any>, TInput> = (ctx: OptimisticHandlerContext<TSchema, TInput>) => void;
|
|
675
|
+
/**
|
|
676
|
+
* Configuration type for defineOptimisticMutations.
|
|
677
|
+
* Maps route names to procedure names to handlers.
|
|
678
|
+
*/
|
|
679
|
+
type OptimisticMutationsConfig<TRouter extends ClientRouterConstraint, TSchema extends Schema<any>> = {
|
|
680
|
+
[K in keyof TRouter["routes"]]?: {
|
|
681
|
+
[K2 in keyof TRouter["routes"][K]["customMutations"]]?: OptimisticMutationHandler<TSchema, InferSchema<TRouter["routes"][K]["customMutations"][K2]["inputValidator"]>>;
|
|
682
|
+
};
|
|
683
|
+
};
|
|
684
|
+
/**
|
|
685
|
+
* Registry type returned by defineOptimisticMutations.
|
|
686
|
+
* Used internally to look up handlers by route and procedure.
|
|
687
|
+
*/
|
|
688
|
+
type OptimisticMutationsRegistry<TSchema extends Schema<any>> = {
|
|
689
|
+
getHandler: (route: string, procedure: string) => OptimisticMutationHandler<TSchema, any> | undefined;
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
declare const defaultMutationMsgSchema: z.ZodObject<{
|
|
693
|
+
type: z.ZodLiteral<"MUTATE">;
|
|
694
|
+
resource: z.ZodString;
|
|
695
|
+
resourceId: z.ZodOptional<z.ZodString>;
|
|
696
|
+
procedure: z.ZodEnum<{
|
|
697
|
+
INSERT: "INSERT";
|
|
698
|
+
UPDATE: "UPDATE";
|
|
699
|
+
}>;
|
|
700
|
+
payload: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
701
|
+
value: z.ZodNullable<z.ZodAny>;
|
|
702
|
+
_meta: z.ZodOptional<z.ZodObject<{
|
|
703
|
+
timestamp: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
704
|
+
}, z.core.$strip>>;
|
|
705
|
+
}, z.core.$strip>>;
|
|
706
|
+
meta: z.ZodOptional<z.ZodObject<{
|
|
707
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
708
|
+
}, z.core.$strip>>;
|
|
709
|
+
id: z.ZodString;
|
|
710
|
+
}, z.core.$strip>;
|
|
711
|
+
type DefaultMutationMessage = Omit<z.infer<typeof defaultMutationMsgSchema>, 'resourceId'> & {
|
|
712
|
+
resourceId: string;
|
|
713
|
+
};
|
|
714
|
+
declare const mutationMsgSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
715
|
+
type: z.ZodLiteral<"MUTATE">;
|
|
716
|
+
resource: z.ZodString;
|
|
717
|
+
resourceId: z.ZodOptional<z.ZodString>;
|
|
718
|
+
procedure: z.ZodString;
|
|
719
|
+
payload: z.ZodOptional<z.ZodAny>;
|
|
720
|
+
meta: z.ZodOptional<z.ZodObject<{
|
|
721
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
722
|
+
}, z.core.$strip>>;
|
|
723
|
+
id: z.ZodString;
|
|
724
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
725
|
+
type: z.ZodLiteral<"MUTATE">;
|
|
726
|
+
resource: z.ZodString;
|
|
727
|
+
resourceId: z.ZodOptional<z.ZodString>;
|
|
728
|
+
procedure: z.ZodEnum<{
|
|
729
|
+
INSERT: "INSERT";
|
|
730
|
+
UPDATE: "UPDATE";
|
|
731
|
+
}>;
|
|
732
|
+
payload: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
733
|
+
value: z.ZodNullable<z.ZodAny>;
|
|
734
|
+
_meta: z.ZodOptional<z.ZodObject<{
|
|
735
|
+
timestamp: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
736
|
+
}, z.core.$strip>>;
|
|
737
|
+
}, z.core.$strip>>;
|
|
738
|
+
meta: z.ZodOptional<z.ZodObject<{
|
|
739
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
740
|
+
}, z.core.$strip>>;
|
|
741
|
+
id: z.ZodString;
|
|
742
|
+
}, z.core.$strip>]>;
|
|
743
|
+
type MutationMessage = z.infer<typeof mutationMsgSchema>;
|
|
744
|
+
declare const serverMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
745
|
+
id: z.ZodString;
|
|
746
|
+
type: z.ZodLiteral<"REJECT">;
|
|
747
|
+
resource: z.ZodString;
|
|
748
|
+
message: z.ZodOptional<z.ZodString>;
|
|
749
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
750
|
+
id: z.ZodString;
|
|
751
|
+
type: z.ZodLiteral<"REPLY">;
|
|
752
|
+
data: z.ZodAny;
|
|
753
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
754
|
+
type: z.ZodLiteral<"MUTATE">;
|
|
755
|
+
resource: z.ZodString;
|
|
756
|
+
resourceId: z.ZodOptional<z.ZodString>;
|
|
757
|
+
procedure: z.ZodEnum<{
|
|
758
|
+
INSERT: "INSERT";
|
|
759
|
+
UPDATE: "UPDATE";
|
|
760
|
+
}>;
|
|
761
|
+
payload: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
762
|
+
value: z.ZodNullable<z.ZodAny>;
|
|
763
|
+
_meta: z.ZodOptional<z.ZodObject<{
|
|
764
|
+
timestamp: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
765
|
+
}, z.core.$strip>>;
|
|
766
|
+
}, z.core.$strip>>;
|
|
767
|
+
meta: z.ZodOptional<z.ZodObject<{
|
|
768
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
769
|
+
}, z.core.$strip>>;
|
|
770
|
+
id: z.ZodString;
|
|
771
|
+
}, z.core.$strip>]>;
|
|
772
|
+
type ServerMessage = z.infer<typeof serverMessageSchema>;
|
|
773
|
+
|
|
774
|
+
declare class OptimisticStore {
|
|
775
|
+
readonly schema: Schema<any>;
|
|
776
|
+
private rawObjPool;
|
|
777
|
+
optimisticMutationStack: Record<string, DefaultMutationMessage[]>;
|
|
778
|
+
customMutationStack: MutationMessage[];
|
|
779
|
+
private optimisticObjGraph;
|
|
780
|
+
private optimisticRawObjPool;
|
|
781
|
+
private logger;
|
|
782
|
+
private onQuerySubscriptionTriggered?;
|
|
783
|
+
customMutationIndex: Record<string, Array<{
|
|
784
|
+
resource: string;
|
|
785
|
+
mutationId: string;
|
|
786
|
+
}>>;
|
|
787
|
+
private collectionSubscriptions;
|
|
788
|
+
private querySnapshots;
|
|
789
|
+
private kvStorage;
|
|
790
|
+
constructor(schema: Schema<any>, storage: ClientOptions["storage"], logger: Logger, afterLoadMutations?: (stack: typeof this.optimisticMutationStack, customStack: MutationMessage[], customIndex: typeof this.customMutationIndex) => void, onStorageLoaded?: (resource: string, itemCount: number) => void, onQuerySubscriptionTriggered?: (query: RawQueryRequest) => void);
|
|
791
|
+
get(query: RawQueryRequest, _queryKey?: string, force?: boolean): any;
|
|
792
|
+
subscribe(query: RawQueryRequest, listener: (v: any[]) => void): () => void;
|
|
793
|
+
addMutation(routeName: string, mutation: DefaultMutationMessage, optimistic?: boolean): void;
|
|
794
|
+
undoMutation(routeName: string, mutationId: string): void;
|
|
795
|
+
addCustomMutationMessage(message: MutationMessage): void;
|
|
796
|
+
registerCustomMutation(messageId: string, mutations: Array<{
|
|
797
|
+
resource: string;
|
|
798
|
+
mutationId: string;
|
|
799
|
+
}>): void;
|
|
800
|
+
confirmCustomMutation(messageId: string): void;
|
|
801
|
+
undoCustomMutation(messageId: string): Array<{
|
|
802
|
+
resource: string;
|
|
803
|
+
mutationId: string;
|
|
804
|
+
resourceId: string;
|
|
805
|
+
}>;
|
|
806
|
+
getCustomMutationMutationIds(): Set<string>;
|
|
807
|
+
loadConsolidatedState(resourceType: string, data: DefaultMutationMessage["payload"][]): void;
|
|
808
|
+
private extractNestedRelations;
|
|
809
|
+
private updateRawObjPool;
|
|
810
|
+
private materializeOneWithInclude;
|
|
811
|
+
private notifyCollectionSubscribers;
|
|
812
|
+
private flattenIncludes;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* Creates an optimistic storage proxy that:
|
|
817
|
+
* - Provides synchronous read access to the optimistic state via QueryBuilder-like methods
|
|
818
|
+
* - Collects insert/update operations in an internal array
|
|
819
|
+
* - Returns collected operations via getOperations()
|
|
820
|
+
*/
|
|
821
|
+
declare const createOptimisticStorageProxy: <TSchema extends Schema<any>>(store: OptimisticStore, schema: TSchema) => {
|
|
822
|
+
proxy: OptimisticStorageProxy<TSchema>;
|
|
823
|
+
getOperations: () => OptimisticOperation[];
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Defines optimistic mutation handlers for custom mutations.
|
|
828
|
+
*
|
|
829
|
+
* These handlers are executed client-side before the mutation is sent to the server,
|
|
830
|
+
* allowing for instant UI updates. If the server rejects the mutation, the optimistic
|
|
831
|
+
* changes are automatically rolled back.
|
|
832
|
+
*
|
|
833
|
+
* @example
|
|
834
|
+
* ```ts
|
|
835
|
+
* const optimisticMutations = defineOptimisticMutations<typeof router, typeof schema>({
|
|
836
|
+
* posts: {
|
|
837
|
+
* like: ({ input, storage }) => {
|
|
838
|
+
* const post = storage.posts.one(input.postId).get();
|
|
839
|
+
* if (post) {
|
|
840
|
+
* storage.posts.update(input.postId, { likes: post.likes + 1 });
|
|
841
|
+
* }
|
|
842
|
+
* },
|
|
843
|
+
* },
|
|
844
|
+
* });
|
|
845
|
+
*
|
|
846
|
+
* const client = createClient({
|
|
847
|
+
* url: 'ws://localhost:3000',
|
|
848
|
+
* schema,
|
|
849
|
+
* optimisticMutations,
|
|
850
|
+
* });
|
|
851
|
+
* ```
|
|
852
|
+
*/
|
|
853
|
+
declare const defineOptimisticMutations: <TRouter extends ClientRouterConstraint, TSchema extends Schema<any>>(config: OptimisticMutationsConfig<TRouter, TSchema>) => OptimisticMutationsRegistry<TSchema>;
|
|
854
|
+
|
|
855
|
+
declare const useLiveQuery: <T extends {
|
|
856
|
+
get: () => U;
|
|
857
|
+
subscribe: (cb: (v: U) => void) => () => void;
|
|
858
|
+
}, U>(observable: T) => ReturnType<T["get"]>;
|
|
859
|
+
declare const useLoadData: (client: Client<ClientRouterConstraint>["client"], query: {
|
|
860
|
+
buildQueryRequest: () => RawQueryRequest | CustomQueryRequest;
|
|
861
|
+
}) => void;
|
|
862
|
+
|
|
863
|
+
type WebSocketClientEventMap = WebSocketEventMap & {
|
|
864
|
+
connectionChange: {
|
|
865
|
+
open: boolean;
|
|
866
|
+
};
|
|
867
|
+
};
|
|
868
|
+
declare class WebSocketClient {
|
|
869
|
+
private ws;
|
|
870
|
+
private url;
|
|
871
|
+
private autoConnect;
|
|
872
|
+
private autoReconnect;
|
|
873
|
+
private reconnectTimeout;
|
|
874
|
+
private reconnectLimit?;
|
|
875
|
+
private reconnectAttempts;
|
|
876
|
+
private eventListeners;
|
|
877
|
+
private reconnectTimer;
|
|
878
|
+
private intentionallyDisconnected;
|
|
879
|
+
private credentials?;
|
|
880
|
+
constructor(options: {
|
|
881
|
+
url: string;
|
|
882
|
+
autoConnect?: boolean;
|
|
883
|
+
autoReconnect?: boolean;
|
|
884
|
+
reconnectTimeout?: number;
|
|
885
|
+
reconnectLimit?: number;
|
|
886
|
+
credentials?: ClientOptions["credentials"];
|
|
887
|
+
});
|
|
888
|
+
connected(): boolean;
|
|
889
|
+
connect(): Promise<void>;
|
|
890
|
+
disconnect(): void;
|
|
891
|
+
addEventListener<K extends keyof WebSocketClientEventMap>(event: K, callback: (event: WebSocketClientEventMap[K]) => void): void;
|
|
892
|
+
removeEventListener<K extends keyof WebSocketClientEventMap>(event: K, callback: (event: WebSocketClientEventMap[K]) => void): void;
|
|
893
|
+
send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;
|
|
894
|
+
private handleOpen;
|
|
895
|
+
private handleClose;
|
|
896
|
+
private handleError;
|
|
897
|
+
private handleMessage;
|
|
898
|
+
private scheduleReconnect;
|
|
899
|
+
private dispatchEvent;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
interface WebSocketClientOptions<TSchema extends Schema<any> = Schema<any>> extends ClientOptions<TSchema> {
|
|
903
|
+
connection?: {
|
|
904
|
+
autoConnect?: boolean;
|
|
905
|
+
autoReconnect?: boolean;
|
|
906
|
+
reconnectTimeout?: number;
|
|
907
|
+
maxReconnectAttempts?: number;
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
type ConnectionStateChangeEvent = {
|
|
911
|
+
type: "CONNECTION_STATE_CHANGE";
|
|
912
|
+
open: boolean;
|
|
913
|
+
};
|
|
914
|
+
type MessageReceivedEvent = {
|
|
915
|
+
type: "MESSAGE_RECEIVED";
|
|
916
|
+
message: ServerMessage;
|
|
917
|
+
};
|
|
918
|
+
type ClientStorageLoadedEvent = {
|
|
919
|
+
type: "CLIENT_STORAGE_LOADED";
|
|
920
|
+
resource: string;
|
|
921
|
+
itemCount: number;
|
|
922
|
+
};
|
|
923
|
+
type DataLoadRequestedEvent = {
|
|
924
|
+
type: "DATA_LOAD_REQUESTED";
|
|
925
|
+
query: RawQueryRequest | CustomQueryRequest;
|
|
926
|
+
subscriptionId: string;
|
|
927
|
+
};
|
|
928
|
+
type DataLoadReplyEvent = {
|
|
929
|
+
type: "DATA_LOAD_REPLY";
|
|
930
|
+
resource: string;
|
|
931
|
+
itemCount: number;
|
|
932
|
+
subscriptionId?: string;
|
|
933
|
+
};
|
|
934
|
+
type MutationSentEvent = {
|
|
935
|
+
type: "MUTATION_SENT";
|
|
936
|
+
mutationId: string;
|
|
937
|
+
resource: string;
|
|
938
|
+
resourceId: string;
|
|
939
|
+
procedure: string;
|
|
940
|
+
optimistic: boolean;
|
|
941
|
+
};
|
|
942
|
+
type MutationReceivedEvent = {
|
|
943
|
+
type: "MUTATION_RECEIVED";
|
|
944
|
+
mutationId: string;
|
|
945
|
+
resource: string;
|
|
946
|
+
resourceId: string;
|
|
947
|
+
procedure: string;
|
|
948
|
+
};
|
|
949
|
+
type MutationRejectedEvent = {
|
|
950
|
+
type: "MUTATION_REJECTED";
|
|
951
|
+
mutationId: string;
|
|
952
|
+
resource: string;
|
|
953
|
+
};
|
|
954
|
+
type SubscriptionCreatedEvent = {
|
|
955
|
+
type: "SUBSCRIPTION_CREATED";
|
|
956
|
+
query: RawQueryRequest | CustomQueryRequest;
|
|
957
|
+
subscriptionKey: string;
|
|
958
|
+
subscriberCount: number;
|
|
959
|
+
};
|
|
960
|
+
type SubscriptionRemovedEvent = {
|
|
961
|
+
type: "SUBSCRIPTION_REMOVED";
|
|
962
|
+
query: RawQueryRequest | CustomQueryRequest;
|
|
963
|
+
subscriptionKey: string;
|
|
964
|
+
};
|
|
965
|
+
type QueryExecutedEvent = {
|
|
966
|
+
type: "QUERY_EXECUTED";
|
|
967
|
+
query: RawQueryRequest;
|
|
968
|
+
resultCount: number;
|
|
969
|
+
};
|
|
970
|
+
type QuerySubscriptionTriggeredEvent = {
|
|
971
|
+
type: "QUERY_SUBSCRIPTION_TRIGGERED";
|
|
972
|
+
query: RawQueryRequest;
|
|
973
|
+
};
|
|
974
|
+
type StoreStateUpdatedEvent = {
|
|
975
|
+
type: "STORE_STATE_UPDATED";
|
|
976
|
+
resource: string;
|
|
977
|
+
itemCount: number;
|
|
978
|
+
};
|
|
979
|
+
type OptimisticMutationAppliedEvent = {
|
|
980
|
+
type: "OPTIMISTIC_MUTATION_APPLIED";
|
|
981
|
+
mutationId: string;
|
|
982
|
+
resource: string;
|
|
983
|
+
resourceId: string;
|
|
984
|
+
procedure: string;
|
|
985
|
+
pendingMutations: number;
|
|
986
|
+
};
|
|
987
|
+
type OptimisticMutationUndoneEvent = {
|
|
988
|
+
type: "OPTIMISTIC_MUTATION_UNDONE";
|
|
989
|
+
mutationId: string;
|
|
990
|
+
resource: string;
|
|
991
|
+
resourceId: string;
|
|
992
|
+
pendingMutations: number;
|
|
993
|
+
};
|
|
994
|
+
type ClientEvents = ConnectionStateChangeEvent | MessageReceivedEvent | ClientStorageLoadedEvent | DataLoadRequestedEvent | DataLoadReplyEvent | MutationSentEvent | MutationReceivedEvent | MutationRejectedEvent | SubscriptionCreatedEvent | SubscriptionRemovedEvent | QueryExecutedEvent | QuerySubscriptionTriggeredEvent | StoreStateUpdatedEvent | OptimisticMutationAppliedEvent | OptimisticMutationUndoneEvent;
|
|
995
|
+
type Client<TRouter extends ClientRouterConstraint> = {
|
|
996
|
+
client: {
|
|
997
|
+
ws: WebSocketClient;
|
|
998
|
+
addEventListener: (listener: (event: ClientEvents) => void) => () => void;
|
|
999
|
+
load: (query: RawQueryRequest | CustomQueryRequest) => () => void;
|
|
1000
|
+
};
|
|
1001
|
+
store: Client$1<TRouter>;
|
|
1002
|
+
};
|
|
1003
|
+
declare const createClient: <TRouter extends ClientRouterConstraint>(opts: WebSocketClientOptions) => Client<TRouter>;
|
|
1004
|
+
|
|
1005
|
+
type ClientOptions<TSchema extends Schema<any> = Schema<any>> = {
|
|
1006
|
+
url: string;
|
|
1007
|
+
schema: TSchema;
|
|
1008
|
+
credentials?: Generatable<PromiseOrSync<Record<string, string>>>;
|
|
1009
|
+
storage: {
|
|
1010
|
+
name: string;
|
|
1011
|
+
} | false;
|
|
1012
|
+
logLevel?: LogLevel;
|
|
1013
|
+
optimisticMutations?: OptimisticMutationsRegistry<TSchema>;
|
|
1014
|
+
};
|
|
1015
|
+
|
|
1016
|
+
export { createClient as A, type ClientOptions as C, type DataLoadRequestedEvent as D, type MessageReceivedEvent as M, type OptimisticMutationsConfig as O, type QueryExecutedEvent as Q, type SubscriptionCreatedEvent as S, type ClientRouterConstraint as a, type Client$1 as b, type OptimisticMutationsRegistry as c, defineOptimisticMutations as d, type OptimisticHandlerContext as e, type OptimisticStorageProxy as f, type OptimisticOperation as g, type OptimisticInsertOperation as h, type OptimisticUpdateOperation as i, type OptimisticMutationHandler as j, createOptimisticStorageProxy as k, useLoadData as l, type ConnectionStateChangeEvent as m, type ClientStorageLoadedEvent as n, type DataLoadReplyEvent as o, type MutationSentEvent as p, type MutationReceivedEvent as q, type MutationRejectedEvent as r, type SubscriptionRemovedEvent as s, type QuerySubscriptionTriggeredEvent as t, useLiveQuery as u, type StoreStateUpdatedEvent as v, type OptimisticMutationAppliedEvent as w, type OptimisticMutationUndoneEvent as x, type ClientEvents as y, type Client as z };
|