@fedify/init 2.1.0-dev.418 → 2.1.0-dev.438

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.
@@ -4,12 +4,11 @@ import vscode_settings_for_deno_default from "../json/vscode-settings-for-deno.j
4
4
  import vscode_settings_default from "../json/vscode-settings.js";
5
5
  import { PACKAGES_PATH } from "./const.js";
6
6
  import { getDependencies, getDevDependencies, joinDepsReg } from "./deps.js";
7
- import { uniq } from "es-toolkit";
8
7
  import { execFileSync } from "node:child_process";
9
8
  import { getLogger } from "@logtape/logtape";
10
9
  import { realpathSync } from "node:fs";
11
10
  import { join, relative } from "node:path";
12
- import { concat, filter, keys, map, pick, pipe, toArray } from "@fxts/core/index.js";
11
+ import { always, cases, concat, filter, head, isArray, isEmpty, isNull, isString, keys, map, pick, pipe, prop, toArray, uniq, unless, when, zip } from "@fxts/core/index.js";
13
12
 
14
13
  //#region src/action/configs.ts
15
14
  const logger = getLogger([
@@ -25,36 +24,27 @@ const logger = getLogger([
25
24
  * @param param0 - Destructured initialization data containing KV, MQ, initializer, and directory
26
25
  * @returns Configuration object with path and Deno-specific settings
27
26
  */
28
- const loadDenoConfig = (data) => {
29
- const unstable = getUnstable(data);
30
- return {
31
- path: "deno.json",
32
- data: {
33
- ...pick(["compilerOptions", "tasks"], data.initializer),
34
- ...unstable.length > 0 ? { unstable } : {},
35
- nodeModulesDir: "auto",
36
- imports: joinDepsReg("deno")(getDependencies(data)),
37
- lint: { plugins: ["jsr:@fedify/lint"] },
38
- ...data.testMode ? { links: getLinks(data) } : {}
39
- }
40
- };
41
- };
42
- const getUnstable = ({ kv: { denoUnstable: kv = [] }, mq: { denoUnstable: mq = [] } }) => pipe(needsUnstableTemporal() ? ["temporal"] : [], concat(kv), concat(mq), toArray, uniq);
27
+ const loadDenoConfig = (data) => ({
28
+ path: "deno.json",
29
+ data: {
30
+ ...pick(["compilerOptions", "tasks"], data.initializer),
31
+ ...getUnstable(data),
32
+ nodeModulesDir: "auto",
33
+ imports: joinDepsReg("deno")(getDependencies(data)),
34
+ lint: { plugins: ["jsr:@fedify/lint"] },
35
+ ...data.testMode && !data.dryRun ? { links: getLinks(data) } : {}
36
+ }
37
+ });
38
+ const getUnstable = ({ kv: { denoUnstable: kv = [] }, mq: { denoUnstable: mq = [] } }) => pipe(needsUnstableTemporal() ? ["temporal"] : [], concat(kv), concat(mq), uniq, toArray, cases(isEmpty, always({}), (unstable) => ({ unstable })));
43
39
  const TEMPORAL_STABLE_FROM = [
44
40
  2,
45
41
  7,
46
42
  0
47
43
  ];
48
- const needsUnstableTemporal = () => {
49
- const version = getInstalledDenoVersion();
50
- if (version == null) return true;
51
- return compareVersions(version, TEMPORAL_STABLE_FROM) < 0;
52
- };
53
- const getInstalledDenoVersion = () => {
54
- const deno = getDenoVersionFromRuntime();
55
- if (deno != null) return deno;
44
+ const needsUnstableTemporal = () => pipe(getDenoVersionFromRuntime(), when(isNull, getDenoVersionFromCommand), when(isString, parseVersion), cases(isArray, isLaterOrEqualThan(TEMPORAL_STABLE_FROM), always(true)));
45
+ const getDenoVersionFromCommand = () => {
56
46
  try {
57
- const output = execFileSync("deno", ["--version"], {
47
+ return execFileSync("deno", ["--version"], {
58
48
  encoding: "utf8",
59
49
  stdio: [
60
50
  "ignore",
@@ -62,37 +52,15 @@ const getInstalledDenoVersion = () => {
62
52
  "ignore"
63
53
  ]
64
54
  });
65
- const version = output.match(/^deno\s+(\d+)\.(\d+)\.(\d+)/m);
66
- if (version == null) return null;
67
- return [
68
- Number(version[1]),
69
- Number(version[2]),
70
- Number(version[3])
71
- ];
72
55
  } catch (error) {
73
56
  logger.debug("Failed to get Deno version by executing `deno --version`: {error}", { error });
74
57
  return null;
75
58
  }
76
59
  };
77
- const getDenoVersionFromRuntime = () => {
78
- const deno = globalThis.Deno?.version?.deno;
79
- if (deno == null) return null;
80
- const version = deno.match(/^(\d+)\.(\d+)\.(\d+)/);
81
- if (version == null) return null;
82
- return [
83
- Number(version[1]),
84
- Number(version[2]),
85
- Number(version[3])
86
- ];
87
- };
88
- const compareVersions = (a, b) => {
89
- for (let i = 0; i < a.length; i++) {
90
- if (a[i] < b[i]) return -1;
91
- if (a[i] > b[i]) return 1;
92
- }
93
- return 0;
94
- };
95
- const getLinks = ({ kv, mq, initializer, dir }) => pipe({ "@fedify/fedify": "" }, merge(initializer.dependencies), merge(kv.dependencies), merge(mq.dependencies), keys, filter((dep) => dep.includes("@fedify/")), map((dep) => dep.replace("@fedify/", "")), map((dep) => join(PACKAGES_PATH, dep)), map((absolutePath) => realpathSync(absolutePath)), map((realAbsolutePath) => relative(realpathSync(dir), realAbsolutePath)), toArray);
60
+ const getDenoVersionFromRuntime = () => pipe(globalThis, prop("Deno"), prop("version"), prop("deno"));
61
+ const parseVersion = (deno) => pipe(deno.match(/^(\d+)\.(\d+)\.(\d+)/), unless(isNull, (arr) => arr.map(Number)));
62
+ const isLaterOrEqualThan = (basis) => (target) => pipe(zip(basis, target), filter(([b, t]) => t !== b), head, (a) => a ? a[0] < a[1] : true);
63
+ const getLinks = ({ kv, mq, initializer, dir }) => pipe({ "@fedify/fedify": "" }, merge(initializer.dependencies), merge(kv.dependencies), merge(mq.dependencies), keys, filter((dep) => dep.includes("@fedify/")), map((dep) => dep.replace("@fedify/", "")), map((dep) => join(PACKAGES_PATH, dep)), map(realpathSync), map((realAbsolutePath) => relative(realpathSync(dir), realAbsolutePath)), toArray);
96
64
  /**
97
65
  * Loads TypeScript configuration object for Node.js/Bun projects.
98
66
  * Uses compiler options from the framework initializer.
@@ -1,6 +1,10 @@
1
1
  import { join } from "node:path";
2
2
 
3
3
  //#region src/action/const.ts
4
+ /**
5
+ * Absolute path to the monorepo *packages/* directory.
6
+ * Used in test mode to resolve local `@fedify/*` package paths.
7
+ */
4
8
  const PACKAGES_PATH = join(import.meta.dirname, "..", "..", "..");
5
9
 
6
10
  //#endregion
@@ -30,7 +30,7 @@ const convertFedifyToLocal = (name) => pipe(name, replace("@fedify/", ""), (pkg)
30
30
  * and message queue descriptions
31
31
  * @returns A record of devDependencies with their versions
32
32
  */
33
- const getDevDependencies = ({ initializer, kv, mq, packageManager }) => pipe({ "@biomejs/biome": "^2.2.4" }, merge(initializer.devDependencies), merge(kv.devDependencies), merge(mq.devDependencies), normalizePackageNames(packageManager));
33
+ const getDevDependencies = ({ initializer, kv, mq, packageManager, testMode }) => pipe({ "@biomejs/biome": "^2.2.4" }, merge(initializer.devDependencies), merge(kv.devDependencies), merge(mq.devDependencies), when(always(testMode), isDeno({ packageManager }) ? removeFedifyDeps : addLocalFedifyDeps), normalizePackageNames(packageManager));
34
34
  /**
35
35
  * Joins package names with their versions for installation dependencies.
36
36
  * For Deno, it prefixes packages with 'jsr:'
@@ -3,6 +3,11 @@ import { noticeConfigEnv, noticeEnvKeyValue } from "./notice.js";
3
3
  import { entries, forEach, pipeLazy, tap, toArray, when } from "@fxts/core";
4
4
 
5
5
  //#region src/action/env.ts
6
+ /**
7
+ * Displays environment variable recommendations to the user.
8
+ * Lists the `.env` key-value pairs from the combined KV store and message
9
+ * queue configurations, so the user knows what to configure.
10
+ */
6
11
  const recommendConfigEnv = pipeLazy((data) => data.env, entries, toArray, when(notEmpty, tap(noticeConfigEnv)), forEach(noticeEnvKeyValue));
7
12
  var env_default = recommendConfigEnv;
8
13
 
@@ -2,6 +2,10 @@ import { CommandError, runSubCommand } from "../utils.js";
2
2
  import { apply, pipe } from "@fxts/core";
3
3
 
4
4
  //#region src/action/install.ts
5
+ /**
6
+ * Runs `<packageManager> install` in the project directory to install all
7
+ * dependencies. Logs an error message if the installation fails.
8
+ */
5
9
  const installDependencies = (data) => pipe(data, ({ packageManager, dir }) => [[packageManager, "install"], { cwd: dir }], apply(runSubCommand)).catch((e) => {
6
10
  if (e instanceof CommandError) {
7
11
  console.error(`Failed to install dependencies using ${data.packageManager}.`);
@@ -3,6 +3,7 @@ import { text } from "@optique/core";
3
3
  import { flow } from "es-toolkit";
4
4
 
5
5
  //#region src/action/notice.ts
6
+ /** Prints the Feddy ASCII art banner to stderr. */
6
7
  function drawDinosaur() {
7
8
  const d = flow(colors.bgBlue, colors.black);
8
9
  const f = colors.blue;
@@ -15,33 +16,53 @@ ${d(" <__.|_|-|_| ")} ${f("|_| \\___|\\__,_|_|_| \\__, |")}
15
16
  ${d(" ")} ${f(" |___/")}
16
17
  `);
17
18
  }
19
+ /** Prints the user's selected initialization options to stdout. */
18
20
  const noticeOptions = ({ packageManager, webFramework, kvStore, messageQueue }) => printMessage`
19
21
  Package manager: ${packageManager};
20
22
  Web framework: ${webFramework};
21
23
  Key–value store: ${kvStore};
22
24
  Message queue: ${messageQueue};
23
25
  `;
26
+ /**
27
+ * Prints the precommand that would be run in dry-run mode,
28
+ * showing the directory and command to execute.
29
+ */
24
30
  function noticePrecommand({ initializer: { command: command$1 }, dir }) {
25
31
  printMessage`📦 Would run command:`;
26
32
  printMessage` cd ${dir}`;
27
33
  printMessage` ${command$1.join(" ")}\n`;
28
34
  }
35
+ /** Prints a header indicating that text files would be created. */
29
36
  const noticeFilesToCreate = () => printMessage`📄 Would create files:\n`;
37
+ /** Prints a header indicating that JSON files would be created or updated. */
30
38
  const noticeFilesToInsert = () => printMessage`Would create/update JSON files:\n`;
39
+ /** Prints a header indicating that dependencies would be installed. */
31
40
  const noticeDepsIfExist = () => printMessage`📦 Would install dependencies:`;
41
+ /** Prints a header indicating that dev dependencies would be installed. */
32
42
  const noticeDevDepsIfExist = () => printMessage`📦 Would install dev dependencies:`;
43
+ /** Prints a single dependency name and version. */
33
44
  const noticeDeps = ([name, version]) => printMessage`${name}@${version}`;
45
+ /**
46
+ * Displays a file's path and content with a horizontal rule separator,
47
+ * used in dry-run mode to preview generated files.
48
+ */
34
49
  function displayFile(path, content, emoji = "📄") {
35
50
  printMessage`${emoji} ${path}`;
36
51
  printMessage`${"─".repeat(60)}`;
37
52
  printMessage`${content}`;
38
53
  printMessage`${"─".repeat(60)}\n`;
39
54
  }
55
+ /** Prints a notice recommending the user edit the `.env` file. */
40
56
  const noticeConfigEnv = () => printMessage`Note that you probably want to edit the ${".env"} file.
41
57
  It currently contains the following values:\n`;
58
+ /** Prints a single environment variable key-value pair. */
42
59
  const noticeEnvKeyValue = ([key, value]) => {
43
60
  printMessage`${text(` ${key}='${value}'`)}`;
44
61
  };
62
+ /**
63
+ * Prints the post-initialization instructions, showing how to start
64
+ * the dev server and where to edit the federation configuration.
65
+ */
45
66
  const noticeHowToRun = ({ initializer: { instruction, federationFile } }) => printMessage`
46
67
  ${instruction}
47
68
 
@@ -1,6 +1,6 @@
1
1
  import { merge, set } from "../utils.js";
2
2
  import { kvStores, messageQueues } from "../lib.js";
3
- import webframeworks_default from "../webframeworks.js";
3
+ import webframeworks_default from "../webframeworks/mod.js";
4
4
  import { pipe } from "@fxts/core";
5
5
  import { existsSync } from "node:fs";
6
6
  import { realpath } from "node:fs/promises";
@@ -1,9 +1,16 @@
1
1
  import { join } from "node:path";
2
2
 
3
3
  //#region src/action/utils.ts
4
+ /** Returns `true` if the current run is in dry-run mode. */
4
5
  const isDry = ({ dryRun }) => dryRun;
6
+ /** Returns `true` if the framework initializer has a precommand to execute. */
5
7
  const hasCommand = (data) => !!data.initializer.command;
8
+ /** Returns `true` if the selected package manager is Deno. */
6
9
  const isDeno = ({ packageManager }) => packageManager === "deno";
10
+ /**
11
+ * Returns a function that prepends the project directory to a
12
+ * `[filename, content]` tuple, resolving the filename into an absolute path.
13
+ */
7
14
  const joinDir = (dir) => ([filename, content]) => [join(dir, ...filename.split("/")), content];
8
15
  /**
9
16
  * Stringify an object into a valid `.env` file format.
package/dist/ask/mod.js CHANGED
@@ -6,6 +6,12 @@ import wf_default from "./wf.js";
6
6
  import { pipe } from "@fxts/core";
7
7
 
8
8
  //#region src/ask/mod.ts
9
+ /**
10
+ * Orchestrates all interactive prompts to fill in missing initialization options.
11
+ * Prompts the user in sequence for: project directory, web framework,
12
+ * package manager, message queue, and key-value store.
13
+ * Returns a fully resolved {@link InitCommandOptions} with all fields guaranteed.
14
+ */
9
15
  const askOptions = (options) => pipe(options, dir_default, wf_default, pm_default, mq_default, kv_default);
10
16
  var ask_default = askOptions;
11
17
 
package/dist/ask/pm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { getInstallUrl, isPackageManagerAvailable, kvStores, messageQueues, packageManagers, runtimes } from "../lib.js";
2
2
  import { PACKAGE_MANAGER } from "../const.js";
3
- import webframeworks_default from "../webframeworks.js";
3
+ import webframeworks_default from "../webframeworks/mod.js";
4
4
  import { pipe, when } from "@fxts/core";
5
5
  import { select } from "@inquirer/prompts";
6
6
  import { message } from "@optique/core/message";
package/dist/ask/wf.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { WEB_FRAMEWORK } from "../const.js";
2
- import webframeworks_default from "../webframeworks.js";
2
+ import webframeworks_default from "../webframeworks/mod.js";
3
3
  import { select } from "@inquirer/prompts";
4
4
 
5
5
  //#region src/ask/wf.ts
package/dist/command.d.ts CHANGED
@@ -2,24 +2,33 @@ import * as _optique_core0 from "@optique/core";
2
2
  import { InferValue } from "@optique/core";
3
3
 
4
4
  //#region src/command.d.ts
5
+
6
+ /**
7
+ * The `@optique/core` option schema for the `fedify init` command.
8
+ * Defines `dir`, `webFramework`, `packageManager`, `kvStore`, `messageQueue`,
9
+ * and `dryRun` options that the CLI parser will accept.
10
+ */
5
11
  declare const initOptions: _optique_core0.Parser<"sync", {
6
12
  readonly dir: string;
7
- readonly webFramework: "hono" | "nitro" | "next" | "elysia" | "express";
13
+ readonly webFramework: "hono" | "nitro" | "next" | "elysia" | "astro" | "express";
8
14
  readonly packageManager: "deno" | "pnpm" | "bun" | "yarn" | "npm";
9
15
  readonly kvStore: "denokv" | "redis" | "postgres";
10
16
  readonly messageQueue: "denokv" | "redis" | "postgres" | "amqp";
11
17
  readonly dryRun: boolean;
12
18
  }, {
13
19
  readonly dir: [_optique_core0.ValueParserResult<string>];
14
- readonly webFramework: [_optique_core0.ValueParserResult<"hono" | "nitro" | "next" | "elysia" | "express">];
20
+ readonly webFramework: [_optique_core0.ValueParserResult<"hono" | "nitro" | "next" | "elysia" | "astro" | "express">];
15
21
  readonly packageManager: [_optique_core0.ValueParserResult<"deno" | "pnpm" | "bun" | "yarn" | "npm">];
16
22
  readonly kvStore: [_optique_core0.ValueParserResult<"denokv" | "redis" | "postgres">];
17
23
  readonly messageQueue: [_optique_core0.ValueParserResult<"denokv" | "redis" | "postgres" | "amqp">];
18
24
  readonly dryRun: _optique_core0.ValueParserResult<boolean>;
19
25
  }>;
26
+ /**
27
+ * The `fedify init` CLI command parser.
28
+ */
20
29
  declare const initCommand: _optique_core0.Parser<"sync", {
21
30
  readonly dir: string;
22
- readonly webFramework: "hono" | "nitro" | "next" | "elysia" | "express";
31
+ readonly webFramework: "hono" | "nitro" | "next" | "elysia" | "astro" | "express";
23
32
  readonly packageManager: "deno" | "pnpm" | "bun" | "yarn" | "npm";
24
33
  readonly kvStore: "denokv" | "redis" | "postgres";
25
34
  readonly messageQueue: "denokv" | "redis" | "postgres" | "amqp";
@@ -27,6 +36,10 @@ declare const initCommand: _optique_core0.Parser<"sync", {
27
36
  } & {
28
37
  readonly command: "init";
29
38
  }, ["matched", string] | ["parsing", Record<string | symbol, unknown>]>;
39
+ /** The inferred value type produced by parsing the `fedify init` command. */
30
40
  type InitCommand = InferValue<typeof initCommand>;
41
+ /**
42
+ * The `test-init` CLI command parser.
43
+ */
31
44
  //#endregion
32
45
  export { InitCommand, initCommand, initOptions };
package/dist/command.js CHANGED
@@ -7,6 +7,11 @@ const webFramework = optional(option("-w", "--web-framework", choice(WEB_FRAMEWO
7
7
  const packageManager = optional(option("-p", "--package-manager", choice(PACKAGE_MANAGER, { metavar: "PACKAGE_MANAGER" }), { description: message`The package manager to use for installing dependencies.` }));
8
8
  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.` }));
9
9
  const messageQueue = optional(option("-m", "--message-queue", choice(MESSAGE_QUEUE, { metavar: "MESSAGE_QUEUE" }), { description: message`The message queue to use for background tasks.` }));
10
+ /**
11
+ * The `@optique/core` option schema for the `fedify init` command.
12
+ * Defines `dir`, `webFramework`, `packageManager`, `kvStore`, `messageQueue`,
13
+ * and `dryRun` options that the CLI parser will accept.
14
+ */
10
15
  const initOptions = object("Initialization options", {
11
16
  dir: optional(argument(path({ metavar: "DIR" }), { description: message`The project directory to initialize. If a specified directory does not exist, it will be created.` })),
12
17
  webFramework,
@@ -15,6 +20,9 @@ const initOptions = object("Initialization options", {
15
20
  messageQueue,
16
21
  dryRun: option("--dry-run", { description: message`Perform a trial run with no changes made.` })
17
22
  });
23
+ /**
24
+ * The `fedify init` CLI command parser.
25
+ */
18
26
  const initCommand = command("init", merge(initOptions, object({ command: constant("init") })), {
19
27
  brief: message`Initialize a new Fedify project directory.`,
20
28
  description: message`Initialize a new Fedify project directory.
@@ -25,6 +33,9 @@ Unless you specify all options (${optionNames(["-w", "--web-framework"])}, ${opt
25
33
  });
26
34
  const noHydRun = object({ noHydRun: option("--no-hyd-run", { description: message`Log outputs without creating files.` }) });
27
35
  const noDryRun = object({ noDryRun: option("--no-dry-run", { description: message`Test with files creations and installations.` }) });
36
+ /**
37
+ * The `test-init` CLI command parser.
38
+ */
28
39
  const testInitCommand = command("test-init", merge(object("Initialization options", {
29
40
  webFramework: multiple(webFramework),
30
41
  packageManager: multiple(packageManager),
package/dist/const.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  //#region src/const.d.ts
2
+ /** All supported package manager identifiers, in display order. */
2
3
  declare const PACKAGE_MANAGER: readonly ["deno", "pnpm", "bun", "yarn", "npm"];
4
+ /** All supported web framework identifiers, in display order. */
5
+
3
6
  //#endregion
4
7
  export { PACKAGE_MANAGER };
package/dist/const.js CHANGED
@@ -1,4 +1,5 @@
1
1
  //#region src/const.ts
2
+ /** All supported package manager identifiers, in display order. */
2
3
  const PACKAGE_MANAGER = [
3
4
  "deno",
4
5
  "pnpm",
@@ -6,24 +7,32 @@ const PACKAGE_MANAGER = [
6
7
  "yarn",
7
8
  "npm"
8
9
  ];
10
+ /** All supported web framework identifiers, in display order. */
9
11
  const WEB_FRAMEWORK = [
10
12
  "hono",
11
13
  "nitro",
12
14
  "next",
13
15
  "elysia",
16
+ "astro",
14
17
  "express"
15
18
  ];
19
+ /** All supported message queue backend identifiers. */
16
20
  const MESSAGE_QUEUE = [
17
21
  "denokv",
18
22
  "redis",
19
23
  "postgres",
20
24
  "amqp"
21
25
  ];
26
+ /** All supported key-value store backend identifiers. */
22
27
  const KV_STORE = [
23
28
  "denokv",
24
29
  "redis",
25
30
  "postgres"
26
31
  ];
32
+ /**
33
+ * External database services that need to be running for integration tests.
34
+ * Used by the test suite to check service availability before running tests.
35
+ */
27
36
  const DB_TO_CHECK = [
28
37
  "redis",
29
38
  "postgres",
package/dist/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  //#region deno.json
2
2
  var name = "@fedify/init";
3
- var version = "2.1.0-dev.418+6c060f4a";
3
+ var version = "2.1.0-dev.438+de6972c1";
4
4
  var license = "MIT";
5
5
  var exports = "./src/mod.ts";
6
6
  var imports = {
package/dist/json/kv.js CHANGED
@@ -33,6 +33,23 @@ var postgres = {
33
33
  "object": "new PostgresKvStore(postgres(process.env.POSTGRES_URL))",
34
34
  "env": { "POSTGRES_URL": "postgres://postgres@localhost:5432/postgres" }
35
35
  };
36
+ var mysql = {
37
+ "label": "MySQL/MariaDB",
38
+ "packageManagers": [
39
+ "deno",
40
+ "bun",
41
+ "npm",
42
+ "yarn",
43
+ "pnpm"
44
+ ],
45
+ "dependencies": { "npm:mysql2": "^3.18.0" },
46
+ "imports": {
47
+ "@fedify/mysql": { "MysqlKvStore": "MysqlKvStore" },
48
+ "mysql2/promise": { "default": "mysql" }
49
+ },
50
+ "object": "new MysqlKvStore(mysql.createPool(process.env.MYSQL_URL))",
51
+ "env": { "MYSQL_URL": "mysql://root@localhost/fedify" }
52
+ };
36
53
  var denokv = {
37
54
  "label": "Deno KV",
38
55
  "packageManagers": ["deno"],
@@ -43,6 +60,7 @@ var denokv = {
43
60
  var kv_default = {
44
61
  redis,
45
62
  postgres,
63
+ mysql,
46
64
  denokv
47
65
  };
48
66
 
package/dist/json/kv.json CHANGED
@@ -29,6 +29,21 @@
29
29
  "POSTGRES_URL": "postgres://postgres@localhost:5432/postgres"
30
30
  }
31
31
  },
32
+ "mysql": {
33
+ "label": "MySQL/MariaDB",
34
+ "packageManagers": ["deno", "bun", "npm", "yarn", "pnpm"],
35
+ "dependencies": {
36
+ "npm:mysql2": "^3.18.0"
37
+ },
38
+ "imports": {
39
+ "@fedify/mysql": { "MysqlKvStore": "MysqlKvStore" },
40
+ "mysql2/promise": { "default": "mysql" }
41
+ },
42
+ "object": "new MysqlKvStore(mysql.createPool(process.env.MYSQL_URL))",
43
+ "env": {
44
+ "MYSQL_URL": "mysql://root@localhost/fedify"
45
+ }
46
+ },
32
47
  "denokv": {
33
48
  "label": "Deno KV",
34
49
  "packageManagers": ["deno"],
package/dist/lib.js CHANGED
@@ -6,7 +6,6 @@ import pm_default from "./json/pm.js";
6
6
  import rt_default from "./json/rt.js";
7
7
  import { entries, evolve, fromEntries, isObject, map, negate, pipe, throwIf } from "@fxts/core";
8
8
  import process from "node:process";
9
- import { commandLine, message } from "@optique/core/message";
10
9
  import { toMerged } from "es-toolkit";
11
10
  import { getLogger } from "@logtape/logtape";
12
11
  import { readFileSync } from "node:fs";
@@ -14,20 +13,44 @@ import { mkdir, readdir, writeFile } from "node:fs/promises";
14
13
  import { dirname, join as join$1 } from "node:path";
15
14
 
16
15
  //#region src/lib.ts
16
+ /** The current `@fedify/init` package version, read from *deno.json*. */
17
17
  const PACKAGE_VERSION = deno_default.version;
18
+ /** Logger instance for the `fedify init` command, scoped to `["fedify", "cli", "init"]`. */
18
19
  const logger = getLogger([
19
20
  "fedify",
20
21
  "cli",
21
22
  "init"
22
23
  ]);
23
24
  const addFedifyDeps = (json) => Object.fromEntries(Object.entries(json).map(([key, value]) => [key, toMerged(value, { dependencies: { [`@fedify/${key}`]: PACKAGE_VERSION } })]));
25
+ /**
26
+ * KV store descriptions loaded from *json/kv.json*, enriched with the
27
+ * appropriate `@fedify/*` dependency at the current package version.
28
+ */
24
29
  const kvStores = addFedifyDeps(kv_default);
30
+ /**
31
+ * Message queue descriptions loaded from *json/mq.json*, enriched with the
32
+ * appropriate `@fedify/*` dependency at the current package version.
33
+ */
25
34
  const messageQueues = addFedifyDeps(mq_default);
26
35
  const toRegExp = (str) => new RegExp(str);
27
36
  const convertPattern = (obj) => pipe(obj, entries, map(([key, value]) => [key, evolve({ outputPattern: toRegExp })(value)]), fromEntries);
37
+ /**
38
+ * Package manager descriptions loaded from *json/pm.json*, with
39
+ * `outputPattern` strings converted to `RegExp` instances.
40
+ */
28
41
  const packageManagers = convertPattern(pm_default);
42
+ /**
43
+ * Runtime descriptions loaded from *json/rt.json*, with `outputPattern`
44
+ * strings converted to `RegExp` instances.
45
+ */
29
46
  const runtimes = convertPattern(rt_default);
47
+ /** Returns the installation URL for the given package manager. */
30
48
  const getInstallUrl = (pm) => packageManagers[pm].installUrl;
49
+ /**
50
+ * Checks whether a package manager is installed and available on the system.
51
+ * Runs the package manager's check command and verifies its output.
52
+ * On Windows, also tries the `.cmd` variant of the command.
53
+ */
31
54
  async function isPackageManagerAvailable(pm) {
32
55
  if (await isCommandAvailable(packageManagers[pm])) return true;
33
56
  if (process.platform !== "win32") return false;
@@ -38,17 +61,19 @@ async function isPackageManagerAvailable(pm) {
38
61
  })) return true;
39
62
  return false;
40
63
  }
64
+ /**
65
+ * Reads a template file from the *templates/* directory and returns its content.
66
+ * Appends `.tpl` to the given path before reading.
67
+ *
68
+ * @param templatePath - Relative path within the templates directory
69
+ * (e.g., `"defaults/federation.ts"`)
70
+ * @returns The template file content as a string
71
+ */
41
72
  const readTemplate = (templatePath) => readFileSync(join$1(import.meta.dirname, "templates", ...(templatePath + ".tpl").split("/")), "utf8");
42
- const getInstruction = (pm, port) => message`
43
- To start the server, run the following command:
44
-
45
- ${commandLine(getDevCommand(pm))}
46
-
47
- Then, try look up an actor from your server:
48
-
49
- ${commandLine(`fedify lookup http://localhost:${port}/users/john`)}
50
-
51
- `;
73
+ /**
74
+ * Returns the shell command string to start the dev server for the given
75
+ * package manager (e.g., `"deno task dev"`, `"bun dev"`, `"npm run dev"`).
76
+ */
52
77
  const getDevCommand = (pm) => pm === "deno" ? "deno task dev" : pm === "bun" ? "bun dev" : `${pm} run dev`;
53
78
  async function isCommandAvailable({ checkCommand, outputPattern }) {
54
79
  try {
@@ -71,12 +96,24 @@ async function isCommandAvailable({ checkCommand, outputPattern }) {
71
96
  throw error;
72
97
  }
73
98
  }
99
+ /**
100
+ * Creates a file at the given path with the given content, creating
101
+ * any necessary parent directories along the way.
102
+ */
74
103
  async function createFile(path, content) {
75
104
  await mkdir(dirname(path), { recursive: true });
76
105
  await writeFile(path, content);
77
106
  }
78
107
  const isNotExistsError = (e) => isObject(e) && "code" in e && e.code === "ENOENT";
108
+ /**
109
+ * Throws the given error unless it is an `ENOENT` (file not found) error.
110
+ * Used to silently handle missing files while re-throwing other errors.
111
+ */
79
112
  const throwUnlessNotExists = throwIf(negate(isNotExistsError));
113
+ /**
114
+ * Checks whether a directory is empty or does not exist.
115
+ * Returns `true` if the directory has no entries or does not exist yet.
116
+ */
80
117
  const isDirectoryEmpty = async (path) => {
81
118
  try {
82
119
  const files = await readdir(path);
@@ -86,45 +123,8 @@ const isDirectoryEmpty = async (path) => {
86
123
  return true;
87
124
  }
88
125
  };
89
- /**
90
- * Converts a package manager to its corresponding runtime.
91
- * @param pm - The package manager (deno, bun, npm, yarn, pnpm)
92
- * @returns The runtime name (deno, bun, or node)
93
- */
94
- const packageManagerToRuntime = (pm) => pm === "deno" ? "deno" : pm === "bun" ? "bun" : "node";
95
- const getNextInitCommand = (pm) => [
96
- ...createNextAppCommand(pm),
97
- ".",
98
- "--yes"
99
- ];
100
- const createNextAppCommand = (pm) => pm === "deno" ? [
101
- "deno",
102
- "-Ar",
103
- "npm:create-next-app@latest"
104
- ] : pm === "bun" ? [
105
- "bun",
106
- "create",
107
- "next-app"
108
- ] : pm === "npm" ? ["npx", "create-next-app"] : [
109
- pm,
110
- "dlx",
111
- "create-next-app"
112
- ];
113
- const getNitroInitCommand = (pm) => [
114
- ...createNitroAppCommand(pm),
115
- pm === "deno" ? "npm:giget@latest" : "giget@latest",
116
- "nitro",
117
- ".",
118
- "&&",
119
- "rm",
120
- "nitro.config.ts"
121
- ];
122
- const createNitroAppCommand = (pm) => pm === "deno" ? [
123
- "deno",
124
- "run",
125
- "-A"
126
- ] : pm === "bun" ? ["bunx"] : pm === "npm" ? ["npx"] : [pm, "dlx"];
126
+ /** Returns `true` if the current run is in test mode. */
127
127
  const isTest = ({ testMode }) => testMode;
128
128
 
129
129
  //#endregion
130
- export { PACKAGE_VERSION, createFile, getDevCommand, getInstallUrl, getInstruction, getNextInitCommand, getNitroInitCommand, isDirectoryEmpty, isPackageManagerAvailable, isTest, kvStores, logger, messageQueues, packageManagerToRuntime, packageManagers, readTemplate, runtimes, throwUnlessNotExists };
130
+ export { PACKAGE_VERSION, createFile, getDevCommand, getInstallUrl, isDirectoryEmpty, isPackageManagerAvailable, isTest, kvStores, logger, messageQueues, packageManagers, readTemplate, runtimes, throwUnlessNotExists };
@@ -0,0 +1,10 @@
1
+ import deno from "@deno/astro-adapter";
2
+ import { fedifyIntegration } from "@fedify/astro";
3
+ import { defineConfig } from "astro/config";
4
+
5
+ // https://astro.build/config
6
+ export default defineConfig({
7
+ integrations: [fedifyIntegration()],
8
+ output: "server",
9
+ adapter: deno(),
10
+ });
@@ -0,0 +1,10 @@
1
+ import node from "@astrojs/node";
2
+ import { fedifyIntegration } from "@fedify/astro";
3
+ import { defineConfig } from "astro/config";
4
+
5
+ // https://astro.build/config
6
+ export default defineConfig({
7
+ integrations: [fedifyIntegration()],
8
+ output: "server",
9
+ adapter: node({ mode: "standalone" }),
10
+ });
@@ -0,0 +1,4 @@
1
+ import { fedifyMiddleware } from "@fedify/astro";
2
+ import federation from "./federation.ts";
3
+
4
+ export const onRequest = fedifyMiddleware(federation, (_context) => undefined);