@stacksjs/buddy 0.70.78 → 0.70.80

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.
@@ -88,6 +88,21 @@ ${sample}${more}
88
88
  log.debug(`[migrate] FK integrity check skipped: ${err instanceof Error ? err.message : String(err)}`);
89
89
  }
90
90
  }
91
+ async function reportFkOrphans() {
92
+ try {
93
+ const { findFkOrphans } = await import("@stacksjs/database"), result = await findFkOrphans();
94
+ if (!result.supported || result.total === 0)
95
+ return;
96
+ const sample = result.orphans.slice(0, 5).map((o) => ` \u2022 ${o.table}.${o.column} \u2192 ${o.parent} (${o.count} row${o.count === 1 ? "" : "s"})`).join(`
97
+ `), more = result.orphans.length > 5 ? `
98
+ + ${result.orphans.length - 5} more \u2014 run \`./buddy doctor\` for the full list.` : "", first = result.orphans[0];
99
+ log.warn(`${result.total} row${result.total === 1 ? "" : "s"} violate foreign keys (orphaned parents), now that SQLite enforces \`foreign_keys = ON\`:
100
+ ${sample}${more}
101
+ ` + "These were written under the old `foreign_keys = OFF` default (#1951). Review and clean up manually \u2014 e.g. " + `DELETE FROM ${first.table} WHERE ${first.column} IS NOT NULL AND ${first.column} NOT IN (SELECT id FROM ${first.parent}). migrate never deletes data.`);
102
+ } catch (err) {
103
+ log.debug(`[migrate] FK orphan scan skipped: ${err instanceof Error ? err.message : String(err)}`);
104
+ }
105
+ }
91
106
  function describeOp(op) {
92
107
  switch (op.kind) {
93
108
  case "drop_table":
@@ -263,6 +278,7 @@ export function migrate(buddy) {
263
278
  log.error("Failed to ensure uuid columns post-migration:", error);
264
279
  }
265
280
  await reportMissingForeignKeys();
281
+ await reportFkOrphans();
266
282
  const APP_ENV = process.env.APP_ENV || "local", marker = readMigrateMarker(), authSuffix = options.auth !== !1 ? " (including auth tables)" : "", outroMessage = marker == null ? `Migrated your ${APP_ENV} database.${authSuffix}` : marker.appliedCount === 0 ? `Nothing to migrate \u2014 your ${APP_ENV} database is already up to date.${authSuffix}` : `Applied ${marker.appliedCount} migration${marker.appliedCount === 1 ? "" : "s"} to your ${APP_ENV} database.${authSuffix}`;
267
283
  await outro(outroMessage, {
268
284
  startTime: perf,
@@ -16,21 +16,20 @@ export function queue(buddy) {
16
16
  };
17
17
  buddy.command("queue:work", "Start processing jobs on the queue").option("-p, --project [project]", descriptions.project, { default: !1 }).option("-q, --queue [queue]", descriptions.queue, { default: !1 }).option("-c, --connection [connection]", descriptions.connection, { default: !1 }).option("--concurrency [concurrency]", descriptions.concurrency, { default: "1" }).option("--verbose", descriptions.verbose, { default: !1 }).action(async (options) => {
18
18
  log.debug("Running `buddy queue:work` ...", options);
19
- const SHUTDOWN_GRACE_MS = 1e4;
19
+ const PARENT_BACKSTOP_MS = (Number(process.env.STACKS_QUEUE_SHUTDOWN_GRACE_MS) || 1e4) + 5000;
20
20
  let shuttingDown = !1;
21
- const cleanup = (signal) => {
21
+ const onSignal = (signal) => {
22
22
  if (shuttingDown)
23
23
  return;
24
24
  shuttingDown = !0;
25
- log.info(`[queue] Received ${signal}, draining workers (max ${SHUTDOWN_GRACE_MS / 1000}s)\u2026`);
26
- import("@stacksjs/queue").then(({ stopProcessor }) => stopProcessor({ graceMs: SHUTDOWN_GRACE_MS })).catch((error) => log.error("[queue] stopProcessor failed", error));
25
+ log.info(`[queue] Received ${signal}; waiting for the worker to drain\u2026`);
27
26
  setTimeout(() => {
28
- log.warn("[queue] Drain timeout exceeded \u2014 forcing shutdown.");
27
+ log.warn("[queue] Worker drain overran its window \u2014 forcing shutdown.");
29
28
  process.exit(ExitCode.FatalError);
30
- }, SHUTDOWN_GRACE_MS).unref();
29
+ }, PARENT_BACKSTOP_MS).unref();
31
30
  };
32
- process.on("SIGINT", () => cleanup("SIGINT"));
33
- process.on("SIGTERM", () => cleanup("SIGTERM"));
31
+ process.on("SIGINT", () => onSignal("SIGINT"));
32
+ process.on("SIGTERM", () => onSignal("SIGTERM"));
34
33
  const perf = await intro("buddy queue:work"), result = await runAction(Action.QueueWork, options);
35
34
  if (result.isErr) {
36
35
  await outro("While running the queue:work command, there was an issue", { startTime: perf, useSeconds: !0 }, result.error);
@@ -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.78",
4
+ "version": "0.70.80",
5
5
  "description": "Meet Buddy. The Stacks runtime.",
6
6
  "author": "Chris Breuer",
7
7
  "contributors": [