@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.
- package/README.md +97 -289
- 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 +20 -9
- 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/local-first/unified-api.d.ts +0 -110
- package/dist/local-first/unified-api.d.ts.map +0 -1
- package/dist/local-first/unified-api.js +0 -348
- package/dist/local-first/unified-api.js.map +0 -1
- package/dist/node-index.d.ts +0 -150
- package/dist/node-index.d.ts.map +0 -1
- package/dist/node-index.js +0 -668
- 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/util/debug.d.ts +0 -3
- package/dist/util/debug.d.ts.map +0 -1
- package/dist/util/debug.js +0 -34
- package/dist/util/debug.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/browser-demo/README.md +0 -204
- package/examples/browser-demo/index.html +0 -466
- package/examples/browser-wasm-integration.md +0 -411
- package/examples/ipc-demo/README.md +0 -127
- package/examples/local-first-usage.ts +0 -138
- package/examples/native-ipc-integration.md +0 -526
- package/examples/tauri-demo/README.md +0 -240
- package/examples/tauri-integration.md +0 -260
- 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 -569
- package/legacy/index.ts +0 -31
- package/legacy/local-first/unified-api.ts +0 -449
- 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 -827
- package/legacy/node-wrapper.ts +0 -329
- package/legacy/plugins/README.md +0 -181
- package/legacy/plugins/example-embedding-plugin.ts +0 -56
- package/legacy/plugins/plugin-system.ts +0 -315
- 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/local-first-api.test.ts +0 -65
- package/legacy/tests/unit/plugin-system.test.ts +0 -388
- 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 -27
- 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/scripts/validate-npm-publish.js +0 -228
- package/web/README.md +0 -27
- package/web/svelte/package.json +0 -31
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { QueryResult } from "./types/node-types";
|
|
2
|
-
|
|
3
|
-
export function isPlainObject(
|
|
4
|
-
value: unknown,
|
|
5
|
-
): value is Record<string, unknown> {
|
|
6
|
-
if (value === null || typeof value !== "object") {
|
|
7
|
-
return false;
|
|
8
|
-
}
|
|
9
|
-
const proto = Object.getPrototypeOf(value);
|
|
10
|
-
return proto === Object.prototype || proto === null;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function normalizeParameterInput(args: unknown[]): unknown[] {
|
|
14
|
-
if (args.length === 0) {
|
|
15
|
-
return [];
|
|
16
|
-
}
|
|
17
|
-
if (args.length === 1) {
|
|
18
|
-
const first = args[0];
|
|
19
|
-
if (Array.isArray(first)) {
|
|
20
|
-
return first;
|
|
21
|
-
}
|
|
22
|
-
if (isPlainObject(first)) {
|
|
23
|
-
return [first];
|
|
24
|
-
}
|
|
25
|
-
return [first];
|
|
26
|
-
}
|
|
27
|
-
return args;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function expandDotNotation(
|
|
31
|
-
row: Record<string, unknown>,
|
|
32
|
-
): Record<string, unknown> {
|
|
33
|
-
const result: Record<string, unknown> = {};
|
|
34
|
-
for (const [key, value] of Object.entries(row)) {
|
|
35
|
-
const parts = key.split(".");
|
|
36
|
-
let cursor: Record<string, unknown> = result;
|
|
37
|
-
for (let index = 0; index < parts.length; index++) {
|
|
38
|
-
const part = parts[index];
|
|
39
|
-
if (index === parts.length - 1) {
|
|
40
|
-
cursor[part] = value;
|
|
41
|
-
} else {
|
|
42
|
-
const next = cursor[part];
|
|
43
|
-
if (!isPlainObject(next)) {
|
|
44
|
-
cursor[part] = {};
|
|
45
|
-
}
|
|
46
|
-
cursor = cursor[part] as Record<string, unknown>;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return result;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function shapeRow(
|
|
54
|
-
row: unknown,
|
|
55
|
-
columns: string[] | undefined,
|
|
56
|
-
mode: { raw: boolean; pluck: boolean; expand: boolean },
|
|
57
|
-
): unknown {
|
|
58
|
-
if (mode.raw) {
|
|
59
|
-
return row;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
let normalized: unknown;
|
|
63
|
-
|
|
64
|
-
if (Array.isArray(row)) {
|
|
65
|
-
if (columns && columns.length > 0) {
|
|
66
|
-
const mapped: Record<string, unknown> = {};
|
|
67
|
-
columns.forEach((column, index) => {
|
|
68
|
-
mapped[column] = row[index];
|
|
69
|
-
});
|
|
70
|
-
normalized = mapped;
|
|
71
|
-
} else {
|
|
72
|
-
normalized = [...row];
|
|
73
|
-
}
|
|
74
|
-
} else if (isPlainObject(row)) {
|
|
75
|
-
normalized = { ...(row as Record<string, unknown>) };
|
|
76
|
-
} else {
|
|
77
|
-
normalized = row;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (mode.pluck) {
|
|
81
|
-
if (Array.isArray(row)) {
|
|
82
|
-
return row[0];
|
|
83
|
-
}
|
|
84
|
-
if (isPlainObject(row)) {
|
|
85
|
-
const keys = Object.keys(row as Record<string, unknown>);
|
|
86
|
-
return keys.length > 0
|
|
87
|
-
? (row as Record<string, unknown>)[keys[0]]
|
|
88
|
-
: undefined;
|
|
89
|
-
}
|
|
90
|
-
if (columns && columns.length > 0 && isPlainObject(normalized)) {
|
|
91
|
-
return (normalized as Record<string, unknown>)[columns[0]];
|
|
92
|
-
}
|
|
93
|
-
return normalized;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (mode.expand && isPlainObject(normalized)) {
|
|
97
|
-
return expandDotNotation(normalized as Record<string, unknown>);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return normalized;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function normalizeQueryResult(raw: unknown): QueryResult {
|
|
104
|
-
if (
|
|
105
|
-
raw && typeof raw === "object" && "rows" in (raw as Record<string, unknown>)
|
|
106
|
-
) {
|
|
107
|
-
const result = raw as Partial<QueryResult> & Record<string, unknown>;
|
|
108
|
-
const columnsValue = Array.isArray(result.columns) ? result.columns : [];
|
|
109
|
-
const rowsValue = Array.isArray(result.rows) ? result.rows : [];
|
|
110
|
-
const changesValue = typeof result.changes === "number"
|
|
111
|
-
? result.changes
|
|
112
|
-
: 0;
|
|
113
|
-
const lastInsertRowIdValue = typeof result.lastInsertRowId === "number"
|
|
114
|
-
? result.lastInsertRowId
|
|
115
|
-
: typeof (result as Record<string, unknown>).lastInsertRowid === "number"
|
|
116
|
-
? Number((result as Record<string, unknown>).lastInsertRowid)
|
|
117
|
-
: 0;
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
rows: rowsValue,
|
|
121
|
-
columns: columnsValue,
|
|
122
|
-
changes: changesValue,
|
|
123
|
-
lastInsertRowId: lastInsertRowIdValue,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (Array.isArray(raw)) {
|
|
128
|
-
return {
|
|
129
|
-
rows: raw,
|
|
130
|
-
columns: [],
|
|
131
|
-
changes: 0,
|
|
132
|
-
lastInsertRowId: 0,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (raw === undefined || raw === null) {
|
|
137
|
-
return { rows: [], columns: [], changes: 0, lastInsertRowId: 0 };
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
rows: [raw],
|
|
142
|
-
columns: [],
|
|
143
|
-
changes: 0,
|
|
144
|
-
lastInsertRowId: 0,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export function splitSqlStatements(sql: string): string[] {
|
|
149
|
-
return sql
|
|
150
|
-
.split(/;\s*(?=(?:[^"']|"[^"]*"|'[^']*')*$)/)
|
|
151
|
-
.map((statement) => statement.trim())
|
|
152
|
-
.filter((statement) => statement.length > 0);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export function sanitizeDataDirName(name: string): string {
|
|
156
|
-
return name.replace(/[\s\\/:]+/g, "_").replace(/_+/g, "_");
|
|
157
|
-
}
|
package/legacy/better-sqlite3.ts
DELETED
package/legacy/cli.ts
DELETED
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* CLI wrapper for PluresDB in Node.js environment
|
|
5
|
-
* This allows VSCode extensions to use pluresdb as a regular npm package
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { PluresNode } from "./node-wrapper";
|
|
9
|
-
import * as path from "path";
|
|
10
|
-
import * as fs from "fs";
|
|
11
|
-
import process from "node:process";
|
|
12
|
-
|
|
13
|
-
// Parse command line arguments
|
|
14
|
-
const args = process.argv.slice(2);
|
|
15
|
-
const command = args[0];
|
|
16
|
-
|
|
17
|
-
if (!command) {
|
|
18
|
-
console.log(`
|
|
19
|
-
PluresDB - P2P Graph Database with SQLite Compatibility
|
|
20
|
-
|
|
21
|
-
Usage: pluresdb <command> [options]
|
|
22
|
-
|
|
23
|
-
Commands:
|
|
24
|
-
serve Start the PluresDB server
|
|
25
|
-
put <key> <value> Store a key-value pair
|
|
26
|
-
get <key> Retrieve a value by key
|
|
27
|
-
delete <key> Delete a key-value pair
|
|
28
|
-
query <sql> Execute SQL query
|
|
29
|
-
vsearch <query> Perform vector search
|
|
30
|
-
list [prefix] List all keys (optionally with prefix)
|
|
31
|
-
config Show configuration
|
|
32
|
-
config set <key> <value> Set configuration value
|
|
33
|
-
--help Show this help message
|
|
34
|
-
--version Show version
|
|
35
|
-
|
|
36
|
-
Examples:
|
|
37
|
-
pluresdb serve --port 8080
|
|
38
|
-
pluresdb put "user:123" '{"name": "John"}'
|
|
39
|
-
pluresdb get "user:123"
|
|
40
|
-
pluresdb query "SELECT * FROM users"
|
|
41
|
-
pluresdb vsearch "machine learning"
|
|
42
|
-
`);
|
|
43
|
-
process.exit(0);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (command === "--version") {
|
|
47
|
-
const packageJson = JSON.parse(
|
|
48
|
-
fs.readFileSync(path.join(__dirname, "../package.json"), "utf8"),
|
|
49
|
-
);
|
|
50
|
-
console.log(packageJson.version);
|
|
51
|
-
process.exit(0);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (command === "--help") {
|
|
55
|
-
console.log(`
|
|
56
|
-
PluresDB - P2P Graph Database with SQLite Compatibility
|
|
57
|
-
|
|
58
|
-
Usage: pluresdb <command> [options]
|
|
59
|
-
|
|
60
|
-
Commands:
|
|
61
|
-
serve Start the PluresDB server
|
|
62
|
-
put <key> <value> Store a key-value pair
|
|
63
|
-
get <key> Retrieve a value by key
|
|
64
|
-
delete <key> Delete a key-value pair
|
|
65
|
-
query <sql> Execute SQL query
|
|
66
|
-
vsearch <query> Perform vector search
|
|
67
|
-
list [prefix] List all keys (optionally with prefix)
|
|
68
|
-
config Show configuration
|
|
69
|
-
config set <key> <value> Set configuration value
|
|
70
|
-
--help Show this help message
|
|
71
|
-
--version Show version
|
|
72
|
-
|
|
73
|
-
Examples:
|
|
74
|
-
pluresdb serve --port 8080
|
|
75
|
-
pluresdb put "user:123" '{"name": "John"}'
|
|
76
|
-
pluresdb get "user:123"
|
|
77
|
-
pluresdb query "SELECT * FROM users"
|
|
78
|
-
pluresdb vsearch "machine learning"
|
|
79
|
-
`);
|
|
80
|
-
process.exit(0);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Parse options
|
|
84
|
-
const options: any = {};
|
|
85
|
-
let i = 1;
|
|
86
|
-
while (i < args.length) {
|
|
87
|
-
const arg = args[i];
|
|
88
|
-
if (arg.startsWith("--")) {
|
|
89
|
-
const key = arg.substring(2);
|
|
90
|
-
const value = args[i + 1];
|
|
91
|
-
if (value && !value.startsWith("--")) {
|
|
92
|
-
options[key] = value;
|
|
93
|
-
i += 2;
|
|
94
|
-
} else {
|
|
95
|
-
options[key] = true;
|
|
96
|
-
i += 1;
|
|
97
|
-
}
|
|
98
|
-
} else {
|
|
99
|
-
i += 1;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async function main() {
|
|
104
|
-
try {
|
|
105
|
-
if (command === "serve") {
|
|
106
|
-
const config = {
|
|
107
|
-
port: options.port ? parseInt(options.port) : 34567,
|
|
108
|
-
host: options.host || "localhost",
|
|
109
|
-
dataDir: options["data-dir"] ||
|
|
110
|
-
path.join(require("os").homedir(), ".pluresdb"),
|
|
111
|
-
webPort: options["web-port"] ? parseInt(options["web-port"]) : 34568,
|
|
112
|
-
logLevel: options["log-level"] || "info",
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
const plures = new PluresNode({ config, autoStart: true });
|
|
116
|
-
|
|
117
|
-
console.log(`🚀 PluresDB server starting...`);
|
|
118
|
-
console.log(`📊 API: http://${config.host}:${config.port}`);
|
|
119
|
-
console.log(`🌐 Web UI: http://${config.host}:${config.webPort}`);
|
|
120
|
-
console.log(`📁 Data: ${config.dataDir}`);
|
|
121
|
-
console.log(`\nPress Ctrl+C to stop the server`);
|
|
122
|
-
|
|
123
|
-
// Handle graceful shutdown
|
|
124
|
-
process.on("SIGINT", async () => {
|
|
125
|
-
console.log("\n🛑 Shutting down PluresDB...");
|
|
126
|
-
await plures.stop();
|
|
127
|
-
process.exit(0);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// Keep the process alive
|
|
131
|
-
await new Promise(() => {});
|
|
132
|
-
} else {
|
|
133
|
-
// For other commands, we need to start the server first
|
|
134
|
-
const plures = new PluresNode({ autoStart: true });
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
switch (command) {
|
|
138
|
-
case "put":
|
|
139
|
-
if (args.length < 3) {
|
|
140
|
-
console.error("Error: put command requires key and value");
|
|
141
|
-
process.exit(1);
|
|
142
|
-
}
|
|
143
|
-
const key = args[1];
|
|
144
|
-
const value = JSON.parse(args[2]);
|
|
145
|
-
await plures.put(key, value);
|
|
146
|
-
console.log(`✅ Stored: ${key}`);
|
|
147
|
-
break;
|
|
148
|
-
|
|
149
|
-
case "get":
|
|
150
|
-
if (args.length < 2) {
|
|
151
|
-
console.error("Error: get command requires key");
|
|
152
|
-
process.exit(1);
|
|
153
|
-
}
|
|
154
|
-
const getKey = args[1];
|
|
155
|
-
const result = await plures.get(getKey);
|
|
156
|
-
if (result === null) {
|
|
157
|
-
console.log("Key not found");
|
|
158
|
-
} else {
|
|
159
|
-
console.log(JSON.stringify(result, null, 2));
|
|
160
|
-
}
|
|
161
|
-
break;
|
|
162
|
-
|
|
163
|
-
case "delete":
|
|
164
|
-
if (args.length < 2) {
|
|
165
|
-
console.error("Error: delete command requires key");
|
|
166
|
-
process.exit(1);
|
|
167
|
-
}
|
|
168
|
-
const deleteKey = args[1];
|
|
169
|
-
await plures.delete(deleteKey);
|
|
170
|
-
console.log(`✅ Deleted: ${deleteKey}`);
|
|
171
|
-
break;
|
|
172
|
-
|
|
173
|
-
case "query":
|
|
174
|
-
if (args.length < 2) {
|
|
175
|
-
console.error("Error: query command requires SQL");
|
|
176
|
-
process.exit(1);
|
|
177
|
-
}
|
|
178
|
-
const sql = args[1];
|
|
179
|
-
const queryResult = await plures.query(sql);
|
|
180
|
-
console.log(JSON.stringify(queryResult, null, 2));
|
|
181
|
-
break;
|
|
182
|
-
|
|
183
|
-
case "vsearch":
|
|
184
|
-
if (args.length < 2) {
|
|
185
|
-
console.error("Error: vsearch command requires query");
|
|
186
|
-
process.exit(1);
|
|
187
|
-
}
|
|
188
|
-
const searchQuery = args[1];
|
|
189
|
-
const limit = options.limit ? parseInt(options.limit) : 10;
|
|
190
|
-
const searchResult = await plures.vectorSearch(searchQuery, limit);
|
|
191
|
-
console.log(JSON.stringify(searchResult, null, 2));
|
|
192
|
-
break;
|
|
193
|
-
|
|
194
|
-
case "list":
|
|
195
|
-
const prefix = args[1];
|
|
196
|
-
const listResult = await plures.list(prefix);
|
|
197
|
-
console.log(JSON.stringify(listResult, null, 2));
|
|
198
|
-
break;
|
|
199
|
-
|
|
200
|
-
case "config":
|
|
201
|
-
if (args[1] === "set") {
|
|
202
|
-
if (args.length < 4) {
|
|
203
|
-
console.error("Error: config set requires key and value");
|
|
204
|
-
process.exit(1);
|
|
205
|
-
}
|
|
206
|
-
const configKey = args[2];
|
|
207
|
-
const configValue = args[3];
|
|
208
|
-
await plures.setConfig({ [configKey]: configValue });
|
|
209
|
-
console.log(`✅ Set config: ${configKey} = ${configValue}`);
|
|
210
|
-
} else {
|
|
211
|
-
const config = await plures.getConfig();
|
|
212
|
-
console.log(JSON.stringify(config, null, 2));
|
|
213
|
-
}
|
|
214
|
-
break;
|
|
215
|
-
|
|
216
|
-
default:
|
|
217
|
-
console.error(`Unknown command: ${command}`);
|
|
218
|
-
console.log('Run "pluresdb --help" for usage information');
|
|
219
|
-
process.exit(1);
|
|
220
|
-
}
|
|
221
|
-
} finally {
|
|
222
|
-
await plures.stop();
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
} catch (error) {
|
|
226
|
-
console.error(
|
|
227
|
-
"Error:",
|
|
228
|
-
error instanceof Error ? error.message : String(error),
|
|
229
|
-
);
|
|
230
|
-
process.exit(1);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Run the main function
|
|
235
|
-
main().catch((error) => {
|
|
236
|
-
console.error(
|
|
237
|
-
"Fatal error:",
|
|
238
|
-
error instanceof Error ? error.message : String(error),
|
|
239
|
-
);
|
|
240
|
-
process.exit(1);
|
|
241
|
-
});
|
package/legacy/config.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
export interface AppConfig {
|
|
2
|
-
kvPath?: string;
|
|
3
|
-
port?: number;
|
|
4
|
-
peers?: string[];
|
|
5
|
-
apiPortOffset?: number; // default 1
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export async function loadConfig(): Promise<AppConfig> {
|
|
9
|
-
const path = getConfigPath();
|
|
10
|
-
try {
|
|
11
|
-
const text = await Deno.readTextFile(path);
|
|
12
|
-
const cfg = JSON.parse(text) as AppConfig;
|
|
13
|
-
return cfg;
|
|
14
|
-
} catch {
|
|
15
|
-
return {};
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export async function saveConfig(cfg: AppConfig): Promise<void> {
|
|
20
|
-
const path = getConfigPath();
|
|
21
|
-
await ensureDirForFile(path);
|
|
22
|
-
await Deno.writeTextFile(path, JSON.stringify(cfg, null, 2));
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function getConfigPath(): string {
|
|
26
|
-
const appName = "PluresDB";
|
|
27
|
-
try {
|
|
28
|
-
const os = Deno.build.os;
|
|
29
|
-
if (os === "windows") {
|
|
30
|
-
const appData = Deno.env.get("APPDATA") || Deno.env.get("LOCALAPPDATA") ||
|
|
31
|
-
".";
|
|
32
|
-
return `${appData}\\${appName}\\config.json`;
|
|
33
|
-
}
|
|
34
|
-
const home = Deno.env.get("HOME") || ".";
|
|
35
|
-
return `${home}/.${appName.toLowerCase()}/config.json`;
|
|
36
|
-
} catch {
|
|
37
|
-
return `./config.json`;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async function ensureDirForFile(filePath: string): Promise<void> {
|
|
42
|
-
const sep = filePath.includes("\\") ? "\\" : "/";
|
|
43
|
-
const dir = filePath.split(sep).slice(0, -1).join(sep);
|
|
44
|
-
if (!dir) return;
|
|
45
|
-
try {
|
|
46
|
-
await Deno.mkdir(dir, { recursive: true });
|
|
47
|
-
} catch {
|
|
48
|
-
/* ignore */
|
|
49
|
-
}
|
|
50
|
-
}
|
package/legacy/core/crdt.ts
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import type { NodeRecord, VectorClock } from "../types/index.ts";
|
|
2
|
-
|
|
3
|
-
export function mergeVectorClocks(a: VectorClock, b: VectorClock): VectorClock {
|
|
4
|
-
const merged: VectorClock = {};
|
|
5
|
-
const keys = new Set([...Object.keys(a ?? {}), ...Object.keys(b ?? {})]);
|
|
6
|
-
for (const key of keys) {
|
|
7
|
-
merged[key] = Math.max(a?.[key] ?? 0, b?.[key] ?? 0);
|
|
8
|
-
}
|
|
9
|
-
return merged;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function isPlainObject(val: unknown): val is Record<string, unknown> {
|
|
13
|
-
return typeof val === "object" && val !== null && !Array.isArray(val);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function deepMergeWithDeletes(
|
|
17
|
-
base: Record<string, unknown>,
|
|
18
|
-
incoming: Record<string, unknown>,
|
|
19
|
-
baseState: Record<string, number> | undefined,
|
|
20
|
-
incomingState: Record<string, number> | undefined,
|
|
21
|
-
now: number,
|
|
22
|
-
): { data: Record<string, unknown>; state: Record<string, number> } {
|
|
23
|
-
const out: Record<string, unknown> = { ...base };
|
|
24
|
-
const outState: Record<string, number> = { ...(baseState ?? {}) };
|
|
25
|
-
for (const [key, incVal] of Object.entries(incoming)) {
|
|
26
|
-
const baseVal = out[key];
|
|
27
|
-
const incTs = (incomingState ?? {})[key] ?? now; // default to now if missing
|
|
28
|
-
const baseTs = (baseState ?? {})[key] ?? 0;
|
|
29
|
-
if (incTs < baseTs) continue; // base wins
|
|
30
|
-
|
|
31
|
-
if (incVal === null) {
|
|
32
|
-
delete out[key];
|
|
33
|
-
outState[key] = incTs;
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
if (isPlainObject(baseVal) && isPlainObject(incVal)) {
|
|
37
|
-
const merged = deepMergeWithDeletes(
|
|
38
|
-
baseVal as Record<string, unknown>,
|
|
39
|
-
incVal as Record<string, unknown>,
|
|
40
|
-
baseState,
|
|
41
|
-
incomingState,
|
|
42
|
-
now,
|
|
43
|
-
);
|
|
44
|
-
out[key] = merged.data;
|
|
45
|
-
outState[key] = incTs;
|
|
46
|
-
} else {
|
|
47
|
-
out[key] = incVal as unknown;
|
|
48
|
-
outState[key] = incTs;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return { data: out, state: outState };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function mergeNodes(
|
|
55
|
-
local: NodeRecord | null,
|
|
56
|
-
incoming: NodeRecord,
|
|
57
|
-
): NodeRecord {
|
|
58
|
-
if (!local) return incoming;
|
|
59
|
-
if (local.id !== incoming.id) {
|
|
60
|
-
throw new Error("mergeNodes called with mismatched ids");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (incoming.timestamp > local.timestamp) {
|
|
64
|
-
const merged = deepMergeWithDeletes(
|
|
65
|
-
local.data,
|
|
66
|
-
incoming.data,
|
|
67
|
-
local.state,
|
|
68
|
-
incoming.state,
|
|
69
|
-
incoming.timestamp,
|
|
70
|
-
);
|
|
71
|
-
return {
|
|
72
|
-
id: local.id,
|
|
73
|
-
data: merged.data,
|
|
74
|
-
vector: incoming.vector ?? local.vector,
|
|
75
|
-
type: incoming.type ?? local.type,
|
|
76
|
-
timestamp: incoming.timestamp,
|
|
77
|
-
state: merged.state,
|
|
78
|
-
vectorClock: mergeVectorClocks(local.vectorClock, incoming.vectorClock),
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
if (incoming.timestamp < local.timestamp) {
|
|
82
|
-
return {
|
|
83
|
-
...local,
|
|
84
|
-
vectorClock: mergeVectorClocks(local.vectorClock, incoming.vectorClock),
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Equal timestamps: deterministic field-wise merge with per-field state
|
|
89
|
-
const merged = deepMergeWithDeletes(
|
|
90
|
-
local.data,
|
|
91
|
-
incoming.data,
|
|
92
|
-
local.state,
|
|
93
|
-
incoming.state,
|
|
94
|
-
incoming.timestamp,
|
|
95
|
-
);
|
|
96
|
-
const mergedVector = incoming.vector ?? local.vector;
|
|
97
|
-
const mergedType = incoming.type ?? local.type;
|
|
98
|
-
return {
|
|
99
|
-
id: local.id,
|
|
100
|
-
data: merged.data,
|
|
101
|
-
vector: mergedVector,
|
|
102
|
-
type: mergedType,
|
|
103
|
-
timestamp: incoming.timestamp, // ties keep timestamp
|
|
104
|
-
state: merged.state,
|
|
105
|
-
vectorClock: mergeVectorClocks(local.vectorClock, incoming.vectorClock),
|
|
106
|
-
};
|
|
107
|
-
}
|