@apex-stack/core 0.1.11 → 0.1.13

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.
@@ -1,6 +1,15 @@
1
1
  // src/ui.ts
2
+ import { readFileSync } from "fs";
3
+ import { fileURLToPath } from "url";
2
4
  var TTY = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR && process.env.TERM !== "dumb";
3
5
  var RESET = "\x1B[0m";
6
+ var VERSION = (() => {
7
+ try {
8
+ return JSON.parse(readFileSync(fileURLToPath(new URL("../package.json", import.meta.url)), "utf8")).version || "";
9
+ } catch {
10
+ return "";
11
+ }
12
+ })();
4
13
  function truecolor(r, g, b, s) {
5
14
  return TTY ? `\x1B[38;2;${r};${g};${b}m${s}${RESET}` : s;
6
15
  }
@@ -40,9 +49,10 @@ function banner(subtitle = "The full-stack, AI-native meta-framework for Alpine.
40
49
  }
41
50
  return out + RESET;
42
51
  });
52
+ const ver = VERSION ? `${color.cyan(`v${VERSION}`)} ${color.gray("\xB7")} ` : "";
43
53
  return `
44
54
  ${rows.join("\n")}
45
- ${color.gray(subtitle)}
55
+ ${ver}${color.gray(subtitle)}
46
56
  `;
47
57
  }
48
58
  var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
@@ -86,6 +96,7 @@ function ready(rows) {
86
96
  }
87
97
 
