Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing generics to Router stages (in options) #241

Merged
merged 7 commits into from
Apr 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## Changelog

- **v5.0.11**
- **v5.0.13**
- fixed: Router/AutoRouter stages were not connected to router-level generics
- **v5.0.12**
- fixed: ./types was not being properly exported
- **v5.0.10**
- fixed: response formatters in finally stage could still cross pollute headers in Node
Expand Down
15 changes: 5 additions & 10 deletions examples/types/additional-arguments.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { RequestHandler } from '../../src/types'
import { IRequestStrict } from '../../src/types'
import { Router } from '../../src/Router'
import { IttyRouter } from '../../src/IttyRouter'
import { AutoRouter } from '../../src/AutoRouter'
import { IRequest } from 'itty-router'
import { IRequest, IRequestStrict, RequestHandler } from '../../src/types'

// we define our environment
type Environment = { age: number }
Expand All @@ -27,19 +23,18 @@ router
// before middleware
.get('/', (request, env) => {
request.user = 'kevin' // invalid (strict)
env.whatever = 123 // valid (any)
env.age = 123 // valid (any)
env.age = 123 // valid
})

// route-level overrides
.get<IRequest, Args>('/', (request, env) => {
request.foo = 'bar' // invalid
request.foo = 'bar' // valid
env.whatever = 123 // invalid
env.age = 123 // valid
})
// route-level overrides
.get<IRequest, AlternativeArgs>('/', (request, env) => {
request.foo = 'bar' // invalid
request.foo = 'bar' // valid
env.age = 123 // invalid
env.name = 'Mittens' // valid
})
Expand All @@ -52,5 +47,5 @@ router
})

.get('/', (request, env) => {
env.age = 'foo' // valid (any)
env.age = 'foo' // invalid
})
33 changes: 33 additions & 0 deletions examples/types/generics-router-stages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { error } from 'console'
import { Router } from '../../src/Router'
import { withParams } from '../../src/withParams'
import { IRequest, IRequestStrict, RequestHandler } from '../../src/types'

// we define our environment
type Environment = { age: number }
type Pet = { name: string }

// and now both args combined (that Workers send to the .fetch())
type Args = [Environment]
type AlternativeArgs = [Pet]

const router = Router<IRequestStrict, Args, Response>({
before: [
(request, env) => {
env.age = 123 // valid
env.foo // invalid
request.foo // invalid
request.body // valid
},
withParams,
],
catch: error,
finally: [
(response, request, env) => {
response.whatever // valid (any)
env.age = 123 // valid
env.foo // invalid
request.foo // invalid
},
]
})
51 changes: 51 additions & 0 deletions examples/types/ittyrouter-generics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { IttyRouter } from '../../src/IttyRouter'
import { IRequest, IRequestStrict, RequestHandler } from '../../src/types'

// we define our environment
type Environment = { age: number }
type Pet = { name: string }

// and now both args combined (that Workers send to the .fetch())
type Args = [Environment]
type AlternativeArgs = [Pet]

// creating some middleware that needs access to CF variables
export const withUser: RequestHandler<IRequest, Args> =
(request, env) => {
request.user = 'Kevin'
env.age = 123
env.name = 'Kevin' // invalid
}

const router = IttyRouter<IRequestStrict, Args>()

router
// before middleware
.get('/', (request, env) => {
request.user = 'kevin' // invalid (strict)
env.age = 123 // valid
})

// route-level overrides
.get<IRequest, Args>('/', (request, env) => {
request.foo = 'bar' // valid
env.whatever = 123 // invalid
env.age = 123 // valid
})
// route-level overrides
.get<IRequest, AlternativeArgs>('/', (request, env) => {
request.foo = 'bar' // valid
env.age = 123 // invalid
env.name = 'Mittens' // valid
})

// after middleware
.get('/', withUser, (request, env) => {
request.user = 'Kevin'
env.age = 123 // valid
env.whatever = 123 // invalid
})

.get('/', (request, env) => {
env.age = 'foo' // invalid
})
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "itty-router",
"version": "5.0.12",
"version": "5.0.13",
"description": "A tiny, zero-dependency router, designed to make beautiful APIs in any environment.",
"main": "./index.js",
"module": "./index.mjs",
Expand Down
1 change: 0 additions & 1 deletion rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const files = (await globby('./src/*.ts', {
types: path.replace('/src/', '/dist/').replace('.ts', '.d.ts'),
})).sort((a, b) => a.shortPath.toLowerCase() < b.shortPath.toLowerCase() ? -1 : 1)


// read original package.json
const pkg = await fs.readJSON('./package.json')

Expand Down
9 changes: 6 additions & 3 deletions src/AutoRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ export const AutoRouter = <
missing = () => error(404),
finally: f = [],
before = [],
...options }: AutoRouterOptions = {}
): AutoRouterType<RequestType, Args, ResponseType> => Router({
...options }: AutoRouterOptions<RequestType, Args, ResponseType> = {}
) => Router<RequestType, Args, ResponseType>({
before: [
// @ts-ignore
withParams,
...before
],
// @ts-ignore
catch: error,
finally: [
// @ts-ignore
(r: any, ...args) => r ?? missing(r, ...args),
format,
...f,
],
...options,
})
}) as AutoRouterType<RequestType, Args, ResponseType>
5 changes: 2 additions & 3 deletions src/IttyRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ export const IttyRouter = <
RequestType extends IRequest = IRequest,
Args extends any[] = any[],
ResponseType = any,
GlobalRequestType = RequestType,
>({ base = '', routes = [], ...other }: IttyRouterOptions = {}): IttyRouterType<RequestType, Args, ResponseType, GlobalRequestType> =>
>({ base = '', routes = [], ...other }: IttyRouterOptions = {}): IttyRouterType<RequestType, Args, ResponseType> =>
// @ts-ignore
({
__proto__: new Proxy({}, {
// @ts-expect-error (we're adding an expected prop "path" to the get)
get: (target: any, prop: string, receiver: object, path: string) =>
(route: string, ...handlers: RequestHandler<GlobalRequestType, Args>[]) =>
(route: string, ...handlers: RequestHandler<RequestType, Args>[]) =>
routes.push(
[
prop.toUpperCase(),
Expand Down
4 changes: 2 additions & 2 deletions src/Router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const Router = <
RequestType = IRequest,
Args extends any[] = any[],
ResponseType = any
>({ base = '', routes = [], ...other }: RouterOptions = {}): RouterType<RequestType, Args, ResponseType> =>
>({ base = '', routes = [], ...other }: RouterOptions<RequestType, Args> = {}): RouterType<RequestType, Args, ResponseType> =>
({
__proto__: new Proxy({}, {
// @ts-expect-error (we're adding an expected prop "path" to the get)
Expand Down Expand Up @@ -72,4 +72,4 @@ export const Router = <

return response
},
} as RouterType<RequestType, Args>)
} as RouterType<RequestType, Args, ResponseType>)
10 changes: 7 additions & 3 deletions src/types/AutoRouterOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import { RequestHandler } from './RequestHandler'
import { ResponseHandler } from './ResponseHandler'
import { RouterOptions } from './RouterOptions'

export type AutoRouterOptions = {
missing?: RequestHandler
export type AutoRouterOptions<
RequestType,
Args extends any[],
ResponseType
> = {
missing?: RequestHandler<RequestType, Args>
format?: ResponseHandler
} & RouterOptions
} & RouterOptions<RequestType, Args, ResponseType>
6 changes: 3 additions & 3 deletions src/types/AutoRouterType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { ResponseHandler } from './ResponseHandler'
import { RouterType } from './RouterType'

export type AutoRouterType<
R = IRequest,
RequestType = IRequest,
Args extends any[] = any[],
ResponseType = any
> = {
missing?: RequestHandler
missing?: RequestHandler<RequestType, Args>
format?: ResponseHandler
} & RouterType<R, Args, ResponseType>
} & RouterType<RequestType, Args, ResponseType>
3 changes: 2 additions & 1 deletion src/types/ErrorHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ import { IRequest } from './IRequest'

export type ErrorHandler<
ErrorType extends Error = StatusError,
RequestType = IRequest, Args extends any[] = any[]
RequestType = IRequest,
Args extends any[] = any[]
> = (error: ErrorType, request: RequestType, ...args: Args) => any
27 changes: 13 additions & 14 deletions src/types/IttyRouterType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,19 @@ import { RouteEntry } from './RouteEntry'
import { CustomRoutes } from './CustomRoutes'

export type IttyRouterType<
R = IRequest,
A extends any[] = any[],
RequestType = IRequest,
Args extends any[] = any[],
ResponseType = any,
GlobalRequestType = R,
> = {
__proto__: IttyRouterType<R>
__proto__: IttyRouterType<RequestType, Args, ResponseType>
routes: RouteEntry[]
fetch: <Args extends any[] = A>(request: RequestLike, ...extra: Args) => Promise<ResponseType>
all: Route<GlobalRequestType, A>
delete: Route<GlobalRequestType, A>
get: Route<GlobalRequestType, A>
head: Route<GlobalRequestType, A>
options: Route<GlobalRequestType, A>
patch: Route<GlobalRequestType, A>
post: Route<GlobalRequestType, A>
put: Route<GlobalRequestType, A>
} & CustomRoutes<Route<GlobalRequestType, A>> & GenericTraps
fetch: <A extends any[] = Args>(request: RequestLike, ...extra: A) => Promise<ResponseType>
all: Route<RequestType, Args>
delete: Route<RequestType, Args>
get: Route<RequestType, Args>
head: Route<RequestType, Args>
options: Route<RequestType, Args>
patch: Route<RequestType, Args>
post: Route<RequestType, Args>
put: Route<RequestType, Args>
} & CustomRoutes<Route<RequestType, Args>> & GenericTraps
6 changes: 4 additions & 2 deletions src/types/RequestHandler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { IRequest } from './IRequest'

export type RequestHandler<R = IRequest, Args extends Array<any> = any[]> =
(request: R, ...args: Args) => any
export type RequestHandler<
RequestType = IRequest,
Args extends Array<any> = any[]
> = (request: RequestType, ...args: Args) => any
6 changes: 3 additions & 3 deletions src/types/ResponseHandler.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { IRequest } from './IRequest'

export type ResponseHandler<
ResponseType = Response,
ResponseType = any,
RequestType = IRequest,
Args extends any[] = any[]
> = (
response: ResponseType & any,
request: RequestType & any,
response: ResponseType,
request: RequestType,
...args: Args
) => any
5 changes: 3 additions & 2 deletions src/types/RouteEntry.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { IRequest } from './IRequest'
import { RequestHandler } from './RequestHandler'

export type RouteEntry = [
export type RouteEntry<RequestType = IRequest, Args extends any[] = any[]> = [
httpMethod: string,
match: RegExp,
handlers: RequestHandler[],
handlers: RequestHandler<RequestType, Args>[],
path?: string,
]
13 changes: 9 additions & 4 deletions src/types/RouterOptions.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { StatusError } from 'StatusError'
import { ErrorHandler } from './ErrorHandler'
import { IRequest } from './IRequest'
import { IttyRouterOptions } from './IttyRouterOptions'
import { RequestHandler } from './RequestHandler'
import { ResponseHandler } from './ResponseHandler'

export type RouterOptions = {
before?: RequestHandler<any>[]
catch?: ErrorHandler
finally?: ResponseHandler[]
export type RouterOptions<
RequestType = IRequest,
Args extends any[] = [],
> = {
before?: RequestHandler<RequestType, Args>[]
catch?: ErrorHandler<StatusError, RequestType, Args>
finally?: ResponseHandler<any, RequestType, Args>[]
} & IttyRouterOptions
15 changes: 10 additions & 5 deletions src/types/RouterType.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { StatusError } from 'StatusError'
import { ErrorHandler } from './ErrorHandler'
import { IRequest } from './IRequest'
import { IttyRouterType } from './IttyRouterType'
import { RequestHandler } from './RequestHandler'
import { ResponseHandler } from './ResponseHandler'

export type RouterType<R = IRequest, Args extends any[] = any[], ResponseType = any> = {
before?: RequestHandler<any>[]
catch?: ErrorHandler
finally?: ResponseHandler[]
} & IttyRouterType<R, Args, ResponseType>
export type RouterType<
RequestType = IRequest,
Args extends any[] = any[],
ResponseType = any
> = {
before?: RequestHandler<RequestType, Args>[]
catch?: ErrorHandler<StatusError, RequestType, Args>
finally?: ResponseHandler<any, RequestType, Args>[]
} & IttyRouterType<RequestType, Args, ResponseType>
Loading