@apex-stack/core 0.1.2 → 0.1.4
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/{chunk-GC3WNE6M.js → chunk-IEXQ7E5C.js} +21 -13
- package/dist/cli.js +255 -25
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -82,6 +82,18 @@ function sanitizeName(name) {
|
|
|
82
82
|
function entryFor(pattern, method, mcpName, route) {
|
|
83
83
|
return { pattern, segments: toSegments(pattern), method, mcpName, route };
|
|
84
84
|
}
|
|
85
|
+
function expandApiModule(name, def) {
|
|
86
|
+
if (!def) return [];
|
|
87
|
+
if (isApexResource(def)) {
|
|
88
|
+
return def.routes.map(
|
|
89
|
+
(r) => entryFor(`/api/${def.name}${r.pathSuffix}`, r.route.method, r.mcpName, r.route)
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
if (typeof def.handler === "function") {
|
|
93
|
+
return [entryFor(`/api/${name}`, def.method, sanitizeName(name), def)];
|
|
94
|
+
}
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
85
97
|
async function loadApiRoutes(root, loadModule) {
|
|
86
98
|
const dir = join(root, "server", "api");
|
|
87
99
|
if (!existsSync(dir)) return [];
|
|
@@ -89,14 +101,7 @@ async function loadApiRoutes(root, loadModule) {
|
|
|
89
101
|
for (const file of readdirSync(dir).filter((f) => /\.(ts|js|mjs)$/.test(f))) {
|
|
90
102
|
const name = file.replace(/\.(ts|js|mjs)$/, "");
|
|
91
103
|
const def = (await loadModule(`/server/api/${file}`)).default;
|
|
92
|
-
|
|
93
|
-
if (isApexResource(def)) {
|
|
94
|
-
for (const r of def.routes) {
|
|
95
|
-
entries.push(entryFor(`/api/${def.name}${r.pathSuffix}`, r.route.method, r.mcpName, r.route));
|
|
96
|
-
}
|
|
97
|
-
} else if (typeof def.handler === "function") {
|
|
98
|
-
entries.push(entryFor(`/api/${name}`, def.method, sanitizeName(name), def));
|
|
99
|
-
}
|
|
104
|
+
entries.push(...expandApiModule(name, def));
|
|
100
105
|
}
|
|
101
106
|
return entries;
|
|
102
107
|
}
|
|
@@ -340,11 +345,9 @@ async function startDevServer(options) {
|
|
|
340
345
|
});
|
|
341
346
|
const app = createApp();
|
|
342
347
|
app.use(fromNodeMiddleware(vite.middlewares));
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
app.use("/mcp", createMcpHandler(apiEntries));
|
|
347
|
-
}
|
|
348
|
+
const loadEntries = () => loadApiRoutes(options.root, (id) => vite.ssrLoadModule(id));
|
|
349
|
+
app.use("/api", defineEventHandler3((event) => loadEntries().then((e) => createApiHandler(e)(event))));
|
|
350
|
+
app.use("/mcp", defineEventHandler3((event) => loadEntries().then((e) => createMcpHandler(e)(event))));
|
|
348
351
|
app.use(
|
|
349
352
|
defineEventHandler3(async (event) => {
|
|
350
353
|
const url = event.path || "/";
|
|
@@ -410,9 +413,14 @@ function notFoundPage(url, routes) {
|
|
|
410
413
|
|
|
411
414
|
export {
|
|
412
415
|
isApexResource,
|
|
416
|
+
expandApiModule,
|
|
417
|
+
createApiHandler,
|
|
418
|
+
hasMcpRoutes,
|
|
419
|
+
createMcpHandler,
|
|
413
420
|
loadComponents,
|
|
414
421
|
renderIslandsPage,
|
|
415
422
|
scanPages,
|
|
423
|
+
matchRoute,
|
|
416
424
|
renderPage,
|
|
417
425
|
startDevServer
|
|
418
426
|
};
|
package/dist/cli.js
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
|
+
createApiHandler,
|
|
3
|
+
createMcpHandler,
|
|
4
|
+
expandApiModule,
|
|
5
|
+
hasMcpRoutes,
|
|
2
6
|
loadComponents,
|
|
7
|
+
matchRoute,
|
|
3
8
|
renderIslandsPage,
|
|
4
9
|
renderPage,
|
|
5
10
|
scanPages,
|
|
6
11
|
startDevServer
|
|
7
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-IEXQ7E5C.js";
|
|
8
13
|
|
|
9
14
|
// src/cli.ts
|
|
10
|
-
import { resolve as
|
|
11
|
-
import { defineCommand as
|
|
15
|
+
import { resolve as resolve5 } from "path";
|
|
16
|
+
import { defineCommand as defineCommand6, runMain } from "citty";
|
|
12
17
|
|
|
13
18
|
// src/commands/build.ts
|
|
14
|
-
import { cpSync, existsSync, mkdirSync, rmSync, writeFileSync } from "fs";
|
|
15
|
-
import { dirname, join as
|
|
16
|
-
import { apex as
|
|
19
|
+
import { cpSync, existsSync as existsSync2, mkdirSync, readdirSync as readdirSync2, rmSync, writeFileSync } from "fs";
|
|
20
|
+
import { dirname, join as join3, resolve } from "path";
|
|
21
|
+
import { apex as apex3 } from "@apex-stack/vite";
|
|
17
22
|
import { defineCommand } from "citty";
|
|
18
23
|
import { createServer as createViteServer } from "vite";
|
|
19
24
|
|
|
@@ -69,6 +74,65 @@ async function buildClient(root, routes, outDir) {
|
|
|
69
74
|
return hrefs;
|
|
70
75
|
}
|
|
71
76
|
|
|
77
|
+
// src/build/buildServer.ts
|
|
78
|
+
import { existsSync, readdirSync } from "fs";
|
|
79
|
+
import { isAbsolute, join as join2 } from "path";
|
|
80
|
+
import { apex as apex2 } from "@apex-stack/vite";
|
|
81
|
+
import { build as build2 } from "vite";
|
|
82
|
+
async function buildServer(root, routes, outDir) {
|
|
83
|
+
const ids = routes.map((r) => r.pageId);
|
|
84
|
+
const compDir = join2(root, "components");
|
|
85
|
+
if (existsSync(compDir)) {
|
|
86
|
+
for (const f of readdirSync(compDir).filter((f2) => f2.endsWith(".alpine"))) {
|
|
87
|
+
ids.push(`/components/${f}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const apiDir = join2(root, "server", "api");
|
|
91
|
+
if (existsSync(apiDir)) {
|
|
92
|
+
for (const f of readdirSync(apiDir).filter((f2) => /\.(ts|js|mjs)$/.test(f2))) {
|
|
93
|
+
ids.push(`/server/api/${f}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const input = {};
|
|
97
|
+
for (const id of ids) input[entryName2(id)] = join2(root, id.slice(1));
|
|
98
|
+
const result = await build2({
|
|
99
|
+
root,
|
|
100
|
+
logLevel: "warn",
|
|
101
|
+
plugins: [apex2({ clientRuntime: "@apex-stack/core/client" })],
|
|
102
|
+
build: {
|
|
103
|
+
ssr: true,
|
|
104
|
+
target: "esnext",
|
|
105
|
+
// Node target — allow top-level await in server modules
|
|
106
|
+
outDir: join2(outDir, "server"),
|
|
107
|
+
emptyOutDir: false,
|
|
108
|
+
rollupOptions: {
|
|
109
|
+
input,
|
|
110
|
+
// Externalize every package import (bare specifier) — deps are resolved at
|
|
111
|
+
// runtime from node_modules. Only the app's own relative/absolute files are
|
|
112
|
+
// bundled. This keeps native/workspace deps (@libsql/client, drizzle, …) out.
|
|
113
|
+
external: (id) => !id.startsWith(".") && !isAbsolute(id),
|
|
114
|
+
output: { format: "esm", entryFileNames: "[name].mjs" }
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
const byFacade = /* @__PURE__ */ new Map();
|
|
119
|
+
for (const chunk of result.output) {
|
|
120
|
+
if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
|
|
121
|
+
byFacade.set(chunk.facadeModuleId, chunk.fileName);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const modules = {};
|
|
125
|
+
for (const id of ids) {
|
|
126
|
+
const abs = join2(root, id.slice(1));
|
|
127
|
+
const file = byFacade.get(abs);
|
|
128
|
+
if (file) modules[id] = file;
|
|
129
|
+
}
|
|
130
|
+
return { modules };
|
|
131
|
+
}
|
|
132
|
+
function entryName2(id) {
|
|
133
|
+
return id.replace(/^\//, "").replace(/\.(alpine|ts|js|mjs)$/, "").replace(/[^a-zA-Z0-9]+/g, "_");
|
|
134
|
+
}
|
|
135
|
+
|
|
72
136
|
// src/commands/build.ts
|
|
73
137
|
function outFile(pattern) {
|
|
74
138
|
const clean = pattern.replace(/^\//, "");
|
|
@@ -79,7 +143,8 @@ var buildCommand = defineCommand({
|
|
|
79
143
|
args: {
|
|
80
144
|
root: { type: "positional", required: false, description: "Project root", default: "." },
|
|
81
145
|
outDir: { type: "string", description: "Output directory", default: "dist" },
|
|
82
|
-
islands: { type: "boolean", description: "Static-first islands mode (zero-JS static)", default: false }
|
|
146
|
+
islands: { type: "boolean", description: "Static-first islands mode (zero-JS static)", default: false },
|
|
147
|
+
server: { type: "boolean", description: "Build a Node server (dynamic routes + API/MCP)", default: false }
|
|
83
148
|
},
|
|
84
149
|
async run({ args }) {
|
|
85
150
|
const root = resolve(process.cwd(), args.root);
|
|
@@ -88,12 +153,15 @@ var buildCommand = defineCommand({
|
|
|
88
153
|
const routes = scanPages(root);
|
|
89
154
|
const staticRoutes = routes.filter((r) => !r.isDynamic);
|
|
90
155
|
const dynamic = routes.filter((r) => r.isDynamic);
|
|
156
|
+
if (args.server) {
|
|
157
|
+
return buildServerTarget(root, outDir, args.outDir, routes);
|
|
158
|
+
}
|
|
91
159
|
const hrefs = args.islands ? /* @__PURE__ */ new Map() : await buildClient(root, staticRoutes, outDir);
|
|
92
160
|
const vite = await createViteServer({
|
|
93
161
|
root,
|
|
94
162
|
appType: "custom",
|
|
95
163
|
server: { middlewareMode: true },
|
|
96
|
-
plugins: [
|
|
164
|
+
plugins: [apex3({ clientRuntime: "@apex-stack/core/client" })]
|
|
97
165
|
});
|
|
98
166
|
try {
|
|
99
167
|
const { registry, css: componentCss } = await loadComponents(
|
|
@@ -109,13 +177,13 @@ var buildCommand = defineCommand({
|
|
|
109
177
|
componentCss
|
|
110
178
|
};
|
|
111
179
|
const html = args.islands ? await renderIslandsPage(common) : await renderPage({ ...common, clientHref: hrefs.get(route.pageId) });
|
|
112
|
-
const dest =
|
|
180
|
+
const dest = join3(outDir, outFile(route.pattern));
|
|
113
181
|
mkdirSync(dirname(dest), { recursive: true });
|
|
114
182
|
writeFileSync(dest, html);
|
|
115
183
|
console.log(` \u2713 ${route.pattern} \u2192 ${outFile(route.pattern)}`);
|
|
116
184
|
}
|
|
117
|
-
const pub =
|
|
118
|
-
if (
|
|
185
|
+
const pub = join3(root, "public");
|
|
186
|
+
if (existsSync2(pub)) cpSync(pub, outDir, { recursive: true });
|
|
119
187
|
console.log(
|
|
120
188
|
`
|
|
121
189
|
Built ${staticRoutes.length} page(s) \u2192 ${args.outDir}/` + (args.islands ? " (islands / static-first)" : " (prerendered + hydrated)")
|
|
@@ -131,10 +199,49 @@ var buildCommand = defineCommand({
|
|
|
131
199
|
}
|
|
132
200
|
}
|
|
133
201
|
});
|
|
202
|
+
async function buildServerTarget(root, outDir, outLabel, routes) {
|
|
203
|
+
const clientHrefs = await buildClient(root, routes, outDir);
|
|
204
|
+
const server = await buildServer(root, routes, outDir);
|
|
205
|
+
const components = {};
|
|
206
|
+
const compDir = join3(root, "components");
|
|
207
|
+
if (existsSync2(compDir)) {
|
|
208
|
+
for (const f of readdirSync2(compDir).filter((f2) => f2.endsWith(".alpine"))) {
|
|
209
|
+
const sf = server.modules[`/components/${f}`];
|
|
210
|
+
if (sf) components[f.replace(/\.alpine$/, "")] = sf;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const api = [];
|
|
214
|
+
const apiDir = join3(root, "server", "api");
|
|
215
|
+
if (existsSync2(apiDir)) {
|
|
216
|
+
for (const f of readdirSync2(apiDir).filter((f2) => /\.(ts|js|mjs)$/.test(f2))) {
|
|
217
|
+
const sf = server.modules[`/server/api/${f}`];
|
|
218
|
+
if (sf) api.push({ name: f.replace(/\.(ts|js|mjs)$/, ""), serverFile: sf });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const manifest = {
|
|
222
|
+
islands: false,
|
|
223
|
+
routes: routes.map((r) => ({
|
|
224
|
+
...r,
|
|
225
|
+
serverFile: server.modules[r.pageId],
|
|
226
|
+
clientHref: clientHrefs.get(r.pageId)
|
|
227
|
+
})),
|
|
228
|
+
components,
|
|
229
|
+
api
|
|
230
|
+
};
|
|
231
|
+
writeFileSync(join3(outDir, "apex-manifest.json"), JSON.stringify(manifest, null, 2));
|
|
232
|
+
const pub = join3(root, "public");
|
|
233
|
+
if (existsSync2(pub)) cpSync(pub, outDir, { recursive: true });
|
|
234
|
+
console.log(
|
|
235
|
+
`
|
|
236
|
+
Built server target \u2192 ${outLabel}/ (${routes.length} route(s), ${api.length} API module(s))
|
|
237
|
+
Run it: apex start
|
|
238
|
+
`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
134
241
|
|
|
135
242
|
// src/commands/make.ts
|
|
136
|
-
import { existsSync as
|
|
137
|
-
import { dirname as dirname2, join as
|
|
243
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
244
|
+
import { dirname as dirname2, join as join4, resolve as resolve2 } from "path";
|
|
138
245
|
import { defineCommand as defineCommand2 } from "citty";
|
|
139
246
|
function pageTemplate(name) {
|
|
140
247
|
return `<script server lang="ts">
|
|
@@ -181,11 +288,11 @@ export default defineApexRoute({
|
|
|
181
288
|
function plan(kind, name, root) {
|
|
182
289
|
switch (kind) {
|
|
183
290
|
case "page":
|
|
184
|
-
return { path:
|
|
291
|
+
return { path: join4(root, "pages", `${name}.alpine`), contents: pageTemplate(name) };
|
|
185
292
|
case "component":
|
|
186
|
-
return { path:
|
|
293
|
+
return { path: join4(root, "components", `${name}.alpine`), contents: componentTemplate() };
|
|
187
294
|
case "api":
|
|
188
|
-
return { path:
|
|
295
|
+
return { path: join4(root, "server", "api", `${name}.ts`), contents: apiTemplate(name) };
|
|
189
296
|
}
|
|
190
297
|
}
|
|
191
298
|
var makeCommand = defineCommand2({
|
|
@@ -205,7 +312,7 @@ var makeCommand = defineCommand2({
|
|
|
205
312
|
}
|
|
206
313
|
const root = resolve2(process.cwd(), args.root);
|
|
207
314
|
const { path, contents } = plan(kind, args.name, root);
|
|
208
|
-
if (
|
|
315
|
+
if (existsSync3(path)) {
|
|
209
316
|
console.error(`
|
|
210
317
|
\u2717 Already exists: ${path}
|
|
211
318
|
`);
|
|
@@ -275,13 +382,15 @@ var mcpCommand = defineCommand3({
|
|
|
275
382
|
|
|
276
383
|
// src/commands/migrate.ts
|
|
277
384
|
import { createRequire } from "module";
|
|
278
|
-
import { join as
|
|
385
|
+
import { join as join5, resolve as resolve3 } from "path";
|
|
279
386
|
import { pathToFileURL } from "url";
|
|
280
387
|
import { defineCommand as defineCommand4 } from "citty";
|
|
281
388
|
var migrateCommand = defineCommand4({
|
|
282
389
|
meta: { name: "migrate", description: "Apply pending SQL migrations (db/migrations/*.sql)" },
|
|
283
390
|
args: {
|
|
284
|
-
db: { type: "string", description: "SQLite file path", default: "data.db" },
|
|
391
|
+
db: { type: "string", description: "SQLite file path (libSQL)", default: "data.db" },
|
|
392
|
+
driver: { type: "string", description: "sqlite | postgres | pglite", default: "sqlite" },
|
|
393
|
+
url: { type: "string", description: "Connection URL (postgres) \u2014 overrides --db" },
|
|
285
394
|
dir: { type: "string", description: "Migrations directory", default: "db/migrations" },
|
|
286
395
|
root: { type: "string", description: "Project root", default: "." }
|
|
287
396
|
},
|
|
@@ -289,14 +398,16 @@ var migrateCommand = defineCommand4({
|
|
|
289
398
|
const root = resolve3(process.cwd(), args.root);
|
|
290
399
|
let data;
|
|
291
400
|
try {
|
|
292
|
-
const require2 = createRequire(
|
|
401
|
+
const require2 = createRequire(join5(root, "package.json"));
|
|
293
402
|
data = await import(pathToFileURL(require2.resolve("@apex-stack/data")).href);
|
|
294
403
|
} catch {
|
|
295
404
|
console.error("\n @apex-stack/data is not installed in this project. Run: npm i @apex-stack/data\n");
|
|
296
405
|
process.exit(1);
|
|
297
406
|
}
|
|
298
|
-
const {
|
|
299
|
-
const
|
|
407
|
+
const config = args.driver === "postgres" ? { driver: "postgres", url: args.url } : args.driver === "pglite" ? { driver: "pglite", dir: args.url } : resolve3(root, args.db);
|
|
408
|
+
const handle = await data.createDb(config);
|
|
409
|
+
const applied = await data.applyMigrations(handle, resolve3(root, args.dir));
|
|
410
|
+
await handle.close();
|
|
300
411
|
console.log(
|
|
301
412
|
applied.length ? `
|
|
302
413
|
\u2713 Applied ${applied.length} migration(s): ${applied.join(", ")}
|
|
@@ -305,8 +416,126 @@ var migrateCommand = defineCommand4({
|
|
|
305
416
|
}
|
|
306
417
|
});
|
|
307
418
|
|
|
419
|
+
// src/commands/start.ts
|
|
420
|
+
import { existsSync as existsSync5 } from "fs";
|
|
421
|
+
import { join as join7, resolve as resolve4 } from "path";
|
|
422
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
423
|
+
|
|
424
|
+
// src/prod/server.ts
|
|
425
|
+
import { createServer as createHttpServer } from "http";
|
|
426
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, statSync } from "fs";
|
|
427
|
+
import { join as join6 } from "path";
|
|
428
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
429
|
+
import {
|
|
430
|
+
createApp,
|
|
431
|
+
defineEventHandler,
|
|
432
|
+
getRequestURL,
|
|
433
|
+
setResponseHeader,
|
|
434
|
+
setResponseStatus,
|
|
435
|
+
toNodeListener
|
|
436
|
+
} from "h3";
|
|
437
|
+
var MIME = {
|
|
438
|
+
".js": "text/javascript",
|
|
439
|
+
".mjs": "text/javascript",
|
|
440
|
+
".css": "text/css",
|
|
441
|
+
".html": "text/html",
|
|
442
|
+
".json": "application/json",
|
|
443
|
+
".svg": "image/svg+xml",
|
|
444
|
+
".png": "image/png",
|
|
445
|
+
".jpg": "image/jpeg",
|
|
446
|
+
".ico": "image/x-icon",
|
|
447
|
+
".woff2": "font/woff2"
|
|
448
|
+
};
|
|
449
|
+
async function startProdServer(options) {
|
|
450
|
+
const dir = options.dir;
|
|
451
|
+
const port = options.port ?? 3e3;
|
|
452
|
+
const manifest = JSON.parse(readFileSync2(join6(dir, "apex-manifest.json"), "utf8"));
|
|
453
|
+
const importServer = (relFile) => import(pathToFileURL2(join6(dir, "server", relFile)).href);
|
|
454
|
+
const registry = {};
|
|
455
|
+
let componentCss = "";
|
|
456
|
+
for (const [name, file] of Object.entries(manifest.components)) {
|
|
457
|
+
const mod = await importServer(file);
|
|
458
|
+
registry[name] = { template: mod.template, rootXData: mod.rootXData, scopeId: mod.scopeId };
|
|
459
|
+
if (mod.css) componentCss += `${mod.css}
|
|
460
|
+
`;
|
|
461
|
+
}
|
|
462
|
+
const apiEntries = [];
|
|
463
|
+
for (const { name, serverFile } of manifest.api) {
|
|
464
|
+
const mod = await importServer(serverFile);
|
|
465
|
+
apiEntries.push(...expandApiModule(name, mod.default));
|
|
466
|
+
}
|
|
467
|
+
const serverFileFor = new Map(manifest.routes.map((r) => [r.pageId, r.serverFile]));
|
|
468
|
+
const loadModule = (id) => importServer(serverFileFor.get(id));
|
|
469
|
+
const app = createApp();
|
|
470
|
+
app.use(
|
|
471
|
+
defineEventHandler((event) => {
|
|
472
|
+
if (event.method !== "GET") return;
|
|
473
|
+
const path = decodeURIComponent(getRequestURL(event).pathname);
|
|
474
|
+
if (path === "/" || path.startsWith("/api") || path === "/mcp") return;
|
|
475
|
+
const file = join6(dir, path);
|
|
476
|
+
if (!file.startsWith(dir) || !existsSync4(file) || !statSync(file).isFile()) return;
|
|
477
|
+
const ext = path.slice(path.lastIndexOf("."));
|
|
478
|
+
setResponseHeader(event, "Content-Type", MIME[ext] ?? "application/octet-stream");
|
|
479
|
+
if (path.startsWith("/assets/")) setResponseHeader(event, "Cache-Control", "public, max-age=31536000, immutable");
|
|
480
|
+
return readFileSync2(file);
|
|
481
|
+
})
|
|
482
|
+
);
|
|
483
|
+
if (apiEntries.length) app.use("/api", createApiHandler(apiEntries));
|
|
484
|
+
if (hasMcpRoutes(apiEntries)) app.use("/mcp", createMcpHandler(apiEntries));
|
|
485
|
+
app.use(
|
|
486
|
+
defineEventHandler(async (event) => {
|
|
487
|
+
const url = getRequestURL(event).pathname;
|
|
488
|
+
const matched = matchRoute(manifest.routes, url);
|
|
489
|
+
if (!matched) {
|
|
490
|
+
setResponseStatus(event, 404);
|
|
491
|
+
setResponseHeader(event, "Content-Type", "text/html");
|
|
492
|
+
return `<!DOCTYPE html><h1>404 \u2014 ${url}</h1>`;
|
|
493
|
+
}
|
|
494
|
+
const route = manifest.routes.find((r) => r.pageId === matched.pageId);
|
|
495
|
+
const render = manifest.islands ? renderIslandsPage : renderPage;
|
|
496
|
+
const html = await render({
|
|
497
|
+
loadModule,
|
|
498
|
+
pageId: matched.pageId,
|
|
499
|
+
params: matched.params,
|
|
500
|
+
url,
|
|
501
|
+
registry,
|
|
502
|
+
componentCss,
|
|
503
|
+
clientHref: route?.clientHref
|
|
504
|
+
});
|
|
505
|
+
setResponseHeader(event, "Content-Type", "text/html");
|
|
506
|
+
return html;
|
|
507
|
+
})
|
|
508
|
+
);
|
|
509
|
+
const server = createHttpServer(toNodeListener(app));
|
|
510
|
+
await new Promise((resolve6) => server.listen(port, resolve6));
|
|
511
|
+
return { server, port };
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// src/commands/start.ts
|
|
515
|
+
var startCommand = defineCommand5({
|
|
516
|
+
meta: { name: "start", description: "Run a production build (from `apex build --server`)" },
|
|
517
|
+
args: {
|
|
518
|
+
dir: { type: "positional", required: false, description: "Build directory", default: "dist" },
|
|
519
|
+
port: { type: "string", description: "Port to listen on", default: "3000" }
|
|
520
|
+
},
|
|
521
|
+
async run({ args }) {
|
|
522
|
+
const dir = resolve4(process.cwd(), args.dir);
|
|
523
|
+
if (!existsSync5(join7(dir, "apex-manifest.json"))) {
|
|
524
|
+
console.error(`
|
|
525
|
+
No build found in ${args.dir}/. Run \`apex build --server\` first.
|
|
526
|
+
`);
|
|
527
|
+
process.exit(1);
|
|
528
|
+
}
|
|
529
|
+
const { port } = await startProdServer({ dir, port: Number(args.port) });
|
|
530
|
+
console.log(`
|
|
531
|
+
\x1B[36mApex JS\x1B[0m production server
|
|
532
|
+
\u2192 http://localhost:${port}
|
|
533
|
+
`);
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
|
|
308
537
|
// src/cli.ts
|
|
309
|
-
var dev =
|
|
538
|
+
var dev = defineCommand6({
|
|
310
539
|
meta: { name: "dev", description: "Start the Apex JS development server" },
|
|
311
540
|
args: {
|
|
312
541
|
root: { type: "positional", required: false, description: "Project root", default: "." },
|
|
@@ -314,7 +543,7 @@ var dev = defineCommand5({
|
|
|
314
543
|
islands: { type: "boolean", description: "Render in islands mode (static-first)", default: false }
|
|
315
544
|
},
|
|
316
545
|
async run({ args }) {
|
|
317
|
-
const root =
|
|
546
|
+
const root = resolve5(process.cwd(), args.root);
|
|
318
547
|
const port = Number(args.port);
|
|
319
548
|
const { port: actual } = await startDevServer({ root, port, islands: args.islands });
|
|
320
549
|
console.log(`
|
|
@@ -323,7 +552,7 @@ var dev = defineCommand5({
|
|
|
323
552
|
`);
|
|
324
553
|
}
|
|
325
554
|
});
|
|
326
|
-
var main =
|
|
555
|
+
var main = defineCommand6({
|
|
327
556
|
meta: {
|
|
328
557
|
name: "apex",
|
|
329
558
|
description: "The full-stack meta-framework for Alpine.js"
|
|
@@ -331,6 +560,7 @@ var main = defineCommand5({
|
|
|
331
560
|
subCommands: {
|
|
332
561
|
dev,
|
|
333
562
|
build: buildCommand,
|
|
563
|
+
start: startCommand,
|
|
334
564
|
make: makeCommand,
|
|
335
565
|
migrate: migrateCommand,
|
|
336
566
|
mcp: mcpCommand
|
package/dist/index.js
CHANGED