@plures/pluresdb 1.6.10 → 2.9.7

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 (93) hide show
  1. package/README.md +97 -289
  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/.tsbuildinfo +1 -1
  8. package/dist/napi/index.d.ts +38 -0
  9. package/dist/napi/index.d.ts.map +1 -0
  10. package/dist/napi/index.js +60 -0
  11. package/dist/napi/index.js.map +1 -0
  12. package/dist/node-index.d.ts +32 -0
  13. package/dist/node-index.d.ts.map +1 -1
  14. package/dist/node-index.js +52 -0
  15. package/dist/node-index.js.map +1 -1
  16. package/embedded.d.ts +1 -0
  17. package/embedded.js +46 -0
  18. package/package.json +21 -8
  19. package/examples/basic-usage.d.ts +0 -2
  20. package/examples/basic-usage.d.ts.map +0 -1
  21. package/examples/basic-usage.js +0 -26
  22. package/examples/basic-usage.js.map +0 -1
  23. package/examples/basic-usage.ts +0 -29
  24. package/examples/browser-demo/README.md +0 -204
  25. package/examples/browser-demo/index.html +0 -466
  26. package/examples/browser-wasm-integration.md +0 -411
  27. package/examples/ipc-demo/README.md +0 -127
  28. package/examples/local-first-usage.ts +0 -138
  29. package/examples/native-ipc-integration.md +0 -526
  30. package/examples/tauri-demo/README.md +0 -240
  31. package/examples/tauri-integration.md +0 -260
  32. package/examples/vscode-extension-example/README.md +0 -95
  33. package/examples/vscode-extension-example/package.json +0 -49
  34. package/examples/vscode-extension-example/src/extension.ts +0 -172
  35. package/examples/vscode-extension-example/tsconfig.json +0 -12
  36. package/examples/vscode-extension-integration.d.ts +0 -31
  37. package/examples/vscode-extension-integration.d.ts.map +0 -1
  38. package/examples/vscode-extension-integration.js +0 -319
  39. package/examples/vscode-extension-integration.js.map +0 -1
  40. package/examples/vscode-extension-integration.ts +0 -41
  41. package/legacy/benchmarks/memory-benchmarks.ts +0 -350
  42. package/legacy/benchmarks/run-benchmarks.ts +0 -315
  43. package/legacy/better-sqlite3-shared.ts +0 -157
  44. package/legacy/better-sqlite3.ts +0 -4
  45. package/legacy/cli.ts +0 -241
  46. package/legacy/config.ts +0 -50
  47. package/legacy/core/crdt.ts +0 -107
  48. package/legacy/core/database.ts +0 -529
  49. package/legacy/healthcheck.ts +0 -162
  50. package/legacy/http/api-server.ts +0 -569
  51. package/legacy/index.ts +0 -31
  52. package/legacy/local-first/unified-api.ts +0 -449
  53. package/legacy/logic/rules.ts +0 -46
  54. package/legacy/main.rs +0 -3
  55. package/legacy/main.ts +0 -197
  56. package/legacy/network/websocket-server.ts +0 -115
  57. package/legacy/node-index.ts +0 -827
  58. package/legacy/node-wrapper.ts +0 -329
  59. package/legacy/plugins/README.md +0 -181
  60. package/legacy/plugins/example-embedding-plugin.ts +0 -56
  61. package/legacy/plugins/plugin-system.ts +0 -315
  62. package/legacy/sqlite-compat.ts +0 -633
  63. package/legacy/sqlite3-compat.ts +0 -55
  64. package/legacy/storage/kv-storage.ts +0 -73
  65. package/legacy/tests/core.test.ts +0 -305
  66. package/legacy/tests/fixtures/performance-data.json +0 -71
  67. package/legacy/tests/fixtures/test-data.json +0 -129
  68. package/legacy/tests/integration/api-server.test.ts +0 -334
  69. package/legacy/tests/integration/mesh-network.test.ts +0 -303
  70. package/legacy/tests/logic.test.ts +0 -34
  71. package/legacy/tests/performance/load.test.ts +0 -290
  72. package/legacy/tests/security/input-validation.test.ts +0 -286
  73. package/legacy/tests/unit/core.test.ts +0 -226
  74. package/legacy/tests/unit/local-first-api.test.ts +0 -65
  75. package/legacy/tests/unit/plugin-system.test.ts +0 -388
  76. package/legacy/tests/unit/subscriptions.test.ts +0 -135
  77. package/legacy/tests/unit/vector-search.test.ts +0 -173
  78. package/legacy/tests/vscode_extension_test.ts +0 -281
  79. package/legacy/types/index.ts +0 -32
  80. package/legacy/types/node-types.ts +0 -80
  81. package/legacy/util/debug.ts +0 -27
  82. package/legacy/vector/index.ts +0 -59
  83. package/legacy/vscode/extension.ts +0 -387
  84. package/scripts/compiled-crud-verify.ts +0 -30
  85. package/scripts/dogfood.ts +0 -297
  86. package/scripts/publish-crates.sh +0 -95
  87. package/scripts/release-check.js +0 -224
  88. package/scripts/run-tests.ts +0 -178
  89. package/scripts/setup-libclang.ps1 +0 -209
  90. package/scripts/update-changelog.js +0 -214
  91. package/scripts/validate-npm-publish.js +0 -228
  92. package/web/README.md +0 -27
  93. 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
- });