@base44-preview/cli 0.0.14-pr.86.814f3a9 → 0.0.14-pr.87.4100d16

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 +182 -48
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -7867,14 +7867,10 @@ var AuthValidationError = class extends Error {
7867
7867
  //#endregion
7868
7868
  //#region src/core/consts.ts
7869
7869
  const PROJECT_SUBDIR = "base44";
7870
- const FUNCTION_CONFIG_FILE = "function.jsonc";
7870
+ const CONFIG_FILE_EXTENSION_GLOB = "{json,jsonc}";
7871
+ const FUNCTION_CONFIG_FILE = `function.${CONFIG_FILE_EXTENSION_GLOB}`;
7871
7872
  function getProjectConfigPatterns() {
7872
- return [
7873
- `${PROJECT_SUBDIR}/config.jsonc`,
7874
- `${PROJECT_SUBDIR}/config.json`,
7875
- "config.jsonc",
7876
- "config.json"
7877
- ];
7873
+ return [`${PROJECT_SUBDIR}/config.${CONFIG_FILE_EXTENSION_GLOB}`, `config.${CONFIG_FILE_EXTENSION_GLOB}`];
7878
7874
  }
7879
7875
  const AUTH_CLIENT_ID = "base44_cli";
7880
7876
 
@@ -16732,7 +16728,7 @@ async function readEntityFile(entityPath) {
16732
16728
  }
16733
16729
  async function readAllEntities(entitiesDir) {
16734
16730
  if (!await pathExists(entitiesDir)) return [];
16735
- const files = await globby("*.{json,jsonc}", {
16731
+ const files = await globby(`*.${CONFIG_FILE_EXTENSION_GLOB}`, {
16736
16732
  cwd: entitiesDir,
16737
16733
  absolute: true
16738
16734
  });
@@ -26329,6 +26325,58 @@ async function printBanner() {
26329
26325
  else console.log(theme.colors.base44Orange(BANNER_LINES.join("\n")));
26330
26326
  }
26331
26327
 
26328
+ //#endregion
26329
+ //#region src/cli/utils/json.ts
26330
+ /**
26331
+ * JSON output utilities for CLI commands.
26332
+ *
26333
+ * These utilities support the `--json` flag which outputs machine-readable JSON
26334
+ * instead of human-friendly formatted output.
26335
+ */
26336
+ let jsonModeEnabled = false;
26337
+ /**
26338
+ * Enable JSON output mode. Called by runCommand when --json flag is detected.
26339
+ */
26340
+ function setJsonMode(enabled) {
26341
+ jsonModeEnabled = enabled;
26342
+ }
26343
+ /**
26344
+ * Check if JSON output mode is currently active.
26345
+ */
26346
+ function isJsonMode() {
26347
+ return jsonModeEnabled;
26348
+ }
26349
+ /**
26350
+ * Output a success JSON response to stdout.
26351
+ * Only outputs if JSON mode is enabled.
26352
+ */
26353
+ function outputJson(data) {
26354
+ if (!jsonModeEnabled) return;
26355
+ const response = {
26356
+ success: true,
26357
+ data
26358
+ };
26359
+ console.log(JSON.stringify(response, null, 2));
26360
+ }
26361
+ /**
26362
+ * Output an error JSON response to stderr.
26363
+ * Only outputs if JSON mode is enabled.
26364
+ *
26365
+ * @param error - The error to output
26366
+ * @param code - Optional error code
26367
+ */
26368
+ function outputJsonError(error, code$1) {
26369
+ if (!jsonModeEnabled) return;
26370
+ const response = {
26371
+ success: false,
26372
+ error: {
26373
+ message: error instanceof Error ? error.message : error,
26374
+ ...code$1 && { code: code$1 }
26375
+ }
26376
+ };
26377
+ console.error(JSON.stringify(response, null, 2));
26378
+ }
26379
+
26332
26380
  //#endregion
26333
26381
  //#region src/cli/utils/runCommand.ts
26334
26382
  /**
@@ -26370,25 +26418,35 @@ async function printBanner() {
26370
26418
  * });
26371
26419
  */
26372
26420
  async function runCommand(commandFn, options) {
26373
- console.log();
26374
- if (options?.fullBanner) {
26375
- await printBanner();
26376
- Ie("");
26377
- } else Ie(theme.colors.base44OrangeBackground(" Base 44 "));
26421
+ const jsonMode = isJsonMode();
26422
+ if (!jsonMode) {
26423
+ console.log();
26424
+ if (options?.fullBanner) {
26425
+ await printBanner();
26426
+ Ie("");
26427
+ } else Ie(theme.colors.base44OrangeBackground(" Base 44 "));
26428
+ }
26378
26429
  await loadProjectEnv();
26379
26430
  try {
26380
26431
  if (options?.requireAuth) {
26381
26432
  if (!await isLoggedIn()) {
26433
+ if (jsonMode) throw new Error("Authentication required. Please run 'base44 login' first.");
26382
26434
  M.info("You need to login first to continue.");
26383
26435
  await login();
26384
26436
  }
26385
26437
  }
26386
- const { outroMessage } = await commandFn();
26387
- Se(outroMessage || "");
26438
+ const { outroMessage, data } = await commandFn();
26439
+ if (jsonMode) outputJson(data ?? {});
26440
+ else Se(outroMessage || "");
26388
26441
  } catch (e$1) {
26389
- if (e$1 instanceof Error) M.error(e$1.stack ?? e$1.message);
26390
- else M.error(String(e$1));
26391
- process.exit(1);
26442
+ if (jsonMode) {
26443
+ outputJsonError(e$1 instanceof Error ? e$1 : String(e$1));
26444
+ process.exit(1);
26445
+ } else {
26446
+ if (e$1 instanceof Error) M.error(e$1.stack ?? e$1.message);
26447
+ else M.error(String(e$1));
26448
+ process.exit(1);
26449
+ }
26392
26450
  }
26393
26451
  }
26394
26452
 
@@ -26398,6 +26456,8 @@ async function runCommand(commandFn, options) {
26398
26456
  * Wraps an async operation with automatic spinner management.
26399
26457
  * The spinner is automatically started, and stopped on both success and error.
26400
26458
  *
26459
+ * In JSON mode, the spinner is suppressed and the operation runs silently.
26460
+ *
26401
26461
  * @param startMessage - Message to show when spinner starts
26402
26462
  * @param operation - The async operation to execute. Receives an updateMessage function
26403
26463
  * to update the spinner text during long-running operations.
@@ -26433,6 +26493,10 @@ async function runCommand(commandFn, options) {
26433
26493
  * );
26434
26494
  */
26435
26495
  async function runTask(startMessage, operation, options) {
26496
+ if (isJsonMode()) {
26497
+ const noopUpdateMessage = () => {};
26498
+ return await operation(noopUpdateMessage);
26499
+ }
26436
26500
  const s = Y();
26437
26501
  s.start(startMessage);
26438
26502
  const updateMessage = (message) => s.message(message);
@@ -26459,6 +26523,10 @@ const onPromptCancel = () => {
26459
26523
 
26460
26524
  //#endregion
26461
26525
  //#region src/cli/commands/auth/login.ts
26526
+ /**
26527
+ * Login command does not support --json output.
26528
+ * It requires interactive browser authentication via device code flow.
26529
+ */
26462
26530
  async function generateAndDisplayDeviceCode() {
26463
26531
  const deviceCodeResponse = await runTask("Generating device code...", async () => {
26464
26532
  return await generateDeviceCode();
@@ -26520,7 +26588,13 @@ const loginCommand = new Command("login").description("Authenticate with Base44"
26520
26588
  //#region src/cli/commands/auth/whoami.ts
26521
26589
  async function whoami() {
26522
26590
  const auth = await readAuth();
26523
- return { outroMessage: `Logged in as: ${theme.styles.bold(auth.email)}` };
26591
+ return {
26592
+ outroMessage: `Logged in as: ${theme.styles.bold(auth.email)}`,
26593
+ data: {
26594
+ email: auth.email,
26595
+ name: auth.name
26596
+ }
26597
+ };
26524
26598
  }
26525
26599
  const whoamiCommand = new Command("whoami").description("Display current authenticated user").action(async () => {
26526
26600
  await runCommand(whoami, { requireAuth: true });
@@ -26528,6 +26602,10 @@ const whoamiCommand = new Command("whoami").description("Display current authent
26528
26602
 
26529
26603
  //#endregion
26530
26604
  //#region src/cli/commands/auth/logout.ts
26605
+ /**
26606
+ * Logout command does not support --json output.
26607
+ * It is a user-facing auth command that is rarely scripted.
26608
+ */
26531
26609
  async function logout() {
26532
26610
  await deleteAuth();
26533
26611
  return { outroMessage: "Logged out successfully" };
@@ -31523,18 +31601,31 @@ async function createArchive(pathToArchive, targetArchivePath) {
31523
31601
  //#region src/cli/commands/entities/push.ts
31524
31602
  async function pushEntitiesAction() {
31525
31603
  const { entities } = await readProjectConfig();
31526
- if (entities.length === 0) return { outroMessage: "No entities found in project" };
31527
- M.info(`Found ${entities.length} entities to push`);
31604
+ if (entities.length === 0) return {
31605
+ outroMessage: "No entities found in project",
31606
+ data: {
31607
+ created: [],
31608
+ updated: [],
31609
+ deleted: []
31610
+ }
31611
+ };
31612
+ if (!isJsonMode()) M.info(`Found ${entities.length} entities to push`);
31528
31613
  const result = await runTask("Pushing entities to Base44", async () => {
31529
31614
  return await pushEntities(entities);
31530
31615
  }, {
31531
31616
  successMessage: "Entities pushed successfully",
31532
31617
  errorMessage: "Failed to push entities"
31533
31618
  });
31534
- if (result.created.length > 0) M.success(`Created: ${result.created.join(", ")}`);
31535
- if (result.updated.length > 0) M.success(`Updated: ${result.updated.join(", ")}`);
31536
- if (result.deleted.length > 0) M.warn(`Deleted: ${result.deleted.join(", ")}`);
31537
- return {};
31619
+ if (!isJsonMode()) {
31620
+ if (result.created.length > 0) M.success(`Created: ${result.created.join(", ")}`);
31621
+ if (result.updated.length > 0) M.success(`Updated: ${result.updated.join(", ")}`);
31622
+ if (result.deleted.length > 0) M.warn(`Deleted: ${result.deleted.join(", ")}`);
31623
+ }
31624
+ return { data: {
31625
+ created: result.created,
31626
+ updated: result.updated,
31627
+ deleted: result.deleted
31628
+ } };
31538
31629
  }
31539
31630
  const entitiesPushCommand = new Command("entities").description("Manage project entities").addCommand(new Command("push").description("Push local entities to Base44").action(async () => {
31540
31631
  await runCommand(pushEntitiesAction, { requireAuth: true });
@@ -31544,21 +31635,32 @@ const entitiesPushCommand = new Command("entities").description("Manage project
31544
31635
  //#region src/cli/commands/functions/deploy.ts
31545
31636
  async function deployFunctionsAction() {
31546
31637
  const { functions } = await readProjectConfig();
31547
- if (functions.length === 0) return { outroMessage: "No functions found. Create functions in the 'functions' directory." };
31548
- M.info(`Found ${functions.length} ${functions.length === 1 ? "function" : "functions"} to deploy`);
31638
+ if (functions.length === 0) return {
31639
+ outroMessage: "No functions found. Create functions in the 'functions' directory.",
31640
+ data: {
31641
+ deployed: [],
31642
+ deleted: []
31643
+ }
31644
+ };
31645
+ if (!isJsonMode()) M.info(`Found ${functions.length} ${functions.length === 1 ? "function" : "functions"} to deploy`);
31549
31646
  const result = await runTask("Deploying functions to Base44", async () => {
31550
31647
  return await pushFunctions(functions);
31551
31648
  }, {
31552
31649
  successMessage: "Functions deployed successfully",
31553
31650
  errorMessage: "Failed to deploy functions"
31554
31651
  });
31555
- if (result.deployed.length > 0) M.success(`Deployed: ${result.deployed.join(", ")}`);
31556
- if (result.deleted.length > 0) M.warn(`Deleted: ${result.deleted.join(", ")}`);
31652
+ if (!isJsonMode()) {
31653
+ if (result.deployed.length > 0) M.success(`Deployed: ${result.deployed.join(", ")}`);
31654
+ if (result.deleted.length > 0) M.warn(`Deleted: ${result.deleted.join(", ")}`);
31655
+ }
31557
31656
  if (result.errors && result.errors.length > 0) {
31558
31657
  const errorMessages = result.errors.map((e$1) => `'${e$1.name}' function: ${e$1.message}`).join("\n");
31559
31658
  throw new Error(`Function deployment errors:\n${errorMessages}`);
31560
31659
  }
31561
- return {};
31660
+ return { data: {
31661
+ deployed: result.deployed,
31662
+ deleted: result.deleted
31663
+ } };
31562
31664
  }
31563
31665
  const functionsDeployCommand = new Command("functions").description("Manage project functions").addCommand(new Command("deploy").description("Deploy local functions to Base44").action(async () => {
31564
31666
  await runCommand(deployFunctionsAction, { requireAuth: true });
@@ -38243,8 +38345,9 @@ async function getTemplateById(templateId) {
38243
38345
  return template;
38244
38346
  }
38245
38347
  function validateNonInteractiveFlags$1(command) {
38246
- const { name: name$1, path: path$17 } = command.opts();
38348
+ const { name: name$1, path: path$17, json } = command.optsWithGlobals();
38247
38349
  const providedCount = [name$1, path$17].filter(Boolean).length;
38350
+ if (json && providedCount < 2) command.error("JSON mode requires all flags: --name, --path");
38248
38351
  if (providedCount > 0 && providedCount < 2) command.error("Non-interactive mode requires all flags: --name, --path");
38249
38352
  }
38250
38353
  async function chooseCreate(options) {
@@ -38362,10 +38465,20 @@ async function executeCreate({ template, name: rawName, description, projectPath
38362
38465
  }
38363
38466
  }
38364
38467
  const dashboardUrl = `${getBase44ApiUrl()}/apps/${projectId}/editor/preview`;
38365
- M.message(`${theme.styles.header("Project")}: ${theme.colors.base44Orange(name$1)}`);
38366
- M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(dashboardUrl)}`);
38367
- if (finalAppUrl) M.message(`${theme.styles.header("Site")}: ${theme.colors.links(finalAppUrl)}`);
38368
- return { outroMessage: "Your project is set up and ready to use" };
38468
+ if (!isJsonMode()) {
38469
+ M.message(`${theme.styles.header("Project")}: ${theme.colors.base44Orange(name$1)}`);
38470
+ M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(dashboardUrl)}`);
38471
+ if (finalAppUrl) M.message(`${theme.styles.header("Site")}: ${theme.colors.links(finalAppUrl)}`);
38472
+ }
38473
+ return {
38474
+ outroMessage: "Your project is set up and ready to use",
38475
+ data: {
38476
+ projectId,
38477
+ path: resolvedPath,
38478
+ dashboardUrl,
38479
+ ...finalAppUrl && { appUrl: finalAppUrl }
38480
+ }
38481
+ };
38369
38482
  }
38370
38483
  const createCommand = new Command("create").description("Create a new Base44 project").option("-n, --name <name>", "Project name").option("-d, --description <description>", "Project description").option("-p, --path <path>", "Path where to create the project").option("-t, --template <id>", "Template ID (e.g., backend-only, backend-and-client)").option("--deploy", "Build and deploy the site").hook("preAction", validateNonInteractiveFlags$1).action(async (options) => {
38371
38484
  await chooseCreate(options);
@@ -38912,22 +39025,27 @@ var open_default = open;
38912
39025
 
38913
39026
  //#endregion
38914
39027
  //#region src/cli/commands/project/dashboard.ts
38915
- async function openDashboard() {
39028
+ async function openDashboard(options) {
38916
39029
  await loadProjectEnv();
38917
39030
  const projectId = getBase44ClientId();
38918
39031
  if (!projectId) throw new Error("App not configured. BASE44_CLIENT_ID environment variable is required. Set it in your .env.local file.");
38919
39032
  const dashboardUrl = `${getBase44ApiUrl()}/apps/${projectId}/editor/workspace/overview`;
38920
- await open_default(dashboardUrl);
38921
- return { outroMessage: `Dashboard opened at ${dashboardUrl}` };
39033
+ const shouldOpen = !isJsonMode() && options.open !== false;
39034
+ if (shouldOpen) await open_default(dashboardUrl);
39035
+ return {
39036
+ outroMessage: shouldOpen ? `Dashboard opened at ${dashboardUrl}` : `Dashboard URL: ${dashboardUrl}`,
39037
+ data: { dashboardUrl }
39038
+ };
38922
39039
  }
38923
- const dashboardCommand = new Command("dashboard").description("Open the app dashboard in your browser").action(async () => {
38924
- await runCommand(openDashboard, { requireAuth: true });
39040
+ const dashboardCommand = new Command("dashboard").description("Open the app dashboard in your browser").option("--no-open", "Print the URL without opening the browser").action(async (options) => {
39041
+ await runCommand(() => openDashboard(options), { requireAuth: true });
38925
39042
  });
38926
39043
 
38927
39044
  //#endregion
38928
39045
  //#region src/cli/commands/project/link.ts
38929
39046
  function validateNonInteractiveFlags(command) {
38930
- const { create: create$1, name: name$1 } = command.opts();
39047
+ const { create: create$1, name: name$1, json } = command.optsWithGlobals();
39048
+ if (json && (!create$1 || !name$1)) command.error("JSON mode requires flags: --create, --name");
38931
39049
  if (create$1 && !name$1) command.error("--name is required when using --create");
38932
39050
  }
38933
39051
  async function promptForProjectDetails() {
@@ -38976,8 +39094,14 @@ async function link(options) {
38976
39094
  });
38977
39095
  await writeEnvLocal(projectRoot.root, projectId);
38978
39096
  const dashboardUrl = `${getBase44ApiUrl()}/apps/${projectId}/editor/workspace/overview`;
38979
- M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(dashboardUrl)}`);
38980
- return { outroMessage: "Project linked" };
39097
+ if (!isJsonMode()) M.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(dashboardUrl)}`);
39098
+ return {
39099
+ outroMessage: "Project linked",
39100
+ data: {
39101
+ projectId,
39102
+ dashboardUrl
39103
+ }
39104
+ };
38981
39105
  }
38982
39106
  const linkCommand = new Command("link").description("Link a local project to a Base44 project").option("-c, --create", "Create a new project (skip selection prompt)").option("-n, --name <name>", "Project name (required when --create is used)").option("-d, --description <description>", "Project description").hook("preAction", validateNonInteractiveFlags).action(async (options) => {
38983
39107
  await runCommand(() => link(options), { requireAuth: true });
@@ -38989,16 +39113,23 @@ async function deployAction(options) {
38989
39113
  const { project } = await readProjectConfig();
38990
39114
  if (!project.site?.outputDirectory) throw new Error("No site configuration found. Please add 'site.outputDirectory' to your config.jsonc");
38991
39115
  const outputDir = resolve(project.root, project.site.outputDirectory);
38992
- if (!options.yes) {
39116
+ if (!options.yes && !isJsonMode()) {
38993
39117
  const shouldDeploy = await ye({ message: `Deploy site from ${project.site.outputDirectory}?` });
38994
- if (pD(shouldDeploy) || !shouldDeploy) return { outroMessage: "Deployment cancelled" };
39118
+ if (pD(shouldDeploy) || !shouldDeploy) return {
39119
+ outroMessage: "Deployment cancelled",
39120
+ data: { cancelled: true }
39121
+ };
38995
39122
  }
38996
- return { outroMessage: `Visit your site at: ${(await runTask("Creating archive and deploying site...", async () => {
39123
+ const result = await runTask("Creating archive and deploying site...", async () => {
38997
39124
  return await deploySite(outputDir);
38998
39125
  }, {
38999
39126
  successMessage: "Site deployed successfully",
39000
39127
  errorMessage: "Deployment failed"
39001
- })).appUrl}` };
39128
+ });
39129
+ return {
39130
+ outroMessage: `Visit your site at: ${result.appUrl}`,
39131
+ data: { appUrl: result.appUrl }
39132
+ };
39002
39133
  }
39003
39134
  const siteDeployCommand = new Command("site").description("Manage site deployments").addCommand(new Command("deploy").description("Deploy built site files to Base44 hosting").option("-y, --yes", "Skip confirmation prompt").action(async (options) => {
39004
39135
  await runCommand(() => deployAction(options), { requireAuth: true });
@@ -39011,7 +39142,10 @@ var version = "0.0.14";
39011
39142
  //#endregion
39012
39143
  //#region src/cli/index.ts
39013
39144
  const program = new Command();
39014
- program.name("base44").description("Base44 CLI - Unified interface for managing Base44 applications").version(version);
39145
+ program.name("base44").description("Base44 CLI - Unified interface for managing Base44 applications").version(version).option("--json", "Output results as JSON (for scripting)");
39146
+ program.hook("preAction", (thisCommand) => {
39147
+ if (thisCommand.optsWithGlobals().json) setJsonMode(true);
39148
+ });
39015
39149
  program.configureHelp({ sortSubcommands: true });
39016
39150
  program.addCommand(loginCommand);
39017
39151
  program.addCommand(whoamiCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/cli",
3
- "version": "0.0.14-pr.86.814f3a9",
3
+ "version": "0.0.14-pr.87.4100d16",
4
4
  "description": "Base44 CLI - Unified interface for managing Base44 applications",
5
5
  "type": "module",
6
6
  "main": "./dist/cli/index.js",