chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,54 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIdentityCenterCheckAssignmentDeletionStatusContract } from '@/lib/api/contracts/tools/aws/identity-center-check-assignment-deletion-status'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { checkAssignmentDeletionStatus, createSSOAdminClient } from '../utils'
const logger = createLogger('IdentityCenterCheckAssignmentDeletionStatusAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(
awsIdentityCenterCheckAssignmentDeletionStatusContract,
request,
{
errorFormat: 'details',
logger,
}
)
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`Checking assignment deletion status for request ${params.requestId}`)
const client = createSSOAdminClient(params)
try {
const result = await checkAssignmentDeletionStatus(
client,
params.instanceArn,
params.requestId
)
logger.info(`Assignment deletion status: ${result.status}`)
return NextResponse.json({
message: `Assignment deletion status: ${result.status}`,
...result,
})
} finally {
client.destroy()
}
} catch (error) {
logger.error('Failed to check assignment deletion status:', error)
return NextResponse.json(
{ error: `Failed to check assignment deletion status: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,50 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIdentityCenterCheckAssignmentStatusContract } from '@/lib/api/contracts/tools/aws/identity-center-check-assignment-status'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { checkAssignmentCreationStatus, createSSOAdminClient } from '../utils'
const logger = createLogger('IdentityCenterCheckAssignmentStatusAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIdentityCenterCheckAssignmentStatusContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`Checking assignment status for request ${params.requestId}`)
const client = createSSOAdminClient(params)
try {
const result = await checkAssignmentCreationStatus(
client,
params.instanceArn,
params.requestId
)
logger.info(`Assignment status: ${result.status}`)
return NextResponse.json({
message: `Assignment status: ${result.status}`,
...result,
})
} finally {
client.destroy()
}
} catch (error) {
logger.error('Failed to check assignment status:', error)
return NextResponse.json(
{ error: `Failed to check assignment status: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,71 @@
import {
CreateAccountAssignmentCommand,
type PrincipalType,
type TargetType,
} from '@aws-sdk/client-sso-admin'
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIdentityCenterCreateAccountAssignmentContract } from '@/lib/api/contracts/tools/aws/identity-center-create-account-assignment'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSSOAdminClient, mapAssignmentStatus } from '../utils'
const logger = createLogger('IdentityCenterCreateAccountAssignmentAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(
awsIdentityCenterCreateAccountAssignmentContract,
request,
{
errorFormat: 'details',
logger,
}
)
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(
`Creating account assignment for ${params.principalType} ${params.principalId} on account ${params.accountId}`
)
const client = createSSOAdminClient(params)
try {
const command = new CreateAccountAssignmentCommand({
InstanceArn: params.instanceArn,
TargetId: params.accountId,
TargetType: 'AWS_ACCOUNT' as TargetType,
PermissionSetArn: params.permissionSetArn,
PrincipalType: params.principalType as PrincipalType,
PrincipalId: params.principalId,
})
const response = await client.send(command)
const status = response.AccountAssignmentCreationStatus ?? {}
const result = mapAssignmentStatus(status)
logger.info(
`Account assignment creation initiated with status ${result.status}, requestId ${result.requestId}`
)
return NextResponse.json({
message: `Account assignment creation ${result.status === 'SUCCEEDED' ? 'succeeded' : 'initiated'}`,
...result,
})
} finally {
client.destroy()
}
} catch (error) {
logger.error('Failed to create account assignment:', error)
return NextResponse.json(
{ error: `Failed to create account assignment: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,71 @@
import {
DeleteAccountAssignmentCommand,
type PrincipalType,
type TargetType,
} from '@aws-sdk/client-sso-admin'
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIdentityCenterDeleteAccountAssignmentContract } from '@/lib/api/contracts/tools/aws/identity-center-delete-account-assignment'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSSOAdminClient, mapAssignmentStatus } from '../utils'
const logger = createLogger('IdentityCenterDeleteAccountAssignmentAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(
awsIdentityCenterDeleteAccountAssignmentContract,
request,
{
errorFormat: 'details',
logger,
}
)
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(
`Deleting account assignment for ${params.principalType} ${params.principalId} on account ${params.accountId}`
)
const client = createSSOAdminClient(params)
try {
const command = new DeleteAccountAssignmentCommand({
InstanceArn: params.instanceArn,
TargetId: params.accountId,
TargetType: 'AWS_ACCOUNT' as TargetType,
PermissionSetArn: params.permissionSetArn,
PrincipalType: params.principalType as PrincipalType,
PrincipalId: params.principalId,
})
const response = await client.send(command)
const status = response.AccountAssignmentDeletionStatus ?? {}
const result = mapAssignmentStatus(status)
logger.info(
`Account assignment deletion initiated with status ${result.status}, requestId ${result.requestId}`
)
return NextResponse.json({
message: `Account assignment deletion ${result.status === 'SUCCEEDED' ? 'succeeded' : 'initiated'}`,
...result,
})
} finally {
client.destroy()
}
} catch (error) {
logger.error('Failed to delete account assignment:', error)
return NextResponse.json(
{ error: `Failed to delete account assignment: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,43 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIdentityCenterDescribeAccountContract } from '@/lib/api/contracts/tools/aws/identity-center-describe-account'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createOrganizationsClient, describeAccount } from '../utils'
const logger = createLogger('IdentityCenterDescribeAccountAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIdentityCenterDescribeAccountContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`Describing AWS account ${params.accountId}`)
const client = createOrganizationsClient(params)
try {
const result = await describeAccount(client, params.accountId)
logger.info(`Successfully described account ${result.name}`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error('Failed to describe account:', error)
return NextResponse.json(
{ error: `Failed to describe account: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,45 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIdentityCenterGetGroupContract } from '@/lib/api/contracts/tools/aws/identity-center-get-group'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIdentityStoreClient, getGroupByDisplayName } from '../utils'
const logger = createLogger('IdentityCenterGetGroupAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIdentityCenterGetGroupContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(
`Looking up group "${params.displayName}" in identity store ${params.identityStoreId}`
)
const client = createIdentityStoreClient(params)
try {
const result = await getGroupByDisplayName(client, params.identityStoreId, params.displayName)
logger.info(`Successfully found group ${result.groupId}`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error('Failed to get group:', error)
return NextResponse.json(
{ error: `Failed to get group: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,43 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIdentityCenterGetUserContract } from '@/lib/api/contracts/tools/aws/identity-center-get-user'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIdentityStoreClient, getUserByEmail } from '../utils'
const logger = createLogger('IdentityCenterGetUserAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIdentityCenterGetUserContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`Looking up user by email in identity store ${params.identityStoreId}`)
const client = createIdentityStoreClient(params)
try {
const result = await getUserByEmail(client, params.identityStoreId, params.email)
logger.info(`Successfully found user ${result.userId}`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error('Failed to get user:', error)
return NextResponse.json(
{ error: `Failed to get user: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,54 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIdentityCenterListAccountAssignmentsContract } from '@/lib/api/contracts/tools/aws/identity-center-list-account-assignments'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSSOAdminClient, listAccountAssignmentsForPrincipal } from '../utils'
const logger = createLogger('IdentityCenterListAccountAssignmentsAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(
awsIdentityCenterListAccountAssignmentsContract,
request,
{
errorFormat: 'details',
logger,
}
)
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`Listing account assignments for ${params.principalType} ${params.principalId}`)
const client = createSSOAdminClient(params)
try {
const result = await listAccountAssignmentsForPrincipal(
client,
params.instanceArn,
params.principalId,
params.principalType,
params.maxResults,
params.nextToken
)
logger.info(`Successfully listed ${result.count} account assignments`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error('Failed to list account assignments:', error)
return NextResponse.json(
{ error: `Failed to list account assignments: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,43 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIdentityCenterListAccountsContract } from '@/lib/api/contracts/tools/aws/identity-center-list-accounts'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createOrganizationsClient, listAccounts } from '../utils'
const logger = createLogger('IdentityCenterListAccountsAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIdentityCenterListAccountsContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info('Listing AWS accounts')
const client = createOrganizationsClient(params)
try {
const result = await listAccounts(client, params.maxResults, params.nextToken)
logger.info(`Successfully listed ${result.count} accounts`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error('Failed to list AWS accounts:', error)
return NextResponse.json(
{ error: `Failed to list AWS accounts: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,48 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIdentityCenterListGroupsContract } from '@/lib/api/contracts/tools/aws/identity-center-list-groups'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createIdentityStoreClient, listGroups } from '../utils'
const logger = createLogger('IdentityCenterListGroupsAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIdentityCenterListGroupsContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`Listing groups in identity store ${params.identityStoreId}`)
const client = createIdentityStoreClient(params)
try {
const result = await listGroups(
client,
params.identityStoreId,
params.maxResults,
params.nextToken
)
logger.info(`Successfully listed ${result.count} groups`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error('Failed to list groups:', error)
return NextResponse.json(
{ error: `Failed to list groups: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,43 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIdentityCenterListInstancesContract } from '@/lib/api/contracts/tools/aws/identity-center-list-instances'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSSOAdminClient, listInstances } from '../utils'
const logger = createLogger('IdentityCenterListInstancesAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIdentityCenterListInstancesContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info('Listing Identity Center instances')
const client = createSSOAdminClient(params)
try {
const result = await listInstances(client, params.maxResults, params.nextToken)
logger.info(`Successfully listed ${result.count} instances`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error('Failed to list Identity Center instances:', error)
return NextResponse.json(
{ error: `Failed to list Identity Center instances: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,48 @@
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { type NextRequest, NextResponse } from 'next/server'
import { awsIdentityCenterListPermissionSetsContract } from '@/lib/api/contracts/tools/aws/identity-center-list-permission-sets'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSSOAdminClient, listPermissionSets } from '../utils'
const logger = createLogger('IdentityCenterListPermissionSetsAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsIdentityCenterListPermissionSetsContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`Listing permission sets for instance ${params.instanceArn}`)
const client = createSSOAdminClient(params)
try {
const result = await listPermissionSets(
client,
params.instanceArn,
params.maxResults,
params.nextToken
)
logger.info(`Successfully listed ${result.count} permission sets`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
logger.error('Failed to list permission sets:', error)
return NextResponse.json(
{ error: `Failed to list permission sets: ${toError(error).message}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,304 @@
import {
DescribeGroupCommand,
DescribeUserCommand,
GetGroupIdCommand,
GetUserIdCommand,
IdentitystoreClient,
ListGroupsCommand,
} from '@aws-sdk/client-identitystore'
import {
DescribeAccountCommand,
ListAccountsCommand,
OrganizationsClient,
} from '@aws-sdk/client-organizations'
import {
type AccountAssignmentOperationStatus,
DescribeAccountAssignmentCreationStatusCommand,
DescribeAccountAssignmentDeletionStatusCommand,
DescribePermissionSetCommand,
ListAccountAssignmentsForPrincipalCommand,
ListInstancesCommand,
ListPermissionSetsCommand,
type PrincipalType,
SSOAdminClient,
} from '@aws-sdk/client-sso-admin'
import type { IdentityCenterConnectionConfig } from '@/tools/identity_center/types'
export function createSSOAdminClient(config: IdentityCenterConnectionConfig): SSOAdminClient {
return new SSOAdminClient({
region: config.region,
credentials: {
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
},
})
}
export function createIdentityStoreClient(
config: IdentityCenterConnectionConfig
): IdentitystoreClient {
return new IdentitystoreClient({
region: config.region,
credentials: {
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
},
})
}
export function createOrganizationsClient(config: IdentityCenterConnectionConfig) {
return new OrganizationsClient({
region: 'us-east-1', // Organizations API only available in us-east-1
credentials: {
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
},
})
}
export async function listInstances(
client: SSOAdminClient,
maxResults?: number | null,
nextToken?: string | null
) {
const command = new ListInstancesCommand({
...(maxResults ? { MaxResults: maxResults } : {}),
...(nextToken ? { NextToken: nextToken } : {}),
})
const response = await client.send(command)
const instances = (response.Instances ?? []).map((instance) => ({
instanceArn: instance.InstanceArn ?? '',
identityStoreId: instance.IdentityStoreId ?? '',
name: instance.Name ?? null,
status: instance.Status ?? '',
statusReason: instance.StatusReason ?? null,
ownerAccountId: instance.OwnerAccountId ?? null,
createdDate: instance.CreatedDate?.toISOString() ?? null,
}))
return { instances, nextToken: response.NextToken ?? null, count: instances.length }
}
export async function listAccounts(
client: OrganizationsClient,
maxResults?: number | null,
nextToken?: string | null
) {
const command = new ListAccountsCommand({
...(maxResults ? { MaxResults: maxResults } : {}),
...(nextToken ? { NextToken: nextToken } : {}),
})
const response = await client.send(command)
const accounts = (response.Accounts ?? []).map((account) => ({
id: account.Id ?? '',
arn: account.Arn ?? '',
name: account.Name ?? '',
email: account.Email ?? '',
status: account.State ?? '',
joinedTimestamp: account.JoinedTimestamp?.toISOString() ?? null,
}))
return { accounts, nextToken: response.NextToken ?? null, count: accounts.length }
}
export async function listPermissionSets(
client: SSOAdminClient,
instanceArn: string,
maxResults?: number | null,
nextToken?: string | null
) {
const listCommand = new ListPermissionSetsCommand({
InstanceArn: instanceArn,
...(maxResults ? { MaxResults: maxResults } : {}),
...(nextToken ? { NextToken: nextToken } : {}),
})
const listResponse = await client.send(listCommand)
const permissionSetArns = listResponse.PermissionSets ?? []
const permissionSets = await Promise.all(
permissionSetArns.map(async (arn) => {
const describeCommand = new DescribePermissionSetCommand({
InstanceArn: instanceArn,
PermissionSetArn: arn,
})
const describeResponse = await client.send(describeCommand)
const ps = describeResponse.PermissionSet
return {
permissionSetArn: ps?.PermissionSetArn ?? arn,
name: ps?.Name ?? '',
description: ps?.Description ?? null,
sessionDuration: ps?.SessionDuration ?? null,
createdDate: ps?.CreatedDate?.toISOString() ?? null,
}
})
)
return {
permissionSets,
nextToken: listResponse.NextToken ?? null,
count: permissionSets.length,
}
}
export async function getUserByEmail(
ssoClient: IdentitystoreClient,
identityStoreId: string,
email: string
) {
const getUserIdCommand = new GetUserIdCommand({
IdentityStoreId: identityStoreId,
AlternateIdentifier: {
UniqueAttribute: {
AttributePath: 'emails.value',
AttributeValue: email,
},
},
})
const getUserIdResponse = await ssoClient.send(getUserIdCommand)
const userId = getUserIdResponse.UserId ?? ''
const describeCommand = new DescribeUserCommand({
IdentityStoreId: identityStoreId,
UserId: userId,
})
const describeResponse = await ssoClient.send(describeCommand)
const primaryEmail =
describeResponse.Emails?.find((e) => e.Primary)?.Value ??
describeResponse.Emails?.[0]?.Value ??
null
return {
userId,
userName: describeResponse.UserName ?? '',
displayName: describeResponse.DisplayName ?? null,
email: primaryEmail,
}
}
export function mapAssignmentStatus(status: AccountAssignmentOperationStatus) {
return {
status: status.Status ?? '',
requestId: status.RequestId ?? '',
accountId: status.TargetId ?? null,
permissionSetArn: status.PermissionSetArn ?? null,
principalType: status.PrincipalType ?? null,
principalId: status.PrincipalId ?? null,
failureReason: status.FailureReason ?? null,
createdDate: status.CreatedDate?.toISOString() ?? null,
}
}
export async function checkAssignmentCreationStatus(
client: SSOAdminClient,
instanceArn: string,
requestId: string
) {
const command = new DescribeAccountAssignmentCreationStatusCommand({
InstanceArn: instanceArn,
AccountAssignmentCreationRequestId: requestId,
})
const response = await client.send(command)
return mapAssignmentStatus(response.AccountAssignmentCreationStatus ?? {})
}
export async function checkAssignmentDeletionStatus(
client: SSOAdminClient,
instanceArn: string,
requestId: string
) {
const command = new DescribeAccountAssignmentDeletionStatusCommand({
InstanceArn: instanceArn,
AccountAssignmentDeletionRequestId: requestId,
})
const response = await client.send(command)
return mapAssignmentStatus(response.AccountAssignmentDeletionStatus ?? {})
}
export async function listGroups(
client: IdentitystoreClient,
identityStoreId: string,
maxResults?: number | null,
nextToken?: string | null
) {
const command = new ListGroupsCommand({
IdentityStoreId: identityStoreId,
...(maxResults ? { MaxResults: maxResults } : {}),
...(nextToken ? { NextToken: nextToken } : {}),
})
const response = await client.send(command)
const groups = (response.Groups ?? []).map((group) => ({
groupId: group.GroupId ?? '',
displayName: group.DisplayName ?? null,
description: group.Description ?? null,
externalIds: group.ExternalIds?.map((e) => ({ issuer: e.Issuer ?? '', id: e.Id ?? '' })) ?? [],
}))
return { groups, nextToken: response.NextToken ?? null, count: groups.length }
}
export async function getGroupByDisplayName(
client: IdentitystoreClient,
identityStoreId: string,
displayName: string
) {
const getGroupIdCommand = new GetGroupIdCommand({
IdentityStoreId: identityStoreId,
AlternateIdentifier: {
UniqueAttribute: {
AttributePath: 'displayName',
AttributeValue: displayName,
},
},
})
const getGroupIdResponse = await client.send(getGroupIdCommand)
const groupId = getGroupIdResponse.GroupId ?? ''
const describeCommand = new DescribeGroupCommand({
IdentityStoreId: identityStoreId,
GroupId: groupId,
})
const describeResponse = await client.send(describeCommand)
return {
groupId,
displayName: describeResponse.DisplayName ?? null,
description: describeResponse.Description ?? null,
}
}
export async function describeAccount(client: OrganizationsClient, accountId: string) {
const command = new DescribeAccountCommand({ AccountId: accountId })
const response = await client.send(command)
const account = response.Account
return {
id: account?.Id ?? '',
arn: account?.Arn ?? '',
name: account?.Name ?? '',
email: account?.Email ?? '',
status: account?.State ?? '',
joinedTimestamp: account?.JoinedTimestamp?.toISOString() ?? null,
}
}
export async function listAccountAssignmentsForPrincipal(
client: SSOAdminClient,
instanceArn: string,
principalId: string,
principalType: string,
maxResults?: number | null,
nextToken?: string | null
) {
const command = new ListAccountAssignmentsForPrincipalCommand({
InstanceArn: instanceArn,
PrincipalId: principalId,
PrincipalType: principalType as PrincipalType,
...(maxResults ? { MaxResults: maxResults } : {}),
...(nextToken ? { NextToken: nextToken } : {}),
})
const response = await client.send(command)
const assignments = (response.AccountAssignments ?? []).map((a) => ({
accountId: a.AccountId ?? '',
permissionSetArn: a.PermissionSetArn ?? '',
principalType: a.PrincipalType ?? '',
principalId: a.PrincipalId ?? '',
}))
return { assignments, nextToken: response.NextToken ?? null, count: assignments.length }
}