@trestleinc/replicate 0.1.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/LICENSE +201 -0
- package/LICENSE.package +201 -0
- package/README.md +871 -0
- package/dist/client/collection.d.ts +94 -0
- package/dist/client/index.d.ts +18 -0
- package/dist/client/logger.d.ts +3 -0
- package/dist/client/storage.d.ts +143 -0
- package/dist/component/_generated/api.js +5 -0
- package/dist/component/_generated/server.js +9 -0
- package/dist/component/convex.config.d.ts +2 -0
- package/dist/component/convex.config.js +3 -0
- package/dist/component/public.d.ts +99 -0
- package/dist/component/public.js +135 -0
- package/dist/component/schema.d.ts +22 -0
- package/dist/component/schema.js +22 -0
- package/dist/index.js +375 -0
- package/dist/server/index.d.ts +17 -0
- package/dist/server/replication.d.ts +122 -0
- package/dist/server/schema.d.ts +73 -0
- package/dist/server/ssr.d.ts +79 -0
- package/dist/server.js +96 -0
- package/dist/ssr.js +19 -0
- package/package.json +108 -0
- package/src/client/collection.ts +550 -0
- package/src/client/index.ts +31 -0
- package/src/client/logger.ts +31 -0
- package/src/client/storage.ts +206 -0
- package/src/component/_generated/api.d.ts +95 -0
- package/src/component/_generated/api.js +23 -0
- package/src/component/_generated/dataModel.d.ts +60 -0
- package/src/component/_generated/server.d.ts +149 -0
- package/src/component/_generated/server.js +90 -0
- package/src/component/convex.config.ts +3 -0
- package/src/component/public.ts +212 -0
- package/src/component/schema.ts +16 -0
- package/src/server/index.ts +26 -0
- package/src/server/replication.ts +244 -0
- package/src/server/schema.ts +97 -0
- package/src/server/ssr.ts +106 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { defineTable } from "convex/server";
|
|
2
|
+
import { v } from "convex/values";
|
|
3
|
+
function cleanDocument(doc) {
|
|
4
|
+
return Object.fromEntries(Object.entries(doc).filter(([_, value])=>null != value));
|
|
5
|
+
}
|
|
6
|
+
async function insertDocumentHelper(ctx, components, tableName, args) {
|
|
7
|
+
const timestamp = Date.now();
|
|
8
|
+
await ctx.runMutation(components.replicate.public.insertDocument, {
|
|
9
|
+
collectionName: tableName,
|
|
10
|
+
documentId: args.id,
|
|
11
|
+
crdtBytes: args.crdtBytes,
|
|
12
|
+
version: args.version
|
|
13
|
+
});
|
|
14
|
+
const db = ctx.db;
|
|
15
|
+
const cleanDoc = cleanDocument(args.materializedDoc);
|
|
16
|
+
await db.insert(tableName, {
|
|
17
|
+
id: args.id,
|
|
18
|
+
...cleanDoc,
|
|
19
|
+
version: args.version,
|
|
20
|
+
timestamp
|
|
21
|
+
});
|
|
22
|
+
return {
|
|
23
|
+
success: true,
|
|
24
|
+
metadata: {
|
|
25
|
+
documentId: args.id,
|
|
26
|
+
timestamp,
|
|
27
|
+
version: args.version,
|
|
28
|
+
collectionName: tableName
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async function updateDocumentHelper(ctx, components, tableName, args) {
|
|
33
|
+
const timestamp = Date.now();
|
|
34
|
+
await ctx.runMutation(components.replicate.public.updateDocument, {
|
|
35
|
+
collectionName: tableName,
|
|
36
|
+
documentId: args.id,
|
|
37
|
+
crdtBytes: args.crdtBytes,
|
|
38
|
+
version: args.version
|
|
39
|
+
});
|
|
40
|
+
const db = ctx.db;
|
|
41
|
+
const existing = await db.query(tableName).withIndex('by_user_id', (q)=>q.eq('id', args.id)).first();
|
|
42
|
+
if (!existing) throw new Error(`Document ${args.id} not found in table ${tableName}`);
|
|
43
|
+
const cleanDoc = cleanDocument(args.materializedDoc);
|
|
44
|
+
await db.patch(existing._id, {
|
|
45
|
+
...cleanDoc,
|
|
46
|
+
version: args.version,
|
|
47
|
+
timestamp
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
success: true,
|
|
51
|
+
metadata: {
|
|
52
|
+
documentId: args.id,
|
|
53
|
+
timestamp,
|
|
54
|
+
version: args.version,
|
|
55
|
+
collectionName: tableName
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async function deleteDocumentHelper(ctx, components, tableName, args) {
|
|
60
|
+
const timestamp = Date.now();
|
|
61
|
+
await ctx.runMutation(components.replicate.public.deleteDocument, {
|
|
62
|
+
collectionName: tableName,
|
|
63
|
+
documentId: args.id,
|
|
64
|
+
crdtBytes: args.crdtBytes,
|
|
65
|
+
version: args.version
|
|
66
|
+
});
|
|
67
|
+
const db = ctx.db;
|
|
68
|
+
const existing = await db.query(tableName).withIndex('by_user_id', (q)=>q.eq('id', args.id)).first();
|
|
69
|
+
if (existing) await db.delete(existing._id);
|
|
70
|
+
return {
|
|
71
|
+
success: true,
|
|
72
|
+
metadata: {
|
|
73
|
+
documentId: args.id,
|
|
74
|
+
timestamp,
|
|
75
|
+
version: args.version,
|
|
76
|
+
collectionName: tableName
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async function streamHelper(ctx, components, tableName, args) {
|
|
81
|
+
return ctx.runQuery(components.replicate.public.stream, {
|
|
82
|
+
collectionName: tableName,
|
|
83
|
+
checkpoint: args.checkpoint,
|
|
84
|
+
limit: args.limit
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function replicatedTable(userFields, applyIndexes) {
|
|
88
|
+
const tableWithMetadata = defineTable({
|
|
89
|
+
...userFields,
|
|
90
|
+
version: v.number(),
|
|
91
|
+
timestamp: v.number()
|
|
92
|
+
});
|
|
93
|
+
if (applyIndexes) return applyIndexes(tableWithMetadata);
|
|
94
|
+
return tableWithMetadata;
|
|
95
|
+
}
|
|
96
|
+
export { deleteDocumentHelper, insertDocumentHelper, replicatedTable, streamHelper, updateDocumentHelper };
|
package/dist/ssr.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
async function loadCollection(httpClient, config) {
|
|
2
|
+
const result = await httpClient.query(config.api.stream, {
|
|
3
|
+
collectionName: config.collection,
|
|
4
|
+
checkpoint: {
|
|
5
|
+
lastModified: 0
|
|
6
|
+
},
|
|
7
|
+
limit: config.limit ?? 100
|
|
8
|
+
});
|
|
9
|
+
const items = [];
|
|
10
|
+
for (const change of result.changes){
|
|
11
|
+
const item = {
|
|
12
|
+
id: change.documentId,
|
|
13
|
+
...change.document
|
|
14
|
+
};
|
|
15
|
+
items.push(item);
|
|
16
|
+
}
|
|
17
|
+
return items;
|
|
18
|
+
}
|
|
19
|
+
export { loadCollection };
|
package/package.json
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@trestleinc/replicate",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Offline-first data replication with Yjs CRDTs and Convex",
|
|
5
|
+
"repository": "github:trestleinc/convex-replicate",
|
|
6
|
+
"homepage": "https://github.com/trestleinc/convex-replicate#readme",
|
|
7
|
+
"bugs": {
|
|
8
|
+
"url": "https://github.com/trestleinc/convex-replicate/issues"
|
|
9
|
+
},
|
|
10
|
+
"license": "Apache-2.0",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"convex",
|
|
13
|
+
"replicate",
|
|
14
|
+
"crdt",
|
|
15
|
+
"yjs",
|
|
16
|
+
"offline-first",
|
|
17
|
+
"tanstack"
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"private": false,
|
|
21
|
+
"resolutions": {
|
|
22
|
+
"convex": "1.28.2"
|
|
23
|
+
},
|
|
24
|
+
"overrides": {
|
|
25
|
+
"convex": "1.28.2"
|
|
26
|
+
},
|
|
27
|
+
"exports": {
|
|
28
|
+
"./package.json": "./package.json",
|
|
29
|
+
"./client": {
|
|
30
|
+
"import": {
|
|
31
|
+
"@convex-dev/component-source": "./src/client/index.ts",
|
|
32
|
+
"types": "./dist/client/index.d.ts",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"./server": {
|
|
37
|
+
"import": {
|
|
38
|
+
"types": "./dist/server/index.d.ts",
|
|
39
|
+
"default": "./dist/server.js"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"./ssr": {
|
|
43
|
+
"import": {
|
|
44
|
+
"types": "./dist/server/ssr.d.ts",
|
|
45
|
+
"default": "./dist/ssr.js"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"./convex.config": {
|
|
49
|
+
"import": {
|
|
50
|
+
"@convex-dev/component-source": "./src/component/convex.config.ts",
|
|
51
|
+
"types": "./dist/component/convex.config.d.ts",
|
|
52
|
+
"default": "./dist/component/convex.config.js"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"files": [
|
|
57
|
+
"dist",
|
|
58
|
+
"src",
|
|
59
|
+
"README.md",
|
|
60
|
+
"LICENSE"
|
|
61
|
+
],
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"yjs": "13.6.27",
|
|
64
|
+
"@tanstack/offline-transactions": "0.1.3",
|
|
65
|
+
"@logtape/logtape": "1.1.2"
|
|
66
|
+
},
|
|
67
|
+
"peerDependencies": {
|
|
68
|
+
"convex": "1.28.2",
|
|
69
|
+
"@tanstack/db": "0.4.20"
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@biomejs/biome": "2.3.4",
|
|
73
|
+
"@rslib/core": "0.17.1",
|
|
74
|
+
"@semantic-release/changelog": "6.0.3",
|
|
75
|
+
"@semantic-release/exec": "7.1.0",
|
|
76
|
+
"@semantic-release/git": "10.0.1",
|
|
77
|
+
"@semantic-release/github": "12.0.1",
|
|
78
|
+
"@tanstack/db": "0.4.20",
|
|
79
|
+
"@types/node": "24.10.0",
|
|
80
|
+
"convex": "1.28.2",
|
|
81
|
+
"semantic-release": "25.0.1",
|
|
82
|
+
"typescript": "5.9.3",
|
|
83
|
+
"zod": "4.1.12"
|
|
84
|
+
},
|
|
85
|
+
"main": "./dist/index.js",
|
|
86
|
+
"types": "./dist/client/index.d.ts",
|
|
87
|
+
"module": "./dist/index.js",
|
|
88
|
+
"publishConfig": {
|
|
89
|
+
"access": "public"
|
|
90
|
+
},
|
|
91
|
+
"scripts": {
|
|
92
|
+
"build": "rslib build",
|
|
93
|
+
"dev": "rslib build --watch",
|
|
94
|
+
"clean": "rm -rf dist",
|
|
95
|
+
"typecheck": "tsc --noEmit",
|
|
96
|
+
"dev:example": "cd examples/tanstack-start && pnpm run dev",
|
|
97
|
+
"build:example": "cd examples/tanstack-start && pnpm run build",
|
|
98
|
+
"lint": "biome lint .",
|
|
99
|
+
"lint:fix": "biome lint --write .",
|
|
100
|
+
"format": "biome format --write .",
|
|
101
|
+
"format:check": "biome format .",
|
|
102
|
+
"check": "biome check .",
|
|
103
|
+
"check:fix": "biome check --write .",
|
|
104
|
+
"version-packages": "node scripts/version-packages.js",
|
|
105
|
+
"publish:npm": "pnpm run build && pnpm run check:fix && pnpm publish --access public",
|
|
106
|
+
"prepublish": "pnpm run build && pnpm run check:fix"
|
|
107
|
+
}
|
|
108
|
+
}
|