bosia 0.7.6 → 0.7.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bosia",
3
- "version": "0.7.6",
3
+ "version": "0.7.8",
4
4
  "type": "module",
5
5
  "description": "A fast, batteries-included fullstack framework — SSR · Svelte 5 Runes · Bun · ElysiaJS. File-based routing inspired by SvelteKit. No Node.js, no Vite, no adapters.",
6
6
  "keywords": [
package/src/core/hooks.ts CHANGED
@@ -113,6 +113,19 @@ export type Metadata = {
113
113
 
114
114
  type MaybePromise<T> = T | Promise<T>;
115
115
 
116
+ // ─── Frame-Guard Opt-Out ──────────────────────────────────
117
+
118
+ /**
119
+ * Internal response header a `handle` can set to opt a single response out of
120
+ * the global `X-Frame-Options: SAMEORIGIN` guard. Use when a trusted proxy hub
121
+ * serves another origin's content that must be embeddable (e.g. an app preview
122
+ * iframe): the proxy strips the upstream `X-Frame-Options`, but the framework
123
+ * would otherwise re-add its own. The header is stripped before the response
124
+ * leaves the process, so it never reaches the client. Other security headers
125
+ * (`X-Content-Type-Options`, `Referrer-Policy`) are unaffected.
126
+ */
127
+ export const NO_FRAME_GUARD_HEADER = "x-bosia-no-frame-guard";
128
+
116
129
  // ─── Middleware Composition ────────────────────────────────
117
130
 
118
131
  /**
@@ -138,12 +138,10 @@ function send(payload,onOk,onErr){
138
138
  function closeForm(){if(form){form.remove();form=null}}
139
139
  function openForm(loc,el){
140
140
  closeForm();
141
- var chain=userFrames(el).join(" → ");
142
141
  var r=el.getBoundingClientRect();
143
142
  form=document.createElement("div");
144
143
  form.style.cssText="position:fixed;left:"+r.left+"px;top:"+(r.bottom+6)+"px;background:#fff;color:#111;border:1px solid #d4d4d8;border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.18);padding:10px;width:340px;z-index:2147483647;font:13px ui-sans-serif,system-ui,sans-serif";
145
- var header='<div style="font-size:11px;color:#71717a;margin-bottom:6px;font-family:ui-monospace,monospace;word-break:break-all">'+chain+'</div>';
146
- form.innerHTML=header+
144
+ form.innerHTML=
147
145
  '<textarea placeholder="Describe a fix (Enter to send, Esc to cancel, empty = open in editor)" style="width:100%;min-height:64px;border:1px solid #e4e4e7;border-radius:4px;padding:6px;font:13px ui-sans-serif,system-ui,sans-serif;resize:vertical;box-sizing:border-box;outline:none"></textarea>'+
148
146
  '<div style="margin-top:8px;display:flex;gap:6px;justify-content:flex-end">'+
149
147
  '<button data-cancel style="padding:4px 10px;border:1px solid #e4e4e7;background:#fff;border-radius:4px;cursor:pointer;font-size:12px">Cancel</button>'+
@@ -12,7 +12,7 @@ import type { RouteManifest } from "./types.ts";
12
12
  // Pre-compile route patterns into RegExp at startup (shared by renderer.ts via module reference)
13
13
  compileRoutes(apiRoutes);
14
14
  compileRoutes(serverRoutes);
15
- import type { Handle, RequestEvent } from "./hooks.ts";
15
+ import { NO_FRAME_GUARD_HEADER, type Handle, type RequestEvent } from "./hooks.ts";
16
16
  import { HttpError, Redirect, ActionFailure } from "./errors.ts";
17
17
  import { CookieJar } from "./cookies.ts";
18
18
  import { safePath } from "./safePath.ts";
@@ -842,7 +842,15 @@ async function handleRequest(request: Request, url: URL): Promise<Response> {
842
842
  const response = userHandle ? await userHandle({ event, resolve }) : await resolve(event);
843
843
 
844
844
  const headers = new Headers(response.headers);
845
- for (const [k, v] of Object.entries(SECURITY_HEADERS)) headers.set(k, v);
845
+ // A handle can mark a response (e.g. a proxied embeddable preview) to opt
846
+ // out of the frame guard. Strip the internal marker so it never ships, and
847
+ // skip only X-Frame-Options for that response — other security headers stay.
848
+ const skipFrameGuard = headers.has(NO_FRAME_GUARD_HEADER);
849
+ headers.delete(NO_FRAME_GUARD_HEADER);
850
+ for (const [k, v] of Object.entries(SECURITY_HEADERS)) {
851
+ if (skipFrameGuard && k === "X-Frame-Options") continue;
852
+ headers.set(k, v);
853
+ }
846
854
  const cspHeader = buildCspHeader(nonce);
847
855
  if (cspHeader) headers.set("Content-Security-Policy", cspHeader);
848
856
  // Apply CORS headers for allowed origins. `Vary: Origin` is set whenever
package/src/lib/index.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  // import type { RequestEvent, LoadEvent, Handle, Cookies } from "bosia"
7
7
 
8
8
  export { cn, getServerTime } from "./utils.ts";
9
- export { sequence } from "../core/hooks.ts";
9
+ export { sequence, NO_FRAME_GUARD_HEADER } from "../core/hooks.ts";
10
10
  export { error, redirect, fail } from "../core/errors.ts";
11
11
  // `invalidate` / `invalidateAll` (server response-cache eviction) live in
12
12
  // "bosia/server" — they touch server-process state and pulling them into