diff --git a/.changeset/wise-berries-yawn.md b/.changeset/wise-berries-yawn.md new file mode 100644 index 0000000..c1d6bf7 --- /dev/null +++ b/.changeset/wise-berries-yawn.md @@ -0,0 +1,5 @@ +--- +'@ssecd/jkn': minor +--- + +add custom base url config diff --git a/README.md b/README.md index 74bbd6e..ba2542f 100644 --- a/README.md +++ b/README.md @@ -125,13 +125,15 @@ function persistSep(sep: VClaimResponse<'sep', 'insertV2'>) { Konfigurasi mengikuti interface berikut: -```ts +````ts interface Config { /** * Kode PPK yang diberikan BPJS. * * Diperlukan untuk melakukan proses encryption * pada web service eRekam Medis. + * + * @default process.env.JKN_PPK_CODE */ ppkCode: string; @@ -214,8 +216,24 @@ interface Config { * @default false */ throw: boolean; + + /** + * Base URL web service dari BPJS. Secara default sudah diatur + * berdasarkan base url yang ada di TrustMark. Nilai dapat diatur + * secara partial, misalnya: + * + * ``` + * baseUrls: { + * vclaim: { + * development: 'http://dev.example.com', + * production: 'http://prod.example.com' + * } + * } + * ``` + */ + baseUrls: Partial>>; } -``` +```` ## API Tersedia diff --git a/src/fetcher.ts b/src/fetcher.ts index e7eb74f..64ff391 100644 --- a/src/fetcher.ts +++ b/src/fetcher.ts @@ -13,6 +13,8 @@ export interface Config { * * Diperlukan untuk melakukan proses encryption * pada web service eRekam Medis. + * + * @default process.env.JKN_PPK_CODE */ ppkCode: string; @@ -95,6 +97,22 @@ export interface Config { * @default false */ throw: boolean; + + /** + * Base URL web service dari BPJS. Secara default sudah diatur + * berdasarkan base url yang ada di TrustMark. Nilai dapat diatur + * secara partial, misalnya: + * + * ``` + * baseUrls: { + * vclaim: { + * development: 'http://dev.example.com', + * production: 'http://prod.example.com' + * } + * } + * ``` + */ + baseUrls: Partial>>; } export interface SendOption { @@ -140,7 +158,7 @@ export type SendResponse = { rekamMedis: LowerResponse; }; -const api_base_urls: Record> = { +const defaultBaseUrls: Record> = { vclaim: { development: 'https://apijkn-dev.bpjs-kesehatan.go.id/vclaim-rest-dev', production: 'https://apijkn.bpjs-kesehatan.go.id/vclaim-rest' @@ -181,7 +199,8 @@ export class Fetcher { pcareUserKey: process.env.JKN_PCARE_USER_KEY ?? '', icareUserKey: process.env.JKN_ICARE_USER_KEY ?? '', rekamMedisUserKey: process.env.JKN_REKAM_MEDIS_USER_KEY ?? '', - throw: false + throw: false, + baseUrls: defaultBaseUrls }; constructor(private userConfig?: Partial | (() => MaybePromise>)) {} @@ -190,16 +209,10 @@ export class Fetcher { if (!this.userConfig || this.configured) return; if (typeof this.userConfig === 'object') { - this.config = { - ...this.config, - ...this.userConfig - }; + this.config = this.mergeConfig(this.config, this.userConfig); } else if (typeof this.userConfig === 'function') { - const config = await this.userConfig(); - this.config = { - ...this.config, - ...config - }; + const userConfig = await this.userConfig(); + this.config = this.mergeConfig(this.config, userConfig); } if (!this.config.consId || !this.config.consSecret) { @@ -209,6 +222,12 @@ export class Fetcher { this.configured = true; } + private mergeConfig(target: Config, source: Partial): Config { + // simple object merge strategy because only baseUrls is typeof object for now + const baseUrls = { ...target.baseUrls, ...source.baseUrls }; + return { ...target, ...source, baseUrls }; + } + private get userKeyMap(): Record { return { vclaim: this.config.vclaimUserKey, @@ -260,7 +279,10 @@ export class Fetcher { let response = ''; try { - const url = new URL(api_base_urls[type][this.config.mode] + option.path); + const baseUrl = this.config.baseUrls[type]; + if (!baseUrl) throw new Error(`base url of type "${type}" is invalid`); + + const url = new URL(baseUrl[this.config.mode] + option.path); const init: RequestInit = { method: option.method ?? 'GET' }; const headers = { ...this.getDefaultHeaders(type), ...(option.headers ?? {}) }; diff --git a/test/fetcher.test.ts b/test/fetcher.test.ts new file mode 100644 index 0000000..ef28fef --- /dev/null +++ b/test/fetcher.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it } from 'vitest'; +import { Fetcher } from '../src/fetcher'; + +describe('Fetcher', () => { + it.concurrent('validate config', async () => { + const userConfig = { + ppkCode: '12345', + baseUrls: { + pcare: { + development: 'http://dev.example.com', + production: 'http://example.com' + } + } + }; + const fetcher = new Fetcher(userConfig); + const config = await fetcher.getConfig(); + + expect(config.ppkCode).toBe(userConfig.ppkCode); + expect(config.baseUrls.pcare).toEqual(userConfig.baseUrls.pcare); + expect(config.baseUrls.pcare?.development).toBe(userConfig.baseUrls.pcare.development); + expect(config.baseUrls.vclaim?.development).toBe( + 'https://apijkn-dev.bpjs-kesehatan.go.id/vclaim-rest-dev' + ); + }); +});