@vesk/vesk-cli 0.2.70 → 0.2.71

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 (2) hide show
  1. package/dist/cli.js +164 -66
  2. package/package.json +5 -5
package/dist/cli.js CHANGED
@@ -53010,6 +53010,142 @@ function installResponsePipeline(res, req, options = {}) {
53010
53010
  });
53011
53011
  }
53012
53012
 
53013
+ // ../adapter/src/web-request.ts
53014
+ import { Buffer as Buffer2 } from "node:buffer";
53015
+ function bodyTooLarge(maxBytes) {
53016
+ const err = new Error(`Request body exceeds limit (${maxBytes} bytes)`);
53017
+ err.status = 413;
53018
+ return err;
53019
+ }
53020
+ function makeWebRequest(nodeReq, url, maxBodyBytes = DEFAULT_MAX_BODY_BYTES) {
53021
+ const parsedUrl = new URL(url, `http://${nodeReq.headers.host || "localhost"}`);
53022
+ const method = nodeReq.method || "GET";
53023
+ let cachedBody = null;
53024
+ let streamTaken = false;
53025
+ let streamEnded = false;
53026
+ const endWaiters = [];
53027
+ const settleEnd = (body) => {
53028
+ if (body !== null) cachedBody = body;
53029
+ streamEnded = true;
53030
+ for (const resolve41 of endWaiters.splice(0)) resolve41();
53031
+ };
53032
+ function createBodyStream() {
53033
+ streamTaken = true;
53034
+ const cache2 = [];
53035
+ let total = 0;
53036
+ return new ReadableStream({
53037
+ start(controller) {
53038
+ nodeReq.on("data", (chunk) => {
53039
+ total += chunk.length;
53040
+ if (total > maxBodyBytes) {
53041
+ settleEnd(Buffer2.concat(cache2));
53042
+ cache2.length = 0;
53043
+ try {
53044
+ controller.error(bodyTooLarge(maxBodyBytes));
53045
+ } catch {
53046
+ }
53047
+ nodeReq.destroy();
53048
+ return;
53049
+ }
53050
+ cache2.push(chunk);
53051
+ try {
53052
+ controller.enqueue(new Uint8Array(chunk));
53053
+ } catch {
53054
+ }
53055
+ });
53056
+ nodeReq.on("end", () => {
53057
+ settleEnd(Buffer2.concat(cache2));
53058
+ cache2.length = 0;
53059
+ try {
53060
+ controller.close();
53061
+ } catch {
53062
+ }
53063
+ });
53064
+ nodeReq.on("error", (e) => {
53065
+ settleEnd(Buffer2.concat(cache2));
53066
+ cache2.length = 0;
53067
+ try {
53068
+ controller.error(e);
53069
+ } catch {
53070
+ }
53071
+ });
53072
+ }
53073
+ });
53074
+ }
53075
+ async function getBody() {
53076
+ if (cachedBody) return cachedBody;
53077
+ if (streamTaken) {
53078
+ while (!streamEnded) await new Promise((r) => endWaiters.push(r));
53079
+ return cachedBody || Buffer2.alloc(0);
53080
+ }
53081
+ const chunks = [];
53082
+ let total = 0;
53083
+ for await (const chunk of nodeReq) {
53084
+ total += chunk.byteLength;
53085
+ if (total > maxBodyBytes) throw bodyTooLarge(maxBodyBytes);
53086
+ chunks.push(Buffer2.from(chunk));
53087
+ }
53088
+ cachedBody = Buffer2.concat(chunks);
53089
+ return cachedBody;
53090
+ }
53091
+ const webRequest = new Request(parsedUrl, {
53092
+ method,
53093
+ headers: nodeReq.headers,
53094
+ body: null
53095
+ });
53096
+ let bodyStream = null;
53097
+ Object.defineProperty(webRequest, "body", {
53098
+ configurable: true,
53099
+ enumerable: false,
53100
+ get: () => {
53101
+ if (bodyStream) return bodyStream;
53102
+ if (method === "GET" || method === "HEAD") return null;
53103
+ bodyStream = createBodyStream();
53104
+ return bodyStream;
53105
+ }
53106
+ });
53107
+ webRequest.json = async () => {
53108
+ try {
53109
+ return JSON.parse((await getBody()).toString());
53110
+ } catch {
53111
+ return null;
53112
+ }
53113
+ };
53114
+ webRequest.text = async () => (await getBody()).toString("utf-8");
53115
+ webRequest.formData = async () => {
53116
+ const body = await getBody();
53117
+ const ct = String(nodeReq.headers["content-type"] || "");
53118
+ if (ct.includes("multipart/form-data")) {
53119
+ const temp = new Request("http://localhost", { method: "POST", headers: nodeReq.headers, body });
53120
+ return temp.formData();
53121
+ }
53122
+ const fd = new FormData();
53123
+ if (ct.includes("x-www-form-urlencoded")) {
53124
+ for (const [k, v] of new URLSearchParams(body.toString()).entries()) fd.append(k, v);
53125
+ }
53126
+ return fd;
53127
+ };
53128
+ webRequest.clone = () => webRequest;
53129
+ const cookies2 = {};
53130
+ for (const part of String(nodeReq.headers.cookie || "").split(";")) {
53131
+ const eq = part.indexOf("=");
53132
+ if (eq === -1) continue;
53133
+ const name = part.slice(0, eq).trim();
53134
+ if (!name) continue;
53135
+ const raw2 = part.slice(eq + 1).trim();
53136
+ try {
53137
+ cookies2[name] = decodeURIComponent(raw2);
53138
+ } catch {
53139
+ cookies2[name] = raw2;
53140
+ }
53141
+ }
53142
+ webRequest.cookies = cookies2;
53143
+ const query = {};
53144
+ for (const [k, v] of parsedUrl.searchParams.entries()) query[k] = v;
53145
+ webRequest.query = query;
53146
+ return webRequest;
53147
+ }
53148
+
53013
53149
  // ../adapter/src/prod-server.ts
