pluresdb 1.0.1 → 1.3.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.
Files changed (79) hide show
  1. package/README.md +100 -5
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/better-sqlite3-shared.d.ts +12 -0
  4. package/dist/better-sqlite3-shared.d.ts.map +1 -0
  5. package/dist/better-sqlite3-shared.js +143 -0
  6. package/dist/better-sqlite3-shared.js.map +1 -0
  7. package/dist/better-sqlite3.d.ts +4 -0
  8. package/dist/better-sqlite3.d.ts.map +1 -0
  9. package/dist/better-sqlite3.js +8 -0
  10. package/dist/better-sqlite3.js.map +1 -0
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +21 -16
  13. package/dist/cli.js.map +1 -1
  14. package/dist/node-index.d.ts +98 -2
  15. package/dist/node-index.d.ts.map +1 -1
  16. package/dist/node-index.js +312 -6
  17. package/dist/node-index.js.map +1 -1
  18. package/dist/node-wrapper.d.ts.map +1 -1
  19. package/dist/node-wrapper.js +5 -3
  20. package/dist/node-wrapper.js.map +1 -1
  21. package/dist/types/index.d.ts.map +1 -1
  22. package/dist/types/index.js.map +1 -1
  23. package/dist/types/node-types.d.ts +12 -0
  24. package/dist/types/node-types.d.ts.map +1 -1
  25. package/dist/types/node-types.js.map +1 -1
  26. package/dist/vscode/extension.d.ts.map +1 -1
  27. package/dist/vscode/extension.js +4 -4
  28. package/dist/vscode/extension.js.map +1 -1
  29. package/examples/basic-usage.d.ts +1 -1
  30. package/examples/vscode-extension-example/src/extension.ts +15 -6
  31. package/examples/vscode-extension-integration.d.ts +24 -17
  32. package/examples/vscode-extension-integration.js +140 -106
  33. package/examples/vscode-extension-integration.ts +1 -1
  34. package/{src → legacy}/benchmarks/memory-benchmarks.ts +85 -51
  35. package/{src → legacy}/benchmarks/run-benchmarks.ts +32 -10
  36. package/legacy/better-sqlite3-shared.ts +157 -0
  37. package/legacy/better-sqlite3.ts +4 -0
  38. package/{src → legacy}/cli.ts +14 -4
  39. package/{src → legacy}/config.ts +2 -1
  40. package/{src → legacy}/core/crdt.ts +4 -1
  41. package/{src → legacy}/core/database.ts +57 -22
  42. package/{src → legacy}/healthcheck.ts +11 -5
  43. package/{src → legacy}/http/api-server.ts +125 -21
  44. package/{src → legacy}/index.ts +2 -2
  45. package/{src → legacy}/logic/rules.ts +3 -1
  46. package/{src → legacy}/main.ts +11 -4
  47. package/legacy/node-index.ts +823 -0
  48. package/{src → legacy}/node-wrapper.ts +18 -9
  49. package/{src → legacy}/sqlite-compat.ts +63 -16
  50. package/{src → legacy}/sqlite3-compat.ts +2 -2
  51. package/{src → legacy}/storage/kv-storage.ts +3 -1
  52. package/{src → legacy}/tests/core.test.ts +37 -13
  53. package/{src → legacy}/tests/fixtures/test-data.json +6 -1
  54. package/{src → legacy}/tests/integration/api-server.test.ts +110 -8
  55. package/{src → legacy}/tests/integration/mesh-network.test.ts +8 -2
  56. package/{src → legacy}/tests/logic.test.ts +6 -2
  57. package/{src → legacy}/tests/performance/load.test.ts +4 -2
  58. package/{src → legacy}/tests/security/input-validation.test.ts +5 -1
  59. package/{src → legacy}/tests/unit/core.test.ts +13 -3
  60. package/{src → legacy}/tests/unit/subscriptions.test.ts +1 -1
  61. package/{src → legacy}/tests/vscode_extension_test.ts +39 -11
  62. package/{src → legacy}/types/node-types.ts +14 -0
  63. package/{src → legacy}/vscode/extension.ts +37 -14
  64. package/package.json +19 -9
  65. package/scripts/compiled-crud-verify.ts +3 -1
  66. package/scripts/dogfood.ts +55 -16
  67. package/scripts/postinstall.js +4 -3
  68. package/scripts/release-check.js +190 -0
  69. package/scripts/run-tests.ts +5 -2
  70. package/scripts/update-changelog.js +214 -0
  71. package/web/svelte/package.json +5 -5
  72. package/src/node-index.ts +0 -385
  73. /package/{src → legacy}/main.rs +0 -0
  74. /package/{src → legacy}/network/websocket-server.ts +0 -0
  75. /package/{src → legacy}/tests/fixtures/performance-data.json +0 -0
  76. /package/{src → legacy}/tests/unit/vector-search.test.ts +0 -0
  77. /package/{src → legacy}/types/index.ts +0 -0
  78. /package/{src → legacy}/util/debug.ts +0 -0
  79. /package/{src → legacy}/vector/index.ts +0 -0
