@barefootjs/hono 0.14.0 → 0.15.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"hono-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/hono-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hono-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/hono-adapter.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,7 @@ import {
7
7
  emitAttrValue,
8
8
  buildLoopChainExpr
9
9
  } from "@barefootjs/jsx";
10
- import { BF_SCOPE, BF_HOST, BF_AT, BF_ROOT, BF_PROPS } from "@barefootjs/shared";
10
+ import { BF_SCOPE, BF_HOST, BF_AT, BF_ROOT, BF_PROPS, BF_REGION } from "@barefootjs/shared";
11
11
  function applyHonoLoopChain(loop) {
12
12
  return buildLoopChainExpr({
13
13
  base: loop.array,
@@ -387,6 +387,9 @@ export default ${this.componentName}` : "";
387
387
  if (element.slotId) {
388
388
  hydrationAttrs += ` bf="${element.slotId}"`;
389
389
  }
390
+ if (element.regionId) {
391
+ hydrationAttrs += ` ${BF_REGION}="${element.regionId}"`;
392
+ }
390
393
  if (children) {
391
394
  return `<${tag}${attrs}${hydrationAttrs}>${children}</${tag}>`;
392
395
  } else {
package/dist/app.d.ts CHANGED
@@ -28,6 +28,7 @@
28
28
  import type { MiddlewareHandler } from 'hono';
29
29
  import type { HtmlEscapedString } from 'hono/utils/html';
30
30
  import { type ImportMapManifest } from '@barefootjs/jsx/import-map';
31
+ import './search-params-ssr.ts';
31
32
  /**
32
33
  * Build manifest shape produced by `bf build`. Each compiled
33
34
  * component is keyed by its manifest name; `__barefoot__` is the
package/dist/app.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAIxD,OAAO,EAAuB,KAAK,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAOxF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACpC,CAAC,aAAa,EAAE,MAAM,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,SAAS,CAAA;CAChF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,qBAAqB,EAC/B,IAAI,EAAE,MAAM,GACX,MAAM,EAAE,CAWV;AAED,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAID,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,iBAAiB,CAAA;IAC7B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAanG;AAED,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAA;IACZ,6DAA6D;IAC7D,QAAQ,EAAE,qBAAqB,CAAA;CAChC;AAQD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAa/F;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,GAAE,gBAAqB,GAAG,iBAAiB,GAAG,IAAI,CAelF;AAID,MAAM,WAAW,wBAAwB;IACvC,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;;OAMG;IACH,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,wBAAwB,GAAG,iBAAiB,CAanF"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAIxD,OAAO,EAAuB,KAAK,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAIxF,OAAO,wBAAwB,CAAA;AAM/B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACpC,CAAC,aAAa,EAAE,MAAM,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,SAAS,CAAA;CAChF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,qBAAqB,EAC/B,IAAI,EAAE,MAAM,GACX,MAAM,EAAE,CAWV;AAED,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAID,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,iBAAiB,CAAA;IAC7B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAanG;AAED,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAA;IACZ,6DAA6D;IAC7D,QAAQ,EAAE,qBAAqB,CAAA;CAChC;AAQD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAa/F;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,GAAE,gBAAqB,GAAG,iBAAiB,GAAG,IAAI,CAelF;AAID,MAAM,WAAW,wBAAwB;IACvC,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;;OAMG;IACH,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,wBAAwB,GAAG,iBAAiB,CAanF"}
package/dist/app.js CHANGED
@@ -63,8 +63,29 @@ data: ${BOOT_ID}
63
63
 
64
64
  // src/app.ts
65
65
  import { html, raw } from "hono/html";
66
- import { useRequestContext } from "hono/jsx-renderer";
66
+ import { useRequestContext as useRequestContext2 } from "hono/jsx-renderer";
67
67
  import { renderImportMapHtml } from "@barefootjs/jsx/import-map";
68
+
69
+ // src/search-params-ssr.ts
70
+ import { useRequestContext } from "hono/jsx-renderer";
71
+ function searchFromRequestUrl(url) {
72
+ try {
73
+ return new URL(url).search;
74
+ } catch {
75
+ return "";
76
+ }
77
+ }
78
+ globalThis.__bf_serverEnvReader = (key) => {
79
+ if (key !== "search")
80
+ return;
81
+ try {
82
+ return searchFromRequestUrl(useRequestContext().req.url);
83
+ } catch {
84
+ return;
85
+ }
86
+ };
87
+
88
+ // src/app.ts
68
89
  var DEV_RELOAD_ENDPOINT_KEY = "bfDevReloadEndpoint";
69
90
  function manifestToScriptUrls(manifest, base) {
70
91
  const out = [];
@@ -107,7 +128,7 @@ function BfDevReload(props = {}) {
107
128
  let endpoint = props.endpoint;
108
129
  if (!endpoint) {
109
130
  try {
110
- endpoint = useRequestContext().get(DEV_RELOAD_ENDPOINT_KEY);
131
+ endpoint = useRequestContext2().get(DEV_RELOAD_ENDPOINT_KEY);
111
132
  } catch {}
112
133
  }
113
134
  if (!endpoint)
package/dist/build.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  emitAttrValue,
8
8
  buildLoopChainExpr
9
9
  } from "@barefootjs/jsx";
10
- import { BF_SCOPE, BF_HOST, BF_AT, BF_ROOT, BF_PROPS } from "@barefootjs/shared";
10
+ import { BF_SCOPE, BF_HOST, BF_AT, BF_ROOT, BF_PROPS, BF_REGION } from "@barefootjs/shared";
11
11
  function applyHonoLoopChain(loop) {
12
12
  return buildLoopChainExpr({
13
13
  base: loop.array,
@@ -387,6 +387,9 @@ export default ${this.componentName}` : "";
387
387
  if (element.slotId) {
388
388
  hydrationAttrs += ` bf="${element.slotId}"`;
389
389
  }
390
+ if (element.regionId) {
391
+ hydrationAttrs += ` ${BF_REGION}="${element.regionId}"`;
392
+ }
390
393
  if (children) {
391
394
  return `<${tag}${attrs}${hydrationAttrs}>${children}</${tag}>`;
392
395
  } else {
@@ -16,7 +16,7 @@
16
16
  */
17
17
  import type { Context as HonoContext } from 'hono/jsx';
18
18
  import type { Context } from '@barefootjs/client';
19
- export { createContext, splitProps, forwardProps, unwrap, __slot, } from '@barefootjs/client';
19
+ export { createContext, splitProps, forwardProps, unwrap, __slot, searchParams, } from '@barefootjs/client';
20
20
  export type { Context, Reactive, Signal, Memo, CleanupFn, EffectFn, SlotMarker, Portal, PortalChildren, PortalOptions, Renderable, } from '@barefootjs/client';
21
21
  /**
22
22
  * Lazily map a BarefootJS Context object to a Hono context. The mapping is
@@ -1 +1 @@
1
- {"version":3,"file":"client-shim.d.ts","sourceRoot":"","sources":["../src/client-shim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAEjD,OAAO,EACL,aAAa,EACb,UAAU,EACV,YAAY,EACZ,MAAM,EACN,MAAM,GACP,MAAM,oBAAoB,CAAA;AAE3B,YAAY,EACV,OAAO,EACP,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,UAAU,EACV,MAAM,EACN,cAAc,EACd,aAAa,EACb,UAAU,GACX,MAAM,oBAAoB,CAAA;AAQ3B;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,GAAG,SAAS,CAAC,CAO/E;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAKlD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAErE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EACjB,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,OAAO,GAChB,OAAO,CAGT;AAYD,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,KAAK,CAEnD;AACD,wBAAgB,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,KAAK,CAEjD;AACD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,KAAK,CAEnD;AACD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,KAAK,CAE7D;AACD,wBAAgB,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,CAEpE;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,IAAI,CAE7C;AACD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,IAAI,CAE/C;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEzC;AACD,wBAAgB,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEvC;AAMD,wBAAgB,YAAY,CAC1B,SAAS,EAAE,OAAO,EAClB,UAAU,CAAC,EAAE,OAAO,EACpB,QAAQ,CAAC,EAAE,OAAO,GACjB,KAAK,CAEP;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAEtD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,CAEzE;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAEhE"}
1
+ {"version":3,"file":"client-shim.d.ts","sourceRoot":"","sources":["../src/client-shim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAEjD,OAAO,EACL,aAAa,EACb,UAAU,EACV,YAAY,EACZ,MAAM,EACN,MAAM,EAMN,YAAY,GACb,MAAM,oBAAoB,CAAA;AAE3B,YAAY,EACV,OAAO,EACP,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,UAAU,EACV,MAAM,EACN,cAAc,EACd,aAAa,EACb,UAAU,GACX,MAAM,oBAAoB,CAAA;AAQ3B;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,GAAG,SAAS,CAAC,CAO/E;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAKlD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAErE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EACjB,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,OAAO,GAChB,OAAO,CAGT;AAYD,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,KAAK,CAEnD;AACD,wBAAgB,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,KAAK,CAEjD;AACD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,KAAK,CAEnD;AACD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,KAAK,CAE7D;AACD,wBAAgB,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,CAEpE;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,IAAI,CAE7C;AACD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,IAAI,CAE/C;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEzC;AACD,wBAAgB,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEvC;AAMD,wBAAgB,YAAY,CAC1B,SAAS,EAAE,OAAO,EAClB,UAAU,CAAC,EAAE,OAAO,EACpB,QAAQ,CAAC,EAAE,OAAO,GACjB,KAAK,CAEP;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAEtD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,CAEzE;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAEhE"}
@@ -5,7 +5,8 @@ import {
5
5
  splitProps,
6
6
  forwardProps,
7
7
  unwrap,
8
- __slot
8
+ __slot,
9
+ searchParams
9
10
  } from "@barefootjs/client";
10
11
  var honoCtxBridge = new WeakMap;
11
12
  function getHonoContext(bfCtx) {
@@ -69,6 +70,7 @@ export {
69
70
  unwrap,
70
71
  untrack,
71
72
  splitProps,
73
+ searchParams,
72
74
  provideContextSSR,
73
75
  provideContext,
74
76
  onMount,
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  emitAttrValue,
8
8
  buildLoopChainExpr
9
9
  } from "@barefootjs/jsx";
10
- import { BF_SCOPE, BF_HOST, BF_AT, BF_ROOT, BF_PROPS } from "@barefootjs/shared";
10
+ import { BF_SCOPE, BF_HOST, BF_AT, BF_ROOT, BF_PROPS, BF_REGION } from "@barefootjs/shared";
11
11
  function applyHonoLoopChain(loop) {
12
12
  return buildLoopChainExpr({
13
13
  base: loop.array,
@@ -387,6 +387,9 @@ export default ${this.componentName}` : "";
387
387
  if (element.slotId) {
388
388
  hydrationAttrs += ` bf="${element.slotId}"`;
389
389
  }
390
+ if (element.regionId) {
391
+ hydrationAttrs += ` ${BF_REGION}="${element.regionId}"`;
392
+ }
390
393
  if (children) {
391
394
  return `<${tag}${attrs}${hydrationAttrs}>${children}</${tag}>`;
392
395
  } else {
@@ -17,16 +17,4 @@ export declare namespace JSX {
17
17
  type IntrinsicAttributes = BaseJSX.IntrinsicAttributes;
18
18
  type ElementChildrenAttribute = BaseJSX.ElementChildrenAttribute;
19
19
  }
20
- /**
21
- * BarefootJS compiler built-in: streaming async boundary.
22
- *
23
- * The compiler intercepts `<Async fallback={...}>` in JSX source and emits it
24
- * as a `<Suspense>` node in the Hono adapter output (IRAsync → renderAsync).
25
- * This declaration provides TypeScript types for source files; no runtime
26
- * implementation is needed because the compiler replaces it before execution.
27
- */
28
- export declare function Async(props: {
29
- fallback: JSX.Element;
30
- children: JSX.Element | JSX.Element[] | null | undefined;
31
- }): JSX.Element;
32
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/jsx/jsx-runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAG3F,OAAO,KAAK,EAAE,GAAG,IAAI,OAAO,EAAE,MAAM,6BAA6B,CAAA;AAEjE,MAAM,CAAC,OAAO,WAAW,GAAG,CAAC,CAAC;IAE5B,KAAK,OAAO,GAAG,OAAO,sBAAsB,EAAE,GAAG,CAAC,OAAO,CAAA;IAGzD,KAAK,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAA;IAClD,KAAK,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAA;IACtD,KAAK,wBAAwB,GAAG,OAAO,CAAC,wBAAwB,CAAA;CACjE;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,KAAK,EAAE;IACnC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;IACrB,QAAQ,EAAE,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,GAAG,SAAS,CAAA;CACzD,GAAG,GAAG,CAAC,OAAO,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/jsx/jsx-runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAG3F,OAAO,KAAK,EAAE,GAAG,IAAI,OAAO,EAAE,MAAM,6BAA6B,CAAA;AAEjE,MAAM,CAAC,OAAO,WAAW,GAAG,CAAC,CAAC;IAE5B,KAAK,OAAO,GAAG,OAAO,sBAAsB,EAAE,GAAG,CAAC,OAAO,CAAA;IAGzD,KAAK,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAA;IAClD,KAAK,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAA;IACtD,KAAK,wBAAwB,GAAG,OAAO,CAAC,wBAAwB,CAAA;CACjE"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Request-scoped environment values for the framework-agnostic `renderToHtml`
3
+ * path — the non-Hono JS hosts (h3 / Elysia / any WinterCG handler) that render
4
+ * BarefootJS components as plain `hono/jsx` without Hono's `jsxRenderer`.
5
+ * spec/router.md v0.5 ("The wedge"), #1922.
6
+ *
7
+ * Hono resolves a request's environment through `useRequestContext()` inside its
8
+ * `jsxRenderer` async context. `renderToHtml` has no such context, so without
9
+ * this an env signal (`searchParams()`, …) resolves to its empty default
10
+ * regardless of the request — query-dependent initial content flashes /
11
+ * mismatches on hydration (the client then corrects it from the live browser
12
+ * state).
13
+ *
14
+ * A process-wide reader mutated per request would RACE across concurrent
15
+ * requests (the spec explicitly forbids it), so the values are scoped with a
16
+ * Node `AsyncLocalStorage`: each render runs inside `runWithRequestEnv(env, …)`
17
+ * and the reader returns the current async context's value — race-free.
18
+ *
19
+ * The reader is published on the shared, KEYED `globalThis.__bf_serverEnvReader`
20
+ * seam (the same one Hono's auto-wire uses, and which `@barefootjs/client`'s env
21
+ * signals read on the server) — never by importing `@barefootjs/client`, so this
22
+ * module can't pull a second client instance. One seam serves every env signal,
23
+ * so a new signal (cookies, …) is a new field on {@link BfRequestEnv}, not a new
24
+ * wrapper function. We install at most once and capture whatever reader was
25
+ * already on the seam (e.g. Hono's `useRequestContext` reader): when no render
26
+ * scope is active — or this env doesn't carry the requested key — we delegate to
27
+ * it, so a process mixing Hono and `renderToHtml` hosts keeps resolving both ways.
28
+ *
29
+ * Lives behind its own subpath (`@barefootjs/hono/request-env`), imported only
30
+ * by the hosts that opt in, so the always-on `renderToHtml` path never loads
31
+ * `node:async_hooks`.
32
+ */
33
+ /**
34
+ * Per-request environment values, keyed to match the `@barefootjs/client` env
35
+ * signals. A new env signal adds a field here; the host passes one more value —
36
+ * no new wrapper function.
37
+ */
38
+ export interface BfRequestEnv {
39
+ /**
40
+ * The request's query string, with or without a leading `?` (e.g.
41
+ * `new URL(req.url).search` on Elysia, `getRequestURL(event).search` on h3).
42
+ * Backs `searchParams()`; `URLSearchParams` strips the `?`.
43
+ */
44
+ search?: string;
45
+ }
46
+ /**
47
+ * Run `fn` — typically `() => renderToHtml(node)` — with the given request
48
+ * environment bound for the duration of its async context, so env signals
49
+ * (`searchParams()`, …) resolve this request's values at SSR. The binding
50
+ * propagates across the awaits inside `renderToHtml` (including `async`
51
+ * components), and concurrent renders each see their own `env` — never a shared
52
+ * per-request global (which the spec forbids because it races).
53
+ *
54
+ * Usage:
55
+ *
56
+ * const html = await runWithRequestEnv(
57
+ * { search: new URL(req.url).search },
58
+ * () => renderToHtml(<Layout …>…</Layout>),
59
+ * )
60
+ */
61
+ export declare function runWithRequestEnv<T>(env: BfRequestEnv, fn: () => T): T;
62
+ /**
63
+ * Wrap a WinterCG `fetch` handler so the whole request runs with its env bound —
64
+ * env signals (`searchParams()`, …) resolve this request's values at SSR with no
65
+ * per-render plumbing. Bind ONCE at the entry point and every `renderToHtml`
66
+ * inside (across routing, handlers, `async` components) inherits it via the
67
+ * async context; concurrent requests never race.
68
+ *
69
+ * export default { port, fetch: withRequestEnv(handler) }
70
+ *
71
+ * Extra args (the framework / Bun server, Workers `env` / `ctx`) pass through
72
+ * unchanged. The env is derived from the `Request` by {@link requestEnv}, so the
73
+ * host never names env keys — a future signal (cookies, …) needs no host change.
74
+ */
75
+ export declare function withRequestEnv<A extends unknown[]>(handler: (request: Request, ...args: A) => Response | Promise<Response>): (request: Request, ...args: A) => Promise<Response>;
76
+ //# sourceMappingURL=request-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-env.d.ts","sourceRoot":"","sources":["../src/request-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAIH;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AA0BD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAGtE;AAaD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,OAAO,EAAE,EAChD,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GACtE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAGrD"}
@@ -0,0 +1,34 @@
1
+ // src/request-env.ts
2
+ var {AsyncLocalStorage} = (() => ({}));
3
+ var envStore = new AsyncLocalStorage;
4
+ var installed = false;
5
+ function ensureReaderInstalled() {
6
+ if (installed)
7
+ return;
8
+ installed = true;
9
+ const holder = globalThis;
10
+ const prior = holder.__bf_serverEnvReader;
11
+ holder.__bf_serverEnvReader = (key) => {
12
+ const env = envStore.getStore();
13
+ if (env) {
14
+ const value = env[key];
15
+ if (value !== undefined)
16
+ return value;
17
+ }
18
+ return typeof prior === "function" ? prior(key) : undefined;
19
+ };
20
+ }
21
+ function runWithRequestEnv(env, fn) {
22
+ ensureReaderInstalled();
23
+ return envStore.run(env, fn);
24
+ }
25
+ function requestEnv(request) {
26
+ return { search: new URL(request.url).search };
27
+ }
28
+ function withRequestEnv(handler) {
29
+ return (request, ...args) => runWithRequestEnv(requestEnv(request), async () => handler(request, ...args));
30
+ }
31
+ export {
32
+ withRequestEnv,
33
+ runWithRequestEnv
34
+ };
package/dist/scripts.js CHANGED
@@ -63,8 +63,29 @@ data: ${BOOT_ID}
63
63
 
64
64
  // src/app.ts
65
65
  import { html, raw } from "hono/html";
66
- import { useRequestContext } from "hono/jsx-renderer";
66
+ import { useRequestContext as useRequestContext2 } from "hono/jsx-renderer";
67
67
  import { renderImportMapHtml } from "@barefootjs/jsx/import-map";
68
+
69
+ // src/search-params-ssr.ts
70
+ import { useRequestContext } from "hono/jsx-renderer";
71
+ function searchFromRequestUrl(url) {
72
+ try {
73
+ return new URL(url).search;
74
+ } catch {
75
+ return "";
76
+ }
77
+ }
78
+ globalThis.__bf_serverEnvReader = (key) => {
79
+ if (key !== "search")
80
+ return;
81
+ try {
82
+ return searchFromRequestUrl(useRequestContext().req.url);
83
+ } catch {
84
+ return;
85
+ }
86
+ };
87
+
88
+ // src/app.ts
68
89
  var DEV_RELOAD_ENDPOINT_KEY = "bfDevReloadEndpoint";
69
90
  function manifestToScriptUrls(manifest, base) {
70
91
  const out = [];
@@ -107,7 +128,7 @@ function BfDevReload(props = {}) {
107
128
  let endpoint = props.endpoint;
108
129
  if (!endpoint) {
109
130
  try {
110
- endpoint = useRequestContext().get(DEV_RELOAD_ENDPOINT_KEY);
131
+ endpoint = useRequestContext2().get(DEV_RELOAD_ENDPOINT_KEY);
111
132
  } catch {}
112
133
  }
113
134
  if (!endpoint)
@@ -132,12 +153,12 @@ function barefootDevReload(opts) {
132
153
  }
133
154
 
134
155
  // src/scripts.tsx
135
- import { useRequestContext as useRequestContext2 } from "hono/jsx-renderer";
156
+ import { useRequestContext as useRequestContext3 } from "hono/jsx-renderer";
136
157
  import { Fragment } from "hono/jsx";
137
158
  import { jsxDEV } from "hono/jsx/jsx-dev-runtime";
138
159
  function BfScripts2(props = {}) {
139
160
  try {
140
- const c = useRequestContext2();
161
+ const c = useRequestContext3();
141
162
  c.set("bfScriptsRendered", true);
142
163
  const scripts = c.get("bfCollectedScripts") || [];
143
164
  const outputSet = c.get("bfOutputScripts") || new Set;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Auto-wire request-scoped `searchParams()` for Hono SSR (spec/router.md "The
3
+ * wedge", v0.5).
4
+ *
5
+ * `@barefootjs/client`'s `searchParams()` is environment-neutral: on the server
6
+ * it asks for the current request's query string through a reader seam. Hono
7
+ * exposes the active request via `useRequestContext()` (async-context scoped),
8
+ * so the reader resolves **per request** with no shared mutable state to race.
9
+ *
10
+ * We publish the reader on the keyed `globalThis.__bf_serverEnvReader` seam —
11
+ * the server-side analogue of the client's `window.__bf_*` seams — rather than
12
+ * importing `@barefootjs/client`. SSR templates resolve the `@barefootjs/client`
13
+ * specifier through the adapter's shim, so this infrastructure module stays
14
+ * decoupled from the client package while still wiring it. This module is
15
+ * imported for its side effect by `app.ts`, so any Hono SSR app that renders
16
+ * the BarefootJS scripts gets request-scoped `searchParams()` with no opt-in.
17
+ *
18
+ * The reader is keyed by env id, so one seam serves every env signal
19
+ * (`searchParams()` via `'search'` today; cookies, … later). Unknown keys
20
+ * return `undefined` to defer to the empty default.
21
+ */
22
+ /** Extract the query string (including leading `?`, or `''`) from a request URL. */
23
+ export declare function searchFromRequestUrl(url: string): string;
24
+ //# sourceMappingURL=search-params-ssr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-params-ssr.d.ts","sourceRoot":"","sources":["../src/search-params-ssr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,oFAAoF;AACpF,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMxD"}
@@ -1 +1 @@
1
- {"version":3,"file":"test-render.d.ts","sourceRoot":"","sources":["../src/test-render.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAStD,MAAM,WAAW,aAAa;IAC5B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,8BAA8B;IAC9B,OAAO,EAAE,eAAe,CAAA;IACxB,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AA2BD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA0KjF"}
1
+ {"version":3,"file":"test-render.d.ts","sourceRoot":"","sources":["../src/test-render.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAStD,MAAM,WAAW,aAAa;IAC5B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,8BAA8B;IAC9B,OAAO,EAAE,eAAe,CAAA;IACxB,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AA2BD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAsLjF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/hono",
3
- "version": "0.14.0",
3
+ "version": "0.15.1",
4
4
  "description": "Hono integration for BarefootJS",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -76,6 +76,10 @@
76
76
  "./render": {
77
77
  "types": "./dist/render.d.ts",
78
78
  "import": "./dist/render.js"
79
+ },
80
+ "./request-env": {
81
+ "types": "./dist/request-env.d.ts",
82
+ "import": "./dist/request-env.js"
79
83
  }
80
84
  },
81
85
  "files": [
@@ -84,7 +88,7 @@
84
88
  ],
85
89
  "scripts": {
86
90
  "build": "bun run build:js && bun run build:types",
87
- "build:js": "bun build ./src/index.ts ./src/adapter/index.ts ./src/scripts.tsx ./src/portals.tsx ./src/portal-ssr.tsx ./src/dialog-context.tsx ./src/client-shim.ts ./src/preload.tsx ./src/dev.tsx ./src/dev-worker.ts ./src/jsx/jsx-runtime/index.ts ./src/jsx/jsx-dev-runtime/index.ts ./src/async.tsx ./src/utils.ts ./src/build.ts ./src/app.ts ./src/render.ts --root ./src --outdir ./dist --format esm --external hono --external @barefootjs/client --external @barefootjs/jsx --external @barefootjs/shared",
91
+ "build:js": "bun build ./src/index.ts ./src/adapter/index.ts ./src/scripts.tsx ./src/portals.tsx ./src/portal-ssr.tsx ./src/dialog-context.tsx ./src/client-shim.ts ./src/preload.tsx ./src/dev.tsx ./src/dev-worker.ts ./src/jsx/jsx-runtime/index.ts ./src/jsx/jsx-dev-runtime/index.ts ./src/async.tsx ./src/utils.ts ./src/build.ts ./src/app.ts ./src/render.ts ./src/request-env.ts --root ./src --outdir ./dist --format esm --external hono --external @barefootjs/client --external @barefootjs/jsx --external @barefootjs/shared",
88
92
  "build:types": "tsgo --emitDeclarationOnly --outDir ./dist",
89
93
  "test": "bun test",
90
94
  "clean": "rm -rf dist",
@@ -29,6 +29,7 @@ function templateOf(source: string): string {
29
29
  describe('compiled <Async> boundary — ErrorBoundary wrapping (#1375)', () => {
30
30
  test('emits ErrorBoundary enclosing Suspense, sharing the fallback', () => {
31
31
  const template = templateOf(`
32
+ import { Async } from '@barefootjs/client'
32
33
  export function Page() {
33
34
  return (
34
35
  <div>
@@ -52,6 +53,7 @@ describe('compiled <Async> boundary — ErrorBoundary wrapping (#1375)', () => {
52
53
 
53
54
  test('injects the aliased ErrorBoundary import alongside Suspense', () => {
54
55
  const template = templateOf(`
56
+ import { Async } from '@barefootjs/client'
55
57
  export function Page() {
56
58
  return (
57
59
  <Async fallback={<p>Loading...</p>}>
@@ -71,6 +73,7 @@ describe('compiled <Async> boundary — ErrorBoundary wrapping (#1375)', () => {
71
73
  // injected Hono import to duplicate the user's own `ErrorBoundary`
72
74
  // binding (which would be a "Duplicate identifier" build error).
73
75
  const template = templateOf(`
76
+ import { Async } from '@barefootjs/client'
74
77
  import { ErrorBoundary } from './my-error-boundary'
75
78
  export function Page() {
76
79
  return (
@@ -91,6 +94,7 @@ describe('compiled <Async> boundary — ErrorBoundary wrapping (#1375)', () => {
91
94
 
92
95
  test('each of multiple boundaries gets its own ErrorBoundary wrapper', () => {
93
96
  const template = templateOf(`
97
+ import { Async } from '@barefootjs/client'
94
98
  export function Dashboard() {
95
99
  return (
96
100
  <div>
@@ -0,0 +1,139 @@
1
+ /** @jsxImportSource hono/jsx */
2
+ /**
3
+ * Request-scoped env signals for the framework-agnostic `renderToHtml` path
4
+ * (h3 / Elysia / … hosts), spec/router.md v0.5, #1922.
5
+ *
6
+ * `runWithRequestEnv({ search }, () => renderToHtml(node))` binds the request's
7
+ * env (here `searchParams()`) for that render's async context, so a host that
8
+ * bypasses Hono's jsxRenderer still resolves the live query at SSR — and
9
+ * concurrent renders never see each other's values (the spec forbids a
10
+ * process-wide per-request global because it races). The env object is keyed, so
11
+ * future signals (cookies, …) ride the same wrapper.
12
+ */
13
+
14
+ import { describe, test, expect, beforeAll } from 'bun:test'
15
+ import { searchParams } from '@barefootjs/client'
16
+ import { renderToHtml } from '../render'
17
+ import { runWithRequestEnv, withRequestEnv } from '../request-env'
18
+
19
+ // A plain hono/jsx component that reads the env signal at SSR — exactly what a
20
+ // compiled BarefootJS component lowers `{searchParams().get('sort') ?? 'none'}`
21
+ // to on the Hono adapter.
22
+ const SortLabel = () => <p>{searchParams().get('sort') ?? 'none'}</p>
23
+
24
+ // Install a prior keyed reader on the seam BEFORE the first `runWithRequestEnv`
25
+ // call below — `request-env` captures whatever reader is already there at
26
+ // install time and delegates to it (mirrors a process where Hono's auto-wire
27
+ // installed its reader first). The prior answers only a sentinel key and returns
28
+ // `undefined` for `search`, so the searchParams tests are unaffected while the
29
+ // delegation suite below can assert the chain.
30
+ const PRIOR_KEY = 'env-test-prior'
31
+ beforeAll(() => {
32
+ ;(
33
+ globalThis as unknown as { __bf_serverEnvReader?: (key: string) => string | undefined }
34
+ ).__bf_serverEnvReader = (key) => (key === PRIOR_KEY ? 'from-prior' : undefined)
35
+ })
36
+
37
+ describe('runWithRequestEnv + renderToHtml', () => {
38
+ test('binds searchParams() to the wrapped query', async () => {
39
+ const html = await runWithRequestEnv({ search: '?sort=price' }, () => renderToHtml(<SortLabel />))
40
+ expect(html).toBe('<p>price</p>')
41
+ })
42
+
43
+ test('a present-but-empty value is kept (URLSearchParams.get returns "")', async () => {
44
+ // `?sort=` → get('sort') === '' (not null), and `'' ?? 'none'` === ''.
45
+ const html = await runWithRequestEnv({ search: '?sort=' }, () => renderToHtml(<SortLabel />))
46
+ expect(html).toBe('<p></p>')
47
+ })
48
+
49
+ test('an absent key falls back to the author default', async () => {
50
+ const html = await runWithRequestEnv({ search: '?other=x' }, () => renderToHtml(<SortLabel />))
51
+ expect(html).toBe('<p>none</p>')
52
+ })
53
+
54
+ test('a leading "?" is optional', async () => {
55
+ const html = await runWithRequestEnv({ search: 'sort=price' }, () => renderToHtml(<SortLabel />))
56
+ expect(html).toBe('<p>price</p>')
57
+ })
58
+
59
+ test('an omitted env key resolves to the empty default', async () => {
60
+ // `{}` carries no `search`, so the reader delegates → empty query → default.
61
+ const html = await runWithRequestEnv({}, () => renderToHtml(<SortLabel />))
62
+ expect(html).toBe('<p>none</p>')
63
+ })
64
+
65
+ test('concurrent renders do not leak each other’s query (async-context scoped)', async () => {
66
+ // Interleave many renders with distinct queries; each must resolve its own.
67
+ const queries = Array.from({ length: 24 }, (_, i) => `?sort=v${i}`)
68
+ const results = await Promise.all(
69
+ queries.map((q, i) =>
70
+ runWithRequestEnv({ search: q }, async () => {
71
+ // Yield so the async contexts genuinely interleave before each reads.
72
+ await new Promise((r) => setTimeout(r, i % 5))
73
+ return renderToHtml(<SortLabel />)
74
+ }),
75
+ ),
76
+ )
77
+ results.forEach((html, i) => expect(html).toBe(`<p>v${i}</p>`))
78
+ })
79
+
80
+ test('outside any scope resolves to the empty query (default)', async () => {
81
+ // No wrapping run() and no other reader wired in this test process → '' →
82
+ // get('sort') is null → author default.
83
+ const html = await renderToHtml(<SortLabel />)
84
+ expect(html).toBe('<p>none</p>')
85
+ })
86
+ })
87
+
88
+ describe('withRequestEnv (WinterCG fetch-handler wrapper)', () => {
89
+ test('binds searchParams() from the Request — the handler just renders', async () => {
90
+ const handler = withRequestEnv(
91
+ async (_req: Request) =>
92
+ new Response(await renderToHtml(<SortLabel />), {
93
+ headers: { 'content-type': 'text/html' },
94
+ }),
95
+ )
96
+ const res = await handler(new Request('https://x.test/list?sort=price'))
97
+ expect(await res.text()).toBe('<p>price</p>')
98
+ })
99
+
100
+ test('derives env from the Request and passes extra args (server / env / ctx) through', async () => {
101
+ const seen: unknown[] = []
102
+ const handler = withRequestEnv(async (_req: Request, a: number, b: string) => {
103
+ seen.push(a, b)
104
+ return new Response(await renderToHtml(<SortLabel />))
105
+ })
106
+ const res = await handler(new Request('https://x.test/?sort=name'), 7, 'z')
107
+ expect(seen).toEqual([7, 'z'])
108
+ expect(await res.text()).toBe('<p>name</p>')
109
+ })
110
+
111
+ test('a request with no query resolves the author default', async () => {
112
+ const handler = withRequestEnv(async () => new Response(await renderToHtml(<SortLabel />)))
113
+ const res = await handler(new Request('https://x.test/list'))
114
+ expect(await res.text()).toBe('<p>none</p>')
115
+ })
116
+ })
117
+
118
+ describe('keyed seam — delegates to the prior reader', () => {
119
+ // The reader currently published on the seam (the chained one once
120
+ // `runWithRequestEnv` has installed it, else the raw prior — either way the
121
+ // delegation behaviour is identical for these cases).
122
+ const seam = () =>
123
+ (globalThis as unknown as { __bf_serverEnvReader: (key: string) => string | undefined })
124
+ .__bf_serverEnvReader
125
+
126
+ test('an unknown key delegates to the prior reader (outside any scope)', () => {
127
+ expect(seam()(PRIOR_KEY)).toBe('from-prior')
128
+ // The prior returns undefined for `search`, so a non-request render still
129
+ // resolves to the empty default rather than leaking a value.
130
+ expect(seam()('search')).toBeUndefined()
131
+ })
132
+
133
+ test('a scoped env wins for its key; absent keys still delegate to the prior', () => {
134
+ runWithRequestEnv({ search: '?sort=price' }, () => {
135
+ expect(seam()('search')).toBe('?sort=price') // scoped value wins over the prior
136
+ expect(seam()(PRIOR_KEY)).toBe('from-prior') // key not in env → delegate
137
+ })
138
+ })
139
+ })
@@ -0,0 +1,23 @@
1
+ /**
2
+ * searchFromRequestUrl — the pure query-extraction helper the Hono SSR
3
+ * auto-wire publishes through the keyed `globalThis.__bf_serverEnvReader` seam
4
+ * (which `@barefootjs/client`'s `searchParams()` reads on the server, key
5
+ * `'search'`), spec/router.md v0.5.
6
+ */
7
+
8
+ import { describe, test, expect } from 'bun:test'
9
+ import { searchFromRequestUrl } from '../search-params-ssr'
10
+
11
+ describe('searchFromRequestUrl', () => {
12
+ test('returns the query string including the leading "?"', () => {
13
+ expect(searchFromRequestUrl('https://example.test/list?sort=price&page=2')).toBe('?sort=price&page=2')
14
+ })
15
+
16
+ test('returns empty string for a query-less URL', () => {
17
+ expect(searchFromRequestUrl('https://example.test/list')).toBe('')
18
+ })
19
+
20
+ test('never throws on a malformed URL', () => {
21
+ expect(searchFromRequestUrl('not a url')).toBe('')
22
+ })
23
+ })
@@ -47,7 +47,7 @@ type HonoRenderCtx = {
47
47
  isInsideLoop?: boolean
48
48
  isLoopItemRoot?: boolean
49
49
  }
50
- import { BF_SCOPE, BF_HOST, BF_AT, BF_ROOT, BF_PROPS } from '@barefootjs/shared'
50
+ import { BF_SCOPE, BF_HOST, BF_AT, BF_ROOT, BF_PROPS, BF_REGION } from '@barefootjs/shared'
51
51
 
52
52
  export interface HonoAdapterOptions {
53
53
  /**
@@ -715,6 +715,9 @@ export class HonoAdapter extends JsxAdapter implements IRNodeEmitter<HonoRenderC
715
715
  if (element.slotId) {
716
716
  hydrationAttrs += ` bf="${element.slotId}"`
717
717
  }
718
+ if (element.regionId) {
719
+ hydrationAttrs += ` ${BF_REGION}="${element.regionId}"`
720
+ }
718
721
 
719
722
  if (children) {
720
723
  return `<${tag}${attrs}${hydrationAttrs}>${children}</${tag}>`
package/src/app.ts CHANGED
@@ -34,6 +34,9 @@ import { useRequestContext } from 'hono/jsx-renderer'
34
34
  // of this runtime/Workers-bundled module while sharing one importmap renderer.
35
35
  import { renderImportMapHtml, type ImportMapManifest } from '@barefootjs/jsx/import-map'
36
36
  import { createDevReloader } from './dev-worker.ts'
37
+ // Side-effect import: auto-wires request-scoped `searchParams()` for SSR so any
38
+ // Hono app rendering the BarefootJS scripts gets it without an opt-in step.
39
+ import './search-params-ssr.ts'
37
40
 
38
41
  const DEV_RELOAD_ENDPOINT_KEY = 'bfDevReloadEndpoint'
39
42
 
@@ -27,6 +27,12 @@ export {
27
27
  forwardProps,
28
28
  unwrap,
29
29
  __slot,
30
+ // Request-scoped env signal (router v0.5). Unlike the reactive primitives
31
+ // below, `searchParams()` is meant to resolve during SSR — on the server it
32
+ // reads the per-request query via the injected reader (the Hono adapter wires
33
+ // it in `search-params-ssr.ts`), defaulting to an empty query — so the real
34
+ // export is re-exported, not a throwing stub.
35
+ searchParams,
30
36
  } from '@barefootjs/client'
31
37
 
32
38
  export type {
@@ -26,15 +26,8 @@ export declare namespace JSX {
26
26
  type ElementChildrenAttribute = BaseJSX.ElementChildrenAttribute
27
27
  }
28
28
 
29
- /**
30
- * BarefootJS compiler built-in: streaming async boundary.
31
- *
32
- * The compiler intercepts `<Async fallback={...}>` in JSX source and emits it
33
- * as a `<Suspense>` node in the Hono adapter output (IRAsync → renderAsync).
34
- * This declaration provides TypeScript types for source files; no runtime
35
- * implementation is needed because the compiler replaces it before execution.
36
- */
37
- export declare function Async(props: {
38
- fallback: JSX.Element
39
- children: JSX.Element | JSX.Element[] | null | undefined
40
- }): JSX.Element
29
+ // Compiler built-ins `<Async>` / `<Region>` are import-scoped to
30
+ // `@barefootjs/client` (`import { Async, Region } from '@barefootjs/client'`),
31
+ // recognised by that import and compiled away (#1915). They are intentionally
32
+ // not re-declared on this JSX runtime a bare tag-name declaration here would
33
+ // reintroduce the phantom-import / collision problems #1915 set out to remove.
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Request-scoped environment values for the framework-agnostic `renderToHtml`
3
+ * path — the non-Hono JS hosts (h3 / Elysia / any WinterCG handler) that render
4
+ * BarefootJS components as plain `hono/jsx` without Hono's `jsxRenderer`.
5
+ * spec/router.md v0.5 ("The wedge"), #1922.
6
+ *
7
+ * Hono resolves a request's environment through `useRequestContext()` inside its
8
+ * `jsxRenderer` async context. `renderToHtml` has no such context, so without
9
+ * this an env signal (`searchParams()`, …) resolves to its empty default
10
+ * regardless of the request — query-dependent initial content flashes /
11
+ * mismatches on hydration (the client then corrects it from the live browser
12
+ * state).
13
+ *
14
+ * A process-wide reader mutated per request would RACE across concurrent
15
+ * requests (the spec explicitly forbids it), so the values are scoped with a
16
+ * Node `AsyncLocalStorage`: each render runs inside `runWithRequestEnv(env, …)`
17
+ * and the reader returns the current async context's value — race-free.
18
+ *
19
+ * The reader is published on the shared, KEYED `globalThis.__bf_serverEnvReader`
20
+ * seam (the same one Hono's auto-wire uses, and which `@barefootjs/client`'s env
21
+ * signals read on the server) — never by importing `@barefootjs/client`, so this
22
+ * module can't pull a second client instance. One seam serves every env signal,
23
+ * so a new signal (cookies, …) is a new field on {@link BfRequestEnv}, not a new
24
+ * wrapper function. We install at most once and capture whatever reader was
25
+ * already on the seam (e.g. Hono's `useRequestContext` reader): when no render
26
+ * scope is active — or this env doesn't carry the requested key — we delegate to
27
+ * it, so a process mixing Hono and `renderToHtml` hosts keeps resolving both ways.
28
+ *
29
+ * Lives behind its own subpath (`@barefootjs/hono/request-env`), imported only
30
+ * by the hosts that opt in, so the always-on `renderToHtml` path never loads
31
+ * `node:async_hooks`.
32
+ */
33
+
34
+ import { AsyncLocalStorage } from 'node:async_hooks'
35
+
36
+ /**
37
+ * Per-request environment values, keyed to match the `@barefootjs/client` env
38
+ * signals. A new env signal adds a field here; the host passes one more value —
39
+ * no new wrapper function.
40
+ */
41
+ export interface BfRequestEnv {
42
+ /**
43
+ * The request's query string, with or without a leading `?` (e.g.
44
+ * `new URL(req.url).search` on Elysia, `getRequestURL(event).search` on h3).
45
+ * Backs `searchParams()`; `URLSearchParams` strips the `?`.
46
+ */
47
+ search?: string
48
+ }
49
+
50
+ type SeamHolder = { __bf_serverEnvReader?: (key: string) => string | undefined }
51
+
52
+ const envStore = new AsyncLocalStorage<BfRequestEnv>()
53
+ let installed = false
54
+
55
+ function ensureReaderInstalled(): void {
56
+ if (installed) return
57
+ installed = true
58
+ const holder = globalThis as unknown as SeamHolder
59
+ // The keyed reader already on the seam (e.g. Hono's useRequestContext-based
60
+ // one, installed at startup by `@barefootjs/hono/app`). We delegate to it when
61
+ // no render scope is active — or this env lacks the key — so a mixed Hono +
62
+ // renderToHtml process still resolves both ways.
63
+ const prior = holder.__bf_serverEnvReader
64
+ holder.__bf_serverEnvReader = (key) => {
65
+ const env = envStore.getStore()
66
+ if (env) {
67
+ const value = env[key as keyof BfRequestEnv]
68
+ if (value !== undefined) return value
69
+ }
70
+ return typeof prior === 'function' ? prior(key) : undefined
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Run `fn` — typically `() => renderToHtml(node)` — with the given request
76
+ * environment bound for the duration of its async context, so env signals
77
+ * (`searchParams()`, …) resolve this request's values at SSR. The binding
78
+ * propagates across the awaits inside `renderToHtml` (including `async`
79
+ * components), and concurrent renders each see their own `env` — never a shared
80
+ * per-request global (which the spec forbids because it races).
81
+ *
82
+ * Usage:
83
+ *
84
+ * const html = await runWithRequestEnv(
85
+ * { search: new URL(req.url).search },
86
+ * () => renderToHtml(<Layout …>…</Layout>),
87
+ * )
88
+ */
89
+ export function runWithRequestEnv<T>(env: BfRequestEnv, fn: () => T): T {
90
+ ensureReaderInstalled()
91
+ return envStore.run(env, fn)
92
+ }
93
+
94
+ /**
95
+ * Derive the request environment from a WinterCG `Request` — the single place
96
+ * that maps a request to env-signal values. A new env signal extends this (and
97
+ * {@link BfRequestEnv}); hosts using {@link withRequestEnv} get it for free.
98
+ */
99
+ function requestEnv(request: Request): BfRequestEnv {
100
+ return { search: new URL(request.url).search }
101
+ // When the cookie env signal lands:
102
+ // cookie: request.headers.get('cookie') ?? undefined
103
+ }
104
+
105
+ /**
106
+ * Wrap a WinterCG `fetch` handler so the whole request runs with its env bound —
107
+ * env signals (`searchParams()`, …) resolve this request's values at SSR with no
108
+ * per-render plumbing. Bind ONCE at the entry point and every `renderToHtml`
109
+ * inside (across routing, handlers, `async` components) inherits it via the
110
+ * async context; concurrent requests never race.
111
+ *
112
+ * export default { port, fetch: withRequestEnv(handler) }
113
+ *
114
+ * Extra args (the framework / Bun server, Workers `env` / `ctx`) pass through
115
+ * unchanged. The env is derived from the `Request` by {@link requestEnv}, so the
116
+ * host never names env keys — a future signal (cookies, …) needs no host change.
117
+ */
118
+ export function withRequestEnv<A extends unknown[]>(
119
+ handler: (request: Request, ...args: A) => Response | Promise<Response>,
120
+ ): (request: Request, ...args: A) => Promise<Response> {
121
+ return (request, ...args) =>
122
+ runWithRequestEnv(requestEnv(request), async () => handler(request, ...args))
123
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Auto-wire request-scoped `searchParams()` for Hono SSR (spec/router.md "The
3
+ * wedge", v0.5).
4
+ *
5
+ * `@barefootjs/client`'s `searchParams()` is environment-neutral: on the server
6
+ * it asks for the current request's query string through a reader seam. Hono
7
+ * exposes the active request via `useRequestContext()` (async-context scoped),
8
+ * so the reader resolves **per request** with no shared mutable state to race.
9
+ *
10
+ * We publish the reader on the keyed `globalThis.__bf_serverEnvReader` seam —
11
+ * the server-side analogue of the client's `window.__bf_*` seams — rather than
12
+ * importing `@barefootjs/client`. SSR templates resolve the `@barefootjs/client`
13
+ * specifier through the adapter's shim, so this infrastructure module stays
14
+ * decoupled from the client package while still wiring it. This module is
15
+ * imported for its side effect by `app.ts`, so any Hono SSR app that renders
16
+ * the BarefootJS scripts gets request-scoped `searchParams()` with no opt-in.
17
+ *
18
+ * The reader is keyed by env id, so one seam serves every env signal
19
+ * (`searchParams()` via `'search'` today; cookies, … later). Unknown keys
20
+ * return `undefined` to defer to the empty default.
21
+ */
22
+
23
+ import { useRequestContext } from 'hono/jsx-renderer'
24
+
25
+ /** Extract the query string (including leading `?`, or `''`) from a request URL. */
26
+ export function searchFromRequestUrl(url: string): string {
27
+ try {
28
+ return new URL(url).search
29
+ } catch {
30
+ return ''
31
+ }
32
+ }
33
+
34
+ ;(
35
+ globalThis as unknown as { __bf_serverEnvReader?: (key: string) => string | undefined }
36
+ ).__bf_serverEnvReader = (key) => {
37
+ if (key !== 'search') return undefined
38
+ try {
39
+ return searchFromRequestUrl(useRequestContext().req.url)
40
+ } catch {
41
+ // No active request context (e.g. a non-request render) — defer to default.
42
+ return undefined
43
+ }
44
+ }
@@ -143,11 +143,10 @@ export async function renderHonoComponent(options: RenderOptions): Promise<strin
143
143
  childModuleWrites.push({ path: tempPath, content: readFileSync(modPath, 'utf8') })
144
144
  }
145
145
 
146
- let parentCode = templateFile.content
147
146
  // Resolve each child import: re-anchor to a pre-compiled module's temp
148
147
  // copy (`moduleTempPaths`), strip it (inlined via `components`), or
149
- // leave it. Both maps key on the import specifier; match the parent's
150
- // import path with or without a `.tsx` extension (`./badge` ↔
148
+ // leave it. Both maps key on the import specifier; match the importing
149
+ // module's path with or without a `.tsx` extension (`./badge` ↔
151
150
  // `./badge.tsx`).
152
151
  //
153
152
  // Assumes one import statement per line — the marked-template adapter
@@ -155,7 +154,8 @@ export async function renderHonoComponent(options: RenderOptions): Promise<strin
155
154
  // per-line scan is sufficient. A multi-line import would not match
156
155
  // here; the unrewritten `../slot` then fails loudly at module
157
156
  // resolution rather than rendering wrong output.
158
- if (componentKeys.size > 0 || moduleTempPaths.size > 0) {
157
+ const rewriteChildImports = (code: string): string => {
158
+ if (componentKeys.size === 0 && moduleTempPaths.size === 0) return code
159
159
  const matchKey = (importPath: string, keys: Iterable<string>): string | undefined => {
160
160
  for (const key of keys) {
161
161
  const keyWithoutExt = key.replace(/\.tsx?$/, '')
@@ -163,7 +163,7 @@ export async function renderHonoComponent(options: RenderOptions): Promise<strin
163
163
  }
164
164
  return undefined
165
165
  }
166
- parentCode = parentCode
166
+ return code
167
167
  .split('\n')
168
168
  .map(line => {
169
169
  const importMatch = line.match(/^(\s*import\s+.*from\s+['"])(.+?)(['"].*)$/)
@@ -178,6 +178,18 @@ export async function renderHonoComponent(options: RenderOptions): Promise<strin
178
178
  .join('\n')
179
179
  }
180
180
 
181
+ const parentCode = rewriteChildImports(templateFile.content)
182
+ // Pre-compiled child modules may themselves import other pre-compiled
183
+ // siblings (#1467 Phase 2c: the demo root's `accordion` sibling imports
184
+ // `../icon`). Their committed copies keep the source specifier, which
185
+ // doesn't resolve from the temp dir — re-anchor through the same map so
186
+ // nested sibling imports land on their own temp copies. `moduleTempPaths`
187
+ // is fully populated before any content is rewritten, so ordering
188
+ // between siblings doesn't matter.
189
+ for (const write of childModuleWrites) {
190
+ write.content = rewriteChildImports(write.content)
191
+ }
192
+
181
193
  // Combine: JSX pragma + child compiled functions + parent compiled code
182
194
  const codeParts = ['/** @jsxImportSource hono/jsx */']
183
195
  for (const childCode of childCodes) {