Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: honojs/hono
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v4.0.7
Choose a base ref
...
head repository: honojs/hono
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v4.0.8
Choose a head ref
  • 7 commits
  • 13 files changed
  • 7 contributors

Commits on Feb 25, 2024

  1. fix(ssg): allow app: Hono<any, any, any> for toSSG (#2272)

    * fix(ssg): allow `app: Hono<any, any, any>` for `toSSG`
    
    * denoify
    yusukebe authored Feb 25, 2024
    Copy the full SHA
    a32482d View commit details

Commits on Feb 26, 2024

  1. fix(ssg): preserve binary files as-is (#2275)

    * fix(ssg): preserve binary files as-is
    
    * denoify
    
    * test(ssg): cleanup
    
    * test(ssg): merge tests for the right content and paths
    berlysia authored Feb 26, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    d4db451 View commit details

Commits on Feb 27, 2024

  1. fix(types): fix comment (#2278)

    `c.jsonT` is removed
    nakasyou authored Feb 27, 2024
    Copy the full SHA
    d7b1fe8 View commit details
  2. fix(sse): Handler stuck when awaiting aborted SSE stream (#2273)

    * cancel internal stream reader on responseReadable abort
    
    * run denoify
    abhi12299 authored and yusukebe committed Feb 27, 2024
    Copy the full SHA
    a3d9f13 View commit details

Commits on Feb 28, 2024

  1. Copy the full SHA
    b4912f3 View commit details
  2. fix(devDependencies): Fix the problem of missing glob package (#2277)

    * fix(pnpm): Fix the problem of missing glob package caused by ghost dependency in pnpm
    
    * run `bun install`
    
    ---------
    
    Co-authored-by: yuanrang.peng <yuanrang.peng@tuya.com>
    Co-authored-by: Yusuke Wada <yusuke@kamawada.com>
    3 people authored Feb 28, 2024
    Copy the full SHA
    c9567b6 View commit details
  3. v4.0.8

    yusukebe committed Feb 28, 2024
    Copy the full SHA
    81264a9 View commit details
Binary file modified bun.lockb
Binary file not shown.
12 changes: 4 additions & 8 deletions deno_dist/helper/ssg/index.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@ import { replaceUrlParam } from '../../client/utils.ts'
import type { Context } from '../../context.ts'
import type { Hono } from '../../hono.ts'
import type { Env, MiddlewareHandler, Schema } from '../../types.ts'
import { bufferToString } from '../../utils/buffer.ts'
import { getExtension } from '../../utils/mime.ts'
import { joinPaths, dirname, filterStaticGenerateRoutes } from './utils.ts'

@@ -202,7 +201,7 @@ export const saveContentToFiles = async (
if (typeof content === 'string') {
await fsModule.writeFile(filePath, content)
} else if (content instanceof ArrayBuffer) {
await fsModule.writeFile(filePath, bufferToString(content))
await fsModule.writeFile(filePath, new Uint8Array(content))
}
files.push(filePath)
}
@@ -215,13 +214,10 @@ export const saveContentToFiles = async (
* `ToSSGInterface` is an experimental feature.
* The API might be changed.
*/
export interface ToSSGInterface<
E extends Env = Env,
S extends Schema = {},
BasePath extends string = '/'
> {
export interface ToSSGInterface {
(
app: Hono<E, S, BasePath>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
app: Hono<any, any, any>,
fsModule: FileSystemModule,
options?: ToSSGOptions
): Promise<ToSSGResult>
3 changes: 2 additions & 1 deletion deno_dist/jsx/jsx-runtime.ts
Original file line number Diff line number Diff line change
@@ -3,5 +3,6 @@ export { jsxDEV as jsxs } from './jsx-dev-runtime.ts'

import { raw, html } from '../helper/html/index.ts'
export { html as jsxTemplate }
export const jsxAttr = (name: string, value: string) => raw(name + '="' + html`${value}` + '"')
export const jsxAttr = (name: string, value: string | Promise<string>) =>
typeof value === 'string' ? raw(name + '="' + html`${value}` + '"') : html`${name}="${value}"`
export const jsxEscape = (value: string) => value
2 changes: 1 addition & 1 deletion deno_dist/types.ts
Original file line number Diff line number Diff line change
@@ -1671,7 +1671,7 @@ export type MergePath<A extends string, B extends string> = A extends ''

export type TypedResponse<T = unknown> = {
data: T
format: 'json' // Currently, support only `json` with `c.jsonT()`
format: 'json' // Currently, support only `json` with `c.json()`
}

type ExtractResponseData<T> = T extends Promise<infer T2>
7 changes: 7 additions & 0 deletions deno_dist/utils/stream.ts
Original file line number Diff line number Diff line change
@@ -12,6 +12,13 @@ export class StreamingApi {

const reader = _readable.getReader()

// in case the user disconnects, let the reader know to cancel
// this in-turn results in responseReadable being closed
// and writeSSE method no longer blocks indefinitely
this.abortSubscribers.push(async () => {
await reader.cancel()
})

this.responseReadable = new ReadableStream({
async pull(controller) {
const { done, value } = await reader.read()
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hono",
"version": "4.0.7",
"version": "4.0.8",
"description": "Ultrafast web framework for the Edges",
"main": "dist/cjs/index.js",
"type": "module",
@@ -520,6 +520,7 @@
"denoify": "^1.6.6",
"esbuild": "^0.15.12",
"eslint": "^8.55.0",
"glob": "7.2.3",
"jsdom": "^22.1.0",
"msw": "1.3.2",
"np": "7.7.0",
25 changes: 25 additions & 0 deletions runtime_tests/deno-jsx/jsx.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/** @jsxImportSource ../../deno_dist/jsx */
import { Style, css } from '../../deno_dist/helper/css/index.ts'
import { Suspense, renderToReadableStream } from '../../deno_dist/jsx/streaming.ts'
import type { HtmlEscapedString } from '../../deno_dist/utils/html.ts'
import { resolveCallback, HtmlEscapedCallbackPhase } from '../../deno_dist/utils/html.ts'
import { assertEquals } from '../deno/deps.ts'

Deno.test('JSX', () => {
@@ -79,3 +81,26 @@ d.replaceWith(c.content)
</script>`,
])
})

Deno.test('JSX: css', async () => {
const className = css`
color: red;
`
const html = (
<html>
<head>
<Style />
</head>
<body>
<div class={className}></div>
</body>
</html>
)

const awaitedHtml = await html
const htmlEscapedString = 'callbacks' in awaitedHtml ? awaitedHtml : await awaitedHtml.toString()
assertEquals(
await resolveCallback(htmlEscapedString, HtmlEscapedCallbackPhase.Stringify, false, {}),
'<html><head><style id="hono-css">.css-3142110215{color:red}</style></head><body><div class="css-3142110215"></div></body></html>'
)
})
44 changes: 42 additions & 2 deletions src/helper/ssg/index.test.tsx
Original file line number Diff line number Diff line change
@@ -285,6 +285,24 @@ describe('fetchRoutesContent function', () => {
describe('saveContentToFiles function', () => {
let fsMock: FileSystemModule
let htmlMap: Map<string, { content: string | ArrayBuffer; mimeType: string }>
// tar.gz, testdir/test.txt
const gzFileBuffer = Buffer.from(
'H4sIAAAAAAAAA+3SQQrCMBSE4aw9RU6gSc3LO0/FLgqukgj29qZgsQgqCEHE/9vMIoEMTMqQy3FMO9OQq1RkTq/i1rkwPkiMUXWvnXG+U/XGSstSi3MufbLWHIZ0mvLYP7v37vxHldv+c27LpbR4Yx44hvBi/3DfX3zdP0j9Eta1KPPoz/ef+mnz7Q4AAAAAAAAAAAAAAAAAPnMFqt1/BQAoAAA=',
'base64'
)
const gzFileArrayBuffer = gzFileBuffer.buffer.slice(
gzFileBuffer.byteOffset,
gzFileBuffer.byteLength + gzFileBuffer.byteOffset
)
// PNG, red dot (1x1)
const pngFileBuffer = Buffer.from(
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR4nGP4z8AAAAMBAQDJ/pLvAAAAAElFTkSuQmCCAAAALw',
'base64'
)
const pngFileArrayBuffer = pngFileBuffer.buffer.slice(
pngFileBuffer.byteOffset,
pngFileBuffer.byteLength + pngFileBuffer.byteOffset
)

beforeEach(() => {
fsMock = {
@@ -297,11 +315,24 @@ describe('saveContentToFiles function', () => {
['/about', { content: 'About Page', mimeType: 'text/html' }],
['/about/', { content: 'About Page', mimeType: 'text/html' }],
['/bravo/index.html', { content: 'About Page', mimeType: 'text/html' }],
['/bravo/index.tar.gz', { content: 'About Page', mimeType: 'application/gzip' }],
['/bravo/release-4.0.0', { content: 'Release 4.0.0', mimeType: 'text/html' }],
['/bravo/2024.02.18-sweet-memories', { content: 'Sweet Memories', mimeType: 'text/html' }],
['/bravo/deep.dive.to.html', { content: 'Deep Dive To HTML', mimeType: 'text/html' }],
['/bravo/alert.js', { content: 'alert("evil content")', mimeType: 'text/html' }],
[
'/bravo/index.tar.gz',
{
content: gzFileArrayBuffer,
mimeType: 'application/gzip',
},
],
[
'/bravo/dot.png',
{
content: pngFileArrayBuffer,
mimeType: 'image/png',
},
],
['/bravo.text/index.html', { content: 'About Page', mimeType: 'text/html' }],
['/bravo.text/', { content: 'Bravo Page', mimeType: 'text/html' }],
])
@@ -315,7 +346,6 @@ describe('saveContentToFiles function', () => {
expect(fsMock.writeFile).toHaveBeenCalledWith('static/about.html', 'About Page')
expect(fsMock.writeFile).toHaveBeenCalledWith('static/about/index.html', 'About Page')
expect(fsMock.writeFile).toHaveBeenCalledWith('static/bravo/index.html', 'About Page')
expect(fsMock.writeFile).toHaveBeenCalledWith('static/bravo/index.tar.gz', 'About Page')
expect(fsMock.writeFile).toHaveBeenCalledWith(
'static/bravo/release-4.0.0.html',
'Release 4.0.0'
@@ -334,6 +364,16 @@ describe('saveContentToFiles function', () => {
)
expect(fsMock.writeFile).toHaveBeenCalledWith('static/bravo.text/index.html', 'About Page')
expect(fsMock.writeFile).toHaveBeenCalledWith('static/bravo.text/index.html', 'Bravo Page')

// binary files
expect(fsMock.writeFile).toHaveBeenCalledWith(
'static/bravo/index.tar.gz',
new Uint8Array(gzFileArrayBuffer)
)
expect(fsMock.writeFile).toHaveBeenCalledWith(
'static/bravo/dot.png',
new Uint8Array(pngFileArrayBuffer)
)
})

it('should correctly create directories if they do not exist', async () => {
12 changes: 4 additions & 8 deletions src/helper/ssg/index.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@ import { replaceUrlParam } from '../../client/utils'
import type { Context } from '../../context'
import type { Hono } from '../../hono'
import type { Env, MiddlewareHandler, Schema } from '../../types'
import { bufferToString } from '../../utils/buffer'
import { getExtension } from '../../utils/mime'
import { joinPaths, dirname, filterStaticGenerateRoutes } from './utils'

@@ -202,7 +201,7 @@ export const saveContentToFiles = async (
if (typeof content === 'string') {
await fsModule.writeFile(filePath, content)
} else if (content instanceof ArrayBuffer) {
await fsModule.writeFile(filePath, bufferToString(content))
await fsModule.writeFile(filePath, new Uint8Array(content))
}
files.push(filePath)
}
@@ -215,13 +214,10 @@ export const saveContentToFiles = async (
* `ToSSGInterface` is an experimental feature.
* The API might be changed.
*/
export interface ToSSGInterface<
E extends Env = Env,
S extends Schema = {},
BasePath extends string = '/'
> {
export interface ToSSGInterface {
(
app: Hono<E, S, BasePath>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
app: Hono<any, any, any>,
fsModule: FileSystemModule,
options?: ToSSGOptions
): Promise<ToSSGResult>
3 changes: 2 additions & 1 deletion src/jsx/jsx-runtime.ts
Original file line number Diff line number Diff line change
@@ -3,5 +3,6 @@ export { jsxDEV as jsxs } from './jsx-dev-runtime'

import { raw, html } from '../helper/html'
export { html as jsxTemplate }
export const jsxAttr = (name: string, value: string) => raw(name + '="' + html`${value}` + '"')
export const jsxAttr = (name: string, value: string | Promise<string>) =>
typeof value === 'string' ? raw(name + '="' + html`${value}` + '"') : html`${name}="${value}"`
export const jsxEscape = (value: string) => value
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
@@ -1671,7 +1671,7 @@ export type MergePath<A extends string, B extends string> = A extends ''

export type TypedResponse<T = unknown> = {
data: T
format: 'json' // Currently, support only `json` with `c.jsonT()`
format: 'json' // Currently, support only `json` with `c.json()`
}

type ExtractResponseData<T> = T extends Promise<infer T2>
7 changes: 7 additions & 0 deletions src/utils/stream.ts
Original file line number Diff line number Diff line change
@@ -12,6 +12,13 @@ export class StreamingApi {

const reader = _readable.getReader()

// in case the user disconnects, let the reader know to cancel
// this in-turn results in responseReadable being closed
// and writeSSE method no longer blocks indefinitely
this.abortSubscribers.push(async () => {
await reader.cancel()
})

this.responseReadable = new ReadableStream({
async pull(controller) {
const { done, value } = await reader.read()
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
@@ -2961,7 +2961,7 @@ gitignore-parser@0.0.2:
resolved "https://registry.npmjs.org/gitignore-parser/-/gitignore-parser-0.0.2.tgz"
integrity sha512-X6mpqUv59uWLGD4n3hZ8Cu8KbF2PMWPSFYmxZjdkpm3yOU7hSUYnzTkZI1mcWqchphvqyuz3/BhgBR4E/JtkCg==

glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
glob@7.2.3, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
version "7.2.3"
resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==