Skip to content
This repository has been archived by the owner on Jun 27, 2024. It is now read-only.

Commit

Permalink
feat(ext): pass prefix to context
Browse files Browse the repository at this point in the history
  • Loading branch information
boywithkeyboard committed Aug 6, 2023
1 parent d711d3a commit 9de1edf
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 164 deletions.
153 changes: 80 additions & 73 deletions cheetah.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,87 +219,89 @@ export class cheetah extends base<cheetah>() {
waitUntil: (promise: Promise<unknown>) => void
},
): Promise<Response> => {
const ip = data?.remoteAddr && this.#runtime === 'deno'
? ((data as Deno.ServeHandlerInfo).remoteAddr)
.hostname
: req.headers.get('cf-connecting-ip') ?? undefined

const parts = req.url.split('?')

parts[0] = parts[0].slice(8)

const __app: AppContext = {
env: data as Record<string, unknown>,
ip,
proxy: this.#proxy,
request: {
pathname: parts[0].substring(parts[0].indexOf('/')),
querystring: parts[1],
},
routes: this.#routes,
runtime: this.#runtime,
}

if (this.#extensions.size > 0) {
let body: Response | void = undefined

for (const e of this.#extensions.values()) {
if (!this.#onPlugIn && e[1].onPlugIn !== undefined) {
await e[1].onPlugIn({
env: __app.env,
routes: this.#routes,
runtime: this.#runtime,
setRoute: (method, pathname, ...handlers) => {
this.#routes.add([
method.toUpperCase() as Uppercase<Method>,
pathname,
RegExp(
`^${
(pathname
.replace(/\/+(\/|$)/g, '$1'))
.replace(/(\/?\.?):(\w+)\+/g, '($1(?<$2>*))')
.replace(/(\/?\.?):(\w+)/g, '($1(?<$2>[^$1/]+?))')
.replace(/\./g, '\\.')
.replace(/(\/?)\*/g, '($1.*)?')
}/*$`,
),
// @ts-ignore:
handlers,
])
},
})
}
try {
const ip = data?.remoteAddr && this.#runtime === 'deno'
? ((data as Deno.ServeHandlerInfo).remoteAddr)
.hostname
: req.headers.get('cf-connecting-ip') ?? undefined

const parts = req.url.split('?')

parts[0] = parts[0].slice(8)

const __app: AppContext = {
env: data as Record<string, unknown>,
ip,
proxy: this.#proxy,
request: {
pathname: parts[0].substring(parts[0].indexOf('/')),
querystring: parts[1],
},
routes: this.#routes,
runtime: this.#runtime,
}

if (
e[0] !== '*' &&
__app.request.pathname.indexOf(e[0]) !== 0
) {
continue
}
if (this.#extensions.size > 0) {
let body: Response | void = undefined

for (const e of this.#extensions.values()) {
if (!this.#onPlugIn && e[1].onPlugIn !== undefined) {
await e[1].onPlugIn({
prefix: e[0],
env: __app.env,
routes: this.#routes,
runtime: this.#runtime,
setRoute: (method, pathname, ...handlers) => {
this.#routes.add([
method.toUpperCase() as Uppercase<Method>,
pathname,
RegExp(
`^${
(pathname
.replace(/\/+(\/|$)/g, '$1'))
.replace(/(\/?\.?):(\w+)\+/g, '($1(?<$2>*))')
.replace(/(\/?\.?):(\w+)/g, '($1(?<$2>[^$1/]+?))')
.replace(/\./g, '\\.')
.replace(/(\/?)\*/g, '($1.*)?')
}/*$`,
),
// @ts-ignore:
handlers,
])
},
})
}

if (e[1].onRequest !== undefined) {
const result = await e[1].onRequest({
app: __app,
req,
_: e[1].__config,
})
if (
e[0] !== '*' &&
__app.request.pathname.indexOf(e[0]) !== 0
) {
continue
}

if (result !== undefined) {
body = result
if (e[1].onRequest !== undefined) {
const result = await e[1].onRequest({
prefix: e[0],
app: __app,
req,
_: e[1].__config,
})

if (result !== undefined) {
body = result
}
}
}
}

if (!this.#onPlugIn) {
this.#onPlugIn = true
}
if (!this.#onPlugIn) {
this.#onPlugIn = true
}

if (body !== undefined) {
return body
if (body !== undefined) {
return body
}
}
}

try {
const route = this.#match(
req.method,
__app.request.pathname,
Expand Down Expand Up @@ -481,7 +483,12 @@ export class cheetah extends base<cheetah>() {
const { onResponse } = e[1]

if (onResponse !== undefined) {
onResponse({ app: __app, c: context, _: e[1].__config })
onResponse({
prefix: e[0],
app: __app,
c: context,
_: e[1].__config,
})
}
}

Expand Down
197 changes: 107 additions & 90 deletions extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,100 +9,117 @@ type HasRequired<T> = Partial<T> extends T ? false : true
type Req = Response | void | undefined
type Res = void | undefined

type ExtensionContext = {
/** The prefix of the routes to which this extension is assigned. */
prefix: string
}

export type Extension<
Config extends Record<string, unknown> | unknown = never,
> = {
__config: Config | undefined
onPlugIn: HasRequired<Config> extends true ? ((context: {
env: AppContext['env']
routes: AppContext['routes']
runtime: AppContext['runtime']
setRoute: <
Pathname extends `/${string}`,
// deno-lint-ignore no-explicit-any
ValidatedBody extends ObjectType | ZodString | ZodUnion<any>,
ValidatedCookies extends ObjectType,
ValidatedHeaders extends ObjectType,
ValidatedQuery extends ObjectType,
>(
method: Method,
pathname: Pathname,
...handler: (
| {
body?: ValidatedBody
cookies?: ValidatedCookies
headers?: ValidatedHeaders
query?: ValidatedQuery
/** @deprecated please pass this option to the `c.req.body()` method! */
transform?: boolean // TODO remove at v2.0
cors?: string
}
| Handler<
Pathname,
ValidatedBody,
ValidatedCookies,
ValidatedHeaders,
ValidatedQuery
>
)[]
) => void | Promise<void>
settings: Config
}) => void | Promise<void>)
: ((context: {
env: AppContext['env']
routes: AppContext['routes']
runtime: AppContext['runtime']
setRoute: <
Pathname extends `/${string}`,
// deno-lint-ignore no-explicit-any
ValidatedBody extends ObjectType | ZodString | ZodUnion<any>,
ValidatedCookies extends ObjectType,
ValidatedHeaders extends ObjectType,
ValidatedQuery extends ObjectType,
>(
method: Method,
pathname: Pathname,
...handlers: (
| {
body?: ValidatedBody
cookies?: ValidatedCookies
headers?: ValidatedHeaders
query?: ValidatedQuery
/** @deprecated please pass this option to the `c.req.body()` method! */
transform?: boolean // TODO remove at v2.0
cors?: string
}
| Handler<
Pathname,
ValidatedBody,
ValidatedCookies,
ValidatedHeaders,
ValidatedQuery
>
)[]
) => void
settings?: Config
}) => void | Promise<void>)
onRequest?: HasRequired<Config> extends true ? ((context: {
app: AppContext
req: Request
_: Config
}) => Req | Promise<Req>)
: ((context: {
app: AppContext
req: Request
_?: Config
}) => Req | Promise<Req>)
onResponse?: HasRequired<Config> extends true ? ((context: {
app: AppContext
c: Context
_: Config
}) => Res | Promise<Res>)
: ((context: {
app: AppContext
c: Context
_?: Config
}) => Res | Promise<Res>)
onPlugIn: HasRequired<Config> extends true ? ((
context: ExtensionContext & {
env: AppContext['env']
routes: AppContext['routes']
runtime: AppContext['runtime']
setRoute: <
Pathname extends `/${string}`,
// deno-lint-ignore no-explicit-any
ValidatedBody extends ObjectType | ZodString | ZodUnion<any>,
ValidatedCookies extends ObjectType,
ValidatedHeaders extends ObjectType,
ValidatedQuery extends ObjectType,
>(
method: Method,
pathname: Pathname,
...handler: (
| {
body?: ValidatedBody
cookies?: ValidatedCookies
headers?: ValidatedHeaders
query?: ValidatedQuery
/** @deprecated please pass this option to the `c.req.body()` method! */
transform?: boolean // TODO remove at v2.0
cors?: string
}
| Handler<
Pathname,
ValidatedBody,
ValidatedCookies,
ValidatedHeaders,
ValidatedQuery
>
)[]
) => void | Promise<void>
settings: Config
},
) => void | Promise<void>)
: ((
context: ExtensionContext & {
env: AppContext['env']
routes: AppContext['routes']
runtime: AppContext['runtime']
setRoute: <
Pathname extends `/${string}`,
// deno-lint-ignore no-explicit-any
ValidatedBody extends ObjectType | ZodString | ZodUnion<any>,
ValidatedCookies extends ObjectType,
ValidatedHeaders extends ObjectType,
ValidatedQuery extends ObjectType,
>(
method: Method,
pathname: Pathname,
...handlers: (
| {
body?: ValidatedBody
cookies?: ValidatedCookies
headers?: ValidatedHeaders
query?: ValidatedQuery
/** @deprecated please pass this option to the `c.req.body()` method! */
transform?: boolean // TODO remove at v2.0
cors?: string
}
| Handler<
Pathname,
ValidatedBody,
ValidatedCookies,
ValidatedHeaders,
ValidatedQuery
>
)[]
) => void
settings?: Config
},
) => void | Promise<void>)
onRequest?: HasRequired<Config> extends true ? ((
context: ExtensionContext & {
app: AppContext
req: Request
_: Config
},
) => Req | Promise<Req>)
: ((
context: ExtensionContext & {
app: AppContext
req: Request
_?: Config
},
) => Req | Promise<Req>)
onResponse?: HasRequired<Config> extends true ? ((
context: ExtensionContext & {
app: AppContext
c: Context
_: Config
},
) => Res | Promise<Res>)
: ((
context: ExtensionContext & {
app: AppContext
c: Context
_?: Config
},
) => Res | Promise<Res>)
}

type ReturnFunction<
Expand Down
4 changes: 3 additions & 1 deletion test/extensions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ Deno.test('Extensions', async (t) => {
})

const b = createExtension({
onResponse({ c }) {
onResponse({ c, prefix }) {
c.res.body = 'custom'

assertEquals(prefix, '/b')
},
})

Expand Down

0 comments on commit 9de1edf

Please sign in to comment.