@stacksjs/ts-cloud 0.9.2 → 0.9.4

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 (191) hide show
  1. package/dist/aws/index.js +1 -269
  2. package/dist/bin/chunk-00kg80qg.js +1 -0
  3. package/dist/bin/chunk-09nwf2gy.js +34 -0
  4. package/dist/bin/chunk-1k5kszjp.js +111 -0
  5. package/dist/bin/chunk-21e0mavm.js +1 -0
  6. package/dist/bin/chunk-271gk1n2.js +6 -0
  7. package/dist/bin/chunk-2empps47.js +2 -0
  8. package/dist/bin/chunk-38pq971s.js +2 -0
  9. package/dist/bin/chunk-3gykfyq4.js +37 -0
  10. package/dist/bin/chunk-3vqfexc4.js +70 -0
  11. package/dist/bin/chunk-4vrqm9h0.js +2 -0
  12. package/dist/bin/chunk-598yf4bs.js +1 -0
  13. package/dist/bin/chunk-5ectjq0b.js +1 -0
  14. package/dist/bin/chunk-5erkxpt7.js +512 -0
  15. package/dist/bin/chunk-5mrtzemj.js +1 -0
  16. package/dist/bin/chunk-5n9fmabb.js +1 -0
  17. package/dist/bin/chunk-9knpg30y.js +1 -0
  18. package/dist/bin/chunk-9pvsff8g.js +1 -0
  19. package/dist/bin/chunk-ax9mr6wm.js +44 -0
  20. package/dist/bin/chunk-axhnkn5g.js +2 -0
  21. package/dist/bin/chunk-c1vcdgvr.js +1 -0
  22. package/dist/bin/chunk-ctd2vg9w.js +2 -0
  23. package/dist/bin/chunk-dbgffky8.js +1 -0
  24. package/dist/bin/chunk-ddk4rt4j.js +6 -0
  25. package/dist/bin/chunk-dwr30vbv.js +1 -0
  26. package/dist/bin/chunk-e0rkrq70.js +1 -0
  27. package/dist/bin/chunk-e3xrwh9z.js +1 -0
  28. package/dist/bin/chunk-etrb03mt.js +1507 -0
  29. package/dist/bin/chunk-fhc6ntvd.js +2 -0
  30. package/dist/bin/chunk-fpm59y25.js +6 -0
  31. package/dist/bin/chunk-fvbxvq6b.js +1 -0
  32. package/dist/bin/chunk-fy8j3y8p.js +92 -0
  33. package/dist/bin/chunk-fz21b57w.js +1 -0
  34. package/dist/bin/chunk-gavvf0pg.js +141 -0
  35. package/dist/bin/chunk-ggn7ax8p.js +4 -0
  36. package/dist/bin/chunk-gpe2prkm.js +1 -0
  37. package/dist/bin/chunk-h5pa5men.js +2 -0
  38. package/dist/bin/chunk-hm08xdxf.js +2 -0
  39. package/dist/bin/chunk-hzgz13nf.js +1 -0
  40. package/dist/bin/chunk-j703btc5.js +50 -0
  41. package/dist/bin/chunk-k9t9wvms.js +1 -0
  42. package/dist/bin/chunk-m669wtgr.js +1 -0
  43. package/dist/bin/chunk-m7dgskt1.js +1 -0
  44. package/dist/bin/chunk-mh0kdzqp.js +2 -0
  45. package/dist/bin/chunk-mr0atd2s.js +2 -0
  46. package/dist/bin/chunk-mz0wbbsj.js +3 -0
  47. package/dist/bin/chunk-ngcyftm2.js +1 -0
  48. package/dist/bin/chunk-p66ptpmr.js +2 -0
  49. package/dist/bin/chunk-qk9qgepa.js +1 -0
  50. package/dist/bin/chunk-rxcvf10f.js +7364 -0
  51. package/dist/bin/chunk-rytk89az.js +60 -0
  52. package/dist/bin/chunk-tga3hhwk.js +6 -0
  53. package/dist/bin/chunk-tx0tqq2k.js +8 -0
  54. package/dist/bin/chunk-vek8a0w6.js +1 -0
  55. package/dist/bin/chunk-vm3q5gf2.js +3 -0
  56. package/dist/bin/chunk-y7s5r8y6.js +3 -0
  57. package/dist/bin/chunk-yv9sth30.js +1 -0
  58. package/dist/bin/chunk-zmegvjp8.js +581 -0
  59. package/dist/bin/cli.js +417 -10597
  60. package/dist/bin/dashboard-server.js +1 -6998
  61. package/dist/chunk-0ccta6z6.js +6 -0
  62. package/dist/chunk-0k1cs6pp.js +1 -0
  63. package/dist/chunk-1egjn203.js +704 -0
  64. package/dist/chunk-2wx29qga.js +5 -0
  65. package/dist/chunk-5m5rqmv7.js +1 -0
  66. package/dist/chunk-8ea5022g.js +114 -0
  67. package/dist/chunk-8xqn3c0w.js +2 -0
  68. package/dist/chunk-b4esxhmw.js +2 -0
  69. package/dist/chunk-b8e5wzwn.js +44 -0
  70. package/dist/chunk-bggt4n6e.js +2 -0
  71. package/dist/chunk-cwkg37rs.js +37 -0
  72. package/dist/chunk-dskvqt67.js +7355 -0
  73. package/dist/chunk-gahsdmxf.js +1617 -0
  74. package/dist/chunk-gnv3r2jg.js +1 -0
  75. package/dist/chunk-hg3c48cp.js +34 -0
  76. package/dist/chunk-m5azeva3.js +2 -0
  77. package/dist/chunk-r3qf56b3.js +92 -0
  78. package/dist/chunk-sdqa9ghv.js +141 -0
  79. package/dist/chunk-svrvvcm7.js +1 -0
  80. package/dist/chunk-v0p3hpc3.js +60 -0
  81. package/dist/chunk-wdzjbecg.js +50 -0
  82. package/dist/chunk-ww8k3g7j.js +1 -0
  83. package/dist/chunk-xmqfc62w.js +1 -0
  84. package/dist/chunk-xrebj679.js +435 -0
  85. package/dist/chunk-xt3s24vr.js +2 -0
  86. package/dist/chunk-y21zk0pn.js +4 -0
  87. package/dist/deploy/attach-credentials.d.ts +57 -0
  88. package/dist/deploy/index.js +1 -168
  89. package/dist/deploy/site-ports.d.ts +151 -0
  90. package/dist/deploy/site-target.d.ts +24 -1
  91. package/dist/dns/index.js +1 -41
  92. package/dist/drivers/index.js +1 -154
  93. package/dist/index.js +100 -6129
  94. package/dist/protection/index.js +1 -89
  95. package/dist/push/index.js +1 -509
  96. package/dist/spend/index.js +1 -173
  97. package/dist/ui/404.html +16 -548
  98. package/dist/ui/_stx/chunk.5ddb5087.js +90 -0
  99. package/dist/ui/_stx/chunk.9fd39d5b.js +86 -0
  100. package/dist/ui/_stx/chunk.d5301f79.js +119 -0
  101. package/dist/ui/_stx/crosswind.222ed683.css +1 -0
  102. package/dist/ui/_stx/crosswind.616c25f3.css +1 -0
  103. package/dist/ui/_stx/crosswind.80baa894.css +320 -0
  104. package/dist/ui/_stx/crosswind.906ee17c.css +1 -0
  105. package/dist/ui/_stx/crosswind.996ed49e.css +1 -0
  106. package/dist/ui/_stx/crosswind.b7a99a5c.css +1 -0
  107. package/dist/ui/_stx/router.fa5bc4dc.js +4 -0
  108. package/dist/ui/_stx/runtime.c696d17a.js +1 -0
  109. package/dist/ui/_stx/style.448ab192.css +1 -0
  110. package/dist/ui/accept-invitation.html +2 -1133
  111. package/dist/ui/access-denied.html +7 -1130
  112. package/dist/ui/account/automation.html +12 -1134
  113. package/dist/ui/account/security.html +13 -1136
  114. package/dist/ui/applications/compose.html +12 -1134
  115. package/dist/ui/applications/new.html +13 -1137
  116. package/dist/ui/data/backups.html +91 -1136
  117. package/dist/ui/data/services.html +89 -1136
  118. package/dist/ui/data/volumes.html +61 -1136
  119. package/dist/ui/index.html +60 -1136
  120. package/dist/ui/infrastructure/topology.html +128 -1135
  121. package/dist/ui/integrations.html +13 -1138
  122. package/dist/ui/operations/alerts.html +59 -1136
  123. package/dist/ui/operations/configuration.html +13 -1135
  124. package/dist/ui/operations/jobs.html +87 -1136
  125. package/dist/ui/operations/maintenance.html +12 -1134
  126. package/dist/ui/operations/observability.html +93 -1136
  127. package/dist/ui/operations/previews.html +12 -1134
  128. package/dist/ui/operations/queue.html +12 -1134
  129. package/dist/ui/operations/regions.html +12 -1134
  130. package/dist/ui/operations/releases.html +12 -1134
  131. package/dist/ui/operations/spend.html +65 -1136
  132. package/dist/ui/operations/workloads.html +115 -1136
  133. package/dist/ui/robots.txt +2 -0
  134. package/dist/ui/security.html +24 -1136
  135. package/dist/ui/server/actions.html +67 -1138
  136. package/dist/ui/server/activity.html +7 -1130
  137. package/dist/ui/server/capacity.html +12 -1134
  138. package/dist/ui/server/database.html +166 -1135
  139. package/dist/ui/server/deployments.html +60 -1136
  140. package/dist/ui/server/diagnostics.html +7 -1130
  141. package/dist/ui/server/firewall.html +286 -1212
  142. package/dist/ui/server/fleet.html +45 -1136
  143. package/dist/ui/server/logs.html +34 -1135
  144. package/dist/ui/server/metrics.html +124 -1140
  145. package/dist/ui/server/security.html +7 -1130
  146. package/dist/ui/server/services.html +46 -1133
  147. package/dist/ui/server/sites.html +287 -1137
  148. package/dist/ui/server/ssh-keys.html +62 -1135
  149. package/dist/ui/server/team.html +155 -1136
  150. package/dist/ui/server/terminal.html +97 -1183
  151. package/dist/ui/serverless/alarms.html +62 -1135
  152. package/dist/ui/serverless/assets.html +47 -1132
  153. package/dist/ui/serverless/cost.html +7 -1130
  154. package/dist/ui/serverless/data.html +46 -1135
  155. package/dist/ui/serverless/deployments.html +47 -1132
  156. package/dist/ui/serverless/firewall.html +7 -1130
  157. package/dist/ui/serverless/functions.html +50 -1136
  158. package/dist/ui/serverless/logs.html +34 -1135
  159. package/dist/ui/serverless/metrics.html +7 -1130
  160. package/dist/ui/serverless/queues.html +58 -1135
  161. package/dist/ui/serverless/secrets.html +62 -1136
  162. package/dist/ui/serverless/traces.html +12 -1134
  163. package/dist/ui/serverless.html +64 -1137
  164. package/dist/ui-src/pages/server/firewall.stx +14 -14
  165. package/package.json +3 -3
  166. package/dist/chunk-01d86gt1.js +0 -1324
  167. package/dist/chunk-050r7ycy.js +0 -46516
  168. package/dist/chunk-29rse4p1.js +0 -12203
  169. package/dist/chunk-32e7ya18.js +0 -642
  170. package/dist/chunk-4cjrg98a.js +0 -597
  171. package/dist/chunk-50jpda9q.js +0 -371
  172. package/dist/chunk-6a1t7fnq.js +0 -12121
  173. package/dist/chunk-728jvrr0.js +0 -1701
  174. package/dist/chunk-7m60qnc8.js +0 -1762
  175. package/dist/chunk-aa2dkn7b.js +0 -205
  176. package/dist/chunk-d48vtdj4.js +0 -433
  177. package/dist/chunk-f55nkpvb.js +0 -8
  178. package/dist/chunk-fgk8cqew.js +0 -152
  179. package/dist/chunk-he9a874b.js +0 -769
  180. package/dist/chunk-hg7rhrgd.js +0 -7274
  181. package/dist/chunk-k2yyatfw.js +0 -10
  182. package/dist/chunk-k4px0bnv.js +0 -23
  183. package/dist/chunk-nsgqsmrh.js +0 -1779
  184. package/dist/chunk-qr803fye.js +0 -2122
  185. package/dist/chunk-rds0sy87.js +0 -1771
  186. package/dist/chunk-rxgchb08.js +0 -42033
  187. package/dist/chunk-ttz2ra5j.js +0 -12
  188. package/dist/chunk-v0bahtg2.js +0 -4
  189. package/dist/chunk-va2yd85b.js +0 -200
  190. package/dist/chunk-x9s0cqfx.js +0 -13
  191. package/dist/chunk-zqtpg06c.js +0 -1752
@@ -1,1779 +0,0 @@
1
- import {
2
- Route53Client
3
- } from "./chunk-32e7ya18.js";
4
- import {
5
- S3Client
6
- } from "./chunk-rds0sy87.js";
7
- import {
8
- AWSClient
9
- } from "./chunk-zqtpg06c.js";
10
- import {
11
- __require
12
- } from "./chunk-v0bahtg2.js";
13
-
14
- // src/aws/iam.ts
15
- function buildQueryParams(action, params) {
16
- const queryParams = [`Action=${action}`, "Version=2010-05-08"];
17
- for (const [key, value] of Object.entries(params)) {
18
- if (value === undefined || value === null)
19
- continue;
20
- if (Array.isArray(value)) {
21
- value.forEach((item, index) => {
22
- if (typeof item === "object" && item !== null) {
23
- for (const [subKey, subValue] of Object.entries(item)) {
24
- queryParams.push(`${key}.member.${index + 1}.${subKey}=${encodeURIComponent(String(subValue))}`);
25
- }
26
- } else {
27
- queryParams.push(`${key}.member.${index + 1}=${encodeURIComponent(String(item))}`);
28
- }
29
- });
30
- } else if (typeof value === "object") {
31
- for (const [subKey, subValue] of Object.entries(value)) {
32
- if (subValue !== undefined && subValue !== null) {
33
- queryParams.push(`${key}.${subKey}=${encodeURIComponent(String(subValue))}`);
34
- }
35
- }
36
- } else {
37
- queryParams.push(`${key}=${encodeURIComponent(String(value))}`);
38
- }
39
- }
40
- return queryParams.join("&");
41
- }
42
- function parseXmlValue(xml, tag) {
43
- const regex = new RegExp(`<${tag}>([^<]*)</${tag}>`);
44
- const match = xml.match(regex);
45
- return match ? match[1] : undefined;
46
- }
47
- function parseXmlArray(xml, containerTag, itemTag) {
48
- const containerRegex = new RegExp(`<${containerTag}>([\\s\\S]*?)</${containerTag}>`);
49
- const containerMatch = xml.match(containerRegex);
50
- if (!containerMatch)
51
- return [];
52
- const items = [];
53
- const itemRegex = new RegExp(`<${itemTag}>([\\s\\S]*?)</${itemTag}>`, "g");
54
- let match;
55
- while ((match = itemRegex.exec(containerMatch[1])) !== null) {
56
- items.push(match[1]);
57
- }
58
- return items;
59
- }
60
-
61
- class IAMClient {
62
- client;
63
- region;
64
- constructor(region = "us-east-1", profile) {
65
- this.client = new AWSClient(undefined, { profile });
66
- this.region = region;
67
- }
68
- async request(action, params = {}) {
69
- const body = buildQueryParams(action, params);
70
- const response = await this.client.request({
71
- service: "iam",
72
- region: this.region,
73
- method: "POST",
74
- path: "/",
75
- headers: {
76
- "Content-Type": "application/x-www-form-urlencoded"
77
- },
78
- body
79
- });
80
- return response;
81
- }
82
- async createUser(params) {
83
- const response = await this.request("CreateUser", params);
84
- return this.parseUser(response);
85
- }
86
- async getUser(params = {}) {
87
- const response = await this.request("GetUser", params);
88
- return this.parseUser(response);
89
- }
90
- async listUsers(params = {}) {
91
- const response = await this.request("ListUsers", params);
92
- const users = this.parseUsers(response);
93
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
94
- const marker = parseXmlValue(response, "Marker");
95
- return { Users: users, IsTruncated: isTruncated, Marker: marker };
96
- }
97
- async updateUser(params) {
98
- await this.request("UpdateUser", params);
99
- }
100
- async deleteUser(params) {
101
- await this.request("DeleteUser", params);
102
- }
103
- parseUser(xml) {
104
- return {
105
- UserName: parseXmlValue(xml, "UserName") || "",
106
- UserId: parseXmlValue(xml, "UserId") || "",
107
- Arn: parseXmlValue(xml, "Arn") || "",
108
- Path: parseXmlValue(xml, "Path"),
109
- CreateDate: parseXmlValue(xml, "CreateDate"),
110
- PasswordLastUsed: parseXmlValue(xml, "PasswordLastUsed")
111
- };
112
- }
113
- parseUsers(xml) {
114
- const memberXmls = parseXmlArray(xml, "Users", "member");
115
- return memberXmls.map((memberXml) => ({
116
- UserName: parseXmlValue(memberXml, "UserName") || "",
117
- UserId: parseXmlValue(memberXml, "UserId") || "",
118
- Arn: parseXmlValue(memberXml, "Arn") || "",
119
- Path: parseXmlValue(memberXml, "Path"),
120
- CreateDate: parseXmlValue(memberXml, "CreateDate"),
121
- PasswordLastUsed: parseXmlValue(memberXml, "PasswordLastUsed")
122
- }));
123
- }
124
- async createGroup(params) {
125
- const response = await this.request("CreateGroup", params);
126
- return this.parseGroup(response);
127
- }
128
- async getGroup(params) {
129
- const response = await this.request("GetGroup", params);
130
- const group = this.parseGroup(response);
131
- const users = this.parseUsers(response);
132
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
133
- const marker = parseXmlValue(response, "Marker");
134
- return { Group: group, Users: users, IsTruncated: isTruncated, Marker: marker };
135
- }
136
- async listGroups(params = {}) {
137
- const response = await this.request("ListGroups", params);
138
- const groups = this.parseGroups(response);
139
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
140
- const marker = parseXmlValue(response, "Marker");
141
- return { Groups: groups, IsTruncated: isTruncated, Marker: marker };
142
- }
143
- async updateGroup(params) {
144
- await this.request("UpdateGroup", params);
145
- }
146
- async deleteGroup(params) {
147
- await this.request("DeleteGroup", params);
148
- }
149
- async addUserToGroup(params) {
150
- await this.request("AddUserToGroup", params);
151
- }
152
- async removeUserFromGroup(params) {
153
- await this.request("RemoveUserFromGroup", params);
154
- }
155
- async listGroupsForUser(params) {
156
- const response = await this.request("ListGroupsForUser", params);
157
- const groups = this.parseGroups(response);
158
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
159
- const marker = parseXmlValue(response, "Marker");
160
- return { Groups: groups, IsTruncated: isTruncated, Marker: marker };
161
- }
162
- parseGroup(xml) {
163
- return {
164
- GroupName: parseXmlValue(xml, "GroupName") || "",
165
- GroupId: parseXmlValue(xml, "GroupId") || "",
166
- Arn: parseXmlValue(xml, "Arn") || "",
167
- Path: parseXmlValue(xml, "Path"),
168
- CreateDate: parseXmlValue(xml, "CreateDate")
169
- };
170
- }
171
- parseGroups(xml) {
172
- const memberXmls = parseXmlArray(xml, "Groups", "member");
173
- return memberXmls.map((memberXml) => ({
174
- GroupName: parseXmlValue(memberXml, "GroupName") || "",
175
- GroupId: parseXmlValue(memberXml, "GroupId") || "",
176
- Arn: parseXmlValue(memberXml, "Arn") || "",
177
- Path: parseXmlValue(memberXml, "Path"),
178
- CreateDate: parseXmlValue(memberXml, "CreateDate")
179
- }));
180
- }
181
- async createRole(params) {
182
- const response = await this.request("CreateRole", params);
183
- return this.parseRole(response);
184
- }
185
- async getRole(params) {
186
- const response = await this.request("GetRole", params);
187
- return this.parseRole(response);
188
- }
189
- async listRoles(params = {}) {
190
- const response = await this.request("ListRoles", params);
191
- const roles = this.parseRoles(response);
192
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
193
- const marker = parseXmlValue(response, "Marker");
194
- return { Roles: roles, IsTruncated: isTruncated, Marker: marker };
195
- }
196
- async updateRole(params) {
197
- await this.request("UpdateRole", params);
198
- }
199
- async updateRoleDescription(params) {
200
- const response = await this.request("UpdateRoleDescription", params);
201
- return this.parseRole(response);
202
- }
203
- async updateAssumeRolePolicy(params) {
204
- await this.request("UpdateAssumeRolePolicy", params);
205
- }
206
- async deleteRole(params) {
207
- await this.request("DeleteRole", params);
208
- }
209
- async tagRole(params) {
210
- await this.request("TagRole", params);
211
- }
212
- async untagRole(params) {
213
- await this.request("UntagRole", params);
214
- }
215
- async listRoleTags(params) {
216
- const response = await this.request("ListRoleTags", params);
217
- const tags = this.parseTags(response);
218
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
219
- const marker = parseXmlValue(response, "Marker");
220
- return { Tags: tags, IsTruncated: isTruncated, Marker: marker };
221
- }
222
- parseRole(xml) {
223
- return {
224
- RoleName: parseXmlValue(xml, "RoleName") || "",
225
- RoleId: parseXmlValue(xml, "RoleId") || "",
226
- Arn: parseXmlValue(xml, "Arn") || "",
227
- Path: parseXmlValue(xml, "Path"),
228
- CreateDate: parseXmlValue(xml, "CreateDate"),
229
- AssumeRolePolicyDocument: parseXmlValue(xml, "AssumeRolePolicyDocument"),
230
- Description: parseXmlValue(xml, "Description"),
231
- MaxSessionDuration: parseXmlValue(xml, "MaxSessionDuration") ? Number.parseInt(parseXmlValue(xml, "MaxSessionDuration"), 10) : undefined
232
- };
233
- }
234
- parseRoles(xml) {
235
- const memberXmls = parseXmlArray(xml, "Roles", "member");
236
- return memberXmls.map((memberXml) => ({
237
- RoleName: parseXmlValue(memberXml, "RoleName") || "",
238
- RoleId: parseXmlValue(memberXml, "RoleId") || "",
239
- Arn: parseXmlValue(memberXml, "Arn") || "",
240
- Path: parseXmlValue(memberXml, "Path"),
241
- CreateDate: parseXmlValue(memberXml, "CreateDate"),
242
- AssumeRolePolicyDocument: parseXmlValue(memberXml, "AssumeRolePolicyDocument"),
243
- Description: parseXmlValue(memberXml, "Description"),
244
- MaxSessionDuration: parseXmlValue(memberXml, "MaxSessionDuration") ? Number.parseInt(parseXmlValue(memberXml, "MaxSessionDuration"), 10) : undefined
245
- }));
246
- }
247
- parseTags(xml) {
248
- const memberXmls = parseXmlArray(xml, "Tags", "member");
249
- return memberXmls.map((memberXml) => ({
250
- Key: parseXmlValue(memberXml, "Key") || "",
251
- Value: parseXmlValue(memberXml, "Value") || ""
252
- }));
253
- }
254
- async createPolicy(params) {
255
- const response = await this.request("CreatePolicy", params);
256
- return this.parsePolicy(response);
257
- }
258
- async getPolicy(params) {
259
- const response = await this.request("GetPolicy", params);
260
- return this.parsePolicy(response);
261
- }
262
- async getPolicyVersion(params) {
263
- const response = await this.request("GetPolicyVersion", params);
264
- return {
265
- VersionId: parseXmlValue(response, "VersionId") || "",
266
- IsDefaultVersion: parseXmlValue(response, "IsDefaultVersion") === "true",
267
- CreateDate: parseXmlValue(response, "CreateDate"),
268
- Document: parseXmlValue(response, "Document")
269
- };
270
- }
271
- async listPolicies(params = {}) {
272
- const response = await this.request("ListPolicies", params);
273
- const policies = this.parsePolicies(response);
274
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
275
- const marker = parseXmlValue(response, "Marker");
276
- return { Policies: policies, IsTruncated: isTruncated, Marker: marker };
277
- }
278
- async listPolicyVersions(params) {
279
- const response = await this.request("ListPolicyVersions", params);
280
- const versions = this.parsePolicyVersions(response);
281
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
282
- const marker = parseXmlValue(response, "Marker");
283
- return { Versions: versions, IsTruncated: isTruncated, Marker: marker };
284
- }
285
- async createPolicyVersion(params) {
286
- const response = await this.request("CreatePolicyVersion", params);
287
- return {
288
- VersionId: parseXmlValue(response, "VersionId") || "",
289
- IsDefaultVersion: parseXmlValue(response, "IsDefaultVersion") === "true",
290
- CreateDate: parseXmlValue(response, "CreateDate")
291
- };
292
- }
293
- async deletePolicyVersion(params) {
294
- await this.request("DeletePolicyVersion", params);
295
- }
296
- async setDefaultPolicyVersion(params) {
297
- await this.request("SetDefaultPolicyVersion", params);
298
- }
299
- async deletePolicy(params) {
300
- await this.request("DeletePolicy", params);
301
- }
302
- async attachUserPolicy(params) {
303
- await this.request("AttachUserPolicy", params);
304
- }
305
- async detachUserPolicy(params) {
306
- await this.request("DetachUserPolicy", params);
307
- }
308
- async attachGroupPolicy(params) {
309
- await this.request("AttachGroupPolicy", params);
310
- }
311
- async detachGroupPolicy(params) {
312
- await this.request("DetachGroupPolicy", params);
313
- }
314
- async attachRolePolicy(params) {
315
- await this.request("AttachRolePolicy", params);
316
- }
317
- async detachRolePolicy(params) {
318
- await this.request("DetachRolePolicy", params);
319
- }
320
- async listAttachedUserPolicies(params) {
321
- const response = await this.request("ListAttachedUserPolicies", params);
322
- const policies = this.parseAttachedPolicies(response);
323
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
324
- const marker = parseXmlValue(response, "Marker");
325
- return { AttachedPolicies: policies, IsTruncated: isTruncated, Marker: marker };
326
- }
327
- async listAttachedGroupPolicies(params) {
328
- const response = await this.request("ListAttachedGroupPolicies", params);
329
- const policies = this.parseAttachedPolicies(response);
330
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
331
- const marker = parseXmlValue(response, "Marker");
332
- return { AttachedPolicies: policies, IsTruncated: isTruncated, Marker: marker };
333
- }
334
- async listAttachedRolePolicies(params) {
335
- const response = await this.request("ListAttachedRolePolicies", params);
336
- const policies = this.parseAttachedPolicies(response);
337
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
338
- const marker = parseXmlValue(response, "Marker");
339
- return { AttachedPolicies: policies, IsTruncated: isTruncated, Marker: marker };
340
- }
341
- parsePolicy(xml) {
342
- return {
343
- PolicyName: parseXmlValue(xml, "PolicyName") || "",
344
- PolicyId: parseXmlValue(xml, "PolicyId") || "",
345
- Arn: parseXmlValue(xml, "Arn") || "",
346
- Path: parseXmlValue(xml, "Path"),
347
- DefaultVersionId: parseXmlValue(xml, "DefaultVersionId"),
348
- AttachmentCount: parseXmlValue(xml, "AttachmentCount") ? Number.parseInt(parseXmlValue(xml, "AttachmentCount"), 10) : undefined,
349
- PermissionsBoundaryUsageCount: parseXmlValue(xml, "PermissionsBoundaryUsageCount") ? Number.parseInt(parseXmlValue(xml, "PermissionsBoundaryUsageCount"), 10) : undefined,
350
- IsAttachable: parseXmlValue(xml, "IsAttachable") === "true",
351
- Description: parseXmlValue(xml, "Description"),
352
- CreateDate: parseXmlValue(xml, "CreateDate"),
353
- UpdateDate: parseXmlValue(xml, "UpdateDate")
354
- };
355
- }
356
- parsePolicies(xml) {
357
- const memberXmls = parseXmlArray(xml, "Policies", "member");
358
- return memberXmls.map((memberXml) => ({
359
- PolicyName: parseXmlValue(memberXml, "PolicyName") || "",
360
- PolicyId: parseXmlValue(memberXml, "PolicyId") || "",
361
- Arn: parseXmlValue(memberXml, "Arn") || "",
362
- Path: parseXmlValue(memberXml, "Path"),
363
- DefaultVersionId: parseXmlValue(memberXml, "DefaultVersionId"),
364
- AttachmentCount: parseXmlValue(memberXml, "AttachmentCount") ? Number.parseInt(parseXmlValue(memberXml, "AttachmentCount"), 10) : undefined,
365
- PermissionsBoundaryUsageCount: parseXmlValue(memberXml, "PermissionsBoundaryUsageCount") ? Number.parseInt(parseXmlValue(memberXml, "PermissionsBoundaryUsageCount"), 10) : undefined,
366
- IsAttachable: parseXmlValue(memberXml, "IsAttachable") === "true",
367
- Description: parseXmlValue(memberXml, "Description"),
368
- CreateDate: parseXmlValue(memberXml, "CreateDate"),
369
- UpdateDate: parseXmlValue(memberXml, "UpdateDate")
370
- }));
371
- }
372
- parsePolicyVersions(xml) {
373
- const memberXmls = parseXmlArray(xml, "Versions", "member");
374
- return memberXmls.map((memberXml) => ({
375
- VersionId: parseXmlValue(memberXml, "VersionId") || "",
376
- IsDefaultVersion: parseXmlValue(memberXml, "IsDefaultVersion") === "true",
377
- CreateDate: parseXmlValue(memberXml, "CreateDate")
378
- }));
379
- }
380
- parseAttachedPolicies(xml) {
381
- const memberXmls = parseXmlArray(xml, "AttachedPolicies", "member");
382
- return memberXmls.map((memberXml) => ({
383
- PolicyName: parseXmlValue(memberXml, "PolicyName") || "",
384
- PolicyArn: parseXmlValue(memberXml, "PolicyArn") || ""
385
- }));
386
- }
387
- async putUserPolicy(params) {
388
- await this.request("PutUserPolicy", params);
389
- }
390
- async getUserPolicy(params) {
391
- const response = await this.request("GetUserPolicy", params);
392
- return {
393
- UserName: parseXmlValue(response, "UserName") || "",
394
- PolicyName: parseXmlValue(response, "PolicyName") || "",
395
- PolicyDocument: decodeURIComponent(parseXmlValue(response, "PolicyDocument") || "")
396
- };
397
- }
398
- async deleteUserPolicy(params) {
399
- await this.request("DeleteUserPolicy", params);
400
- }
401
- async listUserPolicies(params) {
402
- const response = await this.request("ListUserPolicies", params);
403
- const policyNames = parseXmlArray(response, "PolicyNames", "member");
404
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
405
- const marker = parseXmlValue(response, "Marker");
406
- return { PolicyNames: policyNames, IsTruncated: isTruncated, Marker: marker };
407
- }
408
- async putGroupPolicy(params) {
409
- await this.request("PutGroupPolicy", params);
410
- }
411
- async getGroupPolicy(params) {
412
- const response = await this.request("GetGroupPolicy", params);
413
- return {
414
- GroupName: parseXmlValue(response, "GroupName") || "",
415
- PolicyName: parseXmlValue(response, "PolicyName") || "",
416
- PolicyDocument: decodeURIComponent(parseXmlValue(response, "PolicyDocument") || "")
417
- };
418
- }
419
- async deleteGroupPolicy(params) {
420
- await this.request("DeleteGroupPolicy", params);
421
- }
422
- async listGroupPolicies(params) {
423
- const response = await this.request("ListGroupPolicies", params);
424
- const policyNames = parseXmlArray(response, "PolicyNames", "member");
425
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
426
- const marker = parseXmlValue(response, "Marker");
427
- return { PolicyNames: policyNames, IsTruncated: isTruncated, Marker: marker };
428
- }
429
- async putRolePolicy(params) {
430
- await this.request("PutRolePolicy", params);
431
- }
432
- async getRolePolicy(params) {
433
- const response = await this.request("GetRolePolicy", params);
434
- return {
435
- RoleName: parseXmlValue(response, "RoleName") || "",
436
- PolicyName: parseXmlValue(response, "PolicyName") || "",
437
- PolicyDocument: decodeURIComponent(parseXmlValue(response, "PolicyDocument") || "")
438
- };
439
- }
440
- async deleteRolePolicy(params) {
441
- await this.request("DeleteRolePolicy", params);
442
- }
443
- async listRolePolicies(params) {
444
- const response = await this.request("ListRolePolicies", params);
445
- const policyNames = parseXmlArray(response, "PolicyNames", "member");
446
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
447
- const marker = parseXmlValue(response, "Marker");
448
- return { PolicyNames: policyNames, IsTruncated: isTruncated, Marker: marker };
449
- }
450
- async createAccessKey(params = {}) {
451
- const response = await this.request("CreateAccessKey", params);
452
- if (typeof response === "object") {
453
- const accessKey = response?.CreateAccessKeyResult?.AccessKey || response?.AccessKey;
454
- if (accessKey) {
455
- return {
456
- AccessKey: {
457
- UserName: accessKey.UserName || "",
458
- AccessKeyId: accessKey.AccessKeyId || "",
459
- Status: accessKey.Status || "Active",
460
- SecretAccessKey: accessKey.SecretAccessKey || "",
461
- CreateDate: accessKey.CreateDate
462
- }
463
- };
464
- }
465
- }
466
- return {
467
- AccessKey: {
468
- UserName: parseXmlValue(response, "UserName") || "",
469
- AccessKeyId: parseXmlValue(response, "AccessKeyId") || "",
470
- Status: parseXmlValue(response, "Status") || "Active",
471
- SecretAccessKey: parseXmlValue(response, "SecretAccessKey") || "",
472
- CreateDate: parseXmlValue(response, "CreateDate")
473
- }
474
- };
475
- }
476
- async listAccessKeys(params = {}) {
477
- const response = await this.request("ListAccessKeys", params);
478
- const keys = this.parseAccessKeys(response);
479
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
480
- const marker = parseXmlValue(response, "Marker");
481
- return { AccessKeyMetadata: keys, IsTruncated: isTruncated, Marker: marker };
482
- }
483
- async updateAccessKey(params) {
484
- await this.request("UpdateAccessKey", params);
485
- }
486
- async deleteAccessKey(params) {
487
- await this.request("DeleteAccessKey", params);
488
- }
489
- async getAccessKeyLastUsed(params) {
490
- const response = await this.request("GetAccessKeyLastUsed", params);
491
- return {
492
- UserName: parseXmlValue(response, "UserName") || "",
493
- AccessKeyLastUsed: {
494
- LastUsedDate: parseXmlValue(response, "LastUsedDate"),
495
- ServiceName: parseXmlValue(response, "ServiceName"),
496
- Region: parseXmlValue(response, "Region")
497
- }
498
- };
499
- }
500
- parseAccessKeys(xml) {
501
- const memberXmls = parseXmlArray(xml, "AccessKeyMetadata", "member");
502
- return memberXmls.map((memberXml) => ({
503
- UserName: parseXmlValue(memberXml, "UserName"),
504
- AccessKeyId: parseXmlValue(memberXml, "AccessKeyId") || "",
505
- Status: parseXmlValue(memberXml, "Status") || "Active",
506
- CreateDate: parseXmlValue(memberXml, "CreateDate")
507
- }));
508
- }
509
- async createInstanceProfile(params) {
510
- const response = await this.request("CreateInstanceProfile", params);
511
- return this.parseInstanceProfile(response);
512
- }
513
- async getInstanceProfile(params) {
514
- const response = await this.request("GetInstanceProfile", params);
515
- return this.parseInstanceProfile(response);
516
- }
517
- async listInstanceProfiles(params = {}) {
518
- const response = await this.request("ListInstanceProfiles", params);
519
- const profiles = this.parseInstanceProfiles(response);
520
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
521
- const marker = parseXmlValue(response, "Marker");
522
- return { InstanceProfiles: profiles, IsTruncated: isTruncated, Marker: marker };
523
- }
524
- async listInstanceProfilesForRole(params) {
525
- const response = await this.request("ListInstanceProfilesForRole", params);
526
- const profiles = this.parseInstanceProfiles(response);
527
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
528
- const marker = parseXmlValue(response, "Marker");
529
- return { InstanceProfiles: profiles, IsTruncated: isTruncated, Marker: marker };
530
- }
531
- async addRoleToInstanceProfile(params) {
532
- await this.request("AddRoleToInstanceProfile", params);
533
- }
534
- async removeRoleFromInstanceProfile(params) {
535
- await this.request("RemoveRoleFromInstanceProfile", params);
536
- }
537
- async deleteInstanceProfile(params) {
538
- await this.request("DeleteInstanceProfile", params);
539
- }
540
- parseInstanceProfile(xml) {
541
- return {
542
- InstanceProfileName: parseXmlValue(xml, "InstanceProfileName") || "",
543
- InstanceProfileId: parseXmlValue(xml, "InstanceProfileId") || "",
544
- Arn: parseXmlValue(xml, "Arn") || "",
545
- Path: parseXmlValue(xml, "Path"),
546
- CreateDate: parseXmlValue(xml, "CreateDate")
547
- };
548
- }
549
- parseInstanceProfiles(xml) {
550
- const memberXmls = parseXmlArray(xml, "InstanceProfiles", "member");
551
- return memberXmls.map((memberXml) => ({
552
- InstanceProfileName: parseXmlValue(memberXml, "InstanceProfileName") || "",
553
- InstanceProfileId: parseXmlValue(memberXml, "InstanceProfileId") || "",
554
- Arn: parseXmlValue(memberXml, "Arn") || "",
555
- Path: parseXmlValue(memberXml, "Path"),
556
- CreateDate: parseXmlValue(memberXml, "CreateDate")
557
- }));
558
- }
559
- async getAccountPasswordPolicy() {
560
- const response = await this.request("GetAccountPasswordPolicy");
561
- return {
562
- MinimumPasswordLength: parseXmlValue(response, "MinimumPasswordLength") ? Number.parseInt(parseXmlValue(response, "MinimumPasswordLength"), 10) : undefined,
563
- RequireSymbols: parseXmlValue(response, "RequireSymbols") === "true",
564
- RequireNumbers: parseXmlValue(response, "RequireNumbers") === "true",
565
- RequireUppercaseCharacters: parseXmlValue(response, "RequireUppercaseCharacters") === "true",
566
- RequireLowercaseCharacters: parseXmlValue(response, "RequireLowercaseCharacters") === "true",
567
- AllowUsersToChangePassword: parseXmlValue(response, "AllowUsersToChangePassword") === "true",
568
- ExpirePasswords: parseXmlValue(response, "ExpirePasswords") === "true",
569
- MaxPasswordAge: parseXmlValue(response, "MaxPasswordAge") ? Number.parseInt(parseXmlValue(response, "MaxPasswordAge"), 10) : undefined,
570
- PasswordReusePrevention: parseXmlValue(response, "PasswordReusePrevention") ? Number.parseInt(parseXmlValue(response, "PasswordReusePrevention"), 10) : undefined,
571
- HardExpiry: parseXmlValue(response, "HardExpiry") === "true"
572
- };
573
- }
574
- async updateAccountPasswordPolicy(params) {
575
- await this.request("UpdateAccountPasswordPolicy", params);
576
- }
577
- async deleteAccountPasswordPolicy() {
578
- await this.request("DeleteAccountPasswordPolicy");
579
- }
580
- async getAccountSummary() {
581
- const response = await this.request("GetAccountSummary");
582
- const summary = {};
583
- const entries = parseXmlArray(response, "SummaryMap", "entry");
584
- for (const entry of entries) {
585
- const key = parseXmlValue(entry, "key");
586
- const value = parseXmlValue(entry, "value");
587
- if (key && value) {
588
- summary[key] = Number.parseInt(value, 10);
589
- }
590
- }
591
- return summary;
592
- }
593
- async listAccountAliases() {
594
- const response = await this.request("ListAccountAliases");
595
- const aliases = parseXmlArray(response, "AccountAliases", "member");
596
- const isTruncated = parseXmlValue(response, "IsTruncated") === "true";
597
- const marker = parseXmlValue(response, "Marker");
598
- return { AccountAliases: aliases, IsTruncated: isTruncated, Marker: marker };
599
- }
600
- async createAccountAlias(params) {
601
- await this.request("CreateAccountAlias", params);
602
- }
603
- async deleteAccountAlias(params) {
604
- await this.request("DeleteAccountAlias", params);
605
- }
606
- async simulatePrincipalPolicy(params) {
607
- const response = await this.request("SimulatePrincipalPolicy", params);
608
- return this.parseSimulationResults(response);
609
- }
610
- parseSimulationResults(xml) {
611
- const resultXmls = parseXmlArray(xml, "EvaluationResults", "member");
612
- const evaluationResults = resultXmls.map((resultXml) => {
613
- const matchedStatementXmls = parseXmlArray(resultXml, "MatchedStatements", "member");
614
- const matchedStatements = matchedStatementXmls.map((stmtXml) => ({
615
- SourcePolicyId: parseXmlValue(stmtXml, "SourcePolicyId"),
616
- SourcePolicyType: parseXmlValue(stmtXml, "SourcePolicyType")
617
- }));
618
- return {
619
- EvalActionName: parseXmlValue(resultXml, "EvalActionName") || "",
620
- EvalResourceName: parseXmlValue(resultXml, "EvalResourceName"),
621
- EvalDecision: parseXmlValue(resultXml, "EvalDecision") || "",
622
- MatchedStatements: matchedStatements.length > 0 ? matchedStatements : undefined
623
- };
624
- });
625
- const isTruncated = parseXmlValue(xml, "IsTruncated") === "true";
626
- const marker = parseXmlValue(xml, "Marker");
627
- return { EvaluationResults: evaluationResults, IsTruncated: isTruncated, Marker: marker };
628
- }
629
- }
630
-
631
- // src/aws/ses.ts
632
- class SESClient {
633
- client;
634
- region;
635
- constructor(region = "us-east-1", credentials) {
636
- this.region = region;
637
- this.client = new AWSClient(credentials);
638
- }
639
- async createEmailIdentity(params) {
640
- const result = await this.client.request({
641
- service: "email",
642
- region: this.region,
643
- method: "POST",
644
- path: "/v2/email/identities",
645
- headers: {
646
- "Content-Type": "application/json"
647
- },
648
- body: JSON.stringify(params)
649
- });
650
- return result;
651
- }
652
- async getEmailIdentity(emailIdentity) {
653
- const result = await this.client.request({
654
- service: "email",
655
- region: this.region,
656
- method: "GET",
657
- path: `/v2/email/identities/${encodeURIComponent(emailIdentity)}`,
658
- headers: {
659
- "Content-Type": "application/json"
660
- }
661
- });
662
- return {
663
- IdentityType: result.IdentityType,
664
- IdentityName: emailIdentity,
665
- SendingEnabled: result.VerifiedForSendingStatus,
666
- VerificationStatus: result.VerificationStatus,
667
- DkimAttributes: result.DkimAttributes,
668
- MailFromAttributes: result.MailFromAttributes
669
- };
670
- }
671
- async putEmailIdentityMailFromAttributes(emailIdentity, params) {
672
- await this.client.request({
673
- service: "email",
674
- region: this.region,
675
- method: "PUT",
676
- path: `/v2/email/identities/${encodeURIComponent(emailIdentity)}/mail-from`,
677
- headers: {
678
- "Content-Type": "application/json"
679
- },
680
- body: JSON.stringify(params)
681
- });
682
- }
683
- async listEmailIdentities(params) {
684
- let path = "/v2/email/identities";
685
- const queryParams = [];
686
- if (params?.PageSize) {
687
- queryParams.push(`PageSize=${params.PageSize}`);
688
- }
689
- if (params?.NextToken) {
690
- queryParams.push(`NextToken=${encodeURIComponent(params.NextToken)}`);
691
- }
692
- if (queryParams.length > 0) {
693
- path += `?${queryParams.join("&")}`;
694
- }
695
- const result = await this.client.request({
696
- service: "email",
697
- region: this.region,
698
- method: "GET",
699
- path,
700
- headers: {
701
- "Content-Type": "application/json"
702
- }
703
- });
704
- return {
705
- EmailIdentities: result.EmailIdentities,
706
- NextToken: result.NextToken
707
- };
708
- }
709
- async deleteEmailIdentity(emailIdentity) {
710
- await this.client.request({
711
- service: "email",
712
- region: this.region,
713
- method: "DELETE",
714
- path: `/v2/email/identities/${encodeURIComponent(emailIdentity)}`,
715
- headers: {
716
- "Content-Type": "application/json"
717
- }
718
- });
719
- }
720
- async putEmailIdentityDkimAttributes(params) {
721
- await this.client.request({
722
- service: "email",
723
- region: this.region,
724
- method: "PUT",
725
- path: `/v2/email/identities/${encodeURIComponent(params.EmailIdentity)}/dkim`,
726
- headers: {
727
- "Content-Type": "application/json"
728
- },
729
- body: JSON.stringify({ SigningEnabled: params.SigningEnabled })
730
- });
731
- }
732
- async sendEmail(params) {
733
- const result = await this.client.request({
734
- service: "email",
735
- region: this.region,
736
- method: "POST",
737
- path: "/v2/email/outbound-emails",
738
- headers: {
739
- "Content-Type": "application/json"
740
- },
741
- body: JSON.stringify(params)
742
- });
743
- return {
744
- MessageId: result.MessageId
745
- };
746
- }
747
- async sendBulkEmail(params) {
748
- const result = await this.client.request({
749
- service: "email",
750
- region: this.region,
751
- method: "POST",
752
- path: "/v2/email/outbound-bulk-emails",
753
- headers: {
754
- "Content-Type": "application/json"
755
- },
756
- body: JSON.stringify(params)
757
- });
758
- return {
759
- BulkEmailEntryResults: result.BulkEmailEntryResults
760
- };
761
- }
762
- async createEmailTemplate(params) {
763
- await this.client.request({
764
- service: "email",
765
- region: this.region,
766
- method: "POST",
767
- path: "/v2/email/templates",
768
- headers: {
769
- "Content-Type": "application/json"
770
- },
771
- body: JSON.stringify(params)
772
- });
773
- }
774
- async getEmailTemplate(templateName) {
775
- const result = await this.client.request({
776
- service: "email",
777
- region: this.region,
778
- method: "GET",
779
- path: `/v2/email/templates/${encodeURIComponent(templateName)}`,
780
- headers: {
781
- "Content-Type": "application/json"
782
- }
783
- });
784
- return result;
785
- }
786
- async deleteEmailTemplate(templateName) {
787
- await this.client.request({
788
- service: "email",
789
- region: this.region,
790
- method: "DELETE",
791
- path: `/v2/email/templates/${encodeURIComponent(templateName)}`,
792
- headers: {
793
- "Content-Type": "application/json"
794
- }
795
- });
796
- }
797
- async listEmailTemplates(params) {
798
- let path = "/v2/email/templates";
799
- const queryParams = [];
800
- if (params?.PageSize) {
801
- queryParams.push(`PageSize=${params.PageSize}`);
802
- }
803
- if (params?.NextToken) {
804
- queryParams.push(`NextToken=${encodeURIComponent(params.NextToken)}`);
805
- }
806
- if (queryParams.length > 0) {
807
- path += `?${queryParams.join("&")}`;
808
- }
809
- const result = await this.client.request({
810
- service: "email",
811
- region: this.region,
812
- method: "GET",
813
- path,
814
- headers: {
815
- "Content-Type": "application/json"
816
- }
817
- });
818
- return result;
819
- }
820
- async getSendStatistics() {
821
- const result = await this.client.request({
822
- service: "ses",
823
- region: this.region,
824
- method: "POST",
825
- path: "/",
826
- headers: {
827
- "Content-Type": "application/x-www-form-urlencoded"
828
- },
829
- body: "Action=GetSendStatistics&Version=2010-12-01"
830
- });
831
- return {
832
- SendDataPoints: result.GetSendStatisticsResponse?.GetSendStatisticsResult?.SendDataPoints?.member
833
- };
834
- }
835
- async getSendQuota() {
836
- const result = await this.client.request({
837
- service: "ses",
838
- region: this.region,
839
- method: "POST",
840
- path: "/",
841
- headers: {
842
- "Content-Type": "application/x-www-form-urlencoded"
843
- },
844
- body: "Action=GetSendQuota&Version=2010-12-01"
845
- });
846
- const quota = result.GetSendQuotaResponse?.GetSendQuotaResult;
847
- return {
848
- Max24HourSend: quota?.Max24HourSend ? Number(quota.Max24HourSend) : undefined,
849
- MaxSendRate: quota?.MaxSendRate ? Number(quota.MaxSendRate) : undefined,
850
- SentLast24Hours: quota?.SentLast24Hours ? Number(quota.SentLast24Hours) : undefined
851
- };
852
- }
853
- async verifyDomain(domain) {
854
- const result = await this.createEmailIdentity({
855
- EmailIdentity: domain
856
- });
857
- return {
858
- dkimTokens: result.DkimAttributes?.Tokens,
859
- verificationStatus: result.DkimAttributes?.Status
860
- };
861
- }
862
- async sendSimpleEmail(params) {
863
- const toAddresses = Array.isArray(params.to) ? params.to : [params.to];
864
- const replyToAddresses = params.replyTo ? Array.isArray(params.replyTo) ? params.replyTo : [params.replyTo] : undefined;
865
- const body = {};
866
- if (params.text) {
867
- body.Text = { Data: params.text };
868
- }
869
- if (params.html) {
870
- body.Html = { Data: params.html };
871
- }
872
- return this.sendEmail({
873
- FromEmailAddress: params.from,
874
- Destination: {
875
- ToAddresses: toAddresses
876
- },
877
- Content: {
878
- Simple: {
879
- Subject: { Data: params.subject },
880
- Body: body
881
- }
882
- },
883
- ReplyToAddresses: replyToAddresses
884
- });
885
- }
886
- async sendTemplatedEmail(params) {
887
- const toAddresses = Array.isArray(params.to) ? params.to : [params.to];
888
- const replyToAddresses = params.replyTo ? Array.isArray(params.replyTo) ? params.replyTo : [params.replyTo] : undefined;
889
- return this.sendEmail({
890
- FromEmailAddress: params.from,
891
- Destination: {
892
- ToAddresses: toAddresses
893
- },
894
- Content: {
895
- Template: {
896
- TemplateName: params.templateName,
897
- TemplateData: JSON.stringify(params.templateData)
898
- }
899
- },
900
- ReplyToAddresses: replyToAddresses
901
- });
902
- }
903
- async getDkimRecords(domain) {
904
- const identity = await this.getEmailIdentity(domain);
905
- if (!identity.DkimAttributes?.Tokens) {
906
- return [];
907
- }
908
- return identity.DkimAttributes.Tokens.map((token) => ({
909
- name: `${token}._domainkey.${domain}`,
910
- type: "CNAME",
911
- value: `${token}.dkim.amazonses.com`
912
- }));
913
- }
914
- async isDomainVerified(domain) {
915
- try {
916
- const identity = await this.getEmailIdentity(domain);
917
- return identity.VerificationStatus === "SUCCESS" && identity.SendingEnabled === true;
918
- } catch {
919
- return false;
920
- }
921
- }
922
- async waitForDomainVerification(domain, maxAttempts = 60, delayMs = 30000) {
923
- for (let i = 0;i < maxAttempts; i++) {
924
- const isVerified = await this.isDomainVerified(domain);
925
- if (isVerified) {
926
- return true;
927
- }
928
- await new Promise((resolve) => setTimeout(resolve, delayMs));
929
- }
930
- return false;
931
- }
932
- buildFormBody(params) {
933
- const entries = Object.entries(params).filter(([, value]) => value !== undefined).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
934
- return entries.join("&");
935
- }
936
- async createReceiptRuleSet(ruleSetName) {
937
- await this.client.request({
938
- service: "ses",
939
- region: this.region,
940
- method: "POST",
941
- path: "/",
942
- headers: {
943
- "Content-Type": "application/x-www-form-urlencoded"
944
- },
945
- body: this.buildFormBody({
946
- Action: "CreateReceiptRuleSet",
947
- Version: "2010-12-01",
948
- RuleSetName: ruleSetName
949
- })
950
- });
951
- }
952
- async deleteReceiptRuleSet(ruleSetName) {
953
- await this.client.request({
954
- service: "ses",
955
- region: this.region,
956
- method: "POST",
957
- path: "/",
958
- headers: {
959
- "Content-Type": "application/x-www-form-urlencoded"
960
- },
961
- body: this.buildFormBody({
962
- Action: "DeleteReceiptRuleSet",
963
- Version: "2010-12-01",
964
- RuleSetName: ruleSetName
965
- })
966
- });
967
- }
968
- async setActiveReceiptRuleSet(ruleSetName) {
969
- await this.client.request({
970
- service: "ses",
971
- region: this.region,
972
- method: "POST",
973
- path: "/",
974
- headers: {
975
- "Content-Type": "application/x-www-form-urlencoded"
976
- },
977
- body: this.buildFormBody({
978
- Action: "SetActiveReceiptRuleSet",
979
- Version: "2010-12-01",
980
- RuleSetName: ruleSetName
981
- })
982
- });
983
- }
984
- async listReceiptRuleSets(nextToken) {
985
- const formParams = {
986
- Action: "ListReceiptRuleSets",
987
- Version: "2010-12-01"
988
- };
989
- if (nextToken) {
990
- formParams.NextToken = nextToken;
991
- }
992
- const result = await this.client.request({
993
- service: "ses",
994
- region: this.region,
995
- method: "POST",
996
- path: "/",
997
- headers: {
998
- "Content-Type": "application/x-www-form-urlencoded"
999
- },
1000
- body: this.buildFormBody(formParams)
1001
- });
1002
- const ruleSetsResult = result?.ListReceiptRuleSetsResponse?.ListReceiptRuleSetsResult || result?.ListReceiptRuleSetsResult;
1003
- const ruleSets = ruleSetsResult?.RuleSets?.member;
1004
- return {
1005
- RuleSets: Array.isArray(ruleSets) ? ruleSets : ruleSets ? [ruleSets] : [],
1006
- NextToken: ruleSetsResult?.NextToken
1007
- };
1008
- }
1009
- async describeReceiptRuleSet(ruleSetName) {
1010
- const result = await this.client.request({
1011
- service: "ses",
1012
- region: this.region,
1013
- method: "POST",
1014
- path: "/",
1015
- headers: {
1016
- "Content-Type": "application/x-www-form-urlencoded"
1017
- },
1018
- body: this.buildFormBody({
1019
- Action: "DescribeReceiptRuleSet",
1020
- Version: "2010-12-01",
1021
- RuleSetName: ruleSetName
1022
- })
1023
- });
1024
- const response = result?.DescribeReceiptRuleSetResponse?.DescribeReceiptRuleSetResult || result?.DescribeReceiptRuleSetResult;
1025
- const rules = response?.Rules?.member;
1026
- return {
1027
- Metadata: response?.Metadata,
1028
- Rules: Array.isArray(rules) ? rules : rules ? [rules] : []
1029
- };
1030
- }
1031
- async createReceiptRule(params) {
1032
- const formParams = {
1033
- Action: "CreateReceiptRule",
1034
- Version: "2010-12-01",
1035
- RuleSetName: params.RuleSetName,
1036
- "Rule.Name": params.Rule.Name,
1037
- "Rule.Enabled": params.Rule.Enabled !== false ? "true" : "false"
1038
- };
1039
- if (params.Rule.TlsPolicy) {
1040
- formParams["Rule.TlsPolicy"] = params.Rule.TlsPolicy;
1041
- }
1042
- if (params.Rule.ScanEnabled !== undefined) {
1043
- formParams["Rule.ScanEnabled"] = params.Rule.ScanEnabled ? "true" : "false";
1044
- }
1045
- if (params.After) {
1046
- formParams.After = params.After;
1047
- }
1048
- if (params.Rule.Recipients) {
1049
- params.Rule.Recipients.forEach((recipient, index) => {
1050
- formParams[`Rule.Recipients.member.${index + 1}`] = recipient;
1051
- });
1052
- }
1053
- params.Rule.Actions.forEach((action, index) => {
1054
- const actionNum = index + 1;
1055
- if (action.S3Action) {
1056
- formParams[`Rule.Actions.member.${actionNum}.S3Action.BucketName`] = action.S3Action.BucketName;
1057
- if (action.S3Action.ObjectKeyPrefix) {
1058
- formParams[`Rule.Actions.member.${actionNum}.S3Action.ObjectKeyPrefix`] = action.S3Action.ObjectKeyPrefix;
1059
- }
1060
- if (action.S3Action.KmsKeyArn) {
1061
- formParams[`Rule.Actions.member.${actionNum}.S3Action.KmsKeyArn`] = action.S3Action.KmsKeyArn;
1062
- }
1063
- }
1064
- if (action.LambdaAction) {
1065
- formParams[`Rule.Actions.member.${actionNum}.LambdaAction.FunctionArn`] = action.LambdaAction.FunctionArn;
1066
- formParams[`Rule.Actions.member.${actionNum}.LambdaAction.InvocationType`] = action.LambdaAction.InvocationType || "Event";
1067
- }
1068
- if (action.SNSAction) {
1069
- formParams[`Rule.Actions.member.${actionNum}.SNSAction.TopicArn`] = action.SNSAction.TopicArn;
1070
- if (action.SNSAction.Encoding) {
1071
- formParams[`Rule.Actions.member.${actionNum}.SNSAction.Encoding`] = action.SNSAction.Encoding;
1072
- }
1073
- }
1074
- if (action.StopAction) {
1075
- formParams[`Rule.Actions.member.${actionNum}.StopAction.Scope`] = action.StopAction.Scope;
1076
- if (action.StopAction.TopicArn) {
1077
- formParams[`Rule.Actions.member.${actionNum}.StopAction.TopicArn`] = action.StopAction.TopicArn;
1078
- }
1079
- }
1080
- });
1081
- await this.client.request({
1082
- service: "ses",
1083
- region: this.region,
1084
- method: "POST",
1085
- path: "/",
1086
- headers: {
1087
- "Content-Type": "application/x-www-form-urlencoded"
1088
- },
1089
- body: this.buildFormBody(formParams)
1090
- });
1091
- }
1092
- async deleteReceiptRule(ruleSetName, ruleName) {
1093
- await this.client.request({
1094
- service: "ses",
1095
- region: this.region,
1096
- method: "POST",
1097
- path: "/",
1098
- headers: {
1099
- "Content-Type": "application/x-www-form-urlencoded"
1100
- },
1101
- body: this.buildFormBody({
1102
- Action: "DeleteReceiptRule",
1103
- Version: "2010-12-01",
1104
- RuleSetName: ruleSetName,
1105
- RuleName: ruleName
1106
- })
1107
- });
1108
- }
1109
- async receiptRuleSetExists(ruleSetName) {
1110
- try {
1111
- await this.describeReceiptRuleSet(ruleSetName);
1112
- return true;
1113
- } catch (error) {
1114
- if (error.code === "RuleSetDoesNotExist" || error.statusCode === 400) {
1115
- return false;
1116
- }
1117
- throw error;
1118
- }
1119
- }
1120
- async getActiveReceiptRuleSet() {
1121
- const result = await this.client.request({
1122
- service: "ses",
1123
- region: this.region,
1124
- method: "POST",
1125
- path: "/",
1126
- headers: {
1127
- "Content-Type": "application/x-www-form-urlencoded"
1128
- },
1129
- body: this.buildFormBody({
1130
- Action: "DescribeActiveReceiptRuleSet",
1131
- Version: "2010-12-01"
1132
- })
1133
- });
1134
- const response = result?.DescribeActiveReceiptRuleSetResponse?.DescribeActiveReceiptRuleSetResult || result?.DescribeActiveReceiptRuleSetResult;
1135
- if (!response?.Metadata) {
1136
- return null;
1137
- }
1138
- const rules = response?.Rules?.member;
1139
- return {
1140
- Metadata: response?.Metadata,
1141
- Rules: Array.isArray(rules) ? rules : rules ? [rules] : []
1142
- };
1143
- }
1144
- async updateReceiptRule(params) {
1145
- const formParams = {
1146
- Action: "UpdateReceiptRule",
1147
- Version: "2010-12-01",
1148
- RuleSetName: params.RuleSetName,
1149
- "Rule.Name": params.Rule.Name
1150
- };
1151
- if (params.Rule.Enabled !== undefined) {
1152
- formParams["Rule.Enabled"] = params.Rule.Enabled ? "true" : "false";
1153
- }
1154
- if (params.Rule.TlsPolicy) {
1155
- formParams["Rule.TlsPolicy"] = params.Rule.TlsPolicy;
1156
- }
1157
- if (params.Rule.ScanEnabled !== undefined) {
1158
- formParams["Rule.ScanEnabled"] = params.Rule.ScanEnabled ? "true" : "false";
1159
- }
1160
- if (params.Rule.Recipients) {
1161
- params.Rule.Recipients.forEach((recipient, index) => {
1162
- formParams[`Rule.Recipients.member.${index + 1}`] = recipient;
1163
- });
1164
- }
1165
- params.Rule.Actions.forEach((action, index) => {
1166
- const actionNum = index + 1;
1167
- if (action.S3Action) {
1168
- formParams[`Rule.Actions.member.${actionNum}.S3Action.BucketName`] = action.S3Action.BucketName;
1169
- if (action.S3Action.ObjectKeyPrefix) {
1170
- formParams[`Rule.Actions.member.${actionNum}.S3Action.ObjectKeyPrefix`] = action.S3Action.ObjectKeyPrefix;
1171
- }
1172
- if (action.S3Action.KmsKeyArn) {
1173
- formParams[`Rule.Actions.member.${actionNum}.S3Action.KmsKeyArn`] = action.S3Action.KmsKeyArn;
1174
- }
1175
- }
1176
- if (action.LambdaAction) {
1177
- formParams[`Rule.Actions.member.${actionNum}.LambdaAction.FunctionArn`] = action.LambdaAction.FunctionArn;
1178
- formParams[`Rule.Actions.member.${actionNum}.LambdaAction.InvocationType`] = action.LambdaAction.InvocationType || "Event";
1179
- }
1180
- if (action.SNSAction) {
1181
- formParams[`Rule.Actions.member.${actionNum}.SNSAction.TopicArn`] = action.SNSAction.TopicArn;
1182
- if (action.SNSAction.Encoding) {
1183
- formParams[`Rule.Actions.member.${actionNum}.SNSAction.Encoding`] = action.SNSAction.Encoding;
1184
- }
1185
- }
1186
- if (action.StopAction) {
1187
- formParams[`Rule.Actions.member.${actionNum}.StopAction.Scope`] = action.StopAction.Scope;
1188
- if (action.StopAction.TopicArn) {
1189
- formParams[`Rule.Actions.member.${actionNum}.StopAction.TopicArn`] = action.StopAction.TopicArn;
1190
- }
1191
- }
1192
- });
1193
- await this.client.request({
1194
- service: "ses",
1195
- region: this.region,
1196
- method: "POST",
1197
- path: "/",
1198
- headers: {
1199
- "Content-Type": "application/x-www-form-urlencoded"
1200
- },
1201
- body: this.buildFormBody(formParams)
1202
- });
1203
- }
1204
- async sendRawEmail(params) {
1205
- const rawMessageBase64 = Buffer.from(params.rawMessage).toString("base64");
1206
- const formParams = {
1207
- Action: "SendRawEmail",
1208
- Version: "2010-12-01",
1209
- Source: params.source,
1210
- "RawMessage.Data": rawMessageBase64
1211
- };
1212
- params.destinations.forEach((dest, index) => {
1213
- formParams[`Destinations.member.${index + 1}`] = dest;
1214
- });
1215
- const result = await this.client.request({
1216
- service: "ses",
1217
- region: this.region,
1218
- method: "POST",
1219
- path: "/",
1220
- headers: {
1221
- "Content-Type": "application/x-www-form-urlencoded"
1222
- },
1223
- body: this.buildFormBody(formParams)
1224
- });
1225
- const response = result?.SendRawEmailResponse?.SendRawEmailResult || result?.SendRawEmailResult;
1226
- return {
1227
- MessageId: response?.MessageId
1228
- };
1229
- }
1230
- async getSuppressedDestination(emailAddress) {
1231
- try {
1232
- const result = await this.client.request({
1233
- service: "ses",
1234
- region: this.region,
1235
- method: "GET",
1236
- path: `/v2/email/suppression/addresses/${encodeURIComponent(emailAddress)}`
1237
- });
1238
- return result?.SuppressedDestination || null;
1239
- } catch (error) {
1240
- if (error.message?.includes("404") || error.message?.includes("NotFoundException")) {
1241
- return null;
1242
- }
1243
- throw error;
1244
- }
1245
- }
1246
- async deleteSuppressedDestination(emailAddress) {
1247
- await this.client.request({
1248
- service: "ses",
1249
- region: this.region,
1250
- method: "DELETE",
1251
- path: `/v2/email/suppression/addresses/${encodeURIComponent(emailAddress)}`
1252
- });
1253
- }
1254
- }
1255
-
1256
- // src/aws/email.ts
1257
- class EmailClient {
1258
- ses;
1259
- s3;
1260
- iam;
1261
- route53;
1262
- region;
1263
- domain;
1264
- defaultFrom;
1265
- constructor(options = {}) {
1266
- this.region = options.region || "us-east-1";
1267
- this.domain = options.domain;
1268
- this.defaultFrom = options.defaultFrom;
1269
- this.ses = new SESClient(this.region);
1270
- this.s3 = new S3Client(this.region);
1271
- this.iam = new IAMClient(this.region);
1272
- this.route53 = new Route53Client(this.region);
1273
- }
1274
- async send(options) {
1275
- const from = options.from || this.defaultFrom;
1276
- if (!from) {
1277
- throw new Error("From address is required. Set defaultFrom in constructor or provide from in options.");
1278
- }
1279
- const fromAddress = options.fromName ? `${options.fromName} <${from}>` : from;
1280
- const toAddresses = Array.isArray(options.to) ? options.to : [options.to];
1281
- if (!options.attachments || options.attachments.length === 0) {
1282
- const result2 = await this.ses.sendSimpleEmail({
1283
- from: fromAddress,
1284
- to: toAddresses,
1285
- subject: options.subject,
1286
- text: options.text,
1287
- html: options.html,
1288
- replyTo: options.replyTo
1289
- });
1290
- return { messageId: result2.MessageId || "" };
1291
- }
1292
- const rawEmail = this.buildRawEmail(options, fromAddress, toAddresses);
1293
- const result = await this.ses.sendEmail({
1294
- FromEmailAddress: fromAddress,
1295
- Destination: {
1296
- ToAddresses: toAddresses,
1297
- CcAddresses: options.cc ? Array.isArray(options.cc) ? options.cc : [options.cc] : undefined,
1298
- BccAddresses: options.bcc ? Array.isArray(options.bcc) ? options.bcc : [options.bcc] : undefined
1299
- },
1300
- Content: {
1301
- Raw: {
1302
- Data: Buffer.from(rawEmail).toString("base64")
1303
- }
1304
- }
1305
- });
1306
- return { messageId: result.MessageId || "" };
1307
- }
1308
- async sendTemplate(options) {
1309
- const from = options.from || this.defaultFrom;
1310
- if (!from) {
1311
- throw new Error("From address is required");
1312
- }
1313
- const fromAddress = options.fromName ? `${options.fromName} <${from}>` : from;
1314
- const result = await this.ses.sendTemplatedEmail({
1315
- from: fromAddress,
1316
- to: options.to,
1317
- templateName: options.templateName,
1318
- templateData: options.templateData,
1319
- replyTo: options.replyTo
1320
- });
1321
- return { messageId: result.MessageId || "" };
1322
- }
1323
- async sendBulk(options) {
1324
- const from = options.from || this.defaultFrom;
1325
- if (!from) {
1326
- throw new Error("From address is required");
1327
- }
1328
- const entries = options.recipients.map((r) => ({
1329
- Destination: {
1330
- ToAddresses: Array.isArray(r.to) ? r.to : [r.to]
1331
- },
1332
- ReplacementEmailContent: r.templateData ? {
1333
- ReplacementTemplate: {
1334
- ReplacementTemplateData: JSON.stringify(r.templateData)
1335
- }
1336
- } : undefined
1337
- }));
1338
- const result = await this.ses.sendBulkEmail({
1339
- FromEmailAddress: from,
1340
- BulkEmailEntries: entries,
1341
- DefaultContent: {
1342
- Template: {
1343
- TemplateName: options.templateName,
1344
- TemplateData: JSON.stringify(options.defaultTemplateData)
1345
- }
1346
- }
1347
- });
1348
- return {
1349
- results: result.BulkEmailEntryResults?.map((r) => ({
1350
- status: r.Status || "UNKNOWN",
1351
- messageId: r.MessageId,
1352
- error: r.Error
1353
- })) || []
1354
- };
1355
- }
1356
- async setupDomain(domain) {
1357
- let identity;
1358
- try {
1359
- identity = await this.ses.getEmailIdentity(domain);
1360
- } catch {
1361
- const createResult = await this.ses.createEmailIdentity({ EmailIdentity: domain });
1362
- identity = {
1363
- VerificationStatus: createResult.DkimAttributes?.Status,
1364
- DkimAttributes: createResult.DkimAttributes,
1365
- SendingEnabled: createResult.VerifiedForSendingStatus
1366
- };
1367
- }
1368
- try {
1369
- await this.ses.putEmailIdentityDkimAttributes({
1370
- EmailIdentity: domain,
1371
- SigningEnabled: true
1372
- });
1373
- } catch {}
1374
- try {
1375
- await this.ses.putEmailIdentityMailFromAttributes(domain, {
1376
- MailFromDomain: `mail.${domain}`,
1377
- BehaviorOnMxFailure: "USE_DEFAULT_VALUE"
1378
- });
1379
- } catch {}
1380
- const dkimRecords = await this.ses.getDkimRecords(domain);
1381
- return {
1382
- domainVerified: identity.SendingEnabled === true,
1383
- dkimStatus: identity.DkimAttributes?.Status || "UNKNOWN",
1384
- dkimTokens: identity.DkimAttributes?.Tokens,
1385
- mailFromStatus: identity.MailFromAttributes?.MailFromDomainStatus
1386
- };
1387
- }
1388
- async getDnsRecords(domain) {
1389
- const records = [];
1390
- const dkimRecords = await this.ses.getDkimRecords(domain);
1391
- for (const record of dkimRecords) {
1392
- records.push({
1393
- type: record.type,
1394
- name: record.name,
1395
- value: record.value,
1396
- ttl: 1800
1397
- });
1398
- }
1399
- records.push({
1400
- type: "MX",
1401
- name: domain,
1402
- value: `inbound-smtp.${this.region}.amazonaws.com`,
1403
- priority: 10,
1404
- ttl: 3600
1405
- });
1406
- records.push({
1407
- type: "MX",
1408
- name: `mail.${domain}`,
1409
- value: `feedback-smtp.${this.region}.amazonses.com`,
1410
- priority: 10,
1411
- ttl: 3600
1412
- });
1413
- records.push({
1414
- type: "TXT",
1415
- name: `mail.${domain}`,
1416
- value: "v=spf1 include:amazonses.com ~all",
1417
- ttl: 3600
1418
- });
1419
- records.push({
1420
- type: "TXT",
1421
- name: `_dmarc.${domain}`,
1422
- value: `v=DMARC1;p=quarantine;pct=25;rua=mailto:dmarcreports@${domain}`,
1423
- ttl: 3600
1424
- });
1425
- return records;
1426
- }
1427
- async isDomainReady(domain) {
1428
- try {
1429
- const identity = await this.ses.getEmailIdentity(domain);
1430
- return identity.SendingEnabled === true && identity.DkimAttributes?.Status === "SUCCESS";
1431
- } catch {
1432
- return false;
1433
- }
1434
- }
1435
- async setupReceiving(config) {
1436
- const policy = {
1437
- Version: "2012-10-17",
1438
- Statement: [
1439
- {
1440
- Sid: "AllowSESPuts",
1441
- Effect: "Allow",
1442
- Principal: { Service: "ses.amazonaws.com" },
1443
- Action: "s3:PutObject",
1444
- Resource: `arn:aws:s3:::${config.bucketName}/*`,
1445
- Condition: {
1446
- StringEquals: { "AWS:SourceAccount": config.accountId }
1447
- }
1448
- }
1449
- ]
1450
- };
1451
- await this.s3.putBucketPolicy(config.bucketName, policy);
1452
- try {
1453
- await this.ses.createReceiptRuleSet(config.ruleSetName);
1454
- } catch (e) {
1455
- if (!e.message?.includes("already exists") && e.code !== "AlreadyExists") {
1456
- throw e;
1457
- }
1458
- }
1459
- const actions = [
1460
- {
1461
- S3Action: {
1462
- BucketName: config.bucketName,
1463
- ObjectKeyPrefix: config.prefix || "inbox/"
1464
- }
1465
- }
1466
- ];
1467
- if (config.lambdaArn) {
1468
- actions.push({
1469
- LambdaAction: {
1470
- FunctionArn: config.lambdaArn,
1471
- InvocationType: "Event"
1472
- }
1473
- });
1474
- }
1475
- try {
1476
- await this.ses.createReceiptRule({
1477
- RuleSetName: config.ruleSetName,
1478
- Rule: {
1479
- Name: config.ruleName,
1480
- Enabled: true,
1481
- TlsPolicy: "Optional",
1482
- Recipients: config.recipients || [config.domain],
1483
- ScanEnabled: config.scanEnabled !== false,
1484
- Actions: actions
1485
- }
1486
- });
1487
- } catch (e) {
1488
- if (e.message?.includes("already exists")) {
1489
- await this.ses.deleteReceiptRule(config.ruleSetName, config.ruleName);
1490
- await this.ses.createReceiptRule({
1491
- RuleSetName: config.ruleSetName,
1492
- Rule: {
1493
- Name: config.ruleName,
1494
- Enabled: true,
1495
- TlsPolicy: "Optional",
1496
- Recipients: config.recipients || [config.domain],
1497
- ScanEnabled: config.scanEnabled !== false,
1498
- Actions: actions
1499
- }
1500
- });
1501
- } else {
1502
- throw e;
1503
- }
1504
- }
1505
- await this.ses.setActiveReceiptRuleSet(config.ruleSetName);
1506
- }
1507
- async getIncomingEmails(options) {
1508
- const objects = await this.s3.list({
1509
- bucket: options.bucket,
1510
- prefix: options.prefix || "incoming/",
1511
- maxKeys: options.maxResults || 100
1512
- });
1513
- return objects.map((obj) => ({
1514
- key: obj.Key || "",
1515
- lastModified: obj.LastModified || "",
1516
- size: obj.Size || 0
1517
- }));
1518
- }
1519
- async readEmail(options) {
1520
- return await this.s3.getObject(options.bucket, options.key);
1521
- }
1522
- async createSmtpCredentials(options) {
1523
- const iamUsername = `ses-smtp-${options.username.replace(/[^a-zA-Z0-9]/g, "-")}`;
1524
- const { AWSClient: AWSClient2 } = await import("./chunk-x9s0cqfx.js");
1525
- const client = new AWSClient2;
1526
- const buildBody = (action, params) => {
1527
- const allParams = { Action: action, Version: "2010-05-08", ...params };
1528
- return Object.entries(allParams).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&");
1529
- };
1530
- try {
1531
- await client.request({
1532
- service: "iam",
1533
- region: "us-east-1",
1534
- method: "POST",
1535
- path: "/",
1536
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
1537
- body: buildBody("CreateUser", { UserName: iamUsername })
1538
- });
1539
- } catch (e) {
1540
- if (!e.message?.includes("EntityAlreadyExists")) {
1541
- throw e;
1542
- }
1543
- }
1544
- const policy = {
1545
- Version: "2012-10-17",
1546
- Statement: [
1547
- {
1548
- Effect: "Allow",
1549
- Action: "ses:SendRawEmail",
1550
- Resource: "*",
1551
- Condition: {
1552
- StringLike: {
1553
- "ses:FromAddress": `*@${options.domain}`
1554
- }
1555
- }
1556
- }
1557
- ]
1558
- };
1559
- const policyName = `ses-smtp-policy-${options.domain.replace(/\./g, "-")}`;
1560
- try {
1561
- await client.request({
1562
- service: "iam",
1563
- region: "us-east-1",
1564
- method: "POST",
1565
- path: "/",
1566
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
1567
- body: buildBody("PutUserPolicy", {
1568
- UserName: iamUsername,
1569
- PolicyName: policyName,
1570
- PolicyDocument: JSON.stringify(policy)
1571
- })
1572
- });
1573
- } catch {}
1574
- const keyResponse = await client.request({
1575
- service: "iam",
1576
- region: "us-east-1",
1577
- method: "POST",
1578
- path: "/",
1579
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
1580
- body: buildBody("CreateAccessKey", { UserName: iamUsername })
1581
- });
1582
- const accessKey = keyResponse?.CreateAccessKeyResult?.AccessKey;
1583
- if (!accessKey?.AccessKeyId || !accessKey?.SecretAccessKey) {
1584
- throw new Error("Failed to create access key");
1585
- }
1586
- const smtpPassword = this.deriveSmtpPassword(accessKey.SecretAccessKey);
1587
- return {
1588
- username: accessKey.AccessKeyId,
1589
- password: smtpPassword,
1590
- server: `email-smtp.${this.region}.amazonaws.com`,
1591
- port: 587
1592
- };
1593
- }
1594
- deriveSmtpPassword(secretAccessKey) {
1595
- const crypto = __require("node:crypto");
1596
- const message = "SendRawEmail";
1597
- const versionInBytes = Buffer.from([4]);
1598
- let signature = crypto.createHmac("sha256", `AWS4${secretAccessKey}`).update("11111111").digest();
1599
- signature = crypto.createHmac("sha256", signature).update(this.region).digest();
1600
- signature = crypto.createHmac("sha256", signature).update("ses").digest();
1601
- signature = crypto.createHmac("sha256", signature).update("aws4_request").digest();
1602
- signature = crypto.createHmac("sha256", signature).update(message).digest();
1603
- const signatureWithVersion = Buffer.concat([versionInBytes, signature]);
1604
- return signatureWithVersion.toString("base64");
1605
- }
1606
- async createTemplate(options) {
1607
- await this.ses.createEmailTemplate({
1608
- TemplateName: options.name,
1609
- TemplateContent: {
1610
- Subject: options.subject,
1611
- Text: options.text,
1612
- Html: options.html
1613
- }
1614
- });
1615
- }
1616
- async getTemplate(name) {
1617
- try {
1618
- const result = await this.ses.getEmailTemplate(name);
1619
- return {
1620
- name: result.TemplateName || name,
1621
- subject: result.TemplateContent?.Subject,
1622
- text: result.TemplateContent?.Text,
1623
- html: result.TemplateContent?.Html
1624
- };
1625
- } catch {
1626
- return null;
1627
- }
1628
- }
1629
- async deleteTemplate(name) {
1630
- await this.ses.deleteEmailTemplate(name);
1631
- }
1632
- async listTemplates() {
1633
- const result = await this.ses.listEmailTemplates();
1634
- return result.TemplatesMetadata?.map((t) => ({
1635
- name: t.TemplateName || "",
1636
- createdAt: t.CreatedTimestamp
1637
- })) || [];
1638
- }
1639
- async deploy(config) {
1640
- const ruleSetName = `${config.appName}-${config.environment}-email-rules`;
1641
- const ruleName = `${config.appName}-inbound-email`;
1642
- const bucketName = config.storage?.bucketName || `${config.appName}-${config.environment}-email`;
1643
- const domainSetup = await this.setupDomain(config.domain);
1644
- const buckets = await this.s3.listBuckets();
1645
- const bucketExists = buckets.Buckets?.some((b) => b.Name === bucketName);
1646
- if (!bucketExists) {
1647
- await this.s3.createBucket(bucketName);
1648
- }
1649
- await this.setupReceiving({
1650
- domain: config.domain,
1651
- ruleSetName,
1652
- ruleName,
1653
- bucketName,
1654
- prefix: config.storage?.prefix || "inbox/",
1655
- accountId: config.accountId,
1656
- recipients: config.catchAll ? [config.domain] : config.mailboxes,
1657
- scanEnabled: true
1658
- });
1659
- const dnsRecords = await this.getDnsRecords(config.domain);
1660
- return {
1661
- success: true,
1662
- domainVerified: domainSetup.domainVerified,
1663
- dkimStatus: domainSetup.dkimStatus,
1664
- receiptRuleSet: ruleSetName,
1665
- storageBucket: bucketName,
1666
- dnsRecords
1667
- };
1668
- }
1669
- async undeploy(config) {
1670
- const ruleSetName = `${config.appName}-${config.environment}-email-rules`;
1671
- const ruleName = `${config.appName}-inbound-email`;
1672
- const bucketName = `${config.appName}-${config.environment}-email`;
1673
- try {
1674
- await this.ses.deleteReceiptRule(ruleSetName, ruleName);
1675
- } catch {}
1676
- try {
1677
- await this.ses.deleteReceiptRuleSet(ruleSetName);
1678
- } catch {}
1679
- if (config.deleteBucket) {
1680
- try {
1681
- await this.s3.emptyAndDeleteBucket(bucketName);
1682
- } catch {}
1683
- }
1684
- }
1685
- async getSendingStats() {
1686
- const quota = await this.ses.getSendQuota();
1687
- return {
1688
- sentLast24Hours: quota.SentLast24Hours || 0,
1689
- maxSendRate: quota.MaxSendRate || 0,
1690
- max24HourSend: quota.Max24HourSend || 0
1691
- };
1692
- }
1693
- buildRawEmail(options, from, to) {
1694
- const boundary = `----=_Part_${Date.now()}_${Math.random().toString(36).substring(2)}`;
1695
- let email = "";
1696
- email += `From: ${from}\r
1697
- `;
1698
- email += `To: ${to.join(", ")}\r
1699
- `;
1700
- if (options.cc) {
1701
- const ccList = Array.isArray(options.cc) ? options.cc : [options.cc];
1702
- email += `Cc: ${ccList.join(", ")}\r
1703
- `;
1704
- }
1705
- email += `Subject: ${options.subject}\r
1706
- `;
1707
- email += `MIME-Version: 1.0\r
1708
- `;
1709
- email += `Content-Type: multipart/mixed; boundary="${boundary}"\r
1710
- `;
1711
- email += `\r
1712
- `;
1713
- if (options.text || options.html) {
1714
- email += `--${boundary}\r
1715
- `;
1716
- if (options.html && options.text) {
1717
- const altBoundary = `----=_Alt_${Date.now()}`;
1718
- email += `Content-Type: multipart/alternative; boundary="${altBoundary}"\r
1719
- `;
1720
- email += `\r
1721
- `;
1722
- email += `--${altBoundary}\r
1723
- `;
1724
- email += `Content-Type: text/plain; charset="UTF-8"\r
1725
- `;
1726
- email += `\r
1727
- `;
1728
- email += `${options.text}\r
1729
- `;
1730
- email += `--${altBoundary}\r
1731
- `;
1732
- email += `Content-Type: text/html; charset="UTF-8"\r
1733
- `;
1734
- email += `\r
1735
- `;
1736
- email += `${options.html}\r
1737
- `;
1738
- email += `--${altBoundary}--\r
1739
- `;
1740
- } else if (options.html) {
1741
- email += `Content-Type: text/html; charset="UTF-8"\r
1742
- `;
1743
- email += `\r
1744
- `;
1745
- email += `${options.html}\r
1746
- `;
1747
- } else {
1748
- email += `Content-Type: text/plain; charset="UTF-8"\r
1749
- `;
1750
- email += `\r
1751
- `;
1752
- email += `${options.text}\r
1753
- `;
1754
- }
1755
- }
1756
- if (options.attachments) {
1757
- for (const attachment of options.attachments) {
1758
- email += `--${boundary}\r
1759
- `;
1760
- email += `Content-Type: ${attachment.contentType || "application/octet-stream"}; name="${attachment.filename}"\r
1761
- `;
1762
- email += `Content-Transfer-Encoding: base64\r
1763
- `;
1764
- email += `Content-Disposition: attachment; filename="${attachment.filename}"\r
1765
- `;
1766
- email += `\r
1767
- `;
1768
- email += `${attachment.content}\r
1769
- `;
1770
- }
1771
- }
1772
- email += `--${boundary}--\r
1773
- `;
1774
- return email;
1775
- }
1776
- }
1777
- var email = new EmailClient;
1778
-
1779
- export { IAMClient, SESClient, EmailClient, email };