@base44-preview/cli 0.1.1-pr.555.067c6ae → 0.1.1-pr.555.5e8fb00
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 +304 -147
- package/dist/cli/index.js.map +17 -17
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -163944,7 +163944,7 @@ var require_view = __commonJS((exports, module) => {
|
|
|
163944
163944
|
var debug = require_src4()("express:view");
|
|
163945
163945
|
var path18 = __require("node:path");
|
|
163946
163946
|
var fs28 = __require("node:fs");
|
|
163947
|
-
var
|
|
163947
|
+
var dirname22 = path18.dirname;
|
|
163948
163948
|
var basename7 = path18.basename;
|
|
163949
163949
|
var extname2 = path18.extname;
|
|
163950
163950
|
var join27 = path18.join;
|
|
@@ -163983,7 +163983,7 @@ var require_view = __commonJS((exports, module) => {
|
|
|
163983
163983
|
for (var i5 = 0;i5 < roots.length && !path19; i5++) {
|
|
163984
163984
|
var root2 = roots[i5];
|
|
163985
163985
|
var loc = resolve12(root2, name2);
|
|
163986
|
-
var dir =
|
|
163986
|
+
var dir = dirname22(loc);
|
|
163987
163987
|
var file2 = basename7(loc);
|
|
163988
163988
|
path19 = this.resolve(dir, file2);
|
|
163989
163989
|
}
|
|
@@ -234018,7 +234018,7 @@ function normalizeBase44Env() {
|
|
|
234018
234018
|
loadProjectEnvFiles();
|
|
234019
234019
|
|
|
234020
234020
|
// src/cli/index.ts
|
|
234021
|
-
import { dirname as
|
|
234021
|
+
import { dirname as dirname26, join as join30 } from "node:path";
|
|
234022
234022
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
234023
234023
|
|
|
234024
234024
|
// ../../node_modules/@clack/core/dist/index.mjs
|
|
@@ -243757,6 +243757,10 @@ var RealtimeHandlerConfigSchema = exports_external.object({
|
|
|
243757
243757
|
name: exports_external.string().min(1),
|
|
243758
243758
|
entry: exports_external.string().min(1)
|
|
243759
243759
|
});
|
|
243760
|
+
var RealtimeHandlerSchemaFileSchema = exports_external.object({
|
|
243761
|
+
inbound: exports_external.unknown().optional(),
|
|
243762
|
+
outbound: exports_external.unknown().optional()
|
|
243763
|
+
});
|
|
243760
243764
|
var DeployRealtimeHandlerResponseSchema = exports_external.object({
|
|
243761
243765
|
status: exports_external.enum(["deployed", "unchanged"]),
|
|
243762
243766
|
handler_name: exports_external.string().optional()
|
|
@@ -243764,7 +243768,8 @@ var DeployRealtimeHandlerResponseSchema = exports_external.object({
|
|
|
243764
243768
|
var RealtimeHandlerSchema = RealtimeHandlerConfigSchema.extend({
|
|
243765
243769
|
entryPath: exports_external.string().min(1),
|
|
243766
243770
|
filePaths: exports_external.array(exports_external.string()).min(1),
|
|
243767
|
-
source: ResourceSourceSchema
|
|
243771
|
+
source: ResourceSourceSchema,
|
|
243772
|
+
messageSchema: exports_external.unknown().optional()
|
|
243768
243773
|
});
|
|
243769
243774
|
|
|
243770
243775
|
// src/core/resources/realtime-handler/api.ts
|
|
@@ -243783,7 +243788,7 @@ async function deploySingleRealtimeHandler(name2, payload) {
|
|
|
243783
243788
|
return result.data;
|
|
243784
243789
|
}
|
|
243785
243790
|
// src/core/resources/realtime-handler/config.ts
|
|
243786
|
-
import { basename as basename4, dirname as dirname8, relative as relative3 } from "node:path";
|
|
243791
|
+
import { basename as basename4, dirname as dirname8, join as join10, relative as relative3 } from "node:path";
|
|
243787
243792
|
async function readRealtimeHandler(entryFile, realtimeDir) {
|
|
243788
243793
|
const handlerDir = dirname8(entryFile);
|
|
243789
243794
|
const filePaths = await globby("**/*.ts", {
|
|
@@ -243801,12 +243806,25 @@ async function readRealtimeHandler(entryFile, realtimeDir) {
|
|
|
243801
243806
|
});
|
|
243802
243807
|
}
|
|
243803
243808
|
const entry = basename4(entryFile);
|
|
243809
|
+
const schemaPath = join10(handlerDir, "schema.jsonc");
|
|
243810
|
+
let messageSchema = undefined;
|
|
243811
|
+
if (await pathExists(schemaPath)) {
|
|
243812
|
+
const parsed = await readJsonFile(schemaPath);
|
|
243813
|
+
const result = RealtimeHandlerSchemaFileSchema.safeParse(parsed);
|
|
243814
|
+
if (result.success) {
|
|
243815
|
+
messageSchema = {
|
|
243816
|
+
inbound: result.data.inbound,
|
|
243817
|
+
outbound: result.data.outbound
|
|
243818
|
+
};
|
|
243819
|
+
}
|
|
243820
|
+
}
|
|
243804
243821
|
return {
|
|
243805
243822
|
name: name2,
|
|
243806
243823
|
entry,
|
|
243807
243824
|
entryPath: entryFile,
|
|
243808
243825
|
filePaths,
|
|
243809
|
-
source: { type: "project" }
|
|
243826
|
+
source: { type: "project" },
|
|
243827
|
+
messageSchema
|
|
243810
243828
|
};
|
|
243811
243829
|
}
|
|
243812
243830
|
async function readAllRealtimeHandlers(realtimeDir) {
|
|
@@ -243925,7 +243943,14 @@ class ProjectConfigReader {
|
|
|
243925
243943
|
}
|
|
243926
243944
|
async readProjectResources(configPath, project) {
|
|
243927
243945
|
const configDir = dirname10(configPath);
|
|
243928
|
-
const [
|
|
243946
|
+
const [
|
|
243947
|
+
entities,
|
|
243948
|
+
functions,
|
|
243949
|
+
realtimeHandlers,
|
|
243950
|
+
agents,
|
|
243951
|
+
connectors,
|
|
243952
|
+
authConfig
|
|
243953
|
+
] = await Promise.all([
|
|
243929
243954
|
entityResource.readAll(join11(configDir, project.entitiesDir)),
|
|
243930
243955
|
functionResource.readAll(join11(configDir, project.functionsDir)),
|
|
243931
243956
|
realtimeHandlerResource.readAll(join11(configDir, project.realtimeDir)),
|
|
@@ -243933,7 +243958,14 @@ class ProjectConfigReader {
|
|
|
243933
243958
|
connectorResource.readAll(join11(configDir, project.connectorsDir)),
|
|
243934
243959
|
authConfigResource.readAll(join11(configDir, project.authDir))
|
|
243935
243960
|
]);
|
|
243936
|
-
return {
|
|
243961
|
+
return {
|
|
243962
|
+
entities,
|
|
243963
|
+
functions,
|
|
243964
|
+
realtimeHandlers,
|
|
243965
|
+
agents,
|
|
243966
|
+
connectors,
|
|
243967
|
+
authConfig
|
|
243968
|
+
};
|
|
243937
243969
|
}
|
|
243938
243970
|
assertPluginProjectDoesNotLoadPlugins(project, configPath) {
|
|
243939
243971
|
if (project.plugin && project.plugins.length > 0) {
|
|
@@ -244322,7 +244354,15 @@ async function createArchive(pathToArchive, targetArchivePath) {
|
|
|
244322
244354
|
}
|
|
244323
244355
|
// src/core/project/deploy.ts
|
|
244324
244356
|
function hasResourcesToDeploy(projectData) {
|
|
244325
|
-
const {
|
|
244357
|
+
const {
|
|
244358
|
+
project,
|
|
244359
|
+
entities,
|
|
244360
|
+
functions,
|
|
244361
|
+
realtimeHandlers,
|
|
244362
|
+
agents,
|
|
244363
|
+
connectors,
|
|
244364
|
+
authConfig
|
|
244365
|
+
} = projectData;
|
|
244326
244366
|
const hasSite = Boolean(project.site?.outputDirectory);
|
|
244327
244367
|
const hasEntities = entities.length > 0;
|
|
244328
244368
|
const hasFunctions = functions.length > 0;
|
|
@@ -244333,7 +244373,15 @@ function hasResourcesToDeploy(projectData) {
|
|
|
244333
244373
|
return hasEntities || hasFunctions || hasRealtimeHandlers || hasAgents || hasConnectors || hasAuthConfig || hasSite;
|
|
244334
244374
|
}
|
|
244335
244375
|
async function deployAll(projectData, options) {
|
|
244336
|
-
const {
|
|
244376
|
+
const {
|
|
244377
|
+
project,
|
|
244378
|
+
entities,
|
|
244379
|
+
functions,
|
|
244380
|
+
realtimeHandlers,
|
|
244381
|
+
agents,
|
|
244382
|
+
connectors,
|
|
244383
|
+
authConfig
|
|
244384
|
+
} = projectData;
|
|
244337
244385
|
await entityResource.push(entities);
|
|
244338
244386
|
await deployFunctionsSequentially(functions, {
|
|
244339
244387
|
onStart: options?.onFunctionStart,
|
|
@@ -253285,125 +253333,12 @@ function getFunctionsCommand() {
|
|
|
253285
253333
|
return new Command("functions").description("Manage backend functions").addCommand(getDeployCommand()).addCommand(getDeleteCommand()).addCommand(getListCommand()).addCommand(getPullCommand());
|
|
253286
253334
|
}
|
|
253287
253335
|
|
|
253288
|
-
// src/cli/commands/realtime/deploy.ts
|
|
253289
|
-
function parseNames3(args) {
|
|
253290
|
-
return args.flatMap((arg) => arg.split(",")).map((n2) => n2.trim()).filter(Boolean);
|
|
253291
|
-
}
|
|
253292
|
-
function resolveHandlersToDeploy(names, allHandlers) {
|
|
253293
|
-
if (names.length === 0)
|
|
253294
|
-
return allHandlers;
|
|
253295
|
-
const notFound = names.filter((n2) => !allHandlers.some((h2) => h2.name === n2));
|
|
253296
|
-
if (notFound.length > 0) {
|
|
253297
|
-
throw new InvalidInputError(`Realtime handler${notFound.length > 1 ? "s" : ""} not found in project: ${notFound.join(", ")}`);
|
|
253298
|
-
}
|
|
253299
|
-
return allHandlers.filter((h2) => names.includes(h2.name));
|
|
253300
|
-
}
|
|
253301
|
-
function formatDeployResult2(result, log) {
|
|
253302
|
-
const label = result.name.padEnd(25);
|
|
253303
|
-
if (result.status === "deployed") {
|
|
253304
|
-
const timing = result.durationMs ? theme.styles.dim(` (${(result.durationMs / 1000).toFixed(1)}s)`) : "";
|
|
253305
|
-
log.success(`${label} deployed${timing}`);
|
|
253306
|
-
} else if (result.status === "unchanged") {
|
|
253307
|
-
log.success(`${label} unchanged`);
|
|
253308
|
-
} else {
|
|
253309
|
-
log.error(`${label} error: ${result.error}`);
|
|
253310
|
-
}
|
|
253311
|
-
}
|
|
253312
|
-
function buildDeploySummary2(results) {
|
|
253313
|
-
const deployed = results.filter((r) => r.status === "deployed").length;
|
|
253314
|
-
const unchanged = results.filter((r) => r.status === "unchanged").length;
|
|
253315
|
-
const failed = results.filter((r) => r.status === "error").length;
|
|
253316
|
-
const parts = [];
|
|
253317
|
-
if (deployed > 0)
|
|
253318
|
-
parts.push(`${deployed} deployed`);
|
|
253319
|
-
if (unchanged > 0)
|
|
253320
|
-
parts.push(`${unchanged} unchanged`);
|
|
253321
|
-
if (failed > 0)
|
|
253322
|
-
parts.push(`${failed} error${failed !== 1 ? "s" : ""}`);
|
|
253323
|
-
return parts.join(", ") || "No realtime handlers deployed";
|
|
253324
|
-
}
|
|
253325
|
-
async function deployRealtimeAction({ log }, names) {
|
|
253326
|
-
const { realtimeHandlers } = await readProjectConfig();
|
|
253327
|
-
const toDeploy = resolveHandlersToDeploy(names, realtimeHandlers);
|
|
253328
|
-
if (toDeploy.length === 0) {
|
|
253329
|
-
return {
|
|
253330
|
-
outroMessage: "No realtime handlers found. Create handlers in the 'realtime' directory."
|
|
253331
|
-
};
|
|
253332
|
-
}
|
|
253333
|
-
log.info(`Found ${toDeploy.length} ${toDeploy.length === 1 ? "realtime handler" : "realtime handlers"} to deploy`);
|
|
253334
|
-
let completed = 0;
|
|
253335
|
-
const total = toDeploy.length;
|
|
253336
|
-
const results = await deployRealtimeHandlersSequentially(toDeploy, {
|
|
253337
|
-
onStart: (startNames) => {
|
|
253338
|
-
const label = startNames.length === 1 ? startNames[0] : `${startNames.length} realtime handlers`;
|
|
253339
|
-
log.step(theme.styles.dim(`[${completed + 1}/${total}] Deploying ${label}...`));
|
|
253340
|
-
},
|
|
253341
|
-
onResult: (result) => {
|
|
253342
|
-
completed++;
|
|
253343
|
-
formatDeployResult2(result, log);
|
|
253344
|
-
}
|
|
253345
|
-
});
|
|
253346
|
-
const hasFailures = results.some((r) => r.status === "error");
|
|
253347
|
-
if (hasFailures) {
|
|
253348
|
-
log.message(buildDeploySummary2(results));
|
|
253349
|
-
throw new CLIExitError(1);
|
|
253350
|
-
}
|
|
253351
|
-
return { outroMessage: buildDeploySummary2(results) };
|
|
253352
|
-
}
|
|
253353
|
-
function getDeployCommand2() {
|
|
253354
|
-
return new Base44Command("deploy").description("Deploy realtime handlers to Base44").argument("[names...]", "Handler names to deploy (deploys all if omitted)").action(async (ctx, rawNames) => {
|
|
253355
|
-
const names = parseNames3(rawNames);
|
|
253356
|
-
return deployRealtimeAction(ctx, names);
|
|
253357
|
-
});
|
|
253358
|
-
}
|
|
253359
|
-
|
|
253360
|
-
// src/cli/commands/realtime/new.ts
|
|
253361
|
-
import { join as join22 } from "node:path";
|
|
253362
|
-
function buildHandlerScaffold(handlerName) {
|
|
253363
|
-
return `import { RealtimeHandler, type Conn } from "base44";
|
|
253364
|
-
|
|
253365
|
-
export class ${handlerName} extends RealtimeHandler {
|
|
253366
|
-
handleConnect(conn: Conn) {
|
|
253367
|
-
console.log("Connected:", conn.userId);
|
|
253368
|
-
}
|
|
253369
|
-
handleMessage(conn: Conn, msg: unknown) {
|
|
253370
|
-
console.log("Message:", msg);
|
|
253371
|
-
}
|
|
253372
|
-
handleTick() {}
|
|
253373
|
-
handleClose(conn: Conn) {}
|
|
253374
|
-
}
|
|
253375
|
-
`;
|
|
253376
|
-
}
|
|
253377
|
-
async function newRealtimeHandlerAction(_ctx, handlerName) {
|
|
253378
|
-
const { project: project2 } = await readProjectConfig();
|
|
253379
|
-
const realtimeDir = join22(project2.root, project2.realtimeDir);
|
|
253380
|
-
const handlerDir = join22(realtimeDir, handlerName);
|
|
253381
|
-
if (await pathExists(handlerDir)) {
|
|
253382
|
-
throw new InvalidInputError(`Realtime handler "${handlerName}" already exists at ${handlerDir}`);
|
|
253383
|
-
}
|
|
253384
|
-
const entryPath = join22(handlerDir, "entry.ts");
|
|
253385
|
-
await writeFile(entryPath, buildHandlerScaffold(handlerName));
|
|
253386
|
-
return {
|
|
253387
|
-
outroMessage: `Created realtime handler "${handlerName}" at ${entryPath}`
|
|
253388
|
-
};
|
|
253389
|
-
}
|
|
253390
|
-
function getNewCommand() {
|
|
253391
|
-
return new Base44Command("new").description("Create a new realtime handler scaffold").argument("<HandlerName>", "Name of the realtime handler class").action(async (ctx, handlerName) => {
|
|
253392
|
-
return newRealtimeHandlerAction(ctx, handlerName);
|
|
253393
|
-
});
|
|
253394
|
-
}
|
|
253395
|
-
|
|
253396
|
-
// src/cli/commands/realtime/index.ts
|
|
253397
|
-
function getRealtimeCommand() {
|
|
253398
|
-
return new Command("realtime").description("Manage realtime handlers").addCommand(getNewCommand()).addCommand(getDeployCommand2());
|
|
253399
|
-
}
|
|
253400
|
-
|
|
253401
253336
|
// src/cli/commands/project/create.ts
|
|
253402
253337
|
import { basename as basename5, resolve as resolve7 } from "node:path";
|
|
253403
253338
|
var import_kebabCase = __toESM(require_kebabCase(), 1);
|
|
253404
253339
|
|
|
253405
253340
|
// src/cli/commands/project/scaffold-shared.ts
|
|
253406
|
-
import { join as
|
|
253341
|
+
import { join as join22 } from "node:path";
|
|
253407
253342
|
var DEFAULT_TEMPLATE_ID = "backend-only";
|
|
253408
253343
|
async function getTemplateById(templateId) {
|
|
253409
253344
|
const templates = await listTemplates();
|
|
@@ -253462,7 +253397,7 @@ async function completeProjectSetup({
|
|
|
253462
253397
|
updateMessage("Building project...");
|
|
253463
253398
|
await execa({ cwd: resolvedPath, shell: true })`${buildCommand}`;
|
|
253464
253399
|
updateMessage("Deploying site...");
|
|
253465
|
-
return await deploySite(
|
|
253400
|
+
return await deploySite(join22(resolvedPath, outputDirectory));
|
|
253466
253401
|
}, {
|
|
253467
253402
|
successMessage: theme.colors.base44Orange("Site deployed successfully"),
|
|
253468
253403
|
errorMessage: "Failed to deploy site"
|
|
@@ -253633,7 +253568,15 @@ async function deployAction({ isNonInteractive, log }, options = {}) {
|
|
|
253633
253568
|
outroMessage: "No resources found to deploy"
|
|
253634
253569
|
};
|
|
253635
253570
|
}
|
|
253636
|
-
const {
|
|
253571
|
+
const {
|
|
253572
|
+
project: project2,
|
|
253573
|
+
entities,
|
|
253574
|
+
functions,
|
|
253575
|
+
realtimeHandlers,
|
|
253576
|
+
agents,
|
|
253577
|
+
connectors,
|
|
253578
|
+
authConfig
|
|
253579
|
+
} = projectData;
|
|
253637
253580
|
const summaryLines = [];
|
|
253638
253581
|
if (entities.length > 0) {
|
|
253639
253582
|
summaryLines.push(` - ${entities.length} ${entities.length === 1 ? "entity" : "entities"}`);
|
|
@@ -253695,7 +253638,7 @@ ${summaryLines.join(`
|
|
|
253695
253638
|
}
|
|
253696
253639
|
return { outroMessage: "App deployed successfully" };
|
|
253697
253640
|
}
|
|
253698
|
-
function
|
|
253641
|
+
function getDeployCommand2() {
|
|
253699
253642
|
return new Base44Command("deploy").description("Deploy all project resources (entities, functions, agents, connectors, and site)").option("-y, --yes", "Skip confirmation prompt").action(deployAction);
|
|
253700
253643
|
}
|
|
253701
253644
|
async function handleOAuthConnectors(connectorResults, isNonInteractive, options, log) {
|
|
@@ -253935,6 +253878,48 @@ function formatEntry(entry) {
|
|
|
253935
253878
|
const message = entry.message.trim();
|
|
253936
253879
|
return `${time3} ${level} ${message}`;
|
|
253937
253880
|
}
|
|
253881
|
+
function entryKey(entry) {
|
|
253882
|
+
return `${entry.time} ${entry.message}`;
|
|
253883
|
+
}
|
|
253884
|
+
function selectNewEntries(entries, state) {
|
|
253885
|
+
const fresh = entries.filter((e2) => {
|
|
253886
|
+
if (e2.time < state.lastTime)
|
|
253887
|
+
return false;
|
|
253888
|
+
if (e2.time === state.lastTime && state.boundaryKeys.has(entryKey(e2))) {
|
|
253889
|
+
return false;
|
|
253890
|
+
}
|
|
253891
|
+
return true;
|
|
253892
|
+
});
|
|
253893
|
+
if (fresh.length === 0)
|
|
253894
|
+
return { fresh, nextState: state };
|
|
253895
|
+
const newMax = fresh.reduce((max, e2) => e2.time > max ? e2.time : max, state.lastTime);
|
|
253896
|
+
const boundaryKeys = newMax === state.lastTime ? new Set(state.boundaryKeys) : new Set;
|
|
253897
|
+
for (const e2 of fresh) {
|
|
253898
|
+
if (e2.time === newMax)
|
|
253899
|
+
boundaryKeys.add(entryKey(e2));
|
|
253900
|
+
}
|
|
253901
|
+
return { fresh, nextState: { lastTime: newMax, boundaryKeys } };
|
|
253902
|
+
}
|
|
253903
|
+
function writeFollowLine(entry, jsonMode) {
|
|
253904
|
+
const line = jsonMode ? JSON.stringify(entry) : formatEntry(entry);
|
|
253905
|
+
process.stdout.write(`${line}
|
|
253906
|
+
`);
|
|
253907
|
+
}
|
|
253908
|
+
async function followLogs(functionNames, options, availableFunctionNames, jsonMode) {
|
|
253909
|
+
let state = { lastTime: "", boundaryKeys: new Set };
|
|
253910
|
+
let first = true;
|
|
253911
|
+
while (true) {
|
|
253912
|
+
const pollOptions = first ? options : { ...options, since: state.lastTime };
|
|
253913
|
+
const entries = await fetchLogsForFunctions(functionNames, pollOptions, availableFunctionNames);
|
|
253914
|
+
const { fresh, nextState } = selectNewEntries(entries, state);
|
|
253915
|
+
state = nextState;
|
|
253916
|
+
fresh.sort((a2, b) => a2.time.localeCompare(b.time));
|
|
253917
|
+
for (const entry of fresh)
|
|
253918
|
+
writeFollowLine(entry, jsonMode);
|
|
253919
|
+
first = false;
|
|
253920
|
+
await new Promise((resolve8) => setTimeout(resolve8, 2000));
|
|
253921
|
+
}
|
|
253922
|
+
}
|
|
253938
253923
|
function formatLogs(entries, env3) {
|
|
253939
253924
|
if (entries.length === 0) {
|
|
253940
253925
|
if (env3 === "prod") {
|
|
@@ -254016,6 +254001,16 @@ async function logsAction(ctx, options) {
|
|
|
254016
254001
|
outroMessage: localProjectRoot ? "No functions found in this project." : "No functions found in this app."
|
|
254017
254002
|
};
|
|
254018
254003
|
}
|
|
254004
|
+
if (options.follow) {
|
|
254005
|
+
if (options.until) {
|
|
254006
|
+
throw new InvalidInputError("--until cannot be combined with --follow (a stream has no end).");
|
|
254007
|
+
}
|
|
254008
|
+
if (options.order) {
|
|
254009
|
+
throw new InvalidInputError("--order cannot be combined with --follow (a live tail always streams oldest to newest).");
|
|
254010
|
+
}
|
|
254011
|
+
options.order = "asc";
|
|
254012
|
+
return followLogs(functionNames, options, availableFunctionNames, ctx.jsonMode);
|
|
254013
|
+
}
|
|
254019
254014
|
let entries = await fetchLogsForFunctions(functionNames, options, availableFunctionNames);
|
|
254020
254015
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
|
|
254021
254016
|
if (limit !== undefined && entries.length > limit) {
|
|
@@ -254031,7 +254026,7 @@ async function logsAction(ctx, options) {
|
|
|
254031
254026
|
};
|
|
254032
254027
|
}
|
|
254033
254028
|
function getLogsCommand() {
|
|
254034
|
-
return new Base44Command("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 datetime or relative shorthand (e.g. 1h, 30m, 2d)", normalizeDatetime).option("--until <datetime>", "Show logs until this time. ISO datetime or relative shorthand (e.g. 1h, 30m, 2d)", normalizeDatetime).addOption(new Option("--level <level>", "Filter by log level").choices([...LogLevelSchema.options]).hideHelp()).option("-n, --limit <n>", "Results per page (1-1000, default: 50)").addOption(new Option("--order <order>", "Sort order").choices(["asc", "desc"])).addOption(new Option("--env <env>", "Which deployment to read logs from: preview (current draft) or prod (published). Default: preview").choices([...LogEnvSchema.options])).action(logsAction);
|
|
254029
|
+
return new Base44Command("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 datetime or relative shorthand (e.g. 1h, 30m, 2d)", normalizeDatetime).option("--until <datetime>", "Show logs until this time. ISO datetime or relative shorthand (e.g. 1h, 30m, 2d)", normalizeDatetime).addOption(new Option("--level <level>", "Filter by log level").choices([...LogLevelSchema.options]).hideHelp()).option("-n, --limit <n>", "Results per page (1-1000, default: 50)").option("-f, --follow", "Stream new logs as they arrive").addOption(new Option("--order <order>", "Sort order").choices(["asc", "desc"])).addOption(new Option("--env <env>", "Which deployment to read logs from: preview (current draft) or prod (published). Default: preview").choices([...LogEnvSchema.options])).action(logsAction);
|
|
254035
254030
|
}
|
|
254036
254031
|
|
|
254037
254032
|
// src/cli/commands/project/scaffold.ts
|
|
@@ -254088,6 +254083,127 @@ Examples:
|
|
|
254088
254083
|
$ base44 scaffold my-app --app-id app_123 Scaffolds the current dir, named "my-app"`).action(scaffoldAction);
|
|
254089
254084
|
}
|
|
254090
254085
|
|
|
254086
|
+
// src/cli/commands/realtime/deploy.ts
|
|
254087
|
+
function parseNames3(args) {
|
|
254088
|
+
return args.flatMap((arg) => arg.split(",")).map((n2) => n2.trim()).filter(Boolean);
|
|
254089
|
+
}
|
|
254090
|
+
function resolveHandlersToDeploy(names, allHandlers) {
|
|
254091
|
+
if (names.length === 0)
|
|
254092
|
+
return allHandlers;
|
|
254093
|
+
const notFound = names.filter((n2) => !allHandlers.some((h2) => h2.name === n2));
|
|
254094
|
+
if (notFound.length > 0) {
|
|
254095
|
+
throw new InvalidInputError(`Realtime handler${notFound.length > 1 ? "s" : ""} not found in project: ${notFound.join(", ")}`);
|
|
254096
|
+
}
|
|
254097
|
+
return allHandlers.filter((h2) => names.includes(h2.name));
|
|
254098
|
+
}
|
|
254099
|
+
function formatDeployResult2(result, log) {
|
|
254100
|
+
const label = result.name.padEnd(25);
|
|
254101
|
+
if (result.status === "deployed") {
|
|
254102
|
+
const timing = result.durationMs ? theme.styles.dim(` (${(result.durationMs / 1000).toFixed(1)}s)`) : "";
|
|
254103
|
+
log.success(`${label} deployed${timing}`);
|
|
254104
|
+
} else if (result.status === "unchanged") {
|
|
254105
|
+
log.success(`${label} unchanged`);
|
|
254106
|
+
} else {
|
|
254107
|
+
log.error(`${label} error: ${result.error}`);
|
|
254108
|
+
}
|
|
254109
|
+
}
|
|
254110
|
+
function buildDeploySummary2(results) {
|
|
254111
|
+
const deployed = results.filter((r) => r.status === "deployed").length;
|
|
254112
|
+
const unchanged = results.filter((r) => r.status === "unchanged").length;
|
|
254113
|
+
const failed = results.filter((r) => r.status === "error").length;
|
|
254114
|
+
const parts = [];
|
|
254115
|
+
if (deployed > 0)
|
|
254116
|
+
parts.push(`${deployed} deployed`);
|
|
254117
|
+
if (unchanged > 0)
|
|
254118
|
+
parts.push(`${unchanged} unchanged`);
|
|
254119
|
+
if (failed > 0)
|
|
254120
|
+
parts.push(`${failed} error${failed !== 1 ? "s" : ""}`);
|
|
254121
|
+
return parts.join(", ") || "No realtime handlers deployed";
|
|
254122
|
+
}
|
|
254123
|
+
async function deployRealtimeAction({ log }, names) {
|
|
254124
|
+
const { realtimeHandlers } = await readProjectConfig();
|
|
254125
|
+
const toDeploy = resolveHandlersToDeploy(names, realtimeHandlers);
|
|
254126
|
+
if (toDeploy.length === 0) {
|
|
254127
|
+
return {
|
|
254128
|
+
outroMessage: "No realtime handlers found. Create handlers in the 'realtime' directory."
|
|
254129
|
+
};
|
|
254130
|
+
}
|
|
254131
|
+
log.info(`Found ${toDeploy.length} ${toDeploy.length === 1 ? "realtime handler" : "realtime handlers"} to deploy`);
|
|
254132
|
+
let completed = 0;
|
|
254133
|
+
const total = toDeploy.length;
|
|
254134
|
+
const results = await deployRealtimeHandlersSequentially(toDeploy, {
|
|
254135
|
+
onStart: (startNames) => {
|
|
254136
|
+
const label = startNames.length === 1 ? startNames[0] : `${startNames.length} realtime handlers`;
|
|
254137
|
+
log.step(theme.styles.dim(`[${completed + 1}/${total}] Deploying ${label}...`));
|
|
254138
|
+
},
|
|
254139
|
+
onResult: (result) => {
|
|
254140
|
+
completed++;
|
|
254141
|
+
formatDeployResult2(result, log);
|
|
254142
|
+
}
|
|
254143
|
+
});
|
|
254144
|
+
const hasFailures = results.some((r) => r.status === "error");
|
|
254145
|
+
if (hasFailures) {
|
|
254146
|
+
log.message(buildDeploySummary2(results));
|
|
254147
|
+
throw new CLIExitError(1);
|
|
254148
|
+
}
|
|
254149
|
+
return { outroMessage: buildDeploySummary2(results) };
|
|
254150
|
+
}
|
|
254151
|
+
function getDeployCommand3() {
|
|
254152
|
+
return new Base44Command("deploy").description("Deploy realtime handlers to Base44").argument("[names...]", "Handler names to deploy (deploys all if omitted)").action(async (ctx, rawNames) => {
|
|
254153
|
+
const names = parseNames3(rawNames);
|
|
254154
|
+
return deployRealtimeAction(ctx, names);
|
|
254155
|
+
});
|
|
254156
|
+
}
|
|
254157
|
+
|
|
254158
|
+
// src/cli/commands/realtime/new.ts
|
|
254159
|
+
import { dirname as dirname19, join as join23 } from "node:path";
|
|
254160
|
+
function buildHandlerScaffold(handlerName) {
|
|
254161
|
+
return `import { RealtimeHandler, type Conn } from "@base44/sdk";
|
|
254162
|
+
|
|
254163
|
+
interface State {
|
|
254164
|
+
// shared state broadcast to all clients
|
|
254165
|
+
}
|
|
254166
|
+
|
|
254167
|
+
interface Message {
|
|
254168
|
+
// messages sent from clients
|
|
254169
|
+
}
|
|
254170
|
+
|
|
254171
|
+
export class ${handlerName} extends RealtimeHandler<State, Message> {
|
|
254172
|
+
handleConnect(conn: Conn) {
|
|
254173
|
+
console.log("Connected:", conn.userId);
|
|
254174
|
+
}
|
|
254175
|
+
handleMessage(conn: Conn, msg: Message) {
|
|
254176
|
+
console.log("Message:", msg);
|
|
254177
|
+
}
|
|
254178
|
+
handleTick() {}
|
|
254179
|
+
handleClose(conn: Conn) {}
|
|
254180
|
+
}
|
|
254181
|
+
`;
|
|
254182
|
+
}
|
|
254183
|
+
async function newRealtimeHandlerAction(_ctx, handlerName) {
|
|
254184
|
+
const { project: project2 } = await readProjectConfig();
|
|
254185
|
+
const realtimeDir = join23(dirname19(project2.configPath), project2.realtimeDir);
|
|
254186
|
+
const handlerDir = join23(realtimeDir, handlerName);
|
|
254187
|
+
if (await pathExists(handlerDir)) {
|
|
254188
|
+
throw new InvalidInputError(`Realtime handler "${handlerName}" already exists at ${handlerDir}`);
|
|
254189
|
+
}
|
|
254190
|
+
const entryPath = join23(handlerDir, "entry.ts");
|
|
254191
|
+
await writeFile(entryPath, buildHandlerScaffold(handlerName));
|
|
254192
|
+
return {
|
|
254193
|
+
outroMessage: `Created realtime handler "${handlerName}" at ${entryPath}`
|
|
254194
|
+
};
|
|
254195
|
+
}
|
|
254196
|
+
function getNewCommand() {
|
|
254197
|
+
return new Base44Command("new").description("Create a new realtime handler scaffold").argument("<HandlerName>", "Name of the realtime handler class").action(async (ctx, handlerName) => {
|
|
254198
|
+
return newRealtimeHandlerAction(ctx, handlerName);
|
|
254199
|
+
});
|
|
254200
|
+
}
|
|
254201
|
+
|
|
254202
|
+
// src/cli/commands/realtime/index.ts
|
|
254203
|
+
function getRealtimeCommand() {
|
|
254204
|
+
return new Command("realtime").description("Manage realtime handlers").addCommand(getNewCommand()).addCommand(getDeployCommand3());
|
|
254205
|
+
}
|
|
254206
|
+
|
|
254091
254207
|
// src/core/resources/sandbox/schema.ts
|
|
254092
254208
|
var FileErrorSchema = exports_external.object({
|
|
254093
254209
|
code: exports_external.string(),
|
|
@@ -254567,8 +254683,8 @@ var EMPTY_TEMPLATE = import_common_tags.stripIndent`
|
|
|
254567
254683
|
// Auto-generated by Base44 CLI - DO NOT EDIT
|
|
254568
254684
|
// Regenerate with: base44 types
|
|
254569
254685
|
//
|
|
254570
|
-
// No entities, functions, agents, or
|
|
254571
|
-
// Add resources to base44/entities/, base44/functions/, base44/agents/, or base44/
|
|
254686
|
+
// No entities, functions, agents, connectors, or realtime handlers found in project.
|
|
254687
|
+
// Add resources to base44/entities/, base44/functions/, base44/agents/, base44/connectors/, or base44/realtime/
|
|
254572
254688
|
// and run \`base44 types generate\` again.
|
|
254573
254689
|
|
|
254574
254690
|
declare module '@base44/sdk' {
|
|
@@ -254580,11 +254696,14 @@ async function generateTypesFile(input) {
|
|
|
254580
254696
|
await writeFile(getTypesOutputPath(input.projectRoot), content);
|
|
254581
254697
|
}
|
|
254582
254698
|
async function generateContent(input) {
|
|
254583
|
-
const { entities, functions, agents, connectors } = input;
|
|
254584
|
-
if (!entities.length && !functions.length && !agents.length && !connectors.length) {
|
|
254699
|
+
const { entities, functions, agents, connectors, realtimeHandlers } = input;
|
|
254700
|
+
if (!entities.length && !functions.length && !agents.length && !connectors.length && !realtimeHandlers.length) {
|
|
254585
254701
|
return EMPTY_TEMPLATE;
|
|
254586
254702
|
}
|
|
254587
|
-
const entityInterfaces = await Promise.all(
|
|
254703
|
+
const [entityInterfaces, realtimeRegistryEntries] = await Promise.all([
|
|
254704
|
+
Promise.all(entities.map((e8) => compileEntity(e8))),
|
|
254705
|
+
Promise.all(realtimeHandlers.map((h5) => compileRealtimeHandler(h5)))
|
|
254706
|
+
]);
|
|
254588
254707
|
const registryEntries = [
|
|
254589
254708
|
[
|
|
254590
254709
|
"EntityTypeRegistry",
|
|
@@ -254592,7 +254711,18 @@ async function generateContent(input) {
|
|
|
254592
254711
|
],
|
|
254593
254712
|
["FunctionNameRegistry", functions.map((f7) => `"${f7.name}": true;`)],
|
|
254594
254713
|
["AgentNameRegistry", agents.map((a5) => `"${a5.name}": true;`)],
|
|
254595
|
-
["ConnectorTypeRegistry", connectors.map((c8) => `"${c8.type}": true;`)]
|
|
254714
|
+
["ConnectorTypeRegistry", connectors.map((c8) => `"${c8.type}": true;`)],
|
|
254715
|
+
[
|
|
254716
|
+
"RealtimeHandlerNameRegistry",
|
|
254717
|
+
realtimeHandlers.map((h5) => `"${h5.name}": true;`)
|
|
254718
|
+
],
|
|
254719
|
+
[
|
|
254720
|
+
"RealtimeHandlerRegistry",
|
|
254721
|
+
realtimeHandlers.filter((h5) => h5.messageSchema).map((h5, _10, arr) => {
|
|
254722
|
+
const idx = realtimeHandlers.indexOf(h5);
|
|
254723
|
+
return `"${h5.name}": ${realtimeRegistryEntries[idx]};`;
|
|
254724
|
+
})
|
|
254725
|
+
]
|
|
254596
254726
|
];
|
|
254597
254727
|
const registries2 = registryEntries.filter(([, entries]) => entries.length > 0).map(([name2, entries]) => registry2(name2, entries));
|
|
254598
254728
|
return [
|
|
@@ -254629,6 +254759,32 @@ async function compileEntity(entity2) {
|
|
|
254629
254759
|
throw new TypeGenerationError(`Failed to generate types for entity "${name2}"`, name2, error48);
|
|
254630
254760
|
}
|
|
254631
254761
|
}
|
|
254762
|
+
async function compileRealtimeHandler(handler) {
|
|
254763
|
+
const { messageSchema } = handler;
|
|
254764
|
+
if (!messageSchema)
|
|
254765
|
+
return "{ inbound: unknown; outbound: unknown }";
|
|
254766
|
+
const compileSchema = async (schema11, typeName) => {
|
|
254767
|
+
if (!schema11)
|
|
254768
|
+
return "unknown";
|
|
254769
|
+
try {
|
|
254770
|
+
const ts8 = await import_json_schema_to_typescript.compile(schema11, typeName, {
|
|
254771
|
+
bannerComment: "",
|
|
254772
|
+
additionalProperties: false,
|
|
254773
|
+
strictIndexSignatures: true
|
|
254774
|
+
});
|
|
254775
|
+
const match = ts8.match(/\{([^]*)\}/);
|
|
254776
|
+
return match ? `{
|
|
254777
|
+
${match[1]}}` : "unknown";
|
|
254778
|
+
} catch {
|
|
254779
|
+
return "unknown";
|
|
254780
|
+
}
|
|
254781
|
+
};
|
|
254782
|
+
const [inbound, outbound] = await Promise.all([
|
|
254783
|
+
compileSchema(messageSchema.inbound, `${handler.name}Inbound`),
|
|
254784
|
+
compileSchema(messageSchema.outbound, `${handler.name}Outbound`)
|
|
254785
|
+
]);
|
|
254786
|
+
return `{ inbound: ${inbound}; outbound: ${outbound} }`;
|
|
254787
|
+
}
|
|
254632
254788
|
function registry2(name2, entries) {
|
|
254633
254789
|
return import_common_tags.source`
|
|
254634
254790
|
interface ${name2} {
|
|
@@ -254668,14 +254824,15 @@ var TYPES_FILE_PATH = "base44/.types/types.d.ts";
|
|
|
254668
254824
|
async function generateTypesAction({
|
|
254669
254825
|
runTask: runTask2
|
|
254670
254826
|
}) {
|
|
254671
|
-
const { entities, functions, agents, connectors, project: project2 } = await readProjectConfig();
|
|
254827
|
+
const { entities, functions, agents, connectors, realtimeHandlers, project: project2 } = await readProjectConfig();
|
|
254672
254828
|
await runTask2("Generating types", async () => {
|
|
254673
254829
|
await generateTypesFile({
|
|
254674
254830
|
projectRoot: project2.root,
|
|
254675
254831
|
entities,
|
|
254676
254832
|
functions,
|
|
254677
254833
|
agents,
|
|
254678
|
-
connectors
|
|
254834
|
+
connectors,
|
|
254835
|
+
realtimeHandlers
|
|
254679
254836
|
});
|
|
254680
254837
|
});
|
|
254681
254838
|
const tsconfigUpdated = await updateProjectConfig(project2.root);
|
|
@@ -254695,7 +254852,7 @@ function getTypesCommand() {
|
|
|
254695
254852
|
// src/cli/dev/dev-server/main.ts
|
|
254696
254853
|
var import_cors = __toESM(require_lib4(), 1);
|
|
254697
254854
|
var import_express6 = __toESM(require_express(), 1);
|
|
254698
|
-
import { dirname as
|
|
254855
|
+
import { dirname as dirname24, join as join29 } from "node:path";
|
|
254699
254856
|
|
|
254700
254857
|
// ../../node_modules/get-port/index.js
|
|
254701
254858
|
import net from "node:net";
|
|
@@ -257053,9 +257210,9 @@ class NodeFsHandler {
|
|
|
257053
257210
|
if (this.fsw.closed) {
|
|
257054
257211
|
return;
|
|
257055
257212
|
}
|
|
257056
|
-
const
|
|
257213
|
+
const dirname23 = sp2.dirname(file2);
|
|
257057
257214
|
const basename8 = sp2.basename(file2);
|
|
257058
|
-
const parent = this.fsw._getWatchedDir(
|
|
257215
|
+
const parent = this.fsw._getWatchedDir(dirname23);
|
|
257059
257216
|
let prevStats = stats;
|
|
257060
257217
|
if (parent.has(basename8))
|
|
257061
257218
|
return;
|
|
@@ -257082,7 +257239,7 @@ class NodeFsHandler {
|
|
|
257082
257239
|
prevStats = newStats2;
|
|
257083
257240
|
}
|
|
257084
257241
|
} catch (error48) {
|
|
257085
|
-
this.fsw._remove(
|
|
257242
|
+
this.fsw._remove(dirname23, basename8);
|
|
257086
257243
|
}
|
|
257087
257244
|
} else if (parent.has(basename8)) {
|
|
257088
257245
|
const at13 = newStats.atimeMs;
|
|
@@ -258115,8 +258272,8 @@ async function createDevServer(options8) {
|
|
|
258115
258272
|
broadcastEntityEvent(io6, appId, entityName, event);
|
|
258116
258273
|
};
|
|
258117
258274
|
const base44ConfigWatcher = new WatchBase44({
|
|
258118
|
-
functions: join29(
|
|
258119
|
-
entities: join29(
|
|
258275
|
+
functions: join29(dirname24(project2.configPath), project2.functionsDir),
|
|
258276
|
+
entities: join29(dirname24(project2.configPath), project2.entitiesDir)
|
|
258120
258277
|
}, devLogger);
|
|
258121
258278
|
base44ConfigWatcher.on("change", async (name2) => {
|
|
258122
258279
|
try {
|
|
@@ -258458,7 +258615,7 @@ function createProgram(context) {
|
|
|
258458
258615
|
program2.addCommand(getCreateCommand());
|
|
258459
258616
|
program2.addCommand(getScaffoldCommand());
|
|
258460
258617
|
program2.addCommand(getDashboardCommand());
|
|
258461
|
-
program2.addCommand(
|
|
258618
|
+
program2.addCommand(getDeployCommand2());
|
|
258462
258619
|
program2.addCommand(getLinkCommand());
|
|
258463
258620
|
program2.addCommand(getEjectCommand());
|
|
258464
258621
|
program2.addCommand(getEntitiesPushCommand());
|
|
@@ -258482,7 +258639,7 @@ var import_detect_agent = __toESM(require_dist5(), 1);
|
|
|
258482
258639
|
import { release, type } from "node:os";
|
|
258483
258640
|
|
|
258484
258641
|
// ../../node_modules/posthog-node/dist/extensions/error-tracking/modifiers/module.node.mjs
|
|
258485
|
-
import { dirname as
|
|
258642
|
+
import { dirname as dirname25, posix, sep } from "path";
|
|
258486
258643
|
function createModulerModifier() {
|
|
258487
258644
|
const getModuleFromFileName = createGetModuleFromFilename();
|
|
258488
258645
|
return async (frames) => {
|
|
@@ -258491,7 +258648,7 @@ function createModulerModifier() {
|
|
|
258491
258648
|
return frames;
|
|
258492
258649
|
};
|
|
258493
258650
|
}
|
|
258494
|
-
function createGetModuleFromFilename(basePath = process.argv[1] ?
|
|
258651
|
+
function createGetModuleFromFilename(basePath = process.argv[1] ? dirname25(process.argv[1]) : process.cwd(), isWindows5 = sep === "\\") {
|
|
258495
258652
|
const normalizedBase = isWindows5 ? normalizeWindowsPath2(basePath) : basePath;
|
|
258496
258653
|
return (filename) => {
|
|
258497
258654
|
if (!filename)
|
|
@@ -262680,7 +262837,7 @@ function addCommandInfoToErrorReporter(program2, errorReporter) {
|
|
|
262680
262837
|
});
|
|
262681
262838
|
}
|
|
262682
262839
|
// src/cli/index.ts
|
|
262683
|
-
var __dirname4 =
|
|
262840
|
+
var __dirname4 = dirname26(fileURLToPath6(import.meta.url));
|
|
262684
262841
|
async function runCLI(options8) {
|
|
262685
262842
|
ensureNpmAssets(join30(__dirname4, "../assets"));
|
|
262686
262843
|
const errorReporter = new ErrorReporter;
|
|
@@ -262721,4 +262878,4 @@ export {
|
|
|
262721
262878
|
CLIExitError
|
|
262722
262879
|
};
|
|
262723
262880
|
|
|
262724
|
-
//# debugId=
|
|
262881
|
+
//# debugId=EDDB07DEADDF53C864756E2164756E21
|