@autometa/http 1.4.20 → 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 -335
  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
package/src/index.ts DELETED
@@ -1,13 +0,0 @@
1
- export * from "./axios-client";
2
- export * from "./http-client";
3
- export * from "./http";
4
- export * from "./http-request";
5
- export * from "./http-response";
6
- export * from "./default-schema";
7
- export type {
8
- HTTPAdditionalOptions,
9
- HTTPMethod,
10
- SchemaParser,
11
- RequestHook,
12
- ResponseHook,
13
- } from "./types";
@@ -1,8 +0,0 @@
1
- {
2
- "hash": "e5d6b890",
3
- "configHash": "0f868888",
4
- "lockfileHash": "aa4bef81",
5
- "browserHash": "892900c3",
6
- "optimized": {},
7
- "chunks": {}
8
- }
@@ -1,3 +0,0 @@
1
- {
2
- "type": "module"
3
- }
@@ -1 +0,0 @@
1
- {"version":"0.34.6","results":[[":schema.map.spec.ts",{"duration":0,"failed":false}],[":http-request.spec.ts",{"duration":0,"failed":false}],[":default-client-factory.other.spec.ts",{"duration":0,"failed":false}],[":request-meta.config.spec.ts",{"duration":0,"failed":false}],[":default-schema.spec.ts",{"duration":0,"failed":false}],[":default-client-factory.axios.spec.ts",{"duration":0,"failed":false}],[":http.spec.ts",{"duration":16,"failed":false}],[":axios-executor.spec.ts",{"duration":6,"failed":false}],[":transform-response.spec.ts",{"duration":17,"failed":false}],[":http.builder.spec.ts",{"duration":10,"failed":false}],[":http.request.spec.ts",{"duration":10,"failed":false}]]}
@@ -1,81 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { MetaConfigBuilder } from "./request-meta.config";
3
-
4
- describe(MetaConfigBuilder.name, () => {
5
- describe("adding schema mapping", () => {
6
- it("should add a schema mapping", () => {
7
- const parser = { parse: <T>(data: T) => data };
8
- const config = new MetaConfigBuilder().schema(parser, 200).build();
9
- expect(config.schemas.toObject()).toEqual({ 200: parser });
10
- });
11
-
12
- it("should multiple schema mappings", () => {
13
- const parser = { parse: <T>(data: T) => data };
14
- const config = new MetaConfigBuilder()
15
- .schema(parser, 200)
16
- .schema(parser, 201)
17
- .build();
18
- expect(config.schemas.toObject()).toEqual({ 200: parser, 201: parser });
19
- });
20
-
21
- it("should add multiple range based schema mappings", () => {
22
- const parser = { parse: <T>(data: T) => data };
23
- const config = new MetaConfigBuilder()
24
- .schema(parser, { from: 200, to: 202 })
25
- .build();
26
- expect(config.schemas.toObject()).toEqual({
27
- 200: parser,
28
- 201: parser,
29
- 202: parser,
30
- });
31
- });
32
- });
33
-
34
- describe('adding "onBeforeSend" hooks', () => {
35
- it("adding a before send hook", () => {
36
- const hook = () => undefined;
37
- const config = new MetaConfigBuilder().onBeforeSend("hook", hook).build();
38
- expect(config.onSend).toEqual([["hook", hook]]);
39
- });
40
-
41
- it("adding multiple before send hooks", () => {
42
- const hook = () => undefined;
43
- const config = new MetaConfigBuilder().onBeforeSend("hook", hook).build();
44
- expect(config.onSend).toEqual([["hook", hook]]);
45
- });
46
- });
47
-
48
- describe('adding "onReceiveResponse" hooks', () => {
49
- it("adding a before send hook", () => {
50
- const hook = () => undefined;
51
- const config = new MetaConfigBuilder()
52
- .onReceiveResponse("hook", hook)
53
- .build();
54
- expect(config.onReceive).toEqual([["hook", hook]]);
55
- });
56
-
57
- it("adding multiple before send hooks", () => {
58
- const hook = () => undefined;
59
- const config = new MetaConfigBuilder()
60
- .onReceiveResponse("hook", hook)
61
- .build();
62
- expect(config.onReceive).toEqual([["hook", hook]]);
63
- });
64
- });
65
-
66
- describe("deriving a request meta config", () => {
67
- it("should derive a config with the same values", () => {
68
- const parser = { parse: <T>(data: T) => data };
69
- const hook = () => undefined;
70
- const configBuilder = new MetaConfigBuilder()
71
- .schema(parser, 200)
72
- .onBeforeSend("send", hook)
73
- .onReceiveResponse("receive", hook);
74
- const original = configBuilder.build();
75
- const derived = configBuilder.derive().build();
76
- expect(derived.schemas).toEqual(original.schemas);
77
- expect(derived.onSend).toEqual(original.onSend);
78
- expect(derived.onReceive).toEqual(original.onReceive);
79
- });
80
- });
81
- });
@@ -1,134 +0,0 @@
1
- import { SchemaMap } from "./schema.map";
2
- import {
3
- HTTPAdditionalOptions,
4
- RequestHook,
5
- ResponseHook,
6
- SchemaParser,
7
- StatusCode,
8
- } from "./types";
9
-
10
- export interface SchemaConfig {
11
- schemas: SchemaMap;
12
- requireSchema: boolean;
13
- allowPlainText: boolean;
14
- }
15
-
16
- export interface HTTPHooks {
17
- onSend: [string, RequestHook][];
18
- onReceive: [string, ResponseHook<unknown>][];
19
- }
20
-
21
- // export type MetaConfig = SchemaConfig & HTTPHooks;
22
-
23
- export class MetaConfig implements SchemaConfig, HTTPHooks {
24
- schemas: SchemaMap;
25
- requireSchema: boolean;
26
- allowPlainText: boolean;
27
- onSend: [string, RequestHook][] = [];
28
- onReceive: [string, ResponseHook<unknown>][] = [];
29
- throwOnServerError: boolean;
30
- options: HTTPAdditionalOptions<unknown> = {};
31
- }
32
-
33
- export class MetaConfigBuilder {
34
- #schemaMap = new SchemaMap();
35
- #requireSchema = false;
36
- #allowPlainText = false;
37
- #onBeforeSend: [string, RequestHook][] = [];
38
- #onAfterSend: [string, ResponseHook<unknown>][] = [];
39
- #throwOnServerError = false;
40
- #options: HTTPAdditionalOptions<unknown> = {};
41
-
42
- options(options: HTTPAdditionalOptions<unknown>) {
43
- this.#options = { ...options };
44
- return this;
45
- }
46
- schemaMap(map: SchemaMap) {
47
- this.#schemaMap = map;
48
- return this;
49
- }
50
-
51
- schema(parser: SchemaParser, ...codes: StatusCode[]): MetaConfigBuilder;
52
- schema(
53
- parser: SchemaParser,
54
- ...range: { from: StatusCode; to: StatusCode }[]
55
- ): MetaConfigBuilder;
56
- schema(
57
- parser: SchemaParser,
58
- ...args: (StatusCode | { from: StatusCode; to: StatusCode })[]
59
- ): MetaConfigBuilder;
60
- schema(
61
- parser: SchemaParser,
62
- ...args: (StatusCode | { from: StatusCode; to: StatusCode })[]
63
- ) {
64
- args.forEach((arg) => {
65
- if (typeof arg === "number") {
66
- this.#schemaMap.registerStatus(parser, arg);
67
- } else if (Array.isArray(arg)) {
68
- this.#schemaMap.registerStatus(parser, ...arg);
69
- } else {
70
- this.#schemaMap.registerRange(parser, arg.from, arg.to);
71
- }
72
- });
73
-
74
- return this;
75
- }
76
-
77
- requireSchema(value: boolean) {
78
- this.#requireSchema = value;
79
- return this;
80
- }
81
-
82
- allowPlainText(value: boolean) {
83
- this.#allowPlainText = value;
84
- return this;
85
- }
86
-
87
- onBeforeSend(description: string, hook: RequestHook) {
88
- this.#onBeforeSend.push([description, hook]);
89
- return this;
90
- }
91
-
92
- #setOnSend(hooks: [string, RequestHook][]) {
93
- this.#onBeforeSend = [...hooks];
94
- return this;
95
- }
96
-
97
- throwOnServerError(value: boolean) {
98
- this.#throwOnServerError = value;
99
- return this;
100
- }
101
-
102
- onReceiveResponse(description: string, hook: ResponseHook<unknown>) {
103
- this.#onAfterSend.push([description, hook]);
104
- return this;
105
- }
106
-
107
- #setOnReceive(hooks: [string, ResponseHook<unknown>][]) {
108
- this.#onAfterSend = [...hooks];
109
- return this;
110
- }
111
-
112
- build() {
113
- const config = new MetaConfig();
114
- config.schemas = this.#schemaMap.derive();
115
- config.requireSchema = this.#requireSchema;
116
- config.allowPlainText = this.#allowPlainText;
117
- config.onSend = this.#onBeforeSend;
118
- config.onReceive = this.#onAfterSend;
119
- config.options = this.#options;
120
- config.throwOnServerError = this.#throwOnServerError;
121
- return config;
122
- }
123
-
124
- derive() {
125
- return new MetaConfigBuilder()
126
- .schemaMap(this.#schemaMap.derive())
127
- .requireSchema(this.#requireSchema)
128
- .allowPlainText(this.#allowPlainText)
129
- .throwOnServerError(this.#throwOnServerError)
130
- .options(this.#options)
131
- .#setOnSend(this.#onBeforeSend)
132
- .#setOnReceive(this.#onAfterSend);
133
- }
134
- }
@@ -1,34 +0,0 @@
1
- import { HTTPMethod } from "./types";
2
-
3
- export interface RequestBaseConfig {
4
- headers?: Record<string, string>;
5
- params?: Record<string, string | string[] | Record<string, unknown>>;
6
- baseUrl?: string;
7
- route?: string[];
8
- method: HTTPMethod;
9
- /**
10
- * Returns the full URL of the request, including the base url,
11
- * routes, and query parameters.
12
- *
13
- * ```ts
14
- * console.log(request.fullUrl())// https://example.com/foo?bar=baz?array=1,2,3
15
- * ```
16
- *
17
- * Note characters may be converted to escape codes. I.e (space => %20) and (comma => %2C)
18
- *
19
- * N.B this method estimates what the url will be. The actual value
20
- * might be different depending on your underlying HTTPClient and
21
- * configuration. For example, query parameters might
22
- * use different array formats.
23
- * @returns The full url of the request
24
- */
25
- get fullUrl(): string;
26
- }
27
-
28
- export interface RequestData<T = unknown> {
29
- data: T;
30
- }
31
-
32
- export type RequestConfig<T> = RequestBaseConfig & RequestData<T>;
33
-
34
- export type RequestConfigBasic = RequestConfig<Record<string, unknown>>;
@@ -1,50 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { SchemaMap } from "./schema.map";
3
-
4
- describe("SchemaMap", () => {
5
- describe("register", () => {
6
- describe("single status", () => {
7
- it("should register a single status code", () => {
8
- const map = new SchemaMap();
9
- const parser = { parse: (data: unknown) => data };
10
- map.registerStatus(parser, 200);
11
- const retrieved = map.getParser(200, false);
12
- expect(retrieved).toBe(parser);
13
- });
14
-
15
- it("should throw if the status code is already registered", () => {
16
- const map = new SchemaMap();
17
- const parser = { parse: <T>(data: T) => data };
18
- map.registerStatus(parser, 200);
19
- expect(() => map.registerStatus(parser, 200)).toThrow();
20
- });
21
- });
22
-
23
- describe("range of statuses", () => {
24
- it("should register a range of statuses", () => {
25
- const map = new SchemaMap();
26
- const parser = { parse: <T>(data: T) => data };
27
- map.registerRange(parser, 200, 202);
28
- const retrieved = map.getParser(200, false);
29
- expect(retrieved).toBe(parser);
30
- });
31
-
32
- it("should throw if the status code is already registered", () => {
33
- const map = new SchemaMap();
34
- const parser = { parse: <T>(data: T) => data };
35
- map.registerRange(parser, 200, 202);
36
- expect(() => map.registerRange(parser, 200, 202)).toThrow();
37
- });
38
- });
39
-
40
- describe("derive", () => {
41
- it("should return a new map with the same values", () => {
42
- const map = new SchemaMap();
43
- const parser = { parse: <T>(data: T) => data };
44
- map.registerRange(parser, 200, 202);
45
- const derived = map.derive();
46
- expect(derived.getParser(200, false)).toBe(parser);
47
- });
48
- });
49
- });
50
- });
package/src/schema.map.ts DELETED
@@ -1,68 +0,0 @@
1
- import { SchemaParser, StatusCode } from "./types";
2
- export class SchemaMap {
3
- #map: Map<StatusCode, SchemaParser>;
4
- constructor(map?: Map<StatusCode, SchemaParser> | SchemaMap) {
5
- if (map instanceof SchemaMap) {
6
- this.#map = new Map(map.#map);
7
- return;
8
- }
9
- this.#map = new Map(map);
10
- }
11
-
12
- derive() {
13
- return new SchemaMap(this.#map);
14
- }
15
-
16
- registerStatus(parser: SchemaParser, ...codes: StatusCode[]) {
17
- codes.forEach((code) => {
18
- if (this.#map.has(code)) {
19
- const msg = `Status code ${code} is already registered with a parser`;
20
- throw new Error(msg);
21
- }
22
- this.#map.set(code, parser);
23
- });
24
- }
25
-
26
- registerRange(parser: SchemaParser, from: StatusCode, to: StatusCode) {
27
- for (let i = from; i <= to; i++) {
28
- if (this.#map.has(i)) {
29
- throw new Error(`Status code ${i} is already registered with a parser`);
30
- }
31
- this.#map.set(i, parser);
32
- }
33
- }
34
-
35
- validate(status: StatusCode, data: unknown, requireSchema: boolean) {
36
- const parser = this.getParser(status, requireSchema);
37
- if ("parse" in parser) {
38
- return parser.parse(data);
39
- }
40
- if ("validate" in parser) {
41
- return parser.validate(data);
42
- }
43
- try {
44
- return parser(data);
45
- } catch (e) {
46
- const msg = `Failed to schema parse response data for status code ${status} with data:
47
-
48
- ${JSON.stringify(data, null, 2)}}`;
49
- throw new Error(msg);
50
- }
51
- }
52
-
53
- getParser(status: StatusCode, requireSchema: boolean) {
54
- const parser = this.#map.get(status);
55
- if (!parser && requireSchema) {
56
- const msg = `No parser registered for status code ${status} but 'requireSchema' is true`;
57
- throw new Error(msg);
58
- }
59
- if (parser) {
60
- return parser;
61
- }
62
- return (data: unknown) => data;
63
- }
64
-
65
- toObject() {
66
- return Object.fromEntries(this.#map) as Record<StatusCode, SchemaParser>;
67
- }
68
- }
@@ -1,43 +0,0 @@
1
- import { AutomationError } from "@autometa/errors";
2
- import isJson from "@stdlib/assert-is-json";
3
- import { highlight } from "cli-highlight";
4
-
5
- export function transformResponse(
6
- allowPlainText: boolean,
7
- data: null | undefined | string
8
- ) {
9
- if (data === null) {
10
- return null;
11
- }
12
- if (data === undefined) {
13
- return undefined;
14
- }
15
- if (data === "") {
16
- return data;
17
- }
18
- if (isJson(data)) {
19
- return JSON.parse(data);
20
- }
21
- if (typeof data === "string" && ["true", "false"].includes(data)) {
22
- return JSON.parse(data);
23
- }
24
- if (typeof data === "string" && /^\d*\.?\d+$/.test(data)) {
25
- return JSON.parse(data);
26
- }
27
-
28
- if (typeof data === "object") {
29
- return data;
30
- }
31
- if (allowPlainText) {
32
- return data;
33
- }
34
- const dataStr = typeof data === "string" ? data : JSON.stringify(data);
35
- const response = highlight(dataStr, { language: "html" });
36
- const message = [
37
- `Could not parse a response as json, and this request was not configured to allow plain text responses.`,
38
- `To allow plain text responses, use the 'allowPlainText' method on the HTTP client.`,
39
- "",
40
- response,
41
- ];
42
- throw new AutomationError(message.join("\n"));
43
- }
package/src/types.ts DELETED
@@ -1,37 +0,0 @@
1
- import type { StatusCodes } from "@autometa/status-codes";
2
- import type { HTTPResponse } from "./http-response";
3
- import type { HTTPRequest } from "./http-request";
4
- export type HTTPMethod =
5
- | "GET"
6
- | "POST"
7
- | "PUT"
8
- | "DELETE"
9
- | "PATCH"
10
- | "HEAD"
11
- | "OPTIONS"
12
- | "TRACE"
13
- | "CONNECT"
14
- | "get"
15
- | "post"
16
- | "put"
17
- | "delete"
18
- | "patch"
19
- | "head"
20
- | "options"
21
- | "trace"
22
- | "connect";
23
-
24
- export type HTTPAdditionalOptions<T> = {
25
- [P in keyof T]: T[P];
26
- };
27
- export type SchemaParser =
28
- | { parse: (data: unknown) => unknown }
29
- | { validate: (data: unknown) => unknown }
30
- | ((data: unknown) => unknown);
31
-
32
- export type StatusCode<T extends typeof StatusCodes = typeof StatusCodes> = {
33
- [P in keyof T]: T[P] extends { status: infer U } ? U : never;
34
- }[keyof T];
35
-
36
- export type RequestHook = <T = unknown>(state: HTTPRequest<T>) => unknown;
37
- export type ResponseHook<T> = (state: HTTPResponse<T>) => unknown;
package/tsup.config.ts DELETED
@@ -1,14 +0,0 @@
1
- import { defineConfig } from "tsup";
2
-
3
- export default defineConfig({
4
- clean: true, // clean up the dist folder
5
- format: ["cjs", "esm"], // generate cjs and esm files
6
- dts: true,
7
- sourcemap: true, // generate sourcemaps
8
- skipNodeModulesBundle: true,
9
- entryPoints: ["src/index.ts"],
10
- target: "es2020",
11
- outDir: "dist",
12
- legacyOutput: true,
13
- external: ["dist"],
14
- });