@controller-contract/server 0.3.3 → 0.4.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/dist/index-DvVe6qYj.d.mts +44 -0
- package/dist/index.d.mts +181 -104
- package/dist/index.mjs +171 -113
- package/dist/utils.d.mts +2 -0
- package/dist/utils.mjs +59 -0
- package/package.json +11 -7
- package/src/classes/controller-builder/controller-builder.ts +24 -0
- package/src/classes/controller-builder/input-builder/input-builder.ts +20 -0
- package/src/classes/controller-builder/input-builder/steps/after-body-step.ts +19 -0
- package/src/classes/controller-builder/input-builder/steps/after-params-step.ts +26 -0
- package/src/classes/controller-builder/input-builder/steps/after-query-step.ts +24 -0
- package/src/classes/controller-builder/steps/endpoint-step.ts +19 -0
- package/src/classes/controller-builder/steps/input-step.ts +67 -0
- package/src/classes/controller-builder/steps/output-step.ts +70 -0
- package/src/classes/controller-router-factory.ts +31 -0
- package/src/classes/controller-router.ts +25 -0
- package/src/classes/framework-setup.ts +28 -0
- package/src/index.ts +1 -2
- package/src/interfaces/controller-blueprint.ts +34 -0
- package/src/interfaces/endable.ts +5 -0
- package/src/interfaces/index.ts +2 -0
- package/src/types/combine-routes-fn.ts +7 -0
- package/src/{classes/controller-contract-controller/controller-contract-controller.ts → types/controller.ts} +5 -5
- package/src/types/create-route-fn.ts +5 -0
- package/src/types/fail-output-from.ts +8 -0
- package/src/types/index.ts +12 -44
- package/src/types/infer-controller-contract.ts +8 -0
- package/src/types/infer-controller-contracts-from-router.ts +3 -3
- package/src/types/input-builder-fn.ts +6 -0
- package/src/types/map-to-controller-contract.ts +7 -0
- package/src/types/no-output-from-inputs.ts +1 -0
- package/src/types/output-fn-outputs.ts +4 -0
- package/src/types/output-fn.ts +23 -0
- package/src/types/prettify.ts +1 -0
- package/src/types/resolved-params.ts +8 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/outputs.ts +9 -28
- package/src/utils/root-only.ts +8 -0
- package/src/utils/standard-outputs.ts +20 -0
- package/src/classes/controller-contract-controller-builder/builder-steps/post-endpoint-step.ts +0 -48
- package/src/classes/controller-contract-controller-builder/builder-steps/post-inject-step.ts +0 -19
- package/src/classes/controller-contract-controller-builder/builder-steps/post-input-step.ts +0 -49
- package/src/classes/controller-contract-controller-builder/controller-contract-controller-builder.ts +0 -24
- package/src/classes/controller-contract-controller-router/controller-contract-controller-router-factory.ts +0 -13
- package/src/classes/controller-contract-controller-router/controller-contract-controller-router.ts +0 -16
- package/src/classes/framework-integration-factory.ts +0 -19
- package/src/interfaces/ControllerContractSpec.ts +0 -25
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExitOutput,
|
|
3
|
+
FailOutput,
|
|
4
|
+
Method,
|
|
5
|
+
PassOutput,
|
|
6
|
+
PathParams,
|
|
7
|
+
} from '@controller-contract/core';
|
|
8
|
+
|
|
9
|
+
import type { ControllerBlueprintSchemas } from '../../../interfaces/controller-blueprint';
|
|
10
|
+
import type {
|
|
11
|
+
CreateRouteFn,
|
|
12
|
+
FailOutputFrom,
|
|
13
|
+
OutputFn,
|
|
14
|
+
Prettify,
|
|
15
|
+
ResolvedParams,
|
|
16
|
+
} from '../../../types';
|
|
17
|
+
import type { Controller } from '../../../types/controller';
|
|
18
|
+
|
|
19
|
+
export class OutputStep<
|
|
20
|
+
TFrameworkContext,
|
|
21
|
+
TFrameworkInjectable,
|
|
22
|
+
TFrameworkRouter,
|
|
23
|
+
const TMethod extends Method,
|
|
24
|
+
const TPath extends string,
|
|
25
|
+
TParams,
|
|
26
|
+
TQuery,
|
|
27
|
+
TBody,
|
|
28
|
+
> {
|
|
29
|
+
constructor(
|
|
30
|
+
private readonly injectable: TFrameworkInjectable,
|
|
31
|
+
private readonly createRoute: CreateRouteFn<
|
|
32
|
+
TFrameworkContext,
|
|
33
|
+
TFrameworkInjectable,
|
|
34
|
+
TFrameworkRouter
|
|
35
|
+
>,
|
|
36
|
+
private readonly method: TMethod,
|
|
37
|
+
private readonly path: TPath,
|
|
38
|
+
private readonly schemas: ControllerBlueprintSchemas<TParams, TQuery, TBody>,
|
|
39
|
+
) {}
|
|
40
|
+
|
|
41
|
+
output<TOutput extends PassOutput<any> | FailOutput<any> | ExitOutput>(
|
|
42
|
+
outputFn: OutputFn<
|
|
43
|
+
TFrameworkContext,
|
|
44
|
+
Prettify<ResolvedParams<TParams, TPath>>,
|
|
45
|
+
TQuery,
|
|
46
|
+
TBody,
|
|
47
|
+
TOutput
|
|
48
|
+
>,
|
|
49
|
+
) {
|
|
50
|
+
const route = this.createRoute({
|
|
51
|
+
injectable: this.injectable,
|
|
52
|
+
method: this.method,
|
|
53
|
+
path: this.path,
|
|
54
|
+
schemas: this.schemas,
|
|
55
|
+
outputFn,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return <
|
|
59
|
+
Controller<
|
|
60
|
+
TMethod,
|
|
61
|
+
TPath,
|
|
62
|
+
Prettify<PathParams<TPath>>,
|
|
63
|
+
TQuery,
|
|
64
|
+
TBody,
|
|
65
|
+
FailOutputFrom<TParams> | FailOutputFrom<TQuery> | FailOutputFrom<TBody> | TOutput,
|
|
66
|
+
TFrameworkRouter
|
|
67
|
+
>
|
|
68
|
+
>(() => route);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CombineRoutesFn } from '../types';
|
|
2
|
+
import type { Controller } from '../types/controller';
|
|
3
|
+
import { ControllerRouter } from './controller-router';
|
|
4
|
+
|
|
5
|
+
type ControllerRouterRecord<TFrameworkRouter> = Record<
|
|
6
|
+
string,
|
|
7
|
+
Controller<any, any, any, any, any, any, TFrameworkRouter>
|
|
8
|
+
>;
|
|
9
|
+
|
|
10
|
+
export class ControllerRouterFactory<TFrameworkRouter> {
|
|
11
|
+
constructor(private readonly combineRoutes: CombineRoutesFn<TFrameworkRouter>) {}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @example
|
|
15
|
+
* const getUser = builder
|
|
16
|
+
* .endpoint('get', '/api/users/:id')
|
|
17
|
+
* .output(async ({ inputs, outputs }) => outputs.pass({ id: inputs.params.id }));
|
|
18
|
+
*
|
|
19
|
+
* const createUser = builder
|
|
20
|
+
* .endpoint('post', '/api/users')
|
|
21
|
+
* .input((s) => s.body(z.object({ name: z.string() })))
|
|
22
|
+
* .output(async ({ inputs, outputs }) => outputs.pass({ name: inputs.body.name }, 201));
|
|
23
|
+
*
|
|
24
|
+
* const usersRouter = controllerRouterFactory.createControllerRouter({ getUser, createUser });
|
|
25
|
+
*/
|
|
26
|
+
createControllerRouter<TRoutes extends ControllerRouterRecord<TFrameworkRouter>>(
|
|
27
|
+
routes: TRoutes,
|
|
28
|
+
) {
|
|
29
|
+
return new ControllerRouter(this.combineRoutes, routes);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { CombineRoutesFn } from '../types';
|
|
2
|
+
import type { Controller } from '../types/controller';
|
|
3
|
+
|
|
4
|
+
export class ControllerRouter<
|
|
5
|
+
TFrameworkRouter,
|
|
6
|
+
TRoutes extends Record<any, Controller<any, any, any, any, any, any, TFrameworkRouter>>,
|
|
7
|
+
> {
|
|
8
|
+
constructor(
|
|
9
|
+
private readonly combineRoutes: CombineRoutesFn<TFrameworkRouter>,
|
|
10
|
+
private readonly routes: TRoutes,
|
|
11
|
+
) {}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @example
|
|
15
|
+
* const usersRouter = controllerRouterFactory.createControllerRouter({ getUser, createUser });
|
|
16
|
+
*
|
|
17
|
+
* const app = express();
|
|
18
|
+
* app.use(express.json());
|
|
19
|
+
* app.use(usersRouter.toRouter());
|
|
20
|
+
* app.listen(3000);
|
|
21
|
+
*/
|
|
22
|
+
toRouter() {
|
|
23
|
+
return this.combineRoutes(this.routes);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { CombineRoutesFn, CreateRouteFn } from '../types';
|
|
2
|
+
import { ControllerBuilder } from './controller-builder/controller-builder';
|
|
3
|
+
import { ControllerRouterFactory } from './controller-router-factory';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @example
|
|
7
|
+
* const setup = new FrameworkSetup<Request, RequestHandler[], Router>();
|
|
8
|
+
*/
|
|
9
|
+
export class FrameworkSetup<TFrameworkContext, TFrameworkInjectable, TFrameworkRouter> {
|
|
10
|
+
/**
|
|
11
|
+
* @example
|
|
12
|
+
* const builder = setup.createControllerBuilder([], (blueprint) => { ... });
|
|
13
|
+
*/
|
|
14
|
+
createControllerBuilder(
|
|
15
|
+
defaultInjectable: TFrameworkInjectable,
|
|
16
|
+
createRoute: CreateRouteFn<TFrameworkContext, TFrameworkInjectable, TFrameworkRouter>,
|
|
17
|
+
) {
|
|
18
|
+
return new ControllerBuilder(defaultInjectable, createRoute);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @example
|
|
23
|
+
* const routerFactory = setup.createControllerRouterFactory((routes) => { ... });
|
|
24
|
+
*/
|
|
25
|
+
createControllerRouterFactory(combineRoutes: CombineRoutesFn<TFrameworkRouter>) {
|
|
26
|
+
return new ControllerRouterFactory(combineRoutes);
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ExitOutput, FailOutput, Method, PassOutput } from '@controller-contract/core';
|
|
2
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
3
|
+
|
|
4
|
+
import type { OutputFnOutputs, Prettify } from '../types';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The true shapes aren't needed at this level. We only need a broad description.
|
|
8
|
+
*/
|
|
9
|
+
export interface ControllerBlueprintSchemas<TParams, TQuery, TBody> {
|
|
10
|
+
params: StandardSchemaV1<any, TParams> | null;
|
|
11
|
+
query: StandardSchemaV1<any, TQuery> | null;
|
|
12
|
+
body: StandardSchemaV1<any, TBody> | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type OutputFnBlueprint<TFrameworkContext> = (
|
|
16
|
+
context: Prettify<
|
|
17
|
+
TFrameworkContext & {
|
|
18
|
+
inputs: {
|
|
19
|
+
params: any;
|
|
20
|
+
query: any;
|
|
21
|
+
body: any;
|
|
22
|
+
};
|
|
23
|
+
outputs: OutputFnOutputs;
|
|
24
|
+
}
|
|
25
|
+
>,
|
|
26
|
+
) => Promise<PassOutput<any> | FailOutput<any> | ExitOutput>;
|
|
27
|
+
|
|
28
|
+
export interface ControllerBlueprint<TFrameworkContext, TFrameworkInjectable> {
|
|
29
|
+
readonly injectable: TFrameworkInjectable;
|
|
30
|
+
readonly method: Method;
|
|
31
|
+
readonly path: string;
|
|
32
|
+
readonly schemas: ControllerBlueprintSchemas<unknown, unknown, unknown>;
|
|
33
|
+
readonly outputFn: OutputFnBlueprint<TFrameworkContext>;
|
|
34
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { Method, Output } from '@controller-contract/core';
|
|
2
2
|
|
|
3
|
-
export type
|
|
3
|
+
export type Controller<
|
|
4
4
|
TMethod extends Method,
|
|
5
5
|
TPath extends string,
|
|
6
6
|
TParamsInput,
|
|
7
7
|
TQueryInput,
|
|
8
8
|
TBodyInput,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
> = (() =>
|
|
9
|
+
TOutput extends Output,
|
|
10
|
+
TFrameworkRouter,
|
|
11
|
+
> = (() => TFrameworkRouter) & {
|
|
12
12
|
// Suppresses the linter warning about unused variables
|
|
13
|
-
'~cc'?: TMethod | TPath | TParamsInput | TQueryInput | TBodyInput |
|
|
13
|
+
'~cc'?: TMethod | TPath | TParamsInput | TQueryInput | TBodyInput | TOutput;
|
|
14
14
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FailOutput, NoInput } from '@controller-contract/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The fail output a validated input can produce. Skipped inputs are `NoInput` and produce none.
|
|
5
|
+
*/
|
|
6
|
+
export type FailOutputFrom<T> = [T] extends [NoInput]
|
|
7
|
+
? never
|
|
8
|
+
: FailOutput<Extract<keyof T, string>>;
|
package/src/types/index.ts
CHANGED
|
@@ -1,44 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
routes: TRoutes,
|
|
14
|
-
) => TRouter;
|
|
15
|
-
|
|
16
|
-
export type Prettify<T> = {
|
|
17
|
-
[K in keyof T]: T[K];
|
|
18
|
-
} & {};
|
|
19
|
-
|
|
20
|
-
export type OutputFn<TFrameworkContext, TPath extends string, TOutput> = (
|
|
21
|
-
context: Prettify<
|
|
22
|
-
TFrameworkContext & {
|
|
23
|
-
params: ParamsFrom<TPath>;
|
|
24
|
-
outputs: typeof outputs;
|
|
25
|
-
}
|
|
26
|
-
>,
|
|
27
|
-
) => Promise<TOutput>;
|
|
28
|
-
|
|
29
|
-
export type SanitizedOutputFn<TFrameworkContext, TPath extends string, TInput, TOutput> = OutputFn<
|
|
30
|
-
TFrameworkContext & { input: TInput },
|
|
31
|
-
TPath,
|
|
32
|
-
TOutput
|
|
33
|
-
>;
|
|
34
|
-
|
|
35
|
-
export type InferControllerContract<T> =
|
|
36
|
-
T extends ControllerContractController<infer M, infer P, any, infer Q, infer B, infer O, any>
|
|
37
|
-
? ControllerContract<M, P, ParamsFrom<P>, Q, B, O>
|
|
38
|
-
: never;
|
|
39
|
-
|
|
40
|
-
export type MapToControllerContract<TRoutes> = {
|
|
41
|
-
[TRouteName in Extract<keyof TRoutes, string> as Capitalize<TRouteName>]: InferControllerContract<
|
|
42
|
-
TRoutes[TRouteName]
|
|
43
|
-
>;
|
|
44
|
-
};
|
|
1
|
+
export * from './combine-routes-fn';
|
|
2
|
+
export * from './controller';
|
|
3
|
+
export * from './create-route-fn';
|
|
4
|
+
export * from './fail-output-from';
|
|
5
|
+
export * from './infer-controller-contract';
|
|
6
|
+
export * from './infer-controller-contracts-from-router';
|
|
7
|
+
export * from './input-builder-fn';
|
|
8
|
+
export * from './map-to-controller-contract';
|
|
9
|
+
export * from './output-fn';
|
|
10
|
+
export * from './output-fn-outputs';
|
|
11
|
+
export * from './prettify';
|
|
12
|
+
export * from './resolved-params';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ControllerContract, PathParams } from '@controller-contract/core';
|
|
2
|
+
|
|
3
|
+
import type { Controller } from './controller';
|
|
4
|
+
|
|
5
|
+
export type InferControllerContract<T> =
|
|
6
|
+
T extends Controller<infer M, infer P, any, infer Q, infer B, infer O, any>
|
|
7
|
+
? ControllerContract<M, P, PathParams<P>, Q, B, O>
|
|
8
|
+
: never;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { MapToControllerContract } from './
|
|
1
|
+
import type { ControllerRouter } from '../classes/controller-router';
|
|
2
|
+
import type { MapToControllerContract } from './map-to-controller-contract';
|
|
3
3
|
|
|
4
4
|
export type InferControllerContractsFromRouter<T> =
|
|
5
|
-
T extends
|
|
5
|
+
T extends ControllerRouter<any, infer TRoutes> ? MapToControllerContract<TRoutes> : never;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { InputBuilder } from '../classes/controller-builder/input-builder/input-builder';
|
|
2
|
+
import type { Endable } from '../interfaces/endable';
|
|
3
|
+
|
|
4
|
+
export type InputBuilderFn<TParams, TQuery, TBody> = (
|
|
5
|
+
inputBuilder: InputBuilder,
|
|
6
|
+
) => Endable<TParams, TQuery, TBody>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type NoOutputFromInputs = never;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ExitOutput, FailOutput, PassOutput } from '@controller-contract/core';
|
|
2
|
+
|
|
3
|
+
import type { OutputFnOutputs } from './output-fn-outputs';
|
|
4
|
+
import type { Prettify } from './prettify';
|
|
5
|
+
|
|
6
|
+
export type OutputFn<
|
|
7
|
+
TFrameworkContext,
|
|
8
|
+
TParams,
|
|
9
|
+
TQuery,
|
|
10
|
+
TBody,
|
|
11
|
+
TOutput extends PassOutput<any> | FailOutput<any> | ExitOutput,
|
|
12
|
+
> = (
|
|
13
|
+
context: Prettify<
|
|
14
|
+
TFrameworkContext & {
|
|
15
|
+
inputs: {
|
|
16
|
+
params: TParams;
|
|
17
|
+
query: TQuery;
|
|
18
|
+
body: TBody;
|
|
19
|
+
};
|
|
20
|
+
outputs: OutputFnOutputs;
|
|
21
|
+
}
|
|
22
|
+
>,
|
|
23
|
+
) => Promise<TOutput>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Prettify<T> = { [K in keyof T]: T[K] } & {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { NoInput, PathParams } from '@controller-contract/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Falls back to the raw path params when no params schema was given.
|
|
5
|
+
*/
|
|
6
|
+
export type ResolvedParams<TParams, TPath extends string> = [TParams] extends [NoInput]
|
|
7
|
+
? PathParams<TPath>
|
|
8
|
+
: TParams;
|
package/src/utils/index.ts
CHANGED
package/src/utils/outputs.ts
CHANGED
|
@@ -1,55 +1,36 @@
|
|
|
1
1
|
import type { ExitOutput, FailOutput, NextOutput, PassOutput } from '@controller-contract/core';
|
|
2
2
|
|
|
3
|
-
export
|
|
4
|
-
|
|
3
|
+
export const outputs = Object.freeze({
|
|
4
|
+
next<T>(data: T, code = 100): NextOutput<T> {
|
|
5
5
|
return {
|
|
6
6
|
type: 'next',
|
|
7
7
|
code,
|
|
8
8
|
data,
|
|
9
9
|
};
|
|
10
|
-
}
|
|
10
|
+
},
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
pass<T>(data: T, code = 200): PassOutput<T> {
|
|
13
13
|
return {
|
|
14
14
|
type: 'pass',
|
|
15
15
|
code,
|
|
16
16
|
data,
|
|
17
17
|
};
|
|
18
|
-
}
|
|
18
|
+
},
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
fail<const T extends string>(data: FailOutput<T>['data'], code = 400): FailOutput<T> {
|
|
21
21
|
return {
|
|
22
22
|
type: 'fail',
|
|
23
23
|
code,
|
|
24
24
|
data,
|
|
25
25
|
};
|
|
26
|
-
}
|
|
26
|
+
},
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Used to escape the controller contract state machine, useful for redirects.
|
|
30
30
|
*/
|
|
31
|
-
|
|
31
|
+
exit(): ExitOutput {
|
|
32
32
|
return {
|
|
33
33
|
type: 'exit',
|
|
34
34
|
};
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function rootOnly(message: string): FailOutput<'root'>['data'] {
|
|
39
|
-
return [{ key: 'root', message }];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const StandardOutputs = Object.freeze({
|
|
43
|
-
// 200
|
|
44
|
-
OK: outputs.pass(rootOnly('ok'), 200),
|
|
45
|
-
Created: outputs.pass(rootOnly('Created'), 201),
|
|
46
|
-
Accepted: outputs.pass(rootOnly('Accepted'), 202),
|
|
47
|
-
// 400
|
|
48
|
-
BadRequest: outputs.fail(rootOnly('Bad Request'), 400),
|
|
49
|
-
Unauthorized: outputs.fail(rootOnly('Unauthorized'), 401),
|
|
50
|
-
Forbidden: outputs.fail(rootOnly('Forbidden'), 403),
|
|
51
|
-
NotFound: outputs.fail(rootOnly('Not Found'), 404),
|
|
52
|
-
// 500
|
|
53
|
-
InternalServerError: outputs.fail(rootOnly('Internal Server Error'), 500),
|
|
54
|
-
BadGateway: outputs.fail(rootOnly('Bad Gateway'), 502),
|
|
35
|
+
},
|
|
55
36
|
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { outputs } from './outputs';
|
|
2
|
+
import { rootOnly } from './root-only';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Useful for quick http basic responses.
|
|
6
|
+
*/
|
|
7
|
+
export const StandardOutputs = Object.freeze({
|
|
8
|
+
// 200
|
|
9
|
+
OK: outputs.pass(rootOnly('ok'), 200),
|
|
10
|
+
Created: outputs.pass(rootOnly('Created'), 201),
|
|
11
|
+
Accepted: outputs.pass(rootOnly('Accepted'), 202),
|
|
12
|
+
// 400
|
|
13
|
+
BadRequest: outputs.fail(rootOnly('Bad Request'), 400),
|
|
14
|
+
Unauthorized: outputs.fail(rootOnly('Unauthorized'), 401),
|
|
15
|
+
Forbidden: outputs.fail(rootOnly('Forbidden'), 403),
|
|
16
|
+
NotFound: outputs.fail(rootOnly('Not Found'), 404),
|
|
17
|
+
// 500
|
|
18
|
+
InternalServerError: outputs.fail(rootOnly('Internal Server Error'), 500),
|
|
19
|
+
BadGateway: outputs.fail(rootOnly('Bad Gateway'), 502),
|
|
20
|
+
});
|
package/src/classes/controller-contract-controller-builder/builder-steps/post-endpoint-step.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { FailOutput, InputChannel, Method, NoInput, Output, ParamsFrom } from '@controller-contract/core';
|
|
2
|
-
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
3
|
-
import type { NullaryControllerContractSpec } from '../../../interfaces/ControllerContractSpec';
|
|
4
|
-
import type { BuilderIntegratorFn, OutputFn } from '../../../types';
|
|
5
|
-
import type { ControllerContractController } from '../../controller-contract-controller/controller-contract-controller';
|
|
6
|
-
import { PostInputStep } from './post-input-step';
|
|
7
|
-
|
|
8
|
-
export class PostEndpointStep<
|
|
9
|
-
TFrameworkContext,
|
|
10
|
-
TFrameworkInject,
|
|
11
|
-
TRouter,
|
|
12
|
-
const TMethod extends Method,
|
|
13
|
-
const TPath extends string,
|
|
14
|
-
> {
|
|
15
|
-
constructor(
|
|
16
|
-
private readonly injectable: TFrameworkInject,
|
|
17
|
-
private readonly integrator: BuilderIntegratorFn<TFrameworkContext, TFrameworkInject, TRouter>,
|
|
18
|
-
private readonly method: TMethod,
|
|
19
|
-
private readonly path: TPath,
|
|
20
|
-
) {}
|
|
21
|
-
|
|
22
|
-
input<const TChannel extends InputChannel, TInput>(channel: TChannel, schema: StandardSchemaV1<TInput>) {
|
|
23
|
-
return new PostInputStep<
|
|
24
|
-
TFrameworkContext,
|
|
25
|
-
TFrameworkInject,
|
|
26
|
-
TRouter,
|
|
27
|
-
TMethod,
|
|
28
|
-
TPath,
|
|
29
|
-
TChannel,
|
|
30
|
-
TInput,
|
|
31
|
-
FailOutput<Extract<keyof TInput, string>>
|
|
32
|
-
>(this.injectable, this.integrator, this.method, this.path, channel, schema);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
output<TOutput extends Output>(outputFn: OutputFn<TFrameworkContext, TPath, TOutput>) {
|
|
36
|
-
const product = this.integrator(<NullaryControllerContractSpec<TFrameworkContext, TFrameworkInject>>{
|
|
37
|
-
type: 'nullary',
|
|
38
|
-
method: this.method,
|
|
39
|
-
path: this.path,
|
|
40
|
-
injectable: this.injectable,
|
|
41
|
-
outputFn,
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
return <ControllerContractController<TMethod, TPath, ParamsFrom<TPath>, NoInput, NoInput, TOutput, TRouter>>(
|
|
45
|
-
(() => product)
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
}
|
package/src/classes/controller-contract-controller-builder/builder-steps/post-inject-step.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { Method } from '@controller-contract/core';
|
|
2
|
-
import type { BuilderIntegratorFn } from '../../../types';
|
|
3
|
-
import { PostEndpointStep } from './post-endpoint-step';
|
|
4
|
-
|
|
5
|
-
export class PostInjectStep<TFrameworkContext, TFrameworkInject, TRouter> {
|
|
6
|
-
constructor(
|
|
7
|
-
private readonly injectable: TFrameworkInject,
|
|
8
|
-
private readonly integrator: BuilderIntegratorFn<TFrameworkContext, TFrameworkInject, TRouter>,
|
|
9
|
-
) {}
|
|
10
|
-
|
|
11
|
-
endpoint<const TMethod extends Method, const TPath extends string>(method: TMethod, path: TPath) {
|
|
12
|
-
return new PostEndpointStep<TFrameworkContext, TFrameworkInject, TRouter, TMethod, TPath>(
|
|
13
|
-
this.injectable,
|
|
14
|
-
this.integrator,
|
|
15
|
-
method,
|
|
16
|
-
path,
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type { InputChannel, Method, NoInput, Output, ParamsFrom } from '@controller-contract/core';
|
|
2
|
-
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
3
|
-
import type { SanitizedControllerContractSpec } from '../../../interfaces/ControllerContractSpec';
|
|
4
|
-
import type { BuilderIntegratorFn, SanitizedOutputFn } from '../../../types';
|
|
5
|
-
import type { ControllerContractController } from '../../controller-contract-controller/controller-contract-controller';
|
|
6
|
-
|
|
7
|
-
export class PostInputStep<
|
|
8
|
-
TFrameworkContext,
|
|
9
|
-
TFrameworkInject,
|
|
10
|
-
TRouter,
|
|
11
|
-
const TMethod extends Method,
|
|
12
|
-
const TPath extends string,
|
|
13
|
-
const TChannel extends InputChannel,
|
|
14
|
-
TInput,
|
|
15
|
-
TOutputFromInput extends Output,
|
|
16
|
-
> {
|
|
17
|
-
constructor(
|
|
18
|
-
private readonly injectable: TFrameworkInject,
|
|
19
|
-
private readonly integrator: BuilderIntegratorFn<TFrameworkContext, TFrameworkInject, TRouter>,
|
|
20
|
-
private readonly method: TMethod,
|
|
21
|
-
private readonly path: TPath,
|
|
22
|
-
private readonly channel: TChannel,
|
|
23
|
-
private readonly schema: StandardSchemaV1<TInput>,
|
|
24
|
-
) {}
|
|
25
|
-
|
|
26
|
-
output<TOutput extends Output>(outputFn: SanitizedOutputFn<TFrameworkContext, TPath, TInput, TOutput>) {
|
|
27
|
-
const product = this.integrator(<SanitizedControllerContractSpec<TFrameworkContext, TFrameworkInject>>{
|
|
28
|
-
type: 'sanitized',
|
|
29
|
-
injectable: this.injectable,
|
|
30
|
-
method: this.method,
|
|
31
|
-
path: this.path,
|
|
32
|
-
channel: this.channel,
|
|
33
|
-
schema: this.schema,
|
|
34
|
-
outputFn,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
return <
|
|
38
|
-
ControllerContractController<
|
|
39
|
-
TMethod,
|
|
40
|
-
TPath,
|
|
41
|
-
ParamsFrom<TPath>,
|
|
42
|
-
TChannel extends 'query' ? TInput : NoInput,
|
|
43
|
-
TChannel extends 'body' ? TInput : NoInput,
|
|
44
|
-
TOutputFromInput | TOutput,
|
|
45
|
-
TRouter
|
|
46
|
-
>
|
|
47
|
-
>(() => product);
|
|
48
|
-
}
|
|
49
|
-
}
|
package/src/classes/controller-contract-controller-builder/controller-contract-controller-builder.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { Method } from '@controller-contract/core';
|
|
2
|
-
import type { BuilderIntegratorFn } from '../../types';
|
|
3
|
-
import { PostEndpointStep } from './builder-steps/post-endpoint-step';
|
|
4
|
-
import { PostInjectStep } from './builder-steps/post-inject-step';
|
|
5
|
-
|
|
6
|
-
export class ControllerContractControllerBuilder<TFrameworkContext, TFrameworkInject, TFrameworkRouter> {
|
|
7
|
-
constructor(
|
|
8
|
-
private readonly injectableDefaultValue: TFrameworkInject,
|
|
9
|
-
private readonly integrator: BuilderIntegratorFn<TFrameworkContext, TFrameworkInject, TFrameworkRouter>,
|
|
10
|
-
) {}
|
|
11
|
-
|
|
12
|
-
inject(injectable: TFrameworkInject) {
|
|
13
|
-
return new PostInjectStep<TFrameworkContext, TFrameworkInject, TFrameworkRouter>(injectable, this.integrator);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
endpoint<const TMethod extends Method, const TPath extends string>(method: TMethod, path: TPath) {
|
|
17
|
-
return new PostEndpointStep<TFrameworkContext, TFrameworkInject, TFrameworkRouter, TMethod, TPath>(
|
|
18
|
-
this.injectableDefaultValue,
|
|
19
|
-
this.integrator,
|
|
20
|
-
method,
|
|
21
|
-
path,
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { RouterIntegratorFn } from '../../types';
|
|
2
|
-
import type { ControllerContractController } from '../controller-contract-controller/controller-contract-controller';
|
|
3
|
-
import { ControllerContractControllerRouter } from './controller-contract-controller-router';
|
|
4
|
-
|
|
5
|
-
export class ControllerContractControllerRouterFactory<TRouter> {
|
|
6
|
-
constructor(private readonly integrator: RouterIntegratorFn<TRouter>) {}
|
|
7
|
-
|
|
8
|
-
createControllerContractControllerRouter<
|
|
9
|
-
TRoutes extends Record<any, ControllerContractController<any, any, any, any, any, any, TRouter>>,
|
|
10
|
-
>(routes: TRoutes) {
|
|
11
|
-
return new ControllerContractControllerRouter(this.integrator, routes);
|
|
12
|
-
}
|
|
13
|
-
}
|