@stacksjs/ts-cloud 0.7.31 → 0.7.33
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/bin/cli.js +357 -356
- package/dist/{chunk-crcjdm09.js → chunk-1nfkggdw.js} +24 -21
- package/dist/{chunk-0c69nbaa.js → chunk-m0zayf6n.js} +30 -10
- package/dist/deploy/dashboard-database.d.ts +8 -6
- package/dist/deploy/index.js +2 -2
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/shared/backups.d.ts +3 -1
- package/dist/drivers/shared/db-provision.d.ts +24 -2
- package/dist/index.js +2 -2
- package/dist/ui/index.html +3 -3
- package/dist/ui/server/actions.html +23 -6
- package/dist/ui/server/backups.html +3 -3
- package/dist/ui/server/database.html +3 -3
- package/dist/ui/server/deployments.html +3 -3
- package/dist/ui/server/firewall.html +3 -3
- package/dist/ui/server/logs.html +3 -3
- package/dist/ui/server/services.html +3 -3
- package/dist/ui/server/sites.html +3 -3
- package/dist/ui/server/ssh-keys.html +26 -4
- package/dist/ui/server/team.html +26 -4
- package/dist/ui/server/terminal.html +3 -3
- package/dist/ui/server/workers.html +3 -3
- package/dist/ui/serverless/alarms.html +3 -3
- package/dist/ui/serverless/assets.html +3 -3
- package/dist/ui/serverless/data.html +3 -3
- package/dist/ui/serverless/deployments.html +3 -3
- package/dist/ui/serverless/functions.html +3 -3
- package/dist/ui/serverless/logs.html +3 -3
- package/dist/ui/serverless/queues.html +3 -3
- package/dist/ui/serverless/scheduler.html +3 -3
- package/dist/ui/serverless/secrets.html +3 -3
- package/dist/ui/serverless/traces.html +3 -3
- package/dist/ui/serverless.html +23 -6
- package/dist/ui-src/pages/server/actions.stx +27 -4
- package/dist/ui-src/pages/server/ssh-keys.stx +22 -1
- package/dist/ui-src/pages/server/team.stx +23 -1
- package/dist/ui-src/pages/serverless.stx +27 -4
- package/package.json +3 -3
|
@@ -22,13 +22,14 @@ import {
|
|
|
22
22
|
buildBackupRestoreScript,
|
|
23
23
|
buildRollbackScript,
|
|
24
24
|
createCloudDriver,
|
|
25
|
+
pgAdminCommand,
|
|
25
26
|
releasePaths,
|
|
26
27
|
resolveHetznerLocation,
|
|
27
28
|
resolveSiteFramework,
|
|
28
29
|
resolveSiteKind,
|
|
29
30
|
resolveUiSource,
|
|
30
31
|
siteInstallBase
|
|
31
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-m0zayf6n.js";
|
|
32
33
|
import {
|
|
33
34
|
artifactKey,
|
|
34
35
|
composeServerlessAppTemplate,
|
|
@@ -10913,33 +10914,33 @@ function mysqlExec(engine, sql) {
|
|
|
10913
10914
|
const sock = engine === "mariadb" ? SOCKETS.mariadb : SOCKETS.mysql;
|
|
10914
10915
|
return [`mysql --socket=${sock} -u root <<'TS_CLOUD_SQL_EOF'`, ...sql, "TS_CLOUD_SQL_EOF"];
|
|
10915
10916
|
}
|
|
10916
|
-
function pgExec(sql) {
|
|
10917
|
-
return [
|
|
10917
|
+
function pgExec(sql, database) {
|
|
10918
|
+
return [`${pgAdminCommand(database)} -tA <<'TS_CLOUD_PG_EOF'`, ...sql, "TS_CLOUD_PG_EOF"];
|
|
10918
10919
|
}
|
|
10919
|
-
function buildListScript(engine) {
|
|
10920
|
+
function buildListScript(engine, database) {
|
|
10920
10921
|
if (engine === "postgres") {
|
|
10921
10922
|
return pgExec([
|
|
10922
10923
|
"SELECT 'DB=' || datname FROM pg_database WHERE datistemplate = false;",
|
|
10923
10924
|
"SELECT 'USER=' || usename FROM pg_user;"
|
|
10924
|
-
]);
|
|
10925
|
+
], database);
|
|
10925
10926
|
}
|
|
10926
10927
|
return mysqlExec(engine, [
|
|
10927
10928
|
"SELECT CONCAT('DB=', schema_name) FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys');",
|
|
10928
10929
|
"SELECT DISTINCT CONCAT('USER=', User) FROM mysql.user WHERE User NOT IN ('root', 'mysql.sys', 'mysql.session', 'mysql.infoschema', 'debian-sys-maint');"
|
|
10929
10930
|
]);
|
|
10930
10931
|
}
|
|
10931
|
-
function buildCreateDatabaseScript(engine, name) {
|
|
10932
|
+
function buildCreateDatabaseScript(engine, name, database) {
|
|
10932
10933
|
if (engine === "postgres") {
|
|
10933
10934
|
return pgExec([
|
|
10934
10935
|
`SELECT 'CREATE DATABASE ${pgIdent(name)}' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = ${pgLit(name)})\\gexec`
|
|
10935
|
-
]);
|
|
10936
|
+
], database);
|
|
10936
10937
|
}
|
|
10937
10938
|
return mysqlExec(engine, [
|
|
10938
10939
|
`CREATE DATABASE IF NOT EXISTS \`${mysqlIdent(name)}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;`
|
|
10939
10940
|
]);
|
|
10940
10941
|
}
|
|
10941
|
-
function buildCreateUserScript(engine, input) {
|
|
10942
|
-
const { username, password, database, access: access4 } = input;
|
|
10942
|
+
function buildCreateUserScript(engine, input, database) {
|
|
10943
|
+
const { username, password, database: grantDb, access: access4 } = input;
|
|
10943
10944
|
if (engine === "postgres") {
|
|
10944
10945
|
const lines2 = [
|
|
10945
10946
|
"DO $$ BEGIN",
|
|
@@ -10947,10 +10948,10 @@ function buildCreateUserScript(engine, input) {
|
|
|
10947
10948
|
` ELSE ALTER ROLE ${pgIdent(username)} LOGIN PASSWORD ${pgLit(password)}; END IF;`,
|
|
10948
10949
|
"END $$;"
|
|
10949
10950
|
];
|
|
10950
|
-
if (
|
|
10951
|
-
lines2.push(access4 === "readonly" ? `GRANT CONNECT ON DATABASE ${pgIdent(
|
|
10951
|
+
if (grantDb) {
|
|
10952
|
+
lines2.push(access4 === "readonly" ? `GRANT CONNECT ON DATABASE ${pgIdent(grantDb)} TO ${pgIdent(username)};` : `GRANT ALL PRIVILEGES ON DATABASE ${pgIdent(grantDb)} TO ${pgIdent(username)};`);
|
|
10952
10953
|
}
|
|
10953
|
-
return pgExec(lines2);
|
|
10954
|
+
return pgExec(lines2, database);
|
|
10954
10955
|
}
|
|
10955
10956
|
const priv = access4 === "readonly" ? "SELECT" : "ALL PRIVILEGES";
|
|
10956
10957
|
const lines = [
|
|
@@ -10959,8 +10960,8 @@ function buildCreateUserScript(engine, input) {
|
|
|
10959
10960
|
`ALTER USER '${mysqlLit(username)}'@'%' IDENTIFIED BY '${mysqlLit(password)}';`,
|
|
10960
10961
|
`ALTER USER '${mysqlLit(username)}'@'localhost' IDENTIFIED BY '${mysqlLit(password)}';`
|
|
10961
10962
|
];
|
|
10962
|
-
if (
|
|
10963
|
-
lines.push(`GRANT ${priv} ON \`${mysqlIdent(
|
|
10963
|
+
if (grantDb) {
|
|
10964
|
+
lines.push(`GRANT ${priv} ON \`${mysqlIdent(grantDb)}\`.* TO '${mysqlLit(username)}'@'%';`, `GRANT ${priv} ON \`${mysqlIdent(grantDb)}\`.* TO '${mysqlLit(username)}'@'localhost';`);
|
|
10964
10965
|
}
|
|
10965
10966
|
lines.push("FLUSH PRIVILEGES;");
|
|
10966
10967
|
return mysqlExec(engine, lines);
|
|
@@ -11002,24 +11003,24 @@ async function runDb(config6, environment, commands, comment) {
|
|
|
11002
11003
|
}
|
|
11003
11004
|
async function listDatabases(config6, environment) {
|
|
11004
11005
|
const engine = resolveDbEngine(config6);
|
|
11005
|
-
const r = await runDb(config6, environment, buildListScript(engine), "ts-cloud db:list");
|
|
11006
|
+
const r = await runDb(config6, environment, buildListScript(engine, resolveAppDatabase(config6)), "ts-cloud db:list");
|
|
11006
11007
|
const parsed = r.ok && r.stdout ? parseDbList(r.stdout) : { databases: [], users: [] };
|
|
11007
11008
|
return { ...r, engine, ...parsed };
|
|
11008
11009
|
}
|
|
11009
11010
|
async function createDatabase(config6, environment, name) {
|
|
11010
11011
|
const engine = resolveDbEngine(config6);
|
|
11011
|
-
return runDb(config6, environment, buildCreateDatabaseScript(engine, name), `ts-cloud db:create ${name}`);
|
|
11012
|
+
return runDb(config6, environment, buildCreateDatabaseScript(engine, name, resolveAppDatabase(config6)), `ts-cloud db:create ${name}`);
|
|
11012
11013
|
}
|
|
11013
11014
|
async function createDatabaseUser(config6, environment, input) {
|
|
11014
11015
|
const engine = resolveDbEngine(config6);
|
|
11015
|
-
return runDb(config6, environment, buildCreateUserScript(engine, input), `ts-cloud db:user ${input.username}`);
|
|
11016
|
+
return runDb(config6, environment, buildCreateUserScript(engine, input, resolveAppDatabase(config6)), `ts-cloud db:user ${input.username}`);
|
|
11016
11017
|
}
|
|
11017
11018
|
var DB_BACKUP_DIR = "/var/backups/ts-cloud/databases";
|
|
11018
|
-
function buildBackupScript(engine, name, destDir = DB_BACKUP_DIR) {
|
|
11019
|
+
function buildBackupScript(engine, name, destDir = DB_BACKUP_DIR, database) {
|
|
11019
11020
|
const file = `${destDir}/${name}-$(date +%Y%m%d-%H%M%S).sql.gz`;
|
|
11020
11021
|
const mkdir4 = `mkdir -p ${destDir}`;
|
|
11021
11022
|
if (engine === "postgres")
|
|
11022
|
-
return [mkdir4,
|
|
11023
|
+
return [mkdir4, `${pgAdminCommand(database, "pg_dump")} ${name} | gzip > "${file}"`, `echo "BACKUP=${file}"`, `ls -l "${file}"`];
|
|
11023
11024
|
const sock = engine === "mariadb" ? SOCKETS.mariadb : SOCKETS.mysql;
|
|
11024
11025
|
return [mkdir4, `mysqldump --socket=${sock} -u root ${name} | gzip > "${file}"`, `echo "BACKUP=${file}"`, `ls -l "${file}"`];
|
|
11025
11026
|
}
|
|
@@ -11045,7 +11046,7 @@ async function backupDatabase(config6, environment, name) {
|
|
|
11045
11046
|
if (!isValidDbIdentifier(name))
|
|
11046
11047
|
return { ok: false, error: "Database name must be a valid identifier.", database: name };
|
|
11047
11048
|
const engine = resolveDbEngine(config6);
|
|
11048
|
-
const r = await runDb(config6, environment, buildBackupScript(engine, name), `ts-cloud db:backup ${name}`);
|
|
11049
|
+
const r = await runDb(config6, environment, buildBackupScript(engine, name, DB_BACKUP_DIR, resolveAppDatabase(config6)), `ts-cloud db:backup ${name}`);
|
|
11049
11050
|
return { ...r, database: name };
|
|
11050
11051
|
}
|
|
11051
11052
|
async function listDatabaseBackups(config6, environment) {
|
|
@@ -12637,7 +12638,7 @@ function renderSiteSnippet(input) {
|
|
|
12637
12638
|
`);
|
|
12638
12639
|
}
|
|
12639
12640
|
function escapeSingle(value) {
|
|
12640
|
-
return value.replace(/\\/g, "\\\\").replaceAll(String.fromCharCode(39), "\\'");
|
|
12641
|
+
return value.replace(/\\/g, "\\\\").replaceAll(String.fromCharCode(39), "\\'").replace(/\r/g, "\\r").replace(/\n/g, "\\n");
|
|
12641
12642
|
}
|
|
12642
12643
|
function normalizeSiteName(name) {
|
|
12643
12644
|
const normalized = name.trim();
|
|
@@ -13404,6 +13405,8 @@ async function startLocalDashboardServer(options = {}) {
|
|
|
13404
13405
|
}
|
|
13405
13406
|
if (body.port !== undefined && body.port !== null && body.port !== "" && (!Number.isInteger(Number(body.port)) || Number(body.port) < 1 || Number(body.port) > 65535))
|
|
13406
13407
|
return json({ ok: false, error: "Port must be a number between 1 and 65535." }, 422);
|
|
13408
|
+
if (typeof body.domain === "string" && body.domain.trim() && !isValidHostname(body.domain.trim()))
|
|
13409
|
+
return json({ ok: false, error: `Domain '${body.domain.trim()}' is not a valid hostname.` }, 422);
|
|
13407
13410
|
let text2 = await readFile(configPath, "utf8");
|
|
13408
13411
|
const set = (key, valueText) => {
|
|
13409
13412
|
text2 = setSitePropertyInCloudConfig({ configText: text2, siteName: name, key, valueText });
|
|
@@ -78,6 +78,17 @@ function buildPantryServiceScript(services) {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// src/drivers/shared/db-provision.ts
|
|
81
|
+
function isLocalDatabase(database) {
|
|
82
|
+
return !database?.host || database.host === "127.0.0.1" || database.host === "localhost";
|
|
83
|
+
}
|
|
84
|
+
function pgAdminCommand(database, tool = "psql") {
|
|
85
|
+
const port = database?.port ?? 5432;
|
|
86
|
+
if (isLocalDatabase(database))
|
|
87
|
+
return `${tool} -p ${port} -U postgres`;
|
|
88
|
+
const user = database?.username || "postgres";
|
|
89
|
+
const env = database?.password ? `PGPASSWORD='${database.password.replace(/'/g, `'\\''`)}' ` : "";
|
|
90
|
+
return `${env}${tool} -h ${database.host} -p ${port} -U ${user} -w`;
|
|
91
|
+
}
|
|
81
92
|
function enabled(spec) {
|
|
82
93
|
return spec === true || typeof spec === "object" && spec != null;
|
|
83
94
|
}
|
|
@@ -121,7 +132,7 @@ function buildServicesProvisionScript(services = {}, _options = {}) {
|
|
|
121
132
|
function buildDatabaseSetupScript(database, services = {}) {
|
|
122
133
|
if (!database?.name)
|
|
123
134
|
return [];
|
|
124
|
-
if (database
|
|
135
|
+
if (!isLocalDatabase(database))
|
|
125
136
|
return [];
|
|
126
137
|
const name = database.name;
|
|
127
138
|
const user = database.username || name;
|
|
@@ -154,10 +165,11 @@ function buildDatabaseSetupScript(database, services = {}) {
|
|
|
154
165
|
return lines;
|
|
155
166
|
};
|
|
156
167
|
const extraUsers2 = database.users || [];
|
|
168
|
+
const pgPort = database.port ?? 5432;
|
|
157
169
|
return [
|
|
158
170
|
pantryEnvActivation(),
|
|
159
|
-
|
|
160
|
-
|
|
171
|
+
`for i in $(seq 1 30); do pg_isready -p ${pgPort} -q && break; sleep 2; done`,
|
|
172
|
+
`${pgAdminCommand(database)} <<'TS_CLOUD_PG_EOF'`,
|
|
161
173
|
...pgEnsureRole(user, pass),
|
|
162
174
|
`SELECT 'CREATE DATABASE ${pgIdent(name)} OWNER ${pgIdent(user)}' ` + `WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = ${pgLit(name)})\\gexec`,
|
|
163
175
|
...extraUsers2.flatMap((u) => [...pgEnsureRole(u.username, u.password), ...pgGrant(u)]),
|
|
@@ -389,7 +401,14 @@ function vhostBody(options) {
|
|
|
389
401
|
return lines;
|
|
390
402
|
}
|
|
391
403
|
function buildNginxVhost(options) {
|
|
392
|
-
const
|
|
404
|
+
const hosts = [options.domain, ...options.aliases || []].filter(Boolean);
|
|
405
|
+
for (const host of hosts) {
|
|
406
|
+
if (!/^(?=.{1,253}$)(?:\*\.)?[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i.test(host.trim()))
|
|
407
|
+
throw new Error(`Refusing to build a vhost: '${host}' is not a valid hostname.`);
|
|
408
|
+
}
|
|
409
|
+
if (!hosts.length)
|
|
410
|
+
throw new Error("Refusing to build a vhost: no server_name (domain) was given.");
|
|
411
|
+
const serverNames = hosts.join(" ");
|
|
393
412
|
const body = vhostBody(options);
|
|
394
413
|
if (options.ssl) {
|
|
395
414
|
const redirect = [
|
|
@@ -1388,7 +1407,7 @@ function buildBackupRestoreScript(database, options = {}) {
|
|
|
1388
1407
|
const name = database.name;
|
|
1389
1408
|
const isPg = database.engine === "postgres";
|
|
1390
1409
|
const locate = options.from ? `TS_CLOUD_DUMP="${options.from}"` : `TS_CLOUD_DUMP="$(find ${BACKUP_OUTPUT_DIR} -type f -name '*${name}*.sql' -o -type f -name '*${name}*.sql.gz' 2>/dev/null | xargs -r ls -1t 2>/dev/null | head -1)"`;
|
|
1391
|
-
const client = isPg ?
|
|
1410
|
+
const client = isPg ? `${pgAdminCommand(database)} -d "${name}"` : `mysql --socket=${engineSocket(database.engine)} -u root "${name}"`;
|
|
1392
1411
|
return [
|
|
1393
1412
|
"set -uo pipefail",
|
|
1394
1413
|
'eval "$(cd /opt/pantry && pantry env 2>/dev/null)" || true',
|
|
@@ -3700,7 +3719,7 @@ function buildRollbackScript(paths, options = {}) {
|
|
|
3700
3719
|
return [
|
|
3701
3720
|
...flip,
|
|
3702
3721
|
`TS_CLOUD_RB_ID=$(basename "$(readlink -f ${paths.current})")`,
|
|
3703
|
-
`if [ -f /etc/systemd/system/${unitBase}@.service ]; then ` + `systemctl start "${unitBase}@\${TS_CLOUD_RB_ID}.service"; sleep 2; ` + `systemctl is-active --quiet "${unitBase}@\${TS_CLOUD_RB_ID}.service" || { echo "rolled-back release failed to start" >&2; exit 1; }; ` + `systemctl enable "${unitBase}@\${TS_CLOUD_RB_ID}.service" 2>/dev/null || true; ` + `systemctl list-units --plain --no-legend --type=service "${unitBase}@*.service" 2>/dev/null | awk '{print $1}' | grep -v "^${unitBase}@\${TS_CLOUD_RB_ID}.service$" | while read -r TS_CLOUD_U; do systemctl stop "$TS_CLOUD_U" 2>/dev/null || true; systemctl disable "$TS_CLOUD_U" 2>/dev/null || true; done; ` + `elif [ -f /etc/systemd/system/${unitBase}.service ]; then systemctl restart ${unitBase}.service; fi`
|
|
3722
|
+
`if [ -f /etc/systemd/system/${unitBase}@.service ]; then ` + `systemctl start "${unitBase}@\${TS_CLOUD_RB_ID}.service"; sleep 2; ` + `systemctl is-active --quiet "${unitBase}@\${TS_CLOUD_RB_ID}.service" || { echo "rolled-back release failed to start" >&2; exit 1; }; ` + `systemctl enable "${unitBase}@\${TS_CLOUD_RB_ID}.service" 2>/dev/null || true; ` + `systemctl list-units --plain --no-legend --type=service "${unitBase}@*.service" 2>/dev/null | awk '{print $1}' | { grep -v "^${unitBase}@\${TS_CLOUD_RB_ID}.service$" || true; } | while read -r TS_CLOUD_U; do systemctl stop "$TS_CLOUD_U" 2>/dev/null || true; systemctl disable "$TS_CLOUD_U" 2>/dev/null || true; done; ` + `elif [ -f /etc/systemd/system/${unitBase}.service ]; then systemctl restart ${unitBase}.service; fi`
|
|
3704
3723
|
];
|
|
3705
3724
|
}
|
|
3706
3725
|
function buildPruneReleases(paths, keep = DEFAULT_KEEP_RELEASES) {
|
|
@@ -3830,7 +3849,7 @@ function buildSiteDeployScript(options) {
|
|
|
3830
3849
|
...buildActivateRelease(paths),
|
|
3831
3850
|
`systemctl enable ${instance} 2>/dev/null || true`,
|
|
3832
3851
|
`for TS_CLOUD_U in \${TS_CLOUD_OLD_UNITS}; do systemctl stop "$TS_CLOUD_U" 2>/dev/null || true; systemctl disable "$TS_CLOUD_U" 2>/dev/null || true; done`,
|
|
3833
|
-
`systemctl list-unit-files --plain --no-legend "${unitBase}@*.service" 2>/dev/null | awk '{print $1}' | grep -v -e "^${instance}$" -e "^${unitBase}@\\.service$" | while read -r TS_CLOUD_U; do systemctl disable "$TS_CLOUD_U" 2>/dev/null || true; done`,
|
|
3852
|
+
`systemctl list-unit-files --plain --no-legend "${unitBase}@*.service" 2>/dev/null | awk '{print $1}' | { grep -v -e "^${instance}$" -e "^${unitBase}@\\.service$" || true; } | while read -r TS_CLOUD_U; do systemctl disable "$TS_CLOUD_U" 2>/dev/null || true; done`,
|
|
3834
3853
|
`if [ -f /etc/systemd/system/${serviceName} ]; then systemctl disable ${serviceName} 2>/dev/null || true; rm -f /etc/systemd/system/${serviceName}; systemctl daemon-reload; fi`,
|
|
3835
3854
|
...buildPruneReleases(paths, keepReleases)
|
|
3836
3855
|
];
|
|
@@ -3975,9 +3994,10 @@ function resolveDashboardAuth(cwd, username, logger) {
|
|
|
3975
3994
|
writeFileSync(file, `${JSON.stringify({ username, password, generatedAt: new Date().toISOString() }, null, 2)}
|
|
3976
3995
|
`);
|
|
3977
3996
|
chmodSync(file, 384);
|
|
3978
|
-
logger.info(`Management dashboard: generated a password and saved it to ${DASHBOARD_CREDENTIALS_FILE} (
|
|
3997
|
+
logger.info(`Management dashboard: generated a password for '${username}' and saved it to ${DASHBOARD_CREDENTIALS_FILE} (read it there — it is not printed). Set TS_CLOUD_UI_PASSWORD to pin your own, or TS_CLOUD_UI_PUBLIC=1 to serve without auth.`);
|
|
3979
3998
|
} catch (error) {
|
|
3980
|
-
logger.warn(`Management dashboard: could not persist the generated password (${error?.message ?? error}). Using it for this deploy only — pass: ${password}
|
|
3999
|
+
logger.warn(`Management dashboard: could not persist the generated password (${error?.message ?? error}). Using it for this deploy only — pass: ${password}
|
|
4000
|
+
This password is now in your deploy log. Set TS_CLOUD_UI_PASSWORD to a value of your own and redeploy once ${DASHBOARD_CREDENTIALS_FILE} is writable.`);
|
|
3981
4001
|
}
|
|
3982
4002
|
return { password, source: "generated" };
|
|
3983
4003
|
}
|
|
@@ -5098,4 +5118,4 @@ function buildCloudFrontOriginConfig(options) {
|
|
|
5098
5118
|
CustomErrorResponses: { Quantity: 0 }
|
|
5099
5119
|
};
|
|
5100
5120
|
}
|
|
5101
|
-
export { siteInstallBase, isPhpSite, resolveSiteDeployTarget, resolveSiteKind, validateDeploymentConfig, PANTRY_PROJECT_DIR, DEFAULT_RPX_CERTS_DIR, normalizeRoutePath, deriveRouteId, buildRpxConfig, buildRpxLbConfig, renderRpxLauncher, RPX_DIR, RPX_LAUNCHER_PATH, RPX_SERVICE_NAME, buildRpxProvisionScript, buildRpxFragmentRefreshScript, BACKUP_RUNNER_PATH, buildBackupRestoreScript, buildUbuntuBootstrapScript, AwsDriver, resolveHetznerLocation, HetznerClient, resolveHetznerApiToken2 as resolveHetznerApiToken, normalizeSshPublicKey, wrapCloudInitUserData, HetznerDriver, LocalBoxDriver, isBoxMode, createCloudDriver, CloudDriverFactory, cloudDrivers, ensureSshKey, ensureFirewall, ensureServer, serverPublicIpv4, buildSshArgs, sshExec, sshExecOrThrow, scpUpload, waitForSsh, waitForCloudInit, UBUNTU_2404_AMI_PARAM, buildBoxUserData, HetznerBoxProvisioner, AwsBoxProvisioner, createBoxProvisioner, releasePaths, buildRollbackScript, resolveExecStart, buildSiteDeployScript, buildStaticSiteDeployScript, releaseTarballTmpPath, buildAwsArtifactFetch, buildLocalArtifactFetch, MANAGEMENT_DASHBOARD_SITE, DASHBOARD_CREDENTIALS_FILE, resolveDashboardAuth, resolveUiSource, ensureManagementDashboard, buildManagementDashboardArtifact, resolveSiteFramework, deploySiteRelease, deployAllComputeSites, reloadRpxGateway, MANAGED_CACHE_POLICY_OPTIMIZED, MANAGED_CACHE_POLICY_DISABLED, MANAGED_ORIGIN_REQUEST_POLICY_ALL_VIEWER, buildCloudFrontOriginConfig };
|
|
5121
|
+
export { siteInstallBase, isPhpSite, resolveSiteDeployTarget, resolveSiteKind, validateDeploymentConfig, PANTRY_PROJECT_DIR, pgAdminCommand, DEFAULT_RPX_CERTS_DIR, normalizeRoutePath, deriveRouteId, buildRpxConfig, buildRpxLbConfig, renderRpxLauncher, RPX_DIR, RPX_LAUNCHER_PATH, RPX_SERVICE_NAME, buildRpxProvisionScript, buildRpxFragmentRefreshScript, BACKUP_RUNNER_PATH, buildBackupRestoreScript, buildUbuntuBootstrapScript, AwsDriver, resolveHetznerLocation, HetznerClient, resolveHetznerApiToken2 as resolveHetznerApiToken, normalizeSshPublicKey, wrapCloudInitUserData, HetznerDriver, LocalBoxDriver, isBoxMode, createCloudDriver, CloudDriverFactory, cloudDrivers, ensureSshKey, ensureFirewall, ensureServer, serverPublicIpv4, buildSshArgs, sshExec, sshExecOrThrow, scpUpload, waitForSsh, waitForCloudInit, UBUNTU_2404_AMI_PARAM, buildBoxUserData, HetznerBoxProvisioner, AwsBoxProvisioner, createBoxProvisioner, releasePaths, buildRollbackScript, resolveExecStart, buildSiteDeployScript, buildStaticSiteDeployScript, releaseTarballTmpPath, buildAwsArtifactFetch, buildLocalArtifactFetch, MANAGEMENT_DASHBOARD_SITE, DASHBOARD_CREDENTIALS_FILE, resolveDashboardAuth, resolveUiSource, ensureManagementDashboard, buildManagementDashboardArtifact, resolveSiteFramework, deploySiteRelease, deployAllComputeSites, reloadRpxGateway, MANAGED_CACHE_POLICY_OPTIMIZED, MANAGED_CACHE_POLICY_DISABLED, MANAGED_ORIGIN_REQUEST_POLICY_ALL_VIEWER, buildCloudFrontOriginConfig };
|
|
@@ -4,20 +4,20 @@
|
|
|
4
4
|
* the pantry UNIX socket; Postgres over local TCP — mirroring the provisioning
|
|
5
5
|
* path in {@link import('../drivers/shared/db-provision')}.
|
|
6
6
|
*/
|
|
7
|
-
import type { CloudConfig, EnvironmentType } from '@ts-cloud/core';
|
|
7
|
+
import type { CloudConfig, DatabaseConfig, EnvironmentType } from '@ts-cloud/core';
|
|
8
8
|
export type DbEngine = 'mysql' | 'mariadb' | 'postgres';
|
|
9
9
|
/** Valid SQL identifier for a database/user name (kept strict for safety). */
|
|
10
10
|
export declare function isValidDbIdentifier(value: string): boolean;
|
|
11
11
|
export declare function resolveDbEngine(config: CloudConfig): DbEngine;
|
|
12
|
-
export declare function buildListScript(engine: DbEngine): string[];
|
|
13
|
-
export declare function buildCreateDatabaseScript(engine: DbEngine, name: string): string[];
|
|
12
|
+
export declare function buildListScript(engine: DbEngine, database?: DatabaseConfig): string[];
|
|
13
|
+
export declare function buildCreateDatabaseScript(engine: DbEngine, name: string, database?: DatabaseConfig): string[];
|
|
14
14
|
export interface CreateUserInput {
|
|
15
15
|
username: string;
|
|
16
16
|
password: string;
|
|
17
17
|
database?: string;
|
|
18
18
|
access?: 'all' | 'readonly';
|
|
19
19
|
}
|
|
20
|
-
export declare function buildCreateUserScript(engine: DbEngine, input: CreateUserInput): string[];
|
|
20
|
+
export declare function buildCreateUserScript(engine: DbEngine, input: CreateUserInput, database?: DatabaseConfig): string[];
|
|
21
21
|
export declare function parseDbList(output: string): {
|
|
22
22
|
databases: string[];
|
|
23
23
|
users: string[];
|
|
@@ -40,9 +40,11 @@ export declare const DB_BACKUP_DIR = "/var/backups/ts-cloud/databases";
|
|
|
40
40
|
/**
|
|
41
41
|
* Script that dumps a single database to a timestamped, gzipped file. The name
|
|
42
42
|
* is a validated SQL identifier (no shell metacharacters), so it is safe to
|
|
43
|
-
* embed directly. The timestamp is computed on the box.
|
|
43
|
+
* embed directly. The timestamp is computed on the box. Postgres connects over
|
|
44
|
+
* the local unix socket for a co-located engine, or TCP with credentials for
|
|
45
|
+
* an external host (see {@link pgAdminCommand}).
|
|
44
46
|
*/
|
|
45
|
-
export declare function buildBackupScript(engine: DbEngine, name: string, destDir?: string): string[];
|
|
47
|
+
export declare function buildBackupScript(engine: DbEngine, name: string, destDir?: string, database?: DatabaseConfig): string[];
|
|
46
48
|
/** Script that lists the most recent dumps (newest first). */
|
|
47
49
|
export declare function buildListBackupsScript(destDir?: string): string[];
|
|
48
50
|
export declare function parseBackups(output: string): Array<{
|
package/dist/deploy/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
sanitizeCloudConfig,
|
|
13
13
|
setMaintenance,
|
|
14
14
|
startLocalDashboardServer
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-1nfkggdw.js";
|
|
16
16
|
import {
|
|
17
17
|
buildAndPushServerlessImage
|
|
18
18
|
} from "../chunk-tskj9fay.js";
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
resolveUiSource,
|
|
31
31
|
siteInstallBase,
|
|
32
32
|
validateDeploymentConfig
|
|
33
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-m0zayf6n.js";
|
|
34
34
|
import"../chunk-stt1z5cx.js";
|
|
35
35
|
import"../chunk-93hjhs78.js";
|
|
36
36
|
import {
|
package/dist/drivers/index.js
CHANGED
|
@@ -34,7 +34,9 @@ export interface BackupRestoreOptions {
|
|
|
34
34
|
* Build the commands that restore a database from a ts-backups dump on the box.
|
|
35
35
|
* With no `from`, the newest dump under {@link BACKUP_OUTPUT_DIR} matching the
|
|
36
36
|
* database name is used. Handles plain `.sql` and gzipped `.sql.gz`. MySQL/
|
|
37
|
-
* MariaDB restore over the root unix socket; Postgres
|
|
37
|
+
* MariaDB restore over the root unix socket; Postgres over the local unix
|
|
38
|
+
* socket for a co-located engine, or TCP with credentials for an external
|
|
39
|
+
* host (see {@link pgAdminCommand}).
|
|
38
40
|
* Returns `[]` when the database has no name.
|
|
39
41
|
*/
|
|
40
42
|
export declare function buildBackupRestoreScript(database: DatabaseConfig | undefined, options?: BackupRestoreOptions): string[];
|
|
@@ -6,10 +6,32 @@
|
|
|
6
6
|
* install nothing and just wire `.env` — see {@link buildManagedDbEnv}.
|
|
7
7
|
*
|
|
8
8
|
* pantry services listen on TCP localhost ports (mysql/mariadb 3306, postgres
|
|
9
|
-
* 5432, redis 6379, memcached 11211, meilisearch 7700)
|
|
10
|
-
*
|
|
9
|
+
* 5432, redis 6379, memcached 11211, meilisearch 7700) and the engine clients
|
|
10
|
+
* are on PATH via `pantry env`. Admin commands (db setup, dumps, restores)
|
|
11
|
+
* connect over the engine's local unix socket — see {@link pgAdminCommand}.
|
|
11
12
|
*/
|
|
12
13
|
import type { ComputeServicesConfig, DatabaseConfig } from '@ts-cloud/core';
|
|
14
|
+
/**
|
|
15
|
+
* True when the database is co-located with the box (the managed-services
|
|
16
|
+
* engine): no host configured, or an explicit loopback host. Anything else is
|
|
17
|
+
* an external/managed database reached over TCP.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isLocalDatabase(database: DatabaseConfig | undefined): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Build the connection prefix for a postgres admin command (`psql`/`pg_dump`)
|
|
22
|
+
* run on the box.
|
|
23
|
+
*
|
|
24
|
+
* The pantry postgres pg_hba grants `trust` on the local unix socket but
|
|
25
|
+
* requires md5 password auth over TCP loopback — and the `postgres` superuser
|
|
26
|
+
* has no password — so against the co-located engine admin clients MUST use
|
|
27
|
+
* the socket: omit `-h` entirely and the pantry client uses its compiled-in
|
|
28
|
+
* default socket dir, which matches the server's by construction (verified
|
|
29
|
+
* on-box: `psql -U postgres` from root connects passwordless). Against an
|
|
30
|
+
* external/managed host, use TCP with the configured credentials
|
|
31
|
+
* (`PGPASSWORD` inline + `-w`, so a missing password fails fast instead of
|
|
32
|
+
* prompting forever).
|
|
33
|
+
*/
|
|
34
|
+
export declare function pgAdminCommand(database: DatabaseConfig | undefined, tool?: 'psql' | 'pg_dump'): string;
|
|
13
35
|
/**
|
|
14
36
|
* Build pantry install + enable/start commands for each requested on-box
|
|
15
37
|
* service. Idempotent (pantry install/enable/start are no-ops when satisfied).
|
package/dist/index.js
CHANGED
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
sanitizeCloudConfig,
|
|
56
56
|
setMaintenance,
|
|
57
57
|
startLocalDashboardServer
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-1nfkggdw.js";
|
|
59
59
|
import {
|
|
60
60
|
buildAndPushServerlessImage
|
|
61
61
|
} from "./chunk-tskj9fay.js";
|
|
@@ -105,7 +105,7 @@ import {
|
|
|
105
105
|
waitForCloudInit,
|
|
106
106
|
waitForSsh,
|
|
107
107
|
wrapCloudInitUserData
|
|
108
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-m0zayf6n.js";
|
|
109
109
|
import {
|
|
110
110
|
ABTestManager,
|
|
111
111
|
AI,
|