@rebasepro/cli 0.13.1-canary.g18cfeb7 → 0.13.1-canary.g249daa1
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/commands/init.d.ts +29 -0
- package/dist/fold-static.d.ts +47 -0
- package/dist/index.es.js +171 -42
- package/dist/index.es.js.map +1 -1
- package/package.json +7 -7
- package/templates/template/.env.example +11 -2
package/dist/commands/init.d.ts
CHANGED
|
@@ -68,6 +68,35 @@ export declare function formatCdTarget(cwd: string, targetDirectory: string): st
|
|
|
68
68
|
* triggering the non-TTY error. */
|
|
69
69
|
export declare function printInitHelp(): void;
|
|
70
70
|
export declare function createRebaseApp(rawArgs: string[]): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Whether `port` is free — on the wildcard address *and* on both loopback addresses.
|
|
73
|
+
*
|
|
74
|
+
* All three, because on macOS/BSD a successful bind does not mean the port is
|
|
75
|
+
* unused. Sockets carry `SO_REUSEADDR` (Node sets it), under which a wildcard
|
|
76
|
+
* bind and a specific-address bind on the same port do not conflict — in either
|
|
77
|
+
* direction. So each probe alone has a blind spot, and they are different ones:
|
|
78
|
+
*
|
|
79
|
+
* - **Wildcard only** (what this used to do) misses a server bound to
|
|
80
|
+
* `127.0.0.1` and `[::1]` — a Homebrew or Postgres.app install, i.e. most
|
|
81
|
+
* developer machines. 5432 was reported free while it was already serving
|
|
82
|
+
* another project's database. Docker then published `*:5432` for the same
|
|
83
|
+
* reason and the container started cleanly, with no "port already allocated"
|
|
84
|
+
* error anywhere to hint at the collision. `DATABASE_URL` pointed at
|
|
85
|
+
* `localhost:5432`, `localhost` resolves to `::1` first, and every command
|
|
86
|
+
* reported success while reading and writing the *pre-existing* database — a
|
|
87
|
+
* `db push` would have created tables, roles and RLS policies inside it.
|
|
88
|
+
*
|
|
89
|
+
* - **Loopback only** misses the opposite case: Docker Desktop publishes a
|
|
90
|
+
* container's port on `*`, and a specific-address bind succeeds right past it.
|
|
91
|
+
* That port is free to probe and unusable to publish, so `docker compose up -d
|
|
92
|
+
* db` fails on "Bind for 0.0.0.0:PORT failed: port is already allocated" —
|
|
93
|
+
* loudly, but only after the project has been generated around the bad port.
|
|
94
|
+
*
|
|
95
|
+
* Requiring all three costs three sockets and leaves neither gap. The wildcard
|
|
96
|
+
* bind is the one the container itself has to make; the loopback binds are the
|
|
97
|
+
* addresses `DATABASE_URL` will actually name.
|
|
98
|
+
*/
|
|
99
|
+
export declare function isPortAvailable(port: number): Promise<boolean>;
|
|
71
100
|
/**
|
|
72
101
|
* The runtime image tag to pin, given the version of the CLI doing the scaffolding.
|
|
73
102
|
*
|
package/dist/fold-static.d.ts
CHANGED
|
@@ -62,6 +62,53 @@ export declare function foldableApps(manifest: FoldableManifest): {
|
|
|
62
62
|
* evidence of a misbuild.
|
|
63
63
|
*/
|
|
64
64
|
export declare function assertBuiltForPath(indexHtml: string, basePath: string, appName: string): void;
|
|
65
|
+
/**
|
|
66
|
+
* The environment every static app is built with, wherever that build is driven from.
|
|
67
|
+
*
|
|
68
|
+
* Shared because there are two drivers — `foldFrontendIntoBundle` here, and
|
|
69
|
+
* `buildAssetApp` in `build.ts` for a standalone `type: "static"` app — and they
|
|
70
|
+
* had already drifted: the path variables were duplicated into both, so a fix
|
|
71
|
+
* applied to one shipped a bundle built the old way from the other. One function
|
|
72
|
+
* makes that impossible rather than merely unlikely.
|
|
73
|
+
*
|
|
74
|
+
* ## REBASE_APP_*
|
|
75
|
+
*
|
|
76
|
+
* The declared path is a build-time input, not only a serving concern: Vite
|
|
77
|
+
* reads `base` from REBASE_APP_BASE, and the trailing slash is that field's
|
|
78
|
+
* convention. See `assertBuiltForPath`.
|
|
79
|
+
*
|
|
80
|
+
* ## NODE_ENV
|
|
81
|
+
*
|
|
82
|
+
* A built app is a production artifact by construction, so build it as one. Not
|
|
83
|
+
* a formality: the scaffold's `.env` carries `NODE_ENV=development` for the dev
|
|
84
|
+
* backend, and Vite's `loadEnv` promotes a `NODE_ENV` found in an env file into
|
|
85
|
+
* the build unless the environment already sets one. So `rebase build` and
|
|
86
|
+
* `rebase cloud deploy` shipped a *development* bundle — `import.meta.env.DEV
|
|
87
|
+
* === true`, development React, dev-only branches live — from commands whose
|
|
88
|
+
* whole purpose is to produce something deployable. Setting it here is what
|
|
89
|
+
* closes it: Vite consults the env file's NODE_ENV only when `process.env`
|
|
90
|
+
* has none.
|
|
91
|
+
*
|
|
92
|
+
* ## VITE_API_URL
|
|
93
|
+
*
|
|
94
|
+
* An app served by the backend it talks to has its API on its own origin by
|
|
95
|
+
* construction, so a baked-in absolute URL can only be wrong. It was: that same
|
|
96
|
+
* `.env` carries `VITE_API_URL=http://localhost:3001` and
|
|
97
|
+
* `frontend/vite.config.ts` reads the project root via `envDir: ".."`, so a
|
|
98
|
+
* stock deploy shipped a site whose every request went to whoever ran the build
|
|
99
|
+
* — passing every server-side health check on the way out. Blanking it here
|
|
100
|
+
* fixes the bundle even for a project whose `.env` predates the `init` fix, or
|
|
101
|
+
* was written by hand. Empty is the right value rather than a missing one: the
|
|
102
|
+
* client falls back to `window.location.origin`, which keeps working when a
|
|
103
|
+
* custom domain is added.
|
|
104
|
+
*
|
|
105
|
+
* Vite prioritises `process.env.VITE_*` over `.env` files, so an explicit
|
|
106
|
+
* `VITE_API_URL=https://api.example.com rebase cloud deploy` still wins — the
|
|
107
|
+
* cross-origin escape hatch stays open, it just has to be deliberate. Nothing on
|
|
108
|
+
* this path loads the project `.env` into `process.env`, so a value inherited
|
|
109
|
+
* here really was set by the caller.
|
|
110
|
+
*/
|
|
111
|
+
export declare function staticBuildEnv(appPath: string, appName: string): Record<string, string>;
|
|
65
112
|
/**
|
|
66
113
|
* Build the project's static apps and fold them into the backend bundle.
|
|
67
114
|
*
|
package/dist/index.es.js
CHANGED
|
@@ -13,9 +13,9 @@ import { execSync, spawn, spawnSync } from "child_process";
|
|
|
13
13
|
import os from "os";
|
|
14
14
|
import { createRebaseClient } from "@rebasepro/client";
|
|
15
15
|
import dotenv from "dotenv";
|
|
16
|
-
import { createRequire } from "module";
|
|
17
16
|
import { BUNDLE_FORMAT_VERSION, DEFAULT_DATA_SOURCE_KEY, RUNTIME_CONTRACT_VERSION, computeSchemaVersion, deserializeCollections, findStorageSuffixCollision, getDataSourceCapabilities, normalizeStorageSources, storageEnvSuffix } from "@rebasepro/types";
|
|
18
17
|
import { generateSDK } from "@rebasepro/codegen";
|
|
18
|
+
import { createRequire } from "module";
|
|
19
19
|
//#region src/utils/package-manager.ts
|
|
20
20
|
/**
|
|
21
21
|
* Package manager detection and command abstraction.
|
|
@@ -978,13 +978,35 @@ function sanitize(properties) {
|
|
|
978
978
|
}
|
|
979
979
|
return out;
|
|
980
980
|
}
|
|
981
|
+
/**
|
|
982
|
+
* The CLI's own version, read by walking up to this package's manifest.
|
|
983
|
+
*
|
|
984
|
+
* The obvious `require("../../package.json")` was wrong everywhere, not only on
|
|
985
|
+
* one install path: `vite build` bundles this module into `dist/index.es.js`, so
|
|
986
|
+
* the specifier resolves relative to `<pkg>/dist/` and lands on
|
|
987
|
+
* `<parent-of-pkg>/package.json` — a file that does not exist under npm, pnpm or
|
|
988
|
+
* the monorepo. Every event ever sent carried `cliVersion: "unknown"`, which is
|
|
989
|
+
* the one field that makes the rest of a payload interpretable.
|
|
990
|
+
*
|
|
991
|
+
* So walk up and check the manifest's `name` rather than counting directory
|
|
992
|
+
* levels: the count differs between `src/telemetry/` and the bundled `dist/`,
|
|
993
|
+
* and a wrong count fails silently by finding *some* package.json — the nearest
|
|
994
|
+
* dependency's, under a hoisted layout. Matching the name cannot do that.
|
|
995
|
+
*/
|
|
981
996
|
function cliVersion() {
|
|
982
997
|
try {
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
998
|
+
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
999
|
+
const root = path.parse(dir).root;
|
|
1000
|
+
while (dir && dir !== root) {
|
|
1001
|
+
const manifest = path.join(dir, "package.json");
|
|
1002
|
+
if (fs.existsSync(manifest)) {
|
|
1003
|
+
const pkg = JSON.parse(fs.readFileSync(manifest, "utf-8"));
|
|
1004
|
+
if (pkg?.name === "@rebasepro/cli" && typeof pkg.version === "string" && pkg.version) return pkg.version;
|
|
1005
|
+
}
|
|
1006
|
+
dir = path.dirname(dir);
|
|
1007
|
+
}
|
|
1008
|
+
} catch {}
|
|
1009
|
+
return "unknown";
|
|
988
1010
|
}
|
|
989
1011
|
function buildEvent(event, properties, identity) {
|
|
990
1012
|
return {
|
|
@@ -1635,6 +1657,49 @@ async function linkScaffoldToCloud(options) {
|
|
|
1635
1657
|
console.warn(chalk.yellow(` ${linkLater}`));
|
|
1636
1658
|
}
|
|
1637
1659
|
}
|
|
1660
|
+
/**
|
|
1661
|
+
* Make the initial commit, after everything that writes into the project has run.
|
|
1662
|
+
*
|
|
1663
|
+
* It used to happen immediately after `git init`, which is before dependency
|
|
1664
|
+
* installation and before introspection — so `init --git --install` ended on a
|
|
1665
|
+
* dirty tree whose only untracked file was `pnpm-lock.yaml`. A lockfile is
|
|
1666
|
+
* precisely the thing that should be in a project's first commit, and a brand
|
|
1667
|
+
* new scaffold whose first `git status` is dirty invites the reader to conclude
|
|
1668
|
+
* the lockfile is deliberately ignored and never commit it at all.
|
|
1669
|
+
*
|
|
1670
|
+
* Introspection has the same shape: it generates `config/collections` and
|
|
1671
|
+
* `schema.generated.ts`, which belong in the commit describing the scaffold that
|
|
1672
|
+
* produced them.
|
|
1673
|
+
*
|
|
1674
|
+
* `git init` stays where it was. Creating the repository early costs nothing and
|
|
1675
|
+
* means a failed install still leaves the user a repository to commit into.
|
|
1676
|
+
*/
|
|
1677
|
+
async function commitScaffold(targetDirectory) {
|
|
1678
|
+
try {
|
|
1679
|
+
await execa("git", ["add", "-A"], { cwd: targetDirectory });
|
|
1680
|
+
let identity = {};
|
|
1681
|
+
try {
|
|
1682
|
+
await execa("git", ["config", "user.email"], { cwd: targetDirectory });
|
|
1683
|
+
} catch {
|
|
1684
|
+
identity = {
|
|
1685
|
+
GIT_AUTHOR_NAME: "Rebase",
|
|
1686
|
+
GIT_AUTHOR_EMAIL: "noreply@rebase.pro",
|
|
1687
|
+
GIT_COMMITTER_NAME: "Rebase",
|
|
1688
|
+
GIT_COMMITTER_EMAIL: "noreply@rebase.pro"
|
|
1689
|
+
};
|
|
1690
|
+
}
|
|
1691
|
+
await execa("git", [
|
|
1692
|
+
"commit",
|
|
1693
|
+
"-m",
|
|
1694
|
+
"Initial commit from Rebase"
|
|
1695
|
+
], {
|
|
1696
|
+
cwd: targetDirectory,
|
|
1697
|
+
env: identity
|
|
1698
|
+
});
|
|
1699
|
+
} catch {
|
|
1700
|
+
console.warn(chalk.yellow(" Warning: Failed to create the initial commit"));
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1638
1703
|
async function createProject$1(options) {
|
|
1639
1704
|
const startedAt = Date.now();
|
|
1640
1705
|
if (fs.existsSync(options.targetDirectory)) {
|
|
@@ -1674,6 +1739,7 @@ async function createProject$1(options) {
|
|
|
1674
1739
|
await applyHeadless(options.targetDirectory, options.headless);
|
|
1675
1740
|
await replacePlaceholders(options);
|
|
1676
1741
|
await configureEnvFile(options.targetDirectory, options.databaseUrl);
|
|
1742
|
+
let gitInitialized = false;
|
|
1677
1743
|
if (options.git) {
|
|
1678
1744
|
console.log(chalk.gray(" Initializing git repository..."));
|
|
1679
1745
|
try {
|
|
@@ -1685,26 +1751,7 @@ async function createProject$1(options) {
|
|
|
1685
1751
|
"refs/heads/main"
|
|
1686
1752
|
], { cwd: options.targetDirectory });
|
|
1687
1753
|
} catch {}
|
|
1688
|
-
|
|
1689
|
-
let identity = {};
|
|
1690
|
-
try {
|
|
1691
|
-
await execa("git", ["config", "user.email"], { cwd: options.targetDirectory });
|
|
1692
|
-
} catch {
|
|
1693
|
-
identity = {
|
|
1694
|
-
GIT_AUTHOR_NAME: "Rebase",
|
|
1695
|
-
GIT_AUTHOR_EMAIL: "noreply@rebase.pro",
|
|
1696
|
-
GIT_COMMITTER_NAME: "Rebase",
|
|
1697
|
-
GIT_COMMITTER_EMAIL: "noreply@rebase.pro"
|
|
1698
|
-
};
|
|
1699
|
-
}
|
|
1700
|
-
await execa("git", [
|
|
1701
|
-
"commit",
|
|
1702
|
-
"-m",
|
|
1703
|
-
"Initial commit from Rebase"
|
|
1704
|
-
], {
|
|
1705
|
-
cwd: options.targetDirectory,
|
|
1706
|
-
env: identity
|
|
1707
|
-
});
|
|
1754
|
+
gitInitialized = true;
|
|
1708
1755
|
} catch {
|
|
1709
1756
|
console.warn(chalk.yellow(" Warning: Failed to initialize git repository"));
|
|
1710
1757
|
}
|
|
@@ -1761,6 +1808,7 @@ async function createProject$1(options) {
|
|
|
1761
1808
|
console.warn(chalk.yellow(` Run \`${installCmd.join(" ")}\` then \`${execCmd.join(" ")}\` manually.`));
|
|
1762
1809
|
}
|
|
1763
1810
|
}
|
|
1811
|
+
if (gitInitialized) await commitScaffold(options.targetDirectory);
|
|
1764
1812
|
await linkScaffoldToCloud(options);
|
|
1765
1813
|
console.log("");
|
|
1766
1814
|
console.log(`${chalk.green.bold("✓")} Project ${chalk.bold(options.projectName)} created successfully!`);
|
|
@@ -2005,18 +2053,51 @@ project directory ${path.basename(options.targetDirectory)}/ was created and is
|
|
|
2005
2053
|
fs.writeFileSync(fullPath, content, "utf-8");
|
|
2006
2054
|
}
|
|
2007
2055
|
}
|
|
2008
|
-
|
|
2056
|
+
/** `undefined` binds the wildcard address, which is a different question — see isPortAvailable. */
|
|
2057
|
+
function canBind(port, host) {
|
|
2009
2058
|
return new Promise((resolve) => {
|
|
2010
2059
|
const server = net.createServer();
|
|
2011
|
-
server.once("error", () => {
|
|
2012
|
-
resolve(
|
|
2060
|
+
server.once("error", (err) => {
|
|
2061
|
+
resolve(err.code === "EAFNOSUPPORT" || err.code === "EADDRNOTAVAIL");
|
|
2013
2062
|
});
|
|
2014
2063
|
server.once("listening", () => {
|
|
2015
2064
|
server.close(() => resolve(true));
|
|
2016
2065
|
});
|
|
2017
|
-
server.listen(port);
|
|
2066
|
+
if (host === void 0) server.listen(port);
|
|
2067
|
+
else server.listen(port, host);
|
|
2018
2068
|
});
|
|
2019
2069
|
}
|
|
2070
|
+
/**
|
|
2071
|
+
* Whether `port` is free — on the wildcard address *and* on both loopback addresses.
|
|
2072
|
+
*
|
|
2073
|
+
* All three, because on macOS/BSD a successful bind does not mean the port is
|
|
2074
|
+
* unused. Sockets carry `SO_REUSEADDR` (Node sets it), under which a wildcard
|
|
2075
|
+
* bind and a specific-address bind on the same port do not conflict — in either
|
|
2076
|
+
* direction. So each probe alone has a blind spot, and they are different ones:
|
|
2077
|
+
*
|
|
2078
|
+
* - **Wildcard only** (what this used to do) misses a server bound to
|
|
2079
|
+
* `127.0.0.1` and `[::1]` — a Homebrew or Postgres.app install, i.e. most
|
|
2080
|
+
* developer machines. 5432 was reported free while it was already serving
|
|
2081
|
+
* another project's database. Docker then published `*:5432` for the same
|
|
2082
|
+
* reason and the container started cleanly, with no "port already allocated"
|
|
2083
|
+
* error anywhere to hint at the collision. `DATABASE_URL` pointed at
|
|
2084
|
+
* `localhost:5432`, `localhost` resolves to `::1` first, and every command
|
|
2085
|
+
* reported success while reading and writing the *pre-existing* database — a
|
|
2086
|
+
* `db push` would have created tables, roles and RLS policies inside it.
|
|
2087
|
+
*
|
|
2088
|
+
* - **Loopback only** misses the opposite case: Docker Desktop publishes a
|
|
2089
|
+
* container's port on `*`, and a specific-address bind succeeds right past it.
|
|
2090
|
+
* That port is free to probe and unusable to publish, so `docker compose up -d
|
|
2091
|
+
* db` fails on "Bind for 0.0.0.0:PORT failed: port is already allocated" —
|
|
2092
|
+
* loudly, but only after the project has been generated around the bad port.
|
|
2093
|
+
*
|
|
2094
|
+
* Requiring all three costs three sockets and leaves neither gap. The wildcard
|
|
2095
|
+
* bind is the one the container itself has to make; the loopback binds are the
|
|
2096
|
+
* addresses `DATABASE_URL` will actually name.
|
|
2097
|
+
*/
|
|
2098
|
+
async function isPortAvailable(port) {
|
|
2099
|
+
return await canBind(port) && await canBind(port, "127.0.0.1") && await canBind(port, "::1");
|
|
2100
|
+
}
|
|
2020
2101
|
async function findAvailablePort(startPort) {
|
|
2021
2102
|
let port = startPort;
|
|
2022
2103
|
while (!await isPortAvailable(port)) port++;
|
|
@@ -2086,6 +2167,7 @@ async function configureEnvFile(targetDirectory, databaseUrl) {
|
|
|
2086
2167
|
envContent = envContent.replace(/^#\s*REBASE_SERVICE_KEY=.*$/m, `REBASE_SERVICE_KEY=${serviceKey}`);
|
|
2087
2168
|
const composeApiPort = /^PORT=(\d+)/m.exec(envContent)?.[1] ?? "3001";
|
|
2088
2169
|
envContent = envContent.replace(/^#\s*CORS_ORIGINS=.*$/m, `CORS_ORIGINS=http://localhost:${composeApiPort}`);
|
|
2170
|
+
envContent = envContent.replace(/^#?\s*VITE_API_URL=.*$/m, "VITE_API_URL=");
|
|
2089
2171
|
const { tag: runtimeVersion, note } = resolveRuntimeImageTag(readCliVersion());
|
|
2090
2172
|
const pinned = `${note ? `${note}\n` : ""}REBASE_VERSION=${runtimeVersion}`;
|
|
2091
2173
|
envContent = /^#?\s*REBASE_VERSION=.*$/m.test(envContent) ? envContent.replace(/^#?\s*REBASE_VERSION=.*$/m, pinned) : `${envContent.trimEnd()}\n\n# The Rebase runtime image tag docker-compose.yml pulls.\n# Change this and restart to upgrade; your project bundle is untouched.\n${pinned}\n`;
|
|
@@ -2096,7 +2178,7 @@ async function configureEnvFile(targetDirectory, databaseUrl) {
|
|
|
2096
2178
|
envContent = envContent.replace(/^DATABASE_URL=.*$/m, `DATABASE_URL=${pinnedUrl}\nDATABASE_PASSWORD=${dbPassword}`);
|
|
2097
2179
|
} else {
|
|
2098
2180
|
const dbPort = await findAvailablePort(5432);
|
|
2099
|
-
envContent = envContent.replace(/^DATABASE_URL=.*$/m, `DATABASE_URL=postgresql://rebase_app:${dbPassword}@
|
|
2181
|
+
envContent = envContent.replace(/^DATABASE_URL=.*$/m, `DATABASE_URL=postgresql://rebase_app:${dbPassword}@127.0.0.1:${dbPort}/rebase?options=-c%20search_path=public&sslmode=disable\nDATABASE_PASSWORD=${dbPassword}`);
|
|
2100
2182
|
const dockerComposePath = path.join(targetDirectory, "docker-compose.yml");
|
|
2101
2183
|
if (fs.existsSync(dockerComposePath)) {
|
|
2102
2184
|
let dockerComposeContent = fs.readFileSync(dockerComposePath, "utf-8");
|
|
@@ -4846,6 +4928,61 @@ function assertBuiltForPath(indexHtml, basePath, appName) {
|
|
|
4846
4928
|
build config — see docs/apps-and-runtimes.md §4.2.`);
|
|
4847
4929
|
}
|
|
4848
4930
|
/**
|
|
4931
|
+
* The environment every static app is built with, wherever that build is driven from.
|
|
4932
|
+
*
|
|
4933
|
+
* Shared because there are two drivers — `foldFrontendIntoBundle` here, and
|
|
4934
|
+
* `buildAssetApp` in `build.ts` for a standalone `type: "static"` app — and they
|
|
4935
|
+
* had already drifted: the path variables were duplicated into both, so a fix
|
|
4936
|
+
* applied to one shipped a bundle built the old way from the other. One function
|
|
4937
|
+
* makes that impossible rather than merely unlikely.
|
|
4938
|
+
*
|
|
4939
|
+
* ## REBASE_APP_*
|
|
4940
|
+
*
|
|
4941
|
+
* The declared path is a build-time input, not only a serving concern: Vite
|
|
4942
|
+
* reads `base` from REBASE_APP_BASE, and the trailing slash is that field's
|
|
4943
|
+
* convention. See `assertBuiltForPath`.
|
|
4944
|
+
*
|
|
4945
|
+
* ## NODE_ENV
|
|
4946
|
+
*
|
|
4947
|
+
* A built app is a production artifact by construction, so build it as one. Not
|
|
4948
|
+
* a formality: the scaffold's `.env` carries `NODE_ENV=development` for the dev
|
|
4949
|
+
* backend, and Vite's `loadEnv` promotes a `NODE_ENV` found in an env file into
|
|
4950
|
+
* the build unless the environment already sets one. So `rebase build` and
|
|
4951
|
+
* `rebase cloud deploy` shipped a *development* bundle — `import.meta.env.DEV
|
|
4952
|
+
* === true`, development React, dev-only branches live — from commands whose
|
|
4953
|
+
* whole purpose is to produce something deployable. Setting it here is what
|
|
4954
|
+
* closes it: Vite consults the env file's NODE_ENV only when `process.env`
|
|
4955
|
+
* has none.
|
|
4956
|
+
*
|
|
4957
|
+
* ## VITE_API_URL
|
|
4958
|
+
*
|
|
4959
|
+
* An app served by the backend it talks to has its API on its own origin by
|
|
4960
|
+
* construction, so a baked-in absolute URL can only be wrong. It was: that same
|
|
4961
|
+
* `.env` carries `VITE_API_URL=http://localhost:3001` and
|
|
4962
|
+
* `frontend/vite.config.ts` reads the project root via `envDir: ".."`, so a
|
|
4963
|
+
* stock deploy shipped a site whose every request went to whoever ran the build
|
|
4964
|
+
* — passing every server-side health check on the way out. Blanking it here
|
|
4965
|
+
* fixes the bundle even for a project whose `.env` predates the `init` fix, or
|
|
4966
|
+
* was written by hand. Empty is the right value rather than a missing one: the
|
|
4967
|
+
* client falls back to `window.location.origin`, which keeps working when a
|
|
4968
|
+
* custom domain is added.
|
|
4969
|
+
*
|
|
4970
|
+
* Vite prioritises `process.env.VITE_*` over `.env` files, so an explicit
|
|
4971
|
+
* `VITE_API_URL=https://api.example.com rebase cloud deploy` still wins — the
|
|
4972
|
+
* cross-origin escape hatch stays open, it just has to be deliberate. Nothing on
|
|
4973
|
+
* this path loads the project `.env` into `process.env`, so a value inherited
|
|
4974
|
+
* here really was set by the caller.
|
|
4975
|
+
*/
|
|
4976
|
+
function staticBuildEnv(appPath, appName) {
|
|
4977
|
+
return {
|
|
4978
|
+
REBASE_APP_PATH: appPath,
|
|
4979
|
+
REBASE_APP_BASE: appPath === "/" ? "/" : `${appPath}/`,
|
|
4980
|
+
REBASE_APP_NAME: appName,
|
|
4981
|
+
NODE_ENV: "production",
|
|
4982
|
+
VITE_API_URL: process.env.VITE_API_URL ?? ""
|
|
4983
|
+
};
|
|
4984
|
+
}
|
|
4985
|
+
/**
|
|
4849
4986
|
* Build the project's static apps and fold them into the backend bundle.
|
|
4850
4987
|
*
|
|
4851
4988
|
* Throws rather than exiting, so the caller decides whether a missing frontend
|
|
@@ -4864,11 +5001,7 @@ async function foldFrontendIntoBundle(options) {
|
|
|
4864
5001
|
cwd: projectRoot,
|
|
4865
5002
|
stdio: "inherit",
|
|
4866
5003
|
shell: true,
|
|
4867
|
-
env:
|
|
4868
|
-
REBASE_APP_PATH: app.path,
|
|
4869
|
-
REBASE_APP_BASE: app.path === "/" ? "/" : `${app.path}/`,
|
|
4870
|
-
REBASE_APP_NAME: app.name
|
|
4871
|
-
}
|
|
5004
|
+
env: staticBuildEnv(app.path, app.name)
|
|
4872
5005
|
});
|
|
4873
5006
|
const assetsDir = path.join(projectRoot, app.output);
|
|
4874
5007
|
if (!fs.existsSync(assetsDir)) throw new Error(`"${app.name}" declared output "${app.output}" does not exist after building — the bundle would ship without a frontend.`);
|
|
@@ -5058,11 +5191,7 @@ async function buildAssetApp(projectRoot, name, app, runtimeRange, outOverride)
|
|
|
5058
5191
|
cwd: projectRoot,
|
|
5059
5192
|
stdio: "inherit",
|
|
5060
5193
|
shell: true,
|
|
5061
|
-
env:
|
|
5062
|
-
REBASE_APP_PATH: basePath,
|
|
5063
|
-
REBASE_APP_BASE: basePath === "/" ? "/" : `${basePath}/`,
|
|
5064
|
-
REBASE_APP_NAME: name
|
|
5065
|
-
}
|
|
5194
|
+
env: staticBuildEnv(basePath, name)
|
|
5066
5195
|
});
|
|
5067
5196
|
} catch {
|
|
5068
5197
|
console.error(chalk.red(` ✗ build command failed for "${name}"`));
|
|
@@ -11184,6 +11313,6 @@ function telemetryNotice() {
|
|
|
11184
11313
|
return chalk.gray(`Usage sharing: ${sharing ? "on" : "off"} — ${chalk.cyan("rebase telemetry")} to inspect or change\n`);
|
|
11185
11314
|
}
|
|
11186
11315
|
//#endregion
|
|
11187
|
-
export { CURRENT_RUNTIME_RANGE, DEFAULT_BUNDLE_DIR, DEFAULT_CONFIG_DIR, DEFAULT_CRONS_DIR, DEFAULT_FUNCTIONS_DIR, DEFAULT_SCHEMA_FILE, DEV_PORT_FILENAME, MANIFEST_FILENAME, ManifestError, TEMPLATE_PLACEHOLDER_FILES, appsCommand, assessManagedCompatibility, authCommand, buildBundle, buildCommand, buildInitQuestions, buildStaticBundle, buildableApps, cloudCommand, collectDeclaredDependencies, configureEnvFile, createRebaseApp, dbCommand, detectFrameworkDepDrift, detectNativeDependencies, detectPackageManager, detectStorageAuthorize, devCommand, doctorCommand, ejectCommand, entry, findBackendApp, findBackendDir, findEnvFile, findFrontendDir, findProjectRoot, findUnusedServerEntry, foldStaticIntoBundle, formatCdTarget, generateSdkCommand, getActiveBackendPlugin, getPMCommands, getProjectPort, isIdentifierLike, isPnpmAvailable, loadManifest, manifestExists, manifestPath, normalizeEsmSpecifiers, pnpmAvailabilityFromProbe, positionals, printInitHelp, readEnvFile, requireBackendDir, requireProjectRoot, resetPnpmAvailabilityCache, resolveBackendPaths, resolveCliVersion, resolveExampleBaseUrl, resolveLocalBin, resolvePluginCliScript, resolveRuntimeImageTag, resolveStartPort, resolveTsx, schemaCommand, selectUserForEmail, startCommand, synthesizeManifest, validateManifest, validateProjectName, validateTsxInstallation, writeManifest };
|
|
11316
|
+
export { CURRENT_RUNTIME_RANGE, DEFAULT_BUNDLE_DIR, DEFAULT_CONFIG_DIR, DEFAULT_CRONS_DIR, DEFAULT_FUNCTIONS_DIR, DEFAULT_SCHEMA_FILE, DEV_PORT_FILENAME, MANIFEST_FILENAME, ManifestError, TEMPLATE_PLACEHOLDER_FILES, appsCommand, assessManagedCompatibility, authCommand, buildBundle, buildCommand, buildInitQuestions, buildStaticBundle, buildableApps, cloudCommand, collectDeclaredDependencies, configureEnvFile, createRebaseApp, dbCommand, detectFrameworkDepDrift, detectNativeDependencies, detectPackageManager, detectStorageAuthorize, devCommand, doctorCommand, ejectCommand, entry, findBackendApp, findBackendDir, findEnvFile, findFrontendDir, findProjectRoot, findUnusedServerEntry, foldStaticIntoBundle, formatCdTarget, generateSdkCommand, getActiveBackendPlugin, getPMCommands, getProjectPort, isIdentifierLike, isPnpmAvailable, isPortAvailable, loadManifest, manifestExists, manifestPath, normalizeEsmSpecifiers, pnpmAvailabilityFromProbe, positionals, printInitHelp, readEnvFile, requireBackendDir, requireProjectRoot, resetPnpmAvailabilityCache, resolveBackendPaths, resolveCliVersion, resolveExampleBaseUrl, resolveLocalBin, resolvePluginCliScript, resolveRuntimeImageTag, resolveStartPort, resolveTsx, schemaCommand, selectUserForEmail, startCommand, synthesizeManifest, validateManifest, validateProjectName, validateTsxInstallation, writeManifest };
|
|
11188
11317
|
|
|
11189
11318
|
//# sourceMappingURL=index.es.js.map
|