@stacksjs/buddy 0.70.77 → 0.70.79
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/deploy.js
CHANGED
package/dist/commands/migrate.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { closeSync, existsSync, mkdirSync, openSync, readdirSync, readFileSync, rmSync } from "node:fs";
|
|
2
2
|
import process from "node:process";
|
|
3
|
-
import { confirm, intro, log, onUnknownSubcommand, outro } from "@stacksjs/cli";
|
|
3
|
+
import { confirm, intro, log, onUnknownSubcommand, outro, text } from "@stacksjs/cli";
|
|
4
4
|
import { Action } from "@stacksjs/enums";
|
|
5
5
|
import { hasTTY, isCI } from "@stacksjs/env";
|
|
6
6
|
import { appPath, frameworkPath, projectPath } from "@stacksjs/path";
|
|
@@ -132,6 +132,37 @@ async function confirmDestructiveMigrations(opts) {
|
|
|
132
132
|
}
|
|
133
133
|
return confirm({ message: "Apply these destructive changes?", initial: !1 });
|
|
134
134
|
}
|
|
135
|
+
function parseGuardBool(raw) {
|
|
136
|
+
if (raw == null || raw === "")
|
|
137
|
+
return;
|
|
138
|
+
const v = raw.toLowerCase().trim();
|
|
139
|
+
if (v === "1" || v === "true" || v === "yes" || v === "on")
|
|
140
|
+
return !0;
|
|
141
|
+
if (v === "0" || v === "false" || v === "no" || v === "off")
|
|
142
|
+
return !1;
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
function parseFreshGuard(raw) {
|
|
146
|
+
const v = raw?.toLowerCase().trim();
|
|
147
|
+
return v === "allow" || v === "confirm" || v === "disabled" ? v : void 0;
|
|
148
|
+
}
|
|
149
|
+
async function resolveMigrationGuards() {
|
|
150
|
+
const isProd = /^prod/i.test(process.env.APP_ENV || "local");
|
|
151
|
+
let cfg = {};
|
|
152
|
+
try {
|
|
153
|
+
const { awaitConfig } = await import("@stacksjs/config");
|
|
154
|
+
cfg = (await awaitConfig()).database?.safety ?? {};
|
|
155
|
+
} catch (error) {
|
|
156
|
+
log.debug(`[migrate] safety config unavailable, using defaults: ${error instanceof Error ? error.message : String(error)}`);
|
|
157
|
+
}
|
|
158
|
+
const confirmMigrate = parseGuardBool(process.env.DB_MIGRATE_CONFIRM) ?? cfg.confirmMigrate ?? !0, migrateFresh = parseFreshGuard(process.env.DB_MIGRATE_FRESH) ?? cfg.migrateFresh ?? (isProd ? "disabled" : "allow");
|
|
159
|
+
return { confirmMigrate, migrateFresh };
|
|
160
|
+
}
|
|
161
|
+
function currentDatabaseLabel() {
|
|
162
|
+
if ((process.env.DB_CONNECTION || "sqlite").toLowerCase() === "sqlite")
|
|
163
|
+
return process.env.DB_DATABASE_PATH || "database/stacks.sqlite";
|
|
164
|
+
return process.env.DB_DATABASE || "stacks";
|
|
165
|
+
}
|
|
135
166
|
export function migrate(buddy) {
|
|
136
167
|
const descriptions = {
|
|
137
168
|
migrate: "Migrates your database",
|
|
@@ -172,6 +203,19 @@ export function migrate(buddy) {
|
|
|
172
203
|
await outro("Diff complete \u2014 no changes applied.", { startTime: perf, useSeconds: !0 });
|
|
173
204
|
process.exit(ExitCode.Success);
|
|
174
205
|
}
|
|
206
|
+
if ((await resolveMigrationGuards()).confirmMigrate && !options.force)
|
|
207
|
+
if (isCI || !hasTTY)
|
|
208
|
+
log.debug("[migrate] confirmMigrate guard skipped \u2014 non-interactive environment.");
|
|
209
|
+
else {
|
|
210
|
+
const APP_ENV = process.env.APP_ENV || "local";
|
|
211
|
+
if (!await confirm({
|
|
212
|
+
message: `Run migrations against the ${APP_ENV} database "${currentDatabaseLabel()}"?`,
|
|
213
|
+
initial: !0
|
|
214
|
+
})) {
|
|
215
|
+
await outro("Migration cancelled \u2014 no changes applied.", { startTime: perf, useSeconds: !0 });
|
|
216
|
+
process.exit(ExitCode.Success);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
175
219
|
const lock = acquireMigrationLock();
|
|
176
220
|
if (!lock.acquired) {
|
|
177
221
|
log.error("Another migration is already running (.stacks/migrations.lock exists). Wait for it to finish, or remove the lockfile if it is stale.");
|
|
@@ -226,7 +270,7 @@ export function migrate(buddy) {
|
|
|
226
270
|
});
|
|
227
271
|
process.exit(ExitCode.Success);
|
|
228
272
|
});
|
|
229
|
-
buddy.command("migrate:fresh", descriptions.migrate).alias("db:fresh").option("-d, --diff", "Show the SQL that would be run", { default: !1 }).option("-p, --project [project]", descriptions.project, { default: !1 }).option("-s, --seed", "Run database seeders after migration", { default: !1 }).option("-a, --auth", descriptions.auth, { default: !0 }).option("--no-auth", "Skip auth/oauth table migrations").option("--verbose", descriptions.verbose, { default: !1 }).action(async (options) => {
|
|
273
|
+
buddy.command("migrate:fresh", descriptions.migrate).alias("db:fresh").option("-d, --diff", "Show the SQL that would be run", { default: !1 }).option("-p, --project [project]", descriptions.project, { default: !1 }).option("-s, --seed", "Run database seeders after migration", { default: !1 }).option("-a, --auth", descriptions.auth, { default: !0 }).option("--no-auth", "Skip auth/oauth table migrations").option("-f, --force", 'Skip the drop-database confirmation (only honored when the migrateFresh guard is "allow")', { default: !1 }).option("--verbose", descriptions.verbose, { default: !1 }).action(async (options) => {
|
|
230
274
|
log.debug("Running `buddy migrate:fresh` ...", options);
|
|
231
275
|
const perf = await intro("buddy migrate:fresh"), validation = validateModelsExist();
|
|
232
276
|
if (!validation.valid) {
|
|
@@ -235,6 +279,28 @@ export function migrate(buddy) {
|
|
|
235
279
|
`);
|
|
236
280
|
process.exit(ExitCode.FatalError);
|
|
237
281
|
}
|
|
282
|
+
const guards = await resolveMigrationGuards(), dbLabel = currentDatabaseLabel(), APP_ENV = process.env.APP_ENV || "local";
|
|
283
|
+
if (guards.migrateFresh === "disabled") {
|
|
284
|
+
log.error(`\`buddy migrate:fresh\` is disabled by your migration safety guards (it DROPS every table).
|
|
285
|
+
Target: ${APP_ENV} database "${dbLabel}"
|
|
286
|
+
To allow it, set database.safety.migrateFresh to 'allow' in config/database.ts,
|
|
287
|
+
or run once with: DB_MIGRATE_FRESH=allow ./buddy migrate:fresh`);
|
|
288
|
+
await outro('migrate:fresh refused \u2014 the migrateFresh guard is set to "disabled".', { startTime: perf, useSeconds: !0 });
|
|
289
|
+
process.exit(ExitCode.FatalError);
|
|
290
|
+
}
|
|
291
|
+
if (!(guards.migrateFresh === "allow" && options.force === !0)) {
|
|
292
|
+
if (isCI || !hasTTY) {
|
|
293
|
+
const hint = guards.migrateFresh === "confirm" ? 'Guard is "confirm": migrate:fresh must be run interactively.' : "Re-run with --force to drop the database non-interactively.";
|
|
294
|
+
log.error(`Refusing to drop the ${APP_ENV} database "${dbLabel}" in a non-interactive environment. ${hint}`);
|
|
295
|
+
await outro("migrate:fresh cancelled.", { startTime: perf, useSeconds: !0 });
|
|
296
|
+
process.exit(ExitCode.FatalError);
|
|
297
|
+
}
|
|
298
|
+
log.warn(`This will DROP ALL TABLES in the ${APP_ENV} database "${dbLabel}" and rebuild them from scratch. All data will be lost.`);
|
|
299
|
+
if ((await text({ message: `Type the database name "${dbLabel}" to confirm (blank to cancel):` })).trim() !== dbLabel) {
|
|
300
|
+
await outro("migrate:fresh cancelled \u2014 confirmation did not match.", { startTime: perf, useSeconds: !0 });
|
|
301
|
+
process.exit(ExitCode.Success);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
238
304
|
const result = await runAction(Action.MigrateFresh, options);
|
|
239
305
|
if (result.isErr)
|
|
240
306
|
log.error("Model migrations failed \u2014 applying auth/notification/RBAC table guarantees before exiting.");
|
package/dist/commands/serve.js
CHANGED
|
@@ -81,6 +81,11 @@ export function serve(buddy) {
|
|
|
81
81
|
log.error(`API proxy to ${apiBase} failed: ${error.message}`);
|
|
82
82
|
return new Response("Bad Gateway", { status: 502 });
|
|
83
83
|
}
|
|
84
|
+
if (existsSync(join(process.cwd(), "resources/views/blog.stx"))) {
|
|
85
|
+
const { renderBlogFeed } = await import("@stacksjs/actions/blog"), feed = await renderBlogFeed(req);
|
|
86
|
+
if (feed)
|
|
87
|
+
return feed;
|
|
88
|
+
}
|
|
84
89
|
globalThis.__stxServeSearch = url.search;
|
|
85
90
|
globalThis.__stxServeCookies = parseCookies(req);
|
|
86
91
|
return;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/buddy",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.70.
|
|
4
|
+
"version": "0.70.79",
|
|
5
5
|
"description": "Meet Buddy. The Stacks runtime.",
|
|
6
6
|
"author": "Chris Breuer",
|
|
7
7
|
"contributors": [
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
"@stacksjs/ui": "^0.70.23",
|
|
136
136
|
"@stacksjs/utils": "^0.70.23",
|
|
137
137
|
"@stacksjs/validation": "^0.70.23",
|
|
138
|
-
"@stacksjs/ts-cloud": "^0.7.
|
|
138
|
+
"@stacksjs/ts-cloud": "^0.7.17"
|
|
139
139
|
},
|
|
140
140
|
"devDependencies": {
|
|
141
141
|
"better-dx": "^0.2.16"
|