duto 0.260808.0 → 0.260915.0
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/LICENSE +2 -2
- package/README.md +35 -13
- package/package.json +54 -13
- package/src/cli.ts +45 -0
- package/src/commands/new.ts +147 -0
- package/src/commands/templates/base/.editorconfig +21 -0
- package/src/commands/templates/base/.env.dev.example +2 -0
- package/src/commands/templates/base/.env.prod.example +2 -0
- package/src/commands/templates/base/README.md +29 -0
- package/src/commands/templates/base/_gitignore +100 -0
- package/src/commands/templates/base/actions/blog/index.get.ts +9 -0
- package/src/commands/templates/base/actions/blog/post/[id].get.ts +9 -0
- package/src/commands/templates/base/actions/index.get.ts +5 -0
- package/src/commands/templates/base/configs/duto.ts +11 -0
- package/src/commands/templates/base/configs/roles.ts +5 -0
- package/src/commands/templates/base/package.json +24 -0
- package/src/commands/templates/base/tsconfig.json +42 -0
- package/src/commands/templates/workerd/wrangler.toml +47 -0
- package/src/commands/upgrade.ts +30 -0
- package/src/enum.ts +2 -0
- package/src/index.d.ts +61 -0
- package/src/index.ts +19 -23
- package/src/middleware.ts +2 -0
- package/src/{cli → pages/cli}/commands/build.ts +13 -7
- package/src/{cli → pages/cli}/commands/dev.ts +11 -4
- package/src/{cli → pages/cli}/commands/preview.ts +6 -4
- package/src/pages/cli/index.ts +10 -0
- package/src/{cli → pages/cli}/utils.ts +4 -5
- package/src/{client → pages/client}/app.tsx +1 -1
- package/src/{client → pages/client}/router.ts +1 -1
- package/src/{compiler → pages/compiler}/file.ts +1 -1
- package/src/{compiler → pages/compiler}/index.ts +2 -4
- package/src/{compiler → pages/compiler}/meta.ts +2 -2
- package/src/{compiler → pages/compiler}/routes.ts +1 -1
- package/src/{compiler → pages/compiler}/types.ts +10 -0
- package/src/{compiler → pages/compiler}/vite-plugin.ts +20 -45
- package/src/{i18n → pages/i18n}/client.ts +2 -2
- package/src/{i18n → pages/i18n}/element.ts +1 -1
- package/src/{i18n → pages/i18n}/server.ts +1 -1
- package/src/pages/index.ts +28 -0
- package/src/{preact → pages/preact}/server.ts +1 -1
- package/src/server/adapter/aws.ts +4 -0
- package/src/server/adapter/workerd.ts +4 -0
- package/src/server/app.ts +91 -0
- package/src/server/auth/ability.ts +72 -0
- package/src/server/auth/authnz.ts +86 -0
- package/src/server/auth/index.ts +5 -0
- package/src/server/auth/token.ts +147 -0
- package/src/server/auth/types.ts +2 -0
- package/src/server/cli/commands/build.ts +41 -0
- package/src/server/cli/commands/deploy.ts +81 -0
- package/src/server/cli/commands/dev.ts +279 -0
- package/src/server/cli/commands/make.ts +98 -0
- package/src/server/cli/commands/migrate.ts +93 -0
- package/src/server/cli/commands/routes.ts +78 -0
- package/src/server/cli/index.ts +27 -0
- package/src/server/cli/stubs.ts +39 -0
- package/src/server/cli/types.ts +3 -0
- package/src/server/cli/utils.ts +437 -0
- package/src/server/config.ts +19 -0
- package/src/server/db/d1.d.ts +1 -0
- package/src/server/db/d1.ts +1 -0
- package/src/server/db/dynamodb.d.ts +1 -0
- package/src/server/db/dynamodb.ts +1 -0
- package/src/server/db/index.ts +1 -0
- package/src/server/entry.ts +19 -0
- package/src/server/handle.ts +30 -0
- package/src/server/middlewares/auth.ts +40 -0
- package/src/server/middlewares/logger.ts +30 -0
- package/src/server/open-api/register.ts +29 -0
- package/src/server/open-api/spec.ts +114 -0
- package/src/server/request.ts +265 -0
- package/src/server/response.ts +142 -0
- package/src/server/routes.ts +473 -0
- package/src/server/types.ts +142 -0
- package/src/server/utils/environment.ts +17 -0
- package/src/server/utils.ts +71 -0
- package/src/server/validator.ts +70 -0
- package/src/utils.ts +15 -0
- package/src/cli/commands/dev-old.ts +0 -213
- package/src/cli/index.ts +0 -28
- package/src/compiler/utils.ts +0 -5
- /package/src/{client → pages/client}/hmr.ts +0 -0
- /package/src/{client → pages/client}/island.ts +0 -0
- /package/src/{client → pages/client}/link.ts +0 -0
- /package/src/{client → pages/client}/storage.ts +0 -0
- /package/src/{compiler → pages/compiler}/aliases.ts +0 -0
- /package/src/{compiler → pages/compiler}/assets.ts +0 -0
- /package/src/{compiler → pages/compiler}/ast.ts +0 -0
- /package/src/{compiler → pages/compiler}/constants.ts +0 -0
- /package/src/{compiler → pages/compiler}/island.ts +0 -0
- /package/src/{components → pages/components}/link.tsx +0 -0
- /package/src/{preact → pages/preact}/client-dev.ts +0 -0
- /package/src/{preact → pages/preact}/client.ts +0 -0
- /package/src/{preact → pages/preact}/context.ts +0 -0
- /package/src/{preact → pages/preact}/signals.ts +0 -0
- /package/src/{preact → pages/preact}/static-html.ts +0 -0
- /package/src/{preact → pages/preact}/types.ts +0 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { STATUS_CODES } from 'node:http'
|
|
2
|
+
import { generateSpecs, resolver } from 'hono-openapi'
|
|
3
|
+
import { array, object, string } from 'zod/mini'
|
|
4
|
+
import { getEnv } from 't0n'
|
|
5
|
+
import { Scalar } from '@scalar/hono-api-reference'
|
|
6
|
+
import { minify } from '@minify-html/node'
|
|
7
|
+
import type { Hono } from '$/types'
|
|
8
|
+
import { useAuth } from '$/middlewares/auth'
|
|
9
|
+
|
|
10
|
+
export function openAPIConfig(opts: any) {
|
|
11
|
+
const {
|
|
12
|
+
disable = false,
|
|
13
|
+
path = '/docs',
|
|
14
|
+
agent = false,
|
|
15
|
+
name = '',
|
|
16
|
+
title = '',
|
|
17
|
+
version = getEnv('APP_VERSION') || getEnv('VERSION_HASH') || '1.0.0',
|
|
18
|
+
description = getEnv('APP_DESCRIPTION', ''),
|
|
19
|
+
auth = {},
|
|
20
|
+
...docs
|
|
21
|
+
} = opts?.docs ?? {}
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
disable,
|
|
25
|
+
path,
|
|
26
|
+
auth,
|
|
27
|
+
agent: !!agent,
|
|
28
|
+
name: name || title || getEnv('APP_NAME', 'API Docs'),
|
|
29
|
+
version,
|
|
30
|
+
desc: description,
|
|
31
|
+
...docs,
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function generateOpenAPI(app: Hono, opts?: any) {
|
|
36
|
+
return await generateSpecs(app, {
|
|
37
|
+
documentation: {
|
|
38
|
+
info: {
|
|
39
|
+
title: opts.name,
|
|
40
|
+
version: opts.version,
|
|
41
|
+
description: opts.desc,
|
|
42
|
+
contact: opts.contact,
|
|
43
|
+
termsOfService: opts.terms || opts.termsOfService,
|
|
44
|
+
license: opts.license,
|
|
45
|
+
},
|
|
46
|
+
externalDocs: opts.externalDocs,
|
|
47
|
+
servers: opts.servers,
|
|
48
|
+
security: useAuth() ? [{'JWT':[]}] : opts.security,
|
|
49
|
+
tags: opts.tags,
|
|
50
|
+
components: {
|
|
51
|
+
...(useAuth() ? { securitySchemes: {
|
|
52
|
+
JWT: {
|
|
53
|
+
type: 'http',
|
|
54
|
+
scheme: 'bearer',
|
|
55
|
+
bearerFormat: 'JWT',
|
|
56
|
+
},
|
|
57
|
+
} } : {}),
|
|
58
|
+
responses: {
|
|
59
|
+
500: {
|
|
60
|
+
description: STATUS_CODES[500],
|
|
61
|
+
content: { // @ts-ignore
|
|
62
|
+
'application/json': await resolver(object({
|
|
63
|
+
m: array(string()),
|
|
64
|
+
})).toOpenAPISchema(),
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
...opts?.responses,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function generateOpenAPIClient(app: Hono, opts?: any) {
|
|
75
|
+
const customCss = `[href="https://www.scalar.com"],.scalar-mcp-layer{display:none!important}`
|
|
76
|
+
app.get(
|
|
77
|
+
opts.path,
|
|
78
|
+
Scalar({
|
|
79
|
+
theme: 'saturn',
|
|
80
|
+
url: opts.path +'/openapi',
|
|
81
|
+
showDeveloperTools: 'never',
|
|
82
|
+
telemetry: false,
|
|
83
|
+
documentDownloadType: 'json', //'direct',
|
|
84
|
+
isLoading: true,
|
|
85
|
+
persistAuth: true,
|
|
86
|
+
hideClientButton: true,
|
|
87
|
+
pageTitle: opts.name,
|
|
88
|
+
agent: { disabled: !opts.agent },
|
|
89
|
+
slug: opts.name?.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[^\w\s_-]/g, '').replace(/[\s_-]+/g, '_').replace(/[^\x00-\x7F]/g, '') +'_'+ opts.version,
|
|
90
|
+
customCss,
|
|
91
|
+
// onLoaded: () => document?.querySelectorAll('[href="https://www.scalar.com"]')?.forEach(el => el.remove()),
|
|
92
|
+
// favicon: 'https://example.com/favicon.png',
|
|
93
|
+
// hideDownloadButton: true,
|
|
94
|
+
defaultHttpClient: {
|
|
95
|
+
targetKey: 'shell',
|
|
96
|
+
clientKey: 'curl',
|
|
97
|
+
},
|
|
98
|
+
hiddenClients: [
|
|
99
|
+
'c', 'clojure', 'csharp', 'dart', 'fsharp', 'go', 'http', 'java', 'julia', 'kotlin', 'node', 'objc', 'ocaml', 'php', 'python', 'powershell', 'r', 'ruby', 'rust', 'swift'
|
|
100
|
+
],
|
|
101
|
+
})
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
const html = await (await app.request('/docs')).text()
|
|
105
|
+
const result = minify(Buffer.from(html), {
|
|
106
|
+
minify_css: true,
|
|
107
|
+
minify_js: true,
|
|
108
|
+
keep_comments: false,
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
return result.toString()
|
|
112
|
+
.replace(',customCss:`' + customCss + '`', '')
|
|
113
|
+
.replace('_integration:`hono`,', '')
|
|
114
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { getCookie, getSignedCookie, setCookie, setSignedCookie, deleteCookie } from 'hono/cookie'
|
|
2
|
+
import { HTTPException } from 'hono/http-exception'
|
|
3
|
+
import { Authnz, Token } from './auth'
|
|
4
|
+
import { addEnv } from 't0n'
|
|
5
|
+
|
|
6
|
+
import type { Context } from 'hono'
|
|
7
|
+
import { routePath, matchedRoutes } from 'hono/route'
|
|
8
|
+
import type { RouterRoute } from 'hono/types'
|
|
9
|
+
import type { CookieOptions, CookiePrefixOptions } from 'hono/utils/cookie'
|
|
10
|
+
import type { CustomHeader, RequestHeader } from 'hono/utils/headers'
|
|
11
|
+
import type { BodyData, ParseBodyOptions } from 'hono/utils/body'
|
|
12
|
+
|
|
13
|
+
// function cookieWrapper(c: Context) {
|
|
14
|
+
// return {
|
|
15
|
+
// all: () => getCookie(c),
|
|
16
|
+
// allSigned: (secret: string) => getSignedCookie(c, secret),
|
|
17
|
+
// get: (name: string, prefixOptions?: CookiePrefixOptions) => prefixOptions ? getCookie(c, name, prefixOptions) : getCookie(c, name),
|
|
18
|
+
// getSigned: (secret: string, name: string, prefixOptions?: CookiePrefixOptions) => prefixOptions ? getSignedCookie(c, secret, name, prefixOptions) : getSignedCookie(c, secret, name),
|
|
19
|
+
// set: (name: string, value: string, opt?: CookieOptions) => setCookie(c, name, value, opt),
|
|
20
|
+
// setSigned: (name: string, value: string, secret: string, opt?: CookieOptions) => setSignedCookie(c, name, value, secret, opt),
|
|
21
|
+
// delete: (name: string, opt?: CookieOptions) => deleteCookie(c, name, opt)
|
|
22
|
+
// }
|
|
23
|
+
// }
|
|
24
|
+
class $Cookie {
|
|
25
|
+
#c!: Context
|
|
26
|
+
constructor(c: Context) {
|
|
27
|
+
this.#c = c
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
all() {
|
|
31
|
+
return getCookie(this.#c)
|
|
32
|
+
}
|
|
33
|
+
allSigned(secret: string) {
|
|
34
|
+
return getSignedCookie(this.#c, secret)
|
|
35
|
+
}
|
|
36
|
+
get(name: string, prefixOptions?: CookiePrefixOptions) {
|
|
37
|
+
return prefixOptions ? getCookie(this.#c, name, prefixOptions) : getCookie(this.#c, name)
|
|
38
|
+
}
|
|
39
|
+
getSigned(secret: string, name: string, prefixOptions?: CookiePrefixOptions) {
|
|
40
|
+
return prefixOptions ? getSignedCookie(this.#c, secret, name, prefixOptions) : getSignedCookie(this.#c, secret, name)
|
|
41
|
+
}
|
|
42
|
+
set(name: string, value: string, opt?: CookieOptions) {
|
|
43
|
+
setCookie(this.#c, name, value, opt)
|
|
44
|
+
}
|
|
45
|
+
setSigned(name: string, value: string, secret: string, opt?: CookieOptions) {
|
|
46
|
+
setSignedCookie(this.#c, name, value, secret, opt)
|
|
47
|
+
}
|
|
48
|
+
delete(name: string, opt?: CookieOptions) {
|
|
49
|
+
deleteCookie(this.#c, name, opt)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const GET_REQUEST: unique symbol = Symbol()
|
|
54
|
+
|
|
55
|
+
export default class $Request {
|
|
56
|
+
#c!: Context
|
|
57
|
+
#cookie: $Cookie
|
|
58
|
+
// #cookie: ReturnType<typeof cookieWrapper>
|
|
59
|
+
#u: Authnz<any> | null = null
|
|
60
|
+
|
|
61
|
+
#host: string
|
|
62
|
+
#protocol: string
|
|
63
|
+
#routePath?: string
|
|
64
|
+
#matchedRoutes: RouterRoute[]
|
|
65
|
+
|
|
66
|
+
constructor(c: Context) {
|
|
67
|
+
this.#c = c
|
|
68
|
+
this.#cookie = new $Cookie(c)
|
|
69
|
+
// this.#cookie = cookieWrapper(c)
|
|
70
|
+
|
|
71
|
+
const url = new URL(c.req.raw.url)
|
|
72
|
+
this.#host = url.protocol +'//'+ url.host
|
|
73
|
+
this.#protocol = url.protocol
|
|
74
|
+
|
|
75
|
+
this.#matchedRoutes = matchedRoutes(c)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static async toContext(c: Context) {
|
|
79
|
+
const req = new $Request(c)
|
|
80
|
+
await req.setAuth()
|
|
81
|
+
c.set(GET_REQUEST as unknown as string, req)
|
|
82
|
+
if (c.env) addEnv(c.env)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async setAuth() {
|
|
86
|
+
this.#u = Authnz.fromToken(await Token.fromRequest(this))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get user() {
|
|
90
|
+
return this.#u ? this.#u?.data : null
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
get auth() {
|
|
94
|
+
return this.#u
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
can(...abilities: string[]) {
|
|
98
|
+
return this.#u ? this.#u.can(...abilities) : false
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
cant(...abilities: string[]) {
|
|
102
|
+
return !this.can(...abilities)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
hasRole(...roles: string[]) {
|
|
106
|
+
return this.#u ? this.#u.hasRole(...roles) : false
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// TODO: fazer funcionar dnv..
|
|
110
|
+
// has(prop: string, value: any = null) {
|
|
111
|
+
// return this.#u ? this.#u.has(prop, value) : false
|
|
112
|
+
// }
|
|
113
|
+
// hasValue(prop: string, value: any = null) {
|
|
114
|
+
// return this.has(prop, value)
|
|
115
|
+
// }
|
|
116
|
+
|
|
117
|
+
// createToken(data: any, exp: number) {
|
|
118
|
+
// return Token.create(this, data, exp)
|
|
119
|
+
// }
|
|
120
|
+
// parseToken(token: string) {
|
|
121
|
+
// return Token.parse(this, token)
|
|
122
|
+
// }
|
|
123
|
+
|
|
124
|
+
get cx() {
|
|
125
|
+
return this.#c
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
get cookie() {
|
|
129
|
+
return this.#cookie
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
get ip(): string | undefined {
|
|
133
|
+
return this.#c.req.header('cf-connecting-ip') // cf
|
|
134
|
+
|| this.#c.req.header('x-forwarded-for')?.split(',').at(-1)?.trim() // aws lambda
|
|
135
|
+
|| this.#c.env?.aws?.lambda?.event?.requestContext?.identity?.sourceIp
|
|
136
|
+
|| this.#c.env?.event?.Records[0]?.cf?.request?.clientIp // aws lambda@edge
|
|
137
|
+
|| this.#c.req.header('x-real-ip') // vercel
|
|
138
|
+
|| this.#c.env?.context?.ip // netlify
|
|
139
|
+
|| this.#c.env?.remoteAddr?.hostname // deno
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
get userAgent(): string | undefined {
|
|
143
|
+
return this.#c.req.header('user-agent')
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
get protocol() {
|
|
147
|
+
return this.#protocol
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
get url() {
|
|
151
|
+
return this.#c.req.raw.url
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
get host() {
|
|
155
|
+
return this.#host
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
get path() {
|
|
159
|
+
return this.#c.req.path
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
get fullPath() {
|
|
163
|
+
const url = this.url
|
|
164
|
+
return url.slice(url.indexOf('/', 8))
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
get method() {
|
|
168
|
+
return this.#c.req.raw.method
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
get routePath() {
|
|
172
|
+
this.#routePath ??= routePath(this.#c)
|
|
173
|
+
return this.#routePath
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
get routeIndex() {
|
|
177
|
+
return this.#c.req.routeIndex
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
get matchedRoutes() {
|
|
181
|
+
return this.#matchedRoutes
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
get raw() {
|
|
185
|
+
return this.#c.req.raw
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
header(name: RequestHeader): string | undefined
|
|
189
|
+
header(name: string): string | undefined
|
|
190
|
+
header(): Record<RequestHeader | (string & CustomHeader), string>
|
|
191
|
+
header(name?: string) { // @ts-ignore
|
|
192
|
+
return this.#c.req.header(name)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
param(key?: string) { // @ts-ignore
|
|
196
|
+
return this.#c.req.param(key)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
query(): Record<string, string>
|
|
200
|
+
query(key: string): string | undefined
|
|
201
|
+
query(key?: string) { // @ts-ignore
|
|
202
|
+
return this.#c.req.query(key)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
queries(): Record<string, string[]>
|
|
206
|
+
queries(key: string):string[] | undefined
|
|
207
|
+
queries(key?: string) { // @ts-ignore
|
|
208
|
+
return this.#c.req.queries(key)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async body<E>() {
|
|
212
|
+
const cType = this.#c.req.header('Content-Type')
|
|
213
|
+
if (!cType) return {} as E
|
|
214
|
+
|
|
215
|
+
if (/^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/.test(cType))
|
|
216
|
+
return await this.json<E>()
|
|
217
|
+
|
|
218
|
+
if (
|
|
219
|
+
cType?.startsWith('multipart/form-data')
|
|
220
|
+
|| cType?.startsWith('application/x-www-form-urlencoded')
|
|
221
|
+
) {
|
|
222
|
+
return await this.parseBody() as E
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return {} as E
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async parseBody<Options extends Partial<ParseBodyOptions>, T extends BodyData<Options>>(
|
|
229
|
+
options?: Options
|
|
230
|
+
): Promise<T>
|
|
231
|
+
async parseBody<T extends BodyData>(options?: Partial<ParseBodyOptions>): Promise<T>
|
|
232
|
+
async parseBody(options?: Partial<ParseBodyOptions>) {
|
|
233
|
+
try {
|
|
234
|
+
return await this.#c.req.parseBody(options)
|
|
235
|
+
} catch (e) {
|
|
236
|
+
throw new HTTPException(400, {
|
|
237
|
+
message: 'Malformed FormData request.'+ (e instanceof Error ? ` ${e.message}` : ` ${String(e)}`)
|
|
238
|
+
})
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async json<E>() {
|
|
243
|
+
try {
|
|
244
|
+
return await this.#c.req.json<E>()
|
|
245
|
+
} catch {
|
|
246
|
+
throw new HTTPException(400, { message: 'Malformed JSON in request body' })
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
text() {
|
|
251
|
+
return this.#c.req.text()
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
arrayBuffer() {
|
|
255
|
+
return this.#c.req.arrayBuffer()
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
blob() {
|
|
259
|
+
return this.#c.req.blob()
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
formData() {
|
|
263
|
+
return this.#c.req.formData()
|
|
264
|
+
}
|
|
265
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { HtmlEscapedCallbackPhase, resolveCallback } from 'hono/utils/html'
|
|
2
|
+
import type {
|
|
3
|
+
ContentfulStatusCode, RedirectStatusCode, StatusCode,
|
|
4
|
+
BaseMime, HeaderRecord,
|
|
5
|
+
ErrorResponse, Errors,
|
|
6
|
+
} from './types'
|
|
7
|
+
|
|
8
|
+
type RBag = {
|
|
9
|
+
status?: StatusCode,
|
|
10
|
+
headers?: HeaderRecord,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default class $Response {
|
|
14
|
+
static raw(
|
|
15
|
+
status?: StatusCode,
|
|
16
|
+
body?: any,
|
|
17
|
+
cType?: BaseMime,
|
|
18
|
+
headers?: HeaderRecord
|
|
19
|
+
) {
|
|
20
|
+
const b: RBag = { status: status || 200 }
|
|
21
|
+
|
|
22
|
+
if (cType || headers) {
|
|
23
|
+
headers ??= {}
|
|
24
|
+
if (cType) headers['Content-Type'] = cType
|
|
25
|
+
b.headers = headers
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return new Response(body ?? null, b)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static text(str?: string, status?: StatusCode, headers?: HeaderRecord) {
|
|
32
|
+
return this.raw(status, str, 'text/plain; charset=UTF-8' as BaseMime, headers)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static json<T>(data?: T, status?: StatusCode, headers?: HeaderRecord) {
|
|
36
|
+
if (data == null)
|
|
37
|
+
return this.raw(status, null, undefined, headers)
|
|
38
|
+
|
|
39
|
+
return this.raw(status, JSON.stringify(data), 'application/json', headers)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static redirect(
|
|
43
|
+
location: string | URL,
|
|
44
|
+
status?: RedirectStatusCode,
|
|
45
|
+
headers?: HeaderRecord
|
|
46
|
+
) {
|
|
47
|
+
const loc = String(location)
|
|
48
|
+
|
|
49
|
+
return new Response(null, {
|
|
50
|
+
status: status || 302,
|
|
51
|
+
headers: { ...headers, 'Location': /[^\x00-\xFF]/.test(loc) ? encodeURI(loc) : loc }
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static html(
|
|
56
|
+
html: string | Promise<string>,
|
|
57
|
+
status?: ContentfulStatusCode,
|
|
58
|
+
headers?: HeaderRecord
|
|
59
|
+
): Response | Promise<Response> {
|
|
60
|
+
const res = (html: string) => this.raw(status, html, 'text/html; charset=UTF-8' as BaseMime, headers)
|
|
61
|
+
return typeof html === 'string'
|
|
62
|
+
? res(html)
|
|
63
|
+
: resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static ok(): Response
|
|
67
|
+
static ok<T>(data: T, headers?: HeaderRecord): Response
|
|
68
|
+
static ok<T>(data?: T, headers?: HeaderRecord) {
|
|
69
|
+
return this.json(data, 200, headers)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static created(): Response
|
|
73
|
+
static created<T>(data: T, headers?: HeaderRecord): Response
|
|
74
|
+
static created<T>(data?: T, headers?: HeaderRecord) {
|
|
75
|
+
return this.json(data, 201, headers)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static accepted(): Response
|
|
79
|
+
static accepted<T>(data: T, headers?: HeaderRecord): Response
|
|
80
|
+
static accepted<T>(data?: T, headers?: HeaderRecord) {
|
|
81
|
+
return this.json(data, 202, headers)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static deleted(headers?: HeaderRecord) {
|
|
85
|
+
return this.noContent(headers)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static noContent(headers?: HeaderRecord) {
|
|
89
|
+
return this.json(null, 204, headers)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static badRequest(): Response
|
|
93
|
+
static badRequest(errors?: Errors | null, msg?: string, headers?: HeaderRecord): Response
|
|
94
|
+
static badRequest(errors?: Errors | null, msg?: string, headers?: HeaderRecord) {
|
|
95
|
+
return this.error(errors, msg, 400, headers)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static unauthorized(): Response
|
|
99
|
+
static unauthorized<T>(data: T, headers?: HeaderRecord): Response
|
|
100
|
+
static unauthorized<T>(data?: T, headers?: HeaderRecord) {
|
|
101
|
+
return this.json(data, 401, headers)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
static forbidden(): Response
|
|
105
|
+
static forbidden<T>(data: T, headers?: HeaderRecord): Response
|
|
106
|
+
static forbidden<T>(data?: T, headers?: HeaderRecord) {
|
|
107
|
+
return this.json(data, 403, headers)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static notFound(): Response
|
|
111
|
+
static notFound<T>(msg: T, headers?: HeaderRecord): Response
|
|
112
|
+
static notFound<T>(msg?: T, headers?: HeaderRecord) {
|
|
113
|
+
return this.json(msg, 404, headers)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
static conflict(): Response
|
|
117
|
+
static conflict(errors?: Errors | null, msg?: string, headers?: HeaderRecord) {
|
|
118
|
+
return this.error(errors, msg, 409, headers)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
static unsupportedMediaType(): Response
|
|
122
|
+
static unsupportedMediaType(errors?: Errors | null, msg?: string, headers?: HeaderRecord) {
|
|
123
|
+
return this.error(errors, msg, 415, headers)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static internalError(): Response
|
|
127
|
+
static internalError(errors?: Errors | null, msg?: string, headers?: HeaderRecord) {
|
|
128
|
+
return this.error(errors, msg, 500, headers)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
static error(errors?: Errors | null, msg?: string, status?: ContentfulStatusCode, headers?: HeaderRecord) {
|
|
132
|
+
status ??= 500
|
|
133
|
+
if (!errors && !msg)
|
|
134
|
+
return this.raw(status, msg)
|
|
135
|
+
|
|
136
|
+
const resp: ErrorResponse = {}
|
|
137
|
+
if (msg) resp.m = msg
|
|
138
|
+
if (errors) resp.e = errors
|
|
139
|
+
|
|
140
|
+
return this.json(resp, status, headers)
|
|
141
|
+
}
|
|
142
|
+
}
|