@adonisjs/session 8.0.0-next.2 → 8.0.0-next.4

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.
@@ -28,6 +28,14 @@ var DatabaseStore = class {
28
28
  return null;
29
29
  }
30
30
  }
31
+ #rowToTaggedSession(row) {
32
+ const data = this.#parseSessionData(row.data, row.id);
33
+ if (!data) return null;
34
+ return {
35
+ id: row.id,
36
+ data
37
+ };
38
+ }
31
39
  async read(sessionId) {
32
40
  debug_default("database store: reading session data %s", sessionId);
33
41
  const row = await this.#client.from(this.#tableName).where("id", sessionId).first();
@@ -60,23 +68,19 @@ var DatabaseStore = class {
60
68
  await this.#client.from(this.#tableName).where("id", sessionId).update({ expires_at: expiresAt });
61
69
  }
62
70
  async tag(sessionId, userId) {
63
- debug_default("database store: tagging session %s with user %s", sessionId, userId);
71
+ debug_default("database store: associating user %s with session %s", userId, sessionId);
64
72
  const data = new MessageBuilder().build({}, void 0, sessionId);
65
73
  const expiresAt = new Date(Date.now() + this.#ttlSeconds * 1e3);
66
74
  await this.#client.insertQuery().table(this.#tableName).insert({
67
75
  id: sessionId,
68
- user_id: userId,
76
+ user_id: String(userId),
69
77
  data,
70
78
  expires_at: expiresAt
71
79
  }).knexQuery.onConflict("id").merge(["user_id"]);
72
80
  }
73
- #rowToTaggedSession(row) {
74
- const data = this.#parseSessionData(row.data, row.id);
75
- if (!data) return null;
76
- return {
77
- id: row.id,
78
- data
79
- };
81
+ async untag(sessionId, userId) {
82
+ debug_default("database store: dissociating user %s from session %s", userId, sessionId);
83
+ await this.#client.query().from(this.#tableName).update({ user_id: null }).where({ id: sessionId });
80
84
  }
81
85
  async tagged(userId) {
82
86
  debug_default("database store: getting sessions tagged with user %s", userId);
@@ -1,10 +1,10 @@
1
- import "../session-C9DdRahS.js";
1
+ import "../session-Dd5u7w5Y.js";
2
2
  import "../main-kn40V-hF.js";
3
- import { t as defineConfig } from "../session-Cb9-DoMh.js";
3
+ import { t as defineConfig } from "../session-C9ZmQmpM.js";
4
4
  import "../debug-BZVg83L1.js";
5
5
  import "../values_store-CvR1Sn37.js";
6
- import "../session_collection-CvS5yIq6.js";
7
- import { t as SessionMiddleware } from "../session_middleware-gegOBxmm.js";
6
+ import "../session_collection-D9JQJjpq.js";
7
+ import { t as SessionMiddleware } from "../session_middleware-BoOMxNVH.js";
8
8
  import { Emitter } from "@adonisjs/core/events";
9
9
  import { AppFactory } from "@adonisjs/core/factories/app";
10
10
  var SessionMiddlewareFactory = class {
package/build/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { r as errors_exports, t as Session } from "./session-C9DdRahS.js";
1
+ import { r as errors_exports, t as Session } from "./session-Dd5u7w5Y.js";
2
2
  import { t as stubsRoot } from "./main-kn40V-hF.js";
3
- import { n as stores, r as configure, t as defineConfig } from "./session-Cb9-DoMh.js";
3
+ import { n as stores, r as configure, t as defineConfig } from "./session-C9ZmQmpM.js";
4
4
  import "./debug-BZVg83L1.js";
5
5
  import { n as ValuesStore, t as ReadOnlyValuesStore } from "./values_store-CvR1Sn37.js";
6
- import { t as SessionCollection } from "./session_collection-CvS5yIq6.js";
6
+ import { t as SessionCollection } from "./session_collection-D9JQJjpq.js";
7
7
  export { ReadOnlyValuesStore, Session, SessionCollection, ValuesStore, configure, defineConfig, errors_exports as errors, stores, stubsRoot };
@@ -1,8 +1,8 @@
1
- import "../session-C9DdRahS.js";
1
+ import "../session-Dd5u7w5Y.js";
2
2
  import "../debug-BZVg83L1.js";
3
3
  import "../values_store-CvR1Sn37.js";
4
- import { t as SessionCollection } from "../session_collection-CvS5yIq6.js";
5
- import { t as SessionMiddleware } from "../session_middleware-gegOBxmm.js";
4
+ import { t as SessionCollection } from "../session_collection-D9JQJjpq.js";
5
+ import { t as SessionMiddleware } from "../session_middleware-BoOMxNVH.js";
6
6
  import { RuntimeException } from "@adonisjs/core/exceptions";
7
7
  import { configProvider } from "@adonisjs/core";
8
8
  var SessionProvider = class {
@@ -71,7 +71,11 @@ var RedisStore = class {
71
71
  }
72
72
  async tag(sessionId, userId) {
73
73
  debug_default("redis store: tagging session %s with user %s", sessionId, userId);
74
- await this.#connection.sadd(this.#getTagKey(userId), sessionId);
74
+ await this.#connection.sadd(this.#getTagKey(userId.toString()), sessionId);
75
+ }
76
+ async untag(sessionId, userId) {
77
+ debug_default("redis store: untagging session %s from user %s", sessionId, userId);
78
+ await this.#connection.srem(this.#getTagKey(userId.toString()), sessionId);
75
79
  }
76
80
  async tagged(userId) {
77
81
  debug_default("redis store: getting sessions tagged with user %s", userId);
@@ -32,7 +32,10 @@ var MemoryStore = class MemoryStore {
32
32
  }
33
33
  touch(_) {}
34
34
  tag(sessionId, userId) {
35
- MemoryStore.tags.set(sessionId, userId);
35
+ MemoryStore.tags.set(sessionId, String(userId));
36
+ }
37
+ untag(sessionId, _userId) {
38
+ MemoryStore.tags.delete(sessionId);
36
39
  }
37
40
  tagged(userId) {
38
41
  const sessions = [];
@@ -50,7 +53,7 @@ var MemoryStore = class MemoryStore {
50
53
  function defineConfig(config) {
51
54
  debug_default("processing session config %O", config);
52
55
  if (!config.store) throw new InvalidArgumentsException("Missing \"store\" property inside the session config");
53
- const { stores: stores$1, cookie, ...rest } = {
56
+ const { stores, cookie, ...rest } = {
54
57
  enabled: true,
55
58
  age: "2h",
56
59
  cookieName: "adonis_session",
@@ -93,7 +96,7 @@ const stores = {
93
96
  },
94
97
  redis: (config) => {
95
98
  return configProvider.create(async (app) => {
96
- const { RedisStore } = await import("./redis-D8D9UtiD.js");
99
+ const { RedisStore } = await import("./redis-rAHxNQ_8.js");
97
100
  const redis = await app.container.make("redis");
98
101
  return (_, sessionConfig) => {
99
102
  return new RedisStore(redis.connection(config.connection), sessionConfig.age);
@@ -123,7 +126,7 @@ const stores = {
123
126
  },
124
127
  database: (config) => {
125
128
  return configProvider.create(async (app) => {
126
- const { DatabaseStore } = await import("./database-vbrhCOPd.js");
129
+ const { DatabaseStore } = await import("./database-JbWAJqhn.js");
127
130
  const db = await app.container.make("lucid.db");
128
131
  const connectionName = config?.connectionName || db.primaryConnectionName;
129
132
  if (!db.manager.has(connectionName)) throw new RuntimeException(`Invalid database connection "${connectionName}" referenced in session config`);
@@ -5,8 +5,9 @@ import { createError } from "@adonisjs/core/exceptions";
5
5
  import { randomUUID } from "node:crypto";
6
6
  import Macroable from "@poppinss/macroable";
7
7
  import lodash from "@poppinss/utils/lodash";
8
+ import is from "@adonisjs/core/helpers/is";
8
9
  var __defProp = Object.defineProperty;
9
- var __export = (all, symbols) => {
10
+ var __exportAll = (all, symbols) => {
10
11
  let target = {};
11
12
  for (var name in all) __defProp(target, name, {
12
13
  get: all[name],
@@ -15,7 +16,7 @@ var __export = (all, symbols) => {
15
16
  if (symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
16
17
  return target;
17
18
  };
18
- var errors_exports = /* @__PURE__ */ __export({
19
+ var errors_exports = /* @__PURE__ */ __exportAll({
19
20
  E_SESSION_NOT_MUTABLE: () => E_SESSION_NOT_MUTABLE,
20
21
  E_SESSION_NOT_READY: () => E_SESSION_NOT_READY,
21
22
  E_SESSION_TAGGING_NOT_SUPPORTED: () => E_SESSION_TAGGING_NOT_SUPPORTED
@@ -23,6 +24,7 @@ var errors_exports = /* @__PURE__ */ __export({
23
24
  const E_SESSION_NOT_MUTABLE = createError("Session store is in readonly mode and cannot be mutated", "E_SESSION_NOT_MUTABLE", 500);
24
25
  const E_SESSION_NOT_READY = createError("Session store has not been initiated. Make sure you have registered the session middleware", "E_SESSION_NOT_READY", 500);
25
26
  const E_SESSION_TAGGING_NOT_SUPPORTED = createError("Session store does not support tagging. Use memory, redis, or database store instead", "E_SESSION_TAGGING_NOT_SUPPORTED", 500);
27
+ const STORE_IN_FLASH = Symbol.for("store_in_flash");
26
28
  var Session = class extends Macroable {
27
29
  #store;
28
30
  #emitter;
@@ -69,6 +71,18 @@ var Session = class extends Macroable {
69
71
  if (mode === "write" && this.readonly) throw new E_SESSION_NOT_MUTABLE();
70
72
  return this.responseFlashMessages;
71
73
  }
74
+ shouldFlashValue(value) {
75
+ if (value && typeof value === "object") return STORE_IN_FLASH in value ? value[STORE_IN_FLASH] : true;
76
+ return true;
77
+ }
78
+ cleanupFlashData(data) {
79
+ if (is.plainObject(data)) return Object.keys(data).reduce((result, key) => {
80
+ const value = data[key];
81
+ if (this.shouldFlashValue(value)) result[key] = value;
82
+ return result;
83
+ }, {});
84
+ return data;
85
+ }
72
86
  #getValuesStore(mode) {
73
87
  if (!this.#valuesStore) throw new E_SESSION_NOT_READY();
74
88
  if (mode === "write" && this.readonly) throw new E_SESSION_NOT_MUTABLE();
@@ -122,8 +136,8 @@ var Session = class extends Macroable {
122
136
  }
123
137
  flash(key, value) {
124
138
  if (typeof key === "string") {
125
- if (value) this.#getFlashStore("write").set(key, value);
126
- } else this.#getFlashStore("write").merge(key);
139
+ if (value && this.shouldFlashValue(value)) this.#getFlashStore("write").set(key, value);
140
+ } else this.#getFlashStore("write").merge(this.cleanupFlashData(key));
127
141
  }
128
142
  flashErrors(errorsCollection) {
129
143
  this.flash({ errorsBag: errorsCollection });
@@ -146,13 +160,20 @@ var Session = class extends Macroable {
146
160
  this.flash("inputErrorsBag", errorsBag);
147
161
  }
148
162
  flashAll() {
149
- return this.#getFlashStore("write").set("input", this.#ctx.request.original());
163
+ let requestInput = this.#ctx.request.original();
164
+ return this.#getFlashStore("write").set("input", this.cleanupFlashData(requestInput));
150
165
  }
151
166
  flashExcept(keys) {
152
- this.#getFlashStore("write").set("input", lodash.omit(this.#ctx.request.original(), keys));
167
+ this.#getFlashStore("write").set("input", lodash.omitBy(this.#ctx.request.original(), (value, key) => {
168
+ if (keys.includes(key)) return true;
169
+ return !this.shouldFlashValue(value);
170
+ }));
153
171
  }
154
172
  flashOnly(keys) {
155
- this.#getFlashStore("write").set("input", lodash.pick(this.#ctx.request.original(), keys));
173
+ this.#getFlashStore("write").set("input", lodash.pickBy(this.#ctx.request.original(), (value, key) => {
174
+ if (keys.includes(key)) return this.shouldFlashValue(value);
175
+ return false;
176
+ }));
156
177
  }
157
178
  reflash() {
158
179
  this.#getFlashStore("write").set("reflashed", this.flashMessages.all());
@@ -1,4 +1,4 @@
1
- import { n as E_SESSION_TAGGING_NOT_SUPPORTED } from "./session-C9DdRahS.js";
1
+ import { n as E_SESSION_TAGGING_NOT_SUPPORTED } from "./session-Dd5u7w5Y.js";
2
2
  import { t as debug_default } from "./debug-BZVg83L1.js";
3
3
  var SessionCollection = class {
4
4
  #store;
@@ -1,4 +1,4 @@
1
- import { t as Session } from "./session-C9DdRahS.js";
1
+ import { t as Session } from "./session-Dd5u7w5Y.js";
2
2
  import { ExceptionHandler } from "@adonisjs/core/http";
3
3
  const originalErrorHandler = ExceptionHandler.prototype.renderValidationErrorAsHTML;
4
4
  ExceptionHandler.macro("renderValidationErrorAsHTML", async function(error, ctx) {
@@ -73,6 +73,8 @@ export declare class Session extends Macroable {
73
73
  * @param ctx - HTTP context
74
74
  */
75
75
  constructor(config: SessionConfig, storeFactory: SessionStoreFactory, emitter: EmitterService, ctx: HttpContext);
76
+ protected shouldFlashValue(value: unknown): unknown;
77
+ protected cleanupFlashData<T>(data: T): T | Record<string, any>;
76
78
  /**
77
79
  * Initiates the session store. The method results in a noop when called multiple times.
78
80
  *
@@ -1,5 +1,5 @@
1
- import "../session-C9DdRahS.js";
1
+ import "../session-Dd5u7w5Y.js";
2
2
  import "../debug-BZVg83L1.js";
3
3
  import "../values_store-CvR1Sn37.js";
4
- import { t as SessionMiddleware } from "../session_middleware-gegOBxmm.js";
4
+ import { t as SessionMiddleware } from "../session_middleware-BoOMxNVH.js";
5
5
  export { SessionMiddleware as default };
@@ -60,7 +60,8 @@ export declare class DatabaseStore implements SessionStoreWithTaggingContract {
60
60
  * @param sessionId - Session identifier
61
61
  * @param userId - User identifier to tag the session with
62
62
  */
63
- tag(sessionId: string, userId: string): Promise<void>;
63
+ tag(sessionId: string, userId: string | number): Promise<void>;
64
+ untag(sessionId: string, userId: string | number): Promise<void>;
64
65
  /**
65
66
  * Get all sessions for a given user ID (tag)
66
67
  *
@@ -64,7 +64,14 @@ export declare class MemoryStore implements SessionStoreWithTaggingContract {
64
64
  * @param sessionId - Session identifier
65
65
  * @param userId - User identifier to tag the session with
66
66
  */
67
- tag(sessionId: string, userId: string): void;
67
+ tag(sessionId: string, userId: string | number): void;
68
+ /**
69
+ * Untag a session from a user ID
70
+ *
71
+ * @param sessionId - Session identifier
72
+ * @param userId - User identifier (unused in memory store, as sessionId uniquely identifies the tag)
73
+ */
74
+ untag(sessionId: string, _userId: string | number): void;
68
75
  /**
69
76
  * Get all sessions for a given user ID (tag)
70
77
  *
@@ -67,7 +67,14 @@ export declare class RedisStore implements SessionStoreWithTaggingContract {
67
67
  * @param sessionId - Session identifier
68
68
  * @param userId - User identifier to tag the session with
69
69
  */
70
- tag(sessionId: string, userId: string): Promise<void>;
70
+ tag(sessionId: string, userId: string | number): Promise<void>;
71
+ /**
72
+ * Untag a session from a user ID
73
+ *
74
+ * @param sessionId - Session identifier
75
+ * @param userId - User identifier to untag the session from
76
+ */
77
+ untag(sessionId: string, userId: string | number): Promise<void>;
71
78
  /**
72
79
  * Get all sessions for a given user ID (tag)
73
80
  *
@@ -84,6 +84,40 @@ export interface SessionStoreContract {
84
84
  */
85
85
  touch(sessionId: string): Promise<void> | void;
86
86
  }
87
+ /**
88
+ * Extended session store contract that supports tagging sessions with user IDs.
89
+ * This enables querying all sessions for a specific user, useful for features
90
+ * like "logout from all devices" or "view active sessions".
91
+ *
92
+ * @example
93
+ * class MyStore implements SessionStoreWithTaggingContract {
94
+ * // ... base SessionStoreContract methods ...
95
+ *
96
+ * async tag(sessionId: string, userId: string) {
97
+ * await this.storage.tag(sessionId, userId)
98
+ * }
99
+ *
100
+ * async tagged(userId: string) {
101
+ * return await this.storage.getSessionsByUser(userId)
102
+ * }
103
+ * }
104
+ */
105
+ export interface SessionStoreWithTaggingContract extends SessionStoreContract {
106
+ /**
107
+ * Associates a session with a user ID (tag).
108
+ * This allows querying all sessions for a specific user.
109
+ */
110
+ tag(sessionId: string, userId: string | number): Promise<void> | void;
111
+ /**
112
+ * Dissociate a session from the user ID (tag).
113
+ */
114
+ untag(sessionId: string, userId: string | number): Promise<void> | void;
115
+ /**
116
+ * Returns all sessions associated with a given user ID (tag).
117
+ * Only returns non-expired sessions.
118
+ */
119
+ tagged(userId: string | number): Promise<TaggedSession[]> | TaggedSession[];
120
+ }
87
121
  /**
88
122
  * Base configuration interface for session management.
89
123
  * Used by the session manager and middleware to control session behavior.
@@ -210,36 +244,6 @@ export type DynamoDBStoreConfig = ({
210
244
  * }
211
245
  */
212
246
  export type SessionStoreFactory = (ctx: HttpContext, sessionConfig: SessionConfig) => SessionStoreContract;
213
- /**
214
- * Extended session store contract that supports tagging sessions with user IDs.
215
- * This enables querying all sessions for a specific user, useful for features
216
- * like "logout from all devices" or "view active sessions".
217
- *
218
- * @example
219
- * class MyStore implements SessionStoreWithTaggingContract {
220
- * // ... base SessionStoreContract methods ...
221
- *
222
- * async tag(sessionId: string, userId: string) {
223
- * await this.storage.tag(sessionId, userId)
224
- * }
225
- *
226
- * async tagged(userId: string) {
227
- * return await this.storage.getSessionsByUser(userId)
228
- * }
229
- * }
230
- */
231
- export interface SessionStoreWithTaggingContract extends SessionStoreContract {
232
- /**
233
- * Associates a session with a user ID (tag).
234
- * This allows querying all sessions for a specific user.
235
- */
236
- tag(sessionId: string, userId: string): Promise<void> | void;
237
- /**
238
- * Returns all sessions associated with a given user ID (tag).
239
- * Only returns non-expired sessions.
240
- */
241
- tagged(userId: string): Promise<TaggedSession[]> | TaggedSession[];
242
- }
243
247
  /**
244
248
  * Represents a tagged session with its ID and data
245
249
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@adonisjs/session",
3
3
  "description": "Session provider for AdonisJS",
4
- "version": "8.0.0-next.2",
4
+ "version": "8.0.0-next.4",
5
5
  "engines": {
6
6
  "node": ">=24.0.0"
7
7
  },
@@ -44,50 +44,50 @@
44
44
  "quick:test": "node --import=@poppinss/ts-exec --enable-source-maps bin/test.ts"
45
45
  },
46
46
  "devDependencies": {
47
- "@adonisjs/assembler": "^8.0.0-next.26",
48
- "@adonisjs/core": "^7.0.0-next.16",
49
- "@adonisjs/eslint-config": "^3.0.0-next.5",
47
+ "@adonisjs/assembler": "^8.0.0-next.31",
48
+ "@adonisjs/core": "^7.0.0-next.27",
49
+ "@adonisjs/eslint-config": "^3.0.0-next.9",
50
50
  "@adonisjs/i18n": "^3.0.0-next.2",
51
- "@adonisjs/lucid": "^22.0.0-next.0",
51
+ "@adonisjs/lucid": "^22.0.0-next.7",
52
52
  "@adonisjs/prettier-config": "^1.4.5",
53
53
  "@adonisjs/redis": "^10.0.0-next.2",
54
54
  "@adonisjs/tsconfig": "^2.0.0-next.3",
55
- "@aws-sdk/client-dynamodb": "^3.955.0",
56
- "@aws-sdk/util-dynamodb": "^3.955.0",
57
- "@japa/api-client": "^3.1.1",
55
+ "@aws-sdk/client-dynamodb": "^3.980.0",
56
+ "@aws-sdk/util-dynamodb": "^3.980.0",
57
+ "@japa/api-client": "^3.2.1",
58
58
  "@japa/assert": "^4.2.0",
59
- "@japa/browser-client": "^2.2.0",
59
+ "@japa/browser-client": "^2.3.0",
60
60
  "@japa/file-system": "^3.0.0",
61
- "@japa/plugin-adonisjs": "^5.1.0-next.0",
62
- "@japa/runner": "^5.0.0",
61
+ "@japa/plugin-adonisjs": "^5.1.0-next.1",
62
+ "@japa/runner": "^5.3.0",
63
63
  "@japa/snapshot": "^2.0.10",
64
- "@poppinss/ts-exec": "^1.4.1",
64
+ "@poppinss/ts-exec": "^1.4.3",
65
65
  "@release-it/conventional-changelog": "^10.0.4",
66
- "@types/node": "^25.0.3",
66
+ "@types/node": "^25.1.0",
67
67
  "@types/set-cookie-parser": "^2.4.10",
68
68
  "@types/supertest": "^6.0.3",
69
69
  "@vinejs/vine": "^4.2.0",
70
+ "better-sqlite3": "^12.6.2",
70
71
  "c8": "^10.1.3",
71
72
  "copyfiles": "^2.4.1",
72
- "better-sqlite3": "^12.5.0",
73
- "mysql2": "^3.15.3",
74
- "pg": "^8.16.3",
75
73
  "cross-env": "^10.1.0",
76
74
  "edge.js": "^6.4.0",
77
75
  "eslint": "^9.39.2",
78
76
  "get-port": "^7.1.0",
79
- "playwright": "^1.57.0",
80
- "prettier": "^3.7.4",
81
- "release-it": "^19.1.0",
82
- "set-cookie-parser": "^2.7.2",
83
- "supertest": "^7.1.4",
84
- "tsdown": "^0.18.1",
85
- "typedoc": "^0.28.15",
77
+ "mysql2": "^3.16.2",
78
+ "pg": "^8.18.0",
79
+ "playwright": "^1.58.1",
80
+ "prettier": "^3.8.1",
81
+ "release-it": "^19.2.4",
82
+ "set-cookie-parser": "^3.0.1",
83
+ "supertest": "^7.2.2",
84
+ "tsdown": "^0.20.1",
85
+ "typedoc": "^0.28.16",
86
86
  "typescript": "^5.9.3"
87
87
  },
88
88
  "dependencies": {
89
89
  "@poppinss/macroable": "^1.1.0",
90
- "@poppinss/utils": "^7.0.0-next.4"
90
+ "@poppinss/utils": "^7.0.0-next.6"
91
91
  },
92
92
  "peerDependencies": {
93
93
  "@adonisjs/assembler": "^8.0.0-next.26",