@plures/pluresdb 1.5.3 → 2.9.6

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.
Files changed (103) hide show
  1. package/README.md +106 -414
  2. package/crates/README.md +99 -0
  3. package/crates/pluresdb-node/README.md +181 -0
  4. package/crates/pluresdb-node/index.d.ts +0 -0
  5. package/crates/pluresdb-node/index.js +265 -0
  6. package/crates/pluresdb-node/package.json +35 -0
  7. package/dist/napi/index.js +60 -0
  8. package/embedded.d.ts +1 -0
  9. package/embedded.js +46 -0
  10. package/package.json +27 -10
  11. package/dist/.tsbuildinfo +0 -1
  12. package/dist/better-sqlite3-shared.d.ts +0 -12
  13. package/dist/better-sqlite3-shared.d.ts.map +0 -1
  14. package/dist/better-sqlite3-shared.js +0 -143
  15. package/dist/better-sqlite3-shared.js.map +0 -1
  16. package/dist/better-sqlite3.d.ts +0 -4
  17. package/dist/better-sqlite3.d.ts.map +0 -1
  18. package/dist/better-sqlite3.js +0 -8
  19. package/dist/better-sqlite3.js.map +0 -1
  20. package/dist/cli.d.ts +0 -7
  21. package/dist/cli.d.ts.map +0 -1
  22. package/dist/cli.js.map +0 -1
  23. package/dist/node-index.d.ts +0 -148
  24. package/dist/node-index.d.ts.map +0 -1
  25. package/dist/node-index.js +0 -665
  26. package/dist/node-index.js.map +0 -1
  27. package/dist/node-wrapper.d.ts +0 -44
  28. package/dist/node-wrapper.d.ts.map +0 -1
  29. package/dist/node-wrapper.js +0 -296
  30. package/dist/node-wrapper.js.map +0 -1
  31. package/dist/types/index.d.ts +0 -28
  32. package/dist/types/index.d.ts.map +0 -1
  33. package/dist/types/index.js +0 -3
  34. package/dist/types/index.js.map +0 -1
  35. package/dist/types/node-types.d.ts +0 -71
  36. package/dist/types/node-types.d.ts.map +0 -1
  37. package/dist/types/node-types.js +0 -6
  38. package/dist/types/node-types.js.map +0 -1
  39. package/dist/vscode/extension.d.ts +0 -81
  40. package/dist/vscode/extension.d.ts.map +0 -1
  41. package/dist/vscode/extension.js +0 -309
  42. package/dist/vscode/extension.js.map +0 -1
  43. package/examples/basic-usage.d.ts +0 -2
  44. package/examples/basic-usage.d.ts.map +0 -1
  45. package/examples/basic-usage.js +0 -26
  46. package/examples/basic-usage.js.map +0 -1
  47. package/examples/basic-usage.ts +0 -29
  48. package/examples/vscode-extension-example/README.md +0 -95
  49. package/examples/vscode-extension-example/package.json +0 -49
  50. package/examples/vscode-extension-example/src/extension.ts +0 -172
  51. package/examples/vscode-extension-example/tsconfig.json +0 -12
  52. package/examples/vscode-extension-integration.d.ts +0 -31
  53. package/examples/vscode-extension-integration.d.ts.map +0 -1
  54. package/examples/vscode-extension-integration.js +0 -319
  55. package/examples/vscode-extension-integration.js.map +0 -1
  56. package/examples/vscode-extension-integration.ts +0 -41
  57. package/legacy/benchmarks/memory-benchmarks.ts +0 -350
  58. package/legacy/benchmarks/run-benchmarks.ts +0 -315
  59. package/legacy/better-sqlite3-shared.ts +0 -157
  60. package/legacy/better-sqlite3.ts +0 -4
  61. package/legacy/cli.ts +0 -241
  62. package/legacy/config.ts +0 -50
  63. package/legacy/core/crdt.ts +0 -107
  64. package/legacy/core/database.ts +0 -529
  65. package/legacy/healthcheck.ts +0 -162
  66. package/legacy/http/api-server.ts +0 -438
  67. package/legacy/index.ts +0 -28
  68. package/legacy/logic/rules.ts +0 -46
  69. package/legacy/main.rs +0 -3
  70. package/legacy/main.ts +0 -197
  71. package/legacy/network/websocket-server.ts +0 -115
  72. package/legacy/node-index.ts +0 -823
  73. package/legacy/node-wrapper.ts +0 -329
  74. package/legacy/sqlite-compat.ts +0 -633
  75. package/legacy/sqlite3-compat.ts +0 -55
  76. package/legacy/storage/kv-storage.ts +0 -73
  77. package/legacy/tests/core.test.ts +0 -305
  78. package/legacy/tests/fixtures/performance-data.json +0 -71
  79. package/legacy/tests/fixtures/test-data.json +0 -129
  80. package/legacy/tests/integration/api-server.test.ts +0 -334
  81. package/legacy/tests/integration/mesh-network.test.ts +0 -303
  82. package/legacy/tests/logic.test.ts +0 -34
  83. package/legacy/tests/performance/load.test.ts +0 -290
  84. package/legacy/tests/security/input-validation.test.ts +0 -286
  85. package/legacy/tests/unit/core.test.ts +0 -226
  86. package/legacy/tests/unit/subscriptions.test.ts +0 -135
  87. package/legacy/tests/unit/vector-search.test.ts +0 -173
  88. package/legacy/tests/vscode_extension_test.ts +0 -281
  89. package/legacy/types/index.ts +0 -32
  90. package/legacy/types/node-types.ts +0 -80
  91. package/legacy/util/debug.ts +0 -14
  92. package/legacy/vector/index.ts +0 -59
  93. package/legacy/vscode/extension.ts +0 -387
  94. package/scripts/compiled-crud-verify.ts +0 -30
  95. package/scripts/dogfood.ts +0 -297
  96. package/scripts/postinstall.js +0 -156
  97. package/scripts/publish-crates.sh +0 -95
  98. package/scripts/release-check.js +0 -224
  99. package/scripts/run-tests.ts +0 -178
  100. package/scripts/setup-libclang.ps1 +0 -209
  101. package/scripts/update-changelog.js +0 -214
  102. package/web/README.md +0 -27
  103. package/web/svelte/package.json +0 -31
