make-service 0.0.3 → 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 +8 -8
- package/dist/index.d.ts +9 -3
- package/dist/index.js +40 -9
- package/dist/index.mjs +39 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -155,21 +155,21 @@ import { typedResponse } from 'make-service'
|
|
|
155
155
|
import type { TypedResponse } from 'make-service'
|
|
156
156
|
|
|
157
157
|
// With JSON
|
|
158
|
-
const response: TypedResponse = new Response(JSON.stringify({ foo: "bar" }))
|
|
159
|
-
const json = await
|
|
158
|
+
const response: TypedResponse = typedResponse(new Response(JSON.stringify({ foo: "bar" })))
|
|
159
|
+
const json = await response.json()
|
|
160
160
|
// ^? unknown
|
|
161
|
-
const json = await
|
|
161
|
+
const json = await response.json<{ foo: string }>()
|
|
162
162
|
// ^? { foo: string }
|
|
163
|
-
const json = await
|
|
163
|
+
const json = await response.json(z.object({ foo: z.string() }))
|
|
164
164
|
// ^? { foo: string }
|
|
165
165
|
|
|
166
166
|
// With text
|
|
167
|
-
const response: TypedResponse = new Response("foo")
|
|
168
|
-
const text = await
|
|
167
|
+
const response: TypedResponse = typedResponse(new Response("foo"))
|
|
168
|
+
const text = await response.text()
|
|
169
169
|
// ^? string
|
|
170
|
-
const text = await
|
|
170
|
+
const text = await response.text<`foo${string}`>()
|
|
171
171
|
// ^? `foo${string}`
|
|
172
|
-
const text = await
|
|
172
|
+
const text = await response.text(z.string().email())
|
|
173
173
|
// ^? string
|
|
174
174
|
```
|
|
175
175
|
|
package/dist/index.d.ts
CHANGED
|
@@ -33,6 +33,12 @@ type HTTPMethod = (typeof HTTP_METHODS)[number];
|
|
|
33
33
|
type TypedResponseJson = ReturnType<typeof getJson>;
|
|
34
34
|
type TypedResponseText = ReturnType<typeof getText>;
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* It merges multiple HeadersInit objects into a single Headers object
|
|
38
|
+
* @param entries Any number of HeadersInit objects
|
|
39
|
+
* @returns a new Headers object with the merged headers
|
|
40
|
+
*/
|
|
41
|
+
declare function mergeHeaders(...entries: (HeadersInit | [string, undefined][] | Record<string, undefined>)[]): Headers;
|
|
36
42
|
/**
|
|
37
43
|
* @param input a string or URL to which the query parameters will be added
|
|
38
44
|
* @param searchParams the query parameters
|
|
@@ -43,7 +49,7 @@ declare function addQueryToInput(input: string | URL, searchParams?: SearchParam
|
|
|
43
49
|
* @param baseURL the base path to the API
|
|
44
50
|
* @returns a function that receives a path and an object of query parameters and returns a URL
|
|
45
51
|
*/
|
|
46
|
-
declare function makeGetApiUrl(baseURL: string): (path: string, searchParams?: SearchParams) => string | URL;
|
|
52
|
+
declare function makeGetApiUrl(baseURL: string | URL): (path: string, searchParams?: SearchParams) => string | URL;
|
|
47
53
|
/**
|
|
48
54
|
* It hacks the Response object to add typed json and text methods
|
|
49
55
|
* @param response the Response to be proxied
|
|
@@ -90,7 +96,7 @@ declare function enhancedFetch(input: string | URL, requestInit?: EnhancedReques
|
|
|
90
96
|
* const users = await response.json(userSchema);
|
|
91
97
|
* // ^? User[]
|
|
92
98
|
*/
|
|
93
|
-
declare function makeService(baseURL: string, baseHeaders?: HeadersInit): {
|
|
99
|
+
declare function makeService(baseURL: string | URL, baseHeaders?: HeadersInit): {
|
|
94
100
|
get: (path: string, requestInit?: ServiceRequestInit) => Promise<TypedResponse>;
|
|
95
101
|
post: (path: string, requestInit?: ServiceRequestInit) => Promise<TypedResponse>;
|
|
96
102
|
put: (path: string, requestInit?: ServiceRequestInit) => Promise<TypedResponse>;
|
|
@@ -100,4 +106,4 @@ declare function makeService(baseURL: string, baseHeaders?: HeadersInit): {
|
|
|
100
106
|
head: (path: string, requestInit?: ServiceRequestInit) => Promise<TypedResponse>;
|
|
101
107
|
};
|
|
102
108
|
|
|
103
|
-
export { EnhancedRequestInit, HTTPMethod, JSONValue, Schema, SearchParams, ServiceRequestInit, TypedResponse, TypedResponseJson, TypedResponseText, addQueryToInput, enhancedFetch, ensureStringBody, makeGetApiUrl, makeService, typedResponse };
|
|
109
|
+
export { EnhancedRequestInit, HTTPMethod, JSONValue, Schema, SearchParams, ServiceRequestInit, TypedResponse, TypedResponseJson, TypedResponseText, addQueryToInput, enhancedFetch, ensureStringBody, makeGetApiUrl, makeService, mergeHeaders, typedResponse };
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ __export(src_exports, {
|
|
|
25
25
|
ensureStringBody: () => ensureStringBody,
|
|
26
26
|
makeGetApiUrl: () => makeGetApiUrl,
|
|
27
27
|
makeService: () => makeService,
|
|
28
|
+
mergeHeaders: () => mergeHeaders,
|
|
28
29
|
typedResponse: () => typedResponse
|
|
29
30
|
});
|
|
30
31
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -61,20 +62,42 @@ function isHTTPMethod(method) {
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
// src/make-service.ts
|
|
65
|
+
function mergeHeaders(...entries) {
|
|
66
|
+
const result = /* @__PURE__ */ new Map();
|
|
67
|
+
for (const entry of entries) {
|
|
68
|
+
const headers = new Headers(entry);
|
|
69
|
+
for (const [key, value] of headers.entries()) {
|
|
70
|
+
if (value === void 0 || value === "undefined") {
|
|
71
|
+
result.delete(key);
|
|
72
|
+
} else {
|
|
73
|
+
result.set(key, value);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return new Headers(Array.from(result.entries()));
|
|
78
|
+
}
|
|
64
79
|
function addQueryToInput(input, searchParams) {
|
|
65
80
|
if (!searchParams)
|
|
66
81
|
return input;
|
|
67
|
-
if (
|
|
82
|
+
if (typeof input === "string") {
|
|
68
83
|
const separator = input.includes("?") ? "&" : "?";
|
|
69
84
|
return `${input}${separator}${new URLSearchParams(searchParams)}`;
|
|
70
85
|
}
|
|
71
86
|
if (searchParams && input instanceof URL) {
|
|
72
|
-
|
|
87
|
+
for (const [key, value] of Object.entries(
|
|
88
|
+
new URLSearchParams(searchParams)
|
|
89
|
+
)) {
|
|
90
|
+
input.searchParams.set(key, value);
|
|
91
|
+
}
|
|
73
92
|
}
|
|
74
93
|
return input;
|
|
75
94
|
}
|
|
76
95
|
function makeGetApiUrl(baseURL) {
|
|
77
|
-
|
|
96
|
+
const base = baseURL instanceof URL ? baseURL.toString() : baseURL;
|
|
97
|
+
return (path, searchParams) => {
|
|
98
|
+
const url = `${base}${path}`.replace(/([^https?:]\/)\/+/g, "$1");
|
|
99
|
+
return addQueryToInput(url, searchParams);
|
|
100
|
+
};
|
|
78
101
|
}
|
|
79
102
|
function typedResponse(response) {
|
|
80
103
|
return new Proxy(response, {
|
|
@@ -95,23 +118,30 @@ function ensureStringBody(body) {
|
|
|
95
118
|
return JSON.stringify(body);
|
|
96
119
|
}
|
|
97
120
|
async function enhancedFetch(input, requestInit) {
|
|
121
|
+
var _a;
|
|
98
122
|
const { query, trace, ...reqInit } = requestInit != null ? requestInit : {};
|
|
99
|
-
const headers =
|
|
123
|
+
const headers = mergeHeaders(
|
|
124
|
+
{
|
|
125
|
+
"content-type": "application/json"
|
|
126
|
+
},
|
|
127
|
+
(_a = reqInit.headers) != null ? _a : {}
|
|
128
|
+
);
|
|
100
129
|
const url = addQueryToInput(input, query);
|
|
101
130
|
const body = ensureStringBody(reqInit.body);
|
|
102
131
|
const enhancedReqInit = { ...reqInit, headers, body };
|
|
103
132
|
trace == null ? void 0 : trace(url, enhancedReqInit);
|
|
104
|
-
const
|
|
105
|
-
const response = await fetch(request);
|
|
133
|
+
const response = await fetch(url, enhancedReqInit);
|
|
106
134
|
return typedResponse(response);
|
|
107
135
|
}
|
|
108
136
|
function makeService(baseURL, baseHeaders) {
|
|
109
137
|
const service = (method) => {
|
|
110
138
|
return async (path, requestInit = {}) => {
|
|
111
|
-
|
|
139
|
+
var _a;
|
|
140
|
+
const url = makeGetApiUrl(baseURL)(path);
|
|
141
|
+
const response = await enhancedFetch(url, {
|
|
112
142
|
...requestInit,
|
|
113
143
|
method,
|
|
114
|
-
headers:
|
|
144
|
+
headers: mergeHeaders(baseHeaders != null ? baseHeaders : {}, (_a = requestInit == null ? void 0 : requestInit.headers) != null ? _a : {})
|
|
115
145
|
});
|
|
116
146
|
return response;
|
|
117
147
|
};
|
|
@@ -119,7 +149,7 @@ function makeService(baseURL, baseHeaders) {
|
|
|
119
149
|
return new Proxy({}, {
|
|
120
150
|
get(_target, prop) {
|
|
121
151
|
if (isHTTPMethod(prop))
|
|
122
|
-
return service(prop);
|
|
152
|
+
return service(prop.toUpperCase());
|
|
123
153
|
throw new Error(`Invalid HTTP method: ${prop.toString()}`);
|
|
124
154
|
}
|
|
125
155
|
});
|
|
@@ -131,5 +161,6 @@ function makeService(baseURL, baseHeaders) {
|
|
|
131
161
|
ensureStringBody,
|
|
132
162
|
makeGetApiUrl,
|
|
133
163
|
makeService,
|
|
164
|
+
mergeHeaders,
|
|
134
165
|
typedResponse
|
|
135
166
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -30,20 +30,42 @@ function isHTTPMethod(method) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// src/make-service.ts
|
|
33
|
+
function mergeHeaders(...entries) {
|
|
34
|
+
const result = /* @__PURE__ */ new Map();
|
|
35
|
+
for (const entry of entries) {
|
|
36
|
+
const headers = new Headers(entry);
|
|
37
|
+
for (const [key, value] of headers.entries()) {
|
|
38
|
+
if (value === void 0 || value === "undefined") {
|
|
39
|
+
result.delete(key);
|
|
40
|
+
} else {
|
|
41
|
+
result.set(key, value);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return new Headers(Array.from(result.entries()));
|
|
46
|
+
}
|
|
33
47
|
function addQueryToInput(input, searchParams) {
|
|
34
48
|
if (!searchParams)
|
|
35
49
|
return input;
|
|
36
|
-
if (
|
|
50
|
+
if (typeof input === "string") {
|
|
37
51
|
const separator = input.includes("?") ? "&" : "?";
|
|
38
52
|
return `${input}${separator}${new URLSearchParams(searchParams)}`;
|
|
39
53
|
}
|
|
40
54
|
if (searchParams && input instanceof URL) {
|
|
41
|
-
|
|
55
|
+
for (const [key, value] of Object.entries(
|
|
56
|
+
new URLSearchParams(searchParams)
|
|
57
|
+
)) {
|
|
58
|
+
input.searchParams.set(key, value);
|
|
59
|
+
}
|
|
42
60
|
}
|
|
43
61
|
return input;
|
|
44
62
|
}
|
|
45
63
|
function makeGetApiUrl(baseURL) {
|
|
46
|
-
|
|
64
|
+
const base = baseURL instanceof URL ? baseURL.toString() : baseURL;
|
|
65
|
+
return (path, searchParams) => {
|
|
66
|
+
const url = `${base}${path}`.replace(/([^https?:]\/)\/+/g, "$1");
|
|
67
|
+
return addQueryToInput(url, searchParams);
|
|
68
|
+
};
|
|
47
69
|
}
|
|
48
70
|
function typedResponse(response) {
|
|
49
71
|
return new Proxy(response, {
|
|
@@ -64,23 +86,30 @@ function ensureStringBody(body) {
|
|
|
64
86
|
return JSON.stringify(body);
|
|
65
87
|
}
|
|
66
88
|
async function enhancedFetch(input, requestInit) {
|
|
89
|
+
var _a;
|
|
67
90
|
const { query, trace, ...reqInit } = requestInit != null ? requestInit : {};
|
|
68
|
-
const headers =
|
|
91
|
+
const headers = mergeHeaders(
|
|
92
|
+
{
|
|
93
|
+
"content-type": "application/json"
|
|
94
|
+
},
|
|
95
|
+
(_a = reqInit.headers) != null ? _a : {}
|
|
96
|
+
);
|
|
69
97
|
const url = addQueryToInput(input, query);
|
|
70
98
|
const body = ensureStringBody(reqInit.body);
|
|
71
99
|
const enhancedReqInit = { ...reqInit, headers, body };
|
|
72
100
|
trace == null ? void 0 : trace(url, enhancedReqInit);
|
|
73
|
-
const
|
|
74
|
-
const response = await fetch(request);
|
|
101
|
+
const response = await fetch(url, enhancedReqInit);
|
|
75
102
|
return typedResponse(response);
|
|
76
103
|
}
|
|
77
104
|
function makeService(baseURL, baseHeaders) {
|
|
78
105
|
const service = (method) => {
|
|
79
106
|
return async (path, requestInit = {}) => {
|
|
80
|
-
|
|
107
|
+
var _a;
|
|
108
|
+
const url = makeGetApiUrl(baseURL)(path);
|
|
109
|
+
const response = await enhancedFetch(url, {
|
|
81
110
|
...requestInit,
|
|
82
111
|
method,
|
|
83
|
-
headers:
|
|
112
|
+
headers: mergeHeaders(baseHeaders != null ? baseHeaders : {}, (_a = requestInit == null ? void 0 : requestInit.headers) != null ? _a : {})
|
|
84
113
|
});
|
|
85
114
|
return response;
|
|
86
115
|
};
|
|
@@ -88,7 +117,7 @@ function makeService(baseURL, baseHeaders) {
|
|
|
88
117
|
return new Proxy({}, {
|
|
89
118
|
get(_target, prop) {
|
|
90
119
|
if (isHTTPMethod(prop))
|
|
91
|
-
return service(prop);
|
|
120
|
+
return service(prop.toUpperCase());
|
|
92
121
|
throw new Error(`Invalid HTTP method: ${prop.toString()}`);
|
|
93
122
|
}
|
|
94
123
|
});
|
|
@@ -99,5 +128,6 @@ export {
|
|
|
99
128
|
ensureStringBody,
|
|
100
129
|
makeGetApiUrl,
|
|
101
130
|
makeService,
|
|
131
|
+
mergeHeaders,
|
|
102
132
|
typedResponse
|
|
103
133
|
};
|