@openvcs/sdk 0.2.4 → 0.2.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 +68 -9
- package/lib/build.d.ts +8 -0
- package/lib/build.js +81 -2
- package/lib/dist.js +1 -0
- package/lib/init.js +2 -2
- package/lib/runtime/factory.d.ts +3 -0
- package/lib/runtime/factory.js +153 -0
- package/lib/runtime/index.d.ts +7 -4
- package/lib/runtime/index.js +13 -154
- package/lib/runtime/registration.d.ts +39 -0
- package/lib/runtime/registration.js +37 -0
- package/lib/runtime/vcs-delegate-base.d.ts +125 -0
- package/lib/runtime/vcs-delegate-base.js +249 -0
- package/lib/runtime/vcs-delegate-metadata.d.ts +120 -0
- package/lib/runtime/vcs-delegate-metadata.js +58 -0
- package/package.json +3 -2
- package/src/lib/build.ts +104 -2
- package/src/lib/dist.ts +2 -0
- package/src/lib/init.ts +2 -2
- package/src/lib/runtime/factory.ts +182 -0
- package/src/lib/runtime/index.ts +14 -177
- package/src/lib/runtime/registration.ts +93 -0
- package/src/lib/runtime/vcs-delegate-base.ts +481 -0
- package/src/lib/runtime/vcs-delegate-metadata.ts +165 -0
- package/test/build.test.js +147 -6
- package/test/cli.test.js +5 -3
- package/test/dist.test.js +27 -18
- package/test/init.test.js +6 -2
- package/test/runtime.test.js +118 -1
- package/test/tsconfig.json +8 -0
- package/test/vcs-delegate-base.test.js +169 -0
- package/test/vcs-delegate-base.types.ts +44 -0
package/test/build.test.js
CHANGED
|
@@ -3,9 +3,35 @@ const fs = require("node:fs");
|
|
|
3
3
|
const path = require("node:path");
|
|
4
4
|
const test = require("node:test");
|
|
5
5
|
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
buildPluginAssets,
|
|
8
|
+
parseBuildArgs,
|
|
9
|
+
readManifest,
|
|
10
|
+
validateDeclaredModuleExec,
|
|
11
|
+
validateGeneratedBootstrapTargets,
|
|
12
|
+
} = require("../lib/build");
|
|
7
13
|
const { cleanupTempDir, makeTempDir, writeJson, writeText } = require("./helpers");
|
|
8
14
|
|
|
15
|
+
test("renderGeneratedBootstrap creates ESM code", () => {
|
|
16
|
+
const output = require("../lib/build").renderGeneratedBootstrap("./plugin.js", true);
|
|
17
|
+
assert.match(output, /^#!/);
|
|
18
|
+
assert.match(output, /import \{ bootstrapPluginModule \}/);
|
|
19
|
+
assert.match(output, /import\('\.\/plugin\.js'\)/);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("renderGeneratedBootstrap creates CJS code", () => {
|
|
23
|
+
const output = require("../lib/build").renderGeneratedBootstrap("./plugin.js", false);
|
|
24
|
+
assert.match(output, /^#!/);
|
|
25
|
+
assert.match(output, /require\('@openvcs\/sdk\/runtime'\)/);
|
|
26
|
+
assert.match(output, /require\('\.\/plugin\.js'\)/);
|
|
27
|
+
assert.match(output, /\(\s*async\s*\(\s*\)\s*=>/);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("renderGeneratedBootstrap handles subdirectory import paths", () => {
|
|
31
|
+
const output = require("../lib/build").renderGeneratedBootstrap("./subdir/plugin.js", true);
|
|
32
|
+
assert.match(output, /import\('\.\/subdir\/plugin\.js'\)/);
|
|
33
|
+
});
|
|
34
|
+
|
|
9
35
|
test("parseBuildArgs uses defaults", () => {
|
|
10
36
|
const parsed = parseBuildArgs([]);
|
|
11
37
|
assert.equal(parsed.pluginDir, process.cwd());
|
|
@@ -39,7 +65,7 @@ test("buildPluginAssets requires package.json for code plugins", () => {
|
|
|
39
65
|
|
|
40
66
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
41
67
|
id: "missing-package",
|
|
42
|
-
module: { exec: "plugin.js" },
|
|
68
|
+
module: { exec: "openvcs-plugin.js" },
|
|
43
69
|
});
|
|
44
70
|
|
|
45
71
|
assert.throws(
|
|
@@ -56,7 +82,7 @@ test("buildPluginAssets runs build:plugin and validates output", () => {
|
|
|
56
82
|
|
|
57
83
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
58
84
|
id: "builder",
|
|
59
|
-
module: { exec: "plugin.js" },
|
|
85
|
+
module: { exec: "openvcs-plugin.js" },
|
|
60
86
|
});
|
|
61
87
|
writeJson(path.join(pluginDir, "package.json"), {
|
|
62
88
|
name: "builder",
|
|
@@ -74,6 +100,11 @@ test("buildPluginAssets runs build:plugin and validates output", () => {
|
|
|
74
100
|
|
|
75
101
|
assert.equal(manifest.pluginId, "builder");
|
|
76
102
|
assert.equal(fs.existsSync(path.join(pluginDir, "bin", "plugin.js")), true);
|
|
103
|
+
assert.equal(fs.existsSync(path.join(pluginDir, "bin", "openvcs-plugin.js")), true);
|
|
104
|
+
assert.match(
|
|
105
|
+
fs.readFileSync(path.join(pluginDir, "bin", "openvcs-plugin.js"), "utf8"),
|
|
106
|
+
/bootstrapPluginModule/
|
|
107
|
+
);
|
|
77
108
|
cleanupTempDir(root);
|
|
78
109
|
});
|
|
79
110
|
|
|
@@ -83,13 +114,123 @@ test("readManifest and validateDeclaredModuleExec stay reusable", () => {
|
|
|
83
114
|
|
|
84
115
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
85
116
|
id: "reusable",
|
|
86
|
-
module: { exec: "plugin.js" },
|
|
117
|
+
module: { exec: "openvcs-plugin.js" },
|
|
87
118
|
});
|
|
88
|
-
writeText(path.join(pluginDir, "bin", "plugin.js"), "export {}
|
|
119
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
120
|
+
writeText(path.join(pluginDir, "bin", "openvcs-plugin.js"), "export {};\n");
|
|
89
121
|
|
|
90
122
|
const manifest = readManifest(pluginDir);
|
|
91
|
-
assert.equal(manifest.moduleExec, "plugin.js");
|
|
123
|
+
assert.equal(manifest.moduleExec, "openvcs-plugin.js");
|
|
124
|
+
assert.doesNotThrow(() => validateGeneratedBootstrapTargets(pluginDir, manifest.moduleExec));
|
|
92
125
|
assert.doesNotThrow(() => validateDeclaredModuleExec(pluginDir, manifest.moduleExec));
|
|
93
126
|
|
|
94
127
|
cleanupTempDir(root);
|
|
95
128
|
});
|
|
129
|
+
|
|
130
|
+
test("validateGeneratedBootstrapTargets rejects module.exec collisions", () => {
|
|
131
|
+
const root = makeTempDir("openvcs-sdk-test");
|
|
132
|
+
const pluginDir = path.join(root, "plugin");
|
|
133
|
+
|
|
134
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
135
|
+
|
|
136
|
+
assert.throws(
|
|
137
|
+
() => validateGeneratedBootstrapTargets(pluginDir, "plugin.js"),
|
|
138
|
+
/must not be plugin\.js/
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
cleanupTempDir(root);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("validateGeneratedBootstrapTargets rejects case-insensitive collisions", () => {
|
|
145
|
+
const root = makeTempDir("openvcs-sdk-test");
|
|
146
|
+
const pluginDir = path.join(root, "plugin");
|
|
147
|
+
|
|
148
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
149
|
+
|
|
150
|
+
assert.throws(
|
|
151
|
+
() => validateGeneratedBootstrapTargets(pluginDir, "Plugin.js"),
|
|
152
|
+
/must not be plugin\.js/
|
|
153
|
+
);
|
|
154
|
+
assert.throws(
|
|
155
|
+
() => validateGeneratedBootstrapTargets(pluginDir, "PLUGIN.JS"),
|
|
156
|
+
/must not be plugin\.js/
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
cleanupTempDir(root);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("generateModuleBootstrap handles subdirectory module.exec paths", () => {
|
|
163
|
+
const root = makeTempDir("openvcs-sdk-test");
|
|
164
|
+
const pluginDir = path.join(root, "plugin");
|
|
165
|
+
|
|
166
|
+
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
167
|
+
id: "subdir-plugin",
|
|
168
|
+
module: { exec: "subdir/openvcs-plugin.js" },
|
|
169
|
+
});
|
|
170
|
+
writeJson(path.join(pluginDir, "package.json"), {
|
|
171
|
+
name: "subdir-plugin",
|
|
172
|
+
type: "module",
|
|
173
|
+
private: true,
|
|
174
|
+
scripts: { "build:plugin": "node ./scripts/build.js" },
|
|
175
|
+
});
|
|
176
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
177
|
+
writeText(path.join(pluginDir, "bin", "subdir", "openvcs-plugin.js"), "export {};\n");
|
|
178
|
+
|
|
179
|
+
const { generateModuleBootstrap } = require("../lib/build");
|
|
180
|
+
generateModuleBootstrap(pluginDir, "subdir/openvcs-plugin.js");
|
|
181
|
+
|
|
182
|
+
const bootstrapContent = fs.readFileSync(
|
|
183
|
+
path.join(pluginDir, "bin", "subdir", "openvcs-plugin.js"),
|
|
184
|
+
"utf8"
|
|
185
|
+
);
|
|
186
|
+
assert.match(bootstrapContent, /\.\.\/plugin\.js/);
|
|
187
|
+
cleanupTempDir(root);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test("detectEsmMode returns true for package.json type: module", () => {
|
|
191
|
+
const root = makeTempDir("openvcs-sdk-test");
|
|
192
|
+
const pluginDir = path.join(root, "plugin");
|
|
193
|
+
|
|
194
|
+
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
195
|
+
id: "esm-plugin",
|
|
196
|
+
module: { exec: "bootstrap.js" },
|
|
197
|
+
});
|
|
198
|
+
writeJson(path.join(pluginDir, "package.json"), {
|
|
199
|
+
name: "esm-plugin",
|
|
200
|
+
type: "module",
|
|
201
|
+
});
|
|
202
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
203
|
+
writeText(path.join(pluginDir, "bin", "bootstrap.js"), "export {};\n");
|
|
204
|
+
|
|
205
|
+
const { generateModuleBootstrap } = require("../lib/build");
|
|
206
|
+
generateModuleBootstrap(pluginDir, "bootstrap.js");
|
|
207
|
+
|
|
208
|
+
const bootstrapContent = fs.readFileSync(path.join(pluginDir, "bin", "bootstrap.js"), "utf8");
|
|
209
|
+
assert.match(bootstrapContent, /^#!/);
|
|
210
|
+
assert.match(bootstrapContent, /^import\s*{/m);
|
|
211
|
+
cleanupTempDir(root);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test("detectEsmMode returns false for package.json type: commonjs", () => {
|
|
215
|
+
const root = makeTempDir("openvcs-sdk-test");
|
|
216
|
+
const pluginDir = path.join(root, "plugin");
|
|
217
|
+
|
|
218
|
+
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
219
|
+
id: "cjs-plugin",
|
|
220
|
+
module: { exec: "bootstrap.js" },
|
|
221
|
+
});
|
|
222
|
+
writeJson(path.join(pluginDir, "package.json"), {
|
|
223
|
+
name: "cjs-plugin",
|
|
224
|
+
type: "commonjs",
|
|
225
|
+
});
|
|
226
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
227
|
+
writeText(path.join(pluginDir, "bin", "bootstrap.js"), "export {};\n");
|
|
228
|
+
|
|
229
|
+
const { generateModuleBootstrap } = require("../lib/build");
|
|
230
|
+
generateModuleBootstrap(pluginDir, "bootstrap.js");
|
|
231
|
+
|
|
232
|
+
const bootstrapContent = fs.readFileSync(path.join(pluginDir, "bin", "bootstrap.js"), "utf8");
|
|
233
|
+
assert.match(bootstrapContent, /require\(/);
|
|
234
|
+
assert.match(bootstrapContent, /\(\s*async\s*\(\s*\)\s*=>/);
|
|
235
|
+
cleanupTempDir(root);
|
|
236
|
+
});
|
package/test/cli.test.js
CHANGED
|
@@ -67,9 +67,10 @@ test("openvcs dist command creates bundle", () => {
|
|
|
67
67
|
|
|
68
68
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
69
69
|
id: "cli-plugin",
|
|
70
|
-
module: { exec: "plugin.js" },
|
|
70
|
+
module: { exec: "openvcs-plugin.js" },
|
|
71
71
|
});
|
|
72
|
-
writeText(path.join(pluginDir, "bin", "plugin.js"), "export {}
|
|
72
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
73
|
+
writeText(path.join(pluginDir, "bin", "openvcs-plugin.js"), "export {};\n");
|
|
73
74
|
|
|
74
75
|
const result = runCli([
|
|
75
76
|
"dist",
|
|
@@ -100,7 +101,7 @@ test("openvcs build command builds code plugin assets", () => {
|
|
|
100
101
|
|
|
101
102
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
102
103
|
id: "build-plugin",
|
|
103
|
-
module: { exec: "plugin.js" },
|
|
104
|
+
module: { exec: "openvcs-plugin.js" },
|
|
104
105
|
});
|
|
105
106
|
writeJson(path.join(pluginDir, "package.json"), {
|
|
106
107
|
name: "build-plugin",
|
|
@@ -119,6 +120,7 @@ test("openvcs build command builds code plugin assets", () => {
|
|
|
119
120
|
assert.equal(result.status, 0);
|
|
120
121
|
assert.equal(result.stdout.trim(), "build-plugin");
|
|
121
122
|
assert.equal(fs.existsSync(path.join(pluginDir, "bin", "plugin.js")), true);
|
|
123
|
+
assert.equal(fs.existsSync(path.join(pluginDir, "bin", "openvcs-plugin.js")), true);
|
|
122
124
|
|
|
123
125
|
cleanupTempDir(root);
|
|
124
126
|
});
|
package/test/dist.test.js
CHANGED
|
@@ -108,7 +108,7 @@ test("readManifest rejects id with path separators", () => {
|
|
|
108
108
|
test("validateDeclaredModuleExec accepts .js/.mjs/.cjs", () => {
|
|
109
109
|
const root = makeTempDir("openvcs-sdk-test");
|
|
110
110
|
const pluginDir = path.join(root, "plugin");
|
|
111
|
-
writeText(path.join(pluginDir, "bin", "plugin.js"), "export {}
|
|
111
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
112
112
|
writeText(path.join(pluginDir, "bin", "plugin.mjs"), "export {};\n");
|
|
113
113
|
writeText(path.join(pluginDir, "bin", "plugin.cjs"), "module.exports = {};\n");
|
|
114
114
|
|
|
@@ -133,7 +133,7 @@ test("validateDeclaredModuleExec rejects non-node extension", () => {
|
|
|
133
133
|
test("validateDeclaredModuleExec rejects absolute path", () => {
|
|
134
134
|
const root = makeTempDir("openvcs-sdk-test");
|
|
135
135
|
const pluginDir = path.join(root, "plugin");
|
|
136
|
-
writeText(path.join(pluginDir, "bin", "plugin.js"), "export {}
|
|
136
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
137
137
|
assert.throws(
|
|
138
138
|
() => __private.validateDeclaredModuleExec(pluginDir, path.resolve(pluginDir, "bin", "plugin.js")),
|
|
139
139
|
/must be a relative path under bin/
|
|
@@ -279,6 +279,7 @@ test("bundlePlugin trims module.exec and includes extra bin files", async () =>
|
|
|
279
279
|
id: "x",
|
|
280
280
|
module: { exec: " module.mjs " },
|
|
281
281
|
});
|
|
282
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
282
283
|
writeText(path.join(pluginDir, "bin", "module.mjs"), "export {};\n");
|
|
283
284
|
writeText(path.join(pluginDir, "bin", "helpers", "util.mjs"), "export const x = 1;\n");
|
|
284
285
|
|
|
@@ -291,6 +292,7 @@ test("bundlePlugin trims module.exec and includes extra bin files", async () =>
|
|
|
291
292
|
});
|
|
292
293
|
const entries = await readBundleEntries(outPath);
|
|
293
294
|
|
|
295
|
+
assert.equal(entries.has("x/bin/plugin.js"), true);
|
|
294
296
|
assert.equal(entries.has("x/bin/module.mjs"), true);
|
|
295
297
|
assert.equal(entries.has("x/bin/helpers/util.mjs"), true);
|
|
296
298
|
cleanupTempDir(root);
|
|
@@ -303,7 +305,7 @@ test("bundlePlugin builds code plugins before packaging", async () => {
|
|
|
303
305
|
|
|
304
306
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
305
307
|
id: "builder",
|
|
306
|
-
module: { exec: "plugin.js" },
|
|
308
|
+
module: { exec: "openvcs-plugin.js" },
|
|
307
309
|
});
|
|
308
310
|
writeJson(path.join(pluginDir, "package.json"), {
|
|
309
311
|
name: "builder",
|
|
@@ -327,6 +329,7 @@ test("bundlePlugin builds code plugins before packaging", async () => {
|
|
|
327
329
|
const entries = await readBundleEntries(outPath);
|
|
328
330
|
|
|
329
331
|
assert.equal(entries.has("builder/bin/plugin.js"), true);
|
|
332
|
+
assert.equal(entries.has("builder/bin/openvcs-plugin.js"), true);
|
|
330
333
|
cleanupTempDir(root);
|
|
331
334
|
});
|
|
332
335
|
|
|
@@ -337,12 +340,12 @@ test("bundlePlugin with no-build requires prebuilt module entrypoint", async ()
|
|
|
337
340
|
|
|
338
341
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
339
342
|
id: "prebuilt",
|
|
340
|
-
module: { exec: "plugin.js" },
|
|
343
|
+
module: { exec: "openvcs-plugin.js" },
|
|
341
344
|
});
|
|
342
345
|
|
|
343
346
|
await assert.rejects(
|
|
344
347
|
() => bundlePlugin({ pluginDir, outDir, verbose: false, noBuild: true, noNpmDeps: true }),
|
|
345
|
-
/module
|
|
348
|
+
/compiled plugin module not found/
|
|
346
349
|
);
|
|
347
350
|
|
|
348
351
|
cleanupTempDir(root);
|
|
@@ -355,7 +358,7 @@ test("bundlePlugin errors when code plugin lacks build:plugin", async () => {
|
|
|
355
358
|
|
|
356
359
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
357
360
|
id: "missing-script",
|
|
358
|
-
module: { exec: "plugin.js" },
|
|
361
|
+
module: { exec: "openvcs-plugin.js" },
|
|
359
362
|
});
|
|
360
363
|
writeJson(path.join(pluginDir, "package.json"), {
|
|
361
364
|
name: "missing-script",
|
|
@@ -416,9 +419,10 @@ test("bundlePlugin rejects plugin id with path separators", async () => {
|
|
|
416
419
|
|
|
417
420
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
418
421
|
id: "bad/id",
|
|
419
|
-
module: { exec: "plugin.js" },
|
|
422
|
+
module: { exec: "openvcs-plugin.js" },
|
|
420
423
|
});
|
|
421
|
-
writeText(path.join(pluginDir, "bin", "plugin.js"), "export {}
|
|
424
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
425
|
+
writeText(path.join(pluginDir, "bin", "openvcs-plugin.js"), "export {};\n");
|
|
422
426
|
|
|
423
427
|
await assert.rejects(
|
|
424
428
|
() => bundlePlugin({ pluginDir, outDir, verbose: false, noBuild: true, noNpmDeps: true }),
|
|
@@ -439,9 +443,10 @@ test("bundlePlugin rejects symlink in bin", async () => {
|
|
|
439
443
|
|
|
440
444
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
441
445
|
id: "x",
|
|
442
|
-
module: { exec: "plugin.js" },
|
|
446
|
+
module: { exec: "openvcs-plugin.js" },
|
|
443
447
|
});
|
|
444
|
-
writeText(path.join(pluginDir, "bin", "plugin.js"), "export {}
|
|
448
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
449
|
+
writeText(path.join(pluginDir, "bin", "openvcs-plugin.js"), "export {};\n");
|
|
445
450
|
writeText(path.join(pluginDir, "bin", "target.js"), "export {};\n");
|
|
446
451
|
fs.symlinkSync(path.join(pluginDir, "bin", "target.js"), path.join(pluginDir, "bin", "link.js"));
|
|
447
452
|
|
|
@@ -460,9 +465,10 @@ test("bundlePlugin output archive keeps plugin-id root directory", async () => {
|
|
|
460
465
|
|
|
461
466
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
462
467
|
id: "root-check",
|
|
463
|
-
module: { exec: "plugin.js" },
|
|
468
|
+
module: { exec: "openvcs-plugin.js" },
|
|
464
469
|
});
|
|
465
|
-
writeText(path.join(pluginDir, "bin", "plugin.js"), "export {}
|
|
470
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
471
|
+
writeText(path.join(pluginDir, "bin", "openvcs-plugin.js"), "export {};\n");
|
|
466
472
|
|
|
467
473
|
const outPath = await bundlePlugin({
|
|
468
474
|
pluginDir,
|
|
@@ -487,9 +493,10 @@ test("bundlePlugin overwrites existing bundle file", async () => {
|
|
|
487
493
|
|
|
488
494
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
489
495
|
id: "replace",
|
|
490
|
-
module: { exec: "plugin.js" },
|
|
496
|
+
module: { exec: "openvcs-plugin.js" },
|
|
491
497
|
});
|
|
492
|
-
writeText(path.join(pluginDir, "bin", "plugin.js"), "export {}
|
|
498
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
499
|
+
writeText(path.join(pluginDir, "bin", "openvcs-plugin.js"), "export {};\n");
|
|
493
500
|
|
|
494
501
|
const existingPath = path.join(outDir, "replace.ovcsp");
|
|
495
502
|
writeText(existingPath, "not-a-tar");
|
|
@@ -514,9 +521,10 @@ test("bundlePlugin generates package-lock in staging, not pluginDir", async () =
|
|
|
514
521
|
|
|
515
522
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
516
523
|
id: "npm-plugin",
|
|
517
|
-
module: { exec: "plugin.js" },
|
|
524
|
+
module: { exec: "openvcs-plugin.js" },
|
|
518
525
|
});
|
|
519
|
-
writeText(path.join(pluginDir, "bin", "plugin.js"), "export {}
|
|
526
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
527
|
+
writeText(path.join(pluginDir, "bin", "openvcs-plugin.js"), "export {};\n");
|
|
520
528
|
writeJson(path.join(pluginDir, "package.json"), {
|
|
521
529
|
name: "npm-plugin",
|
|
522
530
|
version: "0.1.0",
|
|
@@ -546,9 +554,10 @@ test("bundlePlugin with --no-npm-deps does not generate lockfile", async () => {
|
|
|
546
554
|
|
|
547
555
|
writeJson(path.join(pluginDir, "openvcs.plugin.json"), {
|
|
548
556
|
id: "no-npm",
|
|
549
|
-
module: { exec: "plugin.js" },
|
|
557
|
+
module: { exec: "openvcs-plugin.js" },
|
|
550
558
|
});
|
|
551
|
-
writeText(path.join(pluginDir, "bin", "plugin.js"), "export {}
|
|
559
|
+
writeText(path.join(pluginDir, "bin", "plugin.js"), "export function OnPluginStart() {}\n");
|
|
560
|
+
writeText(path.join(pluginDir, "bin", "openvcs-plugin.js"), "export {};\n");
|
|
552
561
|
writeJson(path.join(pluginDir, "package.json"), {
|
|
553
562
|
name: "no-npm",
|
|
554
563
|
version: "0.1.0",
|
package/test/init.test.js
CHANGED
|
@@ -81,9 +81,13 @@ test("writeModuleTemplate scaffolds SDK runtime entrypoint", () => {
|
|
|
81
81
|
});
|
|
82
82
|
|
|
83
83
|
const pluginSource = fs.readFileSync(path.join(targetDir, "src", "plugin.ts"), "utf8");
|
|
84
|
+
const manifest = JSON.parse(
|
|
85
|
+
fs.readFileSync(path.join(targetDir, "openvcs.plugin.json"), "utf8")
|
|
86
|
+
);
|
|
84
87
|
|
|
85
|
-
assert.
|
|
86
|
-
assert.match(pluginSource, /
|
|
88
|
+
assert.equal(manifest.module.exec, "openvcs-plugin.js");
|
|
89
|
+
assert.match(pluginSource, /OnPluginStart/);
|
|
90
|
+
assert.match(pluginSource, /PluginDefinition/);
|
|
87
91
|
assert.match(pluginSource, /context\.host\.info\('OpenVCS plugin started'\)/);
|
|
88
92
|
|
|
89
93
|
cleanupTempDir(root);
|
package/test/runtime.test.js
CHANGED
|
@@ -2,7 +2,10 @@ const assert = require("node:assert/strict");
|
|
|
2
2
|
const { EventEmitter } = require("node:events");
|
|
3
3
|
const test = require("node:test");
|
|
4
4
|
|
|
5
|
-
const {
|
|
5
|
+
const {
|
|
6
|
+
bootstrapPluginModule,
|
|
7
|
+
createPluginRuntime,
|
|
8
|
+
} = require("../lib/runtime");
|
|
6
9
|
const {
|
|
7
10
|
parseFramedMessages,
|
|
8
11
|
serializeFramedMessage,
|
|
@@ -116,3 +119,117 @@ test("createPluginRuntime reports missing methods as plugin failures", async ()
|
|
|
116
119
|
},
|
|
117
120
|
]);
|
|
118
121
|
});
|
|
122
|
+
|
|
123
|
+
test("bootstrapPluginModule runs OnPluginStart before starting runtime", async () => {
|
|
124
|
+
const stdin = new EventEmitter();
|
|
125
|
+
const chunks = [];
|
|
126
|
+
const stdout = {
|
|
127
|
+
write(chunk) {
|
|
128
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
129
|
+
return true;
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
await bootstrapPluginModule({
|
|
134
|
+
modulePath: "./plugin.js",
|
|
135
|
+
transport: { stdin, stdout },
|
|
136
|
+
async importPluginModule() {
|
|
137
|
+
return {
|
|
138
|
+
PluginDefinition: {
|
|
139
|
+
plugin: {
|
|
140
|
+
async "plugin.init"(_params, context) {
|
|
141
|
+
context.host.info("booted");
|
|
142
|
+
return null;
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
vcs: {
|
|
146
|
+
async "vcs.get_caps"() {
|
|
147
|
+
return { commits: true };
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
OnPluginStart() {
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
stdin.emit(
|
|
158
|
+
"data",
|
|
159
|
+
serializeFramedMessage({
|
|
160
|
+
jsonrpc: "2.0",
|
|
161
|
+
id: 4,
|
|
162
|
+
method: "plugin.initialize",
|
|
163
|
+
params: {},
|
|
164
|
+
})
|
|
165
|
+
);
|
|
166
|
+
stdin.emit(
|
|
167
|
+
"data",
|
|
168
|
+
serializeFramedMessage({
|
|
169
|
+
jsonrpc: "2.0",
|
|
170
|
+
id: 5,
|
|
171
|
+
method: "plugin.init",
|
|
172
|
+
params: {},
|
|
173
|
+
})
|
|
174
|
+
);
|
|
175
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
176
|
+
|
|
177
|
+
const parsed = parseFramedMessages(Buffer.concat(chunks));
|
|
178
|
+
assert.deepEqual(parsed.messages, [
|
|
179
|
+
{
|
|
180
|
+
jsonrpc: "2.0",
|
|
181
|
+
id: 4,
|
|
182
|
+
result: {
|
|
183
|
+
protocol_version: 1,
|
|
184
|
+
implements: {
|
|
185
|
+
plugin: true,
|
|
186
|
+
vcs: true,
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
jsonrpc: "2.0",
|
|
192
|
+
method: "host.log",
|
|
193
|
+
params: {
|
|
194
|
+
level: "info",
|
|
195
|
+
target: "openvcs.plugin",
|
|
196
|
+
message: "booted",
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
jsonrpc: "2.0",
|
|
201
|
+
id: 5,
|
|
202
|
+
result: null,
|
|
203
|
+
},
|
|
204
|
+
]);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test("bootstrapPluginModule rejects modules without OnPluginStart", async () => {
|
|
208
|
+
await assert.rejects(
|
|
209
|
+
() =>
|
|
210
|
+
bootstrapPluginModule({
|
|
211
|
+
modulePath: "./plugin.js",
|
|
212
|
+
async importPluginModule() {
|
|
213
|
+
return {};
|
|
214
|
+
},
|
|
215
|
+
}),
|
|
216
|
+
/must export OnPluginStart/
|
|
217
|
+
);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test("bootstrapPluginModule rejects when OnPluginStart throws", async () => {
|
|
221
|
+
await assert.rejects(
|
|
222
|
+
() =>
|
|
223
|
+
bootstrapPluginModule({
|
|
224
|
+
modulePath: "./plugin.js",
|
|
225
|
+
async importPluginModule() {
|
|
226
|
+
return {
|
|
227
|
+
OnPluginStart() {
|
|
228
|
+
throw new Error("startup failure");
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
},
|
|
232
|
+
}),
|
|
233
|
+
/plugin startup failed/
|
|
234
|
+
);
|
|
235
|
+
});
|