bun-plugin-stx 0.2.169 → 0.2.171

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/serve.js CHANGED
@@ -8721,6 +8721,7 @@ var defaultGeneratedDir4 = /* @__PURE__ */ resolve12(process20.cwd(), "src/gener
8721
8721
  import { BUILD_ID_HEADER, extractPageResponseStatus, findContainerRegion, getBuildId, mergeCrosswindConfig, stateDir, stateDirName } from "@stacksjs/stx";
8722
8722
  import { buildCodeFrame, locateFailureLine } from "@stacksjs/stx/build-message";
8723
8723
  import { clearBundleFailures, getBundleFailures } from "@stacksjs/stx/client-script-bundler";
8724
+ import { compressResponse, runPageAction as sharedRunPageAction } from "@stacksjs/stx";
8724
8725
  var defaultStxModule = import("@stacksjs/stx");
8725
8726
  var REACTIVE_TEMPLATE_DIRECTIVE_RE = /@for|:for|@if|:if|@else|:else|x-for|x-if|x-else/;
8726
8727
  function extractServerScriptsFromTemplate(content) {
@@ -9379,6 +9380,7 @@ function __stxOverlay(errs){
9379
9380
  const full = reqCtx ?? {
9380
9381
  url: "",
9381
9382
  path: "",
9383
+ method: "GET",
9382
9384
  search,
9383
9385
  host,
9384
9386
  cookieHeader: activeServeCookieHeader,
@@ -9520,7 +9522,7 @@ function __stxOverlay(errs){
9520
9522
  pageMiddlewarePatterns.length = 0;
9521
9523
  await Promise.all(files.map((f) => detectPageMiddleware(f)));
9522
9524
  try {
9523
- const { Router } = await import("./chunk-z66h8w4a.js");
9525
+ const { Router } = await import("./chunk-ebg5468e.js");
9524
9526
  const pagesDirs = patterns.map((p) => p.replace(/\/$/, "")).filter(Boolean);
9525
9527
  const router = new Router(process19.cwd(), { pagesDirs, stateDir: stateDirName() });
9526
9528
  if (!options.quiet)
@@ -9700,57 +9702,17 @@ function __stxOverlay(errs){
9700
9702
  return "";
9701
9703
  }
9702
9704
  }
9703
- async function parseFormBody(request) {
9704
- const type = request.headers.get("content-type") || "";
9705
- const form = {};
9706
- const put = (key, value) => {
9707
- const existing = form[key];
9708
- if (existing === undefined)
9709
- form[key] = value;
9710
- else if (Array.isArray(existing))
9711
- existing.push(value);
9712
- else
9713
- form[key] = [existing, value];
9714
- };
9715
- if (type.includes("multipart/form-data")) {
9716
- const data = await request.formData();
9717
- for (const [key, value] of data.entries()) {
9718
- if (typeof value === "string")
9719
- put(key, value);
9720
- }
9721
- return form;
9722
- }
9723
- if (type.includes("application/x-www-form-urlencoded")) {
9724
- for (const [key, value] of new URLSearchParams(await request.text()).entries())
9725
- put(key, value);
9726
- return form;
9727
- }
9728
- return form;
9729
- }
9730
9705
  async function runPageAction(context, reqCtx) {
9731
- if (!reqCtx || reqCtx.method === "GET" || reqCtx.method === "HEAD")
9732
- return;
9733
- if (typeof context.action !== "function" || !reqCtx.request)
9706
+ if (!reqCtx)
9734
9707
  return;
9735
- let form = {};
9736
- try {
9737
- form = await parseFormBody(reqCtx.request);
9738
- } catch {}
9739
- const result = await context.action({
9708
+ const result = await sharedRunPageAction(context, {
9740
9709
  request: reqCtx.request,
9741
- form,
9710
+ method: reqCtx.method,
9742
9711
  params: reqCtx.params ?? {},
9743
- query: context.query ?? {},
9744
9712
  cookies: reqCtx.cookies ?? {}
9745
9713
  });
9746
- if (result && typeof result === "object") {
9747
- const to = result.redirect;
9748
- if (typeof to === "string" && to) {
9749
- reqCtx.actionRedirect = to;
9750
- return;
9751
- }
9752
- Object.assign(context, result);
9753
- }
9714
+ if (result.redirect)
9715
+ reqCtx.actionRedirect = result.redirect;
9754
9716
  }
9755
9717
  async function processTemplate(filePath, reqCtx) {
9756
9718
  const content = await Bun.file(filePath).text();
@@ -10136,426 +10098,427 @@ ${html}`;
10136
10098
  reusePort: options.reusePort ?? false,
10137
10099
  idleTimeout: 0,
10138
10100
  async fetch(req, server) {
10139
- const url = new URL(req.url);
10140
- let path = url.pathname;
10141
- const proxyRules = stxConfig.server?.proxy;
10142
- if (proxyRules) {
10143
- for (const [prefix, rule] of Object.entries(proxyRules)) {
10144
- if (path !== prefix && !path.startsWith(prefix))
10145
- continue;
10146
- const ruleCfg = typeof rule === "string" ? { target: rule } : rule;
10147
- const outPath = ruleCfg.rewrite ? ruleCfg.rewrite(path) : path;
10148
- const target = new URL(ruleCfg.target);
10149
- const outUrl = new URL(outPath + url.search, target);
10150
- const headers = new Headers(req.headers);
10151
- if (ruleCfg.changeOrigin !== false)
10152
- headers.set("host", target.host);
10153
- try {
10154
- return await fetch(outUrl, {
10155
- method: req.method,
10156
- headers,
10157
- body: req.body,
10158
- redirect: "manual",
10159
- ...req.body ? { duplex: "half" } : {}
10160
- });
10161
- } catch (err) {
10162
- return new Response(`[stx dev proxy] ${prefix} \u2192 ${ruleCfg.target} failed: ${err instanceof Error ? err.message : String(err)}`, { status: 502 });
10101
+ return compressResponse(req, await (async () => {
10102
+ const url = new URL(req.url);
10103
+ let path = url.pathname;
10104
+ const proxyRules = stxConfig.server?.proxy;
10105
+ if (proxyRules) {
10106
+ for (const [prefix, rule] of Object.entries(proxyRules)) {
10107
+ if (path !== prefix && !path.startsWith(prefix))
10108
+ continue;
10109
+ const ruleCfg = typeof rule === "string" ? { target: rule } : rule;
10110
+ const outPath = ruleCfg.rewrite ? ruleCfg.rewrite(path) : path;
10111
+ const target = new URL(ruleCfg.target);
10112
+ const outUrl = new URL(outPath + url.search, target);
10113
+ const headers = new Headers(req.headers);
10114
+ if (ruleCfg.changeOrigin !== false)
10115
+ headers.set("host", target.host);
10116
+ try {
10117
+ return await fetch(outUrl, {
10118
+ method: req.method,
10119
+ headers,
10120
+ body: req.body,
10121
+ redirect: "manual",
10122
+ ...req.body ? { duplex: "half" } : {}
10123
+ });
10124
+ } catch (err) {
10125
+ return new Response(`[stx dev proxy] ${prefix} \u2192 ${ruleCfg.target} failed: ${err instanceof Error ? err.message : String(err)}`, { status: 502 });
10126
+ }
10163
10127
  }
10164
10128
  }
10165
- }
10166
- let i18nLocale = null;
10167
- if (i18nConfig && !url.pathname.startsWith("/api/")) {
10168
- const stripped = localeFromPath(url.pathname);
10169
- i18nLocale = stripped.locale;
10170
- if (stripped.path !== url.pathname) {
10171
- const rewritten = new URL(req.url);
10172
- rewritten.pathname = stripped.path;
10173
- const headers = new Headers(req.headers);
10174
- headers.set("x-stx-locale", stripped.locale);
10175
- req = new Request(rewritten, { headers, method: req.method, body: req.body, redirect: req.redirect, duplex: "half" });
10176
- path = stripped.path;
10177
- } else if (i18nLocale) {
10178
- const headers = new Headers(req.headers);
10179
- headers.set("x-stx-locale", i18nLocale);
10180
- req = new Request(req, { headers });
10181
- }
10182
- }
10183
- let mintedCsrfToken = null;
10184
- const _i18nResp = await (async () => {
10185
- activeServeLocale = i18nLocale;
10186
- activeServeSearch = url.search;
10187
- activeServeHost = req.headers.get("host") || "";
10188
- activeServeCookieHeader = req.headers.get("cookie") || "";
10189
- activeServeCookies = parseCookies(req);
10190
- activeServeIp = server.requestIP(req)?.address || (req.headers.get("x-forwarded-for") || "").split(",")[0].trim();
10191
- mintedCsrfToken = csrfTokenToMint(req, activeServeCookies);
10192
- if (mintedCsrfToken)
10193
- activeServeCookies[CSRF_COOKIE] = mintedCsrfToken;
10194
- const reqCtx = {
10195
- url: req.url,
10196
- path,
10197
- search: activeServeSearch,
10198
- host: activeServeHost,
10199
- cookieHeader: activeServeCookieHeader,
10200
- cookies: activeServeCookies,
10201
- ip: activeServeIp,
10202
- locale: activeServeLocale,
10203
- params: {},
10204
- method: (req.method || "GET").toUpperCase(),
10205
- request: req
10206
- };
10207
- try {
10208
- if (req.method === "OPTIONS") {
10209
- return new Response(null, { headers: corsHeaders });
10129
+ let i18nLocale = null;
10130
+ if (i18nConfig && !url.pathname.startsWith("/api/")) {
10131
+ const stripped = localeFromPath(url.pathname);
10132
+ i18nLocale = stripped.locale;
10133
+ if (stripped.path !== url.pathname) {
10134
+ const rewritten = new URL(req.url);
10135
+ rewritten.pathname = stripped.path;
10136
+ const headers = new Headers(req.headers);
10137
+ headers.set("x-stx-locale", stripped.locale);
10138
+ req = new Request(rewritten, { headers, method: req.method, body: req.body, redirect: req.redirect, duplex: "half" });
10139
+ path = stripped.path;
10140
+ } else if (i18nLocale) {
10141
+ const headers = new Headers(req.headers);
10142
+ headers.set("x-stx-locale", i18nLocale);
10143
+ req = new Request(req, { headers });
10210
10144
  }
10211
- if (path === "/_stx/hmr") {
10212
- let controller;
10213
- let keepalive;
10214
- const stream = new ReadableStream({
10215
- start(c) {
10216
- controller = c;
10217
- hmrClients.add(c);
10218
- c.enqueue(hmrEncoder.encode(`data: {"type":"connected"}
10145
+ }
10146
+ let mintedCsrfToken = null;
10147
+ const _i18nResp = await (async () => {
10148
+ activeServeLocale = i18nLocale;
10149
+ activeServeSearch = url.search;
10150
+ activeServeHost = req.headers.get("host") || "";
10151
+ activeServeCookieHeader = req.headers.get("cookie") || "";
10152
+ activeServeCookies = parseCookies(req);
10153
+ activeServeIp = server.requestIP(req)?.address || (req.headers.get("x-forwarded-for") || "").split(",")[0].trim();
10154
+ mintedCsrfToken = csrfTokenToMint(req, activeServeCookies);
10155
+ if (mintedCsrfToken)
10156
+ activeServeCookies[CSRF_COOKIE] = mintedCsrfToken;
10157
+ const reqCtx = {
10158
+ url: req.url,
10159
+ path,
10160
+ search: activeServeSearch,
10161
+ host: activeServeHost,
10162
+ cookieHeader: activeServeCookieHeader,
10163
+ cookies: activeServeCookies,
10164
+ ip: activeServeIp,
10165
+ locale: activeServeLocale,
10166
+ params: {},
10167
+ method: (req.method || "GET").toUpperCase(),
10168
+ request: req
10169
+ };
10170
+ try {
10171
+ if (req.method === "OPTIONS") {
10172
+ return new Response(null, { headers: corsHeaders });
10173
+ }
10174
+ if (path === "/_stx/hmr") {
10175
+ let controller;
10176
+ let keepalive;
10177
+ const stream = new ReadableStream({
10178
+ start(c) {
10179
+ controller = c;
10180
+ hmrClients.add(c);
10181
+ c.enqueue(hmrEncoder.encode(`data: {"type":"connected"}
10219
10182
 
10220
10183
  `));
10221
- if (currentBuildErrors.length > 0) {
10222
- c.enqueue(hmrEncoder.encode(`data: ${JSON.stringify({ type: "build-error", errors: currentBuildErrors })}
10184
+ if (currentBuildErrors.length > 0) {
10185
+ c.enqueue(hmrEncoder.encode(`data: ${JSON.stringify({ type: "build-error", errors: currentBuildErrors })}
10223
10186
 
10224
10187
  `));
10225
- }
10226
- keepalive = setInterval(() => {
10227
- try {
10228
- c.enqueue(hmrEncoder.encode(`: keepalive
10188
+ }
10189
+ keepalive = setInterval(() => {
10190
+ try {
10191
+ c.enqueue(hmrEncoder.encode(`: keepalive
10229
10192
 
10230
10193
  `));
10231
- } catch {}
10232
- }, 5000);
10233
- },
10234
- cancel() {
10235
- if (keepalive)
10236
- clearInterval(keepalive);
10237
- if (controller)
10238
- hmrClients.delete(controller);
10239
- }
10240
- });
10241
- return new Response(stream, {
10242
- headers: {
10243
- "Content-Type": "text/event-stream",
10244
- "Cache-Control": "no-cache, no-transform",
10245
- Connection: "keep-alive",
10246
- "X-Accel-Buffering": "no"
10247
- }
10248
- });
10249
- }
10250
- if (path === "/_stx/runtime.js" || path === "/_stx/router.js") {
10251
- const stx = await stxModule;
10252
- const content2 = path === "/_stx/runtime.js" ? await stx.getCachedSignalsRuntime(stxConfig.debug === true) : await stx.getCachedRouterScript();
10253
- const etag = `"${Bun.hash(content2).toString(16)}"`;
10254
- const headers = {
10255
- "Content-Type": "application/javascript; charset=utf-8",
10256
- "Cache-Control": "public, max-age=0, must-revalidate",
10257
- ETag: etag,
10258
- ...corsHeaders
10259
- };
10260
- if (req.headers.get("if-none-match") === etag)
10261
- return new Response(null, { status: 304, headers });
10262
- if (req.method === "HEAD")
10263
- return new Response(null, { headers });
10264
- return new Response(content2, { headers });
10265
- }
10266
- if (path === "/_stx/stores.js") {
10267
- const stx = await stxModule;
10268
- const code = typeof stx.getStoreScript === "function" ? await stx.getStoreScript() : null;
10269
- return new Response(code ?? "", {
10270
- status: code === null ? 404 : 200,
10271
- headers: {
10194
+ } catch {}
10195
+ }, 5000);
10196
+ },
10197
+ cancel() {
10198
+ if (keepalive)
10199
+ clearInterval(keepalive);
10200
+ if (controller)
10201
+ hmrClients.delete(controller);
10202
+ }
10203
+ });
10204
+ return new Response(stream, {
10205
+ headers: {
10206
+ "Content-Type": "text/event-stream",
10207
+ "Cache-Control": "no-cache, no-transform",
10208
+ Connection: "keep-alive",
10209
+ "X-Accel-Buffering": "no"
10210
+ }
10211
+ });
10212
+ }
10213
+ if (path === "/_stx/runtime.js" || path === "/_stx/router.js") {
10214
+ const stx = await stxModule;
10215
+ const content2 = path === "/_stx/runtime.js" ? await stx.getCachedSignalsRuntime(stxConfig.debug === true) : await stx.getCachedRouterScript();
10216
+ const etag = `"${Bun.hash(content2).toString(16)}"`;
10217
+ const headers = {
10272
10218
  "Content-Type": "application/javascript; charset=utf-8",
10273
- "Cache-Control": "no-store",
10219
+ "Cache-Control": "public, max-age=0, must-revalidate",
10220
+ ETag: etag,
10274
10221
  ...corsHeaders
10275
- }
10276
- });
10277
- }
10278
- const crosswindAsset = path.match(/^\/_stx\/crosswind\.([a-f0-9]{16})\.css$/);
10279
- if (crosswindAsset) {
10280
- const stx = await stxModule;
10281
- const content2 = stx.getCrosswindServeAsset(crosswindAsset[1]);
10282
- if (content2 === undefined)
10283
- return new Response("Crosswind asset not found", { status: 404 });
10284
- const headers = {
10285
- "Content-Type": "text/css; charset=utf-8",
10286
- "Cache-Control": "public, max-age=31536000, immutable",
10287
- ...corsHeaders
10288
- };
10289
- if (req.method === "HEAD")
10290
- return new Response(null, { headers });
10291
- return new Response(content2, { headers });
10292
- }
10293
- if (options.onRequest) {
10294
- const hookResult = await options.onRequest(req);
10295
- if (hookResult instanceof Response)
10296
- return hookResult;
10297
- if (hookResult && typeof hookResult === "object")
10298
- Object.assign(reqCtx, hookResult);
10299
- }
10300
- const route = resolveRouteMiddleware(path);
10301
- const extraNames = extraProtectedPrefixes.some((p) => path === p || path.startsWith(p.endsWith("/") ? p : `${p}/`)) ? ["auth"] : [];
10302
- const requested = [...globalMiddlewareNames, ...route.names, ...extraNames];
10303
- if (requested.length > 0) {
10304
- const expanded = expandMiddlewareNames(requested);
10305
- const cookies = parseCookies(req);
10306
- const ctx = {
10307
- path,
10308
- url,
10309
- params: route.params,
10310
- cookies,
10311
- redirect: (to, status = 302) => {
10312
- const sep = to.includes("?") ? "&" : "?";
10313
- const next = encodeURIComponent(path + (url.search || ""));
10314
- return new Response(null, {
10315
- status,
10316
- headers: { Location: `${to}${sep}next=${next}` }
10317
- });
10318
- }
10319
- };
10320
- for (const entry of expanded) {
10321
- const colon = entry.indexOf(":");
10322
- const name = colon === -1 ? entry : entry.slice(0, colon);
10323
- const args = colon === -1 ? [] : entry.slice(colon + 1).split(",");
10324
- const handler = middlewareRegistry[name];
10325
- if (!handler) {
10326
- console.warn(`[stx serve] unknown middleware "${name}" on ${path}`);
10327
- continue;
10328
- }
10329
- const result = await handler(req, ctx, ...args);
10330
- if (result instanceof Response)
10331
- return result;
10222
+ };
10223
+ if (req.headers.get("if-none-match") === etag)
10224
+ return new Response(null, { status: 304, headers });
10225
+ if (req.method === "HEAD")
10226
+ return new Response(null, { headers });
10227
+ return new Response(content2, { headers });
10332
10228
  }
10333
- }
10334
- if (options.routes) {
10335
- const routeHandler = options.routes[path];
10336
- if (routeHandler) {
10337
- return routeHandler(req);
10229
+ if (path === "/_stx/stores.js") {
10230
+ const stx = await stxModule;
10231
+ const code = typeof stx.getStoreScript === "function" ? await stx.getStoreScript() : null;
10232
+ return new Response(code ?? "", {
10233
+ status: code === null ? 404 : 200,
10234
+ headers: {
10235
+ "Content-Type": "application/javascript; charset=utf-8",
10236
+ "Cache-Control": "no-store",
10237
+ ...corsHeaders
10238
+ }
10239
+ });
10338
10240
  }
10339
- }
10340
- if (path.startsWith("/_stx/component/")) {
10341
- const componentName = decodeURIComponent(path.slice("/_stx/component/".length));
10342
- if (componentName) {
10343
- try {
10344
- const { processDirectives, defaultConfig: defaultConfig4 } = await stxModule;
10345
- const componentTemplate = `<${componentName} />`;
10346
- const componentOpts = {
10347
- ...defaultConfig4,
10348
- ...componentsDir && { componentsDir },
10349
- ...layoutsDir && { layoutsDir },
10350
- ...partialsDir && { partialsDir },
10351
- autoShell: false
10352
- };
10353
- const html = await processDirectives(componentTemplate, {}, `${componentsDir}/${componentName}.stx`, componentOpts, new Set);
10354
- return new Response(html, {
10355
- headers: { "Content-Type": "text/html; charset=utf-8", ...corsHeaders }
10356
- });
10357
- } catch (e) {
10358
- return new Response(`<div class="stx-async-error">${e.message}</div>`, {
10359
- status: 500,
10360
- headers: { "Content-Type": "text/html; charset=utf-8", ...corsHeaders }
10361
- });
10241
+ const crosswindAsset = path.match(/^\/_stx\/crosswind\.([a-f0-9]{16})\.css$/);
10242
+ if (crosswindAsset) {
10243
+ const stx = await stxModule;
10244
+ const content2 = stx.getCrosswindServeAsset(crosswindAsset[1]);
10245
+ if (content2 === undefined)
10246
+ return new Response("Crosswind asset not found", { status: 404 });
10247
+ const headers = {
10248
+ "Content-Type": "text/css; charset=utf-8",
10249
+ "Cache-Control": "public, max-age=31536000, immutable",
10250
+ ...corsHeaders
10251
+ };
10252
+ if (req.method === "HEAD")
10253
+ return new Response(null, { headers });
10254
+ return new Response(content2, { headers });
10255
+ }
10256
+ if (options.onRequest) {
10257
+ const hookResult = await options.onRequest(req);
10258
+ if (hookResult instanceof Response)
10259
+ return hookResult;
10260
+ if (hookResult && typeof hookResult === "object")
10261
+ Object.assign(reqCtx, hookResult);
10262
+ }
10263
+ const route = resolveRouteMiddleware(path);
10264
+ const extraNames = extraProtectedPrefixes.some((p) => path === p || path.startsWith(p.endsWith("/") ? p : `${p}/`)) ? ["auth"] : [];
10265
+ const requested = [...globalMiddlewareNames, ...route.names, ...extraNames];
10266
+ if (requested.length > 0) {
10267
+ const expanded = expandMiddlewareNames(requested);
10268
+ const cookies = parseCookies(req);
10269
+ const ctx = {
10270
+ path,
10271
+ url,
10272
+ params: route.params,
10273
+ cookies,
10274
+ redirect: (to, status = 302) => {
10275
+ const sep = to.includes("?") ? "&" : "?";
10276
+ const next = encodeURIComponent(path + (url.search || ""));
10277
+ return new Response(null, {
10278
+ status,
10279
+ headers: { Location: `${to}${sep}next=${next}` }
10280
+ });
10281
+ }
10282
+ };
10283
+ for (const entry of expanded) {
10284
+ const colon = entry.indexOf(":");
10285
+ const name = colon === -1 ? entry : entry.slice(0, colon);
10286
+ const args = colon === -1 ? [] : entry.slice(colon + 1).split(",");
10287
+ const handler = middlewareRegistry[name];
10288
+ if (!handler) {
10289
+ console.warn(`[stx serve] unknown middleware "${name}" on ${path}`);
10290
+ continue;
10291
+ }
10292
+ const result = await handler(req, ctx, ...args);
10293
+ if (result instanceof Response)
10294
+ return result;
10362
10295
  }
10363
10296
  }
10364
- }
10365
- if (path.startsWith("/api/data/") && req.method === "POST") {
10366
- try {
10367
- const tableName = path.replace("/api/data/", "").split("/")[0];
10368
- if (!tableName) {
10369
- return new Response(JSON.stringify({ error: "Table name required" }), {
10370
- status: 400,
10371
- headers: { "Content-Type": "application/json", ...corsHeaders }
10372
- });
10297
+ if (options.routes) {
10298
+ const routeHandler = options.routes[path];
10299
+ if (routeHandler) {
10300
+ return routeHandler(req);
10373
10301
  }
10374
- if (!/^[a-zA-Z_]\w*$/.test(tableName)) {
10375
- return new Response(JSON.stringify({ error: "Invalid table name" }), {
10376
- status: 400,
10377
- headers: { "Content-Type": "application/json", ...corsHeaders }
10378
- });
10302
+ }
10303
+ if (path.startsWith("/_stx/component/")) {
10304
+ const componentName = decodeURIComponent(path.slice("/_stx/component/".length));
10305
+ if (componentName) {
10306
+ try {
10307
+ const { processDirectives, defaultConfig: defaultConfig4 } = await stxModule;
10308
+ const componentTemplate = `<${componentName} />`;
10309
+ const componentOpts = {
10310
+ ...defaultConfig4,
10311
+ ...componentsDir && { componentsDir },
10312
+ ...layoutsDir && { layoutsDir },
10313
+ ...partialsDir && { partialsDir },
10314
+ autoShell: false
10315
+ };
10316
+ const html = await processDirectives(componentTemplate, {}, `${componentsDir}/${componentName}.stx`, componentOpts, new Set);
10317
+ return new Response(html, {
10318
+ headers: { "Content-Type": "text/html; charset=utf-8", ...corsHeaders }
10319
+ });
10320
+ } catch (e) {
10321
+ return new Response(`<div class="stx-async-error">${e.message}</div>`, {
10322
+ status: 500,
10323
+ headers: { "Content-Type": "text/html; charset=utf-8", ...corsHeaders }
10324
+ });
10325
+ }
10379
10326
  }
10380
- const body = await req.json();
10381
- const { Database } = await import("bun:sqlite");
10382
- const dbPath = nodePath.resolve(process19.cwd(), "database/stacks.sqlite");
10383
- const db = new Database(dbPath);
10327
+ }
10328
+ if (path.startsWith("/api/data/") && req.method === "POST") {
10384
10329
  try {
10385
- const tableInfo = db.query(`PRAGMA table_info("${tableName}")`).all();
10386
- const validColumns = tableInfo.map((c) => c.name).filter((n) => n !== "id" && n !== "created_at" && n !== "updated_at");
10387
- const columns = [];
10388
- const placeholders = [];
10389
- const values = [];
10390
- for (const col of validColumns) {
10391
- if (body[col] !== undefined && body[col] !== "") {
10392
- columns.push(col);
10393
- placeholders.push("?");
10394
- values.push(body[col]);
10395
- }
10396
- }
10397
- const now = new Date().toISOString();
10398
- if (tableInfo.some((c) => c.name === "created_at")) {
10399
- columns.push("created_at");
10400
- placeholders.push("?");
10401
- values.push(now);
10402
- }
10403
- if (tableInfo.some((c) => c.name === "updated_at")) {
10404
- columns.push("updated_at");
10405
- placeholders.push("?");
10406
- values.push(now);
10330
+ const tableName = path.replace("/api/data/", "").split("/")[0];
10331
+ if (!tableName) {
10332
+ return new Response(JSON.stringify({ error: "Table name required" }), {
10333
+ status: 400,
10334
+ headers: { "Content-Type": "application/json", ...corsHeaders }
10335
+ });
10407
10336
  }
10408
- if (columns.length === 0) {
10409
- return new Response(JSON.stringify({ error: "No valid fields provided" }), {
10337
+ if (!/^[a-zA-Z_]\w*$/.test(tableName)) {
10338
+ return new Response(JSON.stringify({ error: "Invalid table name" }), {
10410
10339
  status: 400,
10411
10340
  headers: { "Content-Type": "application/json", ...corsHeaders }
10412
10341
  });
10413
10342
  }
10414
- const query = `INSERT INTO "${tableName}" (${columns.join(", ")}) VALUES (${placeholders.join(", ")})`;
10415
- const stmt = db.prepare(query);
10416
- const result = stmt.run(...values);
10417
- return new Response(JSON.stringify({
10418
- success: true,
10419
- id: result.lastInsertRowid,
10420
- message: "Record created successfully"
10421
- }), {
10422
- status: 201,
10423
- headers: { "Content-Type": "application/json", ...corsHeaders }
10424
- });
10425
- } catch (error) {
10426
- console.error("API Error:", error);
10427
- return new Response(JSON.stringify({
10428
- error: error.message || "Failed to create record"
10429
- }), {
10430
- status: 500,
10431
- headers: { "Content-Type": "application/json", ...corsHeaders }
10432
- });
10433
- } finally {
10434
- db.close();
10435
- }
10436
- } catch {}
10437
- }
10438
- if (path === "/index")
10439
- path = "/";
10440
- if (path === "/") {
10441
- const indexContent = await getRoute("/", reqCtx);
10442
- if (!indexContent) {
10443
- const homeContent = await getRoute("/home", reqCtx);
10444
- if (homeContent) {
10445
- return new Response(null, {
10446
- status: 302,
10447
- headers: {
10448
- Location: "/home",
10449
- ...corsHeaders
10343
+ const body = await req.json();
10344
+ const { Database } = await import("bun:sqlite");
10345
+ const dbPath = nodePath.resolve(process19.cwd(), "database/stacks.sqlite");
10346
+ const db = new Database(dbPath);
10347
+ try {
10348
+ const tableInfo = db.query(`PRAGMA table_info("${tableName}")`).all();
10349
+ const validColumns = tableInfo.map((c) => c.name).filter((n) => n !== "id" && n !== "created_at" && n !== "updated_at");
10350
+ const columns = [];
10351
+ const placeholders = [];
10352
+ const values = [];
10353
+ for (const col of validColumns) {
10354
+ if (body[col] !== undefined && body[col] !== "") {
10355
+ columns.push(col);
10356
+ placeholders.push("?");
10357
+ values.push(body[col]);
10358
+ }
10450
10359
  }
10451
- });
10360
+ const now = new Date().toISOString();
10361
+ if (tableInfo.some((c) => c.name === "created_at")) {
10362
+ columns.push("created_at");
10363
+ placeholders.push("?");
10364
+ values.push(now);
10365
+ }
10366
+ if (tableInfo.some((c) => c.name === "updated_at")) {
10367
+ columns.push("updated_at");
10368
+ placeholders.push("?");
10369
+ values.push(now);
10370
+ }
10371
+ if (columns.length === 0) {
10372
+ return new Response(JSON.stringify({ error: "No valid fields provided" }), {
10373
+ status: 400,
10374
+ headers: { "Content-Type": "application/json", ...corsHeaders }
10375
+ });
10376
+ }
10377
+ const query = `INSERT INTO "${tableName}" (${columns.join(", ")}) VALUES (${placeholders.join(", ")})`;
10378
+ const stmt = db.prepare(query);
10379
+ const result = stmt.run(...values);
10380
+ return new Response(JSON.stringify({
10381
+ success: true,
10382
+ id: result.lastInsertRowid,
10383
+ message: "Record created successfully"
10384
+ }), {
10385
+ status: 201,
10386
+ headers: { "Content-Type": "application/json", ...corsHeaders }
10387
+ });
10388
+ } catch (error) {
10389
+ console.error("API Error:", error);
10390
+ return new Response(JSON.stringify({
10391
+ error: error.message || "Failed to create record"
10392
+ }), {
10393
+ status: 500,
10394
+ headers: { "Content-Type": "application/json", ...corsHeaders }
10395
+ });
10396
+ } finally {
10397
+ db.close();
10398
+ }
10399
+ } catch {}
10400
+ }
10401
+ if (path === "/index")
10402
+ path = "/";
10403
+ if (path === "/") {
10404
+ const indexContent = await getRoute("/", reqCtx);
10405
+ if (!indexContent) {
10406
+ const homeContent = await getRoute("/home", reqCtx);
10407
+ if (homeContent) {
10408
+ return new Response(null, {
10409
+ status: 302,
10410
+ headers: {
10411
+ Location: "/home",
10412
+ ...corsHeaders
10413
+ }
10414
+ });
10415
+ }
10452
10416
  }
10453
10417
  }
10454
- }
10455
- const content = await getRoute(path, reqCtx);
10456
- if (reqCtx.actionRedirect) {
10457
- return new Response(null, {
10458
- status: 303,
10459
- headers: { ...corsHeaders, Location: reqCtx.actionRedirect }
10460
- });
10461
- }
10462
- if (content) {
10463
- const responseStatus = reqCtx.responseStatus ?? 200;
10464
- const isSpaNav = req.headers.get("X-STX-Router") === "true";
10465
- if (isSpaNav) {
10466
- const layoutMatch = content.match(/<!-- stx-layout: ([^ ]+) -->/);
10467
- const pageLayout = layoutMatch ? layoutMatch[1] : "default";
10468
- const groupMetaMatch = content.match(/<meta\b[^>]*name=["']stx-layout-group["'][^>]*content=["']([^"']+)["'][^>]*>/i);
10469
- const pageLayoutGroup = i18nConfig && i18nLocale ? `i18n:${i18nLocale}` : groupMetaMatch?.[1] || deriveLayoutGroup(pageLayout);
10470
- let fragment = content;
10471
- let containerAttrs = "";
10472
- let mainContentStart = -1;
10473
- let mainContentEnd = -1;
10474
- const headStyles = [];
10475
- const headMatch = content.match(/<head\b[^>]*>([\s\S]*?)<\/head>/i);
10476
- if (headMatch) {
10477
- const headContent = headMatch[1];
10478
- let styleMatch;
10479
- const styleRe = /<style\b[^>]*>[\s\S]*?<\/style>/gi;
10480
- while ((styleMatch = styleRe.exec(headContent)) !== null) {
10481
- if (styleMatch[0].includes("data-crosswind")) {
10482
- const cssContent = styleMatch[0].replace(/<style[^>]*>/, "").replace(/<\/style>/, "");
10483
- const hiddenRule = cssContent.indexOf("[hidden]");
10484
- if (hiddenRule !== -1) {
10485
- const afterPreflight = cssContent.indexOf("}", hiddenRule) + 1;
10486
- const utilities = cssContent.slice(afterPreflight).trim();
10487
- if (utilities) {
10488
- headStyles.push(`<style data-crosswind="fragment">${utilities}</style>`);
10418
+ const content = await getRoute(path, reqCtx);
10419
+ if (reqCtx.actionRedirect) {
10420
+ return new Response(null, {
10421
+ status: 303,
10422
+ headers: { ...corsHeaders, Location: reqCtx.actionRedirect }
10423
+ });
10424
+ }
10425
+ if (content) {
10426
+ const responseStatus = reqCtx.responseStatus ?? 200;
10427
+ const isSpaNav = req.headers.get("X-STX-Router") === "true";
10428
+ if (isSpaNav) {
10429
+ const layoutMatch = content.match(/<!-- stx-layout: ([^ ]+) -->/);
10430
+ const pageLayout = layoutMatch ? layoutMatch[1] : "default";
10431
+ const groupMetaMatch = content.match(/<meta\b[^>]*name=["']stx-layout-group["'][^>]*content=["']([^"']+)["'][^>]*>/i);
10432
+ const pageLayoutGroup = i18nConfig && i18nLocale ? `i18n:${i18nLocale}` : groupMetaMatch?.[1] || deriveLayoutGroup(pageLayout);
10433
+ let fragment = content;
10434
+ let containerAttrs = "";
10435
+ let mainContentStart = -1;
10436
+ let mainContentEnd = -1;
10437
+ const headStyles = [];
10438
+ const headMatch = content.match(/<head\b[^>]*>([\s\S]*?)<\/head>/i);
10439
+ if (headMatch) {
10440
+ const headContent = headMatch[1];
10441
+ let styleMatch;
10442
+ const styleRe = /<style\b[^>]*>[\s\S]*?<\/style>/gi;
10443
+ while ((styleMatch = styleRe.exec(headContent)) !== null) {
10444
+ if (styleMatch[0].includes("data-crosswind")) {
10445
+ const cssContent = styleMatch[0].replace(/<style[^>]*>/, "").replace(/<\/style>/, "");
10446
+ const hiddenRule = cssContent.indexOf("[hidden]");
10447
+ if (hiddenRule !== -1) {
10448
+ const afterPreflight = cssContent.indexOf("}", hiddenRule) + 1;
10449
+ const utilities = cssContent.slice(afterPreflight).trim();
10450
+ if (utilities) {
10451
+ headStyles.push(`<style data-crosswind="fragment">${utilities}</style>`);
10452
+ }
10489
10453
  }
10454
+ continue;
10490
10455
  }
10491
- continue;
10456
+ headStyles.push(styleMatch[0]);
10457
+ }
10458
+ const crosswindLinkRe = /<link\b[^>]*\bdata-crosswind=(?:"generated"|'generated')[^>]*>/gi;
10459
+ let crosswindLinkMatch;
10460
+ while ((crosswindLinkMatch = crosswindLinkRe.exec(headContent)) !== null) {
10461
+ headStyles.push(crosswindLinkMatch[0]);
10492
10462
  }
10493
- headStyles.push(styleMatch[0]);
10494
10463
  }
10495
- const crosswindLinkRe = /<link\b[^>]*\bdata-crosswind=(?:"generated"|'generated')[^>]*>/gi;
10496
- let crosswindLinkMatch;
10497
- while ((crosswindLinkMatch = crosswindLinkRe.exec(headContent)) !== null) {
10498
- headStyles.push(crosswindLinkMatch[0]);
10464
+ const containerSelector = stxConfig?.router?.container || "main";
10465
+ const containerRegion = findContainerRegion(fragment, containerSelector);
10466
+ if (!containerRegion) {
10467
+ console.warn(`[stx] No SPA swap container matching "${containerSelector}" in ${new URL(req.url).pathname}. SPA navigation is disabled for links on this page; the full document will load instead. Add a matching element, or point router.container at one this page has.`);
10499
10468
  }
10500
- }
10501
- const containerSelector = stxConfig?.router?.container || "main";
10502
- const containerRegion = findContainerRegion(fragment, containerSelector);
10503
- if (!containerRegion) {
10504
- console.warn(`[stx] No SPA swap container matching "${containerSelector}" in ${new URL(req.url).pathname}. SPA navigation is disabled for links on this page; the full document will load instead. Add a matching element, or point router.container at one this page has.`);
10505
- }
10506
- const mainOpenMatch = containerRegion ? { 0: containerRegion.openTag, index: containerRegion.openIndex } : null;
10507
- const mainCloseIdx = containerRegion ? containerRegion.end : -1;
10508
- if (mainOpenMatch && mainCloseIdx !== -1) {
10509
- const bodyMatch = content.match(/<body\b[^>]*>/i);
10510
- if (bodyMatch) {
10511
- const bodyStart = bodyMatch.index + bodyMatch[0].length;
10512
- const mainIdx = mainOpenMatch.index;
10513
- const beforeMain = content.slice(bodyStart, mainIdx);
10514
- let bodyStyleMatch;
10515
- const bodyStyleRe = /<style\b[^>]*>[\s\S]*?<\/style>/gi;
10516
- while ((bodyStyleMatch = bodyStyleRe.exec(beforeMain)) !== null) {
10517
- headStyles.push(bodyStyleMatch[0]);
10469
+ const mainOpenMatch = containerRegion ? { 0: containerRegion.openTag, index: containerRegion.openIndex } : null;
10470
+ const mainCloseIdx = containerRegion ? containerRegion.end : -1;
10471
+ if (mainOpenMatch && mainCloseIdx !== -1) {
10472
+ const bodyMatch = content.match(/<body\b[^>]*>/i);
10473
+ if (bodyMatch) {
10474
+ const bodyStart = bodyMatch.index + bodyMatch[0].length;
10475
+ const mainIdx = mainOpenMatch.index;
10476
+ const beforeMain = content.slice(bodyStart, mainIdx);
10477
+ let bodyStyleMatch;
10478
+ const bodyStyleRe = /<style\b[^>]*>[\s\S]*?<\/style>/gi;
10479
+ while ((bodyStyleMatch = bodyStyleRe.exec(beforeMain)) !== null) {
10480
+ headStyles.push(bodyStyleMatch[0]);
10481
+ }
10518
10482
  }
10483
+ containerAttrs = mainOpenMatch[0].replace(new RegExp(`^<${containerRegion.tagName}\\b`, "i"), "").replace(/\/?>$/, "").trim();
10484
+ const mainStart = mainOpenMatch.index + mainOpenMatch[0].length;
10485
+ mainContentStart = mainStart;
10486
+ mainContentEnd = mainCloseIdx;
10487
+ fragment = fragment.slice(mainStart, mainCloseIdx).trim();
10519
10488
  }
10520
- containerAttrs = mainOpenMatch[0].replace(new RegExp(`^<${containerRegion.tagName}\\b`, "i"), "").replace(/\/?>$/, "").trim();
10521
- const mainStart = mainOpenMatch.index + mainOpenMatch[0].length;
10522
- mainContentStart = mainStart;
10523
- mainContentEnd = mainCloseIdx;
10524
- fragment = fragment.slice(mainStart, mainCloseIdx).trim();
10525
- }
10526
- const pageSetupScripts = [];
10527
- const pageSetupScriptOffsets = new Set;
10528
- const appendOutsideMainScript = (match) => {
10529
- const offset = match.index;
10530
- const insideMain = mainContentStart !== -1 && offset >= mainContentStart && offset < mainContentEnd;
10531
- if (insideMain || pageSetupScriptOffsets.has(offset))
10532
- return;
10533
- pageSetupScriptOffsets.add(offset);
10534
- pageSetupScripts.push(match[0]);
10535
- };
10536
- const routeParamsRe = /<script\b[^>]*data-stx-route-params[^>]*>[\s\S]*?<\/script>/gi;
10537
- let setupMatch;
10538
- while ((setupMatch = routeParamsRe.exec(content)) !== null) {
10539
- appendOutsideMainScript(setupMatch);
10540
- }
10541
- const allScriptRe = /<script\b[^>]*data-stx-scoped[^>]*>[\s\S]*?<\/script>/gi;
10542
- while ((setupMatch = allScriptRe.exec(content)) !== null) {
10543
- const scriptContent = setupMatch[0];
10544
- if (scriptContent.includes("__stx_early_mounts"))
10545
- continue;
10546
- if (scriptContent.includes("data-stx-reactive") && scriptContent.includes("window.__stx_reactive"))
10547
- continue;
10548
- appendOutsideMainScript(setupMatch);
10549
- }
10550
- const bridgeInitRe = /<script\b[^>]*data-stx-reactive[^>]*>(?![\s\S]*window\.__stx_reactive)[\s\S]*?<\/script>/gi;
10551
- while ((setupMatch = bridgeInitRe.exec(content)) !== null) {
10552
- appendOutsideMainScript(setupMatch);
10553
- }
10554
- fragment = fragment.replace(/<script data-stx-scoped>\s*;?\(function\(\)\s*\{[\s\S]*?<\/script>/g, "");
10555
- const clearStale = "<script data-stx-page>if(window.stx)window.stx._latestSetup=null;</script>";
10556
- const componentFactoryScripts = pageSetupScripts.filter((script) => script.includes("data-stx-component-factories"));
10557
- const trailingPageScripts = pageSetupScripts.filter((script) => !script.includes("data-stx-component-factories"));
10558
- fragment = `${headStyles.join(`
10489
+ const pageSetupScripts = [];
10490
+ const pageSetupScriptOffsets = new Set;
10491
+ const appendOutsideMainScript = (match) => {
10492
+ const offset = match.index;
10493
+ const insideMain = mainContentStart !== -1 && offset >= mainContentStart && offset < mainContentEnd;
10494
+ if (insideMain || pageSetupScriptOffsets.has(offset))
10495
+ return;
10496
+ pageSetupScriptOffsets.add(offset);
10497
+ pageSetupScripts.push(match[0]);
10498
+ };
10499
+ const routeParamsRe = /<script\b[^>]*data-stx-route-params[^>]*>[\s\S]*?<\/script>/gi;
10500
+ let setupMatch;
10501
+ while ((setupMatch = routeParamsRe.exec(content)) !== null) {
10502
+ appendOutsideMainScript(setupMatch);
10503
+ }
10504
+ const allScriptRe = /<script\b[^>]*data-stx-scoped[^>]*>[\s\S]*?<\/script>/gi;
10505
+ while ((setupMatch = allScriptRe.exec(content)) !== null) {
10506
+ const scriptContent = setupMatch[0];
10507
+ if (scriptContent.includes("__stx_early_mounts"))
10508
+ continue;
10509
+ if (scriptContent.includes("data-stx-reactive") && scriptContent.includes("window.__stx_reactive"))
10510
+ continue;
10511
+ appendOutsideMainScript(setupMatch);
10512
+ }
10513
+ const bridgeInitRe = /<script\b[^>]*data-stx-reactive[^>]*>(?![\s\S]*window\.__stx_reactive)[\s\S]*?<\/script>/gi;
10514
+ while ((setupMatch = bridgeInitRe.exec(content)) !== null) {
10515
+ appendOutsideMainScript(setupMatch);
10516
+ }
10517
+ fragment = fragment.replace(/<script data-stx-scoped>\s*;?\(function\(\)\s*\{[\s\S]*?<\/script>/g, "");
10518
+ const clearStale = "<script data-stx-page>if(window.stx)window.stx._latestSetup=null;</script>";
10519
+ const componentFactoryScripts = pageSetupScripts.filter((script) => script.includes("data-stx-component-factories"));
10520
+ const trailingPageScripts = pageSetupScripts.filter((script) => !script.includes("data-stx-component-factories"));
10521
+ fragment = `${headStyles.join(`
10559
10522
  `)}
10560
10523
  ${componentFactoryScripts.join(`
10561
10524
  `)}
@@ -10563,215 +10526,216 @@ ${fragment}
10563
10526
  ${clearStale}
10564
10527
  ${trailingPageScripts.join(`
10565
10528
  `)}`;
10566
- const titleMatch = content.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
10567
- const pageTitle = titleMatch ? titleMatch[1].trim() : "";
10568
- const shipsRuntime = content.includes("data-stx-runtime");
10569
- return new Response(fragment, {
10570
- status: isRenderFailure(content) ? 500 : responseStatus,
10529
+ const titleMatch = content.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
10530
+ const pageTitle = titleMatch ? titleMatch[1].trim() : "";
10531
+ const shipsRuntime = content.includes("data-stx-runtime");
10532
+ return new Response(fragment, {
10533
+ status: isRenderFailure(content) ? 500 : responseStatus,
10534
+ headers: {
10535
+ "Content-Type": "text/html; charset=utf-8",
10536
+ "X-STX-Fragment": "true",
10537
+ "X-STX-Layout": pageLayout,
10538
+ "X-STX-Layout-Group": pageLayoutGroup,
10539
+ "X-STX-Runtime": shipsRuntime ? "true" : "false",
10540
+ ...pageTitle && { "X-STX-Title": encodeURIComponent(pageTitle) },
10541
+ [BUILD_ID_HEADER]: getBuildId(),
10542
+ ...containerAttrs && { "X-STX-Container-Attrs": encodeURIComponent(containerAttrs) },
10543
+ "Cache-Control": "no-store",
10544
+ ...corsHeaders
10545
+ }
10546
+ });
10547
+ }
10548
+ let cleaned = content;
10549
+ let runtimeCount = 0;
10550
+ cleaned = content.replace(/<script data-stx-scoped>\(function\(\)\{'use strict';var cloakStyle[\s\S]*?<\/script>/g, (match) => {
10551
+ runtimeCount++;
10552
+ return runtimeCount === 1 ? match : "";
10553
+ });
10554
+ const pageRenderFailed = isRenderFailure(cleaned);
10555
+ if (pageRenderFailed) {
10556
+ console.error(`[stx] render failed for ${new URL(req.url).pathname} \u2014 serving 500`);
10557
+ for (const custom500 of ["/500", "/errors/500"]) {
10558
+ try {
10559
+ const errorPage = usableErrorPage(await getRoute(custom500, reqCtx));
10560
+ if (errorPage) {
10561
+ const isProd2 = isProductionServe();
10562
+ return new Response(isProd2 ? errorPage : injectHmrClient(errorPage), {
10563
+ status: 500,
10564
+ headers: {
10565
+ "Content-Type": "text/html; charset=utf-8",
10566
+ "Cache-Control": "no-store",
10567
+ ...corsHeaders
10568
+ }
10569
+ });
10570
+ }
10571
+ } catch {}
10572
+ }
10573
+ }
10574
+ return new Response(injectHmrClient(cleaned), {
10575
+ status: pageRenderFailed ? 500 : responseStatus,
10571
10576
  headers: {
10572
10577
  "Content-Type": "text/html; charset=utf-8",
10573
- "X-STX-Fragment": "true",
10574
- "X-STX-Layout": pageLayout,
10575
- "X-STX-Layout-Group": pageLayoutGroup,
10576
- "X-STX-Runtime": shipsRuntime ? "true" : "false",
10577
- ...pageTitle && { "X-STX-Title": encodeURIComponent(pageTitle) },
10578
- [BUILD_ID_HEADER]: getBuildId(),
10579
- ...containerAttrs && { "X-STX-Container-Attrs": encodeURIComponent(containerAttrs) },
10580
10578
  "Cache-Control": "no-store",
10581
10579
  ...corsHeaders
10582
10580
  }
10583
10581
  });
10584
10582
  }
10585
- let cleaned = content;
10586
- let runtimeCount = 0;
10587
- cleaned = content.replace(/<script data-stx-scoped>\(function\(\)\{'use strict';var cloakStyle[\s\S]*?<\/script>/g, (match) => {
10588
- runtimeCount++;
10589
- return runtimeCount === 1 ? match : "";
10590
- });
10591
- const pageRenderFailed = isRenderFailure(cleaned);
10592
- if (pageRenderFailed) {
10593
- console.error(`[stx] render failed for ${new URL(req.url).pathname} \u2014 serving 500`);
10594
- for (const custom500 of ["/500", "/errors/500"]) {
10595
- try {
10596
- const errorPage = usableErrorPage(await getRoute(custom500, reqCtx));
10597
- if (errorPage) {
10598
- const isProd2 = isProductionServe();
10599
- return new Response(isProd2 ? errorPage : injectHmrClient(errorPage), {
10600
- status: 500,
10601
- headers: {
10602
- "Content-Type": "text/html; charset=utf-8",
10603
- "Cache-Control": "no-store",
10604
- ...corsHeaders
10605
- }
10606
- });
10607
- }
10608
- } catch {}
10609
- }
10610
- }
10611
- return new Response(injectHmrClient(cleaned), {
10612
- status: pageRenderFailed ? 500 : responseStatus,
10613
- headers: {
10614
- "Content-Type": "text/html; charset=utf-8",
10615
- "Cache-Control": "no-store",
10616
- ...corsHeaders
10617
- }
10618
- });
10619
- }
10620
- const contentWithExt = await getRoute(`${path}.html`, reqCtx);
10621
- if (contentWithExt) {
10622
- return new Response(injectHmrClient(contentWithExt), {
10623
- status: reqCtx.responseStatus ?? 200,
10624
- headers: {
10625
- "Content-Type": "text/html; charset=utf-8",
10626
- "Cache-Control": "no-store",
10627
- ...corsHeaders
10628
- }
10629
- });
10630
- }
10631
- if (path.startsWith("/chunk-") || path.endsWith(".js") || path.endsWith(".css")) {
10632
- try {
10633
- const buildFile = Bun.file(stateDir(process19.cwd(), path));
10634
- if (await buildFile.exists()) {
10635
- const ext = path.split(".").pop()?.toLowerCase();
10636
- const contentType = ext === "css" ? "text/css" : ext === "js" ? "application/javascript" : "text/plain";
10637
- return new Response(buildFile, {
10638
- headers: {
10639
- "Content-Type": contentType,
10640
- "Cache-Control": "no-store"
10641
- }
10642
- });
10643
- }
10644
- } catch {}
10645
- }
10646
- if (path.startsWith("/assets/") || path.startsWith("/resources/assets/")) {
10647
- await ensureAssets();
10648
- let assetPathname;
10649
- try {
10650
- assetPathname = decodeURIComponent(path);
10651
- } catch {
10652
- return new Response("Invalid asset path", { status: 400 });
10583
+ const contentWithExt = await getRoute(`${path}.html`, reqCtx);
10584
+ if (contentWithExt) {
10585
+ return new Response(injectHmrClient(contentWithExt), {
10586
+ status: reqCtx.responseStatus ?? 200,
10587
+ headers: {
10588
+ "Content-Type": "text/html; charset=utf-8",
10589
+ "Cache-Control": "no-store",
10590
+ ...corsHeaders
10591
+ }
10592
+ });
10653
10593
  }
10654
- if (!isSafeAssetPath(assetPathname))
10655
- return new Response("Invalid asset path", { status: 400 });
10656
- for (const assetPath of assetRequestPaths(assetPathname)) {
10594
+ if (path.startsWith("/chunk-") || path.endsWith(".js") || path.endsWith(".css")) {
10657
10595
  try {
10658
- const filePath = nodePath.resolve(process19.cwd(), `.${assetPath}`);
10659
- const file = Bun.file(filePath);
10660
- if (await file.exists()) {
10661
- const ext = getAssetExtension(assetPath);
10662
- if (isBundledAssetExtension(ext))
10663
- return bundleBrowserAsset(filePath);
10664
- return new Response(file, {
10596
+ const buildFile = Bun.file(stateDir(process19.cwd(), path));
10597
+ if (await buildFile.exists()) {
10598
+ const ext = path.split(".").pop()?.toLowerCase();
10599
+ const contentType = ext === "css" ? "text/css" : ext === "js" ? "application/javascript" : "text/plain";
10600
+ return new Response(buildFile, {
10665
10601
  headers: {
10666
- "Content-Type": staticContentTypes[ext || ""] || "application/octet-stream",
10602
+ "Content-Type": contentType,
10667
10603
  "Cache-Control": "no-store"
10668
10604
  }
10669
10605
  });
10670
10606
  }
10607
+ } catch {}
10608
+ }
10609
+ if (path.startsWith("/assets/") || path.startsWith("/resources/assets/")) {
10610
+ await ensureAssets();
10611
+ let assetPathname;
10612
+ try {
10613
+ assetPathname = decodeURIComponent(path);
10671
10614
  } catch {
10672
- continue;
10615
+ return new Response("Invalid asset path", { status: 400 });
10673
10616
  }
10674
- }
10675
- }
10676
- if ((req.method === "GET" || req.method === "HEAD") && path !== "/") {
10677
- const publicRoot = nodePath.resolve(process19.cwd(), publicDir);
10678
- let safePathname;
10679
- try {
10680
- safePathname = decodeURIComponent(path);
10681
- } catch {
10682
- safePathname = path;
10683
- }
10684
- if (!safePathname.includes("\x00")) {
10685
- const resolvedPath = nodePath.resolve(publicRoot, `.${safePathname}`);
10686
- const isInsidePublicRoot = resolvedPath === publicRoot || resolvedPath.startsWith(`${publicRoot}${nodePath.sep}`);
10687
- if (isInsidePublicRoot) {
10617
+ if (!isSafeAssetPath(assetPathname))
10618
+ return new Response("Invalid asset path", { status: 400 });
10619
+ for (const assetPath of assetRequestPaths(assetPathname)) {
10688
10620
  try {
10689
- const file = Bun.file(resolvedPath);
10621
+ const filePath = nodePath.resolve(process19.cwd(), `.${assetPath}`);
10622
+ const file = Bun.file(filePath);
10690
10623
  if (await file.exists()) {
10691
- const stat4 = await file.stat().catch(() => null);
10692
- if (stat4 && !stat4.isDirectory()) {
10693
- const ext = resolvedPath.split(".").pop()?.toLowerCase();
10694
- return new Response(file, {
10695
- headers: {
10696
- "Content-Type": staticContentTypes[ext || ""] || "application/octet-stream",
10697
- "Cache-Control": staticCacheControl(resolvedPath)
10698
- }
10699
- });
10700
- }
10624
+ const ext = getAssetExtension(assetPath);
10625
+ if (isBundledAssetExtension(ext))
10626
+ return bundleBrowserAsset(filePath);
10627
+ return new Response(file, {
10628
+ headers: {
10629
+ "Content-Type": staticContentTypes[ext || ""] || "application/octet-stream",
10630
+ "Cache-Control": "no-store"
10631
+ }
10632
+ });
10701
10633
  }
10702
- } catch {}
10634
+ } catch {
10635
+ continue;
10636
+ }
10703
10637
  }
10704
10638
  }
10705
- }
10706
- if (path === "/favicon.ico") {
10707
- return new Response(null, { status: 204 });
10708
- }
10709
- const isProd = isProductionServe();
10710
- for (const custom404 of ["/404", "/errors/404"]) {
10711
- try {
10712
- const customContent = await getRoute(custom404, reqCtx);
10713
- if (customContent) {
10714
- return new Response(isProd ? customContent : injectHmrClient(customContent), {
10715
- status: 404,
10716
- headers: { "Content-Type": "text/html; charset=utf-8" }
10717
- });
10639
+ if ((req.method === "GET" || req.method === "HEAD") && path !== "/") {
10640
+ const publicRoot = nodePath.resolve(process19.cwd(), publicDir);
10641
+ let safePathname;
10642
+ try {
10643
+ safePathname = decodeURIComponent(path);
10644
+ } catch {
10645
+ safePathname = path;
10718
10646
  }
10719
- } catch {}
10720
- }
10721
- let availableRoutes;
10722
- if (!isProd) {
10723
- const files = await discoverFiles();
10724
- availableRoutes = [];
10725
- for (const filePath of files) {
10726
- let normalizedPath = filePath.replace(/^\.\//, "").replace(/\\/g, "/");
10727
- for (const pattern of patterns) {
10728
- const normalizedPattern = pattern.replace(/\\/g, "/").replace(/\/$/, "");
10729
- if (normalizedPath.startsWith(`${normalizedPattern}/`)) {
10730
- normalizedPath = normalizedPath.slice(normalizedPattern.length + 1);
10731
- break;
10647
+ if (!safePathname.includes("\x00")) {
10648
+ const resolvedPath = nodePath.resolve(publicRoot, `.${safePathname}`);
10649
+ const isInsidePublicRoot = resolvedPath === publicRoot || resolvedPath.startsWith(`${publicRoot}${nodePath.sep}`);
10650
+ if (isInsidePublicRoot) {
10651
+ try {
10652
+ const file = Bun.file(resolvedPath);
10653
+ if (await file.exists()) {
10654
+ const stat4 = await file.stat().catch(() => null);
10655
+ if (stat4 && !stat4.isDirectory()) {
10656
+ const ext = resolvedPath.split(".").pop()?.toLowerCase();
10657
+ return new Response(file, {
10658
+ headers: {
10659
+ "Content-Type": staticContentTypes[ext || ""] || "application/octet-stream",
10660
+ "Cache-Control": staticCacheControl(resolvedPath)
10661
+ }
10662
+ });
10663
+ }
10664
+ }
10665
+ } catch {}
10732
10666
  }
10733
10667
  }
10734
- let route2 = normalizedPath.replace(/\.(stx|md|html)$/, "");
10735
- if (route2.startsWith("pages/")) {
10736
- route2 = route2.slice(6);
10668
+ }
10669
+ if (path === "/favicon.ico") {
10670
+ return new Response(null, { status: 204 });
10671
+ }
10672
+ const isProd = isProductionServe();
10673
+ for (const custom404 of ["/404", "/errors/404"]) {
10674
+ try {
10675
+ const customContent = await getRoute(custom404, reqCtx);
10676
+ if (customContent) {
10677
+ return new Response(isProd ? customContent : injectHmrClient(customContent), {
10678
+ status: 404,
10679
+ headers: { "Content-Type": "text/html; charset=utf-8" }
10680
+ });
10681
+ }
10682
+ } catch {}
10683
+ }
10684
+ let availableRoutes;
10685
+ if (!isProd) {
10686
+ const files = await discoverFiles();
10687
+ availableRoutes = [];
10688
+ for (const filePath of files) {
10689
+ let normalizedPath = filePath.replace(/^\.\//, "").replace(/\\/g, "/");
10690
+ for (const pattern of patterns) {
10691
+ const normalizedPattern = pattern.replace(/\\/g, "/").replace(/\/$/, "");
10692
+ if (normalizedPath.startsWith(`${normalizedPattern}/`)) {
10693
+ normalizedPath = normalizedPath.slice(normalizedPattern.length + 1);
10694
+ break;
10695
+ }
10696
+ }
10697
+ let route2 = normalizedPath.replace(/\.(stx|md|html)$/, "");
10698
+ if (route2.startsWith("pages/")) {
10699
+ route2 = route2.slice(6);
10700
+ }
10701
+ availableRoutes.push(route2);
10737
10702
  }
10738
- availableRoutes.push(route2);
10739
10703
  }
10704
+ const notFoundHtml = render404Page({ path, routes: availableRoutes, isProduction: isProd });
10705
+ return new Response(isProd ? notFoundHtml : injectHmrClient(notFoundHtml), {
10706
+ status: 404,
10707
+ headers: { "Content-Type": "text/html; charset=utf-8" }
10708
+ });
10709
+ } finally {
10710
+ activeServeLocale = null;
10711
+ activeServeSearch = "";
10712
+ activeServeHost = "";
10713
+ activeServeCookieHeader = "";
10714
+ activeServeCookies = {};
10715
+ activeServeIp = "";
10716
+ }
10717
+ })();
10718
+ let _finalResp = await applyI18nToResponse(_i18nResp, i18nLocale ?? (i18nConfig?.defaultLocale ?? "en"), path);
10719
+ if (mintedCsrfToken) {
10720
+ try {
10721
+ _finalResp.headers.append("Set-Cookie", csrfCookieHeader(mintedCsrfToken, req.url.startsWith("https://")));
10722
+ } catch {
10723
+ const headers = new Headers(_finalResp.headers);
10724
+ headers.append("Set-Cookie", csrfCookieHeader(mintedCsrfToken, req.url.startsWith("https://")));
10725
+ _finalResp = new Response(_finalResp.body, {
10726
+ status: _finalResp.status,
10727
+ statusText: _finalResp.statusText,
10728
+ headers
10729
+ });
10740
10730
  }
10741
- const notFoundHtml = render404Page({ path, routes: availableRoutes, isProduction: isProd });
10742
- return new Response(isProd ? notFoundHtml : injectHmrClient(notFoundHtml), {
10743
- status: 404,
10744
- headers: { "Content-Type": "text/html; charset=utf-8" }
10745
- });
10746
- } finally {
10747
- activeServeLocale = null;
10748
- activeServeSearch = "";
10749
- activeServeHost = "";
10750
- activeServeCookieHeader = "";
10751
- activeServeCookies = {};
10752
- activeServeIp = "";
10753
10731
  }
10754
- })();
10755
- let _finalResp = await applyI18nToResponse(_i18nResp, i18nLocale ?? (i18nConfig?.defaultLocale ?? "en"), path);
10756
- if (mintedCsrfToken) {
10757
- try {
10758
- _finalResp.headers.append("Set-Cookie", csrfCookieHeader(mintedCsrfToken, req.url.startsWith("https://")));
10759
- } catch {
10760
- const headers = new Headers(_finalResp.headers);
10761
- headers.append("Set-Cookie", csrfCookieHeader(mintedCsrfToken, req.url.startsWith("https://")));
10762
- _finalResp = new Response(_finalResp.body, {
10763
- status: _finalResp.status,
10764
- statusText: _finalResp.statusText,
10765
- headers
10766
- });
10732
+ if (options.onResponse) {
10733
+ const hooked = await options.onResponse(req, _finalResp);
10734
+ if (hooked instanceof Response)
10735
+ return hooked;
10767
10736
  }
10768
- }
10769
- if (options.onResponse) {
10770
- const hooked = await options.onResponse(req, _finalResp);
10771
- if (hooked instanceof Response)
10772
- return hooked;
10773
- }
10774
- return _finalResp;
10737
+ return _finalResp;
10738
+ })());
10775
10739
  }
10776
10740
  });
10777
10741
  break;