@plures/pluresdb 1.6.10 → 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.
Files changed (126) hide show
  1. package/README.md +97 -289
  2. package/crates/README.md +99 -0
  3. package/crates/pluresdb-node/README.md +181 -0
  4. package/crates/pluresdb-node/index.d.ts +0 -0
  5. package/crates/pluresdb-node/index.js +265 -0
  6. package/crates/pluresdb-node/package.json +35 -0
  7. package/dist/napi/index.js +60 -0
  8. package/embedded.d.ts +1 -0
  9. package/embedded.js +46 -0
  10. package/package.json +20 -9
  11. package/dist/.tsbuildinfo +0 -1
  12. package/dist/better-sqlite3-shared.d.ts +0 -12
  13. package/dist/better-sqlite3-shared.d.ts.map +0 -1
  14. package/dist/better-sqlite3-shared.js +0 -143
  15. package/dist/better-sqlite3-shared.js.map +0 -1
  16. package/dist/better-sqlite3.d.ts +0 -4
  17. package/dist/better-sqlite3.d.ts.map +0 -1
  18. package/dist/better-sqlite3.js +0 -8
  19. package/dist/better-sqlite3.js.map +0 -1
  20. package/dist/cli.d.ts +0 -7
  21. package/dist/cli.d.ts.map +0 -1
  22. package/dist/cli.js.map +0 -1
  23. package/dist/local-first/unified-api.d.ts +0 -110
  24. package/dist/local-first/unified-api.d.ts.map +0 -1
  25. package/dist/local-first/unified-api.js +0 -348
  26. package/dist/local-first/unified-api.js.map +0 -1
  27. package/dist/node-index.d.ts +0 -150
  28. package/dist/node-index.d.ts.map +0 -1
  29. package/dist/node-index.js +0 -668
  30. package/dist/node-index.js.map +0 -1
  31. package/dist/node-wrapper.d.ts +0 -44
  32. package/dist/node-wrapper.d.ts.map +0 -1
  33. package/dist/node-wrapper.js +0 -296
  34. package/dist/node-wrapper.js.map +0 -1
  35. package/dist/types/index.d.ts +0 -28
  36. package/dist/types/index.d.ts.map +0 -1
  37. package/dist/types/index.js +0 -3
  38. package/dist/types/index.js.map +0 -1
  39. package/dist/types/node-types.d.ts +0 -71
  40. package/dist/types/node-types.d.ts.map +0 -1
  41. package/dist/types/node-types.js +0 -6
  42. package/dist/types/node-types.js.map +0 -1
  43. package/dist/util/debug.d.ts +0 -3
  44. package/dist/util/debug.d.ts.map +0 -1
  45. package/dist/util/debug.js +0 -34
  46. package/dist/util/debug.js.map +0 -1
  47. package/dist/vscode/extension.d.ts +0 -81
  48. package/dist/vscode/extension.d.ts.map +0 -1
  49. package/dist/vscode/extension.js +0 -309
  50. package/dist/vscode/extension.js.map +0 -1
  51. package/examples/basic-usage.d.ts +0 -2
  52. package/examples/basic-usage.d.ts.map +0 -1
  53. package/examples/basic-usage.js +0 -26
  54. package/examples/basic-usage.js.map +0 -1
  55. package/examples/basic-usage.ts +0 -29
  56. package/examples/browser-demo/README.md +0 -204
  57. package/examples/browser-demo/index.html +0 -466
  58. package/examples/browser-wasm-integration.md +0 -411
  59. package/examples/ipc-demo/README.md +0 -127
  60. package/examples/local-first-usage.ts +0 -138
  61. package/examples/native-ipc-integration.md +0 -526
  62. package/examples/tauri-demo/README.md +0 -240
  63. package/examples/tauri-integration.md +0 -260
  64. package/examples/vscode-extension-example/README.md +0 -95
  65. package/examples/vscode-extension-example/package.json +0 -49
  66. package/examples/vscode-extension-example/src/extension.ts +0 -172
  67. package/examples/vscode-extension-example/tsconfig.json +0 -12
  68. package/examples/vscode-extension-integration.d.ts +0 -31
  69. package/examples/vscode-extension-integration.d.ts.map +0 -1
  70. package/examples/vscode-extension-integration.js +0 -319
  71. package/examples/vscode-extension-integration.js.map +0 -1
  72. package/examples/vscode-extension-integration.ts +0 -41
  73. package/legacy/benchmarks/memory-benchmarks.ts +0 -350
  74. package/legacy/benchmarks/run-benchmarks.ts +0 -315
  75. package/legacy/better-sqlite3-shared.ts +0 -157
  76. package/legacy/better-sqlite3.ts +0 -4
  77. package/legacy/cli.ts +0 -241
  78. package/legacy/config.ts +0 -50
  79. package/legacy/core/crdt.ts +0 -107
  80. package/legacy/core/database.ts +0 -529
  81. package/legacy/healthcheck.ts +0 -162
  82. package/legacy/http/api-server.ts +0 -569
  83. package/legacy/index.ts +0 -31
  84. package/legacy/local-first/unified-api.ts +0 -449
  85. package/legacy/logic/rules.ts +0 -46
  86. package/legacy/main.rs +0 -3
  87. package/legacy/main.ts +0 -197
  88. package/legacy/network/websocket-server.ts +0 -115
  89. package/legacy/node-index.ts +0 -827
  90. package/legacy/node-wrapper.ts +0 -329
  91. package/legacy/plugins/README.md +0 -181
  92. package/legacy/plugins/example-embedding-plugin.ts +0 -56
  93. package/legacy/plugins/plugin-system.ts +0 -315
  94. package/legacy/sqlite-compat.ts +0 -633
  95. package/legacy/sqlite3-compat.ts +0 -55
  96. package/legacy/storage/kv-storage.ts +0 -73
  97. package/legacy/tests/core.test.ts +0 -305
  98. package/legacy/tests/fixtures/performance-data.json +0 -71
  99. package/legacy/tests/fixtures/test-data.json +0 -129
  100. package/legacy/tests/integration/api-server.test.ts +0 -334
  101. package/legacy/tests/integration/mesh-network.test.ts +0 -303
  102. package/legacy/tests/logic.test.ts +0 -34
  103. package/legacy/tests/performance/load.test.ts +0 -290
  104. package/legacy/tests/security/input-validation.test.ts +0 -286
  105. package/legacy/tests/unit/core.test.ts +0 -226
  106. package/legacy/tests/unit/local-first-api.test.ts +0 -65
  107. package/legacy/tests/unit/plugin-system.test.ts +0 -388
  108. package/legacy/tests/unit/subscriptions.test.ts +0 -135
  109. package/legacy/tests/unit/vector-search.test.ts +0 -173
  110. package/legacy/tests/vscode_extension_test.ts +0 -281
  111. package/legacy/types/index.ts +0 -32
  112. package/legacy/types/node-types.ts +0 -80
  113. package/legacy/util/debug.ts +0 -27
  114. package/legacy/vector/index.ts +0 -59
  115. package/legacy/vscode/extension.ts +0 -387
  116. package/scripts/compiled-crud-verify.ts +0 -30
  117. package/scripts/dogfood.ts +0 -297
  118. package/scripts/postinstall.js +0 -156
  119. package/scripts/publish-crates.sh +0 -95
  120. package/scripts/release-check.js +0 -224
  121. package/scripts/run-tests.ts +0 -178
  122. package/scripts/setup-libclang.ps1 +0 -209
  123. package/scripts/update-changelog.js +0 -214
  124. package/scripts/validate-npm-publish.js +0 -228
  125. package/web/README.md +0 -27
  126. package/web/svelte/package.json +0 -31
@@ -1,449 +0,0 @@
1
- /**
2
- * Unified Local-First API for PluresDB
3
- *
4
- * Automatically selects the best integration method based on runtime environment:
5
- * - Browser (WASM): Direct in-process WebAssembly
6
- * - Tauri: Direct Rust crate linking via Tauri commands
7
- * - Native IPC: Shared memory inter-process communication
8
- * - Network: HTTP REST API (fallback for backward compatibility)
9
- *
10
- * This provides a consistent API across all platforms while maximizing performance
11
- * and minimizing network overhead.
12
- */
13
-
14
- import { debugLog } from "../util/debug";
15
-
16
- export interface LocalFirstOptions {
17
- /**
18
- * Integration mode. If not specified, auto-detects the best mode.
19
- * - "auto": Auto-detect runtime environment
20
- * - "wasm": WebAssembly (browser)
21
- * - "tauri": Tauri native integration
22
- * - "ipc": Shared memory IPC
23
- * - "network": HTTP REST API (backward compatibility)
24
- */
25
- mode?: "auto" | "wasm" | "tauri" | "ipc" | "network";
26
-
27
- /**
28
- * Database name (for WASM mode)
29
- */
30
- dbName?: string;
31
-
32
- /**
33
- * IPC channel name (for IPC mode)
34
- */
35
- channelName?: string;
36
-
37
- /**
38
- * Network URL (for network mode)
39
- */
40
- networkUrl?: string;
41
-
42
- /**
43
- * Network port (for network mode)
44
- */
45
- port?: number;
46
- }
47
-
48
- export interface LocalFirstBackend {
49
- put(id: string, data: unknown): Promise<string>;
50
- get(id: string): Promise<unknown>;
51
- delete(id: string): Promise<void>;
52
- list(): Promise<unknown[]>;
53
- vectorSearch?(query: string, limit: number): Promise<unknown[]>;
54
- close?(): Promise<void>;
55
- }
56
-
57
- /**
58
- * Runtime environment detection
59
- */
60
- class RuntimeDetector {
61
- static isBrowser(): boolean {
62
- return typeof globalThis !== "undefined" &&
63
- typeof (globalThis as any).window !== "undefined" &&
64
- typeof (globalThis as any).document !== "undefined" &&
65
- typeof (globalThis as any).WebAssembly !== "undefined";
66
- }
67
-
68
- static isTauri(): boolean {
69
- return typeof globalThis !== "undefined" &&
70
- typeof (globalThis as any).window !== "undefined" &&
71
- (globalThis as any).window?.__TAURI__ !== undefined;
72
- }
73
-
74
- static isNode(): boolean {
75
- const globalProcess = (globalThis as any).process;
76
- return typeof globalProcess !== "undefined" &&
77
- globalProcess.versions?.node != null;
78
- }
79
-
80
- static isDeno(): boolean {
81
- return typeof globalThis !== "undefined" &&
82
- (globalThis as any).Deno !== undefined;
83
- }
84
-
85
- static hasIPCEnvironment(): boolean {
86
- if (this.isNode()) {
87
- return (globalThis as any).process?.env?.PLURESDB_IPC === "true";
88
- }
89
- if (this.isDeno()) {
90
- const Deno = (globalThis as any).Deno;
91
- return Deno?.env?.get?.("PLURESDB_IPC") === "true";
92
- }
93
- return false;
94
- }
95
-
96
- static detectBestMode(): "wasm" | "tauri" | "ipc" | "network" {
97
- if (this.isTauri()) {
98
- debugLog("Detected Tauri environment - using native integration");
99
- return "tauri";
100
- }
101
-
102
- if (this.isBrowser()) {
103
- debugLog("Detected browser environment - using WASM");
104
- return "wasm";
105
- }
106
-
107
- if (this.hasIPCEnvironment()) {
108
- debugLog("Detected IPC environment - using shared memory");
109
- return "ipc";
110
- }
111
-
112
- debugLog("Using network mode (fallback)");
113
- return "network";
114
- }
115
- }
116
-
117
- /**
118
- * WASM Backend (Browser)
119
- *
120
- * Uses WebAssembly for direct in-process database access.
121
- * Data is persisted in IndexedDB.
122
- */
123
- class WasmBackend implements LocalFirstBackend {
124
- private db: unknown = null;
125
- private dbName: string;
126
-
127
- constructor(dbName: string = "pluresdb") {
128
- this.dbName = dbName;
129
- }
130
-
131
- async initialize(): Promise<void> {
132
- // Note: This is a placeholder. The actual WASM module will be implemented
133
- // in Phase 1 of the roadmap (pluresdb-wasm crate).
134
- throw new Error(
135
- "WASM backend not yet implemented. Please see docs/LOCAL_FIRST_INTEGRATION.md for implementation status.",
136
- );
137
- }
138
-
139
- async put(id: string, data: unknown): Promise<string> {
140
- if (!this.db) await this.initialize();
141
- return (this.db as any).put(id, data);
142
- }
143
-
144
- async get(id: string): Promise<unknown> {
145
- if (!this.db) await this.initialize();
146
- return (this.db as any).get(id);
147
- }
148
-
149
- async delete(id: string): Promise<void> {
150
- if (!this.db) await this.initialize();
151
- return (this.db as any).delete(id);
152
- }
153
-
154
- async list(): Promise<unknown[]> {
155
- if (!this.db) await this.initialize();
156
- return (this.db as any).list();
157
- }
158
-
159
- async vectorSearch(query: string, limit: number): Promise<unknown[]> {
160
- if (!this.db) await this.initialize();
161
- return (this.db as any).vectorSearch(query, limit);
162
- }
163
-
164
- async close(): Promise<void> {
165
- if (this.db) {
166
- await (this.db as any).close();
167
- this.db = null;
168
- }
169
- }
170
- }
171
-
172
- /**
173
- * Tauri Backend
174
- *
175
- * Uses Tauri commands to invoke Rust functions directly.
176
- * Provides native performance with no network overhead.
177
- */
178
- class TauriBackend implements LocalFirstBackend {
179
- private invoke: any;
180
-
181
- constructor() {
182
- const win = typeof globalThis !== "undefined" ? (globalThis as any).window : undefined;
183
- if (!win || !win.__TAURI__) {
184
- throw new Error("Tauri backend requires Tauri environment");
185
- }
186
- this.invoke = win.__TAURI__.invoke;
187
- }
188
-
189
- async put(id: string, data: unknown): Promise<string> {
190
- return await this.invoke("pluresdb_put", { id, data });
191
- }
192
-
193
- async get(id: string): Promise<unknown> {
194
- return await this.invoke("pluresdb_get", { id });
195
- }
196
-
197
- async delete(id: string): Promise<void> {
198
- await this.invoke("pluresdb_delete", { id });
199
- }
200
-
201
- async list(): Promise<unknown[]> {
202
- return await this.invoke("pluresdb_list");
203
- }
204
-
205
- async vectorSearch(query: string, limit: number): Promise<unknown[]> {
206
- return await this.invoke("pluresdb_vector_search", { query, limit });
207
- }
208
- }
209
-
210
- /**
211
- * IPC Backend (Native Apps)
212
- *
213
- * Uses shared memory and message passing for inter-process communication.
214
- * Provides low-latency access without network overhead.
215
- */
216
- class IPCBackend implements LocalFirstBackend {
217
- private channelName: string;
218
-
219
- constructor(channelName: string = "pluresdb") {
220
- this.channelName = channelName;
221
- }
222
-
223
- async initialize(): Promise<void> {
224
- // Note: This is a placeholder. The actual IPC implementation will be
225
- // in Phase 3 of the roadmap (pluresdb-ipc crate).
226
- throw new Error(
227
- "IPC backend not yet implemented. Please see docs/LOCAL_FIRST_INTEGRATION.md for implementation status.",
228
- );
229
- }
230
-
231
- async put(id: string, data: unknown): Promise<string> {
232
- throw new Error("IPC backend not yet implemented");
233
- }
234
-
235
- async get(id: string): Promise<unknown> {
236
- throw new Error("IPC backend not yet implemented");
237
- }
238
-
239
- async delete(id: string): Promise<void> {
240
- throw new Error("IPC backend not yet implemented");
241
- }
242
-
243
- async list(): Promise<unknown[]> {
244
- throw new Error("IPC backend not yet implemented");
245
- }
246
-
247
- async vectorSearch(query: string, limit: number): Promise<unknown[]> {
248
- throw new Error("IPC backend not yet implemented");
249
- }
250
- }
251
-
252
- /**
253
- * Network Backend (HTTP REST API)
254
- *
255
- * Uses HTTP requests to communicate with a PluresDB server.
256
- * This is the fallback mode for backward compatibility.
257
- */
258
- class NetworkBackend implements LocalFirstBackend {
259
- private baseUrl: string;
260
-
261
- constructor(url?: string, port?: number) {
262
- this.baseUrl = url || `http://localhost:${port || 34567}`;
263
- }
264
-
265
- async put(id: string, data: unknown): Promise<string> {
266
- const response = await fetch(`${this.baseUrl}/api/put`, {
267
- method: "POST",
268
- headers: { "Content-Type": "application/json" },
269
- body: JSON.stringify({ id, data }),
270
- });
271
-
272
- if (!response.ok) {
273
- throw new Error(`PUT failed: ${response.statusText}`);
274
- }
275
-
276
- // API returns { ok: true }, return the id
277
- await response.json();
278
- return id;
279
- }
280
-
281
- async get(id: string): Promise<unknown> {
282
- const response = await fetch(`${this.baseUrl}/api/get?id=${encodeURIComponent(id)}`);
283
-
284
- if (!response.ok) {
285
- if (response.status === 404) return null;
286
- throw new Error(`GET failed: ${response.statusText}`);
287
- }
288
-
289
- // API returns the node data directly (can be null)
290
- return await response.json();
291
- }
292
-
293
- async delete(id: string): Promise<void> {
294
- const response = await fetch(`${this.baseUrl}/api/delete?id=${encodeURIComponent(id)}`, {
295
- method: "DELETE",
296
- });
297
-
298
- if (!response.ok) {
299
- throw new Error(`DELETE failed: ${response.statusText}`);
300
- }
301
- }
302
-
303
- async list(): Promise<unknown[]> {
304
- const response = await fetch(`${this.baseUrl}/api/list`);
305
-
306
- if (!response.ok) {
307
- throw new Error(`LIST failed: ${response.statusText}`);
308
- }
309
-
310
- // API returns array of { id, data }
311
- const nodes = await response.json() as Array<{ id: string; data: unknown }>;
312
- return nodes;
313
- }
314
-
315
- async vectorSearch(query: string, limit: number): Promise<unknown[]> {
316
- const response = await fetch(`${this.baseUrl}/api/search`, {
317
- method: "POST",
318
- headers: { "Content-Type": "application/json" },
319
- body: JSON.stringify({ query, limit }),
320
- });
321
-
322
- if (!response.ok) {
323
- throw new Error(`VECTOR_SEARCH failed: ${response.statusText}`);
324
- }
325
-
326
- // API returns array of { id, data }
327
- const nodes = await response.json() as Array<{ id: string; data: unknown }>;
328
- return nodes;
329
- }
330
- }
331
-
332
- /**
333
- * PluresDB Local-First API
334
- *
335
- * Unified interface that works across all platforms:
336
- * - Browser (WASM)
337
- * - Tauri (native)
338
- * - Native apps (IPC)
339
- * - Traditional apps (network)
340
- *
341
- * Automatically selects the best integration method or allows manual override.
342
- *
343
- * @example
344
- * ```typescript
345
- * // Auto-detect best mode
346
- * const db = new PluresDBLocalFirst();
347
- *
348
- * // Manual mode selection
349
- * const db = new PluresDBLocalFirst({ mode: "wasm", dbName: "my-app" });
350
- *
351
- * // Use the API (same across all modes)
352
- * await db.put("user:1", { name: "Alice", email: "alice@example.com" });
353
- * const user = await db.get("user:1");
354
- * const results = await db.vectorSearch("Find users named Alice", 10);
355
- * ```
356
- */
357
- export class PluresDBLocalFirst {
358
- private backend: LocalFirstBackend;
359
- private mode: string;
360
-
361
- constructor(options: LocalFirstOptions = {}) {
362
- const mode = options.mode || "auto";
363
- const actualMode = mode === "auto" ? RuntimeDetector.detectBestMode() : mode;
364
-
365
- this.mode = actualMode;
366
-
367
- switch (actualMode) {
368
- case "wasm":
369
- this.backend = new WasmBackend(options.dbName);
370
- break;
371
-
372
- case "tauri":
373
- this.backend = new TauriBackend();
374
- break;
375
-
376
- case "ipc":
377
- this.backend = new IPCBackend(options.channelName);
378
- break;
379
-
380
- case "network":
381
- this.backend = new NetworkBackend(options.networkUrl, options.port);
382
- break;
383
-
384
- default:
385
- throw new Error(`Unknown mode: ${actualMode}`);
386
- }
387
-
388
- debugLog(`Initialized in ${this.mode} mode`);
389
- }
390
-
391
- /**
392
- * Get the current integration mode
393
- */
394
- getMode(): string {
395
- return this.mode;
396
- }
397
-
398
- /**
399
- * Insert or update a node
400
- */
401
- async put(id: string, data: unknown): Promise<string> {
402
- return this.backend.put(id, data);
403
- }
404
-
405
- /**
406
- * Retrieve a node by ID
407
- */
408
- async get(id: string): Promise<unknown> {
409
- return this.backend.get(id);
410
- }
411
-
412
- /**
413
- * Delete a node by ID
414
- */
415
- async delete(id: string): Promise<void> {
416
- return this.backend.delete(id);
417
- }
418
-
419
- /**
420
- * List all nodes
421
- */
422
- async list(): Promise<unknown[]> {
423
- return this.backend.list();
424
- }
425
-
426
- /**
427
- * Vector search (semantic similarity)
428
- */
429
- async vectorSearch(query: string, limit: number = 10): Promise<unknown[]> {
430
- if (!this.backend.vectorSearch) {
431
- throw new Error("Vector search not supported in this mode");
432
- }
433
- return this.backend.vectorSearch(query, limit);
434
- }
435
-
436
- /**
437
- * Close the database connection
438
- */
439
- async close(): Promise<void> {
440
- if (this.backend.close) {
441
- await this.backend.close();
442
- }
443
- }
444
- }
445
-
446
- /**
447
- * Legacy export for backward compatibility
448
- */
449
- export default PluresDBLocalFirst;
@@ -1,46 +0,0 @@
1
- import type { NodeRecord } from "../types/index.ts";
2
-
3
- // Minimal DB interface to avoid circular imports
4
- export interface DatabaseLike {
5
- put(id: string, data: Record<string, unknown>): Promise<void>;
6
- get<T = Record<string, unknown>>(
7
- id: string,
8
- ): Promise<(T & { id: string }) | null>;
9
- }
10
-
11
- export interface RuleContext {
12
- db: DatabaseLike;
13
- }
14
-
15
- export type RulePredicate = (node: NodeRecord) => boolean | Promise<boolean>;
16
- export type RuleAction = (ctx: RuleContext, node: NodeRecord) => Promise<void>;
17
-
18
- export interface Rule {
19
- name: string;
20
- whenType?: string;
21
- predicate?: RulePredicate;
22
- action: RuleAction;
23
- }
24
-
25
- export class RuleEngine {
26
- private readonly rules: Map<string, Rule> = new Map();
27
-
28
- addRule(rule: Rule): void {
29
- this.rules.set(rule.name, rule);
30
- }
31
-
32
- removeRule(name: string): void {
33
- this.rules.delete(name);
34
- }
35
-
36
- async evaluateNode(node: NodeRecord, ctx: RuleContext): Promise<void> {
37
- for (const rule of this.rules.values()) {
38
- if (rule.whenType && node.type !== rule.whenType) continue;
39
- if (rule.predicate) {
40
- const ok = await rule.predicate(node);
41
- if (!ok) continue;
42
- }
43
- await rule.action(ctx, node);
44
- }
45
- }
46
- }
package/legacy/main.rs DELETED
@@ -1,3 +0,0 @@
1
- fn main() {
2
- println!("Hello, world!");
3
- }
package/legacy/main.ts DELETED
@@ -1,197 +0,0 @@
1
- import { GunDB } from "./core/database.ts";
2
- import { debugLog as _debugLog } from "./util/debug.ts";
3
- import { startApiServer } from "./http/api-server.ts";
4
- import { loadConfig, saveConfig } from "./config.ts";
5
-
6
- function printUsage() {
7
- console.log(
8
- [
9
- "Usage:",
10
- " deno run -A src/main.ts serve [--port <port>] [--kv <path>] [ws://peer ...]",
11
- " deno run -A src/main.ts put <id> <json> [--kv <path>]",
12
- " deno run -A src/main.ts get <id> [--kv <path>]",
13
- " deno run -A src/main.ts delete <id> [--kv <path>]",
14
- " deno run -A src/main.ts vsearch <query> <k> [--kv <path>]",
15
- " deno run -A src/main.ts type <id> <TypeName> [--kv <path>]",
16
- " deno run -A src/main.ts instances <TypeName> [--kv <path>]",
17
- " deno run -A src/main.ts list [--kv <path>]",
18
- "",
19
- ].join("\n"),
20
- );
21
- }
22
-
23
- if (import.meta.main) {
24
- const [cmd, ...rest] = Deno.args;
25
- switch (cmd) {
26
- case "serve": {
27
- const cfg = await loadConfig();
28
- let port = cfg.port ?? 8080;
29
- let kvPath: string | undefined = cfg.kvPath;
30
- const pi = rest.indexOf("--port");
31
- if (pi >= 0 && rest[pi + 1]) {
32
- const n = Number(rest[pi + 1]);
33
- if (Number.isFinite(n)) port = n;
34
- }
35
- const ki = rest.indexOf("--kv");
36
- if (ki >= 0 && rest[ki + 1]) kvPath = rest[ki + 1];
37
- const peers = (cfg.peers ?? []).concat(
38
- rest.filter((v) => v.startsWith("ws://") || v.startsWith("wss://")),
39
- );
40
-
41
- const db = new GunDB();
42
- await db.ready(kvPath);
43
- db.serve({ port });
44
- for (const p of peers) db.connect(p);
45
-
46
- const api = startApiServer({ port: port + (cfg.apiPortOffset ?? 1), db });
47
- console.log(`PluresDB node serving on ws://localhost:${port}`);
48
- console.log(`HTTP API/UI on ${api.url}`);
49
- if (peers.length) console.log("Connected to peers:", peers.join(", "));
50
-
51
- // Keep process alive
52
- await new Promise(() => {});
53
- break;
54
- }
55
- case "put": {
56
- const [id, json, ...flags] = rest;
57
- if (!id || !json) {
58
- printUsage();
59
- Deno.exit(1);
60
- }
61
- let kvPath: string | undefined;
62
- const ki = flags.indexOf("--kv");
63
- if (ki >= 0 && flags[ki + 1]) kvPath = flags[ki + 1];
64
- const db = new GunDB();
65
- await db.ready(kvPath);
66
- const obj = JSON.parse(json);
67
- await db.put(id, obj);
68
- console.log("ok");
69
- await db.close();
70
- break;
71
- }
72
- case "get": {
73
- const [id, ...flags] = rest;
74
- if (!id) {
75
- printUsage();
76
- Deno.exit(1);
77
- }
78
- let kvPath: string | undefined;
79
- const ki = flags.indexOf("--kv");
80
- if (ki >= 0 && flags[ki + 1]) kvPath = flags[ki + 1];
81
- const db = new GunDB();
82
- await db.ready(kvPath);
83
- const val = await db.get<Record<string, unknown>>(id);
84
- console.log(JSON.stringify(val));
85
- await db.close();
86
- break;
87
- }
88
- case "delete": {
89
- const [id, ...flags] = rest;
90
- if (!id) {
91
- printUsage();
92
- Deno.exit(1);
93
- }
94
- let kvPath: string | undefined;
95
- const ki = flags.indexOf("--kv");
96
- if (ki >= 0 && flags[ki + 1]) kvPath = flags[ki + 1];
97
- const db = new GunDB();
98
- await db.ready(kvPath);
99
- await db.delete(id);
100
- console.log("ok");
101
- await db.close();
102
- break;
103
- }
104
- case "vsearch": {
105
- const [query, kRaw, ...flags] = rest;
106
- if (!query || !kRaw) {
107
- printUsage();
108
- Deno.exit(1);
109
- }
110
- const k = Number(kRaw);
111
- if (!Number.isFinite(k)) {
112
- printUsage();
113
- Deno.exit(1);
114
- }
115
- let kvPath: string | undefined;
116
- const ki = flags.indexOf("--kv");
117
- if (ki >= 0 && flags[ki + 1]) kvPath = flags[ki + 1];
118
- const db = new GunDB();
119
- await db.ready(kvPath);
120
- const results = await db.vectorSearch(query, k);
121
- console.log(
122
- JSON.stringify(results.map((n) => ({ id: n.id, data: n.data }))),
123
- );
124
- await db.close();
125
- break;
126
- }
127
- case "type": {
128
- const [id, typeName, ...flags] = rest;
129
- if (!id || !typeName) {
130
- printUsage();
131
- Deno.exit(1);
132
- }
133
- let kvPath: string | undefined;
134
- const ki = flags.indexOf("--kv");
135
- if (ki >= 0 && flags[ki + 1]) kvPath = flags[ki + 1];
136
- const db = new GunDB();
137
- await db.ready(kvPath);
138
- await db.setType(id, typeName);
139
- console.log("ok");
140
- await db.close();
141
- break;
142
- }
143
- case "instances": {
144
- const [typeName, ...flags] = rest;
145
- if (!typeName) {
146
- printUsage();
147
- Deno.exit(1);
148
- }
149
- let kvPath: string | undefined;
150
- const ki = flags.indexOf("--kv");
151
- if (ki >= 0 && flags[ki + 1]) kvPath = flags[ki + 1];
152
- const db = new GunDB();
153
- await db.ready(kvPath);
154
- const rows = await db.instancesOf(typeName);
155
- console.log(
156
- JSON.stringify(rows.map((n) => ({ id: n.id, data: n.data }))),
157
- );
158
- await db.close();
159
- break;
160
- }
161
- case "list": {
162
- const flags = rest;
163
- let kvPath: string | undefined;
164
- const ki = flags.indexOf("--kv");
165
- if (ki >= 0 && flags[ki + 1]) kvPath = flags[ki + 1];
166
- const db = new GunDB();
167
- await db.ready(kvPath);
168
- const nodes = await db.getAll();
169
- const out = nodes.map((node) => ({
170
- id: node.id,
171
- data: node.data as Record<string, unknown>,
172
- }));
173
- console.log(JSON.stringify(out));
174
- await db.close();
175
- break;
176
- }
177
- case "config": {
178
- const cfg = await loadConfig();
179
- console.log(JSON.stringify(cfg, null, 2));
180
- break;
181
- }
182
- case "config:set": {
183
- const [key, value] = rest;
184
- if (!key || value === undefined) {
185
- printUsage();
186
- Deno.exit(1);
187
- }
188
- const cfg = await loadConfig();
189
- (cfg as any)[key] = /^[0-9]+$/.test(value) ? Number(value) : value;
190
- await saveConfig(cfg);
191
- console.log("ok");
192
- break;
193
- }
194
- default:
195
- printUsage();
196
- }
197
- }