@pipelab/plugin-construct 1.0.0-beta.1 → 1.0.0-beta.2
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/package.json +7 -4
- package/CHANGELOG.md +0 -18
- package/src/assets/construct.webp +0 -0
- package/src/assets/script.ts +0 -288
- package/src/declarations.d.ts +0 -1
- package/src/export-c3p.ts +0 -75
- package/src/export-project.ts +0 -75
- package/src/export-shared.ts +0 -286
- package/src/export.test.ts +0 -37
- package/src/index.ts +0 -34
- package/tests/e2e/construct.spec.ts +0 -60
- package/tests/e2e/fixtures/c3-export/test.c3p +0 -0
- package/tests/e2e/fixtures/c3-export.json +0 -51
- package/tests/e2e/fixtures/html-export/index.html +0 -29
- package/tests/e2e/vitest.config.mts +0 -20
- package/tsconfig.json +0 -10
- package/tsdown.config.ts +0 -15
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pipelab/plugin-construct",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.2",
|
|
4
4
|
"license": "FSL-1.1-MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/CynToolkit/pipelab.git",
|
|
8
8
|
"directory": "plugins/plugin-construct"
|
|
9
9
|
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
10
13
|
"type": "module",
|
|
11
14
|
"main": "./dist/index.cjs",
|
|
12
15
|
"module": "./dist/index.mjs",
|
|
@@ -18,15 +21,15 @@
|
|
|
18
21
|
"es-toolkit": "1.25.2",
|
|
19
22
|
"playwright": "1.48.2",
|
|
20
23
|
"valibot": "0.42.1",
|
|
21
|
-
"@pipelab/plugin-core": "1.0.0-beta.
|
|
24
|
+
"@pipelab/plugin-core": "1.0.0-beta.2"
|
|
22
25
|
},
|
|
23
26
|
"devDependencies": {
|
|
24
27
|
"@types/node": "24",
|
|
25
28
|
"tsdown": "0.21.2",
|
|
26
29
|
"typescript": "5.9.3",
|
|
27
30
|
"vitest": "3.1.4",
|
|
28
|
-
"@pipelab/
|
|
29
|
-
"@pipelab/
|
|
31
|
+
"@pipelab/tsconfig": "1.0.0-beta.1",
|
|
32
|
+
"@pipelab/test-utils": "1.0.0-beta.2"
|
|
30
33
|
},
|
|
31
34
|
"test": {
|
|
32
35
|
"env": {
|
package/CHANGELOG.md
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# @pipelab/plugin-construct
|
|
2
|
-
|
|
3
|
-
## 1.0.0-beta.1
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- @pipelab/plugin-core@1.0.0-beta.1
|
|
8
|
-
|
|
9
|
-
## 1.0.0-beta.0
|
|
10
|
-
|
|
11
|
-
### Major Changes
|
|
12
|
-
|
|
13
|
-
- e1befbf: initial release
|
|
14
|
-
|
|
15
|
-
### Patch Changes
|
|
16
|
-
|
|
17
|
-
- Updated dependencies [e1befbf]
|
|
18
|
-
- @pipelab/plugin-core@1.0.0-beta.0
|
|
Binary file
|
package/src/assets/script.ts
DELETED
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
import { Page } from "playwright";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
|
|
4
|
-
const registerInstallButtonListener = (page: Page, log: typeof console.log) => {
|
|
5
|
-
// as soon as it appear, without blocking flow
|
|
6
|
-
// accept installing plugins
|
|
7
|
-
const installDialog = page.locator("#addonConfirmInstallDialog");
|
|
8
|
-
const installBtn = installDialog.locator(".okButton");
|
|
9
|
-
installBtn
|
|
10
|
-
.waitFor({
|
|
11
|
-
timeout: 0,
|
|
12
|
-
})
|
|
13
|
-
.then(async () => {
|
|
14
|
-
await installBtn.click();
|
|
15
|
-
log("installBtn clicked");
|
|
16
|
-
registerInstallButtonListener(page, log);
|
|
17
|
-
})
|
|
18
|
-
.catch(async (e) => {
|
|
19
|
-
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
20
|
-
log("installBtn.click() failed", e.message);
|
|
21
|
-
});
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const registerSaveLoginExpiredistener = (page: Page, log: typeof console.log) => {
|
|
25
|
-
// as soon as it appear, without blocking flow
|
|
26
|
-
// accept installing plugins
|
|
27
|
-
const installDialog = page.locator("#confirmDialog");
|
|
28
|
-
const cancelBtn = installDialog.locator(".cancelConfirmButton");
|
|
29
|
-
cancelBtn
|
|
30
|
-
.waitFor({
|
|
31
|
-
timeout: 0,
|
|
32
|
-
})
|
|
33
|
-
.then(async () => {
|
|
34
|
-
await cancelBtn.click();
|
|
35
|
-
log("cancelBtn clicked");
|
|
36
|
-
registerSaveLoginExpiredistener(page, log);
|
|
37
|
-
})
|
|
38
|
-
.catch(async (e) => {
|
|
39
|
-
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
40
|
-
log("cancelBtn.click() failed", e.message);
|
|
41
|
-
});
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const registerWebglErrorListener = (page: Page, log: typeof console.log) => {
|
|
45
|
-
// as soon as it appear, without blocking flow
|
|
46
|
-
// ignore webgl error
|
|
47
|
-
const okDialog = page.locator("#okDialog");
|
|
48
|
-
const webglErrorButton = okDialog.locator(".okButton");
|
|
49
|
-
webglErrorButton
|
|
50
|
-
.waitFor({
|
|
51
|
-
timeout: 0,
|
|
52
|
-
})
|
|
53
|
-
.then(async () => {
|
|
54
|
-
const text = await okDialog.allInnerTexts();
|
|
55
|
-
|
|
56
|
-
if (text.join().toLowerCase().includes("webgl")) {
|
|
57
|
-
await webglErrorButton.click();
|
|
58
|
-
log("webglErrorButton clicked");
|
|
59
|
-
registerWebglErrorListener(page, log);
|
|
60
|
-
}
|
|
61
|
-
})
|
|
62
|
-
.catch(async (e) => {
|
|
63
|
-
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
64
|
-
log("webglErrorButton.click() failed", e.message);
|
|
65
|
-
});
|
|
66
|
-
};
|
|
67
|
-
const registerDeprecatedFeatures = (page: Page, log: typeof console.log) => {
|
|
68
|
-
// as soon as it appear, without blocking flow
|
|
69
|
-
// ignore deprecated feature
|
|
70
|
-
const deprecatedFeaturesDialog = page.locator("#deprecatedFeaturesDialog");
|
|
71
|
-
const okButton = deprecatedFeaturesDialog.locator(".okButton");
|
|
72
|
-
okButton
|
|
73
|
-
.waitFor({
|
|
74
|
-
timeout: 0,
|
|
75
|
-
})
|
|
76
|
-
.then(async () => {
|
|
77
|
-
await okButton.click();
|
|
78
|
-
log("okButton clicked");
|
|
79
|
-
registerDeprecatedFeatures(page, log);
|
|
80
|
-
})
|
|
81
|
-
.catch(async (e) => {
|
|
82
|
-
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
83
|
-
log("deprecatedFeatures.okButton.click() failed", e.message);
|
|
84
|
-
});
|
|
85
|
-
};
|
|
86
|
-
const registerWelcomeToConstructListener = (page: Page, log: typeof console.log) => {
|
|
87
|
-
// as soon as it appear, without blocking flow
|
|
88
|
-
// ignore deprecated feature
|
|
89
|
-
const welcomeTourDialog = page.locator("#welcomeTourDialog");
|
|
90
|
-
const okButton = welcomeTourDialog.locator(".noThanksLink");
|
|
91
|
-
okButton
|
|
92
|
-
.waitFor({
|
|
93
|
-
timeout: 0,
|
|
94
|
-
})
|
|
95
|
-
.then(async () => {
|
|
96
|
-
await okButton.click();
|
|
97
|
-
log("okButton clicked");
|
|
98
|
-
// registerWelcomeToConstructListener(page, log); // usually only once
|
|
99
|
-
})
|
|
100
|
-
.catch(async (e) => {
|
|
101
|
-
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
102
|
-
log("welcomeTour.okButton.click() failed", e.message);
|
|
103
|
-
});
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
const registerMissingAddonErrorListener = (page: Page, log: typeof console.log) => {
|
|
107
|
-
// as soon as it appear, without blocking flow
|
|
108
|
-
// ignore missing addon and throw
|
|
109
|
-
const okDialog = page.locator("#missingAddonsDialog");
|
|
110
|
-
const webglErrorButton = okDialog.locator(".okButton");
|
|
111
|
-
webglErrorButton
|
|
112
|
-
.waitFor({
|
|
113
|
-
timeout: 0,
|
|
114
|
-
})
|
|
115
|
-
.then(async () => {
|
|
116
|
-
throw new Error("Missing addon. You should bundle addons with your project");
|
|
117
|
-
})
|
|
118
|
-
.catch(async (e) => {
|
|
119
|
-
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
120
|
-
log("missingAddon.okButton.waitFor() failed", e.message);
|
|
121
|
-
});
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const registerNewVersionAvailableListener = (page: Page, log: typeof console.log) => {
|
|
125
|
-
// as soon as it appear, without blocking flow
|
|
126
|
-
// ignore new version available and throw
|
|
127
|
-
const newVersionAvailableDialog = page.locator("#confirmDialog");
|
|
128
|
-
const cancelButton = newVersionAvailableDialog.locator(".cancelConfirmButton");
|
|
129
|
-
cancelButton
|
|
130
|
-
.waitFor({
|
|
131
|
-
timeout: 0,
|
|
132
|
-
})
|
|
133
|
-
.then(async () => {
|
|
134
|
-
await cancelButton.click();
|
|
135
|
-
log("cancelButton clicked");
|
|
136
|
-
registerNewVersionAvailableListener(page, log);
|
|
137
|
-
})
|
|
138
|
-
.catch(async (e) => {
|
|
139
|
-
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
140
|
-
log("cancelButton.click() failed", e.message);
|
|
141
|
-
});
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
export const script = async (
|
|
145
|
-
page: Page,
|
|
146
|
-
log: typeof console.log,
|
|
147
|
-
filePath: string,
|
|
148
|
-
username: string | undefined,
|
|
149
|
-
password: string | undefined,
|
|
150
|
-
version: string | undefined,
|
|
151
|
-
downloadDir: string,
|
|
152
|
-
) => {
|
|
153
|
-
let url = "https://editor.construct.net/";
|
|
154
|
-
if (version) {
|
|
155
|
-
url += version;
|
|
156
|
-
}
|
|
157
|
-
log("Navigating to URL", url);
|
|
158
|
-
// const serviceWorkerPromise = page.waitForEvent("serviceworker");
|
|
159
|
-
await page.goto(url);
|
|
160
|
-
log("after navigating");
|
|
161
|
-
|
|
162
|
-
// const serviceworker = await serviceWorkerPromise;
|
|
163
|
-
registerWelcomeToConstructListener(page, log);
|
|
164
|
-
registerNewVersionAvailableListener(page, log);
|
|
165
|
-
|
|
166
|
-
log("after event");
|
|
167
|
-
|
|
168
|
-
await page.waitForTimeout(2000);
|
|
169
|
-
log("after wait");
|
|
170
|
-
|
|
171
|
-
if (username && password) {
|
|
172
|
-
log("Authenticating");
|
|
173
|
-
await page.getByTitle("User account").locator("ui-icon").click();
|
|
174
|
-
await page.getByRole("menuitem", { name: "Log in" }).locator("span").click();
|
|
175
|
-
await page.frameLocator("#loginDialog iframe").getByLabel("Username").fill(username);
|
|
176
|
-
await page.frameLocator("#loginDialog iframe").getByLabel("Password").fill(password);
|
|
177
|
-
|
|
178
|
-
const tokenPromise = page.waitForResponse(/https:\/\/account.*\.construct\.net\/login.json/i);
|
|
179
|
-
|
|
180
|
-
await page.frameLocator("#loginDialog iframe").getByRole("button", { name: "Log in" }).click();
|
|
181
|
-
|
|
182
|
-
const response = await tokenPromise;
|
|
183
|
-
const jsonResponse = await response.json();
|
|
184
|
-
|
|
185
|
-
if (jsonResponse.request.status === "error") {
|
|
186
|
-
await page.close();
|
|
187
|
-
|
|
188
|
-
throw new Error("Invalid credentials");
|
|
189
|
-
}
|
|
190
|
-
log("Authenticated");
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
await page.waitForTimeout(2000);
|
|
194
|
-
|
|
195
|
-
const [fileChooser] = await Promise.all([
|
|
196
|
-
page.waitForEvent("filechooser"),
|
|
197
|
-
page.keyboard.press("ControlOrMeta+O"),
|
|
198
|
-
]);
|
|
199
|
-
log("filechooser");
|
|
200
|
-
|
|
201
|
-
console.log("filePath", filePath);
|
|
202
|
-
await fileChooser.setFiles([filePath]);
|
|
203
|
-
log("Set file");
|
|
204
|
-
|
|
205
|
-
// await page.getByText("Not now").click({
|
|
206
|
-
// timeout: 1000
|
|
207
|
-
// });
|
|
208
|
-
|
|
209
|
-
const progressDialog = page.locator("#progressDialog");
|
|
210
|
-
// <progress class="progressBar" value="0.293996941070648" max="1"></progress>
|
|
211
|
-
const progessBar = progressDialog.locator(".progressBar");
|
|
212
|
-
|
|
213
|
-
log("Waiting for progress dialog");
|
|
214
|
-
await progressDialog.waitFor({
|
|
215
|
-
timeout: 0,
|
|
216
|
-
});
|
|
217
|
-
log("Got loading progress dialog");
|
|
218
|
-
|
|
219
|
-
const progressInterval = setInterval(async () => {
|
|
220
|
-
const text = await progessBar.getAttribute("value");
|
|
221
|
-
const textAsNumber = parseFloat(text);
|
|
222
|
-
const finalText = Number.isNaN(textAsNumber) ? 0 : textAsNumber;
|
|
223
|
-
log("progress", `${finalText * 100}%`);
|
|
224
|
-
}, 500);
|
|
225
|
-
|
|
226
|
-
// as soon as it appear, without blocking flow
|
|
227
|
-
// ignore asking for update
|
|
228
|
-
const notNowBtn = page.getByText("Not now");
|
|
229
|
-
notNowBtn
|
|
230
|
-
.waitFor({
|
|
231
|
-
timeout: 0,
|
|
232
|
-
})
|
|
233
|
-
.then(async () => {
|
|
234
|
-
return notNowBtn.click();
|
|
235
|
-
})
|
|
236
|
-
.then(() => {
|
|
237
|
-
log("notNowBtn clicked");
|
|
238
|
-
})
|
|
239
|
-
.catch(async (e) => {
|
|
240
|
-
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
241
|
-
log("notNowBtn.click() failed", e.message);
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
registerInstallButtonListener(page, log);
|
|
245
|
-
registerWebglErrorListener(page, log);
|
|
246
|
-
registerMissingAddonErrorListener(page, log);
|
|
247
|
-
registerDeprecatedFeatures(page, log);
|
|
248
|
-
registerSaveLoginExpiredistener(page, log);
|
|
249
|
-
|
|
250
|
-
log("Waiting for progress dialog to disapear");
|
|
251
|
-
await progressDialog.waitFor({
|
|
252
|
-
state: "detached",
|
|
253
|
-
timeout: 0,
|
|
254
|
-
});
|
|
255
|
-
log("Got progress dialog to disapear");
|
|
256
|
-
clearTimeout(progressInterval);
|
|
257
|
-
|
|
258
|
-
await page.getByRole("button", { name: "Menu" }).click();
|
|
259
|
-
await page.getByRole("menuitem", { name: "Project" }).click();
|
|
260
|
-
await page.getByRole("menuitem", { name: "Export" }).click();
|
|
261
|
-
log('"Export" clicked');
|
|
262
|
-
await page
|
|
263
|
-
.locator("ui-iconviewitem")
|
|
264
|
-
.filter({ hasText: "Web (HTML5)" })
|
|
265
|
-
.locator("ui-icon")
|
|
266
|
-
.click();
|
|
267
|
-
log('"Web" clicked');
|
|
268
|
-
|
|
269
|
-
await page.locator("#exportSelectPlatformDialog").getByRole("button", { name: "Next" }).click();
|
|
270
|
-
|
|
271
|
-
await page.getByLabel("Offline support").uncheck();
|
|
272
|
-
log("Disabled offline support");
|
|
273
|
-
|
|
274
|
-
await page.locator("#exportStandardOptionsDialog").getByRole("button", { name: "Next" }).click();
|
|
275
|
-
log('"Next" clicked');
|
|
276
|
-
const downloadPromise = page.waitForEvent("download");
|
|
277
|
-
await page.locator(".downloadExportedProject").click();
|
|
278
|
-
const download = await downloadPromise;
|
|
279
|
-
await page.getByRole("button", { name: "OK" }).click();
|
|
280
|
-
log('"Download" clicked');
|
|
281
|
-
|
|
282
|
-
const finalPath = join(downloadDir, download.suggestedFilename());
|
|
283
|
-
await download.saveAs(finalPath);
|
|
284
|
-
log("File Downloaded");
|
|
285
|
-
|
|
286
|
-
await page.close();
|
|
287
|
-
return finalPath;
|
|
288
|
-
};
|
package/src/declarations.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
declare module "*.webp";
|
package/src/export-c3p.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ExtractInputsFromAction,
|
|
3
|
-
createAction,
|
|
4
|
-
createActionRunner,
|
|
5
|
-
createPathParam,
|
|
6
|
-
fileExists,
|
|
7
|
-
} from "@pipelab/plugin-core";
|
|
8
|
-
import { exportc3p, sharedParams } from "./export-shared.js";
|
|
9
|
-
|
|
10
|
-
export const ID = "export-construct-project";
|
|
11
|
-
|
|
12
|
-
export const exportAction = createAction({
|
|
13
|
-
id: ID,
|
|
14
|
-
name: "Export .c3p",
|
|
15
|
-
displayString:
|
|
16
|
-
"`Export project ${fmt.param(params.file, 'primary', 'No path selected')} with version ${params.version ? params.version : 'stable'}`",
|
|
17
|
-
meta: {},
|
|
18
|
-
params: {
|
|
19
|
-
file: createPathParam("", {
|
|
20
|
-
label: "File (.c3p)",
|
|
21
|
-
required: true,
|
|
22
|
-
control: {
|
|
23
|
-
type: "path",
|
|
24
|
-
label: "Pick a file (.c3p)",
|
|
25
|
-
options: {
|
|
26
|
-
properties: ["openFile"],
|
|
27
|
-
filters: [{ name: "Construct Project", extensions: ["c3p"] }],
|
|
28
|
-
title: "aaaa",
|
|
29
|
-
message: "bbbb",
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
}),
|
|
33
|
-
...sharedParams,
|
|
34
|
-
},
|
|
35
|
-
outputs: {
|
|
36
|
-
folder: {
|
|
37
|
-
type: "path",
|
|
38
|
-
deprecated: true,
|
|
39
|
-
value: undefined as undefined | string,
|
|
40
|
-
label: "Exported zip",
|
|
41
|
-
// schema: schema.string()
|
|
42
|
-
},
|
|
43
|
-
parentFolder: {
|
|
44
|
-
type: "path",
|
|
45
|
-
deprecated: false,
|
|
46
|
-
value: undefined as undefined | string,
|
|
47
|
-
label: "Path to parent folder of exported zip",
|
|
48
|
-
// schema: schema.string()
|
|
49
|
-
},
|
|
50
|
-
zipFile: {
|
|
51
|
-
type: "path",
|
|
52
|
-
deprecated: false,
|
|
53
|
-
value: undefined as undefined | string,
|
|
54
|
-
label: "Exported zip",
|
|
55
|
-
// schema: schema.string()
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
description: "Export construct project from .c3p file",
|
|
59
|
-
icon: "",
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
export const ExportActionRunner = createActionRunner<typeof exportAction>(async (options) => {
|
|
63
|
-
const file = options.inputs.file;
|
|
64
|
-
|
|
65
|
-
const c3pFileExists = await fileExists(file);
|
|
66
|
-
|
|
67
|
-
if (!c3pFileExists) {
|
|
68
|
-
throw new Error("You must specify a valid .c3p file");
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
await exportc3p(file, options);
|
|
72
|
-
options.log("exportc3p done");
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
export type Params = ExtractInputsFromAction<typeof exportAction>;
|
package/src/export-project.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
|
-
import {
|
|
3
|
-
ExtractInputsFromAction,
|
|
4
|
-
createAction,
|
|
5
|
-
createActionRunner,
|
|
6
|
-
createPathParam,
|
|
7
|
-
fileExists,
|
|
8
|
-
} from "@pipelab/plugin-core";
|
|
9
|
-
import { exportc3p, sharedParams } from "./export-shared.js";
|
|
10
|
-
import { throttle } from "es-toolkit";
|
|
11
|
-
import { zipFolder } from "@pipelab/plugin-core";
|
|
12
|
-
|
|
13
|
-
export const ID = "export-construct-project-folder";
|
|
14
|
-
|
|
15
|
-
export const exportProjectAction = createAction({
|
|
16
|
-
id: ID,
|
|
17
|
-
name: "Export folder",
|
|
18
|
-
displayString: "`Export project ${params.version ? `r${params.version}` : ''}`",
|
|
19
|
-
meta: {},
|
|
20
|
-
params: {
|
|
21
|
-
folder: createPathParam("", {
|
|
22
|
-
required: true,
|
|
23
|
-
label: "Folder",
|
|
24
|
-
control: {
|
|
25
|
-
type: "path",
|
|
26
|
-
options: {
|
|
27
|
-
properties: ["openDirectory"],
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
}),
|
|
31
|
-
...sharedParams,
|
|
32
|
-
},
|
|
33
|
-
outputs: {
|
|
34
|
-
folder: {
|
|
35
|
-
type: "path",
|
|
36
|
-
deprecated: true,
|
|
37
|
-
value: undefined as undefined | string,
|
|
38
|
-
label: "Exported zip",
|
|
39
|
-
// schema: schema.string()
|
|
40
|
-
},
|
|
41
|
-
parentFolder: {
|
|
42
|
-
type: "path",
|
|
43
|
-
deprecated: false,
|
|
44
|
-
value: undefined as undefined | string,
|
|
45
|
-
label: "Path to parent folder of exported zip",
|
|
46
|
-
// schema: schema.string()
|
|
47
|
-
},
|
|
48
|
-
zipFile: {
|
|
49
|
-
type: "path",
|
|
50
|
-
deprecated: false,
|
|
51
|
-
value: undefined as undefined | string,
|
|
52
|
-
label: "Exported zip",
|
|
53
|
-
// schema: schema.string()
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
description: "Export construct project from folder",
|
|
57
|
-
icon: "",
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
export const ExportProjectActionRunner = createActionRunner<typeof exportProjectAction>(
|
|
61
|
-
async (options) => {
|
|
62
|
-
const c3pFolderExists = await fileExists(options.inputs.folder);
|
|
63
|
-
if (!c3pFolderExists) {
|
|
64
|
-
throw new Error("You must specify a valid construct project folder");
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const outputPath = join(options.cwd, "c3_tmp_proj.c3p");
|
|
68
|
-
|
|
69
|
-
const to = await zipFolder(options.inputs.folder, outputPath, options.log);
|
|
70
|
-
|
|
71
|
-
await exportc3p(to, options);
|
|
72
|
-
},
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
export type Params = ExtractInputsFromAction<typeof exportProjectAction>;
|
package/src/export-shared.ts
DELETED
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Action,
|
|
3
|
-
ActionRunnerData,
|
|
4
|
-
createNumberParam,
|
|
5
|
-
createPasswordParam,
|
|
6
|
-
createPathParam,
|
|
7
|
-
createStringParam,
|
|
8
|
-
InputsDefinition,
|
|
9
|
-
ParamsToInput,
|
|
10
|
-
runWithLiveLogs,
|
|
11
|
-
fetchPackage,
|
|
12
|
-
} from "@pipelab/plugin-core";
|
|
13
|
-
import { script } from "./assets/script.js";
|
|
14
|
-
import * as v from "valibot";
|
|
15
|
-
import { BrowserContext } from "playwright";
|
|
16
|
-
import { dirname, join, delimiter } from "node:path";
|
|
17
|
-
import { cp, mkdir } from "node:fs/promises";
|
|
18
|
-
import { homedir } from "node:os";
|
|
19
|
-
import { createRequire } from "node:module";
|
|
20
|
-
|
|
21
|
-
const platform = process.platform;
|
|
22
|
-
const { LOCALAPPDATA, XDG_CONFIG_HOME } = process.env;
|
|
23
|
-
|
|
24
|
-
const isCI = process.env.CI === "true";
|
|
25
|
-
|
|
26
|
-
let baseProfile;
|
|
27
|
-
if (platform === "win32") {
|
|
28
|
-
baseProfile = join(LOCALAPPDATA ?? "", "Google", "Chrome", "User Data");
|
|
29
|
-
} else if (platform === "linux") {
|
|
30
|
-
baseProfile = join(XDG_CONFIG_HOME ?? "", "google-chrome");
|
|
31
|
-
} else if (platform === "darwin") {
|
|
32
|
-
baseProfile = join(homedir(), "Library", "Application Support", "Google", "Chrome");
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const sharedParams = {
|
|
36
|
-
username: createStringParam("", {
|
|
37
|
-
label: "Username",
|
|
38
|
-
required: false,
|
|
39
|
-
description: "Your Construct username",
|
|
40
|
-
}),
|
|
41
|
-
password: createPasswordParam("", {
|
|
42
|
-
description:
|
|
43
|
-
"Your Construct password. Will only be used locally to automate the export on Construct website via a local browser. Will not be sent to any server.",
|
|
44
|
-
required: false,
|
|
45
|
-
label: "Password",
|
|
46
|
-
}),
|
|
47
|
-
version: createStringParam("", {
|
|
48
|
-
description: "The Construct version you want to use",
|
|
49
|
-
label: "Version",
|
|
50
|
-
required: false,
|
|
51
|
-
}),
|
|
52
|
-
headless: {
|
|
53
|
-
description: "Whether to show the browser while export",
|
|
54
|
-
required: false,
|
|
55
|
-
control: {
|
|
56
|
-
type: "boolean",
|
|
57
|
-
},
|
|
58
|
-
value: false,
|
|
59
|
-
label: "Start headless",
|
|
60
|
-
},
|
|
61
|
-
timeout: createNumberParam(120, {
|
|
62
|
-
description: "The timeout (in seconds) to close the browser if it's stuck",
|
|
63
|
-
required: false,
|
|
64
|
-
label: "Timeout",
|
|
65
|
-
}),
|
|
66
|
-
// customBrowser: {
|
|
67
|
-
// description: 'Start your own browser rather than the predefined one',
|
|
68
|
-
// control: {
|
|
69
|
-
// type: 'path',
|
|
70
|
-
// options: {
|
|
71
|
-
// properties: ['openFile']
|
|
72
|
-
// }
|
|
73
|
-
// },
|
|
74
|
-
// label: 'Custom browser',
|
|
75
|
-
// value: ''
|
|
76
|
-
// },
|
|
77
|
-
customProfile: createPathParam(undefined, {
|
|
78
|
-
required: false,
|
|
79
|
-
description:
|
|
80
|
-
"Use your own profile (X:\\Users\\XXX\\AppData\\Local\\Google\\Chrome\\User Data). Usefull if you want to reuse plugins installed in your current browser",
|
|
81
|
-
control: {
|
|
82
|
-
type: "path",
|
|
83
|
-
options: {
|
|
84
|
-
properties: ["openDirectory"],
|
|
85
|
-
defaultPath: baseProfile,
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
label: "Custom profile",
|
|
89
|
-
}),
|
|
90
|
-
// addonsFolder: {
|
|
91
|
-
// description: 'Folder containing addons to import in the editor',
|
|
92
|
-
// required: false,
|
|
93
|
-
// control: {
|
|
94
|
-
// type: 'path',
|
|
95
|
-
// options: {
|
|
96
|
-
// buttonLabel: 'Addons folder',
|
|
97
|
-
// properties: ['openDirectory']
|
|
98
|
-
// }
|
|
99
|
-
// },
|
|
100
|
-
// value: '',
|
|
101
|
-
// label: 'Addons folder'
|
|
102
|
-
// }
|
|
103
|
-
} satisfies InputsDefinition;
|
|
104
|
-
|
|
105
|
-
type Inputs = ParamsToInput<typeof sharedParams>;
|
|
106
|
-
|
|
107
|
-
export const exportc3p = async <ACTION extends Action>(
|
|
108
|
-
file: string,
|
|
109
|
-
{ cwd, log, inputs, setOutput, paths, abortSignal, context: ctx }: ActionRunnerData<ACTION>,
|
|
110
|
-
) => {
|
|
111
|
-
let browserContext: BrowserContext | undefined = undefined;
|
|
112
|
-
let browser: any | undefined = undefined;
|
|
113
|
-
|
|
114
|
-
abortSignal.addEventListener("abort", () => {
|
|
115
|
-
console.error("aborted");
|
|
116
|
-
|
|
117
|
-
browserContext?.close();
|
|
118
|
-
});
|
|
119
|
-
const newInputs = inputs as Inputs;
|
|
120
|
-
|
|
121
|
-
// const { addonsFolder } = newInputs
|
|
122
|
-
|
|
123
|
-
const { thirdparty, node, pnpm } = paths;
|
|
124
|
-
|
|
125
|
-
const browserName: "chromium" | "firefox" | "webkit" = "chromium";
|
|
126
|
-
|
|
127
|
-
const { packageDir: playwrightPkgPath } = await fetchPackage("playwright-core", "1.48.2", {
|
|
128
|
-
installDeps: true,
|
|
129
|
-
context: ctx,
|
|
130
|
-
});
|
|
131
|
-
const playwrightCli = join(playwrightPkgPath, "cli.js");
|
|
132
|
-
const browsersPath = join(thirdparty, "playwright-browsers");
|
|
133
|
-
|
|
134
|
-
process.env.PLAYWRIGHT_BROWSERS_PATH = browsersPath;
|
|
135
|
-
|
|
136
|
-
log("Downloading browser to", browsersPath);
|
|
137
|
-
await runWithLiveLogs(
|
|
138
|
-
node,
|
|
139
|
-
[playwrightCli, "install", browserName],
|
|
140
|
-
{
|
|
141
|
-
env: {
|
|
142
|
-
...process.env,
|
|
143
|
-
PLAYWRIGHT_BROWSERS_PATH: browsersPath,
|
|
144
|
-
PATH: `${dirname(node)}${delimiter}${process.env.PATH}`,
|
|
145
|
-
},
|
|
146
|
-
cancelSignal: abortSignal,
|
|
147
|
-
},
|
|
148
|
-
log,
|
|
149
|
-
{
|
|
150
|
-
onStdout(data) {
|
|
151
|
-
log(data);
|
|
152
|
-
},
|
|
153
|
-
onStderr(data) {
|
|
154
|
-
log(data);
|
|
155
|
-
},
|
|
156
|
-
},
|
|
157
|
-
);
|
|
158
|
-
|
|
159
|
-
const require = createRequire(import.meta.url);
|
|
160
|
-
const playwrightModule = require(join(playwrightPkgPath, "index.js"));
|
|
161
|
-
const playwright = playwrightModule.default || playwrightModule;
|
|
162
|
-
|
|
163
|
-
const downloadDir = join(cwd, "playwright");
|
|
164
|
-
|
|
165
|
-
log("Browser downloaded to", downloadDir);
|
|
166
|
-
|
|
167
|
-
log("Exporting construct project");
|
|
168
|
-
|
|
169
|
-
console.log("newInputs", newInputs);
|
|
170
|
-
|
|
171
|
-
const browserInstance = playwright[browserName];
|
|
172
|
-
|
|
173
|
-
let version = newInputs.version;
|
|
174
|
-
// if version is full digit, prepend "r", otherwise, use as is
|
|
175
|
-
if (version && /^\d+$/.test(version as string)) {
|
|
176
|
-
version = `r${version}`;
|
|
177
|
-
}
|
|
178
|
-
const headless = newInputs.headless;
|
|
179
|
-
|
|
180
|
-
// if (newInputs.customBrowser && !newInputs.customProfile) {
|
|
181
|
-
// throw new Error('You must specify a custom profile when using a custom browser')
|
|
182
|
-
// }
|
|
183
|
-
|
|
184
|
-
// if (!newInputs.customBrowser && newInputs.customProfile) {
|
|
185
|
-
// throw new Error('You must specify a custom browser when using a custom profile')
|
|
186
|
-
// }
|
|
187
|
-
|
|
188
|
-
// if (newInputs.customBrowser && newInputs.customProfile) {
|
|
189
|
-
if (newInputs.customProfile) {
|
|
190
|
-
const customProfile = join(cwd, "playwright-profile");
|
|
191
|
-
|
|
192
|
-
await mkdir(customProfile, {
|
|
193
|
-
recursive: true,
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
const indexedDbPathSource = join(newInputs.customProfile as string, "Default", "IndexedDB");
|
|
197
|
-
const indexedDbPathDestination = join(customProfile, "Default", "IndexedDB");
|
|
198
|
-
const pathsToCopy = [
|
|
199
|
-
"https_editor.construct.net_0.indexeddb.blob",
|
|
200
|
-
"https_editor.construct.net_0.indexeddb.leveldb",
|
|
201
|
-
];
|
|
202
|
-
|
|
203
|
-
for (const p of pathsToCopy) {
|
|
204
|
-
const from = join(indexedDbPathSource, p);
|
|
205
|
-
const to = join(indexedDbPathDestination, p);
|
|
206
|
-
await cp(from, to, { recursive: true });
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
browserContext = await browserInstance.launchPersistentContext(customProfile, {
|
|
210
|
-
headless: headless as boolean,
|
|
211
|
-
locale: "en-US",
|
|
212
|
-
recordVideo: isCI
|
|
213
|
-
? {
|
|
214
|
-
dir: join(process.cwd(), "playwright"),
|
|
215
|
-
}
|
|
216
|
-
: undefined,
|
|
217
|
-
});
|
|
218
|
-
} else {
|
|
219
|
-
browser = await browserInstance.launch({
|
|
220
|
-
headless: headless as boolean,
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
browserContext = await browser.newContext({
|
|
224
|
-
locale: "en-US",
|
|
225
|
-
recordVideo: isCI
|
|
226
|
-
? {
|
|
227
|
-
dir: join(process.cwd(), "playwright"),
|
|
228
|
-
}
|
|
229
|
-
: undefined,
|
|
230
|
-
});
|
|
231
|
-
await browserContext?.clearPermissions();
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (!browserContext) {
|
|
235
|
-
throw new Error("Failed to initialize browser context");
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const page = await browserContext.newPage();
|
|
239
|
-
|
|
240
|
-
page.setDefaultTimeout((newInputs.timeout as number) * 1000);
|
|
241
|
-
|
|
242
|
-
// this exact sequn=ence make it work
|
|
243
|
-
await page.addInitScript(() => {
|
|
244
|
-
// @ts-expect-error dds
|
|
245
|
-
delete self.showOpenFilePicker;
|
|
246
|
-
});
|
|
247
|
-
page.on("filechooser", (worker) => {
|
|
248
|
-
console.log("filechooser created: " + worker.page.name);
|
|
249
|
-
});
|
|
250
|
-
// ---------------------------------
|
|
251
|
-
|
|
252
|
-
try {
|
|
253
|
-
const result = await script(
|
|
254
|
-
page,
|
|
255
|
-
log,
|
|
256
|
-
file,
|
|
257
|
-
newInputs.username as string,
|
|
258
|
-
newInputs.password as string,
|
|
259
|
-
version as string,
|
|
260
|
-
downloadDir,
|
|
261
|
-
// addonsFolder,
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
log("Setting output result to ", result);
|
|
265
|
-
|
|
266
|
-
setOutput("folder", result); // deprecated
|
|
267
|
-
|
|
268
|
-
setOutput("parentFolder", dirname(result));
|
|
269
|
-
setOutput("zipFile", result);
|
|
270
|
-
} catch (e: any) {
|
|
271
|
-
log("error, no result, crashed", e);
|
|
272
|
-
throw new Error("ConstructExport failed: " + e.message);
|
|
273
|
-
} finally {
|
|
274
|
-
if (browserContext) {
|
|
275
|
-
await browserContext.close();
|
|
276
|
-
}
|
|
277
|
-
if (browser) {
|
|
278
|
-
await browser.close();
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
export const constructVersionValidator = (options: any) => {
|
|
284
|
-
void options;
|
|
285
|
-
return v.pipe(v.string(), v.regex(/^\d+(-\d+)?$/, "Invalid version"));
|
|
286
|
-
};
|
package/src/export.test.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest";
|
|
2
|
-
import { ExportActionRunner } from "./export-c3p.js";
|
|
3
|
-
import { browserWindow } from "@pipelab/shared";
|
|
4
|
-
|
|
5
|
-
test("adds 1 + 2 to equal 3", async () => {
|
|
6
|
-
const outputs: Record<string, unknown> = {};
|
|
7
|
-
// await ExportActionRunner({
|
|
8
|
-
// inputs: {
|
|
9
|
-
// password: '123',
|
|
10
|
-
// headless: false,
|
|
11
|
-
// username: 'abc',
|
|
12
|
-
// version: '350',
|
|
13
|
-
// file: ''
|
|
14
|
-
// },
|
|
15
|
-
// log: (...args) => {
|
|
16
|
-
// console.log(...args)
|
|
17
|
-
// },
|
|
18
|
-
// setOutput: (key, value) => {
|
|
19
|
-
// outputs[key] = value
|
|
20
|
-
// },
|
|
21
|
-
// meta: {
|
|
22
|
-
// definition: ''
|
|
23
|
-
// },
|
|
24
|
-
// setMeta: () => {
|
|
25
|
-
// console.log('set meta defined here')
|
|
26
|
-
// },
|
|
27
|
-
// cwd: '',
|
|
28
|
-
// paths: {
|
|
29
|
-
// assets: '',
|
|
30
|
-
// unpack: ''
|
|
31
|
-
// },
|
|
32
|
-
// api: undefined,
|
|
33
|
-
// browserWindow
|
|
34
|
-
// })
|
|
35
|
-
console.log("outputs", outputs);
|
|
36
|
-
expect(true).toBe(true);
|
|
37
|
-
}, 120_000);
|
package/src/index.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { createNodeDefinition } from "@pipelab/plugin-core";
|
|
2
|
-
import { exportAction, ExportActionRunner } from "./export-c3p";
|
|
3
|
-
import { exportProjectAction, ExportProjectActionRunner } from "./export-project";
|
|
4
|
-
const icon = new URL("./assets/construct.webp", import.meta.url).href;
|
|
5
|
-
import { constructVersionValidator } from "./export-shared";
|
|
6
|
-
|
|
7
|
-
export default createNodeDefinition({
|
|
8
|
-
description: "Construct",
|
|
9
|
-
name: "Construct",
|
|
10
|
-
id: "construct",
|
|
11
|
-
icon: {
|
|
12
|
-
type: "image",
|
|
13
|
-
image: icon,
|
|
14
|
-
},
|
|
15
|
-
nodes: [
|
|
16
|
-
{
|
|
17
|
-
node: exportAction,
|
|
18
|
-
runner: ExportActionRunner,
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
node: exportProjectAction,
|
|
22
|
-
runner: ExportProjectActionRunner,
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
validators: [
|
|
26
|
-
// {
|
|
27
|
-
// id: 'construct-version',
|
|
28
|
-
// description: 'Version must be a valid semver',
|
|
29
|
-
// validator: constructVersionValidator
|
|
30
|
-
// }
|
|
31
|
-
],
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
export type { Params as ExportParams } from "./export-c3p";
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { expect, test, describe, afterEach } from "vitest";
|
|
2
|
-
import { readFile, access } from "node:fs/promises";
|
|
3
|
-
import { join, resolve, dirname } from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { createSandbox, runAction } from "@pipelab/test-utils";
|
|
6
|
-
import { ExportActionRunner } from "../../src/export-c3p";
|
|
7
|
-
|
|
8
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
-
const __dirname = dirname(__filename);
|
|
10
|
-
const fixturesPath = join(__dirname, "fixtures");
|
|
11
|
-
|
|
12
|
-
describe("End-to-End: Construct 3 Export Pipeline", () => {
|
|
13
|
-
let sandbox: Awaited<ReturnType<typeof createSandbox>>;
|
|
14
|
-
|
|
15
|
-
afterEach(async () => {
|
|
16
|
-
if (sandbox) {
|
|
17
|
-
await sandbox.remove();
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test(
|
|
22
|
-
"should run the full C3 export action",
|
|
23
|
-
async () => {
|
|
24
|
-
sandbox = await createSandbox("c3-pipeline-e2e");
|
|
25
|
-
const fixtures = fixturesPath;
|
|
26
|
-
const jsonProject = JSON.parse(await readFile(join(fixtures, "c3-export.json"), "utf-8"));
|
|
27
|
-
|
|
28
|
-
// 1. Prepare inputs
|
|
29
|
-
const testC3pPath = resolve(fixtures, "c3-export/test.c3p");
|
|
30
|
-
const blockParams = jsonProject.canvas?.blocks?.[0]?.params;
|
|
31
|
-
|
|
32
|
-
const inputs = {
|
|
33
|
-
file: testC3pPath,
|
|
34
|
-
version: JSON.parse(blockParams?.version?.value || '"stable"'),
|
|
35
|
-
type: JSON.parse(blockParams?.type?.value || '"web"'),
|
|
36
|
-
// Add other required inputs from sharedParams if needed
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// 2. Run the action directly
|
|
40
|
-
const result = await runAction(ExportActionRunner, {
|
|
41
|
-
inputs,
|
|
42
|
-
sandboxPath: sandbox.path,
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// 3. Verification
|
|
46
|
-
const outputs = result.outputs;
|
|
47
|
-
expect(outputs).toBeDefined();
|
|
48
|
-
|
|
49
|
-
expect(outputs.folder).toEqual(expect.any(String));
|
|
50
|
-
expect(outputs.parentFolder).toEqual(expect.any(String));
|
|
51
|
-
expect(outputs.zipFile).toEqual(expect.any(String));
|
|
52
|
-
|
|
53
|
-
// Verify that the output files/folders actually exist
|
|
54
|
-
await expect(access(outputs.folder as string)).resolves.not.toThrow();
|
|
55
|
-
await expect(access(outputs.parentFolder as string)).resolves.not.toThrow();
|
|
56
|
-
await expect(access(outputs.zipFile as string)).resolves.not.toThrow();
|
|
57
|
-
},
|
|
58
|
-
10 * 60 * 1000,
|
|
59
|
-
);
|
|
60
|
-
});
|
|
Binary file
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"description": "Export from Construct, package with Electron, then upload to Steam",
|
|
3
|
-
"name": "From Construct to Steam",
|
|
4
|
-
"variables": [],
|
|
5
|
-
"canvas": {
|
|
6
|
-
"triggers": [
|
|
7
|
-
{
|
|
8
|
-
"type": "event",
|
|
9
|
-
"origin": {
|
|
10
|
-
"pluginId": "system",
|
|
11
|
-
"nodeId": "manual"
|
|
12
|
-
},
|
|
13
|
-
"uid": "manual-start",
|
|
14
|
-
"params": {}
|
|
15
|
-
}
|
|
16
|
-
],
|
|
17
|
-
"blocks": [
|
|
18
|
-
{
|
|
19
|
-
"uid": "export-construct-project",
|
|
20
|
-
"type": "action",
|
|
21
|
-
"origin": {
|
|
22
|
-
"nodeId": "export-construct-project",
|
|
23
|
-
"pluginId": "construct"
|
|
24
|
-
},
|
|
25
|
-
"params": {
|
|
26
|
-
"file": {
|
|
27
|
-
"editor": "editor",
|
|
28
|
-
"value": "\"./tests/e2e/fixtures/c3-export/test.c3p\""
|
|
29
|
-
},
|
|
30
|
-
"username": {
|
|
31
|
-
"editor": "editor",
|
|
32
|
-
"value": ""
|
|
33
|
-
},
|
|
34
|
-
"password": {
|
|
35
|
-
"editor": "editor",
|
|
36
|
-
"value": ""
|
|
37
|
-
},
|
|
38
|
-
"version": {
|
|
39
|
-
"editor": "editor",
|
|
40
|
-
"value": ""
|
|
41
|
-
},
|
|
42
|
-
"headless": {
|
|
43
|
-
"editor": "editor",
|
|
44
|
-
"value": true
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
]
|
|
49
|
-
},
|
|
50
|
-
"version": "3.0.0"
|
|
51
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Test</title>
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
OK
|
|
10
|
-
<script>
|
|
11
|
-
// window.electronAPI.exit(0)
|
|
12
|
-
|
|
13
|
-
const ws = new WebSocket("ws://localhost:31753");
|
|
14
|
-
|
|
15
|
-
ws.onopen = () => {
|
|
16
|
-
console.log("WebSocket opened");
|
|
17
|
-
|
|
18
|
-
/** @type {import('@pipelab/core').MakeInputOutput<import('@pipelab/core').MessageExit, 'input'>} */
|
|
19
|
-
const orderPath = {
|
|
20
|
-
url: "/exit",
|
|
21
|
-
body: {
|
|
22
|
-
code: 0,
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
ws.send(JSON.stringify(orderPath));
|
|
26
|
-
};
|
|
27
|
-
</script>
|
|
28
|
-
</body>
|
|
29
|
-
</html>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "vitest/config";
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
test: {
|
|
5
|
-
fileParallelism: false,
|
|
6
|
-
testTimeout: 60000,
|
|
7
|
-
hookTimeout: 60000,
|
|
8
|
-
maxWorkers: 1,
|
|
9
|
-
minWorkers: 1,
|
|
10
|
-
poolOptions: {
|
|
11
|
-
forks: {
|
|
12
|
-
singleFork: true,
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
include: ["**/*.spec.ts"],
|
|
16
|
-
root: "tests/e2e",
|
|
17
|
-
environment: "node",
|
|
18
|
-
env: { NODE_ENV: "development", PIPELAB_DISABLE_HISTORY: "true" },
|
|
19
|
-
},
|
|
20
|
-
});
|
package/tsconfig.json
DELETED
package/tsdown.config.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "tsdown";
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
entry: ["src/index.ts"],
|
|
5
|
-
format: ["esm", "cjs"],
|
|
6
|
-
dts: true,
|
|
7
|
-
clean: true,
|
|
8
|
-
loader: {
|
|
9
|
-
".webp": "dataurl",
|
|
10
|
-
".png": "dataurl",
|
|
11
|
-
".jpg": "dataurl",
|
|
12
|
-
".jpeg": "dataurl",
|
|
13
|
-
".svg": "dataurl",
|
|
14
|
-
},
|
|
15
|
-
});
|