@adonisjs/session 7.0.0-2 → 7.0.0-3

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.
Files changed (45) hide show
  1. package/README.md +5 -8
  2. package/build/index.d.ts +5 -3
  3. package/build/index.js +5 -3
  4. package/build/providers/session_provider.d.ts +5 -8
  5. package/build/providers/session_provider.js +13 -35
  6. package/build/src/client.d.ts +13 -25
  7. package/build/src/client.js +24 -43
  8. package/build/src/debug.d.ts +3 -0
  9. package/build/src/debug.js +10 -0
  10. package/build/src/define_config.d.ts +6 -3
  11. package/build/src/define_config.js +34 -5
  12. package/build/src/drivers/cookie.d.ts +7 -9
  13. package/build/src/drivers/cookie.js +10 -6
  14. package/build/src/drivers/file.d.ts +11 -14
  15. package/build/src/drivers/file.js +64 -41
  16. package/build/src/drivers/memory.d.ts +4 -8
  17. package/build/src/drivers/memory.js +0 -3
  18. package/build/src/drivers/redis.d.ts +4 -6
  19. package/build/src/drivers/redis.js +24 -28
  20. package/build/src/drivers_collection.d.ts +22 -0
  21. package/build/src/drivers_collection.js +38 -0
  22. package/build/src/errors.d.ts +8 -0
  23. package/build/src/errors.js +17 -0
  24. package/build/src/helpers.d.ts +6 -0
  25. package/build/src/helpers.js +37 -0
  26. package/build/src/session.d.ts +86 -59
  27. package/build/src/session.js +221 -221
  28. package/build/src/session_middleware.d.ts +19 -5
  29. package/build/src/session_middleware.js +42 -6
  30. package/build/src/store.d.ts +17 -14
  31. package/build/src/store.js +33 -17
  32. package/build/src/types/extended.d.ts +19 -0
  33. package/build/src/types/main.d.ts +106 -0
  34. package/build/src/types/main.js +9 -0
  35. package/package.json +23 -20
  36. package/build/src/bindings/api_client.d.ts +0 -2
  37. package/build/src/bindings/api_client.js +0 -135
  38. package/build/src/bindings/http_context.d.ts +0 -5
  39. package/build/src/bindings/http_context.js +0 -17
  40. package/build/src/bindings/types.d.ts +0 -77
  41. package/build/src/session_manager.d.ts +0 -38
  42. package/build/src/session_manager.js +0 -149
  43. package/build/src/types.d.ts +0 -61
  44. package/build/src/types.js +0 -1
  45. /package/build/src/{bindings/types.js → types/extended.js} +0 -0
@@ -6,366 +6,366 @@
6
6
  * For the full copyright and license information, please view the LICENSE
7
7
  * file that was distributed with this source code.
8
8
  */
9
- import { Exception } from '@poppinss/utils';
10
9
  import lodash from '@poppinss/utils/lodash';
11
10
  import { cuid } from '@adonisjs/core/helpers';
12
11
  import { Store } from './store.js';
12
+ import * as errors from './errors.js';
13
+ import debug from './debug.js';
13
14
  /**
14
- * Session class exposes the API to read/write values to the session for
15
- * a given request.
15
+ * The session class exposes the API to read and write values to
16
+ * the session store.
17
+ *
18
+ * A session instance is isolated between requests but
19
+ * uses a centralized persistence store and
16
20
  */
17
21
  export class Session {
18
- /**
19
- * Session id for the current request. It will be different
20
- * from the "this.sessionId" when regenerate is called.
21
- */
22
- #currentSessionId;
23
- /**
24
- * A instance of store with values read from the driver. The store
25
- * in initiated inside the [[initiate]] method
26
- */
27
- #store;
28
- /**
29
- * Whether or not to re-generate the session id before committing
30
- * session values.
31
- */
32
- #regeneratedSessionId = false;
33
- /**
34
- * Session key for setting flash messages
35
- */
36
- #flashMessagesKey = '__flash__';
37
- /**
38
- * The HTTP context for the current request.
39
- */
40
- #ctx;
41
- /**
42
- * Configuration for the session
43
- */
44
22
  #config;
45
- /**
46
- * The session driver instance used to read and write session data.
47
- */
48
23
  #driver;
24
+ #emitter;
25
+ #ctx;
26
+ #readonly = false;
27
+ #store;
49
28
  /**
50
- * Set to true inside the `initiate` method
51
- */
52
- initiated = false;
53
- /**
54
- * A boolean to know if it's a fresh session or not. Fresh
55
- * sessions are those, whose session id is not present
56
- * in cookie
29
+ * Session id refers to the session id that will be committed
30
+ * as a cookie during the response.
57
31
  */
58
- fresh = false;
32
+ #sessionId;
59
33
  /**
60
- * A boolean to know if store is initiated in readonly mode
61
- * or not. This is done during Websocket requests
34
+ * Session id from cookie refers to the value we read from the
35
+ * cookie during the HTTP request.
36
+ *
37
+ * This only might not exist during the first request. Also during
38
+ * session id re-generation, this value will be different from
39
+ * the session id.
62
40
  */
63
- readonly = false;
41
+ #sessionIdFromCookie;
64
42
  /**
65
- * Session id for the given request. A new session id is only
66
- * generated when the cookie for the session id is missing
43
+ * Store of flash messages that be written during the
44
+ * HTTP request
67
45
  */
68
- sessionId;
46
+ responseFlashMessages = new Store({});
69
47
  /**
70
- * A copy of previously set flash messages
48
+ * Store of flash messages for the current HTTP request.
71
49
  */
72
50
  flashMessages = new Store({});
73
51
  /**
74
- * A copy of flash messages. The `input` messages
75
- * are overwritten when any of the input related
76
- * methods are used.
77
- *
78
- * The `others` object is expanded with each call.
52
+ * The key to use for storing flash messages inside
53
+ * the session store.
79
54
  */
80
- responseFlashMessages = new Store({});
81
- constructor(ctx, config, driver) {
82
- this.#ctx = ctx;
83
- this.#config = config;
84
- this.#driver = driver;
85
- this.sessionId = this.#getSessionId();
86
- this.#currentSessionId = this.sessionId;
87
- }
55
+ flashKey = '__flash__';
88
56
  /**
89
- * Returns a merged copy of flash messages or null
90
- * when nothing is set
57
+ * Session id for the current HTTP request
91
58
  */
92
- #setFlashMessages() {
93
- if (this.responseFlashMessages.isEmpty) {
94
- return;
95
- }
96
- const { input, ...others } = this.responseFlashMessages.all();
97
- this.put(this.#flashMessagesKey, { ...input, ...others });
59
+ get sessionId() {
60
+ return this.#sessionId;
98
61
  }
99
62
  /**
100
- * Returns the existing session id or creates one.
63
+ * A boolean to know if a fresh session is created during
64
+ * the request
101
65
  */
102
- #getSessionId() {
103
- const sessionId = this.#ctx.request.cookie(this.#config.cookieName);
104
- if (sessionId) {
105
- return sessionId;
106
- }
107
- this.fresh = true;
108
- return cuid();
66
+ get fresh() {
67
+ return this.#sessionIdFromCookie === undefined;
109
68
  }
110
69
  /**
111
- * Ensures the session store is initialized
70
+ * A boolean to know if session is in readonly
71
+ * state
112
72
  */
113
- #ensureIsReady() {
114
- if (!this.initiated) {
115
- throw new Exception('Session store is not initiated yet. Make sure you are using the session hook', { code: 'E_RUNTIME_EXCEPTION', status: 500 });
116
- }
73
+ get readonly() {
74
+ return this.#readonly;
117
75
  }
118
76
  /**
119
- * Raises exception when session store is in readonly mode
77
+ * A boolean to know if session store has been initiated
120
78
  */
121
- #ensureIsMutable() {
122
- if (this.readonly) {
123
- throw new Exception('Session store is in readonly mode and cannot be mutated', {
124
- status: 500,
125
- code: 'E_RUNTIME_EXCEPTION',
126
- });
127
- }
79
+ get initiated() {
80
+ return !!this.#store;
128
81
  }
129
82
  /**
130
- * Touches the session cookie
83
+ * A boolean to know if the session id has been re-generated
84
+ * during the current request
131
85
  */
132
- #touchSessionCookie() {
133
- this.#ctx.logger.trace('touching session cookie');
134
- this.#ctx.response.cookie(this.#config.cookieName, this.sessionId, this.#config.cookie);
86
+ get hasRegeneratedSession() {
87
+ return !!(this.#sessionIdFromCookie && this.#sessionIdFromCookie !== this.#sessionId);
135
88
  }
136
89
  /**
137
- * Commits the session value to the store
90
+ * A boolean to know if the session store is empty
138
91
  */
139
- async #commitValuesToStore() {
140
- this.#ctx.logger.trace('persist session store with driver');
141
- await this.#driver.write(this.sessionId, this.#store.toJSON());
92
+ get isEmpty() {
93
+ return this.#store?.isEmpty ?? true;
142
94
  }
143
95
  /**
144
- * Touches the driver to make sure the session values doesn't expire
96
+ * A boolean to know if the session store has been
97
+ * modified
145
98
  */
146
- async #touchDriver() {
147
- this.#ctx.logger.trace('touch driver for liveliness');
148
- await this.#driver.touch(this.sessionId);
99
+ get hasBeenModified() {
100
+ return this.#store?.hasBeenModified ?? false;
101
+ }
102
+ constructor(config, driver, emitter, ctx) {
103
+ this.#ctx = ctx;
104
+ this.#config = config;
105
+ this.#driver = driver;
106
+ this.#emitter = emitter;
107
+ this.#sessionIdFromCookie = ctx.request.cookie(config.cookieName, undefined);
108
+ this.#sessionId = this.#sessionIdFromCookie || cuid();
149
109
  }
150
110
  /**
151
- * Reading flash messages from the last HTTP request and
152
- * updating the flash messages bag
111
+ * Returns the flash messages store for a given
112
+ * mode
153
113
  */
154
- #readLastRequestFlashMessage() {
155
- if (this.readonly) {
156
- return;
114
+ #getFlashStore(mode) {
115
+ if (!this.#store) {
116
+ throw new errors.E_SESSION_NOT_READY();
117
+ }
118
+ if (mode === 'write' && this.readonly) {
119
+ throw new errors.E_SESSION_NOT_MUTABLE();
157
120
  }
158
- this.flashMessages.update(this.pull(this.#flashMessagesKey, null));
121
+ return this.responseFlashMessages;
159
122
  }
160
123
  /**
161
- * Share flash messages & read only session's functions with views
162
- * (only when view property exists)
124
+ * Returns the store instance for a given mode
163
125
  */
164
- #shareLocalsWithView() {
165
- if (!this.#ctx['view'] || typeof this.#ctx['view'].share !== 'function') {
166
- return;
126
+ #getStore(mode) {
127
+ if (!this.#store) {
128
+ throw new errors.E_SESSION_NOT_READY();
129
+ }
130
+ if (mode === 'write' && this.readonly) {
131
+ throw new errors.E_SESSION_NOT_MUTABLE();
167
132
  }
168
- this.#ctx['view'].share({
169
- flashMessages: this.flashMessages,
170
- session: {
171
- get: this.get.bind(this),
172
- has: this.has.bind(this),
173
- all: this.all.bind(this),
174
- },
175
- });
133
+ return this.#store;
176
134
  }
177
135
  /**
178
- * Initiating the session by reading it's value from the
179
- * driver and feeding it to a store.
180
- *
181
- * Multiple calls to `initiate` results in a noop.
136
+ * Initiates the session store. The method results in a noop
137
+ * when called multiple times
182
138
  */
183
139
  async initiate(readonly) {
184
- if (this.initiated) {
140
+ if (this.#store) {
185
141
  return;
186
142
  }
187
- this.readonly = readonly;
188
- const contents = await this.#driver.read(this.sessionId);
143
+ debug('initiating session (readonly: %s)', readonly);
144
+ this.#readonly = readonly;
145
+ const contents = await this.#driver.read(this.#sessionId);
189
146
  this.#store = new Store(contents);
190
- this.initiated = true;
191
- this.#readLastRequestFlashMessage();
192
- this.#shareLocalsWithView();
193
- }
194
- /**
195
- * Re-generates the session id. This can is used to avoid
196
- * session fixation attacks.
197
- */
198
- regenerate() {
199
- this.#ctx.logger.trace('explicitly re-generating session id');
200
- this.sessionId = cuid();
201
- this.#regeneratedSessionId = true;
147
+ /**
148
+ * Extract flash messages from the store and keep a local
149
+ * copy of it.
150
+ */
151
+ if (this.has(this.flashKey)) {
152
+ debug('reading flash data');
153
+ if (this.#readonly) {
154
+ this.flashMessages.update(this.get(this.flashKey, null));
155
+ }
156
+ else {
157
+ this.flashMessages.update(this.pull(this.flashKey, null));
158
+ }
159
+ }
160
+ this.#emitter.emit('session:initiated', { session: this });
202
161
  }
203
162
  /**
204
- * Set/update session value
163
+ * Put a key-value pair to the session data store
205
164
  */
206
165
  put(key, value) {
207
- this.#ensureIsReady();
208
- this.#ensureIsMutable();
209
- this.#store.set(key, value);
166
+ this.#getStore('write').set(key, value);
210
167
  }
211
168
  /**
212
- * Find if the value exists in the session
169
+ * Check if a key exists inside the datastore
213
170
  */
214
171
  has(key) {
215
- this.#ensureIsReady();
216
- return this.#store.has(key);
172
+ return this.#getStore('read').has(key);
217
173
  }
218
174
  /**
219
- * Get value from the session. The default value is returned
220
- * when actual value is `undefined`
175
+ * Get the value of a key from the session datastore.
176
+ * You can specify a default value to use, when key
177
+ * does not exists or has undefined value.
221
178
  */
222
179
  get(key, defaultValue) {
223
- this.#ensureIsReady();
224
- return this.#store.get(key, defaultValue);
180
+ return this.#getStore('read').get(key, defaultValue);
225
181
  }
226
182
  /**
227
- * Returns everything from the session
183
+ * Get everything from the session store
228
184
  */
229
185
  all() {
230
- this.#ensureIsReady();
231
- return this.#store.all();
186
+ return this.#getStore('read').all();
232
187
  }
233
188
  /**
234
- * Remove value for a given key from the session
189
+ * Remove a key from the session datastore
235
190
  */
236
191
  forget(key) {
237
- this.#ensureIsReady();
238
- this.#ensureIsMutable();
239
- this.#store.unset(key);
192
+ return this.#getStore('write').unset(key);
240
193
  }
241
194
  /**
242
- * The method is equivalent to calling `session.get` followed
243
- * by `session.forget`
195
+ * Read value for a key from the session datastore
196
+ * and remove it simultaneously.
244
197
  */
245
198
  pull(key, defaultValue) {
246
- this.#ensureIsReady();
247
- this.#ensureIsMutable();
248
- return this.#store.pull(key, defaultValue);
199
+ return this.#getStore('write').pull(key, defaultValue);
249
200
  }
250
201
  /**
251
- * Increment value for a number inside the session store. The
252
- * method raises an error when underlying value is not
253
- * a number
202
+ * Increment the value of a key inside the session
203
+ * store.
204
+ *
205
+ * A new key will be defined if does not exists already.
206
+ * The value of a new key will be 1
254
207
  */
255
208
  increment(key, steps = 1) {
256
- this.#ensureIsReady();
257
- this.#ensureIsMutable();
258
- this.#store.increment(key, steps);
209
+ return this.#getStore('write').increment(key, steps);
259
210
  }
260
211
  /**
261
- * Decrement value for a number inside the session store. The
262
- * method raises an error when underlying value is not
263
- * a number
212
+ * Increment the value of a key inside the session
213
+ * store.
214
+ *
215
+ * A new key will be defined if does not exists already.
216
+ * The value of a new key will be -1
264
217
  */
265
218
  decrement(key, steps = 1) {
266
- this.#ensureIsReady();
267
- this.#ensureIsMutable();
268
- this.#store.decrement(key, steps);
219
+ return this.#getStore('write').decrement(key, steps);
269
220
  }
270
221
  /**
271
- * Remove everything from the session
222
+ * Empty the session store
272
223
  */
273
224
  clear() {
274
- this.#ensureIsReady();
275
- this.#ensureIsMutable();
276
- this.#store.clear();
225
+ return this.#getStore('write').clear();
277
226
  }
278
227
  /**
279
- * Add a new flash message
228
+ * Flash validation error messages. Make sure the error
229
+ * is an instance of VineJS ValidationException
280
230
  */
231
+ flashValidationErrors(error) {
232
+ const errorsBag = error.messages.reduce((result, message) => {
233
+ if (result[message.field]) {
234
+ result[message.field].push(message.message);
235
+ }
236
+ else {
237
+ result[message.field] = [message.message];
238
+ }
239
+ return result;
240
+ }, {});
241
+ this.flashExcept(['_csrf', '_method']);
242
+ this.flash('errors', errorsBag);
243
+ }
281
244
  flash(key, value) {
282
- this.#ensureIsReady();
283
- this.#ensureIsMutable();
284
- /**
285
- * Update value
286
- */
287
245
  if (typeof key === 'string') {
288
246
  if (value) {
289
- this.responseFlashMessages.set(key, value);
247
+ this.#getFlashStore('write').set(key, value);
290
248
  }
291
249
  }
292
250
  else {
293
- this.responseFlashMessages.merge(key);
251
+ this.#getFlashStore('write').merge(key);
294
252
  }
295
253
  }
296
254
  /**
297
- * Flash all form values
255
+ * Flash form input data to the flash messages store
298
256
  */
299
257
  flashAll() {
300
- this.#ensureIsReady();
301
- this.#ensureIsMutable();
302
- this.responseFlashMessages.set('input', this.#ctx.request.original());
258
+ return this.#getFlashStore('write').set('input', this.#ctx.request.original());
303
259
  }
304
260
  /**
305
- * Flash all form values except mentioned keys
261
+ * Flash form input data (except some keys) to the flash messages store
306
262
  */
307
263
  flashExcept(keys) {
308
- this.#ensureIsReady();
309
- this.#ensureIsMutable();
310
- this.responseFlashMessages.set('input', lodash.omit(this.#ctx.request.original(), keys));
264
+ this.#getFlashStore('write').set('input', lodash.omit(this.#ctx.request.original(), keys));
311
265
  }
312
266
  /**
313
- * Flash only defined keys from the form values
267
+ * Flash form input data (only some keys) to the flash messages store
314
268
  */
315
269
  flashOnly(keys) {
316
- this.#ensureIsReady();
317
- this.#ensureIsMutable();
318
- this.responseFlashMessages.set('input', lodash.pick(this.#ctx.request.original(), keys));
270
+ this.#getFlashStore('write').set('input', lodash.pick(this.#ctx.request.original(), keys));
319
271
  }
320
272
  /**
321
- * Reflash existing flash messages
273
+ * Reflash messages from the last request in the current response
322
274
  */
323
275
  reflash() {
324
- this.flash(this.flashMessages.all());
276
+ this.#getFlashStore('write').set('reflashed', this.flashMessages.all());
325
277
  }
326
278
  /**
327
- * Reflash selected keys from the existing flash messages
279
+ * Reflash messages (only some keys) from the last
280
+ * request in the current response
328
281
  */
329
282
  reflashOnly(keys) {
330
- this.flash(lodash.pick(this.flashMessages.all(), keys));
283
+ this.#getFlashStore('write').set('reflashed', lodash.pick(this.flashMessages.all(), keys));
331
284
  }
332
285
  /**
333
- * Omit selected keys from the existing flash messages
334
- * and flash the rest of values
286
+ * Reflash messages (except some keys) from the last
287
+ * request in the current response
335
288
  */
336
289
  reflashExcept(keys) {
337
- this.flash(lodash.omit(this.flashMessages.all(), keys));
290
+ this.#getFlashStore('write').set('reflashed', lodash.omit(this.flashMessages.all(), keys));
291
+ }
292
+ /**
293
+ * Re-generate the session id and migrate data to it.
294
+ */
295
+ regenerate() {
296
+ this.#sessionId = cuid();
338
297
  }
339
298
  /**
340
- * Writes value to the underlying session driver.
299
+ * Commit session changes. No more mutations will be
300
+ * allowed after commit.
341
301
  */
342
302
  async commit() {
343
- if (!this.initiated) {
344
- this.#touchSessionCookie();
345
- await this.#touchDriver();
303
+ if (!this.#store || this.readonly) {
346
304
  return;
347
305
  }
348
306
  /**
349
- * Cleanup old session and re-generate new session
307
+ * If the flash messages store is not empty, we should put
308
+ * its messages inside main session store.
350
309
  */
351
- if (this.#regeneratedSessionId) {
352
- await this.#driver.destroy(this.#currentSessionId);
310
+ if (!this.responseFlashMessages.isEmpty) {
311
+ const { input, reflashed, ...others } = this.responseFlashMessages.all();
312
+ this.put(this.flashKey, { ...reflashed, ...input, ...others });
353
313
  }
314
+ debug('committing session data');
354
315
  /**
355
- * Touch the session cookie to keep it alive.
316
+ * Touch the session id cookie to stay alive
356
317
  */
357
- this.#touchSessionCookie();
358
- this.#setFlashMessages();
318
+ this.#ctx.response.cookie(this.#config.cookieName, this.#sessionId, this.#config.cookie);
359
319
  /**
360
- * Commit values to the store if not empty.
361
- * Otherwise delete the session store to cleanup
362
- * the storage space.
320
+ * Delete the session data when the session store
321
+ * is empty.
322
+ *
323
+ * Also we only destroy the session id we read from the cookie.
324
+ * If there was no session id in the cookie, there won't be
325
+ * any data inside the store either.
363
326
  */
364
- if (!this.#store.isEmpty) {
365
- await this.#commitValuesToStore();
327
+ if (this.isEmpty) {
328
+ if (this.#sessionIdFromCookie) {
329
+ await this.#driver.destroy(this.#sessionIdFromCookie);
330
+ }
331
+ this.#emitter.emit('session:committed', { session: this });
332
+ return;
333
+ }
334
+ /**
335
+ * Touch the store expiry when the session store was
336
+ * not modified.
337
+ */
338
+ if (!this.hasBeenModified) {
339
+ if (this.#sessionIdFromCookie && this.#sessionIdFromCookie !== this.#sessionId) {
340
+ await this.#driver.destroy(this.#sessionIdFromCookie);
341
+ await this.#driver.write(this.#sessionId, this.#store.toJSON());
342
+ this.#emitter.emit('session:migrated', {
343
+ fromSessionId: this.#sessionIdFromCookie,
344
+ toSessionId: this.sessionId,
345
+ session: this,
346
+ });
347
+ }
348
+ else {
349
+ await this.#driver.touch(this.#sessionId);
350
+ }
351
+ this.#emitter.emit('session:committed', { session: this });
352
+ return;
353
+ }
354
+ /**
355
+ * Otherwise commit to the session store
356
+ */
357
+ if (this.#sessionIdFromCookie && this.#sessionIdFromCookie !== this.#sessionId) {
358
+ await this.#driver.destroy(this.#sessionIdFromCookie);
359
+ await this.#driver.write(this.#sessionId, this.#store.toJSON());
360
+ this.#emitter.emit('session:migrated', {
361
+ fromSessionId: this.#sessionIdFromCookie,
362
+ toSessionId: this.sessionId,
363
+ session: this,
364
+ });
366
365
  }
367
366
  else {
368
- await this.#driver.destroy(this.sessionId);
367
+ await this.#driver.write(this.#sessionId, this.#store.toJSON());
369
368
  }
369
+ this.#emitter.emit('session:committed', { session: this });
370
370
  }
371
371
  }
@@ -1,8 +1,22 @@
1
- import type { HttpContext } from '@adonisjs/core/http';
1
+ import { EmitterService } from '@adonisjs/core/types';
2
2
  import type { NextFn } from '@adonisjs/core/types/http';
3
- import { SessionManager } from './session_manager.js';
3
+ import { HttpContext } from '@adonisjs/core/http';
4
+ import { Session } from './session.js';
5
+ import type { SessionConfig } from './types/main.js';
6
+ /**
7
+ * HttpContext augmentations
8
+ */
9
+ declare module '@adonisjs/core/http' {
10
+ interface HttpContext {
11
+ session: Session;
12
+ }
13
+ }
14
+ /**
15
+ * Session middleware is used to initiate the session store
16
+ * and commit its values during an HTTP request
17
+ */
4
18
  export default class SessionMiddleware {
5
- protected session: SessionManager;
6
- constructor(session: SessionManager);
7
- handle(ctx: HttpContext, next: NextFn): Promise<void>;
19
+ #private;
20
+ constructor(config: SessionConfig, emitter: EmitterService);
21
+ handle(ctx: HttpContext, next: NextFn): Promise<any>;
8
22
  }