pluresdb 1.0.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.
- package/LICENSE +72 -0
- package/README.md +322 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +253 -0
- package/dist/cli.js.map +1 -0
- package/dist/node-index.d.ts +52 -0
- package/dist/node-index.d.ts.map +1 -0
- package/dist/node-index.js +359 -0
- package/dist/node-index.js.map +1 -0
- package/dist/node-wrapper.d.ts +44 -0
- package/dist/node-wrapper.d.ts.map +1 -0
- package/dist/node-wrapper.js +294 -0
- package/dist/node-wrapper.js.map +1 -0
- package/dist/types/index.d.ts +28 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/node-types.d.ts +59 -0
- package/dist/types/node-types.d.ts.map +1 -0
- package/dist/types/node-types.js +6 -0
- package/dist/types/node-types.js.map +1 -0
- package/dist/vscode/extension.d.ts +81 -0
- package/dist/vscode/extension.d.ts.map +1 -0
- package/dist/vscode/extension.js +309 -0
- package/dist/vscode/extension.js.map +1 -0
- package/examples/basic-usage.d.ts +2 -0
- package/examples/basic-usage.d.ts.map +1 -0
- package/examples/basic-usage.js +26 -0
- package/examples/basic-usage.js.map +1 -0
- package/examples/basic-usage.ts +29 -0
- package/examples/vscode-extension-example/README.md +95 -0
- package/examples/vscode-extension-example/package.json +49 -0
- package/examples/vscode-extension-example/src/extension.ts +163 -0
- package/examples/vscode-extension-example/tsconfig.json +12 -0
- package/examples/vscode-extension-integration.d.ts +24 -0
- package/examples/vscode-extension-integration.d.ts.map +1 -0
- package/examples/vscode-extension-integration.js +285 -0
- package/examples/vscode-extension-integration.js.map +1 -0
- package/examples/vscode-extension-integration.ts +41 -0
- package/package.json +115 -0
- package/scripts/compiled-crud-verify.ts +28 -0
- package/scripts/dogfood.ts +258 -0
- package/scripts/postinstall.js +155 -0
- package/scripts/run-tests.ts +175 -0
- package/scripts/setup-libclang.ps1 +209 -0
- package/src/benchmarks/memory-benchmarks.ts +316 -0
- package/src/benchmarks/run-benchmarks.ts +293 -0
- package/src/cli.ts +231 -0
- package/src/config.ts +49 -0
- package/src/core/crdt.ts +104 -0
- package/src/core/database.ts +494 -0
- package/src/healthcheck.ts +156 -0
- package/src/http/api-server.ts +334 -0
- package/src/index.ts +28 -0
- package/src/logic/rules.ts +44 -0
- package/src/main.rs +3 -0
- package/src/main.ts +190 -0
- package/src/network/websocket-server.ts +115 -0
- package/src/node-index.ts +385 -0
- package/src/node-wrapper.ts +320 -0
- package/src/sqlite-compat.ts +586 -0
- package/src/sqlite3-compat.ts +55 -0
- package/src/storage/kv-storage.ts +71 -0
- package/src/tests/core.test.ts +281 -0
- package/src/tests/fixtures/performance-data.json +71 -0
- package/src/tests/fixtures/test-data.json +124 -0
- package/src/tests/integration/api-server.test.ts +232 -0
- package/src/tests/integration/mesh-network.test.ts +297 -0
- package/src/tests/logic.test.ts +30 -0
- package/src/tests/performance/load.test.ts +288 -0
- package/src/tests/security/input-validation.test.ts +282 -0
- package/src/tests/unit/core.test.ts +216 -0
- package/src/tests/unit/subscriptions.test.ts +135 -0
- package/src/tests/unit/vector-search.test.ts +173 -0
- package/src/tests/vscode_extension_test.ts +253 -0
- package/src/types/index.ts +32 -0
- package/src/types/node-types.ts +66 -0
- package/src/util/debug.ts +14 -0
- package/src/vector/index.ts +59 -0
- package/src/vscode/extension.ts +364 -0
- package/web/README.md +27 -0
- package/web/svelte/package.json +31 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
#!/usr/bin/env -S deno run -A --unstable-kv
|
|
2
|
+
|
|
3
|
+
import { GunDB } from "../src/core/database.ts";
|
|
4
|
+
import { startApiServer } from "../src/http/api-server.ts";
|
|
5
|
+
|
|
6
|
+
declare const Deno: any;
|
|
7
|
+
|
|
8
|
+
interface StepResult {
|
|
9
|
+
name: string;
|
|
10
|
+
ok: boolean;
|
|
11
|
+
details?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function main() {
|
|
15
|
+
const results: StepResult[] = [];
|
|
16
|
+
const kvDir = await Deno.makeTempDir({ prefix: "pluresdb-dogfood-" });
|
|
17
|
+
const kvPath = `${kvDir}/kv`;
|
|
18
|
+
const wsPort = 4600 + Math.floor(Math.random() * 5000);
|
|
19
|
+
const apiPort = wsPort + 1;
|
|
20
|
+
const apiUrl = `http://localhost:${apiPort}`;
|
|
21
|
+
|
|
22
|
+
const db = new GunDB();
|
|
23
|
+
await db.ready(kvPath);
|
|
24
|
+
db.serve({ port: wsPort });
|
|
25
|
+
const api = startApiServer({ port: apiPort, db });
|
|
26
|
+
|
|
27
|
+
const cleanupTasks: Array<() => Promise<void> | void> = [
|
|
28
|
+
async () => {
|
|
29
|
+
try {
|
|
30
|
+
api.close();
|
|
31
|
+
} catch (_) {
|
|
32
|
+
/* ignore */
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
async () => {
|
|
36
|
+
try {
|
|
37
|
+
await db.close();
|
|
38
|
+
} catch (_) {
|
|
39
|
+
/* ignore */
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
async () => {
|
|
43
|
+
try {
|
|
44
|
+
await Deno.remove(kvDir, { recursive: true });
|
|
45
|
+
} catch (_) {
|
|
46
|
+
/* ignore */
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
const finalize = async () => {
|
|
52
|
+
for (const task of cleanupTasks) {
|
|
53
|
+
await Promise.resolve(task());
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const assert = (cond: boolean, message: string) => {
|
|
58
|
+
if (!cond) {
|
|
59
|
+
throw new Error(message);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const record = (name: string, ok: boolean, details?: string) => {
|
|
64
|
+
const entry: StepResult = { name, ok, details };
|
|
65
|
+
results.push(entry);
|
|
66
|
+
const icon = ok ? "โ
" : "โ";
|
|
67
|
+
console.log(`${icon} ${name}${details ? ` โ ${details}` : ""}`);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
console.log("๐ Starting PluresDB dogfooding run");
|
|
72
|
+
console.log(`๐๏ธ KV path: ${kvPath}`);
|
|
73
|
+
console.log(`๐ Mesh port: ${wsPort}`);
|
|
74
|
+
console.log(`๐ API port: ${apiPort}`);
|
|
75
|
+
|
|
76
|
+
await waitFor(
|
|
77
|
+
async () => {
|
|
78
|
+
try {
|
|
79
|
+
const res = await fetch(`${apiUrl}/api/list`);
|
|
80
|
+
return res.ok;
|
|
81
|
+
} catch (_) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{ timeoutMs: 10_000, intervalMs: 250 },
|
|
86
|
+
);
|
|
87
|
+
record("Server readiness", true);
|
|
88
|
+
|
|
89
|
+
const nodeId = "dogfood:api";
|
|
90
|
+
const initialPayload = {
|
|
91
|
+
type: "DogfoodTest",
|
|
92
|
+
text: "Hello from the dogfooding script",
|
|
93
|
+
vector: Array.from({ length: 4 }, (_, i) => i + 1),
|
|
94
|
+
};
|
|
95
|
+
const putRes = await fetch(`${apiUrl}/api/put`, {
|
|
96
|
+
method: "POST",
|
|
97
|
+
headers: { "content-type": "application/json" },
|
|
98
|
+
body: JSON.stringify({ id: nodeId, data: initialPayload }),
|
|
99
|
+
});
|
|
100
|
+
assert(putRes.ok, `API put failed (${putRes.status})`);
|
|
101
|
+
record("API put", true);
|
|
102
|
+
|
|
103
|
+
const getRes = await fetch(`${apiUrl}/api/get?id=${encodeURIComponent(nodeId)}`);
|
|
104
|
+
assert(getRes.ok, "API get failed");
|
|
105
|
+
const getJson = await getRes.json();
|
|
106
|
+
assert(getJson.text === initialPayload.text, "Unexpected API get payload");
|
|
107
|
+
record("API get", true);
|
|
108
|
+
|
|
109
|
+
const listRes = await fetch(`${apiUrl}/api/list`);
|
|
110
|
+
assert(listRes.ok, "API list failed");
|
|
111
|
+
const listJson = await listRes.json();
|
|
112
|
+
assert(
|
|
113
|
+
Array.isArray(listJson) && listJson.some((n: any) => n.id === nodeId),
|
|
114
|
+
"Node missing from API list",
|
|
115
|
+
);
|
|
116
|
+
record("API list", true);
|
|
117
|
+
|
|
118
|
+
const searchRes = await fetch(
|
|
119
|
+
`${apiUrl}/api/search?q=${encodeURIComponent("dogfood script test")}&k=5`,
|
|
120
|
+
);
|
|
121
|
+
assert(searchRes.ok, "API search failed");
|
|
122
|
+
const searchJson = await searchRes.json();
|
|
123
|
+
assert(Array.isArray(searchJson) && searchJson.length > 0, "Vector search returned no results");
|
|
124
|
+
record("API vector search", true);
|
|
125
|
+
|
|
126
|
+
const updatePayload = {
|
|
127
|
+
type: "DogfoodTest",
|
|
128
|
+
text: "Hello from the updated dogfooding script",
|
|
129
|
+
};
|
|
130
|
+
const putUpdate = await fetch(`${apiUrl}/api/put`, {
|
|
131
|
+
method: "POST",
|
|
132
|
+
headers: { "content-type": "application/json" },
|
|
133
|
+
body: JSON.stringify({ id: nodeId, data: updatePayload }),
|
|
134
|
+
});
|
|
135
|
+
assert(putUpdate.ok, "API put update failed");
|
|
136
|
+
record("API update", true);
|
|
137
|
+
|
|
138
|
+
const historyRes = await fetch(`${apiUrl}/api/history?id=${encodeURIComponent(nodeId)}`);
|
|
139
|
+
assert(historyRes.ok, "API history failed");
|
|
140
|
+
const historyJson = await historyRes.json();
|
|
141
|
+
assert(Array.isArray(historyJson) && historyJson.length >= 2, "API history missing versions");
|
|
142
|
+
record("API history", true, `${historyJson.length} versions`);
|
|
143
|
+
|
|
144
|
+
const restoreTimestamp =
|
|
145
|
+
historyJson.at(-1)?.timestamp ?? historyJson[historyJson.length - 1]?.timestamp;
|
|
146
|
+
assert(typeof restoreTimestamp === "number", "Failed to locate restore timestamp");
|
|
147
|
+
const restoreRes = await fetch(
|
|
148
|
+
`${apiUrl}/api/restore?id=${encodeURIComponent(nodeId)}×tamp=${restoreTimestamp}`,
|
|
149
|
+
);
|
|
150
|
+
assert(restoreRes.ok, "API restore failed");
|
|
151
|
+
record("API restore", true);
|
|
152
|
+
|
|
153
|
+
const restored = await (
|
|
154
|
+
await fetch(`${apiUrl}/api/get?id=${encodeURIComponent(nodeId)}`)
|
|
155
|
+
).json();
|
|
156
|
+
assert(restored.text === initialPayload.text, "Restore did not revert payload");
|
|
157
|
+
record("API post-restore verification", true);
|
|
158
|
+
|
|
159
|
+
const instancesRes = await fetch(
|
|
160
|
+
`${apiUrl}/api/instances?type=${encodeURIComponent("DogfoodTest")}`,
|
|
161
|
+
);
|
|
162
|
+
assert(instancesRes.ok, "API instances failed");
|
|
163
|
+
const instancesJson = await instancesRes.json();
|
|
164
|
+
assert(
|
|
165
|
+
Array.isArray(instancesJson) && instancesJson.some((n: any) => n.id === nodeId),
|
|
166
|
+
"Instances endpoint missing node",
|
|
167
|
+
);
|
|
168
|
+
record("API type instances", true);
|
|
169
|
+
|
|
170
|
+
const webRes = await fetch(`${apiUrl}/`);
|
|
171
|
+
assert(webRes.ok, "Web UI endpoint failed");
|
|
172
|
+
const webHtml = await webRes.text();
|
|
173
|
+
record("Web UI fetch", true, `${webHtml.length} chars`);
|
|
174
|
+
|
|
175
|
+
const cliId = "dogfood:cli";
|
|
176
|
+
const cliPut = await runCli([
|
|
177
|
+
"put",
|
|
178
|
+
cliId,
|
|
179
|
+
JSON.stringify({ type: "DogfoodTest", text: "CLI write" }),
|
|
180
|
+
"--kv",
|
|
181
|
+
kvPath,
|
|
182
|
+
]);
|
|
183
|
+
assert(cliPut.code === 0, `CLI put failed: ${cliPut.stderr}`);
|
|
184
|
+
record("CLI put", true);
|
|
185
|
+
|
|
186
|
+
const cliGet = await runCli(["get", cliId, "--kv", kvPath]);
|
|
187
|
+
assert(cliGet.code === 0, `CLI get failed: ${cliGet.stderr}`);
|
|
188
|
+
const cliGetJson = JSON.parse(cliGet.stdout.trim() || "null");
|
|
189
|
+
assert(cliGetJson?.text === "CLI write", "CLI get returned wrong payload");
|
|
190
|
+
record("CLI get", true);
|
|
191
|
+
|
|
192
|
+
const cliList = await runCli(["list", "--kv", kvPath]);
|
|
193
|
+
assert(cliList.code === 0, `CLI list failed: ${cliList.stderr}`);
|
|
194
|
+
const cliListJson = JSON.parse(cliList.stdout.trim() || "[]");
|
|
195
|
+
assert(Array.isArray(cliListJson) && cliListJson.length >= 2, "CLI list missing entries");
|
|
196
|
+
record("CLI list", true);
|
|
197
|
+
|
|
198
|
+
const cliSearch = await runCli(["vsearch", "dogfooding", "5", "--kv", kvPath]);
|
|
199
|
+
assert(cliSearch.code === 0, `CLI vsearch failed: ${cliSearch.stderr}`);
|
|
200
|
+
const cliSearchJson = JSON.parse(cliSearch.stdout.trim() || "[]");
|
|
201
|
+
assert(
|
|
202
|
+
Array.isArray(cliSearchJson) && cliSearchJson.length > 0,
|
|
203
|
+
"CLI vsearch returned no results",
|
|
204
|
+
);
|
|
205
|
+
record("CLI vector search", true);
|
|
206
|
+
|
|
207
|
+
console.log("\n๐ Dogfooding run succeeded!");
|
|
208
|
+
} catch (error) {
|
|
209
|
+
record("Dogfooding run", false, error instanceof Error ? error.message : String(error));
|
|
210
|
+
await finalize();
|
|
211
|
+
console.log("\nโ Dogfooding run failed");
|
|
212
|
+
console.log(error);
|
|
213
|
+
Deno.exit(1);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
await finalize();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async function runCli(args: string[]) {
|
|
220
|
+
const command = new Deno.Command("deno", {
|
|
221
|
+
args: ["run", "-A", "--unstable-kv", "--no-lock", "src/main.ts", ...args],
|
|
222
|
+
stdout: "piped",
|
|
223
|
+
stderr: "piped",
|
|
224
|
+
});
|
|
225
|
+
const { code, stdout, stderr } = await command.output();
|
|
226
|
+
return {
|
|
227
|
+
code,
|
|
228
|
+
stdout: new TextDecoder().decode(stdout),
|
|
229
|
+
stderr: new TextDecoder().decode(stderr),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async function waitFor(
|
|
234
|
+
fn: () => Promise<boolean>,
|
|
235
|
+
opts: { timeoutMs: number; intervalMs: number },
|
|
236
|
+
) {
|
|
237
|
+
const deadline = Date.now() + opts.timeoutMs;
|
|
238
|
+
while (Date.now() < deadline) {
|
|
239
|
+
if (await fn()) return;
|
|
240
|
+
await sleep(opts.intervalMs);
|
|
241
|
+
}
|
|
242
|
+
throw new Error("Timed out waiting for condition");
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function sleep(ms: number): Promise<void>;
|
|
246
|
+
function sleep<T>(ms: number, value: T): Promise<T>;
|
|
247
|
+
function sleep(ms: number, value?: unknown) {
|
|
248
|
+
return new Promise((resolve) => {
|
|
249
|
+
const timer = setTimeout(() => {
|
|
250
|
+
clearTimeout(timer);
|
|
251
|
+
resolve(value);
|
|
252
|
+
}, ms);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if ((import.meta as any).main) {
|
|
257
|
+
await main();
|
|
258
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-install script for PluresDB npm package
|
|
3
|
+
* This script ensures Deno is available and sets up the environment
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { spawn, exec } = require("child_process");
|
|
7
|
+
const fs = require("fs");
|
|
8
|
+
const path = require("path");
|
|
9
|
+
const os = require("os");
|
|
10
|
+
|
|
11
|
+
const DENO_VERSION = "1.40.0";
|
|
12
|
+
|
|
13
|
+
function log(message) {
|
|
14
|
+
console.log(`[pluresdb] ${message}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function logError(message) {
|
|
18
|
+
console.error(`[pluresdb] ERROR: ${message}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function isDenoInstalled() {
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
exec("deno --version", (error) => {
|
|
24
|
+
resolve(!error);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function installDeno() {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const platform = os.platform();
|
|
32
|
+
const arch = os.arch();
|
|
33
|
+
|
|
34
|
+
log("Installing Deno...");
|
|
35
|
+
|
|
36
|
+
let installCommand;
|
|
37
|
+
|
|
38
|
+
if (platform === "win32") {
|
|
39
|
+
// Windows - use PowerShell
|
|
40
|
+
installCommand = `powershell -c "iwr https://deno.land/install.ps1 -useb | iex"`;
|
|
41
|
+
} else if (platform === "darwin") {
|
|
42
|
+
// macOS - use Homebrew or curl
|
|
43
|
+
installCommand = "curl -fsSL https://deno.land/install.sh | sh";
|
|
44
|
+
} else {
|
|
45
|
+
// Linux - use curl
|
|
46
|
+
installCommand = "curl -fsSL https://deno.land/install.sh | sh";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
exec(installCommand, (error, stdout, stderr) => {
|
|
50
|
+
if (error) {
|
|
51
|
+
logError(`Failed to install Deno: ${error.message}`);
|
|
52
|
+
logError("Please install Deno manually from https://deno.land/");
|
|
53
|
+
reject(error);
|
|
54
|
+
} else {
|
|
55
|
+
log("Deno installed successfully");
|
|
56
|
+
resolve();
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function createStartScript() {
|
|
63
|
+
const scriptContent = `#!/bin/bash
|
|
64
|
+
# PluresDB start script
|
|
65
|
+
export DENO_INSTALL="$HOME/.deno"
|
|
66
|
+
export PATH="$DENO_INSTALL/bin:$PATH"
|
|
67
|
+
|
|
68
|
+
# Start PluresDB
|
|
69
|
+
deno run -A "${path.join(__dirname, "../src/main.ts")}" serve "$@"
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
const scriptPath = path.join(__dirname, "../bin/pluresdb.sh");
|
|
73
|
+
const scriptDir = path.dirname(scriptPath);
|
|
74
|
+
|
|
75
|
+
if (!fs.existsSync(scriptDir)) {
|
|
76
|
+
fs.mkdirSync(scriptDir, { recursive: true });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fs.writeFileSync(scriptPath, scriptContent);
|
|
80
|
+
fs.chmodSync(scriptPath, "755");
|
|
81
|
+
|
|
82
|
+
log("Created start script");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function createWindowsStartScript() {
|
|
86
|
+
const scriptContent = `@echo off
|
|
87
|
+
REM PluresDB start script for Windows
|
|
88
|
+
set DENO_INSTALL=%USERPROFILE%\\.deno
|
|
89
|
+
set PATH=%DENO_INSTALL%\\bin;%PATH%
|
|
90
|
+
|
|
91
|
+
REM Start PluresDB
|
|
92
|
+
deno run -A "${path.join(__dirname, "../src/main.ts")}" serve %*
|
|
93
|
+
`;
|
|
94
|
+
|
|
95
|
+
const scriptPath = path.join(__dirname, "../bin/pluresdb.bat");
|
|
96
|
+
const scriptDir = path.dirname(scriptPath);
|
|
97
|
+
|
|
98
|
+
if (!fs.existsSync(scriptDir)) {
|
|
99
|
+
fs.mkdirSync(scriptDir, { recursive: true });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
fs.writeFileSync(scriptPath, scriptContent);
|
|
103
|
+
|
|
104
|
+
log("Created Windows start script");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function main() {
|
|
108
|
+
try {
|
|
109
|
+
log("Setting up PluresDB...");
|
|
110
|
+
|
|
111
|
+
// Check if Deno is installed
|
|
112
|
+
const denoInstalled = await isDenoInstalled();
|
|
113
|
+
|
|
114
|
+
if (!denoInstalled) {
|
|
115
|
+
log("Deno not found, attempting to install...");
|
|
116
|
+
try {
|
|
117
|
+
await installDeno();
|
|
118
|
+
} catch (error) {
|
|
119
|
+
logError("Failed to install Deno automatically");
|
|
120
|
+
logError("Please install Deno manually:");
|
|
121
|
+
logError(" Windows: iwr https://deno.land/install.ps1 -useb | iex");
|
|
122
|
+
logError(" macOS/Linux: curl -fsSL https://deno.land/install.sh | sh");
|
|
123
|
+
logError(" Or visit: https://deno.land/");
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
log("Deno is already installed");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Create start scripts
|
|
131
|
+
createStartScript();
|
|
132
|
+
if (os.platform() === "win32") {
|
|
133
|
+
createWindowsStartScript();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Create data directory
|
|
137
|
+
const dataDir = path.join(os.homedir(), ".pluresdb");
|
|
138
|
+
if (!fs.existsSync(dataDir)) {
|
|
139
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
140
|
+
log(`Created data directory: ${dataDir}`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
log("Setup complete!");
|
|
144
|
+
log("Usage:");
|
|
145
|
+
log(" npx pluresdb serve");
|
|
146
|
+
log(" or");
|
|
147
|
+
log(" node node_modules/pluresdb/dist/cli.js serve");
|
|
148
|
+
} catch (error) {
|
|
149
|
+
logError(`Setup failed: ${error.message}`);
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Run the setup
|
|
155
|
+
main();
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env -S deno run -A --unstable-kv
|
|
2
|
+
|
|
3
|
+
// @ts-nocheck
|
|
4
|
+
|
|
5
|
+
interface TestSuite {
|
|
6
|
+
name: string;
|
|
7
|
+
command: string;
|
|
8
|
+
description: string;
|
|
9
|
+
timeout?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface TestResults {
|
|
13
|
+
suite: string;
|
|
14
|
+
passed: boolean;
|
|
15
|
+
duration: number;
|
|
16
|
+
output: string;
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class TestRunner {
|
|
21
|
+
private results: TestResults[] = [];
|
|
22
|
+
|
|
23
|
+
async runTestSuite(suite: TestSuite): Promise<TestResults> {
|
|
24
|
+
console.log(`\n๐งช Running ${suite.name}...`);
|
|
25
|
+
console.log(` ${suite.description}`);
|
|
26
|
+
|
|
27
|
+
const startTime = performance.now();
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const command = new Deno.Command("deno", {
|
|
31
|
+
args: suite.command.split(" "),
|
|
32
|
+
stdout: "piped",
|
|
33
|
+
stderr: "piped",
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const { code, stdout, stderr } = await command.output();
|
|
37
|
+
const duration = performance.now() - startTime;
|
|
38
|
+
|
|
39
|
+
const output = new TextDecoder().decode(stdout);
|
|
40
|
+
const error = new TextDecoder().decode(stderr);
|
|
41
|
+
|
|
42
|
+
const result: TestResults = {
|
|
43
|
+
suite: suite.name,
|
|
44
|
+
passed: code === 0,
|
|
45
|
+
duration,
|
|
46
|
+
output,
|
|
47
|
+
error: code !== 0 ? error : undefined,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
this.results.push(result);
|
|
51
|
+
|
|
52
|
+
if (result.passed) {
|
|
53
|
+
console.log(` โ
Passed (${duration.toFixed(2)}ms)`);
|
|
54
|
+
} else {
|
|
55
|
+
console.log(` โ Failed (${duration.toFixed(2)}ms)`);
|
|
56
|
+
console.log(` Error: ${result.error}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return result;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
const duration = performance.now() - startTime;
|
|
62
|
+
|
|
63
|
+
const result: TestResults = {
|
|
64
|
+
suite: suite.name,
|
|
65
|
+
passed: false,
|
|
66
|
+
duration,
|
|
67
|
+
output: "",
|
|
68
|
+
error: error.message,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
this.results.push(result);
|
|
72
|
+
|
|
73
|
+
console.log(` โ Failed (${duration.toFixed(2)}ms)`);
|
|
74
|
+
console.log(` Error: ${error.message}`);
|
|
75
|
+
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
printSummary() {
|
|
81
|
+
console.log("\n" + "=".repeat(80));
|
|
82
|
+
console.log("TEST SUMMARY");
|
|
83
|
+
console.log("=".repeat(80));
|
|
84
|
+
|
|
85
|
+
const passed = this.results.filter((r) => r.passed).length;
|
|
86
|
+
const total = this.results.length;
|
|
87
|
+
const totalDuration = this.results.reduce((sum, r) => sum + r.duration, 0);
|
|
88
|
+
|
|
89
|
+
console.log(`Total Tests: ${total}`);
|
|
90
|
+
console.log(`Passed: ${passed}`);
|
|
91
|
+
console.log(`Failed: ${total - passed}`);
|
|
92
|
+
console.log(`Total Duration: ${totalDuration.toFixed(2)}ms`);
|
|
93
|
+
console.log(`Success Rate: ${((passed / total) * 100).toFixed(1)}%`);
|
|
94
|
+
|
|
95
|
+
console.log("\nDetailed Results:");
|
|
96
|
+
this.results.forEach((result) => {
|
|
97
|
+
const status = result.passed ? "โ
" : "โ";
|
|
98
|
+
console.log(` ${status} ${result.suite} (${result.duration.toFixed(2)}ms)`);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (passed < total) {
|
|
102
|
+
console.log("\nFailed Tests:");
|
|
103
|
+
this.results
|
|
104
|
+
.filter((r) => !r.passed)
|
|
105
|
+
.forEach((result) => {
|
|
106
|
+
console.log(`\nโ ${result.suite}:`);
|
|
107
|
+
console.log(` Error: ${result.error}`);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function main() {
|
|
114
|
+
console.log("๐ PluresDB Test Suite Runner");
|
|
115
|
+
console.log("===============================");
|
|
116
|
+
|
|
117
|
+
const testSuites: TestSuite[] = [
|
|
118
|
+
{
|
|
119
|
+
name: "Unit Tests",
|
|
120
|
+
command: "test -A --unstable-kv --parallel src/tests/unit/",
|
|
121
|
+
description: "Core functionality tests (CRUD, subscriptions, vector search)",
|
|
122
|
+
timeout: 30000,
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: "Integration Tests",
|
|
126
|
+
command: "test -A --unstable-kv --parallel src/tests/integration/",
|
|
127
|
+
description: "Mesh networking and API server tests",
|
|
128
|
+
timeout: 60000,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: "Performance Tests",
|
|
132
|
+
command: "test -A --unstable-kv --parallel src/tests/performance/",
|
|
133
|
+
description: "Load testing and performance validation",
|
|
134
|
+
timeout: 120000,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "Security Tests",
|
|
138
|
+
command: "test -A --unstable-kv --parallel src/tests/security/",
|
|
139
|
+
description: "Input validation and security testing",
|
|
140
|
+
timeout: 30000,
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: "Code Quality",
|
|
144
|
+
command: "lint src/",
|
|
145
|
+
description: "Code linting and style checks",
|
|
146
|
+
timeout: 10000,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: "Type Checking",
|
|
150
|
+
command: "check src/main.ts",
|
|
151
|
+
description: "TypeScript type checking",
|
|
152
|
+
timeout: 15000,
|
|
153
|
+
},
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
const runner = new TestRunner();
|
|
157
|
+
|
|
158
|
+
for (const suite of testSuites) {
|
|
159
|
+
await runner.runTestSuite(suite);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
runner.printSummary();
|
|
163
|
+
|
|
164
|
+
const failedTests = runner.results.filter((r) => !r.passed).length;
|
|
165
|
+
if (failedTests > 0) {
|
|
166
|
+
console.log(`\nโ ${failedTests} test suite(s) failed!`);
|
|
167
|
+
Deno.exit(1);
|
|
168
|
+
} else {
|
|
169
|
+
console.log("\n๐ All tests passed!");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (import.meta.main) {
|
|
174
|
+
await main();
|
|
175
|
+
}
|