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 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?: StandardSchemaV1<Input, Output>) => Promise<Output>;
31
- type TypedResponseText = <Input extends string = string, Output = Input>(schema?: StandardSchemaV1<Input, Output>) => Promise<Output>;
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 StandardSchemaV1.Issue[];
147
- constructor(message: string, issues: readonly StandardSchemaV1.Issue[]);
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?: StandardSchemaV1<Input, Output>) => Promise<Output>;
31
- type TypedResponseText = <Input extends string = string, Output = Input>(schema?: StandardSchemaV1<Input, Output>) => Promise<Output>;
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 StandardSchemaV1.Issue[];
147
- constructor(message: string, issues: readonly StandardSchemaV1.Issue[]);
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 (!searchParams) return url;
52
+ if (searchParams === void 0) return url;
53
53
  if (typeof url === "string") {
54
- const separator = url.includes("?") ? "&" : "?";
55
- return `${url}${separator}${new URLSearchParams(searchParams)}`;
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 (searchParams && url instanceof URL) {
60
+ if (url instanceof URL) {
58
61
  const result = new URL(url.toString());
59
- for (const [key, value] of new URLSearchParams(searchParams).entries()) {
60
- result.searchParams.set(key, value);
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}($|/)`), `${value}$1`);
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(JSON.stringify({ message, issues }, null, 2));
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 (!searchParams) return url;
16
+ if (searchParams === void 0) return url;
17
17
  if (typeof url === "string") {
18
- const separator = url.includes("?") ? "&" : "?";
19
- return `${url}${separator}${new URLSearchParams(searchParams)}`;
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 (searchParams && url instanceof URL) {
24
+ if (url instanceof URL) {
22
25
  const result = new URL(url.toString());
23
- for (const [key, value] of new URLSearchParams(searchParams).entries()) {
24
- result.searchParams.set(key, value);
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}($|/)`), `${value}$1`);
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(JSON.stringify({ message, issues }, null, 2));
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.0.2",
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/*"