@adonisjs/session 7.0.0-1 → 7.0.0-11

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 (57) hide show
  1. package/README.md +5 -8
  2. package/build/configure.js +29 -2
  3. package/build/factories/main.d.ts +1 -0
  4. package/build/factories/main.js +9 -0
  5. package/build/factories/session_middleware_factory.d.ts +22 -0
  6. package/build/factories/session_middleware_factory.js +47 -0
  7. package/build/index.d.ts +5 -3
  8. package/build/index.js +5 -3
  9. package/build/providers/session_provider.d.ts +15 -4
  10. package/build/providers/session_provider.js +37 -20
  11. package/build/src/client.d.ts +23 -30
  12. package/build/src/client.js +46 -61
  13. package/build/src/debug.d.ts +3 -0
  14. package/build/src/debug.js +10 -0
  15. package/build/src/define_config.d.ts +6 -3
  16. package/build/src/define_config.js +34 -5
  17. package/build/src/drivers/cookie.d.ts +7 -9
  18. package/build/src/drivers/cookie.js +10 -6
  19. package/build/src/drivers/file.d.ts +11 -14
  20. package/build/src/drivers/file.js +90 -34
  21. package/build/src/drivers/memory.d.ts +4 -8
  22. package/build/src/drivers/memory.js +0 -3
  23. package/build/src/drivers/redis.d.ts +4 -6
  24. package/build/src/drivers/redis.js +25 -29
  25. package/build/src/drivers_collection.d.ts +21 -0
  26. package/build/src/drivers_collection.js +38 -0
  27. package/build/src/errors.d.ts +8 -0
  28. package/build/src/errors.js +17 -0
  29. package/build/src/helpers.d.ts +6 -0
  30. package/build/src/helpers.js +43 -0
  31. package/build/src/plugins/edge.d.ts +6 -0
  32. package/build/src/plugins/edge.js +92 -0
  33. package/build/src/plugins/japa/api_client.d.ts +75 -0
  34. package/build/src/plugins/japa/api_client.js +145 -0
  35. package/build/src/plugins/japa/browser_client.d.ts +36 -0
  36. package/build/src/plugins/japa/browser_client.js +119 -0
  37. package/build/src/session.d.ts +86 -59
  38. package/build/src/session.js +235 -222
  39. package/build/src/session_middleware.d.ts +19 -2
  40. package/build/src/session_middleware.js +43 -4
  41. package/build/src/store.d.ts +48 -35
  42. package/build/src/store.js +85 -57
  43. package/build/src/types/extended.d.ts +19 -0
  44. package/build/src/types/main.d.ts +106 -0
  45. package/build/src/types/main.js +9 -0
  46. package/build/stubs/config.stub +28 -92
  47. package/package.json +49 -26
  48. package/build/src/bindings/api_client.d.ts +0 -2
  49. package/build/src/bindings/api_client.js +0 -135
  50. package/build/src/bindings/http_context.d.ts +0 -5
  51. package/build/src/bindings/http_context.js +0 -17
  52. package/build/src/bindings/types.d.ts +0 -77
  53. package/build/src/session_manager.d.ts +0 -38
  54. package/build/src/session_manager.js +0 -149
  55. package/build/src/types.d.ts +0 -61
  56. package/build/src/types.js +0 -1
  57. /package/build/src/{bindings/types.js → types/extended.js} +0 -0
