make-service 4.0.2 → 4.1.1
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 +0 -6
- package/dist/index.d.mts +32 -7
- package/dist/index.d.ts +32 -7
- package/dist/index.js +19 -11
- package/dist/index.mjs +19 -11
- package/package.json +2 -5
package/README.md
CHANGED
|
@@ -74,12 +74,6 @@ Or you can use it with Deno:
|
|
|
74
74
|
import { makeService } from "https://deno.land/x/make_service/mod.ts";
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
If you want to use it with a schema parser - such as [zod](https://zod.dev/), [arktype](https://arktype.dev/), [valibot](https://valibot.dev/), or other [standard-schema](https://standardschema.dev) libraries -, you need to install it as a peer dependency:
|
|
78
|
-
|
|
79
|
-
```sh
|
|
80
|
-
npm install make-service @standard-schema/spec
|
|
81
|
-
```
|
|
82
|
-
|
|
83
77
|
# API
|
|
84
78
|
|
|
85
79
|
This library exports the `makeService` function and some primitives used to build it. You can use the primitives as you wish but the `makeService` will have all the features combined.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,32 @@
|
|
|
1
|
-
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
-
|
|
3
1
|
declare const HTTP_METHODS: readonly ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD", "CONNECT"];
|
|
4
2
|
|
|
3
|
+
/** A minimal subset of the Standard Schema specification used internally */
|
|
4
|
+
interface StandardSchema<Input = unknown, Output = Input> {
|
|
5
|
+
readonly '~standard': StandardSchema.Props<Input, Output>;
|
|
6
|
+
}
|
|
7
|
+
declare namespace StandardSchema {
|
|
8
|
+
interface Props<Input = unknown, Output = Input> {
|
|
9
|
+
readonly version: 1;
|
|
10
|
+
readonly vendor: string;
|
|
11
|
+
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
12
|
+
}
|
|
13
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
14
|
+
interface SuccessResult<Output> {
|
|
15
|
+
readonly value: Output;
|
|
16
|
+
readonly issues?: undefined;
|
|
17
|
+
}
|
|
18
|
+
interface FailureResult {
|
|
19
|
+
readonly issues: readonly Issue[];
|
|
20
|
+
}
|
|
21
|
+
interface Issue {
|
|
22
|
+
readonly message: string;
|
|
23
|
+
readonly path?: readonly (PropertyKey | PathSegment)[];
|
|
24
|
+
}
|
|
25
|
+
interface PathSegment {
|
|
26
|
+
readonly key: PropertyKey;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
5
30
|
type JSONValue = string | number | boolean | Date | {
|
|
6
31
|
[x: string]: JSONValue | undefined | null;
|
|
7
32
|
} | Array<JSONValue | undefined | null>;
|
|
@@ -27,8 +52,8 @@ type BaseOptions = {
|
|
|
27
52
|
responseTransformer?: ResponseTransformer;
|
|
28
53
|
};
|
|
29
54
|
type HTTPMethod = (typeof HTTP_METHODS)[number];
|
|
30
|
-
type TypedResponseJson = <Input = unknown, Output = Input>(schema?:
|
|
31
|
-
type TypedResponseText = <Input extends string = string, Output = Input>(schema?:
|
|
55
|
+
type TypedResponseJson = <Input = unknown, Output = Input>(schema?: StandardSchema<Input, Output>) => Promise<Output>;
|
|
56
|
+
type TypedResponseText = <Input extends string = string, Output = Input>(schema?: StandardSchema<Input, Output>) => Promise<Output>;
|
|
32
57
|
type GetJson = (response: Response) => TypedResponseJson;
|
|
33
58
|
type GetText = (response: Response) => TypedResponseText;
|
|
34
59
|
type Prettify<T> = {
|
|
@@ -143,8 +168,8 @@ declare function typeOf(t: unknown): "array" | "arraybuffer" | "bigint" | "blob"
|
|
|
143
168
|
* Error thrown when the response cannot be parsed.
|
|
144
169
|
*/
|
|
145
170
|
declare class ParseResponseError extends Error {
|
|
146
|
-
issues: readonly
|
|
147
|
-
constructor(message: string, issues: readonly
|
|
171
|
+
issues: readonly StandardSchema.Issue[];
|
|
172
|
+
constructor(message: string, issues: readonly StandardSchema.Issue[]);
|
|
148
173
|
}
|
|
149
174
|
|
|
150
|
-
export { type BaseOptions, type EnhancedRequestInit, type GetJson, type GetText, type HTTPMethod, type JSONValue, ParseResponseError, type PathParams, type RequestTransformer, type ResponseTransformer, type SearchParams, type ServiceRequestInit, type TypedResponse, type TypedResponseJson, type TypedResponseText, addQueryToURL, enhancedFetch, ensureStringBody, makeFetcher, makeGetApiURL, makeService, mergeHeaders, replaceURLParams, typeOf, typedResponse };
|
|
175
|
+
export { type BaseOptions, type EnhancedRequestInit, type GetJson, type GetText, type HTTPMethod, type JSONValue, ParseResponseError, type PathParams, type RequestTransformer, type ResponseTransformer, type SearchParams, type ServiceRequestInit, StandardSchema, type TypedResponse, type TypedResponseJson, type TypedResponseText, addQueryToURL, enhancedFetch, ensureStringBody, makeFetcher, makeGetApiURL, makeService, mergeHeaders, replaceURLParams, typeOf, typedResponse };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,32 @@
|
|
|
1
|
-
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
-
|
|
3
1
|
declare const HTTP_METHODS: readonly ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD", "CONNECT"];
|
|
4
2
|
|
|
3
|
+
/** A minimal subset of the Standard Schema specification used internally */
|
|
4
|
+
interface StandardSchema<Input = unknown, Output = Input> {
|
|
5
|
+
readonly '~standard': StandardSchema.Props<Input, Output>;
|
|
6
|
+
}
|
|
7
|
+
declare namespace StandardSchema {
|
|
8
|
+
interface Props<Input = unknown, Output = Input> {
|
|
9
|
+
readonly version: 1;
|
|
10
|
+
readonly vendor: string;
|
|
11
|
+
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
12
|
+
}
|
|
13
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
14
|
+
interface SuccessResult<Output> {
|
|
15
|
+
readonly value: Output;
|
|
16
|
+
readonly issues?: undefined;
|
|
17
|
+
}
|
|
18
|
+
interface FailureResult {
|
|
19
|
+
readonly issues: readonly Issue[];
|
|
20
|
+
}
|
|
21
|
+
interface Issue {
|
|
22
|
+
readonly message: string;
|
|
23
|
+
readonly path?: readonly (PropertyKey | PathSegment)[];
|
|
24
|
+
}
|
|
25
|
+
interface PathSegment {
|
|
26
|
+
readonly key: PropertyKey;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
5
30
|
type JSONValue = string | number | boolean | Date | {
|
|
6
31
|
[x: string]: JSONValue | undefined | null;
|
|
7
32
|
} | Array<JSONValue | undefined | null>;
|
|
@@ -27,8 +52,8 @@ type BaseOptions = {
|
|
|
27
52
|
responseTransformer?: ResponseTransformer;
|
|
28
53
|
};
|
|
29
54
|
type HTTPMethod = (typeof HTTP_METHODS)[number];
|
|
30
|
-
type TypedResponseJson = <Input = unknown, Output = Input>(schema?:
|
|
31
|
-
type TypedResponseText = <Input extends string = string, Output = Input>(schema?:
|
|
55
|
+
type TypedResponseJson = <Input = unknown, Output = Input>(schema?: StandardSchema<Input, Output>) => Promise<Output>;
|
|
56
|
+
type TypedResponseText = <Input extends string = string, Output = Input>(schema?: StandardSchema<Input, Output>) => Promise<Output>;
|
|
32
57
|
type GetJson = (response: Response) => TypedResponseJson;
|
|
33
58
|
type GetText = (response: Response) => TypedResponseText;
|
|
34
59
|
type Prettify<T> = {
|
|
@@ -143,8 +168,8 @@ declare function typeOf(t: unknown): "array" | "arraybuffer" | "bigint" | "blob"
|
|
|
143
168
|
* Error thrown when the response cannot be parsed.
|
|
144
169
|
*/
|
|
145
170
|
declare class ParseResponseError extends Error {
|
|
146
|
-
issues: readonly
|
|
147
|
-
constructor(message: string, issues: readonly
|
|
171
|
+
issues: readonly StandardSchema.Issue[];
|
|
172
|
+
constructor(message: string, issues: readonly StandardSchema.Issue[]);
|
|
148
173
|
}
|
|
149
174
|
|
|
150
|
-
export { type BaseOptions, type EnhancedRequestInit, type GetJson, type GetText, type HTTPMethod, type JSONValue, ParseResponseError, type PathParams, type RequestTransformer, type ResponseTransformer, type SearchParams, type ServiceRequestInit, type TypedResponse, type TypedResponseJson, type TypedResponseText, addQueryToURL, enhancedFetch, ensureStringBody, makeFetcher, makeGetApiURL, makeService, mergeHeaders, replaceURLParams, typeOf, typedResponse };
|
|
175
|
+
export { type BaseOptions, type EnhancedRequestInit, type GetJson, type GetText, type HTTPMethod, type JSONValue, ParseResponseError, type PathParams, type RequestTransformer, type ResponseTransformer, type SearchParams, type ServiceRequestInit, StandardSchema, type TypedResponse, type TypedResponseJson, type TypedResponseText, addQueryToURL, enhancedFetch, ensureStringBody, makeFetcher, makeGetApiURL, makeService, mergeHeaders, replaceURLParams, typeOf, typedResponse };
|
package/dist/index.js
CHANGED
|
@@ -49,15 +49,23 @@ var HTTP_METHODS = [
|
|
|
49
49
|
|
|
50
50
|
// src/primitives.ts
|
|
51
51
|
function addQueryToURL(url, searchParams) {
|
|
52
|
-
if (
|
|
52
|
+
if (searchParams === void 0) return url;
|
|
53
53
|
if (typeof url === "string") {
|
|
54
|
-
const
|
|
55
|
-
|
|
54
|
+
const hasQuery = url.includes("?");
|
|
55
|
+
const qs = new URLSearchParams(searchParams).toString();
|
|
56
|
+
if (!qs) return hasQuery ? url : `${url}?`;
|
|
57
|
+
const separator = hasQuery ? "&" : "?";
|
|
58
|
+
return `${url}${separator}${qs}`;
|
|
56
59
|
}
|
|
57
|
-
if (
|
|
60
|
+
if (url instanceof URL) {
|
|
58
61
|
const result = new URL(url.toString());
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
const qs = new URLSearchParams(searchParams);
|
|
63
|
+
if (!qs.toString()) {
|
|
64
|
+
if (!result.search) result.search = "?";
|
|
65
|
+
} else {
|
|
66
|
+
for (const [key, value] of qs.entries()) {
|
|
67
|
+
result.searchParams.set(key, value);
|
|
68
|
+
}
|
|
61
69
|
}
|
|
62
70
|
return result;
|
|
63
71
|
}
|
|
@@ -66,7 +74,7 @@ function addQueryToURL(url, searchParams) {
|
|
|
66
74
|
function ensureStringBody(body) {
|
|
67
75
|
if (typeof body === "undefined") return body;
|
|
68
76
|
if (typeof body === "string") return body;
|
|
69
|
-
return ["number", "boolean", "array", "object"].includes(typeOf(body)) ? JSON.stringify(body) : body;
|
|
77
|
+
return ["number", "boolean", "array", "object", "date"].includes(typeOf(body)) ? JSON.stringify(body) : body;
|
|
70
78
|
}
|
|
71
79
|
function makeGetApiURL(baseURL) {
|
|
72
80
|
const base = baseURL instanceof URL ? baseURL.toString() : baseURL;
|
|
@@ -93,7 +101,7 @@ function replaceURLParams(url, params) {
|
|
|
93
101
|
if (!params) return url;
|
|
94
102
|
let urlString = String(url);
|
|
95
103
|
for (const [key, value] of Object.entries(params)) {
|
|
96
|
-
urlString = urlString.replace(new RegExp(`:${key}($|/)
|
|
104
|
+
urlString = urlString.replace(new RegExp(`:${key}($|/)`, "g"), `${value}$1`);
|
|
97
105
|
}
|
|
98
106
|
return url instanceof URL ? new URL(urlString) : urlString;
|
|
99
107
|
}
|
|
@@ -102,7 +110,7 @@ function typeOf(t) {
|
|
|
102
110
|
}
|
|
103
111
|
var ParseResponseError = class extends Error {
|
|
104
112
|
constructor(message, issues) {
|
|
105
|
-
super(
|
|
113
|
+
super(message);
|
|
106
114
|
this.issues = issues;
|
|
107
115
|
this.name = "ParseResponseError";
|
|
108
116
|
this.issues = issues;
|
|
@@ -142,8 +150,8 @@ function typedResponse(response, options) {
|
|
|
142
150
|
const getTextFn = options?.getText ?? getText;
|
|
143
151
|
return new Proxy(response, {
|
|
144
152
|
get(target, prop) {
|
|
145
|
-
if (prop === "json") return getJsonFn(target);
|
|
146
|
-
if (prop === "text") return getTextFn(target);
|
|
153
|
+
if (prop === "json") return getJsonFn(target.clone());
|
|
154
|
+
if (prop === "text") return getTextFn(target.clone());
|
|
147
155
|
const value = Reflect.get(target, prop);
|
|
148
156
|
if (typeof value === "function") {
|
|
149
157
|
return value.bind(target);
|
package/dist/index.mjs
CHANGED
|
@@ -13,15 +13,23 @@ var HTTP_METHODS = [
|
|
|
13
13
|
|
|
14
14
|
// src/primitives.ts
|
|
15
15
|
function addQueryToURL(url, searchParams) {
|
|
16
|
-
if (
|
|
16
|
+
if (searchParams === void 0) return url;
|
|
17
17
|
if (typeof url === "string") {
|
|
18
|
-
const
|
|
19
|
-
|
|
18
|
+
const hasQuery = url.includes("?");
|
|
19
|
+
const qs = new URLSearchParams(searchParams).toString();
|
|
20
|
+
if (!qs) return hasQuery ? url : `${url}?`;
|
|
21
|
+
const separator = hasQuery ? "&" : "?";
|
|
22
|
+
return `${url}${separator}${qs}`;
|
|
20
23
|
}
|
|
21
|
-
if (
|
|
24
|
+
if (url instanceof URL) {
|
|
22
25
|
const result = new URL(url.toString());
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
const qs = new URLSearchParams(searchParams);
|
|
27
|
+
if (!qs.toString()) {
|
|
28
|
+
if (!result.search) result.search = "?";
|
|
29
|
+
} else {
|
|
30
|
+
for (const [key, value] of qs.entries()) {
|
|
31
|
+
result.searchParams.set(key, value);
|
|
32
|
+
}
|
|
25
33
|
}
|
|
26
34
|
return result;
|
|
27
35
|
}
|
|
@@ -30,7 +38,7 @@ function addQueryToURL(url, searchParams) {
|
|
|
30
38
|
function ensureStringBody(body) {
|
|
31
39
|
if (typeof body === "undefined") return body;
|
|
32
40
|
if (typeof body === "string") return body;
|
|
33
|
-
return ["number", "boolean", "array", "object"].includes(typeOf(body)) ? JSON.stringify(body) : body;
|
|
41
|
+
return ["number", "boolean", "array", "object", "date"].includes(typeOf(body)) ? JSON.stringify(body) : body;
|
|
34
42
|
}
|
|
35
43
|
function makeGetApiURL(baseURL) {
|
|
36
44
|
const base = baseURL instanceof URL ? baseURL.toString() : baseURL;
|
|
@@ -57,7 +65,7 @@ function replaceURLParams(url, params) {
|
|
|
57
65
|
if (!params) return url;
|
|
58
66
|
let urlString = String(url);
|
|
59
67
|
for (const [key, value] of Object.entries(params)) {
|
|
60
|
-
urlString = urlString.replace(new RegExp(`:${key}($|/)
|
|
68
|
+
urlString = urlString.replace(new RegExp(`:${key}($|/)`, "g"), `${value}$1`);
|
|
61
69
|
}
|
|
62
70
|
return url instanceof URL ? new URL(urlString) : urlString;
|
|
63
71
|
}
|
|
@@ -66,7 +74,7 @@ function typeOf(t) {
|
|
|
66
74
|
}
|
|
67
75
|
var ParseResponseError = class extends Error {
|
|
68
76
|
constructor(message, issues) {
|
|
69
|
-
super(
|
|
77
|
+
super(message);
|
|
70
78
|
this.issues = issues;
|
|
71
79
|
this.name = "ParseResponseError";
|
|
72
80
|
this.issues = issues;
|
|
@@ -106,8 +114,8 @@ function typedResponse(response, options) {
|
|
|
106
114
|
const getTextFn = options?.getText ?? getText;
|
|
107
115
|
return new Proxy(response, {
|
|
108
116
|
get(target, prop) {
|
|
109
|
-
if (prop === "json") return getJsonFn(target);
|
|
110
|
-
if (prop === "text") return getTextFn(target);
|
|
117
|
+
if (prop === "json") return getJsonFn(target.clone());
|
|
118
|
+
if (prop === "text") return getTextFn(target.clone());
|
|
111
119
|
const value = Reflect.get(target, prop);
|
|
112
120
|
if (typeof value === "function") {
|
|
113
121
|
return value.bind(target);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "make-service",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.1",
|
|
4
4
|
"description": "Some utilities to extend the 'fetch' API to better interact with external APIs.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@biomejs/biome": "^2.0.0",
|
|
36
|
-
"@standard-schema/spec": "^1.0.0",
|
|
37
36
|
"@types/node": "^24.0.3",
|
|
38
37
|
"arktype": "^2.1.20",
|
|
39
38
|
"jsdom": "^26.1.0",
|
|
@@ -43,9 +42,7 @@
|
|
|
43
42
|
"vitest": "latest",
|
|
44
43
|
"zod": "3.25.67"
|
|
45
44
|
},
|
|
46
|
-
"peerDependencies": {
|
|
47
|
-
"@standard-schema/spec": "^1.0.0"
|
|
48
|
-
},
|
|
45
|
+
"peerDependencies": {},
|
|
49
46
|
"files": [
|
|
50
47
|
"README.md",
|
|
51
48
|
"./dist/*"
|