@@ -3,7 +3,7 @@
3
3
  * This module provides a Node.js-compatible API for VSCode extensions
4
4
  */
5
5
 
6
- import { spawn, ChildProcess } from "node:child_process";
6
+ import { ChildProcess, spawn } from "node:child_process";
7
7
  import { EventEmitter } from "node:events";
8
8
  import * as path from "node:path";
9
9
  import * as fs from "node:fs";
@@ -66,17 +66,21 @@ export class PluresNode extends EventEmitter {
66
66
  if (fs.existsSync(denoPath) || this.isCommandAvailable(denoPath)) {
67
67
  return denoPath;
68
68
  }
69
- } catch (error) {
69
+ } catch {
70
70
  // Continue to next path
71
71
  }
72
72
  }
73
73
 
74
- throw new Error("Deno not found. Please install Deno from https://deno.land/");
74
+ throw new Error(
75
+ "Deno not found. Please install Deno from https://deno.land/",
76
+ );
75
77
  }
76
78
 
77
79
  private isCommandAvailable(command: string): boolean {
78
80
  try {
79
- require("child_process").execSync(`"${command}" --version`, { stdio: "ignore" });
81
+ require("child_process").execSync(`"${command}" --version`, {
82
+ stdio: "ignore",
83
+ });
80
84
  return true;
81
85
  } catch {
82
86
  return false;
@@ -169,7 +173,7 @@ export class PluresNode extends EventEmitter {
169
173
  if (response.ok) {
170
174
  return;
171
175
  }
172
- } catch (error) {
176
+ } catch {
173
177
  // Server not ready yet
174
178
  }
175
179
 
@@ -243,7 +247,9 @@ export class PluresNode extends EventEmitter {
243
247
  }
244
248
 
245
249
  async get(key: string): Promise<any> {
246
- const response = await fetch(`${this.apiUrl}/api/data/${encodeURIComponent(key)}`);
250
+ const response = await fetch(
251
+ `${this.apiUrl}/api/data/${encodeURIComponent(key)}`,
252
+ );
247
253
 
248
254
  if (!response.ok) {
249
255
  if (response.status === 404) {
@@ -256,9 +262,12 @@ export class PluresNode extends EventEmitter {
256
262
  }
257
263
 
258
264
  async delete(key: string): Promise<void> {
259
- const response = await fetch(`${this.apiUrl}/api/data/${encodeURIComponent(key)}`, {
260
- method: "DELETE",
261
- });
265
+ const response = await fetch(
266
+ `${this.apiUrl}/api/data/${encodeURIComponent(key)}`,
267
+ {
268
+ method: "DELETE",
269
+ },
270
+ );
262
271
 
263
272
  if (!response.ok) {
264
273
  throw new Error(`Delete failed: ${response.statusText}`);
@@ -96,7 +96,10 @@ export class Database {
96
96
  }
97
97
  }
98
98
 
99
- async run(sql: string, params: any[] = []): Promise<{ lastID: number; changes: number }> {
99
+ async run(
100
+ sql: string,
101
+ params: any[] = [],
102
+ ): Promise<{ lastID: number; changes: number }> {
100
103
  if (!this.isOpen) {
101
104
  throw new Error("Database is not open");
102
105
  }
@@ -137,7 +140,11 @@ export class Database {
137
140
  }
138
141
  }
139
142
 
140
- async each(sql: string, params: any[] = [], callback: (row: any) => void): Promise<number> {
143
+ async each(
144
+ sql: string,
145
+ params: any[] = [],
146
+ callback: (row: any) => void,
147
+ ): Promise<number> {
141
148
  if (!this.isOpen) {
142
149
  throw new Error("Database is not open");
143
150
  }
@@ -190,7 +197,9 @@ export class Database {
190
197
  return statements.map((statement) => ({ sql: statement }));
191
198
  }
192
199
 
193
- private async executeStatement(statement: { sql: string; params?: any[] }): Promise<any> {
200
+ private async executeStatement(
201
+ statement: { sql: string; params?: any[] },
202
+ ): Promise<any> {
194
203
  const sql = statement.sql.toLowerCase().trim();
195
204
 
196
205
  if (sql.startsWith("create table")) {
@@ -203,7 +212,10 @@ export class Database {
203
212
  return await this.update(statement.sql, statement.params || []);
204
213
  } else if (sql.startsWith("delete")) {
205
214
  return await this.delete(statement.sql, statement.params || []);
206
- } else if (sql.startsWith("begin") || sql.startsWith("commit") || sql.startsWith("rollback")) {
215
+ } else if (
216
+ sql.startsWith("begin") || sql.startsWith("commit") ||
217
+ sql.startsWith("rollback")
218
+ ) {
207
219
  // Transaction commands - handled by transaction method
208
220
  return { changes: 0 };
209
221
  } else {
@@ -223,7 +235,9 @@ export class Database {
223
235
 
224
236
  private async createTable(sql: string): Promise<void> {
225
237
  // Extract table name and columns from CREATE TABLE statement
226
- const tableMatch = sql.match(/CREATE TABLE\s+(?:IF NOT EXISTS\s+)?(\w+)\s*\(([^)]+)\)/i);
238
+ const tableMatch = sql.match(
239
+ /CREATE TABLE\s+(?:IF NOT EXISTS\s+)?(\w+)\s*\(([^)]+)\)/i,
240
+ );
227
241
  if (!tableMatch) {
228
242
  throw new Error(`Invalid CREATE TABLE statement: ${sql}`);
229
243
  }
@@ -265,7 +279,10 @@ export class Database {
265
279
  }
266
280
  }
267
281
 
268
- private async insert(sql: string, params: any[]): Promise<{ lastID: number; changes: number }> {
282
+ private async insert(
283
+ sql: string,
284
+ params: any[],
285
+ ): Promise<{ lastID: number; changes: number }> {
269
286
  const insertMatch = sql.match(
270
287
  /INSERT\s+(?:INTO\s+)?(\w+)\s*\(([^)]+)\)\s*VALUES\s*\(([^)]+)\)/i,
271
288
  );
@@ -295,7 +312,9 @@ export class Database {
295
312
  });
296
313
 
297
314
  // Generate unique ID
298
- const id = `${tableName}:${Date.now()}:${Math.random().toString(36).substr(2, 9)}`;
315
+ const id = `${tableName}:${Date.now()}:${
316
+ Math.random().toString(36).substr(2, 9)
317
+ }`;
299
318
  row.id = id;
300
319
  row.created_at = new Date().toISOString();
301
320
 
@@ -309,8 +328,13 @@ export class Database {
309
328
  return { lastID: 0, changes: 1 };
310
329
  }
311
330
 
312
- private async update(sql: string, params: any[]): Promise<{ changes: number }> {
313
- const updateMatch = sql.match(/UPDATE\s+(\w+)\s+SET\s+([^WHERE]+)(?:\s+WHERE\s+(.+))?/i);
331
+ private async update(
332
+ sql: string,
333
+ params: any[],
334
+ ): Promise<{ changes: number }> {
335
+ const updateMatch = sql.match(
336
+ /UPDATE\s+(\w+)\s+SET\s+([^WHERE]+)(?:\s+WHERE\s+(.+))?/i,
337
+ );
314
338
  if (!updateMatch) {
315
339
  throw new Error(`Invalid UPDATE statement: ${sql}`);
316
340
  }
@@ -342,13 +366,21 @@ export class Database {
342
366
  if (whereClause) {
343
367
  // Simple WHERE clause evaluation (basic implementation)
344
368
  if (this.evaluateWhereClause(row, whereClause, params)) {
345
- const updatedRow = { ...row, ...updates, updated_at: new Date().toISOString() };
369
+ const updatedRow = {
370
+ ...row,
371
+ ...updates,
372
+ updated_at: new Date().toISOString(),
373
+ };
346
374
  await this.plures.put(getRowId(row), updatedRow);
347
375
  changes++;
348
376
  }
349
377
  } else {
350
378
  // Update all rows
351
- const updatedRow = { ...row, ...updates, updated_at: new Date().toISOString() };
379
+ const updatedRow = {
380
+ ...row,
381
+ ...updates,
382
+ updated_at: new Date().toISOString(),
383
+ };
352
384
  await this.plures.put(getRowId(row), updatedRow);
353
385
  changes++;
354
386
  }
@@ -361,7 +393,10 @@ export class Database {
361
393
  return { changes };
362
394
  }
363
395
 
364
- private async delete(sql: string, params: any[]): Promise<{ changes: number }> {
396
+ private async delete(
397
+ sql: string,
398
+ params: any[],
399
+ ): Promise<{ changes: number }> {
365
400
  const deleteMatch = sql.match(/DELETE\s+FROM\s+(\w+)(?:\s+WHERE\s+(.+))?/i);
366
401
  if (!deleteMatch) {
367
402
  throw new Error(`Invalid DELETE statement: ${sql}`);
@@ -415,7 +450,9 @@ export class Database {
415
450
 
416
451
  // Apply WHERE clause
417
452
  if (whereClause) {
418
- results = results.filter((row) => this.evaluateWhereClause(row, whereClause, params));
453
+ results = results.filter((row) =>
454
+ this.evaluateWhereClause(row, whereClause, params)
455
+ );
419
456
  }
420
457
 
421
458
  // Apply ORDER BY
@@ -449,7 +486,11 @@ export class Database {
449
486
  return results;
450
487
  }
451
488
 
452
- private evaluateWhereClause(row: RowRecord, whereClause: string, params: any[]): boolean {
489
+ private evaluateWhereClause(
490
+ row: RowRecord,
491
+ whereClause: string,
492
+ params: any[],
493
+ ): boolean {
453
494
  // Simple WHERE clause evaluation
454
495
  // This is a basic implementation - in production, you'd want a proper SQL parser
455
496
 
@@ -504,7 +545,10 @@ function compareValues(a: unknown, b: unknown, desc = false): number {
504
545
  if (typeof value === "string") {
505
546
  return value;
506
547
  }
507
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
548
+ if (
549
+ typeof value === "number" || typeof value === "boolean" ||
550
+ typeof value === "bigint"
551
+ ) {
508
552
  return value.toString();
509
553
  }
510
554
  try {
@@ -545,7 +589,10 @@ export class PreparedStatement {
545
589
  return await this.db.all(this.sql, params);
546
590
  }
547
591
 
548
- async each(params: any[] = [], callback: (row: any) => void): Promise<number> {
592
+ async each(
593
+ params: any[] = [],
594
+ callback: (row: any) => void,
595
+ ): Promise<number> {
549
596
  return await this.db.each(this.sql, params, callback);
550
597
  }
551
598
 
@@ -27,7 +27,7 @@ export class Database extends PluresDBDatabase {
27
27
  }
28
28
  }
29
29
 
30
- configure(option: string, value: any): void {
30
+ configure(_option: string, _value: any): void {
31
31
  // No-op for compatibility
32
32
  }
33
33
 
@@ -35,7 +35,7 @@ export class Database extends PluresDBDatabase {
35
35
  // No-op for compatibility
36
36
  }
37
37
 
38
- loadExtension(path: string, callback?: (err: Error | null) => void): void {
38
+ loadExtension(_path: string, callback?: (err: Error | null) => void): void {
39
39
  if (callback) {
40
40
  callback(new Error("Extensions not supported in PluresDB"), null);
41
41
  }
@@ -56,7 +56,9 @@ export class KvStorage {
56
56
 
57
57
  async *listNodeHistory(id: string): AsyncIterable<NodeRecord> {
58
58
  const kv = this.ensureKv();
59
- for await (const entry of kv.list<NodeRecord>({ prefix: ["history", id] })) {
59
+ for await (
60
+ const entry of kv.list<NodeRecord>({ prefix: ["history", id] })
61
+ ) {
60
62
  if (entry.value) yield entry.value;
61
63
  }
62
64
  }
@@ -24,7 +24,11 @@ Deno.test("put and get returns stored data", async () => {
24
24
  });
25
25
 
26
26
  Deno.test(
27
- { name: "subscription receives updates", sanitizeOps: false, sanitizeResources: false },
27
+ {
28
+ name: "subscription receives updates",
29
+ sanitizeOps: false,
30
+ sanitizeResources: false,
31
+ },
28
32
  async () => {
29
33
  const db = new GunDB();
30
34
  try {
@@ -36,13 +40,15 @@ Deno.test(
36
40
  const updated = new Promise((resolve) =>
37
41
  db.on(
38
42
  "user:bob",
39
- (n) => n && (n.data as Record<string, unknown>).age === 42 && resolve(true),
40
- ),
43
+ (n) =>
44
+ n && (n.data as Record<string, unknown>).age === 42 &&
45
+ resolve(true),
46
+ )
41
47
  );
42
48
  await db.put("user:bob", { name: "Bob", age: 41 });
43
49
  await db.put("user:bob", { name: "Bob", age: 42 });
44
50
  const timeout = new Promise((_, rej) =>
45
- setTimeout(() => rej(new Error("timeout: subscription")), 2000),
51
+ setTimeout(() => rej(new Error("timeout: subscription")), 2000)
46
52
  );
47
53
  await Promise.race([updated, timeout]);
48
54
  } finally {
@@ -72,7 +78,11 @@ Deno.test("vector search returns relevant notes", async () => {
72
78
  });
73
79
 
74
80
  Deno.test(
75
- { name: "delete emits subscription with null", sanitizeOps: false, sanitizeResources: false },
81
+ {
82
+ name: "delete emits subscription with null",
83
+ sanitizeOps: false,
84
+ sanitizeResources: false,
85
+ },
76
86
  async () => {
77
87
  const db = new GunDB();
78
88
  try {
@@ -83,11 +93,11 @@ Deno.test(
83
93
  await db.ready(kvPath);
84
94
  await db.put("user:carol", { name: "Carol" });
85
95
  const deleted = new Promise((resolve) =>
86
- db.on("user:carol", (n) => n === null && resolve(true)),
96
+ db.on("user:carol", (n) => n === null && resolve(true))
87
97
  );
88
98
  await db.delete("user:carol");
89
99
  const timeout = new Promise((_, rej) =>
90
- setTimeout(() => rej(new Error("timeout: delete")), 2000),
100
+ setTimeout(() => rej(new Error("timeout: delete")), 2000)
91
101
  );
92
102
  await Promise.race([deleted, timeout]);
93
103
  } finally {
@@ -121,7 +131,7 @@ Deno.test(
121
131
  await dbA.put("mesh:one", { text: "hello from A" });
122
132
 
123
133
  const receivedSnapshot = new Promise((resolve) =>
124
- dbB.on("mesh:one", (n) => n && resolve(true)),
134
+ dbB.on("mesh:one", (n) => n && resolve(true))
125
135
  );
126
136
  dbB.connect(serverUrl);
127
137
  await receivedSnapshot;
@@ -129,8 +139,10 @@ Deno.test(
129
139
  const receivedOnA = new Promise((resolve) =>
130
140
  dbA.on(
131
141
  "mesh:fromB",
132
- (n) => n && (n.data as Record<string, unknown>).who === "B" && resolve(true),
133
- ),
142
+ (n) =>
143
+ n && (n.data as Record<string, unknown>).who === "B" &&
144
+ resolve(true),
145
+ )
134
146
  );
135
147
  await dbB.put("mesh:fromB", { who: "B", text: "hi A" });
136
148
  await receivedOnA;
@@ -204,7 +216,12 @@ Deno.test("CRDT merge: equal timestamps deterministic merge", () => {
204
216
  const merged = mergeNodes(local, incoming);
205
217
  assertEquals(merged.id, "n1");
206
218
  assertEquals(merged.timestamp, t);
207
- assertEquals(merged.data, { a: 1, shared: 2, b: 2, nested: { x: 1, y: 2, z: 3 } });
219
+ assertEquals(merged.data, {
220
+ a: 1,
221
+ shared: 2,
222
+ b: 2,
223
+ nested: { x: 1, y: 2, z: 3 },
224
+ });
208
225
  assertEquals(merged.type, "TypeA");
209
226
  assertEquals(merged.vector, [0.1, 0.2]);
210
227
  assertEquals(merged.vectorClock.peerA, 2);
@@ -237,7 +254,11 @@ Deno.test("CRDT merge: LWW on differing timestamps", () => {
237
254
  });
238
255
 
239
256
  Deno.test(
240
- { name: "off stops receiving events", sanitizeOps: false, sanitizeResources: false },
257
+ {
258
+ name: "off stops receiving events",
259
+ sanitizeOps: false,
260
+ sanitizeResources: false,
261
+ },
241
262
  async () => {
242
263
  const db = new GunDB();
243
264
  try {
@@ -265,7 +286,10 @@ Deno.test(
265
286
  Deno.test("type system helpers: setType + instancesOf", async () => {
266
287
  const db = new GunDB();
267
288
  try {
268
- const kvPath = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
289
+ const kvPath = await Deno.makeTempFile({
290
+ prefix: "kv_",
291
+ suffix: ".sqlite",
292
+ });
269
293
  await db.ready(kvPath);
270
294
  await db.put("t:1", { name: "Alice" });
271
295
  await db.setType("t:1", "Person");
@@ -33,7 +33,12 @@
33
33
  "profile": {
34
34
  "bio": "Product manager with a focus on developer tools",
35
35
  "location": "Seattle, WA",
36
- "interests": ["Product", "Strategy", "Developer Experience", "Leadership"]
36
+ "interests": [
37
+ "Product",
38
+ "Strategy",
39
+ "Developer Experience",
40
+ "Leadership"
41
+ ]
37
42
  }
38
43
  }
39
44
  ],
@@ -1,7 +1,7 @@
1
1
  // @ts-nocheck
2
2
  import { assertEquals, assertExists } from "jsr:@std/assert@1.0.14";
3
3
  import { GunDB } from "../../core/database.ts";
4
- import { startApiServer, type ApiServerHandle } from "../../http/api-server.ts";
4
+ import { type ApiServerHandle, startApiServer } from "../../http/api-server.ts";
5
5
 
6
6
  function randomPort(): number {
7
7
  return 18000 + Math.floor(Math.random() * 10000);
@@ -88,8 +88,8 @@ Deno.test("API Server - Vector Search Endpoint", async () => {
88
88
  }),
89
89
  });
90
90
 
91
- assertEquals(searchResponse.status, 200);
92
- const results = await searchResponse.json();
91
+ assertEquals(searchResponse.status, 200);
92
+ const results = await searchResponse.json();
93
93
  assertExists(results);
94
94
  assertEquals(Array.isArray(results), true);
95
95
  } finally {
@@ -119,7 +119,10 @@ Deno.test("API Server - WebSocket Connection", async () => {
119
119
  const ws = new WebSocket(wsUrl);
120
120
 
121
121
  const connectionPromise = new Promise((resolve, reject) => {
122
- const timer = setTimeout(() => reject(new Error("Connection timeout")), 5000);
122
+ const timer = setTimeout(
123
+ () => reject(new Error("Connection timeout")),
124
+ 5000,
125
+ );
123
126
  ws.onopen = () => {
124
127
  clearTimeout(timer);
125
128
  resolve(true);
@@ -221,10 +224,109 @@ Deno.test("API Server - CORS Headers", async () => {
221
224
  },
222
225
  });
223
226
 
224
- assertEquals(optionsResponse.status, 200);
225
- assertExists(optionsResponse.headers.get("Access-Control-Allow-Origin"));
226
- assertExists(optionsResponse.headers.get("Access-Control-Allow-Methods"));
227
- await optionsResponse.body?.cancel();
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);
228
330
  } finally {
229
331
  api?.close();
230
332
  await db.close();
@@ -84,7 +84,10 @@ meshTest("Mesh Network - Basic Connection and Sync", async () => {
84
84
  });
85
85
 
86
86
  dbB.connect(serverUrl);
87
- await withTimeout(receivedData as Promise<unknown>, "Timed out waiting for initial mesh sync");
87
+ await withTimeout(
88
+ receivedData as Promise<unknown>,
89
+ "Timed out waiting for initial mesh sync",
90
+ );
88
91
 
89
92
  // Verify data was received
90
93
  const syncedData = await dbB.get("mesh:test");
@@ -280,7 +283,10 @@ meshTest("Mesh Network - Connection Error Handling", async () => {
280
283
  const db = new GunDB();
281
284
 
282
285
  try {
283
- const kvPath = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
286
+ const kvPath = await Deno.makeTempFile({
287
+ prefix: "kv_",
288
+ suffix: ".sqlite",
289
+ });
284
290
  await db.ready(kvPath);
285
291
 
286
292
  // Try to connect to non-existent server
@@ -4,14 +4,18 @@ import type { Rule } from "../logic/rules.ts";
4
4
  Deno.test("rule engine classification: Person.age >= 18 -> adult = true", async () => {
5
5
  const db = new GunDB();
6
6
  try {
7
- const kvPath = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
7
+ const kvPath = await Deno.makeTempFile({
8
+ prefix: "kv_",
9
+ suffix: ".sqlite",
10
+ });
8
11
  await db.ready(kvPath);
9
12
 
10
13
  const rule: Rule = {
11
14
  name: "adultClassifier",
12
15
  whenType: "Person",
13
16
  predicate: (node) =>
14
- typeof (node.data as any).age === "number" && (node.data as any).age >= 18,
17
+ typeof (node.data as any).age === "number" &&
18
+ (node.data as any).age >= 18,
15
19
  action: async (ctx, node) => {
16
20
  const data = { ...(node.data as Record<string, unknown>), adult: true };
17
21
  await ctx.db.put(node.id, data);
@@ -118,8 +118,10 @@ Deno.test("Performance - Vector Search Operations", async () => {
118
118
  const count = 500;
119
119
  for (let i = 0; i < count; i++) {
120
120
  await db.put(`doc:${i}`, {
121
- text: `Document ${i} about machine learning and artificial intelligence`,
122
- content: `This is document number ${i} containing information about AI and ML algorithms`,
121
+ text:
122
+ `Document ${i} about machine learning and artificial intelligence`,
123
+ content:
124
+ `This is document number ${i} containing information about AI and ML algorithms`,
123
125
  });
124
126
  }
125
127
 
@@ -1,5 +1,9 @@
1
1
  // @ts-nocheck
2
- import { assertEquals, assertExists, assertRejects } from "jsr:@std/assert@1.0.14";
2
+ import {
3
+ assertEquals,
4
+ assertExists,
5
+ assertRejects,
6
+ } from "jsr:@std/assert@1.0.14";
3
7
  import { GunDB } from "../../core/database.ts";
4
8
 
5
9
  Deno.test("Security - SQL Injection Prevention", async () => {
@@ -1,5 +1,9 @@
1
1
  // @ts-nocheck
2
- import { assertEquals, assertExists, assertRejects } from "jsr:@std/assert@1.0.14";
2
+ import {
3
+ assertEquals,
4
+ assertExists,
5
+ assertRejects,
6
+ } from "jsr:@std/assert@1.0.14";
3
7
  import { GunDB } from "../../core/database.ts";
4
8
  import { mergeNodes } from "../../core/crdt.ts";
5
9
  import type { NodeRecord } from "../../types/index.ts";
@@ -104,7 +108,9 @@ Deno.test("Core Database - Vector Search", async () => {
104
108
  await db.ready(kvPath);
105
109
 
106
110
  // Add documents with text content
107
- await db.put("doc:1", { text: "Machine learning and artificial intelligence" });
111
+ await db.put("doc:1", {
112
+ text: "Machine learning and artificial intelligence",
113
+ });
108
114
  await db.put("doc:2", { text: "Cooking recipes and food preparation" });
109
115
  await db.put("doc:3", { text: "Deep learning neural networks" });
110
116
 
@@ -184,7 +190,11 @@ Deno.test("Core Database - Error Handling", async () => {
184
190
  const db = new GunDB();
185
191
 
186
192
  // Test operations before ready
187
- await assertRejects(() => db.put("test", { value: 1 }), Error, "Database not ready");
193
+ await assertRejects(
194
+ () => db.put("test", { value: 1 }),
195
+ Error,
196
+ "Database not ready",
197
+ );
188
198
 
189
199
  await assertRejects(() => db.get("test"), Error, "Database not ready");
190
200
 
@@ -100,7 +100,7 @@ Deno.test("Subscriptions - Multiple Subscribers", async () => {
100
100
  }
101
101
  });
102
102
 
103
- Deno.test("Subscriptions - Error Handling", async () => {
103
+ Deno.test("Subscriptions - Error Handling", () => {
104
104
  const db = new GunDB();
105
105
 
106
106
  // Test subscription before ready