(
secretId: string,
versionData: Omit<NewSecretVersion, 'secretId' | 'version' | 'createdAt' | 'isActive'>,
options: SecretQueryOptions = {},
)
| 254 | } |
| 255 | |
| 256 | async rotateSecret( |
| 257 | secretId: string, |
| 258 | versionData: Omit<NewSecretVersion, 'secretId' | 'version' | 'createdAt' | 'isActive'>, |
| 259 | options: SecretQueryOptions = {}, |
| 260 | ): Promise<SecretSummary> { |
| 261 | return this.db.transaction(async (tx) => { |
| 262 | const orgId = options.organizationId ?? DEFAULT_ORGANIZATION_ID; |
| 263 | const [secret] = await tx |
| 264 | .select() |
| 265 | .from(secrets) |
| 266 | .where(and(eq(secrets.id, secretId), eq(secrets.organizationId, orgId))) |
| 267 | .limit(1); |
| 268 | |
| 269 | if (!secret) { |
| 270 | throw new NotFoundException(`Secret ${secretId} not found`); |
| 271 | } |
| 272 | |
| 273 | const [{ maxVersion }] = await tx |
| 274 | .select({ maxVersion: sql<number>`COALESCE(max(${secretVersions.version}), 0)` }) |
| 275 | .from(secretVersions) |
| 276 | .where( |
| 277 | and(eq(secretVersions.secretId, secretId), eq(secretVersions.organizationId, orgId)), |
| 278 | ); |
| 279 | |
| 280 | const newVersionNumber = (maxVersion ?? 0) + 1; |
| 281 | |
| 282 | await tx |
| 283 | .update(secretVersions) |
| 284 | .set({ isActive: false }) |
| 285 | .where( |
| 286 | and(eq(secretVersions.secretId, secretId), eq(secretVersions.organizationId, orgId)), |
| 287 | ); |
| 288 | |
| 289 | const [insertedVersion] = await tx |
| 290 | .insert(secretVersions) |
| 291 | .values({ |
| 292 | ...versionData, |
| 293 | secretId, |
| 294 | version: newVersionNumber, |
| 295 | isActive: true, |
| 296 | organizationId: versionData.organizationId ?? orgId, |
| 297 | }) |
| 298 | .returning(); |
| 299 | |
| 300 | const [updatedSecret] = await tx |
| 301 | .update(secrets) |
| 302 | .set({ updatedAt: sql`now()` }) |
| 303 | .where(eq(secrets.id, secretId)) |
| 304 | .returning(); |
| 305 | |
| 306 | return this.mapSummary({ |
| 307 | id: updatedSecret.id, |
| 308 | name: updatedSecret.name, |
| 309 | description: updatedSecret.description, |
| 310 | tags: updatedSecret.tags, |
| 311 | createdAt: updatedSecret.createdAt, |
| 312 | updatedAt: updatedSecret.updatedAt, |
| 313 | versionId: insertedVersion.id, |
nothing calls this directly
no test coverage detected