@adonisjs/session 7.6.0 → 7.7.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/build/{chunk-CVMFYEYR.js → chunk-6BSSM3HO.js} +2 -2
- package/build/chunk-G7KFHA57.js +59 -0
- package/build/chunk-G7KFHA57.js.map +1 -0
- package/build/{chunk-3AQCEGXQ.js → chunk-Q24L5XPC.js} +25 -3
- package/build/{chunk-3AQCEGXQ.js.map → chunk-Q24L5XPC.js.map} +1 -1
- package/build/{chunk-I6SY5ILN.js → chunk-XP3CBOXR.js} +20 -2
- package/build/chunk-XP3CBOXR.js.map +1 -0
- package/build/{database-55YUHLA6.js → database-443FB7MM.js} +35 -6
- package/build/database-443FB7MM.js.map +1 -0
- package/build/factories/main.js +4 -3
- package/build/factories/main.js.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.js +6 -2
- package/build/make/migration/sessions.stub +1 -0
- package/build/providers/session_provider.d.ts +2 -1
- package/build/providers/session_provider.js +24 -10
- package/build/providers/session_provider.js.map +1 -1
- package/build/redis-YGX2CNE2.js +119 -0
- package/build/redis-YGX2CNE2.js.map +1 -0
- package/build/src/errors.d.ts +5 -0
- package/build/src/session.d.ts +8 -0
- package/build/src/session_collection.d.ts +55 -0
- package/build/src/session_middleware.js +2 -2
- package/build/src/stores/database.d.ts +10 -2
- package/build/src/stores/memory.d.ts +14 -2
- package/build/src/stores/redis.d.ts +15 -8
- package/build/src/types.d.ts +28 -0
- package/package.json +1 -1
- package/build/chunk-I6SY5ILN.js.map +0 -1
- package/build/database-55YUHLA6.js.map +0 -1
- package/build/redis-OJU6MUHZ.js +0 -59
- package/build/redis-OJU6MUHZ.js.map +0 -1
- /package/build/{chunk-CVMFYEYR.js.map → chunk-6BSSM3HO.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Session
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XP3CBOXR.js";
|
|
4
4
|
|
|
5
5
|
// src/session_middleware.ts
|
|
6
6
|
import { ExceptionHandler } from "@adonisjs/core/http";
|
|
@@ -41,4 +41,4 @@ var SessionMiddleware = class {
|
|
|
41
41
|
export {
|
|
42
42
|
SessionMiddleware
|
|
43
43
|
};
|
|
44
|
-
//# sourceMappingURL=chunk-
|
|
44
|
+
//# sourceMappingURL=chunk-6BSSM3HO.js.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
E_SESSION_TAGGING_NOT_SUPPORTED
|
|
3
|
+
} from "./chunk-XP3CBOXR.js";
|
|
4
|
+
import {
|
|
5
|
+
debug_default
|
|
6
|
+
} from "./chunk-5ECC6OWF.js";
|
|
7
|
+
|
|
8
|
+
// src/session_collection.ts
|
|
9
|
+
var SessionCollection = class {
|
|
10
|
+
#store;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
const storeFactory = config.stores[config.store];
|
|
13
|
+
this.#store = storeFactory(null, config);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Check if the current store supports tagging
|
|
17
|
+
*/
|
|
18
|
+
supportsTagging() {
|
|
19
|
+
return "tag" in this.#store && "tagged" in this.#store;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Returns the session data for the given session ID,
|
|
23
|
+
* or null if the session does not exist
|
|
24
|
+
*/
|
|
25
|
+
async get(sessionId) {
|
|
26
|
+
debug_default("session collection: getting session data %s", sessionId);
|
|
27
|
+
return this.#store.read(sessionId);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Destroys a session by its ID
|
|
31
|
+
*/
|
|
32
|
+
async destroy(sessionId) {
|
|
33
|
+
debug_default("session collection: destroying session %s", sessionId);
|
|
34
|
+
return this.#store.destroy(sessionId);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Tag a session with a user ID.
|
|
38
|
+
* Only supported by Memory, Redis and Database stores.
|
|
39
|
+
*/
|
|
40
|
+
async tag(sessionId, userId) {
|
|
41
|
+
debug_default("session collection: tagging session %s with user %s", sessionId, userId);
|
|
42
|
+
if (!this.supportsTagging()) throw new E_SESSION_TAGGING_NOT_SUPPORTED();
|
|
43
|
+
return this.#store.tag(sessionId, userId);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get all sessions for a given user ID (tag).
|
|
47
|
+
* Only supported by Memory, Redis and Database stores.
|
|
48
|
+
*/
|
|
49
|
+
async tagged(userId) {
|
|
50
|
+
debug_default("session collection: getting sessions tagged with user %s", userId);
|
|
51
|
+
if (!this.supportsTagging()) throw new E_SESSION_TAGGING_NOT_SUPPORTED();
|
|
52
|
+
return this.#store.tagged(userId);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export {
|
|
57
|
+
SessionCollection
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=chunk-G7KFHA57.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/session_collection.ts"],"sourcesContent":["/**\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport debug from './debug.js'\nimport { E_SESSION_TAGGING_NOT_SUPPORTED } from './errors.js'\nimport type {\n ResolvedSessionConfig,\n SessionData,\n SessionStoreWithTaggingContract,\n TaggedSession,\n} from './types.js'\n\n/**\n * SessionCollection provides APIs for programmatic session\n * management. It allows reading, destroying, and tagging\n * sessions without an HTTP context.\n *\n * @example\n * ```ts\n * import app from '@adonisjs/core/services/app'\n * import { SessionCollection } from '@adonisjs/session'\n *\n * const sessionCollection = await app.container.make(SessionCollection)\n *\n * // List all sessions for a user\n * const sessions = await sessionCollection.tagged(String(user.id))\n *\n * // Destroy a specific session\n * await sessionCollection.destroy(sessionId)\n * ```\n */\nexport class SessionCollection {\n #store: SessionStoreWithTaggingContract\n\n constructor(config: ResolvedSessionConfig) {\n const storeFactory = config.stores[config.store]\n this.#store = storeFactory(null as any, config) as SessionStoreWithTaggingContract\n }\n\n /**\n * Check if the current store supports tagging\n */\n supportsTagging(): boolean {\n return 'tag' in this.#store && 'tagged' in this.#store\n }\n\n /**\n * Returns the session data for the given session ID,\n * or null if the session does not exist\n */\n async get(sessionId: string): Promise<SessionData | null> {\n debug('session collection: getting session data %s', sessionId)\n return this.#store.read(sessionId)\n }\n\n /**\n * Destroys a session by its ID\n */\n async destroy(sessionId: string): Promise<void> {\n debug('session collection: destroying session %s', sessionId)\n return this.#store.destroy(sessionId)\n }\n\n /**\n * Tag a session with a user ID.\n * Only supported by Memory, Redis and Database stores.\n */\n async tag(sessionId: string, userId: string): Promise<void> {\n debug('session collection: tagging session %s with user %s', sessionId, userId)\n if (!this.supportsTagging()) throw new E_SESSION_TAGGING_NOT_SUPPORTED()\n\n return (this.#store as SessionStoreWithTaggingContract).tag(sessionId, userId)\n }\n\n /**\n * Get all sessions for a given user ID (tag).\n * Only supported by Memory, Redis and Database stores.\n */\n async tagged(userId: string): Promise<TaggedSession[]> {\n debug('session collection: getting sessions tagged with user %s', userId)\n if (!this.supportsTagging()) throw new E_SESSION_TAGGING_NOT_SUPPORTED()\n\n return (this.#store as SessionStoreWithTaggingContract).tagged(userId)\n }\n}\n"],"mappings":";;;;;;;;AAqCO,IAAM,oBAAN,MAAwB;AAAA,EAC7B;AAAA,EAEA,YAAY,QAA+B;AACzC,UAAM,eAAe,OAAO,OAAO,OAAO,KAAK;AAC/C,SAAK,SAAS,aAAa,MAAa,MAAM;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,kBAA2B;AACzB,WAAO,SAAS,KAAK,UAAU,YAAY,KAAK;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,IAAI,WAAgD;AACxD,kBAAM,+CAA+C,SAAS;AAC9D,WAAO,KAAK,OAAO,KAAK,SAAS;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,WAAkC;AAC9C,kBAAM,6CAA6C,SAAS;AAC5D,WAAO,KAAK,OAAO,QAAQ,SAAS;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,IAAI,WAAmB,QAA+B;AAC1D,kBAAM,uDAAuD,WAAW,MAAM;AAC9E,QAAI,CAAC,KAAK,gBAAgB,EAAG,OAAM,IAAI,gCAAgC;AAEvE,WAAQ,KAAK,OAA2C,IAAI,WAAW,MAAM;AAAA,EAC/E;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,QAA0C;AACrD,kBAAM,4DAA4D,MAAM;AACxE,QAAI,CAAC,KAAK,gBAAgB,EAAG,OAAM,IAAI,gCAAgC;AAEvE,WAAQ,KAAK,OAA2C,OAAO,MAAM;AAAA,EACvE;AACF;","names":[]}
|
|
@@ -35,6 +35,10 @@ import { InvalidArgumentsException, RuntimeException } from "@poppinss/utils";
|
|
|
35
35
|
// src/stores/memory.ts
|
|
36
36
|
var MemoryStore = class _MemoryStore {
|
|
37
37
|
static sessions = /* @__PURE__ */ new Map();
|
|
38
|
+
/**
|
|
39
|
+
* Maps session IDs to user IDs (for tagging)
|
|
40
|
+
*/
|
|
41
|
+
static tags = /* @__PURE__ */ new Map();
|
|
38
42
|
/**
|
|
39
43
|
* Read session id value from the memory
|
|
40
44
|
*/
|
|
@@ -52,9 +56,27 @@ var MemoryStore = class _MemoryStore {
|
|
|
52
56
|
*/
|
|
53
57
|
destroy(sessionId) {
|
|
54
58
|
_MemoryStore.sessions.delete(sessionId);
|
|
59
|
+
_MemoryStore.tags.delete(sessionId);
|
|
55
60
|
}
|
|
56
61
|
touch() {
|
|
57
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Tag a session with a user ID
|
|
65
|
+
*/
|
|
66
|
+
async tag(sessionId, userId) {
|
|
67
|
+
_MemoryStore.tags.set(sessionId, userId);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get all sessions for a given user ID (tag)
|
|
71
|
+
*/
|
|
72
|
+
async tagged(userId) {
|
|
73
|
+
const sessions = [];
|
|
74
|
+
for (const [sessionId, taggedUserId] of _MemoryStore.tags) {
|
|
75
|
+
const data = _MemoryStore.sessions.get(sessionId);
|
|
76
|
+
if (taggedUserId === userId && data) sessions.push({ id: sessionId, data });
|
|
77
|
+
}
|
|
78
|
+
return sessions;
|
|
79
|
+
}
|
|
58
80
|
};
|
|
59
81
|
|
|
60
82
|
// src/define_config.ts
|
|
@@ -108,7 +130,7 @@ var stores = {
|
|
|
108
130
|
},
|
|
109
131
|
redis: (config) => {
|
|
110
132
|
return configProvider.create(async (app) => {
|
|
111
|
-
const { RedisStore } = await import("./redis-
|
|
133
|
+
const { RedisStore } = await import("./redis-YGX2CNE2.js");
|
|
112
134
|
const redis = await app.container.make("redis");
|
|
113
135
|
return (_, sessionConfig) => {
|
|
114
136
|
return new RedisStore(redis.connection(config.connection), sessionConfig.age);
|
|
@@ -138,7 +160,7 @@ var stores = {
|
|
|
138
160
|
},
|
|
139
161
|
database: (config) => {
|
|
140
162
|
return configProvider.create(async (app) => {
|
|
141
|
-
const { DatabaseStore } = await import("./database-
|
|
163
|
+
const { DatabaseStore } = await import("./database-443FB7MM.js");
|
|
142
164
|
const db = await app.container.make("lucid.db");
|
|
143
165
|
const connectionName = config?.connectionName || db.primaryConnectionName;
|
|
144
166
|
if (!db.manager.has(connectionName)) {
|
|
@@ -161,4 +183,4 @@ export {
|
|
|
161
183
|
defineConfig,
|
|
162
184
|
stores
|
|
163
185
|
};
|
|
164
|
-
//# sourceMappingURL=chunk-
|
|
186
|
+
//# sourceMappingURL=chunk-Q24L5XPC.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../configure.ts","../src/define_config.ts","../src/stores/memory.ts"],"sourcesContent":["/*\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport type Configure from '@adonisjs/core/commands/configure'\nimport { stubsRoot } from './stubs/main.js'\n\n/**\n * Configures the package\n */\nexport async function configure(command: Configure) {\n const codemods = await command.createCodemods()\n\n /**\n * Publish config file\n */\n await codemods.makeUsingStub(stubsRoot, 'config/session.stub', {})\n\n /**\n * Define environment variables\n */\n await codemods.defineEnvVariables({ SESSION_DRIVER: 'cookie' })\n\n /**\n * Define environment variables validations\n */\n await codemods.defineEnvValidations({\n variables: {\n SESSION_DRIVER: `Env.schema.enum(['cookie', 'memory'] as const)`,\n },\n leadingComment: 'Variables for configuring session package',\n })\n\n /**\n * Register middleware\n */\n await codemods.registerMiddleware('router', [\n {\n path: '@adonisjs/session/session_middleware',\n },\n ])\n\n /**\n * Register provider and commands\n */\n await codemods.updateRcFile((rcFile) => {\n rcFile.addProvider('@adonisjs/session/session_provider')\n rcFile.addCommand('@adonisjs/session/commands')\n })\n}\n","/*\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/// <reference types=\"@adonisjs/redis/redis_provider\" />\n/// <reference types=\"@adonisjs/lucid/database_provider\" />\n\nimport string from '@poppinss/utils/string'\nimport { configProvider } from '@adonisjs/core'\nimport type { ConfigProvider } from '@adonisjs/core/types'\nimport { InvalidArgumentsException, RuntimeException } from '@poppinss/utils'\nimport type { CookieOptions } from '@adonisjs/core/types/http'\n\nimport debug from './debug.js'\nimport { MemoryStore } from './stores/memory.js'\nimport type {\n SessionConfig,\n FileStoreConfig,\n RedisStoreConfig,\n SessionStoreFactory,\n DynamoDBStoreConfig,\n DatabaseStoreConfig,\n} from './types.js'\n\n/**\n * Resolved config with stores\n */\ntype ResolvedConfig<KnownStores extends Record<string, SessionStoreFactory>> = SessionConfig & {\n store: keyof KnownStores\n stores: KnownStores\n cookie: Partial<CookieOptions>\n}\n\n/**\n * Helper to normalize session config\n */\nexport function defineConfig<\n KnownStores extends Record<string, SessionStoreFactory | ConfigProvider<SessionStoreFactory>>,\n>(\n config: Partial<SessionConfig> & {\n store: keyof KnownStores | 'memory'\n stores: KnownStores\n }\n): ConfigProvider<\n ResolvedConfig<{\n [K in keyof KnownStores]: SessionStoreFactory\n }>\n> {\n debug('processing session config %O', config)\n\n /**\n * Make sure a store is defined\n */\n if (!config.store) {\n throw new InvalidArgumentsException('Missing \"store\" property inside the session config')\n }\n\n /**\n * Destructuring config with the default values. We pull out\n * stores and cookie values, since we have to transform\n * them in the output value.\n */\n const { stores, cookie, ...rest } = {\n enabled: true,\n age: '2h',\n cookieName: 'adonis_session',\n clearWithBrowser: false,\n ...config,\n }\n\n const cookieOptions: Partial<CookieOptions> = { ...cookie }\n\n /**\n * Define maxAge property when session id cookie is\n * not a session cookie.\n */\n if (!rest.clearWithBrowser) {\n cookieOptions.maxAge = string.seconds.parse(rest.age)\n debug('computing maxAge \"%s\" for session id cookie', cookieOptions.maxAge)\n }\n\n return configProvider.create(async (app) => {\n const storesNames = Object.keys(config.stores)\n\n /**\n * List of stores with memory store always configured\n */\n const storesList = {\n memory: () => new MemoryStore(),\n } as Record<string, SessionStoreFactory>\n\n /**\n * Looping for stores and resolving them\n */\n for (let storeName of storesNames) {\n const store = config.stores[storeName]\n if (typeof store === 'function') {\n storesList[storeName] = store\n } else {\n storesList[storeName] = await store.resolver(app)\n }\n }\n\n const transformedConfig = {\n ...rest,\n cookie: cookieOptions,\n stores: storesList as { [K in keyof KnownStores]: SessionStoreFactory },\n }\n\n debug('transformed session config %O', transformedConfig)\n return transformedConfig\n })\n}\n\n/**\n * Inbuilt stores to store the session data.\n */\nexport const stores: {\n file: (config: FileStoreConfig) => ConfigProvider<SessionStoreFactory>\n redis: (config: RedisStoreConfig) => ConfigProvider<SessionStoreFactory>\n cookie: () => ConfigProvider<SessionStoreFactory>\n dynamodb: (config: DynamoDBStoreConfig) => ConfigProvider<SessionStoreFactory>\n database: (config?: DatabaseStoreConfig) => ConfigProvider<SessionStoreFactory>\n} = {\n file: (config) => {\n return configProvider.create(async () => {\n const { FileStore } = await import('./stores/file.js')\n return (_, sessionConfig: SessionConfig) => {\n return new FileStore(config, sessionConfig.age)\n }\n })\n },\n redis: (config) => {\n return configProvider.create(async (app) => {\n const { RedisStore } = await import('./stores/redis.js')\n const redis = await app.container.make('redis')\n\n return (_, sessionConfig: SessionConfig) => {\n return new RedisStore(redis.connection(config.connection), sessionConfig.age)\n }\n })\n },\n cookie: () => {\n return configProvider.create(async () => {\n const { CookieStore } = await import('./stores/cookie.js')\n return (ctx, sessionConfig: SessionConfig) => {\n return new CookieStore(sessionConfig.cookie, ctx)\n }\n })\n },\n dynamodb: (config) => {\n return configProvider.create(async () => {\n const { DynamoDBStore } = await import('./stores/dynamodb.js')\n const { DynamoDBClient } = await import('@aws-sdk/client-dynamodb')\n\n const client =\n 'clientConfig' in config ? new DynamoDBClient(config.clientConfig) : config.client\n\n return (_, sessionConfig: SessionConfig) => {\n return new DynamoDBStore(client, sessionConfig.age, {\n tableName: config.tableName,\n keyAttribute: config.keyAttribute,\n })\n }\n })\n },\n database: (config) => {\n return configProvider.create(async (app) => {\n const { DatabaseStore } = await import('./stores/database.js')\n const db = await app.container.make('lucid.db')\n const connectionName = config?.connectionName || db.primaryConnectionName\n\n if (!db.manager.has(connectionName)) {\n throw new RuntimeException(\n `Invalid database connection \"${connectionName}\" referenced in session config`\n )\n }\n\n return (_, sessionConfig: SessionConfig) => {\n return new DatabaseStore(db.connection(connectionName), sessionConfig.age, {\n tableName: config?.tableName,\n gcProbability: config?.gcProbability,\n })\n }\n })\n },\n}\n","/**\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport type { SessionData, SessionStoreContract } from '../types.js'\n\n/**\n * Memory store is meant to be used for writing tests.\n */\nexport class MemoryStore implements SessionStoreContract {\n static sessions: Map<string, SessionData> = new Map()\n\n /**\n * Read session id value from the memory\n */\n read(sessionId: string): SessionData | null {\n return MemoryStore.sessions.get(sessionId) || null\n }\n\n /**\n * Save in memory value for a given session id\n */\n write(sessionId: string, values: SessionData): void {\n MemoryStore.sessions.set(sessionId, values)\n }\n\n /**\n * Cleanup for a single session\n */\n destroy(sessionId: string): void {\n MemoryStore.sessions.delete(sessionId)\n }\n\n touch(): void {}\n}\n"],"mappings":"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","names":["stores"]}
|
|
1
|
+
{"version":3,"sources":["../configure.ts","../src/define_config.ts","../src/stores/memory.ts"],"sourcesContent":["/*\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport type Configure from '@adonisjs/core/commands/configure'\nimport { stubsRoot } from './stubs/main.js'\n\n/**\n * Configures the package\n */\nexport async function configure(command: Configure) {\n const codemods = await command.createCodemods()\n\n /**\n * Publish config file\n */\n await codemods.makeUsingStub(stubsRoot, 'config/session.stub', {})\n\n /**\n * Define environment variables\n */\n await codemods.defineEnvVariables({ SESSION_DRIVER: 'cookie' })\n\n /**\n * Define environment variables validations\n */\n await codemods.defineEnvValidations({\n variables: {\n SESSION_DRIVER: `Env.schema.enum(['cookie', 'memory'] as const)`,\n },\n leadingComment: 'Variables for configuring session package',\n })\n\n /**\n * Register middleware\n */\n await codemods.registerMiddleware('router', [\n {\n path: '@adonisjs/session/session_middleware',\n },\n ])\n\n /**\n * Register provider and commands\n */\n await codemods.updateRcFile((rcFile) => {\n rcFile.addProvider('@adonisjs/session/session_provider')\n rcFile.addCommand('@adonisjs/session/commands')\n })\n}\n","/*\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/// <reference types=\"@adonisjs/redis/redis_provider\" />\n/// <reference types=\"@adonisjs/lucid/database_provider\" />\n\nimport string from '@poppinss/utils/string'\nimport { configProvider } from '@adonisjs/core'\nimport type { ConfigProvider } from '@adonisjs/core/types'\nimport { InvalidArgumentsException, RuntimeException } from '@poppinss/utils'\nimport type { CookieOptions } from '@adonisjs/core/types/http'\n\nimport debug from './debug.js'\nimport { MemoryStore } from './stores/memory.js'\nimport type {\n SessionConfig,\n FileStoreConfig,\n RedisStoreConfig,\n SessionStoreFactory,\n DynamoDBStoreConfig,\n DatabaseStoreConfig,\n} from './types.js'\n\n/**\n * Resolved config with stores\n */\ntype ResolvedConfig<KnownStores extends Record<string, SessionStoreFactory>> = SessionConfig & {\n store: keyof KnownStores\n stores: KnownStores\n cookie: Partial<CookieOptions>\n}\n\n/**\n * Helper to normalize session config\n */\nexport function defineConfig<\n KnownStores extends Record<string, SessionStoreFactory | ConfigProvider<SessionStoreFactory>>,\n>(\n config: Partial<SessionConfig> & {\n store: keyof KnownStores | 'memory'\n stores: KnownStores\n }\n): ConfigProvider<\n ResolvedConfig<{\n [K in keyof KnownStores]: SessionStoreFactory\n }>\n> {\n debug('processing session config %O', config)\n\n /**\n * Make sure a store is defined\n */\n if (!config.store) {\n throw new InvalidArgumentsException('Missing \"store\" property inside the session config')\n }\n\n /**\n * Destructuring config with the default values. We pull out\n * stores and cookie values, since we have to transform\n * them in the output value.\n */\n const { stores, cookie, ...rest } = {\n enabled: true,\n age: '2h',\n cookieName: 'adonis_session',\n clearWithBrowser: false,\n ...config,\n }\n\n const cookieOptions: Partial<CookieOptions> = { ...cookie }\n\n /**\n * Define maxAge property when session id cookie is\n * not a session cookie.\n */\n if (!rest.clearWithBrowser) {\n cookieOptions.maxAge = string.seconds.parse(rest.age)\n debug('computing maxAge \"%s\" for session id cookie', cookieOptions.maxAge)\n }\n\n return configProvider.create(async (app) => {\n const storesNames = Object.keys(config.stores)\n\n /**\n * List of stores with memory store always configured\n */\n const storesList = {\n memory: () => new MemoryStore(),\n } as Record<string, SessionStoreFactory>\n\n /**\n * Looping for stores and resolving them\n */\n for (let storeName of storesNames) {\n const store = config.stores[storeName]\n if (typeof store === 'function') {\n storesList[storeName] = store\n } else {\n storesList[storeName] = await store.resolver(app)\n }\n }\n\n const transformedConfig = {\n ...rest,\n cookie: cookieOptions,\n stores: storesList as { [K in keyof KnownStores]: SessionStoreFactory },\n }\n\n debug('transformed session config %O', transformedConfig)\n return transformedConfig\n })\n}\n\n/**\n * Inbuilt stores to store the session data.\n */\nexport const stores: {\n file: (config: FileStoreConfig) => ConfigProvider<SessionStoreFactory>\n redis: (config: RedisStoreConfig) => ConfigProvider<SessionStoreFactory>\n cookie: () => ConfigProvider<SessionStoreFactory>\n dynamodb: (config: DynamoDBStoreConfig) => ConfigProvider<SessionStoreFactory>\n database: (config?: DatabaseStoreConfig) => ConfigProvider<SessionStoreFactory>\n} = {\n file: (config) => {\n return configProvider.create(async () => {\n const { FileStore } = await import('./stores/file.js')\n return (_, sessionConfig: SessionConfig) => {\n return new FileStore(config, sessionConfig.age)\n }\n })\n },\n redis: (config) => {\n return configProvider.create(async (app) => {\n const { RedisStore } = await import('./stores/redis.js')\n const redis = await app.container.make('redis')\n\n return (_, sessionConfig: SessionConfig) => {\n return new RedisStore(redis.connection(config.connection), sessionConfig.age)\n }\n })\n },\n cookie: () => {\n return configProvider.create(async () => {\n const { CookieStore } = await import('./stores/cookie.js')\n return (ctx, sessionConfig: SessionConfig) => {\n return new CookieStore(sessionConfig.cookie, ctx)\n }\n })\n },\n dynamodb: (config) => {\n return configProvider.create(async () => {\n const { DynamoDBStore } = await import('./stores/dynamodb.js')\n const { DynamoDBClient } = await import('@aws-sdk/client-dynamodb')\n\n const client =\n 'clientConfig' in config ? new DynamoDBClient(config.clientConfig) : config.client\n\n return (_, sessionConfig: SessionConfig) => {\n return new DynamoDBStore(client, sessionConfig.age, {\n tableName: config.tableName,\n keyAttribute: config.keyAttribute,\n })\n }\n })\n },\n database: (config) => {\n return configProvider.create(async (app) => {\n const { DatabaseStore } = await import('./stores/database.js')\n const db = await app.container.make('lucid.db')\n const connectionName = config?.connectionName || db.primaryConnectionName\n\n if (!db.manager.has(connectionName)) {\n throw new RuntimeException(\n `Invalid database connection \"${connectionName}\" referenced in session config`\n )\n }\n\n return (_, sessionConfig: SessionConfig) => {\n return new DatabaseStore(db.connection(connectionName), sessionConfig.age, {\n tableName: config?.tableName,\n gcProbability: config?.gcProbability,\n })\n }\n })\n },\n}\n","/**\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport type { SessionData, SessionStoreWithTaggingContract, TaggedSession } from '../types.js'\n\n/**\n * Memory store is meant to be used for writing tests.\n */\nexport class MemoryStore implements SessionStoreWithTaggingContract {\n static sessions: Map<string, SessionData> = new Map()\n\n /**\n * Maps session IDs to user IDs (for tagging)\n */\n static tags: Map<string, string> = new Map()\n\n /**\n * Read session id value from the memory\n */\n read(sessionId: string): SessionData | null {\n return MemoryStore.sessions.get(sessionId) || null\n }\n\n /**\n * Save in memory value for a given session id\n */\n write(sessionId: string, values: SessionData): void {\n MemoryStore.sessions.set(sessionId, values)\n }\n\n /**\n * Cleanup for a single session\n */\n destroy(sessionId: string): void {\n MemoryStore.sessions.delete(sessionId)\n MemoryStore.tags.delete(sessionId)\n }\n\n touch(): void {}\n\n /**\n * Tag a session with a user ID\n */\n async tag(sessionId: string, userId: string): Promise<void> {\n MemoryStore.tags.set(sessionId, userId)\n }\n\n /**\n * Get all sessions for a given user ID (tag)\n */\n async tagged(userId: string): Promise<TaggedSession[]> {\n const sessions: TaggedSession[] = []\n\n for (const [sessionId, taggedUserId] of MemoryStore.tags) {\n const data = MemoryStore.sessions.get(sessionId)\n if (taggedUserId === userId && data) sessions.push({ id: sessionId, data })\n }\n\n return sessions\n }\n}\n"],"mappings":"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","names":["stores"]}
|
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
var errors_exports = {};
|
|
14
14
|
__export(errors_exports, {
|
|
15
15
|
E_SESSION_NOT_MUTABLE: () => E_SESSION_NOT_MUTABLE,
|
|
16
|
-
E_SESSION_NOT_READY: () => E_SESSION_NOT_READY
|
|
16
|
+
E_SESSION_NOT_READY: () => E_SESSION_NOT_READY,
|
|
17
|
+
E_SESSION_TAGGING_NOT_SUPPORTED: () => E_SESSION_TAGGING_NOT_SUPPORTED
|
|
17
18
|
});
|
|
18
19
|
import { createError } from "@poppinss/utils";
|
|
19
20
|
var E_SESSION_NOT_MUTABLE = createError(
|
|
@@ -26,6 +27,11 @@ var E_SESSION_NOT_READY = createError(
|
|
|
26
27
|
"E_SESSION_NOT_READY",
|
|
27
28
|
500
|
|
28
29
|
);
|
|
30
|
+
var E_SESSION_TAGGING_NOT_SUPPORTED = createError(
|
|
31
|
+
"Session store does not support tagging operations. Only Redis, Database and Memory stores support tagging.",
|
|
32
|
+
"E_SESSION_TAGGING_NOT_SUPPORTED",
|
|
33
|
+
500
|
|
34
|
+
);
|
|
29
35
|
|
|
30
36
|
// src/session.ts
|
|
31
37
|
import Macroable from "@poppinss/macroable";
|
|
@@ -338,6 +344,17 @@ var Session = class extends Macroable {
|
|
|
338
344
|
regenerate() {
|
|
339
345
|
this.#sessionId = cuid();
|
|
340
346
|
}
|
|
347
|
+
/**
|
|
348
|
+
* Tag the current session with a user ID. This allows you to
|
|
349
|
+
* later retrieve all sessions for a given user via SessionCollection.
|
|
350
|
+
*
|
|
351
|
+
* Only Memory, Redis and Database stores support tagging. Other stores
|
|
352
|
+
* will throw an error.
|
|
353
|
+
*/
|
|
354
|
+
async tag(userId) {
|
|
355
|
+
if (!("tag" in this.#store)) throw new E_SESSION_TAGGING_NOT_SUPPORTED();
|
|
356
|
+
await this.#store.tag(this.#sessionId, userId);
|
|
357
|
+
}
|
|
341
358
|
/**
|
|
342
359
|
* Commit session changes. No more mutations will be
|
|
343
360
|
* allowed after commit.
|
|
@@ -390,7 +407,8 @@ var Session = class extends Macroable {
|
|
|
390
407
|
};
|
|
391
408
|
|
|
392
409
|
export {
|
|
410
|
+
E_SESSION_TAGGING_NOT_SUPPORTED,
|
|
393
411
|
errors_exports,
|
|
394
412
|
Session
|
|
395
413
|
};
|
|
396
|
-
//# sourceMappingURL=chunk-
|
|
414
|
+
//# sourceMappingURL=chunk-XP3CBOXR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/session.ts"],"sourcesContent":["/*\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport { createError } from '@poppinss/utils'\n\n/**\n * Raised when session store is not mutable\n */\nexport const E_SESSION_NOT_MUTABLE = createError(\n 'Session store is in readonly mode and cannot be mutated',\n 'E_SESSION_NOT_MUTABLE',\n 500\n)\n\n/**\n * Raised when session store has been initiated\n */\nexport const E_SESSION_NOT_READY = createError(\n 'Session store has not been initiated. Make sure you have registered the session middleware',\n 'E_SESSION_NOT_READY',\n 500\n)\n\n/**\n * Raised when trying to use tagging with a store that\n * doesn't support tagging operations\n */\nexport const E_SESSION_TAGGING_NOT_SUPPORTED = createError(\n 'Session store does not support tagging operations. Only Redis, Database and Memory stores support tagging.',\n 'E_SESSION_TAGGING_NOT_SUPPORTED',\n 500\n)\n","/*\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport type { I18n } from '@adonisjs/i18n'\nimport Macroable from '@poppinss/macroable'\nimport lodash from '@poppinss/utils/lodash'\nimport { cuid } from '@adonisjs/core/helpers'\nimport type { HttpContext } from '@adonisjs/core/http'\nimport type { EmitterService } from '@adonisjs/core/types'\nimport type { HttpError } from '@adonisjs/core/types/http'\n\nimport debug from './debug.js'\nimport * as errors from './errors.js'\nimport { ReadOnlyValuesStore, ValuesStore } from './values_store.js'\nimport type {\n SessionData,\n SessionConfig,\n SessionStoreFactory,\n AllowedSessionValues,\n SessionStoreContract,\n SessionStoreWithTaggingContract,\n} from './types.js'\n\n/**\n * The session class exposes the API to read and write values to\n * the session store.\n *\n * A session instance is isolated between requests but\n * uses a centralized persistence store and\n */\nexport class Session extends Macroable {\n #store: SessionStoreContract | SessionStoreWithTaggingContract\n #emitter: EmitterService\n #ctx: HttpContext\n #readonly: boolean = false\n\n /**\n * Session values store\n */\n #valuesStore?: ValuesStore\n\n /**\n * Session id refers to the session id that will be committed\n * as a cookie during the response.\n */\n #sessionId: string\n\n /**\n * Session id from cookie refers to the value we read from the\n * cookie during the HTTP request.\n *\n * This only might not exist during the first request. Also during\n * session id re-generation, this value will be different from\n * the session id.\n */\n #sessionIdFromCookie?: string\n\n /**\n * Store of flash messages that be written during the\n * HTTP request\n */\n responseFlashMessages = new ValuesStore({})\n\n /**\n * Store of flash messages for the current HTTP request.\n */\n flashMessages = new ValuesStore({})\n\n /**\n * The key to use for storing flash messages inside\n * the session store.\n */\n flashKey: string = '__flash__'\n\n /**\n * Session id for the current HTTP request\n */\n get sessionId() {\n return this.#sessionId\n }\n\n /**\n * A boolean to know if a fresh session is created during\n * the request\n */\n get fresh(): boolean {\n return this.#sessionIdFromCookie === undefined\n }\n\n /**\n * A boolean to know if session is in readonly\n * state\n */\n get readonly() {\n return this.#readonly\n }\n\n /**\n * A boolean to know if session store has been initiated\n */\n get initiated() {\n return !!this.#valuesStore\n }\n\n /**\n * A boolean to know if the session id has been re-generated\n * during the current request\n */\n get hasRegeneratedSession() {\n return !!(this.#sessionIdFromCookie && this.#sessionIdFromCookie !== this.#sessionId)\n }\n\n /**\n * A boolean to know if the session store is empty\n */\n get isEmpty() {\n return this.#valuesStore?.isEmpty ?? true\n }\n\n /**\n * A boolean to know if the session store has been\n * modified\n */\n get hasBeenModified() {\n return this.#valuesStore?.hasBeenModified ?? false\n }\n\n constructor(\n public config: SessionConfig,\n storeFactory: SessionStoreFactory,\n emitter: EmitterService,\n ctx: HttpContext\n ) {\n super()\n this.#ctx = ctx\n this.#emitter = emitter\n this.#store = storeFactory(ctx, config)\n this.#sessionIdFromCookie = ctx.request.cookie(config.cookieName, undefined)\n this.#sessionId = this.#sessionIdFromCookie || cuid()\n }\n\n /**\n * Returns the flash messages store for a given\n * mode\n */\n #getFlashStore(mode: 'write' | 'read'): ValuesStore {\n if (!this.#valuesStore) {\n throw new errors.E_SESSION_NOT_READY()\n }\n\n if (mode === 'write' && this.readonly) {\n throw new errors.E_SESSION_NOT_MUTABLE()\n }\n\n return this.responseFlashMessages\n }\n\n /**\n * Returns the store instance for a given mode\n */\n #getValuesStore(mode: 'write' | 'read'): ValuesStore {\n if (!this.#valuesStore) {\n throw new errors.E_SESSION_NOT_READY()\n }\n\n if (mode === 'write' && this.readonly) {\n throw new errors.E_SESSION_NOT_MUTABLE()\n }\n\n return this.#valuesStore\n }\n\n /**\n * Initiates the session store. The method results in a noop\n * when called multiple times\n */\n async initiate(readonly: boolean): Promise<void> {\n if (this.#valuesStore) {\n return\n }\n\n debug('initiating session (readonly: %s)', readonly)\n\n this.#readonly = readonly\n const contents = await this.#store.read(this.#sessionId)\n this.#valuesStore = new ValuesStore(contents)\n\n /**\n * Extract flash messages from the store and keep a local\n * copy of it.\n */\n if (this.has(this.flashKey)) {\n debug('reading flash data')\n if (this.#readonly) {\n this.flashMessages.update(this.get(this.flashKey, null))\n } else {\n this.flashMessages.update(this.pull(this.flashKey, null))\n }\n }\n\n /**\n * Share session with the templates. We assume the view property\n * is a reference to edge templates\n */\n if ('view' in this.#ctx) {\n this.#ctx.view.share({\n session: new ReadOnlyValuesStore(this.#valuesStore.all()),\n flashMessages: new ReadOnlyValuesStore(this.flashMessages.all()),\n old: function (key: string, defaultValue?: any) {\n return this.flashMessages.get(key, defaultValue)\n },\n })\n }\n\n this.#emitter.emit('session:initiated', { session: this })\n }\n\n /**\n * Put a key-value pair to the session data store\n */\n put(key: string, value: AllowedSessionValues) {\n this.#getValuesStore('write').set(key, value)\n }\n\n /**\n * Check if a key exists inside the datastore\n */\n has(key: string): boolean {\n return this.#getValuesStore('read').has(key)\n }\n\n /**\n * Get the value of a key from the session datastore.\n * You can specify a default value to use, when key\n * does not exists or has undefined value.\n */\n get(key: string, defaultValue?: any) {\n return this.#getValuesStore('read').get(key, defaultValue)\n }\n\n /**\n * Get everything from the session store\n */\n all() {\n return this.#getValuesStore('read').all()\n }\n\n /**\n * Remove a key from the session datastore\n */\n forget(key: string) {\n return this.#getValuesStore('write').unset(key)\n }\n\n /**\n * Read value for a key from the session datastore\n * and remove it simultaneously.\n */\n pull(key: string, defaultValue?: any) {\n return this.#getValuesStore('write').pull(key, defaultValue)\n }\n\n /**\n * Increment the value of a key inside the session\n * store.\n *\n * A new key will be defined if does not exists already.\n * The value of a new key will be 1\n */\n increment(key: string, steps: number = 1) {\n return this.#getValuesStore('write').increment(key, steps)\n }\n\n /**\n * Increment the value of a key inside the session\n * store.\n *\n * A new key will be defined if does not exists already.\n * The value of a new key will be -1\n */\n decrement(key: string, steps: number = 1) {\n return this.#getValuesStore('write').decrement(key, steps)\n }\n\n /**\n * Empty the session store\n */\n clear() {\n return this.#getValuesStore('write').clear()\n }\n\n /**\n * Add a key-value pair to flash messages\n */\n flash(key: string, value: AllowedSessionValues): void\n flash(keyValue: SessionData): void\n flash(key: string | SessionData, value?: AllowedSessionValues): void {\n if (typeof key === 'string') {\n if (value) {\n this.#getFlashStore('write').set(key, value)\n }\n } else {\n this.#getFlashStore('write').merge(key)\n }\n }\n\n /**\n * Flash errors to the errorsBag. You can read these\n * errors via the \"@error\" tag.\n *\n * Appends new messages to the existing collection.\n */\n flashErrors(errorsCollection: Record<string, string | string[]>) {\n this.flash({ errorsBag: errorsCollection })\n }\n\n /**\n * Flash validation error messages. Make sure the error\n * is an instance of VineJS ValidationException.\n *\n * Overrides existing inputErrors\n */\n flashValidationErrors(error: HttpError) {\n const errorsBag = error.messages.reduce((result: Record<string, string[]>, message: any) => {\n if (result[message.field]) {\n result[message.field].push(message.message)\n } else {\n result[message.field] = [message.message]\n }\n return result\n }, {})\n\n this.flashExcept(['_csrf', '_method', 'password', 'password_confirmation'])\n\n /**\n * Adding the error summary to the \"errorsBag\" so that\n * we display the validation error globally using\n * the \"@error\" tag.\n */\n let summary = 'The form could not be saved. Please check the errors below.'\n if ('i18n' in this.#ctx) {\n summary = (this.#ctx.i18n as I18n).t(\n `errors.${error.code}`,\n {\n count: error.messages.length,\n },\n summary\n )\n }\n\n this.flashErrors({\n [String(error.code)]: summary,\n })\n\n /**\n * Adding to inputErrorsBag for \"@inputError\" tag\n * to read validation errors\n */\n this.flash('inputErrorsBag', errorsBag)\n\n /**\n * For legacy support and not to break apps using\n * the older version of @adonisjs/session package\n */\n this.flash('errors', errorsBag)\n }\n\n /**\n * Flash form input data to the flash messages store\n */\n flashAll() {\n return this.#getFlashStore('write').set('input', this.#ctx.request.original())\n }\n\n /**\n * Flash form input data (except some keys) to the flash messages store\n */\n flashExcept(keys: string[]): void {\n this.#getFlashStore('write').set('input', lodash.omit(this.#ctx.request.original(), keys))\n }\n\n /**\n * Flash form input data (only some keys) to the flash messages store\n */\n flashOnly(keys: string[]): void {\n this.#getFlashStore('write').set('input', lodash.pick(this.#ctx.request.original(), keys))\n }\n\n /**\n * Reflash messages from the last request in the current response\n */\n reflash(): void {\n this.#getFlashStore('write').set('reflashed', this.flashMessages.all())\n }\n\n /**\n * Reflash messages (only some keys) from the last\n * request in the current response\n */\n reflashOnly(keys: string[]) {\n this.#getFlashStore('write').set('reflashed', lodash.pick(this.flashMessages.all(), keys))\n }\n\n /**\n * Reflash messages (except some keys) from the last\n * request in the current response\n */\n reflashExcept(keys: string[]) {\n this.#getFlashStore('write').set('reflashed', lodash.omit(this.flashMessages.all(), keys))\n }\n\n /**\n * Re-generate the session id and migrate data to it.\n */\n regenerate() {\n this.#sessionId = cuid()\n }\n\n /**\n * Tag the current session with a user ID. This allows you to\n * later retrieve all sessions for a given user via SessionCollection.\n *\n * Only Memory, Redis and Database stores support tagging. Other stores\n * will throw an error.\n */\n async tag(userId: string): Promise<void> {\n if (!('tag' in this.#store)) throw new errors.E_SESSION_TAGGING_NOT_SUPPORTED()\n await this.#store.tag(this.#sessionId, userId)\n }\n\n /**\n * Commit session changes. No more mutations will be\n * allowed after commit.\n */\n async commit() {\n if (!this.#valuesStore || this.readonly) {\n return\n }\n\n /**\n * If the flash messages store is not empty, we should put\n * its messages inside main session store.\n */\n if (!this.responseFlashMessages.isEmpty) {\n const { input, reflashed, ...others } = this.responseFlashMessages.all()\n this.put(this.flashKey, { ...reflashed, ...input, ...others })\n }\n\n debug('committing session data')\n\n /**\n * Touch the session id cookie to stay alive\n */\n this.#ctx.response.cookie(this.config.cookieName, this.#sessionId, this.config.cookie!)\n\n /**\n * Delete the session data when the session store\n * is empty.\n *\n * Also we only destroy the session id we read from the cookie.\n * If there was no session id in the cookie, there won't be\n * any data inside the store either.\n */\n if (this.isEmpty) {\n if (this.#sessionIdFromCookie) {\n await this.#store.destroy(this.#sessionIdFromCookie)\n }\n this.#emitter.emit('session:committed', { session: this })\n return\n }\n\n /**\n * Touch the store expiry when the session store was\n * not modified.\n */\n if (!this.hasBeenModified) {\n if (this.#sessionIdFromCookie && this.#sessionIdFromCookie !== this.#sessionId) {\n await this.#store.destroy(this.#sessionIdFromCookie)\n await this.#store.write(this.#sessionId, this.#valuesStore.toJSON())\n this.#emitter.emit('session:migrated', {\n fromSessionId: this.#sessionIdFromCookie,\n toSessionId: this.sessionId,\n session: this,\n })\n } else {\n await this.#store.touch(this.#sessionId)\n }\n this.#emitter.emit('session:committed', { session: this })\n return\n }\n\n /**\n * Otherwise commit to the session store\n */\n if (this.#sessionIdFromCookie && this.#sessionIdFromCookie !== this.#sessionId) {\n await this.#store.destroy(this.#sessionIdFromCookie)\n await this.#store.write(this.#sessionId, this.#valuesStore.toJSON())\n this.#emitter.emit('session:migrated', {\n fromSessionId: this.#sessionIdFromCookie,\n toSessionId: this.sessionId,\n session: this,\n })\n } else {\n await this.#store.write(this.#sessionId, this.#valuesStore.toJSON())\n }\n\n this.#emitter.emit('session:committed', { session: this })\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -33,6 +33,16 @@ var DatabaseStore = class {
|
|
|
33
33
|
await this.#client.from(this.#tableName).where("expires_at", "<=", expiredBefore).delete();
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Parses and verifies session data using MessageBuilder
|
|
38
|
+
*/
|
|
39
|
+
#parseSessionData(contents, sessionId) {
|
|
40
|
+
try {
|
|
41
|
+
return new MessageBuilder().verify(contents, sessionId);
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
36
46
|
/**
|
|
37
47
|
* Returns session data
|
|
38
48
|
*/
|
|
@@ -47,11 +57,7 @@ var DatabaseStore = class {
|
|
|
47
57
|
await this.destroy(sessionId);
|
|
48
58
|
return null;
|
|
49
59
|
}
|
|
50
|
-
|
|
51
|
-
return new MessageBuilder().verify(row.data, sessionId);
|
|
52
|
-
} catch {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
60
|
+
return this.#parseSessionData(row.data, sessionId);
|
|
55
61
|
}
|
|
56
62
|
/**
|
|
57
63
|
* Write session values to the database
|
|
@@ -82,8 +88,31 @@ var DatabaseStore = class {
|
|
|
82
88
|
const expiresAt = new Date(Date.now() + this.#ttlSeconds * 1e3);
|
|
83
89
|
await this.#client.from(this.#tableName).where("id", sessionId).update({ expires_at: expiresAt });
|
|
84
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Tag a session with a user ID
|
|
93
|
+
*/
|
|
94
|
+
async tag(sessionId, userId) {
|
|
95
|
+
debug_default("database store: tagging session %s with user %s", sessionId, userId);
|
|
96
|
+
await this.#client.from(this.#tableName).where("id", sessionId).update({ user_id: userId });
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Converts a database row to a TaggedSession object
|
|
100
|
+
*/
|
|
101
|
+
#rowToTaggedSession(row) {
|
|
102
|
+
const data = this.#parseSessionData(row.data, row.id);
|
|
103
|
+
if (!data) return null;
|
|
104
|
+
return { id: row.id, data };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get all sessions for a given user ID (tag)
|
|
108
|
+
*/
|
|
109
|
+
async tagged(userId) {
|
|
110
|
+
debug_default("database store: getting sessions tagged with user %s", userId);
|
|
111
|
+
const rows = await this.#client.from(this.#tableName).select("id", "data").where("user_id", userId).where("expires_at", ">", /* @__PURE__ */ new Date());
|
|
112
|
+
return rows.map((row) => this.#rowToTaggedSession(row)).filter((session) => session !== null);
|
|
113
|
+
}
|
|
85
114
|
};
|
|
86
115
|
export {
|
|
87
116
|
DatabaseStore
|
|
88
117
|
};
|
|
89
|
-
//# sourceMappingURL=database-
|
|
118
|
+
//# sourceMappingURL=database-443FB7MM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/stores/database.ts"],"sourcesContent":["/**\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport string from '@poppinss/utils/string'\nimport { MessageBuilder } from '@adonisjs/core/helpers'\nimport type { QueryClientContract } from '@adonisjs/lucid/types/database'\n\nimport debug from '../debug.js'\nimport type { SessionStoreWithTaggingContract, SessionData, TaggedSession } from '../types.js'\n\n/**\n * Database store to read/write session to SQL databases using Lucid\n */\nexport class DatabaseStore implements SessionStoreWithTaggingContract {\n #client: QueryClientContract\n #tableName: string\n #ttlSeconds: number\n #gcProbability: number\n\n constructor(\n client: QueryClientContract,\n age: string | number,\n options?: {\n /**\n * Defaults to \"sessions\"\n */\n tableName?: string\n\n /**\n * The probability (in percent) that garbage collection will be\n * triggered on any given request. For example, 2 means 2% chance.\n *\n * Set to 0 to disable garbage collection.\n *\n * Defaults to 2 (2% chance)\n */\n gcProbability?: number\n }\n ) {\n this.#client = client\n this.#tableName = options?.tableName ?? 'sessions'\n this.#ttlSeconds = string.seconds.parse(age)\n this.#gcProbability = options?.gcProbability ?? 2\n debug('initiating database store')\n }\n\n /**\n * Run garbage collection to delete expired sessions.\n * This is called based on gcProbability after writing session data.\n */\n async #collectGarbage(): Promise<void> {\n if (this.#gcProbability <= 0) {\n return\n }\n\n const random = Math.random() * 100\n if (random < this.#gcProbability) {\n debug('database store: running garbage collection')\n const expiredBefore = new Date(Date.now())\n await this.#client.from(this.#tableName).where('expires_at', '<=', expiredBefore).delete()\n }\n }\n\n /**\n * Parses and verifies session data using MessageBuilder\n */\n #parseSessionData(contents: string, sessionId: string): SessionData | null {\n try {\n return new MessageBuilder().verify<SessionData>(contents, sessionId)\n } catch {\n return null\n }\n }\n\n /**\n * Returns session data\n */\n async read(sessionId: string): Promise<SessionData | null> {\n debug('database store: reading session data %s', sessionId)\n\n const row = await this.#client.from(this.#tableName).where('id', sessionId).first()\n\n if (!row) {\n return null\n }\n\n /**\n * Check if the session has expired. If so, delete it and return null.\n */\n const expiresAt = new Date(row.expires_at).getTime()\n if (Date.now() > expiresAt) {\n await this.destroy(sessionId)\n return null\n }\n\n return this.#parseSessionData(row.data, sessionId)\n }\n\n /**\n * Write session values to the database\n */\n async write(sessionId: string, values: Object): Promise<void> {\n debug('database store: writing session data %s, %O', sessionId, values)\n\n const message = new MessageBuilder().build(values, undefined, sessionId)\n const expiresAt = new Date(Date.now() + this.#ttlSeconds * 1000)\n\n await this.#client\n .insertQuery()\n .table(this.#tableName)\n .insert({\n id: sessionId,\n data: message,\n expires_at: expiresAt,\n })\n .knexQuery.onConflict('id')\n .merge(['data', 'expires_at'])\n\n await this.#collectGarbage()\n }\n\n /**\n * Cleanup session by removing it\n */\n async destroy(sessionId: string): Promise<void> {\n debug('database store: destroying session data %s', sessionId)\n\n await this.#client.from(this.#tableName).where('id', sessionId).delete()\n }\n\n /**\n * Updates the session expiry\n */\n async touch(sessionId: string): Promise<void> {\n debug('database store: touching session data %s', sessionId)\n\n const expiresAt = new Date(Date.now() + this.#ttlSeconds * 1000)\n\n await this.#client\n .from(this.#tableName)\n .where('id', sessionId)\n .update({ expires_at: expiresAt })\n }\n\n /**\n * Tag a session with a user ID\n */\n async tag(sessionId: string, userId: string): Promise<void> {\n debug('database store: tagging session %s with user %s', sessionId, userId)\n\n await this.#client.from(this.#tableName).where('id', sessionId).update({ user_id: userId })\n }\n\n /**\n * Converts a database row to a TaggedSession object\n */\n #rowToTaggedSession(row: { id: string; data: string }): TaggedSession | null {\n const data = this.#parseSessionData(row.data, row.id)\n if (!data) return null\n\n return { id: row.id, data }\n }\n\n /**\n * Get all sessions for a given user ID (tag)\n */\n async tagged(userId: string): Promise<TaggedSession[]> {\n debug('database store: getting sessions tagged with user %s', userId)\n\n const rows = await this.#client\n .from(this.#tableName)\n .select('id', 'data')\n .where('user_id', userId)\n .where('expires_at', '>', new Date())\n\n return rows.map((row) => this.#rowToTaggedSession(row)).filter((session) => session !== null)\n }\n}\n"],"mappings":"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","names":[]}
|
package/build/factories/main.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
defineConfig
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-Q24L5XPC.js";
|
|
4
4
|
import "../chunk-V3OAEXMJ.js";
|
|
5
|
+
import "../chunk-G7KFHA57.js";
|
|
5
6
|
import {
|
|
6
7
|
SessionMiddleware
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
8
|
+
} from "../chunk-6BSSM3HO.js";
|
|
9
|
+
import "../chunk-XP3CBOXR.js";
|
|
9
10
|
import "../chunk-TE5JP3SX.js";
|
|
10
11
|
import "../chunk-5ECC6OWF.js";
|
|
11
12
|
import "../chunk-PZ5AY32C.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../factories/session_middleware_factory.ts"],"sourcesContent":["/*\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport { Emitter } from '@adonisjs/core/events'\nimport { AppFactory } from '@adonisjs/core/factories/app'\nimport type { ApplicationService, EventsList } from '@adonisjs/core/types'\n\nimport { defineConfig } from '../index.js'\nimport SessionMiddleware from '../src/session_middleware.js'\nimport type { SessionConfig, SessionStoreFactory } from '../src/types.js'\n\n/**\n * Exposes the API to create an instance of the session middleware\n * without additional plumbing\n */\nexport class SessionMiddlewareFactory {\n #config: Partial<SessionConfig> & {\n store: string\n stores: Record<string, SessionStoreFactory>\n } = {\n store: 'memory',\n stores: {},\n }\n\n #emitter?: Emitter<EventsList>\n\n #getApp() {\n return new AppFactory().create(new URL('./', import.meta.url), () => {}) as ApplicationService\n }\n\n #getEmitter() {\n return this.#emitter || new Emitter<EventsList>(this.#getApp())\n }\n\n /**\n * Merge custom options\n */\n merge(options: {\n config?: Partial<SessionConfig> & {\n store: string\n stores: Record<string, SessionStoreFactory>\n }\n emitter?: Emitter<EventsList>\n }) {\n if (options.config) {\n this.#config = options.config\n }\n\n if (options.emitter) {\n this.#emitter = options.emitter\n }\n\n return this\n }\n\n /**\n * Creates an instance of the session middleware\n */\n async create() {\n const config = await defineConfig(this.#config).resolver(this.#getApp())\n return new SessionMiddleware(config, this.#getEmitter())\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../factories/session_middleware_factory.ts"],"sourcesContent":["/*\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport { Emitter } from '@adonisjs/core/events'\nimport { AppFactory } from '@adonisjs/core/factories/app'\nimport type { ApplicationService, EventsList } from '@adonisjs/core/types'\n\nimport { defineConfig } from '../index.js'\nimport SessionMiddleware from '../src/session_middleware.js'\nimport type { SessionConfig, SessionStoreFactory } from '../src/types.js'\n\n/**\n * Exposes the API to create an instance of the session middleware\n * without additional plumbing\n */\nexport class SessionMiddlewareFactory {\n #config: Partial<SessionConfig> & {\n store: string\n stores: Record<string, SessionStoreFactory>\n } = {\n store: 'memory',\n stores: {},\n }\n\n #emitter?: Emitter<EventsList>\n\n #getApp() {\n return new AppFactory().create(new URL('./', import.meta.url), () => {}) as ApplicationService\n }\n\n #getEmitter() {\n return this.#emitter || new Emitter<EventsList>(this.#getApp())\n }\n\n /**\n * Merge custom options\n */\n merge(options: {\n config?: Partial<SessionConfig> & {\n store: string\n stores: Record<string, SessionStoreFactory>\n }\n emitter?: Emitter<EventsList>\n }) {\n if (options.config) {\n this.#config = options.config\n }\n\n if (options.emitter) {\n this.#emitter = options.emitter\n }\n\n return this\n }\n\n /**\n * Creates an instance of the session middleware\n */\n async create() {\n const config = await defineConfig(this.#config).resolver(this.#getApp())\n return new SessionMiddleware(config, this.#getEmitter())\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AASA,SAAS,eAAe;AACxB,SAAS,kBAAkB;AAWpB,IAAM,2BAAN,MAA+B;AAAA,EACpC,UAGI;AAAA,IACF,OAAO;AAAA,IACP,QAAQ,CAAC;AAAA,EACX;AAAA,EAEA;AAAA,EAEA,UAAU;AACR,WAAO,IAAI,WAAW,EAAE,OAAO,IAAI,IAAI,MAAM,YAAY,GAAG,GAAG,MAAM;AAAA,IAAC,CAAC;AAAA,EACzE;AAAA,EAEA,cAAc;AACZ,WAAO,KAAK,YAAY,IAAI,QAAoB,KAAK,QAAQ,CAAC;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAMH;AACD,QAAI,QAAQ,QAAQ;AAClB,WAAK,UAAU,QAAQ;AAAA,IACzB;AAEA,QAAI,QAAQ,SAAS;AACnB,WAAK,WAAW,QAAQ;AAAA,IAC1B;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS;AACb,UAAM,SAAS,MAAM,aAAa,KAAK,OAAO,EAAE,SAAS,KAAK,QAAQ,CAAC;AACvE,WAAO,IAAI,kBAAkB,QAAQ,KAAK,YAAY,CAAC;AAAA,EACzD;AACF;","names":[]}
|
package/build/index.d.ts
CHANGED
|
@@ -11,4 +11,5 @@ export { configure } from './configure.js';
|
|
|
11
11
|
export { Session } from './src/session.js';
|
|
12
12
|
export { stubsRoot } from './stubs/main.js';
|
|
13
13
|
export { defineConfig, stores } from './src/define_config.js';
|
|
14
|
+
export { SessionCollection } from './src/session_collection.js';
|
|
14
15
|
export { ReadOnlyValuesStore, ValuesStore } from './src/values_store.js';
|
package/build/index.js
CHANGED
|
@@ -2,14 +2,17 @@ import {
|
|
|
2
2
|
configure,
|
|
3
3
|
defineConfig,
|
|
4
4
|
stores
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-Q24L5XPC.js";
|
|
6
6
|
import {
|
|
7
7
|
stubsRoot
|
|
8
8
|
} from "./chunk-V3OAEXMJ.js";
|
|
9
|
+
import {
|
|
10
|
+
SessionCollection
|
|
11
|
+
} from "./chunk-G7KFHA57.js";
|
|
9
12
|
import {
|
|
10
13
|
Session,
|
|
11
14
|
errors_exports
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-XP3CBOXR.js";
|
|
13
16
|
import {
|
|
14
17
|
ReadOnlyValuesStore,
|
|
15
18
|
ValuesStore
|
|
@@ -19,6 +22,7 @@ import "./chunk-PZ5AY32C.js";
|
|
|
19
22
|
export {
|
|
20
23
|
ReadOnlyValuesStore,
|
|
21
24
|
Session,
|
|
25
|
+
SessionCollection,
|
|
22
26
|
ValuesStore,
|
|
23
27
|
configure,
|
|
24
28
|
defineConfig,
|
|
@@ -15,6 +15,7 @@ export default class extends BaseSchema {
|
|
|
15
15
|
this.schema.createTable(this.tableName, (table) => {
|
|
16
16
|
table.string('id').primary()
|
|
17
17
|
table.text('data').notNullable()
|
|
18
|
+
table.string('user_id').nullable().index()
|
|
18
19
|
table.timestamp('expires_at').notNullable().index()
|
|
19
20
|
})
|
|
20
21
|
}
|
|
@@ -23,6 +23,7 @@ declare module '@adonisjs/core/types' {
|
|
|
23
23
|
* AdonisJS application
|
|
24
24
|
*/
|
|
25
25
|
export default class SessionProvider {
|
|
26
|
+
#private;
|
|
26
27
|
protected app: ApplicationService;
|
|
27
28
|
constructor(app: ApplicationService);
|
|
28
29
|
/**
|
|
@@ -31,7 +32,7 @@ export default class SessionProvider {
|
|
|
31
32
|
*/
|
|
32
33
|
protected registerEdgePlugin(): Promise<void>;
|
|
33
34
|
/**
|
|
34
|
-
* Registering
|
|
35
|
+
* Registering bindings
|
|
35
36
|
*/
|
|
36
37
|
register(): void;
|
|
37
38
|
/**
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SessionCollection
|
|
3
|
+
} from "../chunk-G7KFHA57.js";
|
|
1
4
|
import {
|
|
2
5
|
SessionMiddleware
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
6
|
+
} from "../chunk-6BSSM3HO.js";
|
|
7
|
+
import "../chunk-XP3CBOXR.js";
|
|
5
8
|
import "../chunk-TE5JP3SX.js";
|
|
6
9
|
import "../chunk-5ECC6OWF.js";
|
|
7
10
|
import "../chunk-PZ5AY32C.js";
|
|
@@ -25,20 +28,31 @@ var SessionProvider = class {
|
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
/**
|
|
28
|
-
*
|
|
31
|
+
* Resolves the session config from the config provider
|
|
32
|
+
*/
|
|
33
|
+
async #resolveConfig() {
|
|
34
|
+
const sessionConfigProvider = this.app.config.get("session", {});
|
|
35
|
+
const config = await configProvider.resolve(this.app, sessionConfigProvider);
|
|
36
|
+
if (!config) {
|
|
37
|
+
throw new RuntimeException(
|
|
38
|
+
'Invalid "config/session.ts" file. Make sure you are using the "defineConfig" method'
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return config;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Registering bindings
|
|
29
45
|
*/
|
|
30
46
|
register() {
|
|
31
47
|
this.app.container.singleton(SessionMiddleware, async (resolver) => {
|
|
32
|
-
const
|
|
33
|
-
const config = await configProvider.resolve(this.app, sessionConfigProvider);
|
|
34
|
-
if (!config) {
|
|
35
|
-
throw new RuntimeException(
|
|
36
|
-
'Invalid "config/session.ts" file. Make sure you are using the "defineConfig" method'
|
|
37
|
-
);
|
|
38
|
-
}
|
|
48
|
+
const config = await this.#resolveConfig();
|
|
39
49
|
const emitter = await resolver.make("emitter");
|
|
40
50
|
return new SessionMiddleware(config, emitter);
|
|
41
51
|
});
|
|
52
|
+
this.app.container.singleton(SessionCollection, async () => {
|
|
53
|
+
const config = await this.#resolveConfig();
|
|
54
|
+
return new SessionCollection(config);
|
|
55
|
+
});
|
|
42
56
|
}
|
|
43
57
|
/**
|
|
44
58
|
* Adding edge tags (if edge is installed)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../providers/session_provider.ts"],"sourcesContent":["/*\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport { configProvider } from '@adonisjs/core'\nimport { RuntimeException } from '@poppinss/utils'\nimport type { ApplicationService } from '@adonisjs/core/types'\n\nimport type { Session } from '../src/session.js'\nimport SessionMiddleware from '../src/session_middleware.js'\n\n/**\n * Events emitted by the session class\n */\ndeclare module '@adonisjs/core/types' {\n interface EventsList {\n 'session:initiated': { session: Session }\n 'session:committed': { session: Session }\n 'session:migrated': { fromSessionId: string; toSessionId: string; session: Session }\n }\n}\n\n/**\n * Session provider configures the session management inside an\n * AdonisJS application\n */\nexport default class SessionProvider {\n constructor(protected app: ApplicationService) {}\n\n /**\n * Registers edge plugin when edge is installed\n * in the user application.\n */\n protected async registerEdgePlugin() {\n if (this.app.usingEdgeJS) {\n const edge = await import('edge.js')\n const { edgePluginSession } = await import('../src/plugins/edge.js')\n edge.default.use(edgePluginSession)\n }\n }\n\n /**\n *
|
|
1
|
+
{"version":3,"sources":["../../providers/session_provider.ts"],"sourcesContent":["/*\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport { configProvider } from '@adonisjs/core'\nimport { RuntimeException } from '@poppinss/utils'\nimport type { ApplicationService } from '@adonisjs/core/types'\n\nimport type { Session } from '../src/session.js'\nimport SessionMiddleware from '../src/session_middleware.js'\nimport { SessionCollection } from '../src/session_collection.js'\n\n/**\n * Events emitted by the session class\n */\ndeclare module '@adonisjs/core/types' {\n interface EventsList {\n 'session:initiated': { session: Session }\n 'session:committed': { session: Session }\n 'session:migrated': { fromSessionId: string; toSessionId: string; session: Session }\n }\n}\n\n/**\n * Session provider configures the session management inside an\n * AdonisJS application\n */\nexport default class SessionProvider {\n constructor(protected app: ApplicationService) {}\n\n /**\n * Registers edge plugin when edge is installed\n * in the user application.\n */\n protected async registerEdgePlugin() {\n if (this.app.usingEdgeJS) {\n const edge = await import('edge.js')\n const { edgePluginSession } = await import('../src/plugins/edge.js')\n edge.default.use(edgePluginSession)\n }\n }\n\n /**\n * Resolves the session config from the config provider\n */\n async #resolveConfig() {\n const sessionConfigProvider = this.app.config.get('session', {})\n const config = await configProvider.resolve<any>(this.app, sessionConfigProvider)\n\n if (!config) {\n throw new RuntimeException(\n 'Invalid \"config/session.ts\" file. Make sure you are using the \"defineConfig\" method'\n )\n }\n\n return config\n }\n\n /**\n * Registering bindings\n */\n register() {\n this.app.container.singleton(SessionMiddleware, async (resolver) => {\n const config = await this.#resolveConfig()\n const emitter = await resolver.make('emitter')\n return new SessionMiddleware(config, emitter)\n })\n\n this.app.container.singleton(SessionCollection, async () => {\n const config = await this.#resolveConfig()\n return new SessionCollection(config)\n })\n }\n\n /**\n * Adding edge tags (if edge is installed)\n */\n async boot() {\n await this.registerEdgePlugin()\n }\n}\n"],"mappings":";;;;;;;;;;;;AASA,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AAsBjC,IAAqB,kBAArB,MAAqC;AAAA,EACnC,YAAsB,KAAyB;AAAzB;AAAA,EAA0B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhD,MAAgB,qBAAqB;AACnC,QAAI,KAAK,IAAI,aAAa;AACxB,YAAM,OAAO,MAAM,OAAO,SAAS;AACnC,YAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,wBAAwB;AACnE,WAAK,QAAQ,IAAI,iBAAiB;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAiB;AACrB,UAAM,wBAAwB,KAAK,IAAI,OAAO,IAAI,WAAW,CAAC,CAAC;AAC/D,UAAM,SAAS,MAAM,eAAe,QAAa,KAAK,KAAK,qBAAqB;AAEhF,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW;AACT,SAAK,IAAI,UAAU,UAAU,mBAAmB,OAAO,aAAa;AAClE,YAAM,SAAS,MAAM,KAAK,eAAe;AACzC,YAAM,UAAU,MAAM,SAAS,KAAK,SAAS;AAC7C,aAAO,IAAI,kBAAkB,QAAQ,OAAO;AAAA,IAC9C,CAAC;AAED,SAAK,IAAI,UAAU,UAAU,mBAAmB,YAAY;AAC1D,YAAM,SAAS,MAAM,KAAK,eAAe;AACzC,aAAO,IAAI,kBAAkB,MAAM;AAAA,IACrC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO;AACX,UAAM,KAAK,mBAAmB;AAAA,EAChC;AACF;","names":[]}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {
|
|
2
|
+
debug_default
|
|
3
|
+
} from "./chunk-5ECC6OWF.js";
|
|
4
|
+
import "./chunk-PZ5AY32C.js";
|
|
5
|
+
|
|
6
|
+
// src/stores/redis.ts
|
|
7
|
+
import string from "@poppinss/utils/string";
|
|
8
|
+
import { MessageBuilder } from "@adonisjs/core/helpers";
|
|
9
|
+
var RedisStore = class {
|
|
10
|
+
#connection;
|
|
11
|
+
#ttlSeconds;
|
|
12
|
+
constructor(connection, age) {
|
|
13
|
+
this.#connection = connection;
|
|
14
|
+
this.#ttlSeconds = string.seconds.parse(age);
|
|
15
|
+
debug_default("initiating redis store");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns the key for a user's tag set (stores session IDs for a user)
|
|
19
|
+
*/
|
|
20
|
+
#getTagKey(userId) {
|
|
21
|
+
return `session_tag:${userId}`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Verify contents with the session id and return them as an object. The verify
|
|
25
|
+
* method can fail when the contents is not JSON
|
|
26
|
+
*/
|
|
27
|
+
#parseSessionData(contents, sessionId) {
|
|
28
|
+
try {
|
|
29
|
+
return new MessageBuilder().verify(contents, sessionId);
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Returns session data
|
|
36
|
+
*/
|
|
37
|
+
async read(sessionId) {
|
|
38
|
+
debug_default("redis store: reading session data %s", sessionId);
|
|
39
|
+
const contents = await this.#connection.get(sessionId);
|
|
40
|
+
if (!contents) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
return this.#parseSessionData(contents, sessionId);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Write session values to redis
|
|
47
|
+
*/
|
|
48
|
+
async write(sessionId, values) {
|
|
49
|
+
debug_default("redis store: writing session data %s, %O", sessionId, values);
|
|
50
|
+
const message = new MessageBuilder().build(values, void 0, sessionId);
|
|
51
|
+
await this.#connection.setex(sessionId, this.#ttlSeconds, message);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Cleanup session by removing it
|
|
55
|
+
*/
|
|
56
|
+
async destroy(sessionId) {
|
|
57
|
+
debug_default("redis store: destroying session data %s", sessionId);
|
|
58
|
+
await this.#connection.del(sessionId);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Updates the value expiry
|
|
62
|
+
*/
|
|
63
|
+
async touch(sessionId) {
|
|
64
|
+
debug_default("redis store: touching session data %s", sessionId);
|
|
65
|
+
await this.#connection.expire(sessionId, this.#ttlSeconds);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Tag a session with a user ID
|
|
69
|
+
*/
|
|
70
|
+
async tag(sessionId, userId) {
|
|
71
|
+
debug_default("redis store: tagging session %s with user %s", sessionId, userId);
|
|
72
|
+
await this.#connection.sadd(this.#getTagKey(userId), sessionId);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Processes a single session result from the pipeline
|
|
76
|
+
*/
|
|
77
|
+
#processSessionResult(options) {
|
|
78
|
+
if (!options.contents) return { session: null, isInvalid: true };
|
|
79
|
+
const data = this.#parseSessionData(options.contents, options.sessionId);
|
|
80
|
+
if (!data) return { session: null, isInvalid: true };
|
|
81
|
+
return { session: { id: options.sessionId, data }, isInvalid: false };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Fetches session contents for multiple session IDs using a pipeline
|
|
85
|
+
*/
|
|
86
|
+
async #fetchSessionContents(sessionIds) {
|
|
87
|
+
const pipeline = this.#connection.pipeline();
|
|
88
|
+
sessionIds.forEach((sessionId) => pipeline.get(sessionId));
|
|
89
|
+
const results = await pipeline.exec();
|
|
90
|
+
return results?.map((result) => result[1]) ?? [];
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Removes invalid session IDs from the user's tag set
|
|
94
|
+
*/
|
|
95
|
+
async #cleanupInvalidSessions(userId, invalidSessionIds) {
|
|
96
|
+
if (invalidSessionIds.length === 0) return;
|
|
97
|
+
await this.#connection.srem(this.#getTagKey(userId), ...invalidSessionIds);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get all sessions for a given user ID (tag)
|
|
101
|
+
*/
|
|
102
|
+
async tagged(userId) {
|
|
103
|
+
debug_default("redis store: getting sessions tagged with user %s", userId);
|
|
104
|
+
const sessionIds = await this.#connection.smembers(this.#getTagKey(userId));
|
|
105
|
+
if (sessionIds.length === 0) return [];
|
|
106
|
+
const contents = await this.#fetchSessionContents(sessionIds);
|
|
107
|
+
const results = sessionIds.map(
|
|
108
|
+
(sessionId, index) => this.#processSessionResult({ sessionId, contents: contents[index] })
|
|
109
|
+
);
|
|
110
|
+
const validSessions = results.filter((r) => r.session !== null).map((r) => r.session);
|
|
111
|
+
const invalidSessionIds = results.map((result, index) => result.isInvalid ? sessionIds[index] : null).filter((id) => id !== null);
|
|
112
|
+
await this.#cleanupInvalidSessions(userId, invalidSessionIds);
|
|
113
|
+
return validSessions;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
export {
|
|
117
|
+
RedisStore
|
|
118
|
+
};
|
|
119
|
+
//# sourceMappingURL=redis-YGX2CNE2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/stores/redis.ts"],"sourcesContent":["/**\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport string from '@poppinss/utils/string'\nimport { MessageBuilder } from '@adonisjs/core/helpers'\nimport type { Connection } from '@adonisjs/redis/types'\n\nimport debug from '../debug.js'\nimport type { SessionStoreWithTaggingContract, SessionData, TaggedSession } from '../types.js'\n\n/**\n * Redis store to read/write session to Redis\n */\nexport class RedisStore implements SessionStoreWithTaggingContract {\n #connection: Connection\n #ttlSeconds: number\n\n constructor(connection: Connection, age: string | number) {\n this.#connection = connection\n this.#ttlSeconds = string.seconds.parse(age)\n debug('initiating redis store')\n }\n\n /**\n * Returns the key for a user's tag set (stores session IDs for a user)\n */\n #getTagKey(userId: string): string {\n return `session_tag:${userId}`\n }\n\n /**\n * Verify contents with the session id and return them as an object. The verify\n * method can fail when the contents is not JSON\n */\n #parseSessionData(contents: string, sessionId: string): SessionData | null {\n try {\n return new MessageBuilder().verify<SessionData>(contents, sessionId)\n } catch {\n return null\n }\n }\n\n /**\n * Returns session data\n */\n async read(sessionId: string): Promise<SessionData | null> {\n debug('redis store: reading session data %s', sessionId)\n\n const contents = await this.#connection.get(sessionId)\n if (!contents) {\n return null\n }\n\n return this.#parseSessionData(contents, sessionId)\n }\n\n /**\n * Write session values to redis\n */\n async write(sessionId: string, values: Record<string, any>): Promise<void> {\n debug('redis store: writing session data %s, %O', sessionId, values)\n\n const message = new MessageBuilder().build(values, undefined, sessionId)\n await this.#connection.setex(sessionId, this.#ttlSeconds, message)\n }\n\n /**\n * Cleanup session by removing it\n */\n async destroy(sessionId: string): Promise<void> {\n debug('redis store: destroying session data %s', sessionId)\n await this.#connection.del(sessionId)\n }\n\n /**\n * Updates the value expiry\n */\n async touch(sessionId: string): Promise<void> {\n debug('redis store: touching session data %s', sessionId)\n await this.#connection.expire(sessionId, this.#ttlSeconds)\n }\n\n /**\n * Tag a session with a user ID\n */\n async tag(sessionId: string, userId: string): Promise<void> {\n debug('redis store: tagging session %s with user %s', sessionId, userId)\n await this.#connection.sadd(this.#getTagKey(userId), sessionId)\n }\n\n /**\n * Processes a single session result from the pipeline\n */\n #processSessionResult(options: { sessionId: string; contents: string | null }): {\n session: TaggedSession | null\n isInvalid: boolean\n } {\n if (!options.contents) return { session: null, isInvalid: true }\n\n const data = this.#parseSessionData(options.contents, options.sessionId)\n if (!data) return { session: null, isInvalid: true }\n\n return { session: { id: options.sessionId, data }, isInvalid: false }\n }\n\n /**\n * Fetches session contents for multiple session IDs using a pipeline\n */\n async #fetchSessionContents(sessionIds: string[]): Promise<Array<string | null>> {\n const pipeline = this.#connection.pipeline()\n sessionIds.forEach((sessionId) => pipeline.get(sessionId))\n const results = await pipeline.exec()\n\n return results?.map((result) => result[1] as string | null) ?? []\n }\n\n /**\n * Removes invalid session IDs from the user's tag set\n */\n async #cleanupInvalidSessions(userId: string, invalidSessionIds: string[]): Promise<void> {\n if (invalidSessionIds.length === 0) return\n\n await this.#connection.srem(this.#getTagKey(userId), ...invalidSessionIds)\n }\n\n /**\n * Get all sessions for a given user ID (tag)\n */\n async tagged(userId: string): Promise<TaggedSession[]> {\n debug('redis store: getting sessions tagged with user %s', userId)\n\n const sessionIds = await this.#connection.smembers(this.#getTagKey(userId))\n if (sessionIds.length === 0) return []\n\n const contents = await this.#fetchSessionContents(sessionIds)\n\n const results = sessionIds.map((sessionId, index) =>\n this.#processSessionResult({ sessionId, contents: contents[index] })\n )\n\n const validSessions = results.filter((r) => r.session !== null).map((r) => r.session!)\n const invalidSessionIds = results\n .map((result, index) => (result.isInvalid ? sessionIds[index] : null))\n .filter((id) => id !== null)\n\n await this.#cleanupInvalidSessions(userId, invalidSessionIds)\n\n return validSessions\n }\n}\n"],"mappings":"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","names":[]}
|
package/build/src/errors.d.ts
CHANGED
|
@@ -6,3 +6,8 @@ export declare const E_SESSION_NOT_MUTABLE: new (args?: any, options?: ErrorOpti
|
|
|
6
6
|
* Raised when session store has been initiated
|
|
7
7
|
*/
|
|
8
8
|
export declare const E_SESSION_NOT_READY: new (args?: any, options?: ErrorOptions) => import("@poppinss/utils").Exception;
|
|
9
|
+
/**
|
|
10
|
+
* Raised when trying to use tagging with a store that
|
|
11
|
+
* doesn't support tagging operations
|
|
12
|
+
*/
|
|
13
|
+
export declare const E_SESSION_TAGGING_NOT_SUPPORTED: new (args?: any, options?: ErrorOptions) => import("@poppinss/utils").Exception;
|
package/build/src/session.d.ts
CHANGED
|
@@ -162,6 +162,14 @@ export declare class Session extends Macroable {
|
|
|
162
162
|
* Re-generate the session id and migrate data to it.
|
|
163
163
|
*/
|
|
164
164
|
regenerate(): void;
|
|
165
|
+
/**
|
|
166
|
+
* Tag the current session with a user ID. This allows you to
|
|
167
|
+
* later retrieve all sessions for a given user via SessionCollection.
|
|
168
|
+
*
|
|
169
|
+
* Only Memory, Redis and Database stores support tagging. Other stores
|
|
170
|
+
* will throw an error.
|
|
171
|
+
*/
|
|
172
|
+
tag(userId: string): Promise<void>;
|
|
165
173
|
/**
|
|
166
174
|
* Commit session changes. No more mutations will be
|
|
167
175
|
* allowed after commit.
|
|
@@ -0,0 +1,55 @@
|
|
|
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 type { ResolvedSessionConfig, SessionData, TaggedSession } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* SessionCollection provides APIs for programmatic session
|
|
12
|
+
* management. It allows reading, destroying, and tagging
|
|
13
|
+
* sessions without an HTTP context.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import app from '@adonisjs/core/services/app'
|
|
18
|
+
* import { SessionCollection } from '@adonisjs/session'
|
|
19
|
+
*
|
|
20
|
+
* const sessionCollection = await app.container.make(SessionCollection)
|
|
21
|
+
*
|
|
22
|
+
* // List all sessions for a user
|
|
23
|
+
* const sessions = await sessionCollection.tagged(String(user.id))
|
|
24
|
+
*
|
|
25
|
+
* // Destroy a specific session
|
|
26
|
+
* await sessionCollection.destroy(sessionId)
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class SessionCollection {
|
|
30
|
+
#private;
|
|
31
|
+
constructor(config: ResolvedSessionConfig);
|
|
32
|
+
/**
|
|
33
|
+
* Check if the current store supports tagging
|
|
34
|
+
*/
|
|
35
|
+
supportsTagging(): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Returns the session data for the given session ID,
|
|
38
|
+
* or null if the session does not exist
|
|
39
|
+
*/
|
|
40
|
+
get(sessionId: string): Promise<SessionData | null>;
|
|
41
|
+
/**
|
|
42
|
+
* Destroys a session by its ID
|
|
43
|
+
*/
|
|
44
|
+
destroy(sessionId: string): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Tag a session with a user ID.
|
|
47
|
+
* Only supported by Memory, Redis and Database stores.
|
|
48
|
+
*/
|
|
49
|
+
tag(sessionId: string, userId: string): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Get all sessions for a given user ID (tag).
|
|
52
|
+
* Only supported by Memory, Redis and Database stores.
|
|
53
|
+
*/
|
|
54
|
+
tagged(userId: string): Promise<TaggedSession[]>;
|
|
55
|
+
}
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
* file that was distributed with this source code.
|
|
8
8
|
*/
|
|
9
9
|
import type { QueryClientContract } from '@adonisjs/lucid/types/database';
|
|
10
|
-
import type {
|
|
10
|
+
import type { SessionStoreWithTaggingContract, SessionData, TaggedSession } from '../types.js';
|
|
11
11
|
/**
|
|
12
12
|
* Database store to read/write session to SQL databases using Lucid
|
|
13
13
|
*/
|
|
14
|
-
export declare class DatabaseStore implements
|
|
14
|
+
export declare class DatabaseStore implements SessionStoreWithTaggingContract {
|
|
15
15
|
#private;
|
|
16
16
|
constructor(client: QueryClientContract, age: string | number, options?: {
|
|
17
17
|
/**
|
|
@@ -44,4 +44,12 @@ export declare class DatabaseStore implements SessionStoreContract {
|
|
|
44
44
|
* Updates the session expiry
|
|
45
45
|
*/
|
|
46
46
|
touch(sessionId: string): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Tag a session with a user ID
|
|
49
|
+
*/
|
|
50
|
+
tag(sessionId: string, userId: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Get all sessions for a given user ID (tag)
|
|
53
|
+
*/
|
|
54
|
+
tagged(userId: string): Promise<TaggedSession[]>;
|
|
47
55
|
}
|
|
@@ -6,12 +6,16 @@
|
|
|
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 type { SessionData,
|
|
9
|
+
import type { SessionData, SessionStoreWithTaggingContract, TaggedSession } from '../types.js';
|
|
10
10
|
/**
|
|
11
11
|
* Memory store is meant to be used for writing tests.
|
|
12
12
|
*/
|
|
13
|
-
export declare class MemoryStore implements
|
|
13
|
+
export declare class MemoryStore implements SessionStoreWithTaggingContract {
|
|
14
14
|
static sessions: Map<string, SessionData>;
|
|
15
|
+
/**
|
|
16
|
+
* Maps session IDs to user IDs (for tagging)
|
|
17
|
+
*/
|
|
18
|
+
static tags: Map<string, string>;
|
|
15
19
|
/**
|
|
16
20
|
* Read session id value from the memory
|
|
17
21
|
*/
|
|
@@ -25,4 +29,12 @@ export declare class MemoryStore implements SessionStoreContract {
|
|
|
25
29
|
*/
|
|
26
30
|
destroy(sessionId: string): void;
|
|
27
31
|
touch(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Tag a session with a user ID
|
|
34
|
+
*/
|
|
35
|
+
tag(sessionId: string, userId: string): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Get all sessions for a given user ID (tag)
|
|
38
|
+
*/
|
|
39
|
+
tagged(userId: string): Promise<TaggedSession[]>;
|
|
28
40
|
}
|
|
@@ -7,28 +7,35 @@
|
|
|
7
7
|
* file that was distributed with this source code.
|
|
8
8
|
*/
|
|
9
9
|
import type { Connection } from '@adonisjs/redis/types';
|
|
10
|
-
import type {
|
|
10
|
+
import type { SessionStoreWithTaggingContract, SessionData, TaggedSession } from '../types.js';
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* Redis store to read/write session to Redis
|
|
13
13
|
*/
|
|
14
|
-
export declare class RedisStore implements
|
|
14
|
+
export declare class RedisStore implements SessionStoreWithTaggingContract {
|
|
15
15
|
#private;
|
|
16
16
|
constructor(connection: Connection, age: string | number);
|
|
17
17
|
/**
|
|
18
|
-
* Returns
|
|
19
|
-
* missing.
|
|
18
|
+
* Returns session data
|
|
20
19
|
*/
|
|
21
20
|
read(sessionId: string): Promise<SessionData | null>;
|
|
22
21
|
/**
|
|
23
|
-
* Write session values to
|
|
22
|
+
* Write session values to redis
|
|
24
23
|
*/
|
|
25
|
-
write(sessionId: string, values:
|
|
24
|
+
write(sessionId: string, values: Record<string, any>): Promise<void>;
|
|
26
25
|
/**
|
|
27
|
-
* Cleanup session
|
|
26
|
+
* Cleanup session by removing it
|
|
28
27
|
*/
|
|
29
28
|
destroy(sessionId: string): Promise<void>;
|
|
30
29
|
/**
|
|
31
30
|
* Updates the value expiry
|
|
32
31
|
*/
|
|
33
32
|
touch(sessionId: string): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Tag a session with a user ID
|
|
35
|
+
*/
|
|
36
|
+
tag(sessionId: string, userId: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Get all sessions for a given user ID (tag)
|
|
39
|
+
*/
|
|
40
|
+
tagged(userId: string): Promise<TaggedSession[]>;
|
|
34
41
|
}
|
package/build/src/types.d.ts
CHANGED
|
@@ -7,6 +7,13 @@ import type { DynamoDBClient, DynamoDBClientConfig } from '@aws-sdk/client-dynam
|
|
|
7
7
|
*/
|
|
8
8
|
export type AllowedSessionValues = string | boolean | number | object | Date | Array<any>;
|
|
9
9
|
export type SessionData = Record<string, AllowedSessionValues>;
|
|
10
|
+
/**
|
|
11
|
+
* Represents a tagged session with its ID and data
|
|
12
|
+
*/
|
|
13
|
+
export interface TaggedSession {
|
|
14
|
+
id: string;
|
|
15
|
+
data: SessionData;
|
|
16
|
+
}
|
|
10
17
|
/**
|
|
11
18
|
* Session stores must implement the session store contract.
|
|
12
19
|
*/
|
|
@@ -32,6 +39,20 @@ export interface SessionStoreContract {
|
|
|
32
39
|
*/
|
|
33
40
|
touch(sessionId: string): Promise<void> | void;
|
|
34
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Extended interface for stores that support tagging sessions
|
|
44
|
+
* (linking sessions to user IDs for example)
|
|
45
|
+
*/
|
|
46
|
+
export interface SessionStoreWithTaggingContract extends SessionStoreContract {
|
|
47
|
+
/**
|
|
48
|
+
* Tag a session with a user ID
|
|
49
|
+
*/
|
|
50
|
+
tag(sessionId: string, userId: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Get all sessions for a given user ID (tag)
|
|
53
|
+
*/
|
|
54
|
+
tagged(userId: string): Promise<TaggedSession[]>;
|
|
55
|
+
}
|
|
35
56
|
/**
|
|
36
57
|
* Base configuration for managing sessions without
|
|
37
58
|
* stores.
|
|
@@ -113,3 +134,10 @@ export interface DatabaseStoreConfig {
|
|
|
113
134
|
* Factory function to instantiate session store
|
|
114
135
|
*/
|
|
115
136
|
export type SessionStoreFactory = (ctx: HttpContext, sessionConfig: SessionConfig) => SessionStoreContract;
|
|
137
|
+
/**
|
|
138
|
+
* Resolved session config after processing by defineConfig
|
|
139
|
+
*/
|
|
140
|
+
export interface ResolvedSessionConfig extends SessionConfig {
|
|
141
|
+
store: string;
|
|
142
|
+
stores: Record<string, SessionStoreFactory>;
|
|
143
|
+
}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/session.ts"],"sourcesContent":["/*\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport { createError } from '@poppinss/utils'\n\n/**\n * Raised when session store is not mutable\n */\nexport const E_SESSION_NOT_MUTABLE = createError(\n 'Session store is in readonly mode and cannot be mutated',\n 'E_SESSION_NOT_MUTABLE',\n 500\n)\n\n/**\n * Raised when session store has been initiated\n */\nexport const E_SESSION_NOT_READY = createError(\n 'Session store has not been initiated. Make sure you have registered the session middleware',\n 'E_SESSION_NOT_READY',\n 500\n)\n","/*\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport type { I18n } from '@adonisjs/i18n'\nimport Macroable from '@poppinss/macroable'\nimport lodash from '@poppinss/utils/lodash'\nimport { cuid } from '@adonisjs/core/helpers'\nimport type { HttpContext } from '@adonisjs/core/http'\nimport type { EmitterService } from '@adonisjs/core/types'\nimport type { HttpError } from '@adonisjs/core/types/http'\n\nimport debug from './debug.js'\nimport * as errors from './errors.js'\nimport { ReadOnlyValuesStore, ValuesStore } from './values_store.js'\nimport type {\n SessionData,\n SessionConfig,\n SessionStoreFactory,\n AllowedSessionValues,\n SessionStoreContract,\n} from './types.js'\n\n/**\n * The session class exposes the API to read and write values to\n * the session store.\n *\n * A session instance is isolated between requests but\n * uses a centralized persistence store and\n */\nexport class Session extends Macroable {\n #store: SessionStoreContract\n #emitter: EmitterService\n #ctx: HttpContext\n #readonly: boolean = false\n\n /**\n * Session values store\n */\n #valuesStore?: ValuesStore\n\n /**\n * Session id refers to the session id that will be committed\n * as a cookie during the response.\n */\n #sessionId: string\n\n /**\n * Session id from cookie refers to the value we read from the\n * cookie during the HTTP request.\n *\n * This only might not exist during the first request. Also during\n * session id re-generation, this value will be different from\n * the session id.\n */\n #sessionIdFromCookie?: string\n\n /**\n * Store of flash messages that be written during the\n * HTTP request\n */\n responseFlashMessages = new ValuesStore({})\n\n /**\n * Store of flash messages for the current HTTP request.\n */\n flashMessages = new ValuesStore({})\n\n /**\n * The key to use for storing flash messages inside\n * the session store.\n */\n flashKey: string = '__flash__'\n\n /**\n * Session id for the current HTTP request\n */\n get sessionId() {\n return this.#sessionId\n }\n\n /**\n * A boolean to know if a fresh session is created during\n * the request\n */\n get fresh(): boolean {\n return this.#sessionIdFromCookie === undefined\n }\n\n /**\n * A boolean to know if session is in readonly\n * state\n */\n get readonly() {\n return this.#readonly\n }\n\n /**\n * A boolean to know if session store has been initiated\n */\n get initiated() {\n return !!this.#valuesStore\n }\n\n /**\n * A boolean to know if the session id has been re-generated\n * during the current request\n */\n get hasRegeneratedSession() {\n return !!(this.#sessionIdFromCookie && this.#sessionIdFromCookie !== this.#sessionId)\n }\n\n /**\n * A boolean to know if the session store is empty\n */\n get isEmpty() {\n return this.#valuesStore?.isEmpty ?? true\n }\n\n /**\n * A boolean to know if the session store has been\n * modified\n */\n get hasBeenModified() {\n return this.#valuesStore?.hasBeenModified ?? false\n }\n\n constructor(\n public config: SessionConfig,\n storeFactory: SessionStoreFactory,\n emitter: EmitterService,\n ctx: HttpContext\n ) {\n super()\n this.#ctx = ctx\n this.#emitter = emitter\n this.#store = storeFactory(ctx, config)\n this.#sessionIdFromCookie = ctx.request.cookie(config.cookieName, undefined)\n this.#sessionId = this.#sessionIdFromCookie || cuid()\n }\n\n /**\n * Returns the flash messages store for a given\n * mode\n */\n #getFlashStore(mode: 'write' | 'read'): ValuesStore {\n if (!this.#valuesStore) {\n throw new errors.E_SESSION_NOT_READY()\n }\n\n if (mode === 'write' && this.readonly) {\n throw new errors.E_SESSION_NOT_MUTABLE()\n }\n\n return this.responseFlashMessages\n }\n\n /**\n * Returns the store instance for a given mode\n */\n #getValuesStore(mode: 'write' | 'read'): ValuesStore {\n if (!this.#valuesStore) {\n throw new errors.E_SESSION_NOT_READY()\n }\n\n if (mode === 'write' && this.readonly) {\n throw new errors.E_SESSION_NOT_MUTABLE()\n }\n\n return this.#valuesStore\n }\n\n /**\n * Initiates the session store. The method results in a noop\n * when called multiple times\n */\n async initiate(readonly: boolean): Promise<void> {\n if (this.#valuesStore) {\n return\n }\n\n debug('initiating session (readonly: %s)', readonly)\n\n this.#readonly = readonly\n const contents = await this.#store.read(this.#sessionId)\n this.#valuesStore = new ValuesStore(contents)\n\n /**\n * Extract flash messages from the store and keep a local\n * copy of it.\n */\n if (this.has(this.flashKey)) {\n debug('reading flash data')\n if (this.#readonly) {\n this.flashMessages.update(this.get(this.flashKey, null))\n } else {\n this.flashMessages.update(this.pull(this.flashKey, null))\n }\n }\n\n /**\n * Share session with the templates. We assume the view property\n * is a reference to edge templates\n */\n if ('view' in this.#ctx) {\n this.#ctx.view.share({\n session: new ReadOnlyValuesStore(this.#valuesStore.all()),\n flashMessages: new ReadOnlyValuesStore(this.flashMessages.all()),\n old: function (key: string, defaultValue?: any) {\n return this.flashMessages.get(key, defaultValue)\n },\n })\n }\n\n this.#emitter.emit('session:initiated', { session: this })\n }\n\n /**\n * Put a key-value pair to the session data store\n */\n put(key: string, value: AllowedSessionValues) {\n this.#getValuesStore('write').set(key, value)\n }\n\n /**\n * Check if a key exists inside the datastore\n */\n has(key: string): boolean {\n return this.#getValuesStore('read').has(key)\n }\n\n /**\n * Get the value of a key from the session datastore.\n * You can specify a default value to use, when key\n * does not exists or has undefined value.\n */\n get(key: string, defaultValue?: any) {\n return this.#getValuesStore('read').get(key, defaultValue)\n }\n\n /**\n * Get everything from the session store\n */\n all() {\n return this.#getValuesStore('read').all()\n }\n\n /**\n * Remove a key from the session datastore\n */\n forget(key: string) {\n return this.#getValuesStore('write').unset(key)\n }\n\n /**\n * Read value for a key from the session datastore\n * and remove it simultaneously.\n */\n pull(key: string, defaultValue?: any) {\n return this.#getValuesStore('write').pull(key, defaultValue)\n }\n\n /**\n * Increment the value of a key inside the session\n * store.\n *\n * A new key will be defined if does not exists already.\n * The value of a new key will be 1\n */\n increment(key: string, steps: number = 1) {\n return this.#getValuesStore('write').increment(key, steps)\n }\n\n /**\n * Increment the value of a key inside the session\n * store.\n *\n * A new key will be defined if does not exists already.\n * The value of a new key will be -1\n */\n decrement(key: string, steps: number = 1) {\n return this.#getValuesStore('write').decrement(key, steps)\n }\n\n /**\n * Empty the session store\n */\n clear() {\n return this.#getValuesStore('write').clear()\n }\n\n /**\n * Add a key-value pair to flash messages\n */\n flash(key: string, value: AllowedSessionValues): void\n flash(keyValue: SessionData): void\n flash(key: string | SessionData, value?: AllowedSessionValues): void {\n if (typeof key === 'string') {\n if (value) {\n this.#getFlashStore('write').set(key, value)\n }\n } else {\n this.#getFlashStore('write').merge(key)\n }\n }\n\n /**\n * Flash errors to the errorsBag. You can read these\n * errors via the \"@error\" tag.\n *\n * Appends new messages to the existing collection.\n */\n flashErrors(errorsCollection: Record<string, string | string[]>) {\n this.flash({ errorsBag: errorsCollection })\n }\n\n /**\n * Flash validation error messages. Make sure the error\n * is an instance of VineJS ValidationException.\n *\n * Overrides existing inputErrors\n */\n flashValidationErrors(error: HttpError) {\n const errorsBag = error.messages.reduce((result: Record<string, string[]>, message: any) => {\n if (result[message.field]) {\n result[message.field].push(message.message)\n } else {\n result[message.field] = [message.message]\n }\n return result\n }, {})\n\n this.flashExcept(['_csrf', '_method', 'password', 'password_confirmation'])\n\n /**\n * Adding the error summary to the \"errorsBag\" so that\n * we display the validation error globally using\n * the \"@error\" tag.\n */\n let summary = 'The form could not be saved. Please check the errors below.'\n if ('i18n' in this.#ctx) {\n summary = (this.#ctx.i18n as I18n).t(\n `errors.${error.code}`,\n {\n count: error.messages.length,\n },\n summary\n )\n }\n\n this.flashErrors({\n [String(error.code)]: summary,\n })\n\n /**\n * Adding to inputErrorsBag for \"@inputError\" tag\n * to read validation errors\n */\n this.flash('inputErrorsBag', errorsBag)\n\n /**\n * For legacy support and not to break apps using\n * the older version of @adonisjs/session package\n */\n this.flash('errors', errorsBag)\n }\n\n /**\n * Flash form input data to the flash messages store\n */\n flashAll() {\n return this.#getFlashStore('write').set('input', this.#ctx.request.original())\n }\n\n /**\n * Flash form input data (except some keys) to the flash messages store\n */\n flashExcept(keys: string[]): void {\n this.#getFlashStore('write').set('input', lodash.omit(this.#ctx.request.original(), keys))\n }\n\n /**\n * Flash form input data (only some keys) to the flash messages store\n */\n flashOnly(keys: string[]): void {\n this.#getFlashStore('write').set('input', lodash.pick(this.#ctx.request.original(), keys))\n }\n\n /**\n * Reflash messages from the last request in the current response\n */\n reflash(): void {\n this.#getFlashStore('write').set('reflashed', this.flashMessages.all())\n }\n\n /**\n * Reflash messages (only some keys) from the last\n * request in the current response\n */\n reflashOnly(keys: string[]) {\n this.#getFlashStore('write').set('reflashed', lodash.pick(this.flashMessages.all(), keys))\n }\n\n /**\n * Reflash messages (except some keys) from the last\n * request in the current response\n */\n reflashExcept(keys: string[]) {\n this.#getFlashStore('write').set('reflashed', lodash.omit(this.flashMessages.all(), keys))\n }\n\n /**\n * Re-generate the session id and migrate data to it.\n */\n regenerate() {\n this.#sessionId = cuid()\n }\n\n /**\n * Commit session changes. No more mutations will be\n * allowed after commit.\n */\n async commit() {\n if (!this.#valuesStore || this.readonly) {\n return\n }\n\n /**\n * If the flash messages store is not empty, we should put\n * its messages inside main session store.\n */\n if (!this.responseFlashMessages.isEmpty) {\n const { input, reflashed, ...others } = this.responseFlashMessages.all()\n this.put(this.flashKey, { ...reflashed, ...input, ...others })\n }\n\n debug('committing session data')\n\n /**\n * Touch the session id cookie to stay alive\n */\n this.#ctx.response.cookie(this.config.cookieName, this.#sessionId, this.config.cookie!)\n\n /**\n * Delete the session data when the session store\n * is empty.\n *\n * Also we only destroy the session id we read from the cookie.\n * If there was no session id in the cookie, there won't be\n * any data inside the store either.\n */\n if (this.isEmpty) {\n if (this.#sessionIdFromCookie) {\n await this.#store.destroy(this.#sessionIdFromCookie)\n }\n this.#emitter.emit('session:committed', { session: this })\n return\n }\n\n /**\n * Touch the store expiry when the session store was\n * not modified.\n */\n if (!this.hasBeenModified) {\n if (this.#sessionIdFromCookie && this.#sessionIdFromCookie !== this.#sessionId) {\n await this.#store.destroy(this.#sessionIdFromCookie)\n await this.#store.write(this.#sessionId, this.#valuesStore.toJSON())\n this.#emitter.emit('session:migrated', {\n fromSessionId: this.#sessionIdFromCookie,\n toSessionId: this.sessionId,\n session: this,\n })\n } else {\n await this.#store.touch(this.#sessionId)\n }\n this.#emitter.emit('session:committed', { session: this })\n return\n }\n\n /**\n * Otherwise commit to the session store\n */\n if (this.#sessionIdFromCookie && this.#sessionIdFromCookie !== this.#sessionId) {\n await this.#store.destroy(this.#sessionIdFromCookie)\n await this.#store.write(this.#sessionId, this.#valuesStore.toJSON())\n this.#emitter.emit('session:migrated', {\n fromSessionId: this.#sessionIdFromCookie,\n toSessionId: this.sessionId,\n session: this,\n })\n } else {\n await this.#store.write(this.#sessionId, this.#valuesStore.toJSON())\n }\n\n this.#emitter.emit('session:committed', { session: this })\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/stores/database.ts"],"sourcesContent":["/**\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport string from '@poppinss/utils/string'\nimport { MessageBuilder } from '@adonisjs/core/helpers'\nimport type { QueryClientContract } from '@adonisjs/lucid/types/database'\n\nimport debug from '../debug.js'\nimport type { SessionStoreContract, SessionData } from '../types.js'\n\n/**\n * Database store to read/write session to SQL databases using Lucid\n */\nexport class DatabaseStore implements SessionStoreContract {\n #client: QueryClientContract\n #tableName: string\n #ttlSeconds: number\n #gcProbability: number\n\n constructor(\n client: QueryClientContract,\n age: string | number,\n options?: {\n /**\n * Defaults to \"sessions\"\n */\n tableName?: string\n\n /**\n * The probability (in percent) that garbage collection will be\n * triggered on any given request. For example, 2 means 2% chance.\n *\n * Set to 0 to disable garbage collection.\n *\n * Defaults to 2 (2% chance)\n */\n gcProbability?: number\n }\n ) {\n this.#client = client\n this.#tableName = options?.tableName ?? 'sessions'\n this.#ttlSeconds = string.seconds.parse(age)\n this.#gcProbability = options?.gcProbability ?? 2\n debug('initiating database store')\n }\n\n /**\n * Run garbage collection to delete expired sessions.\n * This is called based on gcProbability after writing session data.\n */\n async #collectGarbage(): Promise<void> {\n if (this.#gcProbability <= 0) {\n return\n }\n\n const random = Math.random() * 100\n if (random < this.#gcProbability) {\n debug('database store: running garbage collection')\n const expiredBefore = new Date(Date.now())\n await this.#client.from(this.#tableName).where('expires_at', '<=', expiredBefore).delete()\n }\n }\n\n /**\n * Returns session data\n */\n async read(sessionId: string): Promise<SessionData | null> {\n debug('database store: reading session data %s', sessionId)\n\n const row = await this.#client.from(this.#tableName).where('id', sessionId).first()\n\n if (!row) {\n return null\n }\n\n /**\n * Check if the session has expired. If so, delete it and return null.\n */\n const expiresAt = new Date(row.expires_at).getTime()\n if (Date.now() > expiresAt) {\n await this.destroy(sessionId)\n return null\n }\n\n /**\n * Verify contents with the session id and return them as an object\n */\n try {\n return new MessageBuilder().verify<SessionData>(row.data, sessionId)\n } catch {\n return null\n }\n }\n\n /**\n * Write session values to the database\n */\n async write(sessionId: string, values: Object): Promise<void> {\n debug('database store: writing session data %s, %O', sessionId, values)\n\n const message = new MessageBuilder().build(values, undefined, sessionId)\n const expiresAt = new Date(Date.now() + this.#ttlSeconds * 1000)\n\n await this.#client\n .insertQuery()\n .table(this.#tableName)\n .insert({\n id: sessionId,\n data: message,\n expires_at: expiresAt,\n })\n .knexQuery.onConflict('id')\n .merge(['data', 'expires_at'])\n\n await this.#collectGarbage()\n }\n\n /**\n * Cleanup session by removing it\n */\n async destroy(sessionId: string): Promise<void> {\n debug('database store: destroying session data %s', sessionId)\n\n await this.#client.from(this.#tableName).where('id', sessionId).delete()\n }\n\n /**\n * Updates the session expiry\n */\n async touch(sessionId: string): Promise<void> {\n debug('database store: touching session data %s', sessionId)\n\n const expiresAt = new Date(Date.now() + this.#ttlSeconds * 1000)\n\n await this.#client\n .from(this.#tableName)\n .where('id', sessionId)\n .update({ expires_at: expiresAt })\n }\n}\n"],"mappings":";;;;;;AASA,OAAO,YAAY;AACnB,SAAS,sBAAsB;AASxB,IAAM,gBAAN,MAAoD;AAAA,EACzD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YACE,QACA,KACA,SAgBA;AACA,SAAK,UAAU;AACf,SAAK,aAAa,SAAS,aAAa;AACxC,SAAK,cAAc,OAAO,QAAQ,MAAM,GAAG;AAC3C,SAAK,iBAAiB,SAAS,iBAAiB;AAChD,kBAAM,2BAA2B;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,kBAAiC;AACrC,QAAI,KAAK,kBAAkB,GAAG;AAC5B;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,OAAO,IAAI;AAC/B,QAAI,SAAS,KAAK,gBAAgB;AAChC,oBAAM,4CAA4C;AAClD,YAAM,gBAAgB,IAAI,KAAK,KAAK,IAAI,CAAC;AACzC,YAAM,KAAK,QAAQ,KAAK,KAAK,UAAU,EAAE,MAAM,cAAc,MAAM,aAAa,EAAE,OAAO;AAAA,IAC3F;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,WAAgD;AACzD,kBAAM,2CAA2C,SAAS;AAE1D,UAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,KAAK,UAAU,EAAE,MAAM,MAAM,SAAS,EAAE,MAAM;AAElF,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,IACT;AAKA,UAAM,YAAY,IAAI,KAAK,IAAI,UAAU,EAAE,QAAQ;AACnD,QAAI,KAAK,IAAI,IAAI,WAAW;AAC1B,YAAM,KAAK,QAAQ,SAAS;AAC5B,aAAO;AAAA,IACT;AAKA,QAAI;AACF,aAAO,IAAI,eAAe,EAAE,OAAoB,IAAI,MAAM,SAAS;AAAA,IACrE,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,WAAmB,QAA+B;AAC5D,kBAAM,+CAA+C,WAAW,MAAM;AAEtE,UAAM,UAAU,IAAI,eAAe,EAAE,MAAM,QAAQ,QAAW,SAAS;AACvE,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,cAAc,GAAI;AAE/D,UAAM,KAAK,QACR,YAAY,EACZ,MAAM,KAAK,UAAU,EACrB,OAAO;AAAA,MACN,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,YAAY;AAAA,IACd,CAAC,EACA,UAAU,WAAW,IAAI,EACzB,MAAM,CAAC,QAAQ,YAAY,CAAC;AAE/B,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,WAAkC;AAC9C,kBAAM,8CAA8C,SAAS;AAE7D,UAAM,KAAK,QAAQ,KAAK,KAAK,UAAU,EAAE,MAAM,MAAM,SAAS,EAAE,OAAO;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,WAAkC;AAC5C,kBAAM,4CAA4C,SAAS;AAE3D,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,cAAc,GAAI;AAE/D,UAAM,KAAK,QACR,KAAK,KAAK,UAAU,EACpB,MAAM,MAAM,SAAS,EACrB,OAAO,EAAE,YAAY,UAAU,CAAC;AAAA,EACrC;AACF;","names":[]}
|
package/build/redis-OJU6MUHZ.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
debug_default
|
|
3
|
-
} from "./chunk-5ECC6OWF.js";
|
|
4
|
-
import "./chunk-PZ5AY32C.js";
|
|
5
|
-
|
|
6
|
-
// src/stores/redis.ts
|
|
7
|
-
import string from "@poppinss/utils/string";
|
|
8
|
-
import { MessageBuilder } from "@adonisjs/core/helpers";
|
|
9
|
-
var RedisStore = class {
|
|
10
|
-
#connection;
|
|
11
|
-
#ttlSeconds;
|
|
12
|
-
constructor(connection, age) {
|
|
13
|
-
this.#connection = connection;
|
|
14
|
-
this.#ttlSeconds = string.seconds.parse(age);
|
|
15
|
-
debug_default("initiating redis store");
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Returns file contents. A new file will be created if it's
|
|
19
|
-
* missing.
|
|
20
|
-
*/
|
|
21
|
-
async read(sessionId) {
|
|
22
|
-
debug_default("redis store: reading session data %s", sessionId);
|
|
23
|
-
const contents = await this.#connection.get(sessionId);
|
|
24
|
-
if (!contents) {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
try {
|
|
28
|
-
return new MessageBuilder().verify(contents, sessionId);
|
|
29
|
-
} catch {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Write session values to a file
|
|
35
|
-
*/
|
|
36
|
-
async write(sessionId, values) {
|
|
37
|
-
debug_default("redis store: writing session data %s, %O", sessionId, values);
|
|
38
|
-
const message = new MessageBuilder().build(values, void 0, sessionId);
|
|
39
|
-
await this.#connection.setex(sessionId, this.#ttlSeconds, message);
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Cleanup session file by removing it
|
|
43
|
-
*/
|
|
44
|
-
async destroy(sessionId) {
|
|
45
|
-
debug_default("redis store: destroying session data %s", sessionId);
|
|
46
|
-
await this.#connection.del(sessionId);
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Updates the value expiry
|
|
50
|
-
*/
|
|
51
|
-
async touch(sessionId) {
|
|
52
|
-
debug_default("redis store: touching session data %s", sessionId);
|
|
53
|
-
await this.#connection.expire(sessionId, this.#ttlSeconds);
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
export {
|
|
57
|
-
RedisStore
|
|
58
|
-
};
|
|
59
|
-
//# sourceMappingURL=redis-OJU6MUHZ.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/stores/redis.ts"],"sourcesContent":["/**\n * @adonisjs/session\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport string from '@poppinss/utils/string'\nimport { MessageBuilder } from '@adonisjs/core/helpers'\nimport type { Connection } from '@adonisjs/redis/types'\n\nimport debug from '../debug.js'\nimport type { SessionStoreContract, SessionData } from '../types.js'\n\n/**\n * File store to read/write session to filesystem\n */\nexport class RedisStore implements SessionStoreContract {\n #connection: Connection\n #ttlSeconds: number\n\n constructor(connection: Connection, age: string | number) {\n this.#connection = connection\n this.#ttlSeconds = string.seconds.parse(age)\n debug('initiating redis store')\n }\n\n /**\n * Returns file contents. A new file will be created if it's\n * missing.\n */\n async read(sessionId: string): Promise<SessionData | null> {\n debug('redis store: reading session data %s', sessionId)\n\n const contents = await this.#connection.get(sessionId)\n if (!contents) {\n return null\n }\n\n /**\n * Verify contents with the session id and return them as an object. The verify\n * method can fail when the contents is not JSON>\n */\n try {\n return new MessageBuilder().verify<SessionData>(contents, sessionId)\n } catch {\n return null\n }\n }\n\n /**\n * Write session values to a file\n */\n async write(sessionId: string, values: Object): Promise<void> {\n debug('redis store: writing session data %s, %O', sessionId, values)\n\n const message = new MessageBuilder().build(values, undefined, sessionId)\n await this.#connection.setex(sessionId, this.#ttlSeconds, message)\n }\n\n /**\n * Cleanup session file by removing it\n */\n async destroy(sessionId: string): Promise<void> {\n debug('redis store: destroying session data %s', sessionId)\n await this.#connection.del(sessionId)\n }\n\n /**\n * Updates the value expiry\n */\n async touch(sessionId: string): Promise<void> {\n debug('redis store: touching session data %s', sessionId)\n await this.#connection.expire(sessionId, this.#ttlSeconds)\n }\n}\n"],"mappings":";;;;;;AASA,OAAO,YAAY;AACnB,SAAS,sBAAsB;AASxB,IAAM,aAAN,MAAiD;AAAA,EACtD;AAAA,EACA;AAAA,EAEA,YAAY,YAAwB,KAAsB;AACxD,SAAK,cAAc;AACnB,SAAK,cAAc,OAAO,QAAQ,MAAM,GAAG;AAC3C,kBAAM,wBAAwB;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,KAAK,WAAgD;AACzD,kBAAM,wCAAwC,SAAS;AAEvD,UAAM,WAAW,MAAM,KAAK,YAAY,IAAI,SAAS;AACrD,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,IACT;AAMA,QAAI;AACF,aAAO,IAAI,eAAe,EAAE,OAAoB,UAAU,SAAS;AAAA,IACrE,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,WAAmB,QAA+B;AAC5D,kBAAM,4CAA4C,WAAW,MAAM;AAEnE,UAAM,UAAU,IAAI,eAAe,EAAE,MAAM,QAAQ,QAAW,SAAS;AACvE,UAAM,KAAK,YAAY,MAAM,WAAW,KAAK,aAAa,OAAO;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,WAAkC;AAC9C,kBAAM,2CAA2C,SAAS;AAC1D,UAAM,KAAK,YAAY,IAAI,SAAS;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,WAAkC;AAC5C,kBAAM,yCAAyC,SAAS;AACxD,UAAM,KAAK,YAAY,OAAO,WAAW,KAAK,WAAW;AAAA,EAC3D;AACF;","names":[]}
|
|
File without changes
|