@chanl/cli 3.0.0 → 3.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.
@@ -0,0 +1,332 @@
1
+ import { Command } from "commander";
2
+ import ora from "ora";
3
+ import chalk from "chalk";
4
+ import { createSdk } from "../utils/sdk-factory.js";
5
+ import {
6
+ printError,
7
+ printSuccess,
8
+ printInfo,
9
+ printBlank,
10
+ printSimpleTable,
11
+ isJsonOutput,
12
+ printJson
13
+ } from "../utils/output.js";
14
+ function createWhatsAppCommand() {
15
+ const whatsapp = new Command("whatsapp").description("Manage WhatsApp senders and message templates").addHelpText(
16
+ "after",
17
+ `
18
+ Sender lifecycle: register \u2192 verify (external numbers only) \u2192 ONLINE.
19
+ Template lifecycle: create \u2192 submit \u2192 Meta approval (usually minutes).
20
+
21
+ Quick Start:
22
+ $ chanl whatsapp senders list
23
+ $ chanl whatsapp senders register --phone +14155551234
24
+ $ chanl whatsapp senders verify <id> --code 123456
25
+ $ chanl whatsapp senders detach <id> # release WITHOUT deregistering
26
+ $ chanl whatsapp templates list
27
+ $ chanl whatsapp templates create --name order_update --body "Order {{1}} shipped"
28
+ $ chanl whatsapp templates submit <id>`
29
+ );
30
+ const senders = new Command("senders").description("WhatsApp sender management");
31
+ senders.command("list").description("List WhatsApp senders with status").action(handleSendersList);
32
+ senders.command("register").description("Register a phone number as a WhatsApp sender").requiredOption("--phone <e164>", "Phone number in E.164 format").option("--name <friendlyName>", "Display name for the sender").action(handleSenderRegister);
33
+ senders.command("status <id>").description("Refresh live sender status from Twilio").action(handleSenderStatus);
34
+ senders.command("verify <id>").description("Submit the OTP code for an external number").requiredOption("--code <digits>", "Verification code (4-10 digits)").action(handleSenderVerify);
35
+ senders.command("detach <id>").description("Release a sender WITHOUT deregistering it from the WABA (safe)").action((id) => handleSenderDelete(id, true));
36
+ senders.command("delete <id>").description("DELETE a sender \u2014 deregisters the number from the WABA on Meta (irreversible)").option("--yes", "Skip the confirmation prompt").action((id, options) => handleSenderDelete(id, false, options.yes));
37
+ whatsapp.addCommand(senders);
38
+ const templates = new Command("templates").description("WhatsApp message templates");
39
+ templates.command("list").description("List templates with approval status").action(handleTemplatesList);
40
+ templates.command("create").description("Create a plain-text template (draft)").requiredOption("--name <friendlyName>", "Template name (e.g. order_update)").requiredOption("--body <text>", "Template body \u2014 use {{1}}, {{2}} placeholders").option("--language <code>", "Language code", "en").option("--var <key=value...>", "Sample variable value (repeatable)", collectVars, {}).action(handleTemplateCreate);
41
+ templates.command("submit <id>").description("Submit a template to Meta for approval").action(handleTemplateSubmit);
42
+ templates.command("status <id>").description("Refresh template approval status").action(handleTemplateStatus);
43
+ templates.command("delete <id>").description("Delete a template").action(handleTemplateDelete);
44
+ whatsapp.addCommand(templates);
45
+ return whatsapp;
46
+ }
47
+ function collectVars(value, acc) {
48
+ const idx = value.indexOf("=");
49
+ if (idx === -1) {
50
+ throw new Error(`--var expects key=value, got "${value}"`);
51
+ }
52
+ acc[value.slice(0, idx)] = value.slice(idx + 1);
53
+ return acc;
54
+ }
55
+ function statusColor(status) {
56
+ if (!status) return "-";
57
+ if (status === "ONLINE" || status === "approved") return chalk.green(status);
58
+ if (status.includes("FAIL") || status === "rejected" || status === "OFFLINE") return chalk.red(status);
59
+ return chalk.yellow(status);
60
+ }
61
+ async function handleSendersList() {
62
+ const sdk = createSdk();
63
+ if (!sdk) return;
64
+ const spinner = ora("Fetching senders...").start();
65
+ try {
66
+ const response = await sdk.whatsapp.listSenders();
67
+ spinner.stop();
68
+ if (!response.success || !response.data) {
69
+ printError("Failed to fetch senders", response.message);
70
+ process.exitCode = 1;
71
+ return;
72
+ }
73
+ if (isJsonOutput()) {
74
+ printJson(response.data);
75
+ return;
76
+ }
77
+ const senders = response.data.senders ?? [];
78
+ if (senders.length === 0) {
79
+ printInfo("No WhatsApp senders connected");
80
+ printInfo("Use 'chanl whatsapp senders register --phone +1...' to connect one");
81
+ return;
82
+ }
83
+ printBlank();
84
+ printSimpleTable(
85
+ ["ID", "Phone", "Name", "Status", "WABA"],
86
+ senders.map((s) => [
87
+ s.id.slice(-12),
88
+ s.phoneNumber,
89
+ (s.friendlyName || "-").slice(0, 24),
90
+ statusColor(s.status),
91
+ s.wabaId?.slice(-8) || "-"
92
+ ])
93
+ );
94
+ printBlank();
95
+ } catch (error) {
96
+ spinner.fail("Failed to fetch senders");
97
+ printError("Error", error instanceof Error ? error.message : "Unknown error");
98
+ process.exitCode = 1;
99
+ }
100
+ }
101
+ async function handleSenderRegister(options) {
102
+ const sdk = createSdk();
103
+ if (!sdk) return;
104
+ const spinner = ora("Registering sender...").start();
105
+ try {
106
+ const response = await sdk.whatsapp.registerSender({
107
+ phoneNumber: options.phone,
108
+ friendlyName: options.name
109
+ });
110
+ spinner.stop();
111
+ if (!response.success || !response.data) {
112
+ printError("Failed to register sender", response.message);
113
+ process.exitCode = 1;
114
+ return;
115
+ }
116
+ if (isJsonOutput()) {
117
+ printJson(response.data);
118
+ return;
119
+ }
120
+ printSuccess(`Sender registered: ${response.data.id} (${response.data.status || "CREATING"})`);
121
+ printInfo(`Watch it come online: chanl whatsapp senders status ${response.data.id}`);
122
+ } catch (error) {
123
+ spinner.fail("Failed to register sender");
124
+ printError("Error", error instanceof Error ? error.message : "Unknown error");
125
+ process.exitCode = 1;
126
+ }
127
+ }
128
+ async function handleSenderStatus(id) {
129
+ const sdk = createSdk();
130
+ if (!sdk) return;
131
+ const spinner = ora("Refreshing sender status...").start();
132
+ try {
133
+ const response = await sdk.whatsapp.refreshSender(id);
134
+ spinner.stop();
135
+ if (!response.success || !response.data) {
136
+ printError("Failed to refresh sender", response.message);
137
+ process.exitCode = 1;
138
+ return;
139
+ }
140
+ if (isJsonOutput()) {
141
+ printJson(response.data);
142
+ return;
143
+ }
144
+ printInfo(`${response.data.phoneNumber}: ${statusColor(response.data.status)}`);
145
+ } catch (error) {
146
+ spinner.fail("Failed to refresh sender");
147
+ printError("Error", error instanceof Error ? error.message : "Unknown error");
148
+ process.exitCode = 1;
149
+ }
150
+ }
151
+ async function handleSenderVerify(id, options) {
152
+ const sdk = createSdk();
153
+ if (!sdk) return;
154
+ const spinner = ora("Submitting verification code...").start();
155
+ try {
156
+ const response = await sdk.whatsapp.verifySender(id, options.code);
157
+ spinner.stop();
158
+ if (!response.success) {
159
+ printError("Verification failed", response.message);
160
+ process.exitCode = 1;
161
+ return;
162
+ }
163
+ printSuccess("Verification code submitted");
164
+ printInfo(`Check status: chanl whatsapp senders status ${id}`);
165
+ } catch (error) {
166
+ spinner.fail("Verification failed");
167
+ printError("Error", error instanceof Error ? error.message : "Unknown error");
168
+ process.exitCode = 1;
169
+ }
170
+ }
171
+ async function handleSenderDelete(id, detach, confirmed = false) {
172
+ const sdk = createSdk();
173
+ if (!sdk) return;
174
+ if (!detach && !confirmed) {
175
+ printError(
176
+ "Refusing to delete without confirmation",
177
+ "A full delete DEREGISTERS the number from the WABA on Meta (irreversible; re-verify needed). Use `chanl whatsapp senders detach <id>` to release safely, or re-run with --yes to deregister."
178
+ );
179
+ process.exitCode = 1;
180
+ return;
181
+ }
182
+ const spinner = ora(detach ? "Detaching sender..." : "Deleting sender...").start();
183
+ try {
184
+ const response = await sdk.whatsapp.deleteSender(id, detach ? { detach: true } : void 0);
185
+ spinner.stop();
186
+ if (!response.success) {
187
+ printError("Failed to remove sender", response.message);
188
+ process.exitCode = 1;
189
+ return;
190
+ }
191
+ printSuccess(detach ? `Sender detached: ${id}` : `Sender deleted (deregistered): ${id}`);
192
+ } catch (error) {
193
+ spinner.fail("Failed to remove sender");
194
+ printError("Error", error instanceof Error ? error.message : "Unknown error");
195
+ process.exitCode = 1;
196
+ }
197
+ }
198
+ async function handleTemplatesList() {
199
+ const sdk = createSdk();
200
+ if (!sdk) return;
201
+ const spinner = ora("Fetching templates...").start();
202
+ try {
203
+ const response = await sdk.whatsapp.listTemplates();
204
+ spinner.stop();
205
+ if (!response.success || !response.data) {
206
+ printError("Failed to fetch templates", response.message);
207
+ process.exitCode = 1;
208
+ return;
209
+ }
210
+ if (isJsonOutput()) {
211
+ printJson(response.data);
212
+ return;
213
+ }
214
+ const templates = response.data.templates ?? [];
215
+ if (templates.length === 0) {
216
+ printInfo("No templates yet");
217
+ printInfo("Use 'chanl whatsapp templates create' to add one");
218
+ return;
219
+ }
220
+ printBlank();
221
+ printSimpleTable(
222
+ ["ID", "Name", "Language", "Approval", "Category"],
223
+ templates.map((t) => [
224
+ t.id.slice(-12),
225
+ t.friendlyName.slice(0, 28),
226
+ t.language || "-",
227
+ statusColor(t.approvalStatus),
228
+ t.category || "-"
229
+ ])
230
+ );
231
+ printBlank();
232
+ } catch (error) {
233
+ spinner.fail("Failed to fetch templates");
234
+ printError("Error", error instanceof Error ? error.message : "Unknown error");
235
+ process.exitCode = 1;
236
+ }
237
+ }
238
+ async function handleTemplateCreate(options) {
239
+ const sdk = createSdk();
240
+ if (!sdk) return;
241
+ const spinner = ora("Creating template...").start();
242
+ try {
243
+ const response = await sdk.whatsapp.createTemplate({
244
+ friendlyName: options.name,
245
+ language: options.language,
246
+ body: options.body,
247
+ variables: Object.keys(options.var).length > 0 ? options.var : void 0
248
+ });
249
+ spinner.stop();
250
+ if (!response.success || !response.data) {
251
+ printError("Failed to create template", response.message);
252
+ process.exitCode = 1;
253
+ return;
254
+ }
255
+ if (isJsonOutput()) {
256
+ printJson(response.data);
257
+ return;
258
+ }
259
+ printSuccess(`Template created: ${response.data.id}`);
260
+ printInfo(`Submit for approval: chanl whatsapp templates submit ${response.data.id}`);
261
+ } catch (error) {
262
+ spinner.fail("Failed to create template");
263
+ printError("Error", error instanceof Error ? error.message : "Unknown error");
264
+ process.exitCode = 1;
265
+ }
266
+ }
267
+ async function handleTemplateSubmit(id) {
268
+ const sdk = createSdk();
269
+ if (!sdk) return;
270
+ const spinner = ora("Submitting template to Meta...").start();
271
+ try {
272
+ const response = await sdk.whatsapp.submitTemplate(id);
273
+ spinner.stop();
274
+ if (!response.success) {
275
+ printError("Failed to submit template", response.message);
276
+ process.exitCode = 1;
277
+ return;
278
+ }
279
+ printSuccess("Template submitted for approval");
280
+ printInfo(`Check status: chanl whatsapp templates status ${id}`);
281
+ } catch (error) {
282
+ spinner.fail("Failed to submit template");
283
+ printError("Error", error instanceof Error ? error.message : "Unknown error");
284
+ process.exitCode = 1;
285
+ }
286
+ }
287
+ async function handleTemplateStatus(id) {
288
+ const sdk = createSdk();
289
+ if (!sdk) return;
290
+ const spinner = ora("Refreshing template status...").start();
291
+ try {
292
+ const response = await sdk.whatsapp.refreshTemplate(id);
293
+ spinner.stop();
294
+ if (!response.success || !response.data) {
295
+ printError("Failed to refresh template", response.message);
296
+ process.exitCode = 1;
297
+ return;
298
+ }
299
+ if (isJsonOutput()) {
300
+ printJson(response.data);
301
+ return;
302
+ }
303
+ printInfo(`${response.data.friendlyName}: ${statusColor(response.data.approvalStatus)}`);
304
+ } catch (error) {
305
+ spinner.fail("Failed to refresh template");
306
+ printError("Error", error instanceof Error ? error.message : "Unknown error");
307
+ process.exitCode = 1;
308
+ }
309
+ }
310
+ async function handleTemplateDelete(id) {
311
+ const sdk = createSdk();
312
+ if (!sdk) return;
313
+ const spinner = ora("Deleting template...").start();
314
+ try {
315
+ const response = await sdk.whatsapp.deleteTemplate(id);
316
+ spinner.stop();
317
+ if (!response.success) {
318
+ printError("Failed to delete template", response.message);
319
+ process.exitCode = 1;
320
+ return;
321
+ }
322
+ printSuccess(`Template deleted: ${id}`);
323
+ } catch (error) {
324
+ spinner.fail("Failed to delete template");
325
+ printError("Error", error instanceof Error ? error.message : "Unknown error");
326
+ process.exitCode = 1;
327
+ }
328
+ }
329
+ export {
330
+ createWhatsAppCommand
331
+ };
332
+ //# sourceMappingURL=whatsapp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/commands/whatsapp.ts"],"sourcesContent":["import { Command } from 'commander';\nimport ora from 'ora';\nimport chalk from 'chalk';\nimport type { WhatsAppSender, WhatsAppTemplate } from '@chanl/sdk';\nimport { createSdk } from '../utils/sdk-factory.js';\nimport {\n printError,\n printSuccess,\n printInfo,\n printBlank,\n printSimpleTable,\n isJsonOutput,\n printJson,\n} from '../utils/output.js';\n\n/**\n * Create the whatsapp command group\n */\nexport function createWhatsAppCommand(): Command {\n const whatsapp = new Command('whatsapp')\n .description('Manage WhatsApp senders and message templates')\n .addHelpText(\n 'after',\n `\nSender lifecycle: register → verify (external numbers only) → ONLINE.\nTemplate lifecycle: create → submit → Meta approval (usually minutes).\n\nQuick Start:\n $ chanl whatsapp senders list\n $ chanl whatsapp senders register --phone +14155551234\n $ chanl whatsapp senders verify <id> --code 123456\n $ chanl whatsapp senders detach <id> # release WITHOUT deregistering\n $ chanl whatsapp templates list\n $ chanl whatsapp templates create --name order_update --body \"Order {{1}} shipped\"\n $ chanl whatsapp templates submit <id>`\n );\n\n // ── senders ──\n const senders = new Command('senders').description('WhatsApp sender management');\n\n senders\n .command('list')\n .description('List WhatsApp senders with status')\n .action(handleSendersList);\n\n senders\n .command('register')\n .description('Register a phone number as a WhatsApp sender')\n .requiredOption('--phone <e164>', 'Phone number in E.164 format')\n .option('--name <friendlyName>', 'Display name for the sender')\n .action(handleSenderRegister);\n\n senders\n .command('status <id>')\n .description('Refresh live sender status from Twilio')\n .action(handleSenderStatus);\n\n senders\n .command('verify <id>')\n .description('Submit the OTP code for an external number')\n .requiredOption('--code <digits>', 'Verification code (4-10 digits)')\n .action(handleSenderVerify);\n\n senders\n .command('detach <id>')\n .description('Release a sender WITHOUT deregistering it from the WABA (safe)')\n .action((id: string) => handleSenderDelete(id, true));\n\n senders\n .command('delete <id>')\n .description('DELETE a sender — deregisters the number from the WABA on Meta (irreversible)')\n .option('--yes', 'Skip the confirmation prompt')\n .action((id: string, options: { yes?: boolean }) => handleSenderDelete(id, false, options.yes));\n\n whatsapp.addCommand(senders);\n\n // ── templates ──\n const templates = new Command('templates').description('WhatsApp message templates');\n\n templates\n .command('list')\n .description('List templates with approval status')\n .action(handleTemplatesList);\n\n templates\n .command('create')\n .description('Create a plain-text template (draft)')\n .requiredOption('--name <friendlyName>', 'Template name (e.g. order_update)')\n .requiredOption('--body <text>', 'Template body — use {{1}}, {{2}} placeholders')\n .option('--language <code>', 'Language code', 'en')\n .option('--var <key=value...>', 'Sample variable value (repeatable)', collectVars, {})\n .action(handleTemplateCreate);\n\n templates\n .command('submit <id>')\n .description('Submit a template to Meta for approval')\n .action(handleTemplateSubmit);\n\n templates\n .command('status <id>')\n .description('Refresh template approval status')\n .action(handleTemplateStatus);\n\n templates\n .command('delete <id>')\n .description('Delete a template')\n .action(handleTemplateDelete);\n\n whatsapp.addCommand(templates);\n\n return whatsapp;\n}\n\nfunction collectVars(value: string, acc: Record<string, string>): Record<string, string> {\n const idx = value.indexOf('=');\n if (idx === -1) {\n throw new Error(`--var expects key=value, got \"${value}\"`);\n }\n acc[value.slice(0, idx)] = value.slice(idx + 1);\n return acc;\n}\n\nfunction statusColor(status?: string): string {\n if (!status) return '-';\n if (status === 'ONLINE' || status === 'approved') return chalk.green(status);\n if (status.includes('FAIL') || status === 'rejected' || status === 'OFFLINE') return chalk.red(status);\n return chalk.yellow(status);\n}\n\nasync function handleSendersList(): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Fetching senders...').start();\n try {\n const response = await sdk.whatsapp.listSenders();\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to fetch senders', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const senders = (response.data as { senders?: WhatsAppSender[] }).senders ?? [];\n if (senders.length === 0) {\n printInfo('No WhatsApp senders connected');\n printInfo(\"Use 'chanl whatsapp senders register --phone +1...' to connect one\");\n return;\n }\n\n printBlank();\n printSimpleTable(\n ['ID', 'Phone', 'Name', 'Status', 'WABA'],\n senders.map((s) => [\n s.id.slice(-12),\n s.phoneNumber,\n (s.friendlyName || '-').slice(0, 24),\n statusColor(s.status),\n s.wabaId?.slice(-8) || '-',\n ])\n );\n printBlank();\n } catch (error) {\n spinner.fail('Failed to fetch senders');\n printError('Error', error instanceof Error ? error.message : 'Unknown error');\n process.exitCode = 1;\n }\n}\n\nasync function handleSenderRegister(options: { phone: string; name?: string }): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Registering sender...').start();\n try {\n const response = await sdk.whatsapp.registerSender({\n phoneNumber: options.phone,\n friendlyName: options.name,\n });\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to register sender', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n printSuccess(`Sender registered: ${response.data.id} (${response.data.status || 'CREATING'})`);\n printInfo(`Watch it come online: chanl whatsapp senders status ${response.data.id}`);\n } catch (error) {\n spinner.fail('Failed to register sender');\n printError('Error', error instanceof Error ? error.message : 'Unknown error');\n process.exitCode = 1;\n }\n}\n\nasync function handleSenderStatus(id: string): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Refreshing sender status...').start();\n try {\n const response = await sdk.whatsapp.refreshSender(id);\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to refresh sender', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n printInfo(`${response.data.phoneNumber}: ${statusColor(response.data.status)}`);\n } catch (error) {\n spinner.fail('Failed to refresh sender');\n printError('Error', error instanceof Error ? error.message : 'Unknown error');\n process.exitCode = 1;\n }\n}\n\nasync function handleSenderVerify(id: string, options: { code: string }): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Submitting verification code...').start();\n try {\n const response = await sdk.whatsapp.verifySender(id, options.code);\n spinner.stop();\n\n if (!response.success) {\n printError('Verification failed', response.message);\n process.exitCode = 1;\n return;\n }\n printSuccess('Verification code submitted');\n printInfo(`Check status: chanl whatsapp senders status ${id}`);\n } catch (error) {\n spinner.fail('Verification failed');\n printError('Error', error instanceof Error ? error.message : 'Unknown error');\n process.exitCode = 1;\n }\n}\n\nasync function handleSenderDelete(id: string, detach: boolean, confirmed = false): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n if (!detach && !confirmed) {\n printError(\n 'Refusing to delete without confirmation',\n 'A full delete DEREGISTERS the number from the WABA on Meta (irreversible; re-verify needed). ' +\n 'Use `chanl whatsapp senders detach <id>` to release safely, or re-run with --yes to deregister.'\n );\n process.exitCode = 1;\n return;\n }\n\n const spinner = ora(detach ? 'Detaching sender...' : 'Deleting sender...').start();\n try {\n const response = await sdk.whatsapp.deleteSender(id, detach ? { detach: true } : undefined);\n spinner.stop();\n\n if (!response.success) {\n printError('Failed to remove sender', response.message);\n process.exitCode = 1;\n return;\n }\n printSuccess(detach ? `Sender detached: ${id}` : `Sender deleted (deregistered): ${id}`);\n } catch (error) {\n spinner.fail('Failed to remove sender');\n printError('Error', error instanceof Error ? error.message : 'Unknown error');\n process.exitCode = 1;\n }\n}\n\nasync function handleTemplatesList(): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Fetching templates...').start();\n try {\n const response = await sdk.whatsapp.listTemplates();\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to fetch templates', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const templates = (response.data as { templates?: WhatsAppTemplate[] }).templates ?? [];\n if (templates.length === 0) {\n printInfo('No templates yet');\n printInfo(\"Use 'chanl whatsapp templates create' to add one\");\n return;\n }\n\n printBlank();\n printSimpleTable(\n ['ID', 'Name', 'Language', 'Approval', 'Category'],\n templates.map((t) => [\n t.id.slice(-12),\n t.friendlyName.slice(0, 28),\n t.language || '-',\n statusColor(t.approvalStatus),\n t.category || '-',\n ])\n );\n printBlank();\n } catch (error) {\n spinner.fail('Failed to fetch templates');\n printError('Error', error instanceof Error ? error.message : 'Unknown error');\n process.exitCode = 1;\n }\n}\n\nasync function handleTemplateCreate(options: {\n name: string;\n body: string;\n language: string;\n var: Record<string, string>;\n}): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Creating template...').start();\n try {\n const response = await sdk.whatsapp.createTemplate({\n friendlyName: options.name,\n language: options.language,\n body: options.body,\n variables: Object.keys(options.var).length > 0 ? options.var : undefined,\n });\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to create template', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n printSuccess(`Template created: ${response.data.id}`);\n printInfo(`Submit for approval: chanl whatsapp templates submit ${response.data.id}`);\n } catch (error) {\n spinner.fail('Failed to create template');\n printError('Error', error instanceof Error ? error.message : 'Unknown error');\n process.exitCode = 1;\n }\n}\n\nasync function handleTemplateSubmit(id: string): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Submitting template to Meta...').start();\n try {\n const response = await sdk.whatsapp.submitTemplate(id);\n spinner.stop();\n\n if (!response.success) {\n printError('Failed to submit template', response.message);\n process.exitCode = 1;\n return;\n }\n printSuccess('Template submitted for approval');\n printInfo(`Check status: chanl whatsapp templates status ${id}`);\n } catch (error) {\n spinner.fail('Failed to submit template');\n printError('Error', error instanceof Error ? error.message : 'Unknown error');\n process.exitCode = 1;\n }\n}\n\nasync function handleTemplateStatus(id: string): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Refreshing template status...').start();\n try {\n const response = await sdk.whatsapp.refreshTemplate(id);\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to refresh template', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n printInfo(`${response.data.friendlyName}: ${statusColor(response.data.approvalStatus)}`);\n } catch (error) {\n spinner.fail('Failed to refresh template');\n printError('Error', error instanceof Error ? error.message : 'Unknown error');\n process.exitCode = 1;\n }\n}\n\nasync function handleTemplateDelete(id: string): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Deleting template...').start();\n try {\n const response = await sdk.whatsapp.deleteTemplate(id);\n spinner.stop();\n\n if (!response.success) {\n printError('Failed to delete template', response.message);\n process.exitCode = 1;\n return;\n }\n printSuccess(`Template deleted: ${id}`);\n } catch (error) {\n spinner.fail('Failed to delete template');\n printError('Error', error instanceof Error ? error.message : 'Unknown error');\n process.exitCode = 1;\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chanl/cli",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Command-line interface for the Chanl AI platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",