@vesk/runtime 0.2.9 → 0.2.10

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @vesk/runtime
2
2
 
3
- Vesk runtime — reactivity engine, block lifecycle, DOM operations, hydration, routing, and server APIs.
3
+ Vesk runtime — reactivity engine, block lifecycle, DOM operations, hydration, routing, server APIs, streaming resources and markdown.
4
4
 
5
5
  ## Install
6
6
 
@@ -13,11 +13,78 @@ npm install @vesk/runtime
13
13
  ```js
14
14
  // Client
15
15
  import { track, effect, derived } from '@vesk/runtime';
16
+ import { Md } from '@vesk/runtime';
17
+ import { useFetch } from '@vesk/runtime';
16
18
 
17
19
  // Server
18
- import { renderPage, parseCookies } from '@vesk/runtime/server';
20
+ import { VeskResponse, VeskRequest } from '@vesk/runtime/server';
19
21
  ```
20
22
 
23
+ ## Reactivity — TrackDecl
24
+
25
+ ```vsk
26
+ component Counter {
27
+ const &[count] = track(0)
28
+ <button onClick={() => count++}>{count}</button>
29
+ }
30
+ ```
31
+
32
+ Outside `.vsk` (plain JS): `const count = track(0)` → `get(count)` / `set(count, 1)` / `peek(count)`. Inside `.vsk` with `&` the cell is auto-tracked — read/write `count` directly.
33
+
34
+ ## useFetch
35
+
36
+ `useFetch` / `createResource` return a thenable `Resource<T>` (`loading`/`error`/`data`, `refresh()`/`abort()`, `into?`). SSR data is stashed in `__vsk_ssr_data` and `resolveSsrResources()`.
37
+
38
+ ```ts
39
+ const posts = useFetch<Post[]>('/api/posts');
40
+ if (posts.loading) return <p>Loading…</p>;
41
+ ```
42
+
43
+ Helpers: `.json(url)` / `.text(url)` / `.arrayBuffer(url)` / `.stream(urlOrFn, opts)`.
44
+
45
+ ### useFetch.stream — progressive streaming
46
+
47
+ Streams `res.body` chunk-by-chunk into a tracked cell so `<Md>` re-renders as data arrives. `urlOrFn` may be a provider `() => string` re-evaluated on every fetch/`refresh()` (so a tracked `docPath` propagates without recreating the resource).
48
+
49
+ ```vsk
50
+ component Docs {
51
+ const &[docPath] = track('welcome') // API param — no .md needed
52
+ const &[doc] = track('')
53
+ const res = useFetch.stream(() => '/api/docs/' + docPath, { into: doc, key: 'doc' })
54
+ <select onchange={(e) => { docPath = (e.target as HTMLSelectElement).value; res.refresh() }}>
55
+ <option value="welcome">Welcome</option>
56
+ </select>
57
+ <Md content={doc} css />
58
+ }
59
+ ```
60
+
61
+ Plain JS (no `&`): `const docPath = track('welcome'); useFetch.stream(() => '/api/docs/' + get(docPath), { into: doc })`.
62
+
63
+ ## Md
64
+
65
+ Tokenizer-based Markdown → HTML (GFM tables, task lists, highlighted code, heading anchors, autolinks). `content` is polymorphic:
66
+
67
+ - **String:** `<Md content="# Hello" />`
68
+ - **Tracked cell:** `const &[live] = track('# hi')` → `<Md content={live} css />` (live re-renders)
69
+ - **Streamed:** `const &[doc] = track('')` + `useFetch.stream(..., { into: doc })` → `<Md content={doc} />`
70
+ - **Public file path** (needs `.md` + leading `/`): `<Md content="/welcome.md" css />`, `"/game.md"`, `"/docs/guide.md"` under `public/`. Missing files render the path literally (never blank).
71
+
72
+ ```vsk
73
+ component Page {
74
+ const &[pubPath] = track('/game.md')
75
+ <Md content={pubPath} css />
76
+ <Md content="/welcome.md" css />
77
+ <Md content="/missing.md" css /> // → renders "/missing.md" literally
78
+ }
79
+ ```
80
+
81
+ ```ts
82
+ // helper APIs
83
+ import { renderMarkdown, MD_BASE_CSS, sanitizeUrl } from '@vesk/runtime';
84
+ ```
85
+
86
+ `VeskResponse.stream(readable)` creates a chunked `ReadableStream` response (`Transfer-Encoding: chunked`).
87
+
21
88
  ## License
