@plures/pluresdb 1.5.3 ā 2.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -414
- package/crates/README.md +99 -0
- package/crates/pluresdb-node/README.md +181 -0
- package/crates/pluresdb-node/index.d.ts +0 -0
- package/crates/pluresdb-node/index.js +265 -0
- package/crates/pluresdb-node/package.json +35 -0
- package/dist/napi/index.js +60 -0
- package/embedded.d.ts +1 -0
- package/embedded.js +46 -0
- package/package.json +27 -10
- package/dist/.tsbuildinfo +0 -1
- package/dist/better-sqlite3-shared.d.ts +0 -12
- package/dist/better-sqlite3-shared.d.ts.map +0 -1
- package/dist/better-sqlite3-shared.js +0 -143
- package/dist/better-sqlite3-shared.js.map +0 -1
- package/dist/better-sqlite3.d.ts +0 -4
- package/dist/better-sqlite3.d.ts.map +0 -1
- package/dist/better-sqlite3.js +0 -8
- package/dist/better-sqlite3.js.map +0 -1
- package/dist/cli.d.ts +0 -7
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/node-index.d.ts +0 -148
- package/dist/node-index.d.ts.map +0 -1
- package/dist/node-index.js +0 -665
- package/dist/node-index.js.map +0 -1
- package/dist/node-wrapper.d.ts +0 -44
- package/dist/node-wrapper.d.ts.map +0 -1
- package/dist/node-wrapper.js +0 -296
- package/dist/node-wrapper.js.map +0 -1
- package/dist/types/index.d.ts +0 -28
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -3
- package/dist/types/index.js.map +0 -1
- package/dist/types/node-types.d.ts +0 -71
- package/dist/types/node-types.d.ts.map +0 -1
- package/dist/types/node-types.js +0 -6
- package/dist/types/node-types.js.map +0 -1
- package/dist/vscode/extension.d.ts +0 -81
- package/dist/vscode/extension.d.ts.map +0 -1
- package/dist/vscode/extension.js +0 -309
- package/dist/vscode/extension.js.map +0 -1
- package/examples/basic-usage.d.ts +0 -2
- package/examples/basic-usage.d.ts.map +0 -1
- package/examples/basic-usage.js +0 -26
- package/examples/basic-usage.js.map +0 -1
- package/examples/basic-usage.ts +0 -29
- package/examples/vscode-extension-example/README.md +0 -95
- package/examples/vscode-extension-example/package.json +0 -49
- package/examples/vscode-extension-example/src/extension.ts +0 -172
- package/examples/vscode-extension-example/tsconfig.json +0 -12
- package/examples/vscode-extension-integration.d.ts +0 -31
- package/examples/vscode-extension-integration.d.ts.map +0 -1
- package/examples/vscode-extension-integration.js +0 -319
- package/examples/vscode-extension-integration.js.map +0 -1
- package/examples/vscode-extension-integration.ts +0 -41
- package/legacy/benchmarks/memory-benchmarks.ts +0 -350
- package/legacy/benchmarks/run-benchmarks.ts +0 -315
- package/legacy/better-sqlite3-shared.ts +0 -157
- package/legacy/better-sqlite3.ts +0 -4
- package/legacy/cli.ts +0 -241
- package/legacy/config.ts +0 -50
- package/legacy/core/crdt.ts +0 -107
- package/legacy/core/database.ts +0 -529
- package/legacy/healthcheck.ts +0 -162
- package/legacy/http/api-server.ts +0 -438
- package/legacy/index.ts +0 -28
- package/legacy/logic/rules.ts +0 -46
- package/legacy/main.rs +0 -3
- package/legacy/main.ts +0 -197
- package/legacy/network/websocket-server.ts +0 -115
- package/legacy/node-index.ts +0 -823
- package/legacy/node-wrapper.ts +0 -329
- package/legacy/sqlite-compat.ts +0 -633
- package/legacy/sqlite3-compat.ts +0 -55
- package/legacy/storage/kv-storage.ts +0 -73
- package/legacy/tests/core.test.ts +0 -305
- package/legacy/tests/fixtures/performance-data.json +0 -71
- package/legacy/tests/fixtures/test-data.json +0 -129
- package/legacy/tests/integration/api-server.test.ts +0 -334
- package/legacy/tests/integration/mesh-network.test.ts +0 -303
- package/legacy/tests/logic.test.ts +0 -34
- package/legacy/tests/performance/load.test.ts +0 -290
- package/legacy/tests/security/input-validation.test.ts +0 -286
- package/legacy/tests/unit/core.test.ts +0 -226
- package/legacy/tests/unit/subscriptions.test.ts +0 -135
- package/legacy/tests/unit/vector-search.test.ts +0 -173
- package/legacy/tests/vscode_extension_test.ts +0 -281
- package/legacy/types/index.ts +0 -32
- package/legacy/types/node-types.ts +0 -80
- package/legacy/util/debug.ts +0 -14
- package/legacy/vector/index.ts +0 -59
- package/legacy/vscode/extension.ts +0 -387
- package/scripts/compiled-crud-verify.ts +0 -30
- package/scripts/dogfood.ts +0 -297
- package/scripts/postinstall.js +0 -156
- package/scripts/publish-crates.sh +0 -95
- package/scripts/release-check.js +0 -224
- package/scripts/run-tests.ts +0 -178
- package/scripts/setup-libclang.ps1 +0 -209
- package/scripts/update-changelog.js +0 -214
- package/web/README.md +0 -27
- package/web/svelte/package.json +0 -31
|
@@ -1,387 +0,0 @@
|
|
|
1
|
-
import * as path from "node:path";
|
|
2
|
-
import { PluresNode, SQLiteCompatibleAPI } from "../node-index";
|
|
3
|
-
import type { PluresDBConfig } from "../types/node-types";
|
|
4
|
-
|
|
5
|
-
type DisposableLike = { dispose(): void };
|
|
6
|
-
|
|
7
|
-
type InputBoxOptions = {
|
|
8
|
-
prompt: string;
|
|
9
|
-
placeHolder?: string;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
type TextDocumentInit = {
|
|
13
|
-
content: string;
|
|
14
|
-
language: string;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
type UriLike = { toString(): string } | string;
|
|
18
|
-
|
|
19
|
-
export type VSCodeWindow = {
|
|
20
|
-
showInformationMessage(message: string): void | Promise<unknown>;
|
|
21
|
-
showErrorMessage(message: string): void | Promise<unknown>;
|
|
22
|
-
showInputBox(options: InputBoxOptions): Promise<string | undefined>;
|
|
23
|
-
showTextDocument(document: unknown): Promise<unknown>;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export type VSCodeCommands = {
|
|
27
|
-
registerCommand(
|
|
28
|
-
command: string,
|
|
29
|
-
callback: (...args: unknown[]) => unknown,
|
|
30
|
-
): DisposableLike;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export type VSCodeWorkspace = {
|
|
34
|
-
openTextDocument(init: TextDocumentInit): Promise<unknown>;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export type VSCodeEnv = {
|
|
38
|
-
openExternal(target: UriLike): Promise<unknown> | unknown;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export type VSCodeUri = {
|
|
42
|
-
parse(target: string): UriLike;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export type VSCodeAPI = {
|
|
46
|
-
window: VSCodeWindow;
|
|
47
|
-
commands: VSCodeCommands;
|
|
48
|
-
workspace: VSCodeWorkspace;
|
|
49
|
-
env: VSCodeEnv;
|
|
50
|
-
Uri: VSCodeUri;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export type ExtensionContextLike = {
|
|
54
|
-
subscriptions: DisposableLike[];
|
|
55
|
-
globalStorageUri: { fsPath: string };
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export type ExtensionOptions = {
|
|
59
|
-
config?: PluresDBConfig;
|
|
60
|
-
commandPrefix?: string;
|
|
61
|
-
pluresInstance?: PluresNode;
|
|
62
|
-
sqliteInstance?: SQLiteCompatibleAPI;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
type CommandFactory = () => Promise<void> | void;
|
|
66
|
-
|
|
67
|
-
const DEFAULT_CONFIG: PluresDBConfig = {
|
|
68
|
-
port: 34567,
|
|
69
|
-
host: "localhost",
|
|
70
|
-
webPort: 34568,
|
|
71
|
-
logLevel: "info",
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
export class PluresVSCodeExtension {
|
|
75
|
-
private readonly vscode: VSCodeAPI;
|
|
76
|
-
private readonly context: ExtensionContextLike;
|
|
77
|
-
private readonly plures: PluresNode;
|
|
78
|
-
private readonly sqlite: SQLiteCompatibleAPI;
|
|
79
|
-
private readonly commandPrefix: string;
|
|
80
|
-
private readonly disposables: DisposableLike[] = [];
|
|
81
|
-
private activated = false;
|
|
82
|
-
|
|
83
|
-
constructor(
|
|
84
|
-
vscodeApi: VSCodeAPI,
|
|
85
|
-
context: ExtensionContextLike,
|
|
86
|
-
options: ExtensionOptions = {},
|
|
87
|
-
) {
|
|
88
|
-
this.vscode = vscodeApi;
|
|
89
|
-
this.context = context;
|
|
90
|
-
this.commandPrefix = options.commandPrefix ?? "pluresdb";
|
|
91
|
-
|
|
92
|
-
const mergedConfig: PluresDBConfig = {
|
|
93
|
-
...DEFAULT_CONFIG,
|
|
94
|
-
dataDir: path.join(context.globalStorageUri.fsPath, "pluresdb"),
|
|
95
|
-
...options.config,
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
this.plures = options.pluresInstance ??
|
|
99
|
-
new PluresNode({ config: mergedConfig, autoStart: false });
|
|
100
|
-
this.sqlite = options.sqliteInstance ??
|
|
101
|
-
new SQLiteCompatibleAPI({ config: mergedConfig, autoStart: false });
|
|
102
|
-
|
|
103
|
-
this.setupEventHandlers();
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async activate(): Promise<void> {
|
|
107
|
-
if (this.activated) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
try {
|
|
112
|
-
await this.plures.start();
|
|
113
|
-
await this.sqlite.start();
|
|
114
|
-
this.registerCommands();
|
|
115
|
-
await this.setupDatabase();
|
|
116
|
-
this.activated = true;
|
|
117
|
-
await this.safeInfo("PluresDB extension activated");
|
|
118
|
-
} catch (error) {
|
|
119
|
-
await this.safeError(
|
|
120
|
-
`Failed to activate PluresDB: ${this.errorMessage(error)}`,
|
|
121
|
-
);
|
|
122
|
-
throw error;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
async deactivate(): Promise<void> {
|
|
127
|
-
if (!this.activated) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
try {
|
|
132
|
-
await this.sqlite.stop();
|
|
133
|
-
await this.plures.stop();
|
|
134
|
-
} finally {
|
|
135
|
-
this.disposeAll();
|
|
136
|
-
this.activated = false;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
getWebUrl(): string {
|
|
141
|
-
return this.plures.getWebUrl();
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
async storeSetting(key: string, value: unknown) {
|
|
145
|
-
return this.sqlite.put(`settings:${key}`, value);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async getSetting(key: string) {
|
|
149
|
-
return this.sqlite.getValue(`settings:${key}`);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async storeDocument(
|
|
153
|
-
id: string,
|
|
154
|
-
content: string,
|
|
155
|
-
language: string,
|
|
156
|
-
filePath: string,
|
|
157
|
-
) {
|
|
158
|
-
return this.sqlite.put(`documents:${id}`, {
|
|
159
|
-
content,
|
|
160
|
-
language,
|
|
161
|
-
filePath,
|
|
162
|
-
updatedAt: new Date().toISOString(),
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
async searchDocuments(query: string, limit = 20) {
|
|
167
|
-
return this.sqlite.vectorSearch(query, limit);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async executeSQL(sql: string, params: unknown[] = []) {
|
|
171
|
-
return this.sqlite.all(sql, params);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
private setupEventHandlers() {
|
|
175
|
-
this.plures.on("started", () => {
|
|
176
|
-
this.safeInfo("PluresDB database started");
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
this.plures.on("stopped", () => {
|
|
180
|
-
this.safeInfo("PluresDB database stopped");
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
this.plures.on("error", (error: unknown) => {
|
|
184
|
-
this.safeError(`PluresDB error: ${this.errorMessage(error)}`);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
this.plures.on("stderr", (output: string) => {
|
|
188
|
-
const trimmed = output.trim();
|
|
189
|
-
if (trimmed.length > 0) {
|
|
190
|
-
this.safeError(trimmed);
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
this.plures.on("stdout", (output: string) => {
|
|
195
|
-
const trimmed = output.trim();
|
|
196
|
-
if (trimmed.length > 0) {
|
|
197
|
-
this.safeInfo(trimmed);
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
private registerCommands() {
|
|
203
|
-
const register = (name: string, factory: CommandFactory) => {
|
|
204
|
-
const disposable = this.vscode.commands.registerCommand(
|
|
205
|
-
`${this.commandPrefix}.${name}`,
|
|
206
|
-
() => factory(),
|
|
207
|
-
);
|
|
208
|
-
this.context.subscriptions.push(disposable);
|
|
209
|
-
this.disposables.push(disposable);
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
register("openWebUI", async () => {
|
|
213
|
-
const webUrl = this.getWebUrl();
|
|
214
|
-
await this.vscode.env.openExternal(this.vscode.Uri.parse(webUrl));
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
register("executeQuery", async () => {
|
|
218
|
-
const sql = await this.vscode.window.showInputBox({
|
|
219
|
-
prompt: "Enter SQL query",
|
|
220
|
-
placeHolder: "SELECT * FROM users",
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
if (!sql) return;
|
|
224
|
-
|
|
225
|
-
try {
|
|
226
|
-
const result = await this.sqlite.all(sql);
|
|
227
|
-
const doc = await this.vscode.workspace.openTextDocument({
|
|
228
|
-
content: JSON.stringify(result, null, 2),
|
|
229
|
-
language: "json",
|
|
230
|
-
});
|
|
231
|
-
await this.vscode.window.showTextDocument(doc);
|
|
232
|
-
} catch (error) {
|
|
233
|
-
await this.safeError(`Query failed: ${this.errorMessage(error)}`);
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
register("vectorSearch", async () => {
|
|
238
|
-
const query = await this.vscode.window.showInputBox({
|
|
239
|
-
prompt: "Enter search query",
|
|
240
|
-
placeHolder: "machine learning",
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
if (!query) return;
|
|
244
|
-
|
|
245
|
-
try {
|
|
246
|
-
const results = await this.sqlite.vectorSearch(query, 10);
|
|
247
|
-
const doc = await this.vscode.workspace.openTextDocument({
|
|
248
|
-
content: JSON.stringify(results, null, 2),
|
|
249
|
-
language: "json",
|
|
250
|
-
});
|
|
251
|
-
await this.vscode.window.showTextDocument(doc);
|
|
252
|
-
} catch (error) {
|
|
253
|
-
await this.safeError(
|
|
254
|
-
`Vector search failed: ${this.errorMessage(error)}`,
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
register("storeData", async () => {
|
|
260
|
-
const key = await this.vscode.window.showInputBox({
|
|
261
|
-
prompt: "Enter key",
|
|
262
|
-
placeHolder: "user:123",
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
if (!key) return;
|
|
266
|
-
|
|
267
|
-
const json = await this.vscode.window.showInputBox({
|
|
268
|
-
prompt: "Enter value (JSON)",
|
|
269
|
-
placeHolder: '{"name": "Ada", "email": "ada@example.com"}',
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
if (!json) return;
|
|
273
|
-
|
|
274
|
-
try {
|
|
275
|
-
const value = JSON.parse(json);
|
|
276
|
-
await this.sqlite.put(key, value);
|
|
277
|
-
await this.safeInfo(`Stored data for key: ${key}`);
|
|
278
|
-
} catch (error) {
|
|
279
|
-
await this.safeError(
|
|
280
|
-
`Failed to store data: ${this.errorMessage(error)}`,
|
|
281
|
-
);
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
register("retrieveData", async () => {
|
|
286
|
-
const key = await this.vscode.window.showInputBox({
|
|
287
|
-
prompt: "Enter key to retrieve",
|
|
288
|
-
placeHolder: "user:123",
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
if (!key) return;
|
|
292
|
-
|
|
293
|
-
try {
|
|
294
|
-
const value = await this.sqlite.getValue(key);
|
|
295
|
-
if (value) {
|
|
296
|
-
const doc = await this.vscode.workspace.openTextDocument({
|
|
297
|
-
content: JSON.stringify(value, null, 2),
|
|
298
|
-
language: "json",
|
|
299
|
-
});
|
|
300
|
-
await this.vscode.window.showTextDocument(doc);
|
|
301
|
-
} else {
|
|
302
|
-
await this.safeInfo("Key not found");
|
|
303
|
-
}
|
|
304
|
-
} catch (error) {
|
|
305
|
-
await this.safeError(
|
|
306
|
-
`Failed to retrieve data: ${this.errorMessage(error)}`,
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
private async setupDatabase() {
|
|
313
|
-
const statements = [
|
|
314
|
-
`CREATE TABLE IF NOT EXISTS settings (
|
|
315
|
-
key TEXT PRIMARY KEY,
|
|
316
|
-
value TEXT,
|
|
317
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
318
|
-
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
319
|
-
)`,
|
|
320
|
-
`CREATE TABLE IF NOT EXISTS documents (
|
|
321
|
-
id TEXT PRIMARY KEY,
|
|
322
|
-
content TEXT,
|
|
323
|
-
language TEXT,
|
|
324
|
-
file_path TEXT,
|
|
325
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
326
|
-
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
327
|
-
)`,
|
|
328
|
-
`CREATE TABLE IF NOT EXISTS search_history (
|
|
329
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
330
|
-
query TEXT,
|
|
331
|
-
results_count INTEGER,
|
|
332
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
333
|
-
)`,
|
|
334
|
-
];
|
|
335
|
-
|
|
336
|
-
for (const sql of statements) {
|
|
337
|
-
try {
|
|
338
|
-
await this.sqlite.exec(sql);
|
|
339
|
-
} catch (error) {
|
|
340
|
-
await this.safeError(
|
|
341
|
-
`Failed to initialize database: ${this.errorMessage(error)}`,
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
private disposeAll() {
|
|
348
|
-
for (const disposable of this.disposables.splice(0)) {
|
|
349
|
-
try {
|
|
350
|
-
disposable.dispose();
|
|
351
|
-
} catch (_error) {
|
|
352
|
-
// ignore
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
private async safeInfo(message: string) {
|
|
358
|
-
try {
|
|
359
|
-
await this.vscode.window.showInformationMessage(message);
|
|
360
|
-
} catch (_error) {
|
|
361
|
-
// ignore message failures in headless tests
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
private async safeError(message: string) {
|
|
366
|
-
try {
|
|
367
|
-
await this.vscode.window.showErrorMessage(message);
|
|
368
|
-
} catch (_error) {
|
|
369
|
-
// ignore message failures in headless tests
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
private errorMessage(error: unknown): string {
|
|
374
|
-
if (error instanceof Error) {
|
|
375
|
-
return error.message;
|
|
376
|
-
}
|
|
377
|
-
return String(error);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
export function createPluresExtension(
|
|
382
|
-
vscodeApi: VSCodeAPI,
|
|
383
|
-
context: ExtensionContextLike,
|
|
384
|
-
options: ExtensionOptions = {},
|
|
385
|
-
) {
|
|
386
|
-
return new PluresVSCodeExtension(vscodeApi, context, options);
|
|
387
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { GunDB } from "../src/core/database.ts";
|
|
2
|
-
|
|
3
|
-
const serverUrl = Deno.env.get("SERVER_URL") ?? "ws://localhost:34567";
|
|
4
|
-
|
|
5
|
-
const clientA = new GunDB();
|
|
6
|
-
const clientB = new GunDB();
|
|
7
|
-
|
|
8
|
-
const kvA = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
|
|
9
|
-
const kvB = await Deno.makeTempFile({ prefix: "kv_", suffix: ".sqlite" });
|
|
10
|
-
|
|
11
|
-
await clientA.ready(kvA);
|
|
12
|
-
await clientB.ready(kvB);
|
|
13
|
-
|
|
14
|
-
clientA.connect(serverUrl);
|
|
15
|
-
clientB.connect(serverUrl);
|
|
16
|
-
|
|
17
|
-
const id = `bin:crud:${crypto.randomUUID()}`;
|
|
18
|
-
|
|
19
|
-
const receivedOnB = new Promise<void>((resolve) =>
|
|
20
|
-
clientB.on(id, (n) => n && resolve())
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
await clientA.put(id, { text: "compiled works" } as Record<string, unknown>);
|
|
24
|
-
|
|
25
|
-
await receivedOnB;
|
|
26
|
-
|
|
27
|
-
await clientA.close();
|
|
28
|
-
await clientB.close();
|
|
29
|
-
|
|
30
|
-
console.log("COMPILED-CRUD-OK", id);
|
package/scripts/dogfood.ts
DELETED
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env -S deno run -A --unstable-kv
|
|
2
|
-
|
|
3
|
-
import { GunDB } from "../legacy/core/database.ts";
|
|
4
|
-
import { startApiServer } from "../legacy/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(
|
|
104
|
-
`${apiUrl}/api/get?id=${encodeURIComponent(nodeId)}`,
|
|
105
|
-
);
|
|
106
|
-
assert(getRes.ok, "API get failed");
|
|
107
|
-
const getJson = await getRes.json();
|
|
108
|
-
assert(getJson.text === initialPayload.text, "Unexpected API get payload");
|
|
109
|
-
record("API get", true);
|
|
110
|
-
|
|
111
|
-
const listRes = await fetch(`${apiUrl}/api/list`);
|
|
112
|
-
assert(listRes.ok, "API list failed");
|
|
113
|
-
const listJson = await listRes.json();
|
|
114
|
-
assert(
|
|
115
|
-
Array.isArray(listJson) && listJson.some((n: any) => n.id === nodeId),
|
|
116
|
-
"Node missing from API list",
|
|
117
|
-
);
|
|
118
|
-
record("API list", true);
|
|
119
|
-
|
|
120
|
-
const searchRes = await fetch(
|
|
121
|
-
`${apiUrl}/api/search?q=${encodeURIComponent("dogfood script test")}&k=5`,
|
|
122
|
-
);
|
|
123
|
-
assert(searchRes.ok, "API search failed");
|
|
124
|
-
const searchJson = await searchRes.json();
|
|
125
|
-
assert(
|
|
126
|
-
Array.isArray(searchJson) && searchJson.length > 0,
|
|
127
|
-
"Vector search returned no results",
|
|
128
|
-
);
|
|
129
|
-
record("API vector search", true);
|
|
130
|
-
|
|
131
|
-
const updatePayload = {
|
|
132
|
-
type: "DogfoodTest",
|
|
133
|
-
text: "Hello from the updated dogfooding script",
|
|
134
|
-
};
|
|
135
|
-
const putUpdate = await fetch(`${apiUrl}/api/put`, {
|
|
136
|
-
method: "POST",
|
|
137
|
-
headers: { "content-type": "application/json" },
|
|
138
|
-
body: JSON.stringify({ id: nodeId, data: updatePayload }),
|
|
139
|
-
});
|
|
140
|
-
assert(putUpdate.ok, "API put update failed");
|
|
141
|
-
record("API update", true);
|
|
142
|
-
|
|
143
|
-
const historyRes = await fetch(
|
|
144
|
-
`${apiUrl}/api/history?id=${encodeURIComponent(nodeId)}`,
|
|
145
|
-
);
|
|
146
|
-
assert(historyRes.ok, "API history failed");
|
|
147
|
-
const historyJson = await historyRes.json();
|
|
148
|
-
assert(
|
|
149
|
-
Array.isArray(historyJson) && historyJson.length >= 2,
|
|
150
|
-
"API history missing versions",
|
|
151
|
-
);
|
|
152
|
-
record("API history", true, `${historyJson.length} versions`);
|
|
153
|
-
|
|
154
|
-
const restoreTimestamp = historyJson.at(-1)?.timestamp ??
|
|
155
|
-
historyJson[historyJson.length - 1]?.timestamp;
|
|
156
|
-
assert(
|
|
157
|
-
typeof restoreTimestamp === "number",
|
|
158
|
-
"Failed to locate restore timestamp",
|
|
159
|
-
);
|
|
160
|
-
const restoreRes = await fetch(
|
|
161
|
-
`${apiUrl}/api/restore?id=${
|
|
162
|
-
encodeURIComponent(nodeId)
|
|
163
|
-
}×tamp=${restoreTimestamp}`,
|
|
164
|
-
);
|
|
165
|
-
assert(restoreRes.ok, "API restore failed");
|
|
166
|
-
record("API restore", true);
|
|
167
|
-
|
|
168
|
-
const restored = await (
|
|
169
|
-
await fetch(`${apiUrl}/api/get?id=${encodeURIComponent(nodeId)}`)
|
|
170
|
-
).json();
|
|
171
|
-
assert(
|
|
172
|
-
restored.text === initialPayload.text,
|
|
173
|
-
"Restore did not revert payload",
|
|
174
|
-
);
|
|
175
|
-
record("API post-restore verification", true);
|
|
176
|
-
|
|
177
|
-
const instancesRes = await fetch(
|
|
178
|
-
`${apiUrl}/api/instances?type=${encodeURIComponent("DogfoodTest")}`,
|
|
179
|
-
);
|
|
180
|
-
assert(instancesRes.ok, "API instances failed");
|
|
181
|
-
const instancesJson = await instancesRes.json();
|
|
182
|
-
assert(
|
|
183
|
-
Array.isArray(instancesJson) &&
|
|
184
|
-
instancesJson.some((n: any) => n.id === nodeId),
|
|
185
|
-
"Instances endpoint missing node",
|
|
186
|
-
);
|
|
187
|
-
record("API type instances", true);
|
|
188
|
-
|
|
189
|
-
const webRes = await fetch(`${apiUrl}/`);
|
|
190
|
-
assert(webRes.ok, "Web UI endpoint failed");
|
|
191
|
-
const webHtml = await webRes.text();
|
|
192
|
-
record("Web UI fetch", true, `${webHtml.length} chars`);
|
|
193
|
-
|
|
194
|
-
const cliId = "dogfood:cli";
|
|
195
|
-
const cliPut = await runCli([
|
|
196
|
-
"put",
|
|
197
|
-
cliId,
|
|
198
|
-
JSON.stringify({ type: "DogfoodTest", text: "CLI write" }),
|
|
199
|
-
"--kv",
|
|
200
|
-
kvPath,
|
|
201
|
-
]);
|
|
202
|
-
assert(cliPut.code === 0, `CLI put failed: ${cliPut.stderr}`);
|
|
203
|
-
record("CLI put", true);
|
|
204
|
-
|
|
205
|
-
const cliGet = await runCli(["get", cliId, "--kv", kvPath]);
|
|
206
|
-
assert(cliGet.code === 0, `CLI get failed: ${cliGet.stderr}`);
|
|
207
|
-
const cliGetJson = JSON.parse(cliGet.stdout.trim() || "null");
|
|
208
|
-
assert(cliGetJson?.text === "CLI write", "CLI get returned wrong payload");
|
|
209
|
-
record("CLI get", true);
|
|
210
|
-
|
|
211
|
-
const cliList = await runCli(["list", "--kv", kvPath]);
|
|
212
|
-
assert(cliList.code === 0, `CLI list failed: ${cliList.stderr}`);
|
|
213
|
-
const cliListJson = JSON.parse(cliList.stdout.trim() || "[]");
|
|
214
|
-
assert(
|
|
215
|
-
Array.isArray(cliListJson) && cliListJson.length >= 2,
|
|
216
|
-
"CLI list missing entries",
|
|
217
|
-
);
|
|
218
|
-
record("CLI list", true);
|
|
219
|
-
|
|
220
|
-
const cliSearch = await runCli([
|
|
221
|
-
"vsearch",
|
|
222
|
-
"dogfooding",
|
|
223
|
-
"5",
|
|
224
|
-
"--kv",
|
|
225
|
-
kvPath,
|
|
226
|
-
]);
|
|
227
|
-
assert(cliSearch.code === 0, `CLI vsearch failed: ${cliSearch.stderr}`);
|
|
228
|
-
const cliSearchJson = JSON.parse(cliSearch.stdout.trim() || "[]");
|
|
229
|
-
assert(
|
|
230
|
-
Array.isArray(cliSearchJson) && cliSearchJson.length > 0,
|
|
231
|
-
"CLI vsearch returned no results",
|
|
232
|
-
);
|
|
233
|
-
record("CLI vector search", true);
|
|
234
|
-
|
|
235
|
-
console.log("\nš Dogfooding run succeeded!");
|
|
236
|
-
} catch (error) {
|
|
237
|
-
record(
|
|
238
|
-
"Dogfooding run",
|
|
239
|
-
false,
|
|
240
|
-
error instanceof Error ? error.message : String(error),
|
|
241
|
-
);
|
|
242
|
-
await finalize();
|
|
243
|
-
console.log("\nā Dogfooding run failed");
|
|
244
|
-
console.log(error);
|
|
245
|
-
Deno.exit(1);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
await finalize();
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
async function runCli(args: string[]) {
|
|
252
|
-
const command = new Deno.Command("deno", {
|
|
253
|
-
args: [
|
|
254
|
-
"run",
|
|
255
|
-
"-A",
|
|
256
|
-
"--unstable-kv",
|
|
257
|
-
"--no-lock",
|
|
258
|
-
"legacy/main.ts",
|
|
259
|
-
...args,
|
|
260
|
-
],
|
|
261
|
-
stdout: "piped",
|
|
262
|
-
stderr: "piped",
|
|
263
|
-
});
|
|
264
|
-
const { code, stdout, stderr } = await command.output();
|
|
265
|
-
return {
|
|
266
|
-
code,
|
|
267
|
-
stdout: new TextDecoder().decode(stdout),
|
|
268
|
-
stderr: new TextDecoder().decode(stderr),
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
async function waitFor(
|
|
273
|
-
fn: () => Promise<boolean>,
|
|
274
|
-
opts: { timeoutMs: number; intervalMs: number },
|
|
275
|
-
) {
|
|
276
|
-
const deadline = Date.now() + opts.timeoutMs;
|
|
277
|
-
while (Date.now() < deadline) {
|
|
278
|
-
if (await fn()) return;
|
|
279
|
-
await sleep(opts.intervalMs);
|
|
280
|
-
}
|
|
281
|
-
throw new Error("Timed out waiting for condition");
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function sleep(ms: number): Promise<void>;
|
|
285
|
-
function sleep<T>(ms: number, value: T): Promise<T>;
|
|
286
|
-
function sleep(ms: number, value?: unknown) {
|
|
287
|
-
return new Promise((resolve) => {
|
|
288
|
-
const timer = setTimeout(() => {
|
|
289
|
-
clearTimeout(timer);
|
|
290
|
-
resolve(value);
|
|
291
|
-
}, ms);
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if ((import.meta as any).main) {
|
|
296
|
-
await main();
|
|
297
|
-
}
|