sgp-sdk 0.0.0-stage → 1.2.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/LICENSE +21 -0
- package/README.md +303 -2
- package/dist/client.d.ts +228 -0
- package/dist/endpoint.d.ts +66 -0
- package/dist/endpoints/crm/address.d.ts +20 -0
- package/dist/endpoints/crm/create-contract.d.ts +109 -0
- package/dist/endpoints/crm/create-customer.d.ts +65 -0
- package/dist/endpoints/crm/update-customer-status.d.ts +43 -0
- package/dist/endpoints/os/list-occurrence-reasons.d.ts +24 -0
- package/dist/endpoints/os/list-occurrence-types.d.ts +25 -0
- package/dist/endpoints/precadastro/list-due-days.d.ts +19 -0
- package/dist/endpoints/precadastro/list-sellers.d.ts +21 -0
- package/dist/endpoints/suporte/add-customer-document.d.ts +24 -0
- package/dist/endpoints/suporte/list-customer-documents.d.ts +25 -0
- package/dist/endpoints/ura/check-coverage.d.ts +46 -0
- package/dist/endpoints/ura/list-annotations.d.ts +32 -0
- package/dist/endpoints/ura/list-clients.d.ts +58 -0
- package/dist/endpoints/ura/list-contracts.d.ts +45 -0
- package/dist/endpoints/ura/list-invoices.d.ts +107 -0
- package/dist/endpoints/ura/list-nas.d.ts +29 -0
- package/dist/endpoints/ura/list-occurrence-methods.d.ts +19 -0
- package/dist/endpoints/ura/list-payment-carriers.d.ts +20 -0
- package/dist/endpoints/ura/list-plans.d.ts +70 -0
- package/dist/endpoints/ura/list-pops.d.ts +19 -0
- package/dist/endpoints/ura/list-service-orders.d.ts +64 -0
- package/dist/endpoints/ura/lookup-customer.d.ts +121 -0
- package/dist/endpoints/ura/open-ticket.d.ts +81 -0
- package/dist/errors.d.ts +59 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +1449 -0
- package/dist/result.d.ts +55 -0
- package/dist/schema/parse.d.ts +19 -0
- package/dist/schema/paths.d.ts +38 -0
- package/dist/sensitivity.d.ts +7 -0
- package/dist/transport.d.ts +65 -0
- package/package.json +34 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SYXS
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,304 @@
|
|
|
1
|
-
#
|
|
1
|
+
# sgp-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Unofficial TypeScript client for the HTTP API of SGP, the ISP ERP by TSMX. Not affiliated with
|
|
4
|
+
TSMX. It is a _dumb_ SDK: typed inputs and outputs, normalized errors, no business rules. Your
|
|
5
|
+
application decides what to do with the data.
|
|
6
|
+
|
|
7
|
+
- Reads, plus writes on `crm`, `ura.openTicket` and `suporte.addCustomerDocument` (see
|
|
8
|
+
[Writes](#writes)).
|
|
9
|
+
- ESM package with types, Node >= 22 (also runs on Bun). The only runtime dependency is `zod`.
|
|
10
|
+
- Methods never throw for network, HTTP or schema failures; they return a result object.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
bun add sgp-sdk
|
|
16
|
+
# or
|
|
17
|
+
npm install sgp-sdk
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Types resolve under `"moduleResolution": "bundler"` (Bun, Next.js, tsx, Vite, esbuild) and under
|
|
21
|
+
`node16` / `nodenext`: the emitted `.d.ts` files carry explicit `.js` extensions.
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { clientPersonalKeys, createSgpClient, omitSensitive } from "sgp-sdk";
|
|
27
|
+
|
|
28
|
+
const sgp = createSgpClient({
|
|
29
|
+
baseUrl: "https://sgp.example.com",
|
|
30
|
+
token: "<token of your app>",
|
|
31
|
+
app: "<app name>",
|
|
32
|
+
// timeoutMs: 20_000, // default
|
|
33
|
+
// fetch: fakeFetch, // default: the global fetch (inject a fake in tests)
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const plans = await sgp.ura.listPlans();
|
|
37
|
+
if (plans.success) {
|
|
38
|
+
console.log(plans.data.planos.length, plans.warnings ?? []);
|
|
39
|
+
} else {
|
|
40
|
+
console.error(plans.error.code, plans.error.status, plans.error.endpoint);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const clients = await sgp.ura.listClients({ cpfcnpj: "00000000000", limit: 1 });
|
|
44
|
+
if (clients.success) {
|
|
45
|
+
for (const client of clients.data.clientes) {
|
|
46
|
+
const safe = omitSensitive(client, clientPersonalKeys); // no name, CPF/CNPJ, address, contacts
|
|
47
|
+
console.log(safe.id);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The SDK never reads the environment: load the credentials your way and pass them in.
|
|
53
|
+
|
|
54
|
+
### Methods
|
|
55
|
+
|
|
56
|
+
Field names in params and responses are exactly what SGP sends. Each method's JSDoc cites the HTTP
|
|
57
|
+
method and path.
|
|
58
|
+
|
|
59
|
+
| Method | SGP route |
|
|
60
|
+
| ------------------------------------------------------- | ------------------------------------------------------- |
|
|
61
|
+
| `ura.listClients(params?)` | `POST /api/ura/clientes/` |
|
|
62
|
+
| `ura.lookupCustomer(params)` | `POST /api/ura/consultacliente/` |
|
|
63
|
+
| `ura.listContracts(params?)` | `POST /api/ura/listacontrato/` |
|
|
64
|
+
| `ura.listAnnotations(params)` **experimental** | `GET /api/ura/cliente/anotacao/list/` |
|
|
65
|
+
| `ura.listServiceOrders(params?)` | `POST /api/ura/ordemservico/list/` |
|
|
66
|
+
| `ura.listInvoices(params?)` | `POST /api/ura/titulos/` |
|
|
67
|
+
| `ura.listPops()` | `POST /api/ura/pops/` |
|
|
68
|
+
| `ura.listNas()` | `POST /api/ura/nas/list/` |
|
|
69
|
+
| `ura.listPaymentCarriers()` | `GET /api/ura/portador/` |
|
|
70
|
+
| `ura.checkCoverage(params)` | `GET /api/ura/viabilidadeinstalacao` |
|
|
71
|
+
| `ura.listPlans()` | `GET /api/ura/consultaplano/` |
|
|
72
|
+
| `ura.listOccurrenceMethods()` | `GET /api/ura/ocorrencia/metodo/list/` |
|
|
73
|
+
| `ura.openTicket(params)` | `POST /api/ura/chamado/` |
|
|
74
|
+
| `os.listOccurrenceTypes()` | `GET /api/os/ocorrencia/tipo/list/` |
|
|
75
|
+
| `os.listOccurrenceReasons()` | `GET /api/os/ocorrencia/motivo/list/` |
|
|
76
|
+
| `precadastro.listDueDays()` | `POST /api/precadastro/vencimento/list` |
|
|
77
|
+
| `precadastro.listSellers()` | `POST /api/precadastro/vendedor/list` |
|
|
78
|
+
| `crm.createIndividualCustomer(params)` | `POST /api/crm/cliente/F` |
|
|
79
|
+
| `crm.createCompanyCustomer(params)` | `POST /api/crm/cliente/J` |
|
|
80
|
+
| `crm.createContract(clienteId, params)` | `POST /api/crm/cliente/{cliente_id}/contratos/` |
|
|
81
|
+
| `crm.updateCustomerStatus(clienteId, params)` | `POST /api/crm/cliente/{cliente_id}/status/` |
|
|
82
|
+
| `suporte.addCustomerDocument(clienteId, file, params?)` | `PUT /api/suporte/cliente/{cliente_id}/documento/add/` |
|
|
83
|
+
| `suporte.listCustomerDocuments(clienteId)` | `GET /api/suporte/cliente/{cliente_id}/documento/list/` |
|
|
84
|
+
|
|
85
|
+
Every route must be allowed on the consumer's token in SGP (System > Tools > Admin Panel >
|
|
86
|
+
Tokens). A route outside the whitelist returns `ROUTE_NOT_ALLOWED`. Paging is the API's own:
|
|
87
|
+
`offset` and `limit`; the SDK never pages for you.
|
|
88
|
+
|
|
89
|
+
`ura.checkCoverage({ gateway, raio, coordenada })` checks installation viability: the answer is keyed
|
|
90
|
+
by the gateway's name (data-defined, e.g. `SGPMaps`) and holds the CTOs within `raio` meters or the
|
|
91
|
+
message `"Localização inviável"`. The coordinate (`"lat,lng"`) comes from the consumer; the SDK does
|
|
92
|
+
not geocode. `lat`, `lng` and `distancia` are always numbers (Geogrid sends them as numeric strings
|
|
93
|
+
and the SDK converts them). A malformed gateway answer, such as a CTO with a non-numeric `lat`, is
|
|
94
|
+
`SCHEMA_MISMATCH`.
|
|
95
|
+
|
|
96
|
+
### Experimental annotation listing
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
const notes = await sgp.ura.listAnnotations({ cliente_id: 10, contrato_id: 100 });
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`ura.listAnnotations` requires at least one of `cliente_id` / `contrato_id`, each a positive safe-integer
|
|
103
|
+
number. Missing filters, nulls, numeric strings and invalid numbers return `VALIDATION` with status 0
|
|
104
|
+
without fetching. Customer-only includes notes with a null contract; contract-only selects that
|
|
105
|
+
contract; both filters mean **AND**, never OR or fallback. No match is a successful empty array.
|
|
106
|
+
|
|
107
|
+
SGP currently ignores these upstream filters (vendor defect reported, not claimed fixed). The SDK
|
|
108
|
+
still sends canonical filters in one authenticated GET and selects raw identities **before** parsing
|
|
109
|
+
selected notes. A definite mismatch excludes a row even if unrelated content is malformed. If a
|
|
110
|
+
needed identity is missing or malformed and no definite mismatch excludes it, the call fails with
|
|
111
|
+
`SCHEMA_MISMATCH`, not partial data. Source identity strings are not coerced. Selected core fields
|
|
112
|
+
are strict; optional-field drift produces ordinary, selected-only schema warnings. Source order and
|
|
113
|
+
duplicates are preserved; unknown fields are stripped.
|
|
114
|
+
|
|
115
|
+
Returns matching notes present in one SGP response; source completeness is not guaranteed while this method is experimental.
|
|
116
|
+
No documented pagination contract proves completeness; there is no automatic paging, retry, polling,
|
|
117
|
+
cache, completeness flag or operational warning. The method, snake_case params and array-shaped
|
|
118
|
+
`SgpResult<ListAnnotationsResponse>` remain usable after the vendor fix; local selection and
|
|
119
|
+
validation remain as defense. Removing the experimental label requires evidence of corrected behavior.
|
|
120
|
+
|
|
121
|
+
The nine declared fields are required numeric `id` / `cliente`, required number-or-null
|
|
122
|
+
`clientecontrato`, required string `anotacao`, optional/nullable numeric `usuario` / `tipo` /
|
|
123
|
+
`alerta_modo`, and optional/nullable string `data_cadastro` / `data_alteracao`. Text and dates are
|
|
124
|
+
preserved verbatim, without HTML rendering, trimming or date parsing. `annotationPersonalKeys`
|
|
125
|
+
classifies note text and staff identity (`anotacao`, `usuario`); `annotationSecretKeys` is empty.
|
|
126
|
+
Use `omitSensitive(note, annotationPersonalKeys)` before logging or forwarding: free text may contain
|
|
127
|
+
user-entered sensitive content even though no credential field is declared.
|
|
128
|
+
|
|
129
|
+
**Trusted server only:** the multi-customer upstream body enters SDK memory, but the SDK never
|
|
130
|
+
returns, logs or caches the bulk array. Injected fetch, tracing and other instrumentation see the
|
|
131
|
+
body **before** SDK selection and MUST NOT capture it. Local selection is not an authorization
|
|
132
|
+
boundary: the application must authorize requested IDs and keep credentials and execution trusted.
|
|
133
|
+
SDK-generated diagnostics contain paths/types, not source values. Existing upstream error details
|
|
134
|
+
are unchanged and may echo request values; treat them as sensitive too. This special filtered read
|
|
135
|
+
is deliberately excluded from the generic filterless probe registry.
|
|
136
|
+
|
|
137
|
+
## Result and error contract
|
|
138
|
+
|
|
139
|
+
Every method returns `SgpResult<T>`:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
type SgpResult<T> =
|
|
143
|
+
| { success: true; data: T; warnings?: SchemaWarning[] }
|
|
144
|
+
| { success: false; error: SgpError };
|
|
145
|
+
|
|
146
|
+
interface SgpError {
|
|
147
|
+
status: number; // HTTP status, 0 when no response arrived
|
|
148
|
+
code: SgpErrorCode;
|
|
149
|
+
message: string; // written by the SDK, in English
|
|
150
|
+
detail?: string; // SGP's own error text (`detail`, `msg`, `errors` or `error`), copied verbatim
|
|
151
|
+
endpoint: string; // path only, never the query string
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
interface SchemaWarning {
|
|
155
|
+
path: string; // e.g. "contratos[0].cobIsento"
|
|
156
|
+
expected: string; // type names only, never values
|
|
157
|
+
received: string;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
| Code | When |
|
|
162
|
+
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
163
|
+
| `UNAUTHORIZED` | 401/403 with `detail` (or `msg`) `"Credenciais de autenticação incorretas."` (wrong token or app) |
|
|
164
|
+
| `ROUTE_NOT_ALLOWED` | 401/403 with `detail` (or `msg`) `"As credenciais de autenticação não foram fornecidas."`. The SDK always sends credentials, so this means the route is not on the token's whitelist |
|
|
165
|
+
| `NOT_FOUND` | 404 |
|
|
166
|
+
| `METHOD_NOT_ALLOWED` | 405 |
|
|
167
|
+
| `VALIDATION` | any other 4xx: SGP refused the input |
|
|
168
|
+
| `SCHEMA_MISMATCH` | 2xx whose body is not JSON, or whose key fields are missing or have the wrong type (`detail` then lists the failing paths) |
|
|
169
|
+
| `UPSTREAM` | 5xx |
|
|
170
|
+
| `TIMEOUT` | the request exceeded `timeoutMs` |
|
|
171
|
+
| `NETWORK` | `fetch` failed before a response (DNS, connection, TLS) |
|
|
172
|
+
| `UNKNOWN` | 401/403 with any other `detail` or `msg`, or a status the rows above do not cover |
|
|
173
|
+
|
|
174
|
+
SGP answers errors in four formats: `{"detail": "..."}`, `{"msg": "..."}`, `{"errors": ...}` (an
|
|
175
|
+
array of messages or an object of field messages, on CRM routes) and `{"error": "..."}` (e.g. a 404
|
|
176
|
+
`Cadastro não encontrado` on CRM routes). `error.detail` holds, in this order: a string `detail`
|
|
177
|
+
(even empty), a non-empty `msg`, the text of `errors`, a non-empty `error`.
|
|
178
|
+
|
|
179
|
+
Guarantees:
|
|
180
|
+
|
|
181
|
+
- The SDK never puts the token, the app, a URL with query string, a raw response body or the
|
|
182
|
+
original message of a `fetch` exception in anything it returns (`data`, `warnings`, `error`).
|
|
183
|
+
- `error.detail` is SGP's text copied verbatim: it may echo values from your request (for example
|
|
184
|
+
a contract ID or a CPF in a `msg`). The SDK adds nothing to it, so treat it like the request
|
|
185
|
+
itself before logging or showing it.
|
|
186
|
+
- 401/403 are classified by that exact `detail` string, not by status (SGP uses either status for
|
|
187
|
+
the same message). If SGP rewords those messages the code falls to `UNKNOWN`.
|
|
188
|
+
- No retry, no cache, no logging, no automatic paging.
|
|
189
|
+
- Redirects are never followed, so the token and payload are not re-sent to another host: a 3xx
|
|
190
|
+
answer is an `UNKNOWN` error carrying its status (`outcome: "unknown"` on a write).
|
|
191
|
+
- Unknown keys are dropped at every level (`strip`): everything that reaches you was declared and
|
|
192
|
+
classified. Required key fields that fail validation are `SCHEMA_MISMATCH`; any other field with
|
|
193
|
+
an unexpected type becomes `undefined` and is reported in `warnings`.
|
|
194
|
+
|
|
195
|
+
## Writes
|
|
196
|
+
|
|
197
|
+
Write methods (`crm.*`, `ura.openTicket` and `suporte.addCustomerDocument`) return
|
|
198
|
+
`SgpWriteResult<T>`: the same as `SgpResult<T>`, but `error` also carries an `outcome` that says
|
|
199
|
+
whether SGP applied the write.
|
|
200
|
+
|
|
201
|
+
- `"not_applied"`: SGP refused the request (4xx) or the SDK rejected it before sending it. SGP did
|
|
202
|
+
not apply the write; fix the input and call again.
|
|
203
|
+
- `"unknown"`: no answer (`TIMEOUT`, `NETWORK`), a 5xx, a 3xx (`UNKNOWN`: redirects are never
|
|
204
|
+
followed), or a 2xx whose body does not confirm the write (`VALIDATION` with the real HTTP
|
|
205
|
+
status). The write may have happened: check the state in SGP before repeating it.
|
|
206
|
+
- A 4xx whose body has `errors` as an array (e.g. a 400 with `{"errors": ["Ocorreu um erro: ..."]}`)
|
|
207
|
+
is SGP's generic exception wrapper: it can fail after applying part of the write, so it is
|
|
208
|
+
`"unknown"`, even when `detail` or `msg` come with it. The `code` stays `VALIDATION` and the
|
|
209
|
+
`message` reads "SGP reported an error while processing the write; it may have been applied."
|
|
210
|
+
401/403/404/405/422 stay `"not_applied"` whatever the body, and so does a 4xx whose `errors` is an
|
|
211
|
+
object of field messages or that carries only `detail` or `msg`.
|
|
212
|
+
|
|
213
|
+
After `outcome: "unknown"`, read the state back before repeating the write:
|
|
214
|
+
|
|
215
|
+
| Write | Read that verifies it |
|
|
216
|
+
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
217
|
+
| `crm.createIndividualCustomer`, `crm.createCompanyCustomer` | `ura.listClients({ cpfcnpj })` |
|
|
218
|
+
| `crm.createContract` | `ura.lookupCustomer` or `ura.listContracts` |
|
|
219
|
+
| `ura.openTicket` | `ura.listServiceOrders({ contrato })`; a ticket with `desativa_os: 1` opens no service order, so there is nothing to look up |
|
|
220
|
+
| `suporte.addCustomerDocument` | `suporte.listCustomerDocuments` |
|
|
221
|
+
| `crm.updateCustomerStatus` | run it again; for status 6 on an existing CRM customer, a 404 `NOT_FOUND` means it was applied (it leaves the CRM) |
|
|
222
|
+
|
|
223
|
+
A write only succeeds on a 2xx whose body carries the key fields (for example `cliente_id`). The one
|
|
224
|
+
exception is `suporte.addCustomerDocument`: SGP answers an empty 2xx, which succeeds with
|
|
225
|
+
`data: null`. Success there does not prove the file was stored; verify it with
|
|
226
|
+
`suporte.listCustomerDocuments`. The SDK never retries a write.
|
|
227
|
+
|
|
228
|
+
Sales flow: create the customer (`crm.createIndividualCustomer` or `crm.createCompanyCustomer`),
|
|
229
|
+
create the contract on it (`crm.createContract(clienteId, params)`), then call
|
|
230
|
+
`crm.updateCustomerStatus(clienteId, { status_id: crmStatus.contratoRealizadoNoSgp })` (status 6).
|
|
231
|
+
Without that last step SGP's screen keeps the customer as a CRM customer and blocks contract status
|
|
232
|
+
changes.
|
|
233
|
+
|
|
234
|
+
`crm.createContract` sends the installation address nested (`endereco_instalacao`) and also as the
|
|
235
|
+
loose fields (`logradouro`, `numero`, ...), and the billing address only nested
|
|
236
|
+
(`endereco_cobranca`). The loose fields carry the installation address; a billing address that
|
|
237
|
+
differs from the installation one has not been verified live, so check it on SGP before sending
|
|
238
|
+
divergent addresses.
|
|
239
|
+
|
|
240
|
+
Scheduling an installation goes through `ura.openTicket` with `data_hora_agendamento`
|
|
241
|
+
(`"AAAA-MM-DD HH:MM"`); `os_instalacao` in `crm.createContract` opens the order without a date.
|
|
242
|
+
|
|
243
|
+
The token whitelist accepts regular expressions and the trailing slash counts: release each path
|
|
244
|
+
exactly as in the table above, so `/api/crm/cliente/F` has no final `/` and
|
|
245
|
+
`/api/crm/cliente/{cliente_id}/status/` has one (the `{cliente_id}` routes need a pattern that
|
|
246
|
+
matches any ID).
|
|
247
|
+
|
|
248
|
+
## Sensitive fields
|
|
249
|
+
|
|
250
|
+
SGP responses carry credentials and personal data. The SDK transcribes them (the consumer decides
|
|
251
|
+
what to show) and marks them: each endpoint exports `as const` tuples with the keys of one response
|
|
252
|
+
item.
|
|
253
|
+
|
|
254
|
+
- `secret`: Central password, PPPoE login and password, Wi-Fi passwords and SSIDs, MACs, links with
|
|
255
|
+
an embedded token.
|
|
256
|
+
- `personal`: CPF/CNPJ, phone, e-mail, address, birth date, customer name, free text typed by
|
|
257
|
+
operators.
|
|
258
|
+
|
|
259
|
+
Tuple names follow the item: `clientSecretKeys` / `clientPersonalKeys`,
|
|
260
|
+
`customerContractSecretKeys` / `customerContractPersonalKeys`, and so on (see the package exports).
|
|
261
|
+
`omitSensitive(item, keys)` returns a shallow copy without those keys and removes them from the
|
|
262
|
+
type, so a leak becomes a compile error:
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
const safe = omitSensitive(client, clientPersonalKeys);
|
|
266
|
+
safe.nome; // type error: `nome` was omitted
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
The SDK only marks and offers the helper; deciding when to apply it is the consumer's job. Strip
|
|
270
|
+
before logging, caching or forwarding an item to a model.
|
|
271
|
+
|
|
272
|
+
## Known limitations
|
|
273
|
+
|
|
274
|
+
- **Placeholder arrays.** These fields are declared as arrays of empty objects
|
|
275
|
+
(`z.array(z.object({}))`) because no sample response had content for them. Every element arrives
|
|
276
|
+
as `{}`, with no warning, and what SGP sends inside is dropped:
|
|
277
|
+
- `listClients`: `clientes[].contratos` and `clientes[].titulos` (use `lookupCustomer` and the
|
|
278
|
+
contract methods for those details);
|
|
279
|
+
- `lookupCustomer`: `contratos[].telefones_cargos`, `contratos[].outros` and
|
|
280
|
+
`contratos[].anotacoes`;
|
|
281
|
+
- `listServiceOrders`: `ordens_servicos[].tecnicos_auxiliares` and
|
|
282
|
+
`ordens_servicos[].classificacoes`;
|
|
283
|
+
- `listPlans`: `planos[].combo`;
|
|
284
|
+
- `os.listOccurrenceTypes` and `os.listOccurrenceReasons`: `classificacoes` and `setores` of
|
|
285
|
+
each item;
|
|
286
|
+
- `listInvoices`: `acordados` and `cobrados` of `titulos[].acordoPagamento`.
|
|
287
|
+
- **Guessed types.** SGP only sent `null` for four `lookupCustomer` fields, so their types are
|
|
288
|
+
inferred: `contratos[].contrato_unificado_principal` (number),
|
|
289
|
+
`contratos[].contrato_unificado_filhos` (array of numbers), `contratos[].endereco_pontoreferencia`
|
|
290
|
+
(string) and `contratos[].tags[].categoria_id` (number). A wrong guess does not fail the call: the
|
|
291
|
+
field comes out as `undefined` and is reported in `warnings`.
|
|
292
|
+
- **A bad element drops the whole array.** When one element of an array field has the wrong type,
|
|
293
|
+
the whole field becomes `undefined`, and the warning names only the failing element. For example,
|
|
294
|
+
a non-string entry in `clientes[].contatos.telefones` drops the whole `telefones` array and the
|
|
295
|
+
warning path is `clientes[0].contatos.telefones[1]`.
|
|
296
|
+
- `listContracts` does not transcribe the address fields returned by `exibir_endereco`.
|
|
297
|
+
|
|
298
|
+
## Pending
|
|
299
|
+
|
|
300
|
+
What is left:
|
|
301
|
+
|
|
302
|
+
- **E-signature of the adhesion term.** Not available in the SGP API.
|
|
303
|
+
- **Boleto delivery methods and invoice (nota fiscal) fields** of the contract. Not available in the
|
|
304
|
+
SGP API, so `crm.createContract` leaves them empty.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { type CreateContractParams, type CreateContractResponse } from "./endpoints/crm/create-contract.js";
|
|
2
|
+
import { type CreateCompanyCustomerParams, type CreateCustomerResponse, type CreateIndividualCustomerParams } from "./endpoints/crm/create-customer.js";
|
|
3
|
+
import { type UpdateCustomerStatusParams, type UpdateCustomerStatusResponse } from "./endpoints/crm/update-customer-status.js";
|
|
4
|
+
import { type ListOccurrenceReasonsResponse } from "./endpoints/os/list-occurrence-reasons.js";
|
|
5
|
+
import { type ListOccurrenceTypesResponse } from "./endpoints/os/list-occurrence-types.js";
|
|
6
|
+
import { type ListDueDaysResponse } from "./endpoints/precadastro/list-due-days.js";
|
|
7
|
+
import { type ListSellersResponse } from "./endpoints/precadastro/list-sellers.js";
|
|
8
|
+
import { type AddCustomerDocumentParams, type AddCustomerDocumentResponse } from "./endpoints/suporte/add-customer-document.js";
|
|
9
|
+
import { type ListCustomerDocumentsResponse } from "./endpoints/suporte/list-customer-documents.js";
|
|
10
|
+
import { type CheckCoverageParams, type CheckCoverageResponse } from "./endpoints/ura/check-coverage.js";
|
|
11
|
+
import { type ListAnnotationsParams, type ListAnnotationsResponse } from "./endpoints/ura/list-annotations.js";
|
|
12
|
+
import { type ListClientsParams, type ListClientsResponse } from "./endpoints/ura/list-clients.js";
|
|
13
|
+
import { type ListContractsParams, type ListContractsResponse } from "./endpoints/ura/list-contracts.js";
|
|
14
|
+
import { type ListInvoicesParams, type ListInvoicesResponse } from "./endpoints/ura/list-invoices.js";
|
|
15
|
+
import { type ListNasResponse } from "./endpoints/ura/list-nas.js";
|
|
16
|
+
import { type ListOccurrenceMethodsResponse } from "./endpoints/ura/list-occurrence-methods.js";
|
|
17
|
+
import { type ListPaymentCarriersResponse } from "./endpoints/ura/list-payment-carriers.js";
|
|
18
|
+
import { type ListPlansResponse } from "./endpoints/ura/list-plans.js";
|
|
19
|
+
import { type ListPopsResponse } from "./endpoints/ura/list-pops.js";
|
|
20
|
+
import { type ListServiceOrdersParams, type ListServiceOrdersResponse } from "./endpoints/ura/list-service-orders.js";
|
|
21
|
+
import { type LookupCustomerParams, type LookupCustomerResponse } from "./endpoints/ura/lookup-customer.js";
|
|
22
|
+
import { type OpenTicketParams, type OpenTicketResponse } from "./endpoints/ura/open-ticket.js";
|
|
23
|
+
import type { SgpResult, SgpWriteResult } from "./result.js";
|
|
24
|
+
import type { SgpClientConfig, SgpFile } from "./transport.js";
|
|
25
|
+
/** Methods that hit the `/api/ura/` routes. All are reads, except `openTicket`: a write that returns an {@link SgpWriteResult}. */
|
|
26
|
+
export interface UraClient {
|
|
27
|
+
/**
|
|
28
|
+
* @experimental Lists annotations: `GET /api/ura/cliente/anotacao/list/`, with local identity selection.
|
|
29
|
+
* Requires positive safe-integer `cliente_id` and/or `contrato_id`; both mean AND.
|
|
30
|
+
* Returns matching notes present in one SGP response; source completeness is not guaranteed while this method is experimental.
|
|
31
|
+
* The bulk upstream body enters SDK memory but is never returned, logged or cached by the SDK.
|
|
32
|
+
* Use only on a trusted server; authorize requested IDs. Injected fetch/tracing must not capture
|
|
33
|
+
* the upstream body. Omit note text/staff identity with `annotationPersonalKeys` before logging.
|
|
34
|
+
* The public API and local validation/selection remain when upstream filtering is fixed.
|
|
35
|
+
*/
|
|
36
|
+
listAnnotations: (params: ListAnnotationsParams) => Promise<SgpResult<ListAnnotationsResponse>>;
|
|
37
|
+
/**
|
|
38
|
+
* Lists clients, one page at a time: `POST /api/ura/clientes/`.
|
|
39
|
+
*
|
|
40
|
+
* Filter with `cliente_id`, `cpfcnpj` or `cliente_nome`; page with `offset` and `limit`.
|
|
41
|
+
*/
|
|
42
|
+
listClients: (params?: ListClientsParams) => Promise<SgpResult<ListClientsResponse>>;
|
|
43
|
+
/**
|
|
44
|
+
* Looks up a customer and its contracts: `POST /api/ura/consultacliente/`.
|
|
45
|
+
*
|
|
46
|
+
* Requires at least one of `cpfcnpj`, `contrato`, `nome`, `login` or `telefone`. Each contract
|
|
47
|
+
* carries secrets (Central and PPPoE credentials, Wi-Fi, MACs, payoff link) and personal data;
|
|
48
|
+
* strip them with `omitSensitive` and the exported key tuples before logging or forwarding.
|
|
49
|
+
*/
|
|
50
|
+
lookupCustomer: (params: LookupCustomerParams) => Promise<SgpResult<LookupCustomerResponse>>;
|
|
51
|
+
/**
|
|
52
|
+
* Lists contract summaries: `POST /api/ura/listacontrato/`.
|
|
53
|
+
*
|
|
54
|
+
* Filter with `contrato`, `plano`, `tipo` or `status`. Without any filter the response may
|
|
55
|
+
* carry the whole contract base. Results contain personal data (name, CPF/CNPJ, e-mail, phone,
|
|
56
|
+
* status reason); strip it with `omitSensitive` and the exported key tuples before logging or
|
|
57
|
+
* forwarding.
|
|
58
|
+
*/
|
|
59
|
+
listContracts: (params?: ListContractsParams) => Promise<SgpResult<ListContractsResponse>>;
|
|
60
|
+
/**
|
|
61
|
+
* Lists service orders (OS), one page at a time: `POST /api/ura/ordemservico/list/`.
|
|
62
|
+
*
|
|
63
|
+
* Filter with `ordem_servico`, `status`, `pop`, `motivo` or `contrato`; page with `offset` and
|
|
64
|
+
* `limit`. Results contain personal data (customer name, free-text content); strip it with
|
|
65
|
+
* `omitSensitive` and the exported key tuples before logging or forwarding.
|
|
66
|
+
*/
|
|
67
|
+
listServiceOrders: (params?: ListServiceOrdersParams) => Promise<SgpResult<ListServiceOrdersResponse>>;
|
|
68
|
+
/** Lists the plan catalog: `GET /api/ura/consultaplano/`. Takes no parameters. */
|
|
69
|
+
listPlans: () => Promise<SgpResult<ListPlansResponse>>;
|
|
70
|
+
/** Lists the occurrence methods: `GET /api/ura/ocorrencia/metodo/list/`. Takes no parameters. */
|
|
71
|
+
listOccurrenceMethods: () => Promise<SgpResult<ListOccurrenceMethodsResponse>>;
|
|
72
|
+
/**
|
|
73
|
+
* Lists invoices (titulos), one page at a time: `POST /api/ura/titulos/`.
|
|
74
|
+
*
|
|
75
|
+
* Filter with `contrato`, `cliente_id`, `cpfcnpj`, `titulo_id`, `status`, `portador` or the date
|
|
76
|
+
* ranges; order with `ordenar` and `ordenar_ordem`; page with `offset` and `limit`. Results
|
|
77
|
+
* contain personal data (customer name, CPF/CNPJ, statement text) and payment links and PIX
|
|
78
|
+
* codes that may resolve to the debtor; strip them with `omitSensitive` and the exported key
|
|
79
|
+
* tuples before logging or forwarding.
|
|
80
|
+
*/
|
|
81
|
+
listInvoices: (params?: ListInvoicesParams) => Promise<SgpResult<ListInvoicesResponse>>;
|
|
82
|
+
/** Lists the POPs (points of presence): `POST /api/ura/pops/`. Takes no parameters. */
|
|
83
|
+
listPops: () => Promise<SgpResult<ListPopsResponse>>;
|
|
84
|
+
/**
|
|
85
|
+
* Lists the NAS (network access servers) and the POPs each serves: `POST /api/ura/nas/list/`.
|
|
86
|
+
* Takes no parameters.
|
|
87
|
+
*
|
|
88
|
+
* `endereco_ip` is network infrastructure; strip it with `omitSensitive` and `nasSecretKeys`
|
|
89
|
+
* before logging or forwarding.
|
|
90
|
+
*/
|
|
91
|
+
listNas: () => Promise<SgpResult<ListNasResponse>>;
|
|
92
|
+
/** Lists the payment carriers (portadores): `GET /api/ura/portador/`. Takes no parameters. */
|
|
93
|
+
listPaymentCarriers: () => Promise<SgpResult<ListPaymentCarriersResponse>>;
|
|
94
|
+
/**
|
|
95
|
+
* Checks installation viability around a coordinate: `GET /api/ura/viabilidadeinstalacao`.
|
|
96
|
+
*
|
|
97
|
+
* The SDK does not geocode: the consumer supplies `coordenada` (`"lat,lng"`), the map `gateway`
|
|
98
|
+
* ID (from `/api/ura/listgatewaymapa`) and the `raio` in meters. The answer is keyed by the gateway's name and
|
|
99
|
+
* holds the CTOs within the radius, or `"Localização inviável"` when there are none.
|
|
100
|
+
*
|
|
101
|
+
* A malformed gateway answer (an entry that is neither CTOs nor a message) is `SCHEMA_MISMATCH`.
|
|
102
|
+
*/
|
|
103
|
+
checkCoverage: (params: CheckCoverageParams) => Promise<SgpResult<CheckCoverageResponse>>;
|
|
104
|
+
/**
|
|
105
|
+
* Opens a ticket on a contract: `POST /api/ura/chamado/`. Opens an occurrence and, unless
|
|
106
|
+
* `desativa_os: 1`, a service order; `data_hora_agendamento` (`"AAAA-MM-DD HH:MM"`) schedules it.
|
|
107
|
+
*
|
|
108
|
+
* Requires `contrato`. To schedule an installation, send `motivoos` with your instance's
|
|
109
|
+
* installation reason code (see `os.listOccurrenceReasons`) and `data_hora_agendamento`. Success is `status` 1 with a `protocolo`; the response carries the
|
|
110
|
+
* customer's name and CPF/CNPJ: strip them with `omitSensitive` and `ticketOpenedPersonalKeys`
|
|
111
|
+
* before logging or forwarding. `contato_nome` and `contato_telefone` in the params are personal
|
|
112
|
+
* data.
|
|
113
|
+
*
|
|
114
|
+
* Never retried by the SDK. With `outcome: "unknown"`, check the state in SGP before repeating.
|
|
115
|
+
*/
|
|
116
|
+
openTicket: (params: OpenTicketParams) => Promise<SgpWriteResult<OpenTicketResponse>>;
|
|
117
|
+
}
|
|
118
|
+
/** Methods that hit the `/api/os/` routes. */
|
|
119
|
+
export interface OsClient {
|
|
120
|
+
/** Lists the occurrence types of service orders (OS): `GET /api/os/ocorrencia/tipo/list/`. Takes no parameters. */
|
|
121
|
+
listOccurrenceTypes: () => Promise<SgpResult<ListOccurrenceTypesResponse>>;
|
|
122
|
+
/** Lists the occurrence reasons of service orders (OS): `GET /api/os/ocorrencia/motivo/list/`. Takes no parameters. */
|
|
123
|
+
listOccurrenceReasons: () => Promise<SgpResult<ListOccurrenceReasonsResponse>>;
|
|
124
|
+
}
|
|
125
|
+
/** Methods that hit the `/api/precadastro/` routes. */
|
|
126
|
+
export interface PrecadastroClient {
|
|
127
|
+
/** Lists the due days offered at pre-registration: `POST /api/precadastro/vencimento/list`. Takes no parameters. */
|
|
128
|
+
listDueDays: () => Promise<SgpResult<ListDueDaysResponse>>;
|
|
129
|
+
/**
|
|
130
|
+
* Lists the sellers (vendedores): `POST /api/precadastro/vendedor/list`. Takes no parameters.
|
|
131
|
+
*
|
|
132
|
+
* Used for `vendedor_id` when creating contracts (v1.1). Sellers are employees: name, CPF and
|
|
133
|
+
* e-mail are personal data; strip them with `omitSensitive` and `sellerPersonalKeys` before
|
|
134
|
+
* logging or forwarding.
|
|
135
|
+
*/
|
|
136
|
+
listSellers: () => Promise<SgpResult<ListSellersResponse>>;
|
|
137
|
+
}
|
|
138
|
+
/** Methods that hit the `/api/crm/` routes. Writes: they return an {@link SgpWriteResult}. */
|
|
139
|
+
export interface CrmClient {
|
|
140
|
+
/**
|
|
141
|
+
* Creates an individual (PF) customer: `POST /api/crm/cliente/F`.
|
|
142
|
+
*
|
|
143
|
+
* Requires `nome`, `cpfcnpj` and `endereco`; the address is sent nested and as loose fields.
|
|
144
|
+
* The response `message` carries the name and CPF; strip it with `omitSensitive` and
|
|
145
|
+
* `customerCreatedPersonalKeys` before logging or forwarding.
|
|
146
|
+
*
|
|
147
|
+
* Never retried by the SDK. With `outcome: "unknown"`, check the state in SGP before repeating.
|
|
148
|
+
*/
|
|
149
|
+
createIndividualCustomer: (params: CreateIndividualCustomerParams) => Promise<SgpWriteResult<CreateCustomerResponse>>;
|
|
150
|
+
/**
|
|
151
|
+
* Creates a company (PJ) customer: `POST /api/crm/cliente/J`.
|
|
152
|
+
*
|
|
153
|
+
* Requires `nome`, `cpfcnpj` and `endereco`; the address is sent nested and as loose fields.
|
|
154
|
+
* The response `message` carries the name and CNPJ; strip it with `omitSensitive` and
|
|
155
|
+
* `customerCreatedPersonalKeys` before logging or forwarding.
|
|
156
|
+
*
|
|
157
|
+
* Never retried by the SDK. With `outcome: "unknown"`, check the state in SGP before repeating.
|
|
158
|
+
*/
|
|
159
|
+
createCompanyCustomer: (params: CreateCompanyCustomerParams) => Promise<SgpWriteResult<CreateCustomerResponse>>;
|
|
160
|
+
/**
|
|
161
|
+
* Creates a contract on a CRM customer: `POST /api/crm/cliente/{cliente_id}/contratos/`.
|
|
162
|
+
*
|
|
163
|
+
* Requires `pop_id`, `plano_id`, `portador_id`, `forma_cobranca_codigo` (`formaCobrancaCodigo`),
|
|
164
|
+
* `vencimento_dia` and both addresses: `endereco_instalacao` and `endereco_cobranca`, sent
|
|
165
|
+
* nested; the installation one also goes as loose fields. SGP requires `login` and `senha`
|
|
166
|
+
* (PPPoE) for an internet service. The params carry secrets (`login`, `senha`, `central_login`,
|
|
167
|
+
* `central_senha`): never log them. The response `cliente` is the customer's name; strip it with
|
|
168
|
+
* `omitSensitive` and `contractCreatedPersonalKeys` before logging or forwarding.
|
|
169
|
+
*
|
|
170
|
+
* The loose address fields carry the installation address. A billing address different from the
|
|
171
|
+
* installation one has not been verified live. `error.detail` is SGP's text and may echo submitted
|
|
172
|
+
* values (e.g. `senha`): treat it as sensitive before logging.
|
|
173
|
+
*
|
|
174
|
+
* `os_instalacao` opens the installation service order without a date; to schedule one, use
|
|
175
|
+
* `ura.openTicket`. The boleto delivery methods and the invoice (nota fiscal) are not in the
|
|
176
|
+
* API: they stay empty.
|
|
177
|
+
*
|
|
178
|
+
* Never retried by the SDK. With `outcome: "unknown"`, check the state in SGP before repeating.
|
|
179
|
+
*/
|
|
180
|
+
createContract: (clienteId: number, params: CreateContractParams) => Promise<SgpWriteResult<CreateContractResponse>>;
|
|
181
|
+
/**
|
|
182
|
+
* Sets the CRM status of a customer: `POST /api/crm/cliente/{cliente_id}/status/`.
|
|
183
|
+
*
|
|
184
|
+
* Set `crmStatus.contratoRealizadoNoSgp` after the contract, or SGP's screen keeps the customer
|
|
185
|
+
* as a CRM customer and blocks contract status changes. The response `message` carries the
|
|
186
|
+
* customer's name; strip it with `omitSensitive` and `customerStatusPersonalKeys` before
|
|
187
|
+
* logging or forwarding.
|
|
188
|
+
*
|
|
189
|
+
* Never retried by the SDK. With `outcome: "unknown"`, check the state in SGP before repeating.
|
|
190
|
+
*/
|
|
191
|
+
updateCustomerStatus: (clienteId: number, params: UpdateCustomerStatusParams) => Promise<SgpWriteResult<UpdateCustomerStatusResponse>>;
|
|
192
|
+
}
|
|
193
|
+
/** Methods that hit the `/api/suporte/` routes. */
|
|
194
|
+
export interface SuporteClient {
|
|
195
|
+
/**
|
|
196
|
+
* Attaches a document to a customer: `PUT /api/suporte/cliente/{cliente_id}/documento/add/`,
|
|
197
|
+
* sent as multipart with the file in the `file` part.
|
|
198
|
+
*
|
|
199
|
+
* SGP answers 200 with an empty body and does not return the document ID: `data` is `null`. To
|
|
200
|
+
* check the upload, use `listCustomerDocuments`. SGP converts images to `.jpeg`, so the stored
|
|
201
|
+
* file name may differ from `file.filename`. `descricao` is personal data when it names the
|
|
202
|
+
* customer.
|
|
203
|
+
*
|
|
204
|
+
* Never retried by the SDK. With `outcome: "unknown"`, check the state in SGP before repeating.
|
|
205
|
+
*/
|
|
206
|
+
addCustomerDocument: (clienteId: number, file: SgpFile, params?: AddCustomerDocumentParams) => Promise<SgpWriteResult<AddCustomerDocumentResponse>>;
|
|
207
|
+
/**
|
|
208
|
+
* Lists the documents attached to a customer: `GET /api/suporte/cliente/{cliente_id}/documento/list/`.
|
|
209
|
+
*
|
|
210
|
+
* Each document carries the file name or link (`arquivo`), its description and the operator:
|
|
211
|
+
* personal data; strip it with `omitSensitive` and `customerDocumentPersonalKeys` before logging
|
|
212
|
+
* or forwarding.
|
|
213
|
+
*/
|
|
214
|
+
listCustomerDocuments: (clienteId: number) => Promise<SgpResult<ListCustomerDocumentsResponse>>;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* SGP client. Reads return an {@link SgpResult}, writes (`crm`, `ura.openTicket`,
|
|
218
|
+
* `suporte.addCustomerDocument`) an {@link SgpWriteResult}; no method ever throws.
|
|
219
|
+
*/
|
|
220
|
+
export interface SgpClient {
|
|
221
|
+
ura: UraClient;
|
|
222
|
+
os: OsClient;
|
|
223
|
+
precadastro: PrecadastroClient;
|
|
224
|
+
crm: CrmClient;
|
|
225
|
+
suporte: SuporteClient;
|
|
226
|
+
}
|
|
227
|
+
/** Creates an SGP client bound to `config`; `token` and `app` are sent on every request. */
|
|
228
|
+
export declare const createSgpClient: (config: SgpClientConfig) => SgpClient;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { SgpResult, SgpWriteResult } from "./result.js";
|
|
3
|
+
import { type ParamValue, type RequestSpec, type SgpClientConfig, type SgpFile } from "./transport.js";
|
|
4
|
+
/** Static description of one SGP route: how to call it, how to parse it and what is sensitive. */
|
|
5
|
+
export interface EndpointDefinition<S extends z.ZodType> {
|
|
6
|
+
method: "GET" | "POST";
|
|
7
|
+
/** Request path starting with `/`; also the `endpoint` of every error. */
|
|
8
|
+
path: string;
|
|
9
|
+
schema: S;
|
|
10
|
+
/** Normalized paths of the required, strict fields (see `parseResponse`). */
|
|
11
|
+
keyFields: readonly string[];
|
|
12
|
+
/** Normalized path of the response items that carry sensitive keys, e.g. `clientes[]`. */
|
|
13
|
+
itemPath: string;
|
|
14
|
+
/** Keys of an item holding secrets (passwords, MACs, links with embedded token). */
|
|
15
|
+
secretKeys: readonly string[];
|
|
16
|
+
/** Keys of an item holding personal data (CPF/CNPJ, phone, e-mail, address, name). */
|
|
17
|
+
personalKeys: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Static description of one SGP write route. Like {@link EndpointDefinition}, but `schema` is the
|
|
21
|
+
* success body: a 2xx only counts as success when it validates (key fields present, right type).
|
|
22
|
+
*/
|
|
23
|
+
export interface WriteEndpointDefinition<S extends z.ZodType> {
|
|
24
|
+
kind: "write";
|
|
25
|
+
method: "POST" | "PUT";
|
|
26
|
+
/** Request path template, e.g. `/api/crm/cliente/{cliente_id}/contratos/`; also the `endpoint` of every error. */
|
|
27
|
+
path: string;
|
|
28
|
+
schema: S;
|
|
29
|
+
/** Normalized paths of the required, strict fields (see `parseResponse`). */
|
|
30
|
+
keyFields: readonly string[];
|
|
31
|
+
/** Normalized path of the response items that carry sensitive keys. */
|
|
32
|
+
itemPath: string;
|
|
33
|
+
/** Keys of an item holding secrets. */
|
|
34
|
+
secretKeys: readonly string[];
|
|
35
|
+
/** Keys of an item holding personal data. */
|
|
36
|
+
personalKeys: readonly string[];
|
|
37
|
+
}
|
|
38
|
+
/** Inputs of one write call: values for the path placeholders, the request params and any files. */
|
|
39
|
+
export interface WriteCall {
|
|
40
|
+
pathParams?: Record<string, string | number>;
|
|
41
|
+
params?: Record<string, ParamValue | undefined>;
|
|
42
|
+
files?: Record<string, SgpFile>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Sends the request described by `def` and parses the response with its schema.
|
|
46
|
+
*
|
|
47
|
+
* Never throws: transport and HTTP failures come back as `{ success: false, error }` and a body
|
|
48
|
+
* that does not match the schema as `SCHEMA_MISMATCH`.
|
|
49
|
+
*/
|
|
50
|
+
export declare const callEndpoint: <S extends z.ZodType>(config: SgpClientConfig, def: EndpointDefinition<S>, params?: RequestSpec["params"], pathParams?: RequestSpec["pathParams"]) => Promise<SgpResult<z.output<S>>>;
|
|
51
|
+
/**
|
|
52
|
+
* Sends the write described by `def` and tells whether SGP applied it.
|
|
53
|
+
*
|
|
54
|
+
* Never throws. Success is a 2xx whose body validates against `def.schema`. A failure carries an
|
|
55
|
+
* `outcome`:
|
|
56
|
+
* - `"not_applied"`: SGP answered 4xx and rejected the request, or the SDK rejected it locally before
|
|
57
|
+
* sending (invalid path params, `VALIDATION` with status 0);
|
|
58
|
+
* - `"unknown"`: no response (timeout, network), 5xx, 3xx (redirects are never followed), a 4xx
|
|
59
|
+
* whose body `errors` is an array (SGP's generic exception wrapper, except 401/403/404/405/422),
|
|
60
|
+
* or a 2xx that is not a valid success (empty or non-JSON body, key field missing). The 2xx case
|
|
61
|
+
* is a `VALIDATION` error with the real HTTP status and, for a JSON body, SGP's own text
|
|
62
|
+
* (`detail`/`msg`/`errors`/`error`) or else the failing paths.
|
|
63
|
+
*
|
|
64
|
+
* Never retried by the SDK. With `outcome: "unknown"`, check the state in SGP before repeating.
|
|
65
|
+
*/
|
|
66
|
+
export declare const callWriteEndpoint: <S extends z.ZodType>(config: SgpClientConfig, def: WriteEndpointDefinition<S>, call?: WriteCall) => Promise<SgpWriteResult<z.output<S>>>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Address as SGP takes it. Pass it once: the SDK serializes it both nested (`endereco`) and as
|
|
3
|
+
* loose fields (`logradouro`, `numero`, ...), which are the two formats the CRM routes read.
|
|
4
|
+
*/
|
|
5
|
+
export interface SgpAddress {
|
|
6
|
+
logradouro: string;
|
|
7
|
+
numero?: string | number;
|
|
8
|
+
complemento?: string;
|
|
9
|
+
bairro: string;
|
|
10
|
+
cidade: string;
|
|
11
|
+
cep: string;
|
|
12
|
+
uf: string;
|
|
13
|
+
pais?: string;
|
|
14
|
+
pontoreferencia?: string;
|
|
15
|
+
/** Map position, `"lat,lng"`. */
|
|
16
|
+
map_ll?: string;
|
|
17
|
+
condominio?: string | number;
|
|
18
|
+
}
|
|
19
|
+
/** The address as a plain record with the same keys and no `undefined` ones. */
|
|
20
|
+
export declare const flatAddress: (address: SgpAddress) => Record<string, string | number>;
|