22
89
 
23
90
  MIT
package/dist/md.d.ts CHANGED
@@ -85,7 +85,9 @@ export declare function setMdConsoleWarnings(enabled: boolean): void;
85
85
  /** Drains the collected passthrough samples (for build-time summaries). */
86
86
  export declare function drainMdHtmlWarnings(): MdHtmlWarning[];
87
87
  export interface MdProps {
88
- /** Markdown source — a plain string or a tracked cell (reactive on client). */
88
+ /** Markdown source — a plain string, a tracked cell (reactive on client), a
89
+ * streamed resource (useFetch.stream — re-renders per chunk), or an
90
+ * absolute public markdown path (runtime-loaded from the app's public dir). */
89
91
  content?: string | {
90
92
  get: () => string;
91
93
  };
package/dist/md.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"md.d.ts","sourceRoot":"","sources":["../src/md.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"md.d.ts","sourceRoot":"","sources":["../src/md.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAwC/D,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAW5C;AAwcD,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAgB/C;AAID,UAAU,MAAM;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACd;AA6ND;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CA6HhE;AAyWD,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,eAAe,CAAC,EAAE,aAAa,EAAE,CAAC;CAClC;AAkZD,MAAM,WAAW,eAAe;IAC/B,wEAAwE;IACxE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,uFAAuF;IACvF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uFAAuF;IACvF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,mDAAmD;IACnD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iFAAiF;IACjF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;4CACwC;IACxC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,WAAW,CAAC;AAE1D;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,UAIjC,CAAC;AAEF,yDAAyD;AACzD,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC;CACf;AAgOD,eAAO,MAAM,WAAW,q8IAoDvB,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,MAAM,CAEhF;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,aAAa,EAAE,CAAA;CAAE,CAQvH;AAOD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,UAAU,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAQtF;AAED,6DAA6D;AAC7D,wBAAgB,WAAW,IAAI;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CAEvE;AAQD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE3D;AAWD,2EAA2E;AAC3E,wBAAgB,mBAAmB,IAAI,aAAa,EAAE,CAErD;AAED,MAAM,WAAW,OAAO;IACvB;;oFAEgF;IAChF,OAAO,CAAC,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,MAAM,CAAA;KAAE,CAAC;IACzC,0FAA0F;IAC1F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,GAAG,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACrB;AAuMD;;;;;;GAMG;AACH,wBAAgB,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,GAAG,MAAM,CAsE3G"}
package/dist/md.js CHANGED
@@ -1,4 +1,6 @@
1
1
  import { effect } from '@vesk/runtime/src/ripple-blocks';
2
+ import { tracked, get, set } from '@vesk/runtime/src/ripple-runtime';
3
+ import { getSsrData, setSsrData } from '@vesk/runtime/src/resource';
2
4
  // =============================================================
3
5
  // Markdown rendering for <Md content={...} />.
4
6
  //
@@ -11,9 +13,10 @@ import { effect } from '@vesk/runtime/src/ripple-blocks';
11
13
  // chrome, heading anchors, autolinks, hard breaks) and can be tuned
12
14
  // via props (css / lineNumbers / copy / highlight / ids / autolink).
13
15
  //
14
- // `content` accepts a plain string or a tracked cell — cells are
15
- // unwrapped for rendering and, on the client, subscribed so the
16
- // rendered markdown updates reactively.
16
+ // `content` accepts a plain string, a tracked cell, a useFetch.stream()
17
+ // resource, or an absolute public markdown path (runtime-loaded) —
18
+ // cells/resources are unwrapped for rendering and, on the client,
19
+ // subscribed so the rendered markdown updates reactively.
17
20
  // =============================================================
18
21
  /** Unwraps tracked cells passed as props (compiler emits the cell itself). */
19
22
  function unwrapMaybeCell(v) {
@@ -2177,6 +2180,126 @@ function wireCopyHandlers(root) {
2177
2180
  function mdIsSSR() {
2178
2181
  return typeof document === 'undefined';
2179
2182
  }
2183
+ // =============================================================
2184
+ // Runtime markdown-file loading (public/*.md) + streaming support
2185
+ //
2186
+ // When `content` resolves to an absolute public markdown path
2187
+ // (e.g. "/docs/guide.md"), <Md> loads the FILE at runtime:
2188
+ // - server: adapter-installed `__vsk_md_read_file` hook reads it,
2189
+ // constrained to the public dir + `.md` suffixes (returns null
2190
+ // outside those bounds), and the content is stashed in
2191
+ // `__vsk_ssr_data` for hydration so there is no flash.
2192
+ // - client: `fetch(path)` with a per-path cache cell; while loading
2193
+ // (or if the file does not exist) the path itself is rendered as
2194
+ // literal markdown text.
2195
+ // `content` may also be a streaming-resource result (useFetch.stream),
2196
+ // whose `.into` cell is subscribed so chunks re-render progressively.
2197
+ // =============================================================
2198
+ /** Tokenizer endsWith (no regex, mirrors compiler rule). */
2199
+ function stringEndsWith(s, suffix) {
2200
+ if (suffix.length > s.length)
2201
+ return false;
2202
+ for (let i = 0; i < suffix.length; i++) {
2203
+ if (s[s.length - suffix.length + i] !== suffix[i])
2204
+ return false;
2205
+ }
2206
+ return true;
2207
+ }
2208
+ function isPublicMarkdownPath(v) {
2209
+ if (typeof v !== 'string')
2210
+ return false;
2211
+ const s = v;
2212
+ if (s.length < 2 || s.charCodeAt(0) !== 47)
2213
+ return false; // '/'
2214
+ if (s.charCodeAt(1) === 47)
2215
+ return false; // '//'
2216
+ for (let i = 0; i < s.length; i++) {
2217
+ const c = s.charCodeAt(i);
2218
+ if (c === 63 || c === 35 || c === 92)
2219
+ return false; // ? # \
2220
+ }
2221
+ const lower = s.toLowerCase();
2222
+ return stringEndsWith(lower, '.md') || stringEndsWith(lower, '.markdown');
2223
+ }
2224
+ const mdPathCache = new Map();
2225
+ const mdPathCells = new Map();
2226
+ const mdPathInflight = new Set();
2227
+ function getMdPathCell(path) {
2228
+ let cell = mdPathCells.get(path);
2229
+ if (!cell) {
2230
+ cell = tracked(undefined);
2231
+ mdPathCells.set(path, cell);
2232
+ }
2233
+ return cell;
2234
+ }
2235
+ function ensureMdPathLoaded(path) {
2236
+ if (mdPathCache.has(path) || mdPathInflight.has(path))
2237
+ return;
2238
+ const ssr = getSsrData('md:' + path);
2239
+ if (typeof ssr === 'string') {
2240
+ mdPathCache.set(path, ssr);
2241
+ return;
2242
+ }
2243
+ mdPathInflight.add(path);
2244
+ fetch(path)
2245
+ .then((r) => (r.ok ? r.text() : Promise.reject(r)))
2246
+ .then((text) => {
2247
+ mdPathCache.set(path, text);
2248
+ set(getMdPathCell(path), text);
2249
+ })
2250
+ .catch(() => {
2251
+ mdPathCache.set(path, null);
2252
+ set(getMdPathCell(path), null);
2253
+ })
2254
+ .finally(() => {
2255
+ mdPathInflight.delete(path);
2256
+ });
2257
+ }
2258
+ function readServerMdPath(path) {
2259
+ const hook = globalThis.__vsk_md_read_file;
2260
+ if (typeof hook !== 'function')
2261
+ return null;
2262
+ try {
2263
+ const out = hook(path);
2264
+ if (typeof out === 'string')
2265
+ return out;
2266
+ }
2267
+ catch {
2268
+ /* read errors fall through to literal rendering */
2269
+ }
2270
+ return null;
2271
+ }
2272
+ /**
2273
+ * Resolves a raw content value to the markdown SOURCE that should be
2274
+ * rendered. Non-path values pass through; public markdown paths are read
2275
+ * on the server (SSR) or resolved from cache while loading on the client.
2276
+ */
2277
+ function resolveMdSource(value) {
2278
+ const s = String(value ?? '');
2279
+ if (!isPublicMarkdownPath(s))
2280
+ return s;
2281
+ if (mdIsSSR()) {
2282
+ const content = readServerMdPath(s);
2283
+ if (content !== null) {
2284
+ setSsrData('md:' + s, content);
2285
+ return content;
2286
+ }
2287
+ return s;
2288
+ }
2289
+ ensureMdPathLoaded(s);
2290
+ const cached = mdPathCache.get(s);
2291
+ return cached === undefined || cached === null ? s : cached;
2292
+ }
2293
+ /** Extracts the streaming target cell from a useFetch.stream() resource. */
2294
+ function streamCellFrom(rawContent) {
2295
+ if (rawContent === null || typeof rawContent !== 'object')
2296
+ return null;
2297
+ const into = rawContent.into;
2298
+ if (into !== null && typeof into === 'object' && typeof into.get === 'function') {
2299
+ return into;
2300
+ }
2301
+ return null;
2302
+ }
2180
2303
  function buildHtml(content, props) {
2181
2304
  // Per-instance props override the process-wide policy from vesk.config.ts.
2182
2305
  const global = getMdPolicy();
@@ -2223,8 +2346,10 @@ function buildHtml(content, props) {
2223
2346
  */
2224
2347
  export function Md(props, _registry, hydrate) {
2225
2348
  const rawContent = props.content;
2226
- const content = String(unwrapMaybeCell(rawContent) ?? '');
2227
- const html = buildHtml(content, props);
2349
+ const streamTarget = streamCellFrom(rawContent);
2350
+ const contentCell = streamTarget ?? rawContent;
2351
+ const content = String(unwrapMaybeCell(contentCell) ?? '');
2352
+ const html = buildHtml(resolveMdSource(content), props);
2228
2353
  const classNameRaw = props.className != null ? String(props.className) : props.class != null ? String(props.class) : '';
2229
2354
  const themeClass = props.theme === 'dark' ? ' vesk-md-dark' : '';
2230
2355
  const className = `vesk-md${themeClass}${classNameRaw ? ' ' + classNameRaw : ''}`;
@@ -2239,9 +2364,11 @@ export function Md(props, _registry, hydrate) {
2239
2364
  if (propFg && propFg !== 'none')
2240
2365
  wrapperParts.push(`--md-code-fg:${propFg}`);
2241
2366
  const wrapperStyle = wrapperParts.length > 0 ? escapeHtml(wrapperParts.join(';')) : '';
2242
- // A tracked `content` cell re-renders the markdown reactively on the
2243
- // client (per-keystroke live editing works without any extra wiring).
2244
- const reactive = isCell(rawContent);
2367
+ // A tracked `content` cell (or a streaming resource's `into` cell)
2368
+ // re-renders the markdown reactively on the client (per-keystroke live
2369
+ // editing and progressive stream chunks work without any extra wiring).
2370
+ const reactive = isCell(contentCell);
2371
+ const pathMode = isPublicMarkdownPath(content);
2245
2372
  if (mdIsSSR()) {
2246
2373
  const attrs = className ? ` class="${escapeHtml(className)}"` : '';
2247
2374
  const styleAttr = style || wrapperStyle ? ` style="${[wrapperStyle, style.split('"').join('&quot;')].filter(Boolean).join(';')}"` : '';
@@ -2254,12 +2381,25 @@ export function Md(props, _registry, hydrate) {
2254
2381
  if (existing)
2255
2382
  el = existing;
2256
2383
  }
2257
- el.innerHTML = html;
2384
+ const claimed = !!el.parentNode;
2385
+ if (pathMode && claimed) {
2386
+ // Retention: the SSR render already shows this path's rendered
2387
+ // file (or the literal path). Only overwrite when the client has
2388
+ // authoritative content (hydrated ssr data / cache); otherwise
2389
+ // trust the markup until the client load resolves.
2390
+ el.setAttribute('data-vsk-md-ssr', '1');
2391
+ if (mdPathCache.has(content))
2392
+ el.innerHTML = html;
2393
+ }
2394
+ else {
2395
+ el.innerHTML = html;
2396
+ }
2258
2397
  el.className = className;
2259
2398
  el.style.cssText = [wrapperStyle, style].filter(Boolean).join(';');
2260
2399
  wireCopyHandlers(el);
2261
- if (reactive)
2262
- subscribeContent(el, rawContent, props);
2400
+ if (reactive || pathMode) {
2401
+ subscribeContent(el, contentCell, props, pathMode && claimed ? { trustInitialSsr: true, initialValue: content } : undefined);
2402
+ }
2263
2403
  // When the element came from SSR it is already in the document —
2264
2404
  // return an empty fragment. When the walker handed us a FRESH
2265
2405
  // element (dynamic branch that had no SSR markup), hand the element
@@ -2273,14 +2413,34 @@ export function Md(props, _registry, hydrate) {
2273
2413
  div.className = className;
2274
2414
  div.style.cssText = [wrapperStyle, style].filter(Boolean).join(';');
2275
2415
  wireCopyHandlers(div);
2276
- if (reactive)
2277
- subscribeContent(div, rawContent, props);
2416
+ if (reactive || pathMode)
2417
+ subscribeContent(div, contentCell, props);
2278
2418
  return div;
2279
2419
  }
2280
- function subscribeContent(el, rawContent, props) {
2420
+ function subscribeContent(el, rawContent, props, opts) {
2421
+ const trust = opts?.trustInitialSsr === true;
2422
+ const initial = opts?.initialValue;
2423
+ let ran = false;
2281
2424
  effect(() => {
2282
2425
  const value = String(unwrapMaybeCell(rawContent) ?? '');
2283
- el.innerHTML = buildHtml(value, props);
2426
+ if (isPublicMarkdownPath(value)) {
2427
+ const known = getSsrData('md:' + value) !== undefined || mdPathCache.has(value);
2428
+ ensureMdPathLoaded(value);
2429
+ const cell = getMdPathCell(value);
2430
+ get(cell);
2431
+ if (trust && !ran && value === initial && !known) {
2432
+ // Keep the SSR-rendered file visible while the client load is
2433
+ // in flight (or the path stays a literal on not-found).
2434
+ ran = true;
2435
+ return;
2436
+ }
2437
+ ran = true;
2438
+ el.innerHTML = buildHtml(resolveMdSource(value), props);
2439
+ wireCopyHandlers(el);
2440
+ return;
2441
+ }
2442
+ ran = true;
2443
+ el.innerHTML = buildHtml(resolveMdSource(value), props);
2284
2444
  wireCopyHandlers(el);
2285
2445
  });
2286
2446
  }
package/dist/request.d.ts CHANGED
@@ -104,6 +104,32 @@ export declare class VeskRequest extends ServerRequest {
104
104
  _parsedUrl: URL | null;
105
105
  __security?: Record<string, unknown>;
106
106
  constructor(input: string | URL, init?: RequestInit);
107
+ /**
108
+ * The request's host header (honoring `x-forwarded-host` when
109
+ * setTrustProxy() is enabled). Falls back to the parsed URL host.
110
+ */
111
+ get host(): string;
112
+ /** Absolute origin (`protocol://host`) — the base for resolving relative URLs. */
113
+ get origin(): string;
114
+ /**
115
+ * Resolves a possibly-relative URL against this request's own origin.
116
+ * Absolute URLs (scheme or protocol-relative `//`) pass through untouched.
117
+ * Used by the runtime SSR fetcher (`resolveFetchUrl`) to make in-app
118
+ * fetches (e.g. `/api/...`) work during server rendering.
119
+ */
120
+ resolveUrl(url: string): string;
121
+ /** locals map accessors so <VeskRequest> can double as the middleware ctx. */
122
+ set(key: string, value: unknown): void;
123
+ get(key: string): unknown;
124
+ /**
125
+ * Wraps an inbound platform `Request` (from dev/prod/platform handlers)
126
+ * into a VeskRequest carrying the same method, headers and cookie store.
127
+ * Params/locals can be seeded so useParams()/useRequest() work in renders.
128
+ */
129
+ static from(request: Request, init?: {
130
+ params?: Record<string, string>;
131
+ locals?: Record<string, unknown>;
132
+ }): VeskRequest;
107
133
  get parsedUrl(): URL;
108
134
  get query(): Record<string, string>;
109
135
  set query(v: Record<string, string>);
@@ -163,6 +189,8 @@ declare class _VeskResponse extends ServerResponse {
163
189
  static rewrite(url: string): _VeskResponse;
164
190
  static next(): _VeskResponse;
165
191
  static html(html: string, init?: ResponseInit): _VeskResponse;
192
+ /** Chunked streaming response over a `ReadableStream` body (SSE, file streams, …). */
193
+ static stream(readable: ReadableStream, init?: ResponseInit): _VeskResponse;
166
194
  }
167
195
  export declare const VeskResponse: typeof _VeskResponse & ((body?: unknown, init?: ResponseInit) => VeskResponseInstance);
168
196
  export declare function applyRequestSecurity(request: VeskRequest, response: VeskResponseInstance): void;
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"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"}
package/dist/request.js CHANGED
@@ -307,6 +307,22 @@ export class VeskRequest extends ServerRequest {
307
307
  this._body = null;
308
308
  this._bodyPromise = null;
309
309
  this._parsedUrl = null;
310
+ const cookieHeader = this.headers?.get('cookie') || '';
311
+ if (cookieHeader) {
312
+ for (const part of cookieHeader.split(';')) {
313
+ const eq = part.indexOf('=');
314
+ if (eq > 0) {
315
+ const name = part.slice(0, eq).trim();
316
+ const val = part.slice(eq + 1).trim();
317
+ try {
318
+ this._cookies[name] = decodeURIComponent(val);
319
+ }
320
+ catch {
321
+ this._cookies[name] = val;
322
+ }
323
+ }
324
+ }
325
+ }
310
326
  Object.defineProperty(this, 'body', {
311
327
  get: () => {
312
328
  if (!this._bodyPromise) {
@@ -318,6 +334,56 @@ export class VeskRequest extends ServerRequest {
318
334
  enumerable: true,
319
335
  });
320
336
  }
337
+ /**
338
+ * The request's host header (honoring `x-forwarded-host` when
339
+ * setTrustProxy() is enabled). Falls back to the parsed URL host.
340
+ */
341
+ get host() {
342
+ const trust = this._security.trustProxy === true;
343
+ const fwd = trust ? this.headers?.get('x-forwarded-host') : undefined;
344
+ const header = typeof fwd === 'string' && fwd ? fwd : (this.headers?.get('host') || '');
345
+ if (header)
346
+ return header;
347
+ return this.parsedUrl.host || 'localhost';
348
+ }
349
+ /** Absolute origin (`protocol://host`) — the base for resolving relative URLs. */
350
+ get origin() {
351
+ return `${this.protocol}://${this.host}`;
352
+ }
353
+ /**
354
+ * Resolves a possibly-relative URL against this request's own origin.
355
+ * Absolute URLs (scheme or protocol-relative `//`) pass through untouched.
356
+ * Used by the runtime SSR fetcher (`resolveFetchUrl`) to make in-app
357
+ * fetches (e.g. `/api/...`) work during server rendering.
358
+ */
359
+ resolveUrl(url) {
360
+ if (/^[a-z][a-z0-9+.-]*:/i.test(url) || url.startsWith('//'))
361
+ return url;
362
+ return new URL(url, this.origin).href;
363
+ }
364
+ /** locals map accessors so <VeskRequest> can double as the middleware ctx. */
365
+ set(key, value) {
366
+ this._locals[key] = value;
367
+ }
368
+ get(key) {
369
+ return this._locals[key];
370
+ }
371
+ /**
372
+ * Wraps an inbound platform `Request` (from dev/prod/platform handlers)
373
+ * into a VeskRequest carrying the same method, headers and cookie store.
374
+ * Params/locals can be seeded so useParams()/useRequest() work in renders.
375
+ */
376
+ static from(request, init) {
377
+ const vreq = new VeskRequest(request instanceof Request ? request.url : String(request), {
378
+ method: request.method,
379
+ headers: request.headers,
380
+ });
381
+ if (init?.params)
382
+ vreq._params = { ...init.params };
383
+ if (init?.locals)
384
+ vreq._locals = { ...init.locals };
385
+ return vreq;
386
+ }
321
387
  get parsedUrl() {
322
388
  if (!this._parsedUrl) {
323
389
  this._parsedUrl = new URL(this.url);
@@ -534,6 +600,10 @@ class _VeskResponse extends ServerResponse {
534
600
  headers: { 'Content-Type': 'text/html; charset=utf-8', ...init?.headers },
535
601
  });
536
602
  }
603
+ /** Chunked streaming response over a `ReadableStream` body (SSE, file streams, …). */
604
+ static stream(readable, init) {
605
+ return new _VeskResponse(readable, init);
606
+ }
537
607
  }
538
608
  export const VeskResponse = new Proxy(_VeskResponse, {
539
609
  apply(target, _thisArg, args) {
@@ -35,6 +35,7 @@ export interface SsrDataSink {
35
35
  clear(): void;
36
36
  }
37
37
  export declare function setSsrSink(sink: SsrDataSink | null): void;
38
+ export declare function getSsrData(key: string): unknown;
38
39
  export declare function setSsrData(key: string, value: unknown): void;
39
40
  export declare function clearSsrData(): void;
40
41
  export declare function mutate(key: string, data?: unknown): void;
@@ -44,6 +45,10 @@ export declare namespace useFetch {
44
45
  var text: <T = string>(url: string, options?: Omit<UseFetchOptions<T>, "body">) => Resource<T>;
45
46
  var json: <T = unknown>(url: string, options?: Omit<UseFetchOptions<T>, "body">) => Resource<T>;
46
47
  var arrayBuffer: <T = ArrayBuffer>(url: string, options?: Omit<UseFetchOptions<T>, "body">) => Resource<T>;
48
+ var stream: (urlOrFn: string | (() => string), options?: Omit<UseFetchOptions<string>, "body"> & {
49
+ into?: Tracked<string>;
50
+ onChunk?: (chunk: string, total: string) => void;
51
+ }) => Resource<string>;
47
52
  }
48
53
  export declare function resolveSsrResources(): Promise<Record<string, unknown>>;
49
54
  //# sourceMappingURL=resource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"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"}
package/dist/resource.js CHANGED
@@ -46,7 +46,7 @@ function getRegistry() {
46
46
  g().__vsk_fetch_registry = map;
47
47
  return map;
48
48
  }
49
- function getSsrData(key) {
49
+ export function getSsrData(key) {
50
50
  const sink = ssrSink;
51
51
  if (sink)
52
52
  return sink.get(key);
@@ -156,10 +156,16 @@ function buildRequestInit(options) {
156
156
  function resolveFetchUrl(url) {
157
157
  if (/^[a-z][a-z0-9+.-]*:/i.test(url) || url.startsWith('//'))
158
158
  return url;
159
- const reqUrl = g().__vesk_request?.url;
159
+ const ctx = g().__vesk_request;
160
+ const resolver = ctx && typeof ctx.resolveUrl === 'function'
161
+ ? ctx.resolveUrl
162
+ : null;
163
+ if (resolver)
164
+ return resolver(url);
165
+ const reqUrl = ctx?.url;
160
166
  const base = typeof reqUrl === 'string' && /^https?:\/\//i.test(reqUrl)
161
167
  ? reqUrl
162
- : g().__vesk_ssr_base_url || '';
168
+ : globalThis.__vesk_ssr_base_url || '';
163
169
  if (base)
164
170
  return new URL(url, base).href;
165
171
  return url;
@@ -237,6 +243,43 @@ async function runFetcher(handle, timeout) {
237
243
  function sleep(ms) {
238
244
  return new Promise(resolve => setTimeout(resolve, ms));
239
245
  }
246
+ /**
247
+ * Reads a streaming `Response` body chunk by chunk (TextDecoder) and
248
+ * progressively fans the running total into a tracked cell via `into`.
249
+ * Falls back to `res.text()` when the body has no readable stream.
250
+ * Returns the fully consumed string so `settle` records the final value.
251
+ */
252
+ function streamText(res, into, onChunk) {
253
+ const decoder = new TextDecoder();
254
+ let total = '';
255
+ const emit = (text) => {
256
+ if (!text)
257
+ return;
258
+ total += text;
259
+ if (into)
260
+ setInto(into, total);
261
+ if (onChunk)
262
+ onChunk(text, total);
263
+ };
264
+ const body = res.body;
265
+ if (body && typeof body.getReader === 'function') {
266
+ const reader = body.getReader();
267
+ return (async () => {
268
+ for (;;) {
269
+ const { done, value } = await reader.read();
270
+ if (done)
271
+ break;
272
+ emit(decoder.decode(value, { stream: true }));
273
+ }
274
+ emit(decoder.decode());
275
+ return total;
276
+ })();
277
+ }
278
+ return res.text().then((text) => {
279
+ emit(text);
280
+ return total;
281
+ });
282
+ }
240
283
  function settle(handle, data) {
241
284
  if (handle.block !== null && is_destroyed(handle.block))
242
285
  return;
@@ -522,6 +565,31 @@ useFetch.arrayBuffer = (url, options) => useFetch(() => doFetch(resolveFetchUrl(
522
565
  ...options,
523
566
  key: options?.key ?? url,
524
567
  });
568
+ /**
569
+ * Streaming fetch: consumes the response body chunk by chunk and reacts
570
+ * progressively. Each decoded chunk updates the target tracked cell (`into`),
571
+ * so anything subscribed to that cell (e.g. `<Md content={doc} />` or a
572
+ * plain `{doc}` interpolation) re-renders as data arrives. `url` may be a
573
+ * provider function — it is re-evaluated on every fetch (including `refresh`),
574
+ * so switching a tracked path propagates without recreating the resource.
575
+ */
576
+ useFetch.stream = (urlOrFn, options) => {
577
+ const streamInto = options?.into;
578
+ const streamOnChunk = options?.onChunk;
579
+ const fetcher = (signal) => {
580
+ const url = typeof urlOrFn === 'function' ? urlOrFn() : urlOrFn;
581
+ const init = buildRequestInit(options ?? {});
582
+ return doFetch(resolveFetchUrl(url), signal ? { ...init, signal } : init).then(async (res) => {
583
+ if (!res.ok)
584
+ throw new HttpError(res.status, res.statusText);
585
+ return streamText(res, streamInto, streamOnChunk);
586
+ });
587
+ };
588
+ const key = options?.key ?? (typeof urlOrFn === 'string' ? urlOrFn : undefined);
589
+ const resource = useFetch(fetcher, { ...options, key });
590
+ resource.into = streamInto;
591
+ return resource;
592
+ };
525
593
  export async function resolveSsrResources() {
526
594
  const sink = ssrSink;
527
595
  if (sink)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vesk/runtime",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "type": "module",
5
5
  "description": "Vesk runtime — reactivity, blocks, DOM operations, hydration",
6
6
  "main": "./dist/index-client.js",
@@ -26,7 +26,7 @@
26
26
  "./package.json": "./package.json"
27
27
  },
28
28
  "dependencies": {
29
- "@vesk/compiler": "^0.2.9"
29
+ "@vesk/compiler": "^0.2.10"
30
30
  },
31
31
  "scripts": {
32
32
  "typecheck": "tsc --noEmit",