
Research
Two Malicious Rust Crates Impersonate Popular Logger to Steal Wallet Keys
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
adonisjs-transaction-decorator
Advanced tools
Transaction decorator and mixin for AdonisJS applications
🚀 Advanced transaction management for AdonisJS applications
Powerful transaction decorator and mixin that provides automatic transaction handling with AsyncLocalStorage, retry mechanisms, debug logging, and comprehensive utilities.
✨ @transaction() decorator - Automatic transaction wrapping for methods
🔄 Nested transaction support - Reuses existing transactions
🔁 Retry mechanism - Configurable retry logic for failed transactions
📊 Debug logging - Transaction lifecycle logging with timing
⚡ Transactional mixin - Automatic transaction injection for Lucid models
🛠 Advanced utilities - Sequence, parallel, conditional execution
🔍 Transaction stats - Runtime statistics and monitoring
🎯 TypeScript first - Full type safety and IntelliSense support
npm install adonisjs-transaction-decorator
import { transaction } from 'adonisjs-transaction-decorator'
class UserService {
@transaction()
async createUser(userData: any) {
// This method automatically runs in a transaction
const user = await User.create(userData)
await Profile.create({ userId: user.id, ...profileData })
return user
}
@transaction({
debug: true,
retry: { attempts: 3, delay: 100 }
})
async createUserWithRetry(userData: any) {
// Automatic retry on failure with debug logging
return await User.create(userData)
}
}
import { Transactional } from 'adonisjs-transaction-decorator'
import { BaseModel } from '@adonisjs/lucid/orm'
class User extends Transactional(BaseModel) {
// All operations automatically use current transaction context
}
class UserController {
@transaction()
async store({ request }: HttpContext) {
// All User operations will use the same transaction
const user = await User.create(request.body())
await User.query().where('active', false).update({ active: true })
return user
}
}
import { runInTransaction } from 'adonisjs-transaction-decorator'
// Execute multiple operations in a transaction
const result = await runInTransaction(async () => {
const user = await User.create({ name: 'John' })
const profile = await Profile.create({ userId: user.id })
return { user, profile }
}, {
debug: true,
isolationLevel: 'repeatable read'
})
interface TransactionOptions {
connection?: string // Custom database connection
isolationLevel?: IsolationLevel // Transaction isolation level
debug?: boolean // Enable debug logging
timeout?: number // Transaction timeout (ms)
retry?: { // Retry configuration
attempts: number
delay: number
}
}
@transaction(options?: TransactionOptions)
Decorator that wraps methods in a transaction.
class OrderService {
@transaction({ isolationLevel: 'serializable' })
async processOrder(orderData: any) {
// High isolation level for critical operations
}
@transaction({
retry: { attempts: 3, delay: 200 },
debug: true
})
async processPayment(paymentData: any) {
// Retry failed payments with logging
}
}
runInTransaction<T>(fn, options?): Promise<T>
Execute a function within a transaction programmatically.
const order = await runInTransaction(async () => {
const order = await Order.create(orderData)
await OrderItem.createMany(items.map(item => ({ ...item, orderId: order.id })))
await Inventory.decrement(items)
return order
}, { debug: true })
getCurrentTransaction(): TransactionClientContract | undefined
Get the current transaction client.
const trx = getCurrentTransaction()
if (trx) {
// Manual database operations with current transaction
await trx.raw('UPDATE counters SET value = value + 1')
}
isInTransaction(): boolean
Check if currently executing within a transaction.
if (isInTransaction()) {
console.log('Running in transaction context')
}
getTransactionStats()
Get current transaction statistics.
const stats = getTransactionStats()
console.log(`Transaction ${stats.id} running for ${stats.duration}ms`)
The Transactional
mixin automatically injects the current transaction into all Lucid model operations:
class User extends Transactional(BaseModel) {
// All static and instance methods automatically use current transaction
}
// Usage
@transaction()
async createUserWithPosts() {
const user = await User.create({ name: 'John' }) // Uses transaction
const post = await Post.create({ userId: user.id }) // Uses transaction
await user.save() // Uses transaction
return user
}
TransactionUtils.sequence<T>(operations, options?): Promise<T[]>
Execute operations sequentially within a transaction.
const results = await TransactionUtils.sequence([
() => User.create({ name: 'Alice' }),
() => User.create({ name: 'Bob' }),
() => User.create({ name: 'Charlie' })
], { debug: true })
TransactionUtils.parallel<T>(operations, options?): Promise<T[]>
Execute operations in parallel within a transaction.
const [user, profile, settings] = await TransactionUtils.parallel([
() => User.create(userData),
() => Profile.create(profileData),
() => Settings.create(settingsData)
])
TransactionUtils.conditional<T>(condition, operation, options?)
Conditionally execute operation in transaction.
const user = await TransactionUtils.conditional(
() => shouldCreateUser,
() => User.create(userData),
{ debug: true }
)
TransactionUtils.withSavepoint<T>(name, operation)
Execute operation with savepoint support (database dependent).
await runInTransaction(async () => {
await User.create(userData)
await TransactionUtils.withSavepoint('checkpoint', async () => {
// This can be rolled back to savepoint on error
await Profile.create(profileData)
})
})
class PaymentService {
@transaction({
retry: { attempts: 3, delay: 1000 },
debug: true
})
async processPayment(amount: number, cardToken: string) {
// Automatically retries on failure
const charge = await this.chargeCard(cardToken, amount)
await Transaction.create({ amount, status: 'completed' })
await this.sendReceipt(charge.receiptEmail)
return charge
}
}
class OrderService {
@transaction({ isolationLevel: 'serializable' })
async fulfillOrder(orderId: number) {
const order = await Order.findOrFail(orderId)
// All operations use the same transaction
for (const item of order.items) {
await Inventory.decrement(item.productId, item.quantity)
await ShippingLabel.create({ orderId, itemId: item.id })
}
await order.merge({ status: 'fulfilled' }).save()
await this.notifyCustomer(order.customerId)
return order
}
}
class DataMigrationService {
@transaction({ connection: 'analytics', debug: true })
async migrateUserData(userId: number) {
// Uses 'analytics' database connection
const user = await User.create(userData)
await UserAnalytics.create({ userId: user.id })
return user
}
}
class ReportService {
@transaction({ debug: true })
async generateReport() {
const stats = getTransactionStats()
console.log(`Report generation started: ${stats.id}`)
// Complex report generation...
await this.aggregateData()
await this.generateCharts()
await this.saveReport()
const finalStats = getTransactionStats()
console.log(`Report completed in ${finalStats.duration}ms`)
}
}
// For critical operations requiring consistency
@transaction({ isolationLevel: 'serializable' })
async transferMoney(fromAccount: number, toAccount: number, amount: number) {
// Prevents phantom reads and ensures data consistency
}
// For most operations (default)
@transaction({ isolationLevel: 'read committed' })
async updateProfile(userId: number, data: any) {
// Good balance of consistency and performance
}
// In development
@transaction({ debug: true })
// In production
@transaction({ debug: false })
@transaction({
retry: { attempts: 3, delay: 500 }
})
async syncWithExternalAPI() {
// Handles temporary network issues
}
class User extends Transactional(BaseModel) {
@beforeCreate()
static async hashPassword(user: User) {
// This will use the current transaction context
user.password = await Hash.make(user.password)
}
}
Contributions are welcome! Please read our Contributing Guide for details.
MIT License - see LICENSE file for details.
FAQs
Transaction decorator and mixin for AdonisJS applications
We found that adonisjs-transaction-decorator demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
Research
A malicious package uses a QR code as steganography in an innovative technique.
Research
/Security News
Socket identified 80 fake candidates targeting engineering roles, including suspected North Korean operators, exposing the new reality of hiring as a security function.