@veroao/react 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 +124 -0
- package/dist/VeroAOProvider.d.ts +14 -0
- package/dist/VeroAOProvider.js +15 -0
- package/dist/client.d.ts +12 -0
- package/dist/client.js +38 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/types.d.ts +52 -0
- package/dist/types.js +1 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# @veroao/react
|
|
2
|
+
|
|
3
|
+
SDK React para o Vero - integra pesquisa de clientes e emissão de factura directamente no teu
|
|
4
|
+
checkout, usando uma chave segura para o browser.
|
|
5
|
+
|
|
6
|
+
## Instalação
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install @veroao/react
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`react` e `react-dom` (>=18) são peer dependencies - usa as que já tens no projecto.
|
|
13
|
+
|
|
14
|
+
## Chave publicável - segura para o browser
|
|
15
|
+
|
|
16
|
+
Este SDK foi desenhado para correr no cliente (browser), por isso usa uma **chave publicável**
|
|
17
|
+
(`vero_live_pk_...` / `vero_test_pk_...`), diferente da chave secreta usada no
|
|
18
|
+
[`@veroao/node`](https://www.npmjs.com/package/@veroao/node). Cria-a no dashboard, em
|
|
19
|
+
Chaves de API, escolhendo o tipo "Publicável".
|
|
20
|
+
|
|
21
|
+
Mesmo que alguém veja esta chave no código-fonte da página, o servidor só a aceita nos endpoints
|
|
22
|
+
de widget (pesquisar clientes, emitir factura) - nunca dá acesso à tua conta completa.
|
|
23
|
+
|
|
24
|
+
## Quick start
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import { VeroAOProvider, useVeroAO } from '@veroao/react'
|
|
28
|
+
|
|
29
|
+
function App() {
|
|
30
|
+
return (
|
|
31
|
+
<VeroAOProvider config={{ apiKey: 'vero_live_pk_...' }}>
|
|
32
|
+
<CheckoutButton />
|
|
33
|
+
</VeroAOProvider>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function CheckoutButton() {
|
|
38
|
+
const { client } = useVeroAO()
|
|
39
|
+
|
|
40
|
+
const handleCreateInvoice = async () => {
|
|
41
|
+
const { data: customers } = await client.listCustomers(orgId, { search: 'Maria' })
|
|
42
|
+
|
|
43
|
+
const invoice = await client.createInvoice(orgId, {
|
|
44
|
+
customerId: customers[0].id,
|
|
45
|
+
documentType: 'FR',
|
|
46
|
+
items: [{ description: 'Plano Pro', quantity: 1, unitPrice: 500000, taxRate: 14 }],
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
window.open(invoice.pdfUrl!, '_blank') // link público, sem autenticação
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return <button onClick={handleCreateInvoice}>Emitir factura</button>
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Configuração do Provider
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
<VeroAOProvider config={{
|
|
60
|
+
apiKey: 'vero_live_pk_...',
|
|
61
|
+
baseUrl: 'https://api.custom.ao/v1', // opcional - útil para testes locais
|
|
62
|
+
environment: 'live', // opcional, default 'test'
|
|
63
|
+
}}>
|
|
64
|
+
{children}
|
|
65
|
+
</VeroAOProvider>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## `useVeroAO()`
|
|
69
|
+
|
|
70
|
+
Devolve `{ client, isLoading, error }`. `client` expõe:
|
|
71
|
+
|
|
72
|
+
- `client.listCustomers(orgId, { search?, limit? })` → `{ data: Customer[] }`
|
|
73
|
+
- `client.createInvoice(orgId, { customerId, items, documentType?, notes?, idempotencyKey? })` → `Invoice`
|
|
74
|
+
|
|
75
|
+
## Tratamento de erros
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
try {
|
|
79
|
+
await client.createInvoice(orgId, input)
|
|
80
|
+
} catch (err) {
|
|
81
|
+
const apiErr = err as { error: string; message?: string }
|
|
82
|
+
if (apiErr.error === 'customer_not_found') {
|
|
83
|
+
// cliente não encontrado nesta organização
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Preços em kwanzas
|
|
89
|
+
|
|
90
|
+
Os valores monetários usam **kwanzas × 100**: `unitPrice: 500000` equivale a 5 000,00 AOA.
|
|
91
|
+
|
|
92
|
+
## Preciso de mais do que isto - criar produtos, listar facturas, notas de crédito...
|
|
93
|
+
|
|
94
|
+
Este SDK só sabe fazer as duas coisas acima, **de propósito**: a chave publicável que usa é
|
|
95
|
+
restrita pelo servidor a essas rotas, para ser segura no browser. Não existe forma de "desbloquear"
|
|
96
|
+
mais operações com uma chave publicável - nem gerir produtos, nem listar facturas existentes, nem
|
|
97
|
+
emitir notas de crédito/débito, nem apagar clientes.
|
|
98
|
+
|
|
99
|
+
Se precisas de qualquer uma dessas operações a partir de uma aplicação React, o padrão correcto é:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
React (browser) → o TEU backend → Vero (com @veroao/node + chave secreta)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Ou seja, cria uma rota de API tua (Next.js API route, Express, etc.) que use
|
|
106
|
+
[`@veroao/node`](https://www.npmjs.com/package/@veroao/node) com a chave secreta, e chama essa
|
|
107
|
+
rota a partir do React - nunca a API do Vero directamente para essas operações.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// app/api/products/route.ts (exemplo Next.js)
|
|
111
|
+
import { createVeroClient } from '@veroao/node'
|
|
112
|
+
|
|
113
|
+
const vero = createVeroClient() // VERO_API_KEY - chave secreta, só no servidor
|
|
114
|
+
|
|
115
|
+
export async function POST(req: Request) {
|
|
116
|
+
const body = await req.json()
|
|
117
|
+
const product = await vero.products.create(ORG_ID, body)
|
|
118
|
+
return Response.json(product)
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
O backend não precisa de ser Node - é só o exemplo mais directo. Se for PHP, Python, Ruby, etc.,
|
|
123
|
+
chama a API REST directamente com o cliente HTTP dessa linguagem; tens as mesmas operações
|
|
124
|
+
disponíveis. Exemplos em cURL, Python e PHP em [vero.ao/docs](https://vero.ao/docs).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { VeroAOClient } from "./client.js";
|
|
3
|
+
import type { VeroAOConfig } from "./types.js";
|
|
4
|
+
export interface VeroAOContextValue {
|
|
5
|
+
client: VeroAOClient;
|
|
6
|
+
isLoading: boolean;
|
|
7
|
+
error: Error | null;
|
|
8
|
+
}
|
|
9
|
+
export interface VeroAOProviderProps {
|
|
10
|
+
config: VeroAOConfig;
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
export declare function VeroAOProvider({ config, children }: VeroAOProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare function useVeroAO(): VeroAOContextValue;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useMemo } from "react";
|
|
3
|
+
import { VeroAOClient } from "./client.js";
|
|
4
|
+
const VeroAOContext = createContext(null);
|
|
5
|
+
export function VeroAOProvider({ config, children }) {
|
|
6
|
+
const client = useMemo(() => new VeroAOClient(config), [config]);
|
|
7
|
+
return (_jsx(VeroAOContext.Provider, { value: { client, isLoading: false, error: null }, children: children }));
|
|
8
|
+
}
|
|
9
|
+
export function useVeroAO() {
|
|
10
|
+
const context = useContext(VeroAOContext);
|
|
11
|
+
if (!context) {
|
|
12
|
+
throw new Error("useVeroAO must be used within a VeroAOProvider");
|
|
13
|
+
}
|
|
14
|
+
return context;
|
|
15
|
+
}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { VeroAOConfig, Customer, Invoice, CreateInvoiceInput, SearchCustomersParams } from "./types.js";
|
|
2
|
+
export declare class VeroAOClient {
|
|
3
|
+
private apiKey;
|
|
4
|
+
private environment;
|
|
5
|
+
private baseUrl;
|
|
6
|
+
constructor(config: VeroAOConfig);
|
|
7
|
+
private request;
|
|
8
|
+
listCustomers(orgId: string, params?: SearchCustomersParams): Promise<{
|
|
9
|
+
data: Customer[];
|
|
10
|
+
}>;
|
|
11
|
+
createInvoice(orgId: string, input: CreateInvoiceInput): Promise<Invoice>;
|
|
12
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export class VeroAOClient {
|
|
2
|
+
apiKey;
|
|
3
|
+
environment;
|
|
4
|
+
baseUrl;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.apiKey = config.apiKey;
|
|
7
|
+
this.environment = config.environment ?? "test";
|
|
8
|
+
this.baseUrl = config.baseUrl || "https://api.vero.ao/v1";
|
|
9
|
+
}
|
|
10
|
+
async request(method, path, body, params) {
|
|
11
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
12
|
+
if (params) {
|
|
13
|
+
Object.entries(params).forEach(([k, v]) => {
|
|
14
|
+
if (v !== undefined)
|
|
15
|
+
url.searchParams.append(k, String(v));
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
const response = await fetch(url.toString(), {
|
|
19
|
+
method,
|
|
20
|
+
headers: {
|
|
21
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
22
|
+
"Content-Type": "application/json",
|
|
23
|
+
},
|
|
24
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
25
|
+
});
|
|
26
|
+
const data = await response.json();
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
throw data;
|
|
29
|
+
}
|
|
30
|
+
return data;
|
|
31
|
+
}
|
|
32
|
+
async listCustomers(orgId, params = {}) {
|
|
33
|
+
return this.request("GET", `/widget/organisations/${orgId}/customers`, undefined, params);
|
|
34
|
+
}
|
|
35
|
+
async createInvoice(orgId, input) {
|
|
36
|
+
return this.request("POST", `/widget/organisations/${orgId}/invoices`, input);
|
|
37
|
+
}
|
|
38
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export interface VeroAOConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
/** Override da URL base (útil para testes locais) */
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
environment?: "live" | "test";
|
|
6
|
+
}
|
|
7
|
+
export interface VeroAOError {
|
|
8
|
+
/** Código de erro da API — ex: "customer_not_found", "unauthorized" */
|
|
9
|
+
error: string;
|
|
10
|
+
message?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface Customer {
|
|
13
|
+
id: string;
|
|
14
|
+
orgId: string;
|
|
15
|
+
name: string;
|
|
16
|
+
taxId?: string | null;
|
|
17
|
+
email?: string | null;
|
|
18
|
+
phone?: string | null;
|
|
19
|
+
}
|
|
20
|
+
export interface InvoiceItem {
|
|
21
|
+
description: string;
|
|
22
|
+
quantity: number;
|
|
23
|
+
unitPrice: number;
|
|
24
|
+
taxRate?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface Invoice {
|
|
27
|
+
id: string;
|
|
28
|
+
orgId: string;
|
|
29
|
+
customerId: string;
|
|
30
|
+
number?: string | null;
|
|
31
|
+
displayCode?: string | null;
|
|
32
|
+
status: "pending" | "issued" | "paid" | "failed" | "cancelled";
|
|
33
|
+
total: number;
|
|
34
|
+
subtotal: number;
|
|
35
|
+
taxAmount: number;
|
|
36
|
+
currency: string;
|
|
37
|
+
pdfUrl?: string | null;
|
|
38
|
+
atcud?: string | null;
|
|
39
|
+
issuedAt?: string | null;
|
|
40
|
+
createdAt: string;
|
|
41
|
+
}
|
|
42
|
+
export interface CreateInvoiceInput {
|
|
43
|
+
customerId: string;
|
|
44
|
+
items: InvoiceItem[];
|
|
45
|
+
notes?: string;
|
|
46
|
+
idempotencyKey?: string;
|
|
47
|
+
documentType?: "FT" | "FR";
|
|
48
|
+
}
|
|
49
|
+
export interface SearchCustomersParams {
|
|
50
|
+
search?: string;
|
|
51
|
+
limit?: number;
|
|
52
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@veroao/react",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Vero-AO SDK for React — faturação certificada AGT em aplicações React",
|
|
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": ["vero-ao", "faturacao", "agt", "angola", "invoicing", "react"],
|
|
16
|
+
"author": "Eterim Prestação de Serviços",
|
|
17
|
+
"license": "ISC",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/eadafonso/vero-sdk-react.git"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"react": ">=18.0.0",
|
|
24
|
+
"react-dom": ">=18.0.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/react": "^18.2.0",
|
|
28
|
+
"@types/react-dom": "^18.2.0",
|
|
29
|
+
"react": "^18.2.0",
|
|
30
|
+
"react-dom": "^18.2.0",
|
|
31
|
+
"typescript": "^5.3.3"
|
|
32
|
+
}
|
|
33
|
+
}
|