53014
53150
  init_platform_output();
53015
53151
  var __dirname4 = dirname11(fileURLToPath3(import.meta.url));
@@ -53067,65 +53203,10 @@ function pumpRemaining(res, reader) {
53067
53203
  res.end();
53068
53204
  })();
53069
53205
  }
53070
- function bodyTooLarge(maxBytes) {
53071
- const err = new Error(`Request body exceeds limit (${maxBytes} bytes)`);
53072
- err.status = 413;
53073
- return err;
53074
- }
53075
53206
  function errorStatus(e, fallback) {
53076
53207
  const s = e?.status ?? e?.statusCode;
53077
53208
  return typeof s === "number" && s >= 400 && s < 600 ? s : fallback;
53078
53209
  }
53079
- function makeWebRequest(nodeReq, url, maxBodyBytes = DEFAULT_MAX_BODY_BYTES) {
53080
- const parsedUrl = new URL(url, `http://${nodeReq.headers.host || "localhost"}`);
53081
- const method = nodeReq.method || "GET";
53082
- let _bodyBuffer = null;
53083
- async function getBody() {
53084
- if (_bodyBuffer) return _bodyBuffer;
53085
- const chunks = [];
53086
- let total = 0;
53087
- for await (const chunk of nodeReq) {
53088
- total += chunk.byteLength;
53089
- if (total > maxBodyBytes) throw bodyTooLarge(maxBodyBytes);
53090
- chunks.push(Buffer.from(chunk));
53091
- }
53092
- _bodyBuffer = Buffer.concat(chunks);
53093
- return _bodyBuffer;
53094
- }
53095
- const webRequest = new Request(parsedUrl, { method, headers: nodeReq.headers, body: null });
53096
- webRequest.json = async () => {
53097
- try {
53098
- return JSON.parse((await getBody()).toString());
53099
- } catch {
53100
- return null;
53101
- }
53102
- };
53103
- webRequest.text = async () => (await getBody()).toString("utf-8");
53104
- webRequest.formData = async () => {
53105
- const body = await getBody();
53106
- const ct = String(nodeReq.headers["content-type"] || "");
53107
- if (ct.includes("multipart/form-data")) {
53108
- const temp = new Request("http://localhost", { method: "POST", headers: nodeReq.headers, body });
53109
- return temp.formData();
53110
- }
53111
- const fd = new FormData();
53112
- if (ct.includes("x-www-form-urlencoded")) {
53113
- for (const [k, v] of new URLSearchParams(body.toString()).entries()) fd.append(k, v);
53114
- }
53115
- return fd;
53116
- };
53117
- webRequest.clone = () => webRequest;
53118
- const cookies2 = {};
53119
- for (const [k, v] of String(nodeReq.headers.cookie || "").split(";").map((s) => s.trim()).filter(Boolean)) {
53120
- const eq = k.indexOf("=");
53121
- if (eq > -1) cookies2[k.slice(0, eq)] = decodeURIComponent(k.slice(eq + 1));
53122
- }
53123
- webRequest.cookies = cookies2;
53124
- const query = {};
53125
- for (const [k, v] of parsedUrl.searchParams.entries()) query[k] = v;
53126
- webRequest.query = query;
53127
- return webRequest;
53128
- }
53129
53210
  async function startProdServer(outDir, options) {
53130
53211
  const port = options?.port || 3e3;
53131
53212
  const host = options?.host || "127.0.0.1";
@@ -53196,15 +53277,22 @@ async function startProdServer(outDir, options) {
53196
53277
  }
53197
53278
  }