88
98
  export {
99
+ VERSION,
89
100
  color,
90
101
  banner,
91
102
  spinner,
@@ -0,0 +1,239 @@
1
+ import {
2
+ loadComponents
3
+ } from "./chunk-4VG3CZ6H.js";
4
+ import {
5
+ createApiHandler,
6
+ createMcpHandler,
7
+ loadApiRoutes
8
+ } from "./chunk-DSUIB3JH.js";
9
+ import {
10
+ matchRoute,
11
+ renderIslandsPage,
12
+ renderPage,
13
+ scanPages
14
+ } from "./chunk-PAMD24NK.js";
15
+
16
+ // src/dev/server.ts
17
+ import { createServer as createHttpServer } from "http";
18
+ import { createRequire } from "module";
19
+ import { join } from "path";
20
+ import { fileURLToPath } from "url";
21
+ import { apex } from "@apex-stack/vite";
22
+ import {
23
+ createApp,
24
+ defineEventHandler,
25
+ fromNodeMiddleware,
26
+ setResponseHeader,
27
+ setResponseStatus,
28
+ toNodeListener
29
+ } from "h3";
30
+ import { createServer as createViteServer } from "vite";
31
+
32
+ // src/dev/errorPage.ts
33
+ import { existsSync, readFileSync } from "fs";
34
+ function esc(s) {
35
+ return s.replace(/[&<>"]/g, (c) => c === "&" ? "&amp;" : c === "<" ? "&lt;" : c === ">" ? "&gt;" : "&quot;");
36
+ }
37
+ function firstFileFrame(stack, root) {
38
+ const re = /(?:file:\/\/\/?)?((?:[A-Za-z]:[\\/]|\/)[^\s():]+):(\d+):(\d+)/g;
39
+ let m;
40
+ const frames = [];
41
+ while (m = re.exec(stack)) {
42
+ let file = m[1];
43
+ if (/^[A-Za-z]:[\\/]/.test(file) === false && !file.startsWith("/")) continue;
44
+ file = file.replace(/\//g, process.platform === "win32" ? "\\" : "/");
45
+ if (existsSync(file) && !file.includes("node_modules")) {
46
+ frames.push({ file, line: Number(m[2]), col: Number(m[3]) });
47
+ }
48
+ }
49
+ return frames.find((f) => f.file.startsWith(root)) ?? frames[0];
50
+ }
51
+ function codeFrame(frame) {
52
+ let lines;
53
+ try {
54
+ lines = readFileSync(frame.file, "utf8").split("\n");
55
+ } catch {
56
+ return "";
57
+ }
58
+ const start = Math.max(0, frame.line - 4);
59
+ const end = Math.min(lines.length, frame.line + 3);
60
+ const rows = [];
61
+ for (let i = start; i < end; i++) {
62
+ const n = i + 1;
63
+ const active = n === frame.line;
64
+ const num = String(n).padStart(4, " ");
65
+ rows.push(
66
+ `<div class="cf-row${active ? " active" : ""}"><span class="cf-num">${num}</span><span class="cf-code">${esc(lines[i] || "")}</span></div>`
67
+ );
68
+ }
69
+ return `<div class="frame"><div class="frame-file">${esc(frame.file)}<span class="frame-pos">:${frame.line}:${frame.col}</span></div><pre class="cf">${rows.join("")}</pre></div>`;
70
+ }
71
+ var SHELL_CSS = `
72
+ :root{color-scheme:dark light}
73
+ *{box-sizing:border-box}
74
+ body{margin:0;min-height:100vh;background:#0a0e1a;color:#f4f7ff;
75
+ font:15px/1.6 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
76
+ display:flex;align-items:flex-start;justify-content:center;padding:clamp(1.5rem,6vh,5rem) 1.25rem}
77
+ @media(prefers-color-scheme:light){body{background:#f4f7ff;color:#0a0e1a}}
78
+ .wrap{width:100%;max-width:860px}
79
+ .brand{display:flex;align-items:center;gap:.55rem;font-weight:600;letter-spacing:-.01em;margin-bottom:1.6rem}
80
+ .mark{width:20px;height:20px}
81
+ .pill{font-size:.8rem;font-weight:600;padding:.15rem .6rem;border-radius:999px;margin-left:.4rem}
82
+ .pill.err{color:#fb7185;background:rgba(244,63,94,.12);border:1px solid rgba(244,63,94,.35)}
83
+ .pill.nf{color:#818cf8;background:rgba(129,140,248,.12);border:1px solid rgba(129,140,248,.35)}
84
+ .kind{font:600 .95rem/1 ui-monospace,SFMono-Regular,Menlo,monospace;color:#fb7185;margin:0 0 .5rem}
85
+ .kind.nf{color:#818cf8}
86
+ h1{font-size:clamp(1.4rem,3.2vw,2rem);line-height:1.2;letter-spacing:-.02em;margin:0 0 .7rem;word-break:break-word}
87
+ .sub{color:#9aa6c4;margin:0 0 1.8rem}
88
+ .sub code{background:rgba(130,140,200,.14);border-radius:.35rem;padding:.05rem .35rem;font-size:.9em}
89
+ .frame{border:1px solid rgba(130,140,200,.18);border-radius:12px;overflow:hidden;margin:0 0 1.4rem;background:#11172b}
90
+ @media(prefers-color-scheme:light){.frame{background:#fff}}
91
+ .frame-file{font:.8rem/1 ui-monospace,SFMono-Regular,Menlo,monospace;color:#9aa6c4;padding:.7rem .9rem;border-bottom:1px solid rgba(130,140,200,.18);overflow-x:auto;white-space:nowrap}
92
+ .frame-pos{color:#fb7185}
93
+ .cf{margin:0;padding:.6rem 0;overflow-x:auto;font:.82rem/1.7 ui-monospace,SFMono-Regular,Menlo,monospace}
94
+ .cf-row{display:flex;padding:0 .9rem;white-space:pre}
95
+ .cf-row.active{background:rgba(244,63,94,.12);box-shadow:inset 3px 0 0 #f43f5e}
96
+ .cf-num{color:#5b6890;-webkit-user-select:none;user-select:none;padding-right:1.1rem;text-align:right}
97
+ .cf-row.active .cf-num{color:#fb7185}
98
+ .cf-code{color:#f4f7ff}
99
+ @media(prefers-color-scheme:light){.cf-code{color:#0a0e1a}}
100
+ details{border:1px solid rgba(130,140,200,.18);border-radius:12px;background:#11172b;overflow:hidden}
101
+ @media(prefers-color-scheme:light){details{background:#fff}}
102
+ summary{cursor:pointer;padding:.7rem .9rem;font-size:.85rem;color:#9aa6c4;user-select:none}
103
+ summary:hover{color:#f4f7ff}
104
+ @media(prefers-color-scheme:light){summary:hover{color:#0a0e1a}}
105
+ .stack{margin:0;padding:0 .9rem 1rem;font:.78rem/1.7 ui-monospace,SFMono-Regular,Menlo,monospace;color:#9aa6c4;overflow-x:auto;white-space:pre-wrap;word-break:break-word}
106
+ .routes{list-style:none;padding:0;margin:0 0 1.4rem;display:flex;flex-wrap:wrap;gap:.5rem}
107
+ .routes li{font:.85rem/1 ui-monospace,SFMono-Regular,Menlo,monospace;color:#818cf8;background:rgba(129,140,248,.1);border:1px solid rgba(129,140,248,.25);border-radius:.45rem;padding:.35rem .6rem}
108
+ .foot{margin-top:1.8rem;color:#5b6890;font-size:.82rem}
109
+ `;
110
+ var MARK = `<svg class="mark" viewBox="0 0 64 64" aria-hidden="true"><defs><linearGradient id="g" x1="0" y1="1" x2="1" y2="0"><stop offset="0" stop-color="#22d3ee"/><stop offset="1" stop-color="#6366f1"/></linearGradient></defs><path d="M32 7 L32 35 L20 56 L4 56 Z" fill="url(#g)"/><path d="M32 7 L60 56 L44 56 L32 35 Z" fill="#6366f1"/></svg>`;
111
+ function page(title, bodyInner) {
112
+ return `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>${esc(title)}</title><style>${SHELL_CSS}</style></head><body><div class="wrap">${bodyInner}</div></body></html>`;
113
+ }
114
+ function renderErrorPage(error, opts) {
115
+ const kind = error.name || "Error";
116
+ const message = error.message || String(error);
117
+ const stack = error.stack || "";
118
+ const frame = stack ? firstFileFrame(stack, opts.root) : void 0;
119
+ const frameHtml = frame ? codeFrame(frame) : "";
120
+ const body = `
121
+ <div class="brand">${MARK} Apex JS <span class="pill err">Dev error</span></div>
122
+ <p class="kind">${esc(kind)}</p>
123
+ <h1>${esc(message)}</h1>
124
+ <p class="sub">While rendering <code>${esc(opts.url)}</code></p>
125
+ ${frameHtml}
126
+ <details${frameHtml ? "" : " open"}><summary>Stack trace</summary><pre class="stack">${esc(stack)}</pre></details>
127
+ <p class="foot">Fix the error and save \u2014 this page reloads automatically.</p>`;
128
+ return page(`${kind} \u2014 Apex JS`, body);
129
+ }
130
+ function renderNotFoundPage(url, routes) {
131
+ const list = routes.length ? routes.map((r) => `<li>${esc(r.pattern)}</li>`).join("") : "<li>no pages yet \u2014 add pages/index.alpine</li>";
132
+ const body = `
133
+ <div class="brand">${MARK} Apex JS <span class="pill nf">404</span></div>
134
+ <p class="kind nf">404 \u2014 Not found</p>
135
+ <h1>No route matches <code>${esc(url)}</code></h1>
136
+ <p class="sub">These routes are available:</p>
137
+ <ul class="routes">${list}</ul>
138
+ <p class="foot">Add a file under <code>pages/</code> to create a new route.</p>`;
139
+ return page("404 \u2014 Apex JS", body);
140
+ }
141
+
142
+ // src/dev/server.ts
143
+ async function startDevServer(options) {
144
+ const port = options.port ?? 3e3;
145
+ const pageId = options.pageId ?? "/pages/index.alpine";
146
+ const req = createRequire(import.meta.url);
147
+ const tryResolve = (spec) => {
148
+ try {
149
+ return req.resolve(spec);
150
+ } catch {
151
+ return void 0;
152
+ }
153
+ };
154
+ const alpine = tryResolve("alpinejs");
155
+ const kit = tryResolve("@apex-stack/kit");
156
+ const coreClient = fileURLToPath(new URL("./client.js", import.meta.url));
157
+ const alias = { "@apex-stack/core/client": coreClient };
158
+ if (alpine) alias.alpinejs = alpine;
159
+ if (kit) alias["@apex-stack/kit"] = kit;
160
+ const vite = await createViteServer({
161
+ root: options.root,
162
+ appType: "custom",
163
+ // Derive the HMR port from the dev port so multiple `apex dev` instances
164
+ // don't all fight over Vite's default 24678.
165
+ server: { middlewareMode: true, fs: { strict: false }, hmr: { port: port + 1 } },
166
+ resolve: { alias },
167
+ // User apps depend on `@apex-stack/core`, so the client module imports the runtime
168
+ // from `@apex-stack/core/client` (a re-export) rather than the internal kit package.
169
+ plugins: [apex({ clientRuntime: "@apex-stack/core/client" })],
170
+ optimizeDeps: { include: ["alpinejs"] }
171
+ });
172
+ const ssrLoad = (id) => {
173
+ const resolved = id[0] === "/" && !id.startsWith(options.root) ? join(options.root, id).replace(/\\/g, "/") : id;
174
+ return vite.ssrLoadModule(resolved);
175
+ };
176
+ const app = createApp();
177
+ app.use(fromNodeMiddleware(vite.middlewares));
178
+ const loadEntries = () => loadApiRoutes(options.root, (id) => ssrLoad(id));
179
+ app.use("/api", defineEventHandler((event) => loadEntries().then((e) => createApiHandler(e)(event))));
180
+ app.use("/mcp", defineEventHandler((event) => loadEntries().then((e) => createMcpHandler(e)(event))));
181
+ app.use(
182
+ defineEventHandler(async (event) => {
183
+ const url = event.path || "/";
184
+ try {
185
+ const routes = scanPages(options.root);
186
+ const matched = routes.length ? matchRoute(routes, url) : { pageId, params: {} };
187
+ if (!matched) {
188
+ setResponseStatus(event, 404);
189
+ setResponseHeader(event, "Content-Type", "text/html");
190
+ return await vite.transformIndexHtml(url, renderNotFoundPage(url, routes));
191
+ }
192
+ const { registry, css: componentCss } = await loadComponents(
193
+ options.root,
194
+ (id) => ssrLoad(id)
195
+ );
196
+ const render = options.islands ? renderIslandsPage : renderPage;
197
+ const html = await render({
198
+ loadModule: (id) => ssrLoad(id),
199
+ pageId: matched.pageId,
200
+ params: matched.params,
201
+ url,
202
+ registry,
203
+ componentCss,
204
+ transformHtml: (u, doc) => vite.transformIndexHtml(u, doc)
205
+ });
206
+ setResponseHeader(event, "Content-Type", "text/html");
207
+ return html;
208
+ } catch (err) {
209
+ const error = err;
210
+ vite.ssrFixStacktrace(error);
211
+ setResponseStatus(event, 500);
212
+ setResponseHeader(event, "Content-Type", "text/html");
213
+ const html = renderErrorPage(error, { url, root: options.root });
214
+ try {
215
+ return await vite.transformIndexHtml(url, html);
216
+ } catch {
217
+ return html;
218
+ }
219
+ }
220
+ })
221
+ );
222
+ const server = createHttpServer(toNodeListener(app));
223
+ await new Promise((resolve) => server.listen(port, resolve));
224
+ return {
225
+ vite,
226
+ server,
227
+ port,
228
+ close: async () => {
229
+ await vite.close();
230
+ await new Promise(
231
+ (resolve, reject) => server.close((e) => e ? reject(e) : resolve())
232
+ );
233
+ }
234
+ };
235
+ }
236
+
237
+ export {
238
+ startDevServer
239
+ };
package/dist/cli.js CHANGED
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ VERSION,
3
4
  banner,
4
5
  color,
5
6
  spinner
6
- } from "./chunk-2L2T47AH.js";
7
+ } from "./chunk-7E5ZQ6UH.js";
7
8
 
8
9
  // src/cli.ts
9
10
  import { defineCommand as defineCommand2, runMain } from "citty";
@@ -103,11 +104,12 @@ var COMMANDS = [
103
104
  var main = defineCommand2({
104
105
  meta: {
105
106
  name: "apex",
107
+ version: VERSION,
106
108
  description: "The full-stack meta-framework for Alpine.js"
107
109
  },
108
110
  subCommands: {
109
111
  new: newCommand,
110
- dev: () => import("./dev-HDRJEPPN.js").then((m) => m.devCommand),
112
+ dev: () => import("./dev-BIPK7O5N.js").then((m) => m.devCommand),
111
113
  build: () => import("./build-QRHQUUZC.js").then((m) => m.buildCommand),
112
114
  start: () => import("./start-VJJXI4W3.js").then((m) => m.startCommand),
113
115
  make: () => import("./make-4LINTKZH.js").then((m) => m.makeCommand),
@@ -2,7 +2,7 @@ import {
2
2
  banner,
3
3
  ready,
4
4
  spinner
5
- } from "./chunk-2L2T47AH.js";
5
+ } from "./chunk-7E5ZQ6UH.js";
6
6
 
7
7
  // src/commands/dev.ts
8
8
  import { resolve } from "path";
@@ -20,7 +20,7 @@ var devCommand = defineCommand({
20
20
  process.stdout.write(banner());
21
21
  const sp = spinner(`Starting dev server${args.islands ? " (islands mode)" : ""}\u2026`);
22
22
  try {
23
- const { startDevServer } = await import("./server-VOIXBL4I.js");
23
+ const { startDevServer } = await import("./server-ODH3M2IG.js");
24
24
  const { port: actual } = await startDevServer({ root, port, islands: Boolean(args.islands) });
25
25
  sp.succeed("Dev server ready");
26
26
  ready([
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startDevServer
3
- } from "./chunk-QZTDKUXK.js";
3
+ } from "./chunk-SH3XEJGV.js";
4
4
  import "./chunk-4VG3CZ6H.js";
5
5
  import {
6
6
  isApexResource
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startDevServer
3
- } from "./chunk-QZTDKUXK.js";
3
+ } from "./chunk-SH3XEJGV.js";
4
4
  import "./chunk-4VG3CZ6H.js";
5
5
  import "./chunk-DSUIB3JH.js";
6
6
  import "./chunk-PAMD24NK.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apex-stack/core",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "The full-stack meta-framework for Alpine.js — CLI and runtime",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,127 +0,0 @@
1
- import {
2
- loadComponents
3
- } from "./chunk-4VG3CZ6H.js";
4
- import {
5
- createApiHandler,
6
- createMcpHandler,
7
- loadApiRoutes
8
- } from "./chunk-DSUIB3JH.js";
9
- import {
10
- matchRoute,
11
- renderIslandsPage,
12
- renderPage,
13
- scanPages
14
- } from "./chunk-PAMD24NK.js";
15
-
16
- // src/dev/server.ts
17
- import { createServer as createHttpServer } from "http";
18
- import { createRequire } from "module";
19
- import { fileURLToPath } from "url";
20
- import { apex } from "@apex-stack/vite";
21
- import {
22
- createApp,
23
- defineEventHandler,
24
- fromNodeMiddleware,
25
- setResponseHeader,
26
- setResponseStatus,
27
- toNodeListener
28
- } from "h3";
29
- import { createServer as createViteServer } from "vite";
30
- async function startDevServer(options) {
31
- const port = options.port ?? 3e3;
32
- const pageId = options.pageId ?? "/pages/index.alpine";
33
- const req = createRequire(import.meta.url);
34
- const tryResolve = (spec) => {
35
- try {
36
- return req.resolve(spec);
37
- } catch {
38
- return void 0;
39
- }
40
- };
41
- const alpine = tryResolve("alpinejs");
42
- const kit = tryResolve("@apex-stack/kit");
43
- const coreClient = fileURLToPath(new URL("./client.js", import.meta.url));
44
- const alias = { "@apex-stack/core/client": coreClient };
45
- if (alpine) alias.alpinejs = alpine;
46
- if (kit) alias["@apex-stack/kit"] = kit;
47
- const vite = await createViteServer({
48
- root: options.root,
49
- appType: "custom",
50
- server: { middlewareMode: true, fs: { strict: false } },
51
- resolve: { alias },
52
- // User apps depend on `@apex-stack/core`, so the client module imports the runtime
53
- // from `@apex-stack/core/client` (a re-export) rather than the internal kit package.
54
- plugins: [apex({ clientRuntime: "@apex-stack/core/client" })],
55
- optimizeDeps: { include: ["alpinejs"] }
56
- });
57
- const app = createApp();
58
- app.use(fromNodeMiddleware(vite.middlewares));
59
- const loadEntries = () => loadApiRoutes(options.root, (id) => vite.ssrLoadModule(id));
60
- app.use("/api", defineEventHandler((event) => loadEntries().then((e) => createApiHandler(e)(event))));
61
- app.use("/mcp", defineEventHandler((event) => loadEntries().then((e) => createMcpHandler(e)(event))));
62
- app.use(
63
- defineEventHandler(async (event) => {
64
- const url = event.path || "/";
65
- try {
66
- const routes = scanPages(options.root);
67
- const matched = routes.length ? matchRoute(routes, url) : { pageId, params: {} };
68
- if (!matched) {
69
- setResponseStatus(event, 404);
70
- setResponseHeader(event, "Content-Type", "text/html");
71
- return notFoundPage(url, routes);
72
- }
73
- const { registry, css: componentCss } = await loadComponents(
74
- options.root,
75
- (id) => vite.ssrLoadModule(id)
76
- );
77
- const render = options.islands ? renderIslandsPage : renderPage;
78
- const html = await render({
79
- loadModule: (id) => vite.ssrLoadModule(id),
80
- pageId: matched.pageId,
81
- params: matched.params,
82
- url,
83
- registry,
84
- componentCss,
85
- transformHtml: (u, doc) => vite.transformIndexHtml(u, doc)
86
- });
87
- setResponseHeader(event, "Content-Type", "text/html");
88
- return html;
89
- } catch (err) {
90
- const error = err;
91
- vite.ssrFixStacktrace(error);
92
- setResponseStatus(event, 500);
93
- setResponseHeader(event, "Content-Type", "text/html");
94
- return `<pre>${escapeHtml(error.stack ?? error.message)}</pre>`;
95
- }
96
- })
97
- );
98
- const server = createHttpServer(toNodeListener(app));
99
- await new Promise((resolve) => server.listen(port, resolve));
100
- return {
101
- vite,
102
- server,
103
- port,
104
- close: async () => {
105
- await vite.close();
106
- await new Promise(
107
- (resolve, reject) => server.close((e) => e ? reject(e) : resolve())
108
- );
109
- }
110
- };
111
- }
112
- function escapeHtml(s) {
113
- return s.replace(/[&<>]/g, (c) => c === "&" ? "&amp;" : c === "<" ? "&lt;" : "&gt;");
114
- }
115
- function notFoundPage(url, routes) {
116
- const list = routes.map((r) => `<li><code>${escapeHtml(r.pattern)}</code></li>`).join("");
117
- return `<!DOCTYPE html><html><head><title>404 \u2014 Apex JS</title></head>
118
- <body style="font-family: system-ui, sans-serif; max-width: 40rem; margin: 3rem auto;">
119
- <h1>404 \u2014 no route for <code>${escapeHtml(url)}</code></h1>
120
- <p>Available routes:</p>
121
- <ul>${list || "<li>(no pages found \u2014 add <code>pages/index.alpine</code>)</li>"}</ul>
122
- </body></html>`;
123
- }
124
-
125
- export {
126
- startDevServer
127
- };