@base44-preview/cli 0.1.18-pr.639.a559cb8 → 0.1.20-pr.641.75be65a

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
@@ -31177,7 +31177,7 @@ function cleanDoc(doc) {
31177
31177
  return mapDoc(doc, (currentDoc) => cleanDocFn(currentDoc));
31178
31178
  }
31179
31179
  function replaceEndOfLine(doc, replacement = literalline) {
31180
- return mapDoc(doc, (currentDoc) => typeof currentDoc === "string" ? join28(replacement, currentDoc.split(`
31180
+ return mapDoc(doc, (currentDoc) => typeof currentDoc === "string" ? join30(replacement, currentDoc.split(`
31181
31181
  `)) : currentDoc);
31182
31182
  }
31183
31183
  function canBreakFn(doc) {
@@ -31257,7 +31257,7 @@ function indentIfBreak(contents, options) {
31257
31257
  negate: options.negate
31258
31258
  };
31259
31259
  }
31260
- function join28(separator, docs) {
31260
+ function join30(separator, docs) {
31261
31261
  assertDoc(separator);
31262
31262
  assertDocArray(docs);
31263
31263
  const parts = [];
@@ -31968,7 +31968,7 @@ var init_doc = __esm(() => {
31968
31968
  MODE_FLAT = Symbol("MODE_FLAT");
31969
31969
  DOC_FILL_PRINTED_LENGTH = Symbol("DOC_FILL_PRINTED_LENGTH");
31970
31970
  builders = {
31971
- join: join28,
31971
+ join: join30,
31972
31972
  line,
31973
31973
  softline,
31974
31974
  hardline,
@@ -119090,7 +119090,7 @@ import path52 from "path";
119090
119090
  import * as path42 from "path";
119091
119091
  import * as fs26 from "fs/promises";
119092
119092
  import * as path22 from "path";
119093
- import process22 from "process";
119093
+ import process23 from "process";
119094
119094
  import * as path32 from "path";
119095
119095
  import process32 from "process";
119096
119096
  import path92 from "path";
@@ -119622,7 +119622,7 @@ function partition2(array2, predicate) {
119622
119622
  return result;
119623
119623
  }
119624
119624
  async function findInDirectory(nameOrNames, { typeCheck, cwd, allowSymlinks = true, filter: filter2 }) {
119625
- const directory = toAbsolutePath(cwd) ?? process22.cwd();
119625
+ const directory = toAbsolutePath(cwd) ?? process23.cwd();
119626
119626
  const names = Array.isArray(nameOrNames) ? nameOrNames : [nameOrNames];
119627
119627
  for (const name of names) {
119628
119628
  const fileOrDirectory = path22.join(directory, name);
@@ -146002,10 +146002,10 @@ __export(exports_supports_color, {
146002
146002
  createSupportsColor: () => createSupportsColor2,
146003
146003
  default: () => supports_color_default2
146004
146004
  });
146005
- import process21 from "node:process";
146005
+ import process24 from "node:process";
146006
146006
  import os9 from "node:os";
146007
146007
  import tty4 from "node:tty";
146008
- function hasFlag2(flag, argv = globalThis.Deno ? globalThis.Deno.args : process21.argv) {
146008
+ function hasFlag2(flag, argv = globalThis.Deno ? globalThis.Deno.args : process24.argv) {
146009
146009
  const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
146010
146010
  const position = argv.indexOf(prefix + flag);
146011
146011
  const terminatorPosition = argv.indexOf("--");
@@ -146068,7 +146068,7 @@ function _supportsColor2(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
146068
146068
  if (env3.TERM === "dumb") {
146069
146069
  return min;
146070
146070
  }
146071
- if (process21.platform === "win32") {
146071
+ if (process24.platform === "win32") {
146072
146072
  const osRelease = os9.release().split(".");
146073
146073
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
146074
146074
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
@@ -146130,7 +146130,7 @@ function createSupportsColor2(stream, options = {}) {
146130
146130
  }
146131
146131
  var env3, flagForceColor2, supportsColor2, supports_color_default2;
146132
146132
  var init_supports_color = __esm(() => {
146133
- ({ env: env3 } = process21);
146133
+ ({ env: env3 } = process24);
146134
146134
  if (hasFlag2("no-color") || hasFlag2("no-colors") || hasFlag2("color=false") || hasFlag2("color=never")) {
146135
146135
  flagForceColor2 = 0;
146136
146136
  } else if (hasFlag2("color") || hasFlag2("colors") || hasFlag2("color=true") || hasFlag2("color=always")) {
@@ -228670,6 +228670,20 @@ function isCLIError(error) {
228670
228670
  function isUserError(error) {
228671
228671
  return error instanceof UserError;
228672
228672
  }
228673
+ var STEP = Symbol.for("base44.commandStep");
228674
+ async function tagStep(step, run) {
228675
+ try {
228676
+ return await run();
228677
+ } catch (error) {
228678
+ if (error !== null && typeof error === "object" && !(STEP in error) && Object.isExtensible(error)) {
228679
+ Object.defineProperty(error, STEP, { value: step, enumerable: false });
228680
+ }
228681
+ throw error;
228682
+ }
228683
+ }
228684
+ function stepOf(error) {
228685
+ return error !== null && typeof error === "object" && STEP in error ? error[STEP] : undefined;
228686
+ }
228673
228687
 
228674
228688
  // src/core/utils/fs.ts
228675
228689
  async function pathExists(path) {
@@ -228796,7 +228810,7 @@ function normalizeBase44Env() {
228796
228810
  loadProjectEnvFiles();
228797
228811
 
228798
228812
  // src/cli/index.ts
228799
- import { dirname as dirname28, join as join37 } from "node:path";
228813
+ import { dirname as dirname29, join as join39 } from "node:path";
228800
228814
  import { fileURLToPath as fileURLToPath6 } from "node:url";
228801
228815
 
228802
228816
  // ../../node_modules/@clack/core/dist/index.mjs
@@ -236449,7 +236463,7 @@ async function initAppContext(options = {}) {
236449
236463
  if (!id) {
236450
236464
  throw new InvalidInputError("App id cannot be empty.");
236451
236465
  }
236452
- cache2 = { id };
236466
+ cache2 = { id, projectRoot: projectRoot?.root };
236453
236467
  return cache2;
236454
236468
  }
236455
236469
  if (cache2) {
@@ -239251,7 +239265,7 @@ import { join as join13 } from "node:path";
239251
239265
  // package.json
239252
239266
  var package_default = {
239253
239267
  name: "base44",
239254
- version: "0.1.18",
239268
+ version: "0.1.20",
239255
239269
  description: "Base44 CLI - Unified interface for managing Base44 applications",
239256
239270
  type: "module",
239257
239271
  bin: {
@@ -239605,11 +239619,325 @@ async function createArchive(pathToArchive, targetArchivePath) {
239605
239619
  import { readFile as readFile3 } from "node:fs/promises";
239606
239620
  import { join as join18 } from "node:path";
239607
239621
 
239622
+ // src/core/site/modules.ts
239623
+ import { stat } from "node:fs/promises";
239624
+ import { relative as relative5, resolve as resolve3, sep } from "node:path";
239625
+ var MAX_TOTAL_MODULE_BYTES = 40 * 1024 * 1024;
239626
+ var MODULE_IGNORE = ["wrangler.json", ".dev.vars"];
239627
+ var RULE_TYPE_TO_MODULE_TYPE = {
239628
+ ESModule: "esm",
239629
+ CompiledWasm: "wasm",
239630
+ Text: "text",
239631
+ Data: "data"
239632
+ };
239633
+ function toPosix(path) {
239634
+ return path.split(sep).join("/");
239635
+ }
239636
+ async function collectModules(config) {
239637
+ const entryPath = resolve3(config.configDir, config.main);
239638
+ if (!await pathExists(entryPath)) {
239639
+ throw new InvalidInputError(`Worker entry module does not exist: ${entryPath} (from "main" in ${config.configPath})`, {
239640
+ hints: [{ message: "Rebuild the project to regenerate the artifact" }]
239641
+ });
239642
+ }
239643
+ const modulesByName = new Map;
239644
+ const entryName = toPosix(relative5(config.configDir, entryPath));
239645
+ modulesByName.set(entryName, {
239646
+ name: entryName,
239647
+ absolutePath: entryPath,
239648
+ size: 0,
239649
+ type: "esm"
239650
+ });
239651
+ const ignore = [...MODULE_IGNORE];
239652
+ if (config.assetsDirectory?.startsWith(config.configDir + sep)) {
239653
+ ignore.push(`${toPosix(relative5(config.configDir, config.assetsDirectory))}/**`);
239654
+ }
239655
+ for (const rule of config.rules) {
239656
+ const type = RULE_TYPE_TO_MODULE_TYPE[rule.type];
239657
+ if (!type) {
239658
+ throw new InvalidInputError(`Unsupported module rule type "${rule.type}" in ${config.configPath}. Supported: ${Object.keys(RULE_TYPE_TO_MODULE_TYPE).join(", ")}.`);
239659
+ }
239660
+ const matches = await globby(rule.globs, {
239661
+ cwd: config.configDir,
239662
+ onlyFiles: true,
239663
+ dot: true,
239664
+ ignore
239665
+ });
239666
+ for (const match of matches.sort()) {
239667
+ if (!modulesByName.has(match)) {
239668
+ modulesByName.set(match, {
239669
+ name: match,
239670
+ absolutePath: resolve3(config.configDir, match),
239671
+ size: 0,
239672
+ type
239673
+ });
239674
+ }
239675
+ }
239676
+ }
239677
+ if (config.uploadSourceMaps) {
239678
+ const maps = await globby("**/*.map", {
239679
+ cwd: config.configDir,
239680
+ onlyFiles: true,
239681
+ dot: true,
239682
+ ignore
239683
+ });
239684
+ for (const map of maps.sort()) {
239685
+ addSourcemap(modulesByName, config.configDir, map);
239686
+ }
239687
+ } else {
239688
+ for (const name of [...modulesByName.keys()]) {
239689
+ const mapName = `${name}.map`;
239690
+ if (await pathExists(resolve3(config.configDir, mapName))) {
239691
+ addSourcemap(modulesByName, config.configDir, mapName);
239692
+ }
239693
+ }
239694
+ }
239695
+ const modules = [...modulesByName.values()];
239696
+ let totalBytes = 0;
239697
+ for (const module of modules) {
239698
+ module.size = (await stat(module.absolutePath)).size;
239699
+ totalBytes += module.size;
239700
+ }
239701
+ if (totalBytes > MAX_TOTAL_MODULE_BYTES) {
239702
+ throw new InvalidInputError(`Worker modules total ${totalBytes} bytes, which exceeds the 40 MB limit for a Base44 deploy.`);
239703
+ }
239704
+ return modules;
239705
+ }
239706
+ function addSourcemap(modulesByName, configDir, name) {
239707
+ if (modulesByName.has(name))
239708
+ return;
239709
+ modulesByName.set(name, {
239710
+ name,
239711
+ absolutePath: resolve3(configDir, name),
239712
+ size: 0,
239713
+ type: "sourcemap"
239714
+ });
239715
+ }
239716
+
239717
+ // src/core/site/wrangler-config.ts
239718
+ import { dirname as dirname12, join as join16, resolve as resolve4 } from "node:path";
239719
+ var WRANGLER_REDIRECT_PATH = join16(".wrangler", "deploy", "config.json");
239720
+ var RedirectConfigSchema = looseObject({
239721
+ configPath: string2().min(1)
239722
+ });
239723
+ var WranglerConfigSchema = looseObject({
239724
+ main: string2().min(1, "wrangler config is missing a 'main' entry module"),
239725
+ no_bundle: boolean2().optional(),
239726
+ rules: array(looseObject({ type: string2(), globs: array(string2()) })).optional(),
239727
+ assets: looseObject({
239728
+ directory: string2().optional(),
239729
+ html_handling: string2().optional(),
239730
+ not_found_handling: string2().optional(),
239731
+ run_worker_first: union([boolean2(), array(string2())]).optional(),
239732
+ headers: string2().optional(),
239733
+ redirects: string2().optional()
239734
+ }).optional(),
239735
+ compatibility_date: string2().optional(),
239736
+ compatibility_flags: array(string2()).optional(),
239737
+ vars: record(string2(), unknown()).optional(),
239738
+ upload_source_maps: boolean2().optional()
239739
+ });
239740
+ async function detectFullStackArtifact(projectRoot) {
239741
+ const redirectPath = join16(projectRoot, WRANGLER_REDIRECT_PATH);
239742
+ return await pathExists(redirectPath) ? redirectPath : null;
239743
+ }
239744
+ async function resolveWranglerConfig(redirectPath) {
239745
+ const configPath = await resolveRedirectedConfigPath(redirectPath);
239746
+ const parsed = await readJsonFile(configPath);
239747
+ const result = WranglerConfigSchema.safeParse(parsed);
239748
+ if (!result.success) {
239749
+ throw new ConfigInvalidError(`Invalid wrangler config: ${prettifyError(result.error)}`, configPath);
239750
+ }
239751
+ const config = result.data;
239752
+ if (config.no_bundle !== true) {
239753
+ throw new InvalidInputError("This framework's output requires bundling; not yet supported. Base44 only deploys pre-bundled Workers output (no_bundle: true).");
239754
+ }
239755
+ const configDir = dirname12(configPath);
239756
+ const assetsDirectory = config.assets?.directory ? resolve4(configDir, config.assets.directory) : null;
239757
+ return {
239758
+ configPath,
239759
+ configDir,
239760
+ main: config.main,
239761
+ assetsDirectory,
239762
+ assetsConfig: config.assets ? toResolvedAssetsConfig(config.assets) : null,
239763
+ compatibilityDate: config.compatibility_date ?? null,
239764
+ compatibilityFlags: config.compatibility_flags ?? [],
239765
+ rules: (config.rules ?? []).map((rule) => ({
239766
+ type: rule.type,
239767
+ globs: rule.globs
239768
+ })),
239769
+ uploadSourceMaps: config.upload_source_maps ?? false
239770
+ };
239771
+ }
239772
+ async function resolveRedirectedConfigPath(redirectPath) {
239773
+ const parsed = await readJsonFile(redirectPath);
239774
+ const result = RedirectConfigSchema.safeParse(parsed);
239775
+ if (!result.success) {
239776
+ throw new ConfigInvalidError(`Invalid deploy redirect file: ${prettifyError(result.error)}`, redirectPath);
239777
+ }
239778
+ const configPath = resolve4(dirname12(redirectPath), result.data.configPath);
239779
+ if (!await pathExists(configPath)) {
239780
+ throw new ConfigInvalidError(`Wrangler config referenced by ${redirectPath} does not exist: ${configPath}`, redirectPath, {
239781
+ hints: [{ message: "Rebuild the project to regenerate the artifact" }]
239782
+ });
239783
+ }
239784
+ return configPath;
239785
+ }
239786
+ function toResolvedAssetsConfig(assets) {
239787
+ return {
239788
+ htmlHandling: assets.html_handling,
239789
+ notFoundHandling: assets.not_found_handling,
239790
+ runWorkerFirst: assets.run_worker_first,
239791
+ headers: assets.headers,
239792
+ redirects: assets.redirects
239793
+ };
239794
+ }
239795
+
239796
+ // src/core/site/full-stack.ts
239797
+ async function resolveFullStackBuild(projectRoot) {
239798
+ const redirectPath = await detectFullStackArtifact(projectRoot);
239799
+ if (!redirectPath) {
239800
+ return null;
239801
+ }
239802
+ const config = await resolveWranglerConfig(redirectPath);
239803
+ return {
239804
+ config,
239805
+ modules: await collectModules(config),
239806
+ assetsDir: config.assetsDirectory && await pathExists(config.assetsDirectory) ? config.assetsDirectory : null
239807
+ };
239808
+ }
239809
+
239608
239810
  // src/core/site/manifest.ts
