hono 4.12.26 → 4.12.28
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/adapter/aws-lambda/handler.js +10 -18
- package/dist/adapter/bun/websocket.js +3 -1
- package/dist/cjs/adapter/aws-lambda/handler.js +10 -18
- package/dist/cjs/adapter/bun/websocket.js +3 -1
- package/dist/cjs/helper/css/common.js +3 -1
- package/dist/cjs/helper/css/index.js +9 -1
- package/dist/cjs/jsx/base.js +8 -14
- package/dist/cjs/jsx/components.js +41 -21
- package/dist/cjs/jsx/context.js +131 -5
- package/dist/cjs/jsx/streaming.js +9 -7
- package/dist/cjs/middleware/serve-static/index.js +1 -1
- package/dist/cjs/utils/body.js +12 -4
- package/dist/cjs/utils/buffer.js +2 -1
- package/dist/cjs/validator/validator.js +3 -3
- package/dist/helper/css/common.js +3 -1
- package/dist/helper/css/index.js +9 -1
- package/dist/jsx/base.js +15 -15
- package/dist/jsx/components.js +42 -22
- package/dist/jsx/context.js +129 -5
- package/dist/jsx/streaming.js +10 -8
- package/dist/middleware/serve-static/index.js +1 -1
- package/dist/types/jsx/base.d.ts +1 -3
- package/dist/types/jsx/context.d.ts +39 -0
- package/dist/types/middleware/context-storage/index.d.ts +2 -2
- package/dist/types/utils/body.d.ts +1 -1
- package/dist/utils/body.js +12 -4
- package/dist/utils/buffer.js +2 -1
- package/dist/validator/validator.js +3 -3
- package/package.json +8 -7
- package/dist/tsconfig.build.tsbuildinfo +0 -1
package/dist/jsx/base.js
CHANGED
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
import { raw } from "../helper/html/index.js";
|
|
3
3
|
import { escapeToBuffer, resolveCallbackSync, stringBufferToString } from "../utils/html.js";
|
|
4
4
|
import { DOM_RENDERER, DOM_MEMO } from "./constants.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
captureRenderContext,
|
|
7
|
+
createContext,
|
|
8
|
+
globalContexts,
|
|
9
|
+
runWithRenderContext,
|
|
10
|
+
useContext
|
|
11
|
+
} from "./context.js";
|
|
6
12
|
import { domRenderers } from "./intrinsic-element/common.js";
|
|
7
13
|
import * as intrinsicElementTags from "./intrinsic-element/components.js";
|
|
8
14
|
import {
|
|
@@ -88,7 +94,7 @@ var JSXNode = class {
|
|
|
88
94
|
key;
|
|
89
95
|
children;
|
|
90
96
|
isEscaped = true;
|
|
91
|
-
|
|
97
|
+
suspendedContext;
|
|
92
98
|
constructor(tag, props, children) {
|
|
93
99
|
if (typeof tag !== "function" && !isValidTagName(tag)) {
|
|
94
100
|
throw new Error(`Invalid JSX tag name: ${tag}`);
|
|
@@ -106,18 +112,12 @@ var JSXNode = class {
|
|
|
106
112
|
return this.props.ref || null;
|
|
107
113
|
}
|
|
108
114
|
toString() {
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
context.values.push(value);
|
|
112
|
-
});
|
|
113
|
-
try {
|
|
115
|
+
const render = () => {
|
|
116
|
+
const buffer = [""];
|
|
114
117
|
this.toStringToBuffer(buffer);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
return buffer.length === 1 ? "callbacks" in buffer ? resolveCallbackSync(raw(buffer[0], buffer.callbacks)).toString() : buffer[0] : stringBufferToString(buffer, buffer.callbacks);
|
|
118
|
+
return buffer.length === 1 ? "callbacks" in buffer ? resolveCallbackSync(raw(buffer[0], buffer.callbacks)).toString() : buffer[0] : stringBufferToString(buffer, buffer.callbacks);
|
|
119
|
+
};
|
|
120
|
+
return this.suspendedContext ? this.suspendedContext(render) : runWithRenderContext(render);
|
|
121
121
|
}
|
|
122
122
|
toStringToBuffer(buffer) {
|
|
123
123
|
const tag = this.tag;
|
|
@@ -193,12 +193,12 @@ var JSXFunctionNode = class extends JSXNode {
|
|
|
193
193
|
if (globalContexts.length === 0) {
|
|
194
194
|
buffer.unshift("", res);
|
|
195
195
|
} else {
|
|
196
|
-
const
|
|
196
|
+
const suspendedContext = captureRenderContext();
|
|
197
197
|
buffer.unshift(
|
|
198
198
|
"",
|
|
199
199
|
res.then((childRes) => {
|
|
200
200
|
if (childRes instanceof JSXNode) {
|
|
201
|
-
childRes.
|
|
201
|
+
childRes.suspendedContext = suspendedContext;
|
|
202
202
|
}
|
|
203
203
|
return childRes;
|
|
204
204
|
})
|
package/dist/jsx/components.js
CHANGED
|
@@ -3,7 +3,7 @@ import { raw } from "../helper/html/index.js";
|
|
|
3
3
|
import { HtmlEscapedCallbackPhase, resolveCallback } from "../utils/html.js";
|
|
4
4
|
import { jsx, Fragment } from "./base.js";
|
|
5
5
|
import { DOM_RENDERER } from "./constants.js";
|
|
6
|
-
import { useContext } from "./context.js";
|
|
6
|
+
import { captureRenderContext, useContext } from "./context.js";
|
|
7
7
|
import { ErrorBoundary as ErrorBoundaryDomRenderer } from "./dom/components.js";
|
|
8
8
|
import { StreamingContext } from "./streaming.js";
|
|
9
9
|
var errorBoundaryCounter = 0;
|
|
@@ -12,8 +12,9 @@ var childrenToString = async (children) => {
|
|
|
12
12
|
return children.flat().map((c) => c == null || typeof c === "boolean" ? "" : c.toString());
|
|
13
13
|
} catch (e) {
|
|
14
14
|
if (e instanceof Promise) {
|
|
15
|
+
const resume = captureRenderContext();
|
|
15
16
|
await e;
|
|
16
|
-
return childrenToString(children);
|
|
17
|
+
return resume(() => childrenToString(children));
|
|
17
18
|
} else {
|
|
18
19
|
throw e;
|
|
19
20
|
}
|
|
@@ -41,51 +42,68 @@ var ErrorBoundary = async ({ children, fallback, fallbackRender, onError }) => {
|
|
|
41
42
|
children = [children];
|
|
42
43
|
}
|
|
43
44
|
const nonce = useContext(StreamingContext)?.scriptNonce;
|
|
44
|
-
let
|
|
45
|
-
const
|
|
45
|
+
let resume;
|
|
46
|
+
const getResume = () => resume ||= captureRenderContext();
|
|
47
|
+
let fallbackStrPromise;
|
|
48
|
+
const resolveFallbackStr = () => fallbackStrPromise ||= (async () => {
|
|
46
49
|
const awaitedFallback = await fallback;
|
|
47
50
|
if (typeof awaitedFallback === "string") {
|
|
48
|
-
|
|
51
|
+
return awaitedFallback;
|
|
49
52
|
} else {
|
|
50
|
-
|
|
51
|
-
if (typeof
|
|
52
|
-
|
|
53
|
+
const fallbackResult = await getResume()(() => awaitedFallback?.toString());
|
|
54
|
+
if (typeof fallbackResult === "string") {
|
|
55
|
+
return raw(
|
|
56
|
+
fallbackResult,
|
|
57
|
+
fallbackResult.callbacks || awaitedFallback?.callbacks
|
|
58
|
+
);
|
|
53
59
|
}
|
|
54
60
|
}
|
|
55
|
-
};
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
return
|
|
61
|
+
})();
|
|
62
|
+
const renderFallback = async (error) => {
|
|
63
|
+
const fallbackStr = await resolveFallbackStr();
|
|
64
|
+
return getResume()(async () => {
|
|
65
|
+
onError?.(error);
|
|
66
|
+
const fallbackRes = fallbackStr !== void 0 ? fallbackStr : fallbackRender && jsx(Fragment, {}, fallbackRender(error)) || "";
|
|
67
|
+
const fallbackResString = await Fragment({
|
|
68
|
+
children: fallbackRes
|
|
69
|
+
}).toString();
|
|
70
|
+
return raw(
|
|
71
|
+
fallbackResString,
|
|
72
|
+
fallbackResString.callbacks || fallbackRes.callbacks
|
|
73
|
+
);
|
|
74
|
+
});
|
|
59
75
|
};
|
|
60
76
|
let resArray = [];
|
|
61
77
|
try {
|
|
62
78
|
resArray = children.map(resolveChildEarly);
|
|
63
79
|
} catch (e) {
|
|
64
|
-
|
|
80
|
+
const resume2 = getResume();
|
|
65
81
|
if (e instanceof Promise) {
|
|
66
82
|
resArray = [
|
|
67
|
-
e.then(() => childrenToString(children)).catch((e2) =>
|
|
83
|
+
e.then(() => resume2(() => childrenToString(children))).catch((e2) => renderFallback(e2))
|
|
68
84
|
];
|
|
69
85
|
} else {
|
|
70
|
-
resArray = [
|
|
86
|
+
resArray = [await renderFallback(e)];
|
|
71
87
|
}
|
|
72
88
|
}
|
|
73
89
|
if (resArray.some((res) => res instanceof Promise)) {
|
|
74
|
-
|
|
90
|
+
getResume();
|
|
75
91
|
const index = errorBoundaryCounter++;
|
|
76
92
|
const replaceRe = RegExp(`(<template id="E:${index}"></template>.*?)(.*?)(<!--E:${index}-->)`);
|
|
77
|
-
|
|
93
|
+
let caught = false;
|
|
78
94
|
const catchCallback = async ({ error: error2, buffer }) => {
|
|
79
95
|
if (caught) {
|
|
80
96
|
return "";
|
|
81
97
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
98
|
+
caught = true;
|
|
99
|
+
const fallbackResString = await renderFallback(error2);
|
|
100
|
+
const fallbackCallbacks = fallbackResString.callbacks;
|
|
85
101
|
if (buffer) {
|
|
86
102
|
buffer[0] = buffer[0].replace(replaceRe, fallbackResString);
|
|
103
|
+
return fallbackCallbacks?.length ? raw("", fallbackCallbacks) : "";
|
|
87
104
|
}
|
|
88
|
-
return
|
|
105
|
+
return raw(
|
|
106
|
+
`<template data-hono-target="E:${index}">${fallbackResString}</template><script>
|
|
89
107
|
((d,c,n) => {
|
|
90
108
|
c=d.currentScript.previousSibling
|
|
91
109
|
d=d.getElementById('E:${index}')
|
|
@@ -93,7 +111,9 @@ if(!d)return
|
|
|
93
111
|
do{n=d.nextSibling;n.remove()}while(n.nodeType!=8||n.nodeValue!='E:${index}')
|
|
94
112
|
d.replaceWith(c.content)
|
|
95
113
|
})(document)
|
|
96
|
-
</script
|
|
114
|
+
</script>`,
|
|
115
|
+
fallbackCallbacks
|
|
116
|
+
);
|
|
97
117
|
};
|
|
98
118
|
let error;
|
|
99
119
|
const promiseAll = Promise.all(resArray).catch((e) => error = e);
|
package/dist/jsx/context.js
CHANGED
|
@@ -4,21 +4,143 @@ import { JSXFragmentNode } from "./base.js";
|
|
|
4
4
|
import { DOM_RENDERER } from "./constants.js";
|
|
5
5
|
import { createContextProviderFunction } from "./dom/context.js";
|
|
6
6
|
var globalContexts = [];
|
|
7
|
+
var alsProbed = false;
|
|
8
|
+
var asyncLocalStorage;
|
|
9
|
+
var fallbackStore;
|
|
10
|
+
var fallbackRendersInFlight = 0;
|
|
11
|
+
var warnedFallbackDefault = false;
|
|
12
|
+
var loadAsyncLocalStorage = () => {
|
|
13
|
+
if (alsProbed) {
|
|
14
|
+
return asyncLocalStorage;
|
|
15
|
+
}
|
|
16
|
+
alsProbed = true;
|
|
17
|
+
const global = globalThis;
|
|
18
|
+
let AsyncLocalStorage;
|
|
19
|
+
for (const probe of [
|
|
20
|
+
// Node.js >= 20.16, Deno, Bun, Cloudflare Workers (nodejs_compat). Property
|
|
21
|
+
// access only, so bundlers don't statically resolve `node:async_hooks`.
|
|
22
|
+
() => global.process?.getBuiltinModule?.("node:async_hooks")?.AsyncLocalStorage,
|
|
23
|
+
// Node.js < 20.16 has no `process.getBuiltinModule`, but a CJS entrypoint
|
|
24
|
+
// exposes the main module's `require` here.
|
|
25
|
+
() => global.process?.mainModule?.require?.("node:async_hooks")?.AsyncLocalStorage
|
|
26
|
+
]) {
|
|
27
|
+
try {
|
|
28
|
+
AsyncLocalStorage = probe();
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
if (AsyncLocalStorage) {
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (AsyncLocalStorage) {
|
|
36
|
+
asyncLocalStorage = new AsyncLocalStorage();
|
|
37
|
+
}
|
|
38
|
+
return asyncLocalStorage;
|
|
39
|
+
};
|
|
40
|
+
var getCurrentStore = () => {
|
|
41
|
+
return loadAsyncLocalStorage()?.getStore() || fallbackStore;
|
|
42
|
+
};
|
|
43
|
+
var warnIfStorelessAccess = () => {
|
|
44
|
+
if (fallbackRendersInFlight > 0 && !warnedFallbackDefault) {
|
|
45
|
+
warnedFallbackDefault = true;
|
|
46
|
+
console.warn(
|
|
47
|
+
"hono/jsx: AsyncLocalStorage is unavailable in this runtime, so useContext() after an await in an async component falls back to the context default value during server-side rendering. To get provided values across await boundaries, use a runtime with AsyncLocalStorage (Node.js >= 20.16, Deno, Bun, or Cloudflare Workers with the nodejs_compat flag)."
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var getContextValuesIn = (store, context) => {
|
|
52
|
+
if (!store) {
|
|
53
|
+
warnIfStorelessAccess();
|
|
54
|
+
return context.values;
|
|
55
|
+
}
|
|
56
|
+
let values = store.get(context);
|
|
57
|
+
if (!values) {
|
|
58
|
+
values = [context.values[0]];
|
|
59
|
+
store.set(context, values);
|
|
60
|
+
}
|
|
61
|
+
return values;
|
|
62
|
+
};
|
|
63
|
+
var readContextValueIn = (store, context) => {
|
|
64
|
+
if (!store) {
|
|
65
|
+
warnIfStorelessAccess();
|
|
66
|
+
return context.values.at(-1);
|
|
67
|
+
}
|
|
68
|
+
const values = store.get(context);
|
|
69
|
+
return values?.length ? values.at(-1) : context.values[0];
|
|
70
|
+
};
|
|
71
|
+
var captureContextValues = (store) => (store ? globalContexts.filter((c) => store.has(c)) : globalContexts).map((c) => [
|
|
72
|
+
c,
|
|
73
|
+
readContextValueIn(store, c)
|
|
74
|
+
]);
|
|
75
|
+
var resumeWithContextValues = (callback, store, contexts) => runWithRenderContext(() => {
|
|
76
|
+
const currentStore = getCurrentStore();
|
|
77
|
+
const valuesPerContext = contexts.map(([context, value]) => {
|
|
78
|
+
const values = getContextValuesIn(currentStore, context);
|
|
79
|
+
values.push(value);
|
|
80
|
+
return values;
|
|
81
|
+
});
|
|
82
|
+
const popContextValues = () => {
|
|
83
|
+
valuesPerContext.forEach((values) => {
|
|
84
|
+
values.pop();
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
try {
|
|
88
|
+
const result = callback();
|
|
89
|
+
if (result instanceof Promise) {
|
|
90
|
+
return result.finally(popContextValues);
|
|
91
|
+
}
|
|
92
|
+
popContextValues();
|
|
93
|
+
return result;
|
|
94
|
+
} catch (e) {
|
|
95
|
+
popContextValues();
|
|
96
|
+
throw e;
|
|
97
|
+
}
|
|
98
|
+
}, store);
|
|
99
|
+
var runWithRenderContext = (callback, resumeStore) => {
|
|
100
|
+
if (getCurrentStore()) {
|
|
101
|
+
return callback();
|
|
102
|
+
}
|
|
103
|
+
const store = resumeStore ?? /* @__PURE__ */ new WeakMap();
|
|
104
|
+
const storage = loadAsyncLocalStorage();
|
|
105
|
+
if (storage) {
|
|
106
|
+
return storage.run(store, callback);
|
|
107
|
+
}
|
|
108
|
+
fallbackStore = store;
|
|
109
|
+
let result;
|
|
110
|
+
try {
|
|
111
|
+
result = callback();
|
|
112
|
+
} finally {
|
|
113
|
+
fallbackStore = void 0;
|
|
114
|
+
}
|
|
115
|
+
if (!warnedFallbackDefault && result instanceof Promise) {
|
|
116
|
+
fallbackRendersInFlight++;
|
|
117
|
+
result = result.finally(() => {
|
|
118
|
+
fallbackRendersInFlight--;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
122
|
+
};
|
|
123
|
+
var captureRenderContext = () => {
|
|
124
|
+
const store = getCurrentStore();
|
|
125
|
+
const contexts = captureContextValues(store);
|
|
126
|
+
return (callback) => resumeWithContextValues(callback, store, contexts);
|
|
127
|
+
};
|
|
7
128
|
var createContext = (defaultValue) => {
|
|
8
129
|
const values = [defaultValue];
|
|
9
130
|
const context = ((props) => {
|
|
10
|
-
|
|
131
|
+
const contextValues = getContextValuesIn(getCurrentStore(), context);
|
|
132
|
+
contextValues.push(props.value);
|
|
11
133
|
let string;
|
|
12
134
|
try {
|
|
13
135
|
string = props.children ? (Array.isArray(props.children) ? new JSXFragmentNode("", {}, props.children) : props.children).toString() : "";
|
|
14
136
|
} catch (e) {
|
|
15
|
-
|
|
137
|
+
contextValues.pop();
|
|
16
138
|
throw e;
|
|
17
139
|
}
|
|
18
140
|
if (string instanceof Promise) {
|
|
19
|
-
return string.finally(() =>
|
|
141
|
+
return string.finally(() => contextValues.pop()).then((resString) => raw(resString, resString.callbacks));
|
|
20
142
|
} else {
|
|
21
|
-
|
|
143
|
+
contextValues.pop();
|
|
22
144
|
return raw(string);
|
|
23
145
|
}
|
|
24
146
|
});
|
|
@@ -29,10 +151,12 @@ var createContext = (defaultValue) => {
|
|
|
29
151
|
return context;
|
|
30
152
|
};
|
|
31
153
|
var useContext = (context) => {
|
|
32
|
-
return
|
|
154
|
+
return readContextValueIn(getCurrentStore(), context);
|
|
33
155
|
};
|
|
34
156
|
export {
|
|
157
|
+
captureRenderContext,
|
|
35
158
|
createContext,
|
|
36
159
|
globalContexts,
|
|
160
|
+
runWithRenderContext,
|
|
37
161
|
useContext
|
|
38
162
|
};
|
package/dist/jsx/streaming.js
CHANGED
|
@@ -4,7 +4,7 @@ import { HtmlEscapedCallbackPhase, resolveCallback } from "../utils/html.js";
|
|
|
4
4
|
import { JSXNode } from "./base.js";
|
|
5
5
|
import { childrenToString } from "./components.js";
|
|
6
6
|
import { DOM_RENDERER, DOM_STASH } from "./constants.js";
|
|
7
|
-
import { createContext, useContext } from "./context.js";
|
|
7
|
+
import { captureRenderContext, createContext, useContext } from "./context.js";
|
|
8
8
|
import { Suspense as SuspenseDomRenderer } from "./dom/components.js";
|
|
9
9
|
import { buildDataStack } from "./dom/render.js";
|
|
10
10
|
var StreamingContext = createContext(null);
|
|
@@ -19,9 +19,8 @@ var Suspense = async ({
|
|
|
19
19
|
const nonce = useContext(StreamingContext)?.scriptNonce;
|
|
20
20
|
let resArray = [];
|
|
21
21
|
const stackNode = { [DOM_STASH]: [0, []] };
|
|
22
|
-
const popNodeStack = (
|
|
22
|
+
const popNodeStack = () => {
|
|
23
23
|
buildDataStack.pop();
|
|
24
|
-
return value;
|
|
25
24
|
};
|
|
26
25
|
try {
|
|
27
26
|
stackNode[DOM_STASH][0] = 0;
|
|
@@ -31,12 +30,15 @@ var Suspense = async ({
|
|
|
31
30
|
);
|
|
32
31
|
} catch (e) {
|
|
33
32
|
if (e instanceof Promise) {
|
|
33
|
+
const resume = captureRenderContext();
|
|
34
34
|
resArray = [
|
|
35
|
-
e.then(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
e.then(
|
|
36
|
+
() => resume(() => {
|
|
37
|
+
stackNode[DOM_STASH][0] = 0;
|
|
38
|
+
buildDataStack.push([[], stackNode]);
|
|
39
|
+
return childrenToString(children).finally(popNodeStack);
|
|
40
|
+
})
|
|
41
|
+
)
|
|
40
42
|
];
|
|
41
43
|
} else {
|
|
42
44
|
throw e;
|
|
@@ -44,7 +44,7 @@ var serveStatic = (options) => {
|
|
|
44
44
|
if (content instanceof Response) {
|
|
45
45
|
return c.newResponse(content.body, content);
|
|
46
46
|
}
|
|
47
|
-
if (content) {
|
|
47
|
+
if (content != null) {
|
|
48
48
|
const mimeType = options.mimes && getMimeType(path, options.mimes) || getMimeType(path);
|
|
49
49
|
c.header("Content-Type", mimeType || "application/octet-stream");
|
|
50
50
|
if (options.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) {
|
package/dist/types/jsx/base.d.ts
CHANGED
|
@@ -23,7 +23,6 @@ export declare namespace JSX {
|
|
|
23
23
|
}
|
|
24
24
|
export declare const getNameSpaceContext: () => Context<string> | undefined;
|
|
25
25
|
export declare const booleanAttributes: string[];
|
|
26
|
-
type LocalContexts = [Context<unknown>, unknown][];
|
|
27
26
|
export type Child = string | Promise<string> | number | JSXNode | null | undefined | boolean | Child[];
|
|
28
27
|
export declare class JSXNode implements HtmlEscaped {
|
|
29
28
|
tag: string | Function;
|
|
@@ -31,7 +30,7 @@ export declare class JSXNode implements HtmlEscaped {
|
|
|
31
30
|
key?: string;
|
|
32
31
|
children: Child[];
|
|
33
32
|
isEscaped: true;
|
|
34
|
-
|
|
33
|
+
suspendedContext?: <T>(callback: () => T) => T;
|
|
35
34
|
constructor(tag: string | Function, props: Props, children: Child[]);
|
|
36
35
|
get type(): string | Function;
|
|
37
36
|
get ref(): any;
|
|
@@ -55,4 +54,3 @@ export declare const Fragment: ({ children, }: {
|
|
|
55
54
|
export declare const isValidElement: (element: unknown) => element is JSXNode;
|
|
56
55
|
export declare const cloneElement: <T extends JSXNode | JSX.Element>(element: T, props: Partial<Props>, ...children: Child[]) => T;
|
|
57
56
|
export declare const reactAPICompatVersion = "19.0.0-hono-jsx";
|
|
58
|
-
export {};
|
|
@@ -8,5 +8,44 @@ export interface Context<T> extends FC<PropsWithChildren<{
|
|
|
8
8
|
}>>;
|
|
9
9
|
}
|
|
10
10
|
export declare const globalContexts: Context<unknown>[];
|
|
11
|
+
/** Per-render context store, isolated per request so values never leak across renders. */
|
|
12
|
+
type RenderStore = WeakMap<Context<unknown>, unknown[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Establish the request-scoped context store for a render.
|
|
15
|
+
*
|
|
16
|
+
* `resumeStore` continues a suspended subtree in the same store on the fallback
|
|
17
|
+
* path (ignored when `AsyncLocalStorage` is available, where isolation is
|
|
18
|
+
* automatic).
|
|
19
|
+
*
|
|
20
|
+
* Without `AsyncLocalStorage` a render can't be followed across `await`, so the
|
|
21
|
+
* store lives in `fallbackStore` only during synchronous work (mirroring
|
|
22
|
+
* React's request storage). Reading context after `await` then finds no store
|
|
23
|
+
* and falls back to the default value — never another request's value.
|
|
24
|
+
*/
|
|
25
|
+
export declare const runWithRenderContext: <T>(callback: () => T, resumeStore?: RenderStore) => T;
|
|
26
|
+
/**
|
|
27
|
+
* Capture the current render store and return a resumer that re-establishes it
|
|
28
|
+
* around a deferred continuation (e.g. a re-render after a suspended promise
|
|
29
|
+
* settles). Shared by every suspension point so none reimplements it.
|
|
30
|
+
*/
|
|
31
|
+
export declare const captureRenderContext: () => (<T>(callback: () => T) => T);
|
|
32
|
+
/**
|
|
33
|
+
* Create a context whose value can be provided with `<Context.Provider>` and
|
|
34
|
+
* read with {@link useContext}.
|
|
35
|
+
*
|
|
36
|
+
* Server-side renders are isolated per request, so a provided value never leaks
|
|
37
|
+
* into a concurrent request — even across `await` in an async component, when
|
|
38
|
+
* `AsyncLocalStorage` is available (Node.js >= 20.16, Deno, Bun, Cloudflare
|
|
39
|
+
* Workers with `nodejs_compat`). Without it, reading context after `await`
|
|
40
|
+
* returns the default value; synchronous components and `use()`-based
|
|
41
|
+
* suspension are unaffected.
|
|
42
|
+
*/
|
|
11
43
|
export declare const createContext: <T>(defaultValue: T) => Context<T>;
|
|
44
|
+
/**
|
|
45
|
+
* Read the current value of a context created with {@link createContext}.
|
|
46
|
+
*
|
|
47
|
+
* Safe to call from async components after `await`. See {@link createContext}
|
|
48
|
+
* for the per-runtime isolation guarantees.
|
|
49
|
+
*/
|
|
12
50
|
export declare const useContext: <T>(context: Context<T>) => T;
|
|
51
|
+
export {};
|
|
@@ -24,11 +24,11 @@ import type { Env, MiddlewareHandler } from '../../types';
|
|
|
24
24
|
* app.use(contextStorage())
|
|
25
25
|
*
|
|
26
26
|
* app.use(async (c, next) => {
|
|
27
|
-
* c.set('message', 'Hono is hot!!)
|
|
27
|
+
* c.set('message', 'Hono is hot!!')
|
|
28
28
|
* await next()
|
|
29
29
|
* })
|
|
30
30
|
*
|
|
31
|
-
* app.get('/', async (c) =>
|
|
31
|
+
* app.get('/', async (c) => c.text(getMessage()))
|
|
32
32
|
*
|
|
33
33
|
* const getMessage = () => {
|
|
34
34
|
* return getContext<Env>().var.message
|
package/dist/utils/body.js
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
// src/utils/body.ts
|
|
2
|
-
import {
|
|
2
|
+
import { bufferToFormData } from "./buffer.js";
|
|
3
|
+
var isRawRequest = (request) => "headers" in request;
|
|
3
4
|
var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
|
|
4
5
|
const { all = false, dot = false } = options;
|
|
5
|
-
const headers = request
|
|
6
|
+
const headers = isRawRequest(request) ? request.headers : request.raw.headers;
|
|
6
7
|
const contentType = headers.get("Content-Type");
|
|
7
|
-
|
|
8
|
+
const mediaType = contentType?.split(";")[0].trim().toLowerCase();
|
|
9
|
+
if (mediaType === "multipart/form-data" || mediaType === "application/x-www-form-urlencoded") {
|
|
8
10
|
return parseFormData(request, { all, dot });
|
|
9
11
|
}
|
|
10
12
|
return {};
|
|
11
13
|
};
|
|
12
14
|
async function parseFormData(request, options) {
|
|
13
|
-
const
|
|
15
|
+
const headers = isRawRequest(request) ? request.headers : request.raw.headers;
|
|
16
|
+
const arrayBuffer = await request.arrayBuffer();
|
|
17
|
+
const formDataPromise = bufferToFormData(arrayBuffer, headers.get("Content-Type") || "");
|
|
18
|
+
if (!isRawRequest(request)) {
|
|
19
|
+
request.bodyCache.formData = formDataPromise;
|
|
20
|
+
}
|
|
21
|
+
const formData = await formDataPromise;
|
|
14
22
|
if (formData) {
|
|
15
23
|
return convertFormDataToBodyData(formData, options);
|
|
16
24
|
}
|
package/dist/utils/buffer.js
CHANGED
|
@@ -64,7 +64,8 @@ var bufferToString = (buffer) => {
|
|
|
64
64
|
var bufferToFormData = (arrayBuffer, contentType) => {
|
|
65
65
|
const response = new Response(arrayBuffer, {
|
|
66
66
|
headers: {
|
|
67
|
-
|
|
67
|
+
// Normalize the media type (case-insensitive) while keeping parameters like the boundary
|
|
68
|
+
"Content-Type": contentType.replace(/^[^;]+/, (mediaType) => mediaType.toLowerCase())
|
|
68
69
|
}
|
|
69
70
|
});
|
|
70
71
|
return response.formData();
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { getCookie } from "../helper/cookie/index.js";
|
|
3
3
|
import { HTTPException } from "../http-exception.js";
|
|
4
4
|
import { bufferToFormData } from "../utils/buffer.js";
|
|
5
|
-
var jsonRegex = /^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))
|
|
6
|
-
var multipartRegex = /^multipart\/form-data(;\s?boundary=[a-zA-Z0-9'"()+_,\-./:=?]+)
|
|
7
|
-
var urlencodedRegex = /^application\/x-www-form-urlencoded(;\s*[a-zA-Z0-9\-]+\=([^;]+))
|
|
5
|
+
var jsonRegex = /^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/i;
|
|
6
|
+
var multipartRegex = /^multipart\/form-data(;\s?boundary=[a-zA-Z0-9'"()+_,\-./:=?]+)?$/i;
|
|
7
|
+
var urlencodedRegex = /^application\/x-www-form-urlencoded(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/i;
|
|
8
8
|
var validator = (target, validationFunc) => {
|
|
9
9
|
return async (c, next) => {
|
|
10
10
|
let value = {};
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono",
|
|
3
|
-
"version": "4.12.
|
|
3
|
+
"version": "4.12.28",
|
|
4
4
|
"description": "Web framework built on Web Standards",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"module": "dist/index.js",
|
|
8
8
|
"types": "dist/types/index.d.ts",
|
|
9
9
|
"files": [
|
|
10
|
-
"dist"
|
|
10
|
+
"dist",
|
|
11
|
+
"!dist/**/*.tsbuildinfo"
|
|
11
12
|
],
|
|
12
13
|
"scripts": {
|
|
13
14
|
"test": "tsc --noEmit && vitest --run",
|
|
@@ -678,17 +679,17 @@
|
|
|
678
679
|
"eslint": "^9.39.3",
|
|
679
680
|
"jsdom": "22.1.0",
|
|
680
681
|
"msw": "^2.6.0",
|
|
681
|
-
"np": "
|
|
682
|
+
"np": "11.2.1",
|
|
682
683
|
"oxc-parser": "^0.96.0",
|
|
683
684
|
"pkg-pr-new": "^0.0.53",
|
|
684
685
|
"prettier": "3.7.4",
|
|
685
686
|
"publint": "0.3.15",
|
|
686
687
|
"typescript": "^5.9.2",
|
|
687
|
-
"undici": "^6.
|
|
688
|
+
"undici": "^6.27.0",
|
|
688
689
|
"vite-plugin-fastly-js-compute": "^0.4.2",
|
|
689
|
-
"vitest": "^4.1.
|
|
690
|
-
"wrangler": "4.
|
|
691
|
-
"ws": "^8.
|
|
690
|
+
"vitest": "^4.1.9",
|
|
691
|
+
"wrangler": "4.107.0",
|
|
692
|
+
"ws": "^8.21.0",
|
|
692
693
|
"zod": "^3.23.8"
|
|
693
694
|
},
|
|
694
695
|
"packageManager": "bun@1.2.20",
|