@stacksjs/ts-cloud-core 0.1.3 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -13
- package/package.json +12 -3
- package/src/advanced-features.test.ts +0 -465
- package/src/aws/cloudformation.ts +0 -421
- package/src/aws/cloudfront.ts +0 -158
- package/src/aws/credentials.test.ts +0 -132
- package/src/aws/credentials.ts +0 -545
- package/src/aws/index.ts +0 -87
- package/src/aws/s3.test.ts +0 -188
- package/src/aws/s3.ts +0 -1088
- package/src/aws/signature.test.ts +0 -670
- package/src/aws/signature.ts +0 -1155
- package/src/backup/disaster-recovery.test.ts +0 -726
- package/src/backup/disaster-recovery.ts +0 -500
- package/src/backup/index.ts +0 -34
- package/src/backup/manager.test.ts +0 -498
- package/src/backup/manager.ts +0 -432
- package/src/cicd/circleci.ts +0 -430
- package/src/cicd/github-actions.ts +0 -424
- package/src/cicd/gitlab-ci.ts +0 -255
- package/src/cicd/index.ts +0 -8
- package/src/cli/history.ts +0 -396
- package/src/cli/index.ts +0 -10
- package/src/cli/progress.ts +0 -458
- package/src/cli/repl.ts +0 -454
- package/src/cli/suggestions.ts +0 -327
- package/src/cli/table.test.ts +0 -319
- package/src/cli/table.ts +0 -332
- package/src/cloudformation/builder.test.ts +0 -327
- package/src/cloudformation/builder.ts +0 -378
- package/src/cloudformation/builders/api-gateway.ts +0 -449
- package/src/cloudformation/builders/cache.ts +0 -334
- package/src/cloudformation/builders/cdn.ts +0 -278
- package/src/cloudformation/builders/compute.ts +0 -485
- package/src/cloudformation/builders/database.ts +0 -392
- package/src/cloudformation/builders/functions.ts +0 -343
- package/src/cloudformation/builders/messaging.ts +0 -140
- package/src/cloudformation/builders/monitoring.ts +0 -300
- package/src/cloudformation/builders/network.ts +0 -264
- package/src/cloudformation/builders/queue.ts +0 -147
- package/src/cloudformation/builders/security.ts +0 -399
- package/src/cloudformation/builders/storage.ts +0 -285
- package/src/cloudformation/index.ts +0 -30
- package/src/cloudformation/types.ts +0 -173
- package/src/compliance/aws-config.ts +0 -543
- package/src/compliance/cloudtrail.ts +0 -376
- package/src/compliance/compliance.test.ts +0 -423
- package/src/compliance/guardduty.ts +0 -446
- package/src/compliance/index.ts +0 -66
- package/src/compliance/security-hub.ts +0 -456
- package/src/containers/build-optimization.ts +0 -416
- package/src/containers/containers.test.ts +0 -508
- package/src/containers/image-scanning.ts +0 -360
- package/src/containers/index.ts +0 -9
- package/src/containers/registry.ts +0 -293
- package/src/containers/service-mesh.ts +0 -520
- package/src/database/database.test.ts +0 -762
- package/src/database/index.ts +0 -9
- package/src/database/migrations.ts +0 -444
- package/src/database/performance.ts +0 -528
- package/src/database/replicas.ts +0 -534
- package/src/database/users.ts +0 -494
- package/src/dependency-graph.ts +0 -143
- package/src/deployment/ab-testing.ts +0 -582
- package/src/deployment/blue-green.ts +0 -452
- package/src/deployment/canary.ts +0 -500
- package/src/deployment/deployment.test.ts +0 -526
- package/src/deployment/index.ts +0 -61
- package/src/deployment/progressive.ts +0 -62
- package/src/dns/dns.test.ts +0 -641
- package/src/dns/dnssec.ts +0 -315
- package/src/dns/index.ts +0 -8
- package/src/dns/resolver.ts +0 -496
- package/src/dns/routing.ts +0 -593
- package/src/email/advanced/analytics.ts +0 -445
- package/src/email/advanced/index.ts +0 -11
- package/src/email/advanced/rules.ts +0 -465
- package/src/email/advanced/scheduling.ts +0 -352
- package/src/email/advanced/search.ts +0 -412
- package/src/email/advanced/shared-mailboxes.ts +0 -404
- package/src/email/advanced/templates.ts +0 -455
- package/src/email/advanced/threading.ts +0 -281
- package/src/email/analytics.ts +0 -467
- package/src/email/bounce-handling.ts +0 -425
- package/src/email/email.test.ts +0 -431
- package/src/email/handlers/__tests__/inbound.test.ts +0 -38
- package/src/email/handlers/__tests__/outbound.test.ts +0 -37
- package/src/email/handlers/converter.ts +0 -227
- package/src/email/handlers/feedback.ts +0 -228
- package/src/email/handlers/inbound.ts +0 -169
- package/src/email/handlers/outbound.ts +0 -178
- package/src/email/index.ts +0 -15
- package/src/email/reputation.ts +0 -303
- package/src/email/templates.ts +0 -352
- package/src/errors/index.test.ts +0 -434
- package/src/errors/index.ts +0 -416
- package/src/health-checks/index.ts +0 -40
- package/src/index.ts +0 -360
- package/src/intrinsic-functions.ts +0 -118
- package/src/lambda/concurrency.ts +0 -330
- package/src/lambda/destinations.ts +0 -345
- package/src/lambda/dlq.ts +0 -425
- package/src/lambda/index.ts +0 -11
- package/src/lambda/lambda.test.ts +0 -840
- package/src/lambda/layers.ts +0 -263
- package/src/lambda/versions.ts +0 -376
- package/src/lambda/vpc.ts +0 -399
- package/src/local/config.ts +0 -114
- package/src/local/index.ts +0 -6
- package/src/local/mock-aws.ts +0 -351
- package/src/modules/ai.ts +0 -340
- package/src/modules/api.ts +0 -478
- package/src/modules/auth.ts +0 -805
- package/src/modules/cache.ts +0 -417
- package/src/modules/cdn.ts +0 -1062
- package/src/modules/communication.ts +0 -1094
- package/src/modules/compute.ts +0 -3348
- package/src/modules/database.ts +0 -554
- package/src/modules/deployment.ts +0 -1079
- package/src/modules/dns.ts +0 -337
- package/src/modules/email.ts +0 -1538
- package/src/modules/filesystem.ts +0 -515
- package/src/modules/index.ts +0 -32
- package/src/modules/messaging.ts +0 -486
- package/src/modules/monitoring.ts +0 -2086
- package/src/modules/network.ts +0 -664
- package/src/modules/parameter-store.ts +0 -325
- package/src/modules/permissions.ts +0 -1081
- package/src/modules/phone.ts +0 -494
- package/src/modules/queue.ts +0 -1260
- package/src/modules/redirects.ts +0 -464
- package/src/modules/registry.ts +0 -699
- package/src/modules/search.ts +0 -401
- package/src/modules/secrets.ts +0 -416
- package/src/modules/security.ts +0 -731
- package/src/modules/sms.ts +0 -389
- package/src/modules/storage.ts +0 -1120
- package/src/modules/workflow.ts +0 -680
- package/src/multi-account/config.ts +0 -521
- package/src/multi-account/index.ts +0 -7
- package/src/multi-account/manager.ts +0 -427
- package/src/multi-region/cross-region.ts +0 -410
- package/src/multi-region/index.ts +0 -8
- package/src/multi-region/manager.ts +0 -483
- package/src/multi-region/regions.ts +0 -435
- package/src/network-security/index.ts +0 -48
- package/src/observability/index.ts +0 -9
- package/src/observability/logs.ts +0 -522
- package/src/observability/metrics.ts +0 -460
- package/src/observability/observability.test.ts +0 -782
- package/src/observability/synthetics.ts +0 -568
- package/src/observability/xray.ts +0 -358
- package/src/phone/advanced/analytics.ts +0 -349
- package/src/phone/advanced/callbacks.ts +0 -428
- package/src/phone/advanced/index.ts +0 -8
- package/src/phone/advanced/ivr-builder.ts +0 -504
- package/src/phone/advanced/recording.ts +0 -310
- package/src/phone/handlers/__tests__/incoming-call.test.ts +0 -40
- package/src/phone/handlers/incoming-call.ts +0 -117
- package/src/phone/handlers/missed-call.ts +0 -116
- package/src/phone/handlers/voicemail.ts +0 -179
- package/src/phone/index.ts +0 -9
- package/src/presets/api-backend.ts +0 -134
- package/src/presets/data-pipeline.ts +0 -204
- package/src/presets/extend.test.ts +0 -295
- package/src/presets/extend.ts +0 -297
- package/src/presets/fullstack-app.ts +0 -144
- package/src/presets/index.ts +0 -27
- package/src/presets/jamstack.ts +0 -135
- package/src/presets/microservices.ts +0 -167
- package/src/presets/ml-api.ts +0 -208
- package/src/presets/nodejs-server.ts +0 -104
- package/src/presets/nodejs-serverless.ts +0 -114
- package/src/presets/realtime-app.ts +0 -184
- package/src/presets/static-site.ts +0 -64
- package/src/presets/traditional-web-app.ts +0 -339
- package/src/presets/wordpress.ts +0 -138
- package/src/preview/github.test.ts +0 -249
- package/src/preview/github.ts +0 -297
- package/src/preview/index.ts +0 -37
- package/src/preview/manager.test.ts +0 -440
- package/src/preview/manager.ts +0 -326
- package/src/preview/notifications.test.ts +0 -582
- package/src/preview/notifications.ts +0 -341
- package/src/queue/batch-processing.ts +0 -402
- package/src/queue/dlq-monitoring.ts +0 -402
- package/src/queue/fifo.ts +0 -342
- package/src/queue/index.ts +0 -9
- package/src/queue/management.ts +0 -428
- package/src/queue/queue.test.ts +0 -429
- package/src/resource-mgmt/index.ts +0 -39
- package/src/resource-naming.ts +0 -62
- package/src/s3/index.ts +0 -523
- package/src/schema/cloud-config.schema.json +0 -554
- package/src/schema/index.ts +0 -68
- package/src/security/certificate-manager.ts +0 -492
- package/src/security/index.ts +0 -9
- package/src/security/scanning.ts +0 -545
- package/src/security/secrets-manager.ts +0 -476
- package/src/security/secrets-rotation.ts +0 -456
- package/src/security/security.test.ts +0 -738
- package/src/sms/advanced/ab-testing.ts +0 -389
- package/src/sms/advanced/analytics.ts +0 -336
- package/src/sms/advanced/campaigns.ts +0 -523
- package/src/sms/advanced/chatbot.ts +0 -224
- package/src/sms/advanced/index.ts +0 -10
- package/src/sms/advanced/link-tracking.ts +0 -248
- package/src/sms/advanced/mms.ts +0 -308
- package/src/sms/handlers/__tests__/send.test.ts +0 -40
- package/src/sms/handlers/delivery-status.ts +0 -133
- package/src/sms/handlers/receive.ts +0 -162
- package/src/sms/handlers/send.ts +0 -174
- package/src/sms/index.ts +0 -9
- package/src/stack-diff.ts +0 -389
- package/src/static-site/index.ts +0 -85
- package/src/template-builder.ts +0 -110
- package/src/template-validator.ts +0 -574
- package/src/utils/cache.ts +0 -291
- package/src/utils/diff.ts +0 -269
- package/src/utils/hash.ts +0 -227
- package/src/utils/index.ts +0 -8
- package/src/utils/parallel.ts +0 -294
- package/src/validators/credentials.test.ts +0 -274
- package/src/validators/credentials.ts +0 -233
- package/src/validators/quotas.test.ts +0 -434
- package/src/validators/quotas.ts +0 -217
- package/test/ai.test.ts +0 -327
- package/test/api.test.ts +0 -511
- package/test/auth.test.ts +0 -632
- package/test/cache.test.ts +0 -406
- package/test/cdn.test.ts +0 -247
- package/test/compute.test.ts +0 -861
- package/test/database.test.ts +0 -523
- package/test/deployment.test.ts +0 -499
- package/test/dns.test.ts +0 -270
- package/test/email.test.ts +0 -439
- package/test/filesystem.test.ts +0 -382
- package/test/integration.test.ts +0 -350
- package/test/messaging.test.ts +0 -514
- package/test/monitoring.test.ts +0 -634
- package/test/network.test.ts +0 -425
- package/test/permissions.test.ts +0 -488
- package/test/queue.test.ts +0 -484
- package/test/registry.test.ts +0 -306
- package/test/security.test.ts +0 -462
- package/test/storage.test.ts +0 -463
- package/test/template-validator.test.ts +0 -559
- package/test/workflow.test.ts +0 -592
- package/tsconfig.json +0 -16
- package/tsconfig.tsbuildinfo +0 -1
package/src/aws/credentials.ts
DELETED
|
@@ -1,545 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AWS Credential Providers
|
|
3
|
-
*
|
|
4
|
-
* Automatically load AWS credentials from various sources:
|
|
5
|
-
* - Environment variables
|
|
6
|
-
* - Shared credentials file (~/.aws/credentials)
|
|
7
|
-
* - EC2 instance metadata
|
|
8
|
-
* - ECS task metadata
|
|
9
|
-
* - Web identity token (for Kubernetes/IRSA)
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { readFileSync, existsSync } from 'node:fs'
|
|
13
|
-
import { homedir } from 'node:os'
|
|
14
|
-
import { join } from 'node:path'
|
|
15
|
-
|
|
16
|
-
export interface AWSCredentials {
|
|
17
|
-
accessKeyId: string
|
|
18
|
-
secretAccessKey: string
|
|
19
|
-
sessionToken?: string
|
|
20
|
-
expiration?: Date
|
|
21
|
-
region?: string
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface CredentialProviderOptions {
|
|
25
|
-
/** Profile name for shared credentials file (default: 'default' or AWS_PROFILE env var) */
|
|
26
|
-
profile?: string
|
|
27
|
-
/** Path to credentials file (default: ~/.aws/credentials) */
|
|
28
|
-
credentialsFile?: string
|
|
29
|
-
/** Path to config file (default: ~/.aws/config) */
|
|
30
|
-
configFile?: string
|
|
31
|
-
/** Timeout for metadata requests in ms (default: 1000) */
|
|
32
|
-
timeout?: number
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Get credentials from environment variables
|
|
37
|
-
* Checks: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
|
|
38
|
-
*/
|
|
39
|
-
export function fromEnvironment(): AWSCredentials | null {
|
|
40
|
-
const accessKeyId = process.env.AWS_ACCESS_KEY_ID
|
|
41
|
-
const secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY
|
|
42
|
-
|
|
43
|
-
if (!accessKeyId || !secretAccessKey) {
|
|
44
|
-
return null
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
accessKeyId,
|
|
49
|
-
secretAccessKey,
|
|
50
|
-
sessionToken: process.env.AWS_SESSION_TOKEN,
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Get credentials from shared credentials file (~/.aws/credentials)
|
|
56
|
-
*/
|
|
57
|
-
export function fromSharedCredentials(options?: CredentialProviderOptions): AWSCredentials | null {
|
|
58
|
-
const profile = options?.profile || process.env.AWS_PROFILE || 'default'
|
|
59
|
-
const credentialsPath = options?.credentialsFile || join(homedir(), '.aws', 'credentials')
|
|
60
|
-
|
|
61
|
-
if (!existsSync(credentialsPath)) {
|
|
62
|
-
return null
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
const content = readFileSync(credentialsPath, 'utf-8')
|
|
67
|
-
return parseCredentialsFile(content, profile)
|
|
68
|
-
} catch {
|
|
69
|
-
return null
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Parse INI-style credentials file
|
|
75
|
-
*/
|
|
76
|
-
function parseCredentialsFile(content: string, profile: string): AWSCredentials | null {
|
|
77
|
-
const lines = content.split('\n')
|
|
78
|
-
let currentProfile: string | null = null
|
|
79
|
-
let accessKeyId: string | undefined
|
|
80
|
-
let secretAccessKey: string | undefined
|
|
81
|
-
let sessionToken: string | undefined
|
|
82
|
-
|
|
83
|
-
for (const line of lines) {
|
|
84
|
-
const trimmed = line.trim()
|
|
85
|
-
|
|
86
|
-
// Skip comments and empty lines
|
|
87
|
-
if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith(';')) {
|
|
88
|
-
continue
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Check for profile header
|
|
92
|
-
const profileMatch = trimmed.match(/^\[([^\]]+)\]$/)
|
|
93
|
-
if (profileMatch) {
|
|
94
|
-
// If we were processing the target profile, we're done
|
|
95
|
-
if (currentProfile === profile && accessKeyId && secretAccessKey) {
|
|
96
|
-
return { accessKeyId, secretAccessKey, sessionToken }
|
|
97
|
-
}
|
|
98
|
-
currentProfile = profileMatch[1]
|
|
99
|
-
accessKeyId = undefined
|
|
100
|
-
secretAccessKey = undefined
|
|
101
|
-
sessionToken = undefined
|
|
102
|
-
continue
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Parse key-value pairs
|
|
106
|
-
if (currentProfile === profile) {
|
|
107
|
-
const [key, ...valueParts] = trimmed.split('=')
|
|
108
|
-
const value = valueParts.join('=').trim()
|
|
109
|
-
|
|
110
|
-
switch (key.trim().toLowerCase()) {
|
|
111
|
-
case 'aws_access_key_id':
|
|
112
|
-
accessKeyId = value
|
|
113
|
-
break
|
|
114
|
-
case 'aws_secret_access_key':
|
|
115
|
-
secretAccessKey = value
|
|
116
|
-
break
|
|
117
|
-
case 'aws_session_token':
|
|
118
|
-
sessionToken = value
|
|
119
|
-
break
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Check if we found credentials for the target profile
|
|
125
|
-
if (currentProfile === profile && accessKeyId && secretAccessKey) {
|
|
126
|
-
return { accessKeyId, secretAccessKey, sessionToken }
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return null
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Get credentials from EC2 instance metadata service (IMDSv2)
|
|
134
|
-
*/
|
|
135
|
-
export async function fromEC2Metadata(options?: CredentialProviderOptions): Promise<AWSCredentials | null> {
|
|
136
|
-
const timeout = options?.timeout ?? 1000
|
|
137
|
-
const metadataUrl = 'http://169.254.169.254'
|
|
138
|
-
|
|
139
|
-
try {
|
|
140
|
-
// Step 1: Get IMDSv2 token
|
|
141
|
-
const tokenResponse = await fetchWithTimeout(
|
|
142
|
-
`${metadataUrl}/latest/api/token`,
|
|
143
|
-
{
|
|
144
|
-
method: 'PUT',
|
|
145
|
-
headers: { 'X-aws-ec2-metadata-token-ttl-seconds': '21600' },
|
|
146
|
-
},
|
|
147
|
-
timeout,
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
if (!tokenResponse.ok) {
|
|
151
|
-
return null
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const token = await tokenResponse.text()
|
|
155
|
-
|
|
156
|
-
// Step 2: Get IAM role name
|
|
157
|
-
const roleResponse = await fetchWithTimeout(
|
|
158
|
-
`${metadataUrl}/latest/meta-data/iam/security-credentials/`,
|
|
159
|
-
{ headers: { 'X-aws-ec2-metadata-token': token } },
|
|
160
|
-
timeout,
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
if (!roleResponse.ok) {
|
|
164
|
-
return null
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const roleName = (await roleResponse.text()).trim()
|
|
168
|
-
|
|
169
|
-
// Step 3: Get credentials for the role
|
|
170
|
-
const credentialsResponse = await fetchWithTimeout(
|
|
171
|
-
`${metadataUrl}/latest/meta-data/iam/security-credentials/${roleName}`,
|
|
172
|
-
{ headers: { 'X-aws-ec2-metadata-token': token } },
|
|
173
|
-
timeout,
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
if (!credentialsResponse.ok) {
|
|
177
|
-
return null
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const data = await credentialsResponse.json() as {
|
|
181
|
-
AccessKeyId: string
|
|
182
|
-
SecretAccessKey: string
|
|
183
|
-
Token: string
|
|
184
|
-
Expiration: string
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return {
|
|
188
|
-
accessKeyId: data.AccessKeyId,
|
|
189
|
-
secretAccessKey: data.SecretAccessKey,
|
|
190
|
-
sessionToken: data.Token,
|
|
191
|
-
expiration: new Date(data.Expiration),
|
|
192
|
-
}
|
|
193
|
-
} catch {
|
|
194
|
-
return null
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Get credentials from ECS task metadata
|
|
200
|
-
*/
|
|
201
|
-
export async function fromECSMetadata(options?: CredentialProviderOptions): Promise<AWSCredentials | null> {
|
|
202
|
-
const timeout = options?.timeout ?? 1000
|
|
203
|
-
|
|
204
|
-
// Check for ECS metadata URI
|
|
205
|
-
const relativeUri = process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
|
|
206
|
-
const fullUri = process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI
|
|
207
|
-
|
|
208
|
-
let credentialsUrl: string | null = null
|
|
209
|
-
|
|
210
|
-
if (relativeUri) {
|
|
211
|
-
credentialsUrl = `http://169.254.170.2${relativeUri}`
|
|
212
|
-
} else if (fullUri) {
|
|
213
|
-
credentialsUrl = fullUri
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (!credentialsUrl) {
|
|
217
|
-
return null
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
try {
|
|
221
|
-
const headers: Record<string, string> = {}
|
|
222
|
-
|
|
223
|
-
// Add authorization token if present
|
|
224
|
-
const authToken = process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN
|
|
225
|
-
if (authToken) {
|
|
226
|
-
headers['Authorization'] = authToken
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const response = await fetchWithTimeout(credentialsUrl, { headers }, timeout)
|
|
230
|
-
|
|
231
|
-
if (!response.ok) {
|
|
232
|
-
return null
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const data = await response.json() as {
|
|
236
|
-
AccessKeyId: string
|
|
237
|
-
SecretAccessKey: string
|
|
238
|
-
Token: string
|
|
239
|
-
Expiration: string
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return {
|
|
243
|
-
accessKeyId: data.AccessKeyId,
|
|
244
|
-
secretAccessKey: data.SecretAccessKey,
|
|
245
|
-
sessionToken: data.Token,
|
|
246
|
-
expiration: new Date(data.Expiration),
|
|
247
|
-
}
|
|
248
|
-
} catch {
|
|
249
|
-
return null
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Get credentials from web identity token (for Kubernetes/IRSA)
|
|
255
|
-
*/
|
|
256
|
-
export async function fromWebIdentity(options?: CredentialProviderOptions): Promise<AWSCredentials | null> {
|
|
257
|
-
const timeout = options?.timeout ?? 5000
|
|
258
|
-
|
|
259
|
-
const tokenFile = process.env.AWS_WEB_IDENTITY_TOKEN_FILE
|
|
260
|
-
const roleArn = process.env.AWS_ROLE_ARN
|
|
261
|
-
const sessionName = process.env.AWS_ROLE_SESSION_NAME || 'ts-cloud-session'
|
|
262
|
-
|
|
263
|
-
if (!tokenFile || !roleArn) {
|
|
264
|
-
return null
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
try {
|
|
268
|
-
// Read the web identity token
|
|
269
|
-
const token = readFileSync(tokenFile, 'utf-8').trim()
|
|
270
|
-
|
|
271
|
-
// Determine region for STS endpoint
|
|
272
|
-
const region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1'
|
|
273
|
-
const stsEndpoint = region.startsWith('us-gov')
|
|
274
|
-
? `https://sts.${region}.amazonaws.com`
|
|
275
|
-
: region === 'us-east-1'
|
|
276
|
-
? 'https://sts.amazonaws.com'
|
|
277
|
-
: `https://sts.${region}.amazonaws.com`
|
|
278
|
-
|
|
279
|
-
// Call STS AssumeRoleWithWebIdentity
|
|
280
|
-
const params = new URLSearchParams({
|
|
281
|
-
Action: 'AssumeRoleWithWebIdentity',
|
|
282
|
-
Version: '2011-06-15',
|
|
283
|
-
RoleArn: roleArn,
|
|
284
|
-
RoleSessionName: sessionName,
|
|
285
|
-
WebIdentityToken: token,
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
const response = await fetchWithTimeout(
|
|
289
|
-
`${stsEndpoint}/?${params.toString()}`,
|
|
290
|
-
{ method: 'POST' },
|
|
291
|
-
timeout,
|
|
292
|
-
)
|
|
293
|
-
|
|
294
|
-
if (!response.ok) {
|
|
295
|
-
return null
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
const text = await response.text()
|
|
299
|
-
|
|
300
|
-
// Parse XML response
|
|
301
|
-
const accessKeyId = extractXmlValue(text, 'AccessKeyId')
|
|
302
|
-
const secretAccessKey = extractXmlValue(text, 'SecretAccessKey')
|
|
303
|
-
const sessionToken = extractXmlValue(text, 'SessionToken')
|
|
304
|
-
const expiration = extractXmlValue(text, 'Expiration')
|
|
305
|
-
|
|
306
|
-
if (!accessKeyId || !secretAccessKey) {
|
|
307
|
-
return null
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return {
|
|
311
|
-
accessKeyId,
|
|
312
|
-
secretAccessKey,
|
|
313
|
-
sessionToken: sessionToken ?? undefined,
|
|
314
|
-
expiration: expiration ? new Date(expiration) : undefined,
|
|
315
|
-
}
|
|
316
|
-
} catch {
|
|
317
|
-
return null
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Get credentials using the default credential chain
|
|
323
|
-
* Tries providers in order: Environment -> Shared Credentials -> Web Identity -> ECS -> EC2
|
|
324
|
-
*/
|
|
325
|
-
export async function getCredentials(options?: CredentialProviderOptions): Promise<AWSCredentials> {
|
|
326
|
-
// 1. Environment variables (fastest, most common in containers)
|
|
327
|
-
const envCreds = fromEnvironment()
|
|
328
|
-
if (envCreds) {
|
|
329
|
-
return envCreds
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// 2. Shared credentials file (common for local development)
|
|
333
|
-
const sharedCreds = fromSharedCredentials(options)
|
|
334
|
-
if (sharedCreds) {
|
|
335
|
-
return sharedCreds
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// 3. Web identity token (Kubernetes/IRSA)
|
|
339
|
-
const webIdentityCreds = await fromWebIdentity(options)
|
|
340
|
-
if (webIdentityCreds) {
|
|
341
|
-
return webIdentityCreds
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// 4. ECS task metadata
|
|
345
|
-
const ecsCreds = await fromECSMetadata(options)
|
|
346
|
-
if (ecsCreds) {
|
|
347
|
-
return ecsCreds
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// 5. EC2 instance metadata
|
|
351
|
-
const ec2Creds = await fromEC2Metadata(options)
|
|
352
|
-
if (ec2Creds) {
|
|
353
|
-
return ec2Creds
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
throw new Error(
|
|
357
|
-
'Could not find AWS credentials. ' +
|
|
358
|
-
'Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, ' +
|
|
359
|
-
'or configure ~/.aws/credentials, or run on an EC2 instance with an IAM role.',
|
|
360
|
-
)
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Create a credential provider that caches and auto-refreshes credentials
|
|
365
|
-
*/
|
|
366
|
-
export function createCredentialProvider(options?: CredentialProviderOptions): () => Promise<AWSCredentials> {
|
|
367
|
-
let cachedCredentials: AWSCredentials | null = null
|
|
368
|
-
let refreshPromise: Promise<AWSCredentials> | null = null
|
|
369
|
-
|
|
370
|
-
return async () => {
|
|
371
|
-
// Check if credentials are still valid (with 5 minute buffer)
|
|
372
|
-
if (cachedCredentials) {
|
|
373
|
-
if (!cachedCredentials.expiration) {
|
|
374
|
-
return cachedCredentials
|
|
375
|
-
}
|
|
376
|
-
const bufferMs = 5 * 60 * 1000 // 5 minutes
|
|
377
|
-
if (cachedCredentials.expiration.getTime() - Date.now() > bufferMs) {
|
|
378
|
-
return cachedCredentials
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// Avoid multiple concurrent refresh calls
|
|
383
|
-
if (refreshPromise) {
|
|
384
|
-
return refreshPromise
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
refreshPromise = getCredentials(options)
|
|
388
|
-
.then((creds) => {
|
|
389
|
-
cachedCredentials = creds
|
|
390
|
-
refreshPromise = null
|
|
391
|
-
return creds
|
|
392
|
-
})
|
|
393
|
-
.catch((err) => {
|
|
394
|
-
refreshPromise = null
|
|
395
|
-
throw err
|
|
396
|
-
})
|
|
397
|
-
|
|
398
|
-
return refreshPromise
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* Helper to fetch with timeout
|
|
404
|
-
*/
|
|
405
|
-
async function fetchWithTimeout(
|
|
406
|
-
url: string,
|
|
407
|
-
options: RequestInit,
|
|
408
|
-
timeoutMs: number,
|
|
409
|
-
): Promise<Response> {
|
|
410
|
-
const controller = new AbortController()
|
|
411
|
-
const timeoutId = setTimeout(() => controller.abort(), timeoutMs)
|
|
412
|
-
|
|
413
|
-
try {
|
|
414
|
-
const response = await fetch(url, { ...options, signal: controller.signal })
|
|
415
|
-
clearTimeout(timeoutId)
|
|
416
|
-
return response
|
|
417
|
-
} catch (error) {
|
|
418
|
-
clearTimeout(timeoutId)
|
|
419
|
-
throw error
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* Extract value from XML element
|
|
425
|
-
*/
|
|
426
|
-
function extractXmlValue(xml: string, tagName: string): string | null {
|
|
427
|
-
const regex = new RegExp(`<${tagName}>([^<]+)</${tagName}>`)
|
|
428
|
-
const match = xml.match(regex)
|
|
429
|
-
return match ? match[1] : null
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// ============================================================================
|
|
433
|
-
// Backwards Compatibility Exports
|
|
434
|
-
// ============================================================================
|
|
435
|
-
|
|
436
|
-
export interface AWSProfile {
|
|
437
|
-
name: string
|
|
438
|
-
accessKeyId: string
|
|
439
|
-
secretAccessKey: string
|
|
440
|
-
sessionToken?: string
|
|
441
|
-
region?: string
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
/**
|
|
445
|
-
* Resolve AWS credentials from various sources
|
|
446
|
-
* @deprecated Use getCredentials() instead
|
|
447
|
-
*/
|
|
448
|
-
export async function resolveCredentials(profile?: string): Promise<AWSCredentials> {
|
|
449
|
-
return getCredentials({ profile })
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
/**
|
|
453
|
-
* Resolve AWS region from environment or config
|
|
454
|
-
*/
|
|
455
|
-
export function resolveRegion(profile?: string): string {
|
|
456
|
-
// Check environment variables first
|
|
457
|
-
const envRegion = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION
|
|
458
|
-
if (envRegion) {
|
|
459
|
-
return envRegion
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// Try to read from config file
|
|
463
|
-
const configPath = join(homedir(), '.aws', 'config')
|
|
464
|
-
if (existsSync(configPath)) {
|
|
465
|
-
try {
|
|
466
|
-
const content = readFileSync(configPath, 'utf-8')
|
|
467
|
-
const targetProfile = profile || process.env.AWS_PROFILE || 'default'
|
|
468
|
-
const profileHeader = targetProfile === 'default' ? '[default]' : `[profile ${targetProfile}]`
|
|
469
|
-
|
|
470
|
-
const lines = content.split('\n')
|
|
471
|
-
let inProfile = false
|
|
472
|
-
|
|
473
|
-
for (const line of lines) {
|
|
474
|
-
const trimmed = line.trim()
|
|
475
|
-
|
|
476
|
-
if (trimmed.startsWith('[')) {
|
|
477
|
-
inProfile = trimmed === profileHeader
|
|
478
|
-
continue
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
if (inProfile && trimmed.startsWith('region')) {
|
|
482
|
-
const [, value] = trimmed.split('=')
|
|
483
|
-
if (value) {
|
|
484
|
-
return value.trim()
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
} catch {
|
|
489
|
-
// Ignore errors
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
// Default to us-east-1
|
|
494
|
-
return 'us-east-1'
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
/**
|
|
498
|
-
* Get AWS account ID using STS GetCallerIdentity
|
|
499
|
-
*/
|
|
500
|
-
export async function getAccountId(credentials?: AWSCredentials): Promise<string> {
|
|
501
|
-
const creds = credentials || await getCredentials()
|
|
502
|
-
const region = resolveRegion()
|
|
503
|
-
|
|
504
|
-
// Import signRequest dynamically to avoid circular dependency
|
|
505
|
-
const { signRequest } = await import('./signature')
|
|
506
|
-
|
|
507
|
-
const stsEndpoint = region.startsWith('us-gov')
|
|
508
|
-
? `https://sts.${region}.amazonaws.com`
|
|
509
|
-
: region === 'us-east-1'
|
|
510
|
-
? 'https://sts.amazonaws.com'
|
|
511
|
-
: `https://sts.${region}.amazonaws.com`
|
|
512
|
-
|
|
513
|
-
const body = 'Action=GetCallerIdentity&Version=2011-06-15'
|
|
514
|
-
|
|
515
|
-
const signed = signRequest({
|
|
516
|
-
method: 'POST',
|
|
517
|
-
url: stsEndpoint,
|
|
518
|
-
body,
|
|
519
|
-
headers: {
|
|
520
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
521
|
-
},
|
|
522
|
-
...creds,
|
|
523
|
-
service: 'sts',
|
|
524
|
-
region,
|
|
525
|
-
})
|
|
526
|
-
|
|
527
|
-
const response = await fetch(signed.url, {
|
|
528
|
-
method: signed.method,
|
|
529
|
-
headers: signed.headers,
|
|
530
|
-
body: signed.body,
|
|
531
|
-
})
|
|
532
|
-
|
|
533
|
-
if (!response.ok) {
|
|
534
|
-
throw new Error(`Failed to get account ID: ${await response.text()}`)
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
const xml = await response.text()
|
|
538
|
-
const accountId = extractXmlValue(xml, 'Account')
|
|
539
|
-
|
|
540
|
-
if (!accountId) {
|
|
541
|
-
throw new Error('Failed to parse account ID from response')
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
return accountId
|
|
545
|
-
}
|
package/src/aws/index.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
// AWS Signature V4
|
|
2
|
-
export {
|
|
3
|
-
signRequest,
|
|
4
|
-
signRequestAsync,
|
|
5
|
-
makeAWSRequest,
|
|
6
|
-
makeAWSRequestAsync,
|
|
7
|
-
makeAWSRequestOnce,
|
|
8
|
-
createPresignedUrl,
|
|
9
|
-
createPresignedUrlAsync,
|
|
10
|
-
detectServiceRegion,
|
|
11
|
-
clearSigningKeyCache,
|
|
12
|
-
getSigningKeyCacheSize,
|
|
13
|
-
parseXMLResponse,
|
|
14
|
-
parseJSONResponse,
|
|
15
|
-
isNodeCryptoAvailable,
|
|
16
|
-
isWebCryptoAvailable,
|
|
17
|
-
} from './signature'
|
|
18
|
-
|
|
19
|
-
export type {
|
|
20
|
-
SignatureOptions,
|
|
21
|
-
SignedRequest,
|
|
22
|
-
PresignedUrlOptions,
|
|
23
|
-
RetryOptions,
|
|
24
|
-
} from './signature'
|
|
25
|
-
|
|
26
|
-
// AWS Credentials
|
|
27
|
-
export {
|
|
28
|
-
// New credential providers
|
|
29
|
-
fromEnvironment,
|
|
30
|
-
fromSharedCredentials,
|
|
31
|
-
fromEC2Metadata,
|
|
32
|
-
fromECSMetadata,
|
|
33
|
-
fromWebIdentity,
|
|
34
|
-
getCredentials,
|
|
35
|
-
createCredentialProvider,
|
|
36
|
-
// Backwards compatibility
|
|
37
|
-
resolveCredentials,
|
|
38
|
-
resolveRegion,
|
|
39
|
-
getAccountId,
|
|
40
|
-
} from './credentials'
|
|
41
|
-
|
|
42
|
-
export type {
|
|
43
|
-
AWSCredentials,
|
|
44
|
-
AWSProfile,
|
|
45
|
-
CredentialProviderOptions,
|
|
46
|
-
} from './credentials'
|
|
47
|
-
|
|
48
|
-
// CloudFormation Client
|
|
49
|
-
export {
|
|
50
|
-
CloudFormationClient,
|
|
51
|
-
} from './cloudformation'
|
|
52
|
-
|
|
53
|
-
export type {
|
|
54
|
-
CloudFormationStack,
|
|
55
|
-
CreateStackOptions,
|
|
56
|
-
UpdateStackOptions,
|
|
57
|
-
StackEvent,
|
|
58
|
-
} from './cloudformation'
|
|
59
|
-
|
|
60
|
-
// S3 Client (High-Level API)
|
|
61
|
-
export {
|
|
62
|
-
S3Client,
|
|
63
|
-
S3Error,
|
|
64
|
-
createS3Client,
|
|
65
|
-
} from './s3'
|
|
66
|
-
|
|
67
|
-
export type {
|
|
68
|
-
S3ClientOptions,
|
|
69
|
-
GetObjectOptions,
|
|
70
|
-
PutObjectOptions,
|
|
71
|
-
ListObjectsOptions,
|
|
72
|
-
ListObjectsResult,
|
|
73
|
-
S3Object,
|
|
74
|
-
HeadObjectResult,
|
|
75
|
-
CopyObjectOptions,
|
|
76
|
-
MultipartUploadOptions,
|
|
77
|
-
MultipartProgress,
|
|
78
|
-
} from './s3'
|
|
79
|
-
|
|
80
|
-
// CloudFront Client
|
|
81
|
-
export {
|
|
82
|
-
CloudFrontClient,
|
|
83
|
-
} from './cloudfront'
|
|
84
|
-
|
|
85
|
-
export type {
|
|
86
|
-
InvalidationOptions,
|
|
87
|
-
} from './cloudfront'
|