239609
239811
  import { createHash } from "node:crypto";
239610
239812
  import { createReadStream } from "node:fs";
239611
- import { stat } from "node:fs/promises";
239612
- import { basename as basename5, extname, join as join16 } from "node:path";
239813
+ import { stat as stat2 } from "node:fs/promises";
239814
+ import { basename as basename5, extname, join as join17 } from "node:path";
239815
+
239816
+ // ../../node_modules/p-map/index.js
239817
+ async function pMap(iterable, mapper, {
239818
+ concurrency = Number.POSITIVE_INFINITY,
239819
+ stopOnError = true,
239820
+ signal
239821
+ } = {}) {
239822
+ return new Promise((resolve_, reject_) => {
239823
+ if (iterable[Symbol.iterator] === undefined && iterable[Symbol.asyncIterator] === undefined) {
239824
+ throw new TypeError(`Expected \`input\` to be either an \`Iterable\` or \`AsyncIterable\`, got (${typeof iterable})`);
239825
+ }
239826
+ if (typeof mapper !== "function") {
239827
+ throw new TypeError("Mapper function is required");
239828
+ }
239829
+ if (!(Number.isSafeInteger(concurrency) && concurrency >= 1 || concurrency === Number.POSITIVE_INFINITY)) {
239830
+ throw new TypeError(`Expected \`concurrency\` to be an integer from 1 and up or \`Infinity\`, got \`${concurrency}\` (${typeof concurrency})`);
239831
+ }
239832
+ const result = [];
239833
+ const errors = [];
239834
+ const skippedIndexesMap = new Map;
239835
+ let isRejected = false;
239836
+ let isResolved = false;
239837
+ let isIterableDone = false;
239838
+ let resolvingCount = 0;
239839
+ let currentIndex = 0;
239840
+ const iterator = iterable[Symbol.iterator] === undefined ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
239841
+ const signalListener = () => {
239842
+ reject(signal.reason);
239843
+ };
239844
+ const cleanup = () => {
239845
+ signal?.removeEventListener("abort", signalListener);
239846
+ };
239847
+ const resolve = (value) => {
239848
+ resolve_(value);
239849
+ cleanup();
239850
+ };
239851
+ const reject = (reason) => {
239852
+ isRejected = true;
239853
+ isResolved = true;
239854
+ reject_(reason);
239855
+ cleanup();
239856
+ };
239857
+ if (signal) {
239858
+ if (signal.aborted) {
239859
+ reject(signal.reason);
239860
+ return;
239861
+ }
239862
+ signal.addEventListener("abort", signalListener, { once: true });
239863
+ }
239864
+ const next = async () => {
239865
+ if (isResolved) {
239866
+ return;
239867
+ }
239868
+ const nextItem = await iterator.next();
239869
+ const index = currentIndex;
239870
+ currentIndex++;
239871
+ if (nextItem.done) {
239872
+ isIterableDone = true;
239873
+ if (resolvingCount === 0 && !isResolved) {
239874
+ if (!stopOnError && errors.length > 0) {
239875
+ reject(new AggregateError(errors));
239876
+ return;
239877
+ }
239878
+ isResolved = true;
239879
+ if (skippedIndexesMap.size === 0) {
239880
+ resolve(result);
239881
+ return;
239882
+ }
239883
+ const pureResult = [];
239884
+ for (const [index, value] of result.entries()) {
239885
+ if (skippedIndexesMap.get(index) === pMapSkip) {
239886
+ continue;
239887
+ }
239888
+ pureResult.push(value);
239889
+ }
239890
+ resolve(pureResult);
239891
+ }
239892
+ return;
239893
+ }
239894
+ resolvingCount++;
239895
+ (async () => {
239896
+ try {
239897
+ const element = await nextItem.value;
239898
+ if (isResolved) {
239899
+ return;
239900
+ }
239901
+ const value = await mapper(element, index);
239902
+ if (value === pMapSkip) {
239903
+ skippedIndexesMap.set(index, value);
239904
+ }
239905
+ result[index] = value;
239906
+ resolvingCount--;
239907
+ await next();
239908
+ } catch (error) {
239909
+ if (stopOnError) {
239910
+ reject(error);
239911
+ } else {
239912
+ errors.push(error);
239913
+ resolvingCount--;
239914
+ try {
239915
+ await next();
239916
+ } catch (error) {
239917
+ reject(error);
239918
+ }
239919
+ }
239920
+ }
239921
+ })();
239922
+ };
239923
+ (async () => {
239924
+ for (let index = 0;index < concurrency; index++) {
239925
+ try {
239926
+ await next();
239927
+ } catch (error) {
239928
+ reject(error);
239929
+ break;
239930
+ }
239931
+ if (isIterableDone || isRejected) {
239932
+ break;
239933
+ }
239934
+ }
239935
+ })();
239936
+ });
239937
+ }
239938
+ var pMapSkip = Symbol("skip");
239939
+
239940
+ // src/core/site/manifest.ts
239613
239941
  var MAX_ASSET_COUNT = 1e5;
239614
239942
  var ASSETS_IGNORE_FILE = ".assetsignore";
