@base44-preview/cli 0.1.16-pr.626.47e8953 → 0.1.16-pr.626.891bf00
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 +450 -447
- package/dist/cli/index.js.map +12 -12
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -246809,49 +246809,6 @@ async function deployAll(projectData, options) {
|
|
|
246809
246809
|
}
|
|
246810
246810
|
return { connectorResults };
|
|
246811
246811
|
}
|
|
246812
|
-
// src/core/project/target.ts
|
|
246813
|
-
import { dirname as dirname13, join as join19, resolve as resolve6 } from "node:path";
|
|
246814
|
-
var DEFAULT_BUILD_COMMAND = "npm run build";
|
|
246815
|
-
var DEFAULT_OUTPUT_DIRECTORY = "dist";
|
|
246816
|
-
async function resolveBuildTarget(projectRoot, overrides = {}) {
|
|
246817
|
-
const project = await readSettingsIfPresent(projectRoot);
|
|
246818
|
-
const root = project?.root ?? projectRoot ?? process.cwd();
|
|
246819
|
-
return {
|
|
246820
|
-
root,
|
|
246821
|
-
configDir: project ? dirname13(project.configPath) : join19(root, PROJECT_SUBDIR),
|
|
246822
|
-
buildCommand: project ? project.site?.buildCommand : DEFAULT_BUILD_COMMAND,
|
|
246823
|
-
outputDir: outputDirectory(project, root, overrides.outputDir),
|
|
246824
|
-
entitiesDir: project?.entitiesDir ?? "entities",
|
|
246825
|
-
agentsDir: project?.agentsDir ?? "agents"
|
|
246826
|
-
};
|
|
246827
|
-
}
|
|
246828
|
-
function outputDirectory(project, root, override) {
|
|
246829
|
-
const configured = override ?? (project ? project.site?.outputDirectory : DEFAULT_OUTPUT_DIRECTORY);
|
|
246830
|
-
return configured ? resolve6(root, configured) : null;
|
|
246831
|
-
}
|
|
246832
|
-
function requireOutputDir(target) {
|
|
246833
|
-
if (target.outputDir === null) {
|
|
246834
|
-
throw new ConfigNotFoundError("No site configuration found.", {
|
|
246835
|
-
hints: [
|
|
246836
|
-
{
|
|
246837
|
-
message: `Add 'site.outputDirectory' to your config.jsonc (e.g., "site": { "outputDirectory": "dist" })`
|
|
246838
|
-
},
|
|
246839
|
-
{ message: `Or pass --output-dir <dir>, relative to ${target.root}` }
|
|
246840
|
-
]
|
|
246841
|
-
});
|
|
246842
|
-
}
|
|
246843
|
-
return target.outputDir;
|
|
246844
|
-
}
|
|
246845
|
-
async function readSettingsIfPresent(projectRoot) {
|
|
246846
|
-
try {
|
|
246847
|
-
return await readProjectSettings(projectRoot);
|
|
246848
|
-
} catch (error) {
|
|
246849
|
-
if (error instanceof ConfigNotFoundError) {
|
|
246850
|
-
return null;
|
|
246851
|
-
}
|
|
246852
|
-
throw error;
|
|
246853
|
-
}
|
|
246854
|
-
}
|
|
246855
246812
|
// src/core/clients/base44-client.ts
|
|
246856
246813
|
var retriedRequests = new WeakSet;
|
|
246857
246814
|
async function captureRequestBody(request, options) {
|
|
@@ -247695,7 +247652,7 @@ function getActorsCommand() {
|
|
|
247695
247652
|
}
|
|
247696
247653
|
|
|
247697
247654
|
// src/cli/commands/agent-skills/pull.ts
|
|
247698
|
-
import { dirname as
|
|
247655
|
+
import { dirname as dirname13, join as join19 } from "node:path";
|
|
247699
247656
|
// src/core/utils/dependencies.ts
|
|
247700
247657
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
247701
247658
|
function verifyDenoInstalled(context) {
|
|
@@ -247784,7 +247741,7 @@ async function pullAction({
|
|
|
247784
247741
|
runTask
|
|
247785
247742
|
}) {
|
|
247786
247743
|
const { project } = await readProjectConfig();
|
|
247787
|
-
const dir =
|
|
247744
|
+
const dir = join19(dirname13(project.configPath), project.agentSkillsDir);
|
|
247788
247745
|
const remote = await runTask("Fetching agent skills from Base44", () => fetchAgentSkills(), {
|
|
247789
247746
|
successMessage: "Agent skills fetched successfully",
|
|
247790
247747
|
errorMessage: "Failed to fetch agent skills"
|
|
@@ -247840,14 +247797,14 @@ function getAgentSkillsCommand() {
|
|
|
247840
247797
|
}
|
|
247841
247798
|
|
|
247842
247799
|
// src/cli/commands/agents/pull.ts
|
|
247843
|
-
import { dirname as
|
|
247800
|
+
import { dirname as dirname14, join as join20 } from "node:path";
|
|
247844
247801
|
async function pullAgentsAction({
|
|
247845
247802
|
log,
|
|
247846
247803
|
runTask
|
|
247847
247804
|
}) {
|
|
247848
247805
|
const { project } = await readProjectConfig();
|
|
247849
|
-
const configDir =
|
|
247850
|
-
const agentsDir =
|
|
247806
|
+
const configDir = dirname14(project.configPath);
|
|
247807
|
+
const agentsDir = join20(configDir, project.agentsDir);
|
|
247851
247808
|
const remoteAgents = await runTask("Fetching agents from Base44", async () => {
|
|
247852
247809
|
return await fetchAgents();
|
|
247853
247810
|
}, {
|
|
@@ -247917,12 +247874,12 @@ function getAgentsCommand() {
|
|
|
247917
247874
|
}
|
|
247918
247875
|
|
|
247919
247876
|
// src/cli/commands/auth/password-login.ts
|
|
247920
|
-
import { dirname as
|
|
247877
|
+
import { dirname as dirname15, join as join21 } from "node:path";
|
|
247921
247878
|
async function passwordLoginAction({ log, runTask }, action) {
|
|
247922
247879
|
const shouldEnable = action === "enable";
|
|
247923
247880
|
const { project } = await readProjectConfig();
|
|
247924
|
-
const configDir =
|
|
247925
|
-
const authDir =
|
|
247881
|
+
const configDir = dirname15(project.configPath);
|
|
247882
|
+
const authDir = join21(configDir, project.authDir);
|
|
247926
247883
|
const updated = await runTask("Updating local auth config", async () => {
|
|
247927
247884
|
const current = await readAuthConfig(authDir) ?? DEFAULT_AUTH_CONFIG;
|
|
247928
247885
|
const merged = { ...current, enableUsernamePassword: shouldEnable };
|
|
@@ -247942,14 +247899,14 @@ function getPasswordLoginCommand() {
|
|
|
247942
247899
|
}
|
|
247943
247900
|
|
|
247944
247901
|
// src/cli/commands/auth/pull.ts
|
|
247945
|
-
import { dirname as
|
|
247902
|
+
import { dirname as dirname16, join as join22 } from "node:path";
|
|
247946
247903
|
async function pullAuthAction({
|
|
247947
247904
|
log,
|
|
247948
247905
|
runTask
|
|
247949
247906
|
}) {
|
|
247950
247907
|
const { project } = await readProjectConfig();
|
|
247951
|
-
const configDir =
|
|
247952
|
-
const authDir =
|
|
247908
|
+
const configDir = dirname16(project.configPath);
|
|
247909
|
+
const authDir = join22(configDir, project.authDir);
|
|
247953
247910
|
const remoteConfig = await runTask("Fetching auth config from Base44", async () => {
|
|
247954
247911
|
return await pullAuthConfig();
|
|
247955
247912
|
}, {
|
|
@@ -248013,7 +247970,7 @@ function getAuthPushCommand() {
|
|
|
248013
247970
|
}
|
|
248014
247971
|
|
|
248015
247972
|
// src/cli/commands/auth/social-login.ts
|
|
248016
|
-
import { dirname as
|
|
247973
|
+
import { dirname as dirname17, join as join23, resolve as resolve6 } from "node:path";
|
|
248017
247974
|
var PROVIDER_LABELS = {
|
|
248018
247975
|
google: "Google",
|
|
248019
247976
|
microsoft: "Microsoft",
|
|
@@ -248053,7 +248010,7 @@ async function socialLoginAction({ log, isNonInteractive, runTask }, provider, a
|
|
|
248053
248010
|
let clientSecret;
|
|
248054
248011
|
if (useCustomOAuth && oauth && oauthCli && hasSecretOptions(options)) {
|
|
248055
248012
|
if (options.envFile) {
|
|
248056
|
-
const secrets = await parseEnvFile(
|
|
248013
|
+
const secrets = await parseEnvFile(resolve6(options.envFile));
|
|
248057
248014
|
const value = secrets[oauthCli.envVar];
|
|
248058
248015
|
if (!value) {
|
|
248059
248016
|
throw new InvalidInputError(`Key "${oauthCli.envVar}" not found in ${options.envFile}.`);
|
|
@@ -248083,8 +248040,8 @@ async function socialLoginAction({ log, isNonInteractive, runTask }, provider, a
|
|
|
248083
248040
|
}
|
|
248084
248041
|
}
|
|
248085
248042
|
const { project } = await readProjectConfig();
|
|
248086
|
-
const configDir =
|
|
248087
|
-
const authDir =
|
|
248043
|
+
const configDir = dirname17(project.configPath);
|
|
248044
|
+
const authDir = join23(configDir, project.authDir);
|
|
248088
248045
|
const { config: updated } = await runTask("Updating local auth config", async () => updateSocialLoginConfig(authDir, provider, shouldEnable, useCustomOAuth && options.clientId ? { clientId: options.clientId } : undefined));
|
|
248089
248046
|
if (clientSecret) {
|
|
248090
248047
|
await runTask("Saving client secret", async () => pushCustomOAuthSecret(provider, clientSecret));
|
|
@@ -248109,7 +248066,7 @@ function getSocialLoginCommand() {
|
|
|
248109
248066
|
}
|
|
248110
248067
|
|
|
248111
248068
|
// src/cli/commands/auth/sso.ts
|
|
248112
|
-
import { dirname as
|
|
248069
|
+
import { dirname as dirname18, join as join24, resolve as resolve7 } from "node:path";
|
|
248113
248070
|
var SSOConfigFileSchema = object({
|
|
248114
248071
|
provider: _enum(Object.values(KNOWN_SSO_PROVIDERS)),
|
|
248115
248072
|
clientId: string2(),
|
|
@@ -248125,7 +248082,7 @@ var SSOConfigFileSchema = object({
|
|
|
248125
248082
|
ssoName: string2().optional()
|
|
248126
248083
|
});
|
|
248127
248084
|
async function loadSSOConfigFile(filePath) {
|
|
248128
|
-
const resolved =
|
|
248085
|
+
const resolved = resolve7(filePath);
|
|
248129
248086
|
const raw = await readJsonFile(resolved);
|
|
248130
248087
|
const result = SSOConfigFileSchema.safeParse(raw);
|
|
248131
248088
|
if (!result.success) {
|
|
@@ -248213,7 +248170,7 @@ async function ssoEnableAction({ isNonInteractive, runTask }, options) {
|
|
|
248213
248170
|
}
|
|
248214
248171
|
let clientSecret;
|
|
248215
248172
|
if (merged.envFile && !merged.clientSecret) {
|
|
248216
|
-
const secrets = await parseEnvFile(
|
|
248173
|
+
const secrets = await parseEnvFile(resolve7(merged.envFile));
|
|
248217
248174
|
const value = secrets.sso_client_secret;
|
|
248218
248175
|
if (!value) {
|
|
248219
248176
|
throw new InvalidInputError(`Key "sso_client_secret" not found in ${merged.envFile}.`);
|
|
@@ -248272,8 +248229,8 @@ async function ssoEnableAction({ isNonInteractive, runTask }, options) {
|
|
|
248272
248229
|
throw error;
|
|
248273
248230
|
}
|
|
248274
248231
|
const { project } = await readProjectConfig();
|
|
248275
|
-
const configDir =
|
|
248276
|
-
const authDir =
|
|
248232
|
+
const configDir = dirname18(project.configPath);
|
|
248233
|
+
const authDir = join24(configDir, project.authDir);
|
|
248277
248234
|
await runTask("Updating local auth config", async () => updateSSOConfig(authDir, provider, true));
|
|
248278
248235
|
await runTask("Saving SSO credentials", async () => pushSSOSecrets(secrets));
|
|
248279
248236
|
return {
|
|
@@ -248288,8 +248245,8 @@ async function ssoDisableAction({ log, runTask }, options) {
|
|
|
248288
248245
|
throw new InvalidInputError("Configuration options cannot be used with disable. To disable SSO: base44 auth sso disable");
|
|
248289
248246
|
}
|
|
248290
248247
|
const { project } = await readProjectConfig();
|
|
248291
|
-
const configDir =
|
|
248292
|
-
const authDir =
|
|
248248
|
+
const configDir = dirname18(project.configPath);
|
|
248249
|
+
const authDir = join24(configDir, project.authDir);
|
|
248293
248250
|
const updated = await runTask("Updating local auth config", async () => updateSSOConfig(authDir, null, false));
|
|
248294
248251
|
await runTask("Removing SSO credentials", async () => deleteSSOSecrets());
|
|
248295
248252
|
if (!hasAnyLoginMethod(updated)) {
|
|
@@ -249171,13 +249128,13 @@ function getConnectorsListAvailableCommand() {
|
|
|
249171
249128
|
}
|
|
249172
249129
|
|
|
249173
249130
|
// src/cli/commands/connectors/pull.ts
|
|
249174
|
-
import { dirname as
|
|
249131
|
+
import { dirname as dirname19, join as join25, resolve as resolve8 } from "node:path";
|
|
249175
249132
|
async function resolveConnectorsDir(options) {
|
|
249176
249133
|
if (!getAppContext().projectRoot) {
|
|
249177
|
-
return
|
|
249134
|
+
return resolve8(options.dir ?? "connectors");
|
|
249178
249135
|
}
|
|
249179
249136
|
const { project } = await readProjectConfig();
|
|
249180
|
-
return
|
|
249137
|
+
return join25(dirname19(project.configPath), project.connectorsDir);
|
|
249181
249138
|
}
|
|
249182
249139
|
async function pullConnectorsAction({ log, runTask, jsonMode }, options) {
|
|
249183
249140
|
const connectorsDir = await resolveConnectorsDir(options);
|
|
@@ -249218,10 +249175,10 @@ function getConnectorsPullCommand() {
|
|
|
249218
249175
|
}
|
|
249219
249176
|
|
|
249220
249177
|
// src/cli/commands/connectors/push.ts
|
|
249221
|
-
import { resolve as
|
|
249178
|
+
import { resolve as resolve9 } from "node:path";
|
|
249222
249179
|
async function readConnectorsToPush(options) {
|
|
249223
249180
|
if (!getAppContext().projectRoot) {
|
|
249224
|
-
return readAllConnectors(
|
|
249181
|
+
return readAllConnectors(resolve9(options.dir ?? "connectors"));
|
|
249225
249182
|
}
|
|
249226
249183
|
const { connectors } = await readProjectConfig();
|
|
249227
249184
|
return connectors;
|
|
@@ -249564,11 +249521,11 @@ function getListCommand() {
|
|
|
249564
249521
|
}
|
|
249565
249522
|
|
|
249566
249523
|
// src/cli/commands/functions/pull.ts
|
|
249567
|
-
import { dirname as
|
|
249524
|
+
import { dirname as dirname20, join as join26 } from "node:path";
|
|
249568
249525
|
async function pullFunctionsAction({ log, runTask }, name) {
|
|
249569
249526
|
const { project, functions } = await readProjectConfig();
|
|
249570
|
-
const configDir =
|
|
249571
|
-
const functionsDir =
|
|
249527
|
+
const configDir = dirname20(project.configPath);
|
|
249528
|
+
const functionsDir = join26(configDir, project.functionsDir);
|
|
249572
249529
|
const pluginFunctionNames = new Set(functions.filter((fn) => fn.source.type === "plugin").map((fn) => fn.name));
|
|
249573
249530
|
const remoteFunctions = await runTask("Fetching functions from Base44", async () => {
|
|
249574
249531
|
const { functions } = await listDeployedFunctions();
|
|
@@ -249669,129 +249626,427 @@ async function maybeAskToBuild(isNonInteractive, buildCommand) {
|
|
|
249669
249626
|
return !Ct(answer) && answer;
|
|
249670
249627
|
}
|
|
249671
249628
|
|
|
249672
|
-
// src/
|
|
249673
|
-
|
|
249674
|
-
|
|
249675
|
-
|
|
249676
|
-
|
|
249677
|
-
|
|
249678
|
-
|
|
249679
|
-
|
|
249680
|
-
|
|
249681
|
-
|
|
249682
|
-
|
|
249683
|
-
|
|
249629
|
+
// src/core/version/schema.ts
|
|
249630
|
+
var DeclareVersionResponseSchema = object({
|
|
249631
|
+
session_id: string2(),
|
|
249632
|
+
uploads: array(object({
|
|
249633
|
+
path: string2(),
|
|
249634
|
+
url: string2(),
|
|
249635
|
+
content_type: string2(),
|
|
249636
|
+
content_length: number2(),
|
|
249637
|
+
checksum_sha256: string2()
|
|
249638
|
+
}))
|
|
249639
|
+
}).transform((data) => ({
|
|
249640
|
+
sessionId: data.session_id,
|
|
249641
|
+
uploads: data.uploads.map((upload) => ({
|
|
249642
|
+
path: upload.path,
|
|
249643
|
+
url: upload.url,
|
|
249644
|
+
contentType: upload.content_type,
|
|
249645
|
+
contentLength: upload.content_length,
|
|
249646
|
+
checksumSha256: upload.checksum_sha256
|
|
249647
|
+
}))
|
|
249648
|
+
}));
|
|
249649
|
+
var CreateVersionResponseSchema = object({
|
|
249650
|
+
version_id: string2(),
|
|
249651
|
+
manifest_hash: string2()
|
|
249652
|
+
}).transform((data) => ({
|
|
249653
|
+
versionId: data.version_id,
|
|
249654
|
+
manifestHash: data.manifest_hash
|
|
249655
|
+
}));
|
|
249656
|
+
var EnvironmentResponseSchema = object({
|
|
249657
|
+
name: string2(),
|
|
249658
|
+
version_id: string2(),
|
|
249659
|
+
manifest_hash: string2(),
|
|
249660
|
+
deployment_id: string2()
|
|
249661
|
+
}).transform((data) => ({
|
|
249662
|
+
name: data.name,
|
|
249663
|
+
versionId: data.version_id,
|
|
249664
|
+
manifestHash: data.manifest_hash,
|
|
249665
|
+
deploymentId: data.deployment_id
|
|
249666
|
+
}));
|
|
249667
|
+
|
|
249668
|
+
// src/core/version/api.ts
|
|
249669
|
+
var DEFAULT_VERSION_UPLOAD_CONCURRENCY = 8;
|
|
249670
|
+
var MAX_VERSION_UPLOAD_CONCURRENCY = 16;
|
|
249671
|
+
function declaredFile({ path, size, digest }) {
|
|
249672
|
+
return { path, size, digest };
|
|
249684
249673
|
}
|
|
249685
|
-
function
|
|
249686
|
-
return
|
|
249674
|
+
function declaredModule(module) {
|
|
249675
|
+
return { ...declaredFile(module), type: module.type };
|
|
249687
249676
|
}
|
|
249688
|
-
|
|
249689
|
-
|
|
249690
|
-
|
|
249691
|
-
|
|
249692
|
-
|
|
249693
|
-
|
|
249694
|
-
|
|
249695
|
-
|
|
249696
|
-
|
|
249697
|
-
const templates = await listTemplates();
|
|
249698
|
-
const template = templates.find((t) => t.id === templateId);
|
|
249699
|
-
if (!template) {
|
|
249700
|
-
const validIds = templates.map((t) => t.id).join(", ");
|
|
249701
|
-
throw new InvalidInputError(`Template "${templateId}" not found.`, {
|
|
249702
|
-
hints: [{ message: `Use one of: ${validIds}` }]
|
|
249703
|
-
});
|
|
249704
|
-
}
|
|
249705
|
-
return template;
|
|
249677
|
+
function declaredAssetsConfig(config) {
|
|
249678
|
+
const stated = {
|
|
249679
|
+
html_handling: config?.htmlHandling ?? null,
|
|
249680
|
+
not_found_handling: config?.notFoundHandling ?? null,
|
|
249681
|
+
run_worker_first: config?.runWorkerFirst ?? null,
|
|
249682
|
+
headers: config?.headers ?? null,
|
|
249683
|
+
redirects: config?.redirects ?? null
|
|
249684
|
+
};
|
|
249685
|
+
return Object.values(stated).every((v) => v === null) ? null : stated;
|
|
249706
249686
|
}
|
|
249707
|
-
async function
|
|
249708
|
-
|
|
249709
|
-
|
|
249710
|
-
|
|
249711
|
-
|
|
249712
|
-
skills,
|
|
249713
|
-
isInteractive
|
|
249714
|
-
}, { runTask }) {
|
|
249715
|
-
const { project, entities } = await readProjectConfig(resolvedPath);
|
|
249716
|
-
let finalAppUrl;
|
|
249717
|
-
if (entities.length > 0) {
|
|
249718
|
-
let shouldPushEntities;
|
|
249719
|
-
if (isInteractive) {
|
|
249720
|
-
const result = await Re({
|
|
249721
|
-
message: "Set up the backend data now? (This pushes the data models used by the template to Base44)"
|
|
249722
|
-
});
|
|
249723
|
-
shouldPushEntities = !Ct(result) && result;
|
|
249724
|
-
} else {
|
|
249725
|
-
shouldPushEntities = !!deploy;
|
|
249726
|
-
}
|
|
249727
|
-
if (shouldPushEntities) {
|
|
249728
|
-
await runTask(`Pushing ${entities.length} data models to Base44...`, async () => {
|
|
249729
|
-
await pushEntities(entities);
|
|
249730
|
-
}, {
|
|
249731
|
-
successMessage: theme.colors.base44Orange("Data models pushed successfully"),
|
|
249732
|
-
errorMessage: "Failed to push data models"
|
|
249733
|
-
});
|
|
249734
|
-
}
|
|
249735
|
-
}
|
|
249736
|
-
if (project.site) {
|
|
249737
|
-
const { installCommand, buildCommand, outputDirectory } = project.site;
|
|
249738
|
-
let shouldDeploy;
|
|
249739
|
-
if (isInteractive) {
|
|
249740
|
-
const result = await Re({
|
|
249741
|
-
message: "Would you like to deploy the site now? (Hosted on Base44)"
|
|
249742
|
-
});
|
|
249743
|
-
shouldDeploy = !Ct(result) && result;
|
|
249744
|
-
} else {
|
|
249745
|
-
shouldDeploy = !!deploy;
|
|
249746
|
-
}
|
|
249747
|
-
if (shouldDeploy && installCommand && buildCommand && outputDirectory) {
|
|
249748
|
-
const { appUrl } = await runTask("Installing dependencies...", async (updateMessage) => {
|
|
249749
|
-
await execa({ cwd: resolvedPath, shell: true })`${installCommand}`;
|
|
249750
|
-
updateMessage("Building project...");
|
|
249751
|
-
await execa({
|
|
249752
|
-
cwd: resolvedPath,
|
|
249753
|
-
shell: true,
|
|
249754
|
-
env: { VITE_BASE44_APP_ID: projectId }
|
|
249755
|
-
})`${buildCommand}`;
|
|
249756
|
-
updateMessage("Deploying site...");
|
|
249757
|
-
return await deploySite(join28(resolvedPath, outputDirectory));
|
|
249758
|
-
}, {
|
|
249759
|
-
successMessage: theme.colors.base44Orange("Site deployed successfully"),
|
|
249760
|
-
errorMessage: "Failed to deploy site"
|
|
249761
|
-
});
|
|
249762
|
-
finalAppUrl = appUrl;
|
|
249763
|
-
}
|
|
249687
|
+
async function post(path, json, doing) {
|
|
249688
|
+
try {
|
|
249689
|
+
return await getAppClient().post(path, { json, timeout: 180000 });
|
|
249690
|
+
} catch (error) {
|
|
249691
|
+
throw await ApiError.fromHttpError(error, doing);
|
|
249764
249692
|
}
|
|
249765
|
-
|
|
249766
|
-
|
|
249767
|
-
|
|
249768
|
-
|
|
249769
|
-
|
|
249770
|
-
|
|
249771
|
-
|
|
249772
|
-
|
|
249773
|
-
|
|
249774
|
-
|
|
249775
|
-
|
|
249776
|
-
|
|
249693
|
+
}
|
|
249694
|
+
var KEYED_RETRY = {
|
|
249695
|
+
limit: 3,
|
|
249696
|
+
methods: ["patch"],
|
|
249697
|
+
statusCodes: [408, 500, 502, 503, 504],
|
|
249698
|
+
retryOnTimeout: true
|
|
249699
|
+
};
|
|
249700
|
+
async function patch(path, json, doing, retry) {
|
|
249701
|
+
try {
|
|
249702
|
+
return await getAppClient().patch(path, {
|
|
249703
|
+
json,
|
|
249704
|
+
timeout: 180000,
|
|
249705
|
+
...retry ? { retry } : {}
|
|
249706
|
+
});
|
|
249707
|
+
} catch (error) {
|
|
249708
|
+
throw await ApiError.fromHttpError(error, doing);
|
|
249777
249709
|
}
|
|
249778
|
-
return {
|
|
249779
|
-
name,
|
|
249780
|
-
dashboardUrl: getDashboardUrl(projectId),
|
|
249781
|
-
appUrl: finalAppUrl
|
|
249782
|
-
};
|
|
249783
249710
|
}
|
|
249784
|
-
function
|
|
249785
|
-
|
|
249786
|
-
|
|
249787
|
-
|
|
249788
|
-
log.message(`${theme.styles.header("Site")}: ${theme.colors.links(appUrl)}`);
|
|
249711
|
+
function parse10(schema, body, what) {
|
|
249712
|
+
const result = schema.safeParse(body);
|
|
249713
|
+
if (!result.success) {
|
|
249714
|
+
throw new SchemaValidationError(`Invalid ${what} response from server`, result.error);
|
|
249789
249715
|
}
|
|
249716
|
+
return result.data;
|
|
249790
249717
|
}
|
|
249791
|
-
|
|
249792
|
-
|
|
249793
|
-
|
|
249794
|
-
|
|
249718
|
+
async function createVersion(artifacts, options = {}) {
|
|
249719
|
+
const declared = parse10(DeclareVersionResponseSchema, await (await post("versions", {
|
|
249720
|
+
static_bundle: artifacts.files.map(declaredFile),
|
|
249721
|
+
...artifacts.siteWorker ? {
|
|
249722
|
+
site_worker: {
|
|
249723
|
+
main: artifacts.siteWorker.main,
|
|
249724
|
+
modules: artifacts.siteWorker.modules.map(declaredModule),
|
|
249725
|
+
assets: artifacts.siteWorker.assets.map(declaredFile),
|
|
249726
|
+
compatibility_date: artifacts.siteWorker.compatibilityDate,
|
|
249727
|
+
compatibility_flags: artifacts.siteWorker.compatibilityFlags,
|
|
249728
|
+
assets_config: declaredAssetsConfig(artifacts.siteWorker.assetsConfig)
|
|
249729
|
+
}
|
|
249730
|
+
} : {},
|
|
249731
|
+
entities: artifacts.entities,
|
|
249732
|
+
agents: artifacts.agents,
|
|
249733
|
+
source_commit: options.sourceCommit
|
|
249734
|
+
}, "declaring a version")).json(), "declare");
|
|
249735
|
+
const declaredFiles = [
|
|
249736
|
+
...artifacts.files,
|
|
249737
|
+
...artifacts.siteWorker?.modules ?? [],
|
|
249738
|
+
...artifacts.siteWorker?.assets ?? []
|
|
249739
|
+
];
|
|
249740
|
+
options.progress?.onDeclared?.({ fileCount: declaredFiles.length });
|
|
249741
|
+
if (declared.uploads.length !== declaredFiles.length) {
|
|
249742
|
+
throw new InternalError(`Declared ${declaredFiles.length} files but the server signed ${declared.uploads.length} upload URLs.`);
|
|
249743
|
+
}
|
|
249744
|
+
const drifted = declared.uploads.findIndex((upload, index) => upload.path !== declaredFiles[index].path);
|
|
249745
|
+
if (drifted !== -1) {
|
|
249746
|
+
throw new InternalError(`Upload ${drifted} is signed for ${declared.uploads[drifted].path}, but that slot declared ${declaredFiles[drifted].path}.`);
|
|
249747
|
+
}
|
|
249748
|
+
let uploadedFiles = 0;
|
|
249749
|
+
await pMap(declared.uploads, async (upload, index) => {
|
|
249750
|
+
await putPresigned(upload, declaredFiles[index].absolutePath);
|
|
249751
|
+
uploadedFiles++;
|
|
249752
|
+
options.progress?.onUpload?.({
|
|
249753
|
+
uploadedFiles,
|
|
249754
|
+
totalFiles: declared.uploads.length
|
|
249755
|
+
});
|
|
249756
|
+
}, { concurrency: options.concurrency ?? DEFAULT_VERSION_UPLOAD_CONCURRENCY });
|
|
249757
|
+
return parse10(CreateVersionResponseSchema, await (await post(`versions/${encodeURIComponent(declared.sessionId)}/finalize`, {}, "creating a version")).json(), "create version");
|
|
249758
|
+
}
|
|
249759
|
+
async function setEnvironmentVersion(environment, versionId, options = {}) {
|
|
249760
|
+
return parse10(EnvironmentResponseSchema, await (await patch(`environments/${encodeURIComponent(environment)}`, {
|
|
249761
|
+
version_id: versionId,
|
|
249762
|
+
...options.idempotencyKey ? { idempotency_key: options.idempotencyKey } : {}
|
|
249763
|
+
}, "setting the environment's version", options.idempotencyKey ? KEYED_RETRY : undefined)).json(), "environment");
|
|
249764
|
+
}
|
|
249765
|
+
// src/core/version/artifacts.ts
|
|
249766
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
249767
|
+
import { join as join28, resolve as resolve11 } from "node:path";
|
|
249768
|
+
|
|
249769
|
+
// src/core/version/project.ts
|
|
249770
|
+
import { dirname as dirname21, join as join27, resolve as resolve10 } from "node:path";
|
|
249771
|
+
var DEFAULT_BUILD_COMMAND = "npm run build";
|
|
249772
|
+
var DEFAULT_OUTPUT_DIRECTORY = "dist";
|
|
249773
|
+
async function resolvePublishTarget(projectRoot, overrides = {}) {
|
|
249774
|
+
const project = await readSettingsIfPresent(projectRoot);
|
|
249775
|
+
const root = project?.root ?? projectRoot ?? process.cwd();
|
|
249776
|
+
return {
|
|
249777
|
+
root,
|
|
249778
|
+
configDir: project ? dirname21(project.configPath) : join27(root, PROJECT_SUBDIR),
|
|
249779
|
+
buildCommand: project ? project.site?.buildCommand : DEFAULT_BUILD_COMMAND,
|
|
249780
|
+
outputDir: outputDirectory(project, root, overrides.outputDir),
|
|
249781
|
+
entitiesDir: project?.entitiesDir ?? "entities",
|
|
249782
|
+
agentsDir: project?.agentsDir ?? "agents"
|
|
249783
|
+
};
|
|
249784
|
+
}
|
|
249785
|
+
function outputDirectory(project, root, override) {
|
|
249786
|
+
const configured = override ?? (project ? project.site?.outputDirectory : DEFAULT_OUTPUT_DIRECTORY);
|
|
249787
|
+
return configured ? resolve10(root, configured) : null;
|
|
249788
|
+
}
|
|
249789
|
+
function requireOutputDir(target) {
|
|
249790
|
+
if (target.outputDir === null) {
|
|
249791
|
+
throw new ConfigNotFoundError("No site configuration found.", {
|
|
249792
|
+
hints: [
|
|
249793
|
+
{
|
|
249794
|
+
message: `Add 'site.outputDirectory' to your config.jsonc (e.g., "site": { "outputDirectory": "dist" })`
|
|
249795
|
+
},
|
|
249796
|
+
{ message: `Or pass --output-dir <dir>, relative to ${target.root}` }
|
|
249797
|
+
]
|
|
249798
|
+
});
|
|
249799
|
+
}
|
|
249800
|
+
return target.outputDir;
|
|
249801
|
+
}
|
|
249802
|
+
async function readSettingsIfPresent(projectRoot) {
|
|
249803
|
+
try {
|
|
249804
|
+
return await readProjectSettings(projectRoot);
|
|
249805
|
+
} catch (error) {
|
|
249806
|
+
if (error instanceof ConfigNotFoundError) {
|
|
249807
|
+
return null;
|
|
249808
|
+
}
|
|
249809
|
+
throw error;
|
|
249810
|
+
}
|
|
249811
|
+
}
|
|
249812
|
+
|
|
249813
|
+
// src/core/version/artifacts.ts
|
|
249814
|
+
var MAX_FILE_COUNT = 50000;
|
|
249815
|
+
var HASH_CONCURRENCY = 32;
|
|
249816
|
+
var ENTRY2 = "index.html";
|
|
249817
|
+
async function digestFile(absolutePath) {
|
|
249818
|
+
const hash = await hashFileInto(createHash2("sha256"), absolutePath);
|
|
249819
|
+
return `sha256:${hash.digest("hex")}`;
|
|
249820
|
+
}
|
|
249821
|
+
async function collectBuildOutput(outputDir, options = {}) {
|
|
249822
|
+
const found = await describeBuildOutput(outputDir);
|
|
249823
|
+
if (found.length > MAX_FILE_COUNT) {
|
|
249824
|
+
throw new InvalidInputError(`Too many files: found ${found.length}, the limit is ${MAX_FILE_COUNT}.`);
|
|
249825
|
+
}
|
|
249826
|
+
if (options.entryFile) {
|
|
249827
|
+
if (found.length === 0) {
|
|
249828
|
+
throw new InvalidInputError(`No files found in ${outputDir}. Build the site before creating a version.`, {
|
|
249829
|
+
hints: [
|
|
249830
|
+
{ message: "Run 'base44 build' first", command: "base44 build" }
|
|
249831
|
+
]
|
|
249832
|
+
});
|
|
249833
|
+
}
|
|
249834
|
+
if (!found.some((f) => f.path === options.entryFile)) {
|
|
249835
|
+
throw new InvalidInputError(`${outputDir} has no ${options.entryFile}, so nothing could enter the site.`);
|
|
249836
|
+
}
|
|
249837
|
+
}
|
|
249838
|
+
return await pMap(found, async (file) => ({ ...file, digest: await digestFile(file.absolutePath) }), { concurrency: HASH_CONCURRENCY });
|
|
249839
|
+
}
|
|
249840
|
+
async function collectSiteWorker(projectRoot) {
|
|
249841
|
+
const built = await resolveFullStackBuild(projectRoot);
|
|
249842
|
+
if (!built) {
|
|
249843
|
+
return null;
|
|
249844
|
+
}
|
|
249845
|
+
const { config, modules, assetsDir } = built;
|
|
249846
|
+
const entry = resolve11(config.configDir, config.main);
|
|
249847
|
+
const main = modules.find((m) => m.absolutePath === entry)?.name;
|
|
249848
|
+
if (!main) {
|
|
249849
|
+
throw new InvalidInputError(`The Worker's entry module ${config.main} is not among the ${modules.length} modules collected from ${config.configDir}.`);
|
|
249850
|
+
}
|
|
249851
|
+
return {
|
|
249852
|
+
main,
|
|
249853
|
+
modules: await pMap(modules, async ({ name, absolutePath, size, type }) => ({
|
|
249854
|
+
path: name,
|
|
249855
|
+
absolutePath,
|
|
249856
|
+
size,
|
|
249857
|
+
digest: await digestFile(absolutePath),
|
|
249858
|
+
type
|
|
249859
|
+
}), { concurrency: HASH_CONCURRENCY }),
|
|
249860
|
+
assets: assetsDir ? await collectBuildOutput(assetsDir) : [],
|
|
249861
|
+
compatibilityDate: config.compatibilityDate,
|
|
249862
|
+
compatibilityFlags: config.compatibilityFlags,
|
|
249863
|
+
assetsConfig: config.assetsConfig
|
|
249864
|
+
};
|
|
249865
|
+
}
|
|
249866
|
+
async function readRawResources(dir) {
|
|
249867
|
+
if (!await pathExists(dir)) {
|
|
249868
|
+
return {};
|
|
249869
|
+
}
|
|
249870
|
+
const files = await globby(`**/*.${CONFIG_FILE_EXTENSION_GLOB}`, {
|
|
249871
|
+
cwd: dir,
|
|
249872
|
+
onlyFiles: true,
|
|
249873
|
+
followSymbolicLinks: false
|
|
249874
|
+
});
|
|
249875
|
+
const payloads = {};
|
|
249876
|
+
for (const relativePath of files.sort()) {
|
|
249877
|
+
const name = relativePath.replace(/\.jsonc?$/, "");
|
|
249878
|
+
payloads[name] = await readJsonFile(join28(dir, ...relativePath.split("/")));
|
|
249879
|
+
}
|
|
249880
|
+
return payloads;
|
|
249881
|
+
}
|
|
249882
|
+
async function collectResources(configDir, dirs) {
|
|
249883
|
+
const [entities, agents] = await Promise.all([
|
|
249884
|
+
readRawResources(join28(configDir, dirs.entitiesDir)),
|
|
249885
|
+
readRawResources(join28(configDir, dirs.agentsDir))
|
|
249886
|
+
]);
|
|
249887
|
+
return { entities, agents };
|
|
249888
|
+
}
|
|
249889
|
+
async function collectArtifacts(target) {
|
|
249890
|
+
const siteWorker = await collectSiteWorker(target.root);
|
|
249891
|
+
return {
|
|
249892
|
+
files: siteWorker ? [] : await collectBuildOutput(requireOutputDir(target), {
|
|
249893
|
+
entryFile: ENTRY2
|
|
249894
|
+
}),
|
|
249895
|
+
...siteWorker ? { siteWorker } : {},
|
|
249896
|
+
...await collectResources(target.configDir, target)
|
|
249897
|
+
};
|
|
249898
|
+
}
|
|
249899
|
+
// src/core/version/gate.ts
|
|
249900
|
+
var VERSIONS_API_ENV = "BASE44_VERSIONS_API";
|
|
249901
|
+
function versionsApiEnabled(env = process.env) {
|
|
249902
|
+
const value = env[VERSIONS_API_ENV];
|
|
249903
|
+
return value === "1" || value === "true";
|
|
249904
|
+
}
|
|
249905
|
+
// src/core/version/publish.ts
|
|
249906
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
249907
|
+
var DEFAULT_ENVIRONMENT = "production";
|
|
249908
|
+
async function tagStep2(step, run) {
|
|
249909
|
+
return await tagStep(step, run);
|
|
249910
|
+
}
|
|
249911
|
+
async function publishVersion(artifacts, options = {}) {
|
|
249912
|
+
const version = await tagStep2("create_version", () => createVersion(artifacts, {
|
|
249913
|
+
sourceCommit: options.sourceCommit,
|
|
249914
|
+
concurrency: options.concurrency,
|
|
249915
|
+
progress: options.progress
|
|
249916
|
+
}));
|
|
249917
|
+
const environment = await tagStep2("deploy", () => setEnvironmentVersion(options.target ?? DEFAULT_ENVIRONMENT, version.versionId, {
|
|
249918
|
+
idempotencyKey: randomUUID4()
|
|
249919
|
+
}));
|
|
249920
|
+
return {
|
|
249921
|
+
environment: environment.name,
|
|
249922
|
+
versionId: environment.versionId,
|
|
249923
|
+
manifestHash: environment.manifestHash,
|
|
249924
|
+
deploymentId: environment.deploymentId
|
|
249925
|
+
};
|
|
249926
|
+
}
|
|
249927
|
+
// src/cli/commands/project/build.ts
|
|
249928
|
+
async function buildAction(ctx) {
|
|
249929
|
+
const app = requireApp(ctx);
|
|
249930
|
+
const target = await resolvePublishTarget(app.projectRoot);
|
|
249931
|
+
await runSiteBuild(ctx, {
|
|
249932
|
+
root: target.root,
|
|
249933
|
+
buildCommand: target.buildCommand,
|
|
249934
|
+
appId: app.id
|
|
249935
|
+
});
|
|
249936
|
+
return {
|
|
249937
|
+
outroMessage: `Site built with app id ${theme.styles.bold(app.id)}`
|
|
249938
|
+
};
|
|
249939
|
+
}
|
|
249940
|
+
function getBuildCommand() {
|
|
249941
|
+
return new Base44Command("build", { requireAuth: false }).description("Build the site with the Base44 app id injected").action(buildAction);
|
|
249942
|
+
}
|
|
249943
|
+
|
|
249944
|
+
// src/cli/commands/project/create.ts
|
|
249945
|
+
import { basename as basename6, resolve as resolve12 } from "node:path";
|
|
249946
|
+
var import_kebabCase = __toESM(require_kebabCase(), 1);
|
|
249947
|
+
|
|
249948
|
+
// src/cli/commands/project/scaffold-shared.ts
|
|
249949
|
+
import { join as join29 } from "node:path";
|
|
249950
|
+
var DEFAULT_TEMPLATE_ID = "backend-only";
|
|
249951
|
+
async function getTemplateById(templateId) {
|
|
249952
|
+
const templates = await listTemplates();
|
|
249953
|
+
const template = templates.find((t) => t.id === templateId);
|
|
249954
|
+
if (!template) {
|
|
249955
|
+
const validIds = templates.map((t) => t.id).join(", ");
|
|
249956
|
+
throw new InvalidInputError(`Template "${templateId}" not found.`, {
|
|
249957
|
+
hints: [{ message: `Use one of: ${validIds}` }]
|
|
249958
|
+
});
|
|
249959
|
+
}
|
|
249960
|
+
return template;
|
|
249961
|
+
}
|
|
249962
|
+
async function completeProjectSetup({
|
|
249963
|
+
projectId,
|
|
249964
|
+
name,
|
|
249965
|
+
resolvedPath,
|
|
249966
|
+
deploy,
|
|
249967
|
+
skills,
|
|
249968
|
+
isInteractive
|
|
249969
|
+
}, { runTask }) {
|
|
249970
|
+
const { project, entities } = await readProjectConfig(resolvedPath);
|
|
249971
|
+
let finalAppUrl;
|
|
249972
|
+
if (entities.length > 0) {
|
|
249973
|
+
let shouldPushEntities;
|
|
249974
|
+
if (isInteractive) {
|
|
249975
|
+
const result = await Re({
|
|
249976
|
+
message: "Set up the backend data now? (This pushes the data models used by the template to Base44)"
|
|
249977
|
+
});
|
|
249978
|
+
shouldPushEntities = !Ct(result) && result;
|
|
249979
|
+
} else {
|
|
249980
|
+
shouldPushEntities = !!deploy;
|
|
249981
|
+
}
|
|
249982
|
+
if (shouldPushEntities) {
|
|
249983
|
+
await runTask(`Pushing ${entities.length} data models to Base44...`, async () => {
|
|
249984
|
+
await pushEntities(entities);
|
|
249985
|
+
}, {
|
|
249986
|
+
successMessage: theme.colors.base44Orange("Data models pushed successfully"),
|
|
249987
|
+
errorMessage: "Failed to push data models"
|
|
249988
|
+
});
|
|
249989
|
+
}
|
|
249990
|
+
}
|
|
249991
|
+
if (project.site) {
|
|
249992
|
+
const { installCommand, buildCommand, outputDirectory } = project.site;
|
|
249993
|
+
let shouldDeploy;
|
|
249994
|
+
if (isInteractive) {
|
|
249995
|
+
const result = await Re({
|
|
249996
|
+
message: "Would you like to deploy the site now? (Hosted on Base44)"
|
|
249997
|
+
});
|
|
249998
|
+
shouldDeploy = !Ct(result) && result;
|
|
249999
|
+
} else {
|
|
250000
|
+
shouldDeploy = !!deploy;
|
|
250001
|
+
}
|
|
250002
|
+
if (shouldDeploy && installCommand && buildCommand && outputDirectory) {
|
|
250003
|
+
const { appUrl } = await runTask("Installing dependencies...", async (updateMessage) => {
|
|
250004
|
+
await execa({ cwd: resolvedPath, shell: true })`${installCommand}`;
|
|
250005
|
+
updateMessage("Building project...");
|
|
250006
|
+
await execa({
|
|
250007
|
+
cwd: resolvedPath,
|
|
250008
|
+
shell: true,
|
|
250009
|
+
env: { VITE_BASE44_APP_ID: projectId }
|
|
250010
|
+
})`${buildCommand}`;
|
|
250011
|
+
updateMessage("Deploying site...");
|
|
250012
|
+
return await deploySite(join29(resolvedPath, outputDirectory));
|
|
250013
|
+
}, {
|
|
250014
|
+
successMessage: theme.colors.base44Orange("Site deployed successfully"),
|
|
250015
|
+
errorMessage: "Failed to deploy site"
|
|
250016
|
+
});
|
|
250017
|
+
finalAppUrl = appUrl;
|
|
250018
|
+
}
|
|
250019
|
+
}
|
|
250020
|
+
if (skills) {
|
|
250021
|
+
try {
|
|
250022
|
+
await runTask("Installing AI agent skills...", async () => {
|
|
250023
|
+
await execa("npx", ["-y", "skills", "add", "base44/skills", "-y"], {
|
|
250024
|
+
cwd: resolvedPath,
|
|
250025
|
+
shell: true
|
|
250026
|
+
});
|
|
250027
|
+
}, {
|
|
250028
|
+
successMessage: theme.colors.base44Orange("AI agent skills added successfully"),
|
|
250029
|
+
errorMessage: "Failed to add AI agent skills - you can add them later with: npx skills add base44/skills"
|
|
250030
|
+
});
|
|
250031
|
+
} catch {}
|
|
250032
|
+
}
|
|
250033
|
+
return {
|
|
250034
|
+
name,
|
|
250035
|
+
dashboardUrl: getDashboardUrl(projectId),
|
|
250036
|
+
appUrl: finalAppUrl
|
|
250037
|
+
};
|
|
250038
|
+
}
|
|
250039
|
+
function printProjectSummary({ name, dashboardUrl, appUrl }, log) {
|
|
250040
|
+
log.message(`${theme.styles.header("Project")}: ${theme.colors.base44Orange(name)}`);
|
|
250041
|
+
log.message(`${theme.styles.header("Dashboard")}: ${theme.colors.links(dashboardUrl)}`);
|
|
250042
|
+
if (appUrl) {
|
|
250043
|
+
log.message(`${theme.styles.header("Site")}: ${theme.colors.links(appUrl)}`);
|
|
250044
|
+
}
|
|
250045
|
+
}
|
|
250046
|
+
|
|
250047
|
+
// src/cli/commands/project/workspace-select.ts
|
|
250048
|
+
function fetchWorkspaces(ctx) {
|
|
250049
|
+
return ctx.runTask("Fetching workspaces...", () => listWorkspaces(), {
|
|
249795
250050
|
successMessage: "Workspaces fetched",
|
|
249796
250051
|
errorMessage: "Failed to fetch workspaces"
|
|
249797
250052
|
});
|
|
@@ -249883,7 +250138,7 @@ async function createInteractive(options, ctx) {
|
|
|
249883
250138
|
}, ctx);
|
|
249884
250139
|
}
|
|
249885
250140
|
async function createNonInteractive(options, ctx) {
|
|
249886
|
-
ctx.log.info(`Creating a new project at ${
|
|
250141
|
+
ctx.log.info(`Creating a new project at ${resolve12(options.path)}`);
|
|
249887
250142
|
const template = await getTemplateById(options.template ?? DEFAULT_TEMPLATE_ID);
|
|
249888
250143
|
return await executeCreate({
|
|
249889
250144
|
template,
|
|
@@ -249907,7 +250162,7 @@ async function executeCreate({
|
|
|
249907
250162
|
}, ctx) {
|
|
249908
250163
|
const { log, runTask } = ctx;
|
|
249909
250164
|
const name = rawName.trim();
|
|
249910
|
-
const resolvedPath =
|
|
250165
|
+
const resolvedPath = resolve12(projectPath);
|
|
249911
250166
|
const organizationId = await resolveWorkspaceId(ctx, flagWorkspaceId, isInteractive);
|
|
249912
250167
|
const { projectId } = await runTask("Setting up your project...", async () => {
|
|
249913
250168
|
return await createProjectFiles({
|
|
@@ -250548,7 +250803,7 @@ function getLogsCommand() {
|
|
|
250548
250803
|
}
|
|
250549
250804
|
|
|
250550
250805
|
// src/cli/commands/project/scaffold.ts
|
|
250551
|
-
import { basename as basename7, resolve as
|
|
250806
|
+
import { basename as basename7, resolve as resolve13 } from "node:path";
|
|
250552
250807
|
function resolveAppId(options) {
|
|
250553
250808
|
const appId = options.appId;
|
|
250554
250809
|
if (!appId) {
|
|
@@ -250564,7 +250819,7 @@ function resolveAppId(options) {
|
|
|
250564
250819
|
async function scaffoldAction(ctx, name, options, command) {
|
|
250565
250820
|
const { log, runTask } = ctx;
|
|
250566
250821
|
const appId = resolveAppId(command.optsWithGlobals());
|
|
250567
|
-
const resolvedPath =
|
|
250822
|
+
const resolvedPath = resolve13("./");
|
|
250568
250823
|
const projectName = (name ?? basename7(resolvedPath)).trim();
|
|
250569
250824
|
const template = await getTemplateById("backend-only");
|
|
250570
250825
|
log.info(`Scaffolding project at ${resolvedPath}`);
|
|
@@ -250612,258 +250867,6 @@ function getVisibilityCommand() {
|
|
|
250612
250867
|
])).action(setVisibility);
|
|
250613
250868
|
}
|
|
250614
250869
|
|
|
250615
|
-
// src/core/version/schema.ts
|
|
250616
|
-
var DeclareVersionResponseSchema = object({
|
|
250617
|
-
session_id: string2(),
|
|
250618
|
-
uploads: array(object({
|
|
250619
|
-
path: string2(),
|
|
250620
|
-
url: string2(),
|
|
250621
|
-
content_type: string2(),
|
|
250622
|
-
content_length: number2(),
|
|
250623
|
-
checksum_sha256: string2()
|
|
250624
|
-
}))
|
|
250625
|
-
}).transform((data) => ({
|
|
250626
|
-
sessionId: data.session_id,
|
|
250627
|
-
uploads: data.uploads.map((upload) => ({
|
|
250628
|
-
path: upload.path,
|
|
250629
|
-
url: upload.url,
|
|
250630
|
-
contentType: upload.content_type,
|
|
250631
|
-
contentLength: upload.content_length,
|
|
250632
|
-
checksumSha256: upload.checksum_sha256
|
|
250633
|
-
}))
|
|
250634
|
-
}));
|
|
250635
|
-
var CreateVersionResponseSchema = object({
|
|
250636
|
-
version_id: string2(),
|
|
250637
|
-
manifest_hash: string2()
|
|
250638
|
-
}).transform((data) => ({
|
|
250639
|
-
versionId: data.version_id,
|
|
250640
|
-
manifestHash: data.manifest_hash
|
|
250641
|
-
}));
|
|
250642
|
-
var EnvironmentResponseSchema = object({
|
|
250643
|
-
name: string2(),
|
|
250644
|
-
version_id: string2(),
|
|
250645
|
-
manifest_hash: string2(),
|
|
250646
|
-
deployment_id: string2()
|
|
250647
|
-
}).transform((data) => ({
|
|
250648
|
-
name: data.name,
|
|
250649
|
-
versionId: data.version_id,
|
|
250650
|
-
manifestHash: data.manifest_hash,
|
|
250651
|
-
deploymentId: data.deployment_id
|
|
250652
|
-
}));
|
|
250653
|
-
|
|
250654
|
-
// src/core/version/api.ts
|
|
250655
|
-
var DEFAULT_VERSION_UPLOAD_CONCURRENCY = 8;
|
|
250656
|
-
var MAX_VERSION_UPLOAD_CONCURRENCY = 16;
|
|
250657
|
-
function declaredFile({ path, size, digest }) {
|
|
250658
|
-
return { path, size, digest };
|
|
250659
|
-
}
|
|
250660
|
-
function declaredModule(module) {
|
|
250661
|
-
return { ...declaredFile(module), type: module.type };
|
|
250662
|
-
}
|
|
250663
|
-
function declaredAssetsConfig(config) {
|
|
250664
|
-
const stated = {
|
|
250665
|
-
html_handling: config?.htmlHandling ?? null,
|
|
250666
|
-
not_found_handling: config?.notFoundHandling ?? null,
|
|
250667
|
-
run_worker_first: config?.runWorkerFirst ?? null,
|
|
250668
|
-
headers: config?.headers ?? null,
|
|
250669
|
-
redirects: config?.redirects ?? null
|
|
250670
|
-
};
|
|
250671
|
-
return Object.values(stated).every((v) => v === null) ? null : stated;
|
|
250672
|
-
}
|
|
250673
|
-
async function post(path, json, doing) {
|
|
250674
|
-
try {
|
|
250675
|
-
return await getAppClient().post(path, { json, timeout: 180000 });
|
|
250676
|
-
} catch (error) {
|
|
250677
|
-
throw await ApiError.fromHttpError(error, doing);
|
|
250678
|
-
}
|
|
250679
|
-
}
|
|
250680
|
-
var KEYED_RETRY = {
|
|
250681
|
-
limit: 3,
|
|
250682
|
-
methods: ["patch"],
|
|
250683
|
-
statusCodes: [408, 500, 502, 503, 504],
|
|
250684
|
-
retryOnTimeout: true
|
|
250685
|
-
};
|
|
250686
|
-
async function patch(path, json, doing, retry) {
|
|
250687
|
-
try {
|
|
250688
|
-
return await getAppClient().patch(path, {
|
|
250689
|
-
json,
|
|
250690
|
-
timeout: 180000,
|
|
250691
|
-
...retry ? { retry } : {}
|
|
250692
|
-
});
|
|
250693
|
-
} catch (error) {
|
|
250694
|
-
throw await ApiError.fromHttpError(error, doing);
|
|
250695
|
-
}
|
|
250696
|
-
}
|
|
250697
|
-
function parse10(schema, body, what) {
|
|
250698
|
-
const result = schema.safeParse(body);
|
|
250699
|
-
if (!result.success) {
|
|
250700
|
-
throw new SchemaValidationError(`Invalid ${what} response from server`, result.error);
|
|
250701
|
-
}
|
|
250702
|
-
return result.data;
|
|
250703
|
-
}
|
|
250704
|
-
async function createVersion(artifacts, options = {}) {
|
|
250705
|
-
const declared = parse10(DeclareVersionResponseSchema, await (await post("versions", {
|
|
250706
|
-
static_bundle: artifacts.files.map(declaredFile),
|
|
250707
|
-
...artifacts.siteWorker ? {
|
|
250708
|
-
site_worker: {
|
|
250709
|
-
main: artifacts.siteWorker.main,
|
|
250710
|
-
modules: artifacts.siteWorker.modules.map(declaredModule),
|
|
250711
|
-
assets: artifacts.siteWorker.assets.map(declaredFile),
|
|
250712
|
-
compatibility_date: artifacts.siteWorker.compatibilityDate,
|
|
250713
|
-
compatibility_flags: artifacts.siteWorker.compatibilityFlags,
|
|
250714
|
-
assets_config: declaredAssetsConfig(artifacts.siteWorker.assetsConfig)
|
|
250715
|
-
}
|
|
250716
|
-
} : {},
|
|
250717
|
-
entities: artifacts.entities,
|
|
250718
|
-
agents: artifacts.agents,
|
|
250719
|
-
source_commit: options.sourceCommit
|
|
250720
|
-
}, "declaring a version")).json(), "declare");
|
|
250721
|
-
const declaredFiles = [
|
|
250722
|
-
...artifacts.files,
|
|
250723
|
-
...artifacts.siteWorker?.modules ?? [],
|
|
250724
|
-
...artifacts.siteWorker?.assets ?? []
|
|
250725
|
-
];
|
|
250726
|
-
options.progress?.onDeclared?.({ fileCount: declaredFiles.length });
|
|
250727
|
-
if (declared.uploads.length !== declaredFiles.length) {
|
|
250728
|
-
throw new InternalError(`Declared ${declaredFiles.length} files but the server signed ${declared.uploads.length} upload URLs.`);
|
|
250729
|
-
}
|
|
250730
|
-
const drifted = declared.uploads.findIndex((upload, index) => upload.path !== declaredFiles[index].path);
|
|
250731
|
-
if (drifted !== -1) {
|
|
250732
|
-
throw new InternalError(`Upload ${drifted} is signed for ${declared.uploads[drifted].path}, but that slot declared ${declaredFiles[drifted].path}.`);
|
|
250733
|
-
}
|
|
250734
|
-
let uploadedFiles = 0;
|
|
250735
|
-
await pMap(declared.uploads, async (upload, index) => {
|
|
250736
|
-
await putPresigned(upload, declaredFiles[index].absolutePath);
|
|
250737
|
-
uploadedFiles++;
|
|
250738
|
-
options.progress?.onUpload?.({
|
|
250739
|
-
uploadedFiles,
|
|
250740
|
-
totalFiles: declared.uploads.length
|
|
250741
|
-
});
|
|
250742
|
-
}, { concurrency: options.concurrency ?? DEFAULT_VERSION_UPLOAD_CONCURRENCY });
|
|
250743
|
-
return parse10(CreateVersionResponseSchema, await (await post(`versions/${encodeURIComponent(declared.sessionId)}/finalize`, {}, "creating a version")).json(), "create version");
|
|
250744
|
-
}
|
|
250745
|
-
async function setEnvironmentVersion(environment, versionId, options = {}) {
|
|
250746
|
-
return parse10(EnvironmentResponseSchema, await (await patch(`environments/${encodeURIComponent(environment)}`, {
|
|
250747
|
-
version_id: versionId,
|
|
250748
|
-
...options.idempotencyKey ? { idempotency_key: options.idempotencyKey } : {}
|
|
250749
|
-
}, "setting the environment's version", options.idempotencyKey ? KEYED_RETRY : undefined)).json(), "environment");
|
|
250750
|
-
}
|
|
250751
|
-
// src/core/version/artifacts.ts
|
|
250752
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
250753
|
-
import { join as join29, resolve as resolve13 } from "node:path";
|
|
250754
|
-
var MAX_FILE_COUNT = 50000;
|
|
250755
|
-
var HASH_CONCURRENCY = 32;
|
|
250756
|
-
var ENTRY2 = "index.html";
|
|
250757
|
-
async function digestFile(absolutePath) {
|
|
250758
|
-
const hash = await hashFileInto(createHash2("sha256"), absolutePath);
|
|
250759
|
-
return `sha256:${hash.digest("hex")}`;
|
|
250760
|
-
}
|
|
250761
|
-
async function collectBuildOutput(outputDir, options = {}) {
|
|
250762
|
-
const found = await describeBuildOutput(outputDir);
|
|
250763
|
-
if (found.length > MAX_FILE_COUNT) {
|
|
250764
|
-
throw new InvalidInputError(`Too many files: found ${found.length}, the limit is ${MAX_FILE_COUNT}.`);
|
|
250765
|
-
}
|
|
250766
|
-
if (options.entryFile) {
|
|
250767
|
-
if (found.length === 0) {
|
|
250768
|
-
throw new InvalidInputError(`No files found in ${outputDir}. Build the site before creating a version.`, {
|
|
250769
|
-
hints: [
|
|
250770
|
-
{ message: "Run 'base44 build' first", command: "base44 build" }
|
|
250771
|
-
]
|
|
250772
|
-
});
|
|
250773
|
-
}
|
|
250774
|
-
if (!found.some((f) => f.path === options.entryFile)) {
|
|
250775
|
-
throw new InvalidInputError(`${outputDir} has no ${options.entryFile}, so nothing could enter the site.`);
|
|
250776
|
-
}
|
|
250777
|
-
}
|
|
250778
|
-
return await pMap(found, async (file) => ({ ...file, digest: await digestFile(file.absolutePath) }), { concurrency: HASH_CONCURRENCY });
|
|
250779
|
-
}
|
|
250780
|
-
async function collectSiteWorker(projectRoot) {
|
|
250781
|
-
const built = await resolveFullStackBuild(projectRoot);
|
|
250782
|
-
if (!built) {
|
|
250783
|
-
return null;
|
|
250784
|
-
}
|
|
250785
|
-
const { config, modules, assetsDir } = built;
|
|
250786
|
-
const entry = resolve13(config.configDir, config.main);
|
|
250787
|
-
const main = modules.find((m) => m.absolutePath === entry)?.name;
|
|
250788
|
-
if (!main) {
|
|
250789
|
-
throw new InvalidInputError(`The Worker's entry module ${config.main} is not among the ${modules.length} modules collected from ${config.configDir}.`);
|
|
250790
|
-
}
|
|
250791
|
-
return {
|
|
250792
|
-
main,
|
|
250793
|
-
modules: await pMap(modules, async ({ name, absolutePath, size, type }) => ({
|
|
250794
|
-
path: name,
|
|
250795
|
-
absolutePath,
|
|
250796
|
-
size,
|
|
250797
|
-
digest: await digestFile(absolutePath),
|
|
250798
|
-
type
|
|
250799
|
-
}), { concurrency: HASH_CONCURRENCY }),
|
|
250800
|
-
assets: assetsDir ? await collectBuildOutput(assetsDir) : [],
|
|
250801
|
-
compatibilityDate: config.compatibilityDate,
|
|
250802
|
-
compatibilityFlags: config.compatibilityFlags,
|
|
250803
|
-
assetsConfig: config.assetsConfig
|
|
250804
|
-
};
|
|
250805
|
-
}
|
|
250806
|
-
async function readRawResources(dir) {
|
|
250807
|
-
if (!await pathExists(dir)) {
|
|
250808
|
-
return {};
|
|
250809
|
-
}
|
|
250810
|
-
const files = await globby(`**/*.${CONFIG_FILE_EXTENSION_GLOB}`, {
|
|
250811
|
-
cwd: dir,
|
|
250812
|
-
onlyFiles: true,
|
|
250813
|
-
followSymbolicLinks: false
|
|
250814
|
-
});
|
|
250815
|
-
const payloads = {};
|
|
250816
|
-
for (const relativePath of files.sort()) {
|
|
250817
|
-
const name = relativePath.replace(/\.jsonc?$/, "");
|
|
250818
|
-
payloads[name] = await readJsonFile(join29(dir, ...relativePath.split("/")));
|
|
250819
|
-
}
|
|
250820
|
-
return payloads;
|
|
250821
|
-
}
|
|
250822
|
-
async function collectResources(configDir, dirs) {
|
|
250823
|
-
const [entities, agents] = await Promise.all([
|
|
250824
|
-
readRawResources(join29(configDir, dirs.entitiesDir)),
|
|
250825
|
-
readRawResources(join29(configDir, dirs.agentsDir))
|
|
250826
|
-
]);
|
|
250827
|
-
return { entities, agents };
|
|
250828
|
-
}
|
|
250829
|
-
async function collectArtifacts(target) {
|
|
250830
|
-
const siteWorker = await collectSiteWorker(target.root);
|
|
250831
|
-
return {
|
|
250832
|
-
files: siteWorker ? [] : await collectBuildOutput(requireOutputDir(target), {
|
|
250833
|
-
entryFile: ENTRY2
|
|
250834
|
-
}),
|
|
250835
|
-
...siteWorker ? { siteWorker } : {},
|
|
250836
|
-
...await collectResources(target.configDir, target)
|
|
250837
|
-
};
|
|
250838
|
-
}
|
|
250839
|
-
// src/core/version/gate.ts
|
|
250840
|
-
var VERSIONS_API_ENV = "BASE44_VERSIONS_API";
|
|
250841
|
-
function versionsApiEnabled(env = process.env) {
|
|
250842
|
-
const value = env[VERSIONS_API_ENV];
|
|
250843
|
-
return value === "1" || value === "true";
|
|
250844
|
-
}
|
|
250845
|
-
// src/core/version/publish.ts
|
|
250846
|
-
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
250847
|
-
var DEFAULT_ENVIRONMENT = "production";
|
|
250848
|
-
async function tagStep2(step, run) {
|
|
250849
|
-
return await tagStep(step, run);
|
|
250850
|
-
}
|
|
250851
|
-
async function publishVersion(artifacts, options = {}) {
|
|
250852
|
-
const version = await tagStep2("create_version", () => createVersion(artifacts, {
|
|
250853
|
-
sourceCommit: options.sourceCommit,
|
|
250854
|
-
concurrency: options.concurrency,
|
|
250855
|
-
progress: options.progress
|
|
250856
|
-
}));
|
|
250857
|
-
const environment = await tagStep2("deploy", () => setEnvironmentVersion(options.target ?? DEFAULT_ENVIRONMENT, version.versionId, {
|
|
250858
|
-
idempotencyKey: randomUUID4()
|
|
250859
|
-
}));
|
|
250860
|
-
return {
|
|
250861
|
-
environment: environment.name,
|
|
250862
|
-
versionId: environment.versionId,
|
|
250863
|
-
manifestHash: environment.manifestHash,
|
|
250864
|
-
deploymentId: environment.deploymentId
|
|
250865
|
-
};
|
|
250866
|
-
}
|
|
250867
250870
|
// src/cli/commands/versions/options.ts
|
|
250868
250871
|
function outputDirOption() {
|
|
250869
250872
|
return new Option2("--output-dir <dir>", "Build output directory (defaults to the project's, else dist)");
|
|
@@ -250893,7 +250896,7 @@ function concurrencyOption() {
|
|
|
250893
250896
|
async function publishAction(ctx, options) {
|
|
250894
250897
|
const { runTask, log, jsonMode } = ctx;
|
|
250895
250898
|
const app = requireApp(ctx);
|
|
250896
|
-
const target = await tagStep2("create_version", () =>
|
|
250899
|
+
const target = await tagStep2("create_version", () => resolvePublishTarget(app.projectRoot, { outputDir: options.outputDir }));
|
|
250897
250900
|
if (options.build !== false) {
|
|
250898
250901
|
await tagStep2("build", () => runSiteBuild(ctx, {
|
|
250899
250902
|
root: target.root,
|
|
@@ -251637,7 +251640,7 @@ function getTypesCommand() {
|
|
|
251637
251640
|
// src/cli/commands/versions/create.ts
|
|
251638
251641
|
async function createAction2(ctx, options) {
|
|
251639
251642
|
const { runTask, jsonMode } = ctx;
|
|
251640
|
-
const target = await
|
|
251643
|
+
const target = await resolvePublishTarget(requireApp(ctx).projectRoot, {
|
|
251641
251644
|
outputDir: options.outputDir
|
|
251642
251645
|
});
|
|
251643
251646
|
const gitHash = await resolveProvenanceCommit(target.root, options.gitHash);
|
|
@@ -260403,4 +260406,4 @@ export {
|
|
|
260403
260406
|
runCLI
|
|
260404
260407
|
};
|
|
260405
260408
|
|
|
260406
|
-
//# debugId=
|
|
260409
|
+
//# debugId=53C2F96B49B467E964756E2164756E21
|