@raystack/chronicle 0.1.0-canary.c5d277e → 0.1.0-canary.cb102e9
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/cli/index.js +481 -42
- package/package.json +1 -1
- package/src/cli/commands/build.ts +30 -2
- package/src/components/ui/search.tsx +10 -6
- package/src/server/adapters/vercel.ts +133 -0
- package/src/server/build-search-index.ts +107 -0
- package/src/server/dev.ts +5 -3
- package/src/server/entry-prod.ts +21 -50
- package/src/server/entry-vercel.ts +28 -0
- package/src/server/handlers/apis-proxy.ts +5 -0
- package/src/server/handlers/search.ts +46 -14
- package/src/server/request-handler.ts +64 -0
- package/src/server/utils/safe-path.ts +14 -0
- package/src/server/vite-config.ts +1 -1
- package/src/themes/default/Page.module.css +8 -4
package/dist/cli/index.js
CHANGED
|
@@ -55,7 +55,7 @@ async function createViteConfig(options) {
|
|
|
55
55
|
remarkDirective
|
|
56
56
|
],
|
|
57
57
|
rehypePlugins: [
|
|
58
|
-
[rehypeShiki, { themes: { light: "github-light", dark: "github-dark" } }]
|
|
58
|
+
[rehypeShiki, { themes: { light: "github-light", dark: "github-dark" }, defaultColor: false }]
|
|
59
59
|
],
|
|
60
60
|
mdExtensions: [".md"],
|
|
61
61
|
mdxExtensions: [".mdx"]
|
|
@@ -85,6 +85,18 @@ async function createViteConfig(options) {
|
|
|
85
85
|
}
|
|
86
86
|
var init_vite_config = () => {};
|
|
87
87
|
|
|
88
|
+
// src/server/utils/safe-path.ts
|
|
89
|
+
import path6 from "path";
|
|
90
|
+
function safePath(baseDir, urlPath) {
|
|
91
|
+
const decoded = decodeURIComponent(urlPath.split("?")[0]);
|
|
92
|
+
const resolved = path6.resolve(baseDir, "." + decoded);
|
|
93
|
+
if (!resolved.startsWith(path6.resolve(baseDir) + path6.sep) && resolved !== path6.resolve(baseDir)) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
return resolved;
|
|
97
|
+
}
|
|
98
|
+
var init_safe_path = () => {};
|
|
99
|
+
|
|
88
100
|
// src/server/dev.ts
|
|
89
101
|
var exports_dev = {};
|
|
90
102
|
__export(exports_dev, {
|
|
@@ -94,7 +106,7 @@ import { createServer as createViteServer } from "vite";
|
|
|
94
106
|
import { createServer } from "http";
|
|
95
107
|
import fsPromises from "fs/promises";
|
|
96
108
|
import { createReadStream } from "fs";
|
|
97
|
-
import
|
|
109
|
+
import path7 from "path";
|
|
98
110
|
import chalk3 from "chalk";
|
|
99
111
|
async function startDevServer(options) {
|
|
100
112
|
const { port, root, contentDir } = options;
|
|
@@ -104,7 +116,7 @@ async function startDevServer(options) {
|
|
|
104
116
|
server: { middlewareMode: true },
|
|
105
117
|
appType: "custom"
|
|
106
118
|
});
|
|
107
|
-
const templatePath =
|
|
119
|
+
const templatePath = path7.resolve(root, "src/server/index.html");
|
|
108
120
|
const server = createServer(async (req, res) => {
|
|
109
121
|
const url = req.url || "/";
|
|
110
122
|
try {
|
|
@@ -115,12 +127,12 @@ async function startDevServer(options) {
|
|
|
115
127
|
});
|
|
116
128
|
return;
|
|
117
129
|
}
|
|
118
|
-
const contentFile =
|
|
119
|
-
if (!url.endsWith(".md") && !url.endsWith(".mdx")) {
|
|
130
|
+
const contentFile = safePath(contentDir, url);
|
|
131
|
+
if (contentFile && !url.endsWith(".md") && !url.endsWith(".mdx")) {
|
|
120
132
|
try {
|
|
121
133
|
const stat = await fsPromises.stat(contentFile);
|
|
122
134
|
if (stat.isFile()) {
|
|
123
|
-
const ext =
|
|
135
|
+
const ext = path7.extname(contentFile).toLowerCase();
|
|
124
136
|
const mimeTypes = {
|
|
125
137
|
".png": "image/png",
|
|
126
138
|
".jpg": "image/jpeg",
|
|
@@ -148,7 +160,7 @@ async function startDevServer(options) {
|
|
|
148
160
|
});
|
|
149
161
|
return;
|
|
150
162
|
}
|
|
151
|
-
const { matchRoute } = await vite.ssrLoadModule(
|
|
163
|
+
const { matchRoute } = await vite.ssrLoadModule(path7.resolve(root, "src/server/router.ts"));
|
|
152
164
|
const routeHandler = matchRoute(new URL(url, `http://localhost:${port}`).href);
|
|
153
165
|
if (routeHandler) {
|
|
154
166
|
const request = new Request(new URL(url, `http://localhost:${port}`));
|
|
@@ -161,11 +173,11 @@ async function startDevServer(options) {
|
|
|
161
173
|
}
|
|
162
174
|
const pathname = new URL(url, `http://localhost:${port}`).pathname;
|
|
163
175
|
const slug = pathname === "/" ? [] : pathname.slice(1).split("/").filter(Boolean);
|
|
164
|
-
const source = await vite.ssrLoadModule(
|
|
165
|
-
const { mdxComponents } = await vite.ssrLoadModule(
|
|
166
|
-
const { loadConfig } = await vite.ssrLoadModule(
|
|
176
|
+
const source = await vite.ssrLoadModule(path7.resolve(root, "src/lib/source.ts"));
|
|
177
|
+
const { mdxComponents } = await vite.ssrLoadModule(path7.resolve(root, "src/components/mdx/index.tsx"));
|
|
178
|
+
const { loadConfig } = await vite.ssrLoadModule(path7.resolve(root, "src/lib/config.ts"));
|
|
167
179
|
const config = loadConfig();
|
|
168
|
-
const { loadApiSpecs } = await vite.ssrLoadModule(
|
|
180
|
+
const { loadApiSpecs } = await vite.ssrLoadModule(path7.resolve(root, "src/lib/openapi.ts"));
|
|
169
181
|
const apiSpecs = config.api?.length ? loadApiSpecs(config.api) : [];
|
|
170
182
|
const [tree, sourcePage] = await Promise.all([
|
|
171
183
|
source.buildPageTree(),
|
|
@@ -187,9 +199,10 @@ async function startDevServer(options) {
|
|
|
187
199
|
}
|
|
188
200
|
let template = await fsPromises.readFile(templatePath, "utf-8");
|
|
189
201
|
template = await vite.transformIndexHtml(url, template);
|
|
190
|
-
const
|
|
202
|
+
const safeJson = JSON.stringify(embeddedData).replace(/</g, "\\u003c");
|
|
203
|
+
const dataScript = `<script>window.__PAGE_DATA__ = ${safeJson}</script>`;
|
|
191
204
|
template = template.replace("<!--head-outlet-->", `<!--head-outlet-->${dataScript}`);
|
|
192
|
-
const { render } = await vite.ssrLoadModule(
|
|
205
|
+
const { render } = await vite.ssrLoadModule(path7.resolve(root, "src/server/entry-server.tsx"));
|
|
193
206
|
const html = render(url, { config, tree, page: pageData, apiSpecs });
|
|
194
207
|
const finalHtml = template.replace("<!--ssr-outlet-->", html);
|
|
195
208
|
res.setHeader("Content-Type", "text/html");
|
|
@@ -219,6 +232,413 @@ async function startDevServer(options) {
|
|
|
219
232
|
}
|
|
220
233
|
var init_dev = __esm(() => {
|
|
221
234
|
init_vite_config();
|
|
235
|
+
init_safe_path();
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// src/lib/config.ts
|
|
239
|
+
import fs3 from "fs";
|
|
240
|
+
import path8 from "path";
|
|
241
|
+
import { parse as parse2 } from "yaml";
|
|
242
|
+
function resolveConfigPath() {
|
|
243
|
+
const projectRoot = process.env.CHRONICLE_PROJECT_ROOT;
|
|
244
|
+
if (projectRoot) {
|
|
245
|
+
const rootPath = path8.join(projectRoot, CONFIG_FILE);
|
|
246
|
+
if (fs3.existsSync(rootPath))
|
|
247
|
+
return rootPath;
|
|
248
|
+
}
|
|
249
|
+
const cwdPath = path8.join(process.cwd(), CONFIG_FILE);
|
|
250
|
+
if (fs3.existsSync(cwdPath))
|
|
251
|
+
return cwdPath;
|
|
252
|
+
const contentDir = process.env.CHRONICLE_CONTENT_DIR;
|
|
253
|
+
if (contentDir) {
|
|
254
|
+
const contentPath = path8.join(contentDir, CONFIG_FILE);
|
|
255
|
+
if (fs3.existsSync(contentPath))
|
|
256
|
+
return contentPath;
|
|
257
|
+
}
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
function loadConfig() {
|
|
261
|
+
const configPath = resolveConfigPath();
|
|
262
|
+
if (!configPath) {
|
|
263
|
+
return defaultConfig;
|
|
264
|
+
}
|
|
265
|
+
const raw = fs3.readFileSync(configPath, "utf-8");
|
|
266
|
+
const userConfig = parse2(raw);
|
|
267
|
+
return {
|
|
268
|
+
...defaultConfig,
|
|
269
|
+
...userConfig,
|
|
270
|
+
theme: {
|
|
271
|
+
name: userConfig.theme?.name ?? defaultConfig.theme.name,
|
|
272
|
+
colors: { ...defaultConfig.theme?.colors, ...userConfig.theme?.colors }
|
|
273
|
+
},
|
|
274
|
+
search: { ...defaultConfig.search, ...userConfig.search },
|
|
275
|
+
footer: userConfig.footer,
|
|
276
|
+
api: userConfig.api,
|
|
277
|
+
llms: { enabled: false, ...userConfig.llms },
|
|
278
|
+
analytics: { enabled: false, ...userConfig.analytics }
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
var CONFIG_FILE = "chronicle.yaml", defaultConfig;
|
|
282
|
+
var init_config = __esm(() => {
|
|
283
|
+
defaultConfig = {
|
|
284
|
+
title: "Documentation",
|
|
285
|
+
theme: { name: "default" },
|
|
286
|
+
search: { enabled: true, placeholder: "Search..." }
|
|
287
|
+
};
|
|
288
|
+
});
|
|
289
|
+
// src/lib/openapi.ts
|
|
290
|
+
import fs4 from "fs";
|
|
291
|
+
import path9 from "path";
|
|
292
|
+
import { parse as parseYaml } from "yaml";
|
|
293
|
+
function loadApiSpecs(apiConfigs) {
|
|
294
|
+
const contentDir = process.env.CHRONICLE_CONTENT_DIR ?? process.cwd();
|
|
295
|
+
return apiConfigs.map((config) => loadApiSpec(config, contentDir));
|
|
296
|
+
}
|
|
297
|
+
function loadApiSpec(config, contentDir) {
|
|
298
|
+
const specPath = path9.resolve(contentDir, config.spec);
|
|
299
|
+
const raw = fs4.readFileSync(specPath, "utf-8");
|
|
300
|
+
const isYaml = specPath.endsWith(".yaml") || specPath.endsWith(".yml");
|
|
301
|
+
const doc = isYaml ? parseYaml(raw) : JSON.parse(raw);
|
|
302
|
+
let v3Doc;
|
|
303
|
+
if ("swagger" in doc && doc.swagger === "2.0") {
|
|
304
|
+
v3Doc = convertV2toV3(doc);
|
|
305
|
+
} else if ("openapi" in doc && doc.openapi.startsWith("3.")) {
|
|
306
|
+
v3Doc = resolveDocument(doc);
|
|
307
|
+
} else {
|
|
308
|
+
throw new Error(`Unsupported spec version in ${config.spec}`);
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
name: config.name,
|
|
312
|
+
basePath: config.basePath,
|
|
313
|
+
server: config.server,
|
|
314
|
+
auth: config.auth,
|
|
315
|
+
document: v3Doc
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
function resolveRef(ref, root) {
|
|
319
|
+
const parts = ref.replace(/^#\//, "").split("/");
|
|
320
|
+
let current = root;
|
|
321
|
+
for (const part of parts) {
|
|
322
|
+
if (current && typeof current === "object" && !Array.isArray(current)) {
|
|
323
|
+
current = current[part];
|
|
324
|
+
} else {
|
|
325
|
+
throw new Error(`Cannot resolve $ref: ${ref}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return current;
|
|
329
|
+
}
|
|
330
|
+
function deepResolveRefs(obj, root, stack = new Set, cache = new Map) {
|
|
331
|
+
if (obj === null || obj === undefined || typeof obj !== "object")
|
|
332
|
+
return obj;
|
|
333
|
+
if (Array.isArray(obj)) {
|
|
334
|
+
return obj.map((item) => deepResolveRefs(item, root, stack, cache));
|
|
335
|
+
}
|
|
336
|
+
const record = obj;
|
|
337
|
+
if (typeof record.$ref === "string") {
|
|
338
|
+
const ref = record.$ref;
|
|
339
|
+
if (cache.has(ref))
|
|
340
|
+
return cache.get(ref);
|
|
341
|
+
if (stack.has(ref))
|
|
342
|
+
return { type: "object", description: "[circular]" };
|
|
343
|
+
stack.add(ref);
|
|
344
|
+
const resolved = deepResolveRefs(resolveRef(ref, root), root, stack, cache);
|
|
345
|
+
stack.delete(ref);
|
|
346
|
+
cache.set(ref, resolved);
|
|
347
|
+
return resolved;
|
|
348
|
+
}
|
|
349
|
+
const result = {};
|
|
350
|
+
for (const [key, value] of Object.entries(record)) {
|
|
351
|
+
result[key] = deepResolveRefs(value, root, stack, cache);
|
|
352
|
+
}
|
|
353
|
+
return result;
|
|
354
|
+
}
|
|
355
|
+
function resolveDocument(doc) {
|
|
356
|
+
const root = doc;
|
|
357
|
+
return deepResolveRefs(doc, root);
|
|
358
|
+
}
|
|
359
|
+
function convertV2toV3(doc) {
|
|
360
|
+
const root = doc;
|
|
361
|
+
const resolved = deepResolveRefs(doc, root);
|
|
362
|
+
const v3Paths = {};
|
|
363
|
+
for (const [pathStr, pathItem] of Object.entries(resolved.paths ?? {})) {
|
|
364
|
+
if (!pathItem)
|
|
365
|
+
continue;
|
|
366
|
+
const v3PathItem = {};
|
|
367
|
+
for (const method of ["get", "post", "put", "delete", "patch"]) {
|
|
368
|
+
const op = pathItem[method];
|
|
369
|
+
if (!op)
|
|
370
|
+
continue;
|
|
371
|
+
v3PathItem[method] = convertV2Operation(op);
|
|
372
|
+
}
|
|
373
|
+
v3Paths[pathStr] = v3PathItem;
|
|
374
|
+
}
|
|
375
|
+
return {
|
|
376
|
+
openapi: "3.0.0",
|
|
377
|
+
info: resolved.info,
|
|
378
|
+
paths: v3Paths,
|
|
379
|
+
tags: resolved.tags ?? []
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
function convertV2Operation(op) {
|
|
383
|
+
const params = op.parameters ?? [];
|
|
384
|
+
const v3Params = params.filter((p) => p.in !== "body").map((p) => ({
|
|
385
|
+
name: p.name,
|
|
386
|
+
in: p.in,
|
|
387
|
+
required: p.required ?? false,
|
|
388
|
+
description: p.description,
|
|
389
|
+
schema: { type: p.type ?? "string", format: p.format }
|
|
390
|
+
}));
|
|
391
|
+
const bodyParam = params.find((p) => p.in === "body");
|
|
392
|
+
let requestBody;
|
|
393
|
+
if (bodyParam?.schema) {
|
|
394
|
+
requestBody = {
|
|
395
|
+
required: bodyParam.required ?? false,
|
|
396
|
+
content: {
|
|
397
|
+
"application/json": {
|
|
398
|
+
schema: bodyParam.schema
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
const v3Responses = {};
|
|
404
|
+
for (const [status, resp] of Object.entries(op.responses ?? {})) {
|
|
405
|
+
const v2Resp = resp;
|
|
406
|
+
const v3Resp = {
|
|
407
|
+
description: v2Resp.description ?? ""
|
|
408
|
+
};
|
|
409
|
+
if (v2Resp.schema) {
|
|
410
|
+
v3Resp.content = {
|
|
411
|
+
"application/json": {
|
|
412
|
+
schema: v2Resp.schema
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
v3Responses[status] = v3Resp;
|
|
417
|
+
}
|
|
418
|
+
const result = {
|
|
419
|
+
operationId: op.operationId,
|
|
420
|
+
summary: op.summary,
|
|
421
|
+
description: op.description,
|
|
422
|
+
tags: op.tags,
|
|
423
|
+
parameters: v3Params,
|
|
424
|
+
responses: v3Responses
|
|
425
|
+
};
|
|
426
|
+
if (requestBody) {
|
|
427
|
+
result.requestBody = requestBody;
|
|
428
|
+
}
|
|
429
|
+
return result;
|
|
430
|
+
}
|
|
431
|
+
var init_openapi = () => {};
|
|
432
|
+
|
|
433
|
+
// src/lib/api-routes.ts
|
|
434
|
+
import slugify from "slugify";
|
|
435
|
+
function getSpecSlug(spec) {
|
|
436
|
+
return slugify(spec.name, { lower: true, strict: true });
|
|
437
|
+
}
|
|
438
|
+
var init_api_routes = () => {};
|
|
439
|
+
|
|
440
|
+
// src/server/build-search-index.ts
|
|
441
|
+
var exports_build_search_index = {};
|
|
442
|
+
__export(exports_build_search_index, {
|
|
443
|
+
generateSearchIndex: () => generateSearchIndex
|
|
444
|
+
});
|
|
445
|
+
import fs5 from "fs/promises";
|
|
446
|
+
import path10 from "path";
|
|
447
|
+
import matter from "gray-matter";
|
|
448
|
+
function extractHeadings(markdown) {
|
|
449
|
+
const headingRegex = /^#{1,6}\s+(.+)$/gm;
|
|
450
|
+
const headings = [];
|
|
451
|
+
let match;
|
|
452
|
+
while ((match = headingRegex.exec(markdown)) !== null) {
|
|
453
|
+
headings.push(match[1].trim());
|
|
454
|
+
}
|
|
455
|
+
return headings.join(" ");
|
|
456
|
+
}
|
|
457
|
+
async function scanContent(contentDir) {
|
|
458
|
+
const docs = [];
|
|
459
|
+
async function scan(dir, prefix = []) {
|
|
460
|
+
let entries;
|
|
461
|
+
try {
|
|
462
|
+
entries = await fs5.readdir(dir, { withFileTypes: true });
|
|
463
|
+
} catch {
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
for (const entry of entries) {
|
|
467
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules")
|
|
468
|
+
continue;
|
|
469
|
+
const fullPath = path10.join(dir, entry.name);
|
|
470
|
+
if (entry.isDirectory()) {
|
|
471
|
+
await scan(fullPath, [...prefix, entry.name]);
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
if (!entry.name.endsWith(".mdx") && !entry.name.endsWith(".md"))
|
|
475
|
+
continue;
|
|
476
|
+
const raw = await fs5.readFile(fullPath, "utf-8");
|
|
477
|
+
const { data: fm, content } = matter(raw);
|
|
478
|
+
const baseName = entry.name.replace(/\.(mdx|md)$/, "");
|
|
479
|
+
const slugs = baseName === "index" ? prefix : [...prefix, baseName];
|
|
480
|
+
const url = slugs.length === 0 ? "/" : "/" + slugs.join("/");
|
|
481
|
+
docs.push({
|
|
482
|
+
id: url,
|
|
483
|
+
url,
|
|
484
|
+
title: fm.title ?? baseName,
|
|
485
|
+
content: extractHeadings(content),
|
|
486
|
+
type: "page"
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
await scan(contentDir);
|
|
491
|
+
return docs;
|
|
492
|
+
}
|
|
493
|
+
function buildApiDocs() {
|
|
494
|
+
const config = loadConfig();
|
|
495
|
+
if (!config.api?.length)
|
|
496
|
+
return [];
|
|
497
|
+
const docs = [];
|
|
498
|
+
const specs = loadApiSpecs(config.api);
|
|
499
|
+
for (const spec of specs) {
|
|
500
|
+
const specSlug = getSpecSlug(spec);
|
|
501
|
+
const paths = spec.document.paths ?? {};
|
|
502
|
+
for (const [, pathItem] of Object.entries(paths)) {
|
|
503
|
+
if (!pathItem)
|
|
504
|
+
continue;
|
|
505
|
+
for (const method of ["get", "post", "put", "delete", "patch"]) {
|
|
506
|
+
const op = pathItem[method];
|
|
507
|
+
if (!op?.operationId)
|
|
508
|
+
continue;
|
|
509
|
+
const url = `/apis/${specSlug}/${encodeURIComponent(op.operationId)}`;
|
|
510
|
+
docs.push({
|
|
511
|
+
id: url,
|
|
512
|
+
url,
|
|
513
|
+
title: `${method.toUpperCase()} ${op.summary ?? op.operationId}`,
|
|
514
|
+
content: op.description ?? "",
|
|
515
|
+
type: "api"
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return docs;
|
|
521
|
+
}
|
|
522
|
+
async function generateSearchIndex(contentDir, outDir) {
|
|
523
|
+
const [contentDocs, apiDocs] = await Promise.all([
|
|
524
|
+
scanContent(contentDir),
|
|
525
|
+
Promise.resolve(buildApiDocs())
|
|
526
|
+
]);
|
|
527
|
+
const documents = [...contentDocs, ...apiDocs];
|
|
528
|
+
const outPath = path10.join(outDir, "search-index.json");
|
|
529
|
+
await fs5.writeFile(outPath, JSON.stringify(documents));
|
|
530
|
+
return documents.length;
|
|
531
|
+
}
|
|
532
|
+
var init_build_search_index = __esm(() => {
|
|
533
|
+
init_config();
|
|
534
|
+
init_openapi();
|
|
535
|
+
init_api_routes();
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
// src/server/adapters/vercel.ts
|
|
539
|
+
var exports_vercel = {};
|
|
540
|
+
__export(exports_vercel, {
|
|
541
|
+
buildVercelOutput: () => buildVercelOutput
|
|
542
|
+
});
|
|
543
|
+
import path11 from "path";
|
|
544
|
+
import fs6 from "fs/promises";
|
|
545
|
+
import { existsSync } from "fs";
|
|
546
|
+
import chalk5 from "chalk";
|
|
547
|
+
async function buildVercelOutput(options) {
|
|
548
|
+
const { distDir, contentDir, projectRoot } = options;
|
|
549
|
+
const outputDir = path11.resolve(projectRoot, ".vercel/output");
|
|
550
|
+
console.log(chalk5.gray("Generating Vercel output..."));
|
|
551
|
+
await fs6.rm(outputDir, { recursive: true, force: true });
|
|
552
|
+
const staticDir = path11.resolve(outputDir, "static");
|
|
553
|
+
const funcDir = path11.resolve(outputDir, "functions/index.func");
|
|
554
|
+
await fs6.mkdir(staticDir, { recursive: true });
|
|
555
|
+
await fs6.mkdir(funcDir, { recursive: true });
|
|
556
|
+
const clientDir = path11.resolve(distDir, "client");
|
|
557
|
+
await copyDir(clientDir, staticDir);
|
|
558
|
+
console.log(chalk5.gray(" Copied client assets to static/"));
|
|
559
|
+
if (existsSync(contentDir)) {
|
|
560
|
+
await copyContentAssets(contentDir, staticDir);
|
|
561
|
+
console.log(chalk5.gray(" Copied content assets to static/"));
|
|
562
|
+
}
|
|
563
|
+
const serverDir = path11.resolve(distDir, "server");
|
|
564
|
+
await copyDir(serverDir, funcDir);
|
|
565
|
+
console.log(chalk5.gray(" Copied server bundle to functions/"));
|
|
566
|
+
const templateSrc = path11.resolve(clientDir, "src/server/index.html");
|
|
567
|
+
await fs6.copyFile(templateSrc, path11.resolve(funcDir, "index.html"));
|
|
568
|
+
await fs6.writeFile(path11.resolve(funcDir, "package.json"), JSON.stringify({ type: "module" }, null, 2));
|
|
569
|
+
await fs6.writeFile(path11.resolve(funcDir, ".vc-config.json"), JSON.stringify({
|
|
570
|
+
runtime: "nodejs24.x",
|
|
571
|
+
handler: "entry-vercel.js",
|
|
572
|
+
launcherType: "Nodejs"
|
|
573
|
+
}, null, 2));
|
|
574
|
+
await fs6.writeFile(path11.resolve(outputDir, "config.json"), JSON.stringify({
|
|
575
|
+
version: 3,
|
|
576
|
+
routes: [
|
|
577
|
+
{ handle: "filesystem" },
|
|
578
|
+
{ src: "/(.*)", dest: "/index" }
|
|
579
|
+
]
|
|
580
|
+
}, null, 2));
|
|
581
|
+
console.log(chalk5.green("Vercel output generated →"), outputDir);
|
|
582
|
+
}
|
|
583
|
+
async function copyDir(src, dest) {
|
|
584
|
+
await fs6.mkdir(dest, { recursive: true });
|
|
585
|
+
const entries = await fs6.readdir(src, { withFileTypes: true });
|
|
586
|
+
for (const entry of entries) {
|
|
587
|
+
const srcPath = path11.join(src, entry.name);
|
|
588
|
+
const destPath = path11.join(dest, entry.name);
|
|
589
|
+
if (entry.isDirectory()) {
|
|
590
|
+
await copyDir(srcPath, destPath);
|
|
591
|
+
} else {
|
|
592
|
+
await fs6.copyFile(srcPath, destPath);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
async function copyContentAssets(contentDir, staticDir) {
|
|
597
|
+
const entries = await fs6.readdir(contentDir, { withFileTypes: true });
|
|
598
|
+
for (const entry of entries) {
|
|
599
|
+
const srcPath = path11.join(contentDir, entry.name);
|
|
600
|
+
if (entry.isDirectory()) {
|
|
601
|
+
const destSubDir = path11.join(staticDir, entry.name);
|
|
602
|
+
await copyContentAssetsRecursive(srcPath, destSubDir);
|
|
603
|
+
} else {
|
|
604
|
+
const ext = path11.extname(entry.name).toLowerCase();
|
|
605
|
+
if (CONTENT_EXTENSIONS.has(ext)) {
|
|
606
|
+
await fs6.copyFile(srcPath, path11.join(staticDir, entry.name));
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
async function copyContentAssetsRecursive(srcDir, destDir) {
|
|
612
|
+
const entries = await fs6.readdir(srcDir, { withFileTypes: true });
|
|
613
|
+
for (const entry of entries) {
|
|
614
|
+
const srcPath = path11.join(srcDir, entry.name);
|
|
615
|
+
if (entry.isDirectory()) {
|
|
616
|
+
await copyContentAssetsRecursive(srcPath, path11.join(destDir, entry.name));
|
|
617
|
+
} else {
|
|
618
|
+
const ext = path11.extname(entry.name).toLowerCase();
|
|
619
|
+
if (CONTENT_EXTENSIONS.has(ext)) {
|
|
620
|
+
await fs6.mkdir(destDir, { recursive: true });
|
|
621
|
+
await fs6.copyFile(srcPath, path11.join(destDir, entry.name));
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
var CONTENT_EXTENSIONS;
|
|
627
|
+
var init_vercel = __esm(() => {
|
|
628
|
+
CONTENT_EXTENSIONS = new Set([
|
|
629
|
+
".png",
|
|
630
|
+
".jpg",
|
|
631
|
+
".jpeg",
|
|
632
|
+
".gif",
|
|
633
|
+
".svg",
|
|
634
|
+
".webp",
|
|
635
|
+
".ico",
|
|
636
|
+
".pdf",
|
|
637
|
+
".json",
|
|
638
|
+
".yaml",
|
|
639
|
+
".yml",
|
|
640
|
+
".txt"
|
|
641
|
+
]);
|
|
222
642
|
});
|
|
223
643
|
|
|
224
644
|
// src/server/prod.ts
|
|
@@ -226,13 +646,13 @@ var exports_prod = {};
|
|
|
226
646
|
__export(exports_prod, {
|
|
227
647
|
startProdServer: () => startProdServer
|
|
228
648
|
});
|
|
229
|
-
import
|
|
230
|
-
import
|
|
649
|
+
import path13 from "path";
|
|
650
|
+
import chalk7 from "chalk";
|
|
231
651
|
async function startProdServer(options) {
|
|
232
652
|
const { port, distDir } = options;
|
|
233
|
-
const serverEntry =
|
|
653
|
+
const serverEntry = path13.resolve(distDir, "server/entry-prod.js");
|
|
234
654
|
const { startServer } = await import(serverEntry);
|
|
235
|
-
console.log(
|
|
655
|
+
console.log(chalk7.cyan("Starting production server..."));
|
|
236
656
|
return startServer({ port, distDir });
|
|
237
657
|
}
|
|
238
658
|
var init_prod = () => {};
|
|
@@ -442,78 +862,97 @@ var devCommand = new Command2("dev").description("Start development server").opt
|
|
|
442
862
|
|
|
443
863
|
// src/cli/commands/build.ts
|
|
444
864
|
import { Command as Command3 } from "commander";
|
|
445
|
-
import
|
|
446
|
-
import
|
|
447
|
-
var buildCommand = new Command3("build").description("Build for production").option("-c, --content <path>", "Content directory").option("-o, --outDir <path>", "Output directory", "dist").action(async (options) => {
|
|
865
|
+
import path12 from "path";
|
|
866
|
+
import chalk6 from "chalk";
|
|
867
|
+
var buildCommand = new Command3("build").description("Build for production").option("-c, --content <path>", "Content directory").option("-o, --outDir <path>", "Output directory", "dist").option("--adapter <adapter>", "Deploy adapter (vercel)").action(async (options) => {
|
|
448
868
|
const contentDir = resolveContentDir(options.content);
|
|
449
|
-
const outDir =
|
|
869
|
+
const outDir = path12.resolve(options.outDir);
|
|
870
|
+
const VALID_ADAPTERS = ["vercel"];
|
|
871
|
+
if (options.adapter && !VALID_ADAPTERS.includes(options.adapter)) {
|
|
872
|
+
console.error(chalk6.red(`Unknown adapter: ${options.adapter}. Valid adapters: ${VALID_ADAPTERS.join(", ")}`));
|
|
873
|
+
process.exit(1);
|
|
874
|
+
}
|
|
450
875
|
process.env.CHRONICLE_PROJECT_ROOT = process.cwd();
|
|
451
876
|
process.env.CHRONICLE_CONTENT_DIR = contentDir;
|
|
452
|
-
console.log(
|
|
877
|
+
console.log(chalk6.cyan("Building for production..."));
|
|
453
878
|
const { build } = await import("vite");
|
|
454
879
|
const { createViteConfig: createViteConfig2 } = await Promise.resolve().then(() => (init_vite_config(), exports_vite_config));
|
|
455
880
|
const baseConfig = await createViteConfig2({ root: PACKAGE_ROOT, contentDir });
|
|
456
|
-
console.log(
|
|
881
|
+
console.log(chalk6.gray("Building client..."));
|
|
457
882
|
await build({
|
|
458
883
|
...baseConfig,
|
|
459
884
|
build: {
|
|
460
|
-
outDir:
|
|
885
|
+
outDir: path12.join(outDir, "client"),
|
|
461
886
|
ssrManifest: true,
|
|
462
887
|
rolldownOptions: {
|
|
463
|
-
input:
|
|
888
|
+
input: path12.resolve(PACKAGE_ROOT, "src/server/index.html")
|
|
464
889
|
}
|
|
465
890
|
}
|
|
466
891
|
});
|
|
467
|
-
|
|
892
|
+
const serverEntry = options.adapter === "vercel" ? path12.resolve(PACKAGE_ROOT, "src/server/entry-vercel.ts") : path12.resolve(PACKAGE_ROOT, "src/server/entry-prod.ts");
|
|
893
|
+
console.log(chalk6.gray("Building server..."));
|
|
468
894
|
await build({
|
|
469
895
|
...baseConfig,
|
|
470
896
|
ssr: {
|
|
471
897
|
noExternal: true
|
|
472
898
|
},
|
|
473
899
|
build: {
|
|
474
|
-
outDir:
|
|
475
|
-
ssr:
|
|
900
|
+
outDir: path12.join(outDir, "server"),
|
|
901
|
+
ssr: serverEntry,
|
|
902
|
+
target: "node22"
|
|
476
903
|
}
|
|
477
904
|
});
|
|
478
|
-
console.log(
|
|
905
|
+
console.log(chalk6.gray("Building search index..."));
|
|
906
|
+
const { generateSearchIndex: generateSearchIndex2 } = await Promise.resolve().then(() => (init_build_search_index(), exports_build_search_index));
|
|
907
|
+
const docCount = await generateSearchIndex2(contentDir, path12.join(outDir, "server"));
|
|
908
|
+
console.log(chalk6.gray(` Indexed ${docCount} documents`));
|
|
909
|
+
console.log(chalk6.green("Build complete →"), outDir);
|
|
910
|
+
if (options.adapter === "vercel") {
|
|
911
|
+
const { buildVercelOutput: buildVercelOutput2 } = await Promise.resolve().then(() => (init_vercel(), exports_vercel));
|
|
912
|
+
await buildVercelOutput2({
|
|
913
|
+
distDir: outDir,
|
|
914
|
+
contentDir,
|
|
915
|
+
projectRoot: process.cwd()
|
|
916
|
+
});
|
|
917
|
+
}
|
|
479
918
|
});
|
|
480
919
|
|
|
481
920
|
// src/cli/commands/start.ts
|
|
482
921
|
import { Command as Command4 } from "commander";
|
|
483
|
-
import
|
|
484
|
-
import
|
|
922
|
+
import path14 from "path";
|
|
923
|
+
import chalk8 from "chalk";
|
|
485
924
|
var startCommand = new Command4("start").description("Start production server").option("-p, --port <port>", "Port number", "3000").option("-c, --content <path>", "Content directory").option("-d, --dist <path>", "Dist directory", "dist").action(async (options) => {
|
|
486
925
|
const contentDir = resolveContentDir(options.content);
|
|
487
926
|
const port = parseInt(options.port, 10);
|
|
488
|
-
const distDir =
|
|
927
|
+
const distDir = path14.resolve(options.dist);
|
|
489
928
|
process.env.CHRONICLE_PROJECT_ROOT = process.cwd();
|
|
490
929
|
process.env.CHRONICLE_CONTENT_DIR = contentDir;
|
|
491
|
-
console.log(
|
|
930
|
+
console.log(chalk8.cyan("Starting production server..."));
|
|
492
931
|
const { startProdServer: startProdServer2 } = await Promise.resolve().then(() => (init_prod(), exports_prod));
|
|
493
932
|
await startProdServer2({ port, root: PACKAGE_ROOT, distDir });
|
|
494
933
|
});
|
|
495
934
|
|
|
496
935
|
// src/cli/commands/serve.ts
|
|
497
936
|
import { Command as Command5 } from "commander";
|
|
498
|
-
import
|
|
499
|
-
import
|
|
937
|
+
import path15 from "path";
|
|
938
|
+
import chalk9 from "chalk";
|
|
500
939
|
var serveCommand = new Command5("serve").description("Build and start production server").option("-p, --port <port>", "Port number", "3000").option("-c, --content <path>", "Content directory").option("-o, --outDir <path>", "Output directory", "dist").action(async (options) => {
|
|
501
940
|
const contentDir = resolveContentDir(options.content);
|
|
502
941
|
const port = parseInt(options.port, 10);
|
|
503
|
-
const outDir =
|
|
942
|
+
const outDir = path15.resolve(options.outDir);
|
|
504
943
|
process.env.CHRONICLE_PROJECT_ROOT = process.cwd();
|
|
505
944
|
process.env.CHRONICLE_CONTENT_DIR = contentDir;
|
|
506
|
-
console.log(
|
|
945
|
+
console.log(chalk9.cyan("Building for production..."));
|
|
507
946
|
const { build } = await import("vite");
|
|
508
947
|
const { createViteConfig: createViteConfig2 } = await Promise.resolve().then(() => (init_vite_config(), exports_vite_config));
|
|
509
948
|
const baseConfig = await createViteConfig2({ root: PACKAGE_ROOT, contentDir });
|
|
510
949
|
await build({
|
|
511
950
|
...baseConfig,
|
|
512
951
|
build: {
|
|
513
|
-
outDir:
|
|
952
|
+
outDir: path15.join(outDir, "client"),
|
|
514
953
|
ssrManifest: true,
|
|
515
954
|
rolldownOptions: {
|
|
516
|
-
input:
|
|
955
|
+
input: path15.resolve(PACKAGE_ROOT, "src/server/index.html")
|
|
517
956
|
}
|
|
518
957
|
}
|
|
519
958
|
});
|
|
@@ -523,11 +962,11 @@ var serveCommand = new Command5("serve").description("Build and start production
|
|
|
523
962
|
noExternal: true
|
|
524
963
|
},
|
|
525
964
|
build: {
|
|
526
|
-
outDir:
|
|
527
|
-
ssr:
|
|
965
|
+
outDir: path15.join(outDir, "server"),
|
|
966
|
+
ssr: path15.resolve(PACKAGE_ROOT, "src/server/entry-prod.ts")
|
|
528
967
|
}
|
|
529
968
|
});
|
|
530
|
-
console.log(
|
|
969
|
+
console.log(chalk9.cyan("Starting production server..."));
|
|
531
970
|
const { startProdServer: startProdServer2 } = await Promise.resolve().then(() => (init_prod(), exports_prod));
|
|
532
971
|
await startProdServer2({ port, root: PACKAGE_ROOT, distDir: outDir });
|
|
533
972
|
});
|