239615
239943
  var ALWAYS_IGNORED = new Set([
@@ -239650,30 +239978,42 @@ var MIME_TYPES = {
239650
239978
  function getAssetContentType(filePath) {
239651
239979
  return MIME_TYPES[extname(filePath).toLowerCase()] ?? "application/octet-stream";
239652
239980
  }
239653
- async function hashAssetFile(appId, absolutePath) {
239654
- const hash = createHash("sha256").update(Buffer.from(appId, "utf8"));
239981
+ async function walkBuildOutput(outputDir) {
239982
+ const found = await globby("**/*", {
239983
+ cwd: outputDir,
239984
+ dot: true,
239985
+ onlyFiles: true,
239986
+ followSymbolicLinks: false,
239987
+ ignoreFiles: [ASSETS_IGNORE_FILE]
239988
+ });
239989
+ return found.filter((path) => !ALWAYS_IGNORED.has(basename5(path))).sort();
239990
+ }
239991
+ var STAT_CONCURRENCY = 32;
239992
+ async function describeBuildOutput(outputDir) {
239993
+ const relativePaths = await walkBuildOutput(outputDir);
239994
+ return await pMap(relativePaths, async (path) => {
239995
+ const absolutePath = join17(outputDir, ...path.split("/"));
239996
+ return { path, absolutePath, size: (await stat2(absolutePath)).size };
239997
+ }, { concurrency: STAT_CONCURRENCY });
239998
+ }
239999
+ async function hashFileInto(hash, absolutePath) {
239655
240000
  for await (const chunk of createReadStream(absolutePath)) {
239656
240001
  hash.update(chunk);
239657
240002
  }
240003
+ return hash;
240004
+ }
240005
+ async function hashAssetFile(appId, absolutePath) {
240006
+ const hash = await hashFileInto(createHash("sha256").update(Buffer.from(appId, "utf8")), absolutePath);
239658
240007
  return hash.digest("hex").slice(0, 32);
239659
240008
  }
239660
240009
  async function buildAssetManifest(assetsDir, appId) {
239661
240010
  const manifest = {};
239662
240011
  const filesByHash = new Map;
239663
- const found = await globby("**/*", {
239664
- cwd: assetsDir,
239665
- dot: true,
239666
- onlyFiles: true,
239667
- followSymbolicLinks: false,
239668
- ignoreFiles: [ASSETS_IGNORE_FILE]
239669
- });
239670
- const relativeFilePaths = found.filter((path) => !ALWAYS_IGNORED.has(basename5(path)));
239671
- if (relativeFilePaths.length > MAX_ASSET_COUNT) {
239672
- throw new InvalidInputError(`Too many static assets: found ${relativeFilePaths.length}, the limit is ${MAX_ASSET_COUNT} files.`);
240012
+ const files = await describeBuildOutput(assetsDir);
240013
+ if (files.length > MAX_ASSET_COUNT) {
240014
+ throw new InvalidInputError(`Too many static assets: found ${files.length}, the limit is ${MAX_ASSET_COUNT} files.`);
239673
240015
  }
239674
- for (const relativePath of relativeFilePaths.sort()) {
239675
- const absolutePath = join16(assetsDir, ...relativePath.split("/"));
239676
- const { size } = await stat(absolutePath);
240016
+ for (const { path: relativePath, absolutePath, size } of files) {
239677
240017
  const hash = await hashAssetFile(appId, absolutePath);
239678
240018
  manifest[`/${relativePath}`] = { hash, size };
239679
240019
  if (!filesByHash.has(hash)) {
@@ -239688,229 +240028,8 @@ async function buildAssetManifest(assetsDir, appId) {
239688
240028
  return { manifest, filesByHash };
239689
240029
  }
239690
240030
 
239691
- // src/core/site/modules.ts
239692
- import { stat as stat2 } from "node:fs/promises";
239693
- import { relative as relative5, resolve as resolve3, sep } from "node:path";
239694
- var MAX_TOTAL_MODULE_BYTES = 40 * 1024 * 1024;
239695
- var MODULE_IGNORE = ["wrangler.json", ".dev.vars"];
239696
- var RULE_TYPE_TO_MODULE_TYPE = {
239697
- ESModule: "esm",
239698
- CompiledWasm: "wasm",
239699
- Text: "text",
239700
- Data: "data"
239701
- };
239702
- function toPosix(path) {
239703
- return path.split(sep).join("/");
239704
- }
239705
- async function collectModules(config) {
239706
- const entryPath = resolve3(config.configDir, config.main);
239707
- if (!await pathExists(entryPath)) {
239708
- throw new InvalidInputError(`Worker entry module does not exist: ${entryPath} (from "main" in ${config.configPath})`, {
239709
- hints: [{ message: "Rebuild the project to regenerate the artifact" }]
239710
- });
239711
- }
239712
- const modulesByName = new Map;
239713
- const entryName = toPosix(relative5(config.configDir, entryPath));
239714
- modulesByName.set(entryName, {
239715
- name: entryName,
239716
- absolutePath: entryPath,
239717
- size: 0,
239718
- type: "esm"
239719
- });
239720
- const ignore = [...MODULE_IGNORE];
239721
- if (config.assetsDirectory?.startsWith(config.configDir + sep)) {
239722
- ignore.push(`${toPosix(relative5(config.configDir, config.assetsDirectory))}/**`);
239723
- }
239724
- for (const rule of config.rules) {
239725
- const type = RULE_TYPE_TO_MODULE_TYPE[rule.type];
239726
- if (!type) {
239727
- throw new InvalidInputError(`Unsupported module rule type "${rule.type}" in ${config.configPath}. Supported: ${Object.keys(RULE_TYPE_TO_MODULE_TYPE).join(", ")}.`);
239728
- }
239729
- const matches = await globby(rule.globs, {
239730
- cwd: config.configDir,
239731
- onlyFiles: true,
239732
- dot: true,
239733
- ignore
239734
- });
239735
- for (const match of matches.sort()) {
239736
- if (!modulesByName.has(match)) {
239737
- modulesByName.set(match, {
239738
- name: match,
239739
- absolutePath: resolve3(config.configDir, match),
239740
- size: 0,
239741
- type
239742
- });
239743
- }
239744
- }
239745
- }
239746
- if (config.uploadSourceMaps) {
239747
- const maps = await globby("**/*.map", {
239748
- cwd: config.configDir,
239749
- onlyFiles: true,
239750
- dot: true,
239751
- ignore
239752
- });
239753
- for (const map of maps.sort()) {
239754
- addSourcemap(modulesByName, config.configDir, map);
239755
- }
239756
- } else {
239757
- for (const name of [...modulesByName.keys()]) {
239758
- const mapName = `${name}.map`;
239759
- if (await pathExists(resolve3(config.configDir, mapName))) {
239760
- addSourcemap(modulesByName, config.configDir, mapName);
239761
- }
239762
- }
239763
- }
239764
- const modules = [...modulesByName.values()];
239765
- let totalBytes = 0;
239766
- for (const module of modules) {
239767
- module.size = (await stat2(module.absolutePath)).size;
239768
- totalBytes += module.size;
239769
- }
239770
- if (totalBytes > MAX_TOTAL_MODULE_BYTES) {
239771
- throw new InvalidInputError(`Worker modules total ${totalBytes} bytes, which exceeds the 40 MB limit for a Base44 deploy.`);
239772
- }
239773
- return modules;
239774
- }
239775
- function addSourcemap(modulesByName, configDir, name) {
239776
- if (modulesByName.has(name))
239777
- return;
239778
- modulesByName.set(name, {
239779
- name,
239780
- absolutePath: resolve3(configDir, name),
239781
- size: 0,
239782
- type: "sourcemap"
239783
- });
239784
- }
239785
-
239786
240031
  // src/core/site/upload.ts
239787
240032
  import { readFile as readFile2 } from "node:fs/promises";
239788
-
239789
- // ../../node_modules/p-map/index.js
239790
- async function pMap(iterable, mapper, {
239791
- concurrency = Number.POSITIVE_INFINITY,
239792
- stopOnError = true,
239793
- signal
239794
- } = {}) {
239795
- return new Promise((resolve_, reject_) => {
239796
- if (iterable[Symbol.iterator] === undefined && iterable[Symbol.asyncIterator] === undefined) {
239797
- throw new TypeError(`Expected \`input\` to be either an \`Iterable\` or \`AsyncIterable\`, got (${typeof iterable})`);
239798
- }
239799
- if (typeof mapper !== "function") {
239800
- throw new TypeError("Mapper function is required");
239801
- }
239802
- if (!(Number.isSafeInteger(concurrency) && concurrency >= 1 || concurrency === Number.POSITIVE_INFINITY)) {
239803
- throw new TypeError(`Expected \`concurrency\` to be an integer from 1 and up or \`Infinity\`, got \`${concurrency}\` (${typeof concurrency})`);
239804
- }
239805
- const result = [];
239806
- const errors = [];
239807
- const skippedIndexesMap = new Map;
239808
- let isRejected = false;
239809
- let isResolved = false;
239810
- let isIterableDone = false;
239811
- let resolvingCount = 0;
239812
- let currentIndex = 0;
239813
- const iterator = iterable[Symbol.iterator] === undefined ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
239814
- const signalListener = () => {
239815
- reject(signal.reason);
239816
- };
239817
- const cleanup = () => {
239818
- signal?.removeEventListener("abort", signalListener);
239819
- };
239820
- const resolve = (value) => {
239821
- resolve_(value);
239822
- cleanup();
239823
- };
239824
- const reject = (reason) => {
239825
- isRejected = true;
239826
- isResolved = true;
239827
- reject_(reason);
239828
- cleanup();
239829
- };
239830
- if (signal) {
239831
- if (signal.aborted) {
239832
- reject(signal.reason);
239833
- return;
239834
- }
239835
- signal.addEventListener("abort", signalListener, { once: true });
239836
- }
239837
- const next = async () => {
239838
- if (isResolved) {
239839
- return;
239840
- }
239841
- const nextItem = await iterator.next();
239842
- const index = currentIndex;
239843
- currentIndex++;
239844
- if (nextItem.done) {
239845
- isIterableDone = true;
239846
- if (resolvingCount === 0 && !isResolved) {
239847
- if (!stopOnError && errors.length > 0) {
239848
- reject(new AggregateError(errors));
239849
- return;
239850
- }
239851
- isResolved = true;
239852
- if (skippedIndexesMap.size === 0) {
239853
- resolve(result);
239854
- return;
239855
- }
239856
- const pureResult = [];
239857
- for (const [index, value] of result.entries()) {
239858
- if (skippedIndexesMap.get(index) === pMapSkip) {
239859
- continue;
239860
- }
239861
- pureResult.push(value);
239862
- }
239863
- resolve(pureResult);
239864
- }
239865
- return;
239866
- }
239867
- resolvingCount++;
239868
- (async () => {
239869
- try {
239870
- const element = await nextItem.value;
239871
- if (isResolved) {
239872
- return;
239873
- }
239874
- const value = await mapper(element, index);
239875
- if (value === pMapSkip) {
239876
- skippedIndexesMap.set(index, value);
239877
- }
239878
- result[index] = value;
239879
- resolvingCount--;
239880
- await next();
239881
- } catch (error) {
239882
- if (stopOnError) {
239883
- reject(error);
239884
- } else {
239885
- errors.push(error);
239886
- resolvingCount--;
239887
- try {
239888
- await next();
239889
- } catch (error) {
239890
- reject(error);
239891
- }
239892
- }
239893
- }
239894
- })();
239895
- };
239896
- (async () => {
239897
- for (let index = 0;index < concurrency; index++) {
239898
- try {
239899
- await next();
239900
- } catch (error) {
239901
- reject(error);
239902
- break;
239903
- }
239904
- if (isIterableDone || isRejected) {
239905
- break;
239906
- }
239907
- }
239908
- })();
239909
- });
239910
- }
239911
- var pMapSkip = Symbol("skip");
239912
-
239913
- // src/core/site/upload.ts
239914
240033
  var DEFAULT_UPLOAD_CONCURRENCY = 3;
239915
240034
  var MAX_UPLOAD_CONCURRENCY = 50;
239916
240035
  var MAX_UPLOAD_ATTEMPTS = 3;
@@ -240009,11 +240128,17 @@ async function uploadPresignedAsset(upload, assets) {
240009
240128
  if (!file) {
240010
240129
  throw new InternalError(`Server requested upload of unknown asset path: ${upload.path}`);
240011
240130
  }
240012
- const content = await readFile2(file.absolutePath);
240131
+ await putPresigned(upload, file.absolutePath);
240132
+ }
240133
+ async function putPresigned(upload, absolutePath) {
240134
+ const content = await readFile2(absolutePath);
240013
240135
  try {
240014
240136
  await distribution_default.put(upload.url, {
240015
240137
  body: new Uint8Array(content),
240016
- headers: { "Content-Type": upload.contentType },
240138
+ headers: {
240139
+ "Content-Type": upload.contentType,
240140
+ ...upload.checksumSha256 ? { "x-amz-checksum-sha256": upload.checksumSha256 } : {}
240141
+ },
240017
240142
  timeout: 120000,
240018
240143
  retry: UPLOAD_RETRY
240019
240144
  });
@@ -240022,85 +240147,6 @@ async function uploadPresignedAsset(upload, assets) {
240022
240147
  }
240023
240148
  }
240024
240149
 
240025
- // src/core/site/wrangler-config.ts
240026
- import { dirname as dirname12, join as join17, resolve as resolve4 } from "node:path";
240027
- var WRANGLER_REDIRECT_PATH = join17(".wrangler", "deploy", "config.json");
240028
- var RedirectConfigSchema = looseObject({
240029
- configPath: string2().min(1)
240030
- });
240031
- var WranglerConfigSchema = looseObject({
240032
- main: string2().min(1, "wrangler config is missing a 'main' entry module"),
240033
- no_bundle: boolean2().optional(),
240034
- rules: array(looseObject({ type: string2(), globs: array(string2()) })).optional(),
240035
- assets: looseObject({
240036
- directory: string2().optional(),
240037
- html_handling: string2().optional(),
240038
- not_found_handling: string2().optional(),
240039
- run_worker_first: union([boolean2(), array(string2())]).optional(),
240040
- headers: string2().optional(),
240041
- redirects: string2().optional()
240042
- }).optional(),
240043
- compatibility_date: string2().optional(),
240044
- compatibility_flags: array(string2()).optional(),
240045
- vars: record(string2(), unknown()).optional(),
240046
- upload_source_maps: boolean2().optional()
240047
- });
240048
- async function detectFullStackArtifact(projectRoot) {
240049
- const redirectPath = join17(projectRoot, WRANGLER_REDIRECT_PATH);
240050
- return await pathExists(redirectPath) ? redirectPath : null;
240051
- }
240052
- async function resolveWranglerConfig(redirectPath) {
240053
- const configPath = await resolveRedirectedConfigPath(redirectPath);
240054
- const parsed = await readJsonFile(configPath);
240055
- const result = WranglerConfigSchema.safeParse(parsed);
240056
- if (!result.success) {
240057
- throw new ConfigInvalidError(`Invalid wrangler config: ${prettifyError(result.error)}`, configPath);
240058
- }
240059
- const config = result.data;
240060
- if (config.no_bundle !== true) {
240061
- throw new InvalidInputError("This framework's output requires bundling; not yet supported. Base44 only deploys pre-bundled Workers output (no_bundle: true).");
240062
- }
240063
- const configDir = dirname12(configPath);
240064
- const assetsDirectory = config.assets?.directory ? resolve4(configDir, config.assets.directory) : null;
240065
- return {
240066
- configPath,
240067
- configDir,
240068
- main: config.main,
240069
- assetsDirectory,
240070
- assetsConfig: config.assets ? toResolvedAssetsConfig(config.assets) : null,
240071
- compatibilityDate: config.compatibility_date ?? null,
240072
- compatibilityFlags: config.compatibility_flags ?? [],
240073
- rules: (config.rules ?? []).map((rule) => ({
240074
- type: rule.type,
240075
- globs: rule.globs
240076
- })),
240077
- uploadSourceMaps: config.upload_source_maps ?? false
240078
- };
240079
- }
240080
- async function resolveRedirectedConfigPath(redirectPath) {
240081
- const parsed = await readJsonFile(redirectPath);
240082
- const result = RedirectConfigSchema.safeParse(parsed);
240083
- if (!result.success) {
240084
- throw new ConfigInvalidError(`Invalid deploy redirect file: ${prettifyError(result.error)}`, redirectPath);
240085
- }
240086
- const configPath = resolve4(dirname12(redirectPath), result.data.configPath);
240087
- if (!await pathExists(configPath)) {
240088
- throw new ConfigInvalidError(`Wrangler config referenced by ${redirectPath} does not exist: ${configPath}`, redirectPath, {
240089
- hints: [{ message: "Rebuild the project to regenerate the artifact" }]
240090
- });
240091
- }
240092
- return configPath;
240093
- }
240094
- function toResolvedAssetsConfig(assets) {
240095
- return {
240096
- htmlHandling: assets.html_handling,
240097
- notFoundHandling: assets.not_found_handling,
240098
- runWorkerFirst: assets.run_worker_first,
240099
- headers: assets.headers,
240100
- redirects: assets.redirects
240101
- };
240102
- }
240103
-
240104
240150
  // src/core/site/deployment.ts
240105
240151
  var NO_ASSETS = { manifest: {}, filesByHash: new Map };
240106
240152
  var DEPLOYMENTS_API_ENV = "BASE44_DEPLOYMENTS_API";
@@ -240108,9 +240154,6 @@ function deploymentsApiEnabled(env = process.env) {
240108
240154
  const value = env[DEPLOYMENTS_API_ENV];
240109
240155
  return value === "1" || value === "true";
240110
240156
  }
240111
- async function hasWorkerBuild(projectRoot) {
240112
- return await detectFullStackArtifact(projectRoot) !== null;
240113
- }
240114
240157
  async function deployToDeployments(options) {
240115
240158
  const { projectRoot, outputDir, gitHash, concurrency, progress } = options;
240116
240159
  const worker = await resolveWorkerBuild(projectRoot, progress);
@@ -240133,12 +240176,11 @@ async function deployToDeployments(options) {
240133
240176
  return { deploymentId: finalized.deploymentId, gitHash };
240134
240177
  }
240135
240178
  async function resolveWorkerBuild(projectRoot, progress) {
240136
- const redirectPath = await detectFullStackArtifact(projectRoot);
240137
- if (!redirectPath) {
240179
+ const built = await resolveFullStackBuild(projectRoot);
240180
+ if (!built) {
240138
240181
  return null;
240139
240182
  }
240140
- const config = await resolveWranglerConfig(redirectPath);
240141
- const assetsDir = config.assetsDirectory && await pathExists(config.assetsDirectory) ? config.assetsDirectory : null;
240183
+ const { config, modules, assetsDir } = built;
240142
240184
  return {
240143
240185
  config: {
240144
240186
  main: config.main,
@@ -240146,7 +240188,7 @@ async function resolveWorkerBuild(projectRoot, progress) {
240146
240188
  compatibility_flags: config.compatibilityFlags,
240147
240189
  assets: buildAssetsConfig(config.assetsConfig, progress)
240148
240190
  },
240149
- modules: await collectModules(config),
240191
+ modules,
240150
240192
  assetsDir
240151
240193
  };
240152
240194
  }
@@ -246699,6 +246741,13 @@ async function resolveGitHash(projectRoot, explicit) {
246699
246741
  }
246700
246742
  return hash;
246701
246743
  }
246744
+ async function resolveProvenanceCommit(projectRoot, explicit) {
246745
+ if (explicit) {
246746
+ return await resolveGitHash(projectRoot, explicit);
246747
+ }
246748
+ const hash = await gitHead(projectRoot);
246749
+ return hash && isGitCommitHash(hash) ? hash : undefined;
246750
+ }
246702
246751
  async function gitHead(projectRoot) {
246703
246752
  try {
246704
246753
  const { stdout } = await execa("git", ["rev-parse", "HEAD"], {
@@ -246710,7 +246759,7 @@ async function gitHead(projectRoot) {
246710
246759
  }
246711
246760
  }
246712
246761
  // src/core/project/deploy.ts
246713
- function hasResourcesToDeploy(projectData, options = {}) {
246762
+ function hasResourcesToDeploy(projectData) {
246714
246763
  const {
246715
246764
  project,
246716
246765
  entities,
@@ -246721,7 +246770,7 @@ function hasResourcesToDeploy(projectData, options = {}) {
246721
246770
  connectors,
246722
246771
  authConfig
246723
246772
  } = projectData;
246724
- const hasSite = Boolean(project.site?.outputDirectory) || Boolean(options.workerBuild);
246773
+ const hasSite = Boolean(project.site?.outputDirectory);
246725
246774
  const hasEntities = entities.length > 0;
246726
246775
  const hasFunctions = functions.length > 0;
246727
246776
  const hasActors = actors.length > 0;
@@ -246743,7 +246792,6 @@ async function deployAll(projectData, options) {
246743
246792
  connectors,
246744
246793
  authConfig
246745
246794
  } = projectData;
246746
- const workerGitHash = await hasWorkerBuild(project.root) ? await resolveGitHash(project.root) : null;
246747
246795
  await setAppVisibility(project.visibility);
246748
246796
  if (project.visibility) {
246749
246797
  options?.onVisibilitySet?.(project.visibility);
@@ -246781,24 +246829,56 @@ async function deployAll(projectData, options) {
246781
246829
  await authConfigResource.push(authConfig);
246782
246830
  const skipConnectorSync = connectors.length === 0 && hasWorkspaceApiKeyAuth();
246783
246831
  const connectorResults = skipConnectorSync ? [] : (await pushConnectors(connectors)).results;
246784
- const outputDir = project.site?.outputDirectory ? resolve5(project.root, project.site.outputDirectory) : null;
246785
- if (workerGitHash) {
246786
- const { deploymentId } = await deployToDeployments({
246787
- projectRoot: project.root,
246788
- outputDir,
246789
- gitHash: workerGitHash
246790
- });
246791
- return {
246792
- deployment: { deploymentId, gitHash: workerGitHash },
246793
- connectorResults
246794
- };
246795
- }
246796
- if (outputDir) {
246832
+ if (project.site?.outputDirectory) {
246833
+ const outputDir = resolve5(project.root, project.site.outputDirectory);
246797
246834
  const { appUrl } = await deploySite(outputDir);
246798
246835
  return { appUrl, connectorResults };
246799
246836
  }
246800
246837
  return { connectorResults };
246801
246838
  }
246839
+ // src/core/project/target.ts
246840
+ import { dirname as dirname13, join as join19, resolve as resolve6 } from "node:path";
246841
+ var DEFAULT_BUILD_COMMAND = "npm run build";
246842
+ var DEFAULT_OUTPUT_DIRECTORY = "dist";
246843
+ async function resolveBuildTarget(projectRoot, overrides = {}) {
246844
+ const project = await readSettingsIfPresent(projectRoot);
246845
+ const root = project?.root ?? projectRoot ?? process.cwd();
246846
+ return {
246847
+ root,
246848
+ configDir: project ? dirname13(project.configPath) : join19(root, PROJECT_SUBDIR),
246849
+ buildCommand: project ? project.site?.buildCommand : DEFAULT_BUILD_COMMAND,
246850
+ outputDir: outputDirectory(project, root, overrides.outputDir),
246851
+ entitiesDir: project?.entitiesDir ?? "entities",
246852
+ agentsDir: project?.agentsDir ?? "agents"
246853
+ };
246854
+ }
246855
+ function outputDirectory(project, root, override) {
246856
+ const configured = override ?? (project ? project.site?.outputDirectory : DEFAULT_OUTPUT_DIRECTORY);
246857
+ return configured ? resolve6(root, configured) : null;
246858
+ }
246859
+ function requireOutputDir(target) {
246860
+ if (target.outputDir === null) {
246861
+ throw new ConfigNotFoundError("No site configuration found.", {
246862
+ hints: [
246863
+ {
246864
+ message: `Add 'site.outputDirectory' to your config.jsonc (e.g., "site": { "outputDirectory": "dist" })`
246865
+ },
246866
+ { message: `Or pass --output-dir <dir>, relative to ${target.root}` }
246867
+ ]
246868
+ });
246869
+ }
246870
+ return target.outputDir;
246871
+ }
246872
+ async function readSettingsIfPresent(projectRoot) {
246873
+ try {
246874
+ return await readProjectSettings(projectRoot);
246875
+ } catch (error) {
246876
+ if (error instanceof ConfigNotFoundError) {
246877
+ return null;
246878
+ }
246879
+ throw error;
246880
+ }
246881
+ }
246802
246882
  // src/core/clients/base44-client.ts
246803
246883
  var retriedRequests = new WeakSet;
246804
246884
  async function captureRequestBody(request, options) {
@@ -247080,6 +247160,12 @@ async function ensureAppContext(ctx, options = {}) {
247080
247160
  ctx.app = appContext;
247081
247161
  ctx.errorReporter.setContext({ appId: appContext.id });
247082
247162
  }
247163
+ function requireApp(ctx) {
247164
+ if (!ctx.app) {
247165
+ throw new InternalError("This command read an app context it never resolved — it is declared with requireAppContext: false.");
247166
+ }
247167
+ return ctx.app;
247168
+ }
247083
247169
 
247084
247170
  // src/cli/utils/version-check.ts
247085
247171
  async function checkForUpgrade() {
@@ -247263,6 +247349,10 @@ function writeJsonError(error) {
247263
247349
  const envelope = {
247264
247350
  error: error instanceof Error ? error.message : String(error)
247265
247351
  };
247352
+ const step = stepOf(error);
247353
+ if (step !== undefined) {
247354
+ envelope.step = step;
247355
+ }
247266
247356
  if (isCLIError(error)) {
247267
247357
  envelope.code = error.code;
247268
247358
  if (error.details.length > 0) {
@@ -247632,7 +247722,7 @@ function getActorsCommand() {
247632
247722
  }
247633
247723
 
247634
247724
  // src/cli/commands/agent-skills/pull.ts
247635
- import { dirname as dirname13, join as join19 } from "node:path";
247725
+ import { dirname as dirname14, join as join20 } from "node:path";
247636
247726
  // src/core/utils/dependencies.ts
247637
247727
  import { spawnSync as spawnSync2 } from "node:child_process";
247638
247728
  function verifyDenoInstalled(context) {
@@ -247721,7 +247811,7 @@ async function pullAction({
247721
247811
  runTask
247722
247812
  }) {
247723
247813
  const { project } = await readProjectConfig();
247724
- const dir = join19(dirname13(project.configPath), project.agentSkillsDir);
247814
+ const dir = join20(dirname14(project.configPath), project.agentSkillsDir);
247725
247815
  const remote = await runTask("Fetching agent skills from Base44", () => fetchAgentSkills(), {
247726
247816
  successMessage: "Agent skills fetched successfully",
247727
247817
  errorMessage: "Failed to fetch agent skills"
@@ -247777,14 +247867,14 @@ function getAgentSkillsCommand() {
247777
247867
  }
247778
247868
 
247779
247869
  // src/cli/commands/agents/pull.ts
247780
- import { dirname as dirname14, join as join20 } from "node:path";
247870
+ import { dirname as dirname15, join as join21 } from "node:path";
247781
247871
  async function pullAgentsAction({
247782
247872
  log,
247783
247873
  runTask
247784
247874
  }) {
247785
247875
  const { project } = await readProjectConfig();
247786
- const configDir = dirname14(project.configPath);
247787
- const agentsDir = join20(configDir, project.agentsDir);
247876
+ const configDir = dirname15(project.configPath);
247877
+ const agentsDir = join21(configDir, project.agentsDir);
247788
247878
  const remoteAgents = await runTask("Fetching agents from Base44", async () => {
247789
247879
  return await fetchAgents();
247790
247880
  }, {
@@ -247854,12 +247944,12 @@ function getAgentsCommand() {
247854
247944
  }
247855
247945
 
247856
247946
  // src/cli/commands/auth/password-login.ts
247857
- import { dirname as dirname15, join as join21 } from "node:path";
247947
+ import { dirname as dirname16, join as join22 } from "node:path";
247858
247948
  async function passwordLoginAction({ log, runTask }, action) {
247859
247949
  const shouldEnable = action === "enable";
247860
247950
  const { project } = await readProjectConfig();
247861
- const configDir = dirname15(project.configPath);
247862
- const authDir = join21(configDir, project.authDir);
247951
+ const configDir = dirname16(project.configPath);
247952
+ const authDir = join22(configDir, project.authDir);
247863
247953
  const updated = await runTask("Updating local auth config", async () => {
247864
247954
  const current = await readAuthConfig(authDir) ?? DEFAULT_AUTH_CONFIG;
247865
247955
  const merged = { ...current, enableUsernamePassword: shouldEnable };
@@ -247879,14 +247969,14 @@ function getPasswordLoginCommand() {
247879
247969
  }
247880
247970
 
247881
247971
  // src/cli/commands/auth/pull.ts
247882
- import { dirname as dirname16, join as join22 } from "node:path";
247972
+ import { dirname as dirname17, join as join23 } from "node:path";
247883
247973
  async function pullAuthAction({
247884
247974
  log,
247885
247975
  runTask
247886
247976
  }) {
247887
247977
  const { project } = await readProjectConfig();
247888
- const configDir = dirname16(project.configPath);
247889
- const authDir = join22(configDir, project.authDir);
247978
+ const configDir = dirname17(project.configPath);
247979
+ const authDir = join23(configDir, project.authDir);
247890
247980
  const remoteConfig = await runTask("Fetching auth config from Base44", async () => {
247891
247981
  return await pullAuthConfig();
247892
247982
  }, {
@@ -247950,7 +248040,7 @@ function getAuthPushCommand() {
247950
248040
  }
247951
248041
 
247952
248042
  // src/cli/commands/auth/social-login.ts
247953
- import { dirname as dirname17, join as join23, resolve as resolve6 } from "node:path";
248043
+ import { dirname as dirname18, join as join24, resolve as resolve7 } from "node:path";
247954
248044
  var PROVIDER_LABELS = {
247955
248045
  google: "Google",
247956
248046
  microsoft: "Microsoft",
@@ -247990,7 +248080,7 @@ async function socialLoginAction({ log, isNonInteractive, runTask }, provider, a
247990
248080
  let clientSecret;
247991
248081
  if (useCustomOAuth && oauth && oauthCli && hasSecretOptions(options)) {
247992
248082
  if (options.envFile) {
247993
- const secrets = await parseEnvFile(resolve6(options.envFile));
248083
+ const secrets = await parseEnvFile(resolve7(options.envFile));
247994
248084
  const value = secrets[oauthCli.envVar];
247995
248085
  if (!value) {
247996
248086
  throw new InvalidInputError(`Key "${oauthCli.envVar}" not found in ${options.envFile}.`);
@@ -248020,8 +248110,8 @@ async function socialLoginAction({ log, isNonInteractive, runTask }, provider, a
248020
248110
  }
248021
248111
  }
248022
248112
  const { project } = await readProjectConfig();
248023
- const configDir = dirname17(project.configPath);
248024
- const authDir = join23(configDir, project.authDir);
248113
+ const configDir = dirname18(project.configPath);
248114
+ const authDir = join24(configDir, project.authDir);
248025
248115
  const { config: updated } = await runTask("Updating local auth config", async () => updateSocialLoginConfig(authDir, provider, shouldEnable, useCustomOAuth && options.clientId ? { clientId: options.clientId } : undefined));
248026
248116
  if (clientSecret) {
248027
248117
  await runTask("Saving client secret", async () => pushCustomOAuthSecret(provider, clientSecret));
@@ -248046,7 +248136,7 @@ function getSocialLoginCommand() {
248046
248136
  }
248047
248137
 
248048
248138
  // src/cli/commands/auth/sso.ts
248049
- import { dirname as dirname18, join as join24, resolve as resolve7 } from "node:path";
248139
+ import { dirname as dirname19, join as join25, resolve as resolve8 } from "node:path";
248050
248140
  var SSOConfigFileSchema = object({
248051
248141
  provider: _enum(Object.values(KNOWN_SSO_PROVIDERS)),
248052
248142
  clientId: string2(),
@@ -248062,7 +248152,7 @@ var SSOConfigFileSchema = object({
248062
248152
  ssoName: string2().optional()
248063
248153
  });
248064
248154
  async function loadSSOConfigFile(filePath) {
248065
- const resolved = resolve7(filePath);
248155
+ const resolved = resolve8(filePath);
248066
248156
  const raw = await readJsonFile(resolved);
248067
248157
  const result = SSOConfigFileSchema.safeParse(raw);
248068
248158
  if (!result.success) {
@@ -248150,7 +248240,7 @@ async function ssoEnableAction({ isNonInteractive, runTask }, options) {
248150
248240
  }
248151
248241
  let clientSecret;
248152
248242
  if (merged.envFile && !merged.clientSecret) {
248153
- const secrets = await parseEnvFile(resolve7(merged.envFile));
248243
+ const secrets = await parseEnvFile(resolve8(merged.envFile));
248154
248244
  const value = secrets.sso_client_secret;
248155
248245
  if (!value) {
248156
248246
  throw new InvalidInputError(`Key "sso_client_secret" not found in ${merged.envFile}.`);
@@ -248209,8 +248299,8 @@ async function ssoEnableAction({ isNonInteractive, runTask }, options) {
248209
248299
  throw error;
248210
248300
  }
248211
248301
  const { project } = await readProjectConfig();
248212
- const configDir = dirname18(project.configPath);
248213
- const authDir = join24(configDir, project.authDir);
248302
+ const configDir = dirname19(project.configPath);
248303
+ const authDir = join25(configDir, project.authDir);
248214
248304
  await runTask("Updating local auth config", async () => updateSSOConfig(authDir, provider, true));
248215
248305
  await runTask("Saving SSO credentials", async () => pushSSOSecrets(secrets));
248216
248306
  return {
@@ -248225,8 +248315,8 @@ async function ssoDisableAction({ log, runTask }, options) {
248225
248315
  throw new InvalidInputError("Configuration options cannot be used with disable. To disable SSO: base44 auth sso disable");
248226
248316
  }
248227
248317
  const { project } = await readProjectConfig();
248228
- const configDir = dirname18(project.configPath);
248229
- const authDir = join24(configDir, project.authDir);
248318
+ const configDir = dirname19(project.configPath);
248319
+ const authDir = join25(configDir, project.authDir);
248230
248320
  const updated = await runTask("Updating local auth config", async () => updateSSOConfig(authDir, null, false));
248231
248321
  await runTask("Removing SSO credentials", async () => deleteSSOSecrets());
248232
248322
  if (!hasAnyLoginMethod(updated)) {
@@ -249108,13 +249198,13 @@ function getConnectorsListAvailableCommand() {
249108
249198
  }
249109
249199
 
249110
249200
  // src/cli/commands/connectors/pull.ts
249111
- import { dirname as dirname19, join as join25, resolve as resolve8 } from "node:path";
249201
+ import { dirname as dirname20, join as join26, resolve as resolve9 } from "node:path";
249112
249202
  async function resolveConnectorsDir(options) {
249113
249203
  if (!getAppContext().projectRoot) {
249114
- return resolve8(options.dir ?? "connectors");
249204
+ return resolve9(options.dir ?? "connectors");
249115
249205
  }
249116
249206
  const { project } = await readProjectConfig();
249117
- return join25(dirname19(project.configPath), project.connectorsDir);
249207
+ return join26(dirname20(project.configPath), project.connectorsDir);
249118
249208
  }
249119
249209
  async function pullConnectorsAction({ log, runTask, jsonMode }, options) {
249120
249210
  const connectorsDir = await resolveConnectorsDir(options);
@@ -249155,10 +249245,10 @@ function getConnectorsPullCommand() {
249155
249245
  }
249156
249246
 
249157
249247
  // src/cli/commands/connectors/push.ts
249158
- import { resolve as resolve9 } from "node:path";
249248
+ import { resolve as resolve10 } from "node:path";
249159
249249
  async function readConnectorsToPush(options) {
249160
249250
  if (!getAppContext().projectRoot) {
249161
- return readAllConnectors(resolve9(options.dir ?? "connectors"));
249251
+ return readAllConnectors(resolve10(options.dir ?? "connectors"));
249162
249252
  }
249163
249253
  const { connectors } = await readProjectConfig();
249164
249254
  return connectors;
@@ -249501,11 +249591,11 @@ function getListCommand() {
249501
249591
  }
249502
249592
 
249503
249593
  // src/cli/commands/functions/pull.ts
249504
- import { dirname as dirname20, join as join26 } from "node:path";
249594
+ import { dirname as dirname21, join as join27 } from "node:path";
249505
249595
  async function pullFunctionsAction({ log, runTask }, name) {
249506
249596
  const { project, functions } = await readProjectConfig();
249507
- const configDir = dirname20(project.configPath);
249508
- const functionsDir = join26(configDir, project.functionsDir);
249597
+ const configDir = dirname21(project.configPath);
249598
+ const functionsDir = join27(configDir, project.functionsDir);
249509
249599
  const pluginFunctionNames = new Set(functions.filter((fn) => fn.source.type === "plugin").map((fn) => fn.name));
249510
249600
  const remoteFunctions = await runTask("Fetching functions from Base44", async () => {
249511
249601
  const { functions } = await listDeployedFunctions();
@@ -249608,14 +249698,11 @@ async function maybeAskToBuild(isNonInteractive, buildCommand) {
249608
249698
 
249609
249699
  // src/cli/commands/project/build.ts
249610
249700
  async function buildAction(ctx) {
249611
- const { app } = ctx;
249612
- if (!app?.projectRoot) {
249613
- throw new ConfigInvalidError("base44 build requires a linked local project. Run it from a project with base44/.app.jsonc.");
249614
- }
249615
- const { project } = await readProjectConfig(app.projectRoot);
249701
+ const app = requireApp(ctx);
249702
+ const target = await resolveBuildTarget(app.projectRoot);
249616
249703
  await runSiteBuild(ctx, {
249617
- root: project.root,
249618
- buildCommand: project.site?.buildCommand,
249704
+ root: target.root,
249705
+ buildCommand: target.buildCommand,
249619
249706
  appId: app.id
249620
249707
  });
249621
249708
  return {
@@ -249623,15 +249710,15 @@ async function buildAction(ctx) {
249623
249710
  };
249624
249711
  }
249625
249712
  function getBuildCommand() {
249626
- return new Base44Command("build").description("Build the site with the Base44 app id injected").action(buildAction);
249713
+ return new Base44Command("build", { requireAuth: false }).description("Build the site with the Base44 app id injected").action(buildAction);
249627
249714
  }
249628
249715
 
249629
249716
  // src/cli/commands/project/create.ts
249630
- import { basename as basename6, resolve as resolve10 } from "node:path";
249717
+ import { basename as basename6, resolve as resolve11 } from "node:path";
249631
249718
  var import_kebabCase = __toESM(require_kebabCase(), 1);
249632
249719
 
249633
249720
  // src/cli/commands/project/scaffold-shared.ts
249634
- import { join as join27 } from "node:path";
249721
+ import { join as join28 } from "node:path";
249635
249722
  var DEFAULT_TEMPLATE_ID = "backend-only";
249636
249723
  async function getTemplateById(templateId) {
249637
249724
  const templates = await listTemplates();
@@ -249694,7 +249781,7 @@ async function completeProjectSetup({
249694
249781
  env: { VITE_BASE44_APP_ID: projectId }
249695
249782
  })`${buildCommand}`;
249696
249783
  updateMessage("Deploying site...");
249697
- return await deploySite(join27(resolvedPath, outputDirectory));
249784
+ return await deploySite(join28(resolvedPath, outputDirectory));
249698
249785
  }, {
249699
249786
  successMessage: theme.colors.base44Orange("Site deployed successfully"),
249700
249787
  errorMessage: "Failed to deploy site"
@@ -249823,7 +249910,7 @@ async function createInteractive(options, ctx) {
249823
249910
  }, ctx);
249824
249911
  }
249825
249912
  async function createNonInteractive(options, ctx) {
249826
- ctx.log.info(`Creating a new project at ${resolve10(options.path)}`);
249913
+ ctx.log.info(`Creating a new project at ${resolve11(options.path)}`);
249827
249914
  const template = await getTemplateById(options.template ?? DEFAULT_TEMPLATE_ID);
249828
249915
  return await executeCreate({
249829
249916
  template,
@@ -249847,7 +249934,7 @@ async function executeCreate({
249847
249934
  }, ctx) {
249848
249935
  const { log, runTask } = ctx;
249849
249936
  const name = rawName.trim();
249850
- const resolvedPath = resolve10(projectPath);
249937
+ const resolvedPath = resolve11(projectPath);
249851
249938
  const organizationId = await resolveWorkspaceId(ctx, flagWorkspaceId, isInteractive);
249852
249939
  const { projectId } = await runTask("Setting up your project...", async () => {
249853
249940
  return await createProjectFiles({
@@ -249904,8 +249991,7 @@ async function deployAction(ctx, options = {}) {
249904
249991
  throw new InvalidInputError("--yes is required in non-interactive mode");
249905
249992
  }
249906
249993
  const projectData = await readProjectConfig(options.projectRoot);
249907
- const workerBuild = await hasWorkerBuild(projectData.project.root);
249908
- if (!hasResourcesToDeploy(projectData, { workerBuild })) {
249994
+ if (!hasResourcesToDeploy(projectData)) {
249909
249995
  return {
249910
249996
  outroMessage: "No resources found to deploy"
249911
249997
  };
@@ -249941,9 +250027,7 @@ async function deployAction(ctx, options = {}) {
249941
250027
  if (project.visibility) {
249942
250028
  summaryLines.push(` - Visibility: ${project.visibility}`);
249943
250029
  }
249944
- if (workerBuild) {
249945
- summaryLines.push(" - Site");
249946
- } else if (project.site?.outputDirectory) {
250030
+ if (project.site?.outputDirectory) {
249947
250031
  summaryLines.push(` - Site from ${project.site.outputDirectory}`);
249948
250032
  }
249949
250033
  if (!options.yes) {
@@ -249998,10 +250082,6 @@ ${summaryLines.join(`
249998
250082
  if (result.appUrl) {
249999
250083
  log.message(`${theme.styles.header("App URL")}: ${theme.colors.links(result.appUrl)}`);
250000
250084
  }
250001
- if (result.deployment) {
250002
- const { deploymentId, gitHash } = result.deployment;
250003
- log.message(`${theme.styles.header("Deployment")}: ${deploymentId} (commit ${gitHash.slice(0, 12)})`);
250004
- }
250005
250085
  return { outroMessage: "App deployed successfully" };
250006
250086
  }
250007
250087
  function getDeployCommand3() {
@@ -250495,7 +250575,7 @@ function getLogsCommand() {
250495
250575
  }
250496
250576
 
250497
250577
  // src/cli/commands/project/scaffold.ts
250498
- import { basename as basename7, resolve as resolve11 } from "node:path";
250578
+ import { basename as basename7, resolve as resolve12 } from "node:path";
250499
250579
  function resolveAppId(options) {
250500
250580
  const appId = options.appId;
250501
250581
  if (!appId) {
@@ -250511,7 +250591,7 @@ function resolveAppId(options) {
250511
250591
  async function scaffoldAction(ctx, name, options, command) {
250512
250592
  const { log, runTask } = ctx;
250513
250593
  const appId = resolveAppId(command.optsWithGlobals());
250514
- const resolvedPath = resolve11("./");
250594
+ const resolvedPath = resolve12("./");
250515
250595
  const projectName = (name ?? basename7(resolvedPath)).trim();
250516
250596
  const template = await getTemplateById("backend-only");
250517
250597
  log.info(`Scaffolding project at ${resolvedPath}`);
@@ -250559,6 +250639,315 @@ function getVisibilityCommand() {
250559
250639
  ])).action(setVisibility);
250560
250640
  }
250561
250641
 
250642
+ // src/core/version/schema.ts
250643
+ var DeclareVersionResponseSchema = object({
250644
+ session_id: string2(),
250645
+ uploads: array(object({
250646
+ path: string2(),
250647
+ url: string2(),
250648
+ content_type: string2(),
250649
+ content_length: number2(),
250650
+ checksum_sha256: string2()
250651
+ }))
250652
+ }).transform((data) => ({
250653
+ sessionId: data.session_id,
250654
+ uploads: data.uploads.map((upload) => ({
250655
+ path: upload.path,
250656
+ url: upload.url,
250657
+ contentType: upload.content_type,
250658
+ contentLength: upload.content_length,
250659
+ checksumSha256: upload.checksum_sha256
250660
+ }))
250661
+ }));
250662
+ var CreateVersionResponseSchema = object({
250663
+ version_id: string2(),
250664
+ manifest_hash: string2()
250665
+ }).transform((data) => ({
250666
+ versionId: data.version_id,
250667
+ manifestHash: data.manifest_hash
250668
+ }));
250669
+ var EnvironmentResponseSchema = object({
250670
+ name: string2(),
250671
+ version_id: string2(),
250672
+ manifest_hash: string2(),
250673
+ deployment_id: string2()
250674
+ }).transform((data) => ({
250675
+ name: data.name,
250676
+ versionId: data.version_id,
250677
+ manifestHash: data.manifest_hash,
250678
+ deploymentId: data.deployment_id
250679
+ }));
250680
+
250681
+ // src/core/version/api.ts
250682
+ var DEFAULT_VERSION_UPLOAD_CONCURRENCY = 8;
250683
+ var MAX_VERSION_UPLOAD_CONCURRENCY = 16;
250684
+ function declaredFile({ path, size, digest }) {
250685
+ return { path, size, digest };
250686
+ }
250687
+ function declaredModule(module) {
250688
+ return { ...declaredFile(module), type: module.type };
250689
+ }
250690
+ function declaredServingConfig(config) {
250691
+ const stated = {
250692
+ html_handling: config?.htmlHandling ?? null,
250693
+ not_found_handling: config?.notFoundHandling ?? null,
250694
+ run_worker_first: config?.runWorkerFirst ?? null,
250695
+ headers: config?.headers ?? null,
250696
+ redirects: config?.redirects ?? null
250697
+ };
250698
+ return Object.values(stated).every((v) => v === null) ? null : stated;
250699
+ }
250700
+ async function post(path, json, doing) {
250701
+ try {
250702
+ return await getAppClient().post(path, { json, timeout: 180000 });
250703
+ } catch (error) {
250704
+ throw await ApiError.fromHttpError(error, doing);
250705
+ }
250706
+ }
250707
+ var KEYED_RETRY = {
250708
+ limit: 3,
250709
+ methods: ["patch"],
250710
+ statusCodes: [408, 500, 502, 503, 504],
250711
+ retryOnTimeout: true
250712
+ };
250713
+ async function patch(path, json, doing, retry) {
250714
+ try {
250715
+ return await getAppClient().patch(path, {
250716
+ json,
250717
+ timeout: 180000,
250718
+ ...retry ? { retry } : {}
250719
+ });
250720
+ } catch (error) {
250721
+ throw await ApiError.fromHttpError(error, doing);
250722
+ }
250723
+ }
250724
+ function parse10(schema, body, what) {
250725
+ const result = schema.safeParse(body);
250726
+ if (!result.success) {
250727
+ throw new SchemaValidationError(`Invalid ${what} response from server`, result.error);
250728
+ }
250729
+ return result.data;
250730
+ }
250731
+ async function createVersion(artifacts, options = {}) {
250732
+ const declared = parse10(DeclareVersionResponseSchema, await (await post("versions", {
250733
+ assets: artifacts.assets.map(declaredFile),
250734
+ ...artifacts.siteWorker ? {
250735
+ site_worker: {
250736
+ main: artifacts.siteWorker.main,
250737
+ modules: artifacts.siteWorker.modules.map(declaredModule),
250738
+ compatibility_date: artifacts.siteWorker.compatibilityDate,
250739
+ compatibility_flags: artifacts.siteWorker.compatibilityFlags,
250740
+ serving_config: declaredServingConfig(artifacts.siteWorker.servingConfig)
250741
+ }
250742
+ } : {},
250743
+ entities: artifacts.entities,
250744
+ agents: artifacts.agents,
250745
+ source_commit: options.sourceCommit
250746
+ }, "declaring a version")).json(), "declare");
250747
+ const declaredFiles = [
250748
+ ...artifacts.assets,
250749
+ ...artifacts.siteWorker?.modules ?? []
250750
+ ];
250751
+ options.progress?.onDeclared?.({ fileCount: declaredFiles.length });
250752
+ if (declared.uploads.length !== declaredFiles.length) {
250753
+ throw new InternalError(`Declared ${declaredFiles.length} files but the server signed ${declared.uploads.length} upload URLs.`);
250754
+ }
250755
+ const drifted = declared.uploads.findIndex((upload, index) => upload.path !== declaredFiles[index].path);
250756
+ if (drifted !== -1) {
250757
+ throw new InternalError(`Upload ${drifted} is signed for ${declared.uploads[drifted].path}, but that slot declared ${declaredFiles[drifted].path}.`);
250758
+ }
250759
+ let uploadedFiles = 0;
250760
+ await pMap(declared.uploads, async (upload, index) => {
250761
+ await putPresigned(upload, declaredFiles[index].absolutePath);
250762
+ uploadedFiles++;
250763
+ options.progress?.onUpload?.({
250764
+ uploadedFiles,
250765
+ totalFiles: declared.uploads.length
250766
+ });
250767
+ }, { concurrency: options.concurrency ?? DEFAULT_VERSION_UPLOAD_CONCURRENCY });
250768
+ return parse10(CreateVersionResponseSchema, await (await post(`versions/${encodeURIComponent(declared.sessionId)}/finalize`, {}, "creating a version")).json(), "create version");
250769
+ }
250770
+ async function setEnvironmentVersion(environment, versionId, options = {}) {
250771
+ return parse10(EnvironmentResponseSchema, await (await patch(`environments/${encodeURIComponent(environment)}`, {
250772
+ version_id: versionId,
250773
+ ...options.idempotencyKey ? { idempotency_key: options.idempotencyKey } : {}
250774
+ }, "setting the environment's version", options.idempotencyKey ? KEYED_RETRY : undefined)).json(), "environment");
250775
+ }
250776
+ // src/core/version/artifacts.ts
250777
+ import { createHash as createHash2 } from "node:crypto";
250778
+ import { join as join29, resolve as resolve13 } from "node:path";
250779
+ var MAX_FILE_COUNT = 50000;
250780
+ var HASH_CONCURRENCY = 32;
250781
+ var ENTRY2 = "index.html";
250782
+ async function digestFile(absolutePath) {
250783
+ const hash = await hashFileInto(createHash2("sha256"), absolutePath);
250784
+ return `sha256:${hash.digest("hex")}`;
250785
+ }
250786
+ async function collectBuildOutput(outputDir, options = {}) {
250787
+ const found = await describeBuildOutput(outputDir);
250788
+ if (found.length > MAX_FILE_COUNT) {
250789
+ throw new InvalidInputError(`Too many files: found ${found.length}, the limit is ${MAX_FILE_COUNT}.`);
250790
+ }
250791
+ if (options.entryFile) {
250792
+ if (found.length === 0) {
250793
+ throw new InvalidInputError(`No files found in ${outputDir}. Build the site before creating a version.`, {
250794
+ hints: [
250795
+ { message: "Run 'base44 build' first", command: "base44 build" }
250796
+ ]
250797
+ });
250798
+ }
250799
+ if (!found.some((f) => f.path === options.entryFile)) {
250800
+ throw new InvalidInputError(`${outputDir} has no ${options.entryFile}, so nothing could enter the site.`);
250801
+ }
250802
+ }
250803
+ return await pMap(found, async (file) => ({ ...file, digest: await digestFile(file.absolutePath) }), { concurrency: HASH_CONCURRENCY });
250804
+ }
250805
+ async function describeSiteWorker(built) {
250806
+ const { config, modules } = built;
250807
+ const entry = resolve13(config.configDir, config.main);
250808
+ const main = modules.find((m) => m.absolutePath === entry)?.name;
250809
+ if (!main) {
250810
+ throw new InvalidInputError(`The Worker's entry module ${config.main} is not among the ${modules.length} modules collected from ${config.configDir}.`);
250811
+ }
250812
+ return {
250813
+ main,
250814
+ modules: await pMap(modules, async ({ name, absolutePath, size, type }) => ({
250815
+ path: name,
250816
+ absolutePath,
250817
+ size,
250818
+ digest: await digestFile(absolutePath),
250819
+ type
250820
+ }), { concurrency: HASH_CONCURRENCY }),
250821
+ compatibilityDate: config.compatibilityDate,
250822
+ compatibilityFlags: config.compatibilityFlags,
250823
+ servingConfig: config.assetsConfig
250824
+ };
250825
+ }
250826
+ async function readRawResources(dir) {
250827
+ if (!await pathExists(dir)) {
250828
+ return {};
250829
+ }
250830
+ const files = await globby(`**/*.${CONFIG_FILE_EXTENSION_GLOB}`, {
250831
+ cwd: dir,
250832
+ onlyFiles: true,
250833
+ followSymbolicLinks: false
250834
+ });
250835
+ const payloads = {};
250836
+ for (const relativePath of files.sort()) {
250837
+ const name = relativePath.replace(/\.jsonc?$/, "");
250838
+ payloads[name] = await readJsonFile(join29(dir, ...relativePath.split("/")));
250839
+ }
250840
+ return payloads;
250841
+ }
250842
+ async function collectResources(configDir, dirs) {
250843
+ const [entities, agents] = await Promise.all([
250844
+ readRawResources(join29(configDir, dirs.entitiesDir)),
250845
+ readRawResources(join29(configDir, dirs.agentsDir))
250846
+ ]);
250847
+ return { entities, agents };
250848
+ }
250849
+ async function collectArtifacts(target) {
250850
+ const built = await resolveFullStackBuild(target.root);
250851
+ const siteWorker = built ? await describeSiteWorker(built) : null;
250852
+ return {
250853
+ assets: built ? built.assetsDir ? await collectBuildOutput(built.assetsDir) : [] : await collectBuildOutput(requireOutputDir(target), {
250854
+ entryFile: ENTRY2
250855
+ }),
250856
+ ...siteWorker ? { siteWorker } : {},
250857
+ ...await collectResources(target.configDir, target)
250858
+ };
250859
+ }
250860
+ // src/core/version/gate.ts
250861
+ var VERSIONS_API_ENV = "BASE44_VERSIONS_API";
250862
+ function versionsApiEnabled(env = process.env) {
250863
+ const value = env[VERSIONS_API_ENV];
250864
+ return value === "1" || value === "true";
250865
+ }
250866
+ // src/core/version/publish.ts
250867
+ import { randomUUID as randomUUID4 } from "node:crypto";
250868
+ var DEFAULT_ENVIRONMENT = "production";
250869
+ async function tagStep2(step, run) {
250870
+ return await tagStep(step, run);
250871
+ }
250872
+ async function publishVersion(artifacts, options = {}) {
250873
+ const version = await tagStep2("create_version", () => createVersion(artifacts, {
250874
+ sourceCommit: options.sourceCommit,
250875
+ concurrency: options.concurrency,
250876
+ progress: options.progress
250877
+ }));
250878
+ const environment = await tagStep2("deploy", () => setEnvironmentVersion(options.target ?? DEFAULT_ENVIRONMENT, version.versionId, {
250879
+ idempotencyKey: randomUUID4()
250880
+ }));
250881
+ return {
250882
+ environment: environment.name,
250883
+ versionId: environment.versionId,
250884
+ manifestHash: environment.manifestHash,
250885
+ deploymentId: environment.deploymentId
250886
+ };
250887
+ }
250888
+ // src/cli/commands/versions/options.ts
250889
+ function outputDirOption() {
250890
+ return new Option2("--output-dir <dir>", "Build output directory (defaults to the project's, else dist)");
250891
+ }
250892
+ function targetOption() {
250893
+ return new Option2("--target <name>", "Environment to serve the version at");
250894
+ }
250895
+ function gitHashOption() {
250896
+ return new Option2("--git-hash <hash>", "Commit the build came from (defaults to the checkout's HEAD)").argParser((value) => {
250897
+ if (!isGitCommitHash(value)) {
250898
+ throw new InvalidArgumentError2("Expected a git commit hash (7-64 hex chars).");
250899
+ }
250900
+ return value;
250901
+ });
250902
+ }
250903
+ function concurrencyOption() {
250904
+ return new Option2("--concurrency <n>", "Parallel file uploads").default(DEFAULT_VERSION_UPLOAD_CONCURRENCY).argParser((value) => {
250905
+ const parsed = Number(value);
250906
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > MAX_VERSION_UPLOAD_CONCURRENCY) {
250907
+ throw new InvalidArgumentError2(`Expected a whole number between 1 and ${MAX_VERSION_UPLOAD_CONCURRENCY}.`);
250908
+ }
250909
+ return parsed;
250910
+ });
250911
+ }
250912
+
250913
+ // src/cli/commands/publish.ts
250914
+ async function publishAction(ctx, options) {
250915
+ const { runTask, log, jsonMode } = ctx;
250916
+ const app = requireApp(ctx);
250917
+ const target = await tagStep2("create_version", () => resolveBuildTarget(app.projectRoot, { outputDir: options.outputDir }));
250918
+ if (options.build !== false) {
250919
+ await tagStep2("build", () => runSiteBuild(ctx, {
250920
+ root: target.root,
250921
+ buildCommand: target.buildCommand,
250922
+ appId: app.id
250923
+ }));
250924
+ }
250925
+ const gitHash = await resolveProvenanceCommit(target.root, options.gitHash);
250926
+ const result = await runTask("Publishing...", async (updateMessage) => {
250927
+ const artifacts = await tagStep2("create_version", () => collectArtifacts(target));
250928
+ return await publishVersion(artifacts, {
250929
+ sourceCommit: gitHash,
250930
+ target: options.target,
250931
+ concurrency: options.concurrency,
250932
+ progress: {
250933
+ onDeclared: ({ fileCount }) => updateMessage(`Uploading ${fileCount} files`),
250934
+ onUpload: ({ uploadedFiles, totalFiles }) => updateMessage(`Uploaded ${uploadedFiles} of ${totalFiles} files`)
250935
+ }
250936
+ });
250937
+ }, { successMessage: "Published", errorMessage: "Publish failed" });
250938
+ if (!jsonMode) {
250939
+ log.message(theme.styles.dim(`version ${result.versionId}`));
250940
+ }
250941
+ return {
250942
+ outroMessage: `${result.environment} now serves ${result.versionId}`,
250943
+ stdout: jsonMode ? `${JSON.stringify(result, null, 2)}
250944
+ ` : undefined
250945
+ };
250946
+ }
250947
+ function getPublishCommand() {
250948
+ return new Base44Command("publish").description("Build the app, record it as a version, and serve that version").option("--no-build", "Publish the existing build output without rebuilding").addOption(outputDirOption()).addOption(targetOption()).addOption(gitHashOption()).addOption(concurrencyOption()).action(publishAction);
250949
+ }
250950
+
250562
250951
  // src/core/resources/sandbox/schema.ts
250563
250952
  var FileErrorSchema = object({
250564
250953
  code: string2(),
@@ -250944,7 +251333,7 @@ function getSecretsListCommand() {
250944
251333
  }
250945
251334
 
250946
251335
  // src/cli/commands/secrets/set.ts
250947
- import { resolve as resolve12 } from "node:path";
251336
+ import { resolve as resolve14 } from "node:path";
250948
251337
  function parseEntries(entries) {
250949
251338
  const secrets = {};
250950
251339
  for (const entry of entries) {
@@ -250975,7 +251364,7 @@ async function setSecretsAction({ log, runTask }, entries, options) {
250975
251364
  validateInput(entries, options);
250976
251365
  let secrets;
250977
251366
  if (options.envFile) {
250978
- secrets = await parseEnvFile(resolve12(options.envFile));
251367
+ secrets = await parseEnvFile(resolve14(options.envFile));
250979
251368
  if (Object.keys(secrets).length === 0) {
250980
251369
  throw new InvalidInputError("The env file contains no valid KEY=VALUE entries.");
250981
251370
  }
@@ -251004,7 +251393,7 @@ function getSecretsCommand() {
251004
251393
  }
251005
251394
 
251006
251395
  // src/cli/commands/site/deploy.ts
251007
- import { resolve as resolve13 } from "node:path";
251396
+ import { resolve as resolve15 } from "node:path";
251008
251397
  async function deployAction2(ctx, options) {
251009
251398
  const { isNonInteractive } = ctx;
251010
251399
  if (isNonInteractive && !options.yes) {
@@ -251012,17 +251401,16 @@ async function deployAction2(ctx, options) {
251012
251401
  }
251013
251402
  const project = await readProjectSettings();
251014
251403
  await maybeBuildBeforeDeploy(ctx, project, options.build);
251015
- const workerBuild = await hasWorkerBuild(project.root);
251016
251404
  if (!options.yes) {
251017
251405
  const outputDirectory = project.site?.outputDirectory;
251018
251406
  const shouldDeploy = await Re({
251019
- message: outputDirectory && !workerBuild ? `Deploy site from ${outputDirectory}?` : "Deploy site?"
251407
+ message: outputDirectory ? `Deploy site from ${outputDirectory}?` : "Deploy site?"
251020
251408
  });
251021
251409
  if (Ct(shouldDeploy) || !shouldDeploy) {
251022
251410
  return { outroMessage: "Deployment cancelled" };
251023
251411
  }
251024
251412
  }
251025
- return workerBuild || deploymentsApiEnabled() ? await deployToDeploymentsApi(ctx, project, options) : await deployTarball(ctx, project);
251413
+ return deploymentsApiEnabled() ? await deployToDeploymentsApi(ctx, project, options) : await deployTarball(ctx, project);
251026
251414
  }
251027
251415
  async function deployToDeploymentsApi(ctx, project, options) {
251028
251416
  const { runTask, log, jsonMode } = ctx;
@@ -251083,7 +251471,7 @@ async function deployTarball({ runTask }, project) {
251083
251471
  }
251084
251472
  function siteOutputDir(project) {
251085
251473
  const outputDirectory = project.site?.outputDirectory;
251086
- return outputDirectory ? resolve13(project.root, outputDirectory) : null;
251474
+ return outputDirectory ? resolve15(project.root, outputDirectory) : null;
251087
251475
  }
251088
251476
  function getSiteDeployCommand() {
251089
251477
  const command = new Base44Command("deploy").description("Deploy built site files to Base44 hosting").option("-y, --yes", "Skip confirmation prompt").option("--build", "Build the site before deploying (skips the prompt)").option("--no-build", "Deploy without building (skips the prompt)");
@@ -251107,6 +251495,229 @@ function parseConcurrency(value) {
251107
251495
  return parsed;
251108
251496
  }
251109
251497
 
251498
+ // src/cli/dev/createDevLogger.ts
251499
+ var colorByType = {
251500
+ error: theme.styles.error,
251501
+ warn: theme.styles.warn,
251502
+ log: (input) => input
251503
+ };
251504
+ var stringify = (item) => {
251505
+ if (typeof item === "string") {
251506
+ return item;
251507
+ }
251508
+ if (item instanceof Error) {
251509
+ return item.toString();
251510
+ }
251511
+ try {
251512
+ return JSON.stringify(item, null, 2) ?? String(item);
251513
+ } catch {
251514
+ return String(item);
251515
+ }
251516
+ };
251517
+ function createDevLogger(label, labelColor = theme.styles.dim) {
251518
+ const prefix = label ? `${labelColor(`[${label}]`)} ` : "";
251519
+ const print = (type, ...args) => {
251520
+ const colorize = colorByType[type];
251521
+ console[type](prefix + args.map((item) => colorize(stringify(item))).join(" "));
251522
+ };
251523
+ return {
251524
+ log: (...args) => print("log", ...args),
251525
+ error: (msg, err) => {
251526
+ print("error", msg);
251527
+ if (err) {
251528
+ print("error", err);
251529
+ }
251530
+ },
251531
+ warn: (...args) => print("warn", ...args)
251532
+ };
251533
+ }
251534
+
251535
+ // src/cli/dev/dev-server/serve-runner.ts
251536
+ import { spawn as spawn2 } from "node:child_process";
251537
+ import process21 from "node:process";
251538
+
251539
+ class ServeRunner {
251540
+ command;
251541
+ cwd;
251542
+ env;
251543
+ logger;
251544
+ child;
251545
+ stopping = false;
251546
+ stopPromise;
251547
+ exitListeners = [];
251548
+ constructor(options) {
251549
+ this.command = options.command;
251550
+ this.cwd = options.cwd;
251551
+ this.env = options.env;
251552
+ this.logger = options.logger;
251553
+ }
251554
+ start() {
251555
+ if (this.child) {
251556
+ return;
251557
+ }
251558
+ const stdin = process21.platform === "win32" ? "ignore" : "inherit";
251559
+ const child = spawn2(this.command, {
251560
+ cwd: this.cwd,
251561
+ shell: true,
251562
+ detached: process21.platform !== "win32",
251563
+ env: { ...process21.env, ...this.env },
251564
+ stdio: [stdin, "pipe", "pipe"],
251565
+ windowsHide: true
251566
+ });
251567
+ this.child = child;
251568
+ this.setupHandlers(child);
251569
+ }
251570
+ onExit(listener) {
251571
+ this.exitListeners.push(listener);
251572
+ }
251573
+ async stop() {
251574
+ if (this.stopPromise) {
251575
+ return this.stopPromise;
251576
+ }
251577
+ this.stopPromise = this.stopChild();
251578
+ return this.stopPromise;
251579
+ }
251580
+ async stopChild() {
251581
+ const child = this.child;
251582
+ if (!child || child.exitCode !== null) {
251583
+ return;
251584
+ }
251585
+ this.stopping = true;
251586
+ const exited = new Promise((resolve) => child.once("exit", () => resolve()));
251587
+ if (process21.platform === "win32" && child.pid) {
251588
+ const taskkill = spawn2("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
251589
+ stdio: "ignore",
251590
+ windowsHide: true
251591
+ });
251592
+ await new Promise((resolve) => {
251593
+ taskkill.once("exit", () => resolve());
251594
+ taskkill.once("error", () => resolve());
251595
+ });
251596
+ } else if (child.pid) {
251597
+ try {
251598
+ process21.kill(-child.pid, "SIGTERM");
251599
+ } catch {
251600
+ child.kill();
251601
+ }
251602
+ }
251603
+ await exited;
251604
+ }
251605
+ setupHandlers(child) {
251606
+ child.stdout?.on("data", (data) => this.emitLines(data, "log"));
251607
+ child.stderr?.on("data", (data) => this.emitLines(data, "error"));
251608
+ child.on("error", (error) => {
251609
+ this.logger.error("Frontend dev server failed to start:", error);
251610
+ this.notifyExit(null);
251611
+ });
251612
+ child.on("exit", (code) => {
251613
+ if (this.stopping) {
251614
+ return;
251615
+ }
251616
+ this.logger.error(`Frontend dev server exited with code ${code}`);
251617
+ this.notifyExit(code);
251618
+ });
251619
+ }
251620
+ notifyExit(code) {
251621
+ for (const listener of this.exitListeners) {
251622
+ listener(code);
251623
+ }
251624
+ }
251625
+ emitLines(data, type) {
251626
+ const lines = data.toString().trimEnd().split(`
251627
+ `);
251628
+ for (const line of lines) {
251629
+ if (type === "error") {
251630
+ this.logger.error(line);
251631
+ } else {
251632
+ this.logger.log(line);
251633
+ }
251634
+ }
251635
+ }
251636
+ }
251637
+
251638
+ // src/cli/dev/serve-command-runner.ts
251639
+ function createServeCommandRunner({
251640
+ serveCommand,
251641
+ projectRoot,
251642
+ appId,
251643
+ appBaseUrl
251644
+ }) {
251645
+ return new ServeRunner({
251646
+ command: serveCommand,
251647
+ cwd: projectRoot,
251648
+ env: {
251649
+ VITE_BASE44_APP_ID: appId,
251650
+ ...appBaseUrl ? { VITE_BASE44_APP_BASE_URL: appBaseUrl } : {}
251651
+ },
251652
+ logger: createDevLogger("frontend", theme.colors.base44Orange)
251653
+ });
251654
+ }
251655
+
251656
+ // src/cli/dev/stop-runner-on-signals.ts
251657
+ import process22 from "node:process";
251658
+ function stopRunnerOnProcessSignals(runner) {
251659
+ const stop = () => void runner.stop();
251660
+ process22.on("SIGINT", stop);
251661
+ process22.on("SIGTERM", stop);
251662
+ }
251663
+
251664
+ // src/cli/commands/site/dev.ts
251665
+ var DEFAULT_SERVE_COMMAND = "npm run dev";
251666
+ async function siteDevAction(ctx) {
251667
+ const { app } = ctx;
251668
+ if (!app?.projectRoot) {
251669
+ throw new ConfigInvalidError("base44 site dev requires a linked local project. Run it from a project with base44/.app.jsonc.");
251670
+ }
251671
+ const { project } = await readProjectConfig(app.projectRoot);
251672
+ const site = project.site;
251673
+ if (!site) {
251674
+ throw new InvalidInputError(`This project has no 'site' block in base44/config.jsonc, so there is no frontend to serve. Add one naming its serveCommand; site dev falls back to "npm run dev".`);
251675
+ }
251676
+ const command = site.serveCommand ?? DEFAULT_SERVE_COMMAND;
251677
+ const runner = createServeCommandRunner({
251678
+ serveCommand: command,
251679
+ projectRoot: project.root,
251680
+ appId: app.id
251681
+ });
251682
+ stopRunnerOnProcessSignals(runner);
251683
+ runner.onExit((code) => process.exit(code ?? 1));
251684
+ runner.start();
251685
+ return { outroMessage: `Frontend dev server running '${command}'` };
251686
+ }
251687
+ function getSiteDevCommand() {
251688
+ return new Base44Command("dev", { requireAuth: false }).description("Run the site's dev server, with no local backend").action(siteDevAction);
251689
+ }
251690
+
251691
+ // src/cli/commands/site/install.ts
251692
+ async function installAction({
251693
+ runTask
251694
+ }) {
251695
+ const { project } = await readProjectConfig();
251696
+ const installCommand = project.site?.installCommand;
251697
+ if (!installCommand) {
251698
+ throw new ConfigNotFoundError("No site install command found.", {
251699
+ hints: [
251700
+ {
251701
+ message: `Add a 'site' block to your config.jsonc (e.g., "site": { "installCommand": "npm ci" }). Inside one, installCommand defaults to "npm install".`
251702
+ }
251703
+ ]
251704
+ });
251705
+ }
251706
+ await runTask("Installing site dependencies...", () => execa({ cwd: project.root, shell: true })`${installCommand}`, {
251707
+ successMessage: "Dependencies installed",
251708
+ errorMessage: "Install failed"
251709
+ });
251710
+ return {
251711
+ outroMessage: `Installed with ${theme.styles.bold(installCommand)}`
251712
+ };
251713
+ }
251714
+ function getSiteInstallCommand() {
251715
+ return new Base44Command("install", {
251716
+ requireAuth: false,
251717
+ requireAppContext: false
251718
+ }).description("Install the site's dependencies with its configured command").action(installAction);
251719
+ }
251720
+
251110
251721
  // src/cli/commands/site/open.ts
251111
251722
  async function openAction({
251112
251723
  isNonInteractive
@@ -251123,7 +251734,7 @@ function getSiteOpenCommand() {
251123
251734
 
251124
251735
  // src/cli/commands/site/index.ts
251125
251736
  function getSiteCommand() {
251126
- return new Command2("site").description("Manage app site (frontend app)").addCommand(getSiteDeployCommand()).addCommand(getSiteOpenCommand());
251737
+ return new Command2("site").description("Manage app site (frontend app)").addCommand(getSiteDeployCommand()).addCommand(getSiteDevCommand()).addCommand(getSiteInstallCommand()).addCommand(getSiteOpenCommand());
251127
251738
  }
251128
251739
 
251129
251740
  // src/core/types/generator.ts
@@ -251215,10 +251826,10 @@ function toPascalCase(name) {
251215
251826
  return name.split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
251216
251827
  }
251217
251828
  // src/core/types/update-project.ts
251218
- import { join as join30 } from "node:path";
251829
+ import { join as join33 } from "node:path";
251219
251830
  var TYPES_INCLUDE_PATH = `${PROJECT_SUBDIR}/${TYPES_OUTPUT_SUBDIR}/*.d.ts`;
251220
251831
  async function updateProjectConfig(projectRoot) {
251221
- const tsconfigPath = join30(projectRoot, "tsconfig.json");
251832
+ const tsconfigPath = join33(projectRoot, "tsconfig.json");
251222
251833
  if (!await pathExists(tsconfigPath)) {
251223
251834
  return false;
251224
251835
  }
@@ -251267,6 +251878,59 @@ function getTypesCommand() {
251267
251878
  return new Command2("types").description("Manage TypeScript type generation").addCommand(getTypesGenerateCommand());
251268
251879
  }
251269
251880
 
251881
+ // src/cli/commands/versions/create.ts
251882
+ async function createAction2(ctx, options) {
251883
+ const { runTask, jsonMode } = ctx;
251884
+ const target = await resolveBuildTarget(requireApp(ctx).projectRoot, {
251885
+ outputDir: options.outputDir
251886
+ });
251887
+ const gitHash = await resolveProvenanceCommit(target.root, options.gitHash);
251888
+ const version = await runTask("Creating version...", async (updateMessage) => await createVersion(await collectArtifacts(target), {
251889
+ sourceCommit: gitHash,
251890
+ concurrency: options.concurrency,
251891
+ progress: {
251892
+ onDeclared: ({ fileCount }) => updateMessage(`Uploading ${fileCount} files`),
251893
+ onUpload: ({ uploadedFiles, totalFiles }) => updateMessage(`Uploaded ${uploadedFiles} of ${totalFiles} files`)
251894
+ }
251895
+ }), {
251896
+ successMessage: "Version created",
251897
+ errorMessage: "Create version failed"
251898
+ });
251899
+ return {
251900
+ outroMessage: `Version ${version.versionId} (${version.manifestHash})`,
251901
+ stdout: jsonMode ? `${JSON.stringify(version, null, 2)}
251902
+ ` : undefined
251903
+ };
251904
+ }
251905
+ function getVersionCreateCommand() {
251906
+ return new Base44Command("create").description("Record the built output as a version, without deploying it").addOption(outputDirOption()).addOption(gitHashOption()).addOption(concurrencyOption()).action(createAction2);
251907
+ }
251908
+
251909
+ // src/cli/commands/versions/deploy.ts
251910
+ import { randomUUID as randomUUID5 } from "node:crypto";
251911
+ async function deployAction3({ runTask, jsonMode }, versionId, options) {
251912
+ const environment = options.target ?? DEFAULT_ENVIRONMENT;
251913
+ const result = await runTask(`Pointing ${environment} at ${versionId}...`, async () => await setEnvironmentVersion(environment, versionId, {
251914
+ idempotencyKey: randomUUID5()
251915
+ }), {
251916
+ successMessage: "Environment updated",
251917
+ errorMessage: "Could not update the environment"
251918
+ });
251919
+ return {
251920
+ outroMessage: `${result.name} now serves ${result.versionId}`,
251921
+ stdout: jsonMode ? `${JSON.stringify(result, null, 2)}
251922
+ ` : undefined
251923
+ };
251924
+ }
251925
+ function getVersionDeployCommand() {
251926
+ return new Base44Command("deploy").description("Point an environment at an already-recorded version (also the rollback)").argument("<version-id>", "The version to serve").addOption(targetOption()).action(deployAction3);
251927
+ }
251928
+
251929
+ // src/cli/commands/versions/index.ts
251930
+ function getVersionsCommand() {
251931
+ return new Command2("versions").description("Record app versions and serve them").addCommand(getVersionCreateCommand()).addCommand(getVersionDeployCommand());
251932
+ }
251933
+
251270
251934
  // src/core/resources/workflow/schema.ts
251271
251935
  var WorkflowRunStatusSchema = _enum([
251272
251936
  "running",
@@ -251643,47 +252307,10 @@ function getWorkspaceCommand() {
251643
252307
  return new Command2("workspace").description("List workspaces, inspect one, and move apps between them").addCommand(getWorkspaceListCommand()).addCommand(getWorkspaceGetCommand()).addCommand(getWorkspaceMoveCommand());
251644
252308
  }
251645
252309
 
251646
- // src/cli/dev/createDevLogger.ts
251647
- var colorByType = {
251648
- error: theme.styles.error,
251649
- warn: theme.styles.warn,
251650
- log: (input) => input
251651
- };
251652
- var stringify = (item) => {
251653
- if (typeof item === "string") {
251654
- return item;
251655
- }
251656
- if (item instanceof Error) {
251657
- return item.toString();
251658
- }
251659
- try {
251660
- return JSON.stringify(item, null, 2) ?? String(item);
251661
- } catch {
251662
- return String(item);
251663
- }
251664
- };
251665
- function createDevLogger(label, labelColor = theme.styles.dim) {
251666
- const prefix = label ? `${labelColor(`[${label}]`)} ` : "";
251667
- const print = (type, ...args) => {
251668
- const colorize = colorByType[type];
251669
- console[type](prefix + args.map((item) => colorize(stringify(item))).join(" "));
251670
- };
251671
- return {
251672
- log: (...args) => print("log", ...args),
251673
- error: (msg, err) => {
251674
- print("error", msg);
251675
- if (err) {
251676
- print("error", err);
251677
- }
251678
- },
251679
- warn: (...args) => print("warn", ...args)
251680
- };
251681
- }
251682
-
251683
252310
  // src/cli/dev/dev-server/main.ts
251684
252311
  var import_cors = __toESM(require_lib4(), 1);
251685
252312
  var import_express6 = __toESM(require_express(), 1);
251686
- import { dirname as dirname26, join as join36 } from "node:path";
252313
+ import { dirname as dirname27, join as join38 } from "node:path";
251687
252314
 
251688
252315
  // ../../node_modules/get-port/index.js
251689
252316
  import net from "node:net";
@@ -251812,8 +252439,8 @@ var $dir = async (options) => dirWithOptions(options);
251812
252439
  var $tmpName = promisify11(tmp.tmpName);
251813
252440
 
251814
252441
  // src/cli/dev/dev-server/function-manager.ts
251815
- import { spawn as spawn2 } from "node:child_process";
251816
- import { dirname as dirname23, join as join31 } from "node:path";
252442
+ import { spawn as spawn3 } from "node:child_process";
252443
+ import { dirname as dirname24, join as join34 } from "node:path";
251817
252444
  import { pathToFileURL } from "node:url";
251818
252445
 
251819
252446
  // src/cli/dev/dev-server/base-function-manager.ts
@@ -251910,7 +252537,7 @@ class FunctionManager extends BaseFunctionManager {
251910
252537
  async stopFunction(_name, { process: proc }) {
251911
252538
  const exited = new Promise((r) => proc.once("exit", () => r()));
251912
252539
  if (process.platform === "win32" && proc.pid) {
251913
- spawn2("taskkill", ["/pid", String(proc.pid), "/T", "/F"]);
252540
+ spawn3("taskkill", ["/pid", String(proc.pid), "/T", "/F"]);
251914
252541
  } else {
251915
252542
  proc.kill();
251916
252543
  }
@@ -251918,8 +252545,8 @@ class FunctionManager extends BaseFunctionManager {
251918
252545
  }
251919
252546
  spawnFunction(func, port) {
251920
252547
  this.logger.log(`Spawning function "${func.name}" on port ${port}`);
251921
- const importMapPath = join31(dirname23(this.wrapperPath), "import-map.json");
251922
- const process2 = spawn2("deno", ["run", "--allow-all", "--import-map", importMapPath, this.wrapperPath], {
252548
+ const importMapPath = join34(dirname24(this.wrapperPath), "import-map.json");
252549
+ const process2 = spawn3("deno", ["run", "--allow-all", "--import-map", importMapPath, this.wrapperPath], {
251923
252550
  env: {
251924
252551
  ...globalThis.process.env,
251925
252552
  FUNCTION_PATH: pathToFileURL(func.entryPath).href,
@@ -251992,7 +252619,7 @@ class FunctionManager extends BaseFunctionManager {
251992
252619
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
251993
252620
  import { isBuiltin } from "node:module";
251994
252621
  import { homedir as homedir3 } from "node:os";
251995
- import { join as join33 } from "node:path";
252622
+ import { join as join35 } from "node:path";
251996
252623
  import { pathToFileURL as pathToFileURL6 } from "node:url";
251997
252624
  var depsPromise;
251998
252625
  function loadDeps() {
@@ -252113,9 +252740,9 @@ export default {
252113
252740
  };
252114
252741
  `;
252115
252742
  function ensureBundlerConfig() {
252116
- const dir = join33(homedir3(), ".base44", "function-bundler");
252743
+ const dir = join35(homedir3(), ".base44", "function-bundler");
252117
252744
  mkdirSync2(dir, { recursive: true });
252118
- const configPath = join33(dir, "deno.json");
252745
+ const configPath = join35(dir, "deno.json");
252119
252746
  writeFileSync2(configPath, `${JSON.stringify({ nodeModulesDir: "auto" }, null, 2)}
252120
252747
  `);
252121
252748
  return configPath;
@@ -253496,11 +254123,11 @@ async function createEntityRoutes(db, logger, broadcast) {
253496
254123
  // src/cli/dev/dev-server/routes/integrations.ts
253497
254124
  var import_express5 = __toESM(require_express(), 1);
253498
254125
  var import_multer = __toESM(require_multer(), 1);
253499
- import { createHash as createHash2, randomUUID as randomUUID4 } from "node:crypto";
254126
+ import { createHash as createHash3, randomUUID as randomUUID6 } from "node:crypto";
253500
254127
  import fs28 from "node:fs";
253501
254128
  import path18 from "node:path";
253502
254129
  function createFileToken(fileUri) {
253503
- return createHash2("sha256").update(fileUri).digest("hex");
254130
+ return createHash3("sha256").update(fileUri).digest("hex");
253504
254131
  }
253505
254132
  function createIntegrationRoutes(mediaFilesDir, baseUrl, remoteProxy, logger) {
253506
254133
  const router = import_express5.Router({ mergeParams: true });
@@ -253513,14 +254140,14 @@ function createIntegrationRoutes(mediaFilesDir, baseUrl, remoteProxy, logger) {
253513
254140
  destination: mediaFilesDir,
253514
254141
  filename: (_req, file, cb) => {
253515
254142
  const ext = path18.extname(file.originalname);
253516
- cb(null, `${randomUUID4()}${ext}`);
254143
+ cb(null, `${randomUUID6()}${ext}`);
253517
254144
  }
253518
254145
  });
253519
254146
  const privateStorage = import_multer.default.diskStorage({
253520
254147
  destination: privateFilesDir,
253521
254148
  filename: (_req, file, cb) => {
253522
254149
  const ext = path18.extname(file.originalname);
253523
- cb(null, `${randomUUID4()}${ext}`);
254150
+ cb(null, `${randomUUID6()}${ext}`);
253524
254151
  }
253525
254152
  });
253526
254153
  const upload = import_multer.default({ storage, limits: { fileSize: MAX_FILE_SIZE } });
@@ -255382,8 +256009,8 @@ async function createDevServer(options) {
255382
256009
  broadcastEntityEvent(io, appId, entityName, event);
255383
256010
  };
255384
256011
  const base44ConfigWatcher = new WatchBase44({
255385
- functions: join36(dirname26(project.configPath), project.functionsDir),
255386
- entities: join36(dirname26(project.configPath), project.entitiesDir)
256012
+ functions: join38(dirname27(project.configPath), project.functionsDir),
256013
+ entities: join38(dirname27(project.configPath), project.entitiesDir)
255387
256014
  }, devLogger);
255388
256015
  base44ConfigWatcher.on("change", async (name) => {
255389
256016
  try {
@@ -255449,127 +256076,6 @@ async function createDevServer(options) {
255449
256076
  return { port, server, shutdown };
255450
256077
  }
255451
256078
 
255452
- // src/cli/dev/dev-server/serve-runner.ts
255453
- import { spawn as spawn3 } from "node:child_process";
255454
- import process23 from "node:process";
255455
-
255456
- class ServeRunner {
255457
- command;
255458
- cwd;
255459
- env;
255460
- logger;
255461
- child;
255462
- stopping = false;
255463
- stopPromise;
255464
- exitListeners = [];
255465
- constructor(options) {
255466
- this.command = options.command;
255467
- this.cwd = options.cwd;
255468
- this.env = options.env;
255469
- this.logger = options.logger;
255470
- }
255471
- start() {
255472
- if (this.child) {
255473
- return;
255474
- }
255475
- const stdin = process23.platform === "win32" ? "ignore" : "inherit";
255476
- const child = spawn3(this.command, {
255477
- cwd: this.cwd,
255478
- shell: true,
255479
- detached: process23.platform !== "win32",
255480
- env: { ...process23.env, ...this.env },
255481
- stdio: [stdin, "pipe", "pipe"],
255482
- windowsHide: true
255483
- });
255484
- this.child = child;
255485
- this.setupHandlers(child);
255486
- }
255487
- onExit(listener) {
255488
- this.exitListeners.push(listener);
255489
- }
255490
- async stop() {
255491
- if (this.stopPromise) {
255492
- return this.stopPromise;
255493
- }
255494
- this.stopPromise = this.stopChild();
255495
- return this.stopPromise;
255496
- }
255497
- async stopChild() {
255498
- const child = this.child;
255499
- if (!child || child.exitCode !== null) {
255500
- return;
255501
- }
255502
- this.stopping = true;
255503
- const exited = new Promise((resolve) => child.once("exit", () => resolve()));
255504
- if (process23.platform === "win32" && child.pid) {
255505
- const taskkill = spawn3("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
255506
- stdio: "ignore",
255507
- windowsHide: true
255508
- });
255509
- await new Promise((resolve) => {
255510
- taskkill.once("exit", () => resolve());
255511
- taskkill.once("error", () => resolve());
255512
- });
255513
- } else if (child.pid) {
255514
- try {
255515
- process23.kill(-child.pid, "SIGTERM");
255516
- } catch {
255517
- child.kill();
255518
- }
255519
- }
255520
- await exited;
255521
- }
255522
- setupHandlers(child) {
255523
- child.stdout?.on("data", (data) => this.emitLines(data, "log"));
255524
- child.stderr?.on("data", (data) => this.emitLines(data, "error"));
255525
- child.on("error", (error) => {
255526
- this.logger.error("Frontend dev server failed to start:", error);
255527
- this.notifyExit(null);
255528
- });
255529
- child.on("exit", (code) => {
255530
- if (this.stopping) {
255531
- return;
255532
- }
255533
- this.logger.error(`Frontend dev server exited with code ${code}`);
255534
- this.notifyExit(code);
255535
- });
255536
- }
255537
- notifyExit(code) {
255538
- for (const listener of this.exitListeners) {
255539
- listener(code);
255540
- }
255541
- }
255542
- emitLines(data, type) {
255543
- const lines = data.toString().trimEnd().split(`
255544
- `);
255545
- for (const line of lines) {
255546
- if (type === "error") {
255547
- this.logger.error(line);
255548
- } else {
255549
- this.logger.log(line);
255550
- }
255551
- }
255552
- }
255553
- }
255554
-
255555
- // src/cli/dev/serve-command-runner.ts
255556
- function createServeCommandRunner({
255557
- serveCommand,
255558
- projectRoot,
255559
- appId,
255560
- appBaseUrl
255561
- }) {
255562
- return new ServeRunner({
255563
- command: serveCommand,
255564
- cwd: projectRoot,
255565
- env: {
255566
- VITE_BASE44_APP_ID: appId,
255567
- VITE_BASE44_APP_BASE_URL: appBaseUrl
255568
- },
255569
- logger: createDevLogger("frontend", theme.colors.base44Orange)
255570
- });
255571
- }
255572
-
255573
256079
  // src/cli/commands/dev.ts
255574
256080
  function localServerUrl(port) {
255575
256081
  return `http://localhost:${port}`;
@@ -255595,11 +256101,6 @@ async function resolveConfiguredSite(app) {
255595
256101
  const serveCommand = project.site?.serveCommand;
255596
256102
  return serveCommand ? { serveCommand, projectRoot: project.root } : undefined;
255597
256103
  }
255598
- function stopRunnerOnProcessSignals(runner) {
255599
- const stop = () => void runner.stop();
255600
- process.on("SIGINT", stop);
255601
- process.on("SIGTERM", stop);
255602
- }
255603
256104
  function startServeCommand(runner, backend) {
255604
256105
  stopRunnerOnProcessSignals(runner);
255605
256106
  runner.onExit(() => {
@@ -255780,7 +256281,7 @@ Examples:
255780
256281
  }
255781
256282
 
255782
256283
  // src/cli/commands/project/eject.ts
255783
- import { resolve as resolve17 } from "node:path";
256284
+ import { resolve as resolve19 } from "node:path";
255784
256285
  var import_kebabCase2 = __toESM(require_kebabCase(), 1);
255785
256286
  async function eject(ctx, options, command) {
255786
256287
  const { log, runTask, isNonInteractive } = ctx;
@@ -255844,7 +256345,7 @@ async function eject(ctx, options, command) {
255844
256345
  Ne("Operation cancelled.");
255845
256346
  throw new CLIExitError(0);
255846
256347
  }
255847
- const resolvedPath = resolve17(selectedPath);
256348
+ const resolvedPath = resolve19(selectedPath);
255848
256349
  await runTask("Downloading your project's code...", async (updateMessage) => {
255849
256350
  await createProjectFilesForExistingProject({
255850
256351
  projectId,
@@ -255933,6 +256434,10 @@ function createProgram(context) {
255933
256434
  program.addCommand(getBranchesCommand());
255934
256435
  program.addCommand(getAuthCommand());
255935
256436
  program.addCommand(getSiteCommand());
256437
+ if (versionsApiEnabled()) {
256438
+ program.addCommand(getPublishCommand());
256439
+ program.addCommand(getVersionsCommand());
256440
+ }
255936
256441
  program.addCommand(getTypesCommand());
255937
256442
  program.addCommand(getExecCommand());
255938
256443
  program.addCommand(getDevCommand());
@@ -255945,7 +256450,7 @@ var import_detect_agent = __toESM(require_dist5(), 1);
255945
256450
  import { release, type } from "node:os";
255946
256451
 
255947
256452
  // ../../node_modules/posthog-node/dist/extensions/error-tracking/modifiers/module.node.mjs
255948
- import { dirname as dirname27, posix, sep as sep2 } from "path";
256453
+ import { dirname as dirname28, posix, sep as sep2 } from "path";
255949
256454
  function createModulerModifier() {
255950
256455
  const getModuleFromFileName = createGetModuleFromFilename();
255951
256456
  return async (frames) => {
@@ -255954,7 +256459,7 @@ function createModulerModifier() {
255954
256459
  return frames;
255955
256460
  };
255956
256461
  }
255957
- function createGetModuleFromFilename(basePath = process.argv[1] ? dirname27(process.argv[1]) : process.cwd(), isWindows = sep2 === "\\") {
256462
+ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname28(process.argv[1]) : process.cwd(), isWindows = sep2 === "\\") {
255958
256463
  const normalizedBase = isWindows ? normalizeWindowsPath2(basePath) : basePath;
255959
256464
  return (filename) => {
255960
256465
  if (!filename)
@@ -259943,9 +260448,9 @@ function addCommandInfoToErrorReporter(program, errorReporter) {
259943
260448
  });
259944
260449
  }
259945
260450
  // src/cli/index.ts
259946
- var __dirname4 = dirname28(fileURLToPath6(import.meta.url));
260451
+ var __dirname4 = dirname29(fileURLToPath6(import.meta.url));
259947
260452
  async function runCLI(options) {
259948
- ensureNpmAssets(join37(__dirname4, "../assets"));
260453
+ ensureNpmAssets(join39(__dirname4, "../assets"));
259949
260454
  const errorReporter = new ErrorReporter;
259950
260455
  errorReporter.registerProcessErrorHandlers();
259951
260456
  const jsonMode = process.argv.includes("--json");
@@ -259984,4 +260489,4 @@ export {
259984
260489
  runCLI
259985
260490
  };
259986
260491
 
259987
- //# debugId=752874D903B2231464756E2164756E21
260492
+ //# debugId=8A4CA9C1B29637E164756E2164756E21