@devup-api/fetch 0.1.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 +24 -0
- package/dist/__tests__/api.test.d.ts +2 -0
- package/dist/__tests__/api.test.d.ts.map +1 -0
- package/dist/__tests__/create-api.test.d.ts +2 -0
- package/dist/__tests__/create-api.test.d.ts.map +1 -0
- package/dist/__tests__/index.test.d.ts +2 -0
- package/dist/__tests__/index.test.d.ts.map +1 -0
- package/dist/__tests__/response-converter.test.d.ts +2 -0
- package/dist/__tests__/response-converter.test.d.ts.map +1 -0
- package/dist/__tests__/url-map.test.d.ts +2 -0
- package/dist/__tests__/url-map.test.d.ts.map +1 -0
- package/dist/__tests__/utils.test.d.ts +2 -0
- package/dist/__tests__/utils.test.d.ts.map +1 -0
- package/dist/api.d.ts +31 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/create-api.d.ts +3 -0
- package/dist/create-api.d.ts.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/response-converter.d.ts +13 -0
- package/dist/response-converter.d.ts.map +1 -0
- package/dist/url-map.d.ts +5 -0
- package/dist/url-map.d.ts.map +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +25 -0
- package/src/__tests__/api.test.ts +245 -0
- package/src/__tests__/create-api.test.ts +25 -0
- package/src/__tests__/index.test.ts +10 -0
- package/src/__tests__/response-converter.test.ts +158 -0
- package/src/__tests__/url-map.test.ts +182 -0
- package/src/__tests__/utils.test.ts +108 -0
- package/src/api.ts +303 -0
- package/src/create-api.ts +8 -0
- package/src/index.ts +2 -0
- package/src/response-converter.ts +44 -0
- package/src/url-map.ts +13 -0
- package/src/utils.ts +18 -0
- package/tsconfig.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @devup-api/fetch
|
|
2
|
+
|
|
3
|
+
devup API Fetch library
|
|
4
|
+
|
|
5
|
+
Provides fetch API for end users.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @devup-api/fetch
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { devupFetch } from '@devup-api/fetch';
|
|
17
|
+
|
|
18
|
+
const response = await devupFetch('https://api.example.com/data', {
|
|
19
|
+
method: 'GET',
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/api.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-api.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/create-api.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-converter.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/response-converter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-map.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/url-map.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/utils.test.ts"],"names":[],"mappings":""}
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Additional, DevupApiRequestInit, DevupApiStruct, DevupApiStructKey, DevupDeleteApiStruct, DevupDeleteApiStructKey, DevupGetApiStruct, DevupGetApiStructKey, DevupPatchApiStruct, DevupPatchApiStructKey, DevupPostApiStruct, DevupPostApiStructKey, DevupPutApiStruct, DevupPutApiStructKey, ExtractValue, RequiredOptions } from '@devup-api/core';
|
|
2
|
+
type DevupApiResponse<T, E = unknown> = {
|
|
3
|
+
data: T;
|
|
4
|
+
error?: undefined;
|
|
5
|
+
response: Response;
|
|
6
|
+
} | {
|
|
7
|
+
data?: undefined;
|
|
8
|
+
error: E;
|
|
9
|
+
response: Response;
|
|
10
|
+
};
|
|
11
|
+
export declare class DevupApi {
|
|
12
|
+
private baseUrl;
|
|
13
|
+
private defaultOptions;
|
|
14
|
+
constructor(baseUrl: string, defaultOptions?: DevupApiRequestInit);
|
|
15
|
+
get<T extends DevupGetApiStructKey, O extends Additional<T, DevupGetApiStruct>>(path: T, ...options: [RequiredOptions<O>] extends [never] ? [options?: DevupApiRequestInit] : [options: DevupApiRequestInit & Omit<O, 'response' | 'error'>]): Promise<DevupApiResponse<ExtractValue<O, 'response'>, ExtractValue<O, 'error', unknown>>>;
|
|
16
|
+
GET<T extends DevupGetApiStructKey, O extends Additional<T, DevupGetApiStruct>>(path: T, ...options: [RequiredOptions<O>] extends [never] ? [options?: DevupApiRequestInit] : [options: DevupApiRequestInit & Omit<O, 'response'>]): Promise<DevupApiResponse<ExtractValue<O, 'response'>, ExtractValue<O, 'error', unknown>>>;
|
|
17
|
+
post<T extends DevupPostApiStructKey, O extends Additional<T, DevupPostApiStruct>>(path: T, ...options: [RequiredOptions<O>] extends [never] ? [options?: DevupApiRequestInit] : [options: DevupApiRequestInit & Omit<O, 'response'>]): Promise<DevupApiResponse<ExtractValue<O, 'response'>, ExtractValue<O, 'error', unknown>>>;
|
|
18
|
+
POST<T extends DevupPostApiStructKey, O extends Additional<T, DevupPostApiStruct>>(path: T, ...options: [RequiredOptions<O>] extends [never] ? [options?: DevupApiRequestInit] : [options: DevupApiRequestInit & Omit<O, 'response'>]): Promise<DevupApiResponse<ExtractValue<O, 'response'>, ExtractValue<O, 'error', unknown>>>;
|
|
19
|
+
put<T extends DevupPutApiStructKey, O extends Additional<T, DevupPutApiStruct>>(path: T, ...options: [RequiredOptions<O>] extends [never] ? [options?: DevupApiRequestInit] : [options: DevupApiRequestInit & Omit<O, 'response'>]): Promise<DevupApiResponse<ExtractValue<O, 'response'>, ExtractValue<O, 'error', unknown>>>;
|
|
20
|
+
PUT<T extends DevupPutApiStructKey, O extends Additional<T, DevupPutApiStruct>>(path: T, ...options: [RequiredOptions<O>] extends [never] ? [options?: DevupApiRequestInit] : [options: DevupApiRequestInit & Omit<O, 'response'>]): Promise<DevupApiResponse<ExtractValue<O, 'response'>, ExtractValue<O, 'error', unknown>>>;
|
|
21
|
+
delete<T extends DevupDeleteApiStructKey, O extends Additional<T, DevupDeleteApiStruct>>(path: T, ...options: [RequiredOptions<O>] extends [never] ? [options?: DevupApiRequestInit] : [options: DevupApiRequestInit & Omit<O, 'response'>]): Promise<DevupApiResponse<ExtractValue<O, 'response'>, ExtractValue<O, 'error', unknown>>>;
|
|
22
|
+
DELETE<T extends DevupDeleteApiStructKey, O extends Additional<T, DevupDeleteApiStruct>>(path: T, ...options: [RequiredOptions<O>] extends [never] ? [options?: DevupApiRequestInit] : [options: DevupApiRequestInit & Omit<O, 'response'>]): Promise<DevupApiResponse<ExtractValue<O, 'response'>, ExtractValue<O, 'error', unknown>>>;
|
|
23
|
+
patch<T extends DevupPatchApiStructKey, O extends Additional<T, DevupPatchApiStruct>>(path: T, ...options: [RequiredOptions<O>] extends [never] ? [options?: DevupApiRequestInit] : [options: DevupApiRequestInit & Omit<O, 'response'>]): Promise<DevupApiResponse<ExtractValue<O, 'response'>, ExtractValue<O, 'error', unknown>>>;
|
|
24
|
+
PATCH<T extends DevupPatchApiStructKey, O extends Additional<T, DevupPatchApiStruct>>(path: T, ...options: [RequiredOptions<O>] extends [never] ? [options?: DevupApiRequestInit] : [options: DevupApiRequestInit & Omit<O, 'response'>]): Promise<DevupApiResponse<ExtractValue<O, 'response'>, ExtractValue<O, 'error', unknown>>>;
|
|
25
|
+
request<T extends DevupApiStructKey, O extends Additional<T, DevupApiStruct>>(path: T, ...options: [RequiredOptions<O>] extends [never] ? [options?: DevupApiRequestInit] : [options: DevupApiRequestInit & Omit<O, 'response'>]): Promise<DevupApiResponse<ExtractValue<O, 'response'>, ExtractValue<O, 'error', unknown>>>;
|
|
26
|
+
setDefaultOptions(options: DevupApiRequestInit): void;
|
|
27
|
+
getBaseUrl(): string;
|
|
28
|
+
getDefaultOptions(): DevupApiRequestInit;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-api.d.ts","sourceRoot":"","sources":["../src/create-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEhC,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,cAAc,CAAC,EAAE,WAAW,GAC3B,QAAQ,CAEV"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var{defineProperty:n,getOwnPropertyNames:O,getOwnPropertyDescriptor:P}=Object,a=Object.prototype.hasOwnProperty,o=(t,e,p)=>{for(let i of O(e))if(!a.call(t,i)&&i!=="default")n(t,i,{get:()=>e[i],enumerable:!0});if(p){for(let i of O(e))if(!a.call(p,i)&&i!=="default")n(p,i,{get:()=>e[i],enumerable:!0});return p}};var c=new WeakMap,E=(t)=>{var e=c.get(t),p;if(e)return e;if(e=n({},"__esModule",{value:!0}),t&&typeof t==="object"||typeof t==="function")O(t).map((i)=>!a.call(e,i)&&n(e,i,{get:()=>t[i],enumerable:!(p=P(t,i))||p.enumerable}));return c.set(t,e),e};var D=(t,e)=>{for(var p in e)n(t,p,{get:e[p],enumerable:!0,configurable:!0,set:(i)=>e[p]=()=>i})};var r={};D(r,{createApi:()=>A});module.exports=E(r);o(r,require("@devup-api/core"),module.exports);var q={};D(q,{createApi:()=>A});async function l(t,e,p="json"){if(e.status===204||t.method==="HEAD"||e.headers.get("Content-Length")==="0")return e.ok?{data:void 0,response:e}:{error:void 0,response:e};if(e.ok){if(p==="stream")return{data:e.body,response:e};return{data:await e[p](),response:e}}let i=await e.text();try{i=JSON.parse(i)}catch{}return{error:i,response:e}}var h=JSON.parse(process.env.DEVUP_API_URL_MAP||"{}");function R(t){return h[t]||{method:"GET",url:t}}function x(t){if(t===null||typeof t!=="object")return!1;return Object.getPrototypeOf(t)===Object.prototype}function m(t,e,p){let i=`${t}${e}`;for(let[s,u]of Object.entries(p??{}))i=i.replace(`{${s}}`,u);return i}class d{baseUrl;defaultOptions;constructor(t,e={}){this.baseUrl=t.replace(/\/$/,""),this.defaultOptions=e}get(t,...e){return this.request(t,{method:"GET",...e[0]})}GET(t,...e){return this.request(t,{method:"GET",...e[0]})}post(t,...e){return this.request(t,{method:"POST",...e[0]})}POST(t,...e){return this.request(t,{method:"POST",...e[0]})}put(t,...e){return this.request(t,{method:"PUT",...e[0]})}PUT(t,...e){return this.request(t,{method:"PUT",...e[0]})}delete(t,...e){return this.request(t,{method:"DELETE",...e[0]})}DELETE(t,...e){return this.request(t,{method:"DELETE",...e[0]})}patch(t,...e){return this.request(t,{method:"PATCH",...e[0]})}PATCH(t,...e){return this.request(t,{method:"PATCH",...e[0]})}request(t,...e){let{method:p,url:i}=R(t),s={...this.defaultOptions,...e[0]},u={...s,method:s.method||p};if(u.body&&x(u.body))u.body=JSON.stringify(u.body);let v=new Request(m(this.baseUrl,i,u.params),u);return fetch(v).then((T)=>l(v,T))}setDefaultOptions(t){this.defaultOptions=t}getBaseUrl(){return this.baseUrl}getDefaultOptions(){return this.defaultOptions}}function A(t,e){return new d(t,e)}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export*from"@devup-api/core";async function o(t,e,u="json"){if(e.status===204||t.method==="HEAD"||e.headers.get("Content-Length")==="0")return e.ok?{data:void 0,response:e}:{error:void 0,response:e};if(e.ok){if(u==="stream")return{data:e.body,response:e};return{data:await e[u](),response:e}}let i=await e.text();try{i=JSON.parse(i)}catch{}return{error:i,response:e}}var v=JSON.parse(process.env.DEVUP_API_URL_MAP||"{}");function O(t){return v[t]||{method:"GET",url:t}}function a(t){if(t===null||typeof t!=="object")return!1;return Object.getPrototypeOf(t)===Object.prototype}function d(t,e,u){let i=`${t}${e}`;for(let[n,p]of Object.entries(u??{}))i=i.replace(`{${n}}`,p);return i}class r{baseUrl;defaultOptions;constructor(t,e={}){this.baseUrl=t.replace(/\/$/,""),this.defaultOptions=e}get(t,...e){return this.request(t,{method:"GET",...e[0]})}GET(t,...e){return this.request(t,{method:"GET",...e[0]})}post(t,...e){return this.request(t,{method:"POST",...e[0]})}POST(t,...e){return this.request(t,{method:"POST",...e[0]})}put(t,...e){return this.request(t,{method:"PUT",...e[0]})}PUT(t,...e){return this.request(t,{method:"PUT",...e[0]})}delete(t,...e){return this.request(t,{method:"DELETE",...e[0]})}DELETE(t,...e){return this.request(t,{method:"DELETE",...e[0]})}patch(t,...e){return this.request(t,{method:"PATCH",...e[0]})}PATCH(t,...e){return this.request(t,{method:"PATCH",...e[0]})}request(t,...e){let{method:u,url:i}=O(t),n={...this.defaultOptions,...e[0]},p={...n,method:n.method||u};if(p.body&&a(p.body))p.body=JSON.stringify(p.body);let s=new Request(d(this.baseUrl,i,p.params),p);return fetch(s).then((A)=>o(s,A))}setDefaultOptions(t){this.defaultOptions=t}getBaseUrl(){return this.baseUrl}getDefaultOptions(){return this.defaultOptions}}function c(t,e){return new r(t,e)}export{c as createApi};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OPENAPI-TYPESCRIPT
|
|
3
|
+
* @param request
|
|
4
|
+
* @param response
|
|
5
|
+
* @param parseAs
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export declare function convertResponse(request: Request, response: Response, parseAs?: 'stream' | 'json' | 'text'): Promise<{
|
|
9
|
+
data?: unknown | undefined;
|
|
10
|
+
error?: unknown | undefined;
|
|
11
|
+
response: Response;
|
|
12
|
+
}>;
|
|
13
|
+
//# sourceMappingURL=response-converter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-converter.d.ts","sourceRoot":"","sources":["../src/response-converter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,QAAQ,GAAG,MAAM,GAAG,MAAe,GAC3C,OAAO,CAAC;IACT,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC1B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC3B,QAAQ,EAAE,QAAQ,CAAA;CACnB,CAAC,CA4BD"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { UrlMapValue } from '@devup-api/core';
|
|
2
|
+
export declare const DEVUP_API_URL_MAP: Record<string, UrlMapValue>;
|
|
3
|
+
export declare function getUrl(key: string): string;
|
|
4
|
+
export declare function getUrlWithMethod(key: string): UrlMapValue;
|
|
5
|
+
//# sourceMappingURL=url-map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-map.d.ts","sourceRoot":"","sources":["../src/url-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAElD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAEzD,CAAA;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1C;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAEzD"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,MAAM,CAKzD;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAMR"}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@devup-api/fetch",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"import": "./dist/index.js",
|
|
8
|
+
"require": "./dist/index.cjs",
|
|
9
|
+
"types": "./dist/index.d.ts"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc && bun build --target node --outfile=dist/index.js src/index.ts --production --packages=external && bun build --target node --outfile=dist/index.cjs --format=cjs src/index.ts --production --packages=external"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@devup-api/core": "0.1.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^24.10",
|
|
23
|
+
"typescript": "^5.9"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { afterEach, beforeEach, expect, mock, test } from 'bun:test'
|
|
2
|
+
import { DevupApi } from '../api'
|
|
3
|
+
|
|
4
|
+
const originalFetch = globalThis.fetch
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
globalThis.fetch = mock(() =>
|
|
8
|
+
Promise.resolve(
|
|
9
|
+
new Response(JSON.stringify({ success: true }), {
|
|
10
|
+
status: 200,
|
|
11
|
+
headers: { 'Content-Type': 'application/json' },
|
|
12
|
+
}),
|
|
13
|
+
),
|
|
14
|
+
) as unknown as typeof fetch
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
globalThis.fetch = originalFetch
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test.each([
|
|
22
|
+
['https://api.example.com', 'https://api.example.com'],
|
|
23
|
+
['https://api.example.com/', 'https://api.example.com'],
|
|
24
|
+
['http://localhost:3000', 'http://localhost:3000'],
|
|
25
|
+
['http://localhost:3000/', 'http://localhost:3000'],
|
|
26
|
+
] as const)('constructor removes trailing slash: %s -> %s', (baseUrl, expected) => {
|
|
27
|
+
const api = new DevupApi(baseUrl)
|
|
28
|
+
expect(api.getBaseUrl()).toBe(expected)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test.each([
|
|
32
|
+
[undefined, {}],
|
|
33
|
+
[{}, {}],
|
|
34
|
+
[
|
|
35
|
+
{ headers: { Authorization: 'Bearer token' } },
|
|
36
|
+
{ headers: { Authorization: 'Bearer token' } },
|
|
37
|
+
],
|
|
38
|
+
] as const)('constructor accepts defaultOptions: %s -> %s', (defaultOptions, expected) => {
|
|
39
|
+
const api = new DevupApi('https://api.example.com', defaultOptions)
|
|
40
|
+
expect(api.getDefaultOptions()).toEqual(expected)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test.each([
|
|
44
|
+
[{}, {}],
|
|
45
|
+
[
|
|
46
|
+
{ headers: { 'Content-Type': 'application/json' } },
|
|
47
|
+
{ headers: { 'Content-Type': 'application/json' } },
|
|
48
|
+
],
|
|
49
|
+
] as const)('setDefaultOptions updates defaultOptions: %s -> %s', (options, expected) => {
|
|
50
|
+
const api = new DevupApi('https://api.example.com')
|
|
51
|
+
api.setDefaultOptions(options)
|
|
52
|
+
expect(api.getDefaultOptions()).toEqual(expected)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test.each([
|
|
56
|
+
['GET', 'get'],
|
|
57
|
+
['GET', 'GET'],
|
|
58
|
+
['POST', 'post'],
|
|
59
|
+
['POST', 'POST'],
|
|
60
|
+
['PUT', 'put'],
|
|
61
|
+
['PUT', 'PUT'],
|
|
62
|
+
['DELETE', 'delete'],
|
|
63
|
+
['DELETE', 'DELETE'],
|
|
64
|
+
['PATCH', 'patch'],
|
|
65
|
+
['PATCH', 'PATCH'],
|
|
66
|
+
] as const)('HTTP method %s calls request with correct method', async (expectedMethod, methodName) => {
|
|
67
|
+
const api = new DevupApi('https://api.example.com')
|
|
68
|
+
const mockFetch = globalThis.fetch as unknown as ReturnType<typeof mock>
|
|
69
|
+
|
|
70
|
+
await api[methodName]('/test' as never)
|
|
71
|
+
|
|
72
|
+
expect(mockFetch).toHaveBeenCalledTimes(1)
|
|
73
|
+
const call = mockFetch.mock.calls[0]
|
|
74
|
+
expect(call).toBeDefined()
|
|
75
|
+
if (call) {
|
|
76
|
+
const request = call[0] as Request
|
|
77
|
+
expect(request.method).toBe(expectedMethod)
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('request serializes plain object body to JSON', async () => {
|
|
82
|
+
const api = new DevupApi('https://api.example.com')
|
|
83
|
+
const mockFetch = globalThis.fetch as unknown as ReturnType<typeof mock>
|
|
84
|
+
|
|
85
|
+
await api.post(
|
|
86
|
+
'/test' as never,
|
|
87
|
+
{
|
|
88
|
+
body: { name: 'test', value: 123 },
|
|
89
|
+
} as never,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
expect(mockFetch).toHaveBeenCalledTimes(1)
|
|
93
|
+
const call = mockFetch.mock.calls[0]
|
|
94
|
+
expect(call).toBeDefined()
|
|
95
|
+
if (call) {
|
|
96
|
+
const request = call[0] as Request
|
|
97
|
+
const body = await request.text()
|
|
98
|
+
expect(body).toBe(JSON.stringify({ name: 'test', value: 123 }))
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
test('request does not serialize non-plain object body', async () => {
|
|
103
|
+
const api = new DevupApi('https://api.example.com')
|
|
104
|
+
const mockFetch = globalThis.fetch as unknown as ReturnType<typeof mock>
|
|
105
|
+
const formData = new FormData()
|
|
106
|
+
formData.append('file', 'test')
|
|
107
|
+
|
|
108
|
+
await api.post(
|
|
109
|
+
'/test' as never,
|
|
110
|
+
{
|
|
111
|
+
body: formData,
|
|
112
|
+
} as never,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
expect(mockFetch).toHaveBeenCalledTimes(1)
|
|
116
|
+
const call = mockFetch.mock.calls[0]
|
|
117
|
+
expect(call).toBeDefined()
|
|
118
|
+
if (call) {
|
|
119
|
+
const request = call[0] as Request
|
|
120
|
+
// FormData should not be serialized with JSON.stringify and should be passed as-is
|
|
121
|
+
// Request body should not be null
|
|
122
|
+
expect(request.body).not.toBeNull()
|
|
123
|
+
// FormData is automatically set to multipart/form-data
|
|
124
|
+
// body should exist
|
|
125
|
+
expect(request.body).toBeDefined()
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
test('request merges defaultOptions with request options', async () => {
|
|
130
|
+
const api = new DevupApi('https://api.example.com', {
|
|
131
|
+
headers: { 'X-Default': 'default-value' },
|
|
132
|
+
})
|
|
133
|
+
const mockFetch = globalThis.fetch as unknown as ReturnType<typeof mock>
|
|
134
|
+
|
|
135
|
+
await api.get(
|
|
136
|
+
'/test' as never,
|
|
137
|
+
{
|
|
138
|
+
headers: { 'X-Request': 'request-value' },
|
|
139
|
+
} as never,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
expect(mockFetch).toHaveBeenCalledTimes(1)
|
|
143
|
+
const call = mockFetch.mock.calls[0]
|
|
144
|
+
expect(call).toBeDefined()
|
|
145
|
+
if (call) {
|
|
146
|
+
const request = call[0] as Request
|
|
147
|
+
// Headers are merged, but we can't easily test the merged result
|
|
148
|
+
// So we just verify the request was made
|
|
149
|
+
expect(request).toBeDefined()
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
test('request uses params to replace path parameters', async () => {
|
|
154
|
+
const api = new DevupApi('https://api.example.com')
|
|
155
|
+
const mockFetch = globalThis.fetch as unknown as ReturnType<typeof mock>
|
|
156
|
+
|
|
157
|
+
await api.get(
|
|
158
|
+
'/users/{id}' as never,
|
|
159
|
+
{
|
|
160
|
+
params: { id: '123' },
|
|
161
|
+
} as never,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
expect(mockFetch).toHaveBeenCalledTimes(1)
|
|
165
|
+
const call = mockFetch.mock.calls[0]
|
|
166
|
+
expect(call).toBeDefined()
|
|
167
|
+
if (call) {
|
|
168
|
+
const request = call[0] as Request
|
|
169
|
+
expect(request.url).toBe('https://api.example.com/users/123')
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
test('request returns response with data on success', async () => {
|
|
174
|
+
globalThis.fetch = mock(() =>
|
|
175
|
+
Promise.resolve(
|
|
176
|
+
new Response(JSON.stringify({ id: 1, name: 'test' }), {
|
|
177
|
+
status: 200,
|
|
178
|
+
headers: { 'Content-Type': 'application/json' },
|
|
179
|
+
}),
|
|
180
|
+
),
|
|
181
|
+
) as unknown as typeof fetch
|
|
182
|
+
|
|
183
|
+
const api = new DevupApi('https://api.example.com')
|
|
184
|
+
const result = (await api.get('/test' as never)) as {
|
|
185
|
+
data?: unknown
|
|
186
|
+
error?: unknown
|
|
187
|
+
response: Response
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
expect('data' in result).toBe(true)
|
|
191
|
+
if ('data' in result && result.data !== undefined) {
|
|
192
|
+
expect(result.data).toEqual({ id: 1, name: 'test' })
|
|
193
|
+
}
|
|
194
|
+
expect('error' in result).toBe(false)
|
|
195
|
+
expect(result.response).toBeDefined()
|
|
196
|
+
expect(result.response.ok).toBe(true)
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
test('request returns response with error on failure', async () => {
|
|
200
|
+
globalThis.fetch = mock(() =>
|
|
201
|
+
Promise.resolve(
|
|
202
|
+
new Response(JSON.stringify({ message: 'Not found' }), {
|
|
203
|
+
status: 404,
|
|
204
|
+
headers: { 'Content-Type': 'application/json' },
|
|
205
|
+
}),
|
|
206
|
+
),
|
|
207
|
+
) as unknown as typeof fetch
|
|
208
|
+
|
|
209
|
+
const api = new DevupApi('https://api.example.com')
|
|
210
|
+
const result = (await api.get('/test' as never)) as {
|
|
211
|
+
data?: unknown
|
|
212
|
+
error?: unknown
|
|
213
|
+
response: Response
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
expect('error' in result).toBe(true)
|
|
217
|
+
if ('error' in result && result.error !== undefined) {
|
|
218
|
+
expect(result.error).toEqual({ message: 'Not found' })
|
|
219
|
+
}
|
|
220
|
+
expect('data' in result).toBe(false)
|
|
221
|
+
expect(result.response).toBeDefined()
|
|
222
|
+
expect(result.response.ok).toBe(false)
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
test('request handles 204 No Content response', async () => {
|
|
226
|
+
globalThis.fetch = mock(() =>
|
|
227
|
+
Promise.resolve(
|
|
228
|
+
new Response(null, {
|
|
229
|
+
status: 204,
|
|
230
|
+
}),
|
|
231
|
+
),
|
|
232
|
+
) as unknown as typeof fetch
|
|
233
|
+
|
|
234
|
+
const api = new DevupApi('https://api.example.com')
|
|
235
|
+
const result = await api.delete('/test' as never)
|
|
236
|
+
|
|
237
|
+
if ('data' in result) {
|
|
238
|
+
expect(result.data).toBeUndefined()
|
|
239
|
+
}
|
|
240
|
+
if ('error' in result) {
|
|
241
|
+
expect(result.error).toBeUndefined()
|
|
242
|
+
}
|
|
243
|
+
expect(result.response).toBeDefined()
|
|
244
|
+
expect(result.response.status).toBe(204)
|
|
245
|
+
})
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
|
+
import { DevupApi } from '../api'
|
|
3
|
+
import { createApi } from '../create-api'
|
|
4
|
+
|
|
5
|
+
test.each([
|
|
6
|
+
['https://api.example.com'],
|
|
7
|
+
['https://api.example.com/'],
|
|
8
|
+
['http://localhost:3000'],
|
|
9
|
+
['http://localhost:3000/'],
|
|
10
|
+
] as const)('createApi returns DevupApi instance: %s', (baseUrl) => {
|
|
11
|
+
const api = createApi(baseUrl)
|
|
12
|
+
expect(api).toBeInstanceOf(DevupApi)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test.each([
|
|
16
|
+
['https://api.example.com', undefined],
|
|
17
|
+
['https://api.example.com', {}],
|
|
18
|
+
['https://api.example.com', { headers: { Authorization: 'Bearer token' } }],
|
|
19
|
+
] as const)('createApi accepts defaultOptions: %s', (baseUrl, defaultOptions) => {
|
|
20
|
+
const api = createApi(baseUrl, defaultOptions)
|
|
21
|
+
expect(api).toBeInstanceOf(DevupApi)
|
|
22
|
+
if (defaultOptions) {
|
|
23
|
+
expect(api.getDefaultOptions()).toEqual(defaultOptions)
|
|
24
|
+
}
|
|
25
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
|
+
import * as indexModule from '../index'
|
|
3
|
+
|
|
4
|
+
// Type imports to verify types are exported (compile-time check)
|
|
5
|
+
|
|
6
|
+
test('index.ts exports', () => {
|
|
7
|
+
expect({ ...indexModule }).toEqual({
|
|
8
|
+
createApi: expect.any(Function),
|
|
9
|
+
})
|
|
10
|
+
})
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
|
+
import { convertResponse } from '../response-converter'
|
|
3
|
+
|
|
4
|
+
test.each([
|
|
5
|
+
['json', 'json'],
|
|
6
|
+
['text', 'text'],
|
|
7
|
+
['stream', 'stream'],
|
|
8
|
+
] as const)('convertResponse parses successful response with parseAs=%s', async (parseAs) => {
|
|
9
|
+
const request = new Request('https://api.example.com/test', { method: 'GET' })
|
|
10
|
+
const response = new Response(JSON.stringify({ id: 1, name: 'test' }), {
|
|
11
|
+
status: 200,
|
|
12
|
+
headers: { 'Content-Type': 'application/json' },
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const result = await convertResponse(request, response, parseAs)
|
|
16
|
+
|
|
17
|
+
expect('data' in result).toBe(true)
|
|
18
|
+
if ('data' in result) {
|
|
19
|
+
if (parseAs === 'stream') {
|
|
20
|
+
expect(result.data).toBeDefined()
|
|
21
|
+
} else if (parseAs === 'text') {
|
|
22
|
+
expect(typeof result.data).toBe('string')
|
|
23
|
+
} else {
|
|
24
|
+
expect(result.data).toEqual({ id: 1, name: 'test' })
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
expect(result.response).toBe(response)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('convertResponse handles 204 No Content with success', async () => {
|
|
31
|
+
const request = new Request('https://api.example.com/test', {
|
|
32
|
+
method: 'DELETE',
|
|
33
|
+
})
|
|
34
|
+
const response = new Response(null, {
|
|
35
|
+
status: 204,
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const result = await convertResponse(request, response)
|
|
39
|
+
|
|
40
|
+
if ('data' in result) {
|
|
41
|
+
expect(result.data).toBeUndefined()
|
|
42
|
+
}
|
|
43
|
+
expect(result.response).toBe(response)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('convertResponse handles 204 No Content with error', async () => {
|
|
47
|
+
const request = new Request('https://api.example.com/test', {
|
|
48
|
+
method: 'DELETE',
|
|
49
|
+
})
|
|
50
|
+
const response = new Response(null, {
|
|
51
|
+
status: 204,
|
|
52
|
+
statusText: 'No Content',
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// Mock response.ok to be false
|
|
56
|
+
Object.defineProperty(response, 'ok', {
|
|
57
|
+
value: false,
|
|
58
|
+
writable: false,
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const result = await convertResponse(request, response)
|
|
62
|
+
|
|
63
|
+
if ('error' in result) {
|
|
64
|
+
expect(result.error).toBeUndefined()
|
|
65
|
+
}
|
|
66
|
+
expect(result.response).toBe(response)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('convertResponse handles HEAD request', async () => {
|
|
70
|
+
const request = new Request('https://api.example.com/test', {
|
|
71
|
+
method: 'HEAD',
|
|
72
|
+
})
|
|
73
|
+
const response = new Response(null, {
|
|
74
|
+
status: 200,
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const result = await convertResponse(request, response)
|
|
78
|
+
|
|
79
|
+
if ('data' in result) {
|
|
80
|
+
expect(result.data).toBeUndefined()
|
|
81
|
+
}
|
|
82
|
+
expect(result.response).toBe(response)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test('convertResponse handles Content-Length: 0', async () => {
|
|
86
|
+
const request = new Request('https://api.example.com/test', { method: 'GET' })
|
|
87
|
+
const response = new Response(null, {
|
|
88
|
+
status: 200,
|
|
89
|
+
headers: { 'Content-Length': '0' },
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const result = await convertResponse(request, response)
|
|
93
|
+
|
|
94
|
+
if ('data' in result) {
|
|
95
|
+
expect(result.data).toBeUndefined()
|
|
96
|
+
}
|
|
97
|
+
expect(result.response).toBe(response)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
test('convertResponse handles error response with JSON', async () => {
|
|
101
|
+
const request = new Request('https://api.example.com/test', { method: 'GET' })
|
|
102
|
+
const response = new Response(JSON.stringify({ message: 'Not found' }), {
|
|
103
|
+
status: 404,
|
|
104
|
+
headers: { 'Content-Type': 'application/json' },
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
const result = await convertResponse(request, response)
|
|
108
|
+
|
|
109
|
+
if ('error' in result) {
|
|
110
|
+
expect(result.error).toEqual({ message: 'Not found' })
|
|
111
|
+
}
|
|
112
|
+
expect(result.response).toBe(response)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
test('convertResponse handles error response with non-JSON text', async () => {
|
|
116
|
+
const request = new Request('https://api.example.com/test', { method: 'GET' })
|
|
117
|
+
const response = new Response('Internal Server Error', {
|
|
118
|
+
status: 500,
|
|
119
|
+
headers: { 'Content-Type': 'text/plain' },
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
const result = await convertResponse(request, response)
|
|
123
|
+
|
|
124
|
+
if ('error' in result) {
|
|
125
|
+
expect(result.error).toBe('Internal Server Error')
|
|
126
|
+
}
|
|
127
|
+
expect(result.response).toBe(response)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
test('convertResponse handles error response with invalid JSON', async () => {
|
|
131
|
+
const request = new Request('https://api.example.com/test', { method: 'GET' })
|
|
132
|
+
const response = new Response('Invalid JSON{', {
|
|
133
|
+
status: 400,
|
|
134
|
+
headers: { 'Content-Type': 'application/json' },
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
const result = await convertResponse(request, response)
|
|
138
|
+
|
|
139
|
+
if ('error' in result) {
|
|
140
|
+
expect(result.error).toBe('Invalid JSON{')
|
|
141
|
+
}
|
|
142
|
+
expect(result.response).toBe(response)
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
test('convertResponse handles non-204 error with Content-Length: 0', async () => {
|
|
146
|
+
const request = new Request('https://api.example.com/test', { method: 'GET' })
|
|
147
|
+
const response = new Response(null, {
|
|
148
|
+
status: 500,
|
|
149
|
+
headers: { 'Content-Length': '0' },
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
const result = await convertResponse(request, response)
|
|
153
|
+
|
|
154
|
+
if ('error' in result) {
|
|
155
|
+
expect(result.error).toBeUndefined()
|
|
156
|
+
}
|
|
157
|
+
expect(result.response).toBe(response)
|
|
158
|
+
})
|