@ranwhenparked/trustap-sdk 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/README.md +251 -0
- package/deno.json +9 -0
- package/eslint.config.js +21 -0
- package/package.json +47 -0
- package/scripts/build-node.mjs +75 -0
- package/scripts/generate-operations-map.mjs +57 -0
- package/scripts/generate-security-map.mjs +92 -0
- package/src/__tests__/auth-middleware.test.ts +171 -0
- package/src/__tests__/client-factory.test.ts +105 -0
- package/src/__tests__/error-handling.test.ts +302 -0
- package/src/__tests__/helpers/mock-http-client.ts +193 -0
- package/src/__tests__/helpers/run-guard.ts +24 -0
- package/src/__tests__/helpers/test-fixtures.ts +82 -0
- package/src/__tests__/node-client.test.ts +244 -0
- package/src/__tests__/operation-proxy.test.ts +268 -0
- package/src/__tests__/query-params.test.ts +232 -0
- package/src/__tests__/setup.ts +44 -0
- package/src/__tests__/types.test.ts +169 -0
- package/src/client-deno.ts +219 -0
- package/src/client-factory.ts +45 -0
- package/src/core.ts +619 -0
- package/src/index.deno.ts +28 -0
- package/src/index.ts +36 -0
- package/src/operations-map.ts +667 -0
- package/src/schema.d.ts +12046 -0
- package/src/security-map.ts +770 -0
- package/src/state-machine.ts +79 -0
- package/src/webhook-schemas.ts +400 -0
- package/tsconfig.build.json +27 -0
- package/tsconfig.json +22 -0
- package/vitest.config.ts +31 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deno-compatible HTTP client for Trustap API
|
|
3
|
+
* This module provides a minimal implementation that works with Web APIs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface Middleware {
|
|
7
|
+
onRequest?(options: { request: Request }): Request | Promise<Request>;
|
|
8
|
+
onResponse?(options: {
|
|
9
|
+
request: Request;
|
|
10
|
+
response: Response;
|
|
11
|
+
}): Response | Promise<Response>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ClientOptions {
|
|
15
|
+
baseUrl: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface RequestOptions {
|
|
19
|
+
params?: {
|
|
20
|
+
query?: Record<string, string | number | boolean>;
|
|
21
|
+
path?: Record<string, string | number>;
|
|
22
|
+
};
|
|
23
|
+
body?: unknown;
|
|
24
|
+
headers?: Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class DenoHttpClient {
|
|
28
|
+
private baseUrl: string;
|
|
29
|
+
private middleware: Middleware[] = [];
|
|
30
|
+
|
|
31
|
+
constructor(options: ClientOptions) {
|
|
32
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
use(middleware: Middleware) {
|
|
36
|
+
this.middleware.push(middleware);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private async buildRequest(
|
|
40
|
+
path: string,
|
|
41
|
+
method: string,
|
|
42
|
+
options: RequestOptions = {},
|
|
43
|
+
): Promise<Request> {
|
|
44
|
+
let url = this.baseUrl + path;
|
|
45
|
+
|
|
46
|
+
// Handle path parameters
|
|
47
|
+
if (options.params?.path) {
|
|
48
|
+
for (const [key, value] of Object.entries(options.params.path)) {
|
|
49
|
+
url = url.replace(`{${key}}`, String(value));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Handle query parameters
|
|
54
|
+
if (options.params?.query) {
|
|
55
|
+
const searchParams = new URLSearchParams();
|
|
56
|
+
for (const [key, value] of Object.entries(options.params.query)) {
|
|
57
|
+
searchParams.set(key, String(value));
|
|
58
|
+
}
|
|
59
|
+
const queryString = searchParams.toString();
|
|
60
|
+
if (queryString) {
|
|
61
|
+
url += (url.includes("?") ? "&" : "?") + queryString;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const headers = new Headers(options.headers);
|
|
66
|
+
|
|
67
|
+
// Set content-type for body requests
|
|
68
|
+
if (options.body && !headers.has("content-type")) {
|
|
69
|
+
headers.set("content-type", "application/json");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let request = new Request(url, {
|
|
73
|
+
method: method.toUpperCase(),
|
|
74
|
+
headers,
|
|
75
|
+
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Apply middleware
|
|
79
|
+
for (const middleware of this.middleware) {
|
|
80
|
+
if (middleware.onRequest) {
|
|
81
|
+
request = await middleware.onRequest({ request });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return request;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private async handleResponse(request: Request, response: Response) {
|
|
89
|
+
let finalResponse = response;
|
|
90
|
+
|
|
91
|
+
// Apply response middleware
|
|
92
|
+
for (const middleware of this.middleware) {
|
|
93
|
+
if (middleware.onResponse) {
|
|
94
|
+
finalResponse = await middleware.onResponse({
|
|
95
|
+
request,
|
|
96
|
+
response: finalResponse,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!finalResponse.ok) {
|
|
102
|
+
let errorData: unknown;
|
|
103
|
+
try {
|
|
104
|
+
errorData = await finalResponse.json();
|
|
105
|
+
} catch {
|
|
106
|
+
errorData = { message: finalResponse.statusText };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const error = new Error(
|
|
110
|
+
`HTTP ${finalResponse.status}: ${finalResponse.statusText}`,
|
|
111
|
+
) as Error & { response: Response; data: unknown };
|
|
112
|
+
error.response = finalResponse;
|
|
113
|
+
error.data = errorData;
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Try to parse as JSON, fall back to text
|
|
118
|
+
try {
|
|
119
|
+
const data: unknown = await finalResponse.json();
|
|
120
|
+
return { data, response: finalResponse };
|
|
121
|
+
} catch {
|
|
122
|
+
const data: unknown = await finalResponse.text();
|
|
123
|
+
return { data, response: finalResponse };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async GET(path: string, options?: RequestOptions) {
|
|
128
|
+
const request = await this.buildRequest(path, "GET", options);
|
|
129
|
+
const response = await fetch(request);
|
|
130
|
+
return this.handleResponse(request, response);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async POST(path: string, options?: RequestOptions) {
|
|
134
|
+
const request = await this.buildRequest(path, "POST", options);
|
|
135
|
+
const response = await fetch(request);
|
|
136
|
+
return this.handleResponse(request, response);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async PUT(path: string, options?: RequestOptions) {
|
|
140
|
+
const request = await this.buildRequest(path, "PUT", options);
|
|
141
|
+
const response = await fetch(request);
|
|
142
|
+
return this.handleResponse(request, response);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async PATCH(path: string, options?: RequestOptions) {
|
|
146
|
+
const request = await this.buildRequest(path, "PATCH", options);
|
|
147
|
+
const response = await fetch(request);
|
|
148
|
+
return this.handleResponse(request, response);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async DELETE(path: string, options?: RequestOptions) {
|
|
152
|
+
const request = await this.buildRequest(path, "DELETE", options);
|
|
153
|
+
const response = await fetch(request);
|
|
154
|
+
return this.handleResponse(request, response);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async HEAD(path: string, options?: RequestOptions) {
|
|
158
|
+
const request = await this.buildRequest(path, "HEAD", options);
|
|
159
|
+
const response = await fetch(request);
|
|
160
|
+
return this.handleResponse(request, response);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async OPTIONS(path: string, options?: RequestOptions) {
|
|
164
|
+
const request = await this.buildRequest(path, "OPTIONS", options);
|
|
165
|
+
const response = await fetch(request);
|
|
166
|
+
return this.handleResponse(request, response);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function createClient(options: ClientOptions) {
|
|
171
|
+
return new DenoHttpClient(options);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Simple path-based client wrapper for compatibility
|
|
175
|
+
export type PathBasedClient = Record<
|
|
176
|
+
string,
|
|
177
|
+
Record<string, (options: RequestOptions) => Promise<unknown>>
|
|
178
|
+
>;
|
|
179
|
+
|
|
180
|
+
export function wrapAsPathBasedClient(client: DenoHttpClient): PathBasedClient {
|
|
181
|
+
return new Proxy({} as PathBasedClient, {
|
|
182
|
+
get(target, prop) {
|
|
183
|
+
const path = String(prop);
|
|
184
|
+
return new Proxy({} as Record<string, unknown>, {
|
|
185
|
+
get(target, method) {
|
|
186
|
+
const httpMethod = String(method).toUpperCase();
|
|
187
|
+
return (options: RequestOptions) => {
|
|
188
|
+
switch (httpMethod) {
|
|
189
|
+
case "GET": {
|
|
190
|
+
return client.GET(path, options);
|
|
191
|
+
}
|
|
192
|
+
case "POST": {
|
|
193
|
+
return client.POST(path, options);
|
|
194
|
+
}
|
|
195
|
+
case "PUT": {
|
|
196
|
+
return client.PUT(path, options);
|
|
197
|
+
}
|
|
198
|
+
case "PATCH": {
|
|
199
|
+
return client.PATCH(path, options);
|
|
200
|
+
}
|
|
201
|
+
case "DELETE": {
|
|
202
|
+
return client.DELETE(path, options);
|
|
203
|
+
}
|
|
204
|
+
case "HEAD": {
|
|
205
|
+
return client.HEAD(path, options);
|
|
206
|
+
}
|
|
207
|
+
case "OPTIONS": {
|
|
208
|
+
return client.OPTIONS(path, options);
|
|
209
|
+
}
|
|
210
|
+
default: {
|
|
211
|
+
throw new Error(`Unsupported HTTP method: ${httpMethod}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CreateTrustapClientOptions,
|
|
3
|
+
MinimalHttpClient,
|
|
4
|
+
} from "./core.ts";
|
|
5
|
+
import type { operations } from "./schema.d.ts";
|
|
6
|
+
import { createTrustapClientCore } from "./core.ts";
|
|
7
|
+
import { operationIdToPath } from "./operations-map.ts";
|
|
8
|
+
import { securityMap } from "./security-map.ts";
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export interface TrustapClientDependencies<
|
|
13
|
+
Middleware,
|
|
14
|
+
Client extends MinimalHttpClient<Middleware>,
|
|
15
|
+
PathClient,
|
|
16
|
+
> {
|
|
17
|
+
createClient: (options: { baseUrl: string }) => Client;
|
|
18
|
+
wrapAsPathBasedClient: (client: Client) => PathClient;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function createTrustapClientWithDeps<
|
|
22
|
+
Middleware,
|
|
23
|
+
Client extends MinimalHttpClient<Middleware>,
|
|
24
|
+
PathClient,
|
|
25
|
+
>(
|
|
26
|
+
deps: TrustapClientDependencies<Middleware, Client, PathClient>,
|
|
27
|
+
options: CreateTrustapClientOptions,
|
|
28
|
+
) {
|
|
29
|
+
return createTrustapClientCore<
|
|
30
|
+
operations,
|
|
31
|
+
Middleware,
|
|
32
|
+
Client,
|
|
33
|
+
typeof operationIdToPath,
|
|
34
|
+
PathClient
|
|
35
|
+
>(
|
|
36
|
+
{
|
|
37
|
+
...deps,
|
|
38
|
+
operationIdToPath,
|
|
39
|
+
securityMap,
|
|
40
|
+
},
|
|
41
|
+
options,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { type CreateTrustapClientOptions, type MinimalHttpClient} from "./core.ts";
|