@@ -0,0 +1,75 @@
1
+ import type { PluginFn } from '@japa/runner/types';
2
+ import type { ApplicationService } from '@adonisjs/core/types';
3
+ import { SessionClient } from '../../client.js';
4
+ import type { SessionData } from '../../types/main.js';
5
+ declare module '@japa/api-client' {
6
+ interface ApiRequest {
7
+ sessionClient: SessionClient;
8
+ /**
9
+ * Make HTTP request along with the provided session data
10
+ */
11
+ withSession(values: SessionData): this;
12
+ /**
13
+ * Make HTTP request along with the provided session flash
14
+ * messages.
15
+ */
16
+ withFlashMessages(values: SessionData): this;
17
+ }
18
+ interface ApiResponse {
19
+ sessionBag: {
20
+ values: SessionData;
21
+ flashMessages: SessionData;
22
+ };
23
+ /**
24
+ * Get session data from the HTTP response
25
+ */
26
+ session(key?: string): any;
27
+ /**
28
+ * Get flash messages from the HTTP response
29
+ */
30
+ flashMessages(): SessionData;
31
+ /**
32
+ * Get flash messages for a specific key from the HTTP response
33
+ */
34
+ flashMessage(key: string): SessionData;
35
+ /**
36
+ * Assert session key-value pair exists
37
+ */
38
+ assertSession(key: string, value?: any): void;
39
+ /**
40
+ * Assert key is missing in session store
41
+ */
42
+ assertSessionMissing(key: string): void;
43
+ /**
44
+ * Assert flash message key-value pair exists
45
+ */
46
+ assertFlashMessage(key: string, value?: any): void;
47
+ /**
48
+ * Assert key is missing flash messages store
49
+ */
50
+ assertFlashMissing(key: string): void;
51
+ /**
52
+ * Assert flash messages has validation errors for
53
+ * the given field
54
+ */
55
+ assertHasValidationError(field: string): void;
56
+ /**
57
+ * Assert flash messages does not have validation errors
58
+ * for the given field
59
+ */
60
+ assertDoesNotHaveValidationError(field: string): void;
61
+ /**
62
+ * Assert error message for a given field
63
+ */
64
+ assertValidationError(field: string, message: string): void;
65
+ /**
66
+ * Assert all error messages for a given field
67
+ */
68
+ assertValidationErrors(field: string, messages: string[]): void;
69
+ }
70
+ }
71
+ /**
72
+ * Hooks AdonisJS Session with the Japa API Client
73
+ * plugin
74
+ */
75
+ export declare const sessionApiClient: (app: ApplicationService) => PluginFn;
@@ -0,0 +1,145 @@
1
+ /*
2
+ * @adonisjs/session
3
+ *
4
+ * (c) AdonisJS
5
+ *
6
+ * For the full copyright and license information, please view the LICENSE
7
+ * file that was distributed with this source code.
8
+ */
9
+ import lodash from '@poppinss/utils/lodash';
10
+ import { RuntimeException } from '@poppinss/utils';
11
+ import { ApiClient, ApiRequest, ApiResponse } from '@japa/api-client';
12
+ import { SessionClient } from '../../client.js';
13
+ import { registerSessionDriver } from '../../helpers.js';
14
+ import sessionDriversList from '../../drivers_collection.js';
15
+ /**
16
+ * Hooks AdonisJS Session with the Japa API Client
17
+ * plugin
18
+ */
19
+ export const sessionApiClient = (app) => {
20
+ const pluginFn = async function () {
21
+ const config = app.config.get('session');
22
+ /**
23
+ * Disallow usage of driver other than memory during testing
24
+ */
25
+ if (config.driver !== 'memory') {
26
+ throw new RuntimeException(`Cannot use session driver "${config.driver}" during testing. Switch to memory driver`);
27
+ }
28
+ /**
29
+ * Register the memory driver if not already registered
30
+ */
31
+ await registerSessionDriver(app, 'memory');
32
+ /**
33
+ * Stick an singleton session client to APIRequest. The session
34
+ * client is used to keep a track of session data we have
35
+ * to send during the request.
36
+ */
37
+ ApiRequest.getter('sessionClient', function () {
38
+ return new SessionClient(sessionDriversList.create('memory', config));
39
+ }, true);
40
+ /**
41
+ * Define session data
42
+ */
43
+ ApiRequest.macro('withSession', function (data) {
44
+ this.sessionClient.merge(data);
45
+ return this;
46
+ });
47
+ /**
48
+ * Define flash messages
49
+ */
50
+ ApiRequest.macro('withFlashMessages', function (data) {
51
+ this.sessionClient.flash(data);
52
+ return this;
53
+ });
54
+ /**
55
+ * Get session data
56
+ */
57
+ ApiResponse.macro('session', function (key) {
58
+ return key ? lodash.get(this.sessionBag.values, key) : this.sessionBag.values;
59
+ });
60
+ /**
61
+ * Get flash messages
62
+ */
63
+ ApiResponse.macro('flashMessages', function () {
64
+ return this.sessionBag.flashMessages;
65
+ });
66
+ ApiResponse.macro('flashMessage', function (key) {
67
+ return lodash.get(this.sessionBag.flashMessages, key);
68
+ });
69
+ /**
70
+ * Response session assertions
71
+ */
72
+ ApiResponse.macro('assertSession', function (key, value) {
73
+ this.assert.property(this.session(), key);
74
+ if (value !== undefined) {
75
+ this.assert.deepEqual(this.session(key), value);
76
+ }
77
+ });
78
+ ApiResponse.macro('assertSessionMissing', function (key) {
79
+ this.assert.notProperty(this.session(), key);
80
+ });
81
+ ApiResponse.macro('assertFlashMessage', function (key, value) {
82
+ this.assert.property(this.flashMessages(), key);
83
+ if (value !== undefined) {
84
+ this.assert.deepEqual(this.flashMessage(key), value);
85
+ }
86
+ });
87
+ ApiResponse.macro('assertFlashMissing', function (key) {
88
+ this.assert.notProperty(this.flashMessages(), key);
89
+ });
90
+ ApiResponse.macro('assertHasValidationError', function (field) {
91
+ this.assert.property(this.flashMessage('errors'), field);
92
+ });
93
+ ApiResponse.macro('assertDoesNotHaveValidationError', function (field) {
94
+ this.assert.notProperty(this.flashMessage('errors'), field);
95
+ });
96
+ ApiResponse.macro('assertValidationError', function (field, message) {
97
+ this.assert.include(this.flashMessage('errors')?.[field] || [], message);
98
+ });
99
+ ApiResponse.macro('assertValidationErrors', function (field, messages) {
100
+ this.assert.deepEqual(this.flashMessage('errors')?.[field] || [], messages);
101
+ });
102
+ /**
103
+ * We define the hook using the "request.setup" method because we
104
+ * want to allow other Japa hooks to mutate the session store
105
+ * without running into race conditions
106
+ */
107
+ ApiClient.onRequest((request) => {
108
+ request.setup(async () => {
109
+ /**
110
+ * Set cookie
111
+ */
112
+ request.withCookie(config.cookieName, request.sessionClient.sessionId);
113
+ /**
114
+ * Persist data
115
+ */
116
+ await request.sessionClient.commit();
117
+ /**
118
+ * Cleanup if request fails
119
+ */
120
+ return async (error) => {
121
+ if (error) {
122
+ await request.sessionClient.destroy();
123
+ }
124
+ };
125
+ });
126
+ request.teardown(async (response) => {
127
+ const sessionId = response.cookie(config.cookieName);
128
+ /**
129
+ * Reading session data from the response cookie
130
+ */
131
+ response.sessionBag = sessionId
132
+ ? await response.request.sessionClient.load(sessionId.value)
133
+ : {
134
+ values: {},
135
+ flashMessages: {},
136
+ };
137
+ /**
138
+ * Cleanup state
139
+ */
140
+ await request.sessionClient.destroy(sessionId?.value);
141
+ });
142
+ });
143
+ };
144
+ return pluginFn;
145
+ };
@@ -0,0 +1,36 @@
1
+ import type { PluginFn } from '@japa/runner/types';
2
+ import type { ApplicationService } from '@adonisjs/core/types';
3
+ import type { CookieOptions as AdonisCookieOptions } from '@adonisjs/core/types/http';
4
+ import { SessionClient } from '../../client.js';
5
+ import type { SessionData } from '../../types/main.js';
6
+ declare module 'playwright' {
7
+ interface BrowserContext {
8
+ sessionClient: SessionClient;
9
+ /**
10
+ * Initiate session. The session id cookie will be defined
11
+ * if missing
12
+ */
13
+ initiateSession(options?: Partial<AdonisCookieOptions>): Promise<void>;
14
+ /**
15
+ * Returns data from the session store
16
+ */
17
+ getSession(): Promise<any>;
18
+ /**
19
+ * Returns data from the session store
20
+ */
21
+ getFlashMessages(): Promise<any>;
22
+ /**
23
+ * Set session data
24
+ */
25
+ setSession(values: SessionData): Promise<void>;
26
+ /**
27
+ * Set flash messages
28
+ */
29
+ setFlashMessages(values: SessionData): Promise<void>;
30
+ }
31
+ }
32
+ /**
33
+ * Hooks AdonisJS Session with the Japa API Client
34
+ * plugin
35
+ */
36
+ export declare const sessionBrowserClient: (app: ApplicationService) => PluginFn;
@@ -0,0 +1,119 @@
1
+ /*
2
+ * @adonisjs/session
3
+ *
4
+ * (c) AdonisJS
5
+ *
6
+ * For the full copyright and license information, please view the LICENSE
7
+ * file that was distributed with this source code.
8
+ */
9
+ import { RuntimeException } from '@poppinss/utils';
10
+ import { decoratorsCollection } from '@japa/browser-client';
11
+ import { SessionClient } from '../../client.js';
12
+ import { registerSessionDriver } from '../../helpers.js';
13
+ import sessionDriversList from '../../drivers_collection.js';
14
+ /**
15
+ * Transforming AdonisJS same site option to playwright
16
+ * same site option.
17
+ */
18
+ function transformSameSiteOption(sameSite) {
19
+ if (!sameSite) {
20
+ return;
21
+ }
22
+ if (sameSite === true || sameSite === 'strict') {
23
+ return 'Strict';
24
+ }
25
+ if (sameSite === 'lax') {
26
+ return 'Lax';
27
+ }
28
+ if (sameSite === 'none') {
29
+ return 'None';
30
+ }
31
+ }
32
+ /**
33
+ * Transforming AdonisJS session config to playwright cookie options.
34
+ */
35
+ function getSessionCookieOptions(config, cookieOptions) {
36
+ const options = { ...config.cookie, ...cookieOptions };
37
+ return {
38
+ ...options,
39
+ expires: undefined,
40
+ sameSite: transformSameSiteOption(options.sameSite),
41
+ };
42
+ }
43
+ /**
44
+ * Hooks AdonisJS Session with the Japa API Client
45
+ * plugin
46
+ */
47
+ export const sessionBrowserClient = (app) => {
48
+ const pluginFn = async function () {
49
+ const config = app.config.get('session');
50
+ /**
51
+ * Disallow usage of driver other than memory during testing
52
+ */
53
+ if (config.driver !== 'memory') {
54
+ throw new RuntimeException(`Cannot use session driver "${config.driver}" during testing. Switch to memory driver`);
55
+ }
56
+ /**
57
+ * Register the memory driver if not already registered
58
+ */
59
+ await registerSessionDriver(app, 'memory');
60
+ decoratorsCollection.register({
61
+ context(context) {
62
+ /**
63
+ * Reference to session client per browser context
64
+ */
65
+ context.sessionClient = new SessionClient(sessionDriversList.create('memory', config));
66
+ /**
67
+ * Initiating session store
68
+ */
69
+ context.initiateSession = async function (options) {
70
+ const sessionId = await context.getCookie(config.cookieName);
71
+ if (sessionId) {
72
+ context.sessionClient.sessionId = sessionId;
73
+ return;
74
+ }
75
+ await context.setCookie(config.cookieName, context.sessionClient.sessionId, getSessionCookieOptions(config, options));
76
+ };
77
+ /**
78
+ * Returns session data
79
+ */
80
+ context.getSession = async function () {
81
+ await context.initiateSession();
82
+ const sessionData = await context.sessionClient.load();
83
+ return sessionData.values;
84
+ };
85
+ /**
86
+ * Returns flash messages from the data store
87
+ */
88
+ context.getFlashMessages = async function () {
89
+ await context.initiateSession();
90
+ const sessionData = await context.sessionClient.load();
91
+ return sessionData.flashMessages;
92
+ };
93
+ /**
94
+ * Set session data
95
+ */
96
+ context.setSession = async function (values) {
97
+ await context.initiateSession();
98
+ context.sessionClient.merge(values);
99
+ await context.sessionClient.commit();
100
+ };
101
+ /**
102
+ * Set flash messages
103
+ */
104
+ context.setFlashMessages = async function (values) {
105
+ await context.initiateSession();
106
+ context.sessionClient.flash(values);
107
+ await context.sessionClient.commit();
108
+ };
109
+ /**
110
+ * Destroy session when context is closed
111
+ */
112
+ context.on('close', async function () {
113
+ await context.sessionClient.destroy();
114
+ });
115
+ },
116
+ });
117
+ };
118
+ return pluginFn;
119
+ };
@@ -1,132 +1,159 @@
1
- import type { SessionConfig, SessionDriverContract, AllowedSessionValues } from './types.js';
1
+ import { EmitterService } from '@adonisjs/core/types';
2
2
  import type { HttpContext } from '@adonisjs/core/http';
