@base44-preview/cli 0.0.44-pr.382.bab01f6 → 0.0.44-pr.384.4b98c80

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.
package/dist/cli/index.js CHANGED
@@ -238249,11 +238249,8 @@ var BackendFunctionSchema = FunctionConfigSchema.extend({
238249
238249
  entryPath: exports_external.string().min(1, "Entry path cannot be empty"),
238250
238250
  filePaths: exports_external.array(exports_external.string()).min(1, "Function must have at least one file")
238251
238251
  });
238252
- var DeployFunctionsResponseSchema = exports_external.object({
238253
- deployed: exports_external.array(exports_external.string()),
238254
- deleted: exports_external.array(exports_external.string()),
238255
- skipped: exports_external.array(exports_external.string()).optional().nullable(),
238256
- errors: exports_external.array(exports_external.object({ name: exports_external.string(), message: exports_external.string() })).nullable()
238252
+ var DeploySingleFunctionResponseSchema = exports_external.object({
238253
+ status: exports_external.enum(["deployed", "unchanged"])
238257
238254
  });
238258
238255
  var FunctionInfoSchema = exports_external.object({
238259
238256
  name: exports_external.string(),
@@ -238280,29 +238277,15 @@ var FunctionLogEntrySchema = exports_external.object({
238280
238277
  var FunctionLogsResponseSchema = exports_external.array(FunctionLogEntrySchema);
238281
238278
 
238282
238279
  // src/core/resources/function/api.ts
238283
- function toDeployPayloadItem(fn) {
238284
- return {
238285
- name: fn.name,
238286
- entry: fn.entry,
238287
- files: fn.files,
238288
- automations: fn.automations
238289
- };
238290
- }
238291
- async function deployFunctions(functions) {
238280
+ async function deploySingleFunction(name2, payload) {
238292
238281
  const appClient = getAppClient();
238293
- const payload = {
238294
- functions: functions.map(toDeployPayloadItem)
238295
- };
238296
238282
  let response;
238297
238283
  try {
238298
- response = await appClient.put("backend-functions", {
238299
- json: payload,
238300
- timeout: false
238301
- });
238284
+ response = await appClient.put(`backend-functions/${encodeURIComponent(name2)}`, { json: payload, timeout: false });
238302
238285
  } catch (error48) {
238303
- throw await ApiError.fromHttpError(error48, "deploying functions");
238286
+ throw await ApiError.fromHttpError(error48, `deploying function "${name2}"`);
238304
238287
  }
238305
- const result = DeployFunctionsResponseSchema.safeParse(await response.json());
238288
+ const result = DeploySingleFunctionResponseSchema.safeParse(await response.json());
238306
238289
  if (!result.success) {
238307
238290
  throw new SchemaValidationError("Invalid response from server", result.error);
238308
238291
  }
@@ -238318,6 +238301,20 @@ async function deleteSingleFunction(name2) {
238318
238301
  throw await ApiError.fromHttpError(error48, `deleting function "${name2}"`);
238319
238302
  }
238320
238303
  }
238304
+ async function listDeployedFunctions() {
238305
+ const appClient = getAppClient();
238306
+ let response;
238307
+ try {
238308
+ response = await appClient.get("backend-functions", { timeout: 30000 });
238309
+ } catch (error48) {
238310
+ throw await ApiError.fromHttpError(error48, "listing deployed functions");
238311
+ }
238312
+ const result = ListFunctionsResponseSchema.safeParse(await response.json());
238313
+ if (!result.success) {
238314
+ throw new SchemaValidationError("Invalid response from server", result.error);
238315
+ }
238316
+ return result.data;
238317
+ }
238321
238318
  function buildLogsQueryString(filters) {
238322
238319
  const params = new URLSearchParams;
238323
238320
  if (filters.since) {
@@ -238354,20 +238351,6 @@ async function fetchFunctionLogs(functionName, filters = {}) {
238354
238351
  }
238355
238352
  return result.data;
238356
238353
  }
238357
- async function listDeployedFunctions() {
238358
- const appClient = getAppClient();
238359
- let response;
238360
- try {
238361
- response = await appClient.get("backend-functions", { timeout: 30000 });
238362
- } catch (error48) {
238363
- throw await ApiError.fromHttpError(error48, "listing deployed functions");
238364
- }
238365
- const result = ListFunctionsResponseSchema.safeParse(await response.json());
238366
- if (!result.success) {
238367
- throw new SchemaValidationError("Invalid response from server", result.error);
238368
- }
238369
- return result.data;
238370
- }
238371
238354
  // src/core/resources/function/config.ts
238372
238355
  import { basename as basename2, dirname as dirname3, join as join5, relative } from "node:path";
238373
238356
  async function readFunctionConfig(configPath) {
@@ -238449,19 +238432,65 @@ async function readAllFunctions(functionsDir) {
238449
238432
  import { dirname as dirname4, relative as relative2 } from "node:path";
238450
238433
  async function loadFunctionCode(fn) {
238451
238434
  const functionDir = dirname4(fn.entryPath);
238452
- const loadedFiles = await Promise.all(fn.filePaths.map(async (filePath) => {
238435
+ const resolvedFiles = await Promise.all(fn.filePaths.map(async (filePath) => {
238453
238436
  const content = await readTextFile(filePath);
238454
238437
  const path11 = relative2(functionDir, filePath).split(/[/\\]/).join("/");
238455
238438
  return { path: path11, content };
238456
238439
  }));
238457
- return { ...fn, files: loadedFiles };
238440
+ return { ...fn, files: resolvedFiles };
238458
238441
  }
238459
- async function pushFunctions(functions) {
238460
- if (functions.length === 0) {
238461
- return { deployed: [], deleted: [], skipped: [], errors: null };
238442
+ async function deployOne(fn) {
238443
+ const start = Date.now();
238444
+ try {
238445
+ const functionWithCode = await loadFunctionCode(fn);
238446
+ const response = await deploySingleFunction(functionWithCode.name, {
238447
+ entry: functionWithCode.entry,
238448
+ files: functionWithCode.files,
238449
+ automations: functionWithCode.automations
238450
+ });
238451
+ return {
238452
+ name: functionWithCode.name,
238453
+ status: response.status,
238454
+ durationMs: Date.now() - start
238455
+ };
238456
+ } catch (error48) {
238457
+ return {
238458
+ name: fn.name,
238459
+ status: "error",
238460
+ error: error48 instanceof Error ? error48.message : String(error48)
238461
+ };
238462
+ }
238463
+ }
238464
+ async function deployFunctionsSequentially(functions, options) {
238465
+ if (functions.length === 0)
238466
+ return [];
238467
+ const results = [];
238468
+ for (const fn of functions) {
238469
+ options?.onStart?.([fn.name]);
238470
+ const result = await deployOne(fn);
238471
+ results.push(result);
238472
+ options?.onResult?.(result);
238462
238473
  }
238463
- const functionsWithCode = await Promise.all(functions.map(loadFunctionCode));
238464
- return deployFunctions(functionsWithCode);
238474
+ return results;
238475
+ }
238476
+ async function pruneRemovedFunctions(localFunctionNames) {
238477
+ const remote = await listDeployedFunctions();
238478
+ const localSet = new Set(localFunctionNames);
238479
+ const toDelete = remote.functions.filter((f) => !localSet.has(f.name));
238480
+ const results = [];
238481
+ for (const fn of toDelete) {
238482
+ try {
238483
+ await deleteSingleFunction(fn.name);
238484
+ results.push({ name: fn.name, deleted: true });
238485
+ } catch (error48) {
238486
+ results.push({
238487
+ name: fn.name,
238488
+ deleted: false,
238489
+ error: error48 instanceof Error ? error48.message : String(error48)
238490
+ });
238491
+ }
238492
+ }
238493
+ return results;
238465
238494
  }
238466
238495
  // src/core/resources/function/pull.ts
238467
238496
  import { join as join6 } from "node:path";
@@ -238526,7 +238555,7 @@ async function isFunctionUnchanged(functionDir, fn) {
238526
238555
  // src/core/resources/function/resource.ts
238527
238556
  var functionResource = {
238528
238557
  readAll: readAllFunctions,
238529
- push: pushFunctions
238558
+ push: (functions) => deployFunctionsSequentially(functions)
238530
238559
  };
238531
238560
  // src/core/project/config.ts
238532
238561
  async function findConfigInDir(dir) {
@@ -238951,10 +238980,13 @@ function hasResourcesToDeploy(projectData) {
238951
238980
  const hasConnectors = connectors.length > 0;
238952
238981
  return hasEntities || hasFunctions || hasAgents || hasConnectors || hasSite;
238953
238982
  }
238954
- async function deployAll(projectData) {
238983
+ async function deployAll(projectData, options) {
238955
238984
  const { project, entities, functions, agents, connectors } = projectData;
238956
238985
  await entityResource.push(entities);
238957
- await functionResource.push(functions);
238986
+ await deployFunctionsSequentially(functions, {
238987
+ onStart: options?.onFunctionStart,
238988
+ onResult: options?.onFunctionResult
238989
+ });
238958
238990
  await agentResource.push(agents);
238959
238991
  const { results: connectorResults } = await pushConnectors(connectors);
238960
238992
  if (project.site?.outputDirectory) {
@@ -247759,41 +247791,101 @@ function getDeleteCommand(context) {
247759
247791
  });
247760
247792
  }
247761
247793
 
247794
+ // src/cli/commands/functions/formatDeployResult.ts
247795
+ function formatDuration(ms) {
247796
+ return `${(ms / 1000).toFixed(1)}s`;
247797
+ }
247798
+ function formatDeployResult(result) {
247799
+ const label = result.name.padEnd(25);
247800
+ if (result.status === "deployed") {
247801
+ const timing = result.durationMs ? theme.styles.dim(` (${formatDuration(result.durationMs)})`) : "";
247802
+ R2.success(`${label} deployed${timing}`);
247803
+ } else if (result.status === "unchanged") {
247804
+ R2.success(`${label} unchanged`);
247805
+ } else {
247806
+ R2.error(`${label} error: ${result.error}`);
247807
+ }
247808
+ }
247809
+
247810
+ // src/cli/commands/functions/parseNames.ts
247811
+ function parseNames2(args) {
247812
+ return args.flatMap((arg) => arg.split(",")).map((n2) => n2.trim()).filter(Boolean);
247813
+ }
247814
+
247762
247815
  // src/cli/commands/functions/deploy.ts
247763
- async function deployFunctionsAction() {
247816
+ function resolveFunctionsToDeploy(names, allFunctions) {
247817
+ if (names.length === 0)
247818
+ return allFunctions;
247819
+ const notFound = names.filter((n2) => !allFunctions.some((f) => f.name === n2));
247820
+ if (notFound.length > 0) {
247821
+ throw new InvalidInputError(`Function${notFound.length > 1 ? "s" : ""} not found in project: ${notFound.join(", ")}`);
247822
+ }
247823
+ return allFunctions.filter((f) => names.includes(f.name));
247824
+ }
247825
+ function formatPruneResults(pruneResults) {
247826
+ for (const pruneResult of pruneResults) {
247827
+ if (pruneResult.deleted) {
247828
+ R2.success(`${pruneResult.name.padEnd(25)} deleted`);
247829
+ } else {
247830
+ R2.error(`${pruneResult.name.padEnd(25)} error: ${pruneResult.error}`);
247831
+ }
247832
+ }
247833
+ if (pruneResults.length > 0) {
247834
+ const pruned = pruneResults.filter((r) => r.deleted).length;
247835
+ R2.info(`${pruned} function${pruned !== 1 ? "s" : ""} removed`);
247836
+ }
247837
+ }
247838
+ function buildDeploySummary(results) {
247839
+ const deployed = results.filter((r) => r.status === "deployed").length;
247840
+ const unchanged = results.filter((r) => r.status === "unchanged").length;
247841
+ const failed = results.filter((r) => r.status === "error").length;
247842
+ const parts = [];
247843
+ if (deployed > 0)
247844
+ parts.push(`${deployed} deployed`);
247845
+ if (unchanged > 0)
247846
+ parts.push(`${unchanged} unchanged`);
247847
+ if (failed > 0)
247848
+ parts.push(`${failed} error${failed !== 1 ? "s" : ""}`);
247849
+ return parts.join(", ") || "No functions deployed";
247850
+ }
247851
+ async function deployFunctionsAction(names, options) {
247852
+ if (options.force && names.length > 0) {
247853
+ throw new InvalidInputError("--force cannot be used when specifying function names");
247854
+ }
247764
247855
  const { functions } = await readProjectConfig();
247765
- if (functions.length === 0) {
247856
+ const toDeploy = resolveFunctionsToDeploy(names, functions);
247857
+ if (toDeploy.length === 0) {
247766
247858
  return {
247767
247859
  outroMessage: "No functions found. Create functions in the 'functions' directory."
247768
247860
  };
247769
247861
  }
247770
- R2.info(`Found ${functions.length} ${functions.length === 1 ? "function" : "functions"} to deploy`);
247771
- const result = await runTask("Deploying functions to Base44", async () => {
247772
- return await pushFunctions(functions);
247773
- }, {
247774
- successMessage: "Functions deployed successfully",
247775
- errorMessage: "Failed to deploy functions"
247862
+ R2.info(`Found ${toDeploy.length} ${toDeploy.length === 1 ? "function" : "functions"} to deploy`);
247863
+ let completed = 0;
247864
+ const total = toDeploy.length;
247865
+ const results = await deployFunctionsSequentially(toDeploy, {
247866
+ onStart: (startNames) => {
247867
+ const label = startNames.length === 1 ? startNames[0] : `${startNames.length} functions`;
247868
+ R2.step(theme.styles.dim(`[${completed + 1}/${total}] Deploying ${label}...`));
247869
+ },
247870
+ onResult: (result) => {
247871
+ completed++;
247872
+ formatDeployResult(result);
247873
+ }
247776
247874
  });
247777
- if (result.deployed.length > 0) {
247778
- R2.success(`Deployed: ${result.deployed.join(", ")}`);
247875
+ if (options.force) {
247876
+ R2.info("Removing remote functions not found locally...");
247877
+ const allLocalNames = functions.map((f) => f.name);
247878
+ const pruneResults = await pruneRemovedFunctions(allLocalNames);
247879
+ formatPruneResults(pruneResults);
247779
247880
  }
247780
- if (result.deleted.length > 0) {
247781
- R2.warn(`Deleted: ${result.deleted.join(", ")}`);
247782
- }
247783
- if (result.errors && result.errors.length > 0) {
247784
- throw new ApiError("Function deployment errors", {
247785
- details: result.errors.map((e2) => `'${e2.name}': ${e2.message}`),
247786
- hints: [
247787
- { message: "Check the function code for syntax errors" },
247788
- { message: "Ensure all imports are valid" }
247789
- ]
247790
- });
247791
- }
247792
- return { outroMessage: "Functions deployed to Base44" };
247881
+ return { outroMessage: buildDeploySummary(results) };
247793
247882
  }
247794
247883
  function getDeployCommand(context) {
247795
- return new Command("deploy").description("Deploy local functions to Base44").action(async () => {
247796
- await runCommand(deployFunctionsAction, { requireAuth: true }, context);
247884
+ return new Command("deploy").description("Deploy functions to Base44").argument("[names...]", "Function names to deploy (deploys all if omitted)").option("--force", "Delete remote functions not found locally").action(async (rawNames, options) => {
247885
+ await runCommand(() => {
247886
+ const names = parseNames2(rawNames);
247887
+ return deployFunctionsAction(names, options);
247888
+ }, { requireAuth: true }, context);
247797
247889
  });
247798
247890
  }
247799
247891
 
@@ -248092,11 +248184,17 @@ ${summaryLines.join(`
248092
248184
  ${summaryLines.join(`
248093
248185
  `)}`);
248094
248186
  }
248095
- const result = await runTask("Deploying your app...", async () => {
248096
- return await deployAll(projectData);
248097
- }, {
248098
- successMessage: theme.colors.base44Orange("Deployment completed"),
248099
- errorMessage: "Deployment failed"
248187
+ let functionCompleted = 0;
248188
+ const functionTotal = functions.length;
248189
+ const result = await deployAll(projectData, {
248190
+ onFunctionStart: (names) => {
248191
+ const label = names.length === 1 ? names[0] : `${names.length} functions`;
248192
+ R2.step(theme.styles.dim(`[${functionCompleted + 1}/${functionTotal}] Deploying ${label}...`));
248193
+ },
248194
+ onFunctionResult: (r) => {
248195
+ functionCompleted++;
248196
+ formatDeployResult(r);
248197
+ }
248100
248198
  });
248101
248199
  const connectorResults = result.connectorResults ?? [];
248102
248200
  await handleOAuthConnectors(connectorResults, options);
@@ -255655,4 +255753,4 @@ export {
255655
255753
  CLIExitError
255656
255754
  };
255657
255755
 
255658
- //# debugId=6D7955D702A30EFA64756E2164756E21
255756
+ //# debugId=8533D2C01A675ED464756E2164756E21