@trenskow/app 0.6.13 → 0.7.1
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/.vscode/launch.json +1 -1
- package/README.md +48 -50
- package/lib/endpoint.js +44 -55
- package/lib/index.js +10 -0
- package/lib/router.js +14 -18
- package/package.json +4 -4
package/.vscode/launch.json
CHANGED
package/README.md
CHANGED
|
@@ -123,21 +123,26 @@ import { Application, Endpoint } from '@trenskow/app';
|
|
|
123
123
|
|
|
124
124
|
const app = new Application({ port: 8080 });
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
.renderer(async ({ result, response }) => {
|
|
126
|
+
try {
|
|
127
|
+
|
|
128
|
+
const root = new Endpoint()
|
|
129
|
+
.mount('iam', await import('./iam.js'));
|
|
130
|
+
|
|
131
|
+
const renderer = async ({ result, response }) => {
|
|
133
132
|
response.headers.contentType = 'text/plain';
|
|
134
133
|
response.end(result);
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
await app
|
|
137
|
+
.root(root)
|
|
138
|
+
.renderer(renderer)
|
|
139
|
+
.start();
|
|
140
|
+
|
|
141
|
+
console.info(`Application is running on port ${app.port}`)
|
|
142
|
+
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error(error);
|
|
145
|
+
}
|
|
141
146
|
````
|
|
142
147
|
|
|
143
148
|
````javascript
|
|
@@ -216,7 +221,7 @@ Endpoints has the [`mount`](#mount) method, which "mounts" a router to the speci
|
|
|
216
221
|
|
|
217
222
|
There is a variant of the `mount` method called [`parameter`](#parameter) which is used to mount an endpoint with a dynamic path – whereas the path is treated like an input parameter (like express' `.param` method). Parameters also supports a transform function, which is able to transform the parameter into something else (eg. a user identifier into a user object).
|
|
218
223
|
|
|
219
|
-
Lastly there is the [`.middleware`](#middleware) method, which is used to attach middleware. Middleware is defined as a router, which
|
|
224
|
+
Lastly there is the [`.middleware`](#middleware) method, which is used to attach middleware. Middleware is defined as a router, which have the type [`Router`](#router-2) and therefore cannot act as an endpoint. You can regard them like transforms or service providers for the request.
|
|
220
225
|
|
|
221
226
|
> `Endpoint` extends `Router`.
|
|
222
227
|
|
|
@@ -228,9 +233,9 @@ All handlers and routers support async functions (and non-async). No need to cal
|
|
|
228
233
|
|
|
229
234
|
Where express gives you the `(req, res, next)` parameters for each handler, this application instead just provides a single parameter, the "`context` object", which contains all the information needed to process the request.
|
|
230
235
|
|
|
231
|
-
Middleware can
|
|
236
|
+
Middleware can assign values to the context to provide data and services, which is then available for subsequent endpoints, routers and handlers.
|
|
232
237
|
|
|
233
|
-
When a request is incoming, the `context`object looks like this.
|
|
238
|
+
When a request is incoming, the `context` object looks like this.
|
|
234
239
|
|
|
235
240
|
| Name | Description | Type |
|
|
236
241
|
| ---------------- | ------------------------------------------------------------ | :-------------------------: |
|
|
@@ -241,7 +246,7 @@ When a request is incoming, the `context`object looks like this.
|
|
|
241
246
|
| `path` | An object that has properties representing different paths. | Object |
|
|
242
247
|
| `path.full` | An array of strings that joined represent the path of the fully requested path. | Array of String |
|
|
243
248
|
| `path.current` | An array of strings that joined represents the path currently being processed. | Array of String |
|
|
244
|
-
| `path.remaining` | An array of strings that joined represents the path that is above the currently processed path. Setting this will rewrite the remaining path. | Array of String |
|
|
249
|
+
| `path.remaining` | An array of strings that joined represents the path that is above the currently processed path. Setting this will rewrite the remaining path (useful when serving single page applications to a browser). | Array of String |
|
|
245
250
|
| `query` | An object holding the URL query parameters as an object ([keys has been converted to camel case](#query-parameters)). | Object |
|
|
246
251
|
| `state` | A string indicating the current state of the request – possible values are `'routing'`, `'rendering'`, `'completed'` or `'aborted'`. | String |
|
|
247
252
|
| `abort` | A function that aborts the request. It takes the parameters `(error, brutally)`, where `error` is the error that needs to be handled by the [renderer](#renderer) – and `brutally` which indicates if the connection should also be closed. | AsyncFunction |
|
|
@@ -267,15 +272,15 @@ JavaScript is a camel cased language. HTTP is a mixture of different case types.
|
|
|
267
272
|
|
|
268
273
|
Case is automatically converted in both directions, so if you do `context.response.headers.contentType = 'application/json'` it will automatically be converted to `Content-Type: application/json` when the response is sent.
|
|
269
274
|
|
|
270
|
-
The same goes for request headers like `Accept-Language: en`
|
|
275
|
+
The same goes for request headers like `Accept-Language: en` which is accessible through `context.request.headers.acceptLanguage`.
|
|
271
276
|
|
|
272
277
|
##### Query parameters
|
|
273
278
|
|
|
274
|
-
Request with `?my-parameter=value` is accessible through `context.query.myParameter` .
|
|
279
|
+
Request with quuries like `?my-parameter=value` is accessible through `context.query.myParameter` .
|
|
275
280
|
|
|
276
281
|
##### Mount paths
|
|
277
282
|
|
|
278
|
-
When [match mode](#constructor) is set to `'loosely'` (default) a request
|
|
283
|
+
When [match mode](#constructor) is set to `'loosely'` (default) a request with the path component `my-route` or `my_route` will match an endpoint mounted at `myRoute`.
|
|
279
284
|
|
|
280
285
|
#### Endpoints, routers and handlers
|
|
281
286
|
|
|
@@ -287,22 +292,13 @@ Endpoints takes care of a path component. As example the `/this/is/my/path/` pat
|
|
|
287
292
|
|
|
288
293
|
Endpoints can have a couple of things mounted / attached to it – those are.
|
|
289
294
|
|
|
290
|
-
* Other endpoints
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
* Parameters
|
|
295
|
+
* Other endpoints (using the [`.mount`](#mount) method of [`Endpoint`](#endpoint-2))
|
|
296
|
+
* Parameters (using the [`.parameter`](#parameter) method of [`Endpoint`](#endpoint-2))
|
|
294
297
|
* which is also a mounted endpoint – but where the path is dynamic and assigned to the `context.parameters` object.
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
* Handlers
|
|
298
|
-
* using the [`.use`](#use) method of [`Router`](#router-2) or [`Endpoint`](#endpoint-2)
|
|
299
|
-
|
|
300
|
-
* Middleware
|
|
298
|
+
* Handlers (using the [`.use`](#use) method of [`Router`](#router-2) or [`Endpoint`](#endpoint-2) )
|
|
299
|
+
* Middleware (using the [`.middleware`](#middleware) method of [`Endpoint`](#endpoint-2) )
|
|
301
300
|
* sets a [`Router`](#routers-2) router to that the request will be passed through.
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
* Methods
|
|
305
|
-
* using the [`.get`, `.post`, `.put`, `.delete`, etc.](#get-post-put-delete-etc) method of [`Endpoint`](#endpoint-2)
|
|
301
|
+
* Methods (using the [`.get`, `.post`, `.put`, `.delete`, etc.](#get-post-put-delete-etc) method of [`Endpoint`](#endpoint-2))
|
|
306
302
|
* When a method returns the request ends and the returned value is send to the client as a response (through the [`Application#renderer`](#renderer))
|
|
307
303
|
|
|
308
304
|
|
|
@@ -311,7 +307,7 @@ Endpoints can have a couple of things mounted / attached to it – those are.
|
|
|
311
307
|
Whenever a function (such as [`.mount`](#mount) or [`.parameter`](#parameters) or [`.root`](#root)) takes an endpoint as a parameter, it can be provided in any of the following ways.
|
|
312
308
|
|
|
313
309
|
* An instance of [`Endpoint`](#endpoint-2).
|
|
314
|
-
* An object that has a `default` key that has an instance of `Endpoint` as the value (useful when using inline imports).
|
|
310
|
+
* An object that has a `default` key that has an instance of `Endpoint` as the value (useful when using inline imports as `await import('my-endpoint.js')`).
|
|
315
311
|
|
|
316
312
|
##### Routers
|
|
317
313
|
|
|
@@ -322,7 +318,7 @@ A router is the same as above, except it only supports [`.use`](#use).
|
|
|
322
318
|
As above, whenever a function takes a router as a parameter, it can be provided in any of the following ways.
|
|
323
319
|
|
|
324
320
|
* An instance of [`Router`](#router-2).
|
|
325
|
-
* An object that has a `default` key that has an instance of `Router` as the value (useful when using inline imports).
|
|
321
|
+
* An object that has a `default` key that has an instance of `Router` as the value (useful when using inline imports as `await import('my-route.js')`).).
|
|
326
322
|
|
|
327
323
|
##### Handlers
|
|
328
324
|
|
|
@@ -340,7 +336,7 @@ Whenever a function takes a handler as a parameter, it can be provided in any of
|
|
|
340
336
|
|
|
341
337
|
### `Application`
|
|
342
338
|
|
|
343
|
-
The `Application` class holds an application and is responsible for handling and bootstrapping request from the server. It does not provide any routing on
|
|
339
|
+
The `Application` class holds an application and is responsible for handling and bootstrapping request from the server. It does not provide any routing on its own, instead it has a [`root`](#root) method, which is used to set the root router.
|
|
344
340
|
|
|
345
341
|
> If no root route has been set, all requests will be responded with `404 Not Found`.
|
|
346
342
|
|
|
@@ -352,17 +348,17 @@ The `Application` class takes an "options" object as it's parameter.
|
|
|
352
348
|
|
|
353
349
|
##### Parameters
|
|
354
350
|
|
|
355
|
-
| Name | Description
|
|
356
|
-
| ------------------------ |
|
|
357
|
-
| options | An object representing the options.
|
|
358
|
-
| `options.port` | The port at which to listen for incoming connections.
|
|
351
|
+
| Name | Description | Type | Required | Default value |
|
|
352
|
+
| ------------------------ | ------------------------------------------------------------ | :-----------------------: | :------: | :--------------------------: |
|
|
353
|
+
| options | An object representing the options. | Object | | {} |
|
|
354
|
+
| `options.port` | The port at which to listen for incoming connections. | Number | | `0` (automatically assigned) |
|
|
359
355
|
| `options.RequestType` | An object that inherits from the [`Request`](#request-2) class (an `http.IncomingMessage` subclass) that is used as the request object in routes. | class | | [`Request`](#Request) |
|
|
360
|
-
| `options.ResponseType` | An object that inherits from the [`Response`](#response-2) class (`http.ServerResponse` subclass) that is used as the response object in routes.
|
|
361
|
-
| `path` | An object that represents path related options.
|
|
362
|
-
| `path.matchMode` | Indicates [how to match requests to mounted paths](#mount-paths).
|
|
363
|
-
| `options.server` | An object that represents how to instantiate the HTTP server.
|
|
364
|
-
| `options.server.create` | A function that is able to create a server.
|
|
365
|
-
| `options.server.options` | An object to be passed as options when creating a server.
|
|
356
|
+
| `options.ResponseType` | An object that inherits from the [`Response`](#response-2) class (`http.ServerResponse` subclass) that is used as the response object in routes. | class | | [`Response`](#Response) |
|
|
357
|
+
| `path` | An object that represents path related options. | Object | | `{}` |
|
|
358
|
+
| `path.matchMode` | Indicates [how to match requests to mounted paths](#mount-paths) (eg. should the path be converted to camel case). | `'loosely'` or `'strict'` | | `'loosely'` |
|
|
359
|
+
| `options.server` | An object that represents how to instantiate the HTTP server. | Object | | `{}` |
|
|
360
|
+
| `options.server.create` | A function that is able to create a server. | Function | | `http.createServer` |
|
|
361
|
+
| `options.server.options` | An object to be passed as options when creating a server. | Object | | `{}` |
|
|
366
362
|
|
|
367
363
|
#### Events
|
|
368
364
|
|
|
@@ -499,7 +495,7 @@ You can only call these methods once per method per endpoint – calling it mult
|
|
|
499
495
|
|
|
500
496
|
These also ends routing. After a method route has been called, the routing will go strait to the renderer.
|
|
501
497
|
|
|
502
|
-
> Notice: If no `head` method is implemented on endpoint, `get` will instead be called (if
|
|
498
|
+
> Notice: If no `head` method is implemented on endpoint, `get` will instead be called (if ). When client requests a `head` the result will be ignored.
|
|
503
499
|
|
|
504
500
|
> Returns the endpoint.
|
|
505
501
|
|
|
@@ -518,11 +514,13 @@ Below is an example on how to use the method.
|
|
|
518
514
|
````javascript
|
|
519
515
|
default export ({ endpoint }) => {
|
|
520
516
|
endpoint
|
|
521
|
-
.get(
|
|
517
|
+
.get(
|
|
518
|
+
async (context) => 'Hello, world!',
|
|
519
|
+
() => console.info("Said hello."));
|
|
522
520
|
};
|
|
523
521
|
````
|
|
524
522
|
|
|
525
|
-
> In the above example `'Hello, world!'` is immediately send to the [renderer](#renderer) and the request ends.
|
|
523
|
+
> In the above example `'Hello, world!'` is immediately send to the [renderer](#renderer) and the request ends. The second handler is also executed, but as it returns `undefined` its return value is ignored.
|
|
526
524
|
|
|
527
525
|
###### Catch all
|
|
528
526
|
|
package/lib/endpoint.js
CHANGED
|
@@ -65,7 +65,7 @@ export default class Endpoint extends Router {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
this._layers.push({
|
|
68
|
-
|
|
68
|
+
handler: this._handleMethod,
|
|
69
69
|
method,
|
|
70
70
|
handlers,
|
|
71
71
|
match
|
|
@@ -91,7 +91,7 @@ export default class Endpoint extends Router {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
this._layers.push({
|
|
94
|
-
|
|
94
|
+
handler: this._handleMount,
|
|
95
95
|
path,
|
|
96
96
|
endpoint
|
|
97
97
|
});
|
|
@@ -130,7 +130,7 @@ export default class Endpoint extends Router {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
this._layers.push({
|
|
133
|
-
|
|
133
|
+
handler: this._handleParameter,
|
|
134
134
|
name,
|
|
135
135
|
transform,
|
|
136
136
|
endpoint
|
|
@@ -168,7 +168,7 @@ export default class Endpoint extends Router {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
this._layers.push({
|
|
171
|
-
|
|
171
|
+
handler: this._handleMiddleware,
|
|
172
172
|
router
|
|
173
173
|
});
|
|
174
174
|
|
|
@@ -183,7 +183,7 @@ export default class Endpoint extends Router {
|
|
|
183
183
|
if (path.isLast) {
|
|
184
184
|
|
|
185
185
|
const methods = this._layers
|
|
186
|
-
.filter((layer) => layer.
|
|
186
|
+
.filter((layer) => layer.handler === this._handleMethod)
|
|
187
187
|
.map((layer) => layer.method.toUpperCase())
|
|
188
188
|
.filter((value, index, array) => array.indexOf(value) === index);
|
|
189
189
|
|
|
@@ -202,80 +202,69 @@ export default class Endpoint extends Router {
|
|
|
202
202
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
-
async
|
|
205
|
+
async _handleMount(layer, path, context, next) {
|
|
206
206
|
|
|
207
|
-
|
|
207
|
+
return await path.pushed(async (component) => {
|
|
208
208
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
return await path.pushed(async (component) => {
|
|
212
|
-
|
|
213
|
-
if (!component) return path.popped(next);
|
|
214
|
-
|
|
215
|
-
if (matchPath(component, layer.path, context)) {
|
|
216
|
-
return await layer.endpoint._route(path, context, next);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return path.popped(next);
|
|
220
|
-
|
|
221
|
-
});
|
|
209
|
+
if (!component) return path.popped(next);
|
|
222
210
|
|
|
211
|
+
if (matchPath(component, layer.path, context)) {
|
|
212
|
+
return await layer.endpoint._route(path, context, next);
|
|
223
213
|
}
|
|
224
214
|
|
|
225
|
-
|
|
215
|
+
return path.popped(next);
|
|
226
216
|
|
|
227
|
-
|
|
217
|
+
});
|
|
228
218
|
|
|
229
|
-
|
|
230
|
-
underlyingMethod = 'get';
|
|
231
|
-
}
|
|
219
|
+
}
|
|
232
220
|
|
|
233
|
-
|
|
234
|
-
if (layer.method !== 'all' && layer.method !== underlyingMethod) return await next();
|
|
221
|
+
async _handleMethod(layer, path, context, next) {
|
|
235
222
|
|
|
236
|
-
|
|
237
|
-
const result = await handler(context);
|
|
238
|
-
if (layer.underlyingMethod === 'head') return;
|
|
239
|
-
if (context.state !== 'routing') return;
|
|
240
|
-
if (typeof result !== 'undefined') context.result = result;
|
|
241
|
-
}
|
|
223
|
+
let underlyingMethod = context.request.method.toLowerCase();
|
|
242
224
|
|
|
243
|
-
|
|
225
|
+
if (underlyingMethod === 'head' && !this._layers.some((layer) => layer.method === 'head')) {
|
|
226
|
+
underlyingMethod = 'get';
|
|
227
|
+
}
|
|
244
228
|
|
|
245
|
-
|
|
229
|
+
if (layer.match === 'direct' && !path.isLast) return await next();
|
|
230
|
+
if (layer.method !== 'all' && layer.method !== underlyingMethod) return await next();
|
|
246
231
|
|
|
247
|
-
|
|
232
|
+
for (let handler of layer.handlers) {
|
|
233
|
+
const result = await handler(context);
|
|
234
|
+
if (layer.underlyingMethod === 'head') return;
|
|
235
|
+
if (context.state !== 'routing') return;
|
|
236
|
+
if (typeof result !== 'undefined') context.result = result;
|
|
237
|
+
}
|
|
248
238
|
|
|
249
|
-
|
|
239
|
+
return context.result;
|
|
250
240
|
|
|
251
|
-
|
|
241
|
+
}
|
|
252
242
|
|
|
253
|
-
|
|
243
|
+
async _handleParameter(layer, path, context, next) {
|
|
254
244
|
|
|
255
|
-
|
|
256
|
-
context.parameters[layer.name] = await layer.transform(
|
|
257
|
-
Object.fromEntries([
|
|
258
|
-
['context', context],
|
|
259
|
-
[layer.name, component]
|
|
260
|
-
])
|
|
261
|
-
);
|
|
262
|
-
}
|
|
245
|
+
return await path.pushed(async (component) => {
|
|
263
246
|
|
|
264
|
-
|
|
247
|
+
if (!component) return await path.popped(next);
|
|
265
248
|
|
|
266
|
-
|
|
249
|
+
context.parameters[layer.name] = component;
|
|
267
250
|
|
|
251
|
+
if (typeof layer.transform === 'function') {
|
|
252
|
+
context.parameters[layer.name] = await layer.transform(
|
|
253
|
+
Object.fromEntries([
|
|
254
|
+
['context', context],
|
|
255
|
+
[layer.name, component]
|
|
256
|
+
])
|
|
257
|
+
);
|
|
268
258
|
}
|
|
269
259
|
|
|
270
|
-
|
|
271
|
-
return await layer.router._route(path, context, next);
|
|
272
|
-
}
|
|
260
|
+
return await layer.endpoint._route(path, context, next);
|
|
273
261
|
|
|
274
|
-
|
|
275
|
-
return await super._handle(layer, path, context, next);
|
|
262
|
+
});
|
|
276
263
|
|
|
277
|
-
|
|
264
|
+
}
|
|
278
265
|
|
|
266
|
+
async _handleMiddleware(layer, path, context, next) {
|
|
267
|
+
return await layer.router._route(path, context, next);
|
|
279
268
|
}
|
|
280
269
|
|
|
281
270
|
}
|
package/lib/index.js
CHANGED
|
@@ -13,6 +13,16 @@ import Request from './request.js';
|
|
|
13
13
|
import Response from './response.js';
|
|
14
14
|
import ApiError from '@trenskow/api-error';
|
|
15
15
|
|
|
16
|
+
import { isObject, matchPath, resolveInlineImport } from './util.js';
|
|
17
|
+
|
|
16
18
|
export default Application;
|
|
17
19
|
|
|
20
|
+
Application.plugin = (plugin) => {
|
|
21
|
+
plugin({ Router, Endpoint, Application, Request, Response, Error: ApiError, util: {
|
|
22
|
+
isObject,
|
|
23
|
+
matchPath,
|
|
24
|
+
resolveInlineImport
|
|
25
|
+
} });
|
|
26
|
+
};
|
|
27
|
+
|
|
18
28
|
export { Router, Endpoint, Application, Request, Response, ApiError as Error };
|
package/lib/router.js
CHANGED
|
@@ -27,7 +27,7 @@ export default class Router {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
this._layers.push({
|
|
30
|
-
|
|
30
|
+
handler: this._handleUse,
|
|
31
31
|
handlers
|
|
32
32
|
});
|
|
33
33
|
|
|
@@ -48,7 +48,7 @@ export default class Router {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
this._layers.push({
|
|
51
|
-
|
|
51
|
+
handler: this._handleMixin,
|
|
52
52
|
router: router
|
|
53
53
|
});
|
|
54
54
|
|
|
@@ -68,27 +68,23 @@ export default class Router {
|
|
|
68
68
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
async
|
|
72
|
-
|
|
73
|
-
switch (layer.type) {
|
|
74
|
-
|
|
75
|
-
case 'use': {
|
|
71
|
+
async _handleUse(layer, _, context, next) {
|
|
76
72
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return await next();
|
|
73
|
+
for (let handler of layer.handlers) {
|
|
74
|
+
await handler(context);
|
|
75
|
+
if (context.state !== 'routing') return;
|
|
76
|
+
}
|
|
83
77
|
|
|
84
|
-
|
|
78
|
+
return await next();
|
|
85
79
|
|
|
86
|
-
|
|
87
|
-
return await layer.router._route(path, context, next);
|
|
88
|
-
}
|
|
80
|
+
}
|
|
89
81
|
|
|
90
|
-
|
|
82
|
+
async _handleMixin(layer, path, context, next) {
|
|
83
|
+
return await layer.router._route(path, context, next);
|
|
84
|
+
}
|
|
91
85
|
|
|
86
|
+
async _handle(layer, path, context, next) {
|
|
87
|
+
return await layer.handler.call(this, layer, path, context, next);
|
|
92
88
|
}
|
|
93
89
|
|
|
94
90
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trenskow/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "A small HTTP router.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
},
|
|
26
26
|
"homepage": "https://github.com/trenskow/app#readme",
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"eslint": "^8.
|
|
28
|
+
"eslint": "^8.20.0",
|
|
29
29
|
"mocha": "^10.0.0",
|
|
30
|
-
"supertest": "^6.2.
|
|
30
|
+
"supertest": "^6.2.4"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@trenskow/api-error": "^2.2
|
|
33
|
+
"@trenskow/api-error": "^2.3.2",
|
|
34
34
|
"@trenskow/caseit": "^1.3.0"
|
|
35
35
|
}
|
|
36
36
|
}
|