alepha 0.14.0 → 0.14.1

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 (94) hide show
  1. package/dist/api/audits/index.d.ts +417 -338
  2. package/dist/api/audits/index.d.ts.map +1 -1
  3. package/dist/api/files/index.d.ts +80 -1
  4. package/dist/api/files/index.d.ts.map +1 -1
  5. package/dist/api/jobs/index.d.ts +236 -157
  6. package/dist/api/jobs/index.d.ts.map +1 -1
  7. package/dist/api/notifications/index.d.ts +21 -1
  8. package/dist/api/notifications/index.d.ts.map +1 -1
  9. package/dist/api/parameters/index.d.ts +451 -4
  10. package/dist/api/parameters/index.d.ts.map +1 -1
  11. package/dist/api/users/index.d.ts +833 -830
  12. package/dist/api/users/index.d.ts.map +1 -1
  13. package/dist/cli/index.d.ts +212 -29
  14. package/dist/cli/index.d.ts.map +1 -1
  15. package/dist/cli/index.js +320 -219
  16. package/dist/cli/index.js.map +1 -1
  17. package/dist/command/index.d.ts +206 -9
  18. package/dist/command/index.d.ts.map +1 -1
  19. package/dist/command/index.js +306 -69
  20. package/dist/command/index.js.map +1 -1
  21. package/dist/core/index.browser.js.map +1 -1
  22. package/dist/core/index.d.ts +1 -1
  23. package/dist/core/index.js.map +1 -1
  24. package/dist/core/index.native.js.map +1 -1
  25. package/dist/file/index.d.ts.map +1 -1
  26. package/dist/file/index.js.map +1 -1
  27. package/dist/orm/index.d.ts +180 -126
  28. package/dist/orm/index.d.ts.map +1 -1
  29. package/dist/orm/index.js +486 -512
  30. package/dist/orm/index.js.map +1 -1
  31. package/dist/queue/redis/index.js +2 -4
  32. package/dist/queue/redis/index.js.map +1 -1
  33. package/dist/redis/index.d.ts +400 -29
  34. package/dist/redis/index.d.ts.map +1 -1
  35. package/dist/redis/index.js +412 -21
  36. package/dist/redis/index.js.map +1 -1
  37. package/dist/scheduler/index.d.ts +6 -6
  38. package/dist/security/index.d.ts +28 -28
  39. package/dist/security/index.d.ts.map +1 -1
  40. package/dist/server/auth/index.d.ts +155 -155
  41. package/dist/server/core/index.d.ts +0 -1
  42. package/dist/server/core/index.d.ts.map +1 -1
  43. package/dist/server/core/index.js.map +1 -1
  44. package/dist/server/health/index.d.ts +17 -17
  45. package/dist/server/helmet/index.d.ts +4 -1
  46. package/dist/server/helmet/index.d.ts.map +1 -1
  47. package/dist/server/multipart/index.d.ts.map +1 -1
  48. package/dist/server/multipart/index.js.map +1 -1
  49. package/dist/server/proxy/index.js.map +1 -1
  50. package/dist/topic/redis/index.js +3 -3
  51. package/dist/topic/redis/index.js.map +1 -1
  52. package/dist/vite/index.js +9 -6
  53. package/dist/vite/index.js.map +1 -1
  54. package/package.json +3 -3
  55. package/src/cli/apps/AlephaCli.ts +8 -3
  56. package/src/cli/apps/AlephaPackageBuilderCli.ts +3 -0
  57. package/src/cli/atoms/changelogOptions.ts +45 -0
  58. package/src/cli/commands/ChangelogCommands.ts +187 -317
  59. package/src/cli/commands/DeployCommands.ts +118 -0
  60. package/src/cli/commands/DrizzleCommands.ts +28 -8
  61. package/src/cli/commands/ViteCommands.ts +23 -9
  62. package/src/cli/defineConfig.ts +15 -0
  63. package/src/cli/index.ts +3 -0
  64. package/src/cli/services/AlephaCliUtils.ts +4 -21
  65. package/src/cli/services/GitMessageParser.ts +77 -0
  66. package/src/command/helpers/EnvUtils.ts +37 -0
  67. package/src/command/index.ts +3 -1
  68. package/src/command/primitives/$command.ts +172 -6
  69. package/src/command/providers/CliProvider.ts +424 -91
  70. package/src/core/Alepha.ts +1 -1
  71. package/src/file/providers/NodeFileSystemProvider.ts +3 -1
  72. package/src/orm/index.ts +8 -4
  73. package/src/orm/interfaces/PgQueryWhere.ts +1 -26
  74. package/src/orm/providers/drivers/BunPostgresProvider.ts +225 -0
  75. package/src/orm/providers/drivers/BunSqliteProvider.ts +180 -0
  76. package/src/orm/providers/drivers/DatabaseProvider.ts +25 -0
  77. package/src/orm/providers/drivers/NodePostgresProvider.ts +0 -25
  78. package/src/orm/services/QueryManager.ts +10 -125
  79. package/src/queue/redis/providers/RedisQueueProvider.ts +2 -7
  80. package/src/redis/index.ts +65 -3
  81. package/src/redis/providers/BunRedisProvider.ts +304 -0
  82. package/src/redis/providers/BunRedisSubscriberProvider.ts +94 -0
  83. package/src/redis/providers/NodeRedisProvider.ts +280 -0
  84. package/src/redis/providers/NodeRedisSubscriberProvider.ts +94 -0
  85. package/src/redis/providers/RedisProvider.ts +134 -140
  86. package/src/redis/providers/RedisSubscriberProvider.ts +58 -49
  87. package/src/server/core/providers/BunHttpServerProvider.ts +0 -3
  88. package/src/server/core/providers/ServerBodyParserProvider.ts +3 -1
  89. package/src/server/core/providers/ServerProvider.ts +7 -4
  90. package/src/server/multipart/providers/ServerMultipartProvider.ts +3 -1
  91. package/src/server/proxy/providers/ServerProxyProvider.ts +1 -1
  92. package/src/topic/redis/providers/RedisTopicProvider.ts +3 -3
  93. package/src/vite/tasks/buildServer.ts +1 -0
  94. package/src/orm/services/PgJsonQueryManager.ts +0 -511
