@stacksjs/ts-cloud 0.7.4 → 0.7.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.
Files changed (58) hide show
  1. package/dist/aws/index.js +259 -0
  2. package/dist/bin/cli.js +316 -316
  3. package/dist/chunk-0wxyppza.js +146 -0
  4. package/dist/chunk-3knnr7wh.js +601 -0
  5. package/dist/chunk-3rsfns7x.js +10427 -0
  6. package/dist/chunk-93hjhs78.js +1752 -0
  7. package/dist/chunk-arsh1g5h.js +1749 -0
  8. package/dist/chunk-b82pbxyp.js +1572 -0
  9. package/dist/chunk-c6rgvg1j.js +46124 -0
  10. package/dist/chunk-d2p5n2aq.js +23 -0
  11. package/dist/chunk-d7p84vz5.js +1699 -0
  12. package/dist/chunk-dpkk640m.js +4392 -0
  13. package/dist/chunk-eq08r166.js +8 -0
  14. package/dist/chunk-hsk6fe6x.js +371 -0
  15. package/dist/chunk-mj1tmhte.js +13 -0
  16. package/dist/chunk-p6309384.js +12828 -0
  17. package/dist/chunk-pegd7rmf.js +10 -0
  18. package/dist/chunk-pqfzdg68.js +12 -0
  19. package/dist/chunk-qpj3edwz.js +601 -0
  20. package/dist/chunk-tjjgajbh.js +1032 -0
  21. package/dist/chunk-tnztxpcb.js +630 -0
  22. package/dist/chunk-tt4kxske.js +1788 -0
  23. package/dist/chunk-v0bahtg2.js +4 -0
  24. package/dist/chunk-vd87cpvn.js +1754 -0
  25. package/dist/chunk-zn0nxxa8.js +1779 -0
  26. package/dist/deploy/index.js +87 -0
  27. package/dist/dns/index.js +31 -0
  28. package/dist/drivers/hetzner/provision.d.ts +53 -0
  29. package/dist/drivers/index.d.ts +5 -1
  30. package/dist/drivers/index.js +98 -0
  31. package/dist/drivers/shared/remote-exec.d.ts +47 -0
  32. package/dist/index.d.ts +1 -1
  33. package/dist/index.js +4383 -91358
  34. package/dist/push/index.js +509 -0
  35. package/dist/ui/index.html +3 -3
  36. package/dist/ui/server/actions.html +3 -3
  37. package/dist/ui/server/backups.html +3 -3
  38. package/dist/ui/server/database.html +3 -3
  39. package/dist/ui/server/deployments.html +3 -3
  40. package/dist/ui/server/firewall.html +3 -3
  41. package/dist/ui/server/logs.html +3 -3
  42. package/dist/ui/server/services.html +3 -3
  43. package/dist/ui/server/sites.html +3 -3
  44. package/dist/ui/server/ssh-keys.html +3 -3
  45. package/dist/ui/server/terminal.html +3 -3
  46. package/dist/ui/server/workers.html +3 -3
  47. package/dist/ui/serverless/alarms.html +3 -3
  48. package/dist/ui/serverless/assets.html +3 -3
  49. package/dist/ui/serverless/data.html +3 -3
  50. package/dist/ui/serverless/deployments.html +3 -3
  51. package/dist/ui/serverless/functions.html +3 -3
  52. package/dist/ui/serverless/logs.html +3 -3
  53. package/dist/ui/serverless/queues.html +3 -3
  54. package/dist/ui/serverless/scheduler.html +3 -3
  55. package/dist/ui/serverless/secrets.html +3 -3
  56. package/dist/ui/serverless/traces.html +3 -3
  57. package/dist/ui/serverless.html +3 -3
  58. package/package.json +3 -3
@@ -0,0 +1,1752 @@
1
+ import {
2
+ AWSClient
3
+ } from "./chunk-arsh1g5h.js";
4
+
5
+ // src/aws/ec2.ts
6
+ class EC2Client {
7
+ client;
8
+ region;
9
+ constructor(region = "us-east-1") {
10
+ this.region = region;
11
+ this.client = new AWSClient;
12
+ }
13
+ async describeInstances(options) {
14
+ const params = {
15
+ Action: "DescribeInstances",
16
+ Version: "2016-11-15"
17
+ };
18
+ if (options?.InstanceIds) {
19
+ options.InstanceIds.forEach((id, i) => {
20
+ params[`InstanceId.${i + 1}`] = id;
21
+ });
22
+ }
23
+ if (options?.Filters) {
24
+ options.Filters.forEach((filter, i) => {
25
+ params[`Filter.${i + 1}.Name`] = filter.Name;
26
+ filter.Values.forEach((val, j) => {
27
+ params[`Filter.${i + 1}.Value.${j + 1}`] = val;
28
+ });
29
+ });
30
+ }
31
+ if (options?.MaxResults) {
32
+ params.MaxResults = String(options.MaxResults);
33
+ }
34
+ if (options?.NextToken) {
35
+ params.NextToken = options.NextToken;
36
+ }
37
+ const result = await this.client.request({
38
+ service: "ec2",
39
+ region: this.region,
40
+ method: "POST",
41
+ path: "/",
42
+ headers: {
43
+ "Content-Type": "application/x-www-form-urlencoded"
44
+ },
45
+ body: new URLSearchParams(params).toString()
46
+ });
47
+ const response = result.DescribeInstancesResponse || result;
48
+ return {
49
+ Reservations: this.parseReservations(response.reservationSet?.item),
50
+ NextToken: response.nextToken
51
+ };
52
+ }
53
+ async getInstance(instanceId) {
54
+ const result = await this.describeInstances({ InstanceIds: [instanceId] });
55
+ return result.Reservations?.[0]?.Instances?.[0];
56
+ }
57
+ async getConsoleOutput(instanceId, latest) {
58
+ const params = {
59
+ Action: "GetConsoleOutput",
60
+ Version: "2016-11-15",
61
+ InstanceId: instanceId
62
+ };
63
+ if (latest) {
64
+ params.Latest = "true";
65
+ }
66
+ const result = await this.client.request({
67
+ service: "ec2",
68
+ region: this.region,
69
+ method: "POST",
70
+ path: "/",
71
+ headers: {
72
+ "Content-Type": "application/x-www-form-urlencoded"
73
+ },
74
+ body: new URLSearchParams(params).toString()
75
+ });
76
+ const response = result.GetConsoleOutputResponse || result;
77
+ return {
78
+ InstanceId: response.instanceId,
79
+ Output: response.output,
80
+ Timestamp: response.timestamp
81
+ };
82
+ }
83
+ async getConsoleOutputDecoded(instanceId, options) {
84
+ const result = await this.getConsoleOutput(instanceId, options?.latest);
85
+ if (!result.Output) {
86
+ return "No console output available yet";
87
+ }
88
+ const decoded = Buffer.from(result.Output, "base64").toString("utf-8");
89
+ if (options?.tailLines) {
90
+ const lines = decoded.split(`
91
+ `);
92
+ return lines.slice(-options.tailLines).join(`
93
+ `);
94
+ }
95
+ return decoded;
96
+ }
97
+ async describeInstanceStatus(options) {
98
+ const params = {
99
+ Action: "DescribeInstanceStatus",
100
+ Version: "2016-11-15"
101
+ };
102
+ if (options?.InstanceIds) {
103
+ options.InstanceIds.forEach((id, i) => {
104
+ params[`InstanceId.${i + 1}`] = id;
105
+ });
106
+ }
107
+ if (options?.IncludeAllInstances) {
108
+ params.IncludeAllInstances = "true";
109
+ }
110
+ if (options?.Filters) {
111
+ options.Filters.forEach((filter, i) => {
112
+ params[`Filter.${i + 1}.Name`] = filter.Name;
113
+ filter.Values.forEach((val, j) => {
114
+ params[`Filter.${i + 1}.Value.${j + 1}`] = val;
115
+ });
116
+ });
117
+ }
118
+ const result = await this.client.request({
119
+ service: "ec2",
120
+ region: this.region,
121
+ method: "POST",
122
+ path: "/",
123
+ headers: {
124
+ "Content-Type": "application/x-www-form-urlencoded"
125
+ },
126
+ body: new URLSearchParams(params).toString()
127
+ });
128
+ return {
129
+ InstanceStatuses: this.parseArray(result.instanceStatusSet?.item).map((item) => ({
130
+ InstanceId: item.instanceId,
131
+ InstanceState: item.instanceState ? {
132
+ Code: Number.parseInt(item.instanceState.code),
133
+ Name: item.instanceState.name
134
+ } : undefined,
135
+ InstanceStatus: item.instanceStatus ? {
136
+ Status: item.instanceStatus.status,
137
+ Details: this.parseArray(item.instanceStatus.details?.item).map((d) => ({
138
+ Name: d.name,
139
+ Status: d.status
140
+ }))
141
+ } : undefined,
142
+ SystemStatus: item.systemStatus ? {
143
+ Status: item.systemStatus.status,
144
+ Details: this.parseArray(item.systemStatus.details?.item).map((d) => ({
145
+ Name: d.name,
146
+ Status: d.status
147
+ }))
148
+ } : undefined
149
+ }))
150
+ };
151
+ }
152
+ async startInstances(instanceIds) {
153
+ const params = {
154
+ Action: "StartInstances",
155
+ Version: "2016-11-15"
156
+ };
157
+ instanceIds.forEach((id, i) => {
158
+ params[`InstanceId.${i + 1}`] = id;
159
+ });
160
+ const result = await this.client.request({
161
+ service: "ec2",
162
+ region: this.region,
163
+ method: "POST",
164
+ path: "/",
165
+ headers: {
166
+ "Content-Type": "application/x-www-form-urlencoded"
167
+ },
168
+ body: new URLSearchParams(params).toString()
169
+ });
170
+ return {
171
+ StartingInstances: this.parseArray(result.instancesSet?.item).map((item) => ({
172
+ InstanceId: item.instanceId,
173
+ CurrentState: item.currentState ? { Name: item.currentState.name } : undefined,
174
+ PreviousState: item.previousState ? { Name: item.previousState.name } : undefined
175
+ }))
176
+ };
177
+ }
178
+ async stopInstances(instanceIds, force) {
179
+ const params = {
180
+ Action: "StopInstances",
181
+ Version: "2016-11-15"
182
+ };
183
+ instanceIds.forEach((id, i) => {
184
+ params[`InstanceId.${i + 1}`] = id;
185
+ });
186
+ if (force) {
187
+ params.Force = "true";
188
+ }
189
+ const result = await this.client.request({
190
+ service: "ec2",
191
+ region: this.region,
192
+ method: "POST",
193
+ path: "/",
194
+ headers: {
195
+ "Content-Type": "application/x-www-form-urlencoded"
196
+ },
197
+ body: new URLSearchParams(params).toString()
198
+ });
199
+ return {
200
+ StoppingInstances: this.parseArray(result.instancesSet?.item).map((item) => ({
201
+ InstanceId: item.instanceId,
202
+ CurrentState: item.currentState ? { Name: item.currentState.name } : undefined,
203
+ PreviousState: item.previousState ? { Name: item.previousState.name } : undefined
204
+ }))
205
+ };
206
+ }
207
+ async rebootInstances(instanceIds) {
208
+ const params = {
209
+ Action: "RebootInstances",
210
+ Version: "2016-11-15"
211
+ };
212
+ instanceIds.forEach((id, i) => {
213
+ params[`InstanceId.${i + 1}`] = id;
214
+ });
215
+ await this.client.request({
216
+ service: "ec2",
217
+ region: this.region,
218
+ method: "POST",
219
+ path: "/",
220
+ headers: {
221
+ "Content-Type": "application/x-www-form-urlencoded"
222
+ },
223
+ body: new URLSearchParams(params).toString()
224
+ });
225
+ }
226
+ async terminateInstances(instanceIds) {
227
+ const params = {
228
+ Action: "TerminateInstances",
229
+ Version: "2016-11-15"
230
+ };
231
+ instanceIds.forEach((id, i) => {
232
+ params[`InstanceId.${i + 1}`] = id;
233
+ });
234
+ const result = await this.client.request({
235
+ service: "ec2",
236
+ region: this.region,
237
+ method: "POST",
238
+ path: "/",
239
+ headers: {
240
+ "Content-Type": "application/x-www-form-urlencoded"
241
+ },
242
+ body: new URLSearchParams(params).toString()
243
+ });
244
+ return {
245
+ TerminatingInstances: this.parseArray(result.instancesSet?.item).map((item) => ({
246
+ InstanceId: item.instanceId,
247
+ CurrentState: item.currentState ? { Name: item.currentState.name } : undefined,
248
+ PreviousState: item.previousState ? { Name: item.previousState.name } : undefined
249
+ }))
250
+ };
251
+ }
252
+ async createImage(options) {
253
+ const params = {
254
+ Action: "CreateImage",
255
+ Version: "2016-11-15",
256
+ InstanceId: options.InstanceId,
257
+ Name: options.Name
258
+ };
259
+ if (options.Description)
260
+ params.Description = options.Description;
261
+ if (options.NoReboot !== undefined)
262
+ params.NoReboot = String(options.NoReboot);
263
+ if (options.TagSpecifications) {
264
+ options.TagSpecifications.forEach((spec, i) => {
265
+ params[`TagSpecification.${i + 1}.ResourceType`] = spec.ResourceType;
266
+ spec.Tags.forEach((tag, j) => {
267
+ params[`TagSpecification.${i + 1}.Tag.${j + 1}.Key`] = tag.Key;
268
+ params[`TagSpecification.${i + 1}.Tag.${j + 1}.Value`] = tag.Value;
269
+ });
270
+ });
271
+ }
272
+ const result = await this.client.request({
273
+ service: "ec2",
274
+ region: this.region,
275
+ method: "POST",
276
+ path: "/",
277
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
278
+ body: new URLSearchParams(params).toString()
279
+ });
280
+ const response = result.CreateImageResponse || result;
281
+ return { ImageId: response.imageId };
282
+ }
283
+ async deregisterImage(imageId) {
284
+ await this.client.request({
285
+ service: "ec2",
286
+ region: this.region,
287
+ method: "POST",
288
+ path: "/",
289
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
290
+ body: new URLSearchParams({ Action: "DeregisterImage", Version: "2016-11-15", ImageId: imageId }).toString()
291
+ });
292
+ }
293
+ async describeVpcs(options) {
294
+ const params = {
295
+ Action: "DescribeVpcs",
296
+ Version: "2016-11-15"
297
+ };
298
+ if (options?.VpcIds) {
299
+ options.VpcIds.forEach((id, i) => {
300
+ params[`VpcId.${i + 1}`] = id;
301
+ });
302
+ }
303
+ if (options?.Filters) {
304
+ options.Filters.forEach((filter, i) => {
305
+ params[`Filter.${i + 1}.Name`] = filter.Name;
306
+ filter.Values.forEach((val, j) => {
307
+ params[`Filter.${i + 1}.Value.${j + 1}`] = val;
308
+ });
309
+ });
310
+ }
311
+ const result = await this.client.request({
312
+ service: "ec2",
313
+ region: this.region,
314
+ method: "POST",
315
+ path: "/",
316
+ headers: {
317
+ "Content-Type": "application/x-www-form-urlencoded"
318
+ },
319
+ body: new URLSearchParams(params).toString()
320
+ });
321
+ return {
322
+ Vpcs: this.parseArray(result.vpcSet?.item).map((item) => ({
323
+ VpcId: item.vpcId,
324
+ CidrBlock: item.cidrBlock,
325
+ State: item.state,
326
+ DhcpOptionsId: item.dhcpOptionsId,
327
+ InstanceTenancy: item.instanceTenancy,
328
+ IsDefault: item.isDefault === "true",
329
+ Tags: this.parseTags(item.tagSet?.item)
330
+ }))
331
+ };
332
+ }
333
+ async describeSubnets(options) {
334
+ const params = {
335
+ Action: "DescribeSubnets",
336
+ Version: "2016-11-15"
337
+ };
338
+ if (options?.SubnetIds) {
339
+ options.SubnetIds.forEach((id, i) => {
340
+ params[`SubnetId.${i + 1}`] = id;
341
+ });
342
+ }
343
+ if (options?.Filters) {
344
+ options.Filters.forEach((filter, i) => {
345
+ params[`Filter.${i + 1}.Name`] = filter.Name;
346
+ filter.Values.forEach((val, j) => {
347
+ params[`Filter.${i + 1}.Value.${j + 1}`] = val;
348
+ });
349
+ });
350
+ }
351
+ const result = await this.client.request({
352
+ service: "ec2",
353
+ region: this.region,
354
+ method: "POST",
355
+ path: "/",
356
+ headers: {
357
+ "Content-Type": "application/x-www-form-urlencoded"
358
+ },
359
+ body: new URLSearchParams(params).toString()
360
+ });
361
+ return {
362
+ Subnets: this.parseArray(result.subnetSet?.item).map((item) => ({
363
+ SubnetId: item.subnetId,
364
+ VpcId: item.vpcId,
365
+ CidrBlock: item.cidrBlock,
366
+ AvailabilityZone: item.availabilityZone,
367
+ AvailableIpAddressCount: Number.parseInt(item.availableIpAddressCount),
368
+ State: item.state,
369
+ MapPublicIpOnLaunch: item.mapPublicIpOnLaunch === "true",
370
+ Tags: this.parseTags(item.tagSet?.item)
371
+ }))
372
+ };
373
+ }
374
+ async describeSecurityGroups(options) {
375
+ const params = {
376
+ Action: "DescribeSecurityGroups",
377
+ Version: "2016-11-15"
378
+ };
379
+ if (options?.GroupIds) {
380
+ options.GroupIds.forEach((id, i) => {
381
+ params[`GroupId.${i + 1}`] = id;
382
+ });
383
+ }
384
+ if (options?.GroupNames) {
385
+ options.GroupNames.forEach((name, i) => {
386
+ params[`GroupName.${i + 1}`] = name;
387
+ });
388
+ }
389
+ if (options?.Filters) {
390
+ options.Filters.forEach((filter, i) => {
391
+ params[`Filter.${i + 1}.Name`] = filter.Name;
392
+ filter.Values.forEach((val, j) => {
393
+ params[`Filter.${i + 1}.Value.${j + 1}`] = val;
394
+ });
395
+ });
396
+ }
397
+ const result = await this.client.request({
398
+ service: "ec2",
399
+ region: this.region,
400
+ method: "POST",
401
+ path: "/",
402
+ headers: {
403
+ "Content-Type": "application/x-www-form-urlencoded"
404
+ },
405
+ body: new URLSearchParams(params).toString()
406
+ });
407
+ return {
408
+ SecurityGroups: this.parseArray(result.securityGroupInfo?.item).map((item) => ({
409
+ GroupId: item.groupId,
410
+ GroupName: item.groupName,
411
+ Description: item.groupDescription,
412
+ VpcId: item.vpcId,
413
+ IpPermissions: this.parseIpPermissions(item.ipPermissions?.item),
414
+ IpPermissionsEgress: this.parseIpPermissions(item.ipPermissionsEgress?.item),
415
+ Tags: this.parseTags(item.tagSet?.item)
416
+ }))
417
+ };
418
+ }
419
+ async describeInternetGateways(options) {
420
+ const params = {
421
+ Action: "DescribeInternetGateways",
422
+ Version: "2016-11-15"
423
+ };
424
+ if (options?.InternetGatewayIds) {
425
+ options.InternetGatewayIds.forEach((id, i) => {
426
+ params[`InternetGatewayId.${i + 1}`] = id;
427
+ });
428
+ }
429
+ if (options?.Filters) {
430
+ options.Filters.forEach((filter, i) => {
431
+ params[`Filter.${i + 1}.Name`] = filter.Name;
432
+ filter.Values.forEach((val, j) => {
433
+ params[`Filter.${i + 1}.Value.${j + 1}`] = val;
434
+ });
435
+ });
436
+ }
437
+ const result = await this.client.request({
438
+ service: "ec2",
439
+ region: this.region,
440
+ method: "POST",
441
+ path: "/",
442
+ headers: {
443
+ "Content-Type": "application/x-www-form-urlencoded"
444
+ },
445
+ body: new URLSearchParams(params).toString()
446
+ });
447
+ return {
448
+ InternetGateways: this.parseArray(result.internetGatewaySet?.item).map((item) => ({
449
+ InternetGatewayId: item.internetGatewayId,
450
+ Attachments: this.parseArray(item.attachmentSet?.item).map((a) => ({
451
+ VpcId: a.vpcId,
452
+ State: a.state
453
+ })),
454
+ Tags: this.parseTags(item.tagSet?.item)
455
+ }))
456
+ };
457
+ }
458
+ async describeAddresses(options) {
459
+ const params = {
460
+ Action: "DescribeAddresses",
461
+ Version: "2016-11-15"
462
+ };
463
+ if (options?.AllocationIds) {
464
+ options.AllocationIds.forEach((id, i) => {
465
+ params[`AllocationId.${i + 1}`] = id;
466
+ });
467
+ }
468
+ if (options?.PublicIps) {
469
+ options.PublicIps.forEach((ip, i) => {
470
+ params[`PublicIp.${i + 1}`] = ip;
471
+ });
472
+ }
473
+ if (options?.Filters) {
474
+ options.Filters.forEach((filter, i) => {
475
+ params[`Filter.${i + 1}.Name`] = filter.Name;
476
+ filter.Values.forEach((val, j) => {
477
+ params[`Filter.${i + 1}.Value.${j + 1}`] = val;
478
+ });
479
+ });
480
+ }
481
+ const result = await this.client.request({
482
+ service: "ec2",
483
+ region: this.region,
484
+ method: "POST",
485
+ path: "/",
486
+ headers: {
487
+ "Content-Type": "application/x-www-form-urlencoded"
488
+ },
489
+ body: new URLSearchParams(params).toString()
490
+ });
491
+ return {
492
+ Addresses: this.parseArray(result.addressesSet?.item).map((item) => ({
493
+ PublicIp: item.publicIp,
494
+ AllocationId: item.allocationId,
495
+ AssociationId: item.associationId,
496
+ InstanceId: item.instanceId,
497
+ NetworkInterfaceId: item.networkInterfaceId,
498
+ PrivateIpAddress: item.privateIpAddress,
499
+ Domain: item.domain,
500
+ Tags: this.parseTags(item.tagSet?.item)
501
+ }))
502
+ };
503
+ }
504
+ async allocateAddress(options) {
505
+ const params = {
506
+ Action: "AllocateAddress",
507
+ Version: "2016-11-15"
508
+ };
509
+ if (options?.Domain) {
510
+ params.Domain = options.Domain;
511
+ }
512
+ if (options?.TagSpecifications) {
513
+ options.TagSpecifications.forEach((spec, i) => {
514
+ params[`TagSpecification.${i + 1}.ResourceType`] = spec.ResourceType;
515
+ spec.Tags.forEach((tag, j) => {
516
+ params[`TagSpecification.${i + 1}.Tag.${j + 1}.Key`] = tag.Key;
517
+ params[`TagSpecification.${i + 1}.Tag.${j + 1}.Value`] = tag.Value;
518
+ });
519
+ });
520
+ }
521
+ const result = await this.client.request({
522
+ service: "ec2",
523
+ region: this.region,
524
+ method: "POST",
525
+ path: "/",
526
+ headers: {
527
+ "Content-Type": "application/x-www-form-urlencoded"
528
+ },
529
+ body: new URLSearchParams(params).toString()
530
+ });
531
+ return {
532
+ AllocationId: result.allocationId,
533
+ PublicIp: result.publicIp,
534
+ Domain: result.domain
535
+ };
536
+ }
537
+ async associateAddress(options) {
538
+ const params = {
539
+ Action: "AssociateAddress",
540
+ Version: "2016-11-15"
541
+ };
542
+ if (options.AllocationId) {
543
+ params.AllocationId = options.AllocationId;
544
+ }
545
+ if (options.PublicIp) {
546
+ params.PublicIp = options.PublicIp;
547
+ }
548
+ if (options.InstanceId) {
549
+ params.InstanceId = options.InstanceId;
550
+ }
551
+ if (options.NetworkInterfaceId) {
552
+ params.NetworkInterfaceId = options.NetworkInterfaceId;
553
+ }
554
+ if (options.PrivateIpAddress) {
555
+ params.PrivateIpAddress = options.PrivateIpAddress;
556
+ }
557
+ if (options.AllowReassociation) {
558
+ params.AllowReassociation = "true";
559
+ }
560
+ const result = await this.client.request({
561
+ service: "ec2",
562
+ region: this.region,
563
+ method: "POST",
564
+ path: "/",
565
+ headers: {
566
+ "Content-Type": "application/x-www-form-urlencoded"
567
+ },
568
+ body: new URLSearchParams(params).toString()
569
+ });
570
+ return {
571
+ AssociationId: result.associationId
572
+ };
573
+ }
574
+ async createTags(options) {
575
+ const params = {
576
+ Action: "CreateTags",
577
+ Version: "2016-11-15"
578
+ };
579
+ options.Resources.forEach((id, i) => {
580
+ params[`ResourceId.${i + 1}`] = id;
581
+ });
582
+ options.Tags.forEach((tag, i) => {
583
+ params[`Tag.${i + 1}.Key`] = tag.Key;
584
+ params[`Tag.${i + 1}.Value`] = tag.Value;
585
+ });
586
+ await this.client.request({
587
+ service: "ec2",
588
+ region: this.region,
589
+ method: "POST",
590
+ path: "/",
591
+ headers: {
592
+ "Content-Type": "application/x-www-form-urlencoded"
593
+ },
594
+ body: new URLSearchParams(params).toString()
595
+ });
596
+ }
597
+ async waitForInstanceState(instanceId, targetState, options) {
598
+ const maxWait = options?.maxWaitMs || 300000;
599
+ const pollInterval = options?.pollIntervalMs || 5000;
600
+ const startTime = Date.now();
601
+ while (Date.now() - startTime < maxWait) {
602
+ let instance;
603
+ try {
604
+ instance = await this.getInstance(instanceId);
605
+ } catch {
606
+ instance = undefined;
607
+ }
608
+ if (instance?.State?.Name === targetState) {
609
+ return instance;
610
+ }
611
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
612
+ }
613
+ return;
614
+ }
615
+ async createVpc(options) {
616
+ const params = {
617
+ Action: "CreateVpc",
618
+ Version: "2016-11-15",
619
+ CidrBlock: options.CidrBlock
620
+ };
621
+ if (options.InstanceTenancy) {
622
+ params.InstanceTenancy = options.InstanceTenancy;
623
+ }
624
+ if (options.TagSpecifications) {
625
+ options.TagSpecifications.forEach((spec, i) => {
626
+ params[`TagSpecification.${i + 1}.ResourceType`] = spec.ResourceType;
627
+ spec.Tags.forEach((tag, j) => {
628
+ params[`TagSpecification.${i + 1}.Tag.${j + 1}.Key`] = tag.Key;
629
+ params[`TagSpecification.${i + 1}.Tag.${j + 1}.Value`] = tag.Value;
630
+ });
631
+ });
632
+ }
633
+ const result = await this.client.request({
634
+ service: "ec2",
635
+ region: this.region,
636
+ method: "POST",
637
+ path: "/",
638
+ headers: {
639
+ "Content-Type": "application/x-www-form-urlencoded"
640
+ },
641
+ body: new URLSearchParams(params).toString()
642
+ });
643
+ const response = result.CreateVpcResponse || result;
644
+ const vpc = response.vpc;
645
+ return {
646
+ Vpc: vpc ? {
647
+ VpcId: vpc.vpcId,
648
+ CidrBlock: vpc.cidrBlock,
649
+ State: vpc.state,
650
+ DhcpOptionsId: vpc.dhcpOptionsId,
651
+ InstanceTenancy: vpc.instanceTenancy,
652
+ IsDefault: vpc.isDefault === "true",
653
+ Tags: this.parseTags(vpc.tagSet?.item)
654
+ } : undefined
655
+ };
656
+ }
657
+ async createSubnet(options) {
658
+ const params = {
659
+ Action: "CreateSubnet",
660
+ Version: "2016-11-15",
661
+ VpcId: options.VpcId,
662
+ CidrBlock: options.CidrBlock
663
+ };
664
+ if (options.AvailabilityZone) {
665
+ params.AvailabilityZone = options.AvailabilityZone;
666
+ }
667
+ if (options.TagSpecifications) {
668
+ options.TagSpecifications.forEach((spec, i) => {
669
+ params[`TagSpecification.${i + 1}.ResourceType`] = spec.ResourceType;
670
+ spec.Tags.forEach((tag, j) => {
671
+ params[`TagSpecification.${i + 1}.Tag.${j + 1}.Key`] = tag.Key;
672
+ params[`TagSpecification.${i + 1}.Tag.${j + 1}.Value`] = tag.Value;
673
+ });
674
+ });
675
+ }
676
+ const result = await this.client.request({
677
+ service: "ec2",
678
+ region: this.region,
679
+ method: "POST",
680
+ path: "/",
681
+ headers: {
682
+ "Content-Type": "application/x-www-form-urlencoded"
683
+ },
684
+ body: new URLSearchParams(params).toString()
685
+ });
686
+ const response = result.CreateSubnetResponse || result;
687
+ const subnet = response.subnet;
688
+ return {
689
+ Subnet: subnet ? {
690
+ SubnetId: subnet.subnetId,
691
+ VpcId: subnet.vpcId,
692
+ CidrBlock: subnet.cidrBlock,
693
+ AvailabilityZone: subnet.availabilityZone,
694
+ AvailableIpAddressCount: subnet.availableIpAddressCount ? Number.parseInt(subnet.availableIpAddressCount) : undefined,
695
+ State: subnet.state,
696
+ MapPublicIpOnLaunch: subnet.mapPublicIpOnLaunch === "true",
697
+ Tags: this.parseTags(subnet.tagSet?.item)
698
+ } : undefined
699
+ };
700
+ }
701
+ async modifySubnetAttribute(options) {
702
+ const params = {
703
+ Action: "ModifySubnetAttribute",
704
+ Version: "2016-11-15",
705
+ SubnetId: options.SubnetId
706
+ };
707
+ if (options.MapPublicIpOnLaunch !== undefined) {
708
+ params["MapPublicIpOnLaunch.Value"] = String(options.MapPublicIpOnLaunch.Value);
709
+ }
710
+ await this.client.request({
711
+ service: "ec2",
712
+ region: this.region,
713
+ method: "POST",
714
+ path: "/",
715
+ headers: {
716
+ "Content-Type": "application/x-www-form-urlencoded"
717
+ },
718
+ body: new URLSearchParams(params).toString()
719
+ });
720
+ }
721
+ async createSecurityGroup(options) {
722
+ const params = {
723
+ Action: "CreateSecurityGroup",
724
+ Version: "2016-11-15",
725
+ GroupName: options.GroupName,
726
+ GroupDescription: options.Description
727
+ };
728
+ if (options.VpcId) {
729
+ params.VpcId = options.VpcId;
730
+ }
731
+ if (options.TagSpecifications) {
732
+ options.TagSpecifications.forEach((spec, i) => {
733
+ params[`TagSpecification.${i + 1}.ResourceType`] = spec.ResourceType;
734
+ spec.Tags.forEach((tag, j) => {
735
+ params[`TagSpecification.${i + 1}.Tag.${j + 1}.Key`] = tag.Key;
736
+ params[`TagSpecification.${i + 1}.Tag.${j + 1}.Value`] = tag.Value;
737
+ });
738
+ });
739
+ }
740
+ const result = await this.client.request({
741
+ service: "ec2",
742
+ region: this.region,
743
+ method: "POST",
744
+ path: "/",
745
+ headers: {
746
+ "Content-Type": "application/x-www-form-urlencoded"
747
+ },
748
+ body: new URLSearchParams(params).toString()
749
+ });
750
+ const response = result.CreateSecurityGroupResponse || result;
751
+ return {
752
+ GroupId: response.groupId
753
+ };
754
+ }
755
+ async authorizeSecurityGroupIngress(options) {
756
+ const params = {
757
+ Action: "AuthorizeSecurityGroupIngress",
758
+ Version: "2016-11-15",
759
+ GroupId: options.GroupId
760
+ };
761
+ this.encodeIpPermissions(params, options.IpPermissions);
762
+ await this.client.request({
763
+ service: "ec2",
764
+ region: this.region,
765
+ method: "POST",
766
+ path: "/",
767
+ headers: {
768
+ "Content-Type": "application/x-www-form-urlencoded"
769
+ },
770
+ body: new URLSearchParams(params).toString()
771
+ });
772
+ }
773
+ async authorizeSecurityGroupEgress(options) {
774
+ const params = {
775
+ Action: "AuthorizeSecurityGroupEgress",
776
+ Version: "2016-11-15",
777
+ GroupId: options.GroupId
778
+ };
779
+ this.encodeIpPermissions(params, options.IpPermissions);
780
+ await this.client.request({
781
+ service: "ec2",
782
+ region: this.region,
783
+ method: "POST",
784
+ path: "/",
785
+ headers: {
786
+ "Content-Type": "application/x-www-form-urlencoded"
787
+ },
788
+ body: new URLSearchParams(params).toString()
789
+ });
790
+ }
791
+ async describeRouteTables(options) {
792
+ const params = {
793
+ Action: "DescribeRouteTables",
794
+ Version: "2016-11-15"
795
+ };
796
+ if (options?.RouteTableIds) {
797
+ options.RouteTableIds.forEach((id, i) => {
798
+ params[`RouteTableId.${i + 1}`] = id;
799
+ });
800
+ }
801
+ if (options?.Filters) {
802
+ options.Filters.forEach((filter, i) => {
803
+ params[`Filter.${i + 1}.Name`] = filter.Name;
804
+ filter.Values.forEach((val, j) => {
805
+ params[`Filter.${i + 1}.Value.${j + 1}`] = val;
806
+ });
807
+ });
808
+ }
809
+ const result = await this.client.request({
810
+ service: "ec2",
811
+ region: this.region,
812
+ method: "POST",
813
+ path: "/",
814
+ headers: {
815
+ "Content-Type": "application/x-www-form-urlencoded"
816
+ },
817
+ body: new URLSearchParams(params).toString()
818
+ });
819
+ const response = result.DescribeRouteTablesResponse || result;
820
+ return {
821
+ RouteTables: this.parseArray(response.routeTableSet?.item).map((item) => ({
822
+ RouteTableId: item.routeTableId,
823
+ VpcId: item.vpcId,
824
+ Routes: this.parseArray(item.routeSet?.item).map((r) => ({
825
+ DestinationCidrBlock: r.destinationCidrBlock,
826
+ GatewayId: r.gatewayId,
827
+ NatGatewayId: r.natGatewayId,
828
+ State: r.state
829
+ })),
830
+ Associations: this.parseArray(item.associationSet?.item).map((a) => ({
831
+ RouteTableAssociationId: a.routeTableAssociationId,
832
+ SubnetId: a.subnetId,
833
+ Main: a.main === "true" || a.main === true
834
+ })),
835
+ Tags: this.parseTags(item.tagSet?.item)
836
+ }))
837
+ };
838
+ }
839
+ async deleteVpc(vpcId) {
840
+ const params = {
841
+ Action: "DeleteVpc",
842
+ Version: "2016-11-15",
843
+ VpcId: vpcId
844
+ };
845
+ await this.client.request({
846
+ service: "ec2",
847
+ region: this.region,
848
+ method: "POST",
849
+ path: "/",
850
+ headers: {
851
+ "Content-Type": "application/x-www-form-urlencoded"
852
+ },
853
+ body: new URLSearchParams(params).toString()
854
+ });
855
+ }
856
+ async deleteSubnet(subnetId) {
857
+ const params = {
858
+ Action: "DeleteSubnet",
859
+ Version: "2016-11-15",
860
+ SubnetId: subnetId
861
+ };
862
+ await this.client.request({
863
+ service: "ec2",
864
+ region: this.region,
865
+ method: "POST",
866
+ path: "/",
867
+ headers: {
868
+ "Content-Type": "application/x-www-form-urlencoded"
869
+ },
870
+ body: new URLSearchParams(params).toString()
871
+ });
872
+ }
873
+ async deleteSecurityGroup(groupId) {
874
+ await this.client.request({
875
+ service: "ec2",
876
+ region: this.region,
877
+ method: "POST",
878
+ path: "/",
879
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
880
+ body: new URLSearchParams({ Action: "DeleteSecurityGroup", Version: "2016-11-15", GroupId: groupId }).toString()
881
+ });
882
+ }
883
+ async describeNetworkInterfaces(options) {
884
+ const params = {
885
+ Action: "DescribeNetworkInterfaces",
886
+ Version: "2016-11-15"
887
+ };
888
+ if (options?.NetworkInterfaceIds) {
889
+ options.NetworkInterfaceIds.forEach((id, i) => {
890
+ params[`NetworkInterfaceId.${i + 1}`] = id;
891
+ });
892
+ }
893
+ if (options?.Filters) {
894
+ options.Filters.forEach((filter, i) => {
895
+ params[`Filter.${i + 1}.Name`] = filter.Name;
896
+ filter.Values.forEach((val, j) => {
897
+ params[`Filter.${i + 1}.Value.${j + 1}`] = val;
898
+ });
899
+ });
900
+ }
901
+ const result = await this.client.request({
902
+ service: "ec2",
903
+ region: this.region,
904
+ method: "POST",
905
+ path: "/",
906
+ headers: {
907
+ "Content-Type": "application/x-www-form-urlencoded"
908
+ },
909
+ body: new URLSearchParams(params).toString()
910
+ });
911
+ const response = result.DescribeNetworkInterfacesResponse || result;
912
+ return {
913
+ NetworkInterfaces: this.parseArray(response.networkInterfaceSet?.item).map((ni) => ({
914
+ NetworkInterfaceId: ni.networkInterfaceId,
915
+ SubnetId: ni.subnetId,
916
+ VpcId: ni.vpcId,
917
+ Status: ni.status,
918
+ Attachment: ni.attachment ? {
919
+ AttachmentId: ni.attachment.attachmentId,
920
+ InstanceId: ni.attachment.instanceId,
921
+ Status: ni.attachment.status
922
+ } : undefined
923
+ }))
924
+ };
925
+ }
926
+ async detachNetworkInterface(attachmentId, force) {
927
+ const params = {
928
+ Action: "DetachNetworkInterface",
929
+ Version: "2016-11-15",
930
+ AttachmentId: attachmentId
931
+ };
932
+ if (force) {
933
+ params.Force = "true";
934
+ }
935
+ await this.client.request({
936
+ service: "ec2",
937
+ region: this.region,
938
+ method: "POST",
939
+ path: "/",
940
+ headers: {
941
+ "Content-Type": "application/x-www-form-urlencoded"
942
+ },
943
+ body: new URLSearchParams(params).toString()
944
+ });
945
+ }
946
+ async deleteNetworkInterface(networkInterfaceId) {
947
+ const params = {
948
+ Action: "DeleteNetworkInterface",
949
+ Version: "2016-11-15",
950
+ NetworkInterfaceId: networkInterfaceId
951
+ };
952
+ await this.client.request({
953
+ service: "ec2",
954
+ region: this.region,
955
+ method: "POST",
956
+ path: "/",
957
+ headers: {
958
+ "Content-Type": "application/x-www-form-urlencoded"
959
+ },
960
+ body: new URLSearchParams(params).toString()
961
+ });
962
+ }
963
+ async describeRegions() {
964
+ const params = {
965
+ Action: "DescribeRegions",
966
+ Version: "2016-11-15"
967
+ };
968
+ const result = await this.client.request({
969
+ service: "ec2",
970
+ region: this.region,
971
+ method: "POST",
972
+ path: "/",
973
+ headers: {
974
+ "Content-Type": "application/x-www-form-urlencoded"
975
+ },
976
+ body: new URLSearchParams(params).toString()
977
+ });
978
+ const response = result.DescribeRegionsResponse || result;
979
+ return {
980
+ Regions: this.parseArray(response.regionInfo?.item).map((r) => ({
981
+ RegionName: r.regionName,
982
+ Endpoint: r.regionEndpoint
983
+ }))
984
+ };
985
+ }
986
+ async runInstances(options) {
987
+ const params = {
988
+ Action: "RunInstances",
989
+ Version: "2016-11-15",
990
+ ImageId: options.ImageId,
991
+ InstanceType: options.InstanceType,
992
+ MinCount: String(options.MinCount),
993
+ MaxCount: String(options.MaxCount)
994
+ };
995
+ if (options.SecurityGroupIds) {
996
+ options.SecurityGroupIds.forEach((id, i) => {
997
+ params[`SecurityGroupId.${i + 1}`] = id;
998
+ });
999
+ }
1000
+ if (options.SubnetId) {
1001
+ params.SubnetId = options.SubnetId;
1002
+ }
1003
+ if (options.UserData) {
1004
+ params.UserData = options.UserData;
1005
+ }
1006
+ if (options.IamInstanceProfile) {
1007
+ if (options.IamInstanceProfile.Name) {
1008
+ params["IamInstanceProfile.Name"] = options.IamInstanceProfile.Name;
1009
+ }
1010
+ if (options.IamInstanceProfile.Arn) {
1011
+ params["IamInstanceProfile.Arn"] = options.IamInstanceProfile.Arn;
1012
+ }
1013
+ }
1014
+ if (options.TagSpecifications) {
1015
+ options.TagSpecifications.forEach((spec, i) => {
1016
+ params[`TagSpecification.${i + 1}.ResourceType`] = spec.ResourceType;
1017
+ spec.Tags.forEach((tag, j) => {
1018
+ params[`TagSpecification.${i + 1}.Tag.${j + 1}.Key`] = tag.Key;
1019
+ params[`TagSpecification.${i + 1}.Tag.${j + 1}.Value`] = tag.Value;
1020
+ });
1021
+ });
1022
+ }
1023
+ const result = await this.client.request({
1024
+ service: "ec2",
1025
+ region: this.region,
1026
+ method: "POST",
1027
+ path: "/",
1028
+ headers: {
1029
+ "Content-Type": "application/x-www-form-urlencoded"
1030
+ },
1031
+ body: new URLSearchParams(params).toString()
1032
+ });
1033
+ const response = result.RunInstancesResponse || result;
1034
+ return {
1035
+ Instances: this.parseInstances(response.instancesSet?.item || response.instancesSet)
1036
+ };
1037
+ }
1038
+ encodeIpPermissions(params, permissions) {
1039
+ permissions.forEach((perm, i) => {
1040
+ const prefix = `IpPermissions.${i + 1}`;
1041
+ if (perm.IpProtocol !== undefined) {
1042
+ params[`${prefix}.IpProtocol`] = perm.IpProtocol;
1043
+ }
1044
+ if (perm.FromPort !== undefined) {
1045
+ params[`${prefix}.FromPort`] = String(perm.FromPort);
1046
+ }
1047
+ if (perm.ToPort !== undefined) {
1048
+ params[`${prefix}.ToPort`] = String(perm.ToPort);
1049
+ }
1050
+ if (perm.IpRanges) {
1051
+ perm.IpRanges.forEach((range, j) => {
1052
+ if (range.CidrIp) {
1053
+ params[`${prefix}.IpRanges.${j + 1}.CidrIp`] = range.CidrIp;
1054
+ }
1055
+ if (range.Description) {
1056
+ params[`${prefix}.IpRanges.${j + 1}.Description`] = range.Description;
1057
+ }
1058
+ });
1059
+ }
1060
+ if (perm.Ipv6Ranges) {
1061
+ perm.Ipv6Ranges.forEach((range, j) => {
1062
+ if (range.CidrIpv6) {
1063
+ params[`${prefix}.Ipv6Ranges.${j + 1}.CidrIpv6`] = range.CidrIpv6;
1064
+ }
1065
+ if (range.Description) {
1066
+ params[`${prefix}.Ipv6Ranges.${j + 1}.Description`] = range.Description;
1067
+ }
1068
+ });
1069
+ }
1070
+ if (perm.UserIdGroupPairs) {
1071
+ perm.UserIdGroupPairs.forEach((pair, j) => {
1072
+ if (pair.GroupId) {
1073
+ params[`${prefix}.Groups.${j + 1}.GroupId`] = pair.GroupId;
1074
+ }
1075
+ if (pair.UserId) {
1076
+ params[`${prefix}.Groups.${j + 1}.UserId`] = pair.UserId;
1077
+ }
1078
+ if (pair.Description) {
1079
+ params[`${prefix}.Groups.${j + 1}.Description`] = pair.Description;
1080
+ }
1081
+ });
1082
+ }
1083
+ });
1084
+ }
1085
+ parseArray(item) {
1086
+ if (!item)
1087
+ return [];
1088
+ return Array.isArray(item) ? item : [item];
1089
+ }
1090
+ parseTags(item) {
1091
+ return this.parseArray(item).map((t) => ({
1092
+ Key: t.key,
1093
+ Value: t.value
1094
+ }));
1095
+ }
1096
+ parseReservations(item) {
1097
+ return this.parseArray(item).map((r) => ({
1098
+ ReservationId: r.reservationId,
1099
+ Instances: this.parseInstances(r.instancesSet?.item || r.instancesSet)
1100
+ }));
1101
+ }
1102
+ parseInstances(item) {
1103
+ return this.parseArray(item).map((i) => ({
1104
+ InstanceId: i.instanceId,
1105
+ ImageId: i.imageId,
1106
+ InstanceType: i.instanceType,
1107
+ State: i.instanceState ? {
1108
+ Code: Number.parseInt(i.instanceState.code),
1109
+ Name: i.instanceState.name
1110
+ } : undefined,
1111
+ PrivateIpAddress: i.privateIpAddress,
1112
+ PublicIpAddress: i.ipAddress,
1113
+ SubnetId: i.subnetId,
1114
+ VpcId: i.vpcId,
1115
+ SecurityGroups: this.parseArray(i.groupSet?.item).map((g) => ({
1116
+ GroupId: g.groupId,
1117
+ GroupName: g.groupName
1118
+ })),
1119
+ Tags: this.parseTags(i.tagSet?.item),
1120
+ LaunchTime: i.launchTime,
1121
+ Placement: i.placement ? {
1122
+ AvailabilityZone: i.placement.availabilityZone,
1123
+ Tenancy: i.placement.tenancy
1124
+ } : undefined,
1125
+ Architecture: i.architecture,
1126
+ RootDeviceType: i.rootDeviceType,
1127
+ RootDeviceName: i.rootDeviceName,
1128
+ BlockDeviceMappings: this.parseArray(i.blockDeviceMapping?.item).map((b) => ({
1129
+ DeviceName: b.deviceName,
1130
+ Ebs: b.ebs ? {
1131
+ VolumeId: b.ebs.volumeId,
1132
+ Status: b.ebs.status,
1133
+ AttachTime: b.ebs.attachTime,
1134
+ DeleteOnTermination: b.ebs.deleteOnTermination === "true"
1135
+ } : undefined
1136
+ })),
1137
+ IamInstanceProfile: i.iamInstanceProfile ? {
1138
+ Arn: i.iamInstanceProfile.arn,
1139
+ Id: i.iamInstanceProfile.id
1140
+ } : undefined
1141
+ }));
1142
+ }
1143
+ parseIpPermissions(item) {
1144
+ return this.parseArray(item).map((p) => ({
1145
+ IpProtocol: p.ipProtocol,
1146
+ FromPort: p.fromPort ? Number.parseInt(p.fromPort) : undefined,
1147
+ ToPort: p.toPort ? Number.parseInt(p.toPort) : undefined,
1148
+ IpRanges: this.parseArray(p.ipRanges?.item).map((r) => ({
1149
+ CidrIp: r.cidrIp,
1150
+ Description: r.description
1151
+ })),
1152
+ Ipv6Ranges: this.parseArray(p.ipv6Ranges?.item).map((r) => ({
1153
+ CidrIpv6: r.cidrIpv6,
1154
+ Description: r.description
1155
+ })),
1156
+ UserIdGroupPairs: this.parseArray(p.groups?.item).map((g) => ({
1157
+ GroupId: g.groupId,
1158
+ UserId: g.userId,
1159
+ Description: g.description
1160
+ }))
1161
+ }));
1162
+ }
1163
+ }
1164
+
1165
+ // src/aws/ssm.ts
1166
+ class SSMClient {
1167
+ client;
1168
+ region;
1169
+ constructor(region = "us-east-1", profile) {
1170
+ this.region = region;
1171
+ this.client = new AWSClient;
1172
+ }
1173
+ async putParameter(options) {
1174
+ const params = {
1175
+ Name: options.Name,
1176
+ Value: options.Value
1177
+ };
1178
+ if (options.Type) {
1179
+ params.Type = options.Type;
1180
+ }
1181
+ if (options.Description) {
1182
+ params.Description = options.Description;
1183
+ }
1184
+ if (options.KeyId) {
1185
+ params.KeyId = options.KeyId;
1186
+ }
1187
+ if (options.Overwrite !== undefined) {
1188
+ params.Overwrite = options.Overwrite;
1189
+ }
1190
+ if (options.AllowedPattern) {
1191
+ params.AllowedPattern = options.AllowedPattern;
1192
+ }
1193
+ if (options.Tags && options.Tags.length > 0) {
1194
+ params.Tags = options.Tags;
1195
+ }
1196
+ if (options.Tier) {
1197
+ params.Tier = options.Tier;
1198
+ }
1199
+ if (options.DataType) {
1200
+ params.DataType = options.DataType;
1201
+ }
1202
+ const result = await this.client.request({
1203
+ service: "ssm",
1204
+ region: this.region,
1205
+ method: "POST",
1206
+ path: "/",
1207
+ headers: {
1208
+ "X-Amz-Target": "AmazonSSM.PutParameter",
1209
+ "Content-Type": "application/x-amz-json-1.1"
1210
+ },
1211
+ body: JSON.stringify(params)
1212
+ });
1213
+ return {
1214
+ Version: result.Version,
1215
+ Tier: result.Tier
1216
+ };
1217
+ }
1218
+ async getParameter(options) {
1219
+ const params = {
1220
+ Name: options.Name
1221
+ };
1222
+ if (options.WithDecryption !== undefined) {
1223
+ params.WithDecryption = options.WithDecryption;
1224
+ }
1225
+ const result = await this.client.request({
1226
+ service: "ssm",
1227
+ region: this.region,
1228
+ method: "POST",
1229
+ path: "/",
1230
+ headers: {
1231
+ "X-Amz-Target": "AmazonSSM.GetParameter",
1232
+ "Content-Type": "application/x-amz-json-1.1"
1233
+ },
1234
+ body: JSON.stringify(params)
1235
+ });
1236
+ return {
1237
+ Parameter: result.Parameter ? this.parseParameter(result.Parameter) : undefined
1238
+ };
1239
+ }
1240
+ async getParameters(options) {
1241
+ const params = {
1242
+ Names: options.Names
1243
+ };
1244
+ if (options.WithDecryption !== undefined) {
1245
+ params.WithDecryption = options.WithDecryption;
1246
+ }
1247
+ const result = await this.client.request({
1248
+ service: "ssm",
1249
+ region: this.region,
1250
+ method: "POST",
1251
+ path: "/",
1252
+ headers: {
1253
+ "X-Amz-Target": "AmazonSSM.GetParameters",
1254
+ "Content-Type": "application/x-amz-json-1.1"
1255
+ },
1256
+ body: JSON.stringify(params)
1257
+ });
1258
+ return {
1259
+ Parameters: result.Parameters?.map((p) => this.parseParameter(p)),
1260
+ InvalidParameters: result.InvalidParameters
1261
+ };
1262
+ }
1263
+ async getParametersByPath(options) {
1264
+ const params = {
1265
+ Path: options.Path
1266
+ };
1267
+ if (options.Recursive !== undefined) {
1268
+ params.Recursive = options.Recursive;
1269
+ }
1270
+ if (options.WithDecryption !== undefined) {
1271
+ params.WithDecryption = options.WithDecryption;
1272
+ }
1273
+ if (options.MaxResults) {
1274
+ params.MaxResults = options.MaxResults;
1275
+ }
1276
+ if (options.NextToken) {
1277
+ params.NextToken = options.NextToken;
1278
+ }
1279
+ if (options.ParameterFilters && options.ParameterFilters.length > 0) {
1280
+ params.ParameterFilters = options.ParameterFilters;
1281
+ }
1282
+ const result = await this.client.request({
1283
+ service: "ssm",
1284
+ region: this.region,
1285
+ method: "POST",
1286
+ path: "/",
1287
+ headers: {
1288
+ "X-Amz-Target": "AmazonSSM.GetParametersByPath",
1289
+ "Content-Type": "application/x-amz-json-1.1"
1290
+ },
1291
+ body: JSON.stringify(params)
1292
+ });
1293
+ return {
1294
+ Parameters: result.Parameters?.map((p) => this.parseParameter(p)),
1295
+ NextToken: result.NextToken
1296
+ };
1297
+ }
1298
+ async deleteParameter(options) {
1299
+ const params = {
1300
+ Name: options.Name
1301
+ };
1302
+ await this.client.request({
1303
+ service: "ssm",
1304
+ region: this.region,
1305
+ method: "POST",
1306
+ path: "/",
1307
+ headers: {
1308
+ "X-Amz-Target": "AmazonSSM.DeleteParameter",
1309
+ "Content-Type": "application/x-amz-json-1.1"
1310
+ },
1311
+ body: JSON.stringify(params)
1312
+ });
1313
+ }
1314
+ async deleteParameters(names) {
1315
+ const params = {
1316
+ Names: names
1317
+ };
1318
+ const result = await this.client.request({
1319
+ service: "ssm",
1320
+ region: this.region,
1321
+ method: "POST",
1322
+ path: "/",
1323
+ headers: {
1324
+ "X-Amz-Target": "AmazonSSM.DeleteParameters",
1325
+ "Content-Type": "application/x-amz-json-1.1"
1326
+ },
1327
+ body: JSON.stringify(params)
1328
+ });
1329
+ return {
1330
+ DeletedParameters: result.DeletedParameters,
1331
+ InvalidParameters: result.InvalidParameters
1332
+ };
1333
+ }
1334
+ async describeParameters(options) {
1335
+ const params = {};
1336
+ if (options?.Filters && options.Filters.length > 0) {
1337
+ params.Filters = options.Filters;
1338
+ }
1339
+ if (options?.ParameterFilters && options.ParameterFilters.length > 0) {
1340
+ params.ParameterFilters = options.ParameterFilters;
1341
+ }
1342
+ if (options?.MaxResults) {
1343
+ params.MaxResults = options.MaxResults;
1344
+ }
1345
+ if (options?.NextToken) {
1346
+ params.NextToken = options.NextToken;
1347
+ }
1348
+ const result = await this.client.request({
1349
+ service: "ssm",
1350
+ region: this.region,
1351
+ method: "POST",
1352
+ path: "/",
1353
+ headers: {
1354
+ "X-Amz-Target": "AmazonSSM.DescribeParameters",
1355
+ "Content-Type": "application/x-amz-json-1.1"
1356
+ },
1357
+ body: JSON.stringify(params)
1358
+ });
1359
+ return {
1360
+ Parameters: result.Parameters?.map((p) => this.parseParameter(p)),
1361
+ NextToken: result.NextToken
1362
+ };
1363
+ }
1364
+ async getParameterHistory(options) {
1365
+ const params = {
1366
+ Name: options.Name
1367
+ };
1368
+ if (options.WithDecryption !== undefined) {
1369
+ params.WithDecryption = options.WithDecryption;
1370
+ }
1371
+ if (options.MaxResults) {
1372
+ params.MaxResults = options.MaxResults;
1373
+ }
1374
+ if (options.NextToken) {
1375
+ params.NextToken = options.NextToken;
1376
+ }
1377
+ const result = await this.client.request({
1378
+ service: "ssm",
1379
+ region: this.region,
1380
+ method: "POST",
1381
+ path: "/",
1382
+ headers: {
1383
+ "X-Amz-Target": "AmazonSSM.GetParameterHistory",
1384
+ "Content-Type": "application/x-amz-json-1.1"
1385
+ },
1386
+ body: JSON.stringify(params)
1387
+ });
1388
+ return {
1389
+ Parameters: result.Parameters?.map((p) => ({
1390
+ Name: p.Name,
1391
+ Type: p.Type,
1392
+ KeyId: p.KeyId,
1393
+ LastModifiedDate: p.LastModifiedDate,
1394
+ LastModifiedUser: p.LastModifiedUser,
1395
+ Description: p.Description,
1396
+ Value: p.Value,
1397
+ Version: p.Version,
1398
+ Labels: p.Labels,
1399
+ Tier: p.Tier
1400
+ })),
1401
+ NextToken: result.NextToken
1402
+ };
1403
+ }
1404
+ async labelParameterVersion(options) {
1405
+ const params = {
1406
+ Name: options.Name,
1407
+ Labels: options.Labels
1408
+ };
1409
+ if (options.ParameterVersion !== undefined) {
1410
+ params.ParameterVersion = options.ParameterVersion;
1411
+ }
1412
+ const result = await this.client.request({
1413
+ service: "ssm",
1414
+ region: this.region,
1415
+ method: "POST",
1416
+ path: "/",
1417
+ headers: {
1418
+ "X-Amz-Target": "AmazonSSM.LabelParameterVersion",
1419
+ "Content-Type": "application/x-amz-json-1.1"
1420
+ },
1421
+ body: JSON.stringify(params)
1422
+ });
1423
+ return {
1424
+ InvalidLabels: result.InvalidLabels,
1425
+ ParameterVersion: result.ParameterVersion
1426
+ };
1427
+ }
1428
+ async addTagsToResource(options) {
1429
+ const params = {
1430
+ ResourceType: options.ResourceType,
1431
+ ResourceId: options.ResourceId,
1432
+ Tags: options.Tags
1433
+ };
1434
+ await this.client.request({
1435
+ service: "ssm",
1436
+ region: this.region,
1437
+ method: "POST",
1438
+ path: "/",
1439
+ headers: {
1440
+ "X-Amz-Target": "AmazonSSM.AddTagsToResource",
1441
+ "Content-Type": "application/x-amz-json-1.1"
1442
+ },
1443
+ body: JSON.stringify(params)
1444
+ });
1445
+ }
1446
+ async removeTagsFromResource(options) {
1447
+ const params = {
1448
+ ResourceType: options.ResourceType,
1449
+ ResourceId: options.ResourceId,
1450
+ TagKeys: options.TagKeys
1451
+ };
1452
+ await this.client.request({
1453
+ service: "ssm",
1454
+ region: this.region,
1455
+ method: "POST",
1456
+ path: "/",
1457
+ headers: {
1458
+ "X-Amz-Target": "AmazonSSM.RemoveTagsFromResource",
1459
+ "Content-Type": "application/x-amz-json-1.1"
1460
+ },
1461
+ body: JSON.stringify(params)
1462
+ });
1463
+ }
1464
+ async listTagsForResource(options) {
1465
+ const params = {
1466
+ ResourceType: options.ResourceType,
1467
+ ResourceId: options.ResourceId
1468
+ };
1469
+ const result = await this.client.request({
1470
+ service: "ssm",
1471
+ region: this.region,
1472
+ method: "POST",
1473
+ path: "/",
1474
+ headers: {
1475
+ "X-Amz-Target": "AmazonSSM.ListTagsForResource",
1476
+ "Content-Type": "application/x-amz-json-1.1"
1477
+ },
1478
+ body: JSON.stringify(params)
1479
+ });
1480
+ return {
1481
+ TagList: result.TagList
1482
+ };
1483
+ }
1484
+ async setString(name, value, options) {
1485
+ return this.putParameter({
1486
+ Name: name,
1487
+ Value: value,
1488
+ Type: "String",
1489
+ Description: options?.description,
1490
+ Overwrite: options?.overwrite ?? true,
1491
+ Tags: options?.tags
1492
+ });
1493
+ }
1494
+ async setSecureString(name, value, options) {
1495
+ return this.putParameter({
1496
+ Name: name,
1497
+ Value: value,
1498
+ Type: "SecureString",
1499
+ Description: options?.description,
1500
+ Overwrite: options?.overwrite ?? true,
1501
+ KeyId: options?.kmsKeyId,
1502
+ Tags: options?.tags
1503
+ });
1504
+ }
1505
+ async getValue(name) {
1506
+ const result = await this.getParameter({
1507
+ Name: name,
1508
+ WithDecryption: true
1509
+ });
1510
+ return result.Parameter?.Value;
1511
+ }
1512
+ async getAllByPath(path, recursive = true) {
1513
+ const allParams = [];
1514
+ let nextToken;
1515
+ do {
1516
+ const result = await this.getParametersByPath({
1517
+ Path: path,
1518
+ Recursive: recursive,
1519
+ WithDecryption: true,
1520
+ NextToken: nextToken
1521
+ });
1522
+ if (result.Parameters) {
1523
+ allParams.push(...result.Parameters);
1524
+ }
1525
+ nextToken = result.NextToken;
1526
+ } while (nextToken);
1527
+ return allParams;
1528
+ }
1529
+ parseParameter(p) {
1530
+ return {
1531
+ Name: p.Name,
1532
+ Type: p.Type,
1533
+ Value: p.Value,
1534
+ Version: p.Version,
1535
+ LastModifiedDate: p.LastModifiedDate,
1536
+ ARN: p.ARN,
1537
+ DataType: p.DataType,
1538
+ Description: p.Description,
1539
+ AllowedPattern: p.AllowedPattern,
1540
+ KeyId: p.KeyId,
1541
+ Tier: p.Tier
1542
+ };
1543
+ }
1544
+ async sendCommand(options) {
1545
+ if (!options.InstanceIds && !options.Targets) {
1546
+ throw new Error("SendCommand requires either InstanceIds or Targets");
1547
+ }
1548
+ const params = {
1549
+ DocumentName: options.DocumentName
1550
+ };
1551
+ if (options.InstanceIds) {
1552
+ params.InstanceIds = options.InstanceIds;
1553
+ }
1554
+ if (options.Targets) {
1555
+ params.Targets = options.Targets;
1556
+ }
1557
+ if (options.Parameters) {
1558
+ params.Parameters = options.Parameters;
1559
+ }
1560
+ if (options.TimeoutSeconds) {
1561
+ params.TimeoutSeconds = options.TimeoutSeconds;
1562
+ }
1563
+ if (options.Comment) {
1564
+ params.Comment = options.Comment;
1565
+ }
1566
+ if (options.OutputS3BucketName) {
1567
+ params.OutputS3BucketName = options.OutputS3BucketName;
1568
+ }
1569
+ if (options.OutputS3KeyPrefix) {
1570
+ params.OutputS3KeyPrefix = options.OutputS3KeyPrefix;
1571
+ }
1572
+ const result = await this.client.request({
1573
+ service: "ssm",
1574
+ region: this.region,
1575
+ method: "POST",
1576
+ path: "/",
1577
+ headers: {
1578
+ "X-Amz-Target": "AmazonSSM.SendCommand",
1579
+ "Content-Type": "application/x-amz-json-1.1"
1580
+ },
1581
+ body: JSON.stringify(params)
1582
+ });
1583
+ return {
1584
+ CommandId: result.Command?.CommandId,
1585
+ Status: result.Command?.Status,
1586
+ StatusDetails: result.Command?.StatusDetails
1587
+ };
1588
+ }
1589
+ async getCommandInvocation(options) {
1590
+ const params = {
1591
+ CommandId: options.CommandId,
1592
+ InstanceId: options.InstanceId
1593
+ };
1594
+ const result = await this.client.request({
1595
+ service: "ssm",
1596
+ region: this.region,
1597
+ method: "POST",
1598
+ path: "/",
1599
+ headers: {
1600
+ "X-Amz-Target": "AmazonSSM.GetCommandInvocation",
1601
+ "Content-Type": "application/x-amz-json-1.1"
1602
+ },
1603
+ body: JSON.stringify(params)
1604
+ });
1605
+ return {
1606
+ Status: result.Status,
1607
+ StatusDetails: result.StatusDetails,
1608
+ StandardOutputContent: result.StandardOutputContent,
1609
+ StandardErrorContent: result.StandardErrorContent,
1610
+ ResponseCode: result.ResponseCode
1611
+ };
1612
+ }
1613
+ async runShellCommand(instanceId, commands, options) {
1614
+ const sendResult = await this.sendCommand({
1615
+ InstanceIds: [instanceId],
1616
+ DocumentName: "AWS-RunShellScript",
1617
+ Parameters: {
1618
+ commands
1619
+ },
1620
+ TimeoutSeconds: options?.timeoutSeconds || 600
1621
+ });
1622
+ if (!sendResult.CommandId) {
1623
+ return { success: false, error: "Failed to send command" };
1624
+ }
1625
+ if (options?.waitForCompletion === false) {
1626
+ return { success: true, status: "Pending" };
1627
+ }
1628
+ const pollInterval = options?.pollIntervalMs || 2000;
1629
+ const maxWait = options?.maxWaitMs || 300000;
1630
+ const startTime = Date.now();
1631
+ while (Date.now() - startTime < maxWait) {
1632
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
1633
+ try {
1634
+ const invocation = await this.getCommandInvocation({
1635
+ CommandId: sendResult.CommandId,
1636
+ InstanceId: instanceId
1637
+ });
1638
+ if (invocation.Status === "Success") {
1639
+ return {
1640
+ success: true,
1641
+ output: invocation.StandardOutputContent,
1642
+ error: invocation.StandardErrorContent,
1643
+ status: invocation.Status
1644
+ };
1645
+ }
1646
+ if (invocation.Status === "Failed" || invocation.Status === "Cancelled" || invocation.Status === "TimedOut") {
1647
+ return {
1648
+ success: false,
1649
+ output: invocation.StandardOutputContent,
1650
+ error: invocation.StandardErrorContent || invocation.StatusDetails,
1651
+ status: invocation.Status
1652
+ };
1653
+ }
1654
+ } catch (e) {
1655
+ if (!e.message?.includes("InvocationDoesNotExist")) {
1656
+ return { success: false, error: e.message };
1657
+ }
1658
+ }
1659
+ }
1660
+ return { success: false, error: "Command timed out waiting for completion" };
1661
+ }
1662
+ async listCommandInvocations(options) {
1663
+ const params = {
1664
+ CommandId: options.CommandId
1665
+ };
1666
+ if (options.Details) {
1667
+ params.Details = true;
1668
+ }
1669
+ const result = await this.client.request({
1670
+ service: "ssm",
1671
+ region: this.region,
1672
+ method: "POST",
1673
+ path: "/",
1674
+ headers: {
1675
+ "X-Amz-Target": "AmazonSSM.ListCommandInvocations",
1676
+ "Content-Type": "application/x-amz-json-1.1"
1677
+ },
1678
+ body: JSON.stringify(params)
1679
+ });
1680
+ const invocations = result.CommandInvocations || [];
1681
+ return invocations.map((inv) => ({
1682
+ InstanceId: inv.InstanceId,
1683
+ Status: inv.Status,
1684
+ StatusDetails: inv.StatusDetails,
1685
+ StandardOutputContent: inv.CommandPlugins?.[0]?.Output,
1686
+ StandardErrorContent: inv.CommandPlugins?.[0]?.StandardErrorUrl
1687
+ }));
1688
+ }
1689
+ async sendCommandByTags(options) {
1690
+ const targets = Object.entries(options.tags).map(([key, value]) => ({
1691
+ Key: `tag:${key}`,
1692
+ Values: [value]
1693
+ }));
1694
+ const sendResult = await this.sendCommand({
1695
+ Targets: targets,
1696
+ DocumentName: "AWS-RunShellScript",
1697
+ Parameters: { commands: options.commands },
1698
+ TimeoutSeconds: options.timeoutSeconds || 600,
1699
+ Comment: options.comment
1700
+ });
1701
+ if (!sendResult.CommandId) {
1702
+ return { success: false, instanceCount: 0, perInstance: [], error: "Failed to send command" };
1703
+ }
1704
+ const pollInterval = options.pollIntervalMs || 3000;
1705
+ const maxWait = options.maxWaitMs || 600000;
1706
+ const startTime = Date.now();
1707
+ const terminalStatuses = new Set(["Success", "Failed", "Cancelled", "TimedOut"]);
1708
+ let lastInvocations = [];
1709
+ while (Date.now() - startTime < maxWait) {
1710
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
1711
+ try {
1712
+ lastInvocations = await this.listCommandInvocations({
1713
+ CommandId: sendResult.CommandId,
1714
+ Details: true
1715
+ });
1716
+ if (lastInvocations.length === 0)
1717
+ continue;
1718
+ const allDone = lastInvocations.every((inv) => terminalStatuses.has(inv.Status || ""));
1719
+ if (allDone) {
1720
+ const perInstance = lastInvocations.map((inv) => ({
1721
+ instanceId: inv.InstanceId,
1722
+ status: inv.Status || "Unknown",
1723
+ output: inv.StandardOutputContent,
1724
+ error: inv.StandardErrorContent || inv.StatusDetails
1725
+ }));
1726
+ const allSucceeded = lastInvocations.every((inv) => inv.Status === "Success");
1727
+ return {
1728
+ success: allSucceeded,
1729
+ instanceCount: lastInvocations.length,
1730
+ perInstance,
1731
+ error: allSucceeded ? undefined : "One or more instances reported a non-success status"
1732
+ };
1733
+ }
1734
+ } catch (e) {
1735
+ if (!e.message?.includes("InvocationDoesNotExist")) {
1736
+ return { success: false, instanceCount: 0, perInstance: [], error: e.message };
1737
+ }
1738
+ }
1739
+ }
1740
+ return {
1741
+ success: false,
1742
+ instanceCount: lastInvocations.length,
1743
+ perInstance: lastInvocations.map((inv) => ({
1744
+ instanceId: inv.InstanceId,
1745
+ status: inv.Status || "Unknown"
1746
+ })),
1747
+ error: "Command timed out waiting for all instances to complete"
1748
+ };
1749
+ }
1750
+ }
1751
+
1752
+ export { EC2Client, SSMClient };