@devpad/api 1.0.1 → 2.0.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/README.md +2 -2
- package/dist/api-client.d.ts +216 -83
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +222 -99
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/request.d.ts +9 -1
- package/dist/request.d.ts.map +1 -1
- package/dist/request.js +29 -14
- package/dist/result.d.ts +8 -40
- package/dist/result.d.ts.map +1 -1
- package/dist/result.js +9 -42
- package/dist/tools.d.ts +5 -5
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +238 -189
- package/package.json +3 -2
package/dist/request.js
CHANGED
|
@@ -4,15 +4,19 @@ import { ApiError, AuthenticationError } from "./errors";
|
|
|
4
4
|
export class ApiClient {
|
|
5
5
|
constructor(options) {
|
|
6
6
|
this.category = "api";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
this.auth_mode = options.auth_mode ?? (options.api_key?.startsWith("jwt:") ? "session" : "key");
|
|
8
|
+
if (this.auth_mode !== "cookie") {
|
|
9
|
+
if (!options.api_key)
|
|
10
|
+
throw new Error("API key is required");
|
|
11
|
+
if (options.api_key.length < 10)
|
|
12
|
+
throw new Error("API key is too short");
|
|
12
13
|
}
|
|
13
14
|
this.base_url = options.base_url;
|
|
14
|
-
this.api_key = options.api_key;
|
|
15
|
+
this.api_key = options.api_key ?? "";
|
|
15
16
|
this.category = options.category || "api";
|
|
17
|
+
this.credentials = options.credentials;
|
|
18
|
+
this.default_headers = options.default_headers ?? {};
|
|
19
|
+
this.custom_fetch = options.custom_fetch;
|
|
16
20
|
this.request_history = new ArrayBufferedQueue(options.max_history_size ?? 5);
|
|
17
21
|
}
|
|
18
22
|
buildUrl(path, query) {
|
|
@@ -41,10 +45,16 @@ export class ApiClient {
|
|
|
41
45
|
});
|
|
42
46
|
const request_headers = {
|
|
43
47
|
"Content-Type": "application/json",
|
|
44
|
-
Authorization: `Bearer ${this.api_key}`,
|
|
45
48
|
"X-Request-ID": requestId,
|
|
49
|
+
...this.default_headers,
|
|
46
50
|
...headers,
|
|
47
51
|
};
|
|
52
|
+
if (this.auth_mode === "session") {
|
|
53
|
+
request_headers.Authorization = `Bearer jwt:${this.api_key.replace(/^jwt:/, "")}`;
|
|
54
|
+
}
|
|
55
|
+
else if (this.auth_mode === "key") {
|
|
56
|
+
request_headers.Authorization = `Bearer ${this.api_key}`;
|
|
57
|
+
}
|
|
48
58
|
// Initialize history entry
|
|
49
59
|
const historyEntry = {
|
|
50
60
|
timestamp,
|
|
@@ -61,7 +71,14 @@ export class ApiClient {
|
|
|
61
71
|
if (body) {
|
|
62
72
|
fetchOptions.body = JSON.stringify(body);
|
|
63
73
|
}
|
|
64
|
-
|
|
74
|
+
if (this.credentials) {
|
|
75
|
+
fetchOptions.credentials = this.credentials;
|
|
76
|
+
}
|
|
77
|
+
else if (this.auth_mode === "cookie") {
|
|
78
|
+
fetchOptions.credentials = "include";
|
|
79
|
+
}
|
|
80
|
+
const fetcher = this.custom_fetch ?? fetch;
|
|
81
|
+
const response = await fetcher(url, fetchOptions);
|
|
65
82
|
const duration = Date.now() - startTime;
|
|
66
83
|
// Update history entry with response info
|
|
67
84
|
historyEntry.status = response.status;
|
|
@@ -117,6 +134,7 @@ export class ApiClient {
|
|
|
117
134
|
catch (error) {
|
|
118
135
|
const duration = Date.now() - startTime;
|
|
119
136
|
console.log(`[ERROR][${this.category}] ${method} ${path} [${requestId}] failed`, {
|
|
137
|
+
url,
|
|
120
138
|
duration: `${duration}ms`,
|
|
121
139
|
error: error instanceof Error ? error.message : String(error),
|
|
122
140
|
body,
|
|
@@ -161,16 +179,13 @@ export class ApiClient {
|
|
|
161
179
|
return this.base_url;
|
|
162
180
|
}
|
|
163
181
|
headers() {
|
|
164
|
-
const isJWT = this.api_key.startsWith("jwt:");
|
|
165
182
|
const headers = {
|
|
166
183
|
"Content-Type": "application/json",
|
|
167
184
|
};
|
|
168
|
-
if (
|
|
169
|
-
|
|
170
|
-
headers.Authorization = `Bearer ${this.api_key.replace("jwt:", "")}`;
|
|
185
|
+
if (this.auth_mode === "session") {
|
|
186
|
+
headers.Authorization = `Bearer jwt:${this.api_key.replace(/^jwt:/, "")}`;
|
|
171
187
|
}
|
|
172
|
-
else {
|
|
173
|
-
// API key in X-API-KEY header
|
|
188
|
+
else if (this.auth_mode === "key") {
|
|
174
189
|
headers["X-API-KEY"] = this.api_key;
|
|
175
190
|
}
|
|
176
191
|
return headers;
|
package/dist/result.d.ts
CHANGED
|
@@ -1,42 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
[K in TName]: TData;
|
|
7
|
-
} & {
|
|
8
|
-
error: null;
|
|
1
|
+
import { err, ok, type Result } from "@f0rbit/corpus";
|
|
2
|
+
export type ApiResultError = {
|
|
3
|
+
message: string;
|
|
4
|
+
code?: string;
|
|
5
|
+
status_code?: number;
|
|
9
6
|
};
|
|
10
|
-
export type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
error: {
|
|
14
|
-
message: string;
|
|
15
|
-
code?: string;
|
|
16
|
-
status_code?: number;
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
export type Result<TData, TName extends string> = Success<TData, TName> | Failure<TName>;
|
|
20
|
-
/**
|
|
21
|
-
* Wraps any async function with Result type for clean error handling
|
|
22
|
-
* Automatically generates context-aware property names
|
|
23
|
-
*
|
|
24
|
-
* @param fn - The async function to wrap
|
|
25
|
-
* @param data_name - The property name for the data in the result
|
|
26
|
-
* @returns Promise that resolves to Result type with success/error pattern
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
* ```typescript
|
|
30
|
-
* const getProject = (id: string) =>
|
|
31
|
-
* wrap(() => client.projects.find(id), 'project');
|
|
32
|
-
*
|
|
33
|
-
* const { project, error } = await getProject('123');
|
|
34
|
-
* if (error) {
|
|
35
|
-
* console.error(error.message);
|
|
36
|
-
* return;
|
|
37
|
-
* }
|
|
38
|
-
* // project is guaranteed to be non-null here
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
export declare function wrap<TData, TName extends string>(fn: () => Promise<TData>, data_name: TName): Promise<Result<TData, TName>>;
|
|
7
|
+
export type ApiResult<T> = Result<T, ApiResultError>;
|
|
8
|
+
export declare function wrap<T>(fn: () => Promise<T>): Promise<ApiResult<T>>;
|
|
9
|
+
export { ok, err, type Result };
|
|
42
10
|
//# sourceMappingURL=result.d.ts.map
|
package/dist/result.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;AAErD,wBAAgB,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAUnE;AAED,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,MAAM,EAAE,CAAC"}
|
package/dist/result.js
CHANGED
|
@@ -1,44 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* Provides type-safe success/failure patterns with context-aware property names
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Wraps any async function with Result type for clean error handling
|
|
7
|
-
* Automatically generates context-aware property names
|
|
8
|
-
*
|
|
9
|
-
* @param fn - The async function to wrap
|
|
10
|
-
* @param data_name - The property name for the data in the result
|
|
11
|
-
* @returns Promise that resolves to Result type with success/error pattern
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```typescript
|
|
15
|
-
* const getProject = (id: string) =>
|
|
16
|
-
* wrap(() => client.projects.find(id), 'project');
|
|
17
|
-
*
|
|
18
|
-
* const { project, error } = await getProject('123');
|
|
19
|
-
* if (error) {
|
|
20
|
-
* console.error(error.message);
|
|
21
|
-
* return;
|
|
22
|
-
* }
|
|
23
|
-
* // project is guaranteed to be non-null here
|
|
24
|
-
* ```
|
|
25
|
-
*/
|
|
26
|
-
export function wrap(fn, data_name) {
|
|
1
|
+
import { err, ok } from "@f0rbit/corpus";
|
|
2
|
+
export function wrap(fn) {
|
|
27
3
|
return fn()
|
|
28
|
-
.then(data =>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const result = {
|
|
35
|
-
error: {
|
|
36
|
-
message: error.message || `Failed to fetch ${data_name}`,
|
|
37
|
-
code: error.code,
|
|
38
|
-
status_code: error.statusCode || error.status_code,
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
result[data_name] = null;
|
|
42
|
-
return result;
|
|
43
|
-
});
|
|
4
|
+
.then(data => ok(data))
|
|
5
|
+
.catch(error => err({
|
|
6
|
+
message: error.message || "Unknown error",
|
|
7
|
+
code: error.code,
|
|
8
|
+
status_code: error.statusCode || error.status_code,
|
|
9
|
+
}));
|
|
44
10
|
}
|
|
11
|
+
export { ok, err };
|
package/dist/tools.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { ApiClient } from "./api-client";
|
|
2
|
+
import type { ApiClient } from "./api-client";
|
|
3
3
|
export declare const project_filters: z.ZodObject<{
|
|
4
4
|
private: z.ZodOptional<z.ZodBoolean>;
|
|
5
5
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -11,17 +11,17 @@ export declare const project_by_id_or_name: z.ZodEffects<z.ZodObject<{
|
|
|
11
11
|
id: z.ZodOptional<z.ZodString>;
|
|
12
12
|
name: z.ZodOptional<z.ZodString>;
|
|
13
13
|
}, "strip", z.ZodTypeAny, {
|
|
14
|
-
id?: string | undefined;
|
|
15
14
|
name?: string | undefined;
|
|
16
|
-
}, {
|
|
17
15
|
id?: string | undefined;
|
|
16
|
+
}, {
|
|
18
17
|
name?: string | undefined;
|
|
19
|
-
}>, {
|
|
20
18
|
id?: string | undefined;
|
|
19
|
+
}>, {
|
|
21
20
|
name?: string | undefined;
|
|
22
|
-
}, {
|
|
23
21
|
id?: string | undefined;
|
|
22
|
+
}, {
|
|
24
23
|
name?: string | undefined;
|
|
24
|
+
id?: string | undefined;
|
|
25
25
|
}>;
|
|
26
26
|
export declare const task_filters: z.ZodObject<{
|
|
27
27
|
project_id: z.ZodOptional<z.ZodString>;
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAQ9C,eAAO,MAAM,eAAe;;;;;;EAE1B,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;EAO/B,CAAC;AAEJ,eAAO,MAAM,YAAY;;;;;;;;;EAGvB,CAAC;AAEH,eAAO,MAAM,UAAU;;;;;;EAErB,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;EAE5B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;EAE1B,CAAC;AAEH,eAAO,MAAM,UAAU;;;;;;EAErB,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;;;;EAG1B,CAAC;AAGH,MAAM,WAAW,cAAc,CAAC,MAAM,GAAG,GAAG,EAAE,OAAO,GAAG,GAAG;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/B,OAAO,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAChE;AAGD,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAsdhD,CAAC;AAGF,wBAAgB,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,qCAIpD;AAGD,eAAO,MAAM,SAAS,UAAqB,CAAC;AAG5C,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAEhE"}
|