@base44-preview/cli 0.0.1-pr.18.d6d2f8e → 0.0.1-pr.20.e0a0f93

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 (2) hide show
  1. package/dist/cli/index.js +144 -7
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from "commander";
3
3
  import chalk from "chalk";
4
- import { cancel, group, intro, log, select, spinner, text } from "@clack/prompts";
4
+ import { cancel, confirm, group, intro, isCancel, log, select, spinner, text } from "@clack/prompts";
5
5
  import pWaitFor from "p-wait-for";
6
6
  import { z } from "zod";
7
7
  import ky from "ky";
@@ -27,14 +27,12 @@ const DeviceCodeResponseSchema = z.object({
27
27
  device_code: z.string().min(1, "Device code cannot be empty"),
28
28
  user_code: z.string().min(1, "User code cannot be empty"),
29
29
  verification_uri: z.url("Invalid verification URL"),
30
- verification_uri_complete: z.url("Invalid complete verification URL"),
31
30
  expires_in: z.number().int().positive("Expires in must be a positive integer"),
32
31
  interval: z.number().int().positive("Interval in must be a positive integer")
33
32
  }).transform((data) => ({
34
33
  deviceCode: data.device_code,
35
34
  userCode: data.user_code,
36
35
  verificationUri: data.verification_uri,
37
- verificationUriComplete: data.verification_uri_complete,
38
36
  expiresIn: data.expires_in,
39
37
  interval: data.interval
40
38
  }));