3
3
  import { Store } from './store.js';
4
+ import type { SessionData, SessionConfig, AllowedSessionValues, SessionDriverContract } from './types/main.js';
5
+ import { HttpError } from '@adonisjs/core/types/http';
4
6
  /**
5
- * Session class exposes the API to read/write values to the session for
6
- * a given request.
7
+ * The session class exposes the API to read and write values to
8
+ * the session store.
9
+ *
10
+ * A session instance is isolated between requests but
11
+ * uses a centralized persistence store and
7
12
  */
8
13
  export declare class Session {
9
14
  #private;
10
15
  /**
11
- * Set to true inside the `initiate` method
16
+ * Store of flash messages that be written during the
17
+ * HTTP request
12
18
  */
13
- initiated: boolean;
19
+ responseFlashMessages: Store;
14
20
  /**
15
- * A boolean to know if it's a fresh session or not. Fresh
16
- * sessions are those, whose session id is not present
17
- * in cookie
21
+ * Store of flash messages for the current HTTP request.
18
22
  */
19
- fresh: boolean;
23
+ flashMessages: Store;
20
24
  /**
21
- * A boolean to know if store is initiated in readonly mode
22
- * or not. This is done during Websocket requests
25
+ * The key to use for storing flash messages inside
26
+ * the session store.
23
27
  */
24
- readonly: boolean;
28
+ flashKey: string;
25
29
  /**
26
- * Session id for the given request. A new session id is only
27
- * generated when the cookie for the session id is missing
30
+ * Session id for the current HTTP request
28
31
  */
29
- sessionId: string;
32
+ get sessionId(): string;
30
33
  /**
31
- * A copy of previously set flash messages
34
+ * A boolean to know if a fresh session is created during
35
+ * the request
32
36
  */
33
- flashMessages: Store;
37
+ get fresh(): boolean;
34
38
  /**
35
- * A copy of flash messages. The `input` messages
36
- * are overwritten when any of the input related
37
- * methods are used.
38
- *
39
- * The `others` object is expanded with each call.
39
+ * A boolean to know if session is in readonly
40
+ * state
40
41
  */
41
- responseFlashMessages: Store;
42
- constructor(ctx: HttpContext, config: SessionConfig, driver: SessionDriverContract);
42
+ get readonly(): boolean;
43
43
  /**
44
- * Initiating the session by reading it's value from the
45
- * driver and feeding it to a store.
46
- *
47
- * Multiple calls to `initiate` results in a noop.
44
+ * A boolean to know if session store has been initiated
48
45
  */
49
- initiate(readonly: boolean): Promise<void>;
46
+ get initiated(): boolean;
50
47
  /**
51
- * Re-generates the session id. This can is used to avoid
52
- * session fixation attacks.
48
+ * A boolean to know if the session id has been re-generated
49
+ * during the current request
53
50
  */
54
- regenerate(): void;
51
+ get hasRegeneratedSession(): boolean;
52
+ /**
53
+ * A boolean to know if the session store is empty
54
+ */
55
+ get isEmpty(): boolean;
56
+ /**
57
+ * A boolean to know if the session store has been
58
+ * modified
59
+ */
60
+ get hasBeenModified(): boolean;
61
+ constructor(config: SessionConfig, driver: SessionDriverContract, emitter: EmitterService, ctx: HttpContext);
62
+ /**
63
+ * Initiates the session store. The method results in a noop
64
+ * when called multiple times
65
+ */
66
+ initiate(readonly: boolean): Promise<void>;
55
67
  /**
56
- * Set/update session value
68
+ * Put a key-value pair to the session data store
57
69
  */
58
70
  put(key: string, value: AllowedSessionValues): void;
59
71
  /**
60
- * Find if the value exists in the session
72
+ * Check if a key exists inside the datastore
61
73
  */
62
74
  has(key: string): boolean;
63
75
  /**
64
- * Get value from the session. The default value is returned
65
- * when actual value is `undefined`
76
+ * Get the value of a key from the session datastore.
77
+ * You can specify a default value to use, when key
78
+ * does not exists or has undefined value.
66
79
  */
67
80
  get(key: string, defaultValue?: any): any;
68
81
  /**
69
- * Returns everything from the session
82
+ * Get everything from the session store
70
83
  */
71
84
  all(): any;
72
85
  /**
73
- * Remove value for a given key from the session
86
+ * Remove a key from the session datastore
74
87
  */
75
88
  forget(key: string): void;
76
89
  /**
77
- * The method is equivalent to calling `session.get` followed
78
- * by `session.forget`
90
+ * Read value for a key from the session datastore
91
+ * and remove it simultaneously.
79
92
  */
80
93
  pull(key: string, defaultValue?: any): any;
81
94
  /**
82
- * Increment value for a number inside the session store. The
83
- * method raises an error when underlying value is not
84
- * a number
95
+ * Increment the value of a key inside the session
96
+ * store.
97
+ *
98
+ * A new key will be defined if does not exists already.
99
+ * The value of a new key will be 1
85
100
  */
86
101
  increment(key: string, steps?: number): void;
87
102
  /**
88
- * Decrement value for a number inside the session store. The
89
- * method raises an error when underlying value is not
90
- * a number
103
+ * Increment the value of a key inside the session
104
+ * store.
105
+ *
106
+ * A new key will be defined if does not exists already.
107
+ * The value of a new key will be -1
91
108
  */
92
109
  decrement(key: string, steps?: number): void;
93
110
  /**
94
- * Remove everything from the session
111
+ * Empty the session store
95
112
  */
96
113
  clear(): void;
97
114
  /**
98
- * Add a new flash message
115
+ * Flash validation error messages. Make sure the error
116
+ * is an instance of VineJS ValidationException
99
117
  */
100
- flash(key: string | {
101
- [key: string]: AllowedSessionValues;
102
- }, value?: AllowedSessionValues): void;
118
+ flashValidationErrors(error: HttpError): void;
103
119
  /**
104
- * Flash all form values
120
+ * Add a key-value pair to flash messages
121
+ */
122
+ flash(key: string, value: AllowedSessionValues): void;
123
+ flash(keyValue: SessionData): void;
124
+ /**
125
+ * Flash form input data to the flash messages store
105
126
  */
106
127
  flashAll(): void;
107
128
  /**
108
- * Flash all form values except mentioned keys
129
+ * Flash form input data (except some keys) to the flash messages store
109
130
  */
110
131
  flashExcept(keys: string[]): void;
111
132
  /**
112
- * Flash only defined keys from the form values
133
+ * Flash form input data (only some keys) to the flash messages store
113
134
  */
114
135
  flashOnly(keys: string[]): void;
115
136
  /**
116
- * Reflash existing flash messages
137
+ * Reflash messages from the last request in the current response
117
138
  */
118
139
  reflash(): void;
119
140
  /**
120
- * Reflash selected keys from the existing flash messages
141
+ * Reflash messages (only some keys) from the last
142
+ * request in the current response
121
143
  */
122
144
  reflashOnly(keys: string[]): void;
123
145
  /**
124
- * Omit selected keys from the existing flash messages
125
- * and flash the rest of values
146
+ * Reflash messages (except some keys) from the last
147
+ * request in the current response
126
148
  */
127
149
  reflashExcept(keys: string[]): void;
128
150
  /**
129
- * Writes value to the underlying session driver.
151
+ * Re-generate the session id and migrate data to it.
152
+ */
153
+ regenerate(): void;
154
+ /**
155
+ * Commit session changes. No more mutations will be
156
+ * allowed after commit.
130
157
  */
131
158
  commit(): Promise<void>;
132
159
  }