@adonisjs/session 6.1.4 → 6.2.2

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.
@@ -1,3 +1,4 @@
1
1
  /// <reference path="session.d.ts" />
2
2
  /// <reference path="context.d.ts" />
3
3
  /// <reference path="container.d.ts" />
4
+ /// <reference path="tests.d.ts" />
@@ -9,3 +9,4 @@
9
9
  /// <reference path="./session.ts" />
10
10
  /// <reference path="./context.ts" />
11
11
  /// <reference path="./container.ts" />
12
+ /// <reference path="./tests.ts" />
@@ -220,6 +220,21 @@ declare module '@ioc:Adonis/Addons/Session' {
220
220
  * SessionClient exposes the API to set session data as a client
221
221
  */
222
222
  export interface SessionClientContract extends StoreContract {
223
+ /**
224
+ * Find if the sessions are enabled
225
+ */
226
+ isEnabled(): boolean;
227
+ /**
228
+ * Flash messages store to set flash messages
229
+ */
230
+ flashMessages: StoreContract;
231
+ /**
232
+ * Load session data from the driver
233
+ */
234
+ load(): Promise<{
235
+ session: Record<string, any>;
236
+ flashMessages: Record<string, any> | null;
237
+ }>;
223
238
  /**
224
239
  * Commits the session data to the session store and returns
225
240
  * the session id and cookie name for it to be accessible
@@ -228,6 +243,7 @@ declare module '@ioc:Adonis/Addons/Session' {
228
243
  commit(): Promise<{
229
244
  cookieName: string;
230
245
  sessionId: string;
246
+ signedSessionId: string;
231
247
  }>;
232
248
  /**
233
249
  * Forget the session data.
@@ -238,6 +254,7 @@ declare module '@ioc:Adonis/Addons/Session' {
238
254
  * Session manager shape
239
255
  */
240
256
  export interface SessionManagerContract {
257
+ isEnabled(): boolean;
241
258
  application: ApplicationContract;
242
259
  client(): SessionClientContract;
243
260
  create(ctx: HttpContextContract): SessionContract;
@@ -0,0 +1,50 @@
1
+ import '@japa/api-client';
2
+ import { AllowedSessionValues, SessionClientContract } from '@ioc:Adonis/Addons/Session';
3
+ declare module '@japa/api-client' {
4
+ interface ApiRequest {
5
+ sessionClient: SessionClientContract;
6
+ /**
7
+ * Send session values in the request
8
+ */
9
+ session(session: Record<string, AllowedSessionValues>): this;
10
+ /**
11
+ * Send flash messages in the request
12
+ */
13
+ flashMessages(messages: Record<string, AllowedSessionValues>): this;
14
+ }
15
+ interface ApiResponse {
16
+ /**
17
+ * A copy of session data loaded from the driver
18
+ */
19
+ sessionJar: {
20
+ session: Record<string, any>;
21
+ flashMessages: Record<string, any> | null;
22
+ };
23
+ /**
24
+ * Get session data
25
+ */
26
+ session(): Record<string, any>;
27
+ /**
28
+ * Get flash messages set by the server
29
+ */
30
+ flashMessages(): Record<string, any>;
31
+ /**
32
+ * Assert response to contain a given session and optionally
33
+ * has the expected value
34
+ */
35
+ assertSession(key: string, value?: any): void;
36
+ /**
37
+ * Assert response to not contain a given session
38
+ */
39
+ assertSessionMissing(key: string): void;
40
+ /**
41
+ * Assert response to contain a given flash message and optionally
42
+ * has the expected value
43
+ */
44
+ assertFlashMessage(key: string, value?: any): void;
45
+ /**
46
+ * Assert response to not contain a given session
47
+ */
48
+ assertFlashMissing(key: string): void;
49
+ }
50
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ /*
3
+ * @adonisjs/session
4
+ *
5
+ * (c) AdonisJS
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ require("@japa/api-client");
@@ -19,5 +19,13 @@ export default class SessionProvider {
19
19
  * Register Session Manager
20
20
  */
21
21
  register(): void;
22
+ /**
23
+ * Register bindings for tests
24
+ */
25
+ protected registerTestsBindings(): void;
26
+ /**
27
+ * Register server bindings
28
+ */
29
+ protected registerServerBindings(): void;
22
30
  boot(): void;
23
31
  }
@@ -24,39 +24,33 @@ class SessionProvider {
24
24
  return new SessionManager(this.app, this.app.config.get('session', {}));
25
25
  });
26
26
  }
27
- boot() {
28
- /**
29
- * Hook session into ctx during request cycle. We make use of hooks over
30
- * middleware, since Hooks guarantee the `after` execution even when
31
- * any middleware or controller raises exception.
32
- */
27
+ /**
28
+ * Register bindings for tests
29
+ */
30
+ registerTestsBindings() {
31
+ this.app.container.withBindings([
32
+ 'Japa/Preset/ApiRequest',
33
+ 'Japa/Preset/ApiResponse',
34
+ 'Japa/Preset/ApiClient',
35
+ 'Adonis/Addons/Session',
36
+ ], (ApiRequest, ApiResponse, ApiClient, Session) => {
37
+ const { defineTestsBindings } = require('../src/Bindings/Tests');
38
+ defineTestsBindings(ApiRequest, ApiResponse, ApiClient, Session);
39
+ });
40
+ }
41
+ /**
42
+ * Register server bindings
43
+ */
44
+ registerServerBindings() {
33
45
  this.app.container.withBindings(['Adonis/Core/Server', 'Adonis/Core/HttpContext', 'Adonis/Addons/Session'], (Server, HttpContext, Session) => {
34
- /**
35
- * Sharing session with the context
36
- */
37
- HttpContext.getter('session', function session() {
38
- return Session.create(this);
39
- }, true);
40
- /**
41
- * Do not register hooks when sessions are disabled
42
- */
43
- if (!this.app.config.get('session.enabled', true)) {
44
- return;
45
- }
46
- /**
47
- * Initiate session store
48
- */
49
- Server.hooks.before(async (ctx) => {
50
- await ctx.session.initiate(false);
51
- });
52
- /**
53
- * Commit store mutations
54
- */
55
- Server.hooks.after(async (ctx) => {
56
- await ctx.session.commit();
57
- });
46
+ const { defineServerBindings } = require('../src/Bindings/Server');
47
+ defineServerBindings(HttpContext, Server, Session);
58
48
  });
59
49
  }
50
+ boot() {
51
+ this.registerServerBindings();
52
+ this.registerTestsBindings();
53
+ }
60
54
  }
61
55
  exports.default = SessionProvider;
62
56
  SessionProvider.needsApplication = true;
@@ -0,0 +1,10 @@
1
+ /// <reference path="../../adonis-typings/index.d.ts" />
2
+ /// <reference types="@adonisjs/http-server/build/adonis-typings" />
3
+ import { ServerContract } from '@ioc:Adonis/Core/Server';
4
+ import { SessionManagerContract } from '@ioc:Adonis/Addons/Session';
5
+ import { HttpContextConstructorContract } from '@ioc:Adonis/Core/HttpContext';
6
+ /**
7
+ * Share "session" with the HTTP context. Define hooks to initiate and
8
+ * commit session when sessions are enabled.
9
+ */
10
+ export declare function defineServerBindings(HttpContext: HttpContextConstructorContract, Server: ServerContract, Session: SessionManagerContract): void;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ /*
3
+ * @adonisjs/session
4
+ *
5
+ * (c) AdonisJS
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.defineServerBindings = void 0;
12
+ /**
13
+ * Share "session" with the HTTP context. Define hooks to initiate and
14
+ * commit session when sessions are enabled.
15
+ */
16
+ function defineServerBindings(HttpContext, Server, Session) {
17
+ /**
18
+ * Sharing session with the context
19
+ */
20
+ HttpContext.getter('session', function session() {
21
+ return Session.create(this);
22
+ }, true);
23
+ /**
24
+ * Do not register hooks when sessions are disabled
25
+ */
26
+ if (!Session.isEnabled()) {
27
+ return;
28
+ }
29
+ /**
30
+ * Initiate session store
31
+ */
32
+ Server.hooks.before(async (ctx) => {
33
+ await ctx.session.initiate(false);
34
+ });
35
+ /**
36
+ * Commit store mutations
37
+ */
38
+ Server.hooks.after(async (ctx) => {
39
+ await ctx.session.commit();
40
+ });
41
+ }
42
+ exports.defineServerBindings = defineServerBindings;
@@ -0,0 +1,7 @@
1
+ /// <reference path="../../adonis-typings/index.d.ts" />
2
+ import { ContainerBindings } from '@ioc:Adonis/Core/Application';
3
+ import { SessionManagerContract } from '@ioc:Adonis/Addons/Session';
4
+ /**
5
+ * Define test bindings
6
+ */
7
+ export declare function defineTestsBindings(ApiRequest: ContainerBindings['Japa/Preset/ApiRequest'], ApiResponse: ContainerBindings['Japa/Preset/ApiResponse'], ApiClient: ContainerBindings['Japa/Preset/ApiClient'], SessionManager: SessionManagerContract): void;
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ /*
3
+ * @adonisjs/session
4
+ *
5
+ * (c) AdonisJS
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.defineTestsBindings = void 0;
12
+ /**
13
+ * Define test bindings
14
+ */
15
+ function defineTestsBindings(ApiRequest, ApiResponse, ApiClient, SessionManager) {
16
+ /**
17
+ * Set "sessionClient" on the api request
18
+ */
19
+ ApiRequest.getter('sessionClient', function () {
20
+ return SessionManager.client();
21
+ }, true);
22
+ /**
23
+ * Send session values in the request
24
+ */
25
+ ApiRequest.macro('session', function (session) {
26
+ if (!this.sessionClient.isEnabled()) {
27
+ throw new Error('Cannot set session. Make sure to enable it inside "config/session" file');
28
+ }
29
+ this.sessionClient.merge(session);
30
+ return this;
31
+ });
32
+ /**
33
+ * Send flash messages in the request
34
+ */
35
+ ApiRequest.macro('flashMessages', function (messages) {
36
+ if (!this.sessionClient.isEnabled()) {
37
+ throw new Error('Cannot set flash messages. Make sure to enable the session inside "config/session" file');
38
+ }
39
+ this.sessionClient.flashMessages.merge(messages);
40
+ return this;
41
+ });
42
+ /**
43
+ * Returns reference to the session data from the session
44
+ * jar
45
+ */
46
+ ApiResponse.macro('session', function () {
47
+ return this.sessionJar.session;
48
+ });
49
+ /**
50
+ * Returns reference to the flash messages from the session
51
+ * jar
52
+ */
53
+ ApiResponse.macro('flashMessages', function () {
54
+ return this.sessionJar.flashMessages || {};
55
+ });
56
+ /**
57
+ * Assert response to contain a given session and optionally
58
+ * has the expected value
59
+ */
60
+ ApiResponse.macro('assertSession', function (name, value) {
61
+ this.ensureHasAssert();
62
+ this.assert.property(this.session(), name);
63
+ if (value !== undefined) {
64
+ this.assert.deepEqual(this.session()[name], value);
65
+ }
66
+ });
67
+ /**
68
+ * Assert response to not contain a given session
69
+ */
70
+ ApiResponse.macro('assertSessionMissing', function (name) {
71
+ this.ensureHasAssert();
72
+ this.assert.notProperty(this.session(), name);
73
+ });
74
+ /**
75
+ * Assert response to contain a given flash message and optionally
76
+ * has the expected value
77
+ */
78
+ ApiResponse.macro('assertFlashMessage', function (name, value) {
79
+ this.ensureHasAssert();
80
+ this.assert.property(this.flashMessages(), name);
81
+ if (value !== undefined) {
82
+ this.assert.deepEqual(this.flashMessages()[name], value);
83
+ }
84
+ });
85
+ /**
86
+ * Assert response to not contain a given session
87
+ */
88
+ ApiResponse.macro('assertFlashMissing', function (name) {
89
+ this.ensureHasAssert();
90
+ this.assert.notProperty(this.flashMessages(), name);
91
+ });
92
+ /**
93
+ * Adding hooks directly on the request object moves the hooks to
94
+ * the end of the queue (basically after the globally hooks)
95
+ */
96
+ ApiClient.onRequest((req) => {
97
+ /**
98
+ * Hook into request and persist session data to be available
99
+ * on the server during the request.
100
+ */
101
+ req.setup(async (request) => {
102
+ /**
103
+ * Persist session data and set the session id within the
104
+ * cookie
105
+ */
106
+ const { cookieName, sessionId } = await request.sessionClient.commit();
107
+ request.cookie(cookieName, sessionId);
108
+ /**
109
+ * Cleanup if request has error. Otherwise the teardown
110
+ * hook will clear
111
+ */
112
+ return async (error) => {
113
+ if (error) {
114
+ await request.sessionClient.forget();
115
+ }
116
+ };
117
+ });
118
+ /**
119
+ * Load messages from the session store and keep a reference to it
120
+ * inside the response object.
121
+ *
122
+ * We also destroy the session after getting a copy of the session
123
+ * data
124
+ */
125
+ req.teardown(async (response) => {
126
+ response.sessionJar = await response.request.sessionClient.load();
127
+ await response.request.sessionClient.forget();
128
+ });
129
+ });
130
+ }
131
+ exports.defineTestsBindings = defineTestsBindings;
@@ -15,9 +15,29 @@ export declare class SessionClient extends Store implements SessionClientContrac
15
15
  * multiple client instances for a different session id
16
16
  */
17
17
  private sessionId;
18
+ /**
19
+ * Session key for setting flash messages
20
+ */
21
+ private flashMessagesKey;
22
+ /**
23
+ * Flash messages store. They are merged with the session data during
24
+ * commit
25
+ */
26
+ flashMessages: Store;
18
27
  constructor(config: SessionConfig, driver: SessionDriverContract, cookieClient: CookieClientContract, values: {
19
28
  [key: string]: any;
20
29
  } | null);
30
+ /**
31
+ * Find if the sessions are enabled
32
+ */
33
+ isEnabled(): boolean;
34
+ /**
35
+ * Load session from the driver
36
+ */
37
+ load(): Promise<{
38
+ session: any;
39
+ flashMessages: any;
40
+ }>;
21
41
  /**
22
42
  * Commits the session data to the session store and returns
23
43
  * the session id and cookie name for it to be accessible
@@ -25,6 +45,7 @@ export declare class SessionClient extends Store implements SessionClientContrac
25
45
  */
26
46
  commit(): Promise<{
27
47
  sessionId: string;
48
+ signedSessionId: string;
28
49
  cookieName: string;
29
50
  }>;
30
51
  /**
@@ -26,6 +26,33 @@ class SessionClient extends Store_1.Store {
26
26
  * multiple client instances for a different session id
27
27
  */
28
28
  this.sessionId = (0, helpers_1.cuid)();
29
+ /**
30
+ * Session key for setting flash messages
31
+ */
32
+ this.flashMessagesKey = '__flash__';
33
+ /**
34
+ * Flash messages store. They are merged with the session data during
35
+ * commit
36
+ */
37
+ this.flashMessages = new Store_1.Store({});
38
+ }
39
+ /**
40
+ * Find if the sessions are enabled
41
+ */
42
+ isEnabled() {
43
+ return this.config.enabled;
44
+ }
45
+ /**
46
+ * Load session from the driver
47
+ */
48
+ async load() {
49
+ const contents = await this.driver.read(this.sessionId);
50
+ const store = new Store_1.Store(contents);
51
+ const flashMessages = store.pull(this.flashMessagesKey, null);
52
+ return {
53
+ session: store.all(),
54
+ flashMessages,
55
+ };
29
56
  }
30
57
  /**
31
58
  * Commits the session data to the session store and returns
@@ -33,10 +60,16 @@ class SessionClient extends Store_1.Store {
33
60
  * by the server
34
61
  */
35
62
  async commit() {
63
+ this.set(this.flashMessagesKey, this.flashMessages.all());
36
64
  await this.driver.write(this.sessionId, this.toJSON());
65
+ /**
66
+ * Clear from the session client memory
67
+ */
37
68
  this.clear();
69
+ this.flashMessages.clear();
38
70
  return {
39
- sessionId: this.cookieClient.sign(this.config.cookieName, this.sessionId),
71
+ sessionId: this.sessionId,
72
+ signedSessionId: this.cookieClient.sign(this.config.cookieName, this.sessionId),
40
73
  cookieName: this.config.cookieName,
41
74
  };
42
75
  }
@@ -44,8 +77,15 @@ class SessionClient extends Store_1.Store {
44
77
  * Clear the session store
45
78
  */
46
79
  async forget() {
80
+ /**
81
+ * Clear from the session client memory
82
+ */
47
83
  this.clear();
48
- this.driver.destroy(this.sessionId);
84
+ this.flashMessages.clear();
85
+ /**
86
+ * Clear with the driver
87
+ */
88
+ await this.driver.destroy(this.sessionId);
49
89
  }
50
90
  }
51
91
  exports.SessionClient = SessionClient;
@@ -59,6 +59,10 @@ export declare class SessionManager implements SessionManagerContract {
59
59
  * An hard exception is raised in case of invalid driver name
60
60
  */
61
61
  private createDriver;
62
+ /**
63
+ * Find if the sessions are enabled
64
+ */
65
+ isEnabled(): boolean;
62
66
  /**
63
67
  * Creates an instance of the session client
64
68
  */
@@ -41,7 +41,7 @@ class SessionManager {
41
41
  * Explicitly overwriting `cookie.expires` and `cookie.maxAge` from
42
42
  * the user defined config
43
43
  */
44
- const processedConfig = Object.assign({}, config, {
44
+ const processedConfig = Object.assign({ enabled: true }, config, {
45
45
  cookie: {
46
46
  ...config.cookie,
47
47
  expires: undefined,
@@ -118,6 +118,12 @@ class SessionManager {
118
118
  return this.createExtendedDriver(ctx);
119
119
  }
120
120
  }
121
+ /**
122
+ * Find if the sessions are enabled
123
+ */
124
+ isEnabled() {
125
+ return this.config.enabled;
126
+ }
121
127
  /**
122
128
  * Creates an instance of the session client
123
129
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonisjs/session",
3
- "version": "6.1.4",
3
+ "version": "6.2.2",
4
4
  "description": "Session provider for AdonisJS",
5
5
  "typings": "./build/adonis-typings/index.d.ts",
6
6
  "main": "build/providers/SessionProvider.js",
@@ -12,39 +12,40 @@
12
12
  "build/instructions.md"
13
13
  ],
14
14
  "dependencies": {
15
- "@poppinss/utils": "^4.0.2",
15
+ "@poppinss/utils": "^4.0.4",
16
16
  "fs-extra": "^10.0.1"
17
17
  },
18
18
  "peerDependencies": {
19
19
  "@adonisjs/core": "^5.5.0"
20
20
  },
21
21
  "devDependencies": {
22
- "@adonisjs/core": "^5.5.0",
23
- "@adonisjs/mrm-preset": "^5.0.2",
24
- "@adonisjs/redis": "^7.1.1",
25
- "@adonisjs/require-ts": "^2.0.10",
26
- "@japa/assert": "^1.2.3",
27
- "@japa/run-failed-tests": "^1.0.3",
28
- "@japa/runner": "^1.2.0",
29
- "@japa/spec-reporter": "^1.1.7",
30
- "@poppinss/dev-utils": "^2.0.2",
31
- "@types/node": "^17.0.21",
32
- "@types/supertest": "^2.0.11",
22
+ "@adonisjs/core": "^5.7.3",
23
+ "@adonisjs/mrm-preset": "^5.0.3",
24
+ "@adonisjs/redis": "^7.2.0",
25
+ "@adonisjs/require-ts": "^2.0.11",
26
+ "@japa/assert": "^1.3.4",
27
+ "@japa/preset-adonis": "^1.0.15",
28
+ "@japa/run-failed-tests": "^1.0.7",
29
+ "@japa/runner": "^2.0.7",
30
+ "@japa/spec-reporter": "^1.1.12",
31
+ "@poppinss/dev-utils": "^2.0.3",
32
+ "@types/node": "^17.0.23",
33
+ "@types/supertest": "^2.0.12",
33
34
  "commitizen": "^4.2.4",
34
35
  "copyfiles": "^2.4.1",
35
36
  "cz-conventional-changelog": "^3.3.0",
36
37
  "del-cli": "^4.0.1",
37
- "eslint": "^8.10.0",
38
- "eslint-config-prettier": "^8.4.0",
38
+ "eslint": "^8.13.0",
39
+ "eslint-config-prettier": "^8.5.0",
39
40
  "eslint-plugin-adonis": "^2.1.0",
40
41
  "eslint-plugin-prettier": "^4.0.0",
41
- "github-label-sync": "^2.0.2",
42
+ "github-label-sync": "^2.2.0",
42
43
  "husky": "^7.0.4",
43
- "mrm": "^3.0.10",
44
- "np": "^7.6.0",
45
- "prettier": "^2.5.1",
44
+ "mrm": "^4.0.0",
45
+ "np": "^7.6.1",
46
+ "prettier": "^2.6.2",
46
47
  "supertest": "^6.2.2",
47
- "typescript": "^4.5.5"
48
+ "typescript": "^4.6.3"
48
49
  },
49
50
  "scripts": {
50
51
  "mrm": "mrm --preset=@adonisjs/mrm-preset",