Skip to content

Commit

Permalink
Fix
Browse files Browse the repository at this point in the history
  • Loading branch information
aquapi committed Jul 11, 2024
1 parent 303efeb commit ac491ad
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 81 deletions.
4 changes: 2 additions & 2 deletions bench/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"dependencies": {
"blitz-new": "npm:@bit-js/blitz@latest",
"blitz-old": "npm:@bit-js/[email protected]",
"elysia": "1.0.21",
"hono": "^4.3.9"
"elysia": "latest",
"hono": "latest"
},
"scripts": {
"jit": "BUN_JSC_jitPolicyScale=0.0 BUN_JSC_thresholdForOptimizeSoon=0.0 BUN_JSC_thresholdForJITSoon=0.0 bun run",
Expand Down
7 changes: 6 additions & 1 deletion src/core/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ import type { ProtoSchema } from '../utils/methods';
/**
* Infer client type
*/
export type InferClient<T extends BaseByte> = UnionToIntersection<InferRoutes<T['routes']>>;
export type InferClient<T extends BaseByte> = UnionToIntersection<
InferRoutes<
T['__infer']['routes'],
T['__infer']['fallbackResponse']
>
>;

/**
* Customize client
Expand Down
8 changes: 4 additions & 4 deletions src/core/client/types/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ type RouteFunc<Path extends string, Init, Return> =

type InferReturn<T extends BaseRoute> = Promisify<AwaitedReturn<T['handler']>>;

export type InferRoute<T extends BaseRoute> = {
export type InferRoute<T extends BaseRoute, FallbackResponse> = {
[K in T['method']]: RouteFunc<
T['path'],
RequestProps<T>,
InferReturn<T>
FallbackResponse | InferReturn<T>
>;
};

export type InferRoutes<T extends RoutesRecord> = T extends [infer Route extends BaseRoute, ...infer Rest extends RoutesRecord]
? InferRoute<Route> | InferRoutes<Rest> : {};
export type InferRoutes<T extends RoutesRecord, FallbackResponse> = T extends [infer Route extends BaseRoute, ...infer Rest extends RoutesRecord]
? InferRoute<Route, FallbackResponse> | InferRoutes<Rest, FallbackResponse> : {};
43 changes: 30 additions & 13 deletions src/core/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,40 +37,51 @@ type HandlerRegisters<T extends RoutesRecord, State> = {
/**
* Create a Byte app
*/
export class Byte<Rec extends RoutesRecord = [], State = {}> implements ProtoSchema {
export class Byte<Rec extends RoutesRecord = [], State = {}, FallbackResponse = never> implements ProtoSchema {
readonly actions: ActionList<State> = [];
readonly defers: DeferFn<State>[] = [];

/**
* Register middlewares that doesn't require validations
*/
pass(...fns: Fn<State>[]) {
this.actions.push([1, fns]);
prepare(fn: Fn<State>) {
this.actions.push([1, fn]);
return this;
}

/**
* Register middlewares
*/
use(...fns: Fn<State>[]) {
this.actions.push([2, fns]);
return this;
use<Middleware extends Fn<State>>(fn: Middleware) {
this.actions.push([2, fn]);
return this as Byte<
Rec, State,
FallbackResponse | Extract<AwaitedReturn<Middleware>, GenericResponse>
>;
}

/**
* Bind a prop to the context
*/
set<Name extends string, Getter extends Fn<State>>(name: Name, fn: Getter) {
this.actions.push([3, fn, name]);
return this as Byte<Rec, State & { [K in Name]: AwaitedReturn<Getter> }>;
return this as Byte<
Rec,
State & { [K in Name]: AwaitedReturn<Getter> },
FallbackResponse
>;
}

/**
* Bind a prop to the context
*/
validate<Name extends string, Getter extends Fn<State>>(name: Name, fn: Getter) {
state<Name extends string, Getter extends Fn<State>>(name: Name, fn: Getter) {
this.actions.push([4, fn, name]);
return this as Byte<Rec, State & { [K in Name]: Exclude<AwaitedReturn<Getter>, GenericResponse> }>;
return this as Byte<
Rec,
State & { [K in Name]: Exclude<AwaitedReturn<Getter>, GenericResponse> },
FallbackResponse | Extract<AwaitedReturn<Getter>, GenericResponse>
>;
}

/**
Expand All @@ -89,13 +100,13 @@ export class Byte<Rec extends RoutesRecord = [], State = {}> implements ProtoSch
// @ts-ignore
plugins[i].plug(this);

return this as Byte<Rec, State & InferPluginState<Plugins>>;
return this as Byte<Rec, State & InferPluginState<Plugins>, FallbackResponse>;
}

/**
* Routes record. Only use this to infer types
*/
readonly routes: Rec = [] as any;
readonly routes: RoutesRecord = [];

/**
* Register sub-routes
Expand Down Expand Up @@ -233,9 +244,15 @@ export class Byte<Rec extends RoutesRecord = [], State = {}> implements ProtoSch
}
}

export interface Byte<Rec, State> extends HandlerRegisters<Rec, State> { };
export interface Byte<Rec, State, FallbackResponse> extends HandlerRegisters<Rec, State> {
__infer: {
routes: Rec;
state: State;
fallbackResponse: FallbackResponse;
}
};

export type BaseByte = Byte<RoutesRecord, any>;
export type BaseByte = Byte<RoutesRecord, any, any>;

// Real stuff
export * from './route';
Expand Down
80 changes: 22 additions & 58 deletions src/core/server/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import { isAsync } from './utils/macro';
// Action
export interface Initializer<State> {
0: 1;
1: Fn<State>[];
1: Fn<State>;
}

export interface Middleware<State> {
0: 2;
1: Fn<State>[];
1: Fn<State>;
}

export interface Setter<State> {
Expand Down Expand Up @@ -104,72 +104,36 @@ export class Route<

for (let j = 0, lJ = list.length; j < lJ; ++j) {
const action = list[j];
const actionType = action[0];

if (actionType === 1) {
const fns = action[1];

for (let k = 0, lK = fns.length; k < lK; ++k, ++idx) {
const fn = fns[k];
const fnKey = 'f' + idx;
const fn = action[1];
const fnKey = 'f' + idx;

keys.push(fnKey);
values.push(fn);
keys.push(fnKey);
values.push(fn);

const fnAsync = isAsync(fn);
hasAsync ||= fnAsync;
const fnAsync = isAsync(fn);
hasAsync ||= fnAsync;

const fnNoContext = fn.length === 0;
noContext &&= fnNoContext;
const fnNoContext = fn.length === 0;
noContext &&= fnNoContext;

++idx;
switch (action[0]) {
case 1:
statements.push(`${fnAsync ? 'await ' : ''}${fnKey}(${noContext ? '' : 'c'})`);
}
} else if (actionType === 2) {
const fns = action[1];

for (let k = 0, lK = fns.length; k < lK; ++k, ++idx) {
const fn = fns[k];
const fnKey = 'f' + idx;

keys.push(fnKey);
values.push(fn);

const fnAsync = isAsync(fn);
hasAsync ||= fnAsync;

const fnNoContext = fn.length === 0;
noContext &&= fnNoContext;
continue;

case 2:
statements.push(`const c${idx}=${fnAsync ? 'await ' : ''}${fnKey}(${noContext ? '' : 'c'});if(c${idx} instanceof Response)return c${idx}`);
}
} else if (actionType === 3) {
const fn = action[1];
const fnKey = 'f' + idx;

keys.push(fnKey);
values.push(fn);

const fnAsync = isAsync(fn);
hasAsync ||= fnAsync;

const fnNoContext = fn.length === 0;
noContext &&= fnNoContext;

statements.push(`c.${action[2]}=${fnAsync ? 'await ' : ''}${fnKey}(${noContext ? '' : 'c'})`);
} else if (actionType === 4) {
const fn = action[1];
const fnKey = 'f' + idx;

keys.push(fnKey);
values.push(fn);

const fnAsync = isAsync(fn);
hasAsync ||= fnAsync;
continue;

const fnNoContext = fn.length === 0;
noContext &&= fnNoContext;
case 3:
statements.push(`c.${action[2]}=${fnAsync ? 'await ' : ''}${fnKey}(${noContext ? '' : 'c'})`);
continue;

statements.push(`const c${idx}=${fnAsync ? 'await ' : ''}${fnKey}(${noContext ? '' : 'c'});if(c${idx} instanceof Response)return c${idx};c.${action[2]}=t${idx}`)
case 4:
statements.push(`const c${idx}=${fnAsync ? 'await ' : ''}${fnKey}(${noContext ? '' : 'c'});if(c${idx} instanceof Response)return c${idx};c.${action[2]}=t${idx}`)
continue;
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/plugins/server/csrf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ import { forbidden } from '../../utils/defaultOptions';
/**
* CSRF action options
*/
export interface CSRFOptions {
export interface CSRFOptions<Fallback extends Fn = Fn> {
origins?: string[];
verify?: (origin: string) => boolean;
fallback?: Fn;
fallback?: Fallback;
}

const defaultCSRF: Fn = (ctx) => {
if (ctx.req.headers.get('Origin') !== ctx.req.url.substring(0, ctx.pathStart))
return new Response(null, forbidden);
};

export function csrf(options?: CSRFOptions): Fn {
export function csrf<Options extends CSRFOptions = CSRFOptions>(options?: Options): Options['fallback'] & {} {
if (typeof options === 'undefined') return defaultCSRF;

const literals = [];
Expand Down

0 comments on commit ac491ad

Please sign in to comment.