Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
strategy:
matrix:
node-version: [latest]
db: [sqlite, postgres, mysql]
services:
redis:
image: redis
Expand All @@ -25,6 +26,31 @@ jobs:
--health-retries 5
ports:
- 6379:6379
postgres:
image: postgres:16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: session_test
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
mysql:
image: mysql:8
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: session_test
options: >-
--health-cmd "mysqladmin ping -h localhost"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 3306:3306
dynamodb-local:
image: amazon/dynamodb-local
ports:
Expand Down Expand Up @@ -61,6 +87,17 @@ jobs:
env:
REDIS_HOST: 0.0.0.0
REDIS_PORT: 6379
DB_CONNECTION: ${{ matrix.db }}
PG_HOST: 0.0.0.0
PG_PORT: 5432
PG_USER: postgres
PG_PASSWORD: postgres
PG_DATABASE: session_test
MYSQL_HOST: 0.0.0.0
MYSQL_PORT: 3306
MYSQL_USER: root
MYSQL_PASSWORD: root
MYSQL_DATABASE: session_test

test_windows:
runs-on: windows-latest
Expand All @@ -82,3 +119,4 @@ jobs:
env:
NO_REDIS: true
NO_DYNAMODB: true
NO_DATABASE: true
26 changes: 26 additions & 0 deletions commands/make_session_table.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* @adonisjs/session
*
* (c) AdonisJS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { stubsRoot } from '../stubs/main.ts'
import { BaseCommand } from '@adonisjs/core/ace'

/**
* Command to create the sessions table migration
*/
export default class MakeSessionTable extends BaseCommand {
static commandName = 'make:session-table'
static description = 'Create a migration for the sessions database table'

async run() {
const codemods = await this.createCodemods()
await codemods.makeUsingStub(stubsRoot, 'make/migration/sessions.stub', {
migration: { tableName: 'sessions', prefix: Date.now() },
})
}
}
41 changes: 33 additions & 8 deletions docker-compose.yml → compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: '3.4'

services:
redis:
image: redis:alpine
Expand All @@ -14,16 +12,43 @@ services:
environment:
- REDIS_URI=redis://redis:6379

postgres:
image: postgres:16-alpine
ports:
- 5432:5432
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: session_test
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5

mysql:
image: mysql:8
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: session_test
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5

dynamodb-local:
image: amazon/dynamodb-local
ports:
- 8000:8000
command: '-jar DynamoDBLocal.jar -inMemory -sharedDb'
command: "-jar DynamoDBLocal.jar -inMemory -sharedDb"
working_dir: /home/dynamodblocal
healthcheck:
test:
[
'CMD-SHELL',
"CMD-SHELL",
'[ "$(curl -s -o /dev/null -I -w ''%{http_code}'' http://localhost:8000)" == "400" ]',
]
interval: 10s
Expand All @@ -36,11 +61,11 @@ services:
condition: service_healthy
image: amazon/aws-cli
volumes:
- './tests_helpers/dynamodb_schemas:/tmp/dynamo'
- "./tests_helpers/dynamodb_schemas:/tmp/dynamo"
environment:
AWS_ACCESS_KEY_ID: 'accessKeyId'
AWS_SECRET_ACCESS_KEY: 'secretAccessKey'
AWS_REGION: 'us-east-1'
AWS_ACCESS_KEY_ID: "accessKeyId"
AWS_SECRET_ACCESS_KEY: "secretAccessKey"
AWS_REGION: "us-east-1"
entrypoint:
- bash
command: '-c "for f in /tmp/dynamo/*.json; do aws dynamodb create-table --endpoint-url "http://dynamodb-local:8000" --cli-input-json file://"$${f#./}"; done"'
3 changes: 2 additions & 1 deletion configure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ export async function configure(command: Configure) {
])

/**
* Register provider
* Register provider and commands
*/
await codemods.updateRcFile((rcFile) => {
rcFile.addProvider('@adonisjs/session/session_provider')
rcFile.addCommand('@adonisjs/session/commands')
})
}
1 change: 1 addition & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export { configure } from './configure.ts'
export { Session } from './src/session.ts'
export { stubsRoot } from './stubs/main.ts'
export { defineConfig, stores } from './src/define_config.ts'
export { SessionCollection } from './src/session_collection.ts'
export { ReadOnlyValuesStore, ValuesStore } from './src/values_store.ts'
20 changes: 17 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"./plugins/api_client": "./build/src/plugins/japa/api_client.js",
"./plugins/browser_client": "./build/src/plugins/japa/browser_client.js",
"./client": "./build/src/client.js",
"./types": "./build/src/types.js"
"./types": "./build/src/types.js",
"./commands": "./build/commands/main.js"
},
"scripts": {
"pretest": "npm run lint",
Expand All @@ -33,7 +34,8 @@
"copy:templates": "copyfiles \"stubs/**/*.stub\" --up=\"1\" build",
"precompile": "npm run lint",
"compile": "tsdown && tsc --emitDeclarationOnly --declaration",
"postcompile": "npm run copy:templates",
"postcompile": "npm run copy:templates && npm run index:commands",
"index:commands": "adonis-kit index build/commands",
"build": "npm run compile",
"docs": "typedoc",
"version": "npm run build",
Expand All @@ -46,6 +48,7 @@
"@adonisjs/core": "^7.0.0-next.16",
"@adonisjs/eslint-config": "^3.0.0-next.5",
"@adonisjs/i18n": "^3.0.0-next.2",
"@adonisjs/lucid": "^22.0.0-next.0",
"@adonisjs/prettier-config": "^1.4.5",
"@adonisjs/redis": "^10.0.0-next.2",
"@adonisjs/tsconfig": "^2.0.0-next.3",
Expand All @@ -66,6 +69,9 @@
"@vinejs/vine": "^4.2.0",
"c8": "^10.1.3",
"copyfiles": "^2.4.1",
"better-sqlite3": "^12.5.0",
"mysql2": "^3.15.3",
"pg": "^8.16.3",
"cross-env": "^10.1.0",
"edge.js": "^6.4.0",
"eslint": "^9.39.2",
Expand All @@ -86,6 +92,7 @@
"peerDependencies": {
"@adonisjs/assembler": "^8.0.0-next.26",
"@adonisjs/core": "^7.0.0-next.16",
"@adonisjs/lucid": "^22.0.0-next.0",
"@adonisjs/redis": "^10.0.0-next.2",
"@aws-sdk/client-dynamodb": "^3.955.0",
"@aws-sdk/util-dynamodb": "^3.955.0",
Expand All @@ -98,6 +105,9 @@
"@adonisjs/assembler": {
"optional": true
},
"@adonisjs/lucid": {
"optional": true
},
"@adonisjs/redis": {
"optional": true
},
Expand All @@ -121,6 +131,9 @@
}
},
"author": "virk,adonisjs",
"contributors": [
"Julien Ripouteau <julien@ripouteau.com>"
],
"license": "MIT",
"homepage": "https://github.com/adonisjs/session#readme",
"repository": {
Expand Down Expand Up @@ -148,7 +161,8 @@
"./src/plugins/edge.ts",
"./src/plugins/japa/api_client.ts",
"./src/plugins/japa/browser_client.ts",
"./src/client.ts"
"./src/client.ts",
"./commands/make_session_table.ts"
],
"outDir": "./build",
"clean": true,
Expand Down
6 changes: 6 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ignoredBuiltDependencies:
- '@swc/core'
- esbuild

onlyBuiltDependencies:
- better-sqlite3
36 changes: 23 additions & 13 deletions providers/session_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { ApplicationService } from '@adonisjs/core/types'

import type { Session } from '../src/session.ts'
import SessionMiddleware from '../src/session_middleware.ts'
import { SessionCollection } from '../src/session_collection.ts'

/**
* Events emitted by the session class
Expand Down Expand Up @@ -45,25 +46,34 @@ export default class SessionProvider {
}

/**
* Registering muddleware
* Resolves the session config from the config provider
*/
register() {
this.app.container.singleton(SessionMiddleware, async (resolver) => {
const sessionConfigProvider = this.app.config.get('session', {})
async #resolveConfig() {
const sessionConfigProvider = this.app.config.get('session', {})
const config = await configProvider.resolve<any>(this.app, sessionConfigProvider)
if (!config) {
throw new RuntimeException(
'Invalid "config/session.ts" file. Make sure you are using the "defineConfig" method'
)
}

/**
* Resolve config from the provider
*/
const config = await configProvider.resolve<any>(this.app, sessionConfigProvider)
if (!config) {
throw new RuntimeException(
'Invalid "config/session.ts" file. Make sure you are using the "defineConfig" method'
)
}
return config
}

/**
* Registering bindings
*/
register() {
this.app.container.singleton(SessionMiddleware, async (resolver) => {
const config = await this.#resolveConfig()
const emitter = await resolver.make('emitter')
return new SessionMiddleware(config, emitter)
})

this.app.container.singleton(SessionCollection, async () => {
const config = await this.#resolveConfig()
return new SessionCollection(config)
})
}

/**
Expand Down
30 changes: 29 additions & 1 deletion src/define_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
*/

/// <reference types="@adonisjs/redis/redis_provider" />
/// <reference types="@adonisjs/lucid/database_provider" />

import { configProvider } from '@adonisjs/core'
import string from '@adonisjs/core/helpers/string'
import type { ConfigProvider } from '@adonisjs/core/types'
import type { CookieOptions } from '@adonisjs/core/types/http'
import { InvalidArgumentsException } from '@adonisjs/core/exceptions'
import { InvalidArgumentsException, RuntimeException } from '@adonisjs/core/exceptions'

import debug from './debug.ts'
import { MemoryStore } from './stores/memory.ts'
Expand All @@ -23,6 +24,7 @@ import type {
RedisStoreConfig,
SessionStoreFactory,
DynamoDBStoreConfig,
DatabaseStoreConfig,
} from './types.ts'

type ConfigInput<
Expand Down Expand Up @@ -170,6 +172,7 @@ export const stores: {
redis: (config: RedisStoreConfig) => ConfigProvider<SessionStoreFactory>
cookie: () => ConfigProvider<SessionStoreFactory>
dynamodb: (config: DynamoDBStoreConfig) => ConfigProvider<SessionStoreFactory>
database: (config?: DatabaseStoreConfig) => ConfigProvider<SessionStoreFactory>
} = {
/**
* Creates a file-based session store
Expand Down Expand Up @@ -231,4 +234,29 @@ export const stores: {
}
})
},
/**
* Creates a database-based session store using Lucid
*
* @param config - Database store configuration
*/
database: (config) => {
return configProvider.create(async (app) => {
const { DatabaseStore } = await import('./stores/database.js')
const db = await app.container.make('lucid.db')
const connectionName = config?.connectionName || db.primaryConnectionName

if (!db.manager.has(connectionName)) {
throw new RuntimeException(
`Invalid database connection "${connectionName}" referenced in session config`
)
}

return (_, sessionConfig: SessionConfig) => {
return new DatabaseStore(db.connection(connectionName), sessionConfig.age, {
tableName: config?.tableName,
gcProbability: config?.gcProbability,
})
}
})
},
}
14 changes: 14 additions & 0 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,17 @@ export const E_SESSION_NOT_READY = createError(
'E_SESSION_NOT_READY',
500
)

/**
* Error thrown when attempting to use tagging features with a store that doesn't support it.
* Only Memory, Redis, and Database stores support session tagging.
*
* @example
* // This will throw E_SESSION_TAGGING_NOT_SUPPORTED when using cookie store
* const sessions = await sessionCollection.tagged(userId)
*/
export const E_SESSION_TAGGING_NOT_SUPPORTED = createError(
'Session store does not support tagging. Use memory, redis, or database store instead',
'E_SESSION_TAGGING_NOT_SUPPORTED',
500
)
Loading