@base44-preview/cli 0.1.5-pr.568.1f028a6 → 0.1.5-pr.570.f3b8004
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/deno-runtime/exec.ts +14 -0
- package/dist/cli/index.js +79 -67
- package/dist/cli/index.js.map +9 -9
- package/package.json +1 -1
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* - BASE44_APP_ID: App identifier from .app.jsonc
|
|
10
10
|
* - BASE44_ACCESS_TOKEN: User's access token
|
|
11
11
|
* - BASE44_APP_BASE_URL: App's published URL / subdomain (used for function calls)
|
|
12
|
+
* - BASE44_PRIVILEGED: When "true", adds the X-Bypass-RLS header (bypass RLS)
|
|
13
|
+
* - BASE44_DATA_ENV: When set, adds the X-Data-Env header (target data environment)
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
16
|
export {};
|
|
@@ -17,6 +19,8 @@ const scriptPath = Deno.env.get("SCRIPT_PATH");
|
|
|
17
19
|
const appId = Deno.env.get("BASE44_APP_ID");
|
|
18
20
|
const accessToken = Deno.env.get("BASE44_ACCESS_TOKEN");
|
|
19
21
|
const appBaseUrl = Deno.env.get("BASE44_APP_BASE_URL");
|
|
22
|
+
const isPrivileged = Deno.env.get("BASE44_PRIVILEGED") === "true";
|
|
23
|
+
const dataEnv = Deno.env.get("BASE44_DATA_ENV");
|
|
20
24
|
|
|
21
25
|
if (!scriptPath) {
|
|
22
26
|
console.error("SCRIPT_PATH environment variable is required");
|
|
@@ -35,10 +39,20 @@ if (!appBaseUrl) {
|
|
|
35
39
|
|
|
36
40
|
import { createClient } from "npm:@base44/sdk";
|
|
37
41
|
|
|
42
|
+
const customHeaders: Record<string, string> = {};
|
|
43
|
+
if (isPrivileged) customHeaders["X-Bypass-RLS"] = "true";
|
|
44
|
+
// QUESTION(@netanelgilad): backend get_data_environment_from_request honors only
|
|
45
|
+
// "dev" and "prod" on X-Data-Env ("share" is host-derived, unknown values fall
|
|
46
|
+
// through to prod). It applies to entity CRUD, but for backend-function invocations
|
|
47
|
+
// a caller-supplied "dev" is dropped by trusted_request_data_env (prod/no-signal
|
|
48
|
+
// pass through). Intended scope for --data-env?
|
|
49
|
+
if (dataEnv) customHeaders["X-Data-Env"] = dataEnv;
|
|
50
|
+
|
|
38
51
|
const base44 = createClient({
|
|
39
52
|
appId,
|
|
40
53
|
token: accessToken,
|
|
41
54
|
serverUrl: appBaseUrl,
|
|
55
|
+
headers: customHeaders,
|
|
42
56
|
});
|
|
43
57
|
|
|
44
58
|
(globalThis as any).base44 = base44;
|
package/dist/cli/index.js
CHANGED
|
@@ -218287,6 +218287,7 @@ var PROJECT_CONFIG_PATTERNS = [
|
|
|
218287
218287
|
`config.${CONFIG_FILE_EXTENSION_GLOB}`
|
|
218288
218288
|
];
|
|
218289
218289
|
var BASE44_APP_ID_ENV_VAR = "BASE44_APP_ID";
|
|
218290
|
+
var DEFAULT_DEV_SERVER_PORT = 4400;
|
|
218290
218291
|
var TYPES_OUTPUT_SUBDIR = ".types";
|
|
218291
218292
|
var TYPES_FILENAME = "types.d.ts";
|
|
218292
218293
|
var AUTH_CLIENT_ID = "base44_cli";
|
|
@@ -236069,13 +236070,11 @@ var CreateProjectResponseSchema = exports_external.looseObject({
|
|
|
236069
236070
|
var AppDetailSchema = exports_external.looseObject({
|
|
236070
236071
|
id: exports_external.string(),
|
|
236071
236072
|
name: exports_external.string().optional(),
|
|
236072
|
-
organization_id: exports_external.string().nullish()
|
|
236073
|
-
is_managed_source_code: exports_external.boolean().optional()
|
|
236073
|
+
organization_id: exports_external.string().nullish()
|
|
236074
236074
|
}).transform((data) => ({
|
|
236075
236075
|
id: data.id,
|
|
236076
236076
|
name: data.name,
|
|
236077
|
-
organizationId: data.organization_id ?? undefined
|
|
236078
|
-
isManagedSourceCode: data.is_managed_source_code
|
|
236077
|
+
organizationId: data.organization_id ?? undefined
|
|
236079
236078
|
}));
|
|
236080
236079
|
var ProjectSchema = exports_external.object({
|
|
236081
236080
|
id: exports_external.string(),
|
|
@@ -241896,15 +241895,14 @@ async function setAppVisibility(visibility) {
|
|
|
241896
241895
|
throw await ApiError.fromHttpError(error48, "updating app visibility");
|
|
241897
241896
|
}
|
|
241898
241897
|
}
|
|
241899
|
-
async function listProjects(
|
|
241898
|
+
async function listProjects() {
|
|
241900
241899
|
let response;
|
|
241901
241900
|
try {
|
|
241902
241901
|
response = await base44Client.get("api/apps", {
|
|
241903
241902
|
searchParams: {
|
|
241904
241903
|
sort: "-updated_date",
|
|
241905
241904
|
fields: "id,name,user_description,is_managed_source_code",
|
|
241906
|
-
limit: 50
|
|
241907
|
-
...options.workspaceId ? { workspace_id: options.workspaceId } : {}
|
|
241905
|
+
limit: 50
|
|
241908
241906
|
}
|
|
241909
241907
|
});
|
|
241910
241908
|
} catch (error48) {
|
|
@@ -241920,9 +241918,7 @@ async function getApp(appId) {
|
|
|
241920
241918
|
let response;
|
|
241921
241919
|
try {
|
|
241922
241920
|
response = await base44Client.get(`api/apps/${appId}`, {
|
|
241923
|
-
searchParams: {
|
|
241924
|
-
fields: "id,name,organization_id,is_managed_source_code"
|
|
241925
|
-
}
|
|
241921
|
+
searchParams: { fields: "id,name,organization_id" }
|
|
241926
241922
|
});
|
|
241927
241923
|
} catch (error48) {
|
|
241928
241924
|
throw await ApiError.fromHttpError(error48, "fetching app");
|
|
@@ -253471,7 +253467,7 @@ function workspaceLabel(workspace2) {
|
|
|
253471
253467
|
const suffix = workspace2.isPersonal ? "personal" : workspace2.userRole ?? "member";
|
|
253472
253468
|
return `${workspace2.name} (${suffix})`;
|
|
253473
253469
|
}
|
|
253474
|
-
async function resolveWorkspaceId(ctx, flagWorkspaceId, isInteractive
|
|
253470
|
+
async function resolveWorkspaceId(ctx, flagWorkspaceId, isInteractive) {
|
|
253475
253471
|
if (flagWorkspaceId) {
|
|
253476
253472
|
return flagWorkspaceId;
|
|
253477
253473
|
}
|
|
@@ -253482,13 +253478,13 @@ async function resolveWorkspaceId(ctx, flagWorkspaceId, isInteractive, options =
|
|
|
253482
253478
|
if (workspaces.length <= 1) {
|
|
253483
253479
|
return;
|
|
253484
253480
|
}
|
|
253485
|
-
const
|
|
253481
|
+
const options = workspaces.map((w) => ({
|
|
253486
253482
|
value: w.id,
|
|
253487
253483
|
label: workspaceLabel(w)
|
|
253488
253484
|
}));
|
|
253489
253485
|
const selected = await Je({
|
|
253490
|
-
message:
|
|
253491
|
-
options
|
|
253486
|
+
message: "Which workspace should this app belong to?",
|
|
253487
|
+
options,
|
|
253492
253488
|
initialValue: workspaces[0].id
|
|
253493
253489
|
});
|
|
253494
253490
|
if (Ct(selected)) {
|
|
@@ -253821,40 +253817,6 @@ async function promptForExistingProject(linkableProjects) {
|
|
|
253821
253817
|
}
|
|
253822
253818
|
return selectedProject;
|
|
253823
253819
|
}
|
|
253824
|
-
async function resolveExplicitAppId(ctx, appId) {
|
|
253825
|
-
const app = await ctx.runTask("Validating app...", () => getApp(appId), {
|
|
253826
|
-
errorMessage: "Could not validate app"
|
|
253827
|
-
}).catch((error48) => {
|
|
253828
|
-
if (error48 instanceof ApiError && (error48.statusCode === 404 || error48.statusCode === 403)) {
|
|
253829
|
-
throw new InvalidInputError(`App "${appId}" not found, or you don't have access to it.`, {
|
|
253830
|
-
hints: [
|
|
253831
|
-
{ message: "Check the app ID is correct" },
|
|
253832
|
-
{
|
|
253833
|
-
message: "Run 'base44 link' without --app-id to browse apps by workspace"
|
|
253834
|
-
}
|
|
253835
|
-
]
|
|
253836
|
-
});
|
|
253837
|
-
}
|
|
253838
|
-
throw error48;
|
|
253839
|
-
});
|
|
253840
|
-
if (app.isManagedSourceCode) {
|
|
253841
|
-
throw new InvalidInputError(`App "${appId}" is a managed-source app and can't be linked with the CLI.`);
|
|
253842
|
-
}
|
|
253843
|
-
return appId;
|
|
253844
|
-
}
|
|
253845
|
-
async function chooseProjectInteractively(ctx, options) {
|
|
253846
|
-
const workspaceId = await resolveWorkspaceId(ctx, options.workspace ?? options.org, !ctx.isNonInteractive, { promptMessage: "Which workspace is the app in?" });
|
|
253847
|
-
const projects = await ctx.runTask("Fetching projects...", () => listProjects({ workspaceId }), {
|
|
253848
|
-
successMessage: "Projects fetched",
|
|
253849
|
-
errorMessage: "Failed to fetch projects"
|
|
253850
|
-
});
|
|
253851
|
-
const linkableProjects = projects.filter((p) => p.isManagedSourceCode !== true);
|
|
253852
|
-
if (!linkableProjects.length) {
|
|
253853
|
-
return;
|
|
253854
|
-
}
|
|
253855
|
-
const selectedProject = await promptForExistingProject(linkableProjects);
|
|
253856
|
-
return selectedProject.id;
|
|
253857
|
-
}
|
|
253858
253820
|
async function link(ctx, options, command2) {
|
|
253859
253821
|
const { log, runTask: runTask2, isNonInteractive } = ctx;
|
|
253860
253822
|
const appId = readExplicitAppId(command2).value;
|
|
@@ -253878,10 +253840,32 @@ async function link(ctx, options, command2) {
|
|
|
253878
253840
|
let finalAppId;
|
|
253879
253841
|
const action = appId ? "choose" : options.create ? "create" : await promptForLinkAction();
|
|
253880
253842
|
if (action === "choose") {
|
|
253881
|
-
const
|
|
253882
|
-
|
|
253843
|
+
const projects = await runTask2("Fetching projects...", async () => listProjects(), {
|
|
253844
|
+
successMessage: "Projects fetched",
|
|
253845
|
+
errorMessage: "Failed to fetch projects"
|
|
253846
|
+
});
|
|
253847
|
+
const linkableProjects = projects.filter((p) => p.isManagedSourceCode !== true);
|
|
253848
|
+
if (!linkableProjects.length) {
|
|
253883
253849
|
return { outroMessage: "No projects available for linking" };
|
|
253884
253850
|
}
|
|
253851
|
+
let linkedAppId;
|
|
253852
|
+
if (appId) {
|
|
253853
|
+
const project2 = linkableProjects.find((p) => p.id === appId);
|
|
253854
|
+
if (!project2) {
|
|
253855
|
+
throw new InvalidInputError(`App with ID "${appId}" not found or not available for linking.`, {
|
|
253856
|
+
hints: [
|
|
253857
|
+
{ message: "Check the app ID is correct" },
|
|
253858
|
+
{
|
|
253859
|
+
message: "Use 'base44 link' without --app-id to see available projects"
|
|
253860
|
+
}
|
|
253861
|
+
]
|
|
253862
|
+
});
|
|
253863
|
+
}
|
|
253864
|
+
linkedAppId = appId;
|
|
253865
|
+
} else {
|
|
253866
|
+
const selectedProject = await promptForExistingProject(linkableProjects);
|
|
253867
|
+
linkedAppId = selectedProject.id;
|
|
253868
|
+
}
|
|
253885
253869
|
await runTask2("Linking project...", async () => {
|
|
253886
253870
|
await writeAppConfig(projectRoot.root, linkedAppId);
|
|
253887
253871
|
setAppContext({ id: linkedAppId, projectRoot: projectRoot.root });
|
|
@@ -253910,7 +253894,7 @@ async function link(ctx, options, command2) {
|
|
|
253910
253894
|
function getLinkCommand() {
|
|
253911
253895
|
return new Base44Command("link", {
|
|
253912
253896
|
requireAppContext: false
|
|
253913
|
-
}).description("Link a local project to a Base44 project (create new or link existing)").configureHelp({ showGlobalOptions: true }).option("-c, --create", "Create a new project (skip selection prompt)").option("-n, --name <name>", "Project name (required when --create is used)").option("-d, --description <description>", "Project description").option("-w, --workspace <id>", "Workspace (organization) ID to
|
|
253897
|
+
}).description("Link a local project to a Base44 project (create new or link existing)").configureHelp({ showGlobalOptions: true }).option("-c, --create", "Create a new project (skip selection prompt)").option("-n, --name <name>", "Project name (required when --create is used)").option("-d, --description <description>", "Project description").option("-w, --workspace <id>", "Workspace (organization) ID to create the app in when using --create (defaults to your personal workspace)").addOption(new Option("--org <id>", "Alias for --workspace").hideHelp()).addOption(new Option("-p, --project-id <id>", "Project ID to link to an existing project").hideHelp()).addOption(new Option("--projectId <id>", "Project ID to link to an existing project").hideHelp()).hook("preAction", validateNonInteractiveFlags).action(link);
|
|
253914
253898
|
}
|
|
253915
253899
|
|
|
253916
253900
|
// src/cli/commands/project/logs.ts
|
|
@@ -258474,17 +258458,14 @@ function getDevCommand() {
|
|
|
258474
258458
|
import { spawn as spawn4 } from "node:child_process";
|
|
258475
258459
|
import { copyFileSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
258476
258460
|
async function runScript(options8) {
|
|
258477
|
-
const { appId, code: code2 } = options8;
|
|
258461
|
+
const { appId, code: code2, local, privileged, dataEnv } = options8;
|
|
258478
258462
|
verifyDenoInstalled("to run scripts with exec");
|
|
258479
258463
|
const cleanupFns = [];
|
|
258480
258464
|
const tempScript = await $file({ postfix: ".ts" });
|
|
258481
258465
|
cleanupFns.push(tempScript.cleanup);
|
|
258482
258466
|
writeFileSync2(tempScript.path, code2, "utf-8");
|
|
258483
258467
|
const scriptPath = `file://${tempScript.path}`;
|
|
258484
|
-
const [appUserToken, appBaseUrl] = await Promise.all([
|
|
258485
|
-
getAppUserToken(),
|
|
258486
|
-
getSiteUrl()
|
|
258487
|
-
]);
|
|
258468
|
+
const [appUserToken, appBaseUrl] = local ? [local.token, local.serverUrl] : await Promise.all([getAppUserToken(), getSiteUrl()]);
|
|
258488
258469
|
const tempWrapper = await $file({ postfix: ".ts" });
|
|
258489
258470
|
cleanupFns.push(tempWrapper.cleanup);
|
|
258490
258471
|
copyFileSync(getExecWrapperPath(), tempWrapper.path);
|
|
@@ -258496,7 +258477,9 @@ async function runScript(options8) {
|
|
|
258496
258477
|
SCRIPT_PATH: scriptPath,
|
|
258497
258478
|
BASE44_APP_ID: appId,
|
|
258498
258479
|
BASE44_ACCESS_TOKEN: appUserToken,
|
|
258499
|
-
BASE44_APP_BASE_URL: appBaseUrl
|
|
258480
|
+
BASE44_APP_BASE_URL: appBaseUrl,
|
|
258481
|
+
...privileged ? { BASE44_PRIVILEGED: "true" } : {},
|
|
258482
|
+
...dataEnv ? { BASE44_DATA_ENV: dataEnv } : {}
|
|
258500
258483
|
},
|
|
258501
258484
|
stdio: "inherit"
|
|
258502
258485
|
});
|
|
@@ -258523,10 +258506,28 @@ function readStdin2() {
|
|
|
258523
258506
|
process.stdin.on("error", reject);
|
|
258524
258507
|
});
|
|
258525
258508
|
}
|
|
258526
|
-
|
|
258527
|
-
|
|
258528
|
-
|
|
258529
|
-
}
|
|
258509
|
+
function parsePort(value) {
|
|
258510
|
+
const port = Number(value);
|
|
258511
|
+
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
|
|
258512
|
+
throw new InvalidInputError(`Invalid --port value: "${value}".`, {
|
|
258513
|
+
hints: [{ message: "Pass a port number, e.g. --port 4400" }]
|
|
258514
|
+
});
|
|
258515
|
+
}
|
|
258516
|
+
return port;
|
|
258517
|
+
}
|
|
258518
|
+
async function resolveLocalTarget(port) {
|
|
258519
|
+
const { email: email3 } = await readAuth();
|
|
258520
|
+
return {
|
|
258521
|
+
serverUrl: `http://localhost:${port}`,
|
|
258522
|
+
token: createJwtToken(email3)
|
|
258523
|
+
};
|
|
258524
|
+
}
|
|
258525
|
+
async function execAction({ app, isNonInteractive }, options8) {
|
|
258526
|
+
if (options8.port !== undefined && !options8.local) {
|
|
258527
|
+
throw new InvalidInputError("--port can only be used with --local.", {
|
|
258528
|
+
hints: [{ message: "Usage: base44 exec --local --port <port>" }]
|
|
258529
|
+
});
|
|
258530
|
+
}
|
|
258530
258531
|
const noInputError = new InvalidInputError("No input provided. Pipe a script to stdin.", {
|
|
258531
258532
|
hints: [
|
|
258532
258533
|
{ message: "File: cat ./script.ts | base44 exec" },
|
|
@@ -258542,22 +258543,33 @@ async function execAction({
|
|
|
258542
258543
|
if (!code2.trim()) {
|
|
258543
258544
|
throw noInputError;
|
|
258544
258545
|
}
|
|
258545
|
-
const
|
|
258546
|
+
const local = options8.local ? await resolveLocalTarget(options8.port !== undefined ? parsePort(options8.port) : DEFAULT_DEV_SERVER_PORT) : undefined;
|
|
258547
|
+
const { exitCode } = await runScript({
|
|
258548
|
+
appId: app.id,
|
|
258549
|
+
code: code2,
|
|
258550
|
+
local,
|
|
258551
|
+
privileged: options8.privileged,
|
|
258552
|
+
dataEnv: options8.dataEnv
|
|
258553
|
+
});
|
|
258546
258554
|
if (exitCode !== 0) {
|
|
258547
258555
|
process.exitCode = exitCode;
|
|
258548
258556
|
}
|
|
258549
258557
|
return {};
|
|
258550
258558
|
}
|
|
258551
258559
|
function getExecCommand() {
|
|
258552
|
-
return new Base44Command("exec").description("Run a script with the Base44 SDK pre-authenticated as the current user").addHelpText("after", `
|
|
258560
|
+
return new Base44Command("exec").description("Run a script with the Base44 SDK pre-authenticated as the current user").option("--local", "Run against the local `base44 dev` server instead of the deployed app").option("--port <number>", `Port the local dev server is on (with --local; defaults to ${DEFAULT_DEV_SERVER_PORT})`).option("--privileged", "Run with admin privileges (bypass RLS). Requires app owner/editor role.").option("--data-env <environment>", "Data environment to run against (e.g. dev, prod)").addHelpText("after", `
|
|
258553
258561
|
Examples:
|
|
258554
258562
|
Run a script file:
|
|
258555
258563
|
$ cat ./script.ts | base44 exec
|
|
258556
258564
|
|
|
258557
258565
|
Inline script:
|
|
258558
|
-
$ echo "const users = await base44.entities.User.list()" | base44 exec
|
|
258559
|
-
|
|
258560
|
-
|
|
258566
|
+
$ echo "const users = await base44.entities.User.list()" | base44 exec
|
|
258567
|
+
|
|
258568
|
+
Against the local dev server (base44 dev must be running):
|
|
258569
|
+
$ echo "await base44.entities.Task.create({ title: 'seed' })" | base44 exec --local
|
|
258570
|
+
|
|
258571
|
+
With privileged access (bypass RLS):
|
|
258572
|
+
$ echo "const all = await base44.entities.Task.list()" | base44 exec --privileged`).action(execAction);
|
|
258561
258573
|
}
|
|
258562
258574
|
|
|
258563
258575
|
// src/cli/commands/project/eject.ts
|
|
@@ -262951,4 +262963,4 @@ export {
|
|
|
262951
262963
|
CLIExitError
|
|
262952
262964
|
};
|
|
262953
262965
|
|
|
262954
|
-
//# debugId=
|
|
262966
|
+
//# debugId=6F90C592BC20AEC764756E2164756E21
|