@veroao/node 1.0.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.
package/README.md ADDED
@@ -0,0 +1,268 @@
1
+ # @veroao/node
2
+
3
+ SDK oficial Vero para Node.js - emite facturas certificadas pela AGT sem sair do teu código.
4
+
5
+ ## Instalação
6
+
7
+ ```bash
8
+ npm install @veroao/node
9
+ ```
10
+
11
+ Requer Node.js 18+ (usa `fetch` nativo, sem dependências).
12
+
13
+ ## Quick start
14
+
15
+ ```typescript
16
+ import { createVeroClient } from '@veroao/node'
17
+
18
+ const vero = createVeroClient() // lê VERO_API_KEY do ambiente
19
+ // ou: createVeroClient({ secretKey: 'vero_test_sk_...' })
20
+
21
+ const ORG_ID = process.env.VERO_ORG_ID!
22
+
23
+ // 1. Garante que o cliente existe (cria ou actualiza pelo teu ID externo)
24
+ const customer = await vero.customers.ensure(ORG_ID, {
25
+ externalId: 'user_123',
26
+ name: 'Maria Fernandes',
27
+ taxId: '003456789LA042',
28
+ phone: '923456789',
29
+ email: 'maria@empresa.ao',
30
+ })
31
+
32
+ // 2. Emite a factura
33
+ const invoice = await vero.invoices.create(ORG_ID, {
34
+ customerId: customer.id,
35
+ items: [
36
+ {
37
+ description: 'Subscrição Mensal - Plano Pro',
38
+ quantity: 1,
39
+ unitPrice: 2500000, // 25 000,00 AOA em kwanzas × 100
40
+ taxRate: 14,
41
+ },
42
+ ],
43
+ })
44
+
45
+ console.log(invoice.number) // "FT FT6326S62896N/1" - formato oficial AGT
46
+ console.log(invoice.pdfUrl) // link para descarregar o PDF (gerado na hora, não expira)
47
+ console.log(invoice.atcud) // código de verificação AGT
48
+ ```
49
+
50
+ A submissão à AGT acontece em segundo plano - `invoice.agtStatus` começa como `pending` e passa a
51
+ `validated` ou `rejected` alguns segundos depois. Consulta o documento novamente (`vero.invoices.get`)
52
+ para confirmar.
53
+
54
+ ## Ambiente test vs live
55
+
56
+ O ambiente é detectado automaticamente a partir do prefixo da chave - não precisas de configurar nada:
57
+
58
+ | Chave | Ambiente | Comportamento |
59
+ |--------------------|----------|-----------------------------------------------------------------------|
60
+ | `vero_test_sk_...` | test | Documentos gerados inteiramente em local, número marcado `TESTE`, **nunca chegam à AGT**, mesmo que a organização já tenha chaves de produção configuradas |
61
+ | `vero_live_sk_...` | live | Documentos certificados pela AGT em produção - valor fiscal real |
62
+
63
+ ```typescript
64
+ const vero = createVeroClient({ secretKey: 'vero_test_sk_...' })
65
+ console.log(vero.environment) // 'test'
66
+ ```
67
+
68
+ Existe também uma chave de sandbox pública e partilhada, sem necessidade de conta - pede-a a
69
+ `GET https://api.vero.ao/v1/sandbox`.
70
+
71
+ ## Referência da API
72
+
73
+ ### `vero.customers`
74
+
75
+ ```typescript
76
+ // Listar (paginado)
77
+ const { data, meta } = await vero.customers.list(orgId, { search: 'Maria', page: 1, limit: 20 })
78
+
79
+ // Obter por ID
80
+ const customer = await vero.customers.get(orgId, customerId)
81
+
82
+ // Criar
83
+ const customer = await vero.customers.create(orgId, {
84
+ name: 'Empresa XYZ',
85
+ taxId: '5000123456',
86
+ phone: '923456789',
87
+ email: 'geral@xyz.ao',
88
+ addressLine1: 'Rua Amílcar Cabral, 45',
89
+ city: 'Luanda',
90
+ })
91
+
92
+ // Actualizar (campos parciais)
93
+ await vero.customers.update(orgId, customerId, { email: 'novo@xyz.ao' })
94
+
95
+ // Upsert pelo externalId - idempotente, seguro chamar a cada pedido
96
+ const customer = await vero.customers.ensure(orgId, {
97
+ externalId: 'user_42',
98
+ name: 'João Baptista',
99
+ taxId: '123456789LA001',
100
+ })
101
+ ```
102
+
103
+ `name` e `taxId` são mutuamente opcionais - omite `name` se `isConsumidorFinal: true` ou se `taxId`
104
+ já identifica a empresa.
105
+
106
+ ### `vero.invoices`
107
+
108
+ ```typescript
109
+ // Emitir (idempotencyKey gerada automaticamente se omitida)
110
+ const invoice = await vero.invoices.create(orgId, {
111
+ customerId: 'uuid...',
112
+ documentType: 'FT', // FT = Factura (a prazo), FR = Factura-Recibo (pagamento imediato)
113
+ items: [{ description: 'Serviço', quantity: 1, unitPrice: 100000, taxRate: 14 }],
114
+ idempotencyKey: 'pedido_789', // passa o teu próprio para evitar duplicados em retries
115
+ })
116
+
117
+ // Listar (paginado, filtros opcionais)
118
+ const { data, meta } = await vero.invoices.list(orgId, { status: 'issued', documentType: 'FT', page: 1 })
119
+
120
+ // Obter por ID
121
+ const invoice = await vero.invoices.get(orgId, invoiceId)
122
+
123
+ // Cancelar (não elimina - fica com status "cancelled")
124
+ await vero.invoices.cancel(orgId, invoice.id, 'Pedido do cliente')
125
+
126
+ // Enviar por email ao cliente (usa o email guardado no cliente)
127
+ await vero.invoices.send(orgId, invoice.id)
128
+ ```
129
+
130
+ `documentType: 'FR'` fica com `status: 'paid'` imediatamente (já está pago); `'FT'` fica `'issued'`
131
+ até seres tu a marcar como pago via `vero.receipts.create`.
132
+
133
+ ### `vero.proformas`
134
+
135
+ ```typescript
136
+ const proforma = await vero.proformas.create(orgId, {
137
+ customerId: 'uuid...',
138
+ items: [{ description: 'Orçamento', quantity: 1, unitPrice: 500000, taxRate: 14 }],
139
+ validUntil: '2026-12-31',
140
+ })
141
+
142
+ // Converter em factura definitiva certificada - sem corpo, usa os dados já na proforma
143
+ const invoice = await vero.proformas.convert(orgId, proforma.id)
144
+
145
+ // Anular (só enquanto estiver em draft, não pode ser desfeito)
146
+ await vero.proformas.cancel(orgId, proforma.id)
147
+ ```
148
+
149
+ Proformas não têm valor fiscal - servem só de orçamento até seres convertidas em factura.
150
+
151
+ ### `vero.creditNotes`
152
+
153
+ ```typescript
154
+ // Emitir nota de crédito contra uma factura - cancela a factura original
155
+ const cn = await vero.creditNotes.create(orgId, invoice.id, 'Devolução parcial')
156
+
157
+ await vero.creditNotes.send(orgId, cn.id) // por email ao cliente
158
+ ```
159
+
160
+ ### `vero.debitNotes`
161
+
162
+ ```typescript
163
+ // Autónoma ou associada a uma factura existente - ao contrário da NC, não exige factura de origem
164
+ const dn = await vero.debitNotes.create(orgId, {
165
+ customerId: customer.id,
166
+ items: [{ description: 'Custos administrativos', quantity: 1, unitPrice: 500000, taxRate: 14 }],
167
+ invoiceId: invoice.id, // opcional - usa o número real dessa factura como referência na AGT
168
+ })
169
+ ```
170
+
171
+ ### `vero.receipts`
172
+
173
+ ```typescript
174
+ // Marca uma factura FT como paga e emite o recibo (documento interno, não vai à AGT)
175
+ const receipt = await vero.receipts.create(orgId, invoice.id, { paymentMethod: 'transfer' })
176
+ ```
177
+
178
+ ### `vero.products`
179
+
180
+ ```typescript
181
+ const product = await vero.products.create(orgId, {
182
+ name: 'Plano Pro', // único campo obrigatório
183
+ code: 'PLAN-PRO', // opcional
184
+ unitPrice: 2500000,
185
+ taxRate: 14, // default 14 se omitido
186
+ unitOfMeasure: 'UN', // default 'UN' se omitido
187
+ })
188
+
189
+ const products = await vero.products.list(orgId) // devolve todos, sem paginação nem filtros
190
+
191
+ await vero.products.update(orgId, product.id, { unitPrice: 2700000 })
192
+ await vero.products.deactivate(orgId, product.id) // soft delete - fica active: false
193
+ ```
194
+
195
+ ### `vero.webhooks`
196
+
197
+ ```typescript
198
+ const webhook = await vero.webhooks.register(orgId, {
199
+ url: 'https://teusite.ao/webhooks/vero',
200
+ events: ['invoice.issued', 'invoice.cancelled', 'proforma.converted', 'proforma.cancelled'],
201
+ })
202
+ console.log(webhook.secret) // segredo HMAC - só é mostrado nesta resposta, guarda-o
203
+
204
+ await vero.webhooks.list(orgId)
205
+ await vero.webhooks.delete(orgId, webhook.id)
206
+ ```
207
+
208
+ O payload enviado ao teu endpoint tem a forma `{ event, orgId, timestamp, data }` - `data` é o próprio
209
+ documento (mesma forma da resposta da API). Para eventos de factura, `data.pdfUrl` é um link **público**,
210
+ sem necessidade de autenticação.
211
+
212
+ ## Tratamento de erros
213
+
214
+ ```typescript
215
+ import { VeroAPIError, VeroAuthError, VeroNotFoundError, VeroRateLimitError } from '@veroao/node'
216
+
217
+ try {
218
+ const invoice = await vero.invoices.create(orgId, input)
219
+ } catch (err) {
220
+ if (err instanceof VeroAuthError) {
221
+ // chave inválida ou revogada
222
+ } else if (err instanceof VeroNotFoundError) {
223
+ // organização ou cliente não encontrado
224
+ } else if (err instanceof VeroRateLimitError) {
225
+ // demasiados pedidos - err.retryAfter (segundos), se o servidor o indicou
226
+ } else if (err instanceof VeroAPIError) {
227
+ console.error(err.status, err.code, err.message)
228
+ }
229
+ }
230
+ ```
231
+
232
+ Erros de rede e respostas 5xx são automaticamente repetidos (até `maxRetries`, default 3, com
233
+ backoff exponencial) antes de lançarem excepção.
234
+
235
+ ## Configuração do cliente
236
+
237
+ ```typescript
238
+ const vero = createVeroClient({
239
+ secretKey: 'vero_live_sk_...',
240
+ baseUrl: 'https://api.vero.ao', // default
241
+ maxRetries: 3, // tentativas em erros 5xx/rede
242
+ timeout: 30_000, // ms por pedido
243
+ })
244
+ ```
245
+
246
+ ## Preços em kwanzas
247
+
248
+ Os valores monetários usam **kwanzas × 100** para evitar problemas de vírgula flutuante:
249
+
250
+ ```typescript
251
+ unitPrice: 2_500_000 // 25 000,00 AOA
252
+ unitPrice: 150_050 // 1 500,50 AOA
253
+ ```
254
+
255
+ ## Variáveis de ambiente
256
+
257
+ | Variável | Descrição |
258
+ |--------------------|--------------------------------------------------------------------|
259
+ | `VERO_API_KEY` | Chave secreta da API (recomendado) |
260
+ | `VERO_SECRET_KEY` | Alias legado - usado só se `VERO_API_KEY` não estiver definida |
261
+
262
+ ## O teu backend não é Node?
263
+
264
+ Este pacote é só uma comodidade - por baixo é tudo pedidos HTTPS normais (`Authorization: Bearer
265
+ vero_..._sk_...`, corpo JSON). Se o teu backend é PHP, Python, Ruby, Java, Go, ou qualquer outra
266
+ linguagem, tens acesso a **exactamente as mesmas operações** chamando a API REST directamente com
267
+ o cliente HTTP dessa linguagem - nada fica limitado por não usares este SDK. Exemplos completos em
268
+ cURL, Python e PHP estão em [vero.ao/docs](https://vero.ao/docs).
@@ -0,0 +1,141 @@
1
+ import type { VeroConfig, ListResult, Customer, CreateCustomerInput, UpdateCustomerInput, EnsureCustomerInput, ListCustomersParams, Invoice, CreateInvoiceInput, ListInvoicesParams, ProformaInvoice, CreateProformaInput, ListProformasParams, CreditNote, DebitNote, CreateDebitNoteInput, Receipt, CreateReceiptInput, Product, CreateProductInput, UpdateProductInput, Webhook, RegisterWebhookInput } from './types.js';
2
+ declare class HttpClient {
3
+ readonly baseUrl: string;
4
+ private readonly secretKey;
5
+ private readonly maxRetries;
6
+ private readonly timeout;
7
+ constructor(config: Required<VeroConfig>);
8
+ request<T>(method: string, path: string, body?: unknown, params?: Record<string, unknown>): Promise<T>;
9
+ get<T>(path: string, params?: Record<string, unknown>): Promise<T>;
10
+ post<T>(path: string, body?: unknown): Promise<T>;
11
+ patch<T>(path: string, body: unknown): Promise<T>;
12
+ delete<T>(path: string): Promise<T>;
13
+ }
14
+ declare class CustomersResource {
15
+ private http;
16
+ constructor(http: HttpClient);
17
+ list(orgId: string, params?: ListCustomersParams): Promise<ListResult<Customer>>;
18
+ get(orgId: string, customerId: string): Promise<Customer>;
19
+ create(orgId: string, input: CreateCustomerInput): Promise<Customer>;
20
+ update(orgId: string, customerId: string, input: UpdateCustomerInput): Promise<Customer>;
21
+ /**
22
+ * Cria ou actualiza um cliente pelo externalId — upsert atómico no servidor.
23
+ * Ideal para sincronizar utilizadores do teu sistema sem criar duplicados.
24
+ *
25
+ * @example
26
+ * const customer = await vero.customers.ensure(orgId, {
27
+ * externalId: 'user_123',
28
+ * name: 'João Silva',
29
+ * taxId: '123456789LA001',
30
+ * })
31
+ */
32
+ ensure(orgId: string, input: EnsureCustomerInput): Promise<Customer>;
33
+ }
34
+ declare class InvoicesResource {
35
+ private http;
36
+ constructor(http: HttpClient);
37
+ /**
38
+ * Emite uma fatura certificada pela AGT.
39
+ * A chave de idempotência é gerada automaticamente — passa a tua própria
40
+ * para garantir que pedidos duplicados não criam faturas duplicadas.
41
+ *
42
+ * @example
43
+ * const invoice = await vero.invoices.create(orgId, {
44
+ * customerId: customer.id,
45
+ * items: [{ description: 'Plano Pro', quantity: 1, unitPrice: 500000, taxRate: 14 }],
46
+ * })
47
+ */
48
+ create(orgId: string, input: CreateInvoiceInput): Promise<Invoice>;
49
+ list(orgId: string, params?: ListInvoicesParams): Promise<ListResult<Invoice>>;
50
+ get(orgId: string, invoiceId: string): Promise<Invoice>;
51
+ cancel(orgId: string, invoiceId: string, reason?: string): Promise<Invoice>;
52
+ /** Envia a fatura por email ao cliente */
53
+ send(orgId: string, invoiceId: string): Promise<void>;
54
+ }
55
+ declare class ProformasResource {
56
+ private http;
57
+ constructor(http: HttpClient);
58
+ create(orgId: string, input: CreateProformaInput): Promise<ProformaInvoice>;
59
+ list(orgId: string, params?: ListProformasParams): Promise<ListResult<ProformaInvoice>>;
60
+ get(orgId: string, proformaId: string): Promise<ProformaInvoice>;
61
+ /** Converte pró-forma em fatura definitiva certificada — sem corpo, usa os dados já na proforma */
62
+ convert(orgId: string, proformaId: string): Promise<Invoice>;
63
+ /** Anula a proforma (não pode ser desfeito) */
64
+ cancel(orgId: string, proformaId: string): Promise<void>;
65
+ }
66
+ declare class CreditNotesResource {
67
+ private http;
68
+ constructor(http: HttpClient);
69
+ /** Emite nota de crédito contra uma fatura — cancela a fatura original */
70
+ create(orgId: string, invoiceId: string, reason?: string): Promise<CreditNote>;
71
+ list(orgId: string): Promise<CreditNote[]>;
72
+ get(orgId: string, id: string): Promise<CreditNote>;
73
+ /** Envia a nota de crédito por email ao cliente */
74
+ send(orgId: string, id: string): Promise<void>;
75
+ }
76
+ declare class DebitNotesResource {
77
+ private http;
78
+ constructor(http: HttpClient);
79
+ /**
80
+ * Emite nota de débito — autónoma ou associada a uma fatura existente.
81
+ * Ao contrário da nota de crédito, não exige uma fatura de origem: serve
82
+ * para qualquer cobrança adicional a um cliente. Se passares `invoiceId`,
83
+ * o Vero usa o número real dessa fatura como referência perante a AGT.
84
+ *
85
+ * @example
86
+ * await vero.debitNotes.create(orgId, {
87
+ * customerId: customer.id,
88
+ * items: [{ description: 'Custos administrativos', quantity: 1, unitPrice: 500000, taxRate: 14 }],
89
+ * invoiceId: invoice.id, // opcional
90
+ * })
91
+ */
92
+ create(orgId: string, input: CreateDebitNoteInput): Promise<DebitNote>;
93
+ list(orgId: string): Promise<DebitNote[]>;
94
+ get(orgId: string, id: string): Promise<DebitNote>;
95
+ /** Envia a nota de débito por email ao cliente */
96
+ send(orgId: string, id: string): Promise<void>;
97
+ }
98
+ declare class ReceiptsResource {
99
+ private http;
100
+ constructor(http: HttpClient);
101
+ /**
102
+ * Emite recibo de pagamento para uma fatura existente.
103
+ * Marca a fatura como paga e gera o recibo certificado.
104
+ */
105
+ create(orgId: string, invoiceId: string, input: CreateReceiptInput): Promise<Receipt>;
106
+ list(orgId: string): Promise<Receipt[]>;
107
+ get(orgId: string, id: string): Promise<Receipt>;
108
+ /** Envia o recibo por email ao cliente */
109
+ send(orgId: string, id: string): Promise<void>;
110
+ }
111
+ declare class ProductsResource {
112
+ private http;
113
+ constructor(http: HttpClient);
114
+ /** Devolve todos os produtos activos e inactivos — este endpoint não pagina nem filtra no servidor */
115
+ list(orgId: string): Promise<Product[]>;
116
+ create(orgId: string, input: CreateProductInput): Promise<Product>;
117
+ update(orgId: string, productId: string, input: UpdateProductInput): Promise<Product>;
118
+ /** Desactiva o produto (soft delete — fica com active: false, não é removido de facto) */
119
+ deactivate(orgId: string, productId: string): Promise<Product>;
120
+ }
121
+ declare class WebhooksResource {
122
+ private http;
123
+ constructor(http: HttpClient);
124
+ register(orgId: string, input: RegisterWebhookInput): Promise<Webhook>;
125
+ list(orgId: string): Promise<Webhook[]>;
126
+ delete(orgId: string, webhookId: string): Promise<void>;
127
+ }
128
+ export declare class VeroClient {
129
+ /** Ambiente detectado automaticamente a partir do prefixo da chave */
130
+ readonly environment: 'live' | 'test';
131
+ readonly customers: CustomersResource;
132
+ readonly invoices: InvoicesResource;
133
+ readonly proformas: ProformasResource;
134
+ readonly creditNotes: CreditNotesResource;
135
+ readonly debitNotes: DebitNotesResource;
136
+ readonly receipts: ReceiptsResource;
137
+ readonly products: ProductsResource;
138
+ readonly webhooks: WebhooksResource;
139
+ constructor(config: VeroConfig);
140
+ }
141
+ export {};
package/dist/client.js ADDED
@@ -0,0 +1,322 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { VeroAPIError, VeroAuthError, VeroNotFoundError, VeroRateLimitError, } from './errors.js';
3
+ // ─── HTTP core ────────────────────────────────────────────────────────────────
4
+ class HttpClient {
5
+ baseUrl;
6
+ secretKey;
7
+ maxRetries;
8
+ timeout;
9
+ constructor(config) {
10
+ this.baseUrl = config.baseUrl;
11
+ this.secretKey = config.secretKey;
12
+ this.maxRetries = config.maxRetries;
13
+ this.timeout = config.timeout;
14
+ }
15
+ async request(method, path, body, params) {
16
+ const url = new URL(`${this.baseUrl}${path}`);
17
+ if (params) {
18
+ for (const [k, v] of Object.entries(params)) {
19
+ if (v !== undefined && v !== null)
20
+ url.searchParams.append(k, String(v));
21
+ }
22
+ }
23
+ let attempt = 0;
24
+ while (true) {
25
+ const controller = new AbortController();
26
+ const timer = setTimeout(() => controller.abort(), this.timeout);
27
+ try {
28
+ const res = await fetch(url.toString(), {
29
+ method,
30
+ headers: {
31
+ Authorization: `Bearer ${this.secretKey}`,
32
+ 'Content-Type': 'application/json',
33
+ },
34
+ body: body !== undefined ? JSON.stringify(body) : undefined,
35
+ signal: controller.signal,
36
+ });
37
+ clearTimeout(timer);
38
+ if (res.status === 204)
39
+ return undefined;
40
+ const data = await res.json().catch(() => ({ error: res.statusText }));
41
+ if (res.ok)
42
+ return data;
43
+ // Erros com retry: 5xx (excepto 400, 401, 403, 404, 409, 422, 429)
44
+ if (res.status === 401)
45
+ throw new VeroAuthError(data?.error);
46
+ if (res.status === 404)
47
+ throw new VeroNotFoundError(data?.error);
48
+ if (res.status === 429) {
49
+ const retryAfter = Number(res.headers.get('Retry-After')) || undefined;
50
+ throw new VeroRateLimitError(retryAfter);
51
+ }
52
+ if (res.status >= 500 && attempt < this.maxRetries) {
53
+ attempt++;
54
+ await sleep(200 * 2 ** attempt); // 400ms, 800ms, 1600ms
55
+ continue;
56
+ }
57
+ throw new VeroAPIError(res.status, data?.error ?? 'api_error', data?.message);
58
+ }
59
+ catch (err) {
60
+ clearTimeout(timer);
61
+ if (err instanceof VeroAPIError)
62
+ throw err;
63
+ if (err.name === 'AbortError') {
64
+ throw new VeroAPIError(408, 'request_timeout', `Timeout após ${this.timeout}ms`);
65
+ }
66
+ if (attempt < this.maxRetries) {
67
+ attempt++;
68
+ await sleep(200 * 2 ** attempt);
69
+ continue;
70
+ }
71
+ throw new VeroAPIError(0, 'network_error', err.message);
72
+ }
73
+ }
74
+ }
75
+ get(path, params) {
76
+ return this.request('GET', path, undefined, params);
77
+ }
78
+ post(path, body) {
79
+ return this.request('POST', path, body);
80
+ }
81
+ patch(path, body) {
82
+ return this.request('PATCH', path, body);
83
+ }
84
+ delete(path) {
85
+ return this.request('DELETE', path);
86
+ }
87
+ }
88
+ function sleep(ms) {
89
+ return new Promise(r => setTimeout(r, ms));
90
+ }
91
+ // ─── Resources ───────────────────────────────────────────────────────────────
92
+ class CustomersResource {
93
+ http;
94
+ constructor(http) {
95
+ this.http = http;
96
+ }
97
+ list(orgId, params = {}) {
98
+ return this.http.get(`/v1/organisations/${orgId}/customers`, params);
99
+ }
100
+ get(orgId, customerId) {
101
+ return this.http.get(`/v1/organisations/${orgId}/customers/${customerId}`);
102
+ }
103
+ create(orgId, input) {
104
+ return this.http.post(`/v1/organisations/${orgId}/customers`, input);
105
+ }
106
+ update(orgId, customerId, input) {
107
+ return this.http.patch(`/v1/organisations/${orgId}/customers/${customerId}`, input);
108
+ }
109
+ /**
110
+ * Cria ou actualiza um cliente pelo externalId — upsert atómico no servidor.
111
+ * Ideal para sincronizar utilizadores do teu sistema sem criar duplicados.
112
+ *
113
+ * @example
114
+ * const customer = await vero.customers.ensure(orgId, {
115
+ * externalId: 'user_123',
116
+ * name: 'João Silva',
117
+ * taxId: '123456789LA001',
118
+ * })
119
+ */
120
+ ensure(orgId, input) {
121
+ return this.http.post(`/v1/organisations/${orgId}/customers/ensure`, input);
122
+ }
123
+ }
124
+ class InvoicesResource {
125
+ http;
126
+ constructor(http) {
127
+ this.http = http;
128
+ }
129
+ /**
130
+ * Emite uma fatura certificada pela AGT.
131
+ * A chave de idempotência é gerada automaticamente — passa a tua própria
132
+ * para garantir que pedidos duplicados não criam faturas duplicadas.
133
+ *
134
+ * @example
135
+ * const invoice = await vero.invoices.create(orgId, {
136
+ * customerId: customer.id,
137
+ * items: [{ description: 'Plano Pro', quantity: 1, unitPrice: 500000, taxRate: 14 }],
138
+ * })
139
+ */
140
+ create(orgId, input) {
141
+ return this.http.post(`/v1/organisations/${orgId}/invoices`, {
142
+ ...input,
143
+ idempotencyKey: input.idempotencyKey ?? randomUUID(),
144
+ });
145
+ }
146
+ list(orgId, params = {}) {
147
+ return this.http.get(`/v1/organisations/${orgId}/invoices`, params);
148
+ }
149
+ get(orgId, invoiceId) {
150
+ return this.http.get(`/v1/organisations/${orgId}/invoices/${invoiceId}`);
151
+ }
152
+ cancel(orgId, invoiceId, reason) {
153
+ return this.http.post(`/v1/organisations/${orgId}/invoices/${invoiceId}/cancel`, { reason });
154
+ }
155
+ /** Envia a fatura por email ao cliente */
156
+ send(orgId, invoiceId) {
157
+ return this.http.post(`/v1/organisations/${orgId}/invoices/${invoiceId}/send`);
158
+ }
159
+ }
160
+ class ProformasResource {
161
+ http;
162
+ constructor(http) {
163
+ this.http = http;
164
+ }
165
+ create(orgId, input) {
166
+ return this.http.post(`/v1/organisations/${orgId}/proformas`, input);
167
+ }
168
+ list(orgId, params = {}) {
169
+ return this.http.get(`/v1/organisations/${orgId}/proformas`, params);
170
+ }
171
+ get(orgId, proformaId) {
172
+ return this.http.get(`/v1/organisations/${orgId}/proformas/${proformaId}`);
173
+ }
174
+ /** Converte pró-forma em fatura definitiva certificada — sem corpo, usa os dados já na proforma */
175
+ convert(orgId, proformaId) {
176
+ return this.http.post(`/v1/organisations/${orgId}/proformas/${proformaId}/convert`);
177
+ }
178
+ /** Anula a proforma (não pode ser desfeito) */
179
+ cancel(orgId, proformaId) {
180
+ return this.http.delete(`/v1/organisations/${orgId}/proformas/${proformaId}`);
181
+ }
182
+ }
183
+ class CreditNotesResource {
184
+ http;
185
+ constructor(http) {
186
+ this.http = http;
187
+ }
188
+ /** Emite nota de crédito contra uma fatura — cancela a fatura original */
189
+ create(orgId, invoiceId, reason) {
190
+ return this.http.post(`/v1/organisations/${orgId}/invoices/${invoiceId}/credit-note`, { reason });
191
+ }
192
+ list(orgId) {
193
+ return this.http.get(`/v1/organisations/${orgId}/credit-notes`);
194
+ }
195
+ get(orgId, id) {
196
+ return this.http.get(`/v1/organisations/${orgId}/credit-notes/${id}`);
197
+ }
198
+ /** Envia a nota de crédito por email ao cliente */
199
+ send(orgId, id) {
200
+ return this.http.post(`/v1/organisations/${orgId}/credit-notes/${id}/send`);
201
+ }
202
+ }
203
+ class DebitNotesResource {
204
+ http;
205
+ constructor(http) {
206
+ this.http = http;
207
+ }
208
+ /**
209
+ * Emite nota de débito — autónoma ou associada a uma fatura existente.
210
+ * Ao contrário da nota de crédito, não exige uma fatura de origem: serve
211
+ * para qualquer cobrança adicional a um cliente. Se passares `invoiceId`,
212
+ * o Vero usa o número real dessa fatura como referência perante a AGT.
213
+ *
214
+ * @example
215
+ * await vero.debitNotes.create(orgId, {
216
+ * customerId: customer.id,
217
+ * items: [{ description: 'Custos administrativos', quantity: 1, unitPrice: 500000, taxRate: 14 }],
218
+ * invoiceId: invoice.id, // opcional
219
+ * })
220
+ */
221
+ create(orgId, input) {
222
+ return this.http.post(`/v1/organisations/${orgId}/debit-notes`, input);
223
+ }
224
+ list(orgId) {
225
+ return this.http.get(`/v1/organisations/${orgId}/debit-notes`);
226
+ }
227
+ get(orgId, id) {
228
+ return this.http.get(`/v1/organisations/${orgId}/debit-notes/${id}`);
229
+ }
230
+ /** Envia a nota de débito por email ao cliente */
231
+ send(orgId, id) {
232
+ return this.http.post(`/v1/organisations/${orgId}/debit-notes/${id}/send`);
233
+ }
234
+ }
235
+ class ReceiptsResource {
236
+ http;
237
+ constructor(http) {
238
+ this.http = http;
239
+ }
240
+ /**
241
+ * Emite recibo de pagamento para uma fatura existente.
242
+ * Marca a fatura como paga e gera o recibo certificado.
243
+ */
244
+ create(orgId, invoiceId, input) {
245
+ return this.http.post(`/v1/organisations/${orgId}/invoices/${invoiceId}/receipt`, input);
246
+ }
247
+ list(orgId) {
248
+ return this.http.get(`/v1/organisations/${orgId}/receipts`);
249
+ }
250
+ get(orgId, id) {
251
+ return this.http.get(`/v1/organisations/${orgId}/receipts/${id}`);
252
+ }
253
+ /** Envia o recibo por email ao cliente */
254
+ send(orgId, id) {
255
+ return this.http.post(`/v1/organisations/${orgId}/receipts/${id}/send`);
256
+ }
257
+ }
258
+ class ProductsResource {
259
+ http;
260
+ constructor(http) {
261
+ this.http = http;
262
+ }
263
+ /** Devolve todos os produtos activos e inactivos — este endpoint não pagina nem filtra no servidor */
264
+ list(orgId) {
265
+ return this.http.get(`/v1/organisations/${orgId}/products`);
266
+ }
267
+ create(orgId, input) {
268
+ return this.http.post(`/v1/organisations/${orgId}/products`, input);
269
+ }
270
+ update(orgId, productId, input) {
271
+ return this.http.patch(`/v1/organisations/${orgId}/products/${productId}`, input);
272
+ }
273
+ /** Desactiva o produto (soft delete — fica com active: false, não é removido de facto) */
274
+ deactivate(orgId, productId) {
275
+ return this.http.delete(`/v1/organisations/${orgId}/products/${productId}`);
276
+ }
277
+ }
278
+ class WebhooksResource {
279
+ http;
280
+ constructor(http) {
281
+ this.http = http;
282
+ }
283
+ register(orgId, input) {
284
+ return this.http.post(`/v1/organisations/${orgId}/webhooks`, input);
285
+ }
286
+ list(orgId) {
287
+ return this.http.get(`/v1/organisations/${orgId}/webhooks`);
288
+ }
289
+ delete(orgId, webhookId) {
290
+ return this.http.delete(`/v1/organisations/${orgId}/webhooks/${webhookId}`);
291
+ }
292
+ }
293
+ // ─── Client principal ─────────────────────────────────────────────────────────
294
+ export class VeroClient {
295
+ /** Ambiente detectado automaticamente a partir do prefixo da chave */
296
+ environment;
297
+ customers;
298
+ invoices;
299
+ proformas;
300
+ creditNotes;
301
+ debitNotes;
302
+ receipts;
303
+ products;
304
+ webhooks;
305
+ constructor(config) {
306
+ this.environment = config.secretKey.includes('_test_') ? 'test' : 'live';
307
+ const http = new HttpClient({
308
+ secretKey: config.secretKey,
309
+ baseUrl: config.baseUrl ?? 'https://api.vero.ao',
310
+ maxRetries: config.maxRetries ?? 3,
311
+ timeout: config.timeout ?? 30_000,
312
+ });
313
+ this.customers = new CustomersResource(http);
314
+ this.invoices = new InvoicesResource(http);
315
+ this.proformas = new ProformasResource(http);
316
+ this.creditNotes = new CreditNotesResource(http);
317
+ this.debitNotes = new DebitNotesResource(http);
318
+ this.receipts = new ReceiptsResource(http);
319
+ this.products = new ProductsResource(http);
320
+ this.webhooks = new WebhooksResource(http);
321
+ }
322
+ }
@@ -0,0 +1,18 @@
1
+ export declare class VeroError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ export declare class VeroAPIError extends VeroError {
5
+ readonly status: number;
6
+ readonly code: string;
7
+ constructor(status: number, code: string, message?: string);
8
+ }
9
+ export declare class VeroAuthError extends VeroAPIError {
10
+ constructor(message?: string);
11
+ }
12
+ export declare class VeroNotFoundError extends VeroAPIError {
13
+ constructor(resource?: string);
14
+ }
15
+ export declare class VeroRateLimitError extends VeroAPIError {
16
+ readonly retryAfter?: number;
17
+ constructor(retryAfter?: number);
18
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,36 @@
1
+ export class VeroError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = 'VeroError';
5
+ }
6
+ }
7
+ export class VeroAPIError extends VeroError {
8
+ status;
9
+ code;
10
+ constructor(status, code, message) {
11
+ super(message ?? code);
12
+ this.name = 'VeroAPIError';
13
+ this.status = status;
14
+ this.code = code;
15
+ }
16
+ }
17
+ export class VeroAuthError extends VeroAPIError {
18
+ constructor(message = 'API key inválida ou revogada') {
19
+ super(401, 'unauthorized', message);
20
+ this.name = 'VeroAuthError';
21
+ }
22
+ }
23
+ export class VeroNotFoundError extends VeroAPIError {
24
+ constructor(resource = 'recurso') {
25
+ super(404, 'not_found', `${resource} não encontrado`);
26
+ this.name = 'VeroNotFoundError';
27
+ }
28
+ }
29
+ export class VeroRateLimitError extends VeroAPIError {
30
+ retryAfter;
31
+ constructor(retryAfter) {
32
+ super(429, 'rate_limit_exceeded', 'Limite de pedidos excedido');
33
+ this.name = 'VeroRateLimitError';
34
+ this.retryAfter = retryAfter;
35
+ }
36
+ }
@@ -0,0 +1,17 @@
1
+ export * from './types.js';
2
+ export * from './errors.js';
3
+ export * from './client.js';
4
+ import { VeroClient } from './client.js';
5
+ import type { VeroConfig } from './types.js';
6
+ /**
7
+ * Cria um cliente Vero a partir da tua chave secreta.
8
+ * O ambiente (test/live) é detectado automaticamente pelo prefixo da chave.
9
+ *
10
+ * @example
11
+ * // Variável de ambiente (recomendado)
12
+ * const vero = createVeroClient()
13
+ *
14
+ * // Chave explícita
15
+ * const vero = createVeroClient({ secretKey: 'vero_test_sk_...' })
16
+ */
17
+ export declare function createVeroClient(config?: Partial<VeroConfig>): VeroClient;
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ export * from './types.js';
2
+ export * from './errors.js';
3
+ export * from './client.js';
4
+ import { VeroClient } from './client.js';
5
+ /**
6
+ * Cria um cliente Vero a partir da tua chave secreta.
7
+ * O ambiente (test/live) é detectado automaticamente pelo prefixo da chave.
8
+ *
9
+ * @example
10
+ * // Variável de ambiente (recomendado)
11
+ * const vero = createVeroClient()
12
+ *
13
+ * // Chave explícita
14
+ * const vero = createVeroClient({ secretKey: 'vero_test_sk_...' })
15
+ */
16
+ export function createVeroClient(config) {
17
+ const secretKey = config?.secretKey ??
18
+ process.env.VERO_API_KEY ??
19
+ process.env.VERO_SECRET_KEY ?? // retrocompatibilidade
20
+ '';
21
+ if (!secretKey) {
22
+ throw new Error('Vero: chave de API não encontrada. Define VERO_API_KEY ou passa secretKey na config.');
23
+ }
24
+ return new VeroClient({ ...config, secretKey });
25
+ }
@@ -0,0 +1,303 @@
1
+ export interface VeroConfig {
2
+ /** Chave secreta da API — vero_test_sk_... ou vero_live_sk_... */
3
+ secretKey: string;
4
+ /** Override da URL base (útil para testes locais) */
5
+ baseUrl?: string;
6
+ /** Número máximo de tentativas em falhas 5xx (default: 3) */
7
+ maxRetries?: number;
8
+ /** Timeout por pedido em ms (default: 30000) */
9
+ timeout?: number;
10
+ }
11
+ export interface ListParams {
12
+ page?: number;
13
+ limit?: number;
14
+ }
15
+ export interface ListResult<T> {
16
+ data: T[];
17
+ meta: {
18
+ total: number;
19
+ page: number;
20
+ limit: number;
21
+ pages: number;
22
+ };
23
+ }
24
+ export interface InvoiceItem {
25
+ description: string;
26
+ /** Quantidade de unidades */
27
+ quantity: number;
28
+ /** Preço unitário em kwanzas × 100 (ex: 10000 = 100 AOA) */
29
+ unitPrice: number;
30
+ /** Taxa IVA Angola: 0 = isento, 5 = reduzida, 14 = normal (default: 14) */
31
+ taxRate?: 0 | 5 | 14;
32
+ /** Obrigatório junto da AGT quando taxRate = 0 (máx. 4 caracteres, ex: "M19") */
33
+ taxExemptionCode?: string;
34
+ /** ID do produto do catálogo (opcional) */
35
+ productId?: string;
36
+ }
37
+ export interface Customer {
38
+ id: string;
39
+ orgId: string;
40
+ name: string;
41
+ taxId?: string | null;
42
+ email?: string | null;
43
+ phone?: string | null;
44
+ addressLine1?: string | null;
45
+ addressLine2?: string | null;
46
+ city?: string | null;
47
+ province?: string | null;
48
+ country?: string | null;
49
+ /** ID externo do teu sistema — útil para upsert via customers.ensure() */
50
+ externalId?: string | null;
51
+ isConsumidorFinal: boolean;
52
+ createdAt: string;
53
+ updatedAt: string;
54
+ }
55
+ export interface CreateCustomerInput {
56
+ /** Obrigatório, a menos que taxId seja indicado ou isConsumidorFinal seja true */
57
+ name?: string;
58
+ /** Obrigatório, a menos que name seja indicado ou isConsumidorFinal seja true */
59
+ taxId?: string;
60
+ email?: string;
61
+ phone?: string;
62
+ addressLine1?: string;
63
+ addressLine2?: string;
64
+ city?: string;
65
+ province?: string;
66
+ country?: string;
67
+ /** ID externo do teu sistema (ex: user ID do teu e-commerce) */
68
+ externalId?: string;
69
+ /** Venda a dinheiro sem identificar o cliente — usa o NIF genérico 999999999 nas faturas */
70
+ isConsumidorFinal?: boolean;
71
+ }
72
+ export interface UpdateCustomerInput extends Partial<CreateCustomerInput> {
73
+ }
74
+ export interface EnsureCustomerInput extends CreateCustomerInput {
75
+ /** Obrigatório para upsert — identifica o cliente no teu sistema */
76
+ externalId: string;
77
+ }
78
+ export interface ListCustomersParams extends ListParams {
79
+ search?: string;
80
+ }
81
+ export type InvoiceStatus = 'pending' | 'issued' | 'paid' | 'failed' | 'cancelled';
82
+ export type DocumentType = 'FT' | 'FR';
83
+ /** Estado da validação junto da AGT — a submissão acontece em segundo plano */
84
+ export type AgtStatus = 'pending' | 'validated' | 'rejected' | null;
85
+ export interface AgtError {
86
+ idError?: string;
87
+ descriptionError?: string;
88
+ }
89
+ export interface Invoice {
90
+ id: string;
91
+ orgId: string;
92
+ customerId: string;
93
+ /** FT = Fatura, FR = Fatura-Recibo */
94
+ documentType: DocumentType;
95
+ /** Formato: "{tipo} {série}/{sequencial}" — ex: "FT FT6326S62896N/1" */
96
+ number?: string | null;
97
+ /** Código de exibição (sem prefixo de tipo) */
98
+ displayCode?: string | null;
99
+ status: InvoiceStatus;
100
+ /** Subtotal sem IVA, em kwanzas × 100 */
101
+ subtotal: number;
102
+ /** IVA total, em kwanzas × 100 */
103
+ taxAmount: number;
104
+ /** Total com IVA, em kwanzas × 100 */
105
+ total: number;
106
+ currency: string;
107
+ items: InvoiceItem[];
108
+ pdfUrl?: string | null;
109
+ /** Código ATCUD para verificação AGT */
110
+ atcud?: string | null;
111
+ hash?: string | null;
112
+ previousHash?: string | null;
113
+ /** Estado da validação na AGT — consulta depois de criar, a submissão é assíncrona */
114
+ agtStatus?: AgtStatus;
115
+ agtErrors?: AgtError[] | null;
116
+ notes?: string | null;
117
+ issuedAt?: string | null;
118
+ cancelledAt?: string | null;
119
+ cancelReason?: string | null;
120
+ createdAt: string;
121
+ }
122
+ export interface CreateInvoiceInput {
123
+ customerId: string;
124
+ items: InvoiceItem[];
125
+ /** FT = Fatura (default), FR = Fatura-Recibo */
126
+ documentType?: DocumentType;
127
+ notes?: string;
128
+ /** Chave de idempotência — gerada automaticamente se omitida */
129
+ idempotencyKey?: string;
130
+ }
131
+ export interface ListInvoicesParams extends ListParams {
132
+ status?: InvoiceStatus;
133
+ documentType?: DocumentType;
134
+ }
135
+ export type ProformaStatus = 'draft' | 'converted' | 'cancelled';
136
+ export interface ProformaInvoice {
137
+ id: string;
138
+ orgId: string;
139
+ customerId: string;
140
+ /** Código de exibição — hex curto, não segue série AGT (proforma não tem valor fiscal) */
141
+ displayCode?: string | null;
142
+ status: ProformaStatus;
143
+ subtotal: number;
144
+ taxAmount: number;
145
+ total: number;
146
+ currency: string;
147
+ items: InvoiceItem[];
148
+ pdfUrl?: string | null;
149
+ /** Preenchido quando status = 'converted' */
150
+ convertedInvoiceId?: string | null;
151
+ convertedAt?: string | null;
152
+ notes?: string | null;
153
+ validUntil?: string | null;
154
+ createdAt: string;
155
+ updatedAt: string;
156
+ }
157
+ export interface CreateProformaInput {
158
+ customerId: string;
159
+ items: InvoiceItem[];
160
+ notes?: string;
161
+ /** Data limite de validade (ISO 8601: "2026-12-31") */
162
+ validUntil?: string;
163
+ }
164
+ export interface ListProformasParams extends ListParams {
165
+ status?: ProformaStatus;
166
+ }
167
+ export interface CreditNote {
168
+ id: string;
169
+ orgId: string;
170
+ invoiceId: string;
171
+ customerId: string;
172
+ number?: string | null;
173
+ displayCode?: string | null;
174
+ status: string;
175
+ subtotal: number;
176
+ taxAmount: number;
177
+ total: number;
178
+ currency: string;
179
+ items: InvoiceItem[];
180
+ reason?: string | null;
181
+ pdfUrl?: string | null;
182
+ atcud?: string | null;
183
+ hash?: string | null;
184
+ previousHash?: string | null;
185
+ agtStatus?: AgtStatus;
186
+ agtErrors?: AgtError[] | null;
187
+ issuedAt?: string | null;
188
+ createdAt: string;
189
+ }
190
+ export interface DebitNote {
191
+ id: string;
192
+ orgId: string;
193
+ /** Preenchido quando ligada a uma fatura concreta */
194
+ invoiceId?: string | null;
195
+ /** Referência textual à fatura de origem (resolvida a partir de invoiceId, se indicado) */
196
+ invoiceRef?: string | null;
197
+ customerId: string;
198
+ number?: string | null;
199
+ displayCode?: string | null;
200
+ status: string;
201
+ subtotal: number;
202
+ taxAmount: number;
203
+ total: number;
204
+ currency: string;
205
+ items: InvoiceItem[];
206
+ reason?: string | null;
207
+ pdfUrl?: string | null;
208
+ atcud?: string | null;
209
+ hash?: string | null;
210
+ agtStatus?: AgtStatus;
211
+ agtErrors?: AgtError[] | null;
212
+ issuedAt?: string | null;
213
+ createdAt: string;
214
+ }
215
+ export interface CreateDebitNoteInput {
216
+ /** Cliente a debitar — obrigatório */
217
+ customerId: string;
218
+ /** Linhas de débito adicional */
219
+ items: InvoiceItem[];
220
+ /** Motivo do débito adicional */
221
+ reason?: string;
222
+ /**
223
+ * UUID de uma fatura desta organização — quando indicado, o Vero usa o número
224
+ * real dessa fatura como referência perante a AGT (mais seguro que invoiceRef).
225
+ */
226
+ invoiceId?: string;
227
+ /** Referência livre (ignorada se invoiceId for indicado) */
228
+ invoiceRef?: string;
229
+ }
230
+ export interface Receipt {
231
+ id: string;
232
+ orgId: string;
233
+ customerId: string;
234
+ invoiceId?: string | null;
235
+ number?: string | null;
236
+ displayCode?: string | null;
237
+ paymentMethod: 'transfer' | 'cash' | 'check';
238
+ subtotal: number;
239
+ taxAmount: number;
240
+ total: number;
241
+ currency: string;
242
+ items: InvoiceItem[];
243
+ pdfUrl?: string | null;
244
+ atcud?: string | null;
245
+ hash?: string | null;
246
+ /** RC é interno — nunca submetido à AGT, por isso não tem agtStatus */
247
+ issuedAt?: string | null;
248
+ createdAt: string;
249
+ }
250
+ export interface CreateReceiptInput {
251
+ /** Método de pagamento */
252
+ paymentMethod: 'transfer' | 'cash' | 'check';
253
+ }
254
+ export interface Product {
255
+ id: string;
256
+ orgId: string;
257
+ /** Código interno único por organização — opcional */
258
+ code?: string | null;
259
+ name: string;
260
+ description?: string | null;
261
+ /** Preço unitário em kwanzas × 100 */
262
+ unitPrice: number;
263
+ taxRate: 0 | 5 | 14;
264
+ /** Obrigatório quando taxRate = 0 */
265
+ taxExemptionCode?: string | null;
266
+ /** Default 'UN' */
267
+ unitOfMeasure: string;
268
+ active: boolean;
269
+ trackStock: boolean;
270
+ stockQuantity: number;
271
+ createdAt: string;
272
+ updatedAt: string;
273
+ }
274
+ export interface CreateProductInput {
275
+ /** Obrigatório — mínimo 1 caractere */
276
+ name: string;
277
+ code?: string;
278
+ description?: string;
279
+ unitPrice: number;
280
+ /** Default 14 */
281
+ taxRate?: 0 | 5 | 14;
282
+ taxExemptionCode?: string;
283
+ /** Default 'UN' */
284
+ unitOfMeasure?: string;
285
+ trackStock?: boolean;
286
+ }
287
+ export interface UpdateProductInput extends Partial<Omit<CreateProductInput, 'code'>> {
288
+ }
289
+ export type WebhookEvent = 'invoice.issued' | 'invoice.cancelled' | 'proforma.converted' | 'proforma.cancelled';
290
+ export interface Webhook {
291
+ id: string;
292
+ orgId: string;
293
+ url: string;
294
+ events: WebhookEvent[];
295
+ active: boolean;
296
+ createdAt: string;
297
+ /** Segredo HMAC para validar X-Vero-Signature — só vem preenchido na criação, nunca mais é devolvido */
298
+ secret?: string;
299
+ }
300
+ export interface RegisterWebhookInput {
301
+ url: string;
302
+ events: WebhookEvent[];
303
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ // ─── Config ───────────────────────────────────────────────────────────────────
2
+ export {};
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@veroao/node",
3
+ "version": "1.0.0",
4
+ "description": "Vero SDK for Node.js — faturação certificada AGT para Angola",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "prepublishOnly": "npm run build"
14
+ },
15
+ "keywords": [
16
+ "vero-ao",
17
+ "faturacao",
18
+ "agt",
19
+ "billing",
20
+ "invoicing",
21
+ "angola"
22
+ ],
23
+ "author": "Eterim Prestação de Serviços",
24
+ "license": "ISC",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/eadafonso/vero-sdk-node.git"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^25.9.0",
31
+ "typescript": "^5.3.3"
32
+ }
33
+ }