@base44-preview/cli 0.1.8-pr.589.9d22ef2 → 0.1.9-pr.595.21d640d
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/assets/templates/backend-and-client/package.json +2 -1
- package/dist/assets/templates/backend-and-client/src/api/base44Client.js +12 -0
- package/dist/assets/templates/backend-and-client/src/lib/app-params.js +28 -0
- package/dist/assets/templates/backend-and-client/vite.config.js +3 -8
- package/dist/cli/index.js +574 -75
- package/dist/cli/index.js.map +24 -15
- package/package.json +1 -1
- package/dist/assets/templates/backend-and-client/src/api/base44Client.js.ejs +0 -5
package/dist/cli/index.js
CHANGED
|
@@ -247201,24 +247201,33 @@ var ResourceSourceSchema = exports_external.discriminatedUnion("type", [
|
|
|
247201
247201
|
]);
|
|
247202
247202
|
|
|
247203
247203
|
// src/core/resources/entity/schema.ts
|
|
247204
|
-
var
|
|
247205
|
-
|
|
247206
|
-
|
|
247207
|
-
|
|
247208
|
-
|
|
247209
|
-
|
|
247210
|
-
|
|
247211
|
-
|
|
247212
|
-
|
|
247213
|
-
|
|
247214
|
-
|
|
247204
|
+
var fieldConditionOperators = new Set([
|
|
247205
|
+
"$eq",
|
|
247206
|
+
"$ne",
|
|
247207
|
+
"$in",
|
|
247208
|
+
"$nin",
|
|
247209
|
+
"$gt",
|
|
247210
|
+
"$gte",
|
|
247211
|
+
"$lt",
|
|
247212
|
+
"$lte",
|
|
247213
|
+
"$exists",
|
|
247214
|
+
"$all",
|
|
247215
|
+
"$size",
|
|
247216
|
+
"$elemMatch"
|
|
247215
247217
|
]);
|
|
247216
|
-
var
|
|
247217
|
-
var
|
|
247218
|
-
|
|
247219
|
-
|
|
247220
|
-
|
|
247221
|
-
|
|
247218
|
+
var isScalar = (value) => value === null || ["string", "number", "boolean"].includes(typeof value);
|
|
247219
|
+
var isValidFieldCondition = (value) => {
|
|
247220
|
+
if (isScalar(value)) {
|
|
247221
|
+
return true;
|
|
247222
|
+
}
|
|
247223
|
+
if (typeof value === "object" && !Array.isArray(value)) {
|
|
247224
|
+
return Object.keys(value).every((k2) => fieldConditionOperators.has(k2));
|
|
247225
|
+
}
|
|
247226
|
+
return false;
|
|
247227
|
+
};
|
|
247228
|
+
var supportedOperators = [...fieldConditionOperators].sort().join(", ");
|
|
247229
|
+
var FieldConditionSchema = exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean(), exports_external.null(), exports_external.looseObject({})]).refine(isValidFieldCondition, `Field condition values must be a primitive or an operator object (${supportedOperators})`);
|
|
247230
|
+
var UserConditionSchema = exports_external.looseObject({}).refine((val) => Object.keys(val).length > 0 && Object.entries(val).every(([key, value]) => !key.startsWith("$") && isScalar(value)), "user_condition compares user attributes by exact equality: a non-empty object of attribute: scalar pairs, no operators");
|
|
247222
247231
|
var rlsConditionAllowedKeys = new Set([
|
|
247223
247232
|
"user_condition",
|
|
247224
247233
|
"created_by",
|
|
@@ -247250,18 +247259,13 @@ var RLSConditionSchema = exports_external.looseObject({
|
|
|
247250
247259
|
return exports_external.array(RefineRLSConditionSchema).optional();
|
|
247251
247260
|
}
|
|
247252
247261
|
});
|
|
247253
|
-
var
|
|
247254
|
-
var
|
|
247255
|
-
|
|
247256
|
-
|
|
247257
|
-
|
|
247258
|
-
|
|
247259
|
-
|
|
247260
|
-
}
|
|
247261
|
-
return false;
|
|
247262
|
-
};
|
|
247263
|
-
var RefineRLSConditionSchema = RLSConditionSchema.refine((val) => Object.entries(val).every(([key, value]) => rlsConditionAllowedKeys.has(key) || isValidFieldCondition(value)), "Field condition values must be a primitive or an operator object ($in, $nin, $ne, $all)");
|
|
247264
|
-
var RLSRuleSchema = exports_external.union([exports_external.boolean(), RefineRLSConditionSchema]);
|
|
247262
|
+
var RefineRLSConditionSchema = RLSConditionSchema.refine((val) => Object.entries(val).every(([key, value]) => rlsConditionAllowedKeys.has(key) || isValidFieldCondition(value)), `Field condition values must be a primitive or an operator object (${supportedOperators})`);
|
|
247263
|
+
var RLSRuleSchema = exports_external.union([
|
|
247264
|
+
exports_external.boolean(),
|
|
247265
|
+
exports_external.null(),
|
|
247266
|
+
exports_external.literal(""),
|
|
247267
|
+
RefineRLSConditionSchema
|
|
247268
|
+
]);
|
|
247265
247269
|
var EntityRLSSchema = exports_external.looseObject({
|
|
247266
247270
|
create: RLSRuleSchema.optional(),
|
|
247267
247271
|
read: RLSRuleSchema.optional(),
|
|
@@ -247277,7 +247281,7 @@ var FieldRLSSchema = exports_external.looseObject({
|
|
|
247277
247281
|
delete: RLSRuleSchema.optional()
|
|
247278
247282
|
});
|
|
247279
247283
|
var PropertyDefinitionSchema = exports_external.looseObject({
|
|
247280
|
-
type: exports_external.string(),
|
|
247284
|
+
type: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]),
|
|
247281
247285
|
title: exports_external.string().optional(),
|
|
247282
247286
|
description: exports_external.string().optional(),
|
|
247283
247287
|
minLength: exports_external.number().int().min(0).optional(),
|
|
@@ -247301,7 +247305,7 @@ var PropertyDefinitionSchema = exports_external.looseObject({
|
|
|
247301
247305
|
});
|
|
247302
247306
|
var EntitySchema = exports_external.looseObject({
|
|
247303
247307
|
type: exports_external.literal("object").default("object"),
|
|
247304
|
-
name: exports_external.string().min(1).regex(
|
|
247308
|
+
name: exports_external.string().min(1).regex(/^\w+$/, "Entity name must contain only letters, numbers, and underscores"),
|
|
247305
247309
|
title: exports_external.string().optional(),
|
|
247306
247310
|
description: exports_external.string().optional(),
|
|
247307
247311
|
properties: exports_external.record(exports_external.string(), PropertyDefinitionSchema).default({}),
|
|
@@ -247868,13 +247872,145 @@ var functionResource = {
|
|
|
247868
247872
|
readAll: readAllFunctions,
|
|
247869
247873
|
push: (functions) => deployFunctionsSequentially(functions)
|
|
247870
247874
|
};
|
|
247875
|
+
// src/core/resources/function/stream-api.ts
|
|
247876
|
+
var StreamLogEventSchema = exports_external.object({
|
|
247877
|
+
time: exports_external.string(),
|
|
247878
|
+
level: exports_external.preprocess((value) => value === "warn" ? "warning" : value, LogLevelSchema),
|
|
247879
|
+
function: exports_external.string().nullable(),
|
|
247880
|
+
message: exports_external.string()
|
|
247881
|
+
});
|
|
247882
|
+
var StreamEndEventSchema = exports_external.object({
|
|
247883
|
+
reason: exports_external.string(),
|
|
247884
|
+
retriable: exports_external.boolean()
|
|
247885
|
+
});
|
|
247886
|
+
function buildStreamUrl(filters) {
|
|
247887
|
+
const { id } = getAppContext();
|
|
247888
|
+
const url2 = new URL(`/api/apps/${id}/functions-mgmt/logs/stream`, getBase44ApiUrl());
|
|
247889
|
+
if (filters.functions?.length) {
|
|
247890
|
+
url2.searchParams.set("function", filters.functions.join(","));
|
|
247891
|
+
}
|
|
247892
|
+
if (filters.env) {
|
|
247893
|
+
url2.searchParams.set("env", filters.env);
|
|
247894
|
+
}
|
|
247895
|
+
return url2.href;
|
|
247896
|
+
}
|
|
247897
|
+
async function buildStreamAuthHeaders() {
|
|
247898
|
+
const workspaceApiKey = getWorkspaceApiKeyFromEnv();
|
|
247899
|
+
if (workspaceApiKey && isWorkspaceApiKey(workspaceApiKey)) {
|
|
247900
|
+
return { api_key: workspaceApiKey };
|
|
247901
|
+
}
|
|
247902
|
+
const auth = await readAuth();
|
|
247903
|
+
if (isTokenExpired(auth)) {
|
|
247904
|
+
const refreshedToken = await refreshAndSaveTokens();
|
|
247905
|
+
if (refreshedToken) {
|
|
247906
|
+
return { Authorization: `Bearer ${refreshedToken}` };
|
|
247907
|
+
}
|
|
247908
|
+
}
|
|
247909
|
+
return { Authorization: `Bearer ${auth.accessToken}` };
|
|
247910
|
+
}
|
|
247911
|
+
function parseStreamEvent(eventName, data) {
|
|
247912
|
+
try {
|
|
247913
|
+
const payload = JSON.parse(data);
|
|
247914
|
+
if (eventName === "end") {
|
|
247915
|
+
const result = StreamEndEventSchema.safeParse(payload);
|
|
247916
|
+
return result.success ? { kind: "end", end: result.data } : null;
|
|
247917
|
+
}
|
|
247918
|
+
if (eventName === "") {
|
|
247919
|
+
const result = StreamLogEventSchema.safeParse(payload);
|
|
247920
|
+
return result.success ? { kind: "log", log: result.data } : null;
|
|
247921
|
+
}
|
|
247922
|
+
return null;
|
|
247923
|
+
} catch {
|
|
247924
|
+
return null;
|
|
247925
|
+
}
|
|
247926
|
+
}
|
|
247927
|
+
var STREAM_SILENCE_TIMEOUT_MS = 60000;
|
|
247928
|
+
async function readOrSilence(reader) {
|
|
247929
|
+
let timer;
|
|
247930
|
+
const silence = new Promise((resolve3) => {
|
|
247931
|
+
timer = setTimeout(() => resolve3("silence"), STREAM_SILENCE_TIMEOUT_MS);
|
|
247932
|
+
});
|
|
247933
|
+
try {
|
|
247934
|
+
return await Promise.race([reader.read(), silence]);
|
|
247935
|
+
} finally {
|
|
247936
|
+
clearTimeout(timer);
|
|
247937
|
+
}
|
|
247938
|
+
}
|
|
247939
|
+
async function* readLines(body) {
|
|
247940
|
+
const reader = body.getReader();
|
|
247941
|
+
const decoder = new TextDecoder;
|
|
247942
|
+
let buffered = "";
|
|
247943
|
+
try {
|
|
247944
|
+
while (true) {
|
|
247945
|
+
const result = await readOrSilence(reader);
|
|
247946
|
+
if (result === "silence") {
|
|
247947
|
+
await reader.cancel();
|
|
247948
|
+
return;
|
|
247949
|
+
}
|
|
247950
|
+
if (result.done || !result.value)
|
|
247951
|
+
return;
|
|
247952
|
+
buffered += decoder.decode(result.value, { stream: true });
|
|
247953
|
+
const lines = buffered.split(`
|
|
247954
|
+
`);
|
|
247955
|
+
buffered = lines.pop() ?? "";
|
|
247956
|
+
yield* lines;
|
|
247957
|
+
}
|
|
247958
|
+
} finally {
|
|
247959
|
+
reader.releaseLock();
|
|
247960
|
+
}
|
|
247961
|
+
}
|
|
247962
|
+
async function* readStreamEvents(body) {
|
|
247963
|
+
let eventName = "";
|
|
247964
|
+
for await (const line of readLines(body)) {
|
|
247965
|
+
if (line.startsWith("event:")) {
|
|
247966
|
+
eventName = line.slice(6).trim();
|
|
247967
|
+
continue;
|
|
247968
|
+
}
|
|
247969
|
+
if (line.startsWith("data:")) {
|
|
247970
|
+
const event = parseStreamEvent(eventName, line.slice(5));
|
|
247971
|
+
eventName = "";
|
|
247972
|
+
if (event)
|
|
247973
|
+
yield event;
|
|
247974
|
+
continue;
|
|
247975
|
+
}
|
|
247976
|
+
if (line.trim() === "")
|
|
247977
|
+
eventName = "";
|
|
247978
|
+
}
|
|
247979
|
+
}
|
|
247980
|
+
var STREAM_CONNECT_TIMEOUT_MS = 1e4;
|
|
247981
|
+
async function openLogStream(filters) {
|
|
247982
|
+
const connectPhase = new AbortController;
|
|
247983
|
+
const connectTimer = setTimeout(() => connectPhase.abort(), STREAM_CONNECT_TIMEOUT_MS);
|
|
247984
|
+
let response;
|
|
247985
|
+
try {
|
|
247986
|
+
response = await fetch(buildStreamUrl(filters), {
|
|
247987
|
+
headers: {
|
|
247988
|
+
Accept: "text/event-stream",
|
|
247989
|
+
...await buildStreamAuthHeaders()
|
|
247990
|
+
},
|
|
247991
|
+
signal: connectPhase.signal
|
|
247992
|
+
});
|
|
247993
|
+
} catch {
|
|
247994
|
+
return null;
|
|
247995
|
+
} finally {
|
|
247996
|
+
clearTimeout(connectTimer);
|
|
247997
|
+
}
|
|
247998
|
+
if (!response.ok || !response.body)
|
|
247999
|
+
return null;
|
|
248000
|
+
return readStreamEvents(response.body);
|
|
248001
|
+
}
|
|
247871
248002
|
// src/core/project/config.ts
|
|
247872
248003
|
class ProjectConfigReader {
|
|
247873
248004
|
pluginSourceByNamespace = new Map;
|
|
247874
|
-
async
|
|
248005
|
+
async readProjectSettings(projectRoot) {
|
|
247875
248006
|
const { root, configPath } = await this.findConfigOrThrow(projectRoot);
|
|
247876
248007
|
const project = await this.readConfigFile(configPath);
|
|
247877
248008
|
this.assertPluginProjectDoesNotLoadPlugins(project, configPath);
|
|
248009
|
+
return { ...project, root, configPath };
|
|
248010
|
+
}
|
|
248011
|
+
async readProjectConfig(projectRoot) {
|
|
248012
|
+
const project = await this.readProjectSettings(projectRoot);
|
|
248013
|
+
const { configPath } = project;
|
|
247878
248014
|
const localResources = await this.readProjectResources(configPath, project);
|
|
247879
248015
|
const pluginResources = await this.readPlugins(project.plugins, configPath);
|
|
247880
248016
|
const entities = mergeProjectAndPluginEntities(localResources.entities, pluginResources.entities, configPath);
|
|
@@ -247884,7 +248020,7 @@ class ProjectConfigReader {
|
|
|
247884
248020
|
];
|
|
247885
248021
|
this.validateFunctionNames(functions, configPath);
|
|
247886
248022
|
return {
|
|
247887
|
-
project
|
|
248023
|
+
project,
|
|
247888
248024
|
entities,
|
|
247889
248025
|
functions,
|
|
247890
248026
|
agents: localResources.agents,
|
|
@@ -248022,6 +248158,10 @@ async function readProjectConfig(projectRoot) {
|
|
|
248022
248158
|
const reader = new ProjectConfigReader;
|
|
248023
248159
|
return await reader.readProjectConfig(projectRoot);
|
|
248024
248160
|
}
|
|
248161
|
+
async function readProjectSettings(projectRoot) {
|
|
248162
|
+
const reader = new ProjectConfigReader;
|
|
248163
|
+
return await reader.readProjectSettings(projectRoot);
|
|
248164
|
+
}
|
|
248025
248165
|
// src/core/project/template.ts
|
|
248026
248166
|
var import_ejs = __toESM(require_ejs(), 1);
|
|
248027
248167
|
var import_front_matter2 = __toESM(require_front_matter(), 1);
|
|
@@ -248034,7 +248174,7 @@ import { join as join12 } from "node:path";
|
|
|
248034
248174
|
// package.json
|
|
248035
248175
|
var package_default = {
|
|
248036
248176
|
name: "base44",
|
|
248037
|
-
version: "0.1.
|
|
248177
|
+
version: "0.1.9",
|
|
248038
248178
|
description: "Base44 CLI - Unified interface for managing Base44 applications",
|
|
248039
248179
|
type: "module",
|
|
248040
248180
|
bin: {
|
|
@@ -248335,7 +248475,9 @@ async function deploySite(siteOutputDir) {
|
|
|
248335
248475
|
if (!await pathExists(siteOutputDir)) {
|
|
248336
248476
|
throw new InvalidInputError(`Output directory does not exist: ${siteOutputDir}. Make sure to build your project first.`, {
|
|
248337
248477
|
hints: [
|
|
248338
|
-
{
|
|
248478
|
+
{
|
|
248479
|
+
message: "Run 'base44 build' first (it injects your app id; a bare 'npm run build' does not)"
|
|
248480
|
+
}
|
|
248339
248481
|
]
|
|
248340
248482
|
});
|
|
248341
248483
|
}
|
|
@@ -248343,7 +248485,9 @@ async function deploySite(siteOutputDir) {
|
|
|
248343
248485
|
if (filePaths.length === 0) {
|
|
248344
248486
|
throw new ConfigInvalidError(`No files found in output directory: ${siteOutputDir}. Make sure to build your project first.`, siteOutputDir, {
|
|
248345
248487
|
hints: [
|
|
248346
|
-
{
|
|
248488
|
+
{
|
|
248489
|
+
message: "Run 'base44 build' first (it injects your app id; a bare 'npm run build' does not)"
|
|
248490
|
+
}
|
|
248347
248491
|
]
|
|
248348
248492
|
});
|
|
248349
248493
|
}
|
|
@@ -255586,6 +255730,14 @@ function writeJsonError(error48) {
|
|
|
255586
255730
|
envelope.hints = error48.hints;
|
|
255587
255731
|
}
|
|
255588
255732
|
}
|
|
255733
|
+
if (error48 instanceof ApiError) {
|
|
255734
|
+
if (error48.statusCode !== undefined) {
|
|
255735
|
+
envelope.statusCode = error48.statusCode;
|
|
255736
|
+
}
|
|
255737
|
+
if (error48.requestId !== undefined) {
|
|
255738
|
+
envelope.requestId = error48.requestId;
|
|
255739
|
+
}
|
|
255740
|
+
}
|
|
255589
255741
|
process.stdout.write(`${JSON.stringify(envelope)}
|
|
255590
255742
|
`);
|
|
255591
255743
|
}
|
|
@@ -255682,6 +255834,18 @@ async function confirmPush({
|
|
|
255682
255834
|
});
|
|
255683
255835
|
return !Ct(proceed) && proceed;
|
|
255684
255836
|
}
|
|
255837
|
+
// src/cli/utils/datetime.ts
|
|
255838
|
+
var import_ms2 = __toESM(require_ms(), 1);
|
|
255839
|
+
var HAS_TIMEZONE_SUFFIX = /Z$|[+-]\d{2}:\d{2}$/;
|
|
255840
|
+
function normalizeDatetime(value) {
|
|
255841
|
+
const duration3 = import_ms2.default(value);
|
|
255842
|
+
if (duration3 !== undefined) {
|
|
255843
|
+
return new Date(Date.now() - duration3).toISOString();
|
|
255844
|
+
}
|
|
255845
|
+
if (HAS_TIMEZONE_SUFFIX.test(value))
|
|
255846
|
+
return value;
|
|
255847
|
+
return `${value}Z`;
|
|
255848
|
+
}
|
|
255685
255849
|
// src/cli/utils/json.ts
|
|
255686
255850
|
function toJsonStdout(result) {
|
|
255687
255851
|
return `${JSON.stringify(result, null, 2)}
|
|
@@ -257539,8 +257703,8 @@ function getDeleteCommand() {
|
|
|
257539
257703
|
}
|
|
257540
257704
|
|
|
257541
257705
|
// src/cli/commands/functions/formatDeployResult.ts
|
|
257542
|
-
function formatDuration(
|
|
257543
|
-
return `${(
|
|
257706
|
+
function formatDuration(ms2) {
|
|
257707
|
+
return `${(ms2 / 1000).toFixed(1)}s`;
|
|
257544
257708
|
}
|
|
257545
257709
|
function formatDeployResult(result, log) {
|
|
257546
257710
|
const label = result.name.padEnd(25);
|
|
@@ -257873,7 +258037,11 @@ async function completeProjectSetup({
|
|
|
257873
258037
|
const { appUrl } = await runTask2("Installing dependencies...", async (updateMessage) => {
|
|
257874
258038
|
await execa({ cwd: resolvedPath, shell: true })`${installCommand}`;
|
|
257875
258039
|
updateMessage("Building project...");
|
|
257876
|
-
await execa({
|
|
258040
|
+
await execa({
|
|
258041
|
+
cwd: resolvedPath,
|
|
258042
|
+
shell: true,
|
|
258043
|
+
env: { VITE_BASE44_APP_ID: projectId }
|
|
258044
|
+
})`${buildCommand}`;
|
|
257877
258045
|
updateMessage("Deploying site...");
|
|
257878
258046
|
return await deploySite(join25(resolvedPath, outputDirectory));
|
|
257879
258047
|
}, {
|
|
@@ -258353,7 +258521,6 @@ function getLinkCommand() {
|
|
|
258353
258521
|
}
|
|
258354
258522
|
|
|
258355
258523
|
// src/cli/commands/project/logs.ts
|
|
258356
|
-
var import_ms2 = __toESM(require_ms(), 1);
|
|
258357
258524
|
function parseFunctionFilters(options) {
|
|
258358
258525
|
const filters = {};
|
|
258359
258526
|
if (options.since) {
|
|
@@ -258381,15 +258548,6 @@ function parseFunctionNames(option) {
|
|
|
258381
258548
|
return [];
|
|
258382
258549
|
return option.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
258383
258550
|
}
|
|
258384
|
-
function normalizeDatetime(value) {
|
|
258385
|
-
const duration3 = import_ms2.default(value);
|
|
258386
|
-
if (duration3 !== undefined) {
|
|
258387
|
-
return new Date(Date.now() - duration3).toISOString();
|
|
258388
|
-
}
|
|
258389
|
-
if (/Z$|[+-]\d{2}:\d{2}$/.test(value))
|
|
258390
|
-
return value;
|
|
258391
|
-
return `${value}Z`;
|
|
258392
|
-
}
|
|
258393
258551
|
function formatEntry(entry) {
|
|
258394
258552
|
const time3 = entry.time.substring(0, 19).replace("T", " ");
|
|
258395
258553
|
const level = entry.level.toUpperCase().padEnd(5);
|
|
@@ -258423,9 +258581,73 @@ function writeFollowLine(entry, jsonMode) {
|
|
|
258423
258581
|
process.stdout.write(`${line}
|
|
258424
258582
|
`);
|
|
258425
258583
|
}
|
|
258426
|
-
|
|
258427
|
-
|
|
258428
|
-
|
|
258584
|
+
var delay2 = (ms2) => new Promise((resolve9) => setTimeout(resolve9, ms2));
|
|
258585
|
+
function streamEventToLogEntry(event) {
|
|
258586
|
+
return {
|
|
258587
|
+
time: event.time,
|
|
258588
|
+
level: event.level,
|
|
258589
|
+
message: event.function ? `[${event.function}] ${event.message}` : event.message,
|
|
258590
|
+
source: event.function ?? ""
|
|
258591
|
+
};
|
|
258592
|
+
}
|
|
258593
|
+
async function printStreamUntilEnd(stream, levelFilter, jsonMode, startTime) {
|
|
258594
|
+
let lastTime = startTime;
|
|
258595
|
+
let producedEvents = false;
|
|
258596
|
+
try {
|
|
258597
|
+
for await (const event of stream) {
|
|
258598
|
+
producedEvents = true;
|
|
258599
|
+
if (event.kind === "end")
|
|
258600
|
+
return { lastTime, producedEvents, end: event.end };
|
|
258601
|
+
if (levelFilter && event.log.level !== levelFilter)
|
|
258602
|
+
continue;
|
|
258603
|
+
writeFollowLine(streamEventToLogEntry(event.log), jsonMode);
|
|
258604
|
+
if (event.log.time > lastTime)
|
|
258605
|
+
lastTime = event.log.time;
|
|
258606
|
+
}
|
|
258607
|
+
} catch {}
|
|
258608
|
+
return { lastTime, producedEvents, end: null };
|
|
258609
|
+
}
|
|
258610
|
+
var STREAM_RECONNECT_DELAY_MS = 1000;
|
|
258611
|
+
var MAX_DROPS_SINCE_LAST_EVENT = 2;
|
|
258612
|
+
async function streamUntilExhausted(options, jsonMode) {
|
|
258613
|
+
const filters = {
|
|
258614
|
+
functions: parseFunctionNames(options.function),
|
|
258615
|
+
env: options.env
|
|
258616
|
+
};
|
|
258617
|
+
let everConnected = false;
|
|
258618
|
+
let lastTime = "";
|
|
258619
|
+
let dropsSinceLastEvent = 0;
|
|
258620
|
+
while (true) {
|
|
258621
|
+
const stream = await openLogStream(filters);
|
|
258622
|
+
if (!stream)
|
|
258623
|
+
break;
|
|
258624
|
+
everConnected = true;
|
|
258625
|
+
const ending = await printStreamUntilEnd(stream, options.level, jsonMode, lastTime);
|
|
258626
|
+
lastTime = ending.lastTime;
|
|
258627
|
+
if (ending.end) {
|
|
258628
|
+
if (!ending.end.retriable)
|
|
258629
|
+
break;
|
|
258630
|
+
dropsSinceLastEvent = 0;
|
|
258631
|
+
} else {
|
|
258632
|
+
dropsSinceLastEvent = ending.producedEvents ? 1 : dropsSinceLastEvent + 1;
|
|
258633
|
+
if (dropsSinceLastEvent >= MAX_DROPS_SINCE_LAST_EVENT)
|
|
258634
|
+
break;
|
|
258635
|
+
}
|
|
258636
|
+
await delay2(STREAM_RECONNECT_DELAY_MS);
|
|
258637
|
+
}
|
|
258638
|
+
return { everConnected, lastTime };
|
|
258639
|
+
}
|
|
258640
|
+
async function followLogs(functionNames, options, availableFunctionNames, jsonMode, logger2) {
|
|
258641
|
+
const { everConnected, lastTime } = await streamUntilExhausted(options, jsonMode);
|
|
258642
|
+
logger2.warn(everConnected ? "Realtime stream disconnected — falling back to polling (lines may lag ~20-30s)." : "Realtime stream unavailable — falling back to polling (lines may lag ~20-30s).");
|
|
258643
|
+
return pollLogs(functionNames, options, availableFunctionNames, jsonMode, {
|
|
258644
|
+
lastTime,
|
|
258645
|
+
boundaryKeys: new Set
|
|
258646
|
+
});
|
|
258647
|
+
}
|
|
258648
|
+
async function pollLogs(functionNames, options, availableFunctionNames, jsonMode, initialState) {
|
|
258649
|
+
let state = initialState;
|
|
258650
|
+
let first = state.lastTime === "";
|
|
258429
258651
|
while (true) {
|
|
258430
258652
|
const pollOptions = first ? options : { ...options, since: state.lastTime };
|
|
258431
258653
|
const entries = await fetchLogsForFunctions(functionNames, pollOptions, availableFunctionNames);
|
|
@@ -258435,7 +258657,7 @@ async function followLogs(functionNames, options, availableFunctionNames, jsonMo
|
|
|
258435
258657
|
for (const entry of fresh)
|
|
258436
258658
|
writeFollowLine(entry, jsonMode);
|
|
258437
258659
|
first = false;
|
|
258438
|
-
await
|
|
258660
|
+
await delay2(2000);
|
|
258439
258661
|
}
|
|
258440
258662
|
}
|
|
258441
258663
|
function formatLogs(entries, env3) {
|
|
@@ -258521,6 +258743,9 @@ async function logsAction(ctx, options) {
|
|
|
258521
258743
|
};
|
|
258522
258744
|
}
|
|
258523
258745
|
if (options.follow) {
|
|
258746
|
+
if (options.since) {
|
|
258747
|
+
throw new InvalidInputError("--since cannot be combined with --follow yet (the realtime stream starts from now).");
|
|
258748
|
+
}
|
|
258524
258749
|
if (options.until) {
|
|
258525
258750
|
throw new InvalidInputError("--until cannot be combined with --follow (a stream has no end).");
|
|
258526
258751
|
}
|
|
@@ -258528,7 +258753,7 @@ async function logsAction(ctx, options) {
|
|
|
258528
258753
|
throw new InvalidInputError("--order cannot be combined with --follow (a live tail always streams oldest to newest).");
|
|
258529
258754
|
}
|
|
258530
258755
|
options.order = "asc";
|
|
258531
|
-
return followLogs(functionNames, options, availableFunctionNames, ctx.jsonMode);
|
|
258756
|
+
return followLogs(functionNames, options, availableFunctionNames, ctx.jsonMode, ctx.log);
|
|
258532
258757
|
}
|
|
258533
258758
|
let entries = await fetchLogsForFunctions(functionNames, options, availableFunctionNames);
|
|
258534
258759
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
|
|
@@ -259030,7 +259255,7 @@ async function deployAction2(ctx, options) {
|
|
|
259030
259255
|
if (isNonInteractive && !options.yes) {
|
|
259031
259256
|
throw new InvalidInputError("--yes is required in non-interactive mode");
|
|
259032
259257
|
}
|
|
259033
|
-
const
|
|
259258
|
+
const project2 = await readProjectSettings();
|
|
259034
259259
|
const outputDirectory = project2.site?.outputDirectory;
|
|
259035
259260
|
if (!outputDirectory) {
|
|
259036
259261
|
throw new ConfigNotFoundError("No site configuration found.", {
|
|
@@ -259267,6 +259492,235 @@ function getTypesCommand() {
|
|
|
259267
259492
|
return new Command("types").description("Manage TypeScript type generation").addCommand(getTypesGenerateCommand());
|
|
259268
259493
|
}
|
|
259269
259494
|
|
|
259495
|
+
// src/core/resources/workflow/schema.ts
|
|
259496
|
+
var WorkflowRunStatusSchema = exports_external.enum([
|
|
259497
|
+
"running",
|
|
259498
|
+
"completed",
|
|
259499
|
+
"failed",
|
|
259500
|
+
"cancelled"
|
|
259501
|
+
]);
|
|
259502
|
+
var WorkflowListItemSchema = exports_external.object({
|
|
259503
|
+
id: exports_external.string(),
|
|
259504
|
+
name: exports_external.string(),
|
|
259505
|
+
description: exports_external.string().nullable().optional(),
|
|
259506
|
+
status: exports_external.string(),
|
|
259507
|
+
status_reason: exports_external.string().nullable().optional(),
|
|
259508
|
+
total_runs: exports_external.number().default(0),
|
|
259509
|
+
consecutive_failures: exports_external.number().default(0),
|
|
259510
|
+
last_run_at: exports_external.string().nullable().optional(),
|
|
259511
|
+
last_run_status: exports_external.string().nullable().optional()
|
|
259512
|
+
}).transform((data) => ({
|
|
259513
|
+
id: data.id,
|
|
259514
|
+
name: data.name,
|
|
259515
|
+
description: data.description ?? null,
|
|
259516
|
+
status: data.status,
|
|
259517
|
+
statusReason: data.status_reason ?? null,
|
|
259518
|
+
totalRuns: data.total_runs,
|
|
259519
|
+
consecutiveFailures: data.consecutive_failures,
|
|
259520
|
+
lastRunAt: data.last_run_at ?? null,
|
|
259521
|
+
lastRunStatus: data.last_run_status ?? null
|
|
259522
|
+
}));
|
|
259523
|
+
var ListWorkflowsResponseSchema = exports_external.array(WorkflowListItemSchema);
|
|
259524
|
+
var WorkflowRunSchema = exports_external.object({
|
|
259525
|
+
run_id: exports_external.string(),
|
|
259526
|
+
workflow_id: exports_external.string(),
|
|
259527
|
+
workflow_name: exports_external.string().default(""),
|
|
259528
|
+
trigger_type: exports_external.string().default(""),
|
|
259529
|
+
status: exports_external.string(),
|
|
259530
|
+
started_at: exports_external.string().nullable().optional(),
|
|
259531
|
+
completed_at: exports_external.string().nullable().optional(),
|
|
259532
|
+
duration_ms: exports_external.number().default(0),
|
|
259533
|
+
steps_count: exports_external.number().default(0),
|
|
259534
|
+
error_message: exports_external.string().nullable().optional(),
|
|
259535
|
+
is_test_run: exports_external.boolean().default(false),
|
|
259536
|
+
status_reason: exports_external.string().default("")
|
|
259537
|
+
}).transform((data) => ({
|
|
259538
|
+
runId: data.run_id,
|
|
259539
|
+
workflowId: data.workflow_id,
|
|
259540
|
+
workflowName: data.workflow_name,
|
|
259541
|
+
triggerType: data.trigger_type,
|
|
259542
|
+
status: data.status,
|
|
259543
|
+
startedAt: data.started_at ?? null,
|
|
259544
|
+
completedAt: data.completed_at ?? null,
|
|
259545
|
+
durationMs: data.duration_ms,
|
|
259546
|
+
stepsCount: data.steps_count,
|
|
259547
|
+
errorMessage: data.error_message ?? null,
|
|
259548
|
+
isTestRun: data.is_test_run,
|
|
259549
|
+
statusReason: data.status_reason
|
|
259550
|
+
}));
|
|
259551
|
+
var ListWorkflowRunsResponseSchema = exports_external.array(WorkflowRunSchema);
|
|
259552
|
+
|
|
259553
|
+
// src/core/resources/workflow/api.ts
|
|
259554
|
+
async function listWorkflows(limit) {
|
|
259555
|
+
const appClient = getAppClient();
|
|
259556
|
+
const searchParams = new URLSearchParams;
|
|
259557
|
+
if (limit !== undefined) {
|
|
259558
|
+
searchParams.set("limit", String(limit));
|
|
259559
|
+
}
|
|
259560
|
+
let response;
|
|
259561
|
+
try {
|
|
259562
|
+
response = await appClient.get("workflows", { searchParams });
|
|
259563
|
+
} catch (error48) {
|
|
259564
|
+
throw await ApiError.fromHttpError(error48, "listing workflows");
|
|
259565
|
+
}
|
|
259566
|
+
const result = ListWorkflowsResponseSchema.safeParse(await response.json());
|
|
259567
|
+
if (!result.success) {
|
|
259568
|
+
throw new SchemaValidationError("Invalid workflows response from server", result.error);
|
|
259569
|
+
}
|
|
259570
|
+
return result.data;
|
|
259571
|
+
}
|
|
259572
|
+
function buildRunsQueryString(filters) {
|
|
259573
|
+
const params = new URLSearchParams;
|
|
259574
|
+
if (filters.status) {
|
|
259575
|
+
params.set("status", filters.status);
|
|
259576
|
+
}
|
|
259577
|
+
if (filters.since) {
|
|
259578
|
+
params.set("since", filters.since);
|
|
259579
|
+
}
|
|
259580
|
+
if (filters.limit !== undefined) {
|
|
259581
|
+
params.set("limit", String(filters.limit));
|
|
259582
|
+
}
|
|
259583
|
+
return params;
|
|
259584
|
+
}
|
|
259585
|
+
async function listWorkflowRuns(filters = {}) {
|
|
259586
|
+
const appClient = getAppClient();
|
|
259587
|
+
let response;
|
|
259588
|
+
try {
|
|
259589
|
+
response = await appClient.get("workflows/runs", {
|
|
259590
|
+
searchParams: buildRunsQueryString(filters)
|
|
259591
|
+
});
|
|
259592
|
+
} catch (error48) {
|
|
259593
|
+
throw await ApiError.fromHttpError(error48, "listing workflow runs");
|
|
259594
|
+
}
|
|
259595
|
+
const result = ListWorkflowRunsResponseSchema.safeParse(await response.json());
|
|
259596
|
+
if (!result.success) {
|
|
259597
|
+
throw new SchemaValidationError("Invalid workflow runs response from server", result.error);
|
|
259598
|
+
}
|
|
259599
|
+
return result.data;
|
|
259600
|
+
}
|
|
259601
|
+
// src/cli/commands/workflows/legacy-app.ts
|
|
259602
|
+
var isWorkflowsNotEnabled = (error48) => error48 instanceof ApiError && error48.statusCode === 403;
|
|
259603
|
+
function rethrowLegacyAppAsExplanation(error48) {
|
|
259604
|
+
if (isWorkflowsNotEnabled(error48)) {
|
|
259605
|
+
throw new InvalidInputError("Workflows are not enabled for this app — it predates the Workflows system, so its automation runs are not readable via this command.");
|
|
259606
|
+
}
|
|
259607
|
+
throw error48;
|
|
259608
|
+
}
|
|
259609
|
+
|
|
259610
|
+
// src/cli/commands/workflows/limit.ts
|
|
259611
|
+
var MAX_LIMIT = 200;
|
|
259612
|
+
function parseLimit(limit) {
|
|
259613
|
+
if (limit === undefined)
|
|
259614
|
+
return;
|
|
259615
|
+
const parsed = Number.parseInt(limit, 10);
|
|
259616
|
+
if (Number.isNaN(parsed) || parsed < 1 || parsed > MAX_LIMIT) {
|
|
259617
|
+
throw new InvalidInputError(`Invalid limit: "${limit}". Must be a number between 1 and ${MAX_LIMIT}.`);
|
|
259618
|
+
}
|
|
259619
|
+
return parsed;
|
|
259620
|
+
}
|
|
259621
|
+
|
|
259622
|
+
// src/cli/commands/workflows/list.ts
|
|
259623
|
+
function formatWorkflowLine(workflow) {
|
|
259624
|
+
const lastRun = workflow.lastRunAt ? `last run ${workflow.lastRunStatus ?? "unknown"} at ${workflow.lastRunAt}` : "never ran";
|
|
259625
|
+
const failures = workflow.consecutiveFailures > 0 ? ` (${workflow.consecutiveFailures} consecutive failures)` : "";
|
|
259626
|
+
return `${workflow.name} [${workflow.status}] runs: ${workflow.totalRuns}, ${lastRun}${failures}`;
|
|
259627
|
+
}
|
|
259628
|
+
async function listAction({ log, runTask: runTask2, jsonMode }, options8) {
|
|
259629
|
+
const limit = parseLimit(options8.limit);
|
|
259630
|
+
const workflows = await runTask2("Fetching workflows from Base44", async () => listWorkflows(limit).catch(rethrowLegacyAppAsExplanation), {
|
|
259631
|
+
successMessage: "Workflows fetched successfully",
|
|
259632
|
+
errorMessage: "Failed to fetch workflows"
|
|
259633
|
+
});
|
|
259634
|
+
if (jsonMode) {
|
|
259635
|
+
return {
|
|
259636
|
+
outroMessage: `Found ${workflows.length} workflows.`,
|
|
259637
|
+
stdout: `${JSON.stringify({ workflows }, null, 2)}
|
|
259638
|
+
`
|
|
259639
|
+
};
|
|
259640
|
+
}
|
|
259641
|
+
if (workflows.length === 0) {
|
|
259642
|
+
return { outroMessage: "This app has no workflows." };
|
|
259643
|
+
}
|
|
259644
|
+
for (const workflow of workflows) {
|
|
259645
|
+
log.info(formatWorkflowLine(workflow));
|
|
259646
|
+
}
|
|
259647
|
+
return { outroMessage: `Found ${workflows.length} workflows.` };
|
|
259648
|
+
}
|
|
259649
|
+
function getWorkflowsListCommand() {
|
|
259650
|
+
return new Base44Command("list").description("List this app's workflows").option("-n, --limit <n>", `Number of workflows to return (1-${MAX_LIMIT}, default: 30)`).action(listAction);
|
|
259651
|
+
}
|
|
259652
|
+
|
|
259653
|
+
// src/cli/commands/workflows/runs.ts
|
|
259654
|
+
function formatDuration2(durationMs) {
|
|
259655
|
+
if (durationMs === 0)
|
|
259656
|
+
return "";
|
|
259657
|
+
return ` ${(durationMs / 1000).toFixed(1)}s`;
|
|
259658
|
+
}
|
|
259659
|
+
function formatRunTags(run) {
|
|
259660
|
+
const tags = [run.triggerType, run.isTestRun ? "test" : null].filter(Boolean);
|
|
259661
|
+
return tags.length > 0 ? ` (${tags.join(", ")})` : "";
|
|
259662
|
+
}
|
|
259663
|
+
function formatFailureDetail(run) {
|
|
259664
|
+
const reason = run.statusReason ? ` [${run.statusReason}]` : "";
|
|
259665
|
+
const message = run.errorMessage ? `
|
|
259666
|
+
${run.errorMessage}` : "";
|
|
259667
|
+
return `${reason}${message}`;
|
|
259668
|
+
}
|
|
259669
|
+
function formatRunLine(run) {
|
|
259670
|
+
const time3 = (run.startedAt ?? "").substring(0, 19).replace("T", " ");
|
|
259671
|
+
const status = run.status.toUpperCase().padEnd(9);
|
|
259672
|
+
const base = `${time3} ${status} ${run.workflowName}${formatRunTags(run)}${formatDuration2(run.durationMs)}`;
|
|
259673
|
+
const failureDetail = run.status === "failed" || run.status === "cancelled" ? formatFailureDetail(run) : "";
|
|
259674
|
+
return `${base}${failureDetail}`;
|
|
259675
|
+
}
|
|
259676
|
+
async function describeEmptyResult(hasFilters) {
|
|
259677
|
+
const workflows = await listWorkflows().catch(() => null);
|
|
259678
|
+
if (workflows === null) {
|
|
259679
|
+
return "No runs found.";
|
|
259680
|
+
}
|
|
259681
|
+
if (workflows.length === 0) {
|
|
259682
|
+
return "This app has no workflows, so there are no runs.";
|
|
259683
|
+
}
|
|
259684
|
+
const names = workflows.map((workflow) => workflow.name).join(", ");
|
|
259685
|
+
return hasFilters ? `No runs match your filters. Workflows in this app: ${names}.` : `No runs yet. Workflows in this app: ${names}.`;
|
|
259686
|
+
}
|
|
259687
|
+
async function runsAction(ctx, options8) {
|
|
259688
|
+
const limit = parseLimit(options8.limit);
|
|
259689
|
+
const runs = await ctx.runTask("Fetching workflow runs from Base44", async () => listWorkflowRuns({
|
|
259690
|
+
status: options8.status,
|
|
259691
|
+
since: options8.since,
|
|
259692
|
+
limit
|
|
259693
|
+
}).catch(rethrowLegacyAppAsExplanation), {
|
|
259694
|
+
successMessage: "Workflow runs fetched successfully",
|
|
259695
|
+
errorMessage: "Failed to fetch workflow runs"
|
|
259696
|
+
});
|
|
259697
|
+
if (ctx.jsonMode) {
|
|
259698
|
+
return {
|
|
259699
|
+
outroMessage: `Found ${runs.length} runs.`,
|
|
259700
|
+
stdout: `${JSON.stringify({ runs }, null, 2)}
|
|
259701
|
+
`
|
|
259702
|
+
};
|
|
259703
|
+
}
|
|
259704
|
+
if (runs.length === 0) {
|
|
259705
|
+
const hasFilters = Boolean(options8.status || options8.since);
|
|
259706
|
+
return { outroMessage: await describeEmptyResult(hasFilters) };
|
|
259707
|
+
}
|
|
259708
|
+
for (const run of runs) {
|
|
259709
|
+
ctx.log.info(formatRunLine(run));
|
|
259710
|
+
}
|
|
259711
|
+
return { outroMessage: `Found ${runs.length} runs.` };
|
|
259712
|
+
}
|
|
259713
|
+
function getWorkflowsRunsCommand() {
|
|
259714
|
+
return new Base44Command("runs").description("List workflow runs for this app, newest first (includes scheduled, manual, and test runs)").addOption(new Option("--status <status>", "Filter by run status").choices([
|
|
259715
|
+
...WorkflowRunStatusSchema.options
|
|
259716
|
+
])).option("--since <datetime>", "Show runs started after this time. ISO datetime or relative shorthand (e.g. 1h, 30m, 2d)", normalizeDatetime).option("-n, --limit <n>", `Number of runs to return (1-${MAX_LIMIT}, default: 30)`).action(runsAction);
|
|
259717
|
+
}
|
|
259718
|
+
|
|
259719
|
+
// src/cli/commands/workflows/index.ts
|
|
259720
|
+
function getWorkflowsCommand() {
|
|
259721
|
+
return new Command("workflows").description("Inspect this app's workflows and their runs").addCommand(getWorkflowsListCommand()).addCommand(getWorkflowsRunsCommand());
|
|
259722
|
+
}
|
|
259723
|
+
|
|
259270
259724
|
// src/cli/commands/workspace/shared.ts
|
|
259271
259725
|
function workspaceTag(workspace2) {
|
|
259272
259726
|
const role = workspace2.userRole ?? "member";
|
|
@@ -260261,7 +260715,8 @@ var fieldTypes = [
|
|
|
260261
260715
|
"number",
|
|
260262
260716
|
"boolean",
|
|
260263
260717
|
"array",
|
|
260264
|
-
"object"
|
|
260718
|
+
"object",
|
|
260719
|
+
"null"
|
|
260265
260720
|
];
|
|
260266
260721
|
|
|
260267
260722
|
class Validator {
|
|
@@ -260321,6 +260776,14 @@ class Validator {
|
|
|
260321
260776
|
if (!property) {
|
|
260322
260777
|
return { hasError: false };
|
|
260323
260778
|
}
|
|
260779
|
+
if (Array.isArray(property.type)) {
|
|
260780
|
+
const types = property.type;
|
|
260781
|
+
const matched = types.some((type) => !this.validateValue(value, { ...property, type }, fieldPath).hasError);
|
|
260782
|
+
return matched ? { hasError: false } : {
|
|
260783
|
+
hasError: true,
|
|
260784
|
+
error: this.createValidationError(`Error in field ${fieldPath}: Input should be a valid ${types.join(" or ")}`)
|
|
260785
|
+
};
|
|
260786
|
+
}
|
|
260324
260787
|
const propertyType = property.type;
|
|
260325
260788
|
if (!fieldTypes.includes(propertyType)) {
|
|
260326
260789
|
return {
|
|
@@ -260361,6 +260824,14 @@ class Validator {
|
|
|
260361
260824
|
}
|
|
260362
260825
|
}
|
|
260363
260826
|
break;
|
|
260827
|
+
case "null":
|
|
260828
|
+
if (value !== null) {
|
|
260829
|
+
return {
|
|
260830
|
+
hasError: true,
|
|
260831
|
+
error: this.createValidationError(`Error in field ${fieldPath}: Input should be null`)
|
|
260832
|
+
};
|
|
260833
|
+
}
|
|
260834
|
+
break;
|
|
260364
260835
|
case "integer":
|
|
260365
260836
|
if (!Number.isInteger(value)) {
|
|
260366
260837
|
return {
|
|
@@ -260780,7 +261251,9 @@ function evaluateCondition(condition, record2, user) {
|
|
|
260780
261251
|
function checkRLS(rule, record2, user) {
|
|
260781
261252
|
if (user?.is_service === true)
|
|
260782
261253
|
return true;
|
|
260783
|
-
if (rule === undefined)
|
|
261254
|
+
if (rule === undefined || rule === null || rule === "")
|
|
261255
|
+
return true;
|
|
261256
|
+
if (typeof rule === "object" && Object.keys(rule).length === 0)
|
|
260784
261257
|
return true;
|
|
260785
261258
|
if (typeof rule === "boolean")
|
|
260786
261259
|
return rule;
|
|
@@ -263331,6 +263804,10 @@ function validateDevOptions(command2) {
|
|
|
263331
263804
|
if (appId !== undefined) {
|
|
263332
263805
|
command2.error(`base44 dev cannot be used with --app-id or ${BASE44_APP_ID_ENV_VAR}.`);
|
|
263333
263806
|
}
|
|
263807
|
+
const { port, remote } = command2.opts();
|
|
263808
|
+
if (remote && port !== undefined) {
|
|
263809
|
+
command2.error("--port applies to the local backend, which --remote does not start.");
|
|
263810
|
+
}
|
|
263334
263811
|
}
|
|
263335
263812
|
function requireLinkedProject({ app }) {
|
|
263336
263813
|
if (!app?.projectRoot) {
|
|
@@ -263338,31 +263815,44 @@ function requireLinkedProject({ app }) {
|
|
|
263338
263815
|
}
|
|
263339
263816
|
return { id: app.id, projectRoot: app.projectRoot };
|
|
263340
263817
|
}
|
|
263341
|
-
async function
|
|
263818
|
+
async function resolveConfiguredSite(app) {
|
|
263342
263819
|
const { project: project2 } = await readProjectConfig(app.projectRoot);
|
|
263343
263820
|
const serveCommand = project2.site?.serveCommand;
|
|
263344
|
-
|
|
263345
|
-
return;
|
|
263346
|
-
}
|
|
263347
|
-
return createServeCommandRunner({
|
|
263348
|
-
serveCommand,
|
|
263349
|
-
projectRoot: project2.root,
|
|
263350
|
-
appId: app.id,
|
|
263351
|
-
appBaseUrl: backendUrl
|
|
263352
|
-
});
|
|
263821
|
+
return serveCommand ? { serveCommand, projectRoot: project2.root } : undefined;
|
|
263353
263822
|
}
|
|
263354
|
-
function
|
|
263823
|
+
function stopRunnerOnProcessSignals(runner) {
|
|
263355
263824
|
const stop2 = () => void runner.stop();
|
|
263356
263825
|
process.on("SIGINT", stop2);
|
|
263357
263826
|
process.on("SIGTERM", stop2);
|
|
263827
|
+
}
|
|
263828
|
+
function startServeCommand(runner, backend) {
|
|
263829
|
+
stopRunnerOnProcessSignals(runner);
|
|
263358
263830
|
runner.onExit(() => {
|
|
263359
263831
|
backend.shutdown().finally(() => process.exit(1));
|
|
263360
263832
|
});
|
|
263361
263833
|
createDevLogger("backend", theme.styles.info).log(`Backend running on ${backend.url}`);
|
|
263362
263834
|
runner.start();
|
|
263363
263835
|
}
|
|
263364
|
-
async function
|
|
263365
|
-
const
|
|
263836
|
+
async function remoteDevAction(app) {
|
|
263837
|
+
const site2 = await resolveConfiguredSite(app);
|
|
263838
|
+
if (!site2) {
|
|
263839
|
+
throw new ConfigInvalidError("base44 dev --remote serves the frontend against the production backend, but this project has no site.serveCommand in base44/config.jsonc.");
|
|
263840
|
+
}
|
|
263841
|
+
const appBaseUrl = await getSiteUrl();
|
|
263842
|
+
const runner = createServeCommandRunner({
|
|
263843
|
+
...site2,
|
|
263844
|
+
appId: app.id,
|
|
263845
|
+
appBaseUrl
|
|
263846
|
+
});
|
|
263847
|
+
stopRunnerOnProcessSignals(runner);
|
|
263848
|
+
runner.onExit((code2) => process.exit(code2 ?? 1));
|
|
263849
|
+
runner.start();
|
|
263850
|
+
return {
|
|
263851
|
+
outroMessage: `Frontend dev server targets ${theme.styles.bold(appBaseUrl)} — every write hits your live app`
|
|
263852
|
+
};
|
|
263853
|
+
}
|
|
263854
|
+
async function localDevAction(ctx, app, options8) {
|
|
263855
|
+
const site2 = await resolveConfiguredSite(app);
|
|
263366
263856
|
const siteUrlPromise = getSiteUrl().catch(() => {
|
|
263367
263857
|
return;
|
|
263368
263858
|
});
|
|
@@ -263377,15 +263867,23 @@ async function devAction(ctx, options8) {
|
|
|
263377
263867
|
}
|
|
263378
263868
|
});
|
|
263379
263869
|
const backendUrl = localServerUrl(backend.port);
|
|
263380
|
-
|
|
263381
|
-
|
|
263870
|
+
if (site2) {
|
|
263871
|
+
const runner = createServeCommandRunner({
|
|
263872
|
+
...site2,
|
|
263873
|
+
appId: app.id,
|
|
263874
|
+
appBaseUrl: backendUrl
|
|
263875
|
+
});
|
|
263382
263876
|
startServeCommand(runner, { url: backendUrl, shutdown: backend.shutdown });
|
|
263383
263877
|
}
|
|
263384
|
-
const outroMessage =
|
|
263878
|
+
const outroMessage = site2 ? "Open your app using the frontend dev server URL" : `Dev server is available at ${theme.colors.links(backendUrl)}`;
|
|
263385
263879
|
return { outroMessage };
|
|
263386
263880
|
}
|
|
263881
|
+
async function devAction(ctx, options8) {
|
|
263882
|
+
const app = requireLinkedProject(ctx);
|
|
263883
|
+
return options8.remote ? remoteDevAction(app) : localDevAction(ctx, app, options8);
|
|
263884
|
+
}
|
|
263387
263885
|
function getDevCommand() {
|
|
263388
|
-
return new Base44Command("dev").description("Start the development server").option("-p, --port <number>", "Port for the development server").hook("preAction", validateDevOptions).action(devAction);
|
|
263886
|
+
return new Base44Command("dev").description("Start the development server").option("-p, --port <number>", "Port for the development server").option("--remote", "Serve the frontend against the production backend instead of a local one").hook("preAction", validateDevOptions).action(devAction);
|
|
263389
263887
|
}
|
|
263390
263888
|
|
|
263391
263889
|
// src/core/exec/run-script.ts
|
|
@@ -263648,6 +264146,7 @@ function createProgram(context) {
|
|
|
263648
264146
|
program2.addCommand(getAgentSkillsCommand());
|
|
263649
264147
|
program2.addCommand(getConnectorsCommand());
|
|
263650
264148
|
program2.addCommand(getFunctionsCommand());
|
|
264149
|
+
program2.addCommand(getWorkflowsCommand());
|
|
263651
264150
|
program2.addCommand(getSecretsCommand());
|
|
263652
264151
|
program2.addCommand(getSandboxCommand());
|
|
263653
264152
|
program2.addCommand(getAuthCommand());
|
|
@@ -267903,4 +268402,4 @@ export {
|
|
|
267903
268402
|
CLIExitError
|
|
267904
268403
|
};
|
|
267905
268404
|
|
|
267906
|
-
//# debugId=
|
|
268405
|
+
//# debugId=844375621C10BF7464756E2164756E21
|