53198
53279
  const functionCache = /* @__PURE__ */ new Map();
53280
+ const functionFailures = /* @__PURE__ */ new Map();
53281
+ function functionFailure(funcPath) {
53282
+ return functionFailures.get(funcPath);
53283
+ }
53199
53284
  async function loadFunction(funcPath) {
53200
53285
  if (functionCache.has(funcPath)) return functionCache.get(funcPath);
53286
+ if (functionFailures.has(funcPath)) return null;
53201
53287
  const fullPath = resolve14(outDir, funcPath);
53202
53288
  if (!existsSync16(fullPath)) return null;
53203
53289
  try {
53204
53290
  const mod = await import(`${fullPath}?t=${Date.now()}`);
53205
53291
  functionCache.set(funcPath, mod);
53206
53292
  return mod;
53207
- } catch {
53293
+ } catch (e) {
53294
+ console.error(`vesk start: failed to load ${funcPath}:`, e instanceof Error ? e.message : e);
53295
+ functionFailures.set(funcPath, e);
53208
53296
  return null;
53209
53297
  }
53210
53298
  }
@@ -53467,18 +53555,24 @@ async function startProdServer(outDir, options) {
53467
53555
  const params = matchPath(route.path, url.pathname);
53468
53556
  if (params) {
53469
53557
  const mod = await loadFunction(route.function);
53470
- if (mod) {
53471
- try {
53472
- const webRequest = makeWebRequest(req, url.href, maxBodyBytes);
53473
- const response = await withSecurityScope(() => mod.handle(webRequest));
53474
- await deliverResponse(res, response);
53475
- return;
53476
- } catch (e) {
53477
- const status = errorStatus(e, 500);
53478
- res.writeHead(status, { "Content-Type": "application/json" });
53479
- res.end(JSON.stringify({ error: status === 500 ? "Internal Server Error" : e instanceof Error ? e.message : String(e) }));
53558
+ if (!mod) {
53559
+ if (functionFailure(route.function)) {
53560
+ res.writeHead(500, { "Content-Type": "application/json" });
53561
+ res.end(JSON.stringify({ error: "Internal Server Error" }));
53480
53562
  return;
53481
53563
  }
53564
+ continue;
53565
+ }
53566
+ try {
53567
+ const webRequest = makeWebRequest(req, url.href, maxBodyBytes);
53568
+ const response = await withSecurityScope(() => mod.handle(webRequest));
53569
+ await deliverResponse(res, response);
53570
+ return;
53571
+ } catch (e) {
53572
+ const status = errorStatus(e, 500);
53573
+ res.writeHead(status, { "Content-Type": "application/json" });
53574
+ res.end(JSON.stringify({ error: status === 500 ? "Internal Server Error" : e instanceof Error ? e.message : String(e) }));
53575
+ return;
53482
53576
  }
53483
53577
  }
53484
53578
  }
@@ -65138,6 +65232,10 @@ var PACKAGES = {
65138
65232
  // servers on fresh checkouts (CI).
65139
65233
  "plugin-pwa": { name: "@vesk/plugin-pwa", entry: "index" },
65140
65234
  "plugin-tailwind": { name: "@vesk/plugin-tailwind", entry: "index" },
65235
+ // The multipart plugin ships as a real published package: an app route imports
65236
+ // it by name, so its dist must exist for the API-function bundler to resolve it
65237
+ // on a fresh checkout (CI).
65238
+ "plugin-multipart": { name: "@vesk/plugin-multipart", entry: "index" },
65141
65239
  // testing last — it depends on the compiler.
65142
65240
  testing: { name: "@vesk/testing", entry: "index" }
65143
65241
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vesk/vesk-cli",
3
- "version": "0.2.70",
3
+ "version": "0.2.71",
4
4
  "type": "module",
5
5
  "description": "Vesk — compiler-first framework for the post-VDOM web. vesk dev, vesk build.",
6
6
  "bin": {
@@ -8,10 +8,10 @@
8
8
  },
9
9
  "main": "./dist/cli.js",
10
10
  "dependencies": {
11
- "@vesk/adapter": "^0.2.70",
12
- "@vesk/compiler": "^0.2.70",
13
- "@vesk/plugin-tailwind": "^0.2.70",
14
- "@vesk/runtime": "^0.2.70",
11
+ "@vesk/adapter": "^0.2.71",
12
+ "@vesk/compiler": "^0.2.71",
13
+ "@vesk/plugin-tailwind": "^0.2.71",
14
+ "@vesk/runtime": "^0.2.71",
15
15
  "esrap": "^2.3.0",
16
16
  "typescript": "^5.8.0",
17
17
  "ws": "^8.18.0",