(
params: OptionalFields<
{
organizationId: string
userId: string
amount: number
operationId: string
description: string
expiresAt: Date | null
logger: Logger
},
'description' | 'expiresAt'
>,
)
| 327 | * Uses advisory lock to serialize with other credit operations for the organization. |
| 328 | */ |
| 329 | export async function grantOrganizationCredits( |
| 330 | params: OptionalFields< |
| 331 | { |
| 332 | organizationId: string |
| 333 | userId: string |
| 334 | amount: number |
| 335 | operationId: string |
| 336 | description: string |
| 337 | expiresAt: Date | null |
| 338 | logger: Logger |
| 339 | }, |
| 340 | 'description' | 'expiresAt' |
| 341 | >, |
| 342 | ): Promise<void> { |
| 343 | const withDefaults = { |
| 344 | description: 'Organization credit purchase', |
| 345 | expiresAt: null, |
| 346 | ...params, |
| 347 | } |
| 348 | const { |
| 349 | organizationId, |
| 350 | userId, |
| 351 | amount, |
| 352 | operationId, |
| 353 | description, |
| 354 | expiresAt, |
| 355 | logger, |
| 356 | } = withDefaults |
| 357 | |
| 358 | await withAdvisoryLockTransaction({ |
| 359 | callback: async (tx) => { |
| 360 | const now = new Date() |
| 361 | |
| 362 | // Use onConflictDoNothing for idempotency - duplicate operation_ids are silently ignored |
| 363 | const result = await tx |
| 364 | .insert(schema.creditLedger) |
| 365 | .values({ |
| 366 | operation_id: operationId, |
| 367 | user_id: userId, |
| 368 | org_id: organizationId, |
| 369 | principal: amount, |
| 370 | balance: amount, |
| 371 | type: 'organization', |
| 372 | description, |
| 373 | priority: GRANT_PRIORITIES.organization, |
| 374 | expires_at: expiresAt, |
| 375 | created_at: now, |
| 376 | }) |
| 377 | .onConflictDoNothing({ target: schema.creditLedger.operation_id }) |
| 378 | .returning({ id: schema.creditLedger.operation_id }) |
| 379 | |
| 380 | if (result.length > 0) { |
| 381 | logger.info( |
| 382 | { organizationId, userId, operationId, amount, expiresAt }, |
| 383 | 'Created new organization credit grant', |
| 384 | ) |
| 385 | } else { |
| 386 | logger.debug( |
no test coverage detected