@pimia/sdk 0.21.0 → 0.27.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 +80 -0
- package/dist/api.d.ts +1020 -116
- package/dist/central-api.d.ts +1928 -0
- package/dist/central-api.js +9 -0
- package/dist/central.d.ts +607 -0
- package/dist/central.js +257 -0
- package/dist/client.d.ts +261 -1
- package/dist/client.js +212 -2
- package/dist/errors.d.ts +11 -0
- package/dist/errors.js +24 -0
- package/dist/index.d.ts +13 -3
- package/dist/index.js +11 -2
- package/dist/tokens.d.ts +45 -0
- package/dist/tokens.js +53 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -63,6 +63,53 @@ cliente exige un `TokenStore` en lugar de un string: persiste el conjunto de
|
|
|
63
63
|
tokens tras cada refresco y no refresques dos veces en paralelo con el mismo
|
|
64
64
|
token. Las dos cosas las cubre el SDK si lo usas como está pensado.
|
|
65
65
|
|
|
66
|
+
## Un servicio que reenvía el token de su usuario
|
|
67
|
+
|
|
68
|
+
Todo lo de arriba supone que **tu app posee un grant**. Hay integraciones que no
|
|
69
|
+
y que no deben: un servicio al que el front le manda, en cada petición, el
|
|
70
|
+
`Authorization` del usuario que ya entró en Pimia. Para ésas está el modo de
|
|
71
|
+
token prestado — sin `clientId`, sin `TokenStore` y sin ceremonia OAuth:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
const pimia = PimiaClient.withBorrowedToken({
|
|
75
|
+
baseUrl: `https://${tenant}.pimia.es`,
|
|
76
|
+
accessToken: bearerDeQuienLlama,
|
|
77
|
+
// La empresa activa viaja en cabecera, como en todo el API. OMÍTELA cuando no
|
|
78
|
+
// la sepas: `company:` vacía es una cabecera presente que no casa con ninguna
|
|
79
|
+
// empresa.
|
|
80
|
+
headers: empresa === null ? {} : { company: String(empresa) },
|
|
81
|
+
// Atiendes una petición web: los reintentos del SDK ESPERAN, y esperar dentro
|
|
82
|
+
// de la petición de un usuario es una petición colgada.
|
|
83
|
+
maxRateLimitRetries: 0,
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
const empresaActiva = await pimia.bootstrap.currentCompanyId()
|
|
87
|
+
const censo = await pimia.crm.assignableUsers()
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Lo que ganas con esto es que **Pimia sigue decidiendo los permisos**: tu servicio
|
|
91
|
+
no puede darle a nadie más de lo que su token ya le daba, y no hay una
|
|
92
|
+
credencial de servicio que auditar aparte.
|
|
93
|
+
|
|
94
|
+
Tres cosas que conviene tener claras:
|
|
95
|
+
|
|
96
|
+
- **Un cliente por petición.** El token vive lo que viva la petición que lo
|
|
97
|
+
trajo; una instancia compartida es una credencial compartida.
|
|
98
|
+
- **No se refresca.** El refresh es del dueño del grant. Cuando el token caduca,
|
|
99
|
+
el 401 sube como `UnauthorizedError` y quien tiene que conseguir otro es quien
|
|
100
|
+
te lo prestó. El cliente no lo intenta —y eso es deliberado: con la rotación
|
|
101
|
+
de Pimia, tocar el refresh de otro revoca su grant entero.
|
|
102
|
+
- **`pimia.oauth` es `null`** en este modo. No hay ceremonia que hacer, y un
|
|
103
|
+
`OAuth` sin `clientId` compondría una URL de autorización rota que sólo
|
|
104
|
+
fallaría en el navegador del usuario.
|
|
105
|
+
|
|
106
|
+
`GET /bootstrap` merece un aviso propio: **es la única respuesta del API que no
|
|
107
|
+
viene envuelta en `data`**. Sus claves cuelgan de la raíz, así que un
|
|
108
|
+
desenvolvedor de `data` escrito «para todas las llamadas» devuelve vacío sin
|
|
109
|
+
error — y el fallo se ve como una empresa sin resolver o como una moneda que cae
|
|
110
|
+
al respaldo, nunca como un fallo. `pimia.bootstrap.currentCompanyId()` y
|
|
111
|
+
`.currency()` lo leen bien; `.get()` te da el cuerpo tal cual.
|
|
112
|
+
|
|
66
113
|
## Reintentar un `POST` sin duplicar
|
|
67
114
|
|
|
68
115
|
Manda una `Idempotency-Key` única por operación y Pimia ejecuta la escritura
|
|
@@ -199,6 +246,39 @@ Detalles que ahorran un rato:
|
|
|
199
246
|
- `signWebhook()` firma un cuerpo como lo haría Pimia: úsalo en **tus tests**,
|
|
200
247
|
no en producción.
|
|
201
248
|
|
|
249
|
+
## El plano central: la cartera del integrador
|
|
250
|
+
|
|
251
|
+
Si eres integrador (una cuenta de **desarrollador** en Pimia), tu cartera, tus
|
|
252
|
+
clients OAuth, las invitaciones, el patrocinio y el traspaso viven en el
|
|
253
|
+
**plano central** (`https://pimia.es/api`), no en la API de un tenant. Es otro
|
|
254
|
+
cliente y otra credencial: el **token personal** de tu cuenta, no un token
|
|
255
|
+
OAuth de instancia.
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
import { PimiaCentralClient, MissingAbilityError } from '@pimia/sdk'
|
|
259
|
+
|
|
260
|
+
const central = new PimiaCentralClient({
|
|
261
|
+
baseUrl: 'https://pimia.es',
|
|
262
|
+
token: () => process.env.PIMIA_CENTRAL_TOKEN!,
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
const { data } = await central.overview() // tu cartera, con la atribución
|
|
266
|
+
await central.invitations.create({ // el cliente nace dueño; pagas tú
|
|
267
|
+
email: 'ana@talleres-ana.es',
|
|
268
|
+
company_name: 'Talleres Ana',
|
|
269
|
+
billing: 'sponsor',
|
|
270
|
+
})
|
|
271
|
+
await central.sponsorship.sponsor({ tenant_slug: 'talleres-ana', plan_id: 6 })
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
El token está acotado por plano: `desarrollador` abre `/desarrollador/*` y
|
|
275
|
+
`central` abre invitaciones, patrocinio y traspaso. Si al tuyo le falta una,
|
|
276
|
+
la llamada lanza `MissingAbilityError` con `ability` diciendo cuál. Lo que el
|
|
277
|
+
plano central NO da es contenido fiscal de ningún cliente: a los datos de una
|
|
278
|
+
instancia se llega por OAuth consentido, con `PimiaClient`.
|
|
279
|
+
|
|
280
|
+
Los tipos salen de `spec/pimia-central-v1.json` (`@pimia/sdk/central-api`).
|
|
281
|
+
|
|
202
282
|
## Más
|
|
203
283
|
|
|
204
284
|
Documentación completa, modelo mental (un tenant = una base URL = un token),
|