@@ -1,334 +0,0 @@
1
- // @ts-nocheck
2
- import { assertEquals, assertExists } from "jsr:@std/assert@1.0.14";
3
- import { GunDB } from "../../core/database.ts";
4
- import { type ApiServerHandle, startApiServer } from "../../http/api-server.ts";
5
-
6
- function randomPort(): number {
7
- return 18000 + Math.floor(Math.random() * 10000);
8
- }
9
-
10
- Deno.test("API Server - HTTP Endpoints", async () => {
11
- const db = new GunDB();
12
- let api: ApiServerHandle | null = null;
13
- try {
14
- const kvPath = await Deno.makeTempFile({
15
- prefix: "kv_",
16
- suffix: ".sqlite",
17
- });
18
- await db.ready(kvPath);
19
-
20
- const port = randomPort();
21
- const apiPort = port + 1;
22
- db.serve({ port });
23
- api = startApiServer({ port: apiPort, db });
24
-
25
- const baseUrl = `http://localhost:${apiPort}`;
26
-
27
- // Test PUT endpoint
28
- const putResponse = await fetch(`${baseUrl}/api/nodes/test:1`, {
29
- method: "PUT",
30
- headers: { "Content-Type": "application/json" },
31
- body: JSON.stringify({ name: "Test Node", value: 123 }),
32
- });
33
- assertEquals(putResponse.status, 200);
34
- await putResponse.body?.cancel();
35
-
36
- // Test GET endpoint
37
- const getResponse = await fetch(`${baseUrl}/api/nodes/test:1`);
38
- assertEquals(getResponse.status, 200);
39
- const data = await getResponse.json();
40
- assertEquals(data.name, "Test Node");
41
- assertEquals(data.value, 123);
42
-
43
- // Test DELETE endpoint
44
- const deleteResponse = await fetch(`${baseUrl}/api/nodes/test:1`, {
45
- method: "DELETE",
46
- });
47
- assertEquals(deleteResponse.status, 200);
48
- await deleteResponse.body?.cancel();
49
-
50
- // Verify deletion
51
- const getAfterDelete = await fetch(`${baseUrl}/api/nodes/test:1`);
52
- assertEquals(getAfterDelete.status, 404);
53
- await getAfterDelete.body?.cancel();
54
- } finally {
55
- api?.close();
56
- await db.close();
57
- }
58
- });
59
-
60
- Deno.test("API Server - Vector Search Endpoint", async () => {
61
- const db = new GunDB();
62
- let api: ApiServerHandle | null = null;
63
- try {
64
- const kvPath = await Deno.makeTempFile({
65
- prefix: "kv_",
66
- suffix: ".sqlite",
67
- });
68
- await db.ready(kvPath);
69
-
70
- // Add test data
71
- await db.put("doc:1", { text: "Machine learning algorithms" });
72
- await db.put("doc:2", { text: "Cooking recipes and food" });
73
-
74
- const port = randomPort();
75
- const apiPort = port + 1;
76
- db.serve({ port });
77
- api = startApiServer({ port: apiPort, db });
78
-
79
- const baseUrl = `http://localhost:${apiPort}`;
80
-
81
- // Test vector search endpoint
82
- const searchResponse = await fetch(`${baseUrl}/api/search`, {
83
- method: "POST",
84
- headers: { "Content-Type": "application/json" },
85
- body: JSON.stringify({
86
- query: "machine learning",
87
- limit: 5,
88
- }),
89
- });
90
-
91
- assertEquals(searchResponse.status, 200);
92
- const results = await searchResponse.json();
93
- assertExists(results);
94
- assertEquals(Array.isArray(results), true);
95
- } finally {
96
- api?.close();
97
- await db.close();
98
- }
99
- });
100
-
101
- Deno.test("API Server - WebSocket Connection", async () => {
102
- const db = new GunDB();
103
- let api: ApiServerHandle | null = null;
104
- try {
105
- const kvPath = await Deno.makeTempFile({
106
- prefix: "kv_",
107
- suffix: ".sqlite",
108
- });
109
- await db.ready(kvPath);
110
-
111
- const port = randomPort();
112
- const apiPort = port + 1;
113
- db.serve({ port });
114
- api = startApiServer({ port: apiPort, db });
115
-
116
- const wsUrl = `ws://localhost:${port}/ws`;
117
-
118
- // Test WebSocket connection
119
- const ws = new WebSocket(wsUrl);
120
-
121
- const connectionPromise = new Promise((resolve, reject) => {
122
- const timer = setTimeout(
123
- () => reject(new Error("Connection timeout")),
124
- 5000,
125
- );
126
- ws.onopen = () => {
127
- clearTimeout(timer);
128
- resolve(true);
129
- };
130
- ws.onerror = (error) => {
131
- clearTimeout(timer);
132
- reject(error);
133
- };
134
- });
135
-
136
- await connectionPromise;
137
-
138
- // Test sending data via WebSocket
139
- const messagePromise = new Promise((resolve) => {
140
- ws.onmessage = (event) => {
141
- const data = JSON.parse(event.data);
142
- if (data.type === "put") {
143
- resolve(data);
144
- }
145
- };
146
- });
147
-
148
- // Send a message
149
- ws.send(
150
- JSON.stringify({
151
- type: "put",
152
- id: "ws:test",
153
- data: { message: "Hello WebSocket" },
154
- }),
155
- );
156
-
157
- await messagePromise;
158
- ws.close();
159
- } finally {
160
- api?.close();
161
- await db.close();
162
- }
163
- });
164
-
165
- Deno.test("API Server - Error Handling", async () => {
166
- const db = new GunDB();
167
- let api: ApiServerHandle | null = null;
168
- try {
169
- const kvPath = await Deno.makeTempFile({
170
- prefix: "kv_",
171
- suffix: ".sqlite",
172
- });
173
- await db.ready(kvPath);
174
-
175
- const port = randomPort();
176
- const apiPort = port + 1;
177
- db.serve({ port });
178
- api = startApiServer({ port: apiPort, db });
179
-
180
- const baseUrl = `http://localhost:${apiPort}`;
181
-
182
- // Test 404 for non-existent node
183
- const notFoundResponse = await fetch(`${baseUrl}/api/nodes/nonexistent`);
184
- assertEquals(notFoundResponse.status, 404);
185
- await notFoundResponse.body?.cancel();
186
-
187
- // Test 400 for invalid JSON
188
- const invalidJsonResponse = await fetch(`${baseUrl}/api/nodes/test`, {
189
- method: "PUT",
190
- headers: { "Content-Type": "application/json" },
191
- body: "invalid json",
192
- });
193
- assertEquals(invalidJsonResponse.status, 400);
194
- await invalidJsonResponse.body?.cancel();
195
- } finally {
196
- api?.close();
197
- await db.close();
198
- }
199
- });
200
-
201
- Deno.test("API Server - CORS Headers", async () => {
202
- const db = new GunDB();
203
- let api: ApiServerHandle | null = null;
204
- try {
205
- const kvPath = await Deno.makeTempFile({
206
- prefix: "kv_",
207
- suffix: ".sqlite",
208
- });
209
- await db.ready(kvPath);
210
-
211
- const port = randomPort();
212
- const apiPort = port + 1;
213
- db.serve({ port });
214
- api = startApiServer({ port: apiPort, db });
215
-
216
- const baseUrl = `http://localhost:${apiPort}`;
217
-
218
- // Test OPTIONS request for CORS
219
- const optionsResponse = await fetch(`${baseUrl}/api/nodes/test`, {
220
- method: "OPTIONS",
221
- headers: {
222
- Origin: "http://localhost:3000",
223
- "Access-Control-Request-Method": "PUT",
224
- },
225
- });
226
-
227
- assertEquals(optionsResponse.status, 200);
228
- assertExists(optionsResponse.headers.get("Access-Control-Allow-Origin"));
229
- assertExists(optionsResponse.headers.get("Access-Control-Allow-Methods"));
230
- await optionsResponse.body?.cancel();
231
- } finally {
232
- api?.close();
233
- await db.close();
234
- }
235
- });
236
-
237
- Deno.test("API Server - P2P API Endpoints", async () => {
238
- const db = new GunDB();
239
- let api: ApiServerHandle | null = null;
240
- try {
241
- const kvPath = await Deno.makeTempFile({
242
- prefix: "kv_",
243
- suffix: ".sqlite",
244
- });
245
- await db.ready(kvPath);
246
-
247
- const port = randomPort();
248
- const apiPort = port + 1;
249
- db.serve({ port });
250
- api = startApiServer({ port: apiPort, db });
251
-
252
- const baseUrl = `http://localhost:${apiPort}`;
253
-
254
- // Test createIdentity endpoint
255
- const identityResponse = await fetch(`${baseUrl}/api/identity`, {
256
- method: "POST",
257
- headers: { "Content-Type": "application/json" },
258
- body: JSON.stringify({ name: "John Doe", email: "john@example.com" }),
259
- });
260
- assertEquals(identityResponse.status, 200);
261
- const identity = await identityResponse.json();
262
- assertExists(identity.id);
263
- assertExists(identity.publicKey);
264
- assertEquals(identity.name, "John Doe");
265
- assertEquals(identity.email, "john@example.com");
266
-
267
- // Test searchPeers endpoint
268
- const peersResponse = await fetch(`${baseUrl}/api/peers/search?q=developer`);
269
- assertEquals(peersResponse.status, 200);
270
- const peers = await peersResponse.json();
271
- assertEquals(Array.isArray(peers), true);
272
-
273
- // Test shareNode endpoint
274
- const shareResponse = await fetch(`${baseUrl}/api/share`, {
275
- method: "POST",
276
- headers: { "Content-Type": "application/json" },
277
- body: JSON.stringify({
278
- nodeId: "node:123",
279
- targetPeerId: "peer:456",
280
- accessLevel: "read-only",
281
- }),
282
- });
283
- assertEquals(shareResponse.status, 200);
284
- const shareData = await shareResponse.json();
285
- assertExists(shareData.sharedNodeId);
286
- assertEquals(shareData.nodeId, "node:123");
287
- assertEquals(shareData.targetPeerId, "peer:456");
288
- assertEquals(shareData.accessLevel, "read-only");
289
-
290
- // Test acceptSharedNode endpoint
291
- const acceptResponse = await fetch(`${baseUrl}/api/share/accept`, {
292
- method: "POST",
293
- headers: { "Content-Type": "application/json" },
294
- body: JSON.stringify({ sharedNodeId: "shared:789" }),
295
- });
296
- assertEquals(acceptResponse.status, 200);
297
- const acceptData = await acceptResponse.json();
298
- assertEquals(acceptData.success, true);
299
- assertEquals(acceptData.sharedNodeId, "shared:789");
300
-
301
- // Test addDevice endpoint
302
- const deviceResponse = await fetch(`${baseUrl}/api/devices`, {
303
- method: "POST",
304
- headers: { "Content-Type": "application/json" },
305
- body: JSON.stringify({ name: "My Laptop", type: "laptop" }),
306
- });
307
- assertEquals(deviceResponse.status, 200);
308
- const device = await deviceResponse.json();
309
- assertExists(device.id);
310
- assertEquals(device.name, "My Laptop");
311
- assertEquals(device.type, "laptop");
312
- assertEquals(device.status, "online");
313
-
314
- // Test syncWithDevice endpoint
315
- const syncResponse = await fetch(`${baseUrl}/api/devices/sync`, {
316
- method: "POST",
317
- headers: { "Content-Type": "application/json" },
318
- body: JSON.stringify({ deviceId: "device:123" }),
319
- });
320
- assertEquals(syncResponse.status, 200);
321
- const syncData = await syncResponse.json();
322
- assertEquals(syncData.success, true);
323
- assertEquals(syncData.deviceId, "device:123");
324
-
325
- // Test GET devices list
326
- const devicesListResponse = await fetch(`${baseUrl}/api/devices`);
327
- assertEquals(devicesListResponse.status, 200);
328
- const devicesList = await devicesListResponse.json();
329
- assertEquals(Array.isArray(devicesList), true);
330
- } finally {
331
- api?.close();
332
- await db.close();
333
- }
334
- });
@@ -1,303 +0,0 @@
1
- // @ts-nocheck
2
- import { assertEquals, assertExists } from "jsr:@std/assert@1.0.14";
3
- import { GunDB } from "../../core/database.ts";
4
-
5
- const shouldRunMeshTests =
6
- (Deno.env.get("RUN_MESH_TESTS") ?? "").toLowerCase() === "true";
7
- const defaultTimeoutMs = Number(
8
- Deno.env.get("RUN_MESH_TEST_TIMEOUT_MS") ?? "10000",
9
- );
10
-
11
- if (!shouldRunMeshTests) {
12
- console.warn(
13
- "[mesh-network.test] Skipping mesh networking integration tests. Set RUN_MESH_TESTS=true to enable.",
14
- );
15
- }
16
-
17
- function withTimeout<T>(
18
- promise: Promise<T>,
19
- message: string,
20
- timeoutMs = defaultTimeoutMs,
21
- ): Promise<T> {
22
- return new Promise((resolve, reject) => {
23
- const timer = setTimeout(() => {
24
- reject(new Error(message));
25
- }, timeoutMs);
26
-
27
- promise.then(
28
- (value) => {
29
- clearTimeout(timer);
30
- resolve(value);
31
- },
32
- (error) => {
33
- clearTimeout(timer);
34
- reject(error);
35
- },
36
- );
37
- });
38
- }
39
-
40
- function meshTest(name: string, fn: () => Promise<void>) {
41
- Deno.test({
42
- name,
43
- ignore: !shouldRunMeshTests,
44
- sanitizeOps: false,
45
- sanitizeResources: false,
46
- fn,
47
- });
48
- }
49
-
50
- function randomPort(): number {
51
- return 18000 + Math.floor(Math.random() * 10000);
52
- }
53
-
54
- meshTest("Mesh Network - Basic Connection and Sync", async () => {
55
- const port = randomPort();
56
- const serverUrl = `ws://localhost:${port}`;
57
-
58
- const dbA = new GunDB();
59
- const dbB = new GunDB();
60
-
61
- try {
62
- const kvA = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
63
- const kvB = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
64
-
65
- await dbA.ready(kvA);
66
- await dbB.ready(kvB);
67
-
68
- // Start server
69
- await dbA.serve({ port });
70
-
71
- // Add data to server
72
- await dbA.put("mesh:test", {
73
- text: "Hello from server A",
74
- timestamp: Date.now(),
75
- });
76
-
77
- // Connect client and wait for sync
78
- const receivedData = new Promise((resolve) => {
79
- dbB.on("mesh:test", (node) => {
80
- if (node && (node.data as any).text === "Hello from server A") {
81
- resolve(true);
82
- }
83
- });
84
- });
85
-
86
- dbB.connect(serverUrl);
87
- await withTimeout(
88
- receivedData as Promise<unknown>,
89
- "Timed out waiting for initial mesh sync",
90
- );
91
-
92
- // Verify data was received
93
- const syncedData = await dbB.get("mesh:test");
94
- assertExists(syncedData);
95
- assertEquals((syncedData as any).text, "Hello from server A");
96
- } finally {
97
- await dbB.close();
98
- await dbA.close();
99
- }
100
- });
101
-
102
- meshTest("Mesh Network - Bidirectional Sync", async () => {
103
- const port = randomPort();
104
- const serverUrl = `ws://localhost:${port}`;
105
-
106
- const dbA = new GunDB();
107
- const dbB = new GunDB();
108
-
109
- try {
110
- const kvA = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
111
- const kvB = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
112
-
113
- await dbA.ready(kvA);
114
- await dbB.ready(kvB);
115
- await dbA.serve({ port });
116
-
117
- // Connect B to A
118
- dbB.connect(serverUrl);
119
- await withTimeout(
120
- new Promise((resolve) => setTimeout(resolve, 100)),
121
- "Timed out waiting for mesh connection",
122
- );
123
-
124
- // A sends data to B
125
- await dbA.put("from:A", { message: "Hello from A" });
126
-
127
- const receivedFromA = new Promise((resolve) => {
128
- dbB.on("from:A", (node) => {
129
- if (node && (node.data as any).message === "Hello from A") {
130
- resolve(true);
131
- }
132
- });
133
- });
134
- await withTimeout(
135
- receivedFromA as Promise<unknown>,
136
- "Timed out waiting for data from node A",
137
- );
138
-
139
- // B sends data to A
140
- await dbB.put("from:B", { message: "Hello from B" });
141
-
142
- const receivedFromB = new Promise((resolve) => {
143
- dbA.on("from:B", (node) => {
144
- if (node && (node.data as any).message === "Hello from B") {
145
- resolve(true);
146
- }
147
- });
148
- });
149
- await withTimeout(
150
- receivedFromB as Promise<unknown>,
151
- "Timed out waiting for data from node B",
152
- );
153
-
154
- // Verify both received data
155
- const dataFromA = await dbB.get("from:A");
156
- const dataFromB = await dbA.get("from:B");
157
-
158
- assertExists(dataFromA);
159
- assertExists(dataFromB);
160
- assertEquals((dataFromA as any).message, "Hello from A");
161
- assertEquals((dataFromB as any).message, "Hello from B");
162
- } finally {
163
- await dbB.close();
164
- await dbA.close();
165
- }
166
- });
167
-
168
- meshTest("Mesh Network - Conflict Resolution", async () => {
169
- const port = randomPort();
170
- const serverUrl = `ws://localhost:${port}`;
171
-
172
- const dbA = new GunDB();
173
- const dbB = new GunDB();
174
-
175
- try {
176
- const kvA = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
177
- const kvB = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
178
-
179
- await dbA.ready(kvA);
180
- await dbB.ready(kvB);
181
- await dbA.serve({ port });
182
-
183
- // Connect B to A
184
- dbB.connect(serverUrl);
185
- await new Promise((resolve) => setTimeout(resolve, 100));
186
-
187
- // Both modify the same key simultaneously
188
- const timestamp = Date.now();
189
- await dbA.put("conflict:test", {
190
- value: "from A",
191
- timestamp: timestamp + 1000,
192
- });
193
- await dbB.put("conflict:test", {
194
- value: "from B",
195
- timestamp: timestamp + 2000,
196
- });
197
-
198
- // Wait for sync
199
- await withTimeout(
200
- new Promise((resolve) => setTimeout(resolve, 500)),
201
- "Timed out waiting for conflict resolution",
202
- );
203
-
204
- // Check that both databases have the same final state
205
- const finalA = await dbA.get("conflict:test");
206
- const finalB = await dbB.get("conflict:test");
207
-
208
- assertExists(finalA);
209
- assertExists(finalB);
210
-
211
- // Should have the newer timestamp (from B)
212
- assertEquals((finalA as any).value, "from B");
213
- assertEquals((finalB as any).value, "from B");
214
- } finally {
215
- await dbB.close();
216
- await dbA.close();
217
- }
218
- });
219
-
220
- meshTest("Mesh Network - Multiple Clients", async () => {
221
- const port = randomPort();
222
- const serverUrl = `ws://localhost:${port}`;
223
-
224
- const dbA = new GunDB(); // Server
225
- const dbB = new GunDB(); // Client 1
226
- const dbC = new GunDB(); // Client 2
227
-
228
- try {
229
- const kvA = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
230
- const kvB = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
231
- const kvC = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
232
-
233
- await dbA.ready(kvA);
234
- await dbB.ready(kvB);
235
- await dbC.ready(kvC);
236
- await dbA.serve({ port });
237
-
238
- // Connect both clients
239
- dbB.connect(serverUrl);
240
- dbC.connect(serverUrl);
241
- await new Promise((resolve) => setTimeout(resolve, 200));
242
-
243
- // B sends data
244
- await dbB.put("multi:test", { from: "B", message: "Hello from B" });
245
-
246
- // Wait for both A and C to receive
247
- const receivedOnA = new Promise((resolve) => {
248
- dbA.on("multi:test", (node) => {
249
- if (node && (node.data as any).from === "B") resolve(true);
250
- });
251
- });
252
-
253
- const receivedOnC = new Promise((resolve) => {
254
- dbC.on("multi:test", (node) => {
255
- if (node && (node.data as any).from === "B") resolve(true);
256
- });
257
- });
258
-
259
- await withTimeout(
260
- Promise.all([receivedOnA, receivedOnC]),
261
- "Timed out waiting for multi-client propagation",
262
- );
263
-
264
- // Verify all have the data
265
- const dataA = await dbA.get("multi:test");
266
- const dataB = await dbB.get("multi:test");
267
- const dataC = await dbC.get("multi:test");
268
-
269
- assertExists(dataA);
270
- assertExists(dataB);
271
- assertExists(dataC);
272
- assertEquals((dataA as any).from, "B");
273
- assertEquals((dataB as any).from, "B");
274
- assertEquals((dataC as any).from, "B");
275
- } finally {
276
- await dbC.close();
277
- await dbB.close();
278
- await dbA.close();
279
- }
280
- });
281
-
282
- meshTest("Mesh Network - Connection Error Handling", async () => {
283
- const db = new GunDB();
284
-
285
- try {
286
- const kvPath = await Deno.makeTempFile({
287
- prefix: "kv_",
288
- suffix: ".sqlite",
289
- });
290
- await db.ready(kvPath);
291
-
292
- // Try to connect to non-existent server
293
- db.connect("ws://localhost:99999");
294
-
295
- // Should not throw error, but connection should fail gracefully
296
- await withTimeout(
297
- new Promise((resolve) => setTimeout(resolve, 1000)),
298
- "Timed out waiting for graceful connection failure",
299
- );
300
- } finally {
301
- await db.close();
302
- }
303
- });
@@ -1,34 +0,0 @@
1
- import { GunDB } from "../core/database.ts";
2
- import type { Rule } from "../logic/rules.ts";
3
-
4
- Deno.test("rule engine classification: Person.age >= 18 -> adult = true", async () => {
5
- const db = new GunDB();
6
- try {
7
- const kvPath = await Deno.makeTempFile({
8
- prefix: "kv_",
9
- suffix: ".sqlite",
10
- });
11
- await db.ready(kvPath);
12
-
13
- const rule: Rule = {
14
- name: "adultClassifier",
15
- whenType: "Person",
16
- predicate: (node) =>
17
- typeof (node.data as any).age === "number" &&
18
- (node.data as any).age >= 18,
19
- action: async (ctx, node) => {
20
- const data = { ...(node.data as Record<string, unknown>), adult: true };
21
- await ctx.db.put(node.id, data);
22
- },
23
- };
24
- db.addRule(rule);
25
-
26
- await db.put("p:alice", { name: "Alice", age: 20, type: "Person" });
27
- const got = await db.get<{ adult?: boolean }>("p:alice");
28
- if (!got || got.adult !== true) {
29
- throw new Error("Expected adult flag set by rule");
30
- }
31
- } finally {
32
- await db.close();
33
- }
34
- });