@stacksjs/buddy 0.70.192 → 0.70.194
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.
|
@@ -53,6 +53,13 @@ export declare function mergeSiteDeployEnv(sites: Record<string, any>, resolvedD
|
|
|
53
53
|
* bare `user@host` (e.g. mail identities) is left alone. Production is untouched.
|
|
54
54
|
*/
|
|
55
55
|
export declare function applyEnvironmentToSites(sites: Record<string, any>, environment: string, config: any): Record<string, any>;
|
|
56
|
+
/**
|
|
57
|
+
* Load the ts-cloud driver used by Buddy. Published installs use the declared
|
|
58
|
+
* package dependency. Framework and ts-cloud development can point at a built
|
|
59
|
+
* local module with TS_CLOUD_MODULE, avoiding stale nested dependency copies
|
|
60
|
+
* while still exercising the exact Buddy deploy path.
|
|
61
|
+
*/
|
|
62
|
+
export declare function loadTsCloudDeployApi(): Promise<typeof import('@stacksjs/ts-cloud')>;
|
|
56
63
|
/**
|
|
57
64
|
* Loopback-bound server-app sites (e.g. the `api` site: env.HOST=127.0.0.1,
|
|
58
65
|
* reached only through `buddy serve`'s same-origin /api proxy on :3000 —
|
package/dist/commands/deploy.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { join, relative } from "node:path";
|
|
3
|
+
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
4
4
|
import process from "node:process";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
5
6
|
import { runAction } from "@stacksjs/actions";
|
|
6
7
|
import { italic, onUnknownSubcommand, outro, prompts, runCommand } from "@stacksjs/cli";
|
|
7
8
|
import { app, dns as dnsConfig, email as emailConfig, cloud as cloudConfig } from "@stacksjs/config";
|
|
@@ -545,15 +546,24 @@ async function deployToHetzner(tsCloudConfig, deployEnv, options) {
|
|
|
545
546
|
log.info("Generate one with: ssh-keygen -t ed25519");
|
|
546
547
|
process.exit(ExitCode.FatalError);
|
|
547
548
|
}
|
|
548
|
-
const { createCloudDriver, deployAllComputeSites, resolveSiteKind } = await
|
|
549
|
+
const { createCloudDriver, deployAllComputeSites, ensureManagementDashboard, resolveSiteKind } = await loadTsCloudDeployApi();
|
|
549
550
|
try {
|
|
550
|
-
await runHetznerDeploy({ tsCloudConfig, environment, verbose, docker: options.docker === !0, createCloudDriver, deployAllComputeSites, resolveSiteKind, onlySite: options.site || void 0 });
|
|
551
|
+
await runHetznerDeploy({ tsCloudConfig, environment, verbose, docker: options.docker === !0, createCloudDriver, deployAllComputeSites, ensureManagementDashboard, resolveSiteKind, onlySite: options.site || void 0 });
|
|
551
552
|
} catch (err) {
|
|
552
553
|
log.error("Hetzner deploy failed:");
|
|
553
554
|
console.error(err instanceof Error ? err.stack || err.message : err);
|
|
554
555
|
process.exit(ExitCode.FatalError);
|
|
555
556
|
}
|
|
556
557
|
}
|
|
558
|
+
export async function loadTsCloudDeployApi() {
|
|
559
|
+
const requested = process.env.TS_CLOUD_MODULE?.trim();
|
|
560
|
+
if (!requested)
|
|
561
|
+
return import("@stacksjs/ts-cloud");
|
|
562
|
+
const modulePath = isAbsolute(requested) ? requested : resolve(process.cwd(), requested);
|
|
563
|
+
if (!existsSync(modulePath))
|
|
564
|
+
throw Error(`TS_CLOUD_MODULE points to a missing module: ${modulePath}`);
|
|
565
|
+
return import(pathToFileURL(modulePath).href);
|
|
566
|
+
}
|
|
557
567
|
export function scrubLoopbackSitePortsForFirewall(tsCloudConfig) {
|
|
558
568
|
const sites = tsCloudConfig?.sites;
|
|
559
569
|
if (!sites)
|
|
@@ -652,7 +662,7 @@ async function startGithubDeployments(args) {
|
|
|
652
662
|
return records;
|
|
653
663
|
}
|
|
654
664
|
async function runHetznerDeploy(args) {
|
|
655
|
-
const { tsCloudConfig, environment, verbose, docker, createCloudDriver, deployAllComputeSites, resolveSiteKind, onlySite } = args, startTime = performance.now();
|
|
665
|
+
const { tsCloudConfig, environment, verbose, docker, createCloudDriver, deployAllComputeSites, ensureManagementDashboard, resolveSiteKind, onlySite } = args, startTime = performance.now();
|
|
656
666
|
console.log("");
|
|
657
667
|
console.log("\uD83D\uDE80 Deploy \u2192 Hetzner Cloud");
|
|
658
668
|
console.log("");
|
|
@@ -661,7 +671,6 @@ async function runHetznerDeploy(args) {
|
|
|
661
671
|
log.info(`Location: ${tsCloudConfig.hetzner?.location || process.env.HCLOUD_LOCATION || "fsn1"}`);
|
|
662
672
|
log.info(`Size: ${tsCloudConfig.infrastructure?.compute?.size || "small"}`);
|
|
663
673
|
try {
|
|
664
|
-
const { ensureManagementDashboard } = await import("@stacksjs/ts-cloud");
|
|
665
674
|
if (typeof ensureManagementDashboard === "function")
|
|
666
675
|
ensureManagementDashboard(tsCloudConfig, {
|
|
667
676
|
cwd: process.cwd(),
|
|
@@ -780,6 +789,7 @@ async function runHetznerDeploy(args) {
|
|
|
780
789
|
log.info(onlySite ? `Shipping site '${onlySite}' to the server...` : "Shipping release to the server...");
|
|
781
790
|
const deployConfig = onlySite ? { ...tsCloudConfig, sites: { [onlySite]: sitesWithResolvedEnv[onlySite] } } : { ...tsCloudConfig, sites: sitesWithResolvedEnv }, ok = await deployAllComputeSites({
|
|
782
791
|
config: deployConfig,
|
|
792
|
+
managementDashboard: !1,
|
|
783
793
|
rpxConfig: { ...tsCloudConfig, sites: sitesWithResolvedEnv },
|
|
784
794
|
environment,
|
|
785
795
|
driver,
|
|
@@ -900,8 +910,8 @@ ENV_CHANGED=0
|
|
|
900
910
|
# The 'user:local' CLI is direct-DB and does NOT read /etc/mail/mail.env, so
|
|
901
911
|
# without SMTP_DB_PATH it writes to ./smtp.db (the SSH cwd) \u2014 a phantom DB the
|
|
902
912
|
# running server never reads, and auth silently 535s. Point it at the real DB.
|
|
903
|
-
|
|
904
|
-
[ -z "$
|
|
913
|
+
MAIL_DB_PATH="$(grep -E '^SMTP_DB_PATH=' "$ENVF" 2>/dev/null | head -1 | cut -d= -f2- || true)"
|
|
914
|
+
[ -z "$MAIL_DB_PATH" ] && MAIL_DB_PATH=/opt/mail/smtp.db
|
|
905
915
|
echo "MAILHOST:$(grep -E '^SMTP_HOSTNAME=' "$ENVF" 2>/dev/null | head -1 | cut -d= -f2- || true)"
|
|
906
916
|
# 1) Register the local delivery domain (merge into SMTP_LOCAL_DOMAINS).
|
|
907
917
|
if [ -n "$DOMAIN" ] && [ -f "$ENVF" ]; then
|
|
@@ -944,8 +954,48 @@ if [ -n "$BOXES_B64" ] && [ -x "$MS" ]; then
|
|
|
944
954
|
[ -z "$addr" ] && continue
|
|
945
955
|
# NOTE: 'user:local info' exits 0 even when the user is absent (it only
|
|
946
956
|
# prints "not found"), so existence is decided from the OUTPUT, not $?.
|
|
947
|
-
if "$MS" user:local info "$addr" 2>&1 | grep -qi 'not found'; then
|
|
948
|
-
|
|
957
|
+
if SMTP_DB_PATH="$MAIL_DB_PATH" "$MS" user:local info "$addr" 2>&1 | grep -qi 'not found'; then
|
|
958
|
+
legacy="\${addr%%@*}"
|
|
959
|
+
# Older single-domain installs used a bare username whose email is this
|
|
960
|
+
# full address. Creating the isolated address then hits users.email's
|
|
961
|
+
# UNIQUE constraint while the CLI still exits zero. Perform mail's
|
|
962
|
+
# documented username migration transactionally, including every
|
|
963
|
+
# username-keyed table, before falling back to a true create.
|
|
964
|
+
migrated=$(MAIL_DB_PATH="$MAIL_DB_PATH" OLD_USERNAME="$legacy" NEW_USERNAME="$addr" /usr/local/bin/bun --bun -e '
|
|
965
|
+
const { Database } = require("bun:sqlite")
|
|
966
|
+
const db = new Database(process.env.MAIL_DB_PATH)
|
|
967
|
+
const oldName = process.env.OLD_USERNAME
|
|
968
|
+
const newName = process.env.NEW_USERNAME
|
|
969
|
+
const oldUser = db.query("SELECT 1 AS found FROM users WHERE username=? AND email=?").get(oldName, newName)
|
|
970
|
+
const newUser = db.query("SELECT 1 AS found FROM users WHERE username=?").get(newName)
|
|
971
|
+
if (oldUser && !newUser) {
|
|
972
|
+
db.transaction(() => {
|
|
973
|
+
for (const table of ["users", "imap_mailboxes", "imap_uids", "webmail_sessions"])
|
|
974
|
+
db.query("UPDATE " + table + " SET username=? WHERE username=?").run(newName, oldName)
|
|
975
|
+
})()
|
|
976
|
+
process.stdout.write("yes")
|
|
977
|
+
}
|
|
978
|
+
db.close()
|
|
979
|
+
' 2>/dev/null || true)
|
|
980
|
+
if [ "$migrated" = yes ]; then
|
|
981
|
+
if [ -d "/opt/mail/mail/$legacy" ] && [ ! -e "/opt/mail/mail/$addr" ]; then
|
|
982
|
+
mv -- "/opt/mail/mail/$legacy" "/opt/mail/mail/$addr"
|
|
983
|
+
chown -R mail-server:mail-server "/opt/mail/mail/$addr"
|
|
984
|
+
fi
|
|
985
|
+
# The declared config password becomes authoritative after migration.
|
|
986
|
+
SMTP_DB_PATH="$MAIL_DB_PATH" "$MS" user:local change-password "$addr" "$pw" >/dev/null 2>&1 || true
|
|
987
|
+
else
|
|
988
|
+
# The CLI action historically returned zero even when an internal
|
|
989
|
+
# create failed. Pin the live DB for both calls and verify the row.
|
|
990
|
+
SMTP_DB_PATH="$MAIL_DB_PATH" "$MS" user:local create "$addr" "$pw" "$addr" >/dev/null 2>&1 || true
|
|
991
|
+
fi
|
|
992
|
+
if SMTP_DB_PATH="$MAIL_DB_PATH" "$MS" user:local info "$addr" 2>&1 | grep -qi 'not found'; then
|
|
993
|
+
echo "FAIL:$addr"
|
|
994
|
+
elif [ "$migrated" = yes ]; then
|
|
995
|
+
echo "MIGRATED:$addr"
|
|
996
|
+
else
|
|
997
|
+
echo "MADE:$addr"
|
|
998
|
+
fi
|
|
949
999
|
else
|
|
950
1000
|
echo "EXISTS:$addr"
|
|
951
1001
|
fi
|
|
@@ -1076,7 +1126,7 @@ if [ "$ENV_CHANGED" = 1 ]; then systemctl restart mail 2>/dev/null || true; echo
|
|
|
1076
1126
|
input: script,
|
|
1077
1127
|
encoding: "utf8",
|
|
1078
1128
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1079
|
-
}), line = (out.match(/MAILTENANT:[^\n]*/) || [])[0] || "MAILTENANT:done", mailHostFromOut = (out.match(/MAILHOST:([^\n]*)/) || [])[1]?.trim(), mailHost = mailHostFromOut || `mail.${domain}`, dkimPubB64 = (out.match(/DKIMPUB:([^\n]*)/) || [])[1]?.trim() || void 0, madeAddrs = new Set([...out.matchAll(/MADE:([^\n]+)/g)].flatMap((m) => m[1] ? [m[1].trim()] : [])), created = boxes.filter((b) => madeAddrs.has(b.address)).map((b) => ({ address: b.address, password: b.password }));
|
|
1129
|
+
}), line = (out.match(/MAILTENANT:[^\n]*/) || [])[0] || "MAILTENANT:done", mailHostFromOut = (out.match(/MAILHOST:([^\n]*)/) || [])[1]?.trim(), mailHost = mailHostFromOut || `mail.${domain}`, dkimPubB64 = (out.match(/DKIMPUB:([^\n]*)/) || [])[1]?.trim() || void 0, madeAddrs = new Set([...out.matchAll(/MADE:([^\n]+)/g)].flatMap((m) => m[1] ? [m[1].trim()] : [])), migratedAddrs = new Set([...out.matchAll(/MIGRATED:([^\n]+)/g)].flatMap((m) => m[1] ? [m[1].trim()] : [])), created = boxes.filter((b) => madeAddrs.has(b.address)).map((b) => ({ address: b.address, password: b.password }));
|
|
1080
1130
|
logger.success(`Mail routing reconciled (${line.replace("MAILTENANT:", "")})`);
|
|
1081
1131
|
const failed = [...out.matchAll(/FAIL:([^\n]+)/g)].flatMap((m) => m[1] ? [m[1].trim()] : []);
|
|
1082
1132
|
if (failed.length)
|
|
@@ -1090,7 +1140,7 @@ if [ "$ENV_CHANGED" = 1 ]; then systemctl restart mail 2>/dev/null || true; echo
|
|
|
1090
1140
|
const certError = (out.match(/CERTFAIL:([^\n]*)/) || [])[1]?.trim();
|
|
1091
1141
|
if (certError)
|
|
1092
1142
|
logger.warn(`Mail: could not issue a certificate for mail.${domain} (clients should use ${mailHostFromOut || "the shared mail host"}): ${certError}`);
|
|
1093
|
-
const seen = new Set([...madeAddrs, ...[...out.matchAll(/EXISTS:([^\n]+)/g)].flatMap((m) => m[1] ? [m[1].trim()] : [])]), unaccounted = boxes.filter((b) => !seen.has(b.address)).map((b) => b.address);
|
|
1143
|
+
const seen = new Set([...madeAddrs, ...migratedAddrs, ...[...out.matchAll(/EXISTS:([^\n]+)/g)].flatMap((m) => m[1] ? [m[1].trim()] : [])]), unaccounted = boxes.filter((b) => !seen.has(b.address)).map((b) => b.address);
|
|
1094
1144
|
if (unaccounted.length)
|
|
1095
1145
|
logger.warn(`Mail: ${unaccounted.length} declared mailbox(es) were not reconciled: ${unaccounted.join(", ")}`);
|
|
1096
1146
|
if (created.length) {
|
|
@@ -1098,6 +1148,8 @@ if [ "$ENV_CHANGED" = 1 ]; then systemctl restart mail 2>/dev/null || true; echo
|
|
|
1098
1148
|
for (const b of created)
|
|
1099
1149
|
logger.info(` ${b.address} ${b.password}`);
|
|
1100
1150
|
}
|
|
1151
|
+
if (migratedAddrs.size)
|
|
1152
|
+
logger.success(`Mail: migrated ${migratedAddrs.size} legacy mailbox username(s) to isolated full addresses`);
|
|
1101
1153
|
return domain ? { domain, mailHost, dkimPubB64, created } : null;
|
|
1102
1154
|
} catch (err) {
|
|
1103
1155
|
logger.warn(`Mail routing reconcile skipped: ${getErrorMessage(err)}`);
|
|
@@ -8,6 +8,11 @@ function markdown(value) {
|
|
|
8
8
|
function code(value) {
|
|
9
9
|
return `\`${String(value).replaceAll("`", "\\`")}\``;
|
|
10
10
|
}
|
|
11
|
+
function stablePath(value) {
|
|
12
|
+
if (typeof value !== "string" || !value.includes(root))
|
|
13
|
+
return value;
|
|
14
|
+
return value.replaceAll(root, "<project root>");
|
|
15
|
+
}
|
|
11
16
|
function optionFlags(option) {
|
|
12
17
|
return option.flags.map((flag) => code(`${flag.length === 1 ? "-" : "--"}${flag}`)).join(", ");
|
|
13
18
|
}
|
|
@@ -34,7 +39,7 @@ function commandSection(command) {
|
|
|
34
39
|
`- Arguments: ${command.arguments.length ? command.arguments.map(argumentSyntax).join(", ") : "none"}`
|
|
35
40
|
];
|
|
36
41
|
if (command.options.length)
|
|
37
|
-
lines.push("", "| Option | Description | Contract | Default |", "| --- | --- | --- | --- |", ...command.options.map((option) => `| ${optionFlags(option)} | ${markdown(option.description || "\u2014")} | ${optionKind(option)} | ${option.default === void 0 ? "\u2014" : code(JSON.stringify(option.default))} |`));
|
|
42
|
+
lines.push("", "| Option | Description | Contract | Default |", "| --- | --- | --- | --- |", ...command.options.map((option) => `| ${optionFlags(option)} | ${markdown(option.description || "\u2014")} | ${optionKind(option)} | ${option.default === void 0 ? "\u2014" : code(JSON.stringify(stablePath(option.default)))} |`));
|
|
38
43
|
if (command.examples.length)
|
|
39
44
|
lines.push("", "Examples:", "", "```bash", ...command.examples, "```");
|
|
40
45
|
return lines.join(`
|
|
@@ -107,8 +112,20 @@ export async function run() {
|
|
|
107
112
|
} else {
|
|
108
113
|
if (!existsSync(outputPath))
|
|
109
114
|
throw Error("Buddy command reference is missing; run bun run docs:buddy");
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
const current = readFileSync(outputPath, "utf8");
|
|
116
|
+
if (current !== expected) {
|
|
117
|
+
const currentLines = current.split(`
|
|
118
|
+
`), expectedLines = expected.split(`
|
|
119
|
+
`), differences = [];
|
|
120
|
+
for (let i = 0;i < Math.max(currentLines.length, expectedLines.length) && differences.length < 6; i++)
|
|
121
|
+
if (currentLines[i] !== expectedLines[i])
|
|
122
|
+
differences.push(` line ${i + 1}:
|
|
123
|
+
committed: ${JSON.stringify(currentLines[i] ?? "<end of file>")}
|
|
124
|
+
generated: ${JSON.stringify(expectedLines[i] ?? "<end of file>")}`);
|
|
125
|
+
throw Error(`Buddy command reference is stale; run bun run docs:buddy
|
|
126
|
+
${differences.join(`
|
|
127
|
+
`)}`);
|
|
128
|
+
}
|
|
112
129
|
console.log("Buddy command reference matches the runtime registry");
|
|
113
130
|
}
|
|
114
131
|
}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { lstatSync, readlinkSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
1
3
|
import process from "node:process";
|
|
2
4
|
import { bold, dim, green, intro, log, onUnknownSubcommand, red, yellow } from "@stacksjs/cli";
|
|
3
5
|
import { feature } from "@stacksjs/config";
|
|
@@ -30,7 +32,25 @@ export function doctor(buddy) {
|
|
|
30
32
|
buddy.command("doctor", "Run health checks on your Stacks installation").option("--no-fail", "Print results but always exit 0 (CI ramp-up)").action(async (options) => {
|
|
31
33
|
log.debug("Running `buddy doctor` ...");
|
|
32
34
|
await intro("buddy doctor");
|
|
33
|
-
const checks = [],
|
|
35
|
+
const checks = [], modulesPath = resolve(process.cwd(), "node_modules");
|
|
36
|
+
try {
|
|
37
|
+
if (lstatSync(modulesPath).isSymbolicLink()) {
|
|
38
|
+
const target = resolve(process.cwd(), readlinkSync(modulesPath)), insideProject = target.startsWith(`${resolve(process.cwd())}/`);
|
|
39
|
+
checks.push({
|
|
40
|
+
name: "Dependency tree",
|
|
41
|
+
status: insideProject ? "warn" : "fail",
|
|
42
|
+
message: insideProject ? `node_modules is a symlink to ${target}` : `node_modules is a symlink to ${target}, which belongs to another project \u2014 installs here mutate it, and what runs locally is not what the lockfile resolves. Remove the link and run \`bun install\`.`
|
|
43
|
+
});
|
|
44
|
+
} else
|
|
45
|
+
checks.push({ name: "Dependency tree", status: "pass", message: "node_modules is this project's own" });
|
|
46
|
+
} catch {
|
|
47
|
+
checks.push({
|
|
48
|
+
name: "Dependency tree",
|
|
49
|
+
status: "warn",
|
|
50
|
+
message: "node_modules is missing \u2014 run `bun install`"
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
const bunVersion = process.versions.bun;
|
|
34
54
|
if (bunVersion && isSupportedBunVersion(bunVersion))
|
|
35
55
|
checks.push({
|
|
36
56
|
name: "Bun Runtime",
|
|
@@ -424,8 +444,10 @@ export function doctor(buddy) {
|
|
|
424
444
|
log.info("");
|
|
425
445
|
if (hasFailures) {
|
|
426
446
|
log.error("Some critical checks failed. Please address the issues above.");
|
|
427
|
-
if (options?.fail !== !1)
|
|
447
|
+
if (options?.fail !== !1) {
|
|
448
|
+
await log.flush();
|
|
428
449
|
process.exit(1);
|
|
450
|
+
}
|
|
429
451
|
} else if (hasWarnings)
|
|
430
452
|
log.info(yellow("Some checks have warnings. Your system should work but may have issues."));
|
|
431
453
|
else
|
|
@@ -19,7 +19,7 @@ function showJson(sourceRevision, path) {
|
|
|
19
19
|
function category(path) {
|
|
20
20
|
if (/(^|\/)(test|tests|__tests__)(\/|$)|\.(test|spec)\.[^.]+$/.test(path))
|
|
21
21
|
return "tests";
|
|
22
|
-
if (path.startsWith("protocol/suite/"))
|
|
22
|
+
if (path.startsWith(".github/protocol/suite/"))
|
|
23
23
|
return "vendored-protocol";
|
|
24
24
|
if (/(^|\/)(dist|generated|coverage)(\/|$)|\.d\.ts$/.test(path))
|
|
25
25
|
return "generated";
|
|
@@ -58,7 +58,7 @@ export function buildSourceManifest(requestedRevision) {
|
|
|
58
58
|
if (!pkg.name || !pkg.version)
|
|
59
59
|
return [];
|
|
60
60
|
return [{ name: pkg.name, path, version: pkg.version, publishable: pkg.private !== !0 }];
|
|
61
|
-
}).sort((a, b) => a.name.localeCompare(b.name) || a.path.localeCompare(b.path)), rootPackage = showJson(sourceRevision, "package.json"), suiteLock = showJson(sourceRevision, "protocol/suite.lock.json");
|
|
61
|
+
}).sort((a, b) => a.name.localeCompare(b.name) || a.path.localeCompare(b.path)), rootPackage = showJson(sourceRevision, "package.json"), suiteLock = showJson(sourceRevision, ".github/protocol/suite.lock.json");
|
|
62
62
|
return {
|
|
63
63
|
schemaVersion: "1.0.0",
|
|
64
64
|
repository: "https://github.com/stacksjs/stacks",
|
package/dist/commands/serve.js
CHANGED
|
@@ -169,9 +169,15 @@ export function serveApi(buddy) {
|
|
|
169
169
|
if (options?.port)
|
|
170
170
|
process.env.PORT = String(options.port);
|
|
171
171
|
process.env.APP_ENV = process.env.APP_ENV || "production";
|
|
172
|
-
await import(
|
|
172
|
+
await import(resolveApiEntry());
|
|
173
173
|
});
|
|
174
174
|
}
|
|
175
|
+
function resolveApiEntry() {
|
|
176
|
+
const vendored = join(process.cwd(), "storage/framework/core/actions/src/serve/api.ts");
|
|
177
|
+
if (existsSync(vendored))
|
|
178
|
+
return vendored;
|
|
179
|
+
return "@stacksjs/actions/serve/api";
|
|
180
|
+
}
|
|
175
181
|
function resolveDefaultsResources() {
|
|
176
182
|
const vendored = "storage/framework/defaults/resources";
|
|
177
183
|
if (existsSync(vendored))
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/buddy",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.70.
|
|
5
|
+
"version": "0.70.194",
|
|
6
6
|
"description": "Meet Buddy. The Stacks runtime.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"@stacksjs/ui": "^0.70.180",
|
|
138
138
|
"@stacksjs/utils": "^0.70.180",
|
|
139
139
|
"@stacksjs/validation": "^0.70.180",
|
|
140
|
-
"@stacksjs/ts-cloud": "^0.7.
|
|
140
|
+
"@stacksjs/ts-cloud": "^0.7.78",
|
|
141
141
|
"ajv": "^8.20.0",
|
|
142
142
|
"ajv-formats": "^3.0.1"
|
|
143
143
|
},
|