package/dist/cli/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { join } from "node:path";
3
- import { $env, $hook, $inject, $module, Alepha, AlephaError, OPTIONS, t } from "alepha";
3
+ import { $atom, $env, $hook, $inject, $module, $use, Alepha, AlephaError, OPTIONS, t } from "alepha";
4
4
  import { FileSystemProvider } from "alepha/file";
5
- import { $command, CliProvider } from "alepha/command";
5
+ import { $command, CliProvider, EnvUtils } from "alepha/command";
6
6
  import { $logger } from "alepha/logger";
7
7
  import { exec, spawn } from "node:child_process";
8
8
  import { access, mkdir, readFile, readdir, unlink, writeFile } from "node:fs/promises";
@@ -173,6 +173,7 @@ const version = packageJson.version;
173
173
  var AlephaCliUtils = class {
174
174
  log = $logger();
175
175
  fs = $inject(FileSystemProvider);
176
+ envUtils = $inject(EnvUtils);
176
177
  /**
177
178
  * Execute a command using npx with inherited stdio.
178
179
  *
@@ -461,23 +462,8 @@ ${models.map((it) => `export const ${it} = models["${it}"];`).join("\n")}
461
462
  * Reads the .env file in the specified root directory and sets
462
463
  * the environment variables in process.env.
463
464
  */
464
- async loadEnvFile(root, files = [".env"]) {
465
- for (const it of files) for (const file of [it, `${it}.local`]) {
466
- const envPath = join(root, file);
467
- try {
468
- const lines = (await readFile(envPath, "utf8")).split("\n");
469
- for (const line of lines) {
470
- const [key, ...rest] = line.split("=");
471
- if (key) {
472
- const value = rest.join("=");
473
- process.env[key.trim()] = value.trim();
474
- }
475
- }
476
- this.log.debug(`Loaded environment variables from ${envPath}`);
477
- } catch {
478
- this.log.debug(`No ${file} file found at ${envPath}, skipping load.`);
479
- }
480
- }
465
+ async loadEnv(root, files = [".env"]) {
466
+ await this.envUtils.loadEnv(root, files);
481
467
  }
482
468
  async getPackageManager(root, flags) {
483
469
  if (flags?.yarn) return "yarn";
@@ -626,8 +612,11 @@ var BiomeCommands = class {
626
612
  };
627
613
 
628
614
  //#endregion
629
- //#region ../../src/cli/commands/ChangelogCommands.ts
630
- const execAsync = promisify(exec);
615
+ //#region ../../src/cli/atoms/changelogOptions.ts
616
+ /**
617
+ * Default scopes to ignore in changelog generation.
618
+ * Commits with these scopes won't appear in release notes.
619
+ */
631
620
  const DEFAULT_IGNORE = [
632
621
  "project",
633
622
  "release",
@@ -639,213 +628,206 @@ const DEFAULT_IGNORE = [
639
628
  "test",
640
629
  "style"
641
630
  ];
642
- function parseCommit(line, config) {
643
- const match = line.match(/^([a-f0-9]+)\s+(.+)$/);
644
- if (!match) return null;
645
- const [, hash, message] = match;
646
- const breaking = message.includes("!:") || message.toLowerCase().includes("breaking");
647
- const ignore = config.ignore ?? DEFAULT_IGNORE;
648
- const conventionalMatch = message.match(/^(feat|fix|docs|refactor|perf|revert)(?:\(([^)]+)\))?!?:\s*(.+)$/i);
649
- if (conventionalMatch) {
650
- const [, type, scope, description] = conventionalMatch;
651
- if (scope) {
652
- const baseScope = scope.split("/")[0];
653
- if (ignore.includes(baseScope) || ignore.includes(scope)) return null;
654
- }
655
- if (!scope && ignore.includes(type.toLowerCase())) return null;
631
+ /**
632
+ * Changelog configuration atom.
633
+ *
634
+ * Configure in `alepha.config.ts`:
635
+ * ```ts
636
+ * import { changelogOptions } from "alepha/cli";
637
+ *
638
+ * alepha.set(changelogOptions, {
639
+ * ignore: ["project", "release", "chore", "docs"],
640
+ * });
641
+ * ```
642
+ */
643
+ const changelogOptions = $atom({
644
+ name: "alepha.changelog",
645
+ schema: t.object({ ignore: t.optional(t.array(t.string())) }),
646
+ default: { ignore: DEFAULT_IGNORE }
647
+ });
648
+
649
+ //#endregion
650
+ //#region ../../src/cli/services/GitMessageParser.ts
651
+ /**
652
+ * Service for parsing git commit messages into structured format.
653
+ *
654
+ * Only parses **conventional commits with a scope**:
655
+ * - `feat(scope): description` → feature
656
+ * - `fix(scope): description` → bug fix
657
+ * - `feat(scope)!: description` → breaking change
658
+ *
659
+ * Commits without scope are ignored, allowing developers to commit
660
+ * work-in-progress changes without polluting release notes:
661
+ * - `cli: work in progress` → ignored (no type)
662
+ * - `fix: quick patch` → ignored (no scope)
663
+ * - `feat(cli): add command` → included
664
+ */
665
+ var GitMessageParser = class {
666
+ log = $logger();
667
+ /**
668
+ * Parse a git commit line into a structured Commit object.
669
+ *
670
+ * **Format:** `type(scope): description` or `type(scope)!: description`
671
+ *
672
+ * **Supported types:** feat, fix, docs, refactor, perf, revert
673
+ *
674
+ * **Breaking changes:** Use `!` before `:` (e.g., `feat(api)!: remove endpoint`)
675
+ *
676
+ * @returns Commit object or null if not matching/ignored
677
+ */
678
+ parseCommit(line, config) {
679
+ const match = line.match(/^([a-f0-9]+)\s+(.+)$/);
680
+ if (!match) return null;
681
+ const [, hash, message] = match;
682
+ const ignore = config.ignore ?? DEFAULT_IGNORE;
683
+ const conventionalMatch = message.match(/^(feat|fix|docs|refactor|perf|revert)\(([^)]+)\)(!)?:\s*(.+)$/i);
684
+ if (!conventionalMatch) return null;
685
+ const [, type, scope, breakingMark, description] = conventionalMatch;
686
+ const baseScope = scope.split("/")[0];
687
+ if (ignore.includes(baseScope) || ignore.includes(scope)) return null;
688
+ const breaking = breakingMark === "!" || description.toLowerCase().includes("breaking");
656
689
  return {
657
690
  hash: hash.substring(0, 8),
658
691
  type: type.toLowerCase(),
659
- scope: scope || null,
692
+ scope,
660
693
  description: description.trim(),
661
694
  breaking
662
695
  };
663
696
  }
664
- const moduleMatch = message.match(/^([a-z][a-z0-9-]*(?:\/[a-z][a-z0-9-]*)?):\s*(.+)$/i);
665
- if (moduleMatch) {
666
- const [, module, description] = moduleMatch;
667
- const baseModule = module.split("/")[0];
668
- if (ignore.includes(baseModule)) return null;
669
- if (config.scopes && !config.scopes.includes(baseModule)) return null;
670
- const desc = description.toLowerCase();
671
- let type = "improve";
672
- if (desc.includes("fix") || desc.includes("bug") || desc.includes("issue")) type = "fix";
673
- else if (desc.includes("add") || desc.includes("new") || desc.includes("implement")) type = "feat";
674
- return {
675
- hash: hash.substring(0, 8),
676
- type,
677
- scope: module,
678
- description: description.trim(),
679
- breaking
680
- };
697
+ };
698
+
699
+ //#endregion
700
+ //#region ../../src/cli/commands/ChangelogCommands.ts
701
+ const execAsync = promisify(exec);
702
+ /**
703
+ * Git provider for executing git commands.
704
+ * Can be substituted in tests with a mock implementation.
705
+ */
706
+ var GitProvider = class {
707
+ async exec(cmd, cwd) {
708
+ const { stdout } = await execAsync(`git ${cmd}`, { cwd });
709
+ return stdout;
681
710
  }
682
- return null;
683
- }
684
- function formatCommit(commit) {
685
- return `- ${commit.scope ? `**${commit.scope}**: ` : ""}${commit.description} (\`${commit.hash}\`)`;
686
- }
687
- function generateChangelog(entries) {
688
- let output = "# Changelog\n\n";
689
- output += "All notable changes to this project will be documented in this file.\n\n";
690
- for (const entry of entries) {
691
- output += `## [${entry.version}] - ${entry.date}\n\n`;
692
- output += formatEntry(entry);
711
+ };
712
+ /**
713
+ * Changelog command for generating release notes from git commits.
714
+ *
715
+ * Usage:
716
+ * - `alepha changelog` - Show unreleased changes since latest tag to HEAD
717
+ * - `alepha changelog --from=1.0.0` - Show changes from version to HEAD
718
+ * - `alepha changelog --from=1.0.0 --to=1.1.0` - Show changes between two refs
719
+ * - `alepha changelog | tee -a CHANGELOG.md` - Append to file
720
+ */
721
+ var ChangelogCommands = class {
722
+ log = $logger();
723
+ git = $inject(GitProvider);
724
+ parser = $inject(GitMessageParser);
725
+ config = $use(changelogOptions);
726
+ /**
727
+ * Format a single commit line.
728
+ * Example: `- **cli**: add new command (\`abc1234\`)`
729
+ */
730
+ formatCommit(commit) {
731
+ return `- **${commit.scope}**: ${commit.description} (\`${commit.hash}\`)`;
693
732
  }
694
- return output;
695
- }
696
- function formatEntry(entry) {
697
- let output = "";
698
- if (entry.breaking.length > 0) {
699
- output += "### Breaking Changes\n\n";
700
- for (const commit of entry.breaking) output += `${formatCommit(commit)}\n`;
701
- output += "\n";
733
+ /**
734
+ * Format the changelog entry with sections.
735
+ */
736
+ formatEntry(entry) {
737
+ const sections = [];
738
+ if (entry.breaking.length > 0) {
739
+ sections.push("### Breaking Changes\n");
740
+ for (const commit of entry.breaking) sections.push(this.formatCommit(commit));
741
+ sections.push("");
742
+ }
743
+ if (entry.features.length > 0) {
744
+ sections.push("### Features\n");
745
+ for (const commit of entry.features) sections.push(this.formatCommit(commit));
746
+ sections.push("");
747
+ }
748
+ if (entry.fixes.length > 0) {
749
+ sections.push("### Bug Fixes\n");
750
+ for (const commit of entry.fixes) sections.push(this.formatCommit(commit));
751
+ sections.push("");
752
+ }
753
+ return sections.join("\n");
702
754
  }
703
- if (entry.features.length > 0) {
704
- output += "### Features\n\n";
705
- for (const commit of entry.features) output += `${formatCommit(commit)}\n`;
706
- output += "\n";
755
+ /**
756
+ * Parse git log output into a changelog entry.
757
+ */
758
+ parseCommits(commitsOutput) {
759
+ const entry = {
760
+ features: [],
761
+ fixes: [],
762
+ breaking: []
763
+ };
764
+ for (const line of commitsOutput.trim().split("\n")) {
765
+ if (!line.trim()) continue;
766
+ const commit = this.parser.parseCommit(line, this.config);
767
+ if (!commit) {
768
+ this.log.trace("Skipping commit", { line });
769
+ continue;
770
+ }
771
+ this.log.trace("Parsed commit", { commit });
772
+ if (commit.breaking) entry.breaking.push(commit);
773
+ if (commit.type === "feat") entry.features.push(commit);
774
+ else if (commit.type === "fix") entry.fixes.push(commit);
775
+ }
776
+ return entry;
707
777
  }
708
- if (entry.fixes.length > 0) {
709
- output += "### Bug Fixes\n\n";
710
- for (const commit of entry.fixes) output += `${formatCommit(commit)}\n`;
711
- output += "\n";
778
+ /**
779
+ * Check if entry has any public commits.
780
+ */
781
+ hasChanges(entry) {
782
+ return entry.features.length > 0 || entry.fixes.length > 0 || entry.breaking.length > 0;
712
783
  }
713
- return output;
714
- }
715
- async function loadConfig(root) {
716
- try {
717
- const pkgPath = join(root, "package.json");
718
- return JSON.parse(await readFile(pkgPath, "utf8")).changelog ?? {};
719
- } catch {
720
- return {};
784
+ /**
785
+ * Get the latest version tag.
786
+ */
787
+ async getLatestTag(git) {
788
+ return (await git("tag --sort=-version:refname")).trim().split("\n").filter((tag) => tag.match(/^\d+\.\d+\.\d+$/))[0] || null;
721
789
  }
722
- }
723
- var ChangelogCommands = class {
724
790
  changelog = $command({
725
791
  name: "changelog",
726
- description: "Generate CHANGELOG.md from git commits",
792
+ description: "Generate changelog from conventional commits (outputs to stdout)",
727
793
  flags: t.object({
728
- release: t.optional(t.boolean({
729
- when: ["--release", "-r"],
730
- description: "Output release notes for the latest version only (for GitHub Release)"
794
+ from: t.optional(t.string({
795
+ aliases: ["f"],
796
+ description: "Starting ref (default: latest tag)"
731
797
  })),
732
- preview: t.optional(t.boolean({
733
- when: ["--preview", "-p"],
734
- description: "Preview unreleased changes (commits since last tag)"
735
- })),
736
- output: t.optional(t.string({
737
- when: ["--output", "-o"],
738
- description: "Output file path (defaults to CHANGELOG.md, use - for stdout)"
739
- })),
740
- limit: t.optional(t.number({
741
- when: ["--limit", "-l"],
742
- description: "Limit number of versions to include"
798
+ to: t.optional(t.string({
799
+ aliases: ["t"],
800
+ description: "Ending ref (default: HEAD)"
743
801
  }))
744
802
  }),
745
- handler: async ({ flags, run, root }) => {
746
- const config = await loadConfig(root);
747
- const git = async (cmd) => {
748
- const { stdout } = await execAsync(`git ${cmd}`, { cwd: root });
749
- return stdout;
750
- };
751
- const tags = (await git("tag --sort=-version:refname")).trim().split("\n").filter((tag) => tag.match(/^\d+\.\d+\.\d+$/));
752
- if (tags.length === 0) throw new Error("No version tags found");
753
- if (flags.preview) {
754
- const latestTag = tags[0];
755
- const commitsOutput = await git(`log ${latestTag}..HEAD --oneline`);
756
- if (!commitsOutput.trim()) {
757
- console.log("No unreleased changes since", latestTag);
803
+ handler: async ({ flags, root }) => {
804
+ const git = (cmd) => this.git.exec(cmd, root);
805
+ let fromRef;
806
+ if (flags.from) {
807
+ fromRef = flags.from;
808
+ this.log.debug("Using specified from ref", { from: fromRef });
809
+ } else {
810
+ const latestTag = await this.getLatestTag(git);
811
+ if (!latestTag) {
812
+ process.stdout.write("No version tags found in repository\n");
758
813
  return;
759
814
  }
760
- const entry = {
761
- version: "Unreleased",
762
- date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
763
- features: [],
764
- fixes: [],
765
- docs: [],
766
- improvements: [],
767
- breaking: []
768
- };
769
- for (const line of commitsOutput.trim().split("\n")) {
770
- if (!line.trim()) continue;
771
- const commit = parseCommit(line, config);
772
- if (!commit) continue;
773
- if (commit.breaking) entry.breaking.push(commit);
774
- switch (commit.type) {
775
- case "feat":
776
- entry.features.push(commit);
777
- break;
778
- case "fix":
779
- entry.fixes.push(commit);
780
- break;
781
- case "docs":
782
- entry.docs.push(commit);
783
- break;
784
- case "refactor":
785
- case "perf":
786
- case "improve":
787
- entry.improvements.push(commit);
788
- break;
789
- }
790
- }
791
- if (!(entry.features.length > 0 || entry.fixes.length > 0 || entry.breaking.length > 0)) {
792
- console.log("No public changes since", latestTag);
793
- return;
794
- }
795
- console.log(`## [Unreleased] - since ${latestTag}\n`);
796
- console.log(formatEntry(entry));
797
- return;
815
+ fromRef = latestTag;
816
+ this.log.debug("Using latest tag", { from: fromRef });
798
817
  }
799
- const entries = [];
800
- const limit = flags.limit || (flags.release ? 1 : tags.length);
801
- for (let i = 0; i < Math.min(limit, tags.length); i++) {
802
- const tag = tags[i];
803
- const prevTag = tags[i + 1];
804
- const date = (await git(`log -1 --format=%ci ${tag}`)).trim().split(" ")[0];
805
- const commitsOutput = await git(`log ${prevTag ? `${prevTag}..${tag}` : tag} --oneline`);
806
- const entry = {
807
- version: tag,
808
- date,
809
- features: [],
810
- fixes: [],
811
- docs: [],
812
- improvements: [],
813
- breaking: []
814
- };
815
- for (const line of commitsOutput.trim().split("\n")) {
816
- if (!line.trim()) continue;
817
- const commit = parseCommit(line, config);
818
- if (!commit) continue;
819
- if (commit.breaking) entry.breaking.push(commit);
820
- switch (commit.type) {
821
- case "feat":
822
- entry.features.push(commit);
823
- break;
824
- case "fix":
825
- entry.fixes.push(commit);
826
- break;
827
- case "docs":
828
- entry.docs.push(commit);
829
- break;
830
- case "refactor":
831
- case "perf":
832
- case "improve":
833
- entry.improvements.push(commit);
834
- break;
835
- }
836
- }
837
- if (entry.features.length > 0 || entry.fixes.length > 0 || entry.breaking.length > 0) entries.push(entry);
818
+ const toRef = flags.to || "HEAD";
819
+ this.log.debug("Using to ref", { to: toRef });
820
+ const commitsOutput = await git(`log ${fromRef}..${toRef} --oneline`);
821
+ if (!commitsOutput.trim()) {
822
+ process.stdout.write(`No changes in range ${fromRef}..${toRef}\n`);
823
+ return;
838
824
  }
839
- if (entries.length === 0) {
840
- console.log("No public commits found");
825
+ const entry = this.parseCommits(commitsOutput);
826
+ if (!this.hasChanges(entry)) {
827
+ process.stdout.write(`No public changes in range ${fromRef}..${toRef}\n`);
841
828
  return;
842
829
  }
843
- let output;
844
- if (flags.release) output = formatEntry(entries[0]);
845
- else output = generateChangelog(entries);
846
- const outputPath = flags.output ?? "CHANGELOG.md";
847
- if (outputPath === "-") console.log(output);
848
- else await run(`Writing ${outputPath}`, () => writeFile(join(root, outputPath), output, "utf8"));
830
+ process.stdout.write(this.formatEntry(entry));
849
831
  }
850
832
  });
851
833
  };
@@ -933,6 +915,87 @@ var CoreCommands = class {
933
915
  });
934
916
  };
935
917
 
918
+ //#endregion
919
+ //#region ../../src/cli/commands/DeployCommands.ts
920
+ var DeployCommands = class {
921
+ log = $logger();
922
+ utils = $inject(AlephaCliUtils);
923
+ /**
924
+ * Deploy the project to a hosting platform (e.g., Vercel, Cloudflare, Surge)
925
+ *
926
+ * Deploy command can be overridden by creating a alepha.config.ts in the project root:
927
+ *
928
+ * ```ts
929
+ * import { defineConfig } from "alepha/cli";
930
+ *
931
+ * export default defineConfig({
932
+ * commands: {
933
+ * deploy: {
934
+ * handler: async ({ root, mode, flags }) => {
935
+ * // Custom deployment logic here
936
+ * },
937
+ * },
938
+ * },
939
+ * });
940
+ * ```
941
+ */
942
+ deploy = $command({
943
+ name: "deploy",
944
+ description: "Deploy the project to a hosting platform (e.g., Vercel, Cloudflare, Surge)",
945
+ mode: true,
946
+ flags: t.object({
947
+ build: t.boolean({
948
+ description: "Build the project before deployment",
949
+ default: false
950
+ }),
951
+ migrate: t.boolean({
952
+ description: "Run database migrations before deployment (if applicable)",
953
+ default: false
954
+ })
955
+ }),
956
+ env: t.object({
957
+ VERCEL_TOKEN: t.optional(t.text({ description: "Vercel API token (e.g., xxxxxxxxxxxxxxxxxxxx)" })),
958
+ VERCEL_ORG_ID: t.optional(t.text({ description: "Vercel organization ID (e.g., team_abc123...)" })),
959
+ VERCEL_PROJECT_ID: t.optional(t.text({ description: "Vercel project ID (e.g., prj_abc123...)" })),
960
+ CLOUDFLARE_API_TOKEN: t.optional(t.text({ description: "Cloudflare API token (e.g., xxxx-xxxx-xxxx-xxxx)" })),
961
+ CLOUDFLARE_ACCOUNT_ID: t.optional(t.text({ description: "Cloudflare account ID (e.g., abc123def456...)" }))
962
+ }),
963
+ handler: async ({ root, mode, flags }) => {
964
+ if (flags.build) await this.utils.exec("alepha build");
965
+ if (await this.utils.exists(root, "dist/vercel.json")) {
966
+ if (flags.migrate) {
967
+ this.log.debug("Running database migrations before deployment...");
968
+ await this.utils.exec(`alepha db migrate --mode=${mode}`);
969
+ }
970
+ await this.utils.ensureDependency(root, "vercel", { dev: true });
971
+ const command = `vercel . --cwd=dist ${mode === "production" ? "--prod" : ""}`.trim();
972
+ this.log.debug(`Deploying to Vercel with command: ${command}`);
973
+ await this.utils.exec(command);
974
+ return;
975
+ }
976
+ if (await this.utils.exists(root, "dist/wrangler.jsonc")) {
977
+ if (flags.migrate) {
978
+ this.log.debug("Running database migrations before deployment...");
979
+ await this.utils.exec(`alepha db migrate --mode=${mode}`);
980
+ }
981
+ await this.utils.ensureDependency(root, "wrangler", { dev: true });
982
+ const command = `wrangler deploy ${mode === "production" ? "" : "--env preview"} --config=dist/wrangler.jsonc`.trim();
983
+ this.log.info(`Deploying to Cloudflare with command: ${command}`);
984
+ await this.utils.exec(command);
985
+ return;
986
+ }
987
+ if (await this.utils.exists(root, "dist/public/404.html")) {
988
+ await this.utils.ensureDependency(root, "surge", { dev: true });
989
+ const distPath = join(root, "dist/public");
990
+ this.log.debug(`Deploying to Surge from directory: ${distPath}`);
991
+ await this.utils.exec(`surge ${distPath}`);
992
+ return;
993
+ }
994
+ throw new AlephaError("No deployment configuration found in the dist folder.");
995
+ }
996
+ });
997
+ };
998
+
936
999
  //#endregion
937
1000
  //#region ../../src/cli/commands/DrizzleCommands.ts
938
1001
  const drizzleCommandFlags = t.object({
@@ -946,7 +1009,7 @@ var DrizzleCommands = class {
946
1009
  * Check if database migrations are up to date.
947
1010
  */
948
1011
  check = $command({
949
- name: "db:check-migrations",
1012
+ name: "check-migrations",
950
1013
  description: "Check if database migration files are up to date",
951
1014
  args: t.optional(t.text({
952
1015
  title: "path",
@@ -1013,7 +1076,7 @@ var DrizzleCommands = class {
1013
1076
  * - Invokes Drizzle Kit's CLI to generate migration files based on the current schema.
1014
1077
  */
1015
1078
  generate = $command({
1016
- name: "db:generate",
1079
+ name: "generate",
1017
1080
  description: "Generate migration files based on current database schema",
1018
1081
  summary: false,
1019
1082
  args: t.optional(t.text({
@@ -1043,7 +1106,7 @@ var DrizzleCommands = class {
1043
1106
  * - Invokes Drizzle Kit's push command to apply schema changes directly.
1044
1107
  */
1045
1108
  push = $command({
1046
- name: "db:push",
1109
+ name: "push",
1047
1110
  description: "Push database schema changes directly to the database",
1048
1111
  summary: false,
1049
1112
  args: t.optional(t.text({
@@ -1071,7 +1134,7 @@ var DrizzleCommands = class {
1071
1134
  * - Invokes Drizzle Kit's migrate command to apply pending migrations.
1072
1135
  */
1073
1136
  migrate = $command({
1074
- name: "db:migrate",
1137
+ name: "migrate",
1075
1138
  description: "Apply pending database migrations",
1076
1139
  summary: false,
1077
1140
  args: t.optional(t.text({
@@ -1099,7 +1162,7 @@ var DrizzleCommands = class {
1099
1162
  * - Invokes Drizzle Kit's studio command to launch the web-based database browser.
1100
1163
  */
1101
1164
  studio = $command({
1102
- name: "db:studio",
1165
+ name: "studio",
1103
1166
  description: "Launch Drizzle Studio database browser",
1104
1167
  summary: false,
1105
1168
  args: t.optional(t.text({
@@ -1119,6 +1182,23 @@ var DrizzleCommands = class {
1119
1182
  }
1120
1183
  });
1121
1184
  /**
1185
+ * Parent command for database operations.
1186
+ */
1187
+ db = $command({
1188
+ name: "db",
1189
+ description: "Database management commands",
1190
+ children: [
1191
+ this.check,
1192
+ this.generate,
1193
+ this.push,
1194
+ this.migrate,
1195
+ this.studio
1196
+ ],
1197
+ handler: async ({ help }) => {
1198
+ help();
1199
+ }
1200
+ });
1201
+ /**
1122
1202
  * Run a drizzle-kit command for all database providers in an Alepha instance.
1123
1203
  *
1124
1204
  * Iterates through all repository providers, prepares Drizzle config for each,
@@ -1130,7 +1210,7 @@ var DrizzleCommands = class {
1130
1210
  const rootDir = options.root;
1131
1211
  const envFiles = [".env"];
1132
1212
  if (options.env) envFiles.push(`.env.${options.env}`);
1133
- await this.utils.loadEnvFile(rootDir, envFiles);
1213
+ await this.utils.loadEnv(rootDir, envFiles);
1134
1214
  this.log.debug(`Using project root: ${rootDir}`);
1135
1215
  const { alepha, entry } = await this.utils.loadAlephaFromServerEntryFile(rootDir, options.args);
1136
1216
  const drizzleKitProvider = alepha.inject("DrizzleKitProvider");
@@ -1179,6 +1259,7 @@ var DrizzleCommands = class {
1179
1259
  dialect: options.dialect,
1180
1260
  dbCredentials: { url: options.providerUrl }
1181
1261
  };
1262
+ if (options.provider.schema) config.schemaFilter = options.provider.schema;
1182
1263
  if (options.providerName === "d1") config.driver = "d1-http";
1183
1264
  if (options.providerName === "pglite") config.driver = "pglite";
1184
1265
  if (options.dialect === "sqlite") if (options.providerName === "d1") {
@@ -1325,8 +1406,7 @@ var ViteCommands = class {
1325
1406
  vercel: t.optional(t.boolean({ description: "Generate Vercel deployment configuration" })),
1326
1407
  cloudflare: t.optional(t.boolean({ description: "Generate Cloudflare Workers configuration" })),
1327
1408
  docker: t.optional(t.boolean({ description: "Generate Docker configuration" })),
1328
- sitemap: t.optional(t.text({ description: "Generate sitemap.xml with base URL" })),
1329
- prerender: t.optional(t.boolean({ description: "Pre-render static pages" }))
1409
+ sitemap: t.optional(t.text({ description: "Generate sitemap.xml with base URL" }))
1330
1410
  }),
1331
1411
  handler: async ({ flags, args, run, root }) => {
1332
1412
  process.env.ALEPHA_BUILD_MODE = "cli";
@@ -1343,7 +1423,7 @@ var ViteCommands = class {
1343
1423
  await this.utils.ensureDependency(root, "vite", { run });
1344
1424
  await run.rm("dist", { alias: "clean dist" });
1345
1425
  const viteAlephaBuildOptions = (await createRequire(import.meta.url)("vite").resolveConfig({}, "build", "production")).plugins.find((it) => it.name === "alepha:build")?.[OPTIONS] || {};
1346
- await this.utils.loadEnvFile(root, [".env", ".env.production"]);
1426
+ await this.utils.loadEnv(root, [".env", ".env.production"]);
1347
1427
  const stats = flags.stats ?? viteAlephaBuildOptions.stats ?? false;
1348
1428
  const hasServer = viteAlephaBuildOptions.serverEntry !== false;
1349
1429
  let hasClient = false;
@@ -1396,7 +1476,7 @@ var ViteCommands = class {
1396
1476
  }));
1397
1477
  }
1398
1478
  });
1399
- if (flags.prerender ?? clientOptions.prerender) await run({
1479
+ if (clientOptions.prerender) await run({
1400
1480
  name: "pre-render pages",
1401
1481
  handler: async () => {
1402
1482
  await prerenderPages({
@@ -1443,13 +1523,22 @@ var ViteCommands = class {
1443
1523
  test = $command({
1444
1524
  name: "test",
1445
1525
  description: "Run tests using Vitest",
1446
- handler: async ({ root }) => {
1526
+ flags: t.object({ config: t.optional(t.string({
1527
+ description: "Path to Vitest config file",
1528
+ alias: "c"
1529
+ })) }),
1530
+ env: t.object({ VITEST_ARGS: t.optional(t.string({
1531
+ default: "",
1532
+ description: "Additional arguments to pass to Vitest. E.g., --coverage"
1533
+ })) }),
1534
+ handler: async ({ root, flags, env }) => {
1447
1535
  await this.utils.ensureConfig(root, {
1448
1536
  tsconfigJson: true,
1449
1537
  viteConfigTs: true
1450
1538
  });
1451
1539
  await this.utils.ensureDependency(root, "vitest");
1452
- await this.utils.exec(`vitest run ${this.env.VITEST_ARGS}`);
1540
+ const config = flags.config ? `--config=${flags.config}` : "";
1541
+ await this.utils.exec(`vitest run ${config} ${env.VITEST_ARGS}`);
1453
1542
  }
1454
1543
  });
1455
1544
  };
@@ -1466,7 +1555,7 @@ var AlephaCliExtension = class {
1466
1555
  if (!await this.fs.exists(extensionPath)) return;
1467
1556
  const { default: Extension } = await import(extensionPath);
1468
1557
  if (typeof Extension !== "function") return;
1469
- this.alepha.with(Extension);
1558
+ this.alepha.inject(Extension, { args: [this.alepha] });
1470
1559
  }
1471
1560
  });
1472
1561
  };
@@ -1474,12 +1563,13 @@ const AlephaCli = $module({
1474
1563
  name: "alepha.cli",
1475
1564
  services: [
1476
1565
  AlephaCliExtension,
1566
+ BiomeCommands,
1477
1567
  ChangelogCommands,
1478
1568
  CoreCommands,
1569
+ DeployCommands,
1479
1570
  DrizzleCommands,
1480
1571
  VerifyCommands,
1481
- ViteCommands,
1482
- BiomeCommands
1572
+ ViteCommands
1483
1573
  ]
1484
1574
  });
1485
1575
 
@@ -1523,6 +1613,8 @@ var AlephaPackageBuilderCli = class {
1523
1613
  await this.fs.writeFile(join(tmpDir, "module-dependencies.json"), JSON.stringify(modules, null, 2));
1524
1614
  const tsconfig = await readFile(join(root, "../../tsconfig.json"), "utf-8");
1525
1615
  const external = Object.keys(JSON.parse(tsconfig).compilerOptions.paths);
1616
+ external.push("bun");
1617
+ external.push("bun:sqlite");
1526
1618
  await run.rm(this.dist);
1527
1619
  const build = async (item) => {
1528
1620
  const entries = [];
@@ -1672,5 +1764,14 @@ async function analyzeModules(srcDir, packageName) {
1672
1764
  }
1673
1765
 
1674
1766
  //#endregion
1675
- export { AlephaCli, AlephaCliUtils, AlephaPackageBuilderCli, BiomeCommands, CoreCommands, DrizzleCommands, VerifyCommands, ViteCommands, analyzeModules, version };
1767
+ //#region ../../src/cli/defineConfig.ts
1768
+ const defineConfig = (config) => {
1769
+ return (alepha) => {
1770
+ const { commands } = config(alepha);
1771
+ return { ...commands };
1772
+ };
1773
+ };
1774
+
1775
+ //#endregion
1776
+ export { AlephaCli, AlephaCliUtils, AlephaPackageBuilderCli, BiomeCommands, ChangelogCommands, CoreCommands, DEFAULT_IGNORE, DeployCommands, DrizzleCommands, GitMessageParser, GitProvider, VerifyCommands, ViteCommands, analyzeModules, changelogOptions, defineConfig, version };
1676
1777
  //# sourceMappingURL=index.js.map