@trestleinc/replicate 1.1.2 → 1.2.0-preview.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 +40 -41
- package/dist/client/index.d.ts +34 -26
- package/dist/client/index.js +904 -732
- package/dist/component/_generated/api.d.ts +2 -2
- package/dist/component/_generated/component.d.ts +84 -27
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/mutations.d.ts +131 -0
- package/dist/component/mutations.js +493 -0
- package/dist/component/schema.d.ts +71 -31
- package/dist/component/schema.js +37 -14
- package/dist/server/index.d.ts +58 -47
- package/dist/server/index.js +227 -132
- package/package.json +3 -1
- package/src/client/collection.ts +334 -523
- package/src/client/errors.ts +1 -1
- package/src/client/index.ts +4 -7
- package/src/client/merge.ts +2 -2
- package/src/client/persistence/indexeddb.ts +10 -14
- package/src/client/prose.ts +147 -203
- package/src/client/services/awareness.ts +373 -0
- package/src/client/services/context.ts +114 -0
- package/src/client/services/seq.ts +78 -0
- package/src/client/services/session.ts +20 -0
- package/src/client/services/sync.ts +122 -0
- package/src/client/subdocs.ts +263 -0
- package/src/component/_generated/api.ts +2 -2
- package/src/component/_generated/component.ts +73 -28
- package/src/component/mutations.ts +734 -0
- package/src/component/schema.ts +31 -14
- package/src/server/collection.ts +98 -0
- package/src/server/index.ts +2 -2
- package/src/server/{storage.ts → replicate.ts} +214 -75
- package/dist/component/public.d.ts +0 -83
- package/dist/component/public.js +0 -325
- package/src/client/prose-schema.ts +0 -55
- package/src/client/services/cursor.ts +0 -109
- package/src/component/public.ts +0 -453
- package/src/server/builder.ts +0 -98
- /package/src/client/{replicate.ts → ops.ts} +0 -0
package/src/component/schema.ts
CHANGED
|
@@ -4,29 +4,46 @@ import { v } from "convex/values";
|
|
|
4
4
|
export default defineSchema({
|
|
5
5
|
documents: defineTable({
|
|
6
6
|
collection: v.string(),
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
document: v.string(),
|
|
8
|
+
bytes: v.bytes(),
|
|
9
9
|
seq: v.number(),
|
|
10
10
|
})
|
|
11
11
|
.index("by_collection", ["collection"])
|
|
12
|
-
.index("
|
|
12
|
+
.index("by_document", ["collection", "document"])
|
|
13
13
|
.index("by_seq", ["collection", "seq"]),
|
|
14
14
|
|
|
15
15
|
snapshots: defineTable({
|
|
16
16
|
collection: v.string(),
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}).index("by_document", ["collection", "
|
|
17
|
+
document: v.string(),
|
|
18
|
+
bytes: v.bytes(),
|
|
19
|
+
vector: v.bytes(),
|
|
20
|
+
seq: v.number(),
|
|
21
|
+
created: v.number(),
|
|
22
|
+
}).index("by_document", ["collection", "document"]),
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
sessions: defineTable({
|
|
25
25
|
collection: v.string(),
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
document: v.string(),
|
|
27
|
+
client: v.string(),
|
|
28
|
+
vector: v.optional(v.bytes()),
|
|
29
|
+
connected: v.boolean(),
|
|
30
|
+
seq: v.number(),
|
|
31
|
+
seen: v.number(),
|
|
32
|
+
user: v.optional(v.string()),
|
|
33
|
+
profile: v.optional(v.object({
|
|
34
|
+
name: v.optional(v.string()),
|
|
35
|
+
color: v.optional(v.string()),
|
|
36
|
+
avatar: v.optional(v.string()),
|
|
37
|
+
})),
|
|
38
|
+
cursor: v.optional(v.object({
|
|
39
|
+
anchor: v.any(),
|
|
40
|
+
head: v.any(),
|
|
41
|
+
field: v.optional(v.string()),
|
|
42
|
+
})),
|
|
43
|
+
timeout: v.optional(v.id("_scheduled_functions")),
|
|
29
44
|
})
|
|
30
45
|
.index("by_collection", ["collection"])
|
|
31
|
-
.index("
|
|
46
|
+
.index("by_document", ["collection", "document"])
|
|
47
|
+
.index("by_client", ["collection", "document", "client"])
|
|
48
|
+
.index("by_connected", ["collection", "document", "connected"]),
|
|
32
49
|
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { GenericMutationCtx, GenericQueryCtx, GenericDataModel } from "convex/server";
|
|
2
|
+
import { Replicate } from "$/server/replicate";
|
|
3
|
+
import type { CompactionConfig } from "$/shared/types";
|
|
4
|
+
|
|
5
|
+
export interface CollectionOptions<T extends object> {
|
|
6
|
+
compaction?: Partial<CompactionConfig>;
|
|
7
|
+
hooks?: {
|
|
8
|
+
evalRead?: (ctx: GenericQueryCtx<GenericDataModel>, collection: string) => void | Promise<void>;
|
|
9
|
+
evalWrite?: (ctx: GenericMutationCtx<GenericDataModel>, doc: T) => void | Promise<void>;
|
|
10
|
+
evalRemove?: (ctx: GenericMutationCtx<GenericDataModel>, docId: string) => void | Promise<void>;
|
|
11
|
+
evalMark?: (ctx: GenericMutationCtx<GenericDataModel>, client: string) => void | Promise<void>;
|
|
12
|
+
evalLeave?: (ctx: GenericMutationCtx<GenericDataModel>, client: string) => void | Promise<void>;
|
|
13
|
+
evalCompact?: (
|
|
14
|
+
ctx: GenericMutationCtx<GenericDataModel>,
|
|
15
|
+
document: string,
|
|
16
|
+
) => void | Promise<void>;
|
|
17
|
+
onStream?: (ctx: GenericQueryCtx<GenericDataModel>, result: any) => void | Promise<void>;
|
|
18
|
+
onInsert?: (ctx: GenericMutationCtx<GenericDataModel>, doc: T) => void | Promise<void>;
|
|
19
|
+
onUpdate?: (ctx: GenericMutationCtx<GenericDataModel>, doc: T) => void | Promise<void>;
|
|
20
|
+
onRemove?: (ctx: GenericMutationCtx<GenericDataModel>, docId: string) => void | Promise<void>;
|
|
21
|
+
transform?: (docs: T[]) => T[] | Promise<T[]>;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function createCollection<T extends object>(
|
|
26
|
+
component: any,
|
|
27
|
+
name: string,
|
|
28
|
+
options?: CollectionOptions<T>,
|
|
29
|
+
) {
|
|
30
|
+
return createCollectionInternal<T>(component, name, options);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const collection = {
|
|
34
|
+
create: createCollection,
|
|
35
|
+
} as const;
|
|
36
|
+
|
|
37
|
+
function createCollectionInternal<T extends object>(
|
|
38
|
+
component: any,
|
|
39
|
+
name: string,
|
|
40
|
+
options?: CollectionOptions<T>,
|
|
41
|
+
) {
|
|
42
|
+
const storage = new Replicate<T>(component, name, options?.compaction);
|
|
43
|
+
|
|
44
|
+
const hooks = options?.hooks;
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
__collection: name,
|
|
48
|
+
|
|
49
|
+
stream: storage.createStreamQuery({
|
|
50
|
+
evalRead: hooks?.evalRead,
|
|
51
|
+
onStream: hooks?.onStream,
|
|
52
|
+
}),
|
|
53
|
+
|
|
54
|
+
material: storage.createSSRQuery({
|
|
55
|
+
evalRead: hooks?.evalRead,
|
|
56
|
+
transform: hooks?.transform,
|
|
57
|
+
}),
|
|
58
|
+
|
|
59
|
+
recovery: storage.createRecoveryQuery({
|
|
60
|
+
evalRead: hooks?.evalRead,
|
|
61
|
+
}),
|
|
62
|
+
|
|
63
|
+
insert: storage.createInsertMutation({
|
|
64
|
+
evalWrite: hooks?.evalWrite,
|
|
65
|
+
onInsert: hooks?.onInsert,
|
|
66
|
+
}),
|
|
67
|
+
|
|
68
|
+
update: storage.createUpdateMutation({
|
|
69
|
+
evalWrite: hooks?.evalWrite,
|
|
70
|
+
onUpdate: hooks?.onUpdate,
|
|
71
|
+
}),
|
|
72
|
+
|
|
73
|
+
remove: storage.createRemoveMutation({
|
|
74
|
+
evalRemove: hooks?.evalRemove,
|
|
75
|
+
onRemove: hooks?.onRemove,
|
|
76
|
+
}),
|
|
77
|
+
|
|
78
|
+
mark: storage.createMarkMutation({
|
|
79
|
+
evalWrite: hooks?.evalMark,
|
|
80
|
+
}),
|
|
81
|
+
|
|
82
|
+
compact: storage.createCompactMutation({
|
|
83
|
+
evalWrite: hooks?.evalCompact,
|
|
84
|
+
}),
|
|
85
|
+
|
|
86
|
+
sessions: storage.createSessionsQuery({
|
|
87
|
+
evalRead: hooks?.evalRead,
|
|
88
|
+
}),
|
|
89
|
+
|
|
90
|
+
cursors: storage.createCursorsQuery({
|
|
91
|
+
evalRead: hooks?.evalRead,
|
|
92
|
+
}),
|
|
93
|
+
|
|
94
|
+
leave: storage.createLeaveMutation({
|
|
95
|
+
evalWrite: hooks?.evalLeave,
|
|
96
|
+
}),
|
|
97
|
+
};
|
|
98
|
+
}
|
package/src/server/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type {
|
|
1
|
+
export { collection } from "$/server/collection";
|
|
2
|
+
export type { CollectionOptions } from "$/server/collection";
|
|
3
3
|
|
|
4
4
|
import { table, prose } from "$/server/schema";
|
|
5
5
|
|
|
@@ -34,32 +34,34 @@ export class Replicate<T extends object> {
|
|
|
34
34
|
|
|
35
35
|
return queryGeneric({
|
|
36
36
|
args: {
|
|
37
|
-
|
|
37
|
+
seq: v.number(),
|
|
38
38
|
limit: v.optional(v.number()),
|
|
39
|
-
|
|
39
|
+
threshold: v.optional(v.number()),
|
|
40
40
|
},
|
|
41
41
|
returns: v.object({
|
|
42
42
|
changes: v.array(
|
|
43
43
|
v.object({
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
document: v.string(),
|
|
45
|
+
bytes: v.bytes(),
|
|
46
46
|
seq: v.number(),
|
|
47
|
-
|
|
47
|
+
type: v.string(),
|
|
48
48
|
}),
|
|
49
49
|
),
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
compact: v.optional(v.
|
|
50
|
+
seq: v.number(),
|
|
51
|
+
more: v.boolean(),
|
|
52
|
+
compact: v.optional(v.object({
|
|
53
|
+
documents: v.array(v.string()),
|
|
54
|
+
})),
|
|
53
55
|
}),
|
|
54
56
|
handler: async (ctx, args) => {
|
|
55
57
|
if (opts?.evalRead) {
|
|
56
58
|
await opts.evalRead(ctx, collection);
|
|
57
59
|
}
|
|
58
|
-
const result = await ctx.runQuery(component.
|
|
60
|
+
const result = await ctx.runQuery(component.mutations.stream, {
|
|
59
61
|
collection,
|
|
60
|
-
|
|
62
|
+
seq: args.seq,
|
|
61
63
|
limit: args.limit,
|
|
62
|
-
|
|
64
|
+
threshold: args.threshold,
|
|
63
65
|
});
|
|
64
66
|
|
|
65
67
|
if (opts?.onStream) {
|
|
@@ -83,9 +85,12 @@ export class Replicate<T extends object> {
|
|
|
83
85
|
args: {},
|
|
84
86
|
returns: v.object({
|
|
85
87
|
documents: v.any(),
|
|
86
|
-
cursor: v.optional(v.number()),
|
|
87
88
|
count: v.number(),
|
|
88
|
-
|
|
89
|
+
crdt: v.optional(v.record(v.string(), v.object({
|
|
90
|
+
bytes: v.bytes(),
|
|
91
|
+
seq: v.number(),
|
|
92
|
+
}))),
|
|
93
|
+
cursor: v.optional(v.number()),
|
|
89
94
|
}),
|
|
90
95
|
handler: async (ctx) => {
|
|
91
96
|
if (opts?.evalRead) {
|
|
@@ -98,24 +103,35 @@ export class Replicate<T extends object> {
|
|
|
98
103
|
|
|
99
104
|
const response: {
|
|
100
105
|
documents: T[];
|
|
101
|
-
cursor?: number;
|
|
102
106
|
count: number;
|
|
103
|
-
|
|
107
|
+
crdt?: Record<string, { bytes: ArrayBuffer; seq: number }>;
|
|
108
|
+
cursor?: number;
|
|
104
109
|
} = {
|
|
105
110
|
documents: docs,
|
|
106
111
|
count: docs.length,
|
|
107
112
|
};
|
|
108
113
|
|
|
109
|
-
if (opts?.includeCRDTState) {
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
if (opts?.includeCRDTState && docs.length > 0) {
|
|
115
|
+
const crdt: Record<string, { bytes: ArrayBuffer; seq: number }> = {};
|
|
116
|
+
let maxSeq = 0;
|
|
117
|
+
|
|
118
|
+
for (const doc of docs) {
|
|
119
|
+
const docId = (doc as { id: string }).id;
|
|
120
|
+
const state = await ctx.runQuery(component.mutations.getDocumentState, {
|
|
121
|
+
collection,
|
|
122
|
+
document: docId,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (state) {
|
|
126
|
+
crdt[docId] = { bytes: state.bytes, seq: state.seq };
|
|
127
|
+
maxSeq = Math.max(maxSeq, state.seq);
|
|
128
|
+
}
|
|
117
129
|
}
|
|
130
|
+
|
|
131
|
+
response.crdt = crdt;
|
|
132
|
+
response.cursor = maxSeq;
|
|
118
133
|
}
|
|
134
|
+
|
|
119
135
|
return response;
|
|
120
136
|
},
|
|
121
137
|
});
|
|
@@ -130,30 +146,30 @@ export class Replicate<T extends object> {
|
|
|
130
146
|
|
|
131
147
|
return mutationGeneric({
|
|
132
148
|
args: {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
149
|
+
document: v.string(),
|
|
150
|
+
bytes: v.bytes(),
|
|
151
|
+
material: v.any(),
|
|
136
152
|
},
|
|
137
153
|
returns: v.object({
|
|
138
154
|
success: v.boolean(),
|
|
139
155
|
seq: v.number(),
|
|
140
156
|
}),
|
|
141
157
|
handler: async (ctx, args) => {
|
|
142
|
-
const doc = args.
|
|
158
|
+
const doc = args.material as T;
|
|
143
159
|
|
|
144
160
|
if (opts?.evalWrite) {
|
|
145
161
|
await opts.evalWrite(ctx, doc);
|
|
146
162
|
}
|
|
147
163
|
|
|
148
|
-
const result = await ctx.runMutation(component.
|
|
164
|
+
const result = await ctx.runMutation(component.mutations.insertDocument, {
|
|
149
165
|
collection,
|
|
150
|
-
|
|
151
|
-
|
|
166
|
+
document: args.document,
|
|
167
|
+
bytes: args.bytes,
|
|
152
168
|
});
|
|
153
169
|
|
|
154
170
|
await ctx.db.insert(collection, {
|
|
155
|
-
id: args.
|
|
156
|
-
...(args.
|
|
171
|
+
id: args.document,
|
|
172
|
+
...(args.material as object),
|
|
157
173
|
timestamp: Date.now(),
|
|
158
174
|
});
|
|
159
175
|
|
|
@@ -178,35 +194,35 @@ export class Replicate<T extends object> {
|
|
|
178
194
|
|
|
179
195
|
return mutationGeneric({
|
|
180
196
|
args: {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
197
|
+
document: v.string(),
|
|
198
|
+
bytes: v.bytes(),
|
|
199
|
+
material: v.any(),
|
|
184
200
|
},
|
|
185
201
|
returns: v.object({
|
|
186
202
|
success: v.boolean(),
|
|
187
203
|
seq: v.number(),
|
|
188
204
|
}),
|
|
189
205
|
handler: async (ctx, args) => {
|
|
190
|
-
const doc = args.
|
|
206
|
+
const doc = args.material as T;
|
|
191
207
|
|
|
192
208
|
if (opts?.evalWrite) {
|
|
193
209
|
await opts.evalWrite(ctx, doc);
|
|
194
210
|
}
|
|
195
211
|
|
|
196
|
-
const result = await ctx.runMutation(component.
|
|
212
|
+
const result = await ctx.runMutation(component.mutations.updateDocument, {
|
|
197
213
|
collection,
|
|
198
|
-
|
|
199
|
-
|
|
214
|
+
document: args.document,
|
|
215
|
+
bytes: args.bytes,
|
|
200
216
|
});
|
|
201
217
|
|
|
202
218
|
const existing = await ctx.db
|
|
203
219
|
.query(collection)
|
|
204
|
-
.withIndex("by_doc_id", q => q.eq("id", args.
|
|
220
|
+
.withIndex("by_doc_id", q => q.eq("id", args.document))
|
|
205
221
|
.first();
|
|
206
222
|
|
|
207
223
|
if (existing) {
|
|
208
224
|
await ctx.db.patch(existing._id, {
|
|
209
|
-
...(args.
|
|
225
|
+
...(args.material as object),
|
|
210
226
|
timestamp: Date.now(),
|
|
211
227
|
});
|
|
212
228
|
}
|
|
@@ -232,28 +248,27 @@ export class Replicate<T extends object> {
|
|
|
232
248
|
|
|
233
249
|
return mutationGeneric({
|
|
234
250
|
args: {
|
|
235
|
-
|
|
236
|
-
|
|
251
|
+
document: v.string(),
|
|
252
|
+
bytes: v.bytes(),
|
|
237
253
|
},
|
|
238
254
|
returns: v.object({
|
|
239
255
|
success: v.boolean(),
|
|
240
256
|
seq: v.number(),
|
|
241
257
|
}),
|
|
242
258
|
handler: async (ctx, args) => {
|
|
243
|
-
const documentId = args.documentId;
|
|
244
259
|
if (opts?.evalRemove) {
|
|
245
|
-
await opts.evalRemove(ctx,
|
|
260
|
+
await opts.evalRemove(ctx, args.document);
|
|
246
261
|
}
|
|
247
262
|
|
|
248
|
-
const result = await ctx.runMutation(component.
|
|
263
|
+
const result = await ctx.runMutation(component.mutations.deleteDocument, {
|
|
249
264
|
collection,
|
|
250
|
-
|
|
251
|
-
|
|
265
|
+
document: args.document,
|
|
266
|
+
bytes: args.bytes,
|
|
252
267
|
});
|
|
253
268
|
|
|
254
269
|
const existing = await ctx.db
|
|
255
270
|
.query(collection)
|
|
256
|
-
.withIndex("by_doc_id", q => q.eq("id",
|
|
271
|
+
.withIndex("by_doc_id", q => q.eq("id", args.document))
|
|
257
272
|
.first();
|
|
258
273
|
|
|
259
274
|
if (existing) {
|
|
@@ -261,7 +276,7 @@ export class Replicate<T extends object> {
|
|
|
261
276
|
}
|
|
262
277
|
|
|
263
278
|
if (opts?.onRemove) {
|
|
264
|
-
await opts.onRemove(ctx,
|
|
279
|
+
await opts.onRemove(ctx, args.document);
|
|
265
280
|
}
|
|
266
281
|
|
|
267
282
|
return {
|
|
@@ -273,26 +288,150 @@ export class Replicate<T extends object> {
|
|
|
273
288
|
}
|
|
274
289
|
|
|
275
290
|
createMarkMutation(opts?: {
|
|
276
|
-
evalWrite?: (ctx: GenericMutationCtx<GenericDataModel>,
|
|
291
|
+
evalWrite?: (ctx: GenericMutationCtx<GenericDataModel>, client: string) => void | Promise<void>;
|
|
277
292
|
}) {
|
|
278
293
|
const component = this.component;
|
|
279
294
|
const collection = this.collectionName;
|
|
280
295
|
|
|
281
296
|
return mutationGeneric({
|
|
282
297
|
args: {
|
|
283
|
-
|
|
284
|
-
|
|
298
|
+
document: v.string(),
|
|
299
|
+
client: v.string(),
|
|
300
|
+
seq: v.optional(v.number()),
|
|
301
|
+
vector: v.optional(v.bytes()),
|
|
302
|
+
user: v.optional(v.string()),
|
|
303
|
+
profile: v.optional(v.object({
|
|
304
|
+
name: v.optional(v.string()),
|
|
305
|
+
color: v.optional(v.string()),
|
|
306
|
+
avatar: v.optional(v.string()),
|
|
307
|
+
})),
|
|
308
|
+
cursor: v.optional(v.object({
|
|
309
|
+
anchor: v.any(),
|
|
310
|
+
head: v.any(),
|
|
311
|
+
field: v.optional(v.string()),
|
|
312
|
+
})),
|
|
313
|
+
interval: v.optional(v.number()),
|
|
285
314
|
},
|
|
286
315
|
returns: v.null(),
|
|
287
316
|
handler: async (ctx, args) => {
|
|
288
317
|
if (opts?.evalWrite) {
|
|
289
|
-
await opts.evalWrite(ctx, args.
|
|
318
|
+
await opts.evalWrite(ctx, args.client);
|
|
290
319
|
}
|
|
291
320
|
|
|
292
|
-
await ctx.runMutation(component.
|
|
321
|
+
await ctx.runMutation(component.mutations.mark, {
|
|
293
322
|
collection,
|
|
294
|
-
|
|
295
|
-
|
|
323
|
+
document: args.document,
|
|
324
|
+
client: args.client,
|
|
325
|
+
seq: args.seq,
|
|
326
|
+
vector: args.vector,
|
|
327
|
+
user: args.user,
|
|
328
|
+
profile: args.profile,
|
|
329
|
+
cursor: args.cursor,
|
|
330
|
+
interval: args.interval,
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
return null;
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
createSessionsQuery(opts?: {
|
|
339
|
+
evalRead?: (ctx: GenericQueryCtx<GenericDataModel>, collection: string) => void | Promise<void>;
|
|
340
|
+
}) {
|
|
341
|
+
const component = this.component;
|
|
342
|
+
const collection = this.collectionName;
|
|
343
|
+
|
|
344
|
+
return queryGeneric({
|
|
345
|
+
args: {
|
|
346
|
+
document: v.string(),
|
|
347
|
+
connected: v.optional(v.boolean()),
|
|
348
|
+
exclude: v.optional(v.string()),
|
|
349
|
+
group: v.optional(v.boolean()),
|
|
350
|
+
},
|
|
351
|
+
returns: v.array(v.object({
|
|
352
|
+
client: v.string(),
|
|
353
|
+
document: v.string(),
|
|
354
|
+
user: v.optional(v.string()),
|
|
355
|
+
profile: v.optional(v.any()),
|
|
356
|
+
cursor: v.optional(v.object({
|
|
357
|
+
anchor: v.any(),
|
|
358
|
+
head: v.any(),
|
|
359
|
+
field: v.optional(v.string()),
|
|
360
|
+
})),
|
|
361
|
+
seen: v.number(),
|
|
362
|
+
})),
|
|
363
|
+
handler: async (ctx, args) => {
|
|
364
|
+
if (opts?.evalRead) {
|
|
365
|
+
await opts.evalRead(ctx, collection);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return await ctx.runQuery(component.mutations.sessions, {
|
|
369
|
+
collection,
|
|
370
|
+
document: args.document,
|
|
371
|
+
connected: args.connected,
|
|
372
|
+
exclude: args.exclude,
|
|
373
|
+
group: args.group,
|
|
374
|
+
});
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
createCursorsQuery(opts?: {
|
|
380
|
+
evalRead?: (ctx: GenericQueryCtx<GenericDataModel>, collection: string) => void | Promise<void>;
|
|
381
|
+
}) {
|
|
382
|
+
const component = this.component;
|
|
383
|
+
const collection = this.collectionName;
|
|
384
|
+
|
|
385
|
+
return queryGeneric({
|
|
386
|
+
args: {
|
|
387
|
+
document: v.string(),
|
|
388
|
+
exclude: v.optional(v.string()),
|
|
389
|
+
},
|
|
390
|
+
returns: v.array(v.object({
|
|
391
|
+
client: v.string(),
|
|
392
|
+
user: v.optional(v.string()),
|
|
393
|
+
profile: v.optional(v.any()),
|
|
394
|
+
cursor: v.object({
|
|
395
|
+
anchor: v.any(),
|
|
396
|
+
head: v.any(),
|
|
397
|
+
field: v.optional(v.string()),
|
|
398
|
+
}),
|
|
399
|
+
})),
|
|
400
|
+
handler: async (ctx, args) => {
|
|
401
|
+
if (opts?.evalRead) {
|
|
402
|
+
await opts.evalRead(ctx, collection);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return await ctx.runQuery(component.mutations.cursors, {
|
|
406
|
+
collection,
|
|
407
|
+
document: args.document,
|
|
408
|
+
exclude: args.exclude,
|
|
409
|
+
});
|
|
410
|
+
},
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
createLeaveMutation(opts?: {
|
|
415
|
+
evalWrite?: (ctx: GenericMutationCtx<GenericDataModel>, client: string) => void | Promise<void>;
|
|
416
|
+
}) {
|
|
417
|
+
const component = this.component;
|
|
418
|
+
const collection = this.collectionName;
|
|
419
|
+
|
|
420
|
+
return mutationGeneric({
|
|
421
|
+
args: {
|
|
422
|
+
document: v.string(),
|
|
423
|
+
client: v.string(),
|
|
424
|
+
},
|
|
425
|
+
returns: v.null(),
|
|
426
|
+
handler: async (ctx, args) => {
|
|
427
|
+
if (opts?.evalWrite) {
|
|
428
|
+
await opts.evalWrite(ctx, args.client);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
await ctx.runMutation(component.mutations.leave, {
|
|
432
|
+
collection,
|
|
433
|
+
document: args.document,
|
|
434
|
+
client: args.client,
|
|
296
435
|
});
|
|
297
436
|
|
|
298
437
|
return null;
|
|
@@ -303,7 +442,7 @@ export class Replicate<T extends object> {
|
|
|
303
442
|
createCompactMutation(opts?: {
|
|
304
443
|
evalWrite?: (
|
|
305
444
|
ctx: GenericMutationCtx<GenericDataModel>,
|
|
306
|
-
|
|
445
|
+
document: string,
|
|
307
446
|
) => void | Promise<void>;
|
|
308
447
|
}) {
|
|
309
448
|
const component = this.component;
|
|
@@ -311,55 +450,55 @@ export class Replicate<T extends object> {
|
|
|
311
450
|
|
|
312
451
|
return mutationGeneric({
|
|
313
452
|
args: {
|
|
314
|
-
|
|
315
|
-
snapshotBytes: v.bytes(),
|
|
316
|
-
stateVector: v.bytes(),
|
|
317
|
-
peerTimeout: v.optional(v.number()),
|
|
453
|
+
document: v.string(),
|
|
318
454
|
},
|
|
319
455
|
returns: v.object({
|
|
320
456
|
success: v.boolean(),
|
|
321
457
|
removed: v.number(),
|
|
322
458
|
retained: v.number(),
|
|
459
|
+
size: v.number(),
|
|
323
460
|
}),
|
|
324
461
|
handler: async (ctx, args) => {
|
|
325
462
|
if (opts?.evalWrite) {
|
|
326
|
-
await opts.evalWrite(ctx, args.
|
|
463
|
+
await opts.evalWrite(ctx, args.document);
|
|
327
464
|
}
|
|
328
465
|
|
|
329
|
-
return await ctx.runMutation(component.
|
|
466
|
+
return await ctx.runMutation(component.mutations.compact, {
|
|
330
467
|
collection,
|
|
331
|
-
|
|
332
|
-
snapshotBytes: args.snapshotBytes,
|
|
333
|
-
stateVector: args.stateVector,
|
|
334
|
-
peerTimeout: args.peerTimeout,
|
|
468
|
+
document: args.document,
|
|
335
469
|
});
|
|
336
470
|
},
|
|
337
471
|
});
|
|
338
472
|
}
|
|
339
473
|
|
|
340
474
|
createRecoveryQuery(opts?: {
|
|
341
|
-
evalRead?: (
|
|
475
|
+
evalRead?: (
|
|
476
|
+
ctx: GenericQueryCtx<GenericDataModel>,
|
|
477
|
+
collection: string,
|
|
478
|
+
document: string,
|
|
479
|
+
) => void | Promise<void>;
|
|
342
480
|
}) {
|
|
343
481
|
const component = this.component;
|
|
344
482
|
const collection = this.collectionName;
|
|
345
483
|
|
|
346
484
|
return queryGeneric({
|
|
347
485
|
args: {
|
|
348
|
-
|
|
486
|
+
document: v.string(),
|
|
487
|
+
vector: v.bytes(),
|
|
349
488
|
},
|
|
350
489
|
returns: v.object({
|
|
351
490
|
diff: v.optional(v.bytes()),
|
|
352
|
-
|
|
353
|
-
cursor: v.number(),
|
|
491
|
+
vector: v.bytes(),
|
|
354
492
|
}),
|
|
355
493
|
handler: async (ctx, args) => {
|
|
356
494
|
if (opts?.evalRead) {
|
|
357
|
-
await opts.evalRead(ctx, collection);
|
|
495
|
+
await opts.evalRead(ctx, collection, args.document);
|
|
358
496
|
}
|
|
359
497
|
|
|
360
|
-
return await ctx.runQuery(component.
|
|
498
|
+
return await ctx.runQuery(component.mutations.recovery, {
|
|
361
499
|
collection,
|
|
362
|
-
|
|
500
|
+
document: args.document,
|
|
501
|
+
vector: args.vector,
|
|
363
502
|
});
|
|
364
503
|
},
|
|
365
504
|
});
|