@trestleinc/replicate 1.1.2 → 1.2.0-preview.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 +40 -41
- 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/client/index.d.ts +0 -314
- package/dist/client/index.js +0 -4027
- package/dist/component/_generated/api.d.ts +0 -31
- package/dist/component/_generated/api.js +0 -25
- package/dist/component/_generated/component.d.ts +0 -91
- package/dist/component/_generated/component.js +0 -1
- package/dist/component/_generated/dataModel.d.ts +0 -42
- package/dist/component/_generated/dataModel.js +0 -1
- package/dist/component/_generated/server.d.ts +0 -117
- package/dist/component/_generated/server.js +0 -73
- package/dist/component/_virtual/rolldown_runtime.js +0 -18
- package/dist/component/convex.config.d.ts +0 -6
- package/dist/component/convex.config.js +0 -8
- package/dist/component/logger.d.ts +0 -12
- package/dist/component/logger.js +0 -27
- package/dist/component/public.d.ts +0 -83
- package/dist/component/public.js +0 -325
- package/dist/component/schema.d.ts +0 -54
- package/dist/component/schema.js +0 -29
- package/dist/component/shared/types.d.ts +0 -9
- package/dist/component/shared/types.js +0 -15
- package/dist/server/index.d.ts +0 -135
- package/dist/server/index.js +0 -368
- package/dist/shared/index.d.ts +0 -29
- package/dist/shared/index.js +0 -1
- 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/README.md
CHANGED
|
@@ -127,16 +127,14 @@ export default defineSchema({
|
|
|
127
127
|
|
|
128
128
|
### Step 3: Create Replication Functions
|
|
129
129
|
|
|
130
|
-
Use `
|
|
130
|
+
Use `collection.create()` to create server-side collection functions:
|
|
131
131
|
|
|
132
132
|
```typescript
|
|
133
133
|
// convex/tasks.ts
|
|
134
|
-
import {
|
|
134
|
+
import { collection } from '@trestleinc/replicate/server';
|
|
135
135
|
import { components } from './_generated/api';
|
|
136
136
|
import type { Task } from '../src/useTasks';
|
|
137
137
|
|
|
138
|
-
const r = replicate(components.replicate);
|
|
139
|
-
|
|
140
138
|
export const {
|
|
141
139
|
stream,
|
|
142
140
|
material,
|
|
@@ -144,18 +142,15 @@ export const {
|
|
|
144
142
|
insert,
|
|
145
143
|
update,
|
|
146
144
|
remove,
|
|
147
|
-
mark,
|
|
148
|
-
compact,
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
peerTimeout: "24h", // Type-safe duration: "30m", "24h", "7d"
|
|
154
|
-
},
|
|
155
|
-
});
|
|
145
|
+
mark,
|
|
146
|
+
compact,
|
|
147
|
+
sessions,
|
|
148
|
+
cursors,
|
|
149
|
+
leave,
|
|
150
|
+
} = collection.create<Task>(components.replicate, 'tasks');
|
|
156
151
|
```
|
|
157
152
|
|
|
158
|
-
**What `
|
|
153
|
+
**What `collection.create()` generates:**
|
|
159
154
|
|
|
160
155
|
- `stream` - Real-time CRDT stream query (cursor-based subscriptions with `seq` numbers)
|
|
161
156
|
- `material` - SSR-friendly query (for server-side rendering)
|
|
@@ -165,6 +160,9 @@ export const {
|
|
|
165
160
|
- `remove` - Dual-storage delete mutation (auto-compacts when threshold exceeded)
|
|
166
161
|
- `mark` - Report sync progress to server (peer tracking for safe compaction)
|
|
167
162
|
- `compact` - Manual compaction trigger (peer-aware, respects active peer sync state)
|
|
163
|
+
- `sessions` - Get connected sessions (presence query)
|
|
164
|
+
- `cursors` - Get cursor positions for collaborative editing
|
|
165
|
+
- `leave` - Explicit disconnect mutation
|
|
168
166
|
|
|
169
167
|
### Step 4: Define Your Collection
|
|
170
168
|
|
|
@@ -296,7 +294,7 @@ For frameworks that support SSR (TanStack Start, Next.js, Remix, SvelteKit), pre
|
|
|
296
294
|
|
|
297
295
|
**Step 1: Prefetch material on the server**
|
|
298
296
|
|
|
299
|
-
Use `ConvexHttpClient` to fetch data during SSR. The `material` query is generated by `
|
|
297
|
+
Use `ConvexHttpClient` to fetch data during SSR. The `material` query is generated by `collection.create()`:
|
|
300
298
|
|
|
301
299
|
```typescript
|
|
302
300
|
// TanStack Start: src/routes/__root.tsx
|
|
@@ -471,12 +469,10 @@ You can customize the behavior of generated functions using optional hooks:
|
|
|
471
469
|
|
|
472
470
|
```typescript
|
|
473
471
|
// convex/tasks.ts
|
|
474
|
-
import {
|
|
472
|
+
import { collection } from '@trestleinc/replicate/server';
|
|
475
473
|
import { components } from './_generated/api';
|
|
476
474
|
import type { Task } from '../src/useTasks';
|
|
477
475
|
|
|
478
|
-
const r = replicate(components.replicate);
|
|
479
|
-
|
|
480
476
|
export const {
|
|
481
477
|
stream,
|
|
482
478
|
material,
|
|
@@ -486,9 +482,10 @@ export const {
|
|
|
486
482
|
remove,
|
|
487
483
|
mark,
|
|
488
484
|
compact,
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
485
|
+
sessions,
|
|
486
|
+
cursors,
|
|
487
|
+
leave,
|
|
488
|
+
} = collection.create<Task>(components.replicate, 'tasks', {
|
|
492
489
|
// Optional hooks for authorization and lifecycle events
|
|
493
490
|
hooks: {
|
|
494
491
|
// Permission checks (eval* hooks validate BEFORE execution, throw to deny)
|
|
@@ -500,7 +497,7 @@ export const {
|
|
|
500
497
|
const userId = await ctx.auth.getUserIdentity();
|
|
501
498
|
if (!userId) throw new Error('Unauthorized');
|
|
502
499
|
},
|
|
503
|
-
evalRemove: async (ctx,
|
|
500
|
+
evalRemove: async (ctx, document) => {
|
|
504
501
|
const userId = await ctx.auth.getUserIdentity();
|
|
505
502
|
if (!userId) throw new Error('Unauthorized');
|
|
506
503
|
},
|
|
@@ -509,7 +506,7 @@ export const {
|
|
|
509
506
|
const userId = await ctx.auth.getUserIdentity();
|
|
510
507
|
if (!userId) throw new Error('Unauthorized');
|
|
511
508
|
},
|
|
512
|
-
evalCompact: async (ctx,
|
|
509
|
+
evalCompact: async (ctx, document) => {
|
|
513
510
|
// Restrict compaction to admin users
|
|
514
511
|
const userId = await ctx.auth.getUserIdentity();
|
|
515
512
|
if (!userId) throw new Error('Unauthorized');
|
|
@@ -519,7 +516,7 @@ export const {
|
|
|
519
516
|
onStream: async (ctx, result) => { /* after stream query */ },
|
|
520
517
|
onInsert: async (ctx, doc) => { /* after insert */ },
|
|
521
518
|
onUpdate: async (ctx, doc) => { /* after update */ },
|
|
522
|
-
onRemove: async (ctx,
|
|
519
|
+
onRemove: async (ctx, document) => { /* after remove */ },
|
|
523
520
|
|
|
524
521
|
// Transform hook (modify documents before returning)
|
|
525
522
|
transform: async (docs) => docs.filter(d => d.isPublic),
|
|
@@ -711,7 +708,7 @@ interface CollectionConfig<T> {
|
|
|
711
708
|
schema: ZodObject; // Required: Zod schema for type inference
|
|
712
709
|
getKey: (item: T) => string | number; // Extract unique key from item
|
|
713
710
|
convexClient: ConvexClient; // Convex client instance
|
|
714
|
-
api: { // API from
|
|
711
|
+
api: { // API from collection.create()
|
|
715
712
|
stream: FunctionReference; // Real-time subscription
|
|
716
713
|
insert: FunctionReference; // Insert mutation
|
|
717
714
|
update: FunctionReference; // Update mutation
|
|
@@ -816,34 +813,33 @@ errors.NonRetriable // Errors that should not be retried (auth, validation)
|
|
|
816
813
|
|
|
817
814
|
### Server-Side (`@trestleinc/replicate/server`)
|
|
818
815
|
|
|
819
|
-
#### `
|
|
816
|
+
#### `collection.create<T>(component, name, options?)`
|
|
820
817
|
|
|
821
|
-
|
|
818
|
+
Creates server-side collection functions that mirror the client-side collection.
|
|
822
819
|
|
|
823
820
|
**Parameters:**
|
|
824
821
|
- `component` - Your Convex component reference (`components.replicate`)
|
|
825
|
-
|
|
826
|
-
|
|
822
|
+
- `name` - Collection name (e.g., `'tasks'`)
|
|
823
|
+
- `options` - Optional configuration for compaction and hooks
|
|
827
824
|
|
|
828
825
|
**Example:**
|
|
829
826
|
```typescript
|
|
830
|
-
import {
|
|
827
|
+
import { collection } from '@trestleinc/replicate/server';
|
|
831
828
|
import { components } from './_generated/api';
|
|
832
829
|
|
|
833
|
-
const
|
|
834
|
-
|
|
830
|
+
export const {
|
|
831
|
+
stream, material, insert, update, remove, recovery, mark, compact, sessions, cursors, leave,
|
|
832
|
+
} = collection.create<Task>(components.replicate, 'tasks');
|
|
835
833
|
```
|
|
836
834
|
|
|
837
|
-
#### `
|
|
835
|
+
#### `CollectionOptions<T>`
|
|
838
836
|
|
|
839
|
-
|
|
837
|
+
Optional configuration for `collection.create()`.
|
|
840
838
|
|
|
841
839
|
**Config:**
|
|
842
840
|
```typescript
|
|
843
|
-
interface
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
// Optional: Compaction settings with type-safe values
|
|
841
|
+
interface CollectionOptions<T> {
|
|
842
|
+
// Optional: Compaction settings
|
|
847
843
|
compaction?: {
|
|
848
844
|
sizeThreshold?: Size; // Size threshold: "100kb", "5mb", "1gb" (default: "5mb")
|
|
849
845
|
peerTimeout?: Duration; // Peer timeout: "30m", "24h", "7d" (default: "24h")
|
|
@@ -854,15 +850,15 @@ interface ReplicateConfig<T> {
|
|
|
854
850
|
// Permission checks (throw to reject)
|
|
855
851
|
evalRead?: (ctx, collection) => Promise<void>;
|
|
856
852
|
evalWrite?: (ctx, doc) => Promise<void>;
|
|
857
|
-
evalRemove?: (ctx,
|
|
853
|
+
evalRemove?: (ctx, document) => Promise<void>;
|
|
858
854
|
evalMark?: (ctx, peerId) => Promise<void>;
|
|
859
|
-
evalCompact?: (ctx,
|
|
855
|
+
evalCompact?: (ctx, document) => Promise<void>;
|
|
860
856
|
|
|
861
857
|
// Lifecycle callbacks (run after operation)
|
|
862
858
|
onStream?: (ctx, result) => Promise<void>;
|
|
863
859
|
onInsert?: (ctx, doc) => Promise<void>;
|
|
864
860
|
onUpdate?: (ctx, doc) => Promise<void>;
|
|
865
|
-
onRemove?: (ctx,
|
|
861
|
+
onRemove?: (ctx, document) => Promise<void>;
|
|
866
862
|
|
|
867
863
|
// Transform hook (modify documents before returning)
|
|
868
864
|
transform?: (docs) => Promise<T[]>;
|
|
@@ -883,6 +879,9 @@ interface ReplicateConfig<T> {
|
|
|
883
879
|
- `remove` - Dual-storage delete mutation (auto-compacts when threshold exceeded)
|
|
884
880
|
- `mark` - Peer sync tracking mutation (reports `syncedSeq` to server)
|
|
885
881
|
- `compact` - Manual compaction mutation (peer-aware, safe for active clients)
|
|
882
|
+
- `sessions` - Get connected sessions (presence query)
|
|
883
|
+
- `cursors` - Get cursor positions for collaborative editing
|
|
884
|
+
- `leave` - Explicit disconnect mutation
|
|
886
885
|
|
|
887
886
|
#### `schema.table(userFields, applyIndexes?)`
|
|
888
887
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trestleinc/replicate",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0-preview.0",
|
|
4
4
|
"description": "Offline-first data replication with Yjs CRDTs and Convex",
|
|
5
5
|
"repository": "github:trestleinc/replicate",
|
|
6
6
|
"homepage": "https://github.com/trestleinc/replicate#readme",
|
|
@@ -82,6 +82,7 @@
|
|
|
82
82
|
"@tanstack/db": "^0.5.15",
|
|
83
83
|
"convex": "^1.31.0",
|
|
84
84
|
"lib0": "^0.2.0",
|
|
85
|
+
"y-protocols": "^1.0.7",
|
|
85
86
|
"yjs": "^13.6.0"
|
|
86
87
|
},
|
|
87
88
|
"peerDependenciesMeta": {
|
|
@@ -111,6 +112,7 @@
|
|
|
111
112
|
"tsdown": "0.18.2",
|
|
112
113
|
"typescript": "5.9.3",
|
|
113
114
|
"typescript-eslint": "8.50.1",
|
|
115
|
+
"y-protocols": "1.0.7",
|
|
114
116
|
"yjs": "13.6.28",
|
|
115
117
|
"zod": "4.2.1"
|
|
116
118
|
},
|