@pimia/sdk 0.4.0 → 0.5.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/dist/client.d.ts CHANGED
@@ -112,6 +112,19 @@ export interface ResponseWithMeta<T> {
112
112
  }
113
113
  /** Lo que se puede afinar en una escritura (`post`/`put`/`patch`). */
114
114
  export type WriteOptions = Pick<RequestOptions, 'headers' | 'query' | 'signal' | 'idempotencyKey'>;
115
+ /**
116
+ * Lo que se puede afinar en una lectura (`get`/`delete` y los atajos de
117
+ * recurso).
118
+ *
119
+ * Sin `idempotencyKey`, que no significa nada en una lectura, y sin `query`,
120
+ * que en `get()` ya es un parámetro propio.
121
+ *
122
+ * Existe sobre todo por `signal`: hasta la 0.4 los atajos de lectura no
123
+ * aceptaban opciones, así que ponerle un timeout a un GET obligaba a bajar a
124
+ * `request()` — o a quedarse sin él, que es lo que pasa de verdad. Un cliente
125
+ * que sondea y se cuelga en una lectura deja de sondear sin dar un solo error.
126
+ */
127
+ export type ReadOptions = Pick<RequestOptions, 'headers' | 'signal'>;
115
128
  export declare class PimiaClient {
116
129
  readonly oauth: OAuth;
117
130
  private readonly baseUrl;
@@ -128,13 +141,13 @@ export declare class PimiaClient {
128
141
  /** Cabeceras `X-RateLimit-*` de la última respuesta. */
129
142
  get rateLimit(): RateLimit;
130
143
  get invoices(): {
131
- list: (query?: RequestOptions["query"]) => Promise<{
144
+ list: (query?: RequestOptions["query"], options?: ReadOptions) => Promise<{
132
145
  data: components["schemas"]["InvoiceResource"][];
133
146
  meta: {
134
147
  invoice_total_count: number;
135
148
  };
136
149
  }>;
137
- get: (id: number | string) => Promise<{
150
+ get: (id: number | string, options?: ReadOptions) => Promise<{
138
151
  data: components["schemas"]["InvoiceResource"] & Record<string, never>;
139
152
  }>;
140
153
  /**
@@ -314,13 +327,13 @@ export declare class PimiaClient {
314
327
  }>>;
315
328
  };
316
329
  get customers(): {
317
- list: (query?: RequestOptions["query"]) => Promise<{
330
+ list: (query?: RequestOptions["query"], options?: ReadOptions) => Promise<{
318
331
  data: components["schemas"]["CustomerResource"][];
319
332
  meta: {
320
333
  customer_total_count: number;
321
334
  };
322
335
  }>;
323
- get: (id: number | string) => Promise<{
336
+ get: (id: number | string, options?: ReadOptions) => Promise<{
324
337
  data: components["schemas"]["CustomerResource"];
325
338
  }>;
326
339
  create: (body: CustomerRequest, options?: WriteOptions) => Promise<{
@@ -366,13 +379,13 @@ export declare class PimiaClient {
366
379
  }>>;
367
380
  };
368
381
  get estimates(): {
369
- list: (query?: RequestOptions["query"]) => Promise<{
382
+ list: (query?: RequestOptions["query"], options?: ReadOptions) => Promise<{
370
383
  data: components["schemas"]["EstimateResource"][];
371
384
  meta: {
372
385
  estimate_total_count: number;
373
386
  };
374
387
  }>;
375
- get: (id: number | string) => Promise<{
388
+ get: (id: number | string, options?: ReadOptions) => Promise<{
376
389
  data: components["schemas"]["EstimateResource"];
377
390
  }>;
378
391
  create: (body: EstimatesRequest, options?: WriteOptions) => Promise<{
@@ -396,9 +409,24 @@ export declare class PimiaClient {
396
409
  * `estimate:{id}:invoice`— y el reintento tras un timeout no te creará
397
410
  * una segunda factura.
398
411
  *
412
+ * Y manda `externalRef` si la venta nació en tu sistema: es lo que hace
413
+ * que `invoice.created` e `invoice.paid` te lleguen con tu referencia en
414
+ * vez de con `null`. **Tiene que ir aquí, en la conversión**; etiquetar
415
+ * después con `PUT /invoices/{id}` llega tarde por dos motivos: para
416
+ * entonces `invoice.created` ya salió con la referencia nula, y entre las
417
+ * dos llamadas hay una ventana en la que la factura existe y no la
418
+ * encuentras por tu referencia.
419
+ *
420
+ * Va como opción y no como segundo parámetro para no romperle la llamada
421
+ * a quien ya hace `convertToInvoice(id, { idempotencyKey })`: el cuerpo lo
422
+ * monta el atajo, y `external_ref` es además el único campo que el
423
+ * endpoint acepta.
424
+ *
399
425
  * Exige `estimates:write` **e** `invoices:write`.
400
426
  */
401
- convertToInvoice: (id: number | string, options?: WriteOptions) => Promise<ResourceEnvelope<{
427
+ convertToInvoice: (id: number | string, options?: WriteOptions & {
428
+ externalRef?: string | null;
429
+ }) => Promise<ResourceEnvelope<{
402
430
  id: string;
403
431
  invoice_date: string;
404
432
  due_date: string;
@@ -484,11 +512,11 @@ export declare class PimiaClient {
484
512
  currency?: components["schemas"]["CurrencyResource"];
485
513
  }>>;
486
514
  };
487
- get<T = unknown>(path: string, query?: RequestOptions['query']): Promise<T>;
515
+ get<T = unknown>(path: string, query?: RequestOptions['query'], options?: ReadOptions): Promise<T>;
488
516
  post<T = unknown>(path: string, body?: unknown, options?: WriteOptions): Promise<T>;
489
517
  put<T = unknown>(path: string, body?: unknown, options?: WriteOptions): Promise<T>;
490
518
  patch<T = unknown>(path: string, body?: unknown, options?: WriteOptions): Promise<T>;
491
- delete<T = unknown>(path: string): Promise<T>;
519
+ delete<T = unknown>(path: string, options?: ReadOptions): Promise<T>;
492
520
  /**
493
521
  * Petición cruda contra `/api/v1`. `path` puede llevar el prefijo o no:
494
522
  * `/invoices` y `/api/v1/invoices` son lo mismo.
package/dist/client.js CHANGED
@@ -44,8 +44,8 @@ export class PimiaClient {
44
44
  }
45
45
  get invoices() {
46
46
  return {
47
- list: (query) => this.get('/invoices', query),
48
- get: (id) => this.get(`/invoices/${id}`),
47
+ list: (query, options) => this.get('/invoices', query, options),
48
+ get: (id, options) => this.get(`/invoices/${id}`, undefined, options),
49
49
  /**
50
50
  * Devuelve `{ data: InvoiceResource }`. El tipo NO sale del spec: el
51
51
  * `200` de `invoices.store` está vacío ahí (ver {@link ResourceEnvelope}).
@@ -57,8 +57,8 @@ export class PimiaClient {
57
57
  }
58
58
  get customers() {
59
59
  return {
60
- list: (query) => this.get('/customers', query),
61
- get: (id) => this.get(`/customers/${id}`),
60
+ list: (query, options) => this.get('/customers', query, options),
61
+ get: (id, options) => this.get(`/customers/${id}`, undefined, options),
62
62
  create: (body, options) => this.post('/customers', body, options),
63
63
  /** El `200` de `customers.update` no está tipado en el spec. */
64
64
  update: (id, body, options) => this.put(`/customers/${id}`, body, options),
@@ -66,8 +66,8 @@ export class PimiaClient {
66
66
  }
67
67
  get estimates() {
68
68
  return {
69
- list: (query) => this.get('/estimates', query),
70
- get: (id) => this.get(`/estimates/${id}`),
69
+ list: (query, options) => this.get('/estimates', query, options),
70
+ get: (id, options) => this.get(`/estimates/${id}`, undefined, options),
71
71
  create: (body, options) => this.post('/estimates', body, options),
72
72
  /**
73
73
  * Convierte un presupuesto aceptado en factura.
@@ -87,13 +87,33 @@ export class PimiaClient {
87
87
  * `estimate:{id}:invoice`— y el reintento tras un timeout no te creará
88
88
  * una segunda factura.
89
89
  *
90
+ * Y manda `externalRef` si la venta nació en tu sistema: es lo que hace
91
+ * que `invoice.created` e `invoice.paid` te lleguen con tu referencia en
92
+ * vez de con `null`. **Tiene que ir aquí, en la conversión**; etiquetar
93
+ * después con `PUT /invoices/{id}` llega tarde por dos motivos: para
94
+ * entonces `invoice.created` ya salió con la referencia nula, y entre las
95
+ * dos llamadas hay una ventana en la que la factura existe y no la
96
+ * encuentras por tu referencia.
97
+ *
98
+ * Va como opción y no como segundo parámetro para no romperle la llamada
99
+ * a quien ya hace `convertToInvoice(id, { idempotencyKey })`: el cuerpo lo
100
+ * monta el atajo, y `external_ref` es además el único campo que el
101
+ * endpoint acepta.
102
+ *
90
103
  * Exige `estimates:write` **e** `invoices:write`.
91
104
  */
92
- convertToInvoice: (id, options) => this.post(`/estimates/${id}/convert-to-invoice`, {}, options),
105
+ convertToInvoice: (id, options) => {
106
+ const { externalRef, ...resto } = options ?? {};
107
+ return this.post(`/estimates/${id}/convert-to-invoice`,
108
+ // Cuerpo vacío si no se pide, y no `external_ref: null`: mandar el
109
+ // null explícito DESVINCULA la referencia, que no es lo mismo que no
110
+ // tocarla.
111
+ externalRef === undefined ? {} : { external_ref: externalRef }, resto);
112
+ },
93
113
  };
94
114
  }
95
- get(path, query) {
96
- return this.request(path, { method: 'GET', query });
115
+ get(path, query, options) {
116
+ return this.request(path, { ...options, method: 'GET', query });
97
117
  }
98
118
  post(path, body, options) {
99
119
  return this.request(path, { ...options, method: 'POST', body });
@@ -104,8 +124,8 @@ export class PimiaClient {
104
124
  patch(path, body, options) {
105
125
  return this.request(path, { ...options, method: 'PATCH', body });
106
126
  }
107
- delete(path) {
108
- return this.request(path, { method: 'DELETE' });
127
+ delete(path, options) {
128
+ return this.request(path, { ...options, method: 'DELETE' });
109
129
  }
110
130
  /**
111
131
  * Petición cruda contra `/api/v1`. `path` puede llevar el prefijo o no:
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  * salen los tipos de `./api`.
7
7
  */
8
8
  export { PimiaClient } from './client.js';
9
- export type { CustomerRequest, CustomerResource, EstimateResource, EstimatesRequest, InvoiceResource, InvoicesRequest, PimiaClientOptions, RateLimit, RequestOptions, ResourceEnvelope, ResponseMeta, ResponseWithMeta, WriteOptions, } from './client.js';
9
+ export type { CustomerRequest, CustomerResource, EstimateResource, EstimatesRequest, InvoiceResource, InvoicesRequest, PimiaClientOptions, RateLimit, ReadOptions, RequestOptions, ResourceEnvelope, ResponseMeta, ResponseWithMeta, WriteOptions, } from './client.js';
10
10
  export { OAuth, createPkceChallenge, createState } from './oauth.js';
11
11
  export type { AuthorizationServerMetadata, AuthorizeUrlOptions, OAuthConfig, PkceChallenge, } from './oauth.js';
12
12
  export { MemoryTokenStore, isExpired, tokenSetFromResponse } from './tokens.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pimia/sdk",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Cliente TypeScript de la API de Pimia para apps de partner: OAuth con PKCE, rotación de refresh persistida, reintentos de rate limit y tipos generados del OpenAPI.",
5
5
  "license": "MIT",
6
6
  "author": "Pimia (https://pimia.es)",