@stacksjs/actions 0.70.87 → 0.70.90
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/action.js +78 -2
- package/dist/actions.js +2 -2
- package/dist/add.js +20 -2
- package/dist/ai/request-model-access.js +10 -2
- package/dist/auth/client.js +44 -3
- package/dist/auth/prune.js +35 -2
- package/dist/auth/setup.js +152 -36
- package/dist/auth/token.js +10 -2
- package/dist/blog-admin.d.ts +55 -0
- package/dist/blog-admin.js +156 -0
- package/dist/blog.d.ts +11 -0
- package/dist/blog.js +306 -56
- package/dist/build/cli.js +6 -2
- package/dist/build/component-libs.js +7 -2
- package/dist/build/core.js +55 -2
- package/dist/build/desktop.js +5 -2
- package/dist/build/docs.js +5 -2
- package/dist/build/frontend-static.js +123 -8
- package/dist/build/server.js +6 -2
- package/dist/build/stacks.js +8 -2
- package/dist/build/views.js +11 -2
- package/dist/build.js +64 -2
- package/dist/bump.js +162 -7
- package/dist/cdn/invalidate-cache.js +0 -1
- package/dist/changelog.js +27 -3
- package/dist/check/ports.js +16 -2
- package/dist/clean.js +4 -2
- package/dist/commit.js +12 -2
- package/dist/copy-types.js +10 -3
- package/dist/database/seed.js +26 -2
- package/dist/deploy/create-receipt-rule.js +36 -2
- package/dist/deploy/index.js +1318 -44
- package/dist/dev/api.js +94 -6
- package/dist/dev/components.js +7 -2
- package/dist/dev/dashboard-globals.js +89 -3
- package/dist/dev/dashboard-utils.js +380 -2
- package/dist/dev/dashboard.js +435 -8
- package/dist/dev/desktop.js +5 -2
- package/dist/dev/docs.js +24 -2
- package/dist/dev/index.js +29 -2
- package/dist/dev/migrate-watcher.js +74 -2
- package/dist/dev/system-tray.js +5 -2
- package/dist/dev/views.js +147 -2
- package/dist/discover-packages.js +32 -2
- package/dist/domains/add.js +61 -2
- package/dist/domains/purchase.js +66 -2
- package/dist/domains/remove.js +24 -2
- package/dist/examples.js +34 -2
- package/dist/find-projects.js +16 -2
- package/dist/fresh.js +17 -2
- package/dist/generate/action-types.js +9 -4
- package/dist/generate/component-meta.js +9 -3
- package/dist/generate/custom-cli-file.js +20 -3
- package/dist/generate/env-files.js +46 -6
- package/dist/generate/ide-helpers.js +8 -3
- package/dist/generate/index.js +158 -2
- package/dist/generate/lib-entries.js +16 -3
- package/dist/generate/pantry-file.js +46 -2
- package/dist/generate/symlink-core.js +2 -2
- package/dist/generate/types.js +3 -2
- package/dist/generate/vscode-custom-data.js +9 -3
- package/dist/generate/web-types.js +0 -1
- package/dist/helpers/component-meta.js +295 -2
- package/dist/helpers/index.js +1 -2
- package/dist/helpers/lib-entries.js +73 -2
- package/dist/helpers/package-json.js +45 -14
- package/dist/helpers/utils.js +105 -2
- package/dist/helpers/vscode-custom-data.js +30 -2
- package/dist/index.d.ts +13 -0
- package/dist/index.js +50 -2
- package/dist/key-generate.js +24 -2
- package/dist/lint/fix.js +4 -3
- package/dist/lint/index.js +4 -3
- package/dist/lint/lint.js +34 -2
- package/dist/make-command.js +64 -14
- package/dist/make-job.js +41 -16
- package/dist/make-policy.js +74 -26
- package/dist/make-resource.js +50 -21
- package/dist/make.js +328 -2
- package/dist/migrate/database.js +16 -2
- package/dist/migrate/fresh.js +31 -2
- package/dist/orm/base.js +0 -2
- package/dist/orm/test.js +0 -1
- package/dist/prepublish.js +16 -2
- package/dist/queue/clear.js +42 -2
- package/dist/queue/dlq-purge.js +28 -2
- package/dist/queue/dlq-retry.js +35 -2
- package/dist/queue/dlq.js +55 -5
- package/dist/queue/failed.js +69 -5
- package/dist/queue/flush.js +49 -3
- package/dist/queue/inspect.js +154 -8
- package/dist/queue/list.js +69 -5
- package/dist/queue/monitor.js +94 -6
- package/dist/queue/pause.js +28 -2
- package/dist/queue/quarantine.js +42 -3
- package/dist/queue/resume.js +27 -2
- package/dist/queue/retry.js +41 -2
- package/dist/queue/schedule-list.js +33 -5
- package/dist/queue/schedule.js +12 -2
- package/dist/queue/status.js +68 -5
- package/dist/queue/table.js +10 -2
- package/dist/queue/unquarantine.js +27 -2
- package/dist/queue/work.js +57 -2
- package/dist/release.js +21 -3
- package/dist/route/list.js +78 -3
- package/dist/run-action.js +1 -2
- package/dist/saas/setup.js +9 -2
- package/dist/scaffold-crud.js +164 -40
- package/dist/schedule/run.js +7 -2
- package/dist/search/flush.js +10 -2
- package/dist/search/import.js +10 -2
- package/dist/search/settings-list.js +10 -2
- package/dist/search/settings.js +9 -2
- package/dist/serve/api.js +35 -2
- package/dist/setup/index.js +1 -2
- package/dist/setup/ssl.js +271 -2
- package/dist/stacks.js +265 -2
- package/dist/templates.js +301 -2
- package/dist/test/feature.js +11 -2
- package/dist/test/index.js +11 -2
- package/dist/test/ui.js +4 -2
- package/dist/test/unit.js +11 -2
- package/dist/typecheck.js +4 -2
- package/dist/types.js +16 -2
- package/dist/upgrade/binary.js +29 -2
- package/dist/upgrade/bun.js +0 -1
- package/dist/upgrade/dependencies.js +0 -2
- package/dist/upgrade/framework-utils.js +193 -2
- package/dist/upgrade/framework.js +310 -7
- package/dist/upgrade/index.js +17 -2
- package/dist/upgrade/packages.js +99 -12
- package/dist/upgrade/shell.js +40 -4
- package/dist/upgrade.js +38 -2
- package/package.json +16 -16
- package/dist/chunk-0c8sd1t6.js +0 -2
- package/dist/chunk-0g2nzhx9.js +0 -240
- package/dist/chunk-0gadhvn7.js +0 -3
- package/dist/chunk-0h27aa4r.js +0 -93
- package/dist/chunk-3peh8kqs.js +0 -851
- package/dist/chunk-62gdfav8.js +0 -3
- package/dist/chunk-6bk53y02.js +0 -3
- package/dist/chunk-78c5n3s2.js +0 -3
- package/dist/chunk-c74qv38e.js +0 -17
- package/dist/chunk-cdk2r2jd.js +0 -1
- package/dist/chunk-dbz9dp2h.js +0 -3
- package/dist/chunk-e142dheq.js +0 -3
- package/dist/chunk-ec4gky40.js +0 -3
- package/dist/chunk-h3d81wrg.js +0 -3
- package/dist/chunk-m3q0x4h0.js +0 -688
- package/dist/chunk-mqgbyhph.js +0 -5
- package/dist/chunk-n24m8prb.js +0 -3
- package/dist/chunk-n5eqwhck.js +0 -7
- package/dist/chunk-nsvnqv8y.js +0 -5
- package/dist/chunk-nty6mmx4.js +0 -283
- package/dist/chunk-s735m9mg.js +0 -1
- package/dist/chunk-tpb8jgsk.js +0 -7
- package/dist/chunk-tsbk5vne.js +0 -3
- package/dist/chunk-xg9xscqz.js +0 -1
- package/dist/chunk-y6e448he.js +0 -7
package/dist/dev/dashboard.js
CHANGED
|
@@ -1,8 +1,435 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { bold, cyan, dim, green, red } from "@stacksjs/cli";
|
|
4
|
+
import { projectPath, storagePath } from "@stacksjs/path";
|
|
5
|
+
import { buildDashboardUrl, buildManifest, discoverModels, findAvailablePort, waitForServer } from "./dashboard-utils";
|
|
6
|
+
const verboseIdx = process.argv.indexOf("--verbose"), verbose = verboseIdx !== -1 && process.argv[verboseIdx + 1] !== "false", startTime = Bun.nanoseconds(), originalConsoleLog = console.log, originalConsoleWarn = console.warn, bufferedLogs = [];
|
|
7
|
+
console.log = (...args) => {
|
|
8
|
+
bufferedLogs.push(args.map(String).join(" "));
|
|
9
|
+
};
|
|
10
|
+
console.warn = (...args) => {
|
|
11
|
+
bufferedLogs.push(args.map(String).join(" "));
|
|
12
|
+
};
|
|
13
|
+
const dashboardPath = storagePath("framework/defaults/views/dashboard"), userDashboardPath = projectPath("resources/views/dashboard"), preferredPort = Number(process.env.PORT_ADMIN) || 3002, dashboardPort = await findAvailablePort(preferredPort), appUrl = process.env.APP_URL || "", hasCustomDomain = appUrl !== "" && appUrl !== "localhost" && !appUrl.includes("localhost:"), domain = hasCustomDomain ? appUrl.replace(/^https?:\/\//, "") : null, dashboardDomain = domain ? `dashboard.${domain}` : null, sslBasePath = `${process.env.HOME}/.stacks/ssl`;
|
|
14
|
+
function restoreConsole() {
|
|
15
|
+
console.log = originalConsoleLog;
|
|
16
|
+
console.warn = (...args) => {
|
|
17
|
+
const msg = args.map(String).join(" ");
|
|
18
|
+
if (msg.includes("[STX] DOM API violation") || msg.includes("unsafe expression"))
|
|
19
|
+
return;
|
|
20
|
+
originalConsoleWarn(...args);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async function startStxServer() {
|
|
24
|
+
try {
|
|
25
|
+
await import("@stacksjs/orm");
|
|
26
|
+
} catch (err) {
|
|
27
|
+
if (verbose)
|
|
28
|
+
console.warn("[dashboard] orm preload failed:", err?.message || err);
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const { hoistDashboardGlobals } = await import("./dashboard-globals");
|
|
32
|
+
await hoistDashboardGlobals({ verbose });
|
|
33
|
+
} catch (err) {
|
|
34
|
+
if (verbose)
|
|
35
|
+
console.warn("[dashboard] globals preload failed:", err?.message || err);
|
|
36
|
+
}
|
|
37
|
+
let serve;
|
|
38
|
+
try {
|
|
39
|
+
serve = (await import("bun-plugin-stx/serve")).serve;
|
|
40
|
+
} catch {
|
|
41
|
+
serve = (await import(projectPath("pantry/bun-plugin-stx/dist/serve.js"))).serve;
|
|
42
|
+
}
|
|
43
|
+
let stxModule;
|
|
44
|
+
try {
|
|
45
|
+
const localStx = process.env.STX_SRC || `${process.env.HOME}/Code/Tools/stx/packages/stx/src/index.ts`;
|
|
46
|
+
if (await Bun.file(localStx).exists())
|
|
47
|
+
stxModule = await import(localStx);
|
|
48
|
+
} catch {}
|
|
49
|
+
if (stxModule && verbose)
|
|
50
|
+
console.log("[Dashboard] Using local stx checkout");
|
|
51
|
+
if (!stxModule)
|
|
52
|
+
try {
|
|
53
|
+
const vendoredStx = projectPath("pantry/@stacksjs/stx/dist/index.js");
|
|
54
|
+
if (await Bun.file(vendoredStx).exists())
|
|
55
|
+
stxModule = await import(vendoredStx);
|
|
56
|
+
} catch {}
|
|
57
|
+
const { listConfigFiles, readConfig, updateConfigKey } = await import(storagePath("framework/defaults/resources/functions/dashboard/config-io.ts")), depRoutes = {
|
|
58
|
+
"/__deps/charts.js": storagePath("framework/core/charts/dist/index.js")
|
|
59
|
+
}, configRoutes = {
|
|
60
|
+
...Object.fromEntries(Object.entries(depRoutes).map(([url, file]) => [
|
|
61
|
+
url,
|
|
62
|
+
async () => {
|
|
63
|
+
const f = Bun.file(file);
|
|
64
|
+
if (!await f.exists())
|
|
65
|
+
return new Response(`// dependency dist missing: ${file}
|
|
66
|
+
// rebuild with: cd ${file.replace(/\/dist\/[^/]+$/, "")} && bun build.ts`, { status: 500, headers: { "content-type": "text/javascript; charset=utf-8" } });
|
|
67
|
+
return new Response(f, {
|
|
68
|
+
headers: {
|
|
69
|
+
"content-type": "text/javascript; charset=utf-8",
|
|
70
|
+
"cache-control": "no-cache"
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
])),
|
|
75
|
+
"/api/config/list": async () => {
|
|
76
|
+
try {
|
|
77
|
+
return Response.json({ ok: !0, files: listConfigFiles() });
|
|
78
|
+
} catch (e) {
|
|
79
|
+
return Response.json({ ok: !1, error: e?.message }, { status: 500 });
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"/api/config/read": async (req) => {
|
|
83
|
+
try {
|
|
84
|
+
const name = new URL(req.url).searchParams.get("name") || "";
|
|
85
|
+
if (!/^[\w-]+$/.test(name))
|
|
86
|
+
return Response.json({ ok: !1, error: "Invalid config name" }, { status: 400 });
|
|
87
|
+
const result = await readConfig(name);
|
|
88
|
+
if (!result)
|
|
89
|
+
return Response.json({ ok: !1, error: "Not found" }, { status: 404 });
|
|
90
|
+
return Response.json({ ok: !0, name, fields: result.fields, values: result.values });
|
|
91
|
+
} catch (e) {
|
|
92
|
+
return Response.json({ ok: !1, error: e?.message }, { status: 500 });
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"/api/config/source": async (req) => {
|
|
96
|
+
try {
|
|
97
|
+
const name = new URL(req.url).searchParams.get("name") || "";
|
|
98
|
+
if (!/^[\w-]+$/.test(name))
|
|
99
|
+
return Response.json({ ok: !1, error: "Invalid config name" }, { status: 400 });
|
|
100
|
+
const result = await readConfig(name);
|
|
101
|
+
if (!result)
|
|
102
|
+
return Response.json({ ok: !1, error: "Not found" }, { status: 404 });
|
|
103
|
+
return new Response(result.source, { headers: { "content-type": "text/plain; charset=utf-8" } });
|
|
104
|
+
} catch (e) {
|
|
105
|
+
return Response.json({ ok: !1, error: e?.message }, { status: 500 });
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"/api/config/update": async (req) => {
|
|
109
|
+
if (req.method !== "POST")
|
|
110
|
+
return Response.json({ ok: !1, error: "Method not allowed" }, { status: 405 });
|
|
111
|
+
try {
|
|
112
|
+
const body = await req.json(), file = body.file?.replace(/\.ts$/, "");
|
|
113
|
+
if (!file || !/^[\w-]+$/.test(file))
|
|
114
|
+
return Response.json({ ok: !1, error: "Invalid file" }, { status: 400 });
|
|
115
|
+
const updates = [];
|
|
116
|
+
if (Array.isArray(body.updates))
|
|
117
|
+
for (const u of body.updates) {
|
|
118
|
+
const k = u.key ?? u.path;
|
|
119
|
+
if (typeof k === "string")
|
|
120
|
+
updates.push({ key: k, value: u.value });
|
|
121
|
+
}
|
|
122
|
+
else if (body.key)
|
|
123
|
+
updates.push({ key: body.key, value: body.value });
|
|
124
|
+
if (updates.length === 0)
|
|
125
|
+
return Response.json({ ok: !1, error: "No updates supplied" }, { status: 400 });
|
|
126
|
+
const results = [];
|
|
127
|
+
for (const u of updates)
|
|
128
|
+
try {
|
|
129
|
+
const r = await updateConfigKey(file, u.key, coerce(u.value));
|
|
130
|
+
results.push({ key: u.key, ok: !0, newValue: r.newValue });
|
|
131
|
+
} catch (err) {
|
|
132
|
+
results.push({ key: u.key, ok: !1, error: err?.message });
|
|
133
|
+
}
|
|
134
|
+
const allOk = results.every((r) => r.ok);
|
|
135
|
+
return Response.json({ ok: allOk, file, results });
|
|
136
|
+
} catch (e) {
|
|
137
|
+
return Response.json({ ok: !1, error: e?.message }, { status: 500 });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
function coerce(v) {
|
|
142
|
+
if (typeof v === "boolean" || typeof v === "number")
|
|
143
|
+
return v;
|
|
144
|
+
if (v === "true")
|
|
145
|
+
return !0;
|
|
146
|
+
if (v === "false")
|
|
147
|
+
return !1;
|
|
148
|
+
if (v === "" || v == null)
|
|
149
|
+
return "";
|
|
150
|
+
if (typeof v === "string" && /^-?\d+(?:\.\d+)?$/.test(v))
|
|
151
|
+
return Number(v);
|
|
152
|
+
return String(v);
|
|
153
|
+
}
|
|
154
|
+
let stacksRoute = null;
|
|
155
|
+
try {
|
|
156
|
+
const router = await import("@stacksjs/router"), routeRegistry = (await import(projectPath("app/Routes.ts"))).default;
|
|
157
|
+
await router.loadRoutes(routeRegistry);
|
|
158
|
+
stacksRoute = router.route;
|
|
159
|
+
} catch (err) {
|
|
160
|
+
const detail = err?.message || String(err);
|
|
161
|
+
console.error(`
|
|
162
|
+
${red(bold(" Dashboard API disabled: Stacks router init failed."))}`);
|
|
163
|
+
console.error(` ${detail}`);
|
|
164
|
+
console.error(dim(" Every /api/dashboard/* endpoint will return 404; pages render but show no data."));
|
|
165
|
+
console.error(dim(` Re-run with --verbose for the full stack trace.
|
|
166
|
+
`));
|
|
167
|
+
if (verbose)
|
|
168
|
+
console.error(err);
|
|
169
|
+
}
|
|
170
|
+
serve({
|
|
171
|
+
patterns: [userDashboardPath, dashboardPath],
|
|
172
|
+
port: dashboardPort,
|
|
173
|
+
componentsDir: storagePath("framework/defaults/resources/components/Dashboard"),
|
|
174
|
+
layoutsDir: dashboardPath,
|
|
175
|
+
partialsDir: dashboardPath,
|
|
176
|
+
quiet: !0,
|
|
177
|
+
routes: configRoutes,
|
|
178
|
+
onRequest: stacksRoute ? async (req) => {
|
|
179
|
+
const pathname = new URL(req.url).pathname;
|
|
180
|
+
if (pathname.startsWith("/api/config/") || pathname.startsWith("/__deps/"))
|
|
181
|
+
return null;
|
|
182
|
+
if (pathname.startsWith("/api/"))
|
|
183
|
+
return stacksRoute.handleRequest(req);
|
|
184
|
+
if (req.method.toUpperCase() !== "GET")
|
|
185
|
+
return stacksRoute.handleRequest(req);
|
|
186
|
+
return null;
|
|
187
|
+
} : void 0,
|
|
188
|
+
auth: !1,
|
|
189
|
+
...stxModule && { stxModule }
|
|
190
|
+
}).catch((err) => {
|
|
191
|
+
restoreConsole();
|
|
192
|
+
console.error(`
|
|
193
|
+
Failed to start dashboard server: ${err?.message || err}
|
|
194
|
+
`);
|
|
195
|
+
process.exit(1);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
async function startReverseProxy() {
|
|
199
|
+
if (!dashboardDomain)
|
|
200
|
+
return !1;
|
|
201
|
+
if (process.env.STACKS_PROXY_MANAGED)
|
|
202
|
+
return !1;
|
|
203
|
+
try {
|
|
204
|
+
const { startProxies } = await import("@stacksjs/rpx");
|
|
205
|
+
await startProxies({
|
|
206
|
+
proxies: [
|
|
207
|
+
{ from: `localhost:${dashboardPort}`, to: dashboardDomain, cleanUrls: !1 }
|
|
208
|
+
],
|
|
209
|
+
https: {
|
|
210
|
+
basePath: sslBasePath,
|
|
211
|
+
validityDays: 825
|
|
212
|
+
},
|
|
213
|
+
regenerateUntrustedCerts: !1,
|
|
214
|
+
verbose
|
|
215
|
+
});
|
|
216
|
+
return !0;
|
|
217
|
+
} catch (error) {
|
|
218
|
+
if (verbose)
|
|
219
|
+
originalConsoleLog(` ${dim(`Proxy: ${error}`)}`);
|
|
220
|
+
return !1;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const configApiPort = dashboardPort + 1;
|
|
224
|
+
function jsonResponse(data, status = 200, extraHeaders = {}) {
|
|
225
|
+
return new Response(JSON.stringify(data), {
|
|
226
|
+
status,
|
|
227
|
+
headers: {
|
|
228
|
+
"Content-Type": "application/json",
|
|
229
|
+
"Access-Control-Allow-Origin": "*",
|
|
230
|
+
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
231
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
232
|
+
...extraHeaders
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
function startConfigApi() {
|
|
237
|
+
Bun.serve({
|
|
238
|
+
port: configApiPort,
|
|
239
|
+
fetch: async (req) => {
|
|
240
|
+
if (req.method === "OPTIONS")
|
|
241
|
+
return new Response(null, {
|
|
242
|
+
headers: {
|
|
243
|
+
"Access-Control-Allow-Origin": "*",
|
|
244
|
+
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
245
|
+
"Access-Control-Allow-Headers": "Content-Type"
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
if (new URL(req.url).pathname === "/api/config/update" && req.method === "POST")
|
|
249
|
+
try {
|
|
250
|
+
const { file, updates } = await req.json();
|
|
251
|
+
if (!file || file.includes("..") || !file.match(/^[\w.-]+\.ts$/))
|
|
252
|
+
return jsonResponse({ error: "Invalid file name" }, 400);
|
|
253
|
+
const filePath = projectPath(`config/${file}`);
|
|
254
|
+
let content = readFileSync(filePath, "utf-8");
|
|
255
|
+
for (const { path: keyPath, value } of updates) {
|
|
256
|
+
const escapedKey = keyPath.split(".").pop().replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), pattern = new RegExp(`(${escapedKey}\\s*:\\s*)(?:'[^']*'|"[^"]*"|\\d+(?:\\.\\d+)?|true|false)`);
|
|
257
|
+
if (pattern.test(content)) {
|
|
258
|
+
const isNum = /^\d+(?:\.\d+)?$/.test(value), isBool = value === "true" || value === "false", sanitizedValue = value.replace(/'/g, "\\'").replace(/\$/g, "$$$$"), replacement = isNum || isBool ? value : `'${sanitizedValue}'`;
|
|
259
|
+
content = content.replace(pattern, `$1${replacement}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
writeFileSync(filePath, content, "utf-8");
|
|
263
|
+
return jsonResponse({ success: !0 });
|
|
264
|
+
} catch (err) {
|
|
265
|
+
return jsonResponse({ error: err.message }, 500);
|
|
266
|
+
}
|
|
267
|
+
return jsonResponse({ error: "Not found" }, 404);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
startConfigApi();
|
|
272
|
+
const [, discoveredModels] = await Promise.all([
|
|
273
|
+
startStxServer(),
|
|
274
|
+
discoverModels(projectPath("app/Models"), storagePath("framework/defaults/app/Models"))
|
|
275
|
+
]);
|
|
276
|
+
async function loadDashboardToggles() {
|
|
277
|
+
const fallback = {
|
|
278
|
+
library: !0,
|
|
279
|
+
content: !0,
|
|
280
|
+
commerce: !0,
|
|
281
|
+
marketing: !0,
|
|
282
|
+
analytics: !0,
|
|
283
|
+
management: !0,
|
|
284
|
+
utilities: !0,
|
|
285
|
+
ci: !1,
|
|
286
|
+
data: { dashboard: !0, activity: !0, users: !0, teams: !0, subscribers: !0, allModels: !0 }
|
|
287
|
+
};
|
|
288
|
+
try {
|
|
289
|
+
const mod = await import(projectPath("config/dashboard.ts")), sections = mod.default?.sections ?? {}, data = sections.data ?? {};
|
|
290
|
+
return {
|
|
291
|
+
library: sections.library?.enabled ?? !0,
|
|
292
|
+
content: sections.content?.enabled ?? !0,
|
|
293
|
+
commerce: sections.commerce?.enabled ?? !0,
|
|
294
|
+
marketing: sections.marketing?.enabled ?? !0,
|
|
295
|
+
analytics: sections.analytics?.enabled ?? !0,
|
|
296
|
+
management: sections.management?.enabled ?? !0,
|
|
297
|
+
utilities: sections.utilities?.enabled ?? !0,
|
|
298
|
+
ci: mod.default?.ci?.enabled ?? !1,
|
|
299
|
+
data: {
|
|
300
|
+
dashboard: data.dashboard?.enabled ?? !0,
|
|
301
|
+
activity: data.activity?.enabled ?? !0,
|
|
302
|
+
users: data.users?.enabled ?? !0,
|
|
303
|
+
teams: data.teams?.enabled ?? !0,
|
|
304
|
+
subscribers: data.subscribers?.enabled ?? !0,
|
|
305
|
+
allModels: data.allModels?.enabled ?? !0
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
} catch {
|
|
309
|
+
return fallback;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
const dashboardToggles = await loadDashboardToggles(), manifestPath = storagePath("framework/defaults/views/dashboard/.discovered-models.json"), manifestPayload = {
|
|
313
|
+
models: buildManifest(discoveredModels),
|
|
314
|
+
sections: dashboardToggles
|
|
315
|
+
};
|
|
316
|
+
writeFileSync(manifestPath, JSON.stringify(manifestPayload, null, 2));
|
|
317
|
+
const serverReady = await waitForServer(dashboardPort);
|
|
318
|
+
restoreConsole();
|
|
319
|
+
let proxyStarted = !1;
|
|
320
|
+
startReverseProxy().then((ok) => {
|
|
321
|
+
proxyStarted = ok;
|
|
322
|
+
}).catch((err) => {
|
|
323
|
+
if (verbose)
|
|
324
|
+
console.warn("[Dashboard] Reverse proxy failed:", err);
|
|
325
|
+
});
|
|
326
|
+
const dashboardHttpsUrl = dashboardDomain ? `https://${dashboardDomain}` : null, dashboardLocalUrl = `http://localhost:${dashboardPort}`, initialUrl = `http://localhost:${dashboardPort}/`, elapsedMs = (Bun.nanoseconds() - startTime) / 1e6;
|
|
327
|
+
console.log();
|
|
328
|
+
console.log(` ${bold(cyan("stacks dashboard"))}`);
|
|
329
|
+
console.log();
|
|
330
|
+
if (dashboardHttpsUrl) {
|
|
331
|
+
console.log(` ${green("\u279C")} ${bold("Local")}: ${cyan(dashboardHttpsUrl)}`);
|
|
332
|
+
console.log(` ${dim("\u279C")} ${dim("Origin")}: ${dim(dashboardLocalUrl)}`);
|
|
333
|
+
} else
|
|
334
|
+
console.log(` ${green("\u279C")} ${bold("Local")}: ${cyan(dashboardLocalUrl)}`);
|
|
335
|
+
console.log(` ${green("\u279C")} ${bold("Window")}: ${dim("Stacks Dashboard")} ${dim("1400\xD7900")}`);
|
|
336
|
+
console.log(` ${green("\u279C")} ${bold("Models")}: ${dim(`${discoveredModels.length} discovered`)}`);
|
|
337
|
+
if (dashboardPort !== preferredPort)
|
|
338
|
+
console.log(` ${dim("\u279C")} ${dim(`Port ${preferredPort} in use, using ${dashboardPort}`)}`);
|
|
339
|
+
if (!serverReady)
|
|
340
|
+
console.log(` ${dim("\u26A0")} ${dim("Dev server may not be ready yet")}`);
|
|
341
|
+
console.log();
|
|
342
|
+
console.log(` ${dim(`ready in ${elapsedMs.toFixed(0)} ms`)}`);
|
|
343
|
+
if (verbose) {
|
|
344
|
+
console.log();
|
|
345
|
+
console.log(` ${dim("\u279C")} ${dim("URL")}: ${dim(initialUrl)}`);
|
|
346
|
+
if (dashboardDomain) {
|
|
347
|
+
console.log(` ${dim("\u279C")} ${dim("SSL")}: ${dim(sslBasePath)}`);
|
|
348
|
+
console.log(` ${dim("\u279C")} ${dim("Proxy")}: ${dim(`localhost:${dashboardPort} \u2192 ${dashboardDomain}`)}`);
|
|
349
|
+
}
|
|
350
|
+
if (bufferedLogs.length > 0) {
|
|
351
|
+
console.log();
|
|
352
|
+
for (const line of bufferedLogs)
|
|
353
|
+
console.log(` ${dim(line)}`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
console.log();
|
|
357
|
+
let createApp;
|
|
358
|
+
const localCraftSdk = process.env.HOME ? `${process.env.HOME}/Code/Tools/craft/packages/typescript/src/index.ts` : void 0;
|
|
359
|
+
if (localCraftSdk && existsSync(localCraftSdk))
|
|
360
|
+
try {
|
|
361
|
+
({ createApp } = await import(localCraftSdk));
|
|
362
|
+
} catch {}
|
|
363
|
+
if (!createApp) {
|
|
364
|
+
const packageNames = ["craft-native", "@craft-native/craft", "@stacksjs/ts-craft"];
|
|
365
|
+
for (const packageName of packageNames)
|
|
366
|
+
try {
|
|
367
|
+
({ createApp } = await import(packageName));
|
|
368
|
+
if (createApp)
|
|
369
|
+
break;
|
|
370
|
+
} catch {}
|
|
371
|
+
}
|
|
372
|
+
if (createApp) {
|
|
373
|
+
const userIconPath = projectPath("resources/assets/images/app-icon.png"), defaultIconPath = storagePath("framework/defaults/resources/assets/images/app-icon.png"), appIconPath = await Bun.file(userIconPath).exists() ? userIconPath : await Bun.file(defaultIconPath).exists() ? defaultIconPath : void 0, craftBinaryPath = (() => {
|
|
374
|
+
const explicit = process.env.CRAFT_BIN;
|
|
375
|
+
if (explicit)
|
|
376
|
+
return existsSync(explicit) ? explicit : void 0;
|
|
377
|
+
const codeTools = `${process.env.HOME}/Code/Tools/craft/craft`;
|
|
378
|
+
if (existsSync(codeTools))
|
|
379
|
+
return codeTools;
|
|
380
|
+
const codeToolsBin = `${process.env.HOME}/Code/Tools/craft/bin/craft`;
|
|
381
|
+
if (existsSync(codeToolsBin))
|
|
382
|
+
return codeToolsBin;
|
|
383
|
+
const codeToolsZig = `${process.env.HOME}/Code/Tools/craft/packages/zig/zig-out/bin/craft`;
|
|
384
|
+
if (existsSync(codeToolsZig))
|
|
385
|
+
return codeToolsZig;
|
|
386
|
+
const homeRel = `${process.env.HOME}/Documents/Projects/craft/packages/zig/zig-out/bin/craft`;
|
|
387
|
+
if (existsSync(homeRel))
|
|
388
|
+
return homeRel;
|
|
389
|
+
return;
|
|
390
|
+
})();
|
|
391
|
+
if (!craftBinaryPath)
|
|
392
|
+
createApp = void 0;
|
|
393
|
+
if (!createApp) {
|
|
394
|
+
console.log(` ${dim("Native window unavailable. Set CRAFT_BIN to a craft binary, or open the URL above in a browser.")}
|
|
395
|
+
`);
|
|
396
|
+
await new Promise(() => {});
|
|
397
|
+
}
|
|
398
|
+
const app = createApp({
|
|
399
|
+
url: initialUrl,
|
|
400
|
+
quiet: !verbose,
|
|
401
|
+
...craftBinaryPath && { craftPath: craftBinaryPath },
|
|
402
|
+
window: {
|
|
403
|
+
title: "Stacks Dashboard",
|
|
404
|
+
width: 1400,
|
|
405
|
+
height: 900,
|
|
406
|
+
titlebarHidden: !0,
|
|
407
|
+
webSidebarMaterial: !0,
|
|
408
|
+
webSidebarWidth: 250,
|
|
409
|
+
...appIconPath && { icon: appIconPath }
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
process.on("SIGINT", () => {
|
|
413
|
+
app.close();
|
|
414
|
+
process.exit(0);
|
|
415
|
+
});
|
|
416
|
+
process.on("SIGTERM", () => {
|
|
417
|
+
app.close();
|
|
418
|
+
process.exit(0);
|
|
419
|
+
});
|
|
420
|
+
try {
|
|
421
|
+
await app.show();
|
|
422
|
+
process.exit(0);
|
|
423
|
+
} catch {
|
|
424
|
+
const fallbackUrl = dashboardHttpsUrl || dashboardLocalUrl;
|
|
425
|
+
console.log(` ${dim("Dashboard available at:")} ${cyan(fallbackUrl)}
|
|
426
|
+
`);
|
|
427
|
+
await new Promise(() => {});
|
|
428
|
+
}
|
|
429
|
+
} else {
|
|
430
|
+
console.log(` ${dim("Native window unavailable. Set CRAFT_BIN to a craft binary, or open the URL above in a browser.")}
|
|
431
|
+
`);
|
|
432
|
+
process.on("SIGINT", () => process.exit(0));
|
|
433
|
+
process.on("SIGTERM", () => process.exit(0));
|
|
434
|
+
await new Promise(() => {});
|
|
435
|
+
}
|
package/dist/dev/desktop.js
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
import{
|
|
1
|
+
import { runCommand } from "@stacksjs/cli";
|
|
2
|
+
import { frameworkPath } from "@stacksjs/path";
|
|
3
|
+
await runCommand("bun run dev", {
|
|
4
|
+
cwd: frameworkPath("views/desktop")
|
|
5
|
+
});
|
package/dist/dev/docs.js
CHANGED
|
@@ -1,2 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
import{
|
|
1
|
+
import { overridesReady, config as appConfig, docs } from "@stacksjs/config";
|
|
2
|
+
import { projectPath } from "@stacksjs/path";
|
|
3
|
+
import { startServer } from "@stacksjs/bunpress";
|
|
4
|
+
await overridesReady;
|
|
5
|
+
const port = Number(process.env.PORT_DOCS) || appConfig.ports?.docs || 3006, appUrl = String(process.env.APP_URL || appConfig.app?.url || ""), domain = appUrl.replace(/^https?:\/\//, "").replace(/\/$/, ""), pathMountedDocs = domain && domain !== "localhost" && !domain.includes(":"), devBaseUrl = pathMountedDocs ? `https://${domain}/docs` : void 0, bunPressConfig = {
|
|
6
|
+
verbose: !1,
|
|
7
|
+
docsDir: projectPath("docs"),
|
|
8
|
+
outDir: projectPath("dist/docs"),
|
|
9
|
+
...docs,
|
|
10
|
+
markdown: docs.markdown ?? {},
|
|
11
|
+
...devBaseUrl && {
|
|
12
|
+
sitemap: {
|
|
13
|
+
...docs.sitemap,
|
|
14
|
+
baseUrl: devBaseUrl
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
await startServer({
|
|
19
|
+
port,
|
|
20
|
+
root: projectPath("docs"),
|
|
21
|
+
watch: !0,
|
|
22
|
+
quiet: !0,
|
|
23
|
+
config: bunPressConfig
|
|
24
|
+
});
|
package/dist/dev/index.js
CHANGED
|
@@ -1,2 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
import{
|
|
1
|
+
import { Action } from "@stacksjs/enums";
|
|
2
|
+
import { runAction } from "../helpers";
|
|
3
|
+
export async function runDevServer(options) {
|
|
4
|
+
await runAction(Action.Dev, options);
|
|
5
|
+
}
|
|
6
|
+
export async function runFrontendDevServer(options) {
|
|
7
|
+
await runAction(Action.Dev, options);
|
|
8
|
+
}
|
|
9
|
+
export async function runBackendDevServer(options) {
|
|
10
|
+
await runApiDevServer(options);
|
|
11
|
+
}
|
|
12
|
+
export async function runApiDevServer(options) {
|
|
13
|
+
await runAction(Action.DevApi, options);
|
|
14
|
+
}
|
|
15
|
+
export async function runComponentsDevServer(options) {
|
|
16
|
+
await runAction(Action.DevComponents, options);
|
|
17
|
+
}
|
|
18
|
+
export async function runDashboardDevServer(options) {
|
|
19
|
+
await runAction(Action.DevDashboard, options);
|
|
20
|
+
}
|
|
21
|
+
export async function runSystemTrayDevServer(options) {
|
|
22
|
+
await runAction(Action.DevSystemTray, options);
|
|
23
|
+
}
|
|
24
|
+
export async function runDesktopDevServer(options) {
|
|
25
|
+
await runAction(Action.DevDesktop, options);
|
|
26
|
+
}
|
|
27
|
+
export async function runDocsDevServer(options) {
|
|
28
|
+
await runAction(Action.DevDocs, options);
|
|
29
|
+
}
|
|
@@ -1,2 +1,74 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
import { existsSync, watch } from "node:fs";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { log } from "@stacksjs/logging";
|
|
4
|
+
import { path } from "@stacksjs/path";
|
|
5
|
+
let debounce, running = !1, queued = !1;
|
|
6
|
+
export function startModelMigrationWatcher() {
|
|
7
|
+
if (["0", "false", "off"].includes(String(process.env.STACKS_DEV_AUTO_MIGRATE).toLowerCase()))
|
|
8
|
+
return;
|
|
9
|
+
const dirs = [path.userModelsPath(""), path.storagePath("framework/models")].filter((d) => {
|
|
10
|
+
try {
|
|
11
|
+
return existsSync(d);
|
|
12
|
+
} catch {
|
|
13
|
+
return !1;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
if (dirs.length === 0)
|
|
17
|
+
return;
|
|
18
|
+
const schedule = (filename) => {
|
|
19
|
+
if (filename && !filename.endsWith(".ts"))
|
|
20
|
+
return;
|
|
21
|
+
if (debounce)
|
|
22
|
+
clearTimeout(debounce);
|
|
23
|
+
debounce = setTimeout(() => void reconcile(), 400);
|
|
24
|
+
};
|
|
25
|
+
let watching = 0;
|
|
26
|
+
for (const dir of dirs)
|
|
27
|
+
try {
|
|
28
|
+
watch(dir, { recursive: !0 }, (_event, filename) => schedule(filename));
|
|
29
|
+
watching += 1;
|
|
30
|
+
} catch (err) {
|
|
31
|
+
log.debug(`[dev] model watch failed for ${dir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
32
|
+
}
|
|
33
|
+
if (watching > 0)
|
|
34
|
+
log.debug("[dev] auto-migrate watcher active \u2014 model edits will sync the database");
|
|
35
|
+
}
|
|
36
|
+
async function reconcile() {
|
|
37
|
+
if (running) {
|
|
38
|
+
queued = !0;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
running = !0;
|
|
42
|
+
try {
|
|
43
|
+
const { previewPendingMigrations, generateMigrations, runDatabaseMigration } = await import("@stacksjs/database"), ops = await previewPendingMigrations();
|
|
44
|
+
if (ops.length === 0)
|
|
45
|
+
return;
|
|
46
|
+
const destructive = ops.filter((o) => o.destructive);
|
|
47
|
+
if (destructive.length > 0) {
|
|
48
|
+
log.warn(`[dev] ${destructive.length} destructive schema change${destructive.length === 1 ? "" : "s"} detected \u2014 not auto-applied. Run \`buddy migrate\` to review and apply.`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
log.info(`[dev] Syncing database to models (${ops.length} change${ops.length === 1 ? "" : "s"})...`);
|
|
52
|
+
const gen = await generateMigrations();
|
|
53
|
+
if (gen.isErr) {
|
|
54
|
+
log.error("[dev] auto-migrate: generation failed", gen.error);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const run = await runDatabaseMigration();
|
|
58
|
+
if (run.isErr) {
|
|
59
|
+
log.error("[dev] auto-migrate: apply failed", run.error);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
log.success("[dev] Database is in sync with your models.");
|
|
63
|
+
} catch (err) {
|
|
64
|
+
log.warn(`[dev] auto-migrate skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
65
|
+
} finally {
|
|
66
|
+
running = !1;
|
|
67
|
+
if (queued) {
|
|
68
|
+
queued = !1;
|
|
69
|
+
if (debounce)
|
|
70
|
+
clearTimeout(debounce);
|
|
71
|
+
debounce = setTimeout(() => void reconcile(), 400);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
package/dist/dev/system-tray.js
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
import{
|
|
1
|
+
import { runCommand } from "@stacksjs/cli";
|
|
2
|
+
import { frameworkPath } from "@stacksjs/path";
|
|
3
|
+
await runCommand("bun run dev", {
|
|
4
|
+
cwd: frameworkPath("system-tray")
|
|
5
|
+
});
|