@@ -690,11 +688,13 @@ async function runCommand(commandFn, options) {
690
688
  * The spinner is automatically started, and stopped on both success and error.
691
689
  *
692
690
  * @param startMessage - Message to show when spinner starts
693
- * @param operation - The async operation to execute
691
+ * @param operation - The async operation to execute. Receives an updateMessage function
692
+ * to update the spinner text during long-running operations.
694
693
  * @param options - Optional configuration for success/error messages
695
694
  * @returns The result of the operation
696
695
  *
697
696
  * @example
697
+ * // Simple usage
698
698
  * const data = await runTask(
699
699
  * "Fetching data...",
700
700
  * async () => {
@@ -706,12 +706,27 @@ async function runCommand(commandFn, options) {
706
706
  * errorMessage: "Failed to fetch data",
707
707
  * }
708
708
  * );
709
+ *
710
+ * @example
711
+ * // With progress updates
712
+ * const result = await runTask(
713
+ * "Processing files...",
714
+ * async (updateMessage) => {
715
+ * for (const file of files) {
716
+ * updateMessage(`Processing ${file.name}...`);
717
+ * await process(file);
718
+ * }
719
+ * return files.length;
720
+ * },
721
+ * { successMessage: "All files processed" }
722
+ * );
709
723
  */
710
724
  async function runTask(startMessage, operation, options) {
711
725
  const s = spinner();
712
726
  s.start(startMessage);
727
+ const updateMessage = (message) => s.message(message);
713
728
  try {
714
- const result = await operation();
729
+ const result = await operation(updateMessage);
715
730
  s.stop(options?.successMessage || startMessage);
716
731
  return result;
717
732
  } catch (error) {
@@ -740,13 +755,13 @@ async function generateAndDisplayDeviceCode() {
740
755
  successMessage: "Device code generated",
741
756
  errorMessage: "Failed to generate device code"
742
757
  });
743
- log.info(`Your code is: ${chalk.bold(deviceCodeResponse.userCode)}\nPlease visit: ${deviceCodeResponse.verificationUriComplete}`);
758
+ log.info(`Verification code: ${chalk.bold(deviceCodeResponse.userCode)}\nPlease confirm this code at: ${deviceCodeResponse.verificationUri}`);
744
759
  return deviceCodeResponse;
745
760
  }
746
761
  async function waitForAuthentication(deviceCode, expiresIn, interval) {
747
762
  let tokenResponse;
748
763
  try {
749
- await runTask("Waiting for you to complete authentication...", async () => {
764
+ await runTask("Waiting for authentication...", async () => {
750
765
  await pWaitFor(async () => {
751
766
  const result = await getTokenFromDeviceCode(deviceCode);
752
767
  if (result !== null) {
@@ -826,6 +841,102 @@ const showProjectCommand = new Command("show-project").description("Display proj
826
841
  await runCommand(showProject);
827
842
  });
828
843
 
844
+ //#endregion
845
+ //#region src/core/site/schema.ts
846
+ /**
847
+ * Represents a single file to be deployed.
848
+ * Contains the relative path and base64-encoded content.
849
+ */
850
+ const SiteFileSchema = z.object({
851
+ path: z.string(),
852
+ content: z.string()
853
+ });
854
+ /**
855
+ * Response from the deploy API endpoint.
856
+ */
857
+ const DeployResponseSchema = z.object({ url: z.string().url() });
858
+
859
+ //#endregion
860
+ //#region src/core/site/config.ts
861
+ async function readSiteFile(outputDir, relativePath) {
862
+ const content = (await readFile(join(outputDir, relativePath))).toString("base64");
863
+ await new Promise((resolve$1) => setTimeout(resolve$1, 20));
864
+ return {
865
+ path: relativePath,
866
+ content
867
+ };
868
+ }
869
+ async function getSiteFilePaths(outputDir) {
870
+ return await globby("**/*", {
871
+ cwd: outputDir,
872
+ onlyFiles: true,
873
+ absolute: false
874
+ });
875
+ }
876
+ /**
877
+ * Reads site files one by one, yielding each file as it's read.
878
+ * Useful for showing progress during file reading.
879
+ *
880
+ * @param outputDir - The directory containing built site files
881
+ * @param filePaths - Array of relative file paths to read
882
+ * @yields Each file as it's read
883
+ *
884
+ * @example
885
+ * const paths = await getSiteFilePaths("./dist");
886
+ * for await (const file of readSiteFilesStream("./dist", paths)) {
887
+ * console.log(`Read: ${file.path}`);
888
+ * }
889
+ */
890
+ async function* readSiteFilesStream(outputDir, filePaths) {
891
+ for (const relativePath of filePaths) yield await readSiteFile(outputDir, relativePath);
892
+ }
893
+
894
+ //#endregion
895
+ //#region src/core/site/api.ts
896
+ /**
897
+ * Uploads site files to the Base44 hosting API.
898
+ *
899
+ * @param files - Array of files with base64-encoded content to upload
900
+ * @returns Deploy response with the site URL
901
+ */
902
+ async function uploadSite(files) {
903
+ await new Promise((resolve$1) => setTimeout(resolve$1, 2e3));
904
+ return { url: "https://example.base44.app" };
905
+ }
906
+
907
+ //#endregion
908
+ //#region src/core/site/deploy.ts
909
+ /**
910
+ * Deploys a site from the given output directory to Base44 hosting.
911
+ * Reads files one by one with progress callback, validates, and uploads to the API.
912
+ *
913
+ * @param outputDir - The directory containing built site files (e.g., "./dist")
914
+ * @param onProgress - Optional callback called for each file read
915
+ * @returns Deploy response with the site URL
916
+ * @throws Error if no files found in the output directory
917
+ *
918
+ * @example
919
+ * const { url } = await deploySite("./dist", (progress) => {
920
+ * console.log(`Reading ${progress.current}/${progress.total}: ${progress.path}`);
921
+ * });
922
+ */
923
+ async function deploySite(outputDir, onProgress) {
924
+ const filePaths = await getSiteFilePaths(outputDir);
925
+ if (filePaths.length === 0) throw new Error(`No files found in output directory: ${outputDir}. Make sure to build your project first.`);
926
+ const files = [];
927
+ let current = 0;
928
+ for await (const file of readSiteFilesStream(outputDir, filePaths)) {
929
+ current++;
930
+ onProgress?.({
931
+ total: filePaths.length,
932
+ current,
933
+ path: file.path
934
+ });
935
+ files.push(file);
936
+ }
937
+ return await uploadSite(files);
938
+ }
939
+
829
940
  //#endregion
830
941
  //#region src/cli/commands/entities/push.ts
831
942
  async function pushEntitiesAction() {
@@ -901,6 +1012,31 @@ const createCommand = new Command("create").description("Create a new Base44 pro
901
1012
  await runCommand(create, { fullBanner: true });
902
1013
  });
903
1014
 
1015
+ //#endregion
1016
+ //#region src/cli/commands/site/deploy.ts
1017
+ async function deployAction() {
1018
+ const { project } = await readProjectConfig();
1019
+ if (!project.site?.outputDirectory) throw new Error("No site configuration found. Please add 'site.outputDirectory' to your config.jsonc");
1020
+ const outputDir = resolve(project.root, project.site.outputDirectory);
1021
+ const shouldDeploy = await confirm({ message: `Deploy site from ${project.site.outputDirectory}?` });
1022
+ if (isCancel(shouldDeploy) || !shouldDeploy) {
1023
+ log.warn("Deployment cancelled");
1024
+ return;
1025
+ }
1026
+ const result = await runTask("Reading site files...", async (updateMessage) => {
1027
+ return await deploySite(outputDir, (progress) => {
1028
+ updateMessage(`Reading files (${progress.current}/${progress.total}): ${progress.path}`);
1029
+ });
1030
+ }, {
1031
+ successMessage: "Site deployed successfully",
1032
+ errorMessage: "Deployment failed"
1033
+ });
1034
+ log.success(`Site deployed to: ${result.url}`);
1035
+ }
1036
+ const siteDeployCommand = new Command("site").description("Manage site deployments").addCommand(new Command("deploy").description("Deploy built site files to Base44 hosting").action(async () => {
1037
+ await runCommand(deployAction);
1038
+ }));
1039
+
904
1040
  //#endregion
905
1041
  //#region package.json
906
1042
  var version = "0.0.1";
@@ -915,6 +1051,7 @@ program.addCommand(logoutCommand);
915
1051
  program.addCommand(createCommand);
916
1052
  program.addCommand(showProjectCommand);
917
1053
  program.addCommand(entitiesPushCommand);
1054
+ program.addCommand(siteDeployCommand);
918
1055
  program.parse();
919
1056
 
920
1057
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/cli",
3
- "version": "0.0.1-pr.18.d6d2f8e",
3
+ "version": "0.0.1-pr.20.e0a0f93",
4
4
  "description": "Base44 CLI - Unified interface for managing Base44 applications",
5
5
  "type": "module",
6
6
  "main": "./dist/cli/index.js",