@base44-preview/cli 0.0.32-pr.269.2da16d6 → 0.0.33-pr.225.220b697
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/README.md +9 -7
- package/dist/cli/index.js +457 -15
- package/dist/cli/index.js.map +15 -11
- package/dist/deno-runtime/main.js +31 -0
- package/dist/deno-runtime/main.js.map +10 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -44,21 +44,23 @@ The CLI will guide you through project setup. For step-by-step tutorials, see th
|
|
|
44
44
|
| Command | Description |
|
|
45
45
|
| ------- | ----------- |
|
|
46
46
|
| [`create`](https://docs.base44.com/developers/references/cli/commands/create) | Create a new Base44 project from a template |
|
|
47
|
-
| [`deploy`](https://docs.base44.com/developers/references/cli/commands/deploy) | Deploy resources and site to Base44 |
|
|
48
|
-
| [`
|
|
47
|
+
| [`deploy`](https://docs.base44.com/developers/references/cli/commands/deploy) | Deploy all project resources and site to Base44 |
|
|
48
|
+
| [`eject`](https://docs.base44.com/developers/references/cli/commands/eject) | Download the code for an existing Base44 project |
|
|
49
|
+
| [`link`](https://docs.base44.com/developers/references/cli/commands/link) | Link a local project to a Base44 project |
|
|
49
50
|
| [`dashboard open`](https://docs.base44.com/developers/references/cli/commands/dashboard) | Open the app dashboard in your browser |
|
|
50
51
|
| [`login`](https://docs.base44.com/developers/references/cli/commands/login) | Authenticate with Base44 |
|
|
51
52
|
| [`logout`](https://docs.base44.com/developers/references/cli/commands/logout) | Sign out and clear stored credentials |
|
|
52
53
|
| [`whoami`](https://docs.base44.com/developers/references/cli/commands/whoami) | Display the current authenticated user |
|
|
53
54
|
| [`agents pull`](https://docs.base44.com/developers/references/cli/commands/agents-pull) | Pull agents from Base44 to local files |
|
|
54
55
|
| [`agents push`](https://docs.base44.com/developers/references/cli/commands/agents-push) | Push local agents to Base44 |
|
|
55
|
-
| [`
|
|
56
|
+
| [`connectors pull`](https://docs.base44.com/developers/references/cli/commands/connectors-pull) | Pull connectors from Base44 to local files |
|
|
57
|
+
| [`connectors push`](https://docs.base44.com/developers/references/cli/commands/connectors-push) | Push local connectors to Base44 |
|
|
58
|
+
| [`entities push`](https://docs.base44.com/developers/references/cli/commands/entities-push) | Push local entities to Base44 |
|
|
56
59
|
| [`functions deploy`](https://docs.base44.com/developers/references/cli/commands/functions-deploy) | Deploy local functions to Base44 |
|
|
60
|
+
| `logs` | Fetch function logs for this app |
|
|
57
61
|
| [`site deploy`](https://docs.base44.com/developers/references/cli/commands/site-deploy) | Deploy built site files to Base44 hosting |
|
|
58
62
|
| [`site open`](https://docs.base44.com/developers/references/cli/commands/site-open) | Open the published site in your browser |
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
<!--| [`eject`](https://docs.base44.com/developers/references/cli/commands/eject) | Create a Base44 backend project from an existing Base44 app | -->
|
|
63
|
+
| [`types generate`](https://docs.base44.com/developers/references/cli/commands/types-generate) | Generate TypeScript types from project resources |
|
|
62
64
|
|
|
63
65
|
## AI agent skills
|
|
64
66
|
|
|
@@ -91,4 +93,4 @@ Found a bug? [Open an issue](https://github.com/base44/cli/issues).
|
|
|
91
93
|
|
|
92
94
|
## License
|
|
93
95
|
|
|
94
|
-
|
|
96
|
+
MIT
|
package/dist/cli/index.js
CHANGED
|
@@ -178514,6 +178514,18 @@ class InvalidInputError extends UserError {
|
|
|
178514
178514
|
code = "INVALID_INPUT";
|
|
178515
178515
|
}
|
|
178516
178516
|
|
|
178517
|
+
class DependencyNotFoundError extends UserError {
|
|
178518
|
+
code = "DEPENDENCY_NOT_FOUND";
|
|
178519
|
+
constructor(message, options) {
|
|
178520
|
+
super(message, {
|
|
178521
|
+
hints: options?.hints ?? [
|
|
178522
|
+
{ message: "Install the required dependency and try again" }
|
|
178523
|
+
],
|
|
178524
|
+
cause: options?.cause
|
|
178525
|
+
});
|
|
178526
|
+
}
|
|
178527
|
+
}
|
|
178528
|
+
|
|
178517
178529
|
class ApiError extends SystemError {
|
|
178518
178530
|
code = "API_ERROR";
|
|
178519
178531
|
statusCode;
|
|
@@ -178545,9 +178557,10 @@ class ApiError extends SystemError {
|
|
|
178545
178557
|
} catch {
|
|
178546
178558
|
message = error48.message;
|
|
178547
178559
|
}
|
|
178560
|
+
const statusCode = ApiError.normalizeStatusCode(error48.response.status, responseBody);
|
|
178548
178561
|
const requestBody = error48.options.context?.__requestBody;
|
|
178549
178562
|
return new ApiError(`Error ${context}: ${message}`, {
|
|
178550
|
-
statusCode
|
|
178563
|
+
statusCode,
|
|
178551
178564
|
requestUrl: error48.request.url,
|
|
178552
178565
|
requestMethod: error48.request.method,
|
|
178553
178566
|
requestBody,
|
|
@@ -178604,6 +178617,12 @@ class ApiError extends SystemError {
|
|
|
178604
178617
|
return;
|
|
178605
178618
|
return REASON_HINTS[reason];
|
|
178606
178619
|
}
|
|
178620
|
+
static normalizeStatusCode(statusCode, responseBody) {
|
|
178621
|
+
if (responseBody?.error_type === "KeyError") {
|
|
178622
|
+
return 404;
|
|
178623
|
+
}
|
|
178624
|
+
return statusCode;
|
|
178625
|
+
}
|
|
178607
178626
|
}
|
|
178608
178627
|
|
|
178609
178628
|
class FileNotFoundError extends SystemError {
|
|
@@ -178629,6 +178648,21 @@ class FileReadError extends SystemError {
|
|
|
178629
178648
|
});
|
|
178630
178649
|
}
|
|
178631
178650
|
}
|
|
178651
|
+
|
|
178652
|
+
class InternalError extends SystemError {
|
|
178653
|
+
code = "INTERNAL_ERROR";
|
|
178654
|
+
constructor(message, options) {
|
|
178655
|
+
super(message, {
|
|
178656
|
+
hints: options?.hints ?? [
|
|
178657
|
+
{
|
|
178658
|
+
message: "This is an unexpected error. Please report it if it persists."
|
|
178659
|
+
}
|
|
178660
|
+
],
|
|
178661
|
+
cause: options?.cause
|
|
178662
|
+
});
|
|
178663
|
+
}
|
|
178664
|
+
}
|
|
178665
|
+
|
|
178632
178666
|
class TypeGenerationError extends SystemError {
|
|
178633
178667
|
code = "TYPE_GENERATION_ERROR";
|
|
178634
178668
|
constructor(message, entityName, cause) {
|
|
@@ -185985,6 +186019,13 @@ var DeployFunctionsResponseSchema = exports_external.object({
|
|
|
185985
186019
|
skipped: exports_external.array(exports_external.string()).optional().nullable(),
|
|
185986
186020
|
errors: exports_external.array(exports_external.object({ name: exports_external.string(), message: exports_external.string() })).nullable()
|
|
185987
186021
|
});
|
|
186022
|
+
var LogLevelSchema = exports_external.enum(["log", "info", "warn", "error", "debug"]);
|
|
186023
|
+
var FunctionLogEntrySchema = exports_external.object({
|
|
186024
|
+
time: exports_external.string(),
|
|
186025
|
+
level: LogLevelSchema,
|
|
186026
|
+
message: exports_external.string()
|
|
186027
|
+
});
|
|
186028
|
+
var FunctionLogsResponseSchema = exports_external.array(FunctionLogEntrySchema);
|
|
185988
186029
|
|
|
185989
186030
|
// src/core/resources/function/api.ts
|
|
185990
186031
|
function toDeployPayloadItem(fn) {
|
|
@@ -186015,6 +186056,42 @@ async function deployFunctions(functions) {
|
|
|
186015
186056
|
}
|
|
186016
186057
|
return result.data;
|
|
186017
186058
|
}
|
|
186059
|
+
function buildLogsQueryString(filters) {
|
|
186060
|
+
const params = new URLSearchParams;
|
|
186061
|
+
if (filters.since) {
|
|
186062
|
+
params.set("since", filters.since);
|
|
186063
|
+
}
|
|
186064
|
+
if (filters.until) {
|
|
186065
|
+
params.set("until", filters.until);
|
|
186066
|
+
}
|
|
186067
|
+
if (filters.level) {
|
|
186068
|
+
params.set("level", filters.level);
|
|
186069
|
+
}
|
|
186070
|
+
if (filters.limit !== undefined) {
|
|
186071
|
+
params.set("limit", String(filters.limit));
|
|
186072
|
+
}
|
|
186073
|
+
if (filters.order) {
|
|
186074
|
+
params.set("order", filters.order);
|
|
186075
|
+
}
|
|
186076
|
+
return params;
|
|
186077
|
+
}
|
|
186078
|
+
async function fetchFunctionLogs(functionName, filters = {}) {
|
|
186079
|
+
const appClient = getAppClient();
|
|
186080
|
+
const searchParams = buildLogsQueryString(filters);
|
|
186081
|
+
let response;
|
|
186082
|
+
try {
|
|
186083
|
+
response = await appClient.get(`functions-mgmt/${functionName}/logs`, {
|
|
186084
|
+
searchParams
|
|
186085
|
+
});
|
|
186086
|
+
} catch (error48) {
|
|
186087
|
+
throw await ApiError.fromHttpError(error48, `fetching function logs: '${functionName}'`);
|
|
186088
|
+
}
|
|
186089
|
+
const result = FunctionLogsResponseSchema.safeParse(await response.json());
|
|
186090
|
+
if (!result.success) {
|
|
186091
|
+
throw new SchemaValidationError("Invalid function logs response from server", result.error);
|
|
186092
|
+
}
|
|
186093
|
+
return result.data;
|
|
186094
|
+
}
|
|
186018
186095
|
// src/core/resources/function/config.ts
|
|
186019
186096
|
import { dirname as dirname4, join as join5 } from "node:path";
|
|
186020
186097
|
async function readFunctionConfig(configPath) {
|
|
@@ -187064,7 +187141,9 @@ var theme = {
|
|
|
187064
187141
|
styles: {
|
|
187065
187142
|
header: source_default.dim,
|
|
187066
187143
|
bold: source_default.bold,
|
|
187067
|
-
dim: source_default.dim
|
|
187144
|
+
dim: source_default.dim,
|
|
187145
|
+
error: source_default.red,
|
|
187146
|
+
warn: source_default.yellow
|
|
187068
187147
|
},
|
|
187069
187148
|
format: {
|
|
187070
187149
|
errorContext(ctx) {
|
|
@@ -193846,7 +193925,7 @@ var {
|
|
|
193846
193925
|
// package.json
|
|
193847
193926
|
var package_default = {
|
|
193848
193927
|
name: "base44",
|
|
193849
|
-
version: "0.0.
|
|
193928
|
+
version: "0.0.33",
|
|
193850
193929
|
description: "Base44 CLI - Unified interface for managing Base44 applications",
|
|
193851
193930
|
type: "module",
|
|
193852
193931
|
bin: {
|
|
@@ -193887,6 +193966,7 @@ var package_default = {
|
|
|
193887
193966
|
"@types/bun": "^1.2.15",
|
|
193888
193967
|
"@types/common-tags": "^1.8.4",
|
|
193889
193968
|
"@types/cors": "^2.8.19",
|
|
193969
|
+
"@types/deno": "^2.5.0",
|
|
193890
193970
|
"@types/ejs": "^3.1.5",
|
|
193891
193971
|
"@types/express": "^5.0.6",
|
|
193892
193972
|
"@types/json-schema": "^7.0.15",
|
|
@@ -193973,7 +194053,6 @@ async function printUpgradeNotificationIfAvailable() {
|
|
|
193973
194053
|
|
|
193974
194054
|
// src/cli/utils/runCommand.ts
|
|
193975
194055
|
async function runCommand(commandFn, options, context) {
|
|
193976
|
-
console.log();
|
|
193977
194056
|
if (options?.fullBanner) {
|
|
193978
194057
|
await printBanner(context.isNonInteractive);
|
|
193979
194058
|
We("");
|
|
@@ -193999,8 +194078,11 @@ async function runCommand(commandFn, options, context) {
|
|
|
193999
194078
|
const appConfig = await initAppConfig();
|
|
194000
194079
|
context.errorReporter.setContext({ appId: appConfig.id });
|
|
194001
194080
|
}
|
|
194002
|
-
const
|
|
194003
|
-
Le(outroMessage || "");
|
|
194081
|
+
const result = await commandFn();
|
|
194082
|
+
Le(result.outroMessage || "");
|
|
194083
|
+
if (result.stdout) {
|
|
194084
|
+
process.stdout.write(result.stdout);
|
|
194085
|
+
}
|
|
194004
194086
|
} catch (error48) {
|
|
194005
194087
|
const errorMessage = error48 instanceof Error ? error48.message : String(error48);
|
|
194006
194088
|
R2.error(errorMessage);
|
|
@@ -195027,6 +195109,122 @@ function getFunctionsDeployCommand(context) {
|
|
|
195027
195109
|
}));
|
|
195028
195110
|
}
|
|
195029
195111
|
|
|
195112
|
+
// src/cli/commands/project/logs.ts
|
|
195113
|
+
function parseFunctionFilters(options) {
|
|
195114
|
+
const filters = {};
|
|
195115
|
+
if (options.since) {
|
|
195116
|
+
filters.since = options.since;
|
|
195117
|
+
}
|
|
195118
|
+
if (options.until) {
|
|
195119
|
+
filters.until = options.until;
|
|
195120
|
+
}
|
|
195121
|
+
if (options.limit) {
|
|
195122
|
+
filters.limit = Number.parseInt(options.limit, 10);
|
|
195123
|
+
}
|
|
195124
|
+
if (options.order) {
|
|
195125
|
+
filters.order = options.order.toLowerCase();
|
|
195126
|
+
}
|
|
195127
|
+
return filters;
|
|
195128
|
+
}
|
|
195129
|
+
function parseFunctionNames(option) {
|
|
195130
|
+
if (!option)
|
|
195131
|
+
return [];
|
|
195132
|
+
return option.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
195133
|
+
}
|
|
195134
|
+
function normalizeDatetime(value) {
|
|
195135
|
+
if (/Z$|[+-]\d{2}:\d{2}$/.test(value))
|
|
195136
|
+
return value;
|
|
195137
|
+
return `${value}Z`;
|
|
195138
|
+
}
|
|
195139
|
+
function formatEntry(entry) {
|
|
195140
|
+
const time3 = entry.time.substring(0, 19).replace("T", " ");
|
|
195141
|
+
const level = entry.level.toUpperCase().padEnd(5);
|
|
195142
|
+
const message = entry.message.trim();
|
|
195143
|
+
return `${time3} ${level} ${message}`;
|
|
195144
|
+
}
|
|
195145
|
+
function formatLogs(entries) {
|
|
195146
|
+
if (entries.length === 0) {
|
|
195147
|
+
return `No logs found matching the filters.
|
|
195148
|
+
`;
|
|
195149
|
+
}
|
|
195150
|
+
const header2 = `Showing ${entries.length} function log entries
|
|
195151
|
+
`;
|
|
195152
|
+
return [header2, ...entries.map(formatEntry)].join(`
|
|
195153
|
+
`);
|
|
195154
|
+
}
|
|
195155
|
+
function normalizeLogEntry(entry, functionName) {
|
|
195156
|
+
return {
|
|
195157
|
+
time: entry.time,
|
|
195158
|
+
level: entry.level,
|
|
195159
|
+
message: `[${functionName}] ${entry.message}`,
|
|
195160
|
+
source: functionName
|
|
195161
|
+
};
|
|
195162
|
+
}
|
|
195163
|
+
async function fetchLogsForFunctions(functionNames, options, availableFunctionNames) {
|
|
195164
|
+
const filters = parseFunctionFilters(options);
|
|
195165
|
+
const allEntries = [];
|
|
195166
|
+
for (const functionName of functionNames) {
|
|
195167
|
+
let logs;
|
|
195168
|
+
try {
|
|
195169
|
+
logs = await fetchFunctionLogs(functionName, filters);
|
|
195170
|
+
} catch (error48) {
|
|
195171
|
+
if (error48 instanceof ApiError && error48.statusCode === 404 && availableFunctionNames.length > 0) {
|
|
195172
|
+
const available = availableFunctionNames.join(", ");
|
|
195173
|
+
throw new InvalidInputError(`Function "${functionName}" was not found in this app`, {
|
|
195174
|
+
hints: [
|
|
195175
|
+
{
|
|
195176
|
+
message: `Available functions in this project: ${available}`
|
|
195177
|
+
},
|
|
195178
|
+
{
|
|
195179
|
+
message: "Make sure the function has been deployed before fetching logs",
|
|
195180
|
+
command: "base44 functions deploy"
|
|
195181
|
+
}
|
|
195182
|
+
]
|
|
195183
|
+
});
|
|
195184
|
+
}
|
|
195185
|
+
throw error48;
|
|
195186
|
+
}
|
|
195187
|
+
const entries = logs.map((entry) => normalizeLogEntry(entry, functionName));
|
|
195188
|
+
allEntries.push(...entries);
|
|
195189
|
+
}
|
|
195190
|
+
if (functionNames.length > 1) {
|
|
195191
|
+
const order = options.order?.toUpperCase() === "ASC" ? 1 : -1;
|
|
195192
|
+
allEntries.sort((a2, b) => order * a2.time.localeCompare(b.time));
|
|
195193
|
+
}
|
|
195194
|
+
return allEntries;
|
|
195195
|
+
}
|
|
195196
|
+
async function getAllFunctionNames() {
|
|
195197
|
+
const { functions } = await readProjectConfig();
|
|
195198
|
+
return functions.map((fn) => fn.name);
|
|
195199
|
+
}
|
|
195200
|
+
async function logsAction(options) {
|
|
195201
|
+
const specifiedFunctions = parseFunctionNames(options.function);
|
|
195202
|
+
const allProjectFunctions = await getAllFunctionNames();
|
|
195203
|
+
const functionNames = specifiedFunctions.length > 0 ? specifiedFunctions : allProjectFunctions;
|
|
195204
|
+
if (functionNames.length === 0) {
|
|
195205
|
+
return { outroMessage: "No functions found in this project." };
|
|
195206
|
+
}
|
|
195207
|
+
let entries = await fetchLogsForFunctions(functionNames, options, allProjectFunctions);
|
|
195208
|
+
const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
|
|
195209
|
+
if (limit !== undefined && entries.length > limit) {
|
|
195210
|
+
entries = entries.slice(0, limit);
|
|
195211
|
+
}
|
|
195212
|
+
const logsOutput = options.json ? `${JSON.stringify(entries, null, 2)}
|
|
195213
|
+
` : formatLogs(entries);
|
|
195214
|
+
return { outroMessage: "Fetched logs", stdout: logsOutput };
|
|
195215
|
+
}
|
|
195216
|
+
function getLogsCommand(context) {
|
|
195217
|
+
return new Command("logs").description("Fetch function logs for this app").option("--function <names>", "Filter by function name(s), comma-separated. If omitted, fetches logs for all project functions").option("--since <datetime>", "Show logs from this time (ISO format)", normalizeDatetime).option("--until <datetime>", "Show logs until this time (ISO format)", normalizeDatetime).option("-n, --limit <n>", "Results per page (1-1000, default: 50)", (v) => {
|
|
195218
|
+
const n2 = Number.parseInt(v, 10);
|
|
195219
|
+
if (Number.isNaN(n2) || n2 < 1 || n2 > 1000) {
|
|
195220
|
+
throw new InvalidInputError(`Invalid limit: "${v}". Must be a number between 1 and 1000.`);
|
|
195221
|
+
}
|
|
195222
|
+
return v;
|
|
195223
|
+
}).addOption(new Option("--order <order>", "Sort order").choices(["asc", "desc"])).option("--json", "Output raw JSON").action(async (options) => {
|
|
195224
|
+
await runCommand(() => logsAction(options), { requireAuth: true }, context);
|
|
195225
|
+
});
|
|
195226
|
+
}
|
|
195227
|
+
|
|
195030
195228
|
// src/cli/commands/project/create.ts
|
|
195031
195229
|
import { basename as basename3, join as join11, resolve as resolve2 } from "node:path";
|
|
195032
195230
|
var import_lodash = __toESM(require_lodash(), 1);
|
|
@@ -195610,9 +195808,12 @@ function getTypesCommand(context) {
|
|
|
195610
195808
|
return new Command("types").description("Manage TypeScript type generation").addCommand(getTypesGenerateCommand(context));
|
|
195611
195809
|
}
|
|
195612
195810
|
|
|
195811
|
+
// src/cli/commands/dev.ts
|
|
195812
|
+
import { dirname as dirname12, join as join16 } from "node:path";
|
|
195813
|
+
|
|
195613
195814
|
// src/cli/dev/dev-server/main.ts
|
|
195614
195815
|
var import_cors = __toESM(require_lib4(), 1);
|
|
195615
|
-
var
|
|
195816
|
+
var import_express2 = __toESM(require_express(), 1);
|
|
195616
195817
|
|
|
195617
195818
|
// node_modules/get-port/index.js
|
|
195618
195819
|
import net from "node:net";
|
|
@@ -195729,13 +195930,232 @@ async function getPorts(options8) {
|
|
|
195729
195930
|
}
|
|
195730
195931
|
|
|
195731
195932
|
// src/cli/dev/dev-server/main.ts
|
|
195933
|
+
var import_http_proxy_middleware2 = __toESM(require_dist2(), 1);
|
|
195934
|
+
|
|
195935
|
+
// src/cli/dev/createDevLogger.ts
|
|
195936
|
+
var colorByType = {
|
|
195937
|
+
error: theme.styles.error,
|
|
195938
|
+
warn: theme.styles.warn,
|
|
195939
|
+
log: (text) => text
|
|
195940
|
+
};
|
|
195941
|
+
function createDevLogger() {
|
|
195942
|
+
const print = (type, msg) => {
|
|
195943
|
+
const colorize = colorByType[type];
|
|
195944
|
+
console[type](colorize(msg));
|
|
195945
|
+
};
|
|
195946
|
+
return {
|
|
195947
|
+
log: (msg) => print("log", msg),
|
|
195948
|
+
error: (msg, err) => {
|
|
195949
|
+
print("error", msg);
|
|
195950
|
+
if (err) {
|
|
195951
|
+
print("error", String(err));
|
|
195952
|
+
}
|
|
195953
|
+
},
|
|
195954
|
+
warn: (msg) => print("warn", msg)
|
|
195955
|
+
};
|
|
195956
|
+
}
|
|
195957
|
+
|
|
195958
|
+
// src/cli/dev/dev-server/function-manager.ts
|
|
195959
|
+
import { spawn as spawn2, spawnSync as spawnSync2 } from "node:child_process";
|
|
195960
|
+
import { dirname as dirname11, join as join15 } from "node:path";
|
|
195961
|
+
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
195962
|
+
var __dirname5 = dirname11(fileURLToPath7(import.meta.url));
|
|
195963
|
+
var WRAPPER_PATH = join15(__dirname5, "../deno-runtime/main.js");
|
|
195964
|
+
var READY_TIMEOUT = 30000;
|
|
195965
|
+
|
|
195966
|
+
class FunctionManager {
|
|
195967
|
+
functions;
|
|
195968
|
+
running = new Map;
|
|
195969
|
+
starting = new Map;
|
|
195970
|
+
logger;
|
|
195971
|
+
constructor(functions, logger) {
|
|
195972
|
+
this.functions = new Map(functions.map((f7) => [f7.name, f7]));
|
|
195973
|
+
this.logger = logger;
|
|
195974
|
+
if (functions.length > 0) {
|
|
195975
|
+
this.verifyDenoIsInstalled();
|
|
195976
|
+
}
|
|
195977
|
+
}
|
|
195978
|
+
verifyDenoIsInstalled() {
|
|
195979
|
+
const result = spawnSync2("deno", ["--version"]);
|
|
195980
|
+
if (result.error) {
|
|
195981
|
+
throw new DependencyNotFoundError("Deno is required to run functions", {
|
|
195982
|
+
hints: [{ message: "Install Deno from https://deno.com/download" }]
|
|
195983
|
+
});
|
|
195984
|
+
}
|
|
195985
|
+
}
|
|
195986
|
+
getFunctionNames() {
|
|
195987
|
+
return Array.from(this.functions.keys());
|
|
195988
|
+
}
|
|
195989
|
+
async ensureRunning(name2) {
|
|
195990
|
+
const backendFunction = this.functions.get(name2);
|
|
195991
|
+
if (!backendFunction) {
|
|
195992
|
+
throw new InvalidInputError(`Function "${name2}" not found`, {
|
|
195993
|
+
hints: [{ message: "Check available functions in your project" }]
|
|
195994
|
+
});
|
|
195995
|
+
}
|
|
195996
|
+
const existing = this.running.get(name2);
|
|
195997
|
+
if (existing?.ready) {
|
|
195998
|
+
return existing.port;
|
|
195999
|
+
}
|
|
196000
|
+
const pending = this.starting.get(name2);
|
|
196001
|
+
if (pending) {
|
|
196002
|
+
return pending;
|
|
196003
|
+
}
|
|
196004
|
+
const promise2 = this.startFunction(name2, backendFunction);
|
|
196005
|
+
this.starting.set(name2, promise2);
|
|
196006
|
+
try {
|
|
196007
|
+
return await promise2;
|
|
196008
|
+
} finally {
|
|
196009
|
+
this.starting.delete(name2);
|
|
196010
|
+
}
|
|
196011
|
+
}
|
|
196012
|
+
async startFunction(name2, backendFunction) {
|
|
196013
|
+
const port = await this.allocatePort();
|
|
196014
|
+
const process21 = this.spawnFunction(backendFunction, port);
|
|
196015
|
+
const runningFunc = {
|
|
196016
|
+
process: process21,
|
|
196017
|
+
port,
|
|
196018
|
+
ready: false
|
|
196019
|
+
};
|
|
196020
|
+
this.running.set(name2, runningFunc);
|
|
196021
|
+
this.setupProcessHandlers(name2, process21);
|
|
196022
|
+
return this.waitForReady(name2, runningFunc);
|
|
196023
|
+
}
|
|
196024
|
+
stopAll() {
|
|
196025
|
+
for (const [name2, { process: process21 }] of this.running) {
|
|
196026
|
+
this.logger.log(`[dev-server] Stopping function: ${name2}`);
|
|
196027
|
+
process21.kill();
|
|
196028
|
+
}
|
|
196029
|
+
this.running.clear();
|
|
196030
|
+
this.starting.clear();
|
|
196031
|
+
}
|
|
196032
|
+
async allocatePort() {
|
|
196033
|
+
const usedPorts = Array.from(this.running.values()).map((r5) => r5.port);
|
|
196034
|
+
return getPorts({ exclude: usedPorts });
|
|
196035
|
+
}
|
|
196036
|
+
spawnFunction(func, port) {
|
|
196037
|
+
this.logger.log(`[dev-server] Spawning function "${func.name}" on port ${port}`);
|
|
196038
|
+
const process21 = spawn2("deno", ["run", "--allow-all", WRAPPER_PATH], {
|
|
196039
|
+
env: {
|
|
196040
|
+
...globalThis.process.env,
|
|
196041
|
+
FUNCTION_PATH: func.entryPath,
|
|
196042
|
+
FUNCTION_PORT: String(port),
|
|
196043
|
+
FUNCTION_NAME: func.name
|
|
196044
|
+
},
|
|
196045
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
196046
|
+
});
|
|
196047
|
+
return process21;
|
|
196048
|
+
}
|
|
196049
|
+
setupProcessHandlers(name2, process21) {
|
|
196050
|
+
process21.stdout?.on("data", (data) => {
|
|
196051
|
+
const lines = data.toString().trim().split(`
|
|
196052
|
+
`);
|
|
196053
|
+
for (const line3 of lines) {
|
|
196054
|
+
this.logger.log(line3);
|
|
196055
|
+
}
|
|
196056
|
+
});
|
|
196057
|
+
process21.stderr?.on("data", (data) => {
|
|
196058
|
+
const lines = data.toString().trim().split(`
|
|
196059
|
+
`);
|
|
196060
|
+
for (const line3 of lines) {
|
|
196061
|
+
this.logger.error(line3);
|
|
196062
|
+
}
|
|
196063
|
+
});
|
|
196064
|
+
process21.on("exit", (code2) => {
|
|
196065
|
+
this.logger.log(`[dev-server] Function "${name2}" exited with code ${code2}`);
|
|
196066
|
+
this.running.delete(name2);
|
|
196067
|
+
});
|
|
196068
|
+
process21.on("error", (error48) => {
|
|
196069
|
+
this.logger.error(`[dev-server] Function "${name2}" error:`, error48);
|
|
196070
|
+
this.running.delete(name2);
|
|
196071
|
+
});
|
|
196072
|
+
}
|
|
196073
|
+
waitForReady(name2, runningFunc) {
|
|
196074
|
+
return new Promise((resolve5, reject) => {
|
|
196075
|
+
runningFunc.process.on("exit", (code2) => {
|
|
196076
|
+
if (!runningFunc.ready) {
|
|
196077
|
+
clearTimeout(timeout3);
|
|
196078
|
+
reject(new InternalError(`Function "${name2}" exited with code ${code2}`, {
|
|
196079
|
+
hints: [{ message: "Check the function code for errors" }]
|
|
196080
|
+
}));
|
|
196081
|
+
}
|
|
196082
|
+
});
|
|
196083
|
+
const timeout3 = setTimeout(() => {
|
|
196084
|
+
runningFunc.process.kill();
|
|
196085
|
+
reject(new InternalError(`Function "${name2}" failed to start within ${READY_TIMEOUT / 1000}s timeout`, {
|
|
196086
|
+
hints: [
|
|
196087
|
+
{ message: "Check the function code for startup errors" }
|
|
196088
|
+
]
|
|
196089
|
+
}));
|
|
196090
|
+
}, READY_TIMEOUT);
|
|
196091
|
+
const onData = (data) => {
|
|
196092
|
+
const output = data.toString();
|
|
196093
|
+
if (output.includes("Listening on")) {
|
|
196094
|
+
runningFunc.ready = true;
|
|
196095
|
+
clearTimeout(timeout3);
|
|
196096
|
+
runningFunc.process.stdout?.off("data", onData);
|
|
196097
|
+
resolve5(runningFunc.port);
|
|
196098
|
+
}
|
|
196099
|
+
};
|
|
196100
|
+
runningFunc.process.stdout?.on("data", onData);
|
|
196101
|
+
});
|
|
196102
|
+
}
|
|
196103
|
+
}
|
|
196104
|
+
|
|
196105
|
+
// src/cli/dev/dev-server/routes/functions.ts
|
|
196106
|
+
var import_express = __toESM(require_express(), 1);
|
|
195732
196107
|
var import_http_proxy_middleware = __toESM(require_dist2(), 1);
|
|
196108
|
+
import { ServerResponse } from "node:http";
|
|
196109
|
+
function createFunctionRouter(manager, logger) {
|
|
196110
|
+
const router = import_express.Router({ mergeParams: true });
|
|
196111
|
+
const portsByRequest = new WeakMap;
|
|
196112
|
+
const proxy = import_http_proxy_middleware.createProxyMiddleware({
|
|
196113
|
+
router: (req) => `http://localhost:${portsByRequest.get(req)}`,
|
|
196114
|
+
changeOrigin: true,
|
|
196115
|
+
on: {
|
|
196116
|
+
proxyReq: (proxyReq, req) => {
|
|
196117
|
+
const xAppId = req.headers["x-app-id"];
|
|
196118
|
+
if (xAppId) {
|
|
196119
|
+
proxyReq.setHeader("Base44-App-Id", xAppId);
|
|
196120
|
+
}
|
|
196121
|
+
proxyReq.setHeader("Base44-Api-Url", `${req.protocol}://${req.headers.host}`);
|
|
196122
|
+
},
|
|
196123
|
+
error: (err, _req, res) => {
|
|
196124
|
+
logger.error("Function proxy error:", err);
|
|
196125
|
+
if (res instanceof ServerResponse && !res.headersSent) {
|
|
196126
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
196127
|
+
res.end(JSON.stringify({
|
|
196128
|
+
error: "Failed to proxy request to function",
|
|
196129
|
+
details: err.message
|
|
196130
|
+
}));
|
|
196131
|
+
}
|
|
196132
|
+
}
|
|
196133
|
+
}
|
|
196134
|
+
});
|
|
196135
|
+
router.all("/:functionName", async (req, res, next) => {
|
|
196136
|
+
const { functionName } = req.params;
|
|
196137
|
+
try {
|
|
196138
|
+
const port = await manager.ensureRunning(functionName);
|
|
196139
|
+
portsByRequest.set(req, port);
|
|
196140
|
+
next();
|
|
196141
|
+
} catch (error48) {
|
|
196142
|
+
logger.error("Function error:", error48);
|
|
196143
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
196144
|
+
res.status(500).json({ error: message });
|
|
196145
|
+
}
|
|
196146
|
+
}, proxy);
|
|
196147
|
+
return router;
|
|
196148
|
+
}
|
|
196149
|
+
|
|
196150
|
+
// src/cli/dev/dev-server/main.ts
|
|
195733
196151
|
var DEFAULT_PORT = 4400;
|
|
195734
196152
|
var BASE44_APP_URL = "https://base44.app";
|
|
195735
|
-
async function createDevServer(options8
|
|
195736
|
-
const
|
|
195737
|
-
const
|
|
195738
|
-
const
|
|
196153
|
+
async function createDevServer(options8) {
|
|
196154
|
+
const { port: userPort } = options8;
|
|
196155
|
+
const port = userPort ?? await getPorts({ port: DEFAULT_PORT });
|
|
196156
|
+
const { functions } = await options8.loadResources();
|
|
196157
|
+
const app = import_express2.default();
|
|
196158
|
+
const remoteProxy = import_http_proxy_middleware2.createProxyMiddleware({
|
|
195739
196159
|
target: BASE44_APP_URL,
|
|
195740
196160
|
changeOrigin: true
|
|
195741
196161
|
});
|
|
@@ -195751,6 +196171,13 @@ async function createDevServer(options8 = {}) {
|
|
|
195751
196171
|
}
|
|
195752
196172
|
next();
|
|
195753
196173
|
});
|
|
196174
|
+
const devLogger = createDevLogger();
|
|
196175
|
+
const functionManager = new FunctionManager(functions, devLogger);
|
|
196176
|
+
if (functionManager.getFunctionNames().length > 0) {
|
|
196177
|
+
R2.info(`Loaded functions: ${functionManager.getFunctionNames().join(", ")}`);
|
|
196178
|
+
const functionRoutes = createFunctionRouter(functionManager, devLogger);
|
|
196179
|
+
app.use("/api/apps/:appId/functions", functionRoutes);
|
|
196180
|
+
}
|
|
195754
196181
|
app.use((req, res, next) => {
|
|
195755
196182
|
return remoteProxy(req, res, next);
|
|
195756
196183
|
});
|
|
@@ -195763,6 +196190,12 @@ async function createDevServer(options8 = {}) {
|
|
|
195763
196190
|
reject(err);
|
|
195764
196191
|
}
|
|
195765
196192
|
} else {
|
|
196193
|
+
const shutdown = () => {
|
|
196194
|
+
functionManager.stopAll();
|
|
196195
|
+
server.close();
|
|
196196
|
+
};
|
|
196197
|
+
process.on("SIGINT", shutdown);
|
|
196198
|
+
process.on("SIGTERM", shutdown);
|
|
195766
196199
|
resolve5({
|
|
195767
196200
|
port,
|
|
195768
196201
|
server
|
|
@@ -195775,7 +196208,15 @@ async function createDevServer(options8 = {}) {
|
|
|
195775
196208
|
// src/cli/commands/dev.ts
|
|
195776
196209
|
async function devAction(options8) {
|
|
195777
196210
|
const port = options8.port ? Number(options8.port) : undefined;
|
|
195778
|
-
const { port: resolvedPort } = await createDevServer({
|
|
196211
|
+
const { port: resolvedPort } = await createDevServer({
|
|
196212
|
+
port,
|
|
196213
|
+
loadResources: async () => {
|
|
196214
|
+
const { project: project2 } = await readProjectConfig();
|
|
196215
|
+
const configDir = dirname12(project2.configPath);
|
|
196216
|
+
const functions = await functionResource.readAll(join16(configDir, project2.functionsDir));
|
|
196217
|
+
return { functions };
|
|
196218
|
+
}
|
|
196219
|
+
});
|
|
195779
196220
|
return {
|
|
195780
196221
|
outroMessage: `Dev server is available at ${theme.colors.links(`http://localhost:${resolvedPort}`)}`
|
|
195781
196222
|
};
|
|
@@ -195899,6 +196340,7 @@ function createProgram(context) {
|
|
|
195899
196340
|
program2.addCommand(getSiteCommand(context));
|
|
195900
196341
|
program2.addCommand(getTypesCommand(context));
|
|
195901
196342
|
program2.addCommand(getDevCommand(context), { hidden: true });
|
|
196343
|
+
program2.addCommand(getLogsCommand(context));
|
|
195902
196344
|
return program2;
|
|
195903
196345
|
}
|
|
195904
196346
|
|
|
@@ -195937,7 +196379,7 @@ function nanoid3(size = 21) {
|
|
|
195937
196379
|
}
|
|
195938
196380
|
|
|
195939
196381
|
// node_modules/posthog-node/dist/extensions/error-tracking/modifiers/module.node.mjs
|
|
195940
|
-
import { dirname as
|
|
196382
|
+
import { dirname as dirname13, posix, sep } from "path";
|
|
195941
196383
|
function createModulerModifier() {
|
|
195942
196384
|
const getModuleFromFileName = createGetModuleFromFilename();
|
|
195943
196385
|
return async (frames) => {
|
|
@@ -195946,7 +196388,7 @@ function createModulerModifier() {
|
|
|
195946
196388
|
return frames;
|
|
195947
196389
|
};
|
|
195948
196390
|
}
|
|
195949
|
-
function createGetModuleFromFilename(basePath = process.argv[1] ?
|
|
196391
|
+
function createGetModuleFromFilename(basePath = process.argv[1] ? dirname13(process.argv[1]) : process.cwd(), isWindows4 = sep === "\\") {
|
|
195950
196392
|
const normalizedBase = isWindows4 ? normalizeWindowsPath2(basePath) : basePath;
|
|
195951
196393
|
return (filename) => {
|
|
195952
196394
|
if (!filename)
|
|
@@ -200163,4 +200605,4 @@ export {
|
|
|
200163
200605
|
CLIExitError
|
|
200164
200606
|
};
|
|
200165
200607
|
|
|
200166
|
-
//# debugId=
|
|
200608
|
+
//# debugId=BDC2926C94F34D8D64756E2164756E21
|