@fedify/cli 2.0.0-pr.469.1873 → 2.0.0-pr.479.1900

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/deno.json +1 -1
  2. package/dist/deno.js +1 -1
  3. package/dist/imagerenderer.js +1 -1
  4. package/dist/init/action/configs.js +22 -13
  5. package/dist/init/action/const.js +10 -0
  6. package/dist/init/action/deps.js +26 -28
  7. package/dist/init/action/install.js +11 -13
  8. package/dist/init/action/mod.js +1 -1
  9. package/dist/init/action/notice.js +8 -19
  10. package/dist/init/action/patch.js +34 -28
  11. package/dist/init/action/precommand.js +7 -2
  12. package/dist/init/action/recommend.js +1 -1
  13. package/dist/init/action/set.js +1 -1
  14. package/dist/init/action/templates.js +2 -1
  15. package/dist/init/ask/kv.js +24 -13
  16. package/dist/init/ask/mq.js +26 -13
  17. package/dist/init/command.js +20 -3
  18. package/dist/init/lib.js +16 -10
  19. package/dist/init/mod.js +2 -1
  20. package/dist/init/templates/nitro/.env.test.tpl +1 -0
  21. package/dist/init/templates/nitro/nitro.config.ts.tpl +12 -3
  22. package/dist/init/test/action.js +15 -0
  23. package/dist/init/test/create.js +100 -0
  24. package/dist/init/test/fill.js +26 -0
  25. package/dist/init/test/lookup.js +189 -0
  26. package/dist/init/test/run.js +26 -0
  27. package/dist/init/test/utils.js +17 -0
  28. package/dist/init/webframeworks.js +35 -33
  29. package/dist/mod.js +4 -2
  30. package/dist/utils.js +75 -8
  31. package/package.json +5 -5
  32. package/src/init/action/configs.ts +56 -13
  33. package/src/init/action/const.ts +9 -0
  34. package/src/init/action/deps.ts +98 -30
  35. package/src/init/action/install.ts +17 -52
  36. package/src/init/action/notice.ts +12 -13
  37. package/src/init/action/patch.ts +49 -28
  38. package/src/init/action/precommand.ts +9 -2
  39. package/src/init/action/set.ts +2 -15
  40. package/src/init/action/templates.ts +3 -2
  41. package/src/init/action/utils.ts +1 -1
  42. package/src/init/ask/kv.ts +64 -21
  43. package/src/init/ask/mq.ts +69 -20
  44. package/src/init/command.ts +39 -1
  45. package/src/init/lib.ts +24 -12
  46. package/src/init/mod.ts +2 -1
  47. package/src/init/templates/nitro/.env.test.tpl +1 -0
  48. package/src/init/templates/nitro/nitro.config.ts.tpl +12 -3
  49. package/src/init/test/action.ts +25 -0
  50. package/src/init/test/create.ts +137 -0
  51. package/src/init/test/fill.ts +61 -0
  52. package/src/init/test/lookup.ts +253 -0
  53. package/src/init/test/run.ts +42 -0
  54. package/src/init/test/types.ts +34 -0
  55. package/src/init/test/utils.ts +21 -0
  56. package/src/init/types.ts +3 -3
  57. package/src/init/webframeworks.ts +39 -23
  58. package/src/mod.ts +10 -1
  59. package/src/utils.ts +128 -10
@@ -3,7 +3,7 @@
3
3
 
4
4
  import { debugOption } from "../globals.js";
5
5
  import { KV_STORE, MESSAGE_QUEUE, PACKAGE_MANAGER, WEB_FRAMEWORK } from "./const.js";
6
- import { argument, choice, command, constant, message, object, option, optionNames, optional } from "@optique/core";
6
+ import { argument, choice, command, constant, message, multiple, object, option, optionNames, optional } from "@optique/core";
7
7
  import { path } from "@optique/run";
8
8
 
9
9
  //#region src/init/command.ts
@@ -11,6 +11,7 @@ const webFramework = optional(option("-w", "--web-framework", choice(WEB_FRAMEWO
11
11
  const packageManager = optional(option("-p", "--package-manager", choice(PACKAGE_MANAGER, { metavar: "PACKAGE_MANAGER" }), { description: message`The package manager to use for installing dependencies.` }));
12
12
  const kvStore = optional(option("-k", "--kv-store", choice(KV_STORE, { metavar: "KV_STORE" }), { description: message`The key-value store to use for caching and some other features.` }));
13
13
  const messageQueue = optional(option("-m", "--message-queue", choice(MESSAGE_QUEUE, { metavar: "MESSAGE_QUEUE" }), { description: message`The message queue to use for background tasks.` }));
14
+ const testMode = option("--test-mode", { description: message`The test mode to use for testing purposes.` });
14
15
  const initCommand = command("init", object("Initialization options", {
15
16
  command: constant("init"),
16
17
  dir: optional(argument(path({ metavar: "DIR" }), { description: message`The project directory to initialize. If a specified directory does not exist, it will be created.` })),
@@ -19,7 +20,8 @@ const initCommand = command("init", object("Initialization options", {
19
20
  kvStore,
20
21
  messageQueue,
21
22
  dryRun: option("-d", "--dry-run", { description: message`Perform a trial run with no changes made.` }),
22
- debugOption
23
+ debugOption,
24
+ testMode
23
25
  }), {
24
26
  brief: message`Initialize a new Fedify project directory.`,
25
27
  description: message`Initialize a new Fedify project directory.
@@ -28,6 +30,21 @@ By default, it initializes the current directory. You can specify a different d
28
30
 
29
31
  Unless you specify all options (${optionNames(["-w", "--web-framework"])}, ${optionNames(["-p", "--package-manager"])}, ${optionNames(["-k", "--kv-store"])}, and ${optionNames(["-m", "--message-queue"])}), it will prompt you to select the options interactively.`
30
32
  });
33
+ const testInitCommand = command("test-init", object("Initialization options", {
34
+ command: constant("test-init"),
35
+ webFramework: multiple(webFramework),
36
+ packageManager: multiple(packageManager),
37
+ kvStore: multiple(kvStore),
38
+ messageQueue: multiple(messageQueue),
39
+ hydRun: option("-h", "--hyd-run", { description: message`Test with files creations and installations.` }),
40
+ dryRun: option("-d", "--dry-run", { description: message`Log outputs without creating files.` }),
41
+ debugOption
42
+ }), {
43
+ brief: message`Test an initializing command .`,
44
+ description: message`Test an initializing command on temporary directories.
45
+
46
+ Unless you specify all options (${optionNames(["-w", "--web-framework"])}, ${optionNames(["-p", "--package-manager"])}, ${optionNames(["-k", "--kv-store"])}, and ${optionNames(["-m", "--message-queue"])}), it will test all combinations of the options.`
47
+ });
31
48
 
32
49
  //#endregion
33
- export { initCommand };
50
+ export { initCommand, testInitCommand };
package/dist/init/lib.js CHANGED
@@ -45,14 +45,14 @@ async function isPackageManagerAvailable(pm) {
45
45
  return false;
46
46
  }
47
47
  const readTemplate = (templatePath) => readFileSync(join(import.meta.dirname, "templates", ...(templatePath + ".tpl").split("/")), "utf8");
48
- const getInstruction = (pm) => message`
48
+ const getInstruction = (pm, port) => message`
49
49
  To start the server, run the following command:
50
50
 
51
51
  ${commandLine(getDevCommand(pm))}
52
52
 
53
53
  Then, try look up an actor from your server:
54
54
 
55
- ${commandLine("fedify lookup http://localhost:8000/users/john")}
55
+ ${commandLine(`fedify lookup http://localhost:${port}/users/john`)}
56
56
 
57
57
  `;
58
58
  const getDevCommand = (pm) => pm === "deno" ? "deno task dev" : pm === "bun" ? "bun dev" : `${pm} run dev`;
@@ -92,18 +92,20 @@ const isDirectoryEmpty = async (path$1) => {
92
92
  return true;
93
93
  }
94
94
  };
95
+ /**
96
+ * Converts a package manager to its corresponding runtime.
97
+ * @param pm - The package manager (deno, bun, npm, yarn, pnpm)
98
+ * @returns The runtime name (deno, bun, or node)
99
+ */
100
+ const packageManagerToRuntime = (pm) => pm === "deno" ? "deno" : pm === "bun" ? "bun" : "node";
95
101
  const getNextInitCommand = (pm) => [
96
102
  ...createNextAppCommand(pm),
97
103
  ".",
98
- "--ts",
99
- "--app",
100
- "--biome",
101
- "--skip-install"
104
+ "--yes"
102
105
  ];
103
106
  const createNextAppCommand = (pm) => pm === "deno" ? [
104
107
  "deno",
105
- "run",
106
- "-A",
108
+ "-Ar",
107
109
  "npm:create-next-app@latest"
108
110
  ] : pm === "bun" ? [
109
111
  "bun",
@@ -118,13 +120,17 @@ const getNitroInitCommand = (pm) => [
118
120
  ...createNitroAppCommand(pm),
119
121
  pm === "deno" ? "npm:giget@latest" : "giget@latest",
120
122
  "nitro",
121
- "."
123
+ ".",
124
+ "&&",
125
+ "rm",
126
+ "nitro.config.ts"
122
127
  ];
123
128
  const createNitroAppCommand = (pm) => pm === "deno" ? [
124
129
  "deno",
125
130
  "run",
126
131
  "-A"
127
132
  ] : pm === "bun" ? ["bunx"] : pm === "npm" ? ["npx"] : [pm, "dlx"];
133
+ const isTest = ({ testMode }) => testMode;
128
134
 
129
135
  //#endregion
130
- export { PACKAGE_VERSION, createFile, getInstallUrl, getInstruction, getLabel, getNextInitCommand, getNitroInitCommand, isDirectoryEmpty, isPackageManagerAvailable, kvStores, logger, messageQueues, readTemplate, throwUnlessNotExists };
136
+ export { PACKAGE_VERSION, createFile, getDevCommand, getInstallUrl, getInstruction, getLabel, getNextInitCommand, getNitroInitCommand, isDirectoryEmpty, isPackageManagerAvailable, isTest, kvStores, logger, messageQueues, packageManagerToRuntime, readTemplate, throwUnlessNotExists };
package/dist/init/mod.js CHANGED
@@ -2,4 +2,5 @@
2
2
  import { Temporal } from "@js-temporal/polyfill";
3
3
 
4
4
  import action_default from "./action/mod.js";
5
- import { initCommand } from "./command.js";
5
+ import { initCommand, testInitCommand } from "./command.js";
6
+ import action_default$1 from "./test/action.js";
@@ -0,0 +1 @@
1
+ HOST=127.0.0.1
@@ -1,5 +1,14 @@
1
- // https://nitro.unjs.io/config
1
+ import { defineNitroConfig } from "nitropack/config"
2
+
3
+ // https://nitro.build/config
2
4
  export default defineNitroConfig({
5
+ errorHandler: "~/error",
6
+ esbuild: {
7
+ options: {
8
+ target: "esnext",
9
+ },
10
+ },
11
+ compatibilityDate: "latest",
3
12
  srcDir: "server",
4
- errorHandler: "~/error"
5
- });
13
+ imports: false
14
+ });
@@ -0,0 +1,15 @@
1
+
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+
4
+ import { set } from "../../utils.js";
5
+ import { fillEmptyOptions } from "./fill.js";
6
+ import { isDryRun, isHydRun, runTests } from "./run.js";
7
+ import { emptyTestDir, genRunId, genTestDirPrefix, logTestDir } from "./utils.js";
8
+ import { pipe, tap, when } from "@fxts/core";
9
+
10
+ //#region src/init/test/action.ts
11
+ const runTestInit = (options) => pipe(options, set("runId", genRunId), set("testDirPrefix", genTestDirPrefix), tap(emptyTestDir), fillEmptyOptions, tap(when(isHydRun, runTests(false))), tap(when(isDryRun, runTests(true))), tap(logTestDir));
12
+ var action_default = runTestInit;
13
+
14
+ //#endregion
15
+ export { action_default as default };
@@ -0,0 +1,100 @@
1
+
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+
4
+ import { CommandError, printErrorMessage, printMessage, product, runSubCommand } from "../../utils.js";
5
+ import pm_default from "../json/pm.js";
6
+ import webframeworks_default from "../webframeworks.js";
7
+ import { kvStores, messageQueues } from "../lib.js";
8
+ import { join, sep } from "node:path";
9
+ import { appendFile, mkdir } from "node:fs/promises";
10
+ import { values } from "@optique/core";
11
+ import process from "node:process";
12
+ import { filter, isEmpty, pipe, toArray } from "@fxts/core";
13
+
14
+ //#region src/init/test/create.ts
15
+ const BANNED_PMS = ["bun", "yarn"];
16
+ const createTestApp = (testDirPrefix, dry) => async (options) => {
17
+ const testDir = join(testDirPrefix, ...options);
18
+ const vals = values(testDir.split(sep).slice(-4));
19
+ try {
20
+ const result = await runSubCommand(toArray(genInitCommand(testDir, dry, options)), {
21
+ cwd: join(import.meta.dirname, "../../.."),
22
+ stdio: [
23
+ "ignore",
24
+ "pipe",
25
+ "pipe"
26
+ ]
27
+ });
28
+ await saveOutputs(testDir, result);
29
+ printMessage` Pass: ${vals}`;
30
+ return testDir;
31
+ } catch (error) {
32
+ if (error instanceof CommandError) await saveOutputs(testDir, {
33
+ stdout: error.stdout,
34
+ stderr: error.stderr
35
+ });
36
+ else {
37
+ const errorMessage = error instanceof Error ? error.message : String(error);
38
+ await saveOutputs(testDir, {
39
+ stdout: "",
40
+ stderr: errorMessage
41
+ });
42
+ }
43
+ printMessage` Fail: ${vals}`;
44
+ return "";
45
+ }
46
+ };
47
+ var create_default = createTestApp;
48
+ function* genInitCommand(testDir, dry, [webFramework, packageManager, kvStore, messageQueue]) {
49
+ yield "deno";
50
+ yield "run";
51
+ yield "-A";
52
+ yield "src/mod.ts";
53
+ yield "init";
54
+ yield testDir;
55
+ yield "-w";
56
+ yield webFramework;
57
+ yield "-p";
58
+ yield packageManager;
59
+ yield "-k";
60
+ yield kvStore;
61
+ yield "-m";
62
+ yield messageQueue;
63
+ yield "--test-mode";
64
+ if (dry) yield "-d";
65
+ }
66
+ const generateTestCases = ({ webFramework, packageManager, kvStore, messageQueue }) => {
67
+ const pms = filterPackageManager(packageManager);
68
+ exitIfCasesEmpty([
69
+ webFramework,
70
+ pms,
71
+ kvStore,
72
+ messageQueue
73
+ ]);
74
+ return product(webFramework, pms, kvStore, messageQueue);
75
+ };
76
+ const filterPackageManager = (pm) => pipe(pm, filter((pm$1) => BANNED_PMS.includes(pm$1) ? printErrorMessage`${pm_default[pm$1]["label"]} is not \
77
+ supported in test mode yet because ${pm_default[pm$1]["label"]} don't \
78
+ support local file dependencies properly.` : true), toArray);
79
+ const exitIfCasesEmpty = (cases) => {
80
+ if (cases.some(isEmpty)) {
81
+ printErrorMessage`No test cases to run. Exiting.`;
82
+ process.exit(1);
83
+ }
84
+ };
85
+ const saveOutputs = async (dirPath, { stdout, stderr }) => {
86
+ await mkdir(dirPath, { recursive: true });
87
+ if (stdout) await appendFile(join(dirPath, "out.txt"), stdout + "\n", "utf8");
88
+ if (stderr) await appendFile(join(dirPath, "err.txt"), stderr + "\n", "utf8");
89
+ };
90
+ function filterOptions(options) {
91
+ const [wf, pm, kv, mq] = options;
92
+ return [
93
+ webframeworks_default[wf].packageManagers,
94
+ kvStores[kv].packageManagers,
95
+ messageQueues[mq].packageManagers
96
+ ].every((pms) => pms.includes(pm));
97
+ }
98
+
99
+ //#endregion
100
+ export { create_default as default, filterOptions, generateTestCases };
@@ -0,0 +1,26 @@
1
+
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+
4
+ import { KV_STORE, MESSAGE_QUEUE, PACKAGE_MANAGER, WEB_FRAMEWORK } from "../const.js";
5
+ import { isEmpty, pipe } from "@fxts/core";
6
+
7
+ //#region src/init/test/fill.ts
8
+ const fillEmptyOptions = (options) => pipe(options, fillWebFramework, fillPackageManager, fillKVStore, fillMessageQueue, fillRunMode);
9
+ const fillOption = (key, allValues) => (options) => ({
10
+ ...options,
11
+ [key]: isEmpty(options[key]) ? allValues : options[key].filter((i) => allValues.includes(i))
12
+ });
13
+ const fillWebFramework = fillOption("webFramework", WEB_FRAMEWORK);
14
+ const fillPackageManager = fillOption("packageManager", PACKAGE_MANAGER);
15
+ const fillKVStore = fillOption("kvStore", KV_STORE);
16
+ const fillMessageQueue = fillOption("messageQueue", MESSAGE_QUEUE);
17
+ const fillRunMode = (options) => ({
18
+ ...options,
19
+ ...options.hydRun || options.dryRun ? {} : {
20
+ hydRun: true,
21
+ dryRun: true
22
+ }
23
+ });
24
+
25
+ //#endregion
26
+ export { fillEmptyOptions };
@@ -0,0 +1,189 @@
1
+
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+
4
+ import { printErrorMessage, printMessage, runSubCommand } from "../../utils.js";
5
+ import webframeworks_default from "../webframeworks.js";
6
+ import { getDevCommand } from "../lib.js";
7
+ import { join, sep } from "node:path";
8
+ import { values } from "@optique/core";
9
+ import process from "node:process";
10
+ import { spawn } from "node:child_process";
11
+ import { createWriteStream } from "node:fs";
12
+
13
+ //#region src/init/test/lookup.ts
14
+ const HANDLE = "john";
15
+ const STARTUP_TIMEOUT = 3e4;
16
+ const CWD = process.cwd();
17
+ const BANNED_WFS = ["next"];
18
+ /**
19
+ * Run servers for all generated apps and test them with the lookup command.
20
+ *
21
+ * @param dirs - Array of paths to generated app directories
22
+ */
23
+ async function runServerAndReadUser(dirs) {
24
+ const valid = dirs.filter(Boolean);
25
+ if (valid.length === 0) {
26
+ printErrorMessage`\nNo directories to lookup test.`;
27
+ return;
28
+ }
29
+ const filtered = filterWebFrameworks(valid);
30
+ printMessage`\nLookup Test start for ${String(filtered.length)} app(s)!`;
31
+ const results = await Array.fromAsync(filtered, testApp);
32
+ const successCount = results.filter(Boolean).length;
33
+ const failCount = results.length - successCount;
34
+ printMessage`Lookup Test Results:
35
+ Total: ${String(results.length)}
36
+ Passed: ${String(successCount)}
37
+ Failed: ${String(failCount)}\n\n`;
38
+ }
39
+ function filterWebFrameworks(dirs) {
40
+ const wfs = new Set(dirs.map((dir) => dir.split(sep).slice(-4, -3)[0]));
41
+ const hasBanned = BANNED_WFS.filter((wf) => wfs.has(wf));
42
+ if (!hasBanned) return dirs;
43
+ const bannedLabels = hasBanned.map((wf) => webframeworks_default[wf]["label"]);
44
+ printErrorMessage`\n${values(bannedLabels)} is not supported in test mode yet.`;
45
+ return dirs.filter((dir) => !BANNED_WFS.includes(dir.split(sep).slice(-4, -3)[0]));
46
+ }
47
+ /**
48
+ * Run the dev server and test with lookup command.
49
+ */
50
+ async function testApp(dir) {
51
+ const [wf, pm, kv, mq] = dir.split(sep).slice(-4);
52
+ printMessage` Testing ${values([
53
+ wf,
54
+ pm,
55
+ kv,
56
+ mq
57
+ ])}...`;
58
+ const result = await serverClosure(dir, getDevCommand(pm), sendLookup);
59
+ printMessage` Lookup ${result ? "successful" : "failed"} for ${values([
60
+ wf,
61
+ pm,
62
+ kv,
63
+ mq
64
+ ])}!`;
65
+ if (!result) printMessage` Check out these files for more details:
66
+ ${join(dir, "out.txt")}
67
+ ${join(dir, "err.txt")}\n`;
68
+ printMessage`\n`;
69
+ return result;
70
+ }
71
+ const sendLookup = async (port) => {
72
+ const serverUrl = `http://localhost:${port}`;
73
+ const lookupTarget = `${serverUrl}/users/${HANDLE}`;
74
+ printMessage` Waiting for server to start at ${serverUrl}...`;
75
+ const isReady = await waitForServer(serverUrl, STARTUP_TIMEOUT);
76
+ if (!isReady) {
77
+ printErrorMessage`Server did not start within \
78
+ ${String(STARTUP_TIMEOUT)}ms`;
79
+ return false;
80
+ }
81
+ printMessage` Server is ready. Running lookup command...`;
82
+ try {
83
+ await runSubCommand([
84
+ "deno",
85
+ "task",
86
+ "cli",
87
+ "lookup",
88
+ lookupTarget
89
+ ], { cwd: CWD });
90
+ return true;
91
+ } catch (error) {
92
+ if (error instanceof Error) printErrorMessage`${error.message}`;
93
+ }
94
+ return false;
95
+ };
96
+ /**
97
+ * Wait for the server to be ready by checking if it responds to requests.
98
+ */
99
+ async function waitForServer(url, timeout) {
100
+ const startTime = Date.now();
101
+ while (Date.now() - startTime < timeout) {
102
+ try {
103
+ const response = await fetch(url, { signal: AbortSignal.timeout(1e3) });
104
+ if (response.ok) return true;
105
+ } catch {}
106
+ await new Promise((resolve) => setTimeout(resolve, 500));
107
+ }
108
+ return false;
109
+ }
110
+ async function serverClosure(dir, cmd, callback) {
111
+ const devCommand = cmd.split(" ");
112
+ const serverProcess = spawn(devCommand[0], devCommand.slice(1), {
113
+ cwd: dir,
114
+ stdio: [
115
+ "ignore",
116
+ "pipe",
117
+ "pipe"
118
+ ],
119
+ detached: true
120
+ });
121
+ const stdout = createWriteStream(join(dir, "out.txt"), { flags: "a" });
122
+ const stderr = createWriteStream(join(dir, "err.txt"), { flags: "a" });
123
+ serverProcess.stdout?.pipe(stdout);
124
+ serverProcess.stderr?.pipe(stderr);
125
+ try {
126
+ const port = await determinePort(serverProcess);
127
+ return await callback(port);
128
+ } finally {
129
+ try {
130
+ process.kill(-serverProcess.pid, "SIGKILL");
131
+ } catch {
132
+ serverProcess.kill("SIGKILL");
133
+ stdout.end();
134
+ stderr.end();
135
+ }
136
+ }
137
+ }
138
+ function determinePort(server) {
139
+ return new Promise((resolve, reject) => {
140
+ const timeout = setTimeout(() => {
141
+ reject(/* @__PURE__ */ new Error("Timeout: Could not determine port from server output"));
142
+ }, STARTUP_TIMEOUT);
143
+ let stdoutData = "";
144
+ let stderrData = "";
145
+ const portPatterns = [
146
+ /listening on.*:(\d+)/i,
147
+ /server.*:(\d+)/i,
148
+ /port\s*:?\s*(\d+)/i,
149
+ /localhost:(\d+)/i,
150
+ /0\.0\.0\.0:(\d+)/i,
151
+ /127\.0\.0\.1:(\d+)/i,
152
+ /https?:\/\/[^:]+:(\d+)/i
153
+ ];
154
+ const checkForPort = (data) => {
155
+ for (const pattern of portPatterns) {
156
+ const match = data.match(pattern);
157
+ if (match && match[1]) {
158
+ const port = Number.parseInt(match[1], 10);
159
+ if (port > 0 && port < 65536) {
160
+ clearTimeout(timeout);
161
+ return port;
162
+ }
163
+ }
164
+ }
165
+ return null;
166
+ };
167
+ server.stdout.on("data", (chunk) => {
168
+ stdoutData += chunk.toString();
169
+ const port = checkForPort(stdoutData);
170
+ if (port) resolve(port);
171
+ });
172
+ server.stderr.on("data", (chunk) => {
173
+ stderrData += chunk.toString();
174
+ const port = checkForPort(stderrData);
175
+ if (port) resolve(port);
176
+ });
177
+ server.on("error", (err) => {
178
+ clearTimeout(timeout);
179
+ reject(err);
180
+ });
181
+ server.on("exit", (code) => {
182
+ clearTimeout(timeout);
183
+ reject(/* @__PURE__ */ new Error(`Server exited with code ${code} before port could be determined`));
184
+ });
185
+ });
186
+ }
187
+
188
+ //#endregion
189
+ export { runServerAndReadUser };
@@ -0,0 +1,26 @@
1
+
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+
4
+ import { printMessage } from "../../utils.js";
5
+ import create_default, { filterOptions, generateTestCases } from "./create.js";
6
+ import { runServerAndReadUser } from "./lookup.js";
7
+ import { join } from "node:path";
8
+ import { optionNames } from "@optique/core";
9
+ import { filter, map as map$1, pipe, tap } from "@fxts/core";
10
+
11
+ //#region src/init/test/run.ts
12
+ const isDryRun = ({ dryRun }) => dryRun;
13
+ const isHydRun = ({ hydRun }) => hydRun;
14
+ const runTests = (dry) => ({ testDirPrefix, dryRun, hydRun,...options }) => pipe(options, printStartMessage, generateTestCases, filter(filterOptions), map$1(create_default(join(testDirPrefix, getMid(dryRun, hydRun, dry)), dry)), Array.fromAsync, runServerAndReadUser);
15
+ const printStartMessage = tap(() => printMessage`\n
16
+ Init Test start!
17
+ Options: ${optionNames([
18
+ "Web Framework",
19
+ "Package Manager",
20
+ "KV Store",
21
+ "Message Queue"
22
+ ])}`);
23
+ const getMid = (dryRun, hydRun, dry) => dryRun === hydRun ? dry ? "dry" : "hyd" : "";
24
+
25
+ //#endregion
26
+ export { isDryRun, isHydRun, runTests };
@@ -0,0 +1,17 @@
1
+
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+
4
+ import { printMessage } from "../../utils.js";
5
+ import { join } from "node:path";
6
+ import { tmpdir } from "node:os";
7
+
8
+ //#region src/init/test/utils.ts
9
+ const genRunId = () => `${Date.now()}-${Math.random().toString(36).slice(2)}`;
10
+ const genTestDirPrefix = ({ runId }) => join(tmpdir(), "fedify-init", runId);
11
+ const emptyTestDir = ({ testDirPrefix }) => Deno.remove(testDirPrefix, { recursive: true }).catch(() => {});
12
+ const logTestDir = ({ runId, testDirPrefix }) => printMessage`Test run completed.
13
+ Run ID: ${runId}
14
+ Path: ${testDirPrefix}`;
15
+
16
+ //#endregion
17
+ export { emptyTestDir, genRunId, genTestDirPrefix, logTestDir };
@@ -3,8 +3,7 @@
3
3
 
4
4
  import { replace } from "../utils.js";
5
5
  import { PACKAGE_MANAGER } from "./const.js";
6
- import { PACKAGE_VERSION, getInstruction, getNextInitCommand, getNitroInitCommand, readTemplate } from "./lib.js";
7
- import { message } from "@optique/core";
6
+ import { PACKAGE_VERSION, getInstruction, getNextInitCommand, getNitroInitCommand, packageManagerToRuntime, readTemplate } from "./lib.js";
8
7
  import { pipe } from "@fxts/core";
9
8
 
10
9
  //#region src/init/webframeworks.ts
@@ -12,27 +11,30 @@ const webFrameworks = {
12
11
  hono: {
13
12
  label: "Hono",
14
13
  packageManagers: PACKAGE_MANAGER,
15
- init: (projectName, pm) => ({
14
+ init: ({ projectName, packageManager: pm }) => ({
16
15
  dependencies: pm === "deno" ? {
17
16
  "@std/dotenv": "^0.225.2",
18
17
  "@hono/hono": "^4.5.0",
19
- "@hongminhee/x-forwarded-fetch": "^0.2.0"
18
+ "@hongminhee/x-forwarded-fetch": "^0.2.0",
19
+ "@fedify/hono": PACKAGE_VERSION
20
20
  } : pm === "bun" ? {
21
21
  hono: "^4.5.0",
22
- "x-forwarded-fetch": "^0.2.0"
22
+ "x-forwarded-fetch": "^0.2.0",
23
+ "@fedify/hono": PACKAGE_VERSION
23
24
  } : {
24
25
  "@dotenvx/dotenvx": "^1.14.1",
25
26
  hono: "^4.5.0",
26
27
  "@hono/node-server": "^1.12.0",
27
28
  tsx: "^4.17.0",
28
- "x-forwarded-fetch": "^0.2.0"
29
+ "x-forwarded-fetch": "^0.2.0",
30
+ "@fedify/hono": PACKAGE_VERSION
29
31
  },
30
32
  devDependencies: pm === "bun" ? { "@types/bun": "^1.1.6" } : {},
31
- federationFile: message`src/federation.ts`,
33
+ federationFile: "src/federation.ts",
32
34
  loggingFile: "src/logging.ts",
33
35
  files: {
34
- "src/app.tsx": pipe("hono/app.tsx", readTemplate, replace(/\/\* hono \*\//, pm === "deno" ? "@hono/hono" : "hono")).replace(/\/\* logger \*\//, projectName),
35
- "src/index.ts": readTemplate(`hono/index/${pm}.ts`)
36
+ "src/app.tsx": pipe("hono/app.tsx", readTemplate, replace(/\/\* hono \*\//, pm === "deno" ? "@hono/hono" : "hono"), replace(/\/\* logger \*\//, projectName)),
37
+ "src/index.ts": readTemplate(`hono/index/${packageManagerToRuntime(pm)}.ts`)
36
38
  },
37
39
  compilerOptions: pm === "deno" ? void 0 : {
38
40
  "lib": ["ESNext", "DOM"],
@@ -50,20 +52,16 @@ const webFrameworks = {
50
52
  "dev": pm === "deno" ? "deno run -A --watch ./src/index.ts" : pm === "bun" ? "bun run --hot ./src/index.ts" : "dotenvx run -- tsx watch ./src/index.ts",
51
53
  "prod": pm === "deno" ? "deno run -A ./src/index.ts" : pm === "bun" ? "bun run ./src/index.ts" : "dotenvx run -- node --import tsx ./src/index.ts"
52
54
  },
53
- instruction: getInstruction(pm)
54
- })
55
+ instruction: getInstruction(pm, 8e3)
56
+ }),
57
+ defaultPort: 8e3
55
58
  },
56
59
  express: {
57
60
  label: "Express",
58
- packageManagers: [
59
- "bun",
60
- "npm",
61
- "yarn",
62
- "pnpm"
63
- ],
64
- init: (projectName, pm) => ({
61
+ packageManagers: PACKAGE_MANAGER,
62
+ init: ({ projectName, packageManager: pm }) => ({
65
63
  dependencies: {
66
- express: "^4.19.2",
64
+ "npm:express": "^4.19.2",
67
65
  "@fedify/express": PACKAGE_VERSION,
68
66
  ...pm !== "deno" && pm !== "bun" ? {
69
67
  "@dotenvx/dotenvx": "^1.14.1",
@@ -74,7 +72,7 @@ const webFrameworks = {
74
72
  "@types/express": "^4.17.21",
75
73
  ...pm === "bun" ? { "@types/bun": "^1.1.6" } : {}
76
74
  },
77
- federationFile: message`src/federation.ts`,
75
+ federationFile: "src/federation.ts",
78
76
  loggingFile: "src/logging.ts",
79
77
  files: {
80
78
  "src/app.ts": readTemplate("express/app.ts").replace(/\/\* logger \*\//, projectName),
@@ -91,41 +89,45 @@ const webFrameworks = {
91
89
  "strict": true
92
90
  },
93
91
  tasks: {
94
- "dev": pm === "bun" ? "bun run --hot ./src/index.ts" : "dotenvx run -- tsx watch ./src/index.ts",
95
- "prod": pm === "bun" ? "bun run ./src/index.ts" : "dotenvx run -- node --import tsx ./src/index.ts"
92
+ "dev": pm === "bun" ? "bun run --hot ./src/index.ts" : pm === "deno" ? "deno run --allow-net --allow-env --allow-sys --watch ./src/index.ts" : "dotenvx run -- tsx watch ./src/index.ts",
93
+ "prod": pm === "bun" ? "bun run ./src/index.ts" : pm === "deno" ? "deno run --allow-net --allow-env --allow-sys ./src/index.ts" : "dotenvx run -- node --import tsx ./src/index.ts"
96
94
  },
97
- instruction: getInstruction(pm)
98
- })
95
+ instruction: getInstruction(pm, 8e3)
96
+ }),
97
+ defaultPort: 8e3
99
98
  },
100
99
  nitro: {
101
100
  label: "Nitro",
102
101
  packageManagers: PACKAGE_MANAGER,
103
- init: (_, pm) => ({
102
+ init: ({ packageManager: pm, testMode }) => ({
104
103
  command: getNitroInitCommand(pm),
105
104
  dependencies: { "@fedify/h3": PACKAGE_VERSION },
106
- federationFile: message`server/federation.ts`,
105
+ federationFile: "server/federation.ts",
107
106
  loggingFile: "server/logging.ts",
108
107
  files: {
109
108
  "server/middleware/federation.ts": readTemplate("nitro/server/middleware/federation.ts"),
110
109
  "server/error.ts": readTemplate("nitro/server/error.ts"),
111
- "nitro.config.ts": readTemplate("nitro/nitro.config.ts")
110
+ "nitro.config.ts": readTemplate("nitro/nitro.config.ts"),
111
+ ...testMode ? { ".env": readTemplate("nitro/.env.test") } : {}
112
112
  },
113
- instruction: getInstruction(pm)
114
- })
113
+ instruction: getInstruction(pm, 3e3)
114
+ }),
115
+ defaultPort: 3e3
115
116
  },
116
117
  next: {
117
118
  label: "Next.js",
118
119
  packageManagers: PACKAGE_MANAGER,
119
- init: (_, pm) => ({
120
+ init: ({ packageManager: pm }) => ({
120
121
  label: "Next.js",
121
122
  command: getNextInitCommand(pm),
122
123
  dependencies: { "@fedify/next": PACKAGE_VERSION },
123
124
  devDependencies: { "@types/node": "^20.11.2" },
124
- federationFile: message`federation/index.ts`,
125
+ federationFile: "federation/index.ts",
125
126
  loggingFile: "logging.ts",
126
127
  files: { "middleware.ts": readTemplate("next/middleware.ts") },
127
- instruction: getInstruction(pm)
128
- })
128
+ instruction: getInstruction(pm, 3e3)
129
+ }),
130
+ defaultPort: 3e3
129
131
  }
130
132
  };
131
133
  var webframeworks_default = webFrameworks;