@plures/pluresdb 1.4.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.
Files changed (96) hide show
  1. package/LICENSE +72 -0
  2. package/README.md +450 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/better-sqlite3-shared.d.ts +12 -0
  5. package/dist/better-sqlite3-shared.d.ts.map +1 -0
  6. package/dist/better-sqlite3-shared.js +143 -0
  7. package/dist/better-sqlite3-shared.js.map +1 -0
  8. package/dist/better-sqlite3.d.ts +4 -0
  9. package/dist/better-sqlite3.d.ts.map +1 -0
  10. package/dist/better-sqlite3.js +8 -0
  11. package/dist/better-sqlite3.js.map +1 -0
  12. package/dist/cli.d.ts +7 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +258 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/node-index.d.ts +148 -0
  17. package/dist/node-index.d.ts.map +1 -0
  18. package/dist/node-index.js +665 -0
  19. package/dist/node-index.js.map +1 -0
  20. package/dist/node-wrapper.d.ts +44 -0
  21. package/dist/node-wrapper.d.ts.map +1 -0
  22. package/dist/node-wrapper.js +296 -0
  23. package/dist/node-wrapper.js.map +1 -0
  24. package/dist/types/index.d.ts +28 -0
  25. package/dist/types/index.d.ts.map +1 -0
  26. package/dist/types/index.js +3 -0
  27. package/dist/types/index.js.map +1 -0
  28. package/dist/types/node-types.d.ts +71 -0
  29. package/dist/types/node-types.d.ts.map +1 -0
  30. package/dist/types/node-types.js +6 -0
  31. package/dist/types/node-types.js.map +1 -0
  32. package/dist/vscode/extension.d.ts +81 -0
  33. package/dist/vscode/extension.d.ts.map +1 -0
  34. package/dist/vscode/extension.js +309 -0
  35. package/dist/vscode/extension.js.map +1 -0
  36. package/examples/basic-usage.d.ts +2 -0
  37. package/examples/basic-usage.d.ts.map +1 -0
  38. package/examples/basic-usage.js +26 -0
  39. package/examples/basic-usage.js.map +1 -0
  40. package/examples/basic-usage.ts +29 -0
  41. package/examples/vscode-extension-example/README.md +95 -0
  42. package/examples/vscode-extension-example/package.json +49 -0
  43. package/examples/vscode-extension-example/src/extension.ts +172 -0
  44. package/examples/vscode-extension-example/tsconfig.json +12 -0
  45. package/examples/vscode-extension-integration.d.ts +31 -0
  46. package/examples/vscode-extension-integration.d.ts.map +1 -0
  47. package/examples/vscode-extension-integration.js +319 -0
  48. package/examples/vscode-extension-integration.js.map +1 -0
  49. package/examples/vscode-extension-integration.ts +41 -0
  50. package/legacy/benchmarks/memory-benchmarks.ts +350 -0
  51. package/legacy/benchmarks/run-benchmarks.ts +315 -0
  52. package/legacy/better-sqlite3-shared.ts +157 -0
  53. package/legacy/better-sqlite3.ts +4 -0
  54. package/legacy/cli.ts +241 -0
  55. package/legacy/config.ts +50 -0
  56. package/legacy/core/crdt.ts +107 -0
  57. package/legacy/core/database.ts +529 -0
  58. package/legacy/healthcheck.ts +162 -0
  59. package/legacy/http/api-server.ts +438 -0
  60. package/legacy/index.ts +28 -0
  61. package/legacy/logic/rules.ts +46 -0
  62. package/legacy/main.rs +3 -0
  63. package/legacy/main.ts +197 -0
  64. package/legacy/network/websocket-server.ts +115 -0
  65. package/legacy/node-index.ts +823 -0
  66. package/legacy/node-wrapper.ts +329 -0
  67. package/legacy/sqlite-compat.ts +633 -0
  68. package/legacy/sqlite3-compat.ts +55 -0
  69. package/legacy/storage/kv-storage.ts +73 -0
  70. package/legacy/tests/core.test.ts +305 -0
  71. package/legacy/tests/fixtures/performance-data.json +71 -0
  72. package/legacy/tests/fixtures/test-data.json +129 -0
  73. package/legacy/tests/integration/api-server.test.ts +334 -0
  74. package/legacy/tests/integration/mesh-network.test.ts +303 -0
  75. package/legacy/tests/logic.test.ts +34 -0
  76. package/legacy/tests/performance/load.test.ts +290 -0
  77. package/legacy/tests/security/input-validation.test.ts +286 -0
  78. package/legacy/tests/unit/core.test.ts +226 -0
  79. package/legacy/tests/unit/subscriptions.test.ts +135 -0
  80. package/legacy/tests/unit/vector-search.test.ts +173 -0
  81. package/legacy/tests/vscode_extension_test.ts +281 -0
  82. package/legacy/types/index.ts +32 -0
  83. package/legacy/types/node-types.ts +80 -0
  84. package/legacy/util/debug.ts +14 -0
  85. package/legacy/vector/index.ts +59 -0
  86. package/legacy/vscode/extension.ts +387 -0
  87. package/package.json +127 -0
  88. package/scripts/compiled-crud-verify.ts +30 -0
  89. package/scripts/dogfood.ts +297 -0
  90. package/scripts/postinstall.js +156 -0
  91. package/scripts/release-check.js +190 -0
  92. package/scripts/run-tests.ts +178 -0
  93. package/scripts/setup-libclang.ps1 +209 -0
  94. package/scripts/update-changelog.js +214 -0
  95. package/web/README.md +27 -0
  96. package/web/svelte/package.json +31 -0
@@ -0,0 +1,226 @@
1
+ // @ts-nocheck
2
+ import {
3
+ assertEquals,
4
+ assertExists,
5
+ assertRejects,
6
+ } from "jsr:@std/assert@1.0.14";
7
+ import { GunDB } from "../../core/database.ts";
8
+ import { mergeNodes } from "../../core/crdt.ts";
9
+ import type { NodeRecord } from "../../types/index.ts";
10
+
11
+ Deno.test("Core Database - Basic CRUD Operations", async () => {
12
+ const db = new GunDB();
13
+ try {
14
+ const kvPath = await Deno.makeTempFile({
15
+ prefix: "kv_",
16
+ suffix: ".sqlite",
17
+ });
18
+ await db.ready(kvPath);
19
+
20
+ // Test put and get
21
+ const user = { name: "Alice", age: 30, email: "alice@example.com" };
22
+ await db.put("user:alice", user as unknown as Record<string, unknown>);
23
+ const got = await db.get<typeof user>("user:alice");
24
+
25
+ assertEquals(got?.name, "Alice");
26
+ assertEquals(got?.age, 30);
27
+ assertEquals(got?.email, "alice@example.com");
28
+
29
+ // Test update
30
+ await db.put("user:alice", { ...user, age: 31 });
31
+ const updated = await db.get<typeof user>("user:alice");
32
+ assertEquals(updated?.age, 31);
33
+
34
+ // Test delete
35
+ await db.delete("user:alice");
36
+ const deleted = await db.get<typeof user>("user:alice");
37
+ assertEquals(deleted, null);
38
+ } finally {
39
+ await db.close();
40
+ }
41
+ });
42
+
43
+ Deno.test("Core Database - Vector Clock Increments", async () => {
44
+ const db = new GunDB();
45
+ try {
46
+ const kvPath = await Deno.makeTempFile({
47
+ prefix: "kv_",
48
+ suffix: ".sqlite",
49
+ });
50
+ await db.ready(kvPath);
51
+
52
+ const id = "vc:test";
53
+ await db.put(id, { value: 1 });
54
+ await db.put(id, { value: 2 });
55
+ await db.put(id, { value: 3 });
56
+
57
+ // Inspect underlying record
58
+ const { KvStorage } = await import("../../storage/kv-storage.ts");
59
+ const kv = new KvStorage();
60
+ await kv.open(kvPath);
61
+ const node = await kv.getNode(id);
62
+ await kv.close();
63
+
64
+ assertExists(node);
65
+ const clockValues = Object.values(node.vectorClock);
66
+ assertEquals(clockValues.length, 1);
67
+ assertEquals(clockValues[0], 3);
68
+ } finally {
69
+ await db.close();
70
+ }
71
+ });
72
+
73
+ Deno.test("Core Database - Type System", async () => {
74
+ const db = new GunDB();
75
+ try {
76
+ const kvPath = await Deno.makeTempFile({
77
+ prefix: "kv_",
78
+ suffix: ".sqlite",
79
+ });
80
+ await db.ready(kvPath);
81
+
82
+ // Test setType and instancesOf
83
+ await db.put("person:1", { name: "Alice" });
84
+ await db.setType("person:1", "Person");
85
+
86
+ await db.put("company:1", { name: "Acme Corp" });
87
+ await db.setType("company:1", "Company");
88
+
89
+ const people = await db.instancesOf("Person");
90
+ assertEquals(people.length, 1);
91
+ assertEquals(people[0].id, "person:1");
92
+
93
+ const companies = await db.instancesOf("Company");
94
+ assertEquals(companies.length, 1);
95
+ assertEquals(companies[0].id, "company:1");
96
+ } finally {
97
+ await db.close();
98
+ }
99
+ });
100
+
101
+ Deno.test("Core Database - Vector Search", async () => {
102
+ const db = new GunDB();
103
+ try {
104
+ const kvPath = await Deno.makeTempFile({
105
+ prefix: "kv_",
106
+ suffix: ".sqlite",
107
+ });
108
+ await db.ready(kvPath);
109
+
110
+ // Add documents with text content
111
+ await db.put("doc:1", {
112
+ text: "Machine learning and artificial intelligence",
113
+ });
114
+ await db.put("doc:2", { text: "Cooking recipes and food preparation" });
115
+ await db.put("doc:3", { text: "Deep learning neural networks" });
116
+
117
+ // Test vector search
118
+ const results = await db.vectorSearch("machine learning", 2);
119
+ assertExists(results);
120
+ assertEquals(results.length, 2);
121
+
122
+ // Should find the most relevant documents
123
+ const docIds = results.map((r) => r.id);
124
+ assertExists(docIds.includes("doc:1"));
125
+ assertExists(docIds.includes("doc:3"));
126
+ } finally {
127
+ await db.close();
128
+ }
129
+ });
130
+
131
+ Deno.test("CRDT Merge - Equal Timestamps", () => {
132
+ const timestamp = Date.now();
133
+ const local: NodeRecord = {
134
+ id: "test:1",
135
+ data: { a: 1, shared: 1, nested: { x: 1, y: 1 } },
136
+ vector: [0.1, 0.2],
137
+ type: "TestType",
138
+ timestamp,
139
+ vectorClock: { peerA: 2 },
140
+ };
141
+
142
+ const incoming: NodeRecord = {
143
+ id: "test:1",
144
+ data: { b: 2, shared: 2, nested: { y: 2, z: 3 } },
145
+ timestamp,
146
+ vectorClock: { peerB: 3 },
147
+ } as unknown as NodeRecord;
148
+
149
+ const merged = mergeNodes(local, incoming);
150
+
151
+ assertEquals(merged.id, "test:1");
152
+ assertEquals(merged.timestamp, timestamp);
153
+ assertEquals(merged.data, {
154
+ a: 1,
155
+ shared: 2,
156
+ b: 2,
157
+ nested: { x: 1, y: 2, z: 3 },
158
+ });
159
+ assertEquals(merged.type, "TestType");
160
+ assertEquals(merged.vector, [0.1, 0.2]);
161
+ assertEquals(merged.vectorClock.peerA, 2);
162
+ assertEquals(merged.vectorClock.peerB, 3);
163
+ });
164
+
165
+ Deno.test("CRDT Merge - LWW on Different Timestamps", () => {
166
+ const t1 = 1000;
167
+ const t2 = 2000;
168
+
169
+ const older: NodeRecord = {
170
+ id: "test:2",
171
+ data: { a: 1, b: 1 },
172
+ timestamp: t1,
173
+ vectorClock: { p1: 1 },
174
+ } as unknown as NodeRecord;
175
+
176
+ const newer: NodeRecord = {
177
+ id: "test:2",
178
+ data: { a: 999, b: 2, c: 3 },
179
+ timestamp: t2,
180
+ vectorClock: { p2: 1 },
181
+ } as unknown as NodeRecord;
182
+
183
+ const merged = mergeNodes(older, newer);
184
+
185
+ assertEquals(merged.data, { a: 999, b: 2, c: 3 });
186
+ assertEquals(merged.timestamp, t2);
187
+ });
188
+
189
+ Deno.test("Core Database - Error Handling", async () => {
190
+ const db = new GunDB();
191
+
192
+ // Test operations before ready
193
+ await assertRejects(
194
+ () => db.put("test", { value: 1 }),
195
+ Error,
196
+ "Database not ready",
197
+ );
198
+
199
+ await assertRejects(() => db.get("test"), Error, "Database not ready");
200
+
201
+ await assertRejects(() => db.delete("test"), Error, "Database not ready");
202
+ });
203
+
204
+ Deno.test("Core Database - Persistence Across Restarts", async () => {
205
+ const kvPath = await Deno.makeTempFile({
206
+ prefix: "kv_",
207
+ suffix: ".sqlite",
208
+ });
209
+ const id = "persist:test";
210
+
211
+ // First session
212
+ const db1 = new GunDB();
213
+ await db1.ready(kvPath);
214
+ await db1.put(id, { value: 123, text: "persistent data" });
215
+ await db1.close();
216
+
217
+ // Second session
218
+ const db2 = new GunDB();
219
+ await db2.ready(kvPath);
220
+ const got = await db2.get<{ value: number; text: string }>(id);
221
+ await db2.close();
222
+
223
+ assertExists(got);
224
+ assertEquals(got.value, 123);
225
+ assertEquals(got.text, "persistent data");
226
+ });
@@ -0,0 +1,135 @@
1
+ // @ts-nocheck
2
+ import { assertEquals, assertThrows } from "jsr:@std/assert@1.0.14";
3
+ import { GunDB } from "../../core/database.ts";
4
+
5
+ Deno.test("Subscriptions - Basic Update Events", async () => {
6
+ const db = new GunDB();
7
+ try {
8
+ const kvPath = await Deno.makeTempFile({
9
+ prefix: "kv_",
10
+ suffix: ".sqlite",
11
+ });
12
+ await db.ready(kvPath);
13
+
14
+ const id = "user:test";
15
+ let updateCount = 0;
16
+ let lastData: any = null;
17
+
18
+ const unsubscribe = db.on(id, (node) => {
19
+ updateCount++;
20
+ lastData = node?.data;
21
+ });
22
+
23
+ // Test initial put
24
+ await db.put(id, { name: "Alice", age: 30 });
25
+ await new Promise((resolve) => setTimeout(resolve, 100));
26
+ assertEquals(updateCount, 1);
27
+ assertEquals(lastData?.name, "Alice");
28
+
29
+ // Test update
30
+ await db.put(id, { name: "Alice", age: 31 });
31
+ await new Promise((resolve) => setTimeout(resolve, 100));
32
+ assertEquals(updateCount, 2);
33
+ assertEquals(lastData?.age, 31);
34
+
35
+ // Test unsubscribe
36
+ unsubscribe();
37
+ await db.put(id, { name: "Alice", age: 32 });
38
+ await new Promise((resolve) => setTimeout(resolve, 100));
39
+ assertEquals(updateCount, 2); // Should not increment
40
+ } finally {
41
+ await db.close();
42
+ }
43
+ });
44
+
45
+ Deno.test("Subscriptions - Delete Events", async () => {
46
+ const db = new GunDB();
47
+ try {
48
+ const kvPath = await Deno.makeTempFile({
49
+ prefix: "kv_",
50
+ suffix: ".sqlite",
51
+ });
52
+ await db.ready(kvPath);
53
+
54
+ const id = "user:delete";
55
+ let deleteReceived = false;
56
+
57
+ const unsubscribe = db.on(id, (node) => {
58
+ if (node === null) {
59
+ deleteReceived = true;
60
+ }
61
+ });
62
+
63
+ await db.put(id, { name: "Bob" });
64
+ await db.delete(id);
65
+ await new Promise((resolve) => setTimeout(resolve, 100));
66
+
67
+ assertEquals(deleteReceived, true);
68
+ unsubscribe();
69
+ } finally {
70
+ await db.close();
71
+ }
72
+ });
73
+
74
+ Deno.test("Subscriptions - Multiple Subscribers", async () => {
75
+ const db = new GunDB();
76
+ try {
77
+ const kvPath = await Deno.makeTempFile({
78
+ prefix: "kv_",
79
+ suffix: ".sqlite",
80
+ });
81
+ await db.ready(kvPath);
82
+
83
+ const id = "user:multi";
84
+ let subscriber1Count = 0;
85
+ let subscriber2Count = 0;
86
+
87
+ const unsubscribe1 = db.on(id, () => subscriber1Count++);
88
+ const unsubscribe2 = db.on(id, () => subscriber2Count++);
89
+
90
+ await db.put(id, { name: "Charlie" });
91
+ await new Promise((resolve) => setTimeout(resolve, 100));
92
+
93
+ assertEquals(subscriber1Count, 1);
94
+ assertEquals(subscriber2Count, 1);
95
+
96
+ unsubscribe1();
97
+ unsubscribe2();
98
+ } finally {
99
+ await db.close();
100
+ }
101
+ });
102
+
103
+ Deno.test("Subscriptions - Error Handling", () => {
104
+ const db = new GunDB();
105
+
106
+ // Test subscription before ready
107
+ assertThrows(() => db.on("test", () => {}), Error, "Database not ready");
108
+ });
109
+
110
+ Deno.test("Subscriptions - Off Method", async () => {
111
+ const db = new GunDB();
112
+ try {
113
+ const kvPath = await Deno.makeTempFile({
114
+ prefix: "kv_",
115
+ suffix: ".sqlite",
116
+ });
117
+ await db.ready(kvPath);
118
+
119
+ const id = "user:off";
120
+ let called = false;
121
+
122
+ const callback = () => {
123
+ called = true;
124
+ };
125
+ db.on(id, callback);
126
+ db.off(id, callback);
127
+
128
+ await db.put(id, { name: "Dave" });
129
+ await new Promise((resolve) => setTimeout(resolve, 100));
130
+
131
+ assertEquals(called, false);
132
+ } finally {
133
+ await db.close();
134
+ }
135
+ });
@@ -0,0 +1,173 @@
1
+ // @ts-nocheck
2
+ import { assertEquals, assertExists } from "jsr:@std/assert@1.0.14";
3
+ import { GunDB } from "../../core/database.ts";
4
+
5
+ Deno.test("Vector Search - Basic Functionality", async () => {
6
+ const db = new GunDB();
7
+ try {
8
+ const kvPath = await Deno.makeTempFile({
9
+ prefix: "kv_",
10
+ suffix: ".sqlite",
11
+ });
12
+ await db.ready(kvPath);
13
+
14
+ // Add documents with different content
15
+ await db.put("doc:1", {
16
+ text: "Machine learning and artificial intelligence algorithms",
17
+ content: "Deep learning neural networks for pattern recognition",
18
+ });
19
+ await db.put("doc:2", {
20
+ text: "Cooking recipes and food preparation techniques",
21
+ content: "Italian pasta recipes and cooking methods",
22
+ });
23
+ await db.put("doc:3", {
24
+ text: "Web development and JavaScript programming",
25
+ content: "React and TypeScript for modern web applications",
26
+ });
27
+
28
+ // Test search with text field
29
+ const results1 = await db.vectorSearch("machine learning", 2);
30
+ assertExists(results1);
31
+ assertEquals(results1.length, 2);
32
+
33
+ // Test search with content field
34
+ const results2 = await db.vectorSearch("neural networks", 1);
35
+ assertExists(results2);
36
+ assertEquals(results2.length, 1);
37
+ assertEquals(results2[0].id, "doc:1");
38
+
39
+ // Test search with different query
40
+ const results3 = await db.vectorSearch("cooking food", 1);
41
+ assertExists(results3);
42
+ assertEquals(results3.length, 1);
43
+ assertEquals(results3[0].id, "doc:2");
44
+ } finally {
45
+ await db.close();
46
+ }
47
+ });
48
+
49
+ Deno.test("Vector Search - Similarity Scoring", async () => {
50
+ const db = new GunDB();
51
+ try {
52
+ const kvPath = await Deno.makeTempFile({
53
+ prefix: "kv_",
54
+ suffix: ".sqlite",
55
+ });
56
+ await db.ready(kvPath);
57
+
58
+ await db.put("doc:1", { text: "Machine learning algorithms" });
59
+ await db.put("doc:2", { text: "Machine learning and AI" });
60
+ await db.put("doc:3", { text: "Cooking recipes" });
61
+
62
+ const results = await db.vectorSearch("machine learning", 3);
63
+ assertExists(results);
64
+ assertEquals(results.length, 3);
65
+
66
+ // Results should be ordered by similarity (highest first)
67
+ assertExists(results[0].similarity);
68
+ assertExists(results[1].similarity);
69
+ assertExists(results[2].similarity);
70
+
71
+ // First result should have highest similarity
72
+ assertEquals(results[0].similarity >= results[1].similarity, true);
73
+ assertEquals(results[1].similarity >= results[2].similarity, true);
74
+ } finally {
75
+ await db.close();
76
+ }
77
+ });
78
+
79
+ Deno.test("Vector Search - Limit Parameter", async () => {
80
+ const db = new GunDB();
81
+ try {
82
+ const kvPath = await Deno.makeTempFile({
83
+ prefix: "kv_",
84
+ suffix: ".sqlite",
85
+ });
86
+ await db.ready(kvPath);
87
+
88
+ // Add multiple documents
89
+ for (let i = 1; i <= 10; i++) {
90
+ await db.put(`doc:${i}`, {
91
+ text: `Document ${i} about machine learning and AI`,
92
+ });
93
+ }
94
+
95
+ // Test different limits
96
+ const results1 = await db.vectorSearch("machine learning", 3);
97
+ assertEquals(results1.length, 3);
98
+
99
+ const results2 = await db.vectorSearch("machine learning", 5);
100
+ assertEquals(results2.length, 5);
101
+
102
+ const results3 = await db.vectorSearch("machine learning", 1);
103
+ assertEquals(results3.length, 1);
104
+ } finally {
105
+ await db.close();
106
+ }
107
+ });
108
+
109
+ Deno.test("Vector Search - Empty Results", async () => {
110
+ const db = new GunDB();
111
+ try {
112
+ const kvPath = await Deno.makeTempFile({
113
+ prefix: "kv_",
114
+ suffix: ".sqlite",
115
+ });
116
+ await db.ready(kvPath);
117
+
118
+ // Search in empty database
119
+ const results = await db.vectorSearch("anything", 5);
120
+ assertEquals(results.length, 0);
121
+ } finally {
122
+ await db.close();
123
+ }
124
+ });
125
+
126
+ Deno.test("Vector Search - Custom Vector Input", async () => {
127
+ const db = new GunDB();
128
+ try {
129
+ const kvPath = await Deno.makeTempFile({
130
+ prefix: "kv_",
131
+ suffix: ".sqlite",
132
+ });
133
+ await db.ready(kvPath);
134
+
135
+ // Add document with custom vector
136
+ const customVector = [0.1, 0.2, 0.3, 0.4, 0.5];
137
+ await db.put("doc:custom", {
138
+ text: "Custom vector document",
139
+ vector: customVector,
140
+ });
141
+
142
+ // Search with custom vector
143
+ const results = await db.vectorSearch(customVector, 1);
144
+ assertExists(results);
145
+ assertEquals(results.length, 1);
146
+ assertEquals(results[0].id, "doc:custom");
147
+ } finally {
148
+ await db.close();
149
+ }
150
+ });
151
+
152
+ Deno.test("Vector Search - No Text Content", async () => {
153
+ const db = new GunDB();
154
+ try {
155
+ const kvPath = await Deno.makeTempFile({
156
+ prefix: "kv_",
157
+ suffix: ".sqlite",
158
+ });
159
+ await db.ready(kvPath);
160
+
161
+ // Add document without text or content
162
+ await db.put("doc:no-text", {
163
+ name: "Document without text",
164
+ value: 123,
165
+ });
166
+
167
+ // Search should return empty results
168
+ const results = await db.vectorSearch("anything", 5);
169
+ assertEquals(results.length, 0);
170
+ } finally {
171
+ await db.close();
172
+ }
173
+ });