From 6b200be8f61ffd6e2876929e122c3647595a51d8 Mon Sep 17 00:00:00 2001 From: Giacomo Debidda Date: Fri, 16 Sep 2022 16:24:21 +0200 Subject: [PATCH] feat(fattureincloud-client): add missing option in listInvoices, improve typings --- .../__tests__/info/clients.test.mjs | 1 - packages/fattureincloud-client/package.json | 14 ++- packages/fattureincloud-client/src/clients.ts | 75 +++++++++++++ .../src/customers/api.ts | 39 +++++-- .../src/customers/clients.ts | 63 +++++++---- packages/fattureincloud-client/src/index.ts | 104 ++++++++++-------- .../fattureincloud-client/src/info/api.ts | 22 +++- .../fattureincloud-client/src/info/clients.ts | 25 ++++- .../fattureincloud-client/src/interfaces.ts | 19 ++-- .../fattureincloud-client/src/invoices/api.ts | 41 +++++-- .../src/invoices/checks.ts | 2 + .../src/invoices/clients.ts | 57 +++++++--- .../fattureincloud-client/src/products/api.ts | 27 ++++- .../src/products/clients.ts | 57 +++++++--- .../fattureincloud-client/src/rate-limit.ts | 21 ++-- 15 files changed, 413 insertions(+), 154 deletions(-) create mode 100644 packages/fattureincloud-client/src/clients.ts diff --git a/packages/fattureincloud-client/__tests__/info/clients.test.mjs b/packages/fattureincloud-client/__tests__/info/clients.test.mjs index e3c1a09f..3d977ba0 100644 --- a/packages/fattureincloud-client/__tests__/info/clients.test.mjs +++ b/packages/fattureincloud-client/__tests__/info/clients.test.mjs @@ -1,4 +1,3 @@ -import { env } from 'process' import { basicClient } from '../../lib/info/clients.js' import { credentials } from '../api-credentials.mjs' diff --git a/packages/fattureincloud-client/package.json b/packages/fattureincloud-client/package.json index 2bb256db..49771f1f 100644 --- a/packages/fattureincloud-client/package.json +++ b/packages/fattureincloud-client/package.json @@ -31,13 +31,16 @@ ".": "./lib/index.js", "./customers": "./lib/customers/clients.js", "./customers/api": "./lib/customers/api.js", + "./error": "./lib/error.js", "./info": "./lib/info/clients.js", "./info/api": "./lib/info/api.js", + "./interfaces": "./lib/interfaces.js", "./invoices": "./lib/invoices/clients.js", "./invoices/api": "./lib/invoices/api.js", "./products": "./lib/products/clients.js", "./products/api": "./lib/products/api.js", - "./package.json": "./package.json" + "./package.json": "./package.json", + "./rate-limit": "./lib/rate-limit.js" }, "typesVersions": { "*": { @@ -47,12 +50,18 @@ "customers/*": [ "./lib/customers/*.d.ts" ], + "error": [ + "./lib/error.d.ts" + ], "info": [ "./lib/info/clients.d.ts" ], "info/*": [ "./lib/info/*.d.ts" ], + "interfaces": [ + "./lib/interfaces.d.ts" + ], "invoices": [ "./lib/invoices/clients.d.ts" ], @@ -64,6 +73,9 @@ ], "products/*": [ "./lib/products/*.d.ts" + ], + "rate-limit": [ + "./lib/rate-limit.d.ts" ] } }, diff --git a/packages/fattureincloud-client/src/clients.ts b/packages/fattureincloud-client/src/clients.ts new file mode 100644 index 00000000..0f59cbeb --- /dev/null +++ b/packages/fattureincloud-client/src/clients.ts @@ -0,0 +1,75 @@ +import makeDebug from 'debug' +import type Bottleneck from 'bottleneck' +import type { Credentials } from './interfaces.js' + +import { + basicClient as customersBasicClient, + rateLimitedClient as customersRateLimitedClient +} from './customers/clients.js' +import type { Client as CustomersClient } from './customers/clients.js' + +import { + basicClient as infoBasicClient, + rateLimitedClient as infoRateLimitedClient +} from './info/clients.js' +import type { Client as InfoClient } from './info/clients.js' + +import { + basicClient as invoicesBasicClient, + rateLimitedClient as invoicesRateLimitedClient +} from './invoices/clients.js' +import type { Client as InvoicesClient } from './invoices/clients.js' + +import { + basicClient as productsBasicClient, + rateLimitedClient as productsRateLimitedClient +} from './products/clients.js' +import type { Client as ProductsClient } from './products/clients.js' + +const debug = makeDebug('fattureincloud-client/clients') + +export interface Client { + customers: CustomersClient + info: InfoClient + invoices: InvoicesClient + products: ProductsClient +} + +/** + * A basic client for all endpoints of the FattureinCloud API. + * + * @remarks This client is not rate-limiting. If you are calling the + * FattureinCloud API more than once, you might want to use the + * rateLimitedClient instead. + * + * @public + */ +export const basicClient = (credentials: Credentials): Client => { + debug('make FattureInCloud basic API client') + + return { + customers: customersBasicClient(credentials), + info: infoBasicClient(credentials), + invoices: invoicesBasicClient(credentials), + products: productsBasicClient(credentials) + } +} + +/** + * A rate-limited client for all endpoints of the FattureinCloud API. + * + * @public + */ +export const rateLimitedClient = ( + credentials: Credentials, + options?: Bottleneck.ConstructorOptions +): Client => { + debug('make FattureInCloud rate-limited API client') + + return { + customers: customersRateLimitedClient(credentials, options), + info: infoRateLimitedClient(credentials, options), + invoices: invoicesRateLimitedClient(credentials, options), + products: productsRateLimitedClient(credentials, options) + } +} diff --git a/packages/fattureincloud-client/src/customers/api.ts b/packages/fattureincloud-client/src/customers/api.ts index 86e14eb8..10b08c74 100644 --- a/packages/fattureincloud-client/src/customers/api.ts +++ b/packages/fattureincloud-client/src/customers/api.ts @@ -10,6 +10,7 @@ import type { APIResponseBodyList, APIResponseBodyUpdate, CreateRequestBody, + Customer, DeleteRequestBody, ListOptions, RetrieveConfig, @@ -21,17 +22,27 @@ const debug = makeDebug('fattureincloud-client/customers/api') const API_ENDPOINT = 'https://api.fattureincloud.it/v1/clienti' /** - * Retrieve a paginated list of customers. + * @public + */ +export interface ListResponseBody { + current_page: number + results: Customer[] + total_pages: number +} + +/** + * Retrieves a paginated list of customers. * * Each page can contain a maximum of 500 results. The FattureInCloud API does * not allow to configure how many results to return for each page. * - * https://api.fattureincloud.it/v1/documentation/dist/#!/Anagrafica/AnagraficaLista + * @see [AnagraficaLista - FattureinCloud.it](https://api.fattureincloud.it/v1/documentation/dist/#!/Anagrafica/AnagraficaLista) + * @public */ export const list = async ( { api_key, api_uid }: Credentials, options?: ListOptions -) => { +): Promise => { debug('list options (before validation and defaults) %O', options) const cf = options?.codice_fiscale || '' @@ -94,9 +105,10 @@ export const list = async ( } /** - * Retrieve a single customer that matches the search criteria. + * Retrieves a single customer that matches the search criteria. * - * https://api.fattureincloud.it/v1/documentation/dist/#!/Anagrafica/AnagraficaLista + * @see [AnagraficaLista - FattureinCloud.it](https://api.fattureincloud.it/v1/documentation/dist/#!/Anagrafica/AnagraficaLista) + * @public */ export const retrieve = async ( { api_key, api_uid }: Credentials, @@ -150,9 +162,10 @@ export const retrieve = async ( } /** - * Create a new customer. + * Creates a new customer. * - * https://api.fattureincloud.it/v1/documentation/dist/#!/Anagrafica/AnagraficaNuovoSingolo + * @see [AnagraficaNuovoSingolo - FattureinCloud.it](https://api.fattureincloud.it/v1/documentation/dist/#!/Anagrafica/AnagraficaNuovoSingolo) + * @public */ export const create = async ( { api_key, api_uid }: Credentials, @@ -221,9 +234,10 @@ export const create = async ( } /** - * Update an existing customer. + * Updates an existing customer. * - * https://api.fattureincloud.it/v1/documentation/dist/#!/Anagrafica/AnagraficaModifica + * @see [AnagraficaNuovoSingolo - FattureinCloud.it](https://api.fattureincloud.it/v1/documentation/dist/#!/Anagrafica/AnagraficaModifica) + * @public */ export const update = async ( { api_key, api_uid }: Credentials, @@ -394,9 +408,10 @@ export const update = async ( } /** - * Delete a customer. + * Deletes a customer. * - * https://api.fattureincloud.it/v1/documentation/dist/#!/Anagrafica/AnagraficaElimina + * @see [AnagraficaElimina - FattureinCloud.it](https://api.fattureincloud.it/v1/documentation/dist/#!/Anagrafica/AnagraficaElimina) + * @public */ export const deleteCustomer = async ( { api_key, api_uid }: Credentials, @@ -427,6 +442,8 @@ export const deleteCustomer = async ( /** * Autopaginate results. + * + * @public */ export async function* listAsyncGenerator( credentials: Credentials, diff --git a/packages/fattureincloud-client/src/customers/clients.ts b/packages/fattureincloud-client/src/customers/clients.ts index a89b6340..efc04acf 100644 --- a/packages/fattureincloud-client/src/customers/clients.ts +++ b/packages/fattureincloud-client/src/customers/clients.ts @@ -10,49 +10,72 @@ import { retrieve as retrieveCustomer, update as updateCustomer } from './api.js' +import type { ListResponseBody } from './api.js' import type { + Customer, CreateRequestBody, ListOptions, DeleteRequestBody, RetrieveConfig, UpdateRequestBody } from './interfaces.js' +import type { BasicClient } from '../interfaces.js' const debug = makeDebug('fattureincloud-client/customers/client') -export const basicClient = (credentials: Credentials) => { +/** + * @public + */ +export interface Client extends BasicClient { + create: (config: CreateRequestBody) => Promise<{ id: string }> + + delete: (config: DeleteRequestBody) => Promise<{ id: string }> + + list: (options?: ListOptions) => Promise + + listAsyncGenerator: ( + options?: ListOptions + ) => AsyncGenerator + + retrieve: (config: RetrieveConfig) => Promise + + update: ( + config: UpdateRequestBody + ) => Promise<{ id: string; campi: string[] }> +} + +/** + * A basic client for FattureinCloud customers. + * + * @public + */ +export const basicClient = (credentials: Credentials): Client => { debug('make FattureInCloud customers API client') return { - create: (config: CreateRequestBody) => { - return createCustomer(credentials, config) - }, + create: (config) => createCustomer(credentials, config), - delete: (config: DeleteRequestBody) => { - return deleteCustomer(credentials, config) - }, + delete: (config) => deleteCustomer(credentials, config), - list: (options?: ListOptions) => { - return listCustomers(credentials, options) - }, + list: (options) => listCustomers(credentials, options), - listAsyncGenerator: (options?: ListOptions) => { - return listCustomersAsyncGenerator(credentials, options) - }, + listAsyncGenerator: (options) => + listCustomersAsyncGenerator(credentials, options), - retrieve: (config: RetrieveConfig) => { - return retrieveCustomer(credentials, config) - }, + retrieve: (config) => retrieveCustomer(credentials, config), - update: (config: UpdateRequestBody) => { - return updateCustomer(credentials, config) - } + update: (config) => updateCustomer(credentials, config) } } +/** + * A rate-limited client for FattureinCloud customers. + * + * @public + */ export const rateLimitedClient = ( credentials: Credentials, options?: Bottleneck.ConstructorOptions -) => { +): Client => { return withRateLimit(basicClient(credentials), options) } diff --git a/packages/fattureincloud-client/src/index.ts b/packages/fattureincloud-client/src/index.ts index 40020440..bb7446cc 100644 --- a/packages/fattureincloud-client/src/index.ts +++ b/packages/fattureincloud-client/src/index.ts @@ -1,50 +1,66 @@ -import makeDebug from 'debug' -import type Bottleneck from 'bottleneck' -import type { Credentials } from './interfaces.js' +/** + * Entry point for the documentation of fattureincloud-client. + * + * @packageDocumentation + */ -import { - basicClient as customersBasicClient, - rateLimitedClient as customersRateLimitedClient -} from './customers/clients.js' +export { basicClient, rateLimitedClient } from './clients.js' +export type { Client } from './clients.js' -import { - basicClient as infoBasicClient, - rateLimitedClient as infoRateLimitedClient -} from './info/clients.js' +export type { Credentials } from './interfaces.js' -import { - basicClient as invoicesBasicClient, - rateLimitedClient as invoicesRateLimitedClient -} from './invoices/clients.js' +export type { Client as CustomersClient } from './customers/clients.js' +export type { ListResponseBody as CustomerListResponseBody } from './customers/api.js' +export type { + Customer, + ListOptions as CustomerListOptions, + RetrieveConfig as CustomerRetrieveConfig, + CreateRequestBody as CustomerCreateRequestBody, + UpdateRequestBody as CustomerUpdateRequestBody, + DeleteRequestBody as CustomerDeleteRequestBody, + APIResponseBodyList as CustomerAPIResponseBodyList, + APIResponseBodyCreate as CustomerAPIResponseBodyCreate, + APIResponseBodyUpdate as CustomerAPIResponseBodyUpdate, + APIResponseBodyDelete as CustomerAPIResponseBodyDelete +} from './customers/interfaces.js' -import { - basicClient as productsBasicClient, - rateLimitedClient as productsRateLimitedClient -} from './products/clients.js' +export type { Client as InfoClient } from './info/clients.js' +export type { AccountResponseBody as InfoAccountResponseBody } from './info/api.js' +export type { + AccountOptions as InfoAccountOptions, + Conto as InfoAccount, + Iva as InfoVat, + Valuta as InfoCurrency +} from './info/interfaces.js' -const debug = makeDebug('fattureincloud-client/index') +export type { Client as InvoicesClient } from './invoices/clients.js' +export type { ListResponseBody as InvoiceListResponseBody } from './invoices/api.js' +export type { + Articolo as InvoiceArticle, + Pagamento as InvoicePayment, + RiassuntoFattura as InvoiceSummary, + DettaglioFattura as InvoiceDetail, + CreateRequestBody as InvoiceCreateRequestBody, + ListOptions as InvoiceListOptions, + RetrieveConfig as InvoiceRetrieveConfig, + DeleteRequestBody as InvoiceDeleteRequestBody, + DataValidation as InvoiceDataValidation, + APIResponseBodyCreate as InvoiceAPIResponseBodyCreate, + APIResponseBodyDelete as InvoiceAPIResponseBodyDelete, + APIResponseBodyDetail as InvoiceAPIResponseBodyDetail, + APIResponseBodyList as InvoiceAPIResponseBodyList +} from './invoices/interfaces.js' -export const basicClient = (credentials: Credentials) => { - debug('make FattureInCloud basic API client') - - return { - customers: customersBasicClient(credentials), - info: infoBasicClient(credentials), - invoices: invoicesBasicClient(credentials), - products: productsBasicClient(credentials) - } -} - -export const rateLimitedClient = ( - credentials: Credentials, - options?: Bottleneck.ConstructorOptions -) => { - debug('make FattureInCloud rate-limited API client') - - return { - customers: customersRateLimitedClient(credentials, options), - info: infoRateLimitedClient(credentials, options), - invoices: invoicesRateLimitedClient(credentials, options), - products: productsRateLimitedClient(credentials, options) - } -} +export type { Client as ProductsClient } from './products/clients.js' +export type { ListResponseBody as ProductListResponseBody } from './products/api.js' +export type { + Product, + ListOptions as ProductListOptions, + RetrieveConfig as ProductRetrieveConfig, + CreateRequestBody as ProductCreateRequestBody, + DeleteRequestBody as ProductDeleteRequestBody, + APIResponseBodyCreate as ProductAPIResponseBodyCreate, + APIResponseBodyList as ProductAPIResponseBodyList, + APIResponseBodyUpdate as ProductAPIResponseBodyUpdate, + APIResponseBodyDelete as ProductAPIResponseBodyDelete +} from './products/interfaces.js' diff --git a/packages/fattureincloud-client/src/info/api.ts b/packages/fattureincloud-client/src/info/api.ts index f6b2dcfd..38518ad2 100644 --- a/packages/fattureincloud-client/src/info/api.ts +++ b/packages/fattureincloud-client/src/info/api.ts @@ -4,16 +4,32 @@ import { newErrorFromApiError } from '../error.js' import { headers } from '../headers.js' import type { Credentials } from '../interfaces.js' import type { + AccountOptions, APIResponseBodyAccountInfo, - AccountOptions + Conto, + Iva, + Valuta } from './interfaces.js' const debug = makeDebug('fattureincloud-client/info/api') const API_ENDPOINT = 'https://api.fattureincloud.it/v1/info' +export interface AccountResponseBody { + success: true + giorni_rimanenti_licenza?: number + ragione_sociale?: string + piano_licenza?: string + lista_conti?: Conto[] + lista_iva?: Iva[] + lista_valute?: Valuta[] +} + /** - * https://api.fattureincloud.it/v1/documentation/dist/#!/Info/InfoLista + * Returns info about a FattureinCloud account. + * + * @see [Informazioni e liste di diversa natura - FattureinCloud.it](https://api.fattureincloud.it/v1/documentation/dist/#!/Info/InfoLista) + * @public */ export const account = async ( { api_key, api_uid }: Credentials, @@ -41,7 +57,7 @@ export const account = async ( throw newErrorFromApiError({ error: b.error, error_code: b.error_code! }) } - const response_body: any = { success: true } // TODO better type + const response_body: AccountResponseBody = { success: true } // TODO better type if (campi.includes('durata_licenza')) { response_body.giorni_rimanenti_licenza = b.durata_licenza diff --git a/packages/fattureincloud-client/src/info/clients.ts b/packages/fattureincloud-client/src/info/clients.ts index 71366614..45c92973 100644 --- a/packages/fattureincloud-client/src/info/clients.ts +++ b/packages/fattureincloud-client/src/info/clients.ts @@ -3,20 +3,37 @@ import type Bottleneck from 'bottleneck' import type { Credentials } from '../interfaces.js' import { rateLimitedClient as withRateLimit } from '../rate-limit.js' import { account as infoAccount } from './api.js' +import type { AccountResponseBody } from './api.js' import type { AccountOptions } from './interfaces.js' +import type { BasicClient } from '../interfaces.js' const debug = makeDebug('fattureincloud-client/info/client') -export const basicClient = (credentials: Credentials) => { +/** + * @public + */ +export interface Client extends BasicClient { + account: (options?: AccountOptions) => Promise +} + +/** + * A basic client for FattureinCloud info. + * + * @public + */ +export const basicClient = (credentials: Credentials): Client => { debug('make FattureInCloud info API client') return { - account: (options?: AccountOptions) => { - return infoAccount(credentials, options) - } + account: (options) => infoAccount(credentials, options) } } +/** + * A rate-limited client for FattureinCloud info. + * + * @public + */ export const rateLimitedClient = ( credentials: Credentials, options?: Bottleneck.ConstructorOptions diff --git a/packages/fattureincloud-client/src/interfaces.ts b/packages/fattureincloud-client/src/interfaces.ts index 5ca046d0..07f67ce0 100644 --- a/packages/fattureincloud-client/src/interfaces.ts +++ b/packages/fattureincloud-client/src/interfaces.ts @@ -1,3 +1,6 @@ +/** + * Credentials of a FattureinCloud account. + */ export interface Credentials { api_key: string api_uid: string @@ -8,10 +11,12 @@ export interface APIResponseBodyError { error_code?: number } -// export interface ResponseBody { -// /** -// * Appropriate status code for the HTTP request. This is necessary because the -// * FattureInCloud API always returns 200. -// */ -// status_code: number -// } +export type PromiseReturningFn = (...args: any) => Promise + +export type AsyncGenReturningFn = ( + ...args: any +) => AsyncGenerator + +export interface BasicClient { + [fn_name: string]: PromiseReturningFn | AsyncGenReturningFn +} diff --git a/packages/fattureincloud-client/src/invoices/api.ts b/packages/fattureincloud-client/src/invoices/api.ts index 05b4940b..bf142a08 100644 --- a/packages/fattureincloud-client/src/invoices/api.ts +++ b/packages/fattureincloud-client/src/invoices/api.ts @@ -26,7 +26,8 @@ import type { CreateRequestBody, DeleteRequestBody, ListOptions, - RetrieveConfig + RetrieveConfig, + RiassuntoFattura } from './interfaces.js' const debug = makeDebug('fattureincloud-client/invoices/api') @@ -34,23 +35,36 @@ const debug = makeDebug('fattureincloud-client/invoices/api') const API_ENDPOINT = 'https://api.fattureincloud.it/v1/fatture' /** - * Retrieve a paginated list of invoices. + * @public + */ +export interface ListResponseBody { + current_page: number + results: RiassuntoFattura[] + results_per_page: number + results_total: number + total_pages: number +} + +/** + * Retrieves a paginated list of invoices. * * Each page can contain a maximum of 250 results. The FattureInCloud API does * not allow to configure how many results to return for each page. * - * https://api.fattureincloud.it/v1/documentation/dist/#!/Documenti_emessi/DocLista + * @see [DocLista - FattureinCloud.it](https://api.fattureincloud.it/v1/documentation/dist/#!/Documenti_emessi/DocLista) + * @public */ export const listInvoices = async ( { api_key, api_uid }: Credentials, options?: ListOptions -) => { +): Promise => { debug('list options (before validation and defaults) %O', options) const date_begin = options?.date_begin || '' const date_end = options?.date_end || '' const year = options?.year const page = options?.page || 1 + const substring_ragione_sociale = options?.substring_ragione_sociale || '' if (page < 1) { throw new Error(`page must be >= 1`) @@ -78,6 +92,7 @@ export const listInvoices = async ( page, date_begin, date_end, + substring_ragione_sociale, year }) @@ -86,6 +101,7 @@ export const listInvoices = async ( api_key, api_uid, anno: year, + cliente: substring_ragione_sociale, data_inizio: date_begin, data_fine: date_end, pagina: page @@ -127,9 +143,10 @@ export const listInvoices = async ( } /** - * Retrieve a single invoice that matches the search criteria. + * Retrieves a single invoice that matches the search criteria. * - * https://api.fattureincloud.it/v1/documentation/dist/#!/Documenti_emessi/DocDettagli + * @see [DocDettagli - FattureinCloud.it](https://api.fattureincloud.it/v1/documentation/dist/#!/Documenti_emessi/DocDettagli) + * @public */ export const retrieveInvoice = async ( { api_key, api_uid }: Credentials, @@ -163,9 +180,10 @@ export const retrieveInvoice = async ( } /** - * Create a new invoice. + * Creates a new invoice. * - * https://api.fattureincloud.it/v1/documentation/dist/#!/Documenti_emessi/DocNuovo + * @see [DocNuovo - FattureinCloud.it](https://api.fattureincloud.it/v1/documentation/dist/#!/Documenti_emessi/DocNuovo) + * @public */ export const createInvoice = async ( { api_key, api_uid }: Credentials, @@ -321,9 +339,10 @@ export const createInvoice = async ( } /** - * Delete an invoice. + * Deletes an invoice. * - * https://api.fattureincloud.it/v1/documentation/dist/#!/Documenti_emessi/DocElimina + * @see [DocElimina - FattureinCloud.it](https://api.fattureincloud.it/v1/documentation/dist/#!/Documenti_emessi/DocElimina) + * @public */ export const deleteInvoice = async ( { api_key, api_uid }: Credentials, @@ -354,6 +373,8 @@ export const deleteInvoice = async ( /** * Autopaginate results. + * + * @public */ export async function* listInvoicesAsyncGenerator( credentials: Credentials, diff --git a/packages/fattureincloud-client/src/invoices/checks.ts b/packages/fattureincloud-client/src/invoices/checks.ts index 6aa5aa6f..c2e19507 100644 --- a/packages/fattureincloud-client/src/invoices/checks.ts +++ b/packages/fattureincloud-client/src/invoices/checks.ts @@ -1,5 +1,7 @@ import type { Articolo, DataValidation } from './interfaces.js' +// TODO: use Joi instead of these functions. + export const isArticoliValid = (lista_articoli?: Articolo[]) => { if (lista_articoli && lista_articoli.length > 0) { return true diff --git a/packages/fattureincloud-client/src/invoices/clients.ts b/packages/fattureincloud-client/src/invoices/clients.ts index 7783023a..b43ee611 100644 --- a/packages/fattureincloud-client/src/invoices/clients.ts +++ b/packages/fattureincloud-client/src/invoices/clients.ts @@ -9,44 +9,65 @@ import { listInvoicesAsyncGenerator, retrieveInvoice } from './api.js' +import type { ListResponseBody } from './api.js' import type { CreateRequestBody, DeleteRequestBody, ListOptions, - RetrieveConfig + RetrieveConfig, + DettaglioFattura } from './interfaces.js' +import type { BasicClient } from '../interfaces.js' const debug = makeDebug('fattureincloud-client/invoices/client') -export const basicClient = (credentials: Credentials) => { +/** + * @public + */ +export interface Client extends BasicClient { + create: (config: CreateRequestBody) => Promise<{ id: string; token: string }> + + delete: (config: DeleteRequestBody) => Promise<{ id: string }> + + list: (options?: ListOptions) => Promise + + listAsyncGenerator: ( + options?: ListOptions + ) => AsyncGenerator + + retrieve: (config: RetrieveConfig) => Promise +} + +/** + * A basic client for FattureinCloud invoices. + * + * @public + */ +export const basicClient = (credentials: Credentials): Client => { debug('make FattureInCloud invoices API client') return { - create: (config: CreateRequestBody) => { - return createInvoice(credentials, config) - }, + create: (config) => createInvoice(credentials, config), - delete: (config: DeleteRequestBody) => { - return deleteInvoice(credentials, config) - }, + delete: (config) => deleteInvoice(credentials, config), - list: (options?: ListOptions) => { - return listInvoices(credentials, options) - }, + list: (options) => listInvoices(credentials, options), - listAsyncGenerator: (options?: ListOptions) => { - return listInvoicesAsyncGenerator(credentials, options) - }, + listAsyncGenerator: (options) => + listInvoicesAsyncGenerator(credentials, options), - retrieve: (config: RetrieveConfig) => { - return retrieveInvoice(credentials, config) - } + retrieve: (config) => retrieveInvoice(credentials, config) } } +/** + * A rate-limited client for FattureinCloud invoices. + * + * @public + */ export const rateLimitedClient = ( credentials: Credentials, options?: Bottleneck.ConstructorOptions -) => { +): Client => { return withRateLimit(basicClient(credentials), options) } diff --git a/packages/fattureincloud-client/src/products/api.ts b/packages/fattureincloud-client/src/products/api.ts index b347b8a1..80c8e6cc 100644 --- a/packages/fattureincloud-client/src/products/api.ts +++ b/packages/fattureincloud-client/src/products/api.ts @@ -11,6 +11,7 @@ import type { CreateRequestBody, DeleteRequestBody, ListOptions, + Product, RetrieveConfig } from './interfaces.js' @@ -18,15 +19,23 @@ const debug = makeDebug('fattureincloud-client/products/api') const API_ENDPOINT = 'https://api.fattureincloud.it/v1/prodotti' +export interface ListResponseBody { + current_page: number + results: Product[] + total_pages: number +} + /** - * Retrieve a paginated list of products. + * Retrieves a paginated list of products. * * https://api.fattureincloud.it/v1/documentation/dist/#!/Prodotti/ProdottiLista + * + * @public */ export const list = async ( { api_key, api_uid }: Credentials, options?: ListOptions -) => { +): Promise => { debug('list options (before validation and defaults) %O', options) const categoria = options?.categoria || '' @@ -88,9 +97,11 @@ export const list = async ( } /** - * Retrieve a single product that matches the search criteria. + * Retrieves a single product that matches the search criteria. * * https://api.fattureincloud.it/v1/documentation/dist/#!/Prodotti/ProdottiLista + * + * @public */ export const retrieve = async ( { api_key, api_uid }: Credentials, @@ -145,9 +156,11 @@ export const retrieve = async ( } /** - * Create a new product. + * Creates a new product. * * https://api.fattureincloud.it/v1/documentation/dist/#!/Prodotti/ProdottoNuovoSingolo + * + * @public */ export const create = async ( { api_key, api_uid }: Credentials, @@ -175,9 +188,11 @@ export const create = async ( } /** - * Delete a product. + * Deletes a product. * * https://api.fattureincloud.it/v1/documentation/dist/#!/Prodotti/ProdottiElimina + * + * @public */ export const deleteProduct = async ( { api_key, api_uid }: Credentials, @@ -208,6 +223,8 @@ export const deleteProduct = async ( /** * Autopaginate results. + * + * @public */ export async function* listAsyncGenerator( credentials: Credentials, diff --git a/packages/fattureincloud-client/src/products/clients.ts b/packages/fattureincloud-client/src/products/clients.ts index d172d65e..c99cb24c 100644 --- a/packages/fattureincloud-client/src/products/clients.ts +++ b/packages/fattureincloud-client/src/products/clients.ts @@ -9,44 +9,65 @@ import { listAsyncGenerator as listProductsAsyncGenerator, retrieve as retrieveProduct } from './api.js' +import type { ListResponseBody } from './api.js' import type { + Product, CreateRequestBody, - DeleteRequestBody, ListOptions, + DeleteRequestBody, RetrieveConfig } from './interfaces.js' +import type { BasicClient } from '../interfaces.js' const debug = makeDebug('fattureincloud-client/products/client') -export const basicClient = (credentials: Credentials) => { +/** + * @public + */ +export interface Client extends BasicClient { + create: (config: CreateRequestBody) => Promise<{ id: string }> + + delete: (config: DeleteRequestBody) => Promise<{ id: string }> + + list: (options?: ListOptions) => Promise + + listAsyncGenerator: ( + options?: ListOptions + ) => AsyncGenerator + + retrieve: (config: RetrieveConfig) => Promise +} + +/** + * A basic client for FattureinCloud products. + * + * @public + */ +export const basicClient = (credentials: Credentials): Client => { debug('make FattureInCloud products API client') return { - create: (config: CreateRequestBody) => { - return createProduct(credentials, config) - }, + create: (config) => createProduct(credentials, config), - delete: (config: DeleteRequestBody) => { - return deleteProduct(credentials, config) - }, + delete: (config) => deleteProduct(credentials, config), - list: (options?: ListOptions) => { - return listProducts(credentials, options) - }, + list: (options) => listProducts(credentials, options), - listAsyncGenerator: (options?: ListOptions) => { - return listProductsAsyncGenerator(credentials, options) - }, + listAsyncGenerator: (options) => + listProductsAsyncGenerator(credentials, options), - retrieve: (config: RetrieveConfig) => { - return retrieveProduct(credentials, config) - } + retrieve: (config) => retrieveProduct(credentials, config) } } +/** + * A rate-limited client for FattureinCloud products. + * + * @public + */ export const rateLimitedClient = ( credentials: Credentials, options?: Bottleneck.ConstructorOptions -) => { +): Client => { return withRateLimit(basicClient(credentials), options) } diff --git a/packages/fattureincloud-client/src/rate-limit.ts b/packages/fattureincloud-client/src/rate-limit.ts index 33670bf9..b95c047d 100644 --- a/packages/fattureincloud-client/src/rate-limit.ts +++ b/packages/fattureincloud-client/src/rate-limit.ts @@ -1,15 +1,9 @@ import makeDebug from 'debug' import Bottleneck from 'bottleneck' +import type { BasicClient, PromiseReturningFn } from './interfaces.js' const debug = makeDebug('fattureincloud-client/rate-limit') -type PromiseReturningFn = (...args: any) => Promise -type AsyncGenReturningFn = (...args: any) => AsyncGenerator - -type Client = { - [fn_name: string]: PromiseReturningFn | AsyncGenReturningFn -} - interface Value { default: number provided: number | null | undefined @@ -24,12 +18,13 @@ const providedOrDefault = (v: Value) => { } /** - * Wrap all methods of a FattureInCloud API client in a rate limit and return a + * Wraps all methods of a FattureInCloud API client in a rate limit and return a * new client that has a rate-limited version of all of its methods. * - * The FattureInCloud API allows only 30 requests per minute. + * @remarks The FattureInCloud API allows only 30 requests per minute. + * @internal */ -export const rateLimitedClient = ( +export const rateLimitedClient = ( client: Client, options?: Bottleneck.ConstructorOptions ) => { @@ -52,7 +47,8 @@ export const rateLimitedClient = ( const limiter = new Bottleneck(limiter_options) debug('limiter options %O', limiter_options) - const rate_limited_client: Client = {} + const rate_limited_client: BasicClient = {} + Object.entries(client).forEach((entry) => { const [fn_name, fn] = entry // a function that returns an async generator COULD be wrapped with @@ -75,5 +71,6 @@ export const rateLimitedClient = ( rate_limited_client[fn_name] = rate_limited_fn } }) - return rate_limited_client + + return rate_limited_client as Client }