@autometa/http 1.4.19 → 2.0.0-rc.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.
Files changed (55) hide show
  1. package/README.md +107 -2
  2. package/dist/assertions/http-adapters.d.ts +35 -0
  3. package/dist/assertions/http-assertions-plugin.d.ts +16 -0
  4. package/dist/assertions/http-ensure.d.ts +42 -0
  5. package/dist/axios-transport.d.ts +22 -0
  6. package/dist/default-schema.d.ts +8 -0
  7. package/dist/fetch-transport.d.ts +21 -0
  8. package/dist/http-request.d.ts +109 -0
  9. package/dist/http-response.d.ts +77 -0
  10. package/dist/http.d.ts +300 -0
  11. package/dist/index.cjs +2076 -0
  12. package/dist/index.cjs.map +1 -0
  13. package/dist/index.d.ts +15 -1116
  14. package/dist/index.js +1727 -845
  15. package/dist/index.js.map +1 -1
  16. package/dist/plugins.d.ts +43 -0
  17. package/dist/request-meta.config.d.ts +56 -0
  18. package/dist/schema.map.d.ts +11 -0
  19. package/dist/transform-response.d.ts +1 -0
  20. package/dist/transport.d.ts +11 -0
  21. package/dist/types.d.ts +39 -0
  22. package/package.json +31 -31
  23. package/.eslintignore +0 -3
  24. package/.eslintrc.cjs +0 -4
  25. package/.turbo/turbo-lint$colon$fix.log +0 -4
  26. package/.turbo/turbo-prettify.log +0 -5
  27. package/.turbo/turbo-test.log +0 -120
  28. package/CHANGELOG.md +0 -326
  29. package/dist/esm/index.js +0 -1117
  30. package/dist/esm/index.js.map +0 -1
  31. package/dist/index.d.cts +0 -1116
  32. package/src/axios-client.ts +0 -35
  33. package/src/default-client-factory.axios.spec.ts +0 -9
  34. package/src/default-client-factory.other.spec.ts +0 -13
  35. package/src/default-client-factory.ts +0 -7
  36. package/src/default-schema.spec.ts +0 -74
  37. package/src/default-schema.ts +0 -127
  38. package/src/http-client.ts +0 -20
  39. package/src/http-request.spec.ts +0 -172
  40. package/src/http-request.ts +0 -201
  41. package/src/http-response.ts +0 -107
  42. package/src/http.spec.ts +0 -189
  43. package/src/http.ts +0 -907
  44. package/src/index.ts +0 -13
  45. package/src/node_modules/.vitest/deps/_metadata.json +0 -8
  46. package/src/node_modules/.vitest/deps/package.json +0 -3
  47. package/src/node_modules/.vitest/results.json +0 -1
  48. package/src/request-meta.config.spec.ts +0 -81
  49. package/src/request-meta.config.ts +0 -134
  50. package/src/request.config.ts +0 -34
  51. package/src/schema.map.spec.ts +0 -50
  52. package/src/schema.map.ts +0 -68
  53. package/src/transform-response.ts +0 -43
  54. package/src/types.ts +0 -37
  55. package/tsup.config.ts +0 -14
@@ -1,107 +0,0 @@
1
- import { HTTPRequest } from "./http-request";
2
- import { StatusCode } from "./types";
3
-
4
- export class HTTPResponse<T = unknown> {
5
- status: StatusCode;
6
- statusText: string;
7
- data: T;
8
- headers: Record<string, string>;
9
- request: HTTPRequest<unknown>;
10
-
11
- constructor() {
12
- this.headers = {};
13
- }
14
-
15
- static fromRaw<T>(response: HTTPResponse<T>) {
16
- const newResponse = new HTTPResponse<T>();
17
- Object.assign(newResponse, response);
18
- return response;
19
- }
20
-
21
- /**
22
- * Decomposes a response, creating an exact copy of the current response,
23
- * but with a new data value. The data can be provided directly as is, or it
24
- * can be generated through a callback function which receives the current
25
- * response data as an argument.
26
- *
27
- * ```ts
28
- * const response = await http.get("/products");
29
- *
30
- * // direct value
31
- * const products = response.data;
32
- * const firstProduct = response.decompose(products[0]);
33
- * // callback transformer
34
- * const secondProduct = response.decompose((products) => products[1]);
35
- * // callback transformer with destructuring
36
- * const secondProduct = response.decompose(([product]) => product);
37
- * ```
38
- * @param value
39
- */
40
- decompose<K>(value: K): HTTPResponse<K>;
41
- decompose<K>(transformFn: (response: T) => K): HTTPResponse<K>;
42
- decompose<K>(transformFnOrVal: K | ((response: T) => K)): HTTPResponse<K> {
43
- const value = getDecompositionValue<T>(this.data, transformFnOrVal);
44
- return new HTTPResponseBuilder()
45
- .status(this.status)
46
- .statusText(this.statusText)
47
- .headers(this.headers)
48
- .request(this.request)
49
- .data(value)
50
- .build() as HTTPResponse<K>;
51
- }
52
- }
53
-
54
- function getDecompositionValue<T>(data: unknown, transformFn: unknown): T {
55
- return typeof transformFn === "function" ? transformFn(data) : transformFn;
56
- }
57
-
58
- export class HTTPResponseBuilder {
59
- #response = new HTTPResponse();
60
-
61
- static create() {
62
- return new HTTPResponseBuilder();
63
- }
64
-
65
- derive() {
66
- return HTTPResponseBuilder.create()
67
- .data(this.#response.data)
68
- .headers(this.#response.headers)
69
- .request(this.#response.request)
70
- .status(this.#response.status)
71
- .statusText(this.#response.statusText);
72
- }
73
-
74
- status(code: StatusCode) {
75
- this.#response.status = code;
76
- return this;
77
- }
78
-
79
- statusText(text: string) {
80
- this.#response.statusText = text;
81
- return this;
82
- }
83
-
84
- data<T>(data: T) {
85
- this.#response.data = data;
86
- return this;
87
- }
88
-
89
- headers(dict: Record<string, string>) {
90
- this.#response.headers = dict;
91
- return this;
92
- }
93
-
94
- header(name: string, value: string) {
95
- this.#response.headers[name] = value;
96
- return this;
97
- }
98
-
99
- request(request: HTTPRequest<unknown>) {
100
- this.#response.request = request;
101
- return this;
102
- }
103
-
104
- build() {
105
- return this.#response;
106
- }
107
- }
package/src/http.spec.ts DELETED
@@ -1,189 +0,0 @@
1
- import { describe, it, expect, vi } from "vitest";
2
- import { HTTP } from "./http";
3
- import { HTTPClient } from "./http-client";
4
- import { HTTPRequest, HTTPRequestBuilder } from "./http-request";
5
- import { HTTPResponse, HTTPResponseBuilder } from "./http-response";
6
- import { HTTPAdditionalOptions } from "./types";
7
-
8
- describe("HTTP", () => {
9
- describe("create", () => {
10
- it("should create a new instance of the HTTP Client", () => {
11
- const client = HTTP.create();
12
- expect(client).toBeInstanceOf(HTTP);
13
- });
14
- });
15
- class MockClient extends HTTPClient {
16
- constructor(readonly testFn: ReturnType<typeof vi.fn>) {
17
- super();
18
- }
19
- async request<TRequestType, TResponseType>(
20
- request: HTTPRequest<TRequestType>,
21
- options?: HTTPAdditionalOptions<unknown> | undefined
22
- ): Promise<HTTPResponse<TResponseType>> {
23
- console.log(request);
24
-
25
- return this.testFn(request, options) as HTTPResponse<TResponseType>;
26
- }
27
- }
28
-
29
- describe("resolving dynamic headers", () => {
30
- it("should resolve dynamic headers", async () => {
31
- const response = HTTPResponseBuilder.create().status(200).build();
32
- const request = HTTPRequestBuilder.create();
33
- const fn = vi.fn().mockImplementation((req: HTTPRequest) => {
34
- response.request = req;
35
- return response;
36
- });
37
- const client = new MockClient(fn);
38
- const http = new HTTP(client, request).sharedHeader("foo", () => "bar");
39
- const result = await http.get();
40
- expect(result.request.headers["foo"]).toBe("bar");
41
- });
42
- });
43
- describe("allowPlainText", () => {
44
- it("should throw an error when allowPlainText is false", async () => {
45
- const response = HTTPResponseBuilder.create().data("Hello World").build();
46
- const fn = vi.fn().mockImplementation((req: HTTPRequest) => {
47
- response.request = req;
48
- return response;
49
- });
50
- const client = new MockClient(fn);
51
- const http = new HTTP(client).allowPlainText(false);
52
- await expect(() => http.get()).rejects.toThrowError(
53
- `Could not parse a response as json, and this request was not configured to allow plain text responses.
54
- To allow plain text responses, use the 'allowPlainText' method on the HTTP client.
55
-
56
- Hello World`
57
- );
58
- });
59
-
60
- it("should return the response when allowPlainText is true", async () => {
61
- const response = HTTPResponseBuilder.create().data("Hello World").build();
62
- const fn = vi.fn().mockReturnValue(response);
63
- const client = new MockClient(fn);
64
- const http = new HTTP(client).allowPlainText(true);
65
- const result = await http.get();
66
- expect(result).toBe(response);
67
- });
68
-
69
- it("should return a new HTTP instance", () => {
70
- const response = HTTPResponseBuilder.create().data("Hello World").build();
71
- const fn = vi.fn().mockReturnValue(response);
72
- const client = new MockClient(fn);
73
- const http = new HTTP(client).allowPlainText(true);
74
- const result = http.allowPlainText(false);
75
- expect(result).toBeInstanceOf(HTTP);
76
- expect(result).not.toBe(http);
77
- });
78
- });
79
-
80
- describe("hooks", () => {
81
- describe("onSend", () => {
82
- it("should call the hook when the request is sent", async () => {
83
- const request = HTTPRequestBuilder.create()
84
- .url(undefined as unknown as string)
85
- .method("GET")
86
- .data(undefined as unknown as string)
87
- .build();
88
- const response = HTTPResponseBuilder.create().build();
89
- const fn = vi.fn().mockReturnValue(response);
90
- const hook = vi
91
- .fn()
92
- .mockImplementation((data: HTTPResponse<unknown>) => {
93
- expect(data).toStrictEqual(request);
94
- });
95
- const client = new MockClient(fn);
96
- const http = new HTTP(client).onSend("test hook", hook);
97
- await http.get();
98
- expect(hook).toHaveBeenCalledWith(request);
99
- });
100
-
101
- it("should propagate errors from the hook", async () => {
102
- const response = HTTPResponseBuilder.create().build();
103
- const fn = vi.fn().mockReturnValue(response);
104
- const hook = vi.fn().mockImplementation((_: HTTPResponse<unknown>) => {
105
- throw new Error("test error");
106
- });
107
- const client = new MockClient(fn);
108
- const http = new HTTP(client).onSend("test hook", hook);
109
- await expect(() => http.get()).rejects.toThrowError(
110
- "An error occurred while sending a request in hook: 'test hook'"
111
- );
112
- });
113
- });
114
-
115
- describe("onReceive", () => {
116
- it("should call the hook when the response is received", async () => {
117
- const response = HTTPResponseBuilder.create().build();
118
- const fn = vi.fn().mockReturnValue(response);
119
- const hook = vi
120
- .fn()
121
- .mockImplementation((data: HTTPResponse<unknown>) => {
122
- expect(data).toStrictEqual(response);
123
- });
124
- const client = new MockClient(fn);
125
- const http = new HTTP(client).onReceive("test hook", hook);
126
- await http.get();
127
- expect(hook).toHaveBeenCalledWith(response);
128
- });
129
-
130
- it("should propagate errors from the hook", async () => {
131
- const response = HTTPResponseBuilder.create().build();
132
- const fn = vi.fn().mockReturnValue(response);
133
- const hook = vi.fn().mockImplementation((_: HTTPResponse<unknown>) => {
134
- throw new Error("test error");
135
- });
136
- const client = new MockClient(fn);
137
- const http = new HTTP(client).onReceive("test hook", hook);
138
- await expect(() => http.get()).rejects.toThrowError(
139
- "An error occurred while receiving a response in hook: 'test hook'"
140
- );
141
- });
142
- });
143
- });
144
-
145
- describe("schemas", () => {
146
- it("should throw an error if there is no schema and requireSchema is true", () => {
147
- const response = HTTPResponseBuilder.create().status(200).build();
148
- const fn = vi.fn().mockReturnValue(response);
149
- const client = new MockClient(fn);
150
- const http = new HTTP(client).requireSchema(true);
151
- expect(() => http.get()).rejects.toThrowError(
152
- `No parser registered for status code 200 but 'requireSchema' is true`
153
- );
154
- });
155
-
156
- it("should throw an error if the response status does not match a schema", () => {
157
- const response = HTTPResponseBuilder.create().status(200).build();
158
- const fn = vi.fn().mockReturnValue(response);
159
- const client = new MockClient(fn);
160
- const http = new HTTP(client).requireSchema(true).schema(vi.fn(), 400);
161
- expect(() => http.get()).rejects.toThrowError(
162
- `No parser registered for status code 200 but 'requireSchema' is true`
163
- );
164
- });
165
-
166
- it("should return the response if the status matches a schema", async () => {
167
- const response = HTTPResponseBuilder.create().status(200).build();
168
- const fn = vi.fn().mockReturnValue(response);
169
- const client = new MockClient(fn);
170
- const http = new HTTP(client).requireSchema(true).schema(vi.fn(), 200);
171
- const result = await http.get();
172
- expect(result).toBe(response);
173
- });
174
-
175
- it("should return the validated response if the status matches a schema", async () => {
176
- const response = HTTPResponseBuilder.create().status(200).data("FooBar");
177
- const validated = response.derive().data("Hello World").build();
178
- const fn = vi.fn().mockReturnValue(response.build());
179
- const client = new MockClient(fn);
180
- const schema = vi.fn().mockReturnValue(validated);
181
- const http = new HTTP(client)
182
- .requireSchema(true)
183
- .allowPlainText(true)
184
- .schema(schema, 200);
185
- const { data } = await http.get();
186
- expect(data).toBe(validated);
187
- });
188
- });
189
- });