@adonisjs/session 6.1.2 → 6.2.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/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # The MIT License
2
2
 
3
- Copyright 2021 Harminder Virk, contributors
3
+ Copyright 2022 Harminder Virk, contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
6
 
@@ -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
+ withSession(session: Record<string, AllowedSessionValues>): this;
10
+ /**
11
+ * Send flash messages in the request
12
+ */
13
+ withFlashMessages(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,125 @@
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('withSession', 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('withFlashMessages', 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
+ * Hook into request and persist session data to be available
94
+ * on the server during the request.
95
+ */
96
+ ApiClient.setup(async (request) => {
97
+ /**
98
+ * Persist session data and set the session id within the
99
+ * cookie
100
+ */
101
+ const { cookieName, sessionId } = await request.sessionClient.commit();
102
+ request.cookie(cookieName, sessionId);
103
+ /**
104
+ * Cleanup if request has error. Otherwise the teardown
105
+ * hook will clear
106
+ */
107
+ return async (error) => {
108
+ if (error) {
109
+ await request.sessionClient.forget();
110
+ }
111
+ };
112
+ });
113
+ /**
114
+ * Load messages from the session store and keep a reference to it
115
+ * inside the response object.
116
+ *
117
+ * We also destroy the session after getting a copy of the session
118
+ * data
119
+ */
120
+ ApiClient.teardown(async (response) => {
121
+ response.sessionJar = await response.request.sessionClient.load();
122
+ await response.request.sessionClient.forget();
123
+ });
124
+ }
125
+ 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.2",
3
+ "version": "6.2.0",
4
4
  "description": "Session provider for AdonisJS",
5
5
  "typings": "./build/adonis-typings/index.d.ts",
6
6
  "main": "build/providers/SessionProvider.js",
@@ -12,45 +12,51 @@
12
12
  "build/instructions.md"
13
13
  ],
14
14
  "dependencies": {
15
- "@poppinss/utils": "^3.2.0",
16
- "fs-extra": "^10.0.0"
15
+ "@poppinss/utils": "^4.0.2",
16
+ "fs-extra": "^10.0.1"
17
17
  },
18
18
  "peerDependencies": {
19
- "@adonisjs/core": "^5.1.0"
19
+ "@adonisjs/core": "^5.5.0"
20
20
  },
21
21
  "devDependencies": {
22
- "@adonisjs/core": "^5.3.1",
23
- "@adonisjs/mrm-preset": "^4.1.2",
24
- "@adonisjs/redis": "^7.0.9",
25
- "@adonisjs/require-ts": "^2.0.8",
26
- "@poppinss/dev-utils": "^1.1.5",
27
- "@types/node": "^16.7.5",
28
- "@types/supertest": "^2.0.11",
22
+ "@adonisjs/core": "^5.6.2",
23
+ "@adonisjs/mrm-preset": "^5.0.3",
24
+ "@adonisjs/redis": "^7.1.1",
25
+ "@adonisjs/require-ts": "^2.0.10",
26
+ "@japa/assert": "^1.3.3",
27
+ "@japa/preset-adonis": "^1.0.11",
28
+ "@japa/run-failed-tests": "^1.0.7",
29
+ "@japa/runner": "^2.0.6",
30
+ "@japa/spec-reporter": "^1.1.12",
31
+ "@poppinss/dev-utils": "^2.0.2",
32
+ "@types/node": "^17.0.23",
33
+ "@types/supertest": "^2.0.12",
34
+ "commitizen": "^4.2.4",
29
35
  "copyfiles": "^2.4.1",
36
+ "cz-conventional-changelog": "^3.3.0",
30
37
  "del-cli": "^4.0.1",
31
- "eslint": "^7.32.0",
32
- "eslint-config-prettier": "^8.3.0",
33
- "eslint-plugin-adonis": "^1.3.3",
34
- "eslint-plugin-prettier": "^3.4.1",
35
- "github-label-sync": "^2.0.2",
36
- "husky": "^7.0.2",
37
- "japa": "^3.1.1",
38
- "mrm": "^3.0.8",
39
- "np": "^7.5.0",
40
- "prettier": "^2.3.2",
41
- "supertest": "^6.1.6",
42
- "typescript": "^4.4.2"
38
+ "eslint": "^8.12.0",
39
+ "eslint-config-prettier": "^8.5.0",
40
+ "eslint-plugin-adonis": "^2.1.0",
41
+ "eslint-plugin-prettier": "^4.0.0",
42
+ "github-label-sync": "^2.1.1",
43
+ "husky": "^7.0.4",
44
+ "mrm": "^4.0.0",
45
+ "np": "^7.6.1",
46
+ "prettier": "^2.6.2",
47
+ "supertest": "^6.2.2",
48
+ "typescript": "^4.6.3"
43
49
  },
44
50
  "scripts": {
45
51
  "mrm": "mrm --preset=@adonisjs/mrm-preset",
46
52
  "pretest": "npm run lint",
47
- "test": "node japaFile.js",
53
+ "test": "node -r @adonisjs/require-ts/build/register ./bin/test.ts",
48
54
  "clean": "del build",
49
55
  "compile": "npm run lint && npm run clean && tsc",
50
56
  "copyfiles": "copyfiles \"templates/**/*.txt\" \"instructions.md\" build",
51
57
  "build": "npm run compile && npm run copyfiles",
52
58
  "commit": "git-cz",
53
- "release": "np",
59
+ "release": "np --message=\"chore(release): %s\"",
54
60
  "version": "npm run build",
55
61
  "prepublishOnly": "npm run build",
56
62
  "lint": "eslint . --ext=.ts",
@@ -111,5 +117,48 @@
111
117
  "np": {
112
118
  "contents": ".",
113
119
  "anyBranch": false
120
+ },
121
+ "mrmConfig": {
122
+ "core": true,
123
+ "license": "MIT",
124
+ "services": [
125
+ "github-actions"
126
+ ],
127
+ "minNodeVersion": "14.15.4",
128
+ "probotApps": [
129
+ "stale",
130
+ "lock"
131
+ ],
132
+ "runGhActionsOnWindows": false
133
+ },
134
+ "eslintConfig": {
135
+ "extends": [
136
+ "plugin:adonis/typescriptPackage",
137
+ "prettier"
138
+ ],
139
+ "plugins": [
140
+ "prettier"
141
+ ],
142
+ "rules": {
143
+ "prettier/prettier": [
144
+ "error",
145
+ {
146
+ "endOfLine": "auto"
147
+ }
148
+ ]
149
+ }
150
+ },
151
+ "eslintIgnore": [
152
+ "build"
153
+ ],
154
+ "prettier": {
155
+ "trailingComma": "es5",
156
+ "semi": false,
157
+ "singleQuote": true,
158
+ "useTabs": false,
159
+ "quoteProps": "consistent",
160
+ "bracketSpacing": true,
161
+ "arrowParens": "always",
162
+ "printWidth": 100
114
163
  }
115
164
  }