@deliverart/sdk-js-core 0.0.6 → 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/CHANGELOG.md +12 -0
- package/dist/index.cjs +75 -0
- package/dist/index.d.cts +29 -4
- package/dist/index.d.ts +29 -4
- package/dist/index.js +74 -0
- package/package.json +3 -2
- package/src/ApiClient.ts +92 -6
- package/src/errors.ts +17 -0
package/CHANGELOG.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -30,16 +30,90 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
AbstractApiRequest: () => AbstractApiRequest,
|
|
33
34
|
createApiClient: () => createApiClient
|
|
34
35
|
});
|
|
35
36
|
module.exports = __toCommonJS(index_exports);
|
|
36
37
|
|
|
37
38
|
// src/ApiClient.ts
|
|
38
39
|
var import_axios = __toESM(require("axios"), 1);
|
|
40
|
+
|
|
41
|
+
// src/errors.ts
|
|
42
|
+
var InputValidationError = class extends Error {
|
|
43
|
+
// eslint-disable-next-line no-unused-vars
|
|
44
|
+
constructor(issues) {
|
|
45
|
+
super("Invalid input");
|
|
46
|
+
this.issues = issues;
|
|
47
|
+
this.name = "InputValidationError";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var OutputValidationError = class extends Error {
|
|
51
|
+
// eslint-disable-next-line no-unused-vars
|
|
52
|
+
constructor(issues) {
|
|
53
|
+
super("Invalid response");
|
|
54
|
+
this.issues = issues;
|
|
55
|
+
this.name = "OutputValidationError";
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// src/ApiClient.ts
|
|
60
|
+
var AbstractApiRequest = class {
|
|
61
|
+
constructor(input, options) {
|
|
62
|
+
this.input = input;
|
|
63
|
+
this.options = options;
|
|
64
|
+
}
|
|
65
|
+
validateInput() {
|
|
66
|
+
const result = this.inputSchema.safeParse(this.input);
|
|
67
|
+
if (!result.success) {
|
|
68
|
+
throw new InputValidationError(result.error.issues);
|
|
69
|
+
}
|
|
70
|
+
return result.data;
|
|
71
|
+
}
|
|
72
|
+
validateQuery() {
|
|
73
|
+
if (!this.querySchema || !this.options?.query) return void 0;
|
|
74
|
+
const result = this.querySchema.safeParse(this.options.query);
|
|
75
|
+
if (!result.success) {
|
|
76
|
+
throw new InputValidationError(result.error.issues);
|
|
77
|
+
}
|
|
78
|
+
return result.data;
|
|
79
|
+
}
|
|
80
|
+
validateHeaders() {
|
|
81
|
+
if (!this.headersSchema || !this.options?.headers) return void 0;
|
|
82
|
+
const result = this.headersSchema.safeParse(this.options.headers);
|
|
83
|
+
if (!result.success) {
|
|
84
|
+
throw new InputValidationError(result.error.issues);
|
|
85
|
+
}
|
|
86
|
+
return result.data;
|
|
87
|
+
}
|
|
88
|
+
validateOutput(data) {
|
|
89
|
+
const result = this.outputSchema.safeParse(data);
|
|
90
|
+
if (!result.success) {
|
|
91
|
+
throw new OutputValidationError(result.error.issues);
|
|
92
|
+
}
|
|
93
|
+
return result.data;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
39
96
|
function createApiClient(config) {
|
|
40
97
|
const http = import_axios.default.create({ baseURL: config.baseUrl });
|
|
41
98
|
const base = {
|
|
42
99
|
http,
|
|
100
|
+
async call(request) {
|
|
101
|
+
const input = request.validateInput();
|
|
102
|
+
const query = request.validateQuery();
|
|
103
|
+
const headers = request.validateHeaders();
|
|
104
|
+
const res = await http.request({
|
|
105
|
+
url: request.getPath(),
|
|
106
|
+
method: request.method,
|
|
107
|
+
headers: {
|
|
108
|
+
"Content-Type": request.contentType,
|
|
109
|
+
Accept: request.accept,
|
|
110
|
+
...headers ?? {}
|
|
111
|
+
},
|
|
112
|
+
params: query,
|
|
113
|
+
data: request.method !== "GET" ? input : void 0
|
|
114
|
+
});
|
|
115
|
+
return request.validateOutput(res.data);
|
|
116
|
+
},
|
|
43
117
|
addPlugin(plugin) {
|
|
44
118
|
const extension = plugin.setup(this);
|
|
45
119
|
return { ...this, ...extension };
|
|
@@ -49,5 +123,6 @@ function createApiClient(config) {
|
|
|
49
123
|
}
|
|
50
124
|
// Annotate the CommonJS export names for ESM import in node:
|
|
51
125
|
0 && (module.exports = {
|
|
126
|
+
AbstractApiRequest,
|
|
52
127
|
createApiClient
|
|
53
128
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,17 +1,42 @@
|
|
|
1
1
|
import { AxiosInstance } from 'axios';
|
|
2
|
+
import { ZodSchema } from 'zod';
|
|
2
3
|
|
|
3
4
|
type ApiExtension = Record<string, unknown>;
|
|
4
5
|
interface ApiClientPlugin<T extends ApiExtension = Record<string, unknown>> {
|
|
5
6
|
setup: (client: ApiClient<Record<string, unknown>>) => T;
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
declare
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
declare abstract class AbstractApiRequest<Input, Output, Query = unknown, Headers = unknown> {
|
|
10
|
+
readonly input: Input;
|
|
11
|
+
readonly options?: {
|
|
12
|
+
query?: Query;
|
|
13
|
+
headers?: Headers;
|
|
14
|
+
} | undefined;
|
|
15
|
+
abstract readonly method: 'GET' | 'POST' | 'PATCH' | 'DELETE';
|
|
16
|
+
abstract readonly contentType: 'application/json' | 'multipart/form-data' | 'application/merge-patch+json';
|
|
17
|
+
abstract readonly accept: 'application/json';
|
|
18
|
+
abstract readonly inputSchema: ZodSchema<Input>;
|
|
19
|
+
abstract readonly outputSchema: ZodSchema<Output>;
|
|
20
|
+
abstract readonly querySchema?: ZodSchema<Query>;
|
|
21
|
+
abstract readonly headersSchema?: ZodSchema<Headers>;
|
|
22
|
+
protected constructor(input: Input, options?: {
|
|
23
|
+
query?: Query;
|
|
24
|
+
headers?: Headers;
|
|
25
|
+
} | undefined);
|
|
26
|
+
abstract getPath(): string;
|
|
27
|
+
validateInput(): Input;
|
|
28
|
+
validateQuery(): Query | undefined;
|
|
29
|
+
validateHeaders(): Headers | undefined;
|
|
30
|
+
validateOutput(data: unknown): Output;
|
|
31
|
+
}
|
|
11
32
|
interface ApiClientBase {
|
|
12
33
|
http: AxiosInstance;
|
|
13
34
|
addPlugin: <T extends ApiExtension>(plugin: ApiClientPlugin<T>) => ApiClient<T>;
|
|
35
|
+
call<I, O, Q, H>(request: AbstractApiRequest<I, O, Q, H>): Promise<O>;
|
|
14
36
|
}
|
|
37
|
+
declare function createApiClient<Extensions extends ApiExtension = NonNullable<unknown>>(config: {
|
|
38
|
+
baseUrl: string;
|
|
39
|
+
}): ApiClient<Extensions>;
|
|
15
40
|
type ApiClient<Extensions extends ApiExtension = NonNullable<unknown>> = ApiClientBase & Extensions;
|
|
16
41
|
|
|
17
|
-
export { type ApiClient, type ApiClientPlugin, type ApiExtension, createApiClient };
|
|
42
|
+
export { AbstractApiRequest, type ApiClient, type ApiClientPlugin, type ApiExtension, createApiClient };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,42 @@
|
|
|
1
1
|
import { AxiosInstance } from 'axios';
|
|
2
|
+
import { ZodSchema } from 'zod';
|
|
2
3
|
|
|
3
4
|
type ApiExtension = Record<string, unknown>;
|
|
4
5
|
interface ApiClientPlugin<T extends ApiExtension = Record<string, unknown>> {
|
|
5
6
|
setup: (client: ApiClient<Record<string, unknown>>) => T;
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
declare
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
declare abstract class AbstractApiRequest<Input, Output, Query = unknown, Headers = unknown> {
|
|
10
|
+
readonly input: Input;
|
|
11
|
+
readonly options?: {
|
|
12
|
+
query?: Query;
|
|
13
|
+
headers?: Headers;
|
|
14
|
+
} | undefined;
|
|
15
|
+
abstract readonly method: 'GET' | 'POST' | 'PATCH' | 'DELETE';
|
|
16
|
+
abstract readonly contentType: 'application/json' | 'multipart/form-data' | 'application/merge-patch+json';
|
|
17
|
+
abstract readonly accept: 'application/json';
|
|
18
|
+
abstract readonly inputSchema: ZodSchema<Input>;
|
|
19
|
+
abstract readonly outputSchema: ZodSchema<Output>;
|
|
20
|
+
abstract readonly querySchema?: ZodSchema<Query>;
|
|
21
|
+
abstract readonly headersSchema?: ZodSchema<Headers>;
|
|
22
|
+
protected constructor(input: Input, options?: {
|
|
23
|
+
query?: Query;
|
|
24
|
+
headers?: Headers;
|
|
25
|
+
} | undefined);
|
|
26
|
+
abstract getPath(): string;
|
|
27
|
+
validateInput(): Input;
|
|
28
|
+
validateQuery(): Query | undefined;
|
|
29
|
+
validateHeaders(): Headers | undefined;
|
|
30
|
+
validateOutput(data: unknown): Output;
|
|
31
|
+
}
|
|
11
32
|
interface ApiClientBase {
|
|
12
33
|
http: AxiosInstance;
|
|
13
34
|
addPlugin: <T extends ApiExtension>(plugin: ApiClientPlugin<T>) => ApiClient<T>;
|
|
35
|
+
call<I, O, Q, H>(request: AbstractApiRequest<I, O, Q, H>): Promise<O>;
|
|
14
36
|
}
|
|
37
|
+
declare function createApiClient<Extensions extends ApiExtension = NonNullable<unknown>>(config: {
|
|
38
|
+
baseUrl: string;
|
|
39
|
+
}): ApiClient<Extensions>;
|
|
15
40
|
type ApiClient<Extensions extends ApiExtension = NonNullable<unknown>> = ApiClientBase & Extensions;
|
|
16
41
|
|
|
17
|
-
export { type ApiClient, type ApiClientPlugin, type ApiExtension, createApiClient };
|
|
42
|
+
export { AbstractApiRequest, type ApiClient, type ApiClientPlugin, type ApiExtension, createApiClient };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,82 @@
|
|
|
1
1
|
// src/ApiClient.ts
|
|
2
2
|
import axios from "axios";
|
|
3
|
+
|
|
4
|
+
// src/errors.ts
|
|
5
|
+
var InputValidationError = class extends Error {
|
|
6
|
+
// eslint-disable-next-line no-unused-vars
|
|
7
|
+
constructor(issues) {
|
|
8
|
+
super("Invalid input");
|
|
9
|
+
this.issues = issues;
|
|
10
|
+
this.name = "InputValidationError";
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var OutputValidationError = class extends Error {
|
|
14
|
+
// eslint-disable-next-line no-unused-vars
|
|
15
|
+
constructor(issues) {
|
|
16
|
+
super("Invalid response");
|
|
17
|
+
this.issues = issues;
|
|
18
|
+
this.name = "OutputValidationError";
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// src/ApiClient.ts
|
|
23
|
+
var AbstractApiRequest = class {
|
|
24
|
+
constructor(input, options) {
|
|
25
|
+
this.input = input;
|
|
26
|
+
this.options = options;
|
|
27
|
+
}
|
|
28
|
+
validateInput() {
|
|
29
|
+
const result = this.inputSchema.safeParse(this.input);
|
|
30
|
+
if (!result.success) {
|
|
31
|
+
throw new InputValidationError(result.error.issues);
|
|
32
|
+
}
|
|
33
|
+
return result.data;
|
|
34
|
+
}
|
|
35
|
+
validateQuery() {
|
|
36
|
+
if (!this.querySchema || !this.options?.query) return void 0;
|
|
37
|
+
const result = this.querySchema.safeParse(this.options.query);
|
|
38
|
+
if (!result.success) {
|
|
39
|
+
throw new InputValidationError(result.error.issues);
|
|
40
|
+
}
|
|
41
|
+
return result.data;
|
|
42
|
+
}
|
|
43
|
+
validateHeaders() {
|
|
44
|
+
if (!this.headersSchema || !this.options?.headers) return void 0;
|
|
45
|
+
const result = this.headersSchema.safeParse(this.options.headers);
|
|
46
|
+
if (!result.success) {
|
|
47
|
+
throw new InputValidationError(result.error.issues);
|
|
48
|
+
}
|
|
49
|
+
return result.data;
|
|
50
|
+
}
|
|
51
|
+
validateOutput(data) {
|
|
52
|
+
const result = this.outputSchema.safeParse(data);
|
|
53
|
+
if (!result.success) {
|
|
54
|
+
throw new OutputValidationError(result.error.issues);
|
|
55
|
+
}
|
|
56
|
+
return result.data;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
3
59
|
function createApiClient(config) {
|
|
4
60
|
const http = axios.create({ baseURL: config.baseUrl });
|
|
5
61
|
const base = {
|
|
6
62
|
http,
|
|
63
|
+
async call(request) {
|
|
64
|
+
const input = request.validateInput();
|
|
65
|
+
const query = request.validateQuery();
|
|
66
|
+
const headers = request.validateHeaders();
|
|
67
|
+
const res = await http.request({
|
|
68
|
+
url: request.getPath(),
|
|
69
|
+
method: request.method,
|
|
70
|
+
headers: {
|
|
71
|
+
"Content-Type": request.contentType,
|
|
72
|
+
Accept: request.accept,
|
|
73
|
+
...headers ?? {}
|
|
74
|
+
},
|
|
75
|
+
params: query,
|
|
76
|
+
data: request.method !== "GET" ? input : void 0
|
|
77
|
+
});
|
|
78
|
+
return request.validateOutput(res.data);
|
|
79
|
+
},
|
|
7
80
|
addPlugin(plugin) {
|
|
8
81
|
const extension = plugin.setup(this);
|
|
9
82
|
return { ...this, ...extension };
|
|
@@ -12,5 +85,6 @@ function createApiClient(config) {
|
|
|
12
85
|
return base;
|
|
13
86
|
}
|
|
14
87
|
export {
|
|
88
|
+
AbstractApiRequest,
|
|
15
89
|
createApiClient
|
|
16
90
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deliverart/sdk-js-core",
|
|
3
3
|
"description": "Core SDK for DeliverArt, providing essential functionalities and utilities.",
|
|
4
|
-
"version": "0.0
|
|
4
|
+
"version": "0.1.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"axios": "1.9.0"
|
|
15
|
+
"axios": "1.9.0",
|
|
16
|
+
"zod": "3.25.67"
|
|
16
17
|
},
|
|
17
18
|
"devDependencies": {
|
|
18
19
|
"@changesets/cli": "^2.29.4",
|
package/src/ApiClient.ts
CHANGED
|
@@ -1,7 +1,78 @@
|
|
|
1
1
|
import axios, { AxiosInstance } from 'axios'
|
|
2
|
+
import { ZodSchema } from 'zod'
|
|
2
3
|
|
|
4
|
+
import { InputValidationError, OutputValidationError } from './errors'
|
|
3
5
|
import type { ApiClientPlugin, ApiExtension } from './types'
|
|
4
6
|
|
|
7
|
+
export abstract class AbstractApiRequest<Input, Output, Query = unknown, Headers = unknown> {
|
|
8
|
+
abstract readonly method: 'GET' | 'POST' | 'PATCH' | 'DELETE'
|
|
9
|
+
abstract readonly contentType:
|
|
10
|
+
| 'application/json'
|
|
11
|
+
| 'multipart/form-data'
|
|
12
|
+
| 'application/merge-patch+json'
|
|
13
|
+
abstract readonly accept: 'application/json'
|
|
14
|
+
abstract readonly inputSchema: ZodSchema<Input>
|
|
15
|
+
abstract readonly outputSchema: ZodSchema<Output>
|
|
16
|
+
abstract readonly querySchema?: ZodSchema<Query>
|
|
17
|
+
abstract readonly headersSchema?: ZodSchema<Headers>
|
|
18
|
+
|
|
19
|
+
protected constructor(
|
|
20
|
+
// eslint-disable-next-line no-unused-vars
|
|
21
|
+
public readonly input: Input,
|
|
22
|
+
// eslint-disable-next-line no-unused-vars
|
|
23
|
+
public readonly options?: {
|
|
24
|
+
query?: Query
|
|
25
|
+
headers?: Headers
|
|
26
|
+
},
|
|
27
|
+
) {}
|
|
28
|
+
|
|
29
|
+
abstract getPath(): string
|
|
30
|
+
|
|
31
|
+
validateInput(): Input {
|
|
32
|
+
const result = this.inputSchema.safeParse(this.input)
|
|
33
|
+
if (!result.success) {
|
|
34
|
+
throw new InputValidationError(result.error.issues)
|
|
35
|
+
}
|
|
36
|
+
return result.data
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
validateQuery(): Query | undefined {
|
|
40
|
+
if (!this.querySchema || !this.options?.query) return undefined
|
|
41
|
+
|
|
42
|
+
const result = this.querySchema.safeParse(this.options.query)
|
|
43
|
+
if (!result.success) {
|
|
44
|
+
throw new InputValidationError(result.error.issues)
|
|
45
|
+
}
|
|
46
|
+
return result.data
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
validateHeaders(): Headers | undefined {
|
|
50
|
+
if (!this.headersSchema || !this.options?.headers) return undefined
|
|
51
|
+
|
|
52
|
+
const result = this.headersSchema.safeParse(this.options.headers)
|
|
53
|
+
if (!result.success) {
|
|
54
|
+
throw new InputValidationError(result.error.issues)
|
|
55
|
+
}
|
|
56
|
+
return result.data
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
validateOutput(data: unknown): Output {
|
|
60
|
+
const result = this.outputSchema.safeParse(data)
|
|
61
|
+
if (!result.success) {
|
|
62
|
+
throw new OutputValidationError(result.error.issues)
|
|
63
|
+
}
|
|
64
|
+
return result.data
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface ApiClientBase {
|
|
69
|
+
http: AxiosInstance
|
|
70
|
+
// eslint-disable-next-line no-unused-vars
|
|
71
|
+
addPlugin: <T extends ApiExtension>(plugin: ApiClientPlugin<T>) => ApiClient<T>
|
|
72
|
+
// eslint-disable-next-line no-unused-vars
|
|
73
|
+
call<I, O, Q, H>(request: AbstractApiRequest<I, O, Q, H>): Promise<O>
|
|
74
|
+
}
|
|
75
|
+
|
|
5
76
|
export function createApiClient<Extensions extends ApiExtension = NonNullable<unknown>>(config: {
|
|
6
77
|
baseUrl: string
|
|
7
78
|
}): ApiClient<Extensions> {
|
|
@@ -9,6 +80,27 @@ export function createApiClient<Extensions extends ApiExtension = NonNullable<un
|
|
|
9
80
|
|
|
10
81
|
const base: ApiClientBase = {
|
|
11
82
|
http,
|
|
83
|
+
|
|
84
|
+
async call<I, O, Q, H>(request: AbstractApiRequest<I, O, Q, H>): Promise<O> {
|
|
85
|
+
const input = request.validateInput()
|
|
86
|
+
const query = request.validateQuery()
|
|
87
|
+
const headers = request.validateHeaders()
|
|
88
|
+
|
|
89
|
+
const res = await http.request({
|
|
90
|
+
url: request.getPath(),
|
|
91
|
+
method: request.method,
|
|
92
|
+
headers: {
|
|
93
|
+
'Content-Type': request.contentType,
|
|
94
|
+
Accept: request.accept,
|
|
95
|
+
...(headers ?? {}),
|
|
96
|
+
},
|
|
97
|
+
params: query,
|
|
98
|
+
data: request.method !== 'GET' ? input : undefined,
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
return request.validateOutput(res.data)
|
|
102
|
+
},
|
|
103
|
+
|
|
12
104
|
addPlugin<T extends ApiExtension>(plugin: ApiClientPlugin<T>) {
|
|
13
105
|
const extension = plugin.setup(this as ApiClient<Extensions & T>)
|
|
14
106
|
return { ...this, ...extension } as ApiClient<Extensions & T>
|
|
@@ -18,11 +110,5 @@ export function createApiClient<Extensions extends ApiExtension = NonNullable<un
|
|
|
18
110
|
return base as ApiClient<Extensions>
|
|
19
111
|
}
|
|
20
112
|
|
|
21
|
-
interface ApiClientBase {
|
|
22
|
-
http: AxiosInstance
|
|
23
|
-
// eslint-disable-next-line no-unused-vars
|
|
24
|
-
addPlugin: <T extends ApiExtension>(plugin: ApiClientPlugin<T>) => ApiClient<T>
|
|
25
|
-
}
|
|
26
|
-
|
|
27
113
|
export type ApiClient<Extensions extends ApiExtension = NonNullable<unknown>> = ApiClientBase &
|
|
28
114
|
Extensions
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ZodIssue } from 'zod'
|
|
2
|
+
|
|
3
|
+
export class InputValidationError extends Error {
|
|
4
|
+
// eslint-disable-next-line no-unused-vars
|
|
5
|
+
constructor(public readonly issues: ZodIssue[]) {
|
|
6
|
+
super('Invalid input')
|
|
7
|
+
this.name = 'InputValidationError'
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class OutputValidationError extends Error {
|
|
12
|
+
// eslint-disable-next-line no-unused-vars
|
|
13
|
+
constructor(public readonly issues: ZodIssue[]) {
|
|
14
|
+
super('Invalid response')
|
|
15
|
+
this.name = 'OutputValidationError'
|
|
16
|
+
}
|
|
17
|
+
}
|