(params: {
workspaceId: string
newKeys: string[]
actingUserId: string
})
| 257 | * Use this instead of `syncWorkspaceEnvCredentials` when the caller knows exactly which keys are new. |
| 258 | */ |
| 259 | export async function createWorkspaceEnvCredentials(params: { |
| 260 | workspaceId: string |
| 261 | newKeys: string[] |
| 262 | actingUserId: string |
| 263 | }): Promise<void> { |
| 264 | const { workspaceId, newKeys, actingUserId } = params |
| 265 | const keys = Array.from(new Set(newKeys.filter(Boolean))) |
| 266 | if (keys.length === 0) return |
| 267 | |
| 268 | const { ownerId, memberUserIds } = await getWorkspaceMembership(workspaceId) |
| 269 | |
| 270 | if (!ownerId) return |
| 271 | |
| 272 | const now = new Date() |
| 273 | |
| 274 | const inserted = await db |
| 275 | .insert(credential) |
| 276 | .values( |
| 277 | keys.map((envKey) => ({ |
| 278 | id: generateId(), |
| 279 | workspaceId, |
| 280 | type: 'env_workspace' as const, |
| 281 | displayName: envKey, |
| 282 | envKey, |
| 283 | createdBy: actingUserId, |
| 284 | createdAt: now, |
| 285 | updatedAt: now, |
| 286 | })) |
| 287 | ) |
| 288 | .onConflictDoNothing() |
| 289 | .returning({ id: credential.id }) |
| 290 | const createdIds = inserted.map((row) => row.id) |
| 291 | |
| 292 | if (createdIds.length === 0 || memberUserIds.length === 0) return |
| 293 | |
| 294 | // Bulk-insert memberships for all new credentials × all workspace members in one query |
| 295 | const membershipValues = createdIds.flatMap((credentialId) => |
| 296 | memberUserIds.map((memberUserId) => ({ |
| 297 | id: generateId(), |
| 298 | credentialId, |
| 299 | userId: memberUserId, |
| 300 | role: (memberUserId === actingUserId ? 'admin' : 'member') as 'admin' | 'member', |
| 301 | status: 'active' as const, |
| 302 | joinedAt: now, |
| 303 | invitedBy: actingUserId, |
| 304 | createdAt: now, |
| 305 | updatedAt: now, |
| 306 | })) |
| 307 | ) |
| 308 | |
| 309 | await db.insert(credentialMember).values(membershipValues).onConflictDoNothing() |
| 310 | } |
| 311 | |
| 312 | /** |
| 313 | * Deletes credential records (and their memberships via cascade) for removed workspace env keys. |
no test coverage detected