@timbra-ec/whatsapp 0.1.0-dev.20260403050717

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,4 @@
1
+
2
+ > @timbra-ec/whatsapp@0.1.1 build /home/runner/work/timbra-app/timbra-app/packages/whatsapp
3
+ > tsc
4
+
@@ -0,0 +1,10 @@
1
+ import type { WhatsAppConfig } from './types';
2
+ export declare function sendWhatsAppMessage(config: WhatsAppConfig, payload: Record<string, unknown>): Promise<{
3
+ messageId: string;
4
+ }>;
5
+ export declare class WhatsAppApiError extends Error {
6
+ readonly code: string;
7
+ readonly statusCode: number;
8
+ constructor(message: string, code: string, statusCode: number);
9
+ }
10
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAgB7C,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CA8BhC;AAED,qBAAa,gBAAiB,SAAQ,KAAK;aAGvB,IAAI,EAAE,MAAM;aACZ,UAAU,EAAE,MAAM;gBAFlC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM;CAKrC"}
package/dist/client.js ADDED
@@ -0,0 +1,35 @@
1
+ const GRAPH_API_VERSION = 'v21.0';
2
+ const BASE_URL = `https://graph.facebook.com/${GRAPH_API_VERSION}`;
3
+ export async function sendWhatsAppMessage(config, payload) {
4
+ const url = `${BASE_URL}/${config.phoneNumberId}/messages`;
5
+ const response = await fetch(url, {
6
+ method: 'POST',
7
+ headers: {
8
+ Authorization: `Bearer ${config.token}`,
9
+ 'Content-Type': 'application/json',
10
+ },
11
+ body: JSON.stringify(payload),
12
+ });
13
+ const data = (await response.json());
14
+ if (!response.ok || data.error) {
15
+ const error = data.error;
16
+ const code = error?.code === 4 || error?.error_subcode === 33 ? 'RATE_LIMITED' : 'API_ERROR';
17
+ throw new WhatsAppApiError(error?.message ?? `WhatsApp API returned ${response.status}`, code, response.status);
18
+ }
19
+ const messageId = data.messages?.[0]?.id;
20
+ if (!messageId) {
21
+ throw new WhatsAppApiError('No message ID in response', 'UNEXPECTED_RESPONSE', response.status);
22
+ }
23
+ return { messageId };
24
+ }
25
+ export class WhatsAppApiError extends Error {
26
+ code;
27
+ statusCode;
28
+ constructor(message, code, statusCode) {
29
+ super(message);
30
+ this.code = code;
31
+ this.statusCode = statusCode;
32
+ this.name = 'WhatsAppApiError';
33
+ }
34
+ }
35
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,MAAM,iBAAiB,GAAG,OAAO,CAAA;AACjC,MAAM,QAAQ,GAAG,8BAA8B,iBAAiB,EAAE,CAAA;AAalE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAsB,EACtB,OAAgC;IAEhC,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,MAAM,CAAC,aAAa,WAAW,CAAA;IAE1D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,MAAM,CAAC,KAAK,EAAE;YACvC,cAAc,EAAE,kBAAkB;SACnC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC9B,CAAC,CAAA;IAEF,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAqB,CAAA;IAExD,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;QACxB,MAAM,IAAI,GAAG,KAAK,EAAE,IAAI,KAAK,CAAC,IAAI,KAAK,EAAE,aAAa,KAAK,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW,CAAA;QAC5F,MAAM,IAAI,gBAAgB,CACxB,KAAK,EAAE,OAAO,IAAI,yBAAyB,QAAQ,CAAC,MAAM,EAAE,EAC5D,IAAI,EACJ,QAAQ,CAAC,MAAM,CAChB,CAAA;IACH,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;IACxC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,gBAAgB,CAAC,2BAA2B,EAAE,qBAAqB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IACjG,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,CAAA;AACtB,CAAC;AAED,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAGvB;IACA;IAHlB,YACE,OAAe,EACC,IAAY,EACZ,UAAkB;QAElC,KAAK,CAAC,OAAO,CAAC,CAAA;QAHE,SAAI,GAAJ,IAAI,CAAQ;QACZ,eAAU,GAAV,UAAU,CAAQ;QAGlC,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAA;IAChC,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ export { sendInvoiceWhatsApp, INVOICE_TEMPLATE_NAME } from './send-invoice-whatsapp';
2
+ export type { WhatsAppConfig, SendInvoiceWhatsAppParams, DeliveryResult } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AACpF,YAAY,EAAE,cAAc,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { sendInvoiceWhatsApp, INVOICE_TEMPLATE_NAME } from './send-invoice-whatsapp';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA"}
@@ -0,0 +1,13 @@
1
+ import type { DeliveryResult, SendInvoiceWhatsAppParams, WhatsAppConfig } from './types';
2
+ /**
3
+ * Pre-approved template name that must be registered in Meta Business Manager.
4
+ *
5
+ * Expected template structure:
6
+ * Header: Document (PDF attachment)
7
+ * Body: "Estimado cliente, su factura {{1}} de {{2}} ha sido autorizada por el SRI.
8
+ * Adjuntamos el comprobante electronico (RIDE) para su registro."
9
+ * Language: es
10
+ */
11
+ export declare const INVOICE_TEMPLATE_NAME = "invoice_notification";
12
+ export declare function sendInvoiceWhatsApp(config: WhatsAppConfig, params: SendInvoiceWhatsAppParams): Promise<DeliveryResult>;
13
+ //# sourceMappingURL=send-invoice-whatsapp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send-invoice-whatsapp.d.ts","sourceRoot":"","sources":["../src/send-invoice-whatsapp.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAExF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,yBAAyB,CAAA;AAE3D,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,cAAc,CAAC,CA0CzB"}
@@ -0,0 +1,55 @@
1
+ import { sendWhatsAppMessage, WhatsAppApiError } from './client';
2
+ /**
3
+ * Pre-approved template name that must be registered in Meta Business Manager.
4
+ *
5
+ * Expected template structure:
6
+ * Header: Document (PDF attachment)
7
+ * Body: "Estimado cliente, su factura {{1}} de {{2}} ha sido autorizada por el SRI.
8
+ * Adjuntamos el comprobante electronico (RIDE) para su registro."
9
+ * Language: es
10
+ */
11
+ export const INVOICE_TEMPLATE_NAME = 'invoice_notification';
12
+ export async function sendInvoiceWhatsApp(config, params) {
13
+ const payload = {
14
+ messaging_product: 'whatsapp',
15
+ to: params.phoneNumber,
16
+ type: 'template',
17
+ template: {
18
+ name: INVOICE_TEMPLATE_NAME,
19
+ language: { code: 'es' },
20
+ components: [
21
+ {
22
+ type: 'header',
23
+ parameters: [
24
+ {
25
+ type: 'document',
26
+ document: {
27
+ link: params.ridePdfUrl,
28
+ filename: `Factura_${params.invoiceNumber}.pdf`,
29
+ },
30
+ },
31
+ ],
32
+ },
33
+ {
34
+ type: 'body',
35
+ parameters: [
36
+ { type: 'text', text: params.invoiceNumber },
37
+ { type: 'text', text: params.businessName },
38
+ ],
39
+ },
40
+ ],
41
+ },
42
+ };
43
+ try {
44
+ const result = await sendWhatsAppMessage(config, payload);
45
+ return { success: true, messageId: result.messageId };
46
+ }
47
+ catch (error) {
48
+ if (error instanceof WhatsAppApiError) {
49
+ return { success: false, error: error.message, code: error.code };
50
+ }
51
+ const message = error instanceof Error ? error.message : 'Unknown error';
52
+ return { success: false, error: message, code: 'UNKNOWN' };
53
+ }
54
+ }
55
+ //# sourceMappingURL=send-invoice-whatsapp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send-invoice-whatsapp.js","sourceRoot":"","sources":["../src/send-invoice-whatsapp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAGhE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAA;AAE3D,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAsB,EACtB,MAAiC;IAEjC,MAAM,OAAO,GAAG;QACd,iBAAiB,EAAE,UAAU;QAC7B,EAAE,EAAE,MAAM,CAAC,WAAW;QACtB,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE;YACR,IAAI,EAAE,qBAAqB;YAC3B,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;YACxB,UAAU,EAAE;gBACV;oBACE,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV;4BACE,IAAI,EAAE,UAAU;4BAChB,QAAQ,EAAE;gCACR,IAAI,EAAE,MAAM,CAAC,UAAU;gCACvB,QAAQ,EAAE,WAAW,MAAM,CAAC,aAAa,MAAM;6BAChD;yBACF;qBACF;iBACF;gBACD;oBACE,IAAI,EAAE,MAAM;oBACZ,UAAU,EAAE;wBACV,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,aAAa,EAAE;wBAC5C,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,YAAY,EAAE;qBAC5C;iBACF;aACF;SACF;KACF,CAAA;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACzD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAA;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,gBAAgB,EAAE,CAAC;YACtC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;QACnE,CAAC;QACD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAA;QACxE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAA;IAC5D,CAAC;AACH,CAAC"}
@@ -0,0 +1,25 @@
1
+ /** WhatsApp Cloud API configuration */
2
+ export interface WhatsAppConfig {
3
+ token: string;
4
+ phoneNumberId: string;
5
+ }
6
+ /** Parameters for sending an invoice via WhatsApp */
7
+ export interface SendInvoiceWhatsAppParams {
8
+ phoneNumber: string;
9
+ invoiceNumber: string;
10
+ ridePdfUrl: string;
11
+ businessName: string;
12
+ }
13
+ interface DeliverySuccess {
14
+ success: true;
15
+ messageId: string;
16
+ }
17
+ interface DeliveryFailure {
18
+ success: false;
19
+ error: string;
20
+ code?: string;
21
+ }
22
+ /** Result of a WhatsApp delivery attempt */
23
+ export type DeliveryResult = DeliverySuccess | DeliveryFailure;
24
+ export {};
25
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,qDAAqD;AACrD,MAAM,WAAW,yBAAyB;IACxC,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,IAAI,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,KAAK,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,4CAA4C;AAC5C,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,eAAe,CAAA"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@timbra-ec/whatsapp",
3
+ "version": "0.1.0-dev.20260403050717",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/timbra-ec/timbra-app.git",
10
+ "directory": "packages/whatsapp"
11
+ },
12
+ "type": "module",
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ }
20
+ },
21
+ "dependencies": {
22
+ "@timbra-ec/types": "0.1.0-dev.20260403050717"
23
+ },
24
+ "devDependencies": {
25
+ "typescript": "^5.8.2"
26
+ },
27
+ "scripts": {
28
+ "build": "tsc",
29
+ "typecheck": "tsc --noEmit",
30
+ "lint": "echo 'no lint configured yet'"
31
+ }
32
+ }
package/src/client.ts ADDED
@@ -0,0 +1,61 @@
1
+ import type { WhatsAppConfig } from './types'
2
+
3
+ const GRAPH_API_VERSION = 'v21.0'
4
+ const BASE_URL = `https://graph.facebook.com/${GRAPH_API_VERSION}`
5
+
6
+ interface GraphApiResponse {
7
+ messages?: { id: string }[]
8
+ error?: {
9
+ message: string
10
+ type: string
11
+ code: number
12
+ error_subcode?: number
13
+ fbtrace_id?: string
14
+ }
15
+ }
16
+
17
+ export async function sendWhatsAppMessage(
18
+ config: WhatsAppConfig,
19
+ payload: Record<string, unknown>,
20
+ ): Promise<{ messageId: string }> {
21
+ const url = `${BASE_URL}/${config.phoneNumberId}/messages`
22
+
23
+ const response = await fetch(url, {
24
+ method: 'POST',
25
+ headers: {
26
+ Authorization: `Bearer ${config.token}`,
27
+ 'Content-Type': 'application/json',
28
+ },
29
+ body: JSON.stringify(payload),
30
+ })
31
+
32
+ const data = (await response.json()) as GraphApiResponse
33
+
34
+ if (!response.ok || data.error) {
35
+ const error = data.error
36
+ const code = error?.code === 4 || error?.error_subcode === 33 ? 'RATE_LIMITED' : 'API_ERROR'
37
+ throw new WhatsAppApiError(
38
+ error?.message ?? `WhatsApp API returned ${response.status}`,
39
+ code,
40
+ response.status,
41
+ )
42
+ }
43
+
44
+ const messageId = data.messages?.[0]?.id
45
+ if (!messageId) {
46
+ throw new WhatsAppApiError('No message ID in response', 'UNEXPECTED_RESPONSE', response.status)
47
+ }
48
+
49
+ return { messageId }
50
+ }
51
+
52
+ export class WhatsAppApiError extends Error {
53
+ constructor(
54
+ message: string,
55
+ public readonly code: string,
56
+ public readonly statusCode: number,
57
+ ) {
58
+ super(message)
59
+ this.name = 'WhatsAppApiError'
60
+ }
61
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { sendInvoiceWhatsApp, INVOICE_TEMPLATE_NAME } from './send-invoice-whatsapp'
2
+ export type { WhatsAppConfig, SendInvoiceWhatsAppParams, DeliveryResult } from './types'
@@ -0,0 +1,60 @@
1
+ import { sendWhatsAppMessage, WhatsAppApiError } from './client'
2
+ import type { DeliveryResult, SendInvoiceWhatsAppParams, WhatsAppConfig } from './types'
3
+
4
+ /**
5
+ * Pre-approved template name that must be registered in Meta Business Manager.
6
+ *
7
+ * Expected template structure:
8
+ * Header: Document (PDF attachment)
9
+ * Body: "Estimado cliente, su factura {{1}} de {{2}} ha sido autorizada por el SRI.
10
+ * Adjuntamos el comprobante electronico (RIDE) para su registro."
11
+ * Language: es
12
+ */
13
+ export const INVOICE_TEMPLATE_NAME = 'invoice_notification'
14
+
15
+ export async function sendInvoiceWhatsApp(
16
+ config: WhatsAppConfig,
17
+ params: SendInvoiceWhatsAppParams,
18
+ ): Promise<DeliveryResult> {
19
+ const payload = {
20
+ messaging_product: 'whatsapp',
21
+ to: params.phoneNumber,
22
+ type: 'template',
23
+ template: {
24
+ name: INVOICE_TEMPLATE_NAME,
25
+ language: { code: 'es' },
26
+ components: [
27
+ {
28
+ type: 'header',
29
+ parameters: [
30
+ {
31
+ type: 'document',
32
+ document: {
33
+ link: params.ridePdfUrl,
34
+ filename: `Factura_${params.invoiceNumber}.pdf`,
35
+ },
36
+ },
37
+ ],
38
+ },
39
+ {
40
+ type: 'body',
41
+ parameters: [
42
+ { type: 'text', text: params.invoiceNumber },
43
+ { type: 'text', text: params.businessName },
44
+ ],
45
+ },
46
+ ],
47
+ },
48
+ }
49
+
50
+ try {
51
+ const result = await sendWhatsAppMessage(config, payload)
52
+ return { success: true, messageId: result.messageId }
53
+ } catch (error) {
54
+ if (error instanceof WhatsAppApiError) {
55
+ return { success: false, error: error.message, code: error.code }
56
+ }
57
+ const message = error instanceof Error ? error.message : 'Unknown error'
58
+ return { success: false, error: message, code: 'UNKNOWN' }
59
+ }
60
+ }
package/src/types.ts ADDED
@@ -0,0 +1,27 @@
1
+ /** WhatsApp Cloud API configuration */
2
+ export interface WhatsAppConfig {
3
+ token: string
4
+ phoneNumberId: string
5
+ }
6
+
7
+ /** Parameters for sending an invoice via WhatsApp */
8
+ export interface SendInvoiceWhatsAppParams {
9
+ phoneNumber: string // E.164 format, e.g., "+593991234567"
10
+ invoiceNumber: string // e.g., "001-001-000000042"
11
+ ridePdfUrl: string
12
+ businessName: string
13
+ }
14
+
15
+ interface DeliverySuccess {
16
+ success: true
17
+ messageId: string
18
+ }
19
+
20
+ interface DeliveryFailure {
21
+ success: false
22
+ error: string
23
+ code?: string
24
+ }
25
+
26
+ /** Result of a WhatsApp delivery attempt */
27
+ export type DeliveryResult = DeliverySuccess | DeliveryFailure
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "@timbra-ec/config-ts/library.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src"]
8
+ }