resend-cli 1.0.3 → 1.1.0

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 (180) hide show
  1. package/.claude/settings.local.json +14 -0
  2. package/.github/scripts/pr-title-check.js +34 -0
  3. package/.github/workflows/ci.yml +32 -0
  4. package/.github/workflows/pr-title-check.yml +13 -0
  5. package/.github/workflows/release.yml +93 -0
  6. package/CHANGELOG.md +31 -0
  7. package/LICENSE +21 -21
  8. package/README.md +416 -19
  9. package/biome.json +36 -0
  10. package/bun.lock +76 -0
  11. package/bunfig.toml +2 -0
  12. package/install.ps1 +140 -0
  13. package/install.sh +294 -0
  14. package/package.json +43 -22
  15. package/src/cli.ts +65 -0
  16. package/src/commands/api-keys/create.ts +114 -0
  17. package/src/commands/api-keys/delete.ts +47 -0
  18. package/src/commands/api-keys/index.ts +26 -0
  19. package/src/commands/api-keys/list.ts +35 -0
  20. package/src/commands/api-keys/utils.ts +8 -0
  21. package/src/commands/auth/index.ts +20 -0
  22. package/src/commands/auth/login.ts +211 -0
  23. package/src/commands/auth/logout.ts +105 -0
  24. package/src/commands/broadcasts/create.ts +196 -0
  25. package/src/commands/broadcasts/delete.ts +46 -0
  26. package/src/commands/broadcasts/get.ts +59 -0
  27. package/src/commands/broadcasts/index.ts +43 -0
  28. package/src/commands/broadcasts/list.ts +60 -0
  29. package/src/commands/broadcasts/send.ts +56 -0
  30. package/src/commands/broadcasts/update.ts +95 -0
  31. package/src/commands/broadcasts/utils.ts +35 -0
  32. package/src/commands/contact-properties/create.ts +118 -0
  33. package/src/commands/contact-properties/delete.ts +48 -0
  34. package/src/commands/contact-properties/get.ts +46 -0
  35. package/src/commands/contact-properties/index.ts +48 -0
  36. package/src/commands/contact-properties/list.ts +68 -0
  37. package/src/commands/contact-properties/update.ts +88 -0
  38. package/src/commands/contact-properties/utils.ts +17 -0
  39. package/src/commands/contacts/add-segment.ts +78 -0
  40. package/src/commands/contacts/create.ts +122 -0
  41. package/src/commands/contacts/delete.ts +49 -0
  42. package/src/commands/contacts/get.ts +53 -0
  43. package/src/commands/contacts/index.ts +58 -0
  44. package/src/commands/contacts/list.ts +57 -0
  45. package/src/commands/contacts/remove-segment.ts +48 -0
  46. package/src/commands/contacts/segments.ts +39 -0
  47. package/src/commands/contacts/topics.ts +45 -0
  48. package/src/commands/contacts/update-topics.ts +90 -0
  49. package/src/commands/contacts/update.ts +77 -0
  50. package/src/commands/contacts/utils.ts +119 -0
  51. package/src/commands/doctor.ts +298 -0
  52. package/src/commands/domains/create.ts +83 -0
  53. package/src/commands/domains/delete.ts +42 -0
  54. package/src/commands/domains/get.ts +47 -0
  55. package/src/commands/domains/index.ts +35 -0
  56. package/src/commands/domains/list.ts +53 -0
  57. package/src/commands/domains/update.ts +75 -0
  58. package/src/commands/domains/utils.ts +44 -0
  59. package/src/commands/domains/verify.ts +38 -0
  60. package/src/commands/emails/batch.ts +140 -0
  61. package/src/commands/emails/index.ts +24 -0
  62. package/src/commands/emails/receiving/attachment.ts +55 -0
  63. package/src/commands/emails/receiving/attachments.ts +68 -0
  64. package/src/commands/emails/receiving/get.ts +58 -0
  65. package/src/commands/emails/receiving/index.ts +28 -0
  66. package/src/commands/emails/receiving/list.ts +59 -0
  67. package/src/commands/emails/receiving/utils.ts +38 -0
  68. package/src/commands/emails/send.ts +189 -0
  69. package/src/commands/segments/create.ts +50 -0
  70. package/src/commands/segments/delete.ts +47 -0
  71. package/src/commands/segments/get.ts +38 -0
  72. package/src/commands/segments/index.ts +36 -0
  73. package/src/commands/segments/list.ts +58 -0
  74. package/src/commands/segments/utils.ts +7 -0
  75. package/src/commands/teams/index.ts +10 -0
  76. package/src/commands/teams/list.ts +35 -0
  77. package/src/commands/teams/remove.ts +83 -0
  78. package/src/commands/teams/switch.ts +73 -0
  79. package/src/commands/topics/create.ts +73 -0
  80. package/src/commands/topics/delete.ts +47 -0
  81. package/src/commands/topics/get.ts +42 -0
  82. package/src/commands/topics/index.ts +42 -0
  83. package/src/commands/topics/list.ts +34 -0
  84. package/src/commands/topics/update.ts +59 -0
  85. package/src/commands/topics/utils.ts +16 -0
  86. package/src/commands/webhooks/create.ts +128 -0
  87. package/src/commands/webhooks/delete.ts +49 -0
  88. package/src/commands/webhooks/get.ts +42 -0
  89. package/src/commands/webhooks/index.ts +44 -0
  90. package/src/commands/webhooks/list.ts +55 -0
  91. package/src/commands/webhooks/update.ts +83 -0
  92. package/src/commands/webhooks/utils.ts +36 -0
  93. package/src/commands/whoami.ts +71 -0
  94. package/src/lib/actions.ts +157 -0
  95. package/src/lib/client.ts +29 -0
  96. package/src/lib/config.ts +211 -0
  97. package/src/lib/files.ts +15 -0
  98. package/src/lib/help-text.ts +36 -0
  99. package/src/lib/output.ts +54 -0
  100. package/src/lib/pagination.ts +36 -0
  101. package/src/lib/prompts.ts +149 -0
  102. package/src/lib/spinner.ts +89 -0
  103. package/src/lib/table.ts +57 -0
  104. package/src/lib/tty.ts +28 -0
  105. package/src/lib/version.ts +4 -0
  106. package/tests/commands/api-keys/create.test.ts +195 -0
  107. package/tests/commands/api-keys/delete.test.ts +156 -0
  108. package/tests/commands/api-keys/list.test.ts +133 -0
  109. package/tests/commands/auth/login.test.ts +119 -0
  110. package/tests/commands/auth/logout.test.ts +146 -0
  111. package/tests/commands/broadcasts/create.test.ts +447 -0
  112. package/tests/commands/broadcasts/delete.test.ts +182 -0
  113. package/tests/commands/broadcasts/get.test.ts +146 -0
  114. package/tests/commands/broadcasts/list.test.ts +196 -0
  115. package/tests/commands/broadcasts/send.test.ts +161 -0
  116. package/tests/commands/broadcasts/update.test.ts +283 -0
  117. package/tests/commands/contact-properties/create.test.ts +250 -0
  118. package/tests/commands/contact-properties/delete.test.ts +183 -0
  119. package/tests/commands/contact-properties/get.test.ts +144 -0
  120. package/tests/commands/contact-properties/list.test.ts +180 -0
  121. package/tests/commands/contact-properties/update.test.ts +216 -0
  122. package/tests/commands/contacts/add-segment.test.ts +188 -0
  123. package/tests/commands/contacts/create.test.ts +270 -0
  124. package/tests/commands/contacts/delete.test.ts +192 -0
  125. package/tests/commands/contacts/get.test.ts +148 -0
  126. package/tests/commands/contacts/list.test.ts +175 -0
  127. package/tests/commands/contacts/remove-segment.test.ts +166 -0
  128. package/tests/commands/contacts/segments.test.ts +167 -0
  129. package/tests/commands/contacts/topics.test.ts +163 -0
  130. package/tests/commands/contacts/update-topics.test.ts +247 -0
  131. package/tests/commands/contacts/update.test.ts +205 -0
  132. package/tests/commands/doctor.test.ts +165 -0
  133. package/tests/commands/domains/create.test.ts +192 -0
  134. package/tests/commands/domains/delete.test.ts +156 -0
  135. package/tests/commands/domains/get.test.ts +137 -0
  136. package/tests/commands/domains/list.test.ts +164 -0
  137. package/tests/commands/domains/update.test.ts +223 -0
  138. package/tests/commands/domains/verify.test.ts +117 -0
  139. package/tests/commands/emails/batch.test.ts +313 -0
  140. package/tests/commands/emails/receiving/attachment.test.ts +140 -0
  141. package/tests/commands/emails/receiving/attachments.test.ts +168 -0
  142. package/tests/commands/emails/receiving/get.test.ts +140 -0
  143. package/tests/commands/emails/receiving/list.test.ts +181 -0
  144. package/tests/commands/emails/send.test.ts +309 -0
  145. package/tests/commands/segments/create.test.ts +163 -0
  146. package/tests/commands/segments/delete.test.ts +182 -0
  147. package/tests/commands/segments/get.test.ts +137 -0
  148. package/tests/commands/segments/list.test.ts +173 -0
  149. package/tests/commands/teams/list.test.ts +63 -0
  150. package/tests/commands/teams/remove.test.ts +103 -0
  151. package/tests/commands/teams/switch.test.ts +96 -0
  152. package/tests/commands/topics/create.test.ts +191 -0
  153. package/tests/commands/topics/delete.test.ts +156 -0
  154. package/tests/commands/topics/get.test.ts +125 -0
  155. package/tests/commands/topics/list.test.ts +124 -0
  156. package/tests/commands/topics/update.test.ts +177 -0
  157. package/tests/commands/webhooks/create.test.ts +224 -0
  158. package/tests/commands/webhooks/delete.test.ts +156 -0
  159. package/tests/commands/webhooks/get.test.ts +125 -0
  160. package/tests/commands/webhooks/list.test.ts +177 -0
  161. package/tests/commands/webhooks/update.test.ts +206 -0
  162. package/tests/commands/whoami.test.ts +99 -0
  163. package/tests/helpers.ts +93 -0
  164. package/tests/lib/client.test.ts +71 -0
  165. package/tests/lib/config.test.ts +414 -0
  166. package/tests/lib/files.test.ts +65 -0
  167. package/tests/lib/help-text.test.ts +96 -0
  168. package/tests/lib/output.test.ts +127 -0
  169. package/tests/lib/prompts.test.ts +178 -0
  170. package/tests/lib/spinner.test.ts +146 -0
  171. package/tests/lib/table.test.ts +63 -0
  172. package/tests/lib/tty.test.ts +85 -0
  173. package/tsconfig.json +14 -0
  174. package/src/index.js +0 -72
  175. package/src/routes.js +0 -37
  176. package/src/sections/apikeys.js +0 -99
  177. package/src/sections/audiences.js +0 -84
  178. package/src/sections/contacts.js +0 -177
  179. package/src/sections/domain.js +0 -195
  180. package/src/sections/email.js +0 -132
@@ -1,84 +0,0 @@
1
- import ora from "ora"
2
- import enquirer from "enquirer";
3
-
4
- const logAudience = (audience) => {
5
- console.log(`- ID: ${audience.id}`)
6
- console.log(`- Name: ${audience.name}`)
7
- if (audience.created_at) {
8
- console.log(`- Created At: ${audience.created_at}`)
9
- }
10
- }
11
-
12
- export default async function({resend, apiKey}) {
13
- let mainForm = new enquirer.Select({
14
- message: "Choose an action",
15
- choices: [
16
- {name: "add", message: "Add Audience"},
17
- {name: "retrieve", message: "List/Retrieve Audience"},
18
- {name: "delete", message: "Delete Audience"},
19
- ]
20
- })
21
- mainForm = await mainForm.run()
22
-
23
- switch (mainForm) {
24
- case "add":
25
- {
26
- let form = new enquirer.Form({
27
- name: "createAudience",
28
- message: "Create an audience",
29
- choices: [
30
- {name: "name", message: "Name", initial: "My Audience"},
31
- ]
32
- })
33
- form = await form.run()
34
- const spinner = ora({text: "Creating audience...", spinner: "toggle9"}).start()
35
- const audience = await resend.audiences.create({name: form.name})
36
- spinner.stop()
37
- console.log(`Audience created.`)
38
- logAudience(audience.data)
39
- }
40
- break
41
- case "retrieve":
42
- {
43
- const audienceId = await selectAudience({resend}, "Choose an audience")
44
- const spinner = ora({text: "Retrieving audience...", spinner: "toggle9"}).start()
45
- const audience = await resend.audiences.get(audienceId)
46
- spinner.stop()
47
- console.log(`Audience '${audience.data.name}' retrieved.`)
48
- logAudience(audience.data)
49
- }
50
- break
51
- case "delete":
52
- {
53
- const audienceId = await selectAudience({resend}, "Choose an audience")
54
- let confirmation = new enquirer.Confirm({
55
- message: "Are you sure you want to delete this audience?",
56
- initial: false
57
- })
58
- confirmation = await confirmation.run()
59
- if (!confirmation) {
60
- console.log("Cancelled.")
61
- process.exit(0)
62
- }
63
- const spinner = ora({text: "Deleting audience...", spinner: "toggle9"}).start()
64
- await resend.audiences.remove(audienceId)
65
- spinner.stop()
66
- console.log("Audience deleted.")
67
- }
68
- break
69
- }
70
- }
71
-
72
- export async function selectAudience({resend}, message) {
73
- const spinner = ora({text: "Fetching audiences...", spinner: "toggle9"}).start()
74
- const audiences = await resend.audiences.list()
75
- spinner.stop()
76
- const choices = audiences.data.data.map((audience) => {return {message: audience.name, name: audience.id}})
77
- let answer = new enquirer.Select({
78
- name: "listAudiences",
79
- message: message ?? "Choose an audience",
80
- choices
81
- })
82
- answer = await answer.run()
83
- return answer
84
- }
@@ -1,177 +0,0 @@
1
- import ora from "ora"
2
- import enquirer from "enquirer";
3
- import {selectAudience} from "./audiences.js";
4
-
5
- const logContact = (contact) => {
6
- console.log("- ID: " + contact.id)
7
- console.log("- Email: " + contact.email)
8
- console.log("- First Name: " + (contact.first_name ?? "N/A"))
9
- console.log("- Last Name: " + (contact.last_name ?? "N/A"))
10
- console.log("- Created At: " + contact.created_at)
11
- console.log("- Unsubscribed: " + contact.unsubscribed)
12
-
13
- }
14
-
15
- export default async function({resend, apiKey}) {
16
- const mainForm = new enquirer.Select({
17
- message: "Choose an action",
18
- choices: [
19
- {name: "add", message: "Add Contact"},
20
- {name: "retrieve", message: "Retrieve Contact"},
21
- {name: "update", message: "Update Contact"},
22
- {name: "delete", message: "Delete Contact"},
23
- {name: "list", message: "List Contacts"},
24
- ]
25
- })
26
- const mainFormResponse = await mainForm.run()
27
- switch (mainFormResponse) {
28
- case "add":
29
- {
30
- const audienceID = await selectAudience({resend}, "Choose an audience to add a contact to")
31
- let form = new enquirer.Form({
32
- name: "createContact",
33
- message: "Add a contact",
34
- choices: [
35
- {name: "email", message: "Email"},
36
- {name: "firstName", message: "First Name", initial: ""},
37
- {name: "lastName", message: "Last Name", initial: ""},
38
- ]
39
- })
40
- form = await form.run()
41
- const spin = ora({text: "Adding contact...", spinner: "toggle9"}).start()
42
- const contact = await resend.contacts.create({
43
- audienceId: audienceID,
44
- email: form.email,
45
- firstName: form.firstName,
46
- lastName: form.lastName
47
- })
48
- spin.stop()
49
- //console.log(contact)
50
- console.log(`Contact with ID ${contact.data.id} added.`)
51
- }
52
- break
53
- case "retrieve":
54
- {
55
- const audienceId = await selectAudience({resend}, "Choose an audience")
56
- let form = new enquirer.Form({
57
- name: "retrieveContact",
58
- message: "Retrieve a contact",
59
- choices: [
60
- {name: "emailOrID", message: "Email or Contact ID"},
61
- ]
62
- })
63
- form = await form.run()
64
- if (form.emailOrID.includes("@")) {
65
- // we need to list contacts and find the contact with the email
66
- const spin = ora({text: "Retrieving contact...", spinner: "toggle9"}).start()
67
- const contacts = await resend.contacts.list({audienceId})
68
- for (let contact of contacts.data.data) {
69
- if (contact.email === form.emailOrID) {
70
- spin.stop()
71
- logContact(contact)
72
- }
73
- }
74
- } else {
75
- const spin = ora({text: "Retrieving contact...", spinner: "toggle9"}).start()
76
- const contact = await resend.contacts.get({id: form.emailOrID, audienceId})
77
- spin.stop()
78
- console.log("- Email: " + contact.data.email)
79
- console.log("- First Name: " + (contact.data.first_name ?? "N/A"))
80
- console.log("- Last Name: " + (contact.data.last_name ?? "N/A"))
81
- console.log("- Created At: " + contact.data.created_at)
82
- console.log("- Unsubscribed: " + contact.data.unsubscribed)
83
- }
84
- }
85
- break
86
- case "update":
87
- {
88
- const audienceId = await selectAudience({resend}, "Choose an audience")
89
- let form = new enquirer.Form({
90
- name: "updateContact",
91
- message: "Update a contact",
92
- choices: [
93
- {name: "emailOrID", message: "Email or Contact ID"},
94
- {name: "firstName", message: "First Name", initial: ""},
95
- {name: "lastName", message: "Last Name", initial: ""},
96
- {name: "unsubscribed", message: "Unsubscribed (either true or false)"}
97
- ]
98
- })
99
- form = await form.run()
100
- if (form.emailOrID.includes("@")) {
101
- // we need to list contacts and find the contact with the email
102
- const spin = ora({text: "Updating contact...", spinner: "toggle9"}).start()
103
- const contacts = await resend.contacts.list({audienceId})
104
- for (let contact of contacts.data.data) {
105
- if (contact.email === form.emailOrID) {
106
- const contactUpdate = await resend.contacts.update({
107
- id: contact.id,
108
- audienceId,
109
- firstName: form.firstName,
110
- lastName: form.lastName,
111
- unsubscribed: form.unsubscribed
112
- })
113
- spin.stop()
114
- console.log(`Contact with ID ${contactUpdate.data.id} updated.`)
115
- }
116
- }
117
- } else {
118
- const spin = ora({text: "Updating contact...", spinner: "toggle9"}).start()
119
- const contactUpdate = await resend.contacts.update({
120
- id: form.emailOrID,
121
- audienceId,
122
- firstName: form.firstName,
123
- lastName: form.lastName,
124
- unsubscribed: form.unsubscribed
125
- })
126
- spin.stop()
127
- console.log(`Contact with ID ${contactUpdate.data.id} updated.`)
128
- }
129
- }
130
- break
131
- case "delete":
132
- {
133
- const audienceId = await selectAudience({resend}, "Choose an audience")
134
- let form = new enquirer.Form({
135
- name: "deleteContact",
136
- message: "Delete a contact",
137
- choices: [
138
- {name: "emailOrID", message: "Email or Contact ID"},
139
- ]
140
- })
141
- form = await form.run()
142
- if (form.emailOrID.includes("@")) {
143
- const spin = ora({text: "Deleting contact...", spinner: "toggle9"}).start()
144
- const contactDelete = await resend.contacts.remove({email: form.emailOrID, audienceId})
145
- spin.stop()
146
- console.log(`Contact with ID ${form.emailOrID} deleted.`)
147
- } else {
148
- const spin = ora({text: "Deleting contact...", spinner: "toggle9"}).start()
149
- const contactDelete = await resend.contacts.remove({id: form.emailOrID, audienceId})
150
- spin.stop()
151
- console.log(`Contact with ID ${form.emailOrID} deleted.`)
152
- }
153
- }
154
- break
155
- case "list":
156
- {
157
- const audienceId = await selectAudience({resend}, "Choose an audience")
158
- const spin = ora({text: "Fetching contacts...", spinner: "toggle9"}).start()
159
- const contacts = await resend.contacts.list({audienceId})
160
- spin.stop()
161
- //show a select with contact names
162
- const choices = contacts.data.data.map((contact) => {return {message: contact.email, name: contact.id}})
163
- let answer = new enquirer.Select({
164
- name: "listContacts",
165
- message: "Choose a contact to view info on",
166
- choices
167
- })
168
- answer = await answer.run()
169
- for (let contact of contacts.data.data) {
170
- if (contact.id === answer) {
171
- logContact(contact)
172
- }
173
- }
174
- }
175
- }
176
- process.exit(0)
177
- }
@@ -1,195 +0,0 @@
1
- import ora from "ora"
2
- import enquirer from "enquirer";
3
-
4
- const logDomain = (domain) => {
5
- console.log(`ID: ${domain.data.id}`)
6
- console.log(`Name: ${domain.data.name}`)
7
- console.log(`Region: ${domain.data.region}`)
8
- console.log(`Status: ${domain.data.status}`)
9
- console.log(`Created At: ${domain.data.created_at}`)
10
- }
11
-
12
- export default async function({resend}) {
13
- let mainForm = new enquirer.Select({
14
- message: "Choose an action",
15
- choices: [
16
- {name: "add", message: "Add Domain"},
17
- {name: "retrieve", message: "Retrieve Domain"},
18
- {name: "verify", message: "Verify Domain"},
19
- {name: "update", message: "Update Domain"},
20
- {name: "list", message: "List Domains"},
21
- {name: "delete", message: "Delete Domain"},
22
- ]
23
- })
24
- mainForm = await mainForm.run()
25
- switch (mainForm) {
26
- case "add":
27
- {
28
- let form = new enquirer.Form({
29
- name: "createDomain",
30
- message: "Add a domain",
31
- choices: [
32
- {name: "name", message: "Domain/subdomain without http"},
33
- {name: "region", message: "Region (possible values: us-east-1, eu-west-1, sa-east-1, ap-northeast-1)", initial: "us-east-1"},
34
- ]
35
- })
36
- form = await form.run()
37
- const spin = ora({text: "Adding domain...", spinner: "toggle9"}).start()
38
- const domain = await resend.domains.create({
39
- name: form.name,
40
- region: form.region
41
- })
42
- if (domain.error) {
43
- spin.stop()
44
- console.error(domain.error.message)
45
- process.exit(1)
46
- }
47
- spin.stop()
48
- console.log(`Domain with ID ${domain.data.id} added.`)
49
-
50
- const choices = domain.data.records.map((record, i) => { return {name: i, message: `Record #${i+1}`} })
51
-
52
- const records = new enquirer.Select({
53
- name: "createRecords",
54
- message: "Add all of the following records to your DNS provider",
55
- choices
56
- })
57
- let recordsResult
58
- async function iterateRecords() {
59
- recordsResult = await records.run()
60
- let record = domain.data.records[recordsResult]
61
- console.log("Add the following record to your DNS provider:")
62
- console.log(`- Type: ${record.type}`)
63
- console.log(`- Value: ${record.value}`)
64
- if (record.priority) {
65
- console.log(`- Priority: ${record.priority}`)
66
- }
67
- if (record.ttl) {
68
- console.log(`- TTL: ${record.ttl}`)
69
- }
70
- console.log("Once you have finished adding the records, run resend-cli and navigate to Domains -> Verify Domain.")
71
- await iterateRecords()
72
- }
73
- await iterateRecords()
74
- }
75
- break
76
- case "retrieve":
77
- {
78
- let form = new enquirer.Form({
79
- name: "retrieveDomain",
80
- message: "Retrieve a domain",
81
- choices: [{name: "id", message: "Domain ID"},]
82
- })
83
- form = await form.run()
84
- const spin = ora({text: "Retrieving domain...", spinner: "toggle9"}).start()
85
- const domain = await resend.domains.get(form.id)
86
- if (domain.error) {
87
- spin.stop()
88
- console.error(domain.error.message)
89
- process.exit(1)
90
- }
91
- spin.stop()
92
- logDomain(domain)
93
- }
94
- break
95
- case "verify":
96
- {
97
- let form = new enquirer.Form({
98
- name: "verifyDomain",
99
- message: "Verify a domain",
100
- choices: [{name: "id", message: "Domain ID"},]
101
- })
102
- form = await form.run()
103
- const spin = ora({text: "Submitting request...", spinner: "toggle9"}).start()
104
- const domain = await resend.domains.verify(form.id)
105
- if (domain.error) {
106
- spin.stop()
107
- console.error(domain.error.message)
108
- process.exit(1)
109
- }
110
- spin.stop()
111
- console.log(`Domain with ID ${domain.data.id} submitted for verification.`)
112
- }
113
- break
114
- case "update":
115
- {
116
- let id = new enquirer.Input({
117
- message: "Enter the ID of the domain you want to update"
118
- })
119
- id = await id.run()
120
- let confirm1 = new enquirer.Confirm({
121
- message: "Enable click tracking?",
122
- initial: false
123
- })
124
- confirm1 = await confirm1.run()
125
- let confirm2 = new enquirer.Confirm({
126
- message: "Enable open tracking?",
127
- initial: false
128
- })
129
- confirm2 = await confirm2.run()
130
-
131
- const spin = ora({text: "Updating domain...", spinner: "toggle9"}).start()
132
- const domain = await resend.domains.update({
133
- id,
134
- clickTracking: confirm1,
135
- openTracking: confirm2
136
- })
137
- if (domain.error) {
138
- spin.stop()
139
- console.error(domain.error.message)
140
- process.exit(1)
141
- }
142
- spin.stop()
143
- console.log(`Domain with ID ${domain.data.id} updated.`)
144
- }
145
- break
146
- case "list":
147
- {
148
- const spin = ora({text: "Fetching domains...", spinner: "toggle9"}).start()
149
- const domains = await resend.domains.list()
150
- if (domains.error) {
151
- spin.stop()
152
- console.error(domains.error.message)
153
- process.exit(1)
154
- }
155
- spin.stop()
156
- const choices = domains.data.data.map((domain) => {return {message: domain.name, name: domain.id}})
157
- let answer = new enquirer.Select({
158
- name: "listDomains",
159
- message: "Choose a domain",
160
- choices
161
- })
162
- answer = await answer.run()
163
- const domain = await resend.domains.get(answer)
164
- logDomain(domain)
165
- }
166
- break
167
- case "delete":
168
- {
169
- let form = new enquirer.Form({
170
- name: "deleteDomain",
171
- message: "Delete a domain",
172
- choices: [{name: "id", message: "Domain ID"},]
173
- })
174
- form = await form.run()
175
- let confirm = new enquirer.Confirm({
176
- message: "Are you sure you want to delete this domain?",
177
- initial: false
178
- })
179
- confirm = await confirm.run()
180
- if (!confirm) {
181
- console.log("Cancelled.")
182
- process.exit(0)
183
- }
184
- const spin = ora({text: "Deleting domain...", spinner: "toggle9"}).start()
185
- const domain = await resend.domains.remove(form.id)
186
- if (domain.error) {
187
- spin.stop()
188
- console.error(domain.error.message)
189
- process.exit(1)
190
- }
191
- spin.stop()
192
- console.log(`Domain with ID ${form.id} deleted.`)
193
- }
194
- }
195
- }
@@ -1,132 +0,0 @@
1
- import ora from "ora"
2
- import enquirer from "enquirer";
3
- import {selectAudience} from "./audiences.js";
4
- import fs from "fs/promises"
5
-
6
- const logEmail = (email) => {
7
- console.log(`ID: ${email.id}`)
8
- console.log(`From: ${email.from}`)
9
- console.log(`To: ${email.to}`)
10
- console.log(`Subject: ${email.subject}`)
11
- console.log(`BCC: ${email.bcc}`)
12
- console.log(`CC: ${email.cc}`)
13
- console.log(`Reply To: ${email.reply_to}`)
14
- console.log(`HTML: ${email.html}`)
15
- console.log(`Text: ${email.text}`)
16
- }
17
-
18
- export const addRecipient = async ({resend}, msg) => {
19
- let method = new enquirer.Select({
20
- message: (msg) + "Choose a method",
21
- choices: [
22
- {name: "manual", message: "Manual Entry"},
23
- {name: "audience", message: "Send to entire Audience"},
24
- {name: "none", message: "None"}
25
- ]
26
- })
27
- method = await method.run()
28
- if (method === "manual") {
29
- let email = new enquirer.Input({
30
- message: "Email Addresses, separated by commas",
31
- initial: "something@someone.co, delivery@resend.com"
32
- })
33
- email = await email.run()
34
- return email.split(",").map((email) => email.trim())
35
- } else if (method === "audience") {
36
- const audienceId = await selectAudience({resend}, "Choose an audience")
37
- const spinner = ora({text: "Retrieving audience...", spinner: "toggle9"}).start()
38
- const audience = await resend.contacts.list({audienceId})
39
- spinner.stop()
40
- // map audience.data.data array into a comma-separated list of email addresses
41
- return audience.data.data.map((contact) => contact.email)
42
- } else {
43
- return []
44
- }
45
- }
46
-
47
- export default async function({resend, apiKey}) {
48
- let mainForm = new enquirer.Select({
49
- message: "Choose an action",
50
- choices: [
51
- {name: "send", message: "Send Email"},
52
- {name: "retrieve", message: "Retrieve Email"},
53
- ]
54
- })
55
- mainForm = await mainForm.run()
56
- switch (mainForm) {
57
- case "send":
58
- {
59
- let from = new enquirer.Input({
60
- message: "From",
61
- initial: "Acme <onboarding@resend.dev>"
62
- })
63
- from = await from.run()
64
- const to = await addRecipient({resend}, "To: ")
65
- let subject = new enquirer.Input({
66
- message: "Subject",
67
- initial: "Changelog | Acne Alpha"
68
- })
69
- subject = await subject.run()
70
- const bcc = await addRecipient({resend}, "BCC: ")
71
- const cc = await addRecipient({resend}, "CC: ")
72
- const reply_to = await addRecipient({resend}, "Reply To: ")
73
- let html = new enquirer.Select({
74
- message: "HTML insert method",
75
- choices: [
76
- {name: "file", message: "From file"},
77
- {name: "input", message: "From input"},
78
- {name: "none", message: "None (text instead)"}
79
- ]
80
- })
81
- html = await html.run()
82
- if (html === "file") {
83
- let file = new enquirer.Input({
84
- message: "File path"
85
- })
86
- file = await file.run()
87
- html = await fs.readFile(file, "utf8")
88
- } else if (html === "input") {
89
- let htmlInput = new enquirer.Input({
90
- message: "HTML",
91
- initial: "<h1>This is an email</h1>"
92
- })
93
- html = await htmlInput.run()
94
- }
95
- let text = new enquirer.Input({
96
- message: "Text (not required if HTML is provided)",
97
- initial: "This is a text email"
98
- })
99
- text = await text.run()
100
- const spinner = ora({text: "Sending email...", spinner: "toggle9"}).start()
101
- const email = await resend.emails.create({
102
- from,
103
- to,
104
- subject,
105
- bcc,
106
- cc,
107
- reply_to,
108
- html,
109
- text
110
- })
111
- if (email.error) {
112
- spinner.stop()
113
- console.error(email.error.message)
114
- process.exit(1)
115
- }
116
- spinner.stop()
117
- console.log(`Email with ID ${email.data.id} sent.`)
118
- }
119
- break
120
- case "retrieve":
121
- {
122
- let emailId = new enquirer.Input({
123
- message: "Email ID"
124
- })
125
- emailId = await emailId.run()
126
- const spinner = ora({text: "Retrieving email...", spinner: "toggle9"}).start()
127
- const email = await resend.emails.get(emailId)
128
- spinner.stop()
129
- logEmail(email.data)
130
- }
131
- }
132
- }