@base44-preview/cli 0.1.12-pr.609.cbdaa40 → 0.1.13-pr.612.0c05567
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 +242 -10
- package/dist/cli/index.js.map +5 -4
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -221222,7 +221222,7 @@ var require_dist5 = __commonJS(function(exports, module) {
|
|
|
221222
221222
|
determineAgent: () => determineAgent
|
|
221223
221223
|
});
|
|
221224
221224
|
module.exports = __toCommonJS2(src_exports);
|
|
221225
|
-
var
|
|
221225
|
+
var import_promises26 = __require("node:fs/promises");
|
|
221226
221226
|
var import_node_fs25 = __require("node:fs");
|
|
221227
221227
|
var DEVIN_LOCAL_PATH = "/opt/.devin";
|
|
221228
221228
|
var CURSOR2 = "cursor";
|
|
@@ -221280,7 +221280,7 @@ var require_dist5 = __commonJS(function(exports, module) {
|
|
|
221280
221280
|
return { isAgent: true, agent: { name: REPLIT } };
|
|
221281
221281
|
}
|
|
221282
221282
|
try {
|
|
221283
|
-
await (0,
|
|
221283
|
+
await (0, import_promises26.access)(DEVIN_LOCAL_PATH, import_node_fs25.constants.F_OK);
|
|
221284
221284
|
return { isAgent: true, agent: { name: DEVIN } };
|
|
221285
221285
|
} catch (error48) {}
|
|
221286
221286
|
return { isAgent: false, agent: undefined };
|
|
@@ -247752,6 +247752,138 @@ var functionResource = {
|
|
|
247752
247752
|
readAll: readAllFunctions,
|
|
247753
247753
|
push: (functions) => deployFunctionsSequentially(functions)
|
|
247754
247754
|
};
|
|
247755
|
+
// src/core/resources/function/stream-api.ts
|
|
247756
|
+
var StreamLogEventSchema = exports_external.object({
|
|
247757
|
+
time: exports_external.string(),
|
|
247758
|
+
level: exports_external.preprocess((value) => value === "warn" ? "warning" : value, LogLevelSchema),
|
|
247759
|
+
function: exports_external.string().nullable(),
|
|
247760
|
+
message: exports_external.string()
|
|
247761
|
+
});
|
|
247762
|
+
var StreamEndEventSchema = exports_external.object({
|
|
247763
|
+
reason: exports_external.string(),
|
|
247764
|
+
retriable: exports_external.boolean()
|
|
247765
|
+
});
|
|
247766
|
+
function buildStreamUrl(filters) {
|
|
247767
|
+
const { id } = getAppContext();
|
|
247768
|
+
const url2 = new URL(`/api/apps/${id}/functions-mgmt/logs/stream`, getBase44ApiUrl());
|
|
247769
|
+
if (filters.functions?.length) {
|
|
247770
|
+
url2.searchParams.set("function", filters.functions.join(","));
|
|
247771
|
+
}
|
|
247772
|
+
if (filters.env) {
|
|
247773
|
+
url2.searchParams.set("env", filters.env);
|
|
247774
|
+
}
|
|
247775
|
+
return url2.href;
|
|
247776
|
+
}
|
|
247777
|
+
async function buildStreamAuthHeaders() {
|
|
247778
|
+
const workspaceApiKey = getWorkspaceApiKeyFromEnv();
|
|
247779
|
+
if (workspaceApiKey && isWorkspaceApiKey(workspaceApiKey)) {
|
|
247780
|
+
return { api_key: workspaceApiKey };
|
|
247781
|
+
}
|
|
247782
|
+
const auth = await readAuth();
|
|
247783
|
+
if (isTokenExpired(auth)) {
|
|
247784
|
+
const refreshedToken = await refreshAndSaveTokens();
|
|
247785
|
+
if (refreshedToken) {
|
|
247786
|
+
return { Authorization: `Bearer ${refreshedToken}` };
|
|
247787
|
+
}
|
|
247788
|
+
}
|
|
247789
|
+
return { Authorization: `Bearer ${auth.accessToken}` };
|
|
247790
|
+
}
|
|
247791
|
+
function parseStreamEvent(eventName, data) {
|
|
247792
|
+
try {
|
|
247793
|
+
const payload = JSON.parse(data);
|
|
247794
|
+
if (eventName === "end") {
|
|
247795
|
+
const result = StreamEndEventSchema.safeParse(payload);
|
|
247796
|
+
return result.success ? { kind: "end", end: result.data } : null;
|
|
247797
|
+
}
|
|
247798
|
+
if (eventName === "") {
|
|
247799
|
+
const result = StreamLogEventSchema.safeParse(payload);
|
|
247800
|
+
return result.success ? { kind: "log", log: result.data } : null;
|
|
247801
|
+
}
|
|
247802
|
+
return null;
|
|
247803
|
+
} catch {
|
|
247804
|
+
return null;
|
|
247805
|
+
}
|
|
247806
|
+
}
|
|
247807
|
+
var STREAM_SILENCE_TIMEOUT_MS = 60000;
|
|
247808
|
+
async function readOrSilence(reader) {
|
|
247809
|
+
let timer;
|
|
247810
|
+
const silence = new Promise((resolve3) => {
|
|
247811
|
+
timer = setTimeout(() => resolve3("silence"), STREAM_SILENCE_TIMEOUT_MS);
|
|
247812
|
+
});
|
|
247813
|
+
try {
|
|
247814
|
+
return await Promise.race([reader.read(), silence]);
|
|
247815
|
+
} finally {
|
|
247816
|
+
clearTimeout(timer);
|
|
247817
|
+
}
|
|
247818
|
+
}
|
|
247819
|
+
async function* readLines(body) {
|
|
247820
|
+
const reader = body.getReader();
|
|
247821
|
+
const decoder = new TextDecoder;
|
|
247822
|
+
let buffered = "";
|
|
247823
|
+
try {
|
|
247824
|
+
while (true) {
|
|
247825
|
+
const result = await readOrSilence(reader);
|
|
247826
|
+
if (result === "silence")
|
|
247827
|
+
return;
|
|
247828
|
+
if (result.done || !result.value)
|
|
247829
|
+
return;
|
|
247830
|
+
buffered += decoder.decode(result.value, { stream: true });
|
|
247831
|
+
const lines = buffered.split(`
|
|
247832
|
+
`);
|
|
247833
|
+
buffered = lines.pop() ?? "";
|
|
247834
|
+
yield* lines;
|
|
247835
|
+
}
|
|
247836
|
+
} finally {
|
|
247837
|
+
await reader.cancel().catch(() => {});
|
|
247838
|
+
}
|
|
247839
|
+
}
|
|
247840
|
+
async function* readStreamEvents(body) {
|
|
247841
|
+
let eventName = "";
|
|
247842
|
+
for await (const line of readLines(body)) {
|
|
247843
|
+
if (line.startsWith(":")) {
|
|
247844
|
+
yield { kind: "ping" };
|
|
247845
|
+
continue;
|
|
247846
|
+
}
|
|
247847
|
+
if (line.startsWith("event:")) {
|
|
247848
|
+
eventName = line.slice(6).trim();
|
|
247849
|
+
continue;
|
|
247850
|
+
}
|
|
247851
|
+
if (line.startsWith("data:")) {
|
|
247852
|
+
const event = parseStreamEvent(eventName, line.slice(5));
|
|
247853
|
+
eventName = "";
|
|
247854
|
+
if (event)
|
|
247855
|
+
yield event;
|
|
247856
|
+
continue;
|
|
247857
|
+
}
|
|
247858
|
+
if (line.trim() === "")
|
|
247859
|
+
eventName = "";
|
|
247860
|
+
}
|
|
247861
|
+
}
|
|
247862
|
+
var STREAM_CONNECT_TIMEOUT_MS = 1e4;
|
|
247863
|
+
var isWorthReconnecting = (status) => status >= 500;
|
|
247864
|
+
async function openLogStream(filters) {
|
|
247865
|
+
const url2 = buildStreamUrl(filters);
|
|
247866
|
+
const headers = {
|
|
247867
|
+
Accept: "text/event-stream",
|
|
247868
|
+
...await buildStreamAuthHeaders()
|
|
247869
|
+
};
|
|
247870
|
+
const connectPhase = new AbortController;
|
|
247871
|
+
const connectTimer = setTimeout(() => connectPhase.abort(), STREAM_CONNECT_TIMEOUT_MS);
|
|
247872
|
+
let response;
|
|
247873
|
+
try {
|
|
247874
|
+
response = await fetch(url2, { headers, signal: connectPhase.signal });
|
|
247875
|
+
} catch {
|
|
247876
|
+
return { kind: "transient" };
|
|
247877
|
+
} finally {
|
|
247878
|
+
clearTimeout(connectTimer);
|
|
247879
|
+
}
|
|
247880
|
+
if (!response.ok) {
|
|
247881
|
+
return isWorthReconnecting(response.status) ? { kind: "transient" } : { kind: "refused" };
|
|
247882
|
+
}
|
|
247883
|
+
if (!response.body)
|
|
247884
|
+
return { kind: "transient" };
|
|
247885
|
+
return { kind: "stream", events: readStreamEvents(response.body) };
|
|
247886
|
+
}
|
|
247755
247887
|
// src/core/project/config.ts
|
|
247756
247888
|
class ProjectConfigReader {
|
|
247757
247889
|
pluginSourceByNamespace = new Map;
|
|
@@ -247927,7 +248059,7 @@ import { join as join12 } from "node:path";
|
|
|
247927
248059
|
// package.json
|
|
247928
248060
|
var package_default = {
|
|
247929
248061
|
name: "base44",
|
|
247930
|
-
version: "0.1.
|
|
248062
|
+
version: "0.1.13",
|
|
247931
248063
|
description: "Base44 CLI - Unified interface for managing Base44 applications",
|
|
247932
248064
|
type: "module",
|
|
247933
248065
|
bin: {
|
|
@@ -258278,6 +258410,7 @@ function getLinkCommand() {
|
|
|
258278
258410
|
}
|
|
258279
258411
|
|
|
258280
258412
|
// src/cli/commands/project/logs.ts
|
|
258413
|
+
import { setTimeout as delay2 } from "node:timers/promises";
|
|
258281
258414
|
function parseFunctionFilters(options) {
|
|
258282
258415
|
const filters = {};
|
|
258283
258416
|
if (options.since) {
|
|
@@ -258338,9 +258471,108 @@ function writeFollowLine(entry, jsonMode) {
|
|
|
258338
258471
|
process.stdout.write(`${line}
|
|
258339
258472
|
`);
|
|
258340
258473
|
}
|
|
258341
|
-
|
|
258342
|
-
|
|
258343
|
-
|
|
258474
|
+
function streamEventToLogEntry(event) {
|
|
258475
|
+
return {
|
|
258476
|
+
time: event.time,
|
|
258477
|
+
level: event.level,
|
|
258478
|
+
message: event.function ? `[${event.function}] ${event.message}` : event.message,
|
|
258479
|
+
source: event.function ?? ""
|
|
258480
|
+
};
|
|
258481
|
+
}
|
|
258482
|
+
async function printStreamUntilEnd(stream, levelFilter, jsonMode, startTime) {
|
|
258483
|
+
let lastTime = startTime;
|
|
258484
|
+
let provedAlive = false;
|
|
258485
|
+
try {
|
|
258486
|
+
for await (const event of stream) {
|
|
258487
|
+
provedAlive = true;
|
|
258488
|
+
if (event.kind === "end")
|
|
258489
|
+
return { lastTime, provedAlive, end: event.end };
|
|
258490
|
+
if (event.kind === "ping")
|
|
258491
|
+
continue;
|
|
258492
|
+
if (levelFilter && event.log.level !== levelFilter)
|
|
258493
|
+
continue;
|
|
258494
|
+
writeFollowLine(streamEventToLogEntry(event.log), jsonMode);
|
|
258495
|
+
if (event.log.time > lastTime)
|
|
258496
|
+
lastTime = event.log.time;
|
|
258497
|
+
}
|
|
258498
|
+
} catch {}
|
|
258499
|
+
return { lastTime, provedAlive, end: null };
|
|
258500
|
+
}
|
|
258501
|
+
var STREAM_RECONNECT_DELAY_MS = 1000;
|
|
258502
|
+
var MAX_DROPS_SINCE_LAST_EVENT = 2;
|
|
258503
|
+
var CONNECT_RETRY_DELAYS_MS = [1000, 2000, 4000, 8000];
|
|
258504
|
+
var countDropTowardGivingUp = (dropsSinceLastEvent, provedAlive) => provedAlive ? 1 : dropsSinceLastEvent + 1;
|
|
258505
|
+
var shouldGiveUpStreaming = (dropsSinceLastEvent) => dropsSinceLastEvent >= MAX_DROPS_SINCE_LAST_EVENT;
|
|
258506
|
+
async function connectWhileTransientlyUnavailable(filters) {
|
|
258507
|
+
let attempt = await openLogStream(filters);
|
|
258508
|
+
for (const retryDelay of CONNECT_RETRY_DELAYS_MS) {
|
|
258509
|
+
if (attempt.kind !== "transient")
|
|
258510
|
+
return attempt;
|
|
258511
|
+
await delay2(retryDelay);
|
|
258512
|
+
attempt = await openLogStream(filters);
|
|
258513
|
+
}
|
|
258514
|
+
return attempt;
|
|
258515
|
+
}
|
|
258516
|
+
async function streamUntilExhausted(firstStream, filters, options, jsonMode) {
|
|
258517
|
+
let events = firstStream;
|
|
258518
|
+
let lastTime = "";
|
|
258519
|
+
let dropsSinceLastEvent = 0;
|
|
258520
|
+
while (true) {
|
|
258521
|
+
const ending = await printStreamUntilEnd(events, options.level, jsonMode, lastTime);
|
|
258522
|
+
lastTime = ending.lastTime;
|
|
258523
|
+
if (ending.end) {
|
|
258524
|
+
if (!ending.end.retriable)
|
|
258525
|
+
return;
|
|
258526
|
+
dropsSinceLastEvent = 0;
|
|
258527
|
+
} else {
|
|
258528
|
+
dropsSinceLastEvent = countDropTowardGivingUp(dropsSinceLastEvent, ending.provedAlive);
|
|
258529
|
+
if (shouldGiveUpStreaming(dropsSinceLastEvent))
|
|
258530
|
+
return;
|
|
258531
|
+
}
|
|
258532
|
+
await delay2(STREAM_RECONNECT_DELAY_MS);
|
|
258533
|
+
const reopened = await connectWhileTransientlyUnavailable(filters);
|
|
258534
|
+
if (reopened.kind !== "stream")
|
|
258535
|
+
return;
|
|
258536
|
+
events = reopened.events;
|
|
258537
|
+
}
|
|
258538
|
+
}
|
|
258539
|
+
function streamLostError() {
|
|
258540
|
+
return new ApiError("The realtime log stream stopped and could not be re-established", {
|
|
258541
|
+
hints: [
|
|
258542
|
+
{ message: "Start a new live tail", command: "base44 logs --follow" },
|
|
258543
|
+
{
|
|
258544
|
+
message: "Or read recent logs without streaming",
|
|
258545
|
+
command: "base44 logs"
|
|
258546
|
+
}
|
|
258547
|
+
]
|
|
258548
|
+
});
|
|
258549
|
+
}
|
|
258550
|
+
async function followLogs(functionNames, options, availableFunctionNames, jsonMode, logger2) {
|
|
258551
|
+
const filters = {
|
|
258552
|
+
functions: parseFunctionNames(options.function),
|
|
258553
|
+
env: options.env
|
|
258554
|
+
};
|
|
258555
|
+
if (options.since) {
|
|
258556
|
+
logger2.warn("--since reads the past, so this run polls instead of streaming (lines may lag ~20-30s).");
|
|
258557
|
+
return pollLogs(functionNames, options, availableFunctionNames, jsonMode, {
|
|
258558
|
+
lastTime: "",
|
|
258559
|
+
boundaryKeys: new Set
|
|
258560
|
+
});
|
|
258561
|
+
}
|
|
258562
|
+
const opened = await connectWhileTransientlyUnavailable(filters);
|
|
258563
|
+
if (opened.kind !== "stream") {
|
|
258564
|
+
logger2.warn(opened.kind === "refused" ? "Realtime logs are not available for this app — falling back to polling (lines may lag ~20-30s)." : "Could not reach the realtime log stream — falling back to polling (lines may lag ~20-30s).");
|
|
258565
|
+
return pollLogs(functionNames, options, availableFunctionNames, jsonMode, {
|
|
258566
|
+
lastTime: "",
|
|
258567
|
+
boundaryKeys: new Set
|
|
258568
|
+
});
|
|
258569
|
+
}
|
|
258570
|
+
await streamUntilExhausted(opened.events, filters, options, jsonMode);
|
|
258571
|
+
throw streamLostError();
|
|
258572
|
+
}
|
|
258573
|
+
async function pollLogs(functionNames, options, availableFunctionNames, jsonMode, initialState) {
|
|
258574
|
+
let state = initialState;
|
|
258575
|
+
let first = state.lastTime === "";
|
|
258344
258576
|
while (true) {
|
|
258345
258577
|
const pollOptions = first ? options : { ...options, since: state.lastTime };
|
|
258346
258578
|
const entries = await fetchLogsForFunctions(functionNames, pollOptions, availableFunctionNames);
|
|
@@ -258350,7 +258582,7 @@ async function followLogs(functionNames, options, availableFunctionNames, jsonMo
|
|
|
258350
258582
|
for (const entry of fresh)
|
|
258351
258583
|
writeFollowLine(entry, jsonMode);
|
|
258352
258584
|
first = false;
|
|
258353
|
-
await
|
|
258585
|
+
await delay2(2000);
|
|
258354
258586
|
}
|
|
258355
258587
|
}
|
|
258356
258588
|
function formatLogs(entries, env3) {
|
|
@@ -258449,7 +258681,7 @@ async function logsAction(ctx, options) {
|
|
|
258449
258681
|
throw new InvalidInputError("--order cannot be combined with --follow (a live tail always streams oldest to newest).");
|
|
258450
258682
|
}
|
|
258451
258683
|
options.order = "asc";
|
|
258452
|
-
return followLogs(functionNames, options, availableFunctionNames, ctx.jsonMode);
|
|
258684
|
+
return followLogs(functionNames, options, availableFunctionNames, ctx.jsonMode, ctx.log);
|
|
258453
258685
|
}
|
|
258454
258686
|
let entries = await fetchLogsForFunctions(functionNames, options, availableFunctionNames);
|
|
258455
258687
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
|
|
@@ -258468,7 +258700,7 @@ async function logsAction(ctx, options) {
|
|
|
258468
258700
|
function getLogsCommand() {
|
|
258469
258701
|
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 deployed 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([
|
|
258470
258702
|
...LogLevelSchema.options
|
|
258471
|
-
])).option("-n, --limit <n>", "Results per page (1-1000
|
|
258703
|
+
])).option("-n, --limit <n>", "Results per page (1-1000; the server returns at most 500)").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);
|
|
258472
258704
|
}
|
|
258473
258705
|
|
|
258474
258706
|
// src/cli/commands/project/scaffold.ts
|
|
@@ -268098,4 +268330,4 @@ export {
|
|
|
268098
268330
|
runCLI
|
|
268099
268331
|
};
|
|
268100
268332
|
|
|
268101
|
-
//# debugId=
|
|
268333
|
+
//# debugId=80FBE85BCE476A3564756E2164756E21
|