@cloudwerk/cli 0.6.0 → 0.7.2

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.
Files changed (3) hide show
  1. package/README.md +74 -0
  2. package/dist/index.js +306 -3999
  3. package/package.json +7 -3
package/dist/index.js CHANGED
@@ -4,21 +4,12 @@
4
4
  import { program } from "commander";
5
5
 
6
6
  // src/commands/dev.ts
7
- import * as path10 from "path";
8
- import * as fs10 from "fs";
7
+ import * as path from "path";
8
+ import * as fs from "fs";
9
9
  import * as os from "os";
10
- import { serve } from "@hono/node-server";
11
- import {
12
- loadConfig,
13
- scanRoutes,
14
- buildRouteManifest,
15
- resolveLayouts,
16
- resolveMiddleware,
17
- resolveRoutesDir as resolveRoutesDir2,
18
- hasErrors,
19
- formatErrors,
20
- formatWarnings
21
- } from "@cloudwerk/core";
10
+ import { createServer } from "vite";
11
+ import devServer from "@hono/vite-dev-server";
12
+ import cloudwerk from "@cloudwerk/vite-plugin";
22
13
 
23
14
  // src/types.ts
24
15
  var CliError = class extends Error {
@@ -73,3655 +64,56 @@ function printStartupBanner(version, localUrl, networkUrl, routes, startupTime)
73
64
  const methodColor = getMethodColor(route.method);
74
65
  console.log(
75
66
  pc.dim(" ") + methodColor(route.method.padEnd(6)) + " " + route.pattern
76
- );
77
- }
78
- if (remainingCount > 0) {
79
- console.log(pc.dim(` ... and ${remainingCount} more routes`));
80
- }
81
- console.log();
82
- }
83
- console.log(pc.dim(` Ready in ${startupTime}ms`));
84
- console.log();
85
- }
86
- function getMethodColor(method) {
87
- switch (method.toUpperCase()) {
88
- case "GET":
89
- return pc.green;
90
- case "POST":
91
- return pc.blue;
92
- case "PUT":
93
- return pc.yellow;
94
- case "PATCH":
95
- return pc.magenta;
96
- case "DELETE":
97
- return pc.red;
98
- case "OPTIONS":
99
- return pc.cyan;
100
- case "HEAD":
101
- return pc.gray;
102
- default:
103
- return pc.white;
104
- }
105
- }
106
- function printError(message, suggestion) {
107
- console.log();
108
- console.log(pc.red("Error: ") + message);
109
- if (suggestion) {
110
- console.log();
111
- console.log(pc.dim(" " + suggestion));
112
- }
113
- console.log();
114
- }
115
- function logRequest(method, path16, status, duration) {
116
- const methodColor = getMethodColor(method);
117
- const statusColor = status >= 400 ? pc.red : status >= 300 ? pc.yellow : pc.green;
118
- console.log(
119
- pc.dim("[") + methodColor(method.padEnd(6)) + pc.dim("]") + " " + path16 + " " + statusColor(String(status)) + " " + pc.dim(`${duration}ms`)
120
- );
121
- }
122
-
123
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/compose.js
124
- var compose = (middleware, onError, onNotFound) => {
125
- return (context, next) => {
126
- let index = -1;
127
- return dispatch(0);
128
- async function dispatch(i) {
129
- if (i <= index) {
130
- throw new Error("next() called multiple times");
131
- }
132
- index = i;
133
- let res;
134
- let isError = false;
135
- let handler;
136
- if (middleware[i]) {
137
- handler = middleware[i][0][0];
138
- context.req.routeIndex = i;
139
- } else {
140
- handler = i === middleware.length && next || void 0;
141
- }
142
- if (handler) {
143
- try {
144
- res = await handler(context, () => dispatch(i + 1));
145
- } catch (err) {
146
- if (err instanceof Error && onError) {
147
- context.error = err;
148
- res = await onError(err, context);
149
- isError = true;
150
- } else {
151
- throw err;
152
- }
153
- }
154
- } else {
155
- if (context.finalized === false && onNotFound) {
156
- res = await onNotFound(context);
157
- }
158
- }
159
- if (res && (context.finalized === false || isError)) {
160
- context.res = res;
161
- }
162
- return context;
163
- }
164
- };
165
- };
166
-
167
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/request/constants.js
168
- var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
169
-
170
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/utils/body.js
171
- var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
172
- const { all = false, dot = false } = options;
173
- const headers = request instanceof HonoRequest ? request.raw.headers : request.headers;
174
- const contentType = headers.get("Content-Type");
175
- if (contentType?.startsWith("multipart/form-data") || contentType?.startsWith("application/x-www-form-urlencoded")) {
176
- return parseFormData(request, { all, dot });
177
- }
178
- return {};
179
- };
180
- async function parseFormData(request, options) {
181
- const formData = await request.formData();
182
- if (formData) {
183
- return convertFormDataToBodyData(formData, options);
184
- }
185
- return {};
186
- }
187
- function convertFormDataToBodyData(formData, options) {
188
- const form = /* @__PURE__ */ Object.create(null);
189
- formData.forEach((value, key) => {
190
- const shouldParseAllValues = options.all || key.endsWith("[]");
191
- if (!shouldParseAllValues) {
192
- form[key] = value;
193
- } else {
194
- handleParsingAllValues(form, key, value);
195
- }
196
- });
197
- if (options.dot) {
198
- Object.entries(form).forEach(([key, value]) => {
199
- const shouldParseDotValues = key.includes(".");
200
- if (shouldParseDotValues) {
201
- handleParsingNestedValues(form, key, value);
202
- delete form[key];
203
- }
204
- });
205
- }
206
- return form;
207
- }
208
- var handleParsingAllValues = (form, key, value) => {
209
- if (form[key] !== void 0) {
210
- if (Array.isArray(form[key])) {
211
- ;
212
- form[key].push(value);
213
- } else {
214
- form[key] = [form[key], value];
215
- }
216
- } else {
217
- if (!key.endsWith("[]")) {
218
- form[key] = value;
219
- } else {
220
- form[key] = [value];
221
- }
222
- }
223
- };
224
- var handleParsingNestedValues = (form, key, value) => {
225
- let nestedForm = form;
226
- const keys = key.split(".");
227
- keys.forEach((key2, index) => {
228
- if (index === keys.length - 1) {
229
- nestedForm[key2] = value;
230
- } else {
231
- if (!nestedForm[key2] || typeof nestedForm[key2] !== "object" || Array.isArray(nestedForm[key2]) || nestedForm[key2] instanceof File) {
232
- nestedForm[key2] = /* @__PURE__ */ Object.create(null);
233
- }
234
- nestedForm = nestedForm[key2];
235
- }
236
- });
237
- };
238
-
239
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/utils/url.js
240
- var splitPath = (path16) => {
241
- const paths = path16.split("/");
242
- if (paths[0] === "") {
243
- paths.shift();
244
- }
245
- return paths;
246
- };
247
- var splitRoutingPath = (routePath) => {
248
- const { groups, path: path16 } = extractGroupsFromPath(routePath);
249
- const paths = splitPath(path16);
250
- return replaceGroupMarks(paths, groups);
251
- };
252
- var extractGroupsFromPath = (path16) => {
253
- const groups = [];
254
- path16 = path16.replace(/\{[^}]+\}/g, (match2, index) => {
255
- const mark = `@${index}`;
256
- groups.push([mark, match2]);
257
- return mark;
258
- });
259
- return { groups, path: path16 };
260
- };
261
- var replaceGroupMarks = (paths, groups) => {
262
- for (let i = groups.length - 1; i >= 0; i--) {
263
- const [mark] = groups[i];
264
- for (let j = paths.length - 1; j >= 0; j--) {
265
- if (paths[j].includes(mark)) {
266
- paths[j] = paths[j].replace(mark, groups[i][1]);
267
- break;
268
- }
269
- }
270
- }
271
- return paths;
272
- };
273
- var patternCache = {};
274
- var getPattern = (label, next) => {
275
- if (label === "*") {
276
- return "*";
277
- }
278
- const match2 = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
279
- if (match2) {
280
- const cacheKey = `${label}#${next}`;
281
- if (!patternCache[cacheKey]) {
282
- if (match2[2]) {
283
- patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [cacheKey, match2[1], new RegExp(`^${match2[2]}(?=/${next})`)] : [label, match2[1], new RegExp(`^${match2[2]}$`)];
284
- } else {
285
- patternCache[cacheKey] = [label, match2[1], true];
286
- }
287
- }
288
- return patternCache[cacheKey];
289
- }
290
- return null;
291
- };
292
- var tryDecode = (str, decoder) => {
293
- try {
294
- return decoder(str);
295
- } catch {
296
- return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match2) => {
297
- try {
298
- return decoder(match2);
299
- } catch {
300
- return match2;
301
- }
302
- });
303
- }
304
- };
305
- var tryDecodeURI = (str) => tryDecode(str, decodeURI);
306
- var getPath = (request) => {
307
- const url = request.url;
308
- const start = url.indexOf("/", url.indexOf(":") + 4);
309
- let i = start;
310
- for (; i < url.length; i++) {
311
- const charCode = url.charCodeAt(i);
312
- if (charCode === 37) {
313
- const queryIndex = url.indexOf("?", i);
314
- const path16 = url.slice(start, queryIndex === -1 ? void 0 : queryIndex);
315
- return tryDecodeURI(path16.includes("%25") ? path16.replace(/%25/g, "%2525") : path16);
316
- } else if (charCode === 63) {
317
- break;
318
- }
319
- }
320
- return url.slice(start, i);
321
- };
322
- var getPathNoStrict = (request) => {
323
- const result = getPath(request);
324
- return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result;
325
- };
326
- var mergePath = (base, sub, ...rest) => {
327
- if (rest.length) {
328
- sub = mergePath(sub, ...rest);
329
- }
330
- return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`;
331
- };
332
- var checkOptionalParameter = (path16) => {
333
- if (path16.charCodeAt(path16.length - 1) !== 63 || !path16.includes(":")) {
334
- return null;
335
- }
336
- const segments = path16.split("/");
337
- const results = [];
338
- let basePath = "";
339
- segments.forEach((segment) => {
340
- if (segment !== "" && !/\:/.test(segment)) {
341
- basePath += "/" + segment;
342
- } else if (/\:/.test(segment)) {
343
- if (/\?/.test(segment)) {
344
- if (results.length === 0 && basePath === "") {
345
- results.push("/");
346
- } else {
347
- results.push(basePath);
348
- }
349
- const optionalSegment = segment.replace("?", "");
350
- basePath += "/" + optionalSegment;
351
- results.push(basePath);
352
- } else {
353
- basePath += "/" + segment;
354
- }
355
- }
356
- });
357
- return results.filter((v, i, a) => a.indexOf(v) === i);
358
- };
359
- var _decodeURI = (value) => {
360
- if (!/[%+]/.test(value)) {
361
- return value;
362
- }
363
- if (value.indexOf("+") !== -1) {
364
- value = value.replace(/\+/g, " ");
365
- }
366
- return value.indexOf("%") !== -1 ? tryDecode(value, decodeURIComponent_) : value;
367
- };
368
- var _getQueryParam = (url, key, multiple) => {
369
- let encoded;
370
- if (!multiple && key && !/[%+]/.test(key)) {
371
- let keyIndex2 = url.indexOf("?", 8);
372
- if (keyIndex2 === -1) {
373
- return void 0;
374
- }
375
- if (!url.startsWith(key, keyIndex2 + 1)) {
376
- keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
377
- }
378
- while (keyIndex2 !== -1) {
379
- const trailingKeyCode = url.charCodeAt(keyIndex2 + key.length + 1);
380
- if (trailingKeyCode === 61) {
381
- const valueIndex = keyIndex2 + key.length + 2;
382
- const endIndex = url.indexOf("&", valueIndex);
383
- return _decodeURI(url.slice(valueIndex, endIndex === -1 ? void 0 : endIndex));
384
- } else if (trailingKeyCode == 38 || isNaN(trailingKeyCode)) {
385
- return "";
386
- }
387
- keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
388
- }
389
- encoded = /[%+]/.test(url);
390
- if (!encoded) {
391
- return void 0;
392
- }
393
- }
394
- const results = {};
395
- encoded ??= /[%+]/.test(url);
396
- let keyIndex = url.indexOf("?", 8);
397
- while (keyIndex !== -1) {
398
- const nextKeyIndex = url.indexOf("&", keyIndex + 1);
399
- let valueIndex = url.indexOf("=", keyIndex);
400
- if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) {
401
- valueIndex = -1;
402
- }
403
- let name = url.slice(
404
- keyIndex + 1,
405
- valueIndex === -1 ? nextKeyIndex === -1 ? void 0 : nextKeyIndex : valueIndex
406
- );
407
- if (encoded) {
408
- name = _decodeURI(name);
409
- }
410
- keyIndex = nextKeyIndex;
411
- if (name === "") {
412
- continue;
413
- }
414
- let value;
415
- if (valueIndex === -1) {
416
- value = "";
417
- } else {
418
- value = url.slice(valueIndex + 1, nextKeyIndex === -1 ? void 0 : nextKeyIndex);
419
- if (encoded) {
420
- value = _decodeURI(value);
421
- }
422
- }
423
- if (multiple) {
424
- if (!(results[name] && Array.isArray(results[name]))) {
425
- results[name] = [];
426
- }
427
- ;
428
- results[name].push(value);
429
- } else {
430
- results[name] ??= value;
431
- }
432
- }
433
- return key ? results[key] : results;
434
- };
435
- var getQueryParam = _getQueryParam;
436
- var getQueryParams = (url, key) => {
437
- return _getQueryParam(url, key, true);
438
- };
439
- var decodeURIComponent_ = decodeURIComponent;
440
-
441
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/request.js
442
- var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_);
443
- var HonoRequest = class {
444
- /**
445
- * `.raw` can get the raw Request object.
446
- *
447
- * @see {@link https://hono.dev/docs/api/request#raw}
448
- *
449
- * @example
450
- * ```ts
451
- * // For Cloudflare Workers
452
- * app.post('/', async (c) => {
453
- * const metadata = c.req.raw.cf?.hostMetadata?
454
- * ...
455
- * })
456
- * ```
457
- */
458
- raw;
459
- #validatedData;
460
- // Short name of validatedData
461
- #matchResult;
462
- routeIndex = 0;
463
- /**
464
- * `.path` can get the pathname of the request.
465
- *
466
- * @see {@link https://hono.dev/docs/api/request#path}
467
- *
468
- * @example
469
- * ```ts
470
- * app.get('/about/me', (c) => {
471
- * const pathname = c.req.path // `/about/me`
472
- * })
473
- * ```
474
- */
475
- path;
476
- bodyCache = {};
477
- constructor(request, path16 = "/", matchResult = [[]]) {
478
- this.raw = request;
479
- this.path = path16;
480
- this.#matchResult = matchResult;
481
- this.#validatedData = {};
482
- }
483
- param(key) {
484
- return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams();
485
- }
486
- #getDecodedParam(key) {
487
- const paramKey = this.#matchResult[0][this.routeIndex][1][key];
488
- const param = this.#getParamValue(paramKey);
489
- return param && /\%/.test(param) ? tryDecodeURIComponent(param) : param;
490
- }
491
- #getAllDecodedParams() {
492
- const decoded = {};
493
- const keys = Object.keys(this.#matchResult[0][this.routeIndex][1]);
494
- for (const key of keys) {
495
- const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
496
- if (value !== void 0) {
497
- decoded[key] = /\%/.test(value) ? tryDecodeURIComponent(value) : value;
498
- }
499
- }
500
- return decoded;
501
- }
502
- #getParamValue(paramKey) {
503
- return this.#matchResult[1] ? this.#matchResult[1][paramKey] : paramKey;
504
- }
505
- query(key) {
506
- return getQueryParam(this.url, key);
507
- }
508
- queries(key) {
509
- return getQueryParams(this.url, key);
510
- }
511
- header(name) {
512
- if (name) {
513
- return this.raw.headers.get(name) ?? void 0;
514
- }
515
- const headerData = {};
516
- this.raw.headers.forEach((value, key) => {
517
- headerData[key] = value;
518
- });
519
- return headerData;
520
- }
521
- async parseBody(options) {
522
- return this.bodyCache.parsedBody ??= await parseBody(this, options);
523
- }
524
- #cachedBody = (key) => {
525
- const { bodyCache, raw: raw2 } = this;
526
- const cachedBody = bodyCache[key];
527
- if (cachedBody) {
528
- return cachedBody;
529
- }
530
- const anyCachedKey = Object.keys(bodyCache)[0];
531
- if (anyCachedKey) {
532
- return bodyCache[anyCachedKey].then((body) => {
533
- if (anyCachedKey === "json") {
534
- body = JSON.stringify(body);
535
- }
536
- return new Response(body)[key]();
537
- });
538
- }
539
- return bodyCache[key] = raw2[key]();
540
- };
541
- /**
542
- * `.json()` can parse Request body of type `application/json`
543
- *
544
- * @see {@link https://hono.dev/docs/api/request#json}
545
- *
546
- * @example
547
- * ```ts
548
- * app.post('/entry', async (c) => {
549
- * const body = await c.req.json()
550
- * })
551
- * ```
552
- */
553
- json() {
554
- return this.#cachedBody("text").then((text) => JSON.parse(text));
555
- }
556
- /**
557
- * `.text()` can parse Request body of type `text/plain`
558
- *
559
- * @see {@link https://hono.dev/docs/api/request#text}
560
- *
561
- * @example
562
- * ```ts
563
- * app.post('/entry', async (c) => {
564
- * const body = await c.req.text()
565
- * })
566
- * ```
567
- */
568
- text() {
569
- return this.#cachedBody("text");
570
- }
571
- /**
572
- * `.arrayBuffer()` parse Request body as an `ArrayBuffer`
573
- *
574
- * @see {@link https://hono.dev/docs/api/request#arraybuffer}
575
- *
576
- * @example
577
- * ```ts
578
- * app.post('/entry', async (c) => {
579
- * const body = await c.req.arrayBuffer()
580
- * })
581
- * ```
582
- */
583
- arrayBuffer() {
584
- return this.#cachedBody("arrayBuffer");
585
- }
586
- /**
587
- * Parses the request body as a `Blob`.
588
- * @example
589
- * ```ts
590
- * app.post('/entry', async (c) => {
591
- * const body = await c.req.blob();
592
- * });
593
- * ```
594
- * @see https://hono.dev/docs/api/request#blob
595
- */
596
- blob() {
597
- return this.#cachedBody("blob");
598
- }
599
- /**
600
- * Parses the request body as `FormData`.
601
- * @example
602
- * ```ts
603
- * app.post('/entry', async (c) => {
604
- * const body = await c.req.formData();
605
- * });
606
- * ```
607
- * @see https://hono.dev/docs/api/request#formdata
608
- */
609
- formData() {
610
- return this.#cachedBody("formData");
611
- }
612
- /**
613
- * Adds validated data to the request.
614
- *
615
- * @param target - The target of the validation.
616
- * @param data - The validated data to add.
617
- */
618
- addValidatedData(target, data) {
619
- this.#validatedData[target] = data;
620
- }
621
- valid(target) {
622
- return this.#validatedData[target];
623
- }
624
- /**
625
- * `.url()` can get the request url strings.
626
- *
627
- * @see {@link https://hono.dev/docs/api/request#url}
628
- *
629
- * @example
630
- * ```ts
631
- * app.get('/about/me', (c) => {
632
- * const url = c.req.url // `http://localhost:8787/about/me`
633
- * ...
634
- * })
635
- * ```
636
- */
637
- get url() {
638
- return this.raw.url;
639
- }
640
- /**
641
- * `.method()` can get the method name of the request.
642
- *
643
- * @see {@link https://hono.dev/docs/api/request#method}
644
- *
645
- * @example
646
- * ```ts
647
- * app.get('/about/me', (c) => {
648
- * const method = c.req.method // `GET`
649
- * })
650
- * ```
651
- */
652
- get method() {
653
- return this.raw.method;
654
- }
655
- get [GET_MATCH_RESULT]() {
656
- return this.#matchResult;
657
- }
658
- /**
659
- * `.matchedRoutes()` can return a matched route in the handler
660
- *
661
- * @deprecated
662
- *
663
- * Use matchedRoutes helper defined in "hono/route" instead.
664
- *
665
- * @see {@link https://hono.dev/docs/api/request#matchedroutes}
666
- *
667
- * @example
668
- * ```ts
669
- * app.use('*', async function logger(c, next) {
670
- * await next()
671
- * c.req.matchedRoutes.forEach(({ handler, method, path }, i) => {
672
- * const name = handler.name || (handler.length < 2 ? '[handler]' : '[middleware]')
673
- * console.log(
674
- * method,
675
- * ' ',
676
- * path,
677
- * ' '.repeat(Math.max(10 - path.length, 0)),
678
- * name,
679
- * i === c.req.routeIndex ? '<- respond from here' : ''
680
- * )
681
- * })
682
- * })
683
- * ```
684
- */
685
- get matchedRoutes() {
686
- return this.#matchResult[0].map(([[, route]]) => route);
687
- }
688
- /**
689
- * `routePath()` can retrieve the path registered within the handler
690
- *
691
- * @deprecated
692
- *
693
- * Use routePath helper defined in "hono/route" instead.
694
- *
695
- * @see {@link https://hono.dev/docs/api/request#routepath}
696
- *
697
- * @example
698
- * ```ts
699
- * app.get('/posts/:id', (c) => {
700
- * return c.json({ path: c.req.routePath })
701
- * })
702
- * ```
703
- */
704
- get routePath() {
705
- return this.#matchResult[0].map(([[, route]]) => route)[this.routeIndex].path;
706
- }
707
- };
708
-
709
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/utils/html.js
710
- var HtmlEscapedCallbackPhase = {
711
- Stringify: 1,
712
- BeforeStream: 2,
713
- Stream: 3
714
- };
715
- var raw = (value, callbacks) => {
716
- const escapedString = new String(value);
717
- escapedString.isEscaped = true;
718
- escapedString.callbacks = callbacks;
719
- return escapedString;
720
- };
721
- var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
722
- if (typeof str === "object" && !(str instanceof String)) {
723
- if (!(str instanceof Promise)) {
724
- str = str.toString();
725
- }
726
- if (str instanceof Promise) {
727
- str = await str;
728
- }
729
- }
730
- const callbacks = str.callbacks;
731
- if (!callbacks?.length) {
732
- return Promise.resolve(str);
733
- }
734
- if (buffer) {
735
- buffer[0] += str;
736
- } else {
737
- buffer = [str];
738
- }
739
- const resStr = Promise.all(callbacks.map((c) => c({ phase, buffer, context }))).then(
740
- (res) => Promise.all(
741
- res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer))
742
- ).then(() => buffer[0])
743
- );
744
- if (preserveCallbacks) {
745
- return raw(await resStr, callbacks);
746
- } else {
747
- return resStr;
748
- }
749
- };
750
-
751
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/context.js
752
- var TEXT_PLAIN = "text/plain; charset=UTF-8";
753
- var setDefaultContentType = (contentType, headers) => {
754
- return {
755
- "Content-Type": contentType,
756
- ...headers
757
- };
758
- };
759
- var Context = class {
760
- #rawRequest;
761
- #req;
762
- /**
763
- * `.env` can get bindings (environment variables, secrets, KV namespaces, D1 database, R2 bucket etc.) in Cloudflare Workers.
764
- *
765
- * @see {@link https://hono.dev/docs/api/context#env}
766
- *
767
- * @example
768
- * ```ts
769
- * // Environment object for Cloudflare Workers
770
- * app.get('*', async c => {
771
- * const counter = c.env.COUNTER
772
- * })
773
- * ```
774
- */
775
- env = {};
776
- #var;
777
- finalized = false;
778
- /**
779
- * `.error` can get the error object from the middleware if the Handler throws an error.
780
- *
781
- * @see {@link https://hono.dev/docs/api/context#error}
782
- *
783
- * @example
784
- * ```ts
785
- * app.use('*', async (c, next) => {
786
- * await next()
787
- * if (c.error) {
788
- * // do something...
789
- * }
790
- * })
791
- * ```
792
- */
793
- error;
794
- #status;
795
- #executionCtx;
796
- #res;
797
- #layout;
798
- #renderer;
799
- #notFoundHandler;
800
- #preparedHeaders;
801
- #matchResult;
802
- #path;
803
- /**
804
- * Creates an instance of the Context class.
805
- *
806
- * @param req - The Request object.
807
- * @param options - Optional configuration options for the context.
808
- */
809
- constructor(req, options) {
810
- this.#rawRequest = req;
811
- if (options) {
812
- this.#executionCtx = options.executionCtx;
813
- this.env = options.env;
814
- this.#notFoundHandler = options.notFoundHandler;
815
- this.#path = options.path;
816
- this.#matchResult = options.matchResult;
817
- }
818
- }
819
- /**
820
- * `.req` is the instance of {@link HonoRequest}.
821
- */
822
- get req() {
823
- this.#req ??= new HonoRequest(this.#rawRequest, this.#path, this.#matchResult);
824
- return this.#req;
825
- }
826
- /**
827
- * @see {@link https://hono.dev/docs/api/context#event}
828
- * The FetchEvent associated with the current request.
829
- *
830
- * @throws Will throw an error if the context does not have a FetchEvent.
831
- */
832
- get event() {
833
- if (this.#executionCtx && "respondWith" in this.#executionCtx) {
834
- return this.#executionCtx;
835
- } else {
836
- throw Error("This context has no FetchEvent");
837
- }
838
- }
839
- /**
840
- * @see {@link https://hono.dev/docs/api/context#executionctx}
841
- * The ExecutionContext associated with the current request.
842
- *
843
- * @throws Will throw an error if the context does not have an ExecutionContext.
844
- */
845
- get executionCtx() {
846
- if (this.#executionCtx) {
847
- return this.#executionCtx;
848
- } else {
849
- throw Error("This context has no ExecutionContext");
850
- }
851
- }
852
- /**
853
- * @see {@link https://hono.dev/docs/api/context#res}
854
- * The Response object for the current request.
855
- */
856
- get res() {
857
- return this.#res ||= new Response(null, {
858
- headers: this.#preparedHeaders ??= new Headers()
859
- });
860
- }
861
- /**
862
- * Sets the Response object for the current request.
863
- *
864
- * @param _res - The Response object to set.
865
- */
866
- set res(_res) {
867
- if (this.#res && _res) {
868
- _res = new Response(_res.body, _res);
869
- for (const [k, v] of this.#res.headers.entries()) {
870
- if (k === "content-type") {
871
- continue;
872
- }
873
- if (k === "set-cookie") {
874
- const cookies = this.#res.headers.getSetCookie();
875
- _res.headers.delete("set-cookie");
876
- for (const cookie of cookies) {
877
- _res.headers.append("set-cookie", cookie);
878
- }
879
- } else {
880
- _res.headers.set(k, v);
881
- }
882
- }
883
- }
884
- this.#res = _res;
885
- this.finalized = true;
886
- }
887
- /**
888
- * `.render()` can create a response within a layout.
889
- *
890
- * @see {@link https://hono.dev/docs/api/context#render-setrenderer}
891
- *
892
- * @example
893
- * ```ts
894
- * app.get('/', (c) => {
895
- * return c.render('Hello!')
896
- * })
897
- * ```
898
- */
899
- render = (...args) => {
900
- this.#renderer ??= (content) => this.html(content);
901
- return this.#renderer(...args);
902
- };
903
- /**
904
- * Sets the layout for the response.
905
- *
906
- * @param layout - The layout to set.
907
- * @returns The layout function.
908
- */
909
- setLayout = (layout) => this.#layout = layout;
910
- /**
911
- * Gets the current layout for the response.
912
- *
913
- * @returns The current layout function.
914
- */
915
- getLayout = () => this.#layout;
916
- /**
917
- * `.setRenderer()` can set the layout in the custom middleware.
918
- *
919
- * @see {@link https://hono.dev/docs/api/context#render-setrenderer}
920
- *
921
- * @example
922
- * ```tsx
923
- * app.use('*', async (c, next) => {
924
- * c.setRenderer((content) => {
925
- * return c.html(
926
- * <html>
927
- * <body>
928
- * <p>{content}</p>
929
- * </body>
930
- * </html>
931
- * )
932
- * })
933
- * await next()
934
- * })
935
- * ```
936
- */
937
- setRenderer = (renderer) => {
938
- this.#renderer = renderer;
939
- };
940
- /**
941
- * `.header()` can set headers.
942
- *
943
- * @see {@link https://hono.dev/docs/api/context#header}
944
- *
945
- * @example
946
- * ```ts
947
- * app.get('/welcome', (c) => {
948
- * // Set headers
949
- * c.header('X-Message', 'Hello!')
950
- * c.header('Content-Type', 'text/plain')
951
- *
952
- * return c.body('Thank you for coming')
953
- * })
954
- * ```
955
- */
956
- header = (name, value, options) => {
957
- if (this.finalized) {
958
- this.#res = new Response(this.#res.body, this.#res);
959
- }
960
- const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers();
961
- if (value === void 0) {
962
- headers.delete(name);
963
- } else if (options?.append) {
964
- headers.append(name, value);
965
- } else {
966
- headers.set(name, value);
967
- }
968
- };
969
- status = (status) => {
970
- this.#status = status;
971
- };
972
- /**
973
- * `.set()` can set the value specified by the key.
974
- *
975
- * @see {@link https://hono.dev/docs/api/context#set-get}
976
- *
977
- * @example
978
- * ```ts
979
- * app.use('*', async (c, next) => {
980
- * c.set('message', 'Hono is hot!!')
981
- * await next()
982
- * })
983
- * ```
984
- */
985
- set = (key, value) => {
986
- this.#var ??= /* @__PURE__ */ new Map();
987
- this.#var.set(key, value);
988
- };
989
- /**
990
- * `.get()` can use the value specified by the key.
991
- *
992
- * @see {@link https://hono.dev/docs/api/context#set-get}
993
- *
994
- * @example
995
- * ```ts
996
- * app.get('/', (c) => {
997
- * const message = c.get('message')
998
- * return c.text(`The message is "${message}"`)
999
- * })
1000
- * ```
1001
- */
1002
- get = (key) => {
1003
- return this.#var ? this.#var.get(key) : void 0;
1004
- };
1005
- /**
1006
- * `.var` can access the value of a variable.
1007
- *
1008
- * @see {@link https://hono.dev/docs/api/context#var}
1009
- *
1010
- * @example
1011
- * ```ts
1012
- * const result = c.var.client.oneMethod()
1013
- * ```
1014
- */
1015
- // c.var.propName is a read-only
1016
- get var() {
1017
- if (!this.#var) {
1018
- return {};
1019
- }
1020
- return Object.fromEntries(this.#var);
1021
- }
1022
- #newResponse(data, arg, headers) {
1023
- const responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders ?? new Headers();
1024
- if (typeof arg === "object" && "headers" in arg) {
1025
- const argHeaders = arg.headers instanceof Headers ? arg.headers : new Headers(arg.headers);
1026
- for (const [key, value] of argHeaders) {
1027
- if (key.toLowerCase() === "set-cookie") {
1028
- responseHeaders.append(key, value);
1029
- } else {
1030
- responseHeaders.set(key, value);
1031
- }
1032
- }
1033
- }
1034
- if (headers) {
1035
- for (const [k, v] of Object.entries(headers)) {
1036
- if (typeof v === "string") {
1037
- responseHeaders.set(k, v);
1038
- } else {
1039
- responseHeaders.delete(k);
1040
- for (const v2 of v) {
1041
- responseHeaders.append(k, v2);
1042
- }
1043
- }
1044
- }
1045
- }
1046
- const status = typeof arg === "number" ? arg : arg?.status ?? this.#status;
1047
- return new Response(data, { status, headers: responseHeaders });
1048
- }
1049
- newResponse = (...args) => this.#newResponse(...args);
1050
- /**
1051
- * `.body()` can return the HTTP response.
1052
- * You can set headers with `.header()` and set HTTP status code with `.status`.
1053
- * This can also be set in `.text()`, `.json()` and so on.
1054
- *
1055
- * @see {@link https://hono.dev/docs/api/context#body}
1056
- *
1057
- * @example
1058
- * ```ts
1059
- * app.get('/welcome', (c) => {
1060
- * // Set headers
1061
- * c.header('X-Message', 'Hello!')
1062
- * c.header('Content-Type', 'text/plain')
1063
- * // Set HTTP status code
1064
- * c.status(201)
1065
- *
1066
- * // Return the response body
1067
- * return c.body('Thank you for coming')
1068
- * })
1069
- * ```
1070
- */
1071
- body = (data, arg, headers) => this.#newResponse(data, arg, headers);
1072
- /**
1073
- * `.text()` can render text as `Content-Type:text/plain`.
1074
- *
1075
- * @see {@link https://hono.dev/docs/api/context#text}
1076
- *
1077
- * @example
1078
- * ```ts
1079
- * app.get('/say', (c) => {
1080
- * return c.text('Hello!')
1081
- * })
1082
- * ```
1083
- */
1084
- text = (text, arg, headers) => {
1085
- return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse(
1086
- text,
1087
- arg,
1088
- setDefaultContentType(TEXT_PLAIN, headers)
1089
- );
1090
- };
1091
- /**
1092
- * `.json()` can render JSON as `Content-Type:application/json`.
1093
- *
1094
- * @see {@link https://hono.dev/docs/api/context#json}
1095
- *
1096
- * @example
1097
- * ```ts
1098
- * app.get('/api', (c) => {
1099
- * return c.json({ message: 'Hello!' })
1100
- * })
1101
- * ```
1102
- */
1103
- json = (object, arg, headers) => {
1104
- return this.#newResponse(
1105
- JSON.stringify(object),
1106
- arg,
1107
- setDefaultContentType("application/json", headers)
1108
- );
1109
- };
1110
- html = (html, arg, headers) => {
1111
- const res = (html2) => this.#newResponse(html2, arg, setDefaultContentType("text/html; charset=UTF-8", headers));
1112
- return typeof html === "object" ? resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html);
1113
- };
1114
- /**
1115
- * `.redirect()` can Redirect, default status code is 302.
1116
- *
1117
- * @see {@link https://hono.dev/docs/api/context#redirect}
1118
- *
1119
- * @example
1120
- * ```ts
1121
- * app.get('/redirect', (c) => {
1122
- * return c.redirect('/')
1123
- * })
1124
- * app.get('/redirect-permanently', (c) => {
1125
- * return c.redirect('/', 301)
1126
- * })
1127
- * ```
1128
- */
1129
- redirect = (location, status) => {
1130
- const locationString = String(location);
1131
- this.header(
1132
- "Location",
1133
- // Multibyes should be encoded
1134
- // eslint-disable-next-line no-control-regex
1135
- !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString)
1136
- );
1137
- return this.newResponse(null, status ?? 302);
1138
- };
1139
- /**
1140
- * `.notFound()` can return the Not Found Response.
1141
- *
1142
- * @see {@link https://hono.dev/docs/api/context#notfound}
1143
- *
1144
- * @example
1145
- * ```ts
1146
- * app.get('/notfound', (c) => {
1147
- * return c.notFound()
1148
- * })
1149
- * ```
1150
- */
1151
- notFound = () => {
1152
- this.#notFoundHandler ??= () => new Response();
1153
- return this.#notFoundHandler(this);
1154
- };
1155
- };
1156
-
1157
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/router.js
1158
- var METHOD_NAME_ALL = "ALL";
1159
- var METHOD_NAME_ALL_LOWERCASE = "all";
1160
- var METHODS = ["get", "post", "put", "delete", "options", "patch"];
1161
- var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
1162
- var UnsupportedPathError = class extends Error {
1163
- };
1164
-
1165
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/utils/constants.js
1166
- var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
1167
-
1168
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/hono-base.js
1169
- var notFoundHandler = (c) => {
1170
- return c.text("404 Not Found", 404);
1171
- };
1172
- var errorHandler = (err, c) => {
1173
- if ("getResponse" in err) {
1174
- const res = err.getResponse();
1175
- return c.newResponse(res.body, res);
1176
- }
1177
- console.error(err);
1178
- return c.text("Internal Server Error", 500);
1179
- };
1180
- var Hono = class _Hono {
1181
- get;
1182
- post;
1183
- put;
1184
- delete;
1185
- options;
1186
- patch;
1187
- all;
1188
- on;
1189
- use;
1190
- /*
1191
- This class is like an abstract class and does not have a router.
1192
- To use it, inherit the class and implement router in the constructor.
1193
- */
1194
- router;
1195
- getPath;
1196
- // Cannot use `#` because it requires visibility at JavaScript runtime.
1197
- _basePath = "/";
1198
- #path = "/";
1199
- routes = [];
1200
- constructor(options = {}) {
1201
- const allMethods = [...METHODS, METHOD_NAME_ALL_LOWERCASE];
1202
- allMethods.forEach((method) => {
1203
- this[method] = (args1, ...args) => {
1204
- if (typeof args1 === "string") {
1205
- this.#path = args1;
1206
- } else {
1207
- this.#addRoute(method, this.#path, args1);
1208
- }
1209
- args.forEach((handler) => {
1210
- this.#addRoute(method, this.#path, handler);
1211
- });
1212
- return this;
1213
- };
1214
- });
1215
- this.on = (method, path16, ...handlers) => {
1216
- for (const p of [path16].flat()) {
1217
- this.#path = p;
1218
- for (const m of [method].flat()) {
1219
- handlers.map((handler) => {
1220
- this.#addRoute(m.toUpperCase(), this.#path, handler);
1221
- });
1222
- }
1223
- }
1224
- return this;
1225
- };
1226
- this.use = (arg1, ...handlers) => {
1227
- if (typeof arg1 === "string") {
1228
- this.#path = arg1;
1229
- } else {
1230
- this.#path = "*";
1231
- handlers.unshift(arg1);
1232
- }
1233
- handlers.forEach((handler) => {
1234
- this.#addRoute(METHOD_NAME_ALL, this.#path, handler);
1235
- });
1236
- return this;
1237
- };
1238
- const { strict, ...optionsWithoutStrict } = options;
1239
- Object.assign(this, optionsWithoutStrict);
1240
- this.getPath = strict ?? true ? options.getPath ?? getPath : getPathNoStrict;
1241
- }
1242
- #clone() {
1243
- const clone = new _Hono({
1244
- router: this.router,
1245
- getPath: this.getPath
1246
- });
1247
- clone.errorHandler = this.errorHandler;
1248
- clone.#notFoundHandler = this.#notFoundHandler;
1249
- clone.routes = this.routes;
1250
- return clone;
1251
- }
1252
- #notFoundHandler = notFoundHandler;
1253
- // Cannot use `#` because it requires visibility at JavaScript runtime.
1254
- errorHandler = errorHandler;
1255
- /**
1256
- * `.route()` allows grouping other Hono instance in routes.
1257
- *
1258
- * @see {@link https://hono.dev/docs/api/routing#grouping}
1259
- *
1260
- * @param {string} path - base Path
1261
- * @param {Hono} app - other Hono instance
1262
- * @returns {Hono} routed Hono instance
1263
- *
1264
- * @example
1265
- * ```ts
1266
- * const app = new Hono()
1267
- * const app2 = new Hono()
1268
- *
1269
- * app2.get("/user", (c) => c.text("user"))
1270
- * app.route("/api", app2) // GET /api/user
1271
- * ```
1272
- */
1273
- route(path16, app) {
1274
- const subApp = this.basePath(path16);
1275
- app.routes.map((r) => {
1276
- let handler;
1277
- if (app.errorHandler === errorHandler) {
1278
- handler = r.handler;
1279
- } else {
1280
- handler = async (c, next) => (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res;
1281
- handler[COMPOSED_HANDLER] = r.handler;
1282
- }
1283
- subApp.#addRoute(r.method, r.path, handler);
1284
- });
1285
- return this;
1286
- }
1287
- /**
1288
- * `.basePath()` allows base paths to be specified.
1289
- *
1290
- * @see {@link https://hono.dev/docs/api/routing#base-path}
1291
- *
1292
- * @param {string} path - base Path
1293
- * @returns {Hono} changed Hono instance
1294
- *
1295
- * @example
1296
- * ```ts
1297
- * const api = new Hono().basePath('/api')
1298
- * ```
1299
- */
1300
- basePath(path16) {
1301
- const subApp = this.#clone();
1302
- subApp._basePath = mergePath(this._basePath, path16);
1303
- return subApp;
1304
- }
1305
- /**
1306
- * `.onError()` handles an error and returns a customized Response.
1307
- *
1308
- * @see {@link https://hono.dev/docs/api/hono#error-handling}
1309
- *
1310
- * @param {ErrorHandler} handler - request Handler for error
1311
- * @returns {Hono} changed Hono instance
1312
- *
1313
- * @example
1314
- * ```ts
1315
- * app.onError((err, c) => {
1316
- * console.error(`${err}`)
1317
- * return c.text('Custom Error Message', 500)
1318
- * })
1319
- * ```
1320
- */
1321
- onError = (handler) => {
1322
- this.errorHandler = handler;
1323
- return this;
1324
- };
1325
- /**
1326
- * `.notFound()` allows you to customize a Not Found Response.
1327
- *
1328
- * @see {@link https://hono.dev/docs/api/hono#not-found}
1329
- *
1330
- * @param {NotFoundHandler} handler - request handler for not-found
1331
- * @returns {Hono} changed Hono instance
1332
- *
1333
- * @example
1334
- * ```ts
1335
- * app.notFound((c) => {
1336
- * return c.text('Custom 404 Message', 404)
1337
- * })
1338
- * ```
1339
- */
1340
- notFound = (handler) => {
1341
- this.#notFoundHandler = handler;
1342
- return this;
1343
- };
1344
- /**
1345
- * `.mount()` allows you to mount applications built with other frameworks into your Hono application.
1346
- *
1347
- * @see {@link https://hono.dev/docs/api/hono#mount}
1348
- *
1349
- * @param {string} path - base Path
1350
- * @param {Function} applicationHandler - other Request Handler
1351
- * @param {MountOptions} [options] - options of `.mount()`
1352
- * @returns {Hono} mounted Hono instance
1353
- *
1354
- * @example
1355
- * ```ts
1356
- * import { Router as IttyRouter } from 'itty-router'
1357
- * import { Hono } from 'hono'
1358
- * // Create itty-router application
1359
- * const ittyRouter = IttyRouter()
1360
- * // GET /itty-router/hello
1361
- * ittyRouter.get('/hello', () => new Response('Hello from itty-router'))
1362
- *
1363
- * const app = new Hono()
1364
- * app.mount('/itty-router', ittyRouter.handle)
1365
- * ```
1366
- *
1367
- * @example
1368
- * ```ts
1369
- * const app = new Hono()
1370
- * // Send the request to another application without modification.
1371
- * app.mount('/app', anotherApp, {
1372
- * replaceRequest: (req) => req,
1373
- * })
1374
- * ```
1375
- */
1376
- mount(path16, applicationHandler, options) {
1377
- let replaceRequest;
1378
- let optionHandler;
1379
- if (options) {
1380
- if (typeof options === "function") {
1381
- optionHandler = options;
1382
- } else {
1383
- optionHandler = options.optionHandler;
1384
- if (options.replaceRequest === false) {
1385
- replaceRequest = (request) => request;
1386
- } else {
1387
- replaceRequest = options.replaceRequest;
1388
- }
1389
- }
1390
- }
1391
- const getOptions = optionHandler ? (c) => {
1392
- const options2 = optionHandler(c);
1393
- return Array.isArray(options2) ? options2 : [options2];
1394
- } : (c) => {
1395
- let executionContext = void 0;
1396
- try {
1397
- executionContext = c.executionCtx;
1398
- } catch {
1399
- }
1400
- return [c.env, executionContext];
1401
- };
1402
- replaceRequest ||= (() => {
1403
- const mergedPath = mergePath(this._basePath, path16);
1404
- const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length;
1405
- return (request) => {
1406
- const url = new URL(request.url);
1407
- url.pathname = url.pathname.slice(pathPrefixLength) || "/";
1408
- return new Request(url, request);
1409
- };
1410
- })();
1411
- const handler = async (c, next) => {
1412
- const res = await applicationHandler(replaceRequest(c.req.raw), ...getOptions(c));
1413
- if (res) {
1414
- return res;
1415
- }
1416
- await next();
1417
- };
1418
- this.#addRoute(METHOD_NAME_ALL, mergePath(path16, "*"), handler);
1419
- return this;
1420
- }
1421
- #addRoute(method, path16, handler) {
1422
- method = method.toUpperCase();
1423
- path16 = mergePath(this._basePath, path16);
1424
- const r = { basePath: this._basePath, path: path16, method, handler };
1425
- this.router.add(method, path16, [handler, r]);
1426
- this.routes.push(r);
1427
- }
1428
- #handleError(err, c) {
1429
- if (err instanceof Error) {
1430
- return this.errorHandler(err, c);
1431
- }
1432
- throw err;
1433
- }
1434
- #dispatch(request, executionCtx, env, method) {
1435
- if (method === "HEAD") {
1436
- return (async () => new Response(null, await this.#dispatch(request, executionCtx, env, "GET")))();
1437
- }
1438
- const path16 = this.getPath(request, { env });
1439
- const matchResult = this.router.match(method, path16);
1440
- const c = new Context(request, {
1441
- path: path16,
1442
- matchResult,
1443
- env,
1444
- executionCtx,
1445
- notFoundHandler: this.#notFoundHandler
1446
- });
1447
- if (matchResult[0].length === 1) {
1448
- let res;
1449
- try {
1450
- res = matchResult[0][0][0][0](c, async () => {
1451
- c.res = await this.#notFoundHandler(c);
1452
- });
1453
- } catch (err) {
1454
- return this.#handleError(err, c);
1455
- }
1456
- return res instanceof Promise ? res.then(
1457
- (resolved) => resolved || (c.finalized ? c.res : this.#notFoundHandler(c))
1458
- ).catch((err) => this.#handleError(err, c)) : res ?? this.#notFoundHandler(c);
1459
- }
1460
- const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler);
1461
- return (async () => {
1462
- try {
1463
- const context = await composed(c);
1464
- if (!context.finalized) {
1465
- throw new Error(
1466
- "Context is not finalized. Did you forget to return a Response object or `await next()`?"
1467
- );
1468
- }
1469
- return context.res;
1470
- } catch (err) {
1471
- return this.#handleError(err, c);
1472
- }
1473
- })();
1474
- }
1475
- /**
1476
- * `.fetch()` will be entry point of your app.
1477
- *
1478
- * @see {@link https://hono.dev/docs/api/hono#fetch}
1479
- *
1480
- * @param {Request} request - request Object of request
1481
- * @param {Env} Env - env Object
1482
- * @param {ExecutionContext} - context of execution
1483
- * @returns {Response | Promise<Response>} response of request
1484
- *
1485
- */
1486
- fetch = (request, ...rest) => {
1487
- return this.#dispatch(request, rest[1], rest[0], request.method);
1488
- };
1489
- /**
1490
- * `.request()` is a useful method for testing.
1491
- * You can pass a URL or pathname to send a GET request.
1492
- * app will return a Response object.
1493
- * ```ts
1494
- * test('GET /hello is ok', async () => {
1495
- * const res = await app.request('/hello')
1496
- * expect(res.status).toBe(200)
1497
- * })
1498
- * ```
1499
- * @see https://hono.dev/docs/api/hono#request
1500
- */
1501
- request = (input, requestInit, Env, executionCtx) => {
1502
- if (input instanceof Request) {
1503
- return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx);
1504
- }
1505
- input = input.toString();
1506
- return this.fetch(
1507
- new Request(
1508
- /^https?:\/\//.test(input) ? input : `http://localhost${mergePath("/", input)}`,
1509
- requestInit
1510
- ),
1511
- Env,
1512
- executionCtx
1513
- );
1514
- };
1515
- /**
1516
- * `.fire()` automatically adds a global fetch event listener.
1517
- * This can be useful for environments that adhere to the Service Worker API, such as non-ES module Cloudflare Workers.
1518
- * @deprecated
1519
- * Use `fire` from `hono/service-worker` instead.
1520
- * ```ts
1521
- * import { Hono } from 'hono'
1522
- * import { fire } from 'hono/service-worker'
1523
- *
1524
- * const app = new Hono()
1525
- * // ...
1526
- * fire(app)
1527
- * ```
1528
- * @see https://hono.dev/docs/api/hono#fire
1529
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API
1530
- * @see https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/
1531
- */
1532
- fire = () => {
1533
- addEventListener("fetch", (event) => {
1534
- event.respondWith(this.#dispatch(event.request, event, void 0, event.request.method));
1535
- });
1536
- };
1537
- };
1538
-
1539
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/router/reg-exp-router/matcher.js
1540
- var emptyParam = [];
1541
- function match(method, path16) {
1542
- const matchers = this.buildAllMatchers();
1543
- const match2 = ((method2, path22) => {
1544
- const matcher = matchers[method2] || matchers[METHOD_NAME_ALL];
1545
- const staticMatch = matcher[2][path22];
1546
- if (staticMatch) {
1547
- return staticMatch;
1548
- }
1549
- const match3 = path22.match(matcher[0]);
1550
- if (!match3) {
1551
- return [[], emptyParam];
1552
- }
1553
- const index = match3.indexOf("", 1);
1554
- return [matcher[1][index], match3];
1555
- });
1556
- this.match = match2;
1557
- return match2(method, path16);
1558
- }
1559
-
1560
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/router/reg-exp-router/node.js
1561
- var LABEL_REG_EXP_STR = "[^/]+";
1562
- var ONLY_WILDCARD_REG_EXP_STR = ".*";
1563
- var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
1564
- var PATH_ERROR = /* @__PURE__ */ Symbol();
1565
- var regExpMetaChars = new Set(".\\+*[^]$()");
1566
- function compareKey(a, b) {
1567
- if (a.length === 1) {
1568
- return b.length === 1 ? a < b ? -1 : 1 : -1;
1569
- }
1570
- if (b.length === 1) {
1571
- return 1;
1572
- }
1573
- if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) {
1574
- return 1;
1575
- } else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) {
1576
- return -1;
1577
- }
1578
- if (a === LABEL_REG_EXP_STR) {
1579
- return 1;
1580
- } else if (b === LABEL_REG_EXP_STR) {
1581
- return -1;
1582
- }
1583
- return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length;
1584
- }
1585
- var Node = class _Node {
1586
- #index;
1587
- #varIndex;
1588
- #children = /* @__PURE__ */ Object.create(null);
1589
- insert(tokens, index, paramMap, context, pathErrorCheckOnly) {
1590
- if (tokens.length === 0) {
1591
- if (this.#index !== void 0) {
1592
- throw PATH_ERROR;
1593
- }
1594
- if (pathErrorCheckOnly) {
1595
- return;
1596
- }
1597
- this.#index = index;
1598
- return;
1599
- }
1600
- const [token, ...restTokens] = tokens;
1601
- const pattern = token === "*" ? restTokens.length === 0 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
1602
- let node;
1603
- if (pattern) {
1604
- const name = pattern[1];
1605
- let regexpStr = pattern[2] || LABEL_REG_EXP_STR;
1606
- if (name && pattern[2]) {
1607
- if (regexpStr === ".*") {
1608
- throw PATH_ERROR;
1609
- }
1610
- regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
1611
- if (/\((?!\?:)/.test(regexpStr)) {
1612
- throw PATH_ERROR;
1613
- }
1614
- }
1615
- node = this.#children[regexpStr];
1616
- if (!node) {
1617
- if (Object.keys(this.#children).some(
1618
- (k) => k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
1619
- )) {
1620
- throw PATH_ERROR;
1621
- }
1622
- if (pathErrorCheckOnly) {
1623
- return;
1624
- }
1625
- node = this.#children[regexpStr] = new _Node();
1626
- if (name !== "") {
1627
- node.#varIndex = context.varIndex++;
1628
- }
1629
- }
1630
- if (!pathErrorCheckOnly && name !== "") {
1631
- paramMap.push([name, node.#varIndex]);
1632
- }
1633
- } else {
1634
- node = this.#children[token];
1635
- if (!node) {
1636
- if (Object.keys(this.#children).some(
1637
- (k) => k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
1638
- )) {
1639
- throw PATH_ERROR;
1640
- }
1641
- if (pathErrorCheckOnly) {
1642
- return;
1643
- }
1644
- node = this.#children[token] = new _Node();
1645
- }
1646
- }
1647
- node.insert(restTokens, index, paramMap, context, pathErrorCheckOnly);
1648
- }
1649
- buildRegExpStr() {
1650
- const childKeys = Object.keys(this.#children).sort(compareKey);
1651
- const strList = childKeys.map((k) => {
1652
- const c = this.#children[k];
1653
- return (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + c.buildRegExpStr();
1654
- });
1655
- if (typeof this.#index === "number") {
1656
- strList.unshift(`#${this.#index}`);
1657
- }
1658
- if (strList.length === 0) {
1659
- return "";
1660
- }
1661
- if (strList.length === 1) {
1662
- return strList[0];
1663
- }
1664
- return "(?:" + strList.join("|") + ")";
1665
- }
1666
- };
1667
-
1668
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/router/reg-exp-router/trie.js
1669
- var Trie = class {
1670
- #context = { varIndex: 0 };
1671
- #root = new Node();
1672
- insert(path16, index, pathErrorCheckOnly) {
1673
- const paramAssoc = [];
1674
- const groups = [];
1675
- for (let i = 0; ; ) {
1676
- let replaced = false;
1677
- path16 = path16.replace(/\{[^}]+\}/g, (m) => {
1678
- const mark = `@\\${i}`;
1679
- groups[i] = [mark, m];
1680
- i++;
1681
- replaced = true;
1682
- return mark;
1683
- });
1684
- if (!replaced) {
1685
- break;
1686
- }
1687
- }
1688
- const tokens = path16.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
1689
- for (let i = groups.length - 1; i >= 0; i--) {
1690
- const [mark] = groups[i];
1691
- for (let j = tokens.length - 1; j >= 0; j--) {
1692
- if (tokens[j].indexOf(mark) !== -1) {
1693
- tokens[j] = tokens[j].replace(mark, groups[i][1]);
1694
- break;
1695
- }
1696
- }
1697
- }
1698
- this.#root.insert(tokens, index, paramAssoc, this.#context, pathErrorCheckOnly);
1699
- return paramAssoc;
1700
- }
1701
- buildRegExp() {
1702
- let regexp = this.#root.buildRegExpStr();
1703
- if (regexp === "") {
1704
- return [/^$/, [], []];
1705
- }
1706
- let captureIndex = 0;
1707
- const indexReplacementMap = [];
1708
- const paramReplacementMap = [];
1709
- regexp = regexp.replace(/#(\d+)|@(\d+)|\.\*\$/g, (_, handlerIndex, paramIndex) => {
1710
- if (handlerIndex !== void 0) {
1711
- indexReplacementMap[++captureIndex] = Number(handlerIndex);
1712
- return "$()";
1713
- }
1714
- if (paramIndex !== void 0) {
1715
- paramReplacementMap[Number(paramIndex)] = ++captureIndex;
1716
- return "";
1717
- }
1718
- return "";
1719
- });
1720
- return [new RegExp(`^${regexp}`), indexReplacementMap, paramReplacementMap];
1721
- }
1722
- };
1723
-
1724
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/router/reg-exp-router/router.js
1725
- var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
1726
- var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
1727
- function buildWildcardRegExp(path16) {
1728
- return wildcardRegExpCache[path16] ??= new RegExp(
1729
- path16 === "*" ? "" : `^${path16.replace(
1730
- /\/\*$|([.\\+*[^\]$()])/g,
1731
- (_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)"
1732
- )}$`
1733
- );
1734
- }
1735
- function clearWildcardRegExpCache() {
1736
- wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
1737
- }
1738
- function buildMatcherFromPreprocessedRoutes(routes) {
1739
- const trie = new Trie();
1740
- const handlerData = [];
1741
- if (routes.length === 0) {
1742
- return nullMatcher;
1743
- }
1744
- const routesWithStaticPathFlag = routes.map(
1745
- (route) => [!/\*|\/:/.test(route[0]), ...route]
1746
- ).sort(
1747
- ([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length
1748
- );
1749
- const staticMap = /* @__PURE__ */ Object.create(null);
1750
- for (let i = 0, j = -1, len = routesWithStaticPathFlag.length; i < len; i++) {
1751
- const [pathErrorCheckOnly, path16, handlers] = routesWithStaticPathFlag[i];
1752
- if (pathErrorCheckOnly) {
1753
- staticMap[path16] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
1754
- } else {
1755
- j++;
1756
- }
1757
- let paramAssoc;
1758
- try {
1759
- paramAssoc = trie.insert(path16, j, pathErrorCheckOnly);
1760
- } catch (e) {
1761
- throw e === PATH_ERROR ? new UnsupportedPathError(path16) : e;
1762
- }
1763
- if (pathErrorCheckOnly) {
1764
- continue;
1765
- }
1766
- handlerData[j] = handlers.map(([h, paramCount]) => {
1767
- const paramIndexMap = /* @__PURE__ */ Object.create(null);
1768
- paramCount -= 1;
1769
- for (; paramCount >= 0; paramCount--) {
1770
- const [key, value] = paramAssoc[paramCount];
1771
- paramIndexMap[key] = value;
1772
- }
1773
- return [h, paramIndexMap];
1774
- });
1775
- }
1776
- const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
1777
- for (let i = 0, len = handlerData.length; i < len; i++) {
1778
- for (let j = 0, len2 = handlerData[i].length; j < len2; j++) {
1779
- const map = handlerData[i][j]?.[1];
1780
- if (!map) {
1781
- continue;
1782
- }
1783
- const keys = Object.keys(map);
1784
- for (let k = 0, len3 = keys.length; k < len3; k++) {
1785
- map[keys[k]] = paramReplacementMap[map[keys[k]]];
1786
- }
1787
- }
1788
- }
1789
- const handlerMap = [];
1790
- for (const i in indexReplacementMap) {
1791
- handlerMap[i] = handlerData[indexReplacementMap[i]];
1792
- }
1793
- return [regexp, handlerMap, staticMap];
1794
- }
1795
- function findMiddleware(middleware, path16) {
1796
- if (!middleware) {
1797
- return void 0;
1798
- }
1799
- for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) {
1800
- if (buildWildcardRegExp(k).test(path16)) {
1801
- return [...middleware[k]];
1802
- }
1803
- }
1804
- return void 0;
1805
- }
1806
- var RegExpRouter = class {
1807
- name = "RegExpRouter";
1808
- #middleware;
1809
- #routes;
1810
- constructor() {
1811
- this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
1812
- this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
1813
- }
1814
- add(method, path16, handler) {
1815
- const middleware = this.#middleware;
1816
- const routes = this.#routes;
1817
- if (!middleware || !routes) {
1818
- throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
1819
- }
1820
- if (!middleware[method]) {
1821
- ;
1822
- [middleware, routes].forEach((handlerMap) => {
1823
- handlerMap[method] = /* @__PURE__ */ Object.create(null);
1824
- Object.keys(handlerMap[METHOD_NAME_ALL]).forEach((p) => {
1825
- handlerMap[method][p] = [...handlerMap[METHOD_NAME_ALL][p]];
1826
- });
1827
- });
1828
- }
1829
- if (path16 === "/*") {
1830
- path16 = "*";
1831
- }
1832
- const paramCount = (path16.match(/\/:/g) || []).length;
1833
- if (/\*$/.test(path16)) {
1834
- const re = buildWildcardRegExp(path16);
1835
- if (method === METHOD_NAME_ALL) {
1836
- Object.keys(middleware).forEach((m) => {
1837
- middleware[m][path16] ||= findMiddleware(middleware[m], path16) || findMiddleware(middleware[METHOD_NAME_ALL], path16) || [];
1838
- });
1839
- } else {
1840
- middleware[method][path16] ||= findMiddleware(middleware[method], path16) || findMiddleware(middleware[METHOD_NAME_ALL], path16) || [];
1841
- }
1842
- Object.keys(middleware).forEach((m) => {
1843
- if (method === METHOD_NAME_ALL || method === m) {
1844
- Object.keys(middleware[m]).forEach((p) => {
1845
- re.test(p) && middleware[m][p].push([handler, paramCount]);
1846
- });
1847
- }
1848
- });
1849
- Object.keys(routes).forEach((m) => {
1850
- if (method === METHOD_NAME_ALL || method === m) {
1851
- Object.keys(routes[m]).forEach(
1852
- (p) => re.test(p) && routes[m][p].push([handler, paramCount])
1853
- );
1854
- }
1855
- });
1856
- return;
1857
- }
1858
- const paths = checkOptionalParameter(path16) || [path16];
1859
- for (let i = 0, len = paths.length; i < len; i++) {
1860
- const path22 = paths[i];
1861
- Object.keys(routes).forEach((m) => {
1862
- if (method === METHOD_NAME_ALL || method === m) {
1863
- routes[m][path22] ||= [
1864
- ...findMiddleware(middleware[m], path22) || findMiddleware(middleware[METHOD_NAME_ALL], path22) || []
1865
- ];
1866
- routes[m][path22].push([handler, paramCount - len + i + 1]);
1867
- }
1868
- });
1869
- }
1870
- }
1871
- match = match;
1872
- buildAllMatchers() {
1873
- const matchers = /* @__PURE__ */ Object.create(null);
1874
- Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => {
1875
- matchers[method] ||= this.#buildMatcher(method);
1876
- });
1877
- this.#middleware = this.#routes = void 0;
1878
- clearWildcardRegExpCache();
1879
- return matchers;
1880
- }
1881
- #buildMatcher(method) {
1882
- const routes = [];
1883
- let hasOwnRoute = method === METHOD_NAME_ALL;
1884
- [this.#middleware, this.#routes].forEach((r) => {
1885
- const ownRoute = r[method] ? Object.keys(r[method]).map((path16) => [path16, r[method][path16]]) : [];
1886
- if (ownRoute.length !== 0) {
1887
- hasOwnRoute ||= true;
1888
- routes.push(...ownRoute);
1889
- } else if (method !== METHOD_NAME_ALL) {
1890
- routes.push(
1891
- ...Object.keys(r[METHOD_NAME_ALL]).map((path16) => [path16, r[METHOD_NAME_ALL][path16]])
1892
- );
1893
- }
1894
- });
1895
- if (!hasOwnRoute) {
1896
- return null;
1897
- } else {
1898
- return buildMatcherFromPreprocessedRoutes(routes);
1899
- }
1900
- }
1901
- };
1902
-
1903
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/router/smart-router/router.js
1904
- var SmartRouter = class {
1905
- name = "SmartRouter";
1906
- #routers = [];
1907
- #routes = [];
1908
- constructor(init) {
1909
- this.#routers = init.routers;
1910
- }
1911
- add(method, path16, handler) {
1912
- if (!this.#routes) {
1913
- throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
1914
- }
1915
- this.#routes.push([method, path16, handler]);
1916
- }
1917
- match(method, path16) {
1918
- if (!this.#routes) {
1919
- throw new Error("Fatal error");
1920
- }
1921
- const routers = this.#routers;
1922
- const routes = this.#routes;
1923
- const len = routers.length;
1924
- let i = 0;
1925
- let res;
1926
- for (; i < len; i++) {
1927
- const router = routers[i];
1928
- try {
1929
- for (let i2 = 0, len2 = routes.length; i2 < len2; i2++) {
1930
- router.add(...routes[i2]);
1931
- }
1932
- res = router.match(method, path16);
1933
- } catch (e) {
1934
- if (e instanceof UnsupportedPathError) {
1935
- continue;
1936
- }
1937
- throw e;
1938
- }
1939
- this.match = router.match.bind(router);
1940
- this.#routers = [router];
1941
- this.#routes = void 0;
1942
- break;
1943
- }
1944
- if (i === len) {
1945
- throw new Error("Fatal error");
1946
- }
1947
- this.name = `SmartRouter + ${this.activeRouter.name}`;
1948
- return res;
1949
- }
1950
- get activeRouter() {
1951
- if (this.#routes || this.#routers.length !== 1) {
1952
- throw new Error("No active router has been determined yet.");
1953
- }
1954
- return this.#routers[0];
1955
- }
1956
- };
1957
-
1958
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/router/trie-router/node.js
1959
- var emptyParams = /* @__PURE__ */ Object.create(null);
1960
- var Node2 = class _Node2 {
1961
- #methods;
1962
- #children;
1963
- #patterns;
1964
- #order = 0;
1965
- #params = emptyParams;
1966
- constructor(method, handler, children) {
1967
- this.#children = children || /* @__PURE__ */ Object.create(null);
1968
- this.#methods = [];
1969
- if (method && handler) {
1970
- const m = /* @__PURE__ */ Object.create(null);
1971
- m[method] = { handler, possibleKeys: [], score: 0 };
1972
- this.#methods = [m];
1973
- }
1974
- this.#patterns = [];
1975
- }
1976
- insert(method, path16, handler) {
1977
- this.#order = ++this.#order;
1978
- let curNode = this;
1979
- const parts = splitRoutingPath(path16);
1980
- const possibleKeys = [];
1981
- for (let i = 0, len = parts.length; i < len; i++) {
1982
- const p = parts[i];
1983
- const nextP = parts[i + 1];
1984
- const pattern = getPattern(p, nextP);
1985
- const key = Array.isArray(pattern) ? pattern[0] : p;
1986
- if (key in curNode.#children) {
1987
- curNode = curNode.#children[key];
1988
- if (pattern) {
1989
- possibleKeys.push(pattern[1]);
1990
- }
1991
- continue;
1992
- }
1993
- curNode.#children[key] = new _Node2();
1994
- if (pattern) {
1995
- curNode.#patterns.push(pattern);
1996
- possibleKeys.push(pattern[1]);
1997
- }
1998
- curNode = curNode.#children[key];
1999
- }
2000
- curNode.#methods.push({
2001
- [method]: {
2002
- handler,
2003
- possibleKeys: possibleKeys.filter((v, i, a) => a.indexOf(v) === i),
2004
- score: this.#order
2005
- }
2006
- });
2007
- return curNode;
2008
- }
2009
- #getHandlerSets(node, method, nodeParams, params) {
2010
- const handlerSets = [];
2011
- for (let i = 0, len = node.#methods.length; i < len; i++) {
2012
- const m = node.#methods[i];
2013
- const handlerSet = m[method] || m[METHOD_NAME_ALL];
2014
- const processedSet = {};
2015
- if (handlerSet !== void 0) {
2016
- handlerSet.params = /* @__PURE__ */ Object.create(null);
2017
- handlerSets.push(handlerSet);
2018
- if (nodeParams !== emptyParams || params && params !== emptyParams) {
2019
- for (let i2 = 0, len2 = handlerSet.possibleKeys.length; i2 < len2; i2++) {
2020
- const key = handlerSet.possibleKeys[i2];
2021
- const processed = processedSet[handlerSet.score];
2022
- handlerSet.params[key] = params?.[key] && !processed ? params[key] : nodeParams[key] ?? params?.[key];
2023
- processedSet[handlerSet.score] = true;
2024
- }
2025
- }
2026
- }
2027
- }
2028
- return handlerSets;
2029
- }
2030
- search(method, path16) {
2031
- const handlerSets = [];
2032
- this.#params = emptyParams;
2033
- const curNode = this;
2034
- let curNodes = [curNode];
2035
- const parts = splitPath(path16);
2036
- const curNodesQueue = [];
2037
- for (let i = 0, len = parts.length; i < len; i++) {
2038
- const part = parts[i];
2039
- const isLast = i === len - 1;
2040
- const tempNodes = [];
2041
- for (let j = 0, len2 = curNodes.length; j < len2; j++) {
2042
- const node = curNodes[j];
2043
- const nextNode = node.#children[part];
2044
- if (nextNode) {
2045
- nextNode.#params = node.#params;
2046
- if (isLast) {
2047
- if (nextNode.#children["*"]) {
2048
- handlerSets.push(
2049
- ...this.#getHandlerSets(nextNode.#children["*"], method, node.#params)
2050
- );
2051
- }
2052
- handlerSets.push(...this.#getHandlerSets(nextNode, method, node.#params));
2053
- } else {
2054
- tempNodes.push(nextNode);
2055
- }
2056
- }
2057
- for (let k = 0, len3 = node.#patterns.length; k < len3; k++) {
2058
- const pattern = node.#patterns[k];
2059
- const params = node.#params === emptyParams ? {} : { ...node.#params };
2060
- if (pattern === "*") {
2061
- const astNode = node.#children["*"];
2062
- if (astNode) {
2063
- handlerSets.push(...this.#getHandlerSets(astNode, method, node.#params));
2064
- astNode.#params = params;
2065
- tempNodes.push(astNode);
2066
- }
2067
- continue;
2068
- }
2069
- const [key, name, matcher] = pattern;
2070
- if (!part && !(matcher instanceof RegExp)) {
2071
- continue;
2072
- }
2073
- const child = node.#children[key];
2074
- const restPathString = parts.slice(i).join("/");
2075
- if (matcher instanceof RegExp) {
2076
- const m = matcher.exec(restPathString);
2077
- if (m) {
2078
- params[name] = m[0];
2079
- handlerSets.push(...this.#getHandlerSets(child, method, node.#params, params));
2080
- if (Object.keys(child.#children).length) {
2081
- child.#params = params;
2082
- const componentCount = m[0].match(/\//)?.length ?? 0;
2083
- const targetCurNodes = curNodesQueue[componentCount] ||= [];
2084
- targetCurNodes.push(child);
2085
- }
2086
- continue;
2087
- }
2088
- }
2089
- if (matcher === true || matcher.test(part)) {
2090
- params[name] = part;
2091
- if (isLast) {
2092
- handlerSets.push(...this.#getHandlerSets(child, method, params, node.#params));
2093
- if (child.#children["*"]) {
2094
- handlerSets.push(
2095
- ...this.#getHandlerSets(child.#children["*"], method, params, node.#params)
2096
- );
2097
- }
2098
- } else {
2099
- child.#params = params;
2100
- tempNodes.push(child);
2101
- }
2102
- }
2103
- }
2104
- }
2105
- curNodes = tempNodes.concat(curNodesQueue.shift() ?? []);
2106
- }
2107
- if (handlerSets.length > 1) {
2108
- handlerSets.sort((a, b) => {
2109
- return a.score - b.score;
2110
- });
2111
- }
2112
- return [handlerSets.map(({ handler, params }) => [handler, params])];
2113
- }
2114
- };
2115
-
2116
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/router/trie-router/router.js
2117
- var TrieRouter = class {
2118
- name = "TrieRouter";
2119
- #node;
2120
- constructor() {
2121
- this.#node = new Node2();
2122
- }
2123
- add(method, path16, handler) {
2124
- const results = checkOptionalParameter(path16);
2125
- if (results) {
2126
- for (let i = 0, len = results.length; i < len; i++) {
2127
- this.#node.insert(method, results[i], handler);
2128
- }
2129
- return;
2130
- }
2131
- this.#node.insert(method, path16, handler);
2132
- }
2133
- match(method, path16) {
2134
- return this.#node.search(method, path16);
2135
- }
2136
- };
2137
-
2138
- // ../../node_modules/.pnpm/hono@4.11.5/node_modules/hono/dist/hono.js
2139
- var Hono2 = class extends Hono {
2140
- /**
2141
- * Creates an instance of the Hono class.
2142
- *
2143
- * @param options - Optional configuration options for the Hono instance.
2144
- */
2145
- constructor(options = {}) {
2146
- super(options);
2147
- this.router = options.router ?? new SmartRouter({
2148
- routers: [new RegExpRouter(), new TrieRouter()]
2149
- });
2150
- }
2151
- };
2152
-
2153
- // src/server/createApp.ts
2154
- import { contextMiddleware, resolveRoutesDir } from "@cloudwerk/core";
2155
- import { setActiveRenderer, getAvailableRenderers } from "@cloudwerk/ui";
2156
-
2157
- // src/server/registerRoutes.ts
2158
- import * as path8 from "path";
2159
- import {
2160
- createHandlerAdapter,
2161
- setRouteConfig,
2162
- NotFoundError,
2163
- RedirectError,
2164
- resolveErrorBoundary,
2165
- resolveNotFoundBoundary,
2166
- resolveLoadingBoundary
2167
- } from "@cloudwerk/core";
2168
- import {
2169
- render,
2170
- renderStream,
2171
- renderToStream,
2172
- generateHydrationScript,
2173
- generatePreloadHints
2174
- } from "@cloudwerk/ui";
2175
-
2176
- // src/server/loadHandler.ts
2177
- import * as fs from "fs";
2178
- import * as path from "path";
2179
- import { builtinModules } from "module";
2180
- import { build } from "esbuild";
2181
- import { pathToFileURL } from "url";
2182
- import { validateRouteConfig } from "@cloudwerk/core";
2183
- var moduleCache = /* @__PURE__ */ new Map();
2184
- async function loadRouteHandler(absolutePath, verbose = false) {
2185
- try {
2186
- const stat = fs.statSync(absolutePath);
2187
- const mtime = stat.mtimeMs;
2188
- const cached = moduleCache.get(absolutePath);
2189
- if (cached && cached.mtime === mtime) {
2190
- return cached.module;
2191
- }
2192
- const nodeVersion = process.versions.node.split(".")[0];
2193
- const target = `node${nodeVersion}`;
2194
- const result = await build({
2195
- entryPoints: [absolutePath],
2196
- bundle: true,
2197
- write: false,
2198
- format: "esm",
2199
- platform: "node",
2200
- target,
2201
- external: [
2202
- "@cloudwerk/core",
2203
- "hono",
2204
- // Use builtinModules for comprehensive Node.js built-in coverage
2205
- ...builtinModules,
2206
- ...builtinModules.map((m) => `node:${m}`)
2207
- ],
2208
- logLevel: verbose ? "warning" : "silent",
2209
- sourcemap: "inline"
2210
- });
2211
- if (!result.outputFiles || result.outputFiles.length === 0) {
2212
- throw new Error("No output from esbuild");
2213
- }
2214
- const code = result.outputFiles[0].text;
2215
- const cacheKey = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2216
- const tempDir = findSafeTempDir(absolutePath);
2217
- const tempFile = path.join(tempDir, `.cloudwerk-route-${cacheKey}.mjs`);
2218
- fs.writeFileSync(tempFile, code);
2219
- try {
2220
- const rawModule = await import(pathToFileURL(tempFile).href);
2221
- let validatedConfig = void 0;
2222
- if ("config" in rawModule) {
2223
- validatedConfig = validateRouteConfig(rawModule.config, absolutePath);
2224
- }
2225
- const module = {
2226
- ...rawModule,
2227
- config: validatedConfig
2228
- };
2229
- moduleCache.set(absolutePath, { module, mtime });
2230
- return module;
2231
- } finally {
2232
- try {
2233
- fs.unlinkSync(tempFile);
2234
- } catch {
2235
- }
2236
- }
2237
- } catch (error) {
2238
- const message = error instanceof Error ? error.message : String(error);
2239
- throw new Error(`Failed to compile route handler at ${absolutePath}: ${message}`);
2240
- }
2241
- }
2242
- function findSafeTempDir(filePath) {
2243
- let dir = path.dirname(filePath);
2244
- const hasSpecialChars = (p) => /\[|\]|\(|\)/.test(path.basename(p));
2245
- while (hasSpecialChars(dir)) {
2246
- const parent = path.dirname(dir);
2247
- if (parent === dir) {
2248
- break;
2249
- }
2250
- dir = parent;
2251
- }
2252
- return dir;
2253
- }
2254
-
2255
- // src/server/loadMiddleware.ts
2256
- import * as fs2 from "fs";
2257
- import * as path2 from "path";
2258
- import { builtinModules as builtinModules2 } from "module";
2259
- import { build as build2 } from "esbuild";
2260
- import { pathToFileURL as pathToFileURL2 } from "url";
2261
- import { createMiddlewareAdapter } from "@cloudwerk/core";
2262
- var middlewareCache = /* @__PURE__ */ new Map();
2263
- async function loadMiddlewareModule(absolutePath, verbose = false) {
2264
- if (!fs2.existsSync(absolutePath)) {
2265
- if (verbose) {
2266
- console.warn(`Middleware not found: ${absolutePath}`);
2267
- }
2268
- return null;
2269
- }
2270
- try {
2271
- const stat = fs2.statSync(absolutePath);
2272
- const mtime = stat.mtimeMs;
2273
- const cached = middlewareCache.get(absolutePath);
2274
- if (cached && cached.mtime === mtime) {
2275
- return extractMiddleware(cached.module, absolutePath, verbose);
2276
- }
2277
- const nodeVersion = process.versions.node.split(".")[0];
2278
- const target = `node${nodeVersion}`;
2279
- const result = await build2({
2280
- entryPoints: [absolutePath],
2281
- bundle: true,
2282
- write: false,
2283
- format: "esm",
2284
- platform: "node",
2285
- target,
2286
- external: [
2287
- "@cloudwerk/core",
2288
- "hono",
2289
- // Use builtinModules for comprehensive Node.js built-in coverage
2290
- ...builtinModules2,
2291
- ...builtinModules2.map((m) => `node:${m}`)
2292
- ],
2293
- logLevel: verbose ? "warning" : "silent",
2294
- sourcemap: "inline"
2295
- });
2296
- if (!result.outputFiles || result.outputFiles.length === 0) {
2297
- throw new Error("No output from esbuild");
2298
- }
2299
- const cacheKey = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2300
- const tempDir = findSafeTempDir2(absolutePath);
2301
- const tempFile = path2.join(tempDir, `.cloudwerk-middleware-${cacheKey}.mjs`);
2302
- fs2.writeFileSync(tempFile, result.outputFiles[0].text);
2303
- try {
2304
- const module = await import(pathToFileURL2(tempFile).href);
2305
- middlewareCache.set(absolutePath, { module, mtime });
2306
- return extractMiddleware(module, absolutePath, verbose);
2307
- } finally {
2308
- try {
2309
- fs2.unlinkSync(tempFile);
2310
- } catch {
2311
- }
2312
- }
2313
- } catch (error) {
2314
- const message = error instanceof Error ? error.message : String(error);
2315
- console.error(`Failed to compile middleware at ${absolutePath}: ${message}`);
2316
- return null;
2317
- }
2318
- }
2319
- function extractMiddleware(module, absolutePath, verbose) {
2320
- const middleware = module.default ?? module.middleware;
2321
- if (!middleware) {
2322
- if (verbose) {
2323
- console.warn(
2324
- `Middleware at ${absolutePath} must export a default function or named 'middleware' export`
2325
- );
2326
- }
2327
- return null;
2328
- }
2329
- if (typeof middleware !== "function") {
2330
- console.warn(
2331
- `Middleware in ${absolutePath} must export a function, got ${typeof middleware}`
2332
- );
2333
- return null;
2334
- }
2335
- return createMiddlewareAdapter(middleware);
2336
- }
2337
- function findSafeTempDir2(filePath) {
2338
- let dir = path2.dirname(filePath);
2339
- const hasSpecialChars = (p) => /\[|\]|\(|\)/.test(path2.basename(p));
2340
- while (hasSpecialChars(dir)) {
2341
- const parent = path2.dirname(dir);
2342
- if (parent === dir) {
2343
- break;
2344
- }
2345
- dir = parent;
2346
- }
2347
- return dir;
2348
- }
2349
-
2350
- // src/server/loadPage.ts
2351
- import * as fs3 from "fs";
2352
- import * as path3 from "path";
2353
- import { builtinModules as builtinModules3 } from "module";
2354
- import { build as build3 } from "esbuild";
2355
- import { pathToFileURL as pathToFileURL3 } from "url";
2356
- import { validateRouteConfig as validateRouteConfig2, hasUseClientDirective, generateComponentId, validateComponentBoundaries, handleBoundaryValidationResult } from "@cloudwerk/core";
2357
- var pageModuleCache = /* @__PURE__ */ new Map();
2358
- async function loadPageModule(absolutePath, verbose = false) {
2359
- try {
2360
- const stat = fs3.statSync(absolutePath);
2361
- const mtime = stat.mtimeMs;
2362
- const cached = pageModuleCache.get(absolutePath);
2363
- if (cached && cached.mtime === mtime) {
2364
- return cached.module;
2365
- }
2366
- const nodeVersion = process.versions.node.split(".")[0];
2367
- const target = `node${nodeVersion}`;
2368
- const result = await build3({
2369
- entryPoints: [absolutePath],
2370
- bundle: true,
2371
- write: false,
2372
- format: "esm",
2373
- platform: "node",
2374
- target,
2375
- jsx: "automatic",
2376
- jsxImportSource: "hono/jsx",
2377
- external: [
2378
- "@cloudwerk/core",
2379
- "@cloudwerk/ui",
2380
- "hono",
2381
- "hono/jsx",
2382
- "hono/jsx/dom",
2383
- "hono/jsx/streaming",
2384
- "hono/html",
2385
- // Use builtinModules for comprehensive Node.js built-in coverage
2386
- ...builtinModules3,
2387
- ...builtinModules3.map((m) => `node:${m}`)
2388
- ],
2389
- logLevel: verbose ? "warning" : "silent",
2390
- sourcemap: "inline"
2391
- });
2392
- if (!result.outputFiles || result.outputFiles.length === 0) {
2393
- throw new Error("No output from esbuild");
2394
- }
2395
- const code = result.outputFiles[0].text;
2396
- const sourceCode = fs3.readFileSync(absolutePath, "utf-8");
2397
- const isClientComponent = hasUseClientDirective(sourceCode);
2398
- const clientComponentId = isClientComponent ? generateComponentId(absolutePath, path3.dirname(absolutePath)) : void 0;
2399
- const validationResult = validateComponentBoundaries(sourceCode, absolutePath, isClientComponent);
2400
- handleBoundaryValidationResult(validationResult, absolutePath, { verbose });
2401
- const cacheKey = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2402
- const tempDir = findSafeTempDir3(absolutePath);
2403
- const tempFile = path3.join(tempDir, `.cloudwerk-page-${cacheKey}.mjs`);
2404
- fs3.writeFileSync(tempFile, code);
2405
- try {
2406
- const rawModule = await import(pathToFileURL3(tempFile).href);
2407
- if (!rawModule.default) {
2408
- throw new Error("Page must have a default export");
2409
- }
2410
- if (typeof rawModule.default !== "function") {
2411
- throw new Error(
2412
- `Page default export must be a function (component), got ${typeof rawModule.default}`
2413
- );
2414
- }
2415
- let validatedConfig = void 0;
2416
- if ("config" in rawModule && rawModule.config !== void 0) {
2417
- validatedConfig = validateRouteConfig2(rawModule.config, absolutePath);
2418
- }
2419
- let validatedLoader = void 0;
2420
- if ("loader" in rawModule && rawModule.loader !== void 0) {
2421
- if (typeof rawModule.loader !== "function") {
2422
- throw new Error(
2423
- `Page loader export must be a function, got ${typeof rawModule.loader}`
2424
- );
2425
- }
2426
- validatedLoader = rawModule.loader;
2427
- }
2428
- let validatedAction = void 0;
2429
- if ("action" in rawModule && rawModule.action !== void 0) {
2430
- if (typeof rawModule.action !== "function") {
2431
- throw new Error(
2432
- `Page action export must be a function, got ${typeof rawModule.action}`
2433
- );
2434
- }
2435
- validatedAction = rawModule.action;
2436
- }
2437
- const actionMethods = ["POST", "PUT", "PATCH", "DELETE"];
2438
- const validatedMethods = {};
2439
- for (const method of actionMethods) {
2440
- if (method in rawModule && rawModule[method] !== void 0) {
2441
- if (typeof rawModule[method] !== "function") {
2442
- throw new Error(
2443
- `Page ${method} export must be a function, got ${typeof rawModule[method]}`
2444
- );
2445
- }
2446
- validatedMethods[method] = rawModule[method];
2447
- }
2448
- }
2449
- let validatedGenerateStaticParams = void 0;
2450
- if ("generateStaticParams" in rawModule && rawModule.generateStaticParams !== void 0) {
2451
- if (typeof rawModule.generateStaticParams !== "function") {
2452
- throw new Error(
2453
- `Page generateStaticParams export must be a function, got ${typeof rawModule.generateStaticParams}`
2454
- );
2455
- }
2456
- validatedGenerateStaticParams = rawModule.generateStaticParams;
2457
- }
2458
- const module = {
2459
- default: rawModule.default,
2460
- config: validatedConfig,
2461
- loader: validatedLoader,
2462
- action: validatedAction,
2463
- ...validatedMethods,
2464
- isClientComponent,
2465
- clientComponentId,
2466
- generateStaticParams: validatedGenerateStaticParams
2467
- };
2468
- pageModuleCache.set(absolutePath, { module, mtime });
2469
- return module;
2470
- } finally {
2471
- try {
2472
- fs3.unlinkSync(tempFile);
2473
- } catch {
2474
- }
2475
- }
2476
- } catch (error) {
2477
- const message = error instanceof Error ? error.message : String(error);
2478
- throw new Error(`Failed to compile page at ${absolutePath}: ${message}`);
2479
- }
2480
- }
2481
- function findSafeTempDir3(filePath) {
2482
- let dir = path3.dirname(filePath);
2483
- const hasSpecialChars = (p) => /\[|\]|\(|\)/.test(path3.basename(p));
2484
- while (hasSpecialChars(dir)) {
2485
- const parent = path3.dirname(dir);
2486
- if (parent === dir) {
2487
- break;
2488
- }
2489
- dir = parent;
2490
- }
2491
- return dir;
2492
- }
2493
-
2494
- // src/server/loadLayout.ts
2495
- import * as fs4 from "fs";
2496
- import * as path4 from "path";
2497
- import { builtinModules as builtinModules4 } from "module";
2498
- import { build as build4 } from "esbuild";
2499
- import { pathToFileURL as pathToFileURL4 } from "url";
2500
- import { hasUseClientDirective as hasUseClientDirective2, generateComponentId as generateComponentId2, validateComponentBoundaries as validateComponentBoundaries2, handleBoundaryValidationResult as handleBoundaryValidationResult2 } from "@cloudwerk/core";
2501
- var layoutModuleCache = /* @__PURE__ */ new Map();
2502
- async function loadLayoutModule(absolutePath, verbose = false) {
2503
- try {
2504
- const stat = fs4.statSync(absolutePath);
2505
- const mtime = stat.mtimeMs;
2506
- const cached = layoutModuleCache.get(absolutePath);
2507
- if (cached && cached.mtime === mtime) {
2508
- return cached.module;
2509
- }
2510
- const nodeVersion = process.versions.node.split(".")[0];
2511
- const target = `node${nodeVersion}`;
2512
- const result = await build4({
2513
- entryPoints: [absolutePath],
2514
- bundle: true,
2515
- write: false,
2516
- format: "esm",
2517
- platform: "node",
2518
- target,
2519
- jsx: "automatic",
2520
- jsxImportSource: "hono/jsx",
2521
- external: [
2522
- "@cloudwerk/core",
2523
- "@cloudwerk/ui",
2524
- "hono",
2525
- "hono/jsx",
2526
- "hono/jsx/dom",
2527
- "hono/jsx/streaming",
2528
- "hono/html",
2529
- // Use builtinModules for comprehensive Node.js built-in coverage
2530
- ...builtinModules4,
2531
- ...builtinModules4.map((m) => `node:${m}`)
2532
- ],
2533
- logLevel: verbose ? "warning" : "silent",
2534
- sourcemap: "inline"
2535
- });
2536
- if (!result.outputFiles || result.outputFiles.length === 0) {
2537
- throw new Error("No output from esbuild");
2538
- }
2539
- const code = result.outputFiles[0].text;
2540
- const sourceCode = fs4.readFileSync(absolutePath, "utf-8");
2541
- const isClientComponent = hasUseClientDirective2(sourceCode);
2542
- const clientComponentId = isClientComponent ? generateComponentId2(absolutePath, path4.dirname(absolutePath)) : void 0;
2543
- const validationResult = validateComponentBoundaries2(sourceCode, absolutePath, isClientComponent);
2544
- handleBoundaryValidationResult2(validationResult, absolutePath, { verbose });
2545
- const cacheKey = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2546
- const tempDir = findSafeTempDir4(absolutePath);
2547
- const tempFile = path4.join(tempDir, `.cloudwerk-layout-${cacheKey}.mjs`);
2548
- fs4.writeFileSync(tempFile, code);
2549
- try {
2550
- const rawModule = await import(pathToFileURL4(tempFile).href);
2551
- if (!rawModule.default) {
2552
- throw new Error("Layout must have a default export");
2553
- }
2554
- if (typeof rawModule.default !== "function") {
2555
- throw new Error(
2556
- `Layout default export must be a function (component), got ${typeof rawModule.default}`
2557
- );
2558
- }
2559
- let validatedLoader = void 0;
2560
- if ("loader" in rawModule && rawModule.loader !== void 0) {
2561
- if (typeof rawModule.loader !== "function") {
2562
- throw new Error(
2563
- `Layout loader export must be a function, got ${typeof rawModule.loader}`
2564
- );
2565
- }
2566
- validatedLoader = rawModule.loader;
2567
- }
2568
- const module = {
2569
- default: rawModule.default,
2570
- loader: validatedLoader,
2571
- isClientComponent,
2572
- clientComponentId
2573
- };
2574
- layoutModuleCache.set(absolutePath, { module, mtime });
2575
- return module;
2576
- } finally {
2577
- try {
2578
- fs4.unlinkSync(tempFile);
2579
- } catch {
2580
- }
2581
- }
2582
- } catch (error) {
2583
- const message = error instanceof Error ? error.message : String(error);
2584
- throw new Error(`Failed to compile layout at ${absolutePath}: ${message}`);
2585
- }
2586
- }
2587
- function findSafeTempDir4(filePath) {
2588
- let dir = path4.dirname(filePath);
2589
- const hasSpecialChars = (p) => /\[|\]|\(|\)/.test(path4.basename(p));
2590
- while (hasSpecialChars(dir)) {
2591
- const parent = path4.dirname(dir);
2592
- if (parent === dir) {
2593
- break;
2594
- }
2595
- dir = parent;
2596
- }
2597
- return dir;
2598
- }
2599
-
2600
- // src/server/loadErrorBoundary.ts
2601
- import * as fs5 from "fs";
2602
- import * as path5 from "path";
2603
- import { builtinModules as builtinModules5 } from "module";
2604
- import { build as build5 } from "esbuild";
2605
- import { pathToFileURL as pathToFileURL5 } from "url";
2606
- var errorBoundaryModuleCache = /* @__PURE__ */ new Map();
2607
- async function loadErrorBoundaryModule(absolutePath, verbose = false) {
2608
- try {
2609
- const stat = fs5.statSync(absolutePath);
2610
- const mtime = stat.mtimeMs;
2611
- const cached = errorBoundaryModuleCache.get(absolutePath);
2612
- if (cached && cached.mtime === mtime) {
2613
- return cached.module;
2614
- }
2615
- const nodeVersion = process.versions.node.split(".")[0];
2616
- const target = `node${nodeVersion}`;
2617
- const result = await build5({
2618
- entryPoints: [absolutePath],
2619
- bundle: true,
2620
- write: false,
2621
- format: "esm",
2622
- platform: "node",
2623
- target,
2624
- jsx: "automatic",
2625
- jsxImportSource: "hono/jsx",
2626
- external: [
2627
- "@cloudwerk/core",
2628
- "@cloudwerk/ui",
2629
- "hono",
2630
- "hono/jsx",
2631
- "hono/jsx/dom",
2632
- "hono/jsx/streaming",
2633
- "hono/html",
2634
- // Use builtinModules for comprehensive Node.js built-in coverage
2635
- ...builtinModules5,
2636
- ...builtinModules5.map((m) => `node:${m}`)
2637
- ],
2638
- logLevel: verbose ? "warning" : "silent",
2639
- sourcemap: "inline"
2640
- });
2641
- if (!result.outputFiles || result.outputFiles.length === 0) {
2642
- throw new Error("No output from esbuild");
2643
- }
2644
- const code = result.outputFiles[0].text;
2645
- const cacheKey = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2646
- const tempDir = findSafeTempDir5(absolutePath);
2647
- const tempFile = path5.join(tempDir, `.cloudwerk-error-${cacheKey}.mjs`);
2648
- fs5.writeFileSync(tempFile, code);
2649
- try {
2650
- const rawModule = await import(pathToFileURL5(tempFile).href);
2651
- if (!rawModule.default) {
2652
- throw new Error("Error boundary must have a default export");
2653
- }
2654
- if (typeof rawModule.default !== "function") {
2655
- throw new Error(
2656
- `Error boundary default export must be a function (component), got ${typeof rawModule.default}`
2657
- );
2658
- }
2659
- let validatedLoader = void 0;
2660
- if ("loader" in rawModule && rawModule.loader !== void 0) {
2661
- if (typeof rawModule.loader !== "function") {
2662
- throw new Error(
2663
- `Error boundary loader export must be a function, got ${typeof rawModule.loader}`
2664
- );
2665
- }
2666
- validatedLoader = rawModule.loader;
2667
- }
2668
- const module = {
2669
- default: rawModule.default,
2670
- loader: validatedLoader
2671
- };
2672
- errorBoundaryModuleCache.set(absolutePath, { module, mtime });
2673
- return module;
2674
- } finally {
2675
- try {
2676
- fs5.unlinkSync(tempFile);
2677
- } catch {
2678
- }
2679
- }
2680
- } catch (error) {
2681
- const message = error instanceof Error ? error.message : String(error);
2682
- throw new Error(`Failed to compile error boundary at ${absolutePath}: ${message}`);
2683
- }
2684
- }
2685
- function findSafeTempDir5(filePath) {
2686
- let dir = path5.dirname(filePath);
2687
- const hasSpecialChars = (p) => /\[|\]|\(|\)/.test(path5.basename(p));
2688
- while (hasSpecialChars(dir)) {
2689
- const parent = path5.dirname(dir);
2690
- if (parent === dir) {
2691
- break;
2692
- }
2693
- dir = parent;
2694
- }
2695
- return dir;
2696
- }
2697
-
2698
- // src/server/loadNotFound.ts
2699
- import * as fs6 from "fs";
2700
- import * as path6 from "path";
2701
- import { builtinModules as builtinModules6 } from "module";
2702
- import { build as build6 } from "esbuild";
2703
- import { pathToFileURL as pathToFileURL6 } from "url";
2704
- var notFoundModuleCache = /* @__PURE__ */ new Map();
2705
- async function loadNotFoundModule(absolutePath, verbose = false) {
2706
- try {
2707
- const stat = fs6.statSync(absolutePath);
2708
- const mtime = stat.mtimeMs;
2709
- const cached = notFoundModuleCache.get(absolutePath);
2710
- if (cached && cached.mtime === mtime) {
2711
- return cached.module;
2712
- }
2713
- const nodeVersion = process.versions.node.split(".")[0];
2714
- const target = `node${nodeVersion}`;
2715
- const result = await build6({
2716
- entryPoints: [absolutePath],
2717
- bundle: true,
2718
- write: false,
2719
- format: "esm",
2720
- platform: "node",
2721
- target,
2722
- jsx: "automatic",
2723
- jsxImportSource: "hono/jsx",
2724
- external: [
2725
- "@cloudwerk/core",
2726
- "@cloudwerk/ui",
2727
- "hono",
2728
- "hono/jsx",
2729
- "hono/jsx/dom",
2730
- "hono/jsx/streaming",
2731
- "hono/html",
2732
- // Use builtinModules for comprehensive Node.js built-in coverage
2733
- ...builtinModules6,
2734
- ...builtinModules6.map((m) => `node:${m}`)
2735
- ],
2736
- logLevel: verbose ? "warning" : "silent",
2737
- sourcemap: "inline"
2738
- });
2739
- if (!result.outputFiles || result.outputFiles.length === 0) {
2740
- throw new Error("No output from esbuild");
2741
- }
2742
- const code = result.outputFiles[0].text;
2743
- const cacheKey = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2744
- const tempDir = findSafeTempDir6(absolutePath);
2745
- const tempFile = path6.join(tempDir, `.cloudwerk-not-found-${cacheKey}.mjs`);
2746
- fs6.writeFileSync(tempFile, code);
2747
- try {
2748
- const rawModule = await import(pathToFileURL6(tempFile).href);
2749
- if (!rawModule.default) {
2750
- throw new Error("Not-found boundary must have a default export");
2751
- }
2752
- if (typeof rawModule.default !== "function") {
2753
- throw new Error(
2754
- `Not-found boundary default export must be a function (component), got ${typeof rawModule.default}`
2755
- );
2756
- }
2757
- let validatedLoader = void 0;
2758
- if ("loader" in rawModule && rawModule.loader !== void 0) {
2759
- if (typeof rawModule.loader !== "function") {
2760
- throw new Error(
2761
- `Not-found boundary loader export must be a function, got ${typeof rawModule.loader}`
2762
- );
2763
- }
2764
- validatedLoader = rawModule.loader;
2765
- }
2766
- const module = {
2767
- default: rawModule.default,
2768
- loader: validatedLoader
2769
- };
2770
- notFoundModuleCache.set(absolutePath, { module, mtime });
2771
- return module;
2772
- } finally {
2773
- try {
2774
- fs6.unlinkSync(tempFile);
2775
- } catch {
2776
- }
2777
- }
2778
- } catch (error) {
2779
- const message = error instanceof Error ? error.message : String(error);
2780
- throw new Error(`Failed to compile not-found boundary at ${absolutePath}: ${message}`);
2781
- }
2782
- }
2783
- function findSafeTempDir6(filePath) {
2784
- let dir = path6.dirname(filePath);
2785
- const hasSpecialChars = (p) => /\[|\]|\(|\)/.test(path6.basename(p));
2786
- while (hasSpecialChars(dir)) {
2787
- const parent = path6.dirname(dir);
2788
- if (parent === dir) {
2789
- break;
2790
- }
2791
- dir = parent;
2792
- }
2793
- return dir;
2794
- }
2795
-
2796
- // src/server/loadLoading.ts
2797
- import * as fs7 from "fs";
2798
- import * as path7 from "path";
2799
- import { builtinModules as builtinModules7 } from "module";
2800
- import { build as build7 } from "esbuild";
2801
- import { pathToFileURL as pathToFileURL7 } from "url";
2802
- var loadingModuleCache = /* @__PURE__ */ new Map();
2803
- async function loadLoadingModule(absolutePath, verbose = false) {
2804
- try {
2805
- const stat = fs7.statSync(absolutePath);
2806
- const mtime = stat.mtimeMs;
2807
- const cached = loadingModuleCache.get(absolutePath);
2808
- if (cached && cached.mtime === mtime) {
2809
- return cached.module;
2810
- }
2811
- const nodeVersion = process.versions.node.split(".")[0];
2812
- const target = `node${nodeVersion}`;
2813
- const result = await build7({
2814
- entryPoints: [absolutePath],
2815
- bundle: true,
2816
- write: false,
2817
- format: "esm",
2818
- platform: "node",
2819
- target,
2820
- jsx: "automatic",
2821
- jsxImportSource: "hono/jsx",
2822
- external: [
2823
- "@cloudwerk/core",
2824
- "@cloudwerk/ui",
2825
- "hono",
2826
- "hono/jsx",
2827
- "hono/jsx/dom",
2828
- "hono/jsx/streaming",
2829
- "hono/html",
2830
- // Use builtinModules for comprehensive Node.js built-in coverage
2831
- ...builtinModules7,
2832
- ...builtinModules7.map((m) => `node:${m}`)
2833
- ],
2834
- logLevel: verbose ? "warning" : "silent",
2835
- sourcemap: "inline"
2836
- });
2837
- if (!result.outputFiles || result.outputFiles.length === 0) {
2838
- throw new Error("No output from esbuild");
2839
- }
2840
- const code = result.outputFiles[0].text;
2841
- const cacheKey = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2842
- const tempDir = findSafeTempDir7(absolutePath);
2843
- const tempFile = path7.join(tempDir, `.cloudwerk-loading-${cacheKey}.mjs`);
2844
- fs7.writeFileSync(tempFile, code);
2845
- try {
2846
- const rawModule = await import(pathToFileURL7(tempFile).href);
2847
- if (!rawModule.default) {
2848
- throw new Error("Loading boundary must have a default export");
2849
- }
2850
- if (typeof rawModule.default !== "function") {
2851
- throw new Error(
2852
- `Loading boundary default export must be a function (component), got ${typeof rawModule.default}`
2853
- );
2854
- }
2855
- let validatedConfig = void 0;
2856
- if ("config" in rawModule && rawModule.config !== void 0) {
2857
- if (typeof rawModule.config !== "object" || rawModule.config === null) {
2858
- throw new Error(
2859
- `Loading boundary config export must be an object, got ${typeof rawModule.config}`
2860
- );
2861
- }
2862
- validatedConfig = rawModule.config;
2863
- }
2864
- const module = {
2865
- default: rawModule.default,
2866
- config: validatedConfig
2867
- };
2868
- loadingModuleCache.set(absolutePath, { module, mtime });
2869
- return module;
2870
- } finally {
2871
- try {
2872
- fs7.unlinkSync(tempFile);
2873
- } catch {
2874
- }
2875
- }
2876
- } catch (error) {
2877
- const message = error instanceof Error ? error.message : String(error);
2878
- throw new Error(`Failed to compile loading boundary at ${absolutePath}: ${message}`);
2879
- }
2880
- }
2881
- function findSafeTempDir7(filePath) {
2882
- let dir = path7.dirname(filePath);
2883
- const hasSpecialChars = (p) => /\[|\]|\(|\)/.test(path7.basename(p));
2884
- while (hasSpecialChars(dir)) {
2885
- const parent = path7.dirname(dir);
2886
- if (parent === dir) {
2887
- break;
2888
- }
2889
- dir = parent;
2890
- }
2891
- return dir;
2892
- }
2893
-
2894
- // src/server/parseSearchParams.ts
2895
- function parseSearchParams(c) {
2896
- const result = {};
2897
- const url = new URL(c.req.url);
2898
- for (const [key, value] of url.searchParams.entries()) {
2899
- const existing = result[key];
2900
- if (existing !== void 0) {
2901
- result[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
2902
- } else {
2903
- result[key] = value;
2904
- }
2905
- }
2906
- return result;
2907
- }
2908
-
2909
- // src/server/hydrationManifest.ts
2910
- import * as fs8 from "fs";
2911
- import { createHydrationManifest, addToHydrationManifest, hasUseClientDirective as hasUseClientDirective3, generateComponentId as generateComponentId3 } from "@cloudwerk/core";
2912
- function createManifestTracker(appDir, basePath = "/__cloudwerk") {
2913
- return {
2914
- components: /* @__PURE__ */ new Map(),
2915
- basePath,
2916
- appDir
2917
- };
2918
- }
2919
- function trackIfClientComponent(tracker, filePath) {
2920
- if (tracker.components.has(filePath)) {
2921
- return true;
2922
- }
2923
- try {
2924
- const content = fs8.readFileSync(filePath, "utf-8");
2925
- if (hasUseClientDirective3(content)) {
2926
- const componentId = generateComponentId3(filePath, tracker.appDir);
2927
- tracker.components.set(filePath, {
2928
- filePath,
2929
- componentId,
2930
- exportName: "default",
2931
- bundled: false
2932
- });
2933
- return true;
2934
- }
2935
- } catch (error) {
2936
- return false;
2937
- }
2938
- return false;
2939
- }
2940
- function createRequestScopedManifest(tracker, usedComponentIds) {
2941
- const manifest = createHydrationManifest(tracker.basePath);
2942
- for (const component of tracker.components.values()) {
2943
- if (usedComponentIds.has(component.componentId)) {
2944
- addToHydrationManifest(
2945
- manifest,
2946
- {
2947
- filePath: component.filePath,
2948
- componentId: component.componentId,
2949
- exportName: component.exportName
2950
- },
2951
- `${tracker.basePath}/${component.componentId}.js`
2952
- );
2953
- }
2954
- }
2955
- return manifest;
2956
- }
2957
- function getComponentByIdFromTracker(tracker, componentId) {
2958
- for (const component of tracker.components.values()) {
2959
- if (component.componentId === componentId) {
2960
- return component;
2961
- }
2962
- }
2963
- return void 0;
2964
- }
2965
-
2966
- // src/server/registerRoutes.ts
2967
- var HTTP_METHODS = [
2968
- "GET",
2969
- "POST",
2970
- "PUT",
2971
- "PATCH",
2972
- "DELETE",
2973
- "OPTIONS",
2974
- "HEAD"
2975
- ];
2976
- async function injectHydrationScripts(response, hydrationCtx) {
2977
- if (hydrationCtx.usedComponentIds.size === 0) {
2978
- return response;
2979
- }
2980
- const manifest = createRequestScopedManifest(
2981
- hydrationCtx.tracker,
2982
- hydrationCtx.usedComponentIds
2983
- );
2984
- const preloadHints = generatePreloadHints(manifest);
2985
- const hydrationScript = generateHydrationScript(manifest);
2986
- if (!preloadHints && !hydrationScript) {
2987
- return response;
2988
- }
2989
- const html = await response.text();
2990
- let modifiedHtml = html;
2991
- if (preloadHints) {
2992
- const headEndIndex = modifiedHtml.indexOf("</head>");
2993
- if (headEndIndex !== -1) {
2994
- modifiedHtml = modifiedHtml.slice(0, headEndIndex) + "\n" + preloadHints + "\n" + modifiedHtml.slice(headEndIndex);
2995
- }
2996
- }
2997
- if (hydrationScript) {
2998
- const bodyEndIndex = modifiedHtml.lastIndexOf("</body>");
2999
- if (bodyEndIndex !== -1) {
3000
- modifiedHtml = modifiedHtml.slice(0, bodyEndIndex) + "\n" + hydrationScript + "\n" + modifiedHtml.slice(bodyEndIndex);
3001
- }
3002
- }
3003
- return new Response(modifiedHtml, {
3004
- status: response.status,
3005
- statusText: response.statusText,
3006
- headers: response.headers
3007
- });
3008
- }
3009
- function isCloudwerkHandler(fn) {
3010
- return typeof fn === "function" && fn.length === 2;
3011
- }
3012
- function createConfigMiddleware(config) {
3013
- return async (_c, next) => {
3014
- setRouteConfig(config);
3015
- await next();
3016
- };
3017
- }
3018
- async function executeLoader(loader, args, c) {
3019
- try {
3020
- const data = await Promise.resolve(loader(args));
3021
- return { data: data ?? {} };
3022
- } catch (error) {
3023
- if (error instanceof RedirectError) {
3024
- return { response: c.redirect(error.url, error.status) };
3025
- }
3026
- throw error;
3027
- }
3028
- }
3029
- async function executeAction(action, args, c) {
3030
- try {
3031
- const result = await Promise.resolve(action(args));
3032
- if (result instanceof Response) {
3033
- return { response: result };
3034
- }
3035
- return { data: result ?? {} };
3036
- } catch (error) {
3037
- if (error instanceof RedirectError) {
3038
- return { response: c.redirect(error.url, error.status) };
3039
- }
3040
- throw error;
3041
- }
3042
- }
3043
- async function registerRoutes(app, manifest, scanResult, logger, verbose = false, hydrationTracker) {
3044
- const registeredRoutes = [];
3045
- for (const route of manifest.routes) {
3046
- if (route.fileType === "page") {
3047
- try {
3048
- logger.debug(`Loading page: ${route.filePath}`);
3049
- const pageModule = await loadPageModule(route.absolutePath, verbose);
3050
- const PageComponent = pageModule.default;
3051
- if (hydrationTracker && pageModule.isClientComponent) {
3052
- trackIfClientComponent(hydrationTracker, route.absolutePath);
3053
- if (verbose) {
3054
- logger.debug(`Tracked client component: ${route.filePath}`);
3055
- }
3056
- }
3057
- const layoutModules = await Promise.all(
3058
- route.layouts.map((layoutPath) => loadLayoutModule(layoutPath, verbose))
3059
- );
3060
- const layouts = layoutModules.map((m) => m.default);
3061
- if (hydrationTracker) {
3062
- for (let i = 0; i < layoutModules.length; i++) {
3063
- if (layoutModules[i].isClientComponent) {
3064
- trackIfClientComponent(hydrationTracker, route.layouts[i]);
3065
- if (verbose) {
3066
- logger.debug(`Tracked client layout: ${route.layouts[i]}`);
3067
- }
3068
- }
3069
- }
3070
- }
3071
- const loadingPath = resolveLoadingBoundary(route.filePath, scanResult.loading);
3072
- let loadingModule = null;
3073
- if (loadingPath) {
3074
- try {
3075
- loadingModule = await loadLoadingModule(loadingPath, verbose);
3076
- if (verbose) {
3077
- logger.info(`Loaded loading boundary: ${loadingPath} -> ${route.urlPattern}`);
3078
- }
3079
- } catch (loadingError) {
3080
- const loadingMessage = loadingError instanceof Error ? loadingError.message : String(loadingError);
3081
- logger.error(`Failed to load loading boundary: ${loadingMessage}`);
3082
- }
3083
- }
3084
- for (const middlewarePath of route.middleware) {
3085
- const middlewareHandler = await loadMiddlewareModule(middlewarePath, verbose);
3086
- if (middlewareHandler) {
3087
- app.use(route.urlPattern, middlewareHandler);
3088
- if (verbose) {
3089
- logger.info(
3090
- `Applied middleware: ${path8.basename(middlewarePath)} -> ${route.urlPattern}`
3091
- );
3092
- }
3093
- }
3094
- }
3095
- if (pageModule.config) {
3096
- app.use(route.urlPattern, createConfigMiddleware(pageModule.config));
3097
- if (verbose) {
3098
- logger.info(`Applied page config: ${route.filePath} -> ${route.urlPattern}`);
3099
- }
3100
- }
3101
- app.get(route.urlPattern, async (c) => {
3102
- const params = c.req.param();
3103
- const searchParams = parseSearchParams(c);
3104
- const request = c.req.raw;
3105
- const pathname = new URL(request.url).pathname;
3106
- const layoutLoaderData = [];
3107
- const hydrationCtx = hydrationTracker ? { usedComponentIds: /* @__PURE__ */ new Set(), tracker: hydrationTracker } : null;
3108
- if (hydrationCtx && pageModule.isClientComponent && pageModule.clientComponentId) {
3109
- hydrationCtx.usedComponentIds.add(pageModule.clientComponentId);
3110
- }
3111
- for (const layoutModule of layoutModules) {
3112
- if (hydrationCtx && layoutModule.isClientComponent && layoutModule.clientComponentId) {
3113
- hydrationCtx.usedComponentIds.add(layoutModule.clientComponentId);
3114
- }
3115
- }
3116
- const streamingDisabled = pageModule.config?.streaming === false;
3117
- const useStreaming = loadingModule && !streamingDisabled;
3118
- if (useStreaming && loadingModule) {
3119
- try {
3120
- const LoadingComponent = loadingModule.default;
3121
- const loadingProps = { params, searchParams, pathname };
3122
- let loadingElement = await Promise.resolve(LoadingComponent(loadingProps));
3123
- for (let i = layouts.length - 1; i >= 0; i--) {
3124
- const Layout = layouts[i];
3125
- const layoutProps = {
3126
- children: loadingElement,
3127
- params
3128
- // Pass empty objects for layout loader data since loaders haven't run
3129
- };
3130
- loadingElement = await Promise.resolve(Layout(layoutProps));
3131
- }
3132
- const contentPromise = (async () => {
3133
- const loaderArgs = { params, request, context: c };
3134
- for (let index = 0; index < layoutModules.length; index++) {
3135
- const layoutModule = layoutModules[index];
3136
- if (layoutModule.loader) {
3137
- const result = await executeLoader(layoutModule.loader, loaderArgs, c);
3138
- if (result.response) {
3139
- throw new Error("Redirect during streaming not supported");
3140
- }
3141
- layoutLoaderData[index] = result.data;
3142
- } else {
3143
- layoutLoaderData[index] = {};
3144
- }
3145
- }
3146
- let pageLoaderData = {};
3147
- if (pageModule.loader) {
3148
- const result = await executeLoader(pageModule.loader, loaderArgs, c);
3149
- if (result.response) {
3150
- throw new Error("Redirect during streaming not supported");
3151
- }
3152
- pageLoaderData = result.data;
3153
- }
3154
- const pageProps = { params, searchParams, ...pageLoaderData };
3155
- let element = await Promise.resolve(PageComponent(pageProps));
3156
- for (let i = layouts.length - 1; i >= 0; i--) {
3157
- const Layout = layouts[i];
3158
- const layoutProps = {
3159
- children: element,
3160
- params,
3161
- ...layoutLoaderData[i]
3162
- };
3163
- element = await Promise.resolve(Layout(layoutProps));
3164
- }
3165
- return element;
3166
- })();
3167
- return renderStream(loadingElement, contentPromise);
3168
- } catch (error) {
3169
- const message = error instanceof Error ? error.message : String(error);
3170
- logger.error(`Streaming error in ${route.filePath}: ${message}`);
3171
- }
3172
- }
3173
- try {
3174
- const loaderArgs = { params, request, context: c };
3175
- for (let index = 0; index < layoutModules.length; index++) {
3176
- const layoutModule = layoutModules[index];
3177
- if (layoutModule.loader) {
3178
- const result = await executeLoader(layoutModule.loader, loaderArgs, c);
3179
- if (result.response) {
3180
- return result.response;
3181
- }
3182
- layoutLoaderData[index] = result.data;
3183
- } else {
3184
- layoutLoaderData[index] = {};
3185
- }
3186
- }
3187
- let pageLoaderData = {};
3188
- if (pageModule.loader) {
3189
- const result = await executeLoader(pageModule.loader, loaderArgs, c);
3190
- if (result.response) {
3191
- return result.response;
3192
- }
3193
- pageLoaderData = result.data;
3194
- }
3195
- const pageProps = { params, searchParams, ...pageLoaderData };
3196
- let element = await Promise.resolve(PageComponent(pageProps));
3197
- for (let i = layouts.length - 1; i >= 0; i--) {
3198
- const Layout = layouts[i];
3199
- const layoutProps = {
3200
- children: element,
3201
- params,
3202
- ...layoutLoaderData[i]
3203
- };
3204
- element = await Promise.resolve(Layout(layoutProps));
3205
- }
3206
- const response = await renderToStream(element);
3207
- if (hydrationCtx && hydrationCtx.usedComponentIds.size > 0) {
3208
- return injectHydrationScripts(response, hydrationCtx);
3209
- }
3210
- return response;
3211
- } catch (error) {
3212
- if (error instanceof NotFoundError) {
3213
- const notFoundPath = resolveNotFoundBoundary(route.filePath, scanResult.notFound);
3214
- if (notFoundPath) {
3215
- try {
3216
- const notFoundModule = await loadNotFoundModule(notFoundPath, verbose);
3217
- const NotFoundComponent = notFoundModule.default;
3218
- const notFoundProps = { params, searchParams };
3219
- let notFoundElement = await Promise.resolve(NotFoundComponent(notFoundProps));
3220
- for (let i = layouts.length - 1; i >= 0; i--) {
3221
- const Layout = layouts[i];
3222
- const layoutProps = {
3223
- children: notFoundElement,
3224
- params,
3225
- ...layoutLoaderData[i]
3226
- };
3227
- notFoundElement = await Promise.resolve(Layout(layoutProps));
3228
- }
3229
- return render(notFoundElement, { status: 404 });
3230
- } catch (boundaryError) {
3231
- const boundaryMessage = boundaryError instanceof Error ? boundaryError.message : String(boundaryError);
3232
- logger.error(`Not-found boundary failed: ${boundaryMessage}`);
3233
- }
3234
- }
3235
- return c.notFound();
3236
- }
3237
- const errorPath = resolveErrorBoundary(route.filePath, scanResult.errors);
3238
- if (errorPath) {
3239
- try {
3240
- const errorModule = await loadErrorBoundaryModule(errorPath, verbose);
3241
- const ErrorComponent = errorModule.default;
3242
- const digest = crypto.randomUUID().slice(0, 8);
3243
- const originalMessage = error instanceof Error ? error.message : String(error);
3244
- logger.error(`Error [${digest}] in ${route.filePath}: ${originalMessage}`);
3245
- const sanitizedError = process.env.NODE_ENV === "production" ? Object.assign(new Error("An error occurred"), { digest }) : Object.assign(
3246
- error instanceof Error ? error : new Error(String(error)),
3247
- { digest }
3248
- );
3249
- const errorProps = {
3250
- error: sanitizedError,
3251
- errorType: "loader",
3252
- reset: () => {
3253
- },
3254
- params,
3255
- searchParams
3256
- };
3257
- let errorElement = await Promise.resolve(ErrorComponent(errorProps));
3258
- for (let i = layouts.length - 1; i >= 0; i--) {
3259
- const Layout = layouts[i];
3260
- const layoutProps = {
3261
- children: errorElement,
3262
- params,
3263
- ...layoutLoaderData[i]
3264
- };
3265
- errorElement = await Promise.resolve(Layout(layoutProps));
3266
- }
3267
- return render(errorElement, { status: 500 });
3268
- } catch (boundaryError) {
3269
- const boundaryMessage = boundaryError instanceof Error ? boundaryError.message : String(boundaryError);
3270
- logger.error(`Error boundary failed: ${boundaryMessage}`);
3271
- }
3272
- }
3273
- const message = error instanceof Error ? error.message : String(error);
3274
- logger.error(`Error rendering page ${route.filePath}: ${message}`);
3275
- return c.html(
3276
- `<!DOCTYPE html><html><body><h1>Internal Server Error</h1></body></html>`,
3277
- 500
3278
- );
3279
- }
3280
- });
3281
- registeredRoutes.push({
3282
- method: "GET",
3283
- pattern: route.urlPattern,
3284
- filePath: route.filePath
3285
- });
3286
- logger.debug(`Registered page ${route.urlPattern}`);
3287
- const actionMethods = ["POST", "PUT", "PATCH", "DELETE"];
3288
- for (const method of actionMethods) {
3289
- const action = pageModule[method] ?? pageModule.action;
3290
- if (action && typeof action === "function") {
3291
- const actionFn = action;
3292
- registerMethod(app, method, route.urlPattern, async (c) => {
3293
- const params = c.req.param();
3294
- const searchParams = parseSearchParams(c);
3295
- const request = c.req.raw;
3296
- const layoutLoaderData = [];
3297
- const actionHydrationCtx = hydrationTracker ? { usedComponentIds: /* @__PURE__ */ new Set(), tracker: hydrationTracker } : null;
3298
- if (actionHydrationCtx && pageModule.isClientComponent && pageModule.clientComponentId) {
3299
- actionHydrationCtx.usedComponentIds.add(pageModule.clientComponentId);
3300
- }
3301
- for (const layoutModule of layoutModules) {
3302
- if (actionHydrationCtx && layoutModule.isClientComponent && layoutModule.clientComponentId) {
3303
- actionHydrationCtx.usedComponentIds.add(layoutModule.clientComponentId);
3304
- }
3305
- }
3306
- try {
3307
- const actionArgs = { params, request, context: c };
3308
- const actionResult = await executeAction(actionFn, actionArgs, c);
3309
- if (actionResult.response) {
3310
- return actionResult.response;
3311
- }
3312
- const loaderArgs = { params, request, context: c };
3313
- for (let index = 0; index < layoutModules.length; index++) {
3314
- const layoutModule = layoutModules[index];
3315
- if (layoutModule.loader) {
3316
- const result = await executeLoader(layoutModule.loader, loaderArgs, c);
3317
- if (result.response) {
3318
- return result.response;
3319
- }
3320
- layoutLoaderData[index] = result.data;
3321
- } else {
3322
- layoutLoaderData[index] = {};
3323
- }
3324
- }
3325
- let pageLoaderData = {};
3326
- if (pageModule.loader) {
3327
- const result = await executeLoader(pageModule.loader, loaderArgs, c);
3328
- if (result.response) {
3329
- return result.response;
3330
- }
3331
- pageLoaderData = result.data;
3332
- }
3333
- const pageProps = {
3334
- params,
3335
- searchParams,
3336
- actionData: actionResult.data,
3337
- ...pageLoaderData
3338
- };
3339
- let element = await Promise.resolve(PageComponent(pageProps));
3340
- for (let i = layouts.length - 1; i >= 0; i--) {
3341
- const Layout = layouts[i];
3342
- const layoutProps = {
3343
- children: element,
3344
- params,
3345
- ...layoutLoaderData[i]
3346
- };
3347
- element = await Promise.resolve(Layout(layoutProps));
3348
- }
3349
- const actionResponse = await renderToStream(element);
3350
- if (actionHydrationCtx && actionHydrationCtx.usedComponentIds.size > 0) {
3351
- return injectHydrationScripts(actionResponse, actionHydrationCtx);
3352
- }
3353
- return actionResponse;
3354
- } catch (error) {
3355
- if (error instanceof NotFoundError) {
3356
- const notFoundPath = resolveNotFoundBoundary(route.filePath, scanResult.notFound);
3357
- if (notFoundPath) {
3358
- try {
3359
- const notFoundModule = await loadNotFoundModule(notFoundPath, verbose);
3360
- const NotFoundComponent = notFoundModule.default;
3361
- const notFoundProps = { params, searchParams };
3362
- let notFoundElement = await Promise.resolve(NotFoundComponent(notFoundProps));
3363
- for (let i = layouts.length - 1; i >= 0; i--) {
3364
- const Layout = layouts[i];
3365
- const layoutProps = {
3366
- children: notFoundElement,
3367
- params,
3368
- ...layoutLoaderData[i]
3369
- };
3370
- notFoundElement = await Promise.resolve(Layout(layoutProps));
3371
- }
3372
- return render(notFoundElement, { status: 404 });
3373
- } catch (boundaryError) {
3374
- const boundaryMessage = boundaryError instanceof Error ? boundaryError.message : String(boundaryError);
3375
- logger.error(`Not-found boundary failed: ${boundaryMessage}`);
3376
- }
3377
- }
3378
- return c.notFound();
3379
- }
3380
- const errorPath = resolveErrorBoundary(route.filePath, scanResult.errors);
3381
- if (errorPath) {
3382
- try {
3383
- const errorModule = await loadErrorBoundaryModule(errorPath, verbose);
3384
- const ErrorComponent = errorModule.default;
3385
- const digest = crypto.randomUUID().slice(0, 8);
3386
- const originalMessage = error instanceof Error ? error.message : String(error);
3387
- logger.error(`Error [${digest}] in ${route.filePath} action: ${originalMessage}`);
3388
- const sanitizedError = process.env.NODE_ENV === "production" ? Object.assign(new Error("An error occurred"), { digest }) : Object.assign(
3389
- error instanceof Error ? error : new Error(String(error)),
3390
- { digest }
3391
- );
3392
- const errorProps = {
3393
- error: sanitizedError,
3394
- errorType: "action",
3395
- reset: () => {
3396
- },
3397
- params,
3398
- searchParams
3399
- };
3400
- let errorElement = await Promise.resolve(ErrorComponent(errorProps));
3401
- for (let i = layouts.length - 1; i >= 0; i--) {
3402
- const Layout = layouts[i];
3403
- const layoutProps = {
3404
- children: errorElement,
3405
- params,
3406
- ...layoutLoaderData[i]
3407
- };
3408
- errorElement = await Promise.resolve(Layout(layoutProps));
3409
- }
3410
- return render(errorElement, { status: 500 });
3411
- } catch (boundaryError) {
3412
- const boundaryMessage = boundaryError instanceof Error ? boundaryError.message : String(boundaryError);
3413
- logger.error(`Error boundary failed: ${boundaryMessage}`);
3414
- }
3415
- }
3416
- const message = error instanceof Error ? error.message : String(error);
3417
- logger.error(`Error executing action ${route.filePath}: ${message}`);
3418
- return c.html(
3419
- `<!DOCTYPE html><html><body><h1>Internal Server Error</h1></body></html>`,
3420
- 500
3421
- );
3422
- }
3423
- });
3424
- registeredRoutes.push({
3425
- method,
3426
- pattern: route.urlPattern,
3427
- filePath: route.filePath
3428
- });
3429
- logger.debug(`Registered ${method} action ${route.urlPattern}`);
3430
- }
3431
- }
3432
- } catch (error) {
3433
- const message = error instanceof Error ? error.message : String(error);
3434
- logger.error(`Failed to load page ${route.filePath}: ${message}`);
3435
- }
3436
- continue;
3437
- }
3438
- if (route.fileType !== "route") {
3439
- logger.debug(`Skipping non-route file: ${route.filePath}`);
3440
- continue;
67
+ );
3441
68
  }
3442
- try {
3443
- for (const middlewarePath of route.middleware) {
3444
- const middlewareHandler = await loadMiddlewareModule(middlewarePath, verbose);
3445
- if (middlewareHandler) {
3446
- app.use(route.urlPattern, middlewareHandler);
3447
- if (verbose) {
3448
- logger.info(`Applied middleware: ${path8.basename(middlewarePath)} -> ${route.urlPattern}`);
3449
- }
3450
- }
3451
- }
3452
- logger.debug(`Loading route handler: ${route.filePath}`);
3453
- const module = await loadRouteHandler(route.absolutePath, verbose);
3454
- if (module.config) {
3455
- app.use(route.urlPattern, createConfigMiddleware(module.config));
3456
- if (verbose) {
3457
- logger.info(`Applied route config: ${route.filePath} -> ${route.urlPattern}`);
3458
- }
3459
- }
3460
- for (const method of HTTP_METHODS) {
3461
- const handler = module[method];
3462
- if (handler && typeof handler === "function") {
3463
- registerMethod(app, method, route.urlPattern, handler);
3464
- registeredRoutes.push({
3465
- method,
3466
- pattern: route.urlPattern,
3467
- filePath: route.filePath
3468
- });
3469
- logger.debug(`Registered ${method} ${route.urlPattern}`);
3470
- }
3471
- }
3472
- } catch (error) {
3473
- const message = error instanceof Error ? error.message : String(error);
3474
- logger.error(`Failed to load route ${route.filePath}: ${message}`);
69
+ if (remainingCount > 0) {
70
+ console.log(pc.dim(` ... and ${remainingCount} more routes`));
3475
71
  }
72
+ console.log();
3476
73
  }
3477
- return registeredRoutes;
74
+ console.log(pc.dim(` Ready in ${startupTime}ms`));
75
+ console.log();
3478
76
  }
3479
- function registerMethod(app, method, pattern, handler) {
3480
- const h = isCloudwerkHandler(handler) ? createHandlerAdapter(handler) : handler;
3481
- switch (method) {
77
+ function getMethodColor(method) {
78
+ switch (method.toUpperCase()) {
3482
79
  case "GET":
3483
- app.get(pattern, h);
3484
- break;
80
+ return pc.green;
3485
81
  case "POST":
3486
- app.post(pattern, h);
3487
- break;
82
+ return pc.blue;
3488
83
  case "PUT":
3489
- app.put(pattern, h);
3490
- break;
84
+ return pc.yellow;
3491
85
  case "PATCH":
3492
- app.patch(pattern, h);
3493
- break;
86
+ return pc.magenta;
3494
87
  case "DELETE":
3495
- app.delete(pattern, h);
3496
- break;
88
+ return pc.red;
3497
89
  case "OPTIONS":
3498
- app.options(pattern, h);
3499
- break;
90
+ return pc.cyan;
3500
91
  case "HEAD":
3501
- app.on("HEAD", [pattern], h);
3502
- break;
3503
- }
3504
- }
3505
-
3506
- // src/server/hydrationRoutes.ts
3507
- import {
3508
- generateHydrationRuntime as generateHydrationRuntime2,
3509
- generateReactHydrationRuntime as generateReactHydrationRuntime2
3510
- } from "@cloudwerk/ui";
3511
-
3512
- // src/server/clientBundle.ts
3513
- import * as fs9 from "fs";
3514
- import * as path9 from "path";
3515
- import { createRequire } from "module";
3516
- import { build as build8 } from "esbuild";
3517
- import { generateComponentId as generateComponentId4, createHydrationManifest as createHydrationManifest2, addToHydrationManifest as addToHydrationManifest2 } from "@cloudwerk/core";
3518
- import { generateHydrationRuntime, generateReactHydrationRuntime } from "@cloudwerk/ui";
3519
- var require2 = createRequire(import.meta.url);
3520
- var honoMainPath = require2.resolve("hono");
3521
- function findNodeModulesDir(filePath) {
3522
- let dir = filePath;
3523
- while (dir !== path9.dirname(dir)) {
3524
- dir = path9.dirname(dir);
3525
- if (path9.basename(dir) === "node_modules") {
3526
- return dir;
3527
- }
92
+ return pc.gray;
93
+ default:
94
+ return pc.white;
3528
95
  }
3529
- return path9.join(path9.dirname(filePath), "..", "..");
3530
96
  }
3531
- var nodeModulesPath = findNodeModulesDir(honoMainPath);
3532
- var bundleCache = /* @__PURE__ */ new Map();
3533
- async function generateBundleOnDemand(componentPath, appDir, options = {}) {
3534
- const { renderer = "hono-jsx" } = options;
3535
- const cacheKey = `${componentPath}:${renderer}`;
3536
- const stat = fs9.statSync(componentPath);
3537
- const cached = bundleCache.get(cacheKey);
3538
- if (cached && cached.mtime === stat.mtimeMs) {
3539
- return {
3540
- content: cached.content,
3541
- componentId: generateComponentId4(componentPath, appDir)
3542
- };
3543
- }
3544
- const jsxImportSource = renderer === "react" ? "react" : "hono/jsx/dom";
3545
- const result = await build8({
3546
- entryPoints: [componentPath],
3547
- bundle: true,
3548
- write: false,
3549
- format: "esm",
3550
- platform: "browser",
3551
- target: ["es2020", "chrome80", "firefox80", "safari14"],
3552
- jsx: "automatic",
3553
- jsxImportSource,
3554
- minify: false,
3555
- sourcemap: "inline",
3556
- define: {
3557
- "process.env.NODE_ENV": JSON.stringify("development")
3558
- },
3559
- logLevel: "silent",
3560
- // Resolve hono/react from the package's node_modules
3561
- nodePaths: [nodeModulesPath]
3562
- });
3563
- if (!result.outputFiles || result.outputFiles.length === 0) {
3564
- throw new Error("No output from esbuild");
97
+ function printError(message, suggestion) {
98
+ console.log();
99
+ console.log(pc.red("Error: ") + message);
100
+ if (suggestion) {
101
+ console.log();
102
+ console.log(pc.dim(" " + suggestion));
3565
103
  }
3566
- const content = result.outputFiles[0].text;
3567
- const componentId = generateComponentId4(componentPath, appDir);
3568
- bundleCache.set(cacheKey, {
3569
- content,
3570
- mtime: stat.mtimeMs,
3571
- bundlePath: `/__cloudwerk/${componentId}.js`
3572
- });
3573
- return { content, componentId };
104
+ console.log();
3574
105
  }
3575
106
 
3576
- // src/server/hydrationRoutes.ts
3577
- var runtimeCache = /* @__PURE__ */ new Map();
3578
- function registerHydrationRoutes(app, options) {
3579
- const { tracker, appDir, logger, verbose = false, renderer = "hono-jsx" } = options;
3580
- app.get("/__cloudwerk/runtime.js", (c) => {
3581
- if (verbose) {
3582
- logger.debug("Serving Hono JSX hydration runtime");
3583
- }
3584
- let runtime = runtimeCache.get("hono-jsx");
3585
- if (!runtime) {
3586
- runtime = generateHydrationRuntime2();
3587
- runtimeCache.set("hono-jsx", runtime);
3588
- }
3589
- return c.text(runtime, 200, {
3590
- "Content-Type": "application/javascript; charset=utf-8",
3591
- "Cache-Control": "public, max-age=31536000, immutable"
3592
- });
3593
- });
3594
- app.get("/__cloudwerk/react-runtime.js", (c) => {
3595
- if (verbose) {
3596
- logger.debug("Serving React hydration runtime");
3597
- }
3598
- let runtime = runtimeCache.get("react");
3599
- if (!runtime) {
3600
- runtime = generateReactHydrationRuntime2();
3601
- runtimeCache.set("react", runtime);
3602
- }
3603
- return c.text(runtime, 200, {
3604
- "Content-Type": "application/javascript; charset=utf-8",
3605
- "Cache-Control": "public, max-age=31536000, immutable"
3606
- });
3607
- });
3608
- app.get("/__cloudwerk/:componentId{.+\\.js$}", async (c) => {
3609
- const componentIdWithExt = c.req.param("componentId");
3610
- const componentId = componentIdWithExt.replace(/\.js$/, "");
3611
- if (verbose) {
3612
- logger.debug(`Serving component bundle: ${componentId}`);
3613
- }
3614
- const component = getComponentByIdFromTracker(tracker, componentId);
3615
- if (!component) {
3616
- logger.warn(`[Cloudwerk] Component not found: ${componentId}`);
3617
- return c.text(`// Component not found: ${componentId}`, 404, {
3618
- "Content-Type": "application/javascript; charset=utf-8"
3619
- });
3620
- }
3621
- try {
3622
- const { content } = await generateBundleOnDemand(
3623
- component.filePath,
3624
- appDir,
3625
- { renderer }
3626
- );
3627
- return c.text(content, 200, {
3628
- "Content-Type": "application/javascript; charset=utf-8",
3629
- "Cache-Control": "no-cache"
3630
- // Dev mode - always check for updates
3631
- });
3632
- } catch (error) {
3633
- const message = error instanceof Error ? error.message : String(error);
3634
- logger.error(`[Cloudwerk] Failed to bundle component ${componentId}: ${message}`);
3635
- return c.text(`// Bundle error: ${message}`, 500, {
3636
- "Content-Type": "application/javascript; charset=utf-8"
3637
- });
3638
- }
3639
- });
3640
- if (verbose) {
3641
- logger.info("Registered hydration routes at /__cloudwerk/*");
3642
- }
3643
- }
107
+ // src/version.ts
108
+ import { createRequire } from "module";
109
+ var require2 = createRequire(import.meta.url);
110
+ var pkg = require2("../package.json");
111
+ var VERSION = pkg.version;
3644
112
 
3645
113
  // src/constants.ts
3646
114
  var DEFAULT_PORT = 3e3;
3647
115
  var DEFAULT_HOST = "localhost";
3648
116
  var SHUTDOWN_TIMEOUT_MS = 5e3;
3649
- var HTTP_STATUS = {
3650
- NOT_FOUND: 404,
3651
- INTERNAL_SERVER_ERROR: 500
3652
- };
3653
-
3654
- // src/server/createApp.ts
3655
- async function createApp(manifest, scanResult, config, logger, verbose = false) {
3656
- const rendererName = config.ui?.renderer ?? "hono-jsx";
3657
- try {
3658
- setActiveRenderer(rendererName);
3659
- if (verbose) {
3660
- logger.info(`Using UI renderer: ${rendererName}`);
3661
- }
3662
- } catch (error) {
3663
- const available = getAvailableRenderers().join(", ");
3664
- throw new Error(
3665
- `Failed to initialize UI renderer "${rendererName}". Available renderers: ${available}.`,
3666
- { cause: error }
3667
- );
3668
- }
3669
- const app = new Hono2({
3670
- strict: false
3671
- });
3672
- app.use("*", contextMiddleware());
3673
- if (verbose) {
3674
- app.use("*", async (c, next) => {
3675
- const start = Date.now();
3676
- await next();
3677
- const duration = Date.now() - start;
3678
- logRequest(c.req.method, c.req.path, c.res.status, duration);
3679
- });
3680
- }
3681
- if (config.globalMiddleware && config.globalMiddleware.length > 0) {
3682
- for (const middleware of config.globalMiddleware) {
3683
- app.use("*", middleware);
3684
- }
3685
- }
3686
- const appDir = resolveRoutesDir(config, manifest.rootDir);
3687
- const hydrationTracker = createManifestTracker(appDir);
3688
- registerHydrationRoutes(app, {
3689
- tracker: hydrationTracker,
3690
- appDir,
3691
- logger,
3692
- verbose,
3693
- renderer: rendererName === "react" ? "react" : "hono-jsx"
3694
- });
3695
- const routes = await registerRoutes(app, manifest, scanResult, logger, verbose, hydrationTracker);
3696
- app.notFound((c) => {
3697
- return c.json(
3698
- {
3699
- error: "Not Found",
3700
- path: c.req.path,
3701
- method: c.req.method
3702
- },
3703
- HTTP_STATUS.NOT_FOUND
3704
- );
3705
- });
3706
- app.onError((err, c) => {
3707
- logger.error(`Request error: ${err.message}`);
3708
- return c.json(
3709
- {
3710
- error: "Internal Server Error",
3711
- message: err.message,
3712
- stack: err.stack
3713
- },
3714
- HTTP_STATUS.INTERNAL_SERVER_ERROR
3715
- );
3716
- });
3717
- return { app, routes };
3718
- }
3719
-
3720
- // src/version.ts
3721
- import { createRequire as createRequire2 } from "module";
3722
- var require3 = createRequire2(import.meta.url);
3723
- var pkg = require3("../package.json");
3724
- var VERSION = pkg.version;
3725
117
 
3726
118
  // src/commands/dev.ts
3727
119
  async function dev(pathArg, options) {
@@ -3729,8 +121,8 @@ async function dev(pathArg, options) {
3729
121
  const verbose = options.verbose ?? false;
3730
122
  const logger = createLogger(verbose);
3731
123
  try {
3732
- const cwd = pathArg ? path10.resolve(process.cwd(), pathArg) : process.cwd();
3733
- if (!fs10.existsSync(cwd)) {
124
+ const cwd = pathArg ? path.resolve(process.cwd(), pathArg) : process.cwd();
125
+ if (!fs.existsSync(cwd)) {
3734
126
  throw new CliError(
3735
127
  `Directory does not exist: ${cwd}`,
3736
128
  "ENOENT",
@@ -3738,47 +130,6 @@ async function dev(pathArg, options) {
3738
130
  );
3739
131
  }
3740
132
  logger.debug(`Working directory: ${cwd}`);
3741
- logger.debug(`Loading configuration...`);
3742
- const config = await loadConfig(cwd);
3743
- logger.debug(`Config loaded: routesDir=${config.routesDir}, extensions=${config.extensions.join(", ")}`);
3744
- const routesDir = resolveRoutesDir2(config, cwd);
3745
- logger.debug(`Routes directory: ${routesDir}`);
3746
- if (!fs10.existsSync(routesDir)) {
3747
- throw new CliError(
3748
- `Routes directory does not exist: ${routesDir}`,
3749
- "ENOENT",
3750
- `Create the "${config.routesDir}" directory or update routesDir in cloudwerk.config.ts`
3751
- );
3752
- }
3753
- logger.debug(`Scanning routes...`);
3754
- const scanResult = await scanRoutes(routesDir, config);
3755
- logger.debug(`Found ${scanResult.routes.length} route files`);
3756
- logger.debug(`Building route manifest...`);
3757
- const manifest = buildRouteManifest(
3758
- scanResult,
3759
- routesDir,
3760
- resolveLayouts,
3761
- resolveMiddleware
3762
- );
3763
- if (hasErrors(manifest)) {
3764
- const errorMessages = formatErrors(manifest.errors);
3765
- logger.error(errorMessages);
3766
- throw new CliError(
3767
- "Route validation failed",
3768
- "VALIDATION_ERROR",
3769
- "Fix the errors above and try again."
3770
- );
3771
- }
3772
- if (manifest.warnings.length > 0) {
3773
- const warningMessages = formatWarnings(manifest.warnings);
3774
- logger.warn(warningMessages);
3775
- }
3776
- if (manifest.routes.length === 0) {
3777
- logger.warn(`No routes found in ${config.routesDir}`);
3778
- logger.warn(`Create a route.ts file to get started.`);
3779
- }
3780
- logger.debug(`Creating Hono app...`);
3781
- const { app, routes } = await createApp(manifest, scanResult, config, logger, verbose);
3782
133
  const port = parseInt(options.port, 10);
3783
134
  if (isNaN(port) || port < 1 || port > 65535) {
3784
135
  throw new CliError(
@@ -3787,37 +138,56 @@ async function dev(pathArg, options) {
3787
138
  "Port must be a number between 1 and 65535"
3788
139
  );
3789
140
  }
3790
- logger.debug(`Starting server on port ${port}...`);
3791
- const host = options.host;
3792
- const server = serve({
3793
- fetch: app.fetch,
3794
- port,
3795
- hostname: host
3796
- });
3797
- server.on("error", (err) => {
3798
- if (err.code === "EADDRINUSE") {
3799
- printError(
3800
- `Port ${port} is already in use`,
3801
- `Try using a different port:
3802
- cloudwerk dev --port ${port + 1}`
3803
- );
3804
- process.exit(1);
3805
- } else {
3806
- printError(err.message);
3807
- process.exit(1);
3808
- }
3809
- });
3810
- await new Promise((resolve3) => {
3811
- server.on("listening", resolve3);
3812
- });
141
+ const viteConfig = {
142
+ root: cwd,
143
+ mode: "development",
144
+ server: {
145
+ port,
146
+ host: options.host,
147
+ strictPort: true
148
+ },
149
+ plugins: [
150
+ cloudwerk({
151
+ verbose
152
+ }),
153
+ devServer({
154
+ entry: "virtual:cloudwerk/server-entry"
155
+ })
156
+ ],
157
+ // Suppress Vite's default startup message - we'll print our own
158
+ logLevel: verbose ? "info" : "warn",
159
+ clearScreen: false
160
+ };
161
+ logger.debug(`Starting Vite dev server...`);
162
+ const server = await createServer(viteConfig);
163
+ await server.listen();
164
+ const resolvedPort = server.config.server.port ?? port;
165
+ const resolvedHost = server.config.server.host === true ? "0.0.0.0" : server.config.server.host ?? "localhost";
166
+ const localHost = resolvedHost === "0.0.0.0" ? "localhost" : resolvedHost;
167
+ const localUrl = `http://${localHost}:${resolvedPort}/`;
168
+ const networkUrl = resolvedHost === "0.0.0.0" ? getNetworkUrl(resolvedPort) : void 0;
3813
169
  const startupTime = Date.now() - startTime;
3814
- const localUrl = `http://${host === "0.0.0.0" ? "localhost" : host}:${port}/`;
3815
- const networkUrl = host === "0.0.0.0" ? getNetworkUrl(port) : void 0;
170
+ const routes = [];
171
+ try {
172
+ const manifestModule = await server.ssrLoadModule("virtual:cloudwerk/manifest");
173
+ const manifest = manifestModule.default;
174
+ if (manifest?.routes) {
175
+ for (const route of manifest.routes) {
176
+ if (route.fileType === "page") {
177
+ routes.push({ method: "GET", pattern: route.urlPattern });
178
+ } else if (route.fileType === "route") {
179
+ routes.push({ method: "ALL", pattern: route.urlPattern });
180
+ }
181
+ }
182
+ }
183
+ } catch {
184
+ logger.debug("Could not load route manifest for startup banner");
185
+ }
3816
186
  printStartupBanner(
3817
187
  VERSION,
3818
188
  localUrl,
3819
189
  networkUrl,
3820
- routes.map((r) => ({ method: r.method, pattern: r.pattern })),
190
+ routes,
3821
191
  startupTime
3822
192
  );
3823
193
  setupGracefulShutdown(server, logger);
@@ -3827,6 +197,15 @@ async function dev(pathArg, options) {
3827
197
  process.exit(1);
3828
198
  }
3829
199
  if (error instanceof Error) {
200
+ if (error.code === "EADDRINUSE") {
201
+ const port = parseInt(options.port, 10);
202
+ printError(
203
+ `Port ${port} is already in use`,
204
+ `Try using a different port:
205
+ cloudwerk dev --port ${port + 1}`
206
+ );
207
+ process.exit(1);
208
+ }
3830
209
  printError(error.message);
3831
210
  if (verbose && error.stack) {
3832
211
  console.log(error.stack);
@@ -3851,185 +230,55 @@ function getNetworkUrl(port) {
3851
230
  return void 0;
3852
231
  }
3853
232
  function setupGracefulShutdown(server, logger) {
3854
- const shutdown = () => {
233
+ const shutdown = async () => {
3855
234
  console.log();
3856
235
  logger.info("Shutting down...");
3857
- server.close(() => {
3858
- logger.info("Server closed");
3859
- process.exit(0);
3860
- });
236
+ await server.close();
237
+ logger.info("Server closed");
238
+ process.exit(0);
239
+ };
240
+ const forceShutdown = () => {
3861
241
  setTimeout(() => {
3862
242
  logger.warn("Forcing shutdown...");
3863
243
  process.exit(0);
3864
244
  }, SHUTDOWN_TIMEOUT_MS);
3865
245
  };
3866
- process.on("SIGINT", shutdown);
3867
- process.on("SIGTERM", shutdown);
3868
- }
3869
-
3870
- // src/commands/build.ts
3871
- import * as path12 from "path";
3872
- import * as fs12 from "fs";
3873
- import {
3874
- loadConfig as loadConfig2,
3875
- scanRoutes as scanRoutes2,
3876
- buildRouteManifest as buildRouteManifest2,
3877
- resolveLayouts as resolveLayouts2,
3878
- resolveMiddleware as resolveMiddleware2,
3879
- resolveRoutesDir as resolveRoutesDir3,
3880
- hasErrors as hasErrors2,
3881
- formatErrors as formatErrors2,
3882
- formatWarnings as formatWarnings2
3883
- } from "@cloudwerk/core";
3884
-
3885
- // src/server/ssg.ts
3886
- import * as fs11 from "fs/promises";
3887
- import * as path11 from "path";
3888
- async function getStaticRoutesAsync(manifest, logger) {
3889
- const staticRoutes = [];
3890
- for (const route of manifest.routes) {
3891
- if (route.fileType !== "page") {
3892
- continue;
3893
- }
3894
- try {
3895
- const module = await loadPageModule(route.absolutePath);
3896
- if (module.config?.rendering === "static") {
3897
- staticRoutes.push({ route, module });
3898
- logger?.debug(`Found static route: ${route.urlPattern}`);
3899
- }
3900
- } catch (error) {
3901
- const errorMessage = error instanceof Error ? error.message : String(error);
3902
- logger?.warn(`Failed to load page module for ${route.urlPattern}: ${errorMessage}`);
3903
- }
3904
- }
3905
- return staticRoutes;
3906
- }
3907
- function hasDynamicSegments(segments) {
3908
- return segments.some(
3909
- (segment) => segment.type === "dynamic" || segment.type === "catchAll" || segment.type === "optionalCatchAll"
3910
- );
3911
- }
3912
- function interpolatePath(urlPattern, params) {
3913
- let result = urlPattern;
3914
- for (const [key, value] of Object.entries(params)) {
3915
- const encodedValue = encodeURIComponent(value);
3916
- result = result.replace(`:${key}`, encodedValue);
3917
- result = result.replace(`*${key}`, encodedValue);
3918
- }
3919
- return result;
3920
- }
3921
- function urlPathToOutputFile(urlPath) {
3922
- let normalizedPath = urlPath;
3923
- if (normalizedPath.startsWith("/")) {
3924
- normalizedPath = normalizedPath.slice(1);
3925
- }
3926
- if (normalizedPath === "") {
3927
- return "index.html";
3928
- }
3929
- return path11.join(normalizedPath, "index.html");
3930
- }
3931
- async function generateStaticSite(app, manifest, outputDir, logger, verbose = false) {
3932
- const staticRoutes = await getStaticRoutesAsync(manifest, verbose ? logger : void 0);
3933
- const results = [];
3934
- await fs11.mkdir(outputDir, { recursive: true });
3935
- for (const { route, module } of staticRoutes) {
3936
- try {
3937
- const urlPaths = await getUrlPathsForRouteWithModule(route, module, verbose ? logger : void 0);
3938
- for (const urlPath of urlPaths) {
3939
- const result = await generateStaticPage(app, urlPath, outputDir, logger, verbose);
3940
- results.push(result);
3941
- }
3942
- } catch (error) {
3943
- const errorMessage = error instanceof Error ? error.message : String(error);
3944
- logger.error(`Failed to generate static pages for ${route.urlPattern}: ${errorMessage}`);
3945
- results.push({
3946
- urlPath: route.urlPattern,
3947
- outputFile: urlPathToOutputFile(route.urlPattern),
3948
- success: false,
3949
- error: errorMessage
3950
- });
3951
- }
3952
- }
3953
- const successCount = results.filter((r) => r.success).length;
3954
- const failureCount = results.filter((r) => !r.success).length;
3955
- return {
3956
- totalPages: results.length,
3957
- successCount,
3958
- failureCount,
3959
- routes: results,
3960
- outputDir
3961
- };
3962
- }
3963
- async function getUrlPathsForRouteWithModule(route, module, logger) {
3964
- if (!hasDynamicSegments(route.segments)) {
3965
- return [route.urlPattern];
3966
- }
3967
- if (!module.generateStaticParams) {
3968
- logger?.warn(
3969
- `Static route ${route.urlPattern} has dynamic segments but no generateStaticParams export. Skipping.`
3970
- );
3971
- return [];
3972
- }
3973
- const paramsList = await module.generateStaticParams({});
3974
- if (!Array.isArray(paramsList)) {
3975
- throw new Error(
3976
- `generateStaticParams must return an array, got ${typeof paramsList}`
3977
- );
3978
- }
3979
- const urlPaths = paramsList.map((params) => {
3980
- if (typeof params !== "object" || params === null) {
3981
- throw new Error(
3982
- `generateStaticParams must return array of objects, got ${typeof params}`
3983
- );
3984
- }
3985
- return interpolatePath(route.urlPattern, params);
246
+ process.on("SIGINT", async () => {
247
+ forceShutdown();
248
+ await shutdown();
249
+ });
250
+ process.on("SIGTERM", async () => {
251
+ forceShutdown();
252
+ await shutdown();
3986
253
  });
3987
- logger?.debug(`Generated ${urlPaths.length} paths for ${route.urlPattern}`);
3988
- return urlPaths;
3989
- }
3990
- async function generateStaticPage(app, urlPath, outputDir, logger, verbose) {
3991
- const outputFile = urlPathToOutputFile(urlPath);
3992
- const outputPath = path11.join(outputDir, outputFile);
3993
- try {
3994
- const url = `http://localhost${urlPath}`;
3995
- const request = new Request(url, { method: "GET" });
3996
- const response = await app.fetch(request);
3997
- if (!response.ok) {
3998
- throw new Error(`Request failed with status ${response.status}`);
3999
- }
4000
- const html = await response.text();
4001
- await fs11.mkdir(path11.dirname(outputPath), { recursive: true });
4002
- await fs11.writeFile(outputPath, html, "utf-8");
4003
- if (verbose) {
4004
- logger.debug(`Generated: ${outputFile}`);
4005
- }
4006
- return {
4007
- urlPath,
4008
- outputFile,
4009
- success: true
4010
- };
4011
- } catch (error) {
4012
- const errorMessage = error instanceof Error ? error.message : String(error);
4013
- logger.error(`Failed to generate ${urlPath}: ${errorMessage}`);
4014
- return {
4015
- urlPath,
4016
- outputFile,
4017
- success: false,
4018
- error: errorMessage
4019
- };
4020
- }
4021
254
  }
4022
255
 
4023
256
  // src/commands/build.ts
257
+ import { builtinModules } from "module";
258
+ import * as path2 from "path";
259
+ import * as fs2 from "fs";
260
+ import { build as viteBuild } from "vite";
261
+ import cloudwerk2, { generateServerEntry } from "@cloudwerk/vite-plugin";
262
+ import {
263
+ scanRoutes,
264
+ buildRouteManifest,
265
+ resolveLayouts,
266
+ resolveMiddleware,
267
+ loadConfig,
268
+ resolveRoutesPath
269
+ } from "@cloudwerk/core/build";
4024
270
  var DEFAULT_OUTPUT_DIR = "./dist";
4025
- var STATIC_SUBDIR = "static";
4026
- async function build9(pathArg, options) {
271
+ var BUILD_TEMP_DIR = ".cloudwerk-build";
272
+ async function build(pathArg, options) {
4027
273
  const startTime = Date.now();
4028
274
  const verbose = options.verbose ?? false;
275
+ const minify = options.minify ?? true;
276
+ const sourcemap = options.sourcemap ?? false;
4029
277
  const logger = createLogger(verbose);
278
+ let tempDir = null;
4030
279
  try {
4031
- const cwd = pathArg ? path12.resolve(process.cwd(), pathArg) : process.cwd();
4032
- if (!fs12.existsSync(cwd)) {
280
+ const cwd = pathArg ? path2.resolve(process.cwd(), pathArg) : process.cwd();
281
+ if (!fs2.existsSync(cwd)) {
4033
282
  throw new CliError(
4034
283
  `Directory does not exist: ${cwd}`,
4035
284
  "ENOENT",
@@ -4037,80 +286,134 @@ async function build9(pathArg, options) {
4037
286
  );
4038
287
  }
4039
288
  logger.debug(`Working directory: ${cwd}`);
4040
- logger.debug(`Loading configuration...`);
4041
- const config = await loadConfig2(cwd);
4042
- logger.debug(`Config loaded: routesDir=${config.routesDir}, extensions=${config.extensions.join(", ")}`);
4043
- const routesDir = resolveRoutesDir3(config, cwd);
4044
- logger.debug(`Routes directory: ${routesDir}`);
4045
- if (!fs12.existsSync(routesDir)) {
4046
- throw new CliError(
4047
- `Routes directory does not exist: ${routesDir}`,
4048
- "ENOENT",
4049
- `Create the "${config.routesDir}" directory or update routesDir in cloudwerk.config.ts`
4050
- );
289
+ const outputBase = options.output ?? DEFAULT_OUTPUT_DIR;
290
+ const outputDir = path2.isAbsolute(outputBase) ? outputBase : path2.resolve(cwd, outputBase);
291
+ if (fs2.existsSync(outputDir)) {
292
+ logger.debug(`Cleaning output directory: ${outputDir}`);
293
+ fs2.rmSync(outputDir, { recursive: true, force: true });
4051
294
  }
4052
- logger.debug(`Scanning routes...`);
4053
- const scanResult = await scanRoutes2(routesDir, config);
4054
- logger.debug(`Found ${scanResult.routes.length} route files`);
4055
- logger.debug(`Building route manifest...`);
4056
- const manifest = buildRouteManifest2(
295
+ fs2.mkdirSync(outputDir, { recursive: true });
296
+ logger.info(`Building to ${outputDir}...`);
297
+ tempDir = path2.join(cwd, BUILD_TEMP_DIR);
298
+ if (!fs2.existsSync(tempDir)) {
299
+ fs2.mkdirSync(tempDir, { recursive: true });
300
+ }
301
+ const cloudwerkConfig = await loadConfig(cwd);
302
+ const appDir = cloudwerkConfig.appDir;
303
+ const routesDir = cloudwerkConfig.routesDir ?? "routes";
304
+ const routesPath = resolveRoutesPath(routesDir, appDir, cwd);
305
+ logger.debug(`Scanning routes from: ${routesPath}`);
306
+ const scanResult = await scanRoutes(routesPath, {
307
+ extensions: cloudwerkConfig.extensions
308
+ });
309
+ const manifest = buildRouteManifest(
4057
310
  scanResult,
4058
- routesDir,
4059
- resolveLayouts2,
4060
- resolveMiddleware2
311
+ routesPath,
312
+ resolveLayouts,
313
+ resolveMiddleware
4061
314
  );
4062
- if (hasErrors2(manifest)) {
4063
- const errorMessages = formatErrors2(manifest.errors);
4064
- logger.error(errorMessages);
4065
- throw new CliError(
4066
- "Route validation failed",
4067
- "VALIDATION_ERROR",
4068
- "Fix the errors above and try again."
4069
- );
4070
- }
4071
- if (manifest.warnings.length > 0) {
4072
- const warningMessages = formatWarnings2(manifest.warnings);
4073
- logger.warn(warningMessages);
4074
- }
4075
- if (manifest.routes.length === 0) {
4076
- logger.warn(`No routes found in ${config.routesDir}`);
4077
- logger.warn(`Create a route.ts file to get started.`);
315
+ logger.debug(`Found ${manifest.routes.length} routes`);
316
+ const renderer = cloudwerkConfig.ui?.renderer ?? "hono-jsx";
317
+ const serverEntryCode = generateServerEntry(manifest, scanResult, {
318
+ appDir,
319
+ routesDir,
320
+ config: cloudwerkConfig,
321
+ serverEntry: null,
322
+ clientEntry: null,
323
+ verbose,
324
+ hydrationEndpoint: "/__cloudwerk",
325
+ renderer,
326
+ root: cwd
327
+ });
328
+ const tempEntryPath = path2.join(tempDir, "_server-entry.ts");
329
+ fs2.writeFileSync(tempEntryPath, serverEntryCode);
330
+ logger.debug(`Generated temp entry: ${tempEntryPath}`);
331
+ logger.debug(`Building client assets...`);
332
+ const clientConfig = {
333
+ root: cwd,
334
+ mode: "production",
335
+ logLevel: verbose ? "info" : "warn",
336
+ plugins: [
337
+ cloudwerk2({ verbose })
338
+ ],
339
+ build: {
340
+ outDir: path2.join(outputDir, "static"),
341
+ emptyOutDir: true,
342
+ minify: minify ? "esbuild" : false,
343
+ sourcemap,
344
+ rollupOptions: {
345
+ input: "virtual:cloudwerk/client-entry",
346
+ output: {
347
+ entryFileNames: "__cloudwerk/client.js",
348
+ chunkFileNames: "__cloudwerk/[name]-[hash].js",
349
+ assetFileNames: "__cloudwerk/[name]-[hash][extname]"
350
+ }
351
+ }
352
+ }
353
+ };
354
+ try {
355
+ await viteBuild(clientConfig);
356
+ logger.debug(`Client assets built successfully`);
357
+ } catch (error) {
358
+ if (verbose) {
359
+ logger.debug(`Client build skipped or failed: ${error instanceof Error ? error.message : String(error)}`);
360
+ }
4078
361
  }
4079
- const outputBase = options.output ?? DEFAULT_OUTPUT_DIR;
4080
- const outputDir = path12.isAbsolute(outputBase) ? outputBase : path12.resolve(cwd, outputBase);
4081
- logger.info(`Building to ${outputDir}...`);
4082
- if (options.ssg) {
4083
- logger.debug(`Scanning for static routes...`);
4084
- const staticRoutes = await getStaticRoutesAsync(manifest, verbose ? logger : void 0);
4085
- if (staticRoutes.length === 0) {
4086
- logger.warn(`No static routes found. Add rendering: 'static' to route configs to enable SSG.`);
4087
- } else {
4088
- logger.info(`Found ${staticRoutes.length} static route(s)`);
4089
- logger.debug(`Creating Hono app for SSG...`);
4090
- const { app } = await createApp(manifest, scanResult, config, logger, verbose);
4091
- const staticOutputDir = path12.join(outputDir, STATIC_SUBDIR);
4092
- logger.info(`Generating static pages to ${staticOutputDir}...`);
4093
- const ssgStartTime = Date.now();
4094
- const result = await generateStaticSite(app, manifest, staticOutputDir, logger, verbose);
4095
- const ssgDuration = Date.now() - ssgStartTime;
4096
- printSSGResults(result, logger, ssgDuration);
4097
- if (result.failureCount > 0) {
4098
- throw new CliError(
4099
- `Failed to generate ${result.failureCount} static page(s)`,
4100
- "SSG_ERROR",
4101
- "Check the errors above and fix any issues."
4102
- );
362
+ logger.debug(`Building server bundle...`);
363
+ const serverConfig = {
364
+ root: cwd,
365
+ mode: "production",
366
+ logLevel: verbose ? "info" : "warn",
367
+ plugins: [
368
+ cloudwerk2({ verbose })
369
+ ],
370
+ build: {
371
+ outDir: outputDir,
372
+ emptyOutDir: false,
373
+ // Don't clear - client assets are already there
374
+ minify: minify ? "esbuild" : false,
375
+ sourcemap,
376
+ ssr: true,
377
+ rollupOptions: {
378
+ input: tempEntryPath,
379
+ // Externalize Node.js builtins (polyfilled by nodejs_compat in Workers)
380
+ external: [...builtinModules, /^node:/],
381
+ output: {
382
+ entryFileNames: "index.js"
383
+ }
4103
384
  }
385
+ },
386
+ ssr: {
387
+ target: "webworker",
388
+ noExternal: true
389
+ // Bundle all dependencies
390
+ },
391
+ resolve: {
392
+ // Prefer browser/worker fields in package.json
393
+ conditions: ["workerd", "worker", "browser", "import", "module", "default"]
4104
394
  }
4105
- } else {
4106
- logger.debug(`Scanning for static routes...`);
4107
- const staticRoutes = await getStaticRoutesAsync(manifest, verbose ? logger : void 0);
4108
- if (staticRoutes.length > 0) {
4109
- logger.info(`Found ${staticRoutes.length} static route(s). Use --ssg to generate static pages.`);
395
+ };
396
+ await viteBuild(serverConfig);
397
+ logger.debug(`Server bundle built successfully`);
398
+ const buildDuration = Date.now() - startTime;
399
+ const serverBundlePath = path2.join(outputDir, "index.js");
400
+ const serverSize = fs2.existsSync(serverBundlePath) ? fs2.statSync(serverBundlePath).size : 0;
401
+ const clientDir = path2.join(outputDir, "static", "__cloudwerk");
402
+ let clientSize = 0;
403
+ if (fs2.existsSync(clientDir)) {
404
+ const clientFiles = fs2.readdirSync(clientDir);
405
+ for (const file of clientFiles) {
406
+ const filePath = path2.join(clientDir, file);
407
+ const stat = fs2.statSync(filePath);
408
+ if (stat.isFile()) {
409
+ clientSize += stat.size;
410
+ }
4110
411
  }
4111
412
  }
4112
- const buildTime = Date.now() - startTime;
4113
- logger.success(`Build completed in ${buildTime}ms`);
413
+ console.log();
414
+ printBuildSummary(serverSize, clientSize, buildDuration, logger);
415
+ console.log();
416
+ logger.success(`Build completed in ${buildDuration}ms`);
4114
417
  } catch (error) {
4115
418
  if (error instanceof CliError) {
4116
419
  printError(error.message, error.suggestion);
@@ -4125,37 +428,41 @@ async function build9(pathArg, options) {
4125
428
  }
4126
429
  printError(String(error));
4127
430
  process.exit(1);
431
+ } finally {
432
+ if (tempDir && fs2.existsSync(tempDir)) {
433
+ try {
434
+ fs2.rmSync(tempDir, { recursive: true, force: true });
435
+ if (verbose) {
436
+ logger.debug(`Cleaned up temp directory: ${tempDir}`);
437
+ }
438
+ } catch {
439
+ }
440
+ }
4128
441
  }
4129
442
  }
4130
- function printSSGResults(result, logger, duration) {
4131
- console.log();
4132
- logger.log("Static Site Generation Results:");
4133
- logger.log(` Total pages: ${result.totalPages}`);
4134
- logger.log(` Generated: ${result.successCount}`);
4135
- if (result.failureCount > 0) {
4136
- logger.log(` Failed: ${result.failureCount}`);
443
+ function printBuildSummary(serverSize, clientSize, buildDuration, logger) {
444
+ logger.log("Build Output:");
445
+ logger.log("");
446
+ logger.log(" Server:");
447
+ logger.log(` Bundle: ${formatSize(serverSize)}`);
448
+ logger.log("");
449
+ if (clientSize > 0) {
450
+ logger.log(" Client:");
451
+ logger.log(` Total: ${formatSize(clientSize)}`);
452
+ logger.log("");
4137
453
  }
4138
- logger.log(` Output: ${result.outputDir}`);
4139
- logger.log(` Duration: ${duration}ms`);
4140
- const pagesToShow = result.routes.filter((r) => r.success).slice(0, 10);
4141
- if (pagesToShow.length > 0) {
4142
- console.log();
4143
- logger.log("Generated pages:");
4144
- for (const page of pagesToShow) {
4145
- logger.log(` ${page.urlPath} -> ${page.outputFile}`);
4146
- }
4147
- if (result.successCount > 10) {
4148
- logger.log(` ... and ${result.successCount - 10} more`);
4149
- }
454
+ const totalSize = serverSize + clientSize;
455
+ logger.log(` Total: ${formatSize(totalSize)}`);
456
+ logger.log(` Duration: ${buildDuration}ms`);
457
+ }
458
+ function formatSize(bytes) {
459
+ if (bytes < 1024) {
460
+ return `${bytes} B`;
4150
461
  }
4151
- const failedPages = result.routes.filter((r) => !r.success);
4152
- if (failedPages.length > 0) {
4153
- console.log();
4154
- logger.error("Failed pages:");
4155
- for (const page of failedPages) {
4156
- logger.error(` ${page.urlPath}: ${page.error}`);
4157
- }
462
+ if (bytes < 1024 * 1024) {
463
+ return `${(bytes / 1024).toFixed(1)} KB`;
4158
464
  }
465
+ return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
4159
466
  }
4160
467
 
4161
468
  // src/commands/config.ts
@@ -4163,9 +470,9 @@ import * as readline from "readline";
4163
470
  import pc2 from "picocolors";
4164
471
 
4165
472
  // src/utils/configWriter.ts
4166
- import * as fs13 from "fs";
4167
- import * as path13 from "path";
4168
- import { loadConfig as loadConfig3 } from "@cloudwerk/core";
473
+ import * as fs3 from "fs";
474
+ import * as path3 from "path";
475
+ import { loadConfig as loadConfig2 } from "@cloudwerk/core/build";
4169
476
  var CONFIG_FILE_NAMES = [
4170
477
  "cloudwerk.config.ts",
4171
478
  "cloudwerk.config.js",
@@ -4173,8 +480,8 @@ var CONFIG_FILE_NAMES = [
4173
480
  ];
4174
481
  function findConfigFile(cwd) {
4175
482
  for (const filename of CONFIG_FILE_NAMES) {
4176
- const configPath = path13.join(cwd, filename);
4177
- if (fs13.existsSync(configPath)) {
483
+ const configPath = path3.join(cwd, filename);
484
+ if (fs3.existsSync(configPath)) {
4178
485
  return configPath;
4179
486
  }
4180
487
  }
@@ -4185,7 +492,7 @@ function readCloudwerkConfig(cwd) {
4185
492
  if (!configPath) {
4186
493
  return {};
4187
494
  }
4188
- const content = fs13.readFileSync(configPath, "utf-8");
495
+ const content = fs3.readFileSync(configPath, "utf-8");
4189
496
  return parseConfigContent(content);
4190
497
  }
4191
498
  function parseConfigContent(content) {
@@ -4206,16 +513,16 @@ function parseConfigContent(content) {
4206
513
  function writeCloudwerkConfig(cwd, updates) {
4207
514
  const configPath = findConfigFile(cwd);
4208
515
  if (!configPath) {
4209
- const newConfigPath = path13.join(cwd, "cloudwerk.config.ts");
516
+ const newConfigPath = path3.join(cwd, "cloudwerk.config.ts");
4210
517
  const content2 = generateMinimalConfig(updates);
4211
- fs13.writeFileSync(newConfigPath, content2, "utf-8");
518
+ fs3.writeFileSync(newConfigPath, content2, "utf-8");
4212
519
  return true;
4213
520
  }
4214
- let content = fs13.readFileSync(configPath, "utf-8");
521
+ let content = fs3.readFileSync(configPath, "utf-8");
4215
522
  if (updates.renderer !== void 0) {
4216
523
  content = updateRenderer(content, updates.renderer);
4217
524
  }
4218
- fs13.writeFileSync(configPath, content, "utf-8");
525
+ fs3.writeFileSync(configPath, content, "utf-8");
4219
526
  return true;
4220
527
  }
4221
528
  function updateRenderer(content, renderer) {
@@ -4259,9 +566,9 @@ function addUiSection(content, renderer) {
4259
566
  function detectIndentation(lines, closingLineIndex) {
4260
567
  for (let i = closingLineIndex - 1; i >= 0; i--) {
4261
568
  const line = lines[i];
4262
- const match2 = line.match(/^(\s+)\S/);
4263
- if (match2) {
4264
- return match2[1];
569
+ const match = line.match(/^(\s+)\S/);
570
+ if (match) {
571
+ return match[1];
4265
572
  }
4266
573
  }
4267
574
  return " ";
@@ -4284,11 +591,11 @@ function generateMinimalConfig(updates) {
4284
591
  }
4285
592
 
4286
593
  // src/utils/tsconfigWriter.ts
4287
- import * as fs14 from "fs";
4288
- import * as path14 from "path";
594
+ import * as fs4 from "fs";
595
+ import * as path4 from "path";
4289
596
  function findTsConfig(cwd) {
4290
- const tsconfigPath = path14.join(cwd, "tsconfig.json");
4291
- if (fs14.existsSync(tsconfigPath)) {
597
+ const tsconfigPath = path4.join(cwd, "tsconfig.json");
598
+ if (fs4.existsSync(tsconfigPath)) {
4292
599
  return tsconfigPath;
4293
600
  }
4294
601
  return null;
@@ -4299,7 +606,7 @@ function readTsConfig(cwd) {
4299
606
  return {};
4300
607
  }
4301
608
  try {
4302
- const content = fs14.readFileSync(tsconfigPath, "utf-8");
609
+ const content = fs4.readFileSync(tsconfigPath, "utf-8");
4303
610
  const config = JSON.parse(content);
4304
611
  return {
4305
612
  jsxImportSource: config.compilerOptions?.jsxImportSource,
@@ -4315,7 +622,7 @@ function updateTsConfig(cwd, updates) {
4315
622
  return false;
4316
623
  }
4317
624
  try {
4318
- const content = fs14.readFileSync(tsconfigPath, "utf-8");
625
+ const content = fs4.readFileSync(tsconfigPath, "utf-8");
4319
626
  const config = JSON.parse(content);
4320
627
  if (!config.compilerOptions) {
4321
628
  config.compilerOptions = {};
@@ -4323,7 +630,7 @@ function updateTsConfig(cwd, updates) {
4323
630
  if (updates.jsxImportSource !== void 0) {
4324
631
  config.compilerOptions.jsxImportSource = updates.jsxImportSource;
4325
632
  }
4326
- fs14.writeFileSync(tsconfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
633
+ fs4.writeFileSync(tsconfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
4327
634
  return true;
4328
635
  } catch {
4329
636
  return false;
@@ -4331,8 +638,8 @@ function updateTsConfig(cwd, updates) {
4331
638
  }
4332
639
 
4333
640
  // src/utils/dependencyManager.ts
4334
- import * as fs15 from "fs";
4335
- import * as path15 from "path";
641
+ import * as fs5 from "fs";
642
+ import * as path5 from "path";
4336
643
  import { execFileSync } from "child_process";
4337
644
  var REACT_SPECIFIC_LIBRARIES = [
4338
645
  "@tanstack/react-query",
@@ -4373,22 +680,22 @@ var REACT_SPECIFIC_LIBRARIES = [
4373
680
  "@use-gesture/react"
4374
681
  ];
4375
682
  function detectPackageManager(cwd) {
4376
- if (fs15.existsSync(path15.join(cwd, "pnpm-lock.yaml"))) {
683
+ if (fs5.existsSync(path5.join(cwd, "pnpm-lock.yaml"))) {
4377
684
  return "pnpm";
4378
685
  }
4379
- if (fs15.existsSync(path15.join(cwd, "yarn.lock"))) {
686
+ if (fs5.existsSync(path5.join(cwd, "yarn.lock"))) {
4380
687
  return "yarn";
4381
688
  }
4382
- if (fs15.existsSync(path15.join(cwd, "bun.lockb"))) {
689
+ if (fs5.existsSync(path5.join(cwd, "bun.lockb"))) {
4383
690
  return "bun";
4384
691
  }
4385
- if (fs15.existsSync(path15.join(cwd, "package-lock.json"))) {
692
+ if (fs5.existsSync(path5.join(cwd, "package-lock.json"))) {
4386
693
  return "npm";
4387
694
  }
4388
- const packageJsonPath = path15.join(cwd, "package.json");
4389
- if (fs15.existsSync(packageJsonPath)) {
695
+ const packageJsonPath = path5.join(cwd, "package.json");
696
+ if (fs5.existsSync(packageJsonPath)) {
4390
697
  try {
4391
- const packageJson = JSON.parse(fs15.readFileSync(packageJsonPath, "utf-8"));
698
+ const packageJson = JSON.parse(fs5.readFileSync(packageJsonPath, "utf-8"));
4392
699
  const pm = packageJson.packageManager;
4393
700
  if (pm) {
4394
701
  if (pm.startsWith("pnpm")) return "pnpm";
@@ -4402,15 +709,15 @@ function detectPackageManager(cwd) {
4402
709
  return "npm";
4403
710
  }
4404
711
  function getInstalledDependencies(cwd) {
4405
- const packageJsonPath = path15.join(cwd, "package.json");
4406
- if (!fs15.existsSync(packageJsonPath)) {
712
+ const packageJsonPath = path5.join(cwd, "package.json");
713
+ if (!fs5.existsSync(packageJsonPath)) {
4407
714
  return {
4408
715
  dependencies: {},
4409
716
  devDependencies: {}
4410
717
  };
4411
718
  }
4412
719
  try {
4413
- const content = fs15.readFileSync(packageJsonPath, "utf-8");
720
+ const content = fs5.readFileSync(packageJsonPath, "utf-8");
4414
721
  const packageJson = JSON.parse(content);
4415
722
  return {
4416
723
  dependencies: packageJson.dependencies || {},
@@ -4751,7 +1058,7 @@ async function askConfirmation(question, defaultValue) {
4751
1058
  // src/index.ts
4752
1059
  program.name("cloudwerk").description("Cloudwerk CLI - Build and deploy full-stack apps to Cloudflare").version(VERSION);
4753
1060
  program.command("dev [path]").description("Start development server").option("-p, --port <number>", "Port to listen on", String(DEFAULT_PORT)).option("-H, --host <host>", "Host to bind", DEFAULT_HOST).option("-c, --config <path>", "Path to config file").option("--verbose", "Enable verbose logging").action(dev);
4754
- program.command("build [path]").description("Build project for production").option("-o, --output <dir>", "Output directory", "./dist").option("--ssg", "Generate static pages for routes with rendering: static").option("-c, --config <path>", "Path to config file").option("--verbose", "Enable verbose logging").action(build9);
1061
+ program.command("build [path]").description("Build project for production deployment to Cloudflare Workers").option("-o, --output <dir>", "Output directory", "./dist").option("--ssg", "Generate static pages for routes with rendering: static").option("--minify", "Minify bundles (default: true)").option("--no-minify", "Disable minification").option("--sourcemap", "Generate source maps").option("-c, --config <path>", "Path to config file").option("--verbose", "Enable verbose logging").action(build);
4755
1062
  var configCmd = program.command("config").description("Manage Cloudwerk configuration");
4756
1063
  configCmd.command("get <key>").description("Get a configuration value").action(configGet);
4757
1064
  configCmd.command("set <key> <value>").description("Set a configuration value").action(configSet);