@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
package/dist/index.mjs
CHANGED
|
@@ -1,171 +1,229 @@
|
|
|
1
|
-
//#region src/classes/controller-
|
|
2
|
-
var
|
|
1
|
+
//#region src/classes/controller-builder/input-builder/steps/after-body-step.ts
|
|
2
|
+
var AfterBodyStep = class {
|
|
3
|
+
paramsSchema;
|
|
4
|
+
querySchema;
|
|
5
|
+
bodySchema;
|
|
6
|
+
constructor(paramsSchema, querySchema, bodySchema) {
|
|
7
|
+
this.paramsSchema = paramsSchema;
|
|
8
|
+
this.querySchema = querySchema;
|
|
9
|
+
this.bodySchema = bodySchema;
|
|
10
|
+
}
|
|
11
|
+
getSchemas() {
|
|
12
|
+
return {
|
|
13
|
+
params: this.paramsSchema,
|
|
14
|
+
query: this.querySchema,
|
|
15
|
+
body: this.bodySchema
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/classes/controller-builder/input-builder/steps/after-query-step.ts
|
|
21
|
+
var AfterQueryStep = class {
|
|
22
|
+
paramsSchema;
|
|
23
|
+
querySchema;
|
|
24
|
+
constructor(paramsSchema, querySchema) {
|
|
25
|
+
this.paramsSchema = paramsSchema;
|
|
26
|
+
this.querySchema = querySchema;
|
|
27
|
+
}
|
|
28
|
+
body(schema) {
|
|
29
|
+
return new AfterBodyStep(this.paramsSchema, this.querySchema, schema);
|
|
30
|
+
}
|
|
31
|
+
getSchemas() {
|
|
32
|
+
return {
|
|
33
|
+
params: this.paramsSchema,
|
|
34
|
+
query: this.querySchema,
|
|
35
|
+
body: null
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/classes/controller-builder/input-builder/steps/after-params-step.ts
|
|
41
|
+
var AfterParamsStep = class {
|
|
42
|
+
paramsSchema;
|
|
43
|
+
constructor(paramsSchema) {
|
|
44
|
+
this.paramsSchema = paramsSchema;
|
|
45
|
+
}
|
|
46
|
+
query(schema) {
|
|
47
|
+
return new AfterQueryStep(this.paramsSchema, schema);
|
|
48
|
+
}
|
|
49
|
+
body(schema) {
|
|
50
|
+
return new AfterBodyStep(this.paramsSchema, null, schema);
|
|
51
|
+
}
|
|
52
|
+
getSchemas() {
|
|
53
|
+
return {
|
|
54
|
+
params: this.paramsSchema,
|
|
55
|
+
query: null,
|
|
56
|
+
body: null
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/classes/controller-builder/input-builder/input-builder.ts
|
|
62
|
+
var InputBuilder = class {
|
|
63
|
+
params(schema) {
|
|
64
|
+
return new AfterParamsStep(schema);
|
|
65
|
+
}
|
|
66
|
+
query(schema) {
|
|
67
|
+
return new AfterQueryStep(null, schema);
|
|
68
|
+
}
|
|
69
|
+
body(schema) {
|
|
70
|
+
return new AfterBodyStep(null, null, schema);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/classes/controller-builder/steps/output-step.ts
|
|
75
|
+
var OutputStep = class {
|
|
3
76
|
injectable;
|
|
4
|
-
|
|
77
|
+
createRoute;
|
|
5
78
|
method;
|
|
6
79
|
path;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
constructor(injectable, integrator, method, path, channel, schema) {
|
|
80
|
+
schemas;
|
|
81
|
+
constructor(injectable, createRoute, method, path, schemas) {
|
|
10
82
|
this.injectable = injectable;
|
|
11
|
-
this.
|
|
83
|
+
this.createRoute = createRoute;
|
|
12
84
|
this.method = method;
|
|
13
85
|
this.path = path;
|
|
14
|
-
this.
|
|
15
|
-
this.schema = schema;
|
|
86
|
+
this.schemas = schemas;
|
|
16
87
|
}
|
|
17
88
|
output(outputFn) {
|
|
18
|
-
const
|
|
19
|
-
type: "sanitized",
|
|
89
|
+
const route = this.createRoute({
|
|
20
90
|
injectable: this.injectable,
|
|
21
91
|
method: this.method,
|
|
22
92
|
path: this.path,
|
|
23
|
-
|
|
24
|
-
schema: this.schema,
|
|
93
|
+
schemas: this.schemas,
|
|
25
94
|
outputFn
|
|
26
95
|
});
|
|
27
|
-
return (() =>
|
|
96
|
+
return (() => route);
|
|
28
97
|
}
|
|
29
98
|
};
|
|
30
99
|
//#endregion
|
|
31
|
-
//#region src/classes/controller-
|
|
32
|
-
var
|
|
100
|
+
//#region src/classes/controller-builder/steps/input-step.ts
|
|
101
|
+
var InputStep = class {
|
|
33
102
|
injectable;
|
|
34
|
-
|
|
103
|
+
createRoute;
|
|
35
104
|
method;
|
|
36
105
|
path;
|
|
37
|
-
constructor(injectable,
|
|
106
|
+
constructor(injectable, createRoute, method, path) {
|
|
38
107
|
this.injectable = injectable;
|
|
39
|
-
this.
|
|
108
|
+
this.createRoute = createRoute;
|
|
40
109
|
this.method = method;
|
|
41
110
|
this.path = path;
|
|
42
111
|
}
|
|
43
|
-
input(
|
|
44
|
-
|
|
112
|
+
input(inputBuilderFn) {
|
|
113
|
+
const schemas = inputBuilderFn(new InputBuilder()).getSchemas();
|
|
114
|
+
return new OutputStep(this.injectable, this.createRoute, this.method, this.path, schemas);
|
|
45
115
|
}
|
|
46
116
|
output(outputFn) {
|
|
47
|
-
const
|
|
48
|
-
|
|
117
|
+
const route = this.createRoute({
|
|
118
|
+
injectable: this.injectable,
|
|
49
119
|
method: this.method,
|
|
50
120
|
path: this.path,
|
|
51
|
-
|
|
121
|
+
schemas: {
|
|
122
|
+
params: null,
|
|
123
|
+
query: null,
|
|
124
|
+
body: null
|
|
125
|
+
},
|
|
52
126
|
outputFn
|
|
53
127
|
});
|
|
54
|
-
return (() =>
|
|
128
|
+
return (() => route);
|
|
55
129
|
}
|
|
56
130
|
};
|
|
57
131
|
//#endregion
|
|
58
|
-
//#region src/classes/controller-
|
|
59
|
-
var
|
|
132
|
+
//#region src/classes/controller-builder/steps/endpoint-step.ts
|
|
133
|
+
var EndpointStep = class {
|
|
60
134
|
injectable;
|
|
61
|
-
|
|
62
|
-
constructor(injectable,
|
|
135
|
+
createRoute;
|
|
136
|
+
constructor(injectable, createRoute) {
|
|
63
137
|
this.injectable = injectable;
|
|
64
|
-
this.
|
|
138
|
+
this.createRoute = createRoute;
|
|
65
139
|
}
|
|
66
140
|
endpoint(method, path) {
|
|
67
|
-
return new
|
|
141
|
+
return new InputStep(this.injectable, this.createRoute, method, path);
|
|
68
142
|
}
|
|
69
143
|
};
|
|
70
144
|
//#endregion
|
|
71
|
-
//#region src/classes/controller-
|
|
72
|
-
var
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
constructor(
|
|
76
|
-
this.
|
|
77
|
-
this.
|
|
145
|
+
//#region src/classes/controller-builder/controller-builder.ts
|
|
146
|
+
var ControllerBuilder = class {
|
|
147
|
+
defaultInjectable;
|
|
148
|
+
createRoute;
|
|
149
|
+
constructor(defaultInjectable, createRoute) {
|
|
150
|
+
this.defaultInjectable = defaultInjectable;
|
|
151
|
+
this.createRoute = createRoute;
|
|
78
152
|
}
|
|
79
153
|
inject(injectable) {
|
|
80
|
-
return new
|
|
154
|
+
return new EndpointStep(injectable, this.createRoute);
|
|
81
155
|
}
|
|
82
156
|
endpoint(method, path) {
|
|
83
|
-
return new
|
|
157
|
+
return new InputStep(this.defaultInjectable, this.createRoute, method, path);
|
|
84
158
|
}
|
|
85
159
|
};
|
|
86
160
|
//#endregion
|
|
87
|
-
//#region src/classes/controller-
|
|
88
|
-
var
|
|
89
|
-
|
|
161
|
+
//#region src/classes/controller-router.ts
|
|
162
|
+
var ControllerRouter = class {
|
|
163
|
+
combineRoutes;
|
|
90
164
|
routes;
|
|
91
|
-
constructor(
|
|
92
|
-
this.
|
|
165
|
+
constructor(combineRoutes, routes) {
|
|
166
|
+
this.combineRoutes = combineRoutes;
|
|
93
167
|
this.routes = routes;
|
|
94
168
|
}
|
|
95
|
-
|
|
96
|
-
|
|
169
|
+
/**
|
|
170
|
+
* @example
|
|
171
|
+
* const usersRouter = controllerRouterFactory.createControllerRouter({ getUser, createUser });
|
|
172
|
+
*
|
|
173
|
+
* const app = express();
|
|
174
|
+
* app.use(express.json());
|
|
175
|
+
* app.use(usersRouter.toRouter());
|
|
176
|
+
* app.listen(3000);
|
|
177
|
+
*/
|
|
178
|
+
toRouter() {
|
|
179
|
+
return this.combineRoutes(this.routes);
|
|
97
180
|
}
|
|
98
181
|
};
|
|
99
182
|
//#endregion
|
|
100
|
-
//#region src/classes/controller-
|
|
101
|
-
var
|
|
102
|
-
|
|
103
|
-
constructor(
|
|
104
|
-
this.
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
183
|
+
//#region src/classes/controller-router-factory.ts
|
|
184
|
+
var ControllerRouterFactory = class {
|
|
185
|
+
combineRoutes;
|
|
186
|
+
constructor(combineRoutes) {
|
|
187
|
+
this.combineRoutes = combineRoutes;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* @example
|
|
191
|
+
* const getUser = builder
|
|
192
|
+
* .endpoint('get', '/api/users/:id')
|
|
193
|
+
* .output(async ({ inputs, outputs }) => outputs.pass({ id: inputs.params.id }));
|
|
194
|
+
*
|
|
195
|
+
* const createUser = builder
|
|
196
|
+
* .endpoint('post', '/api/users')
|
|
197
|
+
* .input((s) => s.body(z.object({ name: z.string() })))
|
|
198
|
+
* .output(async ({ inputs, outputs }) => outputs.pass({ name: inputs.body.name }, 201));
|
|
199
|
+
*
|
|
200
|
+
* const usersRouter = controllerRouterFactory.createControllerRouter({ getUser, createUser });
|
|
201
|
+
*/
|
|
202
|
+
createControllerRouter(routes) {
|
|
203
|
+
return new ControllerRouter(this.combineRoutes, routes);
|
|
108
204
|
}
|
|
109
205
|
};
|
|
110
206
|
//#endregion
|
|
111
|
-
//#region src/classes/framework-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
207
|
+
//#region src/classes/framework-setup.ts
|
|
208
|
+
/**
|
|
209
|
+
* @example
|
|
210
|
+
* const setup = new FrameworkSetup<Request, RequestHandler[], Router>();
|
|
211
|
+
*/
|
|
212
|
+
var FrameworkSetup = class {
|
|
213
|
+
/**
|
|
214
|
+
* @example
|
|
215
|
+
* const builder = setup.createControllerBuilder([], (blueprint) => { ... });
|
|
216
|
+
*/
|
|
217
|
+
createControllerBuilder(defaultInjectable, createRoute) {
|
|
218
|
+
return new ControllerBuilder(defaultInjectable, createRoute);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* @example
|
|
222
|
+
* const routerFactory = setup.createControllerRouterFactory((routes) => { ... });
|
|
223
|
+
*/
|
|
224
|
+
createControllerRouterFactory(combineRoutes) {
|
|
225
|
+
return new ControllerRouterFactory(combineRoutes);
|
|
118
226
|
}
|
|
119
227
|
};
|
|
120
228
|
//#endregion
|
|
121
|
-
|
|
122
|
-
let outputs;
|
|
123
|
-
(function(_outputs) {
|
|
124
|
-
function next(data, code = 100) {
|
|
125
|
-
return {
|
|
126
|
-
type: "next",
|
|
127
|
-
code,
|
|
128
|
-
data
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
_outputs.next = next;
|
|
132
|
-
function pass(data, code = 200) {
|
|
133
|
-
return {
|
|
134
|
-
type: "pass",
|
|
135
|
-
code,
|
|
136
|
-
data
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
_outputs.pass = pass;
|
|
140
|
-
function fail(data, code = 400) {
|
|
141
|
-
return {
|
|
142
|
-
type: "fail",
|
|
143
|
-
code,
|
|
144
|
-
data
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
_outputs.fail = fail;
|
|
148
|
-
function exit() {
|
|
149
|
-
return { type: "exit" };
|
|
150
|
-
}
|
|
151
|
-
_outputs.exit = exit;
|
|
152
|
-
})(outputs || (outputs = {}));
|
|
153
|
-
function rootOnly(message) {
|
|
154
|
-
return [{
|
|
155
|
-
key: "root",
|
|
156
|
-
message
|
|
157
|
-
}];
|
|
158
|
-
}
|
|
159
|
-
const StandardOutputs = Object.freeze({
|
|
160
|
-
OK: outputs.pass(rootOnly("ok"), 200),
|
|
161
|
-
Created: outputs.pass(rootOnly("Created"), 201),
|
|
162
|
-
Accepted: outputs.pass(rootOnly("Accepted"), 202),
|
|
163
|
-
BadRequest: outputs.fail(rootOnly("Bad Request"), 400),
|
|
164
|
-
Unauthorized: outputs.fail(rootOnly("Unauthorized"), 401),
|
|
165
|
-
Forbidden: outputs.fail(rootOnly("Forbidden"), 403),
|
|
166
|
-
NotFound: outputs.fail(rootOnly("Not Found"), 404),
|
|
167
|
-
InternalServerError: outputs.fail(rootOnly("Internal Server Error"), 500),
|
|
168
|
-
BadGateway: outputs.fail(rootOnly("Bad Gateway"), 502)
|
|
169
|
-
});
|
|
170
|
-
//#endregion
|
|
171
|
-
export { FrameworkIntegrationFactory, StandardOutputs, outputs, rootOnly };
|
|
229
|
+
export { FrameworkSetup };
|
package/dist/utils.d.mts
ADDED
package/dist/utils.mjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
//#region src/utils/outputs.ts
|
|
2
|
+
const outputs = Object.freeze({
|
|
3
|
+
next(data, code = 100) {
|
|
4
|
+
return {
|
|
5
|
+
type: "next",
|
|
6
|
+
code,
|
|
7
|
+
data
|
|
8
|
+
};
|
|
9
|
+
},
|
|
10
|
+
pass(data, code = 200) {
|
|
11
|
+
return {
|
|
12
|
+
type: "pass",
|
|
13
|
+
code,
|
|
14
|
+
data
|
|
15
|
+
};
|
|
16
|
+
},
|
|
17
|
+
fail(data, code = 400) {
|
|
18
|
+
return {
|
|
19
|
+
type: "fail",
|
|
20
|
+
code,
|
|
21
|
+
data
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
/**
|
|
25
|
+
* Used to escape the controller contract state machine, useful for redirects.
|
|
26
|
+
*/
|
|
27
|
+
exit() {
|
|
28
|
+
return { type: "exit" };
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/utils/root-only.ts
|
|
33
|
+
/**
|
|
34
|
+
* Useful for quickly sending a root level error to the client.
|
|
35
|
+
*/
|
|
36
|
+
function rootOnly(message) {
|
|
37
|
+
return [{
|
|
38
|
+
key: "root",
|
|
39
|
+
message
|
|
40
|
+
}];
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/utils/standard-outputs.ts
|
|
44
|
+
/**
|
|
45
|
+
* Useful for quick http basic responses.
|
|
46
|
+
*/
|
|
47
|
+
const StandardOutputs = Object.freeze({
|
|
48
|
+
OK: outputs.pass(rootOnly("ok"), 200),
|
|
49
|
+
Created: outputs.pass(rootOnly("Created"), 201),
|
|
50
|
+
Accepted: outputs.pass(rootOnly("Accepted"), 202),
|
|
51
|
+
BadRequest: outputs.fail(rootOnly("Bad Request"), 400),
|
|
52
|
+
Unauthorized: outputs.fail(rootOnly("Unauthorized"), 401),
|
|
53
|
+
Forbidden: outputs.fail(rootOnly("Forbidden"), 403),
|
|
54
|
+
NotFound: outputs.fail(rootOnly("Not Found"), 404),
|
|
55
|
+
InternalServerError: outputs.fail(rootOnly("Internal Server Error"), 500),
|
|
56
|
+
BadGateway: outputs.fail(rootOnly("Bad Gateway"), 502)
|
|
57
|
+
});
|
|
58
|
+
//#endregion
|
|
59
|
+
export { StandardOutputs, outputs, rootOnly };
|
package/package.json
CHANGED
|
@@ -1,30 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@controller-contract/server",
|
|
3
|
-
"
|
|
4
|
-
"version": "0.3.3",
|
|
5
|
-
"author": "kennychulo",
|
|
3
|
+
"version": "0.4.0",
|
|
6
4
|
"license": "MIT",
|
|
5
|
+
"author": "kennychulo",
|
|
7
6
|
"files": [
|
|
8
7
|
"dist",
|
|
9
8
|
"src",
|
|
10
9
|
"LICENSE",
|
|
11
10
|
"package.json"
|
|
12
11
|
],
|
|
12
|
+
"type": "module",
|
|
13
13
|
"exports": {
|
|
14
14
|
".": "./dist/index.mjs",
|
|
15
|
+
"./utils": "./dist/utils.mjs",
|
|
15
16
|
"./package.json": "./package.json"
|
|
16
17
|
},
|
|
17
18
|
"publishConfig": {
|
|
18
19
|
"access": "public"
|
|
19
20
|
},
|
|
20
|
-
"devDependencies": {
|
|
21
|
-
"@controller-contract/core": "0.3.2"
|
|
22
|
-
},
|
|
23
21
|
"dependencies": {
|
|
24
22
|
"@standard-schema/spec": "1.1.0"
|
|
25
23
|
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@controller-contract/core": "0.4.2"
|
|
26
|
+
},
|
|
26
27
|
"peerDependencies": {
|
|
27
|
-
"@controller-contract/core": "0.
|
|
28
|
+
"@controller-contract/core": "0.4.2"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=24"
|
|
28
32
|
},
|
|
29
33
|
"scripts": {
|
|
30
34
|
"build": "tsdown",
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Method } from '@controller-contract/core';
|
|
2
|
+
|
|
3
|
+
import type { CreateRouteFn } from '../../types';
|
|
4
|
+
import { EndpointStep } from './steps/endpoint-step';
|
|
5
|
+
import { InputStep } from './steps/input-step';
|
|
6
|
+
|
|
7
|
+
export class ControllerBuilder<TFrameworkContext, TFrameworkInjectable, TFrameworkRouter> {
|
|
8
|
+
constructor(
|
|
9
|
+
private readonly defaultInjectable: TFrameworkInjectable,
|
|
10
|
+
private readonly createRoute: CreateRouteFn<
|
|
11
|
+
TFrameworkContext,
|
|
12
|
+
TFrameworkInjectable,
|
|
13
|
+
TFrameworkRouter
|
|
14
|
+
>,
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
inject(injectable: TFrameworkInjectable) {
|
|
18
|
+
return new EndpointStep(injectable, this.createRoute);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
endpoint<const TMethod extends Method, const TPath extends string>(method: TMethod, path: TPath) {
|
|
22
|
+
return new InputStep(this.defaultInjectable, this.createRoute, method, path);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { NoInput } from '@controller-contract/core';
|
|
2
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
3
|
+
|
|
4
|
+
import { AfterBodyStep } from './steps/after-body-step';
|
|
5
|
+
import { AfterParamsStep } from './steps/after-params-step';
|
|
6
|
+
import { AfterQueryStep } from './steps/after-query-step';
|
|
7
|
+
|
|
8
|
+
export class InputBuilder {
|
|
9
|
+
params<TParams>(schema: StandardSchemaV1<any, TParams>) {
|
|
10
|
+
return new AfterParamsStep<TParams>(schema);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
query<TQuery>(schema: StandardSchemaV1<any, TQuery>) {
|
|
14
|
+
return new AfterQueryStep<NoInput, TQuery>(null, schema);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
body<TBody>(schema: StandardSchemaV1<any, TBody>) {
|
|
18
|
+
return new AfterBodyStep<NoInput, NoInput, TBody>(null, null, schema);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
|
|
3
|
+
import type { ControllerBlueprintSchemas, Endable } from '../../../../interfaces';
|
|
4
|
+
|
|
5
|
+
export class AfterBodyStep<TParams, TQuery, TBody> implements Endable<TParams, TQuery, TBody> {
|
|
6
|
+
constructor(
|
|
7
|
+
private readonly paramsSchema: StandardSchemaV1<any, TParams> | null,
|
|
8
|
+
private readonly querySchema: StandardSchemaV1<any, TQuery> | null,
|
|
9
|
+
private readonly bodySchema: StandardSchemaV1<any, TBody>,
|
|
10
|
+
) {}
|
|
11
|
+
|
|
12
|
+
getSchemas(): ControllerBlueprintSchemas<TParams, TQuery, TBody> {
|
|
13
|
+
return {
|
|
14
|
+
params: this.paramsSchema,
|
|
15
|
+
query: this.querySchema,
|
|
16
|
+
body: this.bodySchema,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { NoInput } from '@controller-contract/core';
|
|
2
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
3
|
+
|
|
4
|
+
import type { ControllerBlueprintSchemas, Endable } from '../../../../interfaces';
|
|
5
|
+
import { AfterBodyStep } from './after-body-step';
|
|
6
|
+
import { AfterQueryStep } from './after-query-step';
|
|
7
|
+
|
|
8
|
+
export class AfterParamsStep<TParams> implements Endable<TParams, NoInput, NoInput> {
|
|
9
|
+
constructor(private readonly paramsSchema: StandardSchemaV1<any, TParams>) {}
|
|
10
|
+
|
|
11
|
+
query<TQuery>(schema: StandardSchemaV1<any, TQuery>) {
|
|
12
|
+
return new AfterQueryStep<TParams, TQuery>(this.paramsSchema, schema);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
body<TBody>(schema: StandardSchemaV1<any, TBody>) {
|
|
16
|
+
return new AfterBodyStep<TParams, NoInput, TBody>(this.paramsSchema, null, schema);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
getSchemas(): ControllerBlueprintSchemas<TParams, NoInput, NoInput> {
|
|
20
|
+
return {
|
|
21
|
+
params: this.paramsSchema,
|
|
22
|
+
query: null,
|
|
23
|
+
body: null,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { NoInput } from '@controller-contract/core';
|
|
2
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
3
|
+
|
|
4
|
+
import type { ControllerBlueprintSchemas, Endable } from '../../../../interfaces';
|
|
5
|
+
import { AfterBodyStep } from './after-body-step';
|
|
6
|
+
|
|
7
|
+
export class AfterQueryStep<TParams, TQuery> implements Endable<TParams, TQuery, NoInput> {
|
|
8
|
+
constructor(
|
|
9
|
+
private readonly paramsSchema: StandardSchemaV1<any, TParams> | null,
|
|
10
|
+
private readonly querySchema: StandardSchemaV1<any, TQuery>,
|
|
11
|
+
) {}
|
|
12
|
+
|
|
13
|
+
body<TBody>(schema: StandardSchemaV1<any, TBody>) {
|
|
14
|
+
return new AfterBodyStep<TParams, TQuery, TBody>(this.paramsSchema, this.querySchema, schema);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
getSchemas(): ControllerBlueprintSchemas<TParams, TQuery, NoInput> {
|
|
18
|
+
return {
|
|
19
|
+
params: this.paramsSchema,
|
|
20
|
+
query: this.querySchema,
|
|
21
|
+
body: null,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Method } from '@controller-contract/core';
|
|
2
|
+
|
|
3
|
+
import type { CreateRouteFn } from '../../../types';
|
|
4
|
+
import { InputStep } from './input-step';
|
|
5
|
+
|
|
6
|
+
export class EndpointStep<TFrameworkContext, TFrameworkInjectable, TFrameworkRouter> {
|
|
7
|
+
constructor(
|
|
8
|
+
private readonly injectable: TFrameworkInjectable,
|
|
9
|
+
private readonly createRoute: CreateRouteFn<
|
|
10
|
+
TFrameworkContext,
|
|
11
|
+
TFrameworkInjectable,
|
|
12
|
+
TFrameworkRouter
|
|
13
|
+
>,
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
endpoint<const TMethod extends Method, const TPath extends string>(method: TMethod, path: TPath) {
|
|
17
|
+
return new InputStep(this.injectable, this.createRoute, method, path);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExitOutput,
|
|
3
|
+
FailOutput,
|
|
4
|
+
Method,
|
|
5
|
+
NoInput,
|
|
6
|
+
PassOutput,
|
|
7
|
+
PathParams,
|
|
8
|
+
} from '@controller-contract/core';
|
|
9
|
+
|
|
10
|
+
import type { Controller, CreateRouteFn, InputBuilderFn, OutputFn, Prettify } from '../../../types';
|
|
11
|
+
import { InputBuilder } from '../input-builder/input-builder';
|
|
12
|
+
import { OutputStep } from './output-step';
|
|
13
|
+
|
|
14
|
+
export class InputStep<
|
|
15
|
+
TFrameworkContext,
|
|
16
|
+
TFrameworkInjectable,
|
|
17
|
+
TFrameworkRouter,
|
|
18
|
+
const TMethod extends Method,
|
|
19
|
+
const TPath extends string,
|
|
20
|
+
> {
|
|
21
|
+
constructor(
|
|
22
|
+
private readonly injectable: TFrameworkInjectable,
|
|
23
|
+
private readonly createRoute: CreateRouteFn<
|
|
24
|
+
TFrameworkContext,
|
|
25
|
+
TFrameworkInjectable,
|
|
26
|
+
TFrameworkRouter
|
|
27
|
+
>,
|
|
28
|
+
private readonly method: TMethod,
|
|
29
|
+
private readonly path: TPath,
|
|
30
|
+
) {}
|
|
31
|
+
|
|
32
|
+
input<TParams, TQuery, TBody>(inputBuilderFn: InputBuilderFn<TParams, TQuery, TBody>) {
|
|
33
|
+
const inputBuilder = new InputBuilder();
|
|
34
|
+
|
|
35
|
+
const schemas = inputBuilderFn(inputBuilder).getSchemas();
|
|
36
|
+
|
|
37
|
+
return new OutputStep(this.injectable, this.createRoute, this.method, this.path, schemas);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
output<TOutput extends PassOutput<any> | FailOutput<any> | ExitOutput>(
|
|
41
|
+
outputFn: OutputFn<TFrameworkContext, Prettify<PathParams<TPath>>, NoInput, NoInput, TOutput>,
|
|
42
|
+
) {
|
|
43
|
+
const route = this.createRoute({
|
|
44
|
+
injectable: this.injectable,
|
|
45
|
+
method: this.method,
|
|
46
|
+
path: this.path,
|
|
47
|
+
schemas: {
|
|
48
|
+
params: null,
|
|
49
|
+
query: null,
|
|
50
|
+
body: null,
|
|
51
|
+
},
|
|
52
|
+
outputFn,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return <
|
|
56
|
+
Controller<
|
|
57
|
+
TMethod,
|
|
58
|
+
TPath,
|
|
59
|
+
Prettify<PathParams<TPath>>,
|
|
60
|
+
NoInput,
|
|
61
|
+
NoInput,
|
|
62
|
+
TOutput,
|
|
63
|
+
TFrameworkRouter
|
|
64
|
+
>
|
|
65
|
+
>(() => route);
|
|
66
|
+
}
|
|
67
|
+
}
|