pluresdb 1.0.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -5
- package/dist/.tsbuildinfo +1 -1
- package/dist/better-sqlite3-shared.d.ts +12 -0
- package/dist/better-sqlite3-shared.d.ts.map +1 -0
- package/dist/better-sqlite3-shared.js +143 -0
- package/dist/better-sqlite3-shared.js.map +1 -0
- package/dist/better-sqlite3.d.ts +4 -0
- package/dist/better-sqlite3.d.ts.map +1 -0
- package/dist/better-sqlite3.js +8 -0
- package/dist/better-sqlite3.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +21 -16
- package/dist/cli.js.map +1 -1
- package/dist/node-index.d.ts +98 -2
- package/dist/node-index.d.ts.map +1 -1
- package/dist/node-index.js +312 -6
- package/dist/node-index.js.map +1 -1
- package/dist/node-wrapper.d.ts.map +1 -1
- package/dist/node-wrapper.js +5 -3
- package/dist/node-wrapper.js.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/node-types.d.ts +12 -0
- package/dist/types/node-types.d.ts.map +1 -1
- package/dist/types/node-types.js.map +1 -1
- package/dist/vscode/extension.d.ts.map +1 -1
- package/dist/vscode/extension.js +4 -4
- package/dist/vscode/extension.js.map +1 -1
- package/examples/basic-usage.d.ts +1 -1
- package/examples/vscode-extension-example/src/extension.ts +15 -6
- package/examples/vscode-extension-integration.d.ts +24 -17
- package/examples/vscode-extension-integration.js +140 -106
- package/examples/vscode-extension-integration.ts +1 -1
- package/{src → legacy}/benchmarks/memory-benchmarks.ts +85 -51
- package/{src → legacy}/benchmarks/run-benchmarks.ts +32 -10
- package/legacy/better-sqlite3-shared.ts +157 -0
- package/legacy/better-sqlite3.ts +4 -0
- package/{src → legacy}/cli.ts +14 -4
- package/{src → legacy}/config.ts +2 -1
- package/{src → legacy}/core/crdt.ts +4 -1
- package/{src → legacy}/core/database.ts +57 -22
- package/{src → legacy}/healthcheck.ts +11 -5
- package/{src → legacy}/http/api-server.ts +125 -21
- package/{src → legacy}/index.ts +2 -2
- package/{src → legacy}/logic/rules.ts +3 -1
- package/{src → legacy}/main.ts +11 -4
- package/legacy/node-index.ts +823 -0
- package/{src → legacy}/node-wrapper.ts +18 -9
- package/{src → legacy}/sqlite-compat.ts +63 -16
- package/{src → legacy}/sqlite3-compat.ts +2 -2
- package/{src → legacy}/storage/kv-storage.ts +3 -1
- package/{src → legacy}/tests/core.test.ts +37 -13
- package/{src → legacy}/tests/fixtures/test-data.json +6 -1
- package/{src → legacy}/tests/integration/api-server.test.ts +110 -8
- package/{src → legacy}/tests/integration/mesh-network.test.ts +8 -2
- package/{src → legacy}/tests/logic.test.ts +6 -2
- package/{src → legacy}/tests/performance/load.test.ts +4 -2
- package/{src → legacy}/tests/security/input-validation.test.ts +5 -1
- package/{src → legacy}/tests/unit/core.test.ts +13 -3
- package/{src → legacy}/tests/unit/subscriptions.test.ts +1 -1
- package/{src → legacy}/tests/vscode_extension_test.ts +39 -11
- package/{src → legacy}/types/node-types.ts +14 -0
- package/{src → legacy}/vscode/extension.ts +37 -14
- package/package.json +19 -9
- package/scripts/compiled-crud-verify.ts +3 -1
- package/scripts/dogfood.ts +55 -16
- package/scripts/postinstall.js +4 -3
- package/scripts/release-check.js +190 -0
- package/scripts/run-tests.ts +5 -2
- package/scripts/update-changelog.js +214 -0
- package/web/svelte/package.json +5 -5
- package/src/node-index.ts +0 -385
- /package/{src → legacy}/main.rs +0 -0
- /package/{src → legacy}/network/websocket-server.ts +0 -0
- /package/{src → legacy}/tests/fixtures/performance-data.json +0 -0
- /package/{src → legacy}/tests/unit/vector-search.test.ts +0 -0
- /package/{src → legacy}/types/index.ts +0 -0
- /package/{src → legacy}/util/debug.ts +0 -0
- /package/{src → legacy}/vector/index.ts +0 -0
|
@@ -58,7 +58,10 @@ function createHarness(storageDir: string): TestHarness {
|
|
|
58
58
|
return inputQueue.shift();
|
|
59
59
|
},
|
|
60
60
|
async showTextDocument(doc: unknown) {
|
|
61
|
-
if (
|
|
61
|
+
if (
|
|
62
|
+
typeof doc === "object" && doc && "content" in doc &&
|
|
63
|
+
"language" in doc
|
|
64
|
+
) {
|
|
62
65
|
const record = doc as RecordedDocument;
|
|
63
66
|
docs.push({ content: record.content, language: record.language });
|
|
64
67
|
}
|
|
@@ -72,7 +75,9 @@ function createHarness(storageDir: string): TestHarness {
|
|
|
72
75
|
},
|
|
73
76
|
env: {
|
|
74
77
|
async openExternal(target) {
|
|
75
|
-
shownTargets.push(
|
|
78
|
+
shownTargets.push(
|
|
79
|
+
typeof target === "string" ? target : target.toString(),
|
|
80
|
+
);
|
|
76
81
|
},
|
|
77
82
|
},
|
|
78
83
|
Uri: {
|
|
@@ -107,7 +112,11 @@ async function getFreePort(): Promise<number> {
|
|
|
107
112
|
return port;
|
|
108
113
|
}
|
|
109
114
|
|
|
110
|
-
async function waitFor(
|
|
115
|
+
async function waitFor(
|
|
116
|
+
predicate: () => Promise<boolean>,
|
|
117
|
+
timeout = 10_000,
|
|
118
|
+
interval = 200,
|
|
119
|
+
) {
|
|
111
120
|
const deadline = Date.now() + timeout;
|
|
112
121
|
while (Date.now() < deadline) {
|
|
113
122
|
if (await predicate()) return;
|
|
@@ -126,7 +135,8 @@ async function removeDirWithRetry(target: string) {
|
|
|
126
135
|
await Deno.remove(target, { recursive: true });
|
|
127
136
|
return;
|
|
128
137
|
} catch (error) {
|
|
129
|
-
const retryable = error instanceof Error &&
|
|
138
|
+
const retryable = error instanceof Error &&
|
|
139
|
+
/used by another process/i.test(error.message);
|
|
130
140
|
if (!retryable || i === delays.length - 1) {
|
|
131
141
|
throw error;
|
|
132
142
|
}
|
|
@@ -198,17 +208,28 @@ Deno.test("VSCode integration dogfood workflow", async () => {
|
|
|
198
208
|
if (!schemaDoc) {
|
|
199
209
|
throw new Error("Expected schema document to open");
|
|
200
210
|
}
|
|
201
|
-
const schemaRows = JSON.parse(schemaDoc.content) as Array<
|
|
211
|
+
const schemaRows = JSON.parse(schemaDoc.content) as Array<
|
|
212
|
+
Record<string, unknown>
|
|
213
|
+
>;
|
|
202
214
|
const columnNames = schemaRows.map((row) => String(row.name));
|
|
203
|
-
assert(
|
|
215
|
+
assert(
|
|
216
|
+
columnNames.includes("key"),
|
|
217
|
+
"Settings table should expose key column",
|
|
218
|
+
);
|
|
204
219
|
|
|
205
|
-
harness.queueInputs(
|
|
220
|
+
harness.queueInputs(
|
|
221
|
+
"user:alpha",
|
|
222
|
+
'{"name":"Ada","vector":[0.2,0.1,0.3,0.4],"role":"builder"}',
|
|
223
|
+
);
|
|
206
224
|
const storeCommand = harness.commands.get("pluresdb.storeData");
|
|
207
225
|
if (!storeCommand) {
|
|
208
226
|
throw new Error("storeData command should be registered");
|
|
209
227
|
}
|
|
210
228
|
await storeCommand();
|
|
211
|
-
assertMatch(
|
|
229
|
+
assertMatch(
|
|
230
|
+
harness.messages.at(-1)?.text ?? "",
|
|
231
|
+
/Stored data for key: user:alpha/,
|
|
232
|
+
);
|
|
212
233
|
|
|
213
234
|
harness.queueInputs("user:alpha");
|
|
214
235
|
const retrieveCommand = harness.commands.get("pluresdb.retrieveData");
|
|
@@ -233,8 +254,13 @@ Deno.test("VSCode integration dogfood workflow", async () => {
|
|
|
233
254
|
if (!vectorDoc) {
|
|
234
255
|
throw new Error("Expected vector search document to open");
|
|
235
256
|
}
|
|
236
|
-
const vectorResults = JSON.parse(vectorDoc.content) as Array<
|
|
237
|
-
|
|
257
|
+
const vectorResults = JSON.parse(vectorDoc.content) as Array<
|
|
258
|
+
Record<string, unknown>
|
|
259
|
+
>;
|
|
260
|
+
assert(
|
|
261
|
+
vectorResults.length > 0,
|
|
262
|
+
"Vector search should return at least one result",
|
|
263
|
+
);
|
|
238
264
|
|
|
239
265
|
const settingsRows = await extension.executeSQL(
|
|
240
266
|
"SELECT name FROM pragma_table_info('documents')",
|
|
@@ -246,7 +272,9 @@ Deno.test("VSCode integration dogfood workflow", async () => {
|
|
|
246
272
|
await removeDirWithRetry(storageDir);
|
|
247
273
|
} catch (error) {
|
|
248
274
|
console.warn(
|
|
249
|
-
`⚠️ Failed to remove temp dir: ${
|
|
275
|
+
`⚠️ Failed to remove temp dir: ${
|
|
276
|
+
error instanceof Error ? error.message : String(error)
|
|
277
|
+
}`,
|
|
250
278
|
);
|
|
251
279
|
}
|
|
252
280
|
}
|
|
@@ -23,6 +23,20 @@ export interface QueryResult {
|
|
|
23
23
|
lastInsertRowId: number;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
export interface BetterSQLite3Options extends PluresDBOptions {
|
|
27
|
+
filename?: string;
|
|
28
|
+
memory?: boolean;
|
|
29
|
+
readonly?: boolean;
|
|
30
|
+
fileMustExist?: boolean;
|
|
31
|
+
verbose?: (...args: unknown[]) => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface BetterSQLite3RunResult {
|
|
35
|
+
changes: number;
|
|
36
|
+
lastInsertRowid: number | null;
|
|
37
|
+
columns?: string[];
|
|
38
|
+
}
|
|
39
|
+
|
|
26
40
|
export interface VectorSearchResult {
|
|
27
41
|
id: string;
|
|
28
42
|
content: string;
|
|
@@ -24,7 +24,10 @@ export type VSCodeWindow = {
|
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
export type VSCodeCommands = {
|
|
27
|
-
registerCommand(
|
|
27
|
+
registerCommand(
|
|
28
|
+
command: string,
|
|
29
|
+
callback: (...args: unknown[]) => unknown,
|
|
30
|
+
): DisposableLike;
|
|
28
31
|
};
|
|
29
32
|
|
|
30
33
|
export type VSCodeWorkspace = {
|
|
@@ -77,7 +80,11 @@ export class PluresVSCodeExtension {
|
|
|
77
80
|
private readonly disposables: DisposableLike[] = [];
|
|
78
81
|
private activated = false;
|
|
79
82
|
|
|
80
|
-
constructor(
|
|
83
|
+
constructor(
|
|
84
|
+
vscodeApi: VSCodeAPI,
|
|
85
|
+
context: ExtensionContextLike,
|
|
86
|
+
options: ExtensionOptions = {},
|
|
87
|
+
) {
|
|
81
88
|
this.vscode = vscodeApi;
|
|
82
89
|
this.context = context;
|
|
83
90
|
this.commandPrefix = options.commandPrefix ?? "pluresdb";
|
|
@@ -88,10 +95,10 @@ export class PluresVSCodeExtension {
|
|
|
88
95
|
...options.config,
|
|
89
96
|
};
|
|
90
97
|
|
|
91
|
-
this.plures =
|
|
92
|
-
|
|
93
|
-
this.sqlite =
|
|
94
|
-
|
|
98
|
+
this.plures = options.pluresInstance ??
|
|
99
|
+
new PluresNode({ config: mergedConfig, autoStart: false });
|
|
100
|
+
this.sqlite = options.sqliteInstance ??
|
|
101
|
+
new SQLiteCompatibleAPI({ config: mergedConfig, autoStart: false });
|
|
95
102
|
|
|
96
103
|
this.setupEventHandlers();
|
|
97
104
|
}
|
|
@@ -109,7 +116,9 @@ export class PluresVSCodeExtension {
|
|
|
109
116
|
this.activated = true;
|
|
110
117
|
await this.safeInfo("PluresDB extension activated");
|
|
111
118
|
} catch (error) {
|
|
112
|
-
await this.safeError(
|
|
119
|
+
await this.safeError(
|
|
120
|
+
`Failed to activate PluresDB: ${this.errorMessage(error)}`,
|
|
121
|
+
);
|
|
113
122
|
throw error;
|
|
114
123
|
}
|
|
115
124
|
}
|
|
@@ -140,7 +149,12 @@ export class PluresVSCodeExtension {
|
|
|
140
149
|
return this.sqlite.getValue(`settings:${key}`);
|
|
141
150
|
}
|
|
142
151
|
|
|
143
|
-
async storeDocument(
|
|
152
|
+
async storeDocument(
|
|
153
|
+
id: string,
|
|
154
|
+
content: string,
|
|
155
|
+
language: string,
|
|
156
|
+
filePath: string,
|
|
157
|
+
) {
|
|
144
158
|
return this.sqlite.put(`documents:${id}`, {
|
|
145
159
|
content,
|
|
146
160
|
language,
|
|
@@ -187,8 +201,9 @@ export class PluresVSCodeExtension {
|
|
|
187
201
|
|
|
188
202
|
private registerCommands() {
|
|
189
203
|
const register = (name: string, factory: CommandFactory) => {
|
|
190
|
-
const disposable = this.vscode.commands.registerCommand(
|
|
191
|
-
|
|
204
|
+
const disposable = this.vscode.commands.registerCommand(
|
|
205
|
+
`${this.commandPrefix}.${name}`,
|
|
206
|
+
() => factory(),
|
|
192
207
|
);
|
|
193
208
|
this.context.subscriptions.push(disposable);
|
|
194
209
|
this.disposables.push(disposable);
|
|
@@ -235,7 +250,9 @@ export class PluresVSCodeExtension {
|
|
|
235
250
|
});
|
|
236
251
|
await this.vscode.window.showTextDocument(doc);
|
|
237
252
|
} catch (error) {
|
|
238
|
-
await this.safeError(
|
|
253
|
+
await this.safeError(
|
|
254
|
+
`Vector search failed: ${this.errorMessage(error)}`,
|
|
255
|
+
);
|
|
239
256
|
}
|
|
240
257
|
});
|
|
241
258
|
|
|
@@ -259,7 +276,9 @@ export class PluresVSCodeExtension {
|
|
|
259
276
|
await this.sqlite.put(key, value);
|
|
260
277
|
await this.safeInfo(`Stored data for key: ${key}`);
|
|
261
278
|
} catch (error) {
|
|
262
|
-
await this.safeError(
|
|
279
|
+
await this.safeError(
|
|
280
|
+
`Failed to store data: ${this.errorMessage(error)}`,
|
|
281
|
+
);
|
|
263
282
|
}
|
|
264
283
|
});
|
|
265
284
|
|
|
@@ -283,7 +302,9 @@ export class PluresVSCodeExtension {
|
|
|
283
302
|
await this.safeInfo("Key not found");
|
|
284
303
|
}
|
|
285
304
|
} catch (error) {
|
|
286
|
-
await this.safeError(
|
|
305
|
+
await this.safeError(
|
|
306
|
+
`Failed to retrieve data: ${this.errorMessage(error)}`,
|
|
307
|
+
);
|
|
287
308
|
}
|
|
288
309
|
});
|
|
289
310
|
}
|
|
@@ -316,7 +337,9 @@ export class PluresVSCodeExtension {
|
|
|
316
337
|
try {
|
|
317
338
|
await this.sqlite.exec(sql);
|
|
318
339
|
} catch (error) {
|
|
319
|
-
await this.safeError(
|
|
340
|
+
await this.safeError(
|
|
341
|
+
`Failed to initialize database: ${this.errorMessage(error)}`,
|
|
342
|
+
);
|
|
320
343
|
}
|
|
321
344
|
}
|
|
322
345
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pluresdb",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "P2P Graph Database with SQLite Compatibility - Local-first, offline-first database for modern applications",
|
|
5
5
|
"main": "dist/node-index.js",
|
|
6
6
|
"types": "dist/node-index.d.ts",
|
|
@@ -15,6 +15,11 @@
|
|
|
15
15
|
"require": "./dist/node-index.js",
|
|
16
16
|
"default": "./dist/node-index.js"
|
|
17
17
|
},
|
|
18
|
+
"./better-sqlite3": {
|
|
19
|
+
"types": "./dist/better-sqlite3.d.ts",
|
|
20
|
+
"require": "./dist/better-sqlite3.js",
|
|
21
|
+
"default": "./dist/better-sqlite3.js"
|
|
22
|
+
},
|
|
18
23
|
"./vscode": {
|
|
19
24
|
"types": "./dist/vscode/extension.d.ts",
|
|
20
25
|
"require": "./dist/vscode/extension.js",
|
|
@@ -42,10 +47,15 @@
|
|
|
42
47
|
"dev": "deno run -A --unstable-kv --watch src/main.ts serve --port 34567",
|
|
43
48
|
"start": "node dist/cli.js serve",
|
|
44
49
|
"test": "deno test -A --unstable-kv",
|
|
50
|
+
"lint": "eslint . --ext .js,.ts,.tsx",
|
|
51
|
+
"fmt:check": "prettier --check .",
|
|
52
|
+
"fmt": "prettier --write .",
|
|
45
53
|
"verify": "npm run build:lib && npm test",
|
|
46
54
|
"prepare": "npm run build:lib",
|
|
47
55
|
"prepublishOnly": "npm run verify && npm run build:web",
|
|
48
|
-
"postinstall": "node scripts/postinstall.js"
|
|
56
|
+
"postinstall": "node scripts/postinstall.js",
|
|
57
|
+
"release-check": "node scripts/release-check.js",
|
|
58
|
+
"update-changelog": "node scripts/update-changelog.js"
|
|
49
59
|
},
|
|
50
60
|
"keywords": [
|
|
51
61
|
"database",
|
|
@@ -81,7 +91,7 @@
|
|
|
81
91
|
"files": [
|
|
82
92
|
"dist/",
|
|
83
93
|
"web/svelte/dist/",
|
|
84
|
-
"
|
|
94
|
+
"legacy/",
|
|
85
95
|
"examples/",
|
|
86
96
|
"scripts/",
|
|
87
97
|
"README.md",
|
|
@@ -90,18 +100,18 @@
|
|
|
90
100
|
],
|
|
91
101
|
"dependencies": {
|
|
92
102
|
"cors": "^2.8.5",
|
|
93
|
-
"express": "^
|
|
103
|
+
"express": "^5.1.0",
|
|
94
104
|
"ws": "^8.18.3"
|
|
95
105
|
},
|
|
96
106
|
"devDependencies": {
|
|
97
107
|
"@types/cors": "^2.8.19",
|
|
98
|
-
"@types/express": "^
|
|
99
|
-
"@types/node": "^
|
|
108
|
+
"@types/express": "^5.0.0",
|
|
109
|
+
"@types/node": "^22.10.0",
|
|
100
110
|
"@types/vscode": "^1.104.0",
|
|
101
111
|
"@types/ws": "^8.18.1",
|
|
102
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
103
|
-
"@typescript-eslint/parser": "^8.
|
|
104
|
-
"eslint": "^9.
|
|
112
|
+
"@typescript-eslint/eslint-plugin": "^8.46.4",
|
|
113
|
+
"@typescript-eslint/parser": "^8.46.4",
|
|
114
|
+
"eslint": "^9.39.1",
|
|
105
115
|
"eslint-config-prettier": "^10.1.8",
|
|
106
116
|
"eslint-plugin-import": "^2.32.0",
|
|
107
117
|
"prettier": "^3.6.2",
|
|
@@ -16,7 +16,9 @@ clientB.connect(serverUrl);
|
|
|
16
16
|
|
|
17
17
|
const id = `bin:crud:${crypto.randomUUID()}`;
|
|
18
18
|
|
|
19
|
-
const receivedOnB = new Promise<void>((resolve) =>
|
|
19
|
+
const receivedOnB = new Promise<void>((resolve) =>
|
|
20
|
+
clientB.on(id, (n) => n && resolve())
|
|
21
|
+
);
|
|
20
22
|
|
|
21
23
|
await clientA.put(id, { text: "compiled works" } as Record<string, unknown>);
|
|
22
24
|
|
package/scripts/dogfood.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env -S deno run -A --unstable-kv
|
|
2
2
|
|
|
3
|
-
import { GunDB } from "../
|
|
4
|
-
import { startApiServer } from "../
|
|
3
|
+
import { GunDB } from "../legacy/core/database.ts";
|
|
4
|
+
import { startApiServer } from "../legacy/http/api-server.ts";
|
|
5
5
|
|
|
6
6
|
declare const Deno: any;
|
|
7
7
|
|
|
@@ -100,7 +100,9 @@ async function main() {
|
|
|
100
100
|
assert(putRes.ok, `API put failed (${putRes.status})`);
|
|
101
101
|
record("API put", true);
|
|
102
102
|
|
|
103
|
-
const getRes = await fetch(
|
|
103
|
+
const getRes = await fetch(
|
|
104
|
+
`${apiUrl}/api/get?id=${encodeURIComponent(nodeId)}`,
|
|
105
|
+
);
|
|
104
106
|
assert(getRes.ok, "API get failed");
|
|
105
107
|
const getJson = await getRes.json();
|
|
106
108
|
assert(getJson.text === initialPayload.text, "Unexpected API get payload");
|
|
@@ -120,7 +122,10 @@ async function main() {
|
|
|
120
122
|
);
|
|
121
123
|
assert(searchRes.ok, "API search failed");
|
|
122
124
|
const searchJson = await searchRes.json();
|
|
123
|
-
assert(
|
|
125
|
+
assert(
|
|
126
|
+
Array.isArray(searchJson) && searchJson.length > 0,
|
|
127
|
+
"Vector search returned no results",
|
|
128
|
+
);
|
|
124
129
|
record("API vector search", true);
|
|
125
130
|
|
|
126
131
|
const updatePayload = {
|
|
@@ -135,17 +140,27 @@ async function main() {
|
|
|
135
140
|
assert(putUpdate.ok, "API put update failed");
|
|
136
141
|
record("API update", true);
|
|
137
142
|
|
|
138
|
-
const historyRes = await fetch(
|
|
143
|
+
const historyRes = await fetch(
|
|
144
|
+
`${apiUrl}/api/history?id=${encodeURIComponent(nodeId)}`,
|
|
145
|
+
);
|
|
139
146
|
assert(historyRes.ok, "API history failed");
|
|
140
147
|
const historyJson = await historyRes.json();
|
|
141
|
-
assert(
|
|
148
|
+
assert(
|
|
149
|
+
Array.isArray(historyJson) && historyJson.length >= 2,
|
|
150
|
+
"API history missing versions",
|
|
151
|
+
);
|
|
142
152
|
record("API history", true, `${historyJson.length} versions`);
|
|
143
153
|
|
|
144
|
-
const restoreTimestamp =
|
|
145
|
-
historyJson
|
|
146
|
-
assert(
|
|
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
|
+
);
|
|
147
160
|
const restoreRes = await fetch(
|
|
148
|
-
`${apiUrl}/api/restore?id=${
|
|
161
|
+
`${apiUrl}/api/restore?id=${
|
|
162
|
+
encodeURIComponent(nodeId)
|
|
163
|
+
}×tamp=${restoreTimestamp}`,
|
|
149
164
|
);
|
|
150
165
|
assert(restoreRes.ok, "API restore failed");
|
|
151
166
|
record("API restore", true);
|
|
@@ -153,7 +168,10 @@ async function main() {
|
|
|
153
168
|
const restored = await (
|
|
154
169
|
await fetch(`${apiUrl}/api/get?id=${encodeURIComponent(nodeId)}`)
|
|
155
170
|
).json();
|
|
156
|
-
assert(
|
|
171
|
+
assert(
|
|
172
|
+
restored.text === initialPayload.text,
|
|
173
|
+
"Restore did not revert payload",
|
|
174
|
+
);
|
|
157
175
|
record("API post-restore verification", true);
|
|
158
176
|
|
|
159
177
|
const instancesRes = await fetch(
|
|
@@ -162,7 +180,8 @@ async function main() {
|
|
|
162
180
|
assert(instancesRes.ok, "API instances failed");
|
|
163
181
|
const instancesJson = await instancesRes.json();
|
|
164
182
|
assert(
|
|
165
|
-
Array.isArray(instancesJson) &&
|
|
183
|
+
Array.isArray(instancesJson) &&
|
|
184
|
+
instancesJson.some((n: any) => n.id === nodeId),
|
|
166
185
|
"Instances endpoint missing node",
|
|
167
186
|
);
|
|
168
187
|
record("API type instances", true);
|
|
@@ -192,10 +211,19 @@ async function main() {
|
|
|
192
211
|
const cliList = await runCli(["list", "--kv", kvPath]);
|
|
193
212
|
assert(cliList.code === 0, `CLI list failed: ${cliList.stderr}`);
|
|
194
213
|
const cliListJson = JSON.parse(cliList.stdout.trim() || "[]");
|
|
195
|
-
assert(
|
|
214
|
+
assert(
|
|
215
|
+
Array.isArray(cliListJson) && cliListJson.length >= 2,
|
|
216
|
+
"CLI list missing entries",
|
|
217
|
+
);
|
|
196
218
|
record("CLI list", true);
|
|
197
219
|
|
|
198
|
-
const cliSearch = await runCli([
|
|
220
|
+
const cliSearch = await runCli([
|
|
221
|
+
"vsearch",
|
|
222
|
+
"dogfooding",
|
|
223
|
+
"5",
|
|
224
|
+
"--kv",
|
|
225
|
+
kvPath,
|
|
226
|
+
]);
|
|
199
227
|
assert(cliSearch.code === 0, `CLI vsearch failed: ${cliSearch.stderr}`);
|
|
200
228
|
const cliSearchJson = JSON.parse(cliSearch.stdout.trim() || "[]");
|
|
201
229
|
assert(
|
|
@@ -206,7 +234,11 @@ async function main() {
|
|
|
206
234
|
|
|
207
235
|
console.log("\n🎉 Dogfooding run succeeded!");
|
|
208
236
|
} catch (error) {
|
|
209
|
-
record(
|
|
237
|
+
record(
|
|
238
|
+
"Dogfooding run",
|
|
239
|
+
false,
|
|
240
|
+
error instanceof Error ? error.message : String(error),
|
|
241
|
+
);
|
|
210
242
|
await finalize();
|
|
211
243
|
console.log("\n❌ Dogfooding run failed");
|
|
212
244
|
console.log(error);
|
|
@@ -218,7 +250,14 @@ async function main() {
|
|
|
218
250
|
|
|
219
251
|
async function runCli(args: string[]) {
|
|
220
252
|
const command = new Deno.Command("deno", {
|
|
221
|
-
args: [
|
|
253
|
+
args: [
|
|
254
|
+
"run",
|
|
255
|
+
"-A",
|
|
256
|
+
"--unstable-kv",
|
|
257
|
+
"--no-lock",
|
|
258
|
+
"legacy/main.ts",
|
|
259
|
+
...args,
|
|
260
|
+
],
|
|
222
261
|
stdout: "piped",
|
|
223
262
|
stderr: "piped",
|
|
224
263
|
});
|
package/scripts/postinstall.js
CHANGED
|
@@ -37,7 +37,8 @@ function installDeno() {
|
|
|
37
37
|
|
|
38
38
|
if (platform === "win32") {
|
|
39
39
|
// Windows - use PowerShell
|
|
40
|
-
installCommand =
|
|
40
|
+
installCommand =
|
|
41
|
+
`powershell -c "iwr https://deno.land/install.ps1 -useb | iex"`;
|
|
41
42
|
} else if (platform === "darwin") {
|
|
42
43
|
// macOS - use Homebrew or curl
|
|
43
44
|
installCommand = "curl -fsSL https://deno.land/install.sh | sh";
|
|
@@ -115,7 +116,7 @@ async function main() {
|
|
|
115
116
|
log("Deno not found, attempting to install...");
|
|
116
117
|
try {
|
|
117
118
|
await installDeno();
|
|
118
|
-
} catch
|
|
119
|
+
} catch {
|
|
119
120
|
logError("Failed to install Deno automatically");
|
|
120
121
|
logError("Please install Deno manually:");
|
|
121
122
|
logError(" Windows: iwr https://deno.land/install.ps1 -useb | iex");
|
|
@@ -147,7 +148,7 @@ async function main() {
|
|
|
147
148
|
log(" node node_modules/pluresdb/dist/cli.js serve");
|
|
148
149
|
} catch (error) {
|
|
149
150
|
logError(`Setup failed: ${error.message}`);
|
|
150
|
-
|
|
151
|
+
Deno.exit(1);
|
|
151
152
|
}
|
|
152
153
|
}
|
|
153
154
|
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pre-release validation checks
|
|
5
|
+
* Ensures the repository is ready for a release
|
|
6
|
+
*
|
|
7
|
+
* Usage: node scripts/release-check.js
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { execSync } = require('child_process');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
function run(cmd, ignoreError = false) {
|
|
15
|
+
try {
|
|
16
|
+
return execSync(cmd, { encoding: 'utf8', stdio: 'pipe' }).trim();
|
|
17
|
+
} catch (e) {
|
|
18
|
+
if (ignoreError) return null;
|
|
19
|
+
throw e;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function checkGitStatus() {
|
|
24
|
+
console.log('🔍 Checking git status...');
|
|
25
|
+
const status = run('git status --porcelain', true);
|
|
26
|
+
|
|
27
|
+
if (status && status.length > 0) {
|
|
28
|
+
console.warn('⚠️ Warning: Working directory has uncommitted changes');
|
|
29
|
+
console.log(status);
|
|
30
|
+
} else {
|
|
31
|
+
console.log('✅ Working directory is clean');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function checkPackageVersions() {
|
|
36
|
+
console.log('\n🔍 Checking package versions...');
|
|
37
|
+
|
|
38
|
+
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
39
|
+
const cargoToml = fs.readFileSync('Cargo.toml', 'utf8');
|
|
40
|
+
|
|
41
|
+
const packageVersion = packageJson.version;
|
|
42
|
+
const cargoMatch = cargoToml.match(/^version\s*=\s*"([^"]+)"/m);
|
|
43
|
+
const cargoVersion = cargoMatch ? cargoMatch[1] : null;
|
|
44
|
+
|
|
45
|
+
console.log(` package.json: ${packageVersion}`);
|
|
46
|
+
console.log(` Cargo.toml: ${cargoVersion || 'not found'}`);
|
|
47
|
+
|
|
48
|
+
if (cargoVersion && packageVersion !== cargoVersion) {
|
|
49
|
+
console.error('❌ Version mismatch between package.json and Cargo.toml');
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log('✅ Package versions are consistent');
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function checkChangelog() {
|
|
58
|
+
console.log('\n🔍 Checking CHANGELOG.md...');
|
|
59
|
+
|
|
60
|
+
if (!fs.existsSync('CHANGELOG.md')) {
|
|
61
|
+
console.error('❌ CHANGELOG.md not found');
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const changelog = fs.readFileSync('CHANGELOG.md', 'utf8');
|
|
66
|
+
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
67
|
+
const currentVersion = packageJson.version;
|
|
68
|
+
|
|
69
|
+
if (!changelog.includes(`## [${currentVersion}]`)) {
|
|
70
|
+
console.warn(`⚠️ Warning: Current version ${currentVersion} not found in CHANGELOG.md`);
|
|
71
|
+
} else {
|
|
72
|
+
console.log(`✅ CHANGELOG.md includes current version ${currentVersion}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function checkCommitMessages() {
|
|
79
|
+
console.log('\n🔍 Checking recent commit messages...');
|
|
80
|
+
|
|
81
|
+
const lastTag = run('git describe --tags --abbrev=0 2>/dev/null', true);
|
|
82
|
+
const range = lastTag ? `${lastTag}..HEAD` : '--all';
|
|
83
|
+
|
|
84
|
+
const commits = run(`git log --format="%s" ${range}`, true);
|
|
85
|
+
|
|
86
|
+
if (!commits) {
|
|
87
|
+
console.log('ℹ️ No commits to check');
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const commitLines = commits.split('\n').filter(Boolean);
|
|
92
|
+
const conventionalTypes = ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'chore', 'ci', 'build', 'revert'];
|
|
93
|
+
|
|
94
|
+
let conventionalCount = 0;
|
|
95
|
+
commitLines.forEach(commit => {
|
|
96
|
+
const match = commit.match(/^(\w+)(\(.+\))?:/);
|
|
97
|
+
if (match && conventionalTypes.includes(match[1])) {
|
|
98
|
+
conventionalCount++;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const percentage = (conventionalCount / commitLines.length * 100).toFixed(0);
|
|
103
|
+
console.log(` ${conventionalCount}/${commitLines.length} commits follow conventional format (${percentage}%)`);
|
|
104
|
+
|
|
105
|
+
if (conventionalCount === 0) {
|
|
106
|
+
console.warn('⚠️ Warning: No conventional commits found');
|
|
107
|
+
} else {
|
|
108
|
+
console.log('✅ Found conventional commits');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function checkBuildStatus() {
|
|
115
|
+
console.log('\n🔍 Checking if project builds...');
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
// Check if npm build works
|
|
119
|
+
console.log(' Running npm run build:lib...');
|
|
120
|
+
run('npm run build:lib');
|
|
121
|
+
console.log('✅ Build successful');
|
|
122
|
+
return true;
|
|
123
|
+
} catch (e) {
|
|
124
|
+
console.error('❌ Build failed');
|
|
125
|
+
console.error(e.message);
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function checkTests() {
|
|
131
|
+
console.log('\n🔍 Checking tests...');
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
console.log(' Running tests...');
|
|
135
|
+
run('npm test');
|
|
136
|
+
console.log('✅ Tests passed');
|
|
137
|
+
return true;
|
|
138
|
+
} catch (e) {
|
|
139
|
+
console.error('❌ Tests failed');
|
|
140
|
+
console.error(e.message);
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function main() {
|
|
146
|
+
console.log('🚀 Running pre-release checks for pluresdb\n');
|
|
147
|
+
|
|
148
|
+
let allPassed = true;
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
checkGitStatus();
|
|
152
|
+
|
|
153
|
+
if (!checkPackageVersions()) {
|
|
154
|
+
allPassed = false;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!checkChangelog()) {
|
|
158
|
+
allPassed = false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
checkCommitMessages();
|
|
162
|
+
|
|
163
|
+
// Skip build and test checks in CI for now
|
|
164
|
+
if (process.env.CI !== 'true') {
|
|
165
|
+
if (!checkBuildStatus()) {
|
|
166
|
+
allPassed = false;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!checkTests()) {
|
|
170
|
+
allPassed = false;
|
|
171
|
+
}
|
|
172
|
+
} else {
|
|
173
|
+
console.log('\nℹ️ Skipping build and test checks in CI');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
console.log('\n' + '='.repeat(50));
|
|
177
|
+
if (allPassed) {
|
|
178
|
+
console.log('✅ All pre-release checks passed!');
|
|
179
|
+
process.exit(0);
|
|
180
|
+
} else {
|
|
181
|
+
console.log('❌ Some pre-release checks failed');
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
} catch (e) {
|
|
185
|
+
console.error('\n❌ Pre-release check error:', e.message);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
main();
|