@forklaunch/universal-sdk 0.3.16 → 0.4.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/lib/index.js +120 -117
- package/lib/index.mjs +125 -118
- package/package.json +8 -8
package/lib/index.js
CHANGED
|
@@ -170,7 +170,33 @@ function mapContentType(contentType) {
|
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
// src/core/
|
|
173
|
+
// src/core/openApi.ts
|
|
174
|
+
function getSdkPathMap(registryOpenApiJson) {
|
|
175
|
+
const sdkPathMap = {};
|
|
176
|
+
Object.entries(registryOpenApiJson?.paths || {}).forEach(
|
|
177
|
+
([path, pathItem]) => {
|
|
178
|
+
const methods = [
|
|
179
|
+
"get",
|
|
180
|
+
"post",
|
|
181
|
+
"put",
|
|
182
|
+
"patch",
|
|
183
|
+
"delete",
|
|
184
|
+
"options",
|
|
185
|
+
"head",
|
|
186
|
+
"trace"
|
|
187
|
+
];
|
|
188
|
+
methods.forEach((method) => {
|
|
189
|
+
if (pathItem[method]?.operationId) {
|
|
190
|
+
sdkPathMap[pathItem[method].operationId] = {
|
|
191
|
+
method,
|
|
192
|
+
path
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
return sdkPathMap;
|
|
199
|
+
}
|
|
174
200
|
async function refreshOpenApi(host, registryOptions, existingRegistryOpenApiHash) {
|
|
175
201
|
if (existingRegistryOpenApiHash === "static" || "static" in registryOptions && registryOptions.static) {
|
|
176
202
|
return {
|
|
@@ -181,7 +207,8 @@ async function refreshOpenApi(host, registryOptions, existingRegistryOpenApiHash
|
|
|
181
207
|
return {
|
|
182
208
|
updateRequired: true,
|
|
183
209
|
registryOpenApiJson: registryOptions.raw,
|
|
184
|
-
registryOpenApiHash: "static"
|
|
210
|
+
registryOpenApiHash: "static",
|
|
211
|
+
sdkPathMap: getSdkPathMap(registryOptions.raw)
|
|
185
212
|
};
|
|
186
213
|
}
|
|
187
214
|
const registry = "path" in registryOptions ? `${host}/${registryOptions.path}` : "url" in registryOptions ? registryOptions.url : null;
|
|
@@ -196,7 +223,8 @@ async function refreshOpenApi(host, registryOptions, existingRegistryOpenApiHash
|
|
|
196
223
|
return {
|
|
197
224
|
updateRequired: true,
|
|
198
225
|
registryOpenApiJson,
|
|
199
|
-
registryOpenApiHash
|
|
226
|
+
registryOpenApiHash,
|
|
227
|
+
sdkPathMap: getSdkPathMap(registryOpenApiJson)
|
|
200
228
|
};
|
|
201
229
|
}
|
|
202
230
|
return {
|
|
@@ -312,13 +340,14 @@ function getSdkPath(path) {
|
|
|
312
340
|
|
|
313
341
|
// src/universalSdk.ts
|
|
314
342
|
var UniversalSdk = class _UniversalSdk {
|
|
315
|
-
constructor(host, ajv, registryOptions, contentTypeParserMap, registryOpenApiJson, registryOpenApiHash) {
|
|
343
|
+
constructor(host, ajv, registryOptions, contentTypeParserMap, registryOpenApiJson, registryOpenApiHash, sdkPathMap) {
|
|
316
344
|
this.host = host;
|
|
317
345
|
this.ajv = ajv;
|
|
318
346
|
this.registryOptions = registryOptions;
|
|
319
347
|
this.contentTypeParserMap = contentTypeParserMap;
|
|
320
348
|
this.registryOpenApiJson = registryOpenApiJson;
|
|
321
349
|
this.registryOpenApiHash = registryOpenApiHash;
|
|
350
|
+
this.sdkPathMap = sdkPathMap;
|
|
322
351
|
}
|
|
323
352
|
/**
|
|
324
353
|
* Creates an instance of UniversalSdk.
|
|
@@ -329,9 +358,11 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
329
358
|
const refreshResult = await refreshOpenApi(host, registryOptions);
|
|
330
359
|
let registryOpenApiJson;
|
|
331
360
|
let registryOpenApiHash;
|
|
361
|
+
let sdkPathMap;
|
|
332
362
|
if (refreshResult.updateRequired) {
|
|
333
363
|
registryOpenApiJson = refreshResult.registryOpenApiJson;
|
|
334
364
|
registryOpenApiHash = refreshResult.registryOpenApiHash;
|
|
365
|
+
sdkPathMap = refreshResult.sdkPathMap;
|
|
335
366
|
}
|
|
336
367
|
const ajv = new import_ajv.default({
|
|
337
368
|
coerceTypes: true,
|
|
@@ -345,18 +376,11 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
345
376
|
registryOptions,
|
|
346
377
|
contentTypeParserMap,
|
|
347
378
|
registryOpenApiJson,
|
|
348
|
-
registryOpenApiHash
|
|
379
|
+
registryOpenApiHash,
|
|
380
|
+
sdkPathMap
|
|
349
381
|
);
|
|
350
382
|
}
|
|
351
|
-
|
|
352
|
-
* Executes an HTTP request.
|
|
353
|
-
*
|
|
354
|
-
* @param {string} route - The route path for the request.
|
|
355
|
-
* @param {'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'} method - The HTTP method.
|
|
356
|
-
* @param {RequestType} [request] - The request object.
|
|
357
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
358
|
-
*/
|
|
359
|
-
async execute(route, method, request) {
|
|
383
|
+
async executeFetchCall(path, request) {
|
|
360
384
|
if (!this.host) {
|
|
361
385
|
throw new Error("Host not initialized, please run .create(..) first");
|
|
362
386
|
}
|
|
@@ -368,9 +392,53 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
368
392
|
if (refreshResult.updateRequired) {
|
|
369
393
|
this.registryOpenApiJson = refreshResult.registryOpenApiJson;
|
|
370
394
|
this.registryOpenApiHash = refreshResult.registryOpenApiHash;
|
|
395
|
+
this.sdkPathMap = refreshResult.sdkPathMap;
|
|
396
|
+
}
|
|
397
|
+
return this.execute(path, request?.method ?? "get", request);
|
|
398
|
+
}
|
|
399
|
+
async executeSdkCall(sdkPath, request) {
|
|
400
|
+
if (!this.host) {
|
|
401
|
+
throw new Error("Host not initialized, please run .create(..) first");
|
|
402
|
+
}
|
|
403
|
+
const refreshResult = await refreshOpenApi(
|
|
404
|
+
this.host,
|
|
405
|
+
this.registryOptions,
|
|
406
|
+
this.registryOpenApiHash
|
|
407
|
+
);
|
|
408
|
+
if (refreshResult.updateRequired) {
|
|
409
|
+
this.registryOpenApiJson = refreshResult.registryOpenApiJson;
|
|
410
|
+
this.registryOpenApiHash = refreshResult.registryOpenApiHash;
|
|
411
|
+
this.sdkPathMap = refreshResult.sdkPathMap;
|
|
412
|
+
}
|
|
413
|
+
if (this.sdkPathMap == null) {
|
|
414
|
+
throw new Error(
|
|
415
|
+
"Sdk path map not initialized, please run .create(..) first"
|
|
416
|
+
);
|
|
371
417
|
}
|
|
418
|
+
const fullSdkPath = sdkPath.split(".");
|
|
419
|
+
while (fullSdkPath.length > 0) {
|
|
420
|
+
fullSdkPath.shift();
|
|
421
|
+
if (fullSdkPath.join(".") in this.sdkPathMap) {
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
if (fullSdkPath.length === 0) {
|
|
426
|
+
throw new Error(`Sdk path not found: ${sdkPath}`);
|
|
427
|
+
}
|
|
428
|
+
const { method, path } = this.sdkPathMap?.[fullSdkPath.join(".")] || {};
|
|
429
|
+
return this.execute(path, method, request);
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Executes an HTTP request.
|
|
433
|
+
*
|
|
434
|
+
* @param {string} route - The route path for the request.
|
|
435
|
+
* @param {'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'} method - The HTTP method.
|
|
436
|
+
* @param {RequestType} [request] - The request object.
|
|
437
|
+
* @returns {Promise<ResponseType>} - The response object.
|
|
438
|
+
*/
|
|
439
|
+
async execute(path, method, request) {
|
|
372
440
|
const { params, body, query, headers } = request || {};
|
|
373
|
-
let url = getSdkPath(this.host +
|
|
441
|
+
let url = getSdkPath(this.host + path);
|
|
374
442
|
if (params) {
|
|
375
443
|
for (const key in params) {
|
|
376
444
|
url = url.replace(`:${key}`, encodeURIComponent(params[key]));
|
|
@@ -379,7 +447,10 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
379
447
|
let defaultContentType = "application/json";
|
|
380
448
|
let parsedBody;
|
|
381
449
|
if (body != null) {
|
|
382
|
-
if (
|
|
450
|
+
if (body instanceof File || body instanceof Blob) {
|
|
451
|
+
defaultContentType = "application/octet-stream";
|
|
452
|
+
parsedBody = body;
|
|
453
|
+
} else if ("schema" in body && body.schema != null) {
|
|
383
454
|
defaultContentType = "application/json";
|
|
384
455
|
parsedBody = (0, import_common2.safeStringify)(body.schema);
|
|
385
456
|
} else if ("json" in body && body.json != null) {
|
|
@@ -390,7 +461,7 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
390
461
|
parsedBody = body.text;
|
|
391
462
|
} else if ("file" in body && body.file != null) {
|
|
392
463
|
defaultContentType = "application/octet-stream";
|
|
393
|
-
parsedBody =
|
|
464
|
+
parsedBody = body.file;
|
|
394
465
|
} else if ("multipartForm" in body && body.multipartForm != null) {
|
|
395
466
|
defaultContentType = "multipart/form-data";
|
|
396
467
|
const formData = new FormData();
|
|
@@ -431,17 +502,17 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
431
502
|
url += queryString ? `?${queryString}` : "";
|
|
432
503
|
}
|
|
433
504
|
const response = await fetch(encodeURI(url), {
|
|
434
|
-
method: method
|
|
505
|
+
method: method?.toUpperCase(),
|
|
435
506
|
headers: {
|
|
436
507
|
...headers,
|
|
437
508
|
...defaultContentType != "multipart/form-data" ? { "Content-Type": body?.contentType ?? defaultContentType } : {}
|
|
438
509
|
},
|
|
439
510
|
body: parsedBody
|
|
440
511
|
});
|
|
441
|
-
const responseOpenApi = this.registryOpenApiJson?.paths?.[
|
|
512
|
+
const responseOpenApi = path != null && method != null ? this.registryOpenApiJson?.paths?.[(0, import_common2.openApiCompliantPath)(path)]?.[method?.toLowerCase()]?.responses?.[response.status] : null;
|
|
442
513
|
if (responseOpenApi == null) {
|
|
443
514
|
throw new Error(
|
|
444
|
-
`Response ${response.status} not found in OpenAPI spec for
|
|
515
|
+
`Response ${response.status} not found in OpenAPI spec for ${path} with method ${method}`
|
|
445
516
|
);
|
|
446
517
|
}
|
|
447
518
|
const contentType = (response.headers.get("content-type") || response.headers.get("Content-Type"))?.split(";")[0];
|
|
@@ -566,78 +637,6 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
566
637
|
headers: response.headers
|
|
567
638
|
};
|
|
568
639
|
}
|
|
569
|
-
/**
|
|
570
|
-
* Executes a request with path parameters.
|
|
571
|
-
*
|
|
572
|
-
* @param {string} route - The route path for the request.
|
|
573
|
-
* @param {'GET' | 'DELETE'} method - The HTTP method.
|
|
574
|
-
* @param {RequestType} [request] - The request object.
|
|
575
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
576
|
-
*/
|
|
577
|
-
async pathParamRequest(route, method, request) {
|
|
578
|
-
return this.execute(route, method, request);
|
|
579
|
-
}
|
|
580
|
-
/**
|
|
581
|
-
* Executes a request with a body.
|
|
582
|
-
*
|
|
583
|
-
* @param {string} route - The route path for the request.
|
|
584
|
-
* @param {'POST' | 'PUT' | 'PATCH'} method - The HTTP method.
|
|
585
|
-
* @param {RequestType} [request] - The request object.
|
|
586
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
587
|
-
*/
|
|
588
|
-
async bodyRequest(route, method, request) {
|
|
589
|
-
return this.execute(route, method, request);
|
|
590
|
-
}
|
|
591
|
-
/**
|
|
592
|
-
* Executes a GET request.
|
|
593
|
-
*
|
|
594
|
-
* @param {string} route - The route path for the request.
|
|
595
|
-
* @param {RequestType} [request] - The request object.
|
|
596
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
597
|
-
*/
|
|
598
|
-
async get(route, request) {
|
|
599
|
-
return this.pathParamRequest(route, "get", request);
|
|
600
|
-
}
|
|
601
|
-
/**
|
|
602
|
-
* Executes a POST request.
|
|
603
|
-
*
|
|
604
|
-
* @param {string} route - The route path for the request.
|
|
605
|
-
* @param {RequestType} [request] - The request object.
|
|
606
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
607
|
-
*/
|
|
608
|
-
async post(route, request) {
|
|
609
|
-
return this.bodyRequest(route, "post", request);
|
|
610
|
-
}
|
|
611
|
-
/**
|
|
612
|
-
* Executes a PUT request.
|
|
613
|
-
*
|
|
614
|
-
* @param {string} route - The route path for the request.
|
|
615
|
-
* @param {RequestType} [request] - The request object.
|
|
616
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
617
|
-
*/
|
|
618
|
-
async put(route, request) {
|
|
619
|
-
return this.bodyRequest(route, "put", request);
|
|
620
|
-
}
|
|
621
|
-
/**
|
|
622
|
-
* Executes a PATCH request.
|
|
623
|
-
*
|
|
624
|
-
* @param {string} route - The route path for the request.
|
|
625
|
-
* @param {RequestType} [request] - The request object.
|
|
626
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
627
|
-
*/
|
|
628
|
-
async patch(route, request) {
|
|
629
|
-
return this.bodyRequest(route, "patch", request);
|
|
630
|
-
}
|
|
631
|
-
/**
|
|
632
|
-
* Executes a DELETE request.
|
|
633
|
-
*
|
|
634
|
-
* @param {string} route - The route path for the request.
|
|
635
|
-
* @param {RequestType} [request] - The request object.
|
|
636
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
637
|
-
*/
|
|
638
|
-
async delete(route, request) {
|
|
639
|
-
return this.pathParamRequest(route, "delete", request);
|
|
640
|
-
}
|
|
641
640
|
};
|
|
642
641
|
|
|
643
642
|
// index.ts
|
|
@@ -652,6 +651,9 @@ var universalSdk = async (options) => {
|
|
|
652
651
|
if (prop === "then" || prop === "catch" || prop === "finally") {
|
|
653
652
|
return void 0;
|
|
654
653
|
}
|
|
654
|
+
if (prop === "fetch") {
|
|
655
|
+
return sdkInternal.executeFetchCall;
|
|
656
|
+
}
|
|
655
657
|
if (typeof prop === "string" && prop in target) {
|
|
656
658
|
const value = target[prop];
|
|
657
659
|
if (typeof value === "function") {
|
|
@@ -659,33 +661,34 @@ var universalSdk = async (options) => {
|
|
|
659
661
|
}
|
|
660
662
|
return value;
|
|
661
663
|
}
|
|
662
|
-
return
|
|
663
|
-
}, {
|
|
664
|
-
get(_innerTarget, innerProp) {
|
|
665
|
-
if (typeof innerProp === "string" && innerProp in target) {
|
|
666
|
-
const value = target[innerProp];
|
|
667
|
-
if (typeof value === "function") {
|
|
668
|
-
return value.bind(target);
|
|
669
|
-
}
|
|
670
|
-
return value;
|
|
671
|
-
}
|
|
672
|
-
return new Proxy(() => {
|
|
673
|
-
}, {
|
|
674
|
-
get(__innerTarget, deepProp) {
|
|
675
|
-
if (typeof deepProp === "string" && deepProp in target) {
|
|
676
|
-
const value = target[deepProp];
|
|
677
|
-
if (typeof value === "function") {
|
|
678
|
-
return value.bind(target);
|
|
679
|
-
}
|
|
680
|
-
return value;
|
|
681
|
-
}
|
|
682
|
-
return void 0;
|
|
683
|
-
}
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
});
|
|
664
|
+
return createSdkProxy([prop]);
|
|
687
665
|
}
|
|
688
666
|
});
|
|
667
|
+
function createSdkProxy(path) {
|
|
668
|
+
return new Proxy(() => {
|
|
669
|
+
}, {
|
|
670
|
+
get(_target, prop) {
|
|
671
|
+
if (prop === "then" || prop === "catch" || prop === "finally") {
|
|
672
|
+
return void 0;
|
|
673
|
+
}
|
|
674
|
+
if (typeof prop === "string" && prop in sdkInternal) {
|
|
675
|
+
const value = sdkInternal[prop];
|
|
676
|
+
if (typeof value === "function") {
|
|
677
|
+
return value.bind(sdkInternal);
|
|
678
|
+
}
|
|
679
|
+
return value;
|
|
680
|
+
}
|
|
681
|
+
const newPath = [...path, prop];
|
|
682
|
+
if (prop === Symbol.toPrimitive || prop === "valueOf" || prop === "toString") {
|
|
683
|
+
return () => sdkInternal.executeSdkCall(path.join("."));
|
|
684
|
+
}
|
|
685
|
+
return createSdkProxy(newPath);
|
|
686
|
+
},
|
|
687
|
+
apply(_target, _thisArg, args) {
|
|
688
|
+
return sdkInternal.executeSdkCall(path.join("."), ...args);
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
}
|
|
689
692
|
return proxyInternal;
|
|
690
693
|
};
|
|
691
694
|
// Annotate the CommonJS export names for ESM import in node:
|
package/lib/index.mjs
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
// src/universalSdk.ts
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
openApiCompliantPath,
|
|
4
|
+
safeParse,
|
|
5
|
+
safeStringify
|
|
6
|
+
} from "@forklaunch/common";
|
|
3
7
|
import Ajv from "ajv";
|
|
4
8
|
import addFormats from "ajv-formats";
|
|
5
9
|
|
|
@@ -134,7 +138,33 @@ function mapContentType(contentType) {
|
|
|
134
138
|
}
|
|
135
139
|
}
|
|
136
140
|
|
|
137
|
-
// src/core/
|
|
141
|
+
// src/core/openApi.ts
|
|
142
|
+
function getSdkPathMap(registryOpenApiJson) {
|
|
143
|
+
const sdkPathMap = {};
|
|
144
|
+
Object.entries(registryOpenApiJson?.paths || {}).forEach(
|
|
145
|
+
([path, pathItem]) => {
|
|
146
|
+
const methods = [
|
|
147
|
+
"get",
|
|
148
|
+
"post",
|
|
149
|
+
"put",
|
|
150
|
+
"patch",
|
|
151
|
+
"delete",
|
|
152
|
+
"options",
|
|
153
|
+
"head",
|
|
154
|
+
"trace"
|
|
155
|
+
];
|
|
156
|
+
methods.forEach((method) => {
|
|
157
|
+
if (pathItem[method]?.operationId) {
|
|
158
|
+
sdkPathMap[pathItem[method].operationId] = {
|
|
159
|
+
method,
|
|
160
|
+
path
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
return sdkPathMap;
|
|
167
|
+
}
|
|
138
168
|
async function refreshOpenApi(host, registryOptions, existingRegistryOpenApiHash) {
|
|
139
169
|
if (existingRegistryOpenApiHash === "static" || "static" in registryOptions && registryOptions.static) {
|
|
140
170
|
return {
|
|
@@ -145,7 +175,8 @@ async function refreshOpenApi(host, registryOptions, existingRegistryOpenApiHash
|
|
|
145
175
|
return {
|
|
146
176
|
updateRequired: true,
|
|
147
177
|
registryOpenApiJson: registryOptions.raw,
|
|
148
|
-
registryOpenApiHash: "static"
|
|
178
|
+
registryOpenApiHash: "static",
|
|
179
|
+
sdkPathMap: getSdkPathMap(registryOptions.raw)
|
|
149
180
|
};
|
|
150
181
|
}
|
|
151
182
|
const registry = "path" in registryOptions ? `${host}/${registryOptions.path}` : "url" in registryOptions ? registryOptions.url : null;
|
|
@@ -160,7 +191,8 @@ async function refreshOpenApi(host, registryOptions, existingRegistryOpenApiHash
|
|
|
160
191
|
return {
|
|
161
192
|
updateRequired: true,
|
|
162
193
|
registryOpenApiJson,
|
|
163
|
-
registryOpenApiHash
|
|
194
|
+
registryOpenApiHash,
|
|
195
|
+
sdkPathMap: getSdkPathMap(registryOpenApiJson)
|
|
164
196
|
};
|
|
165
197
|
}
|
|
166
198
|
return {
|
|
@@ -276,13 +308,14 @@ function getSdkPath(path) {
|
|
|
276
308
|
|
|
277
309
|
// src/universalSdk.ts
|
|
278
310
|
var UniversalSdk = class _UniversalSdk {
|
|
279
|
-
constructor(host, ajv, registryOptions, contentTypeParserMap, registryOpenApiJson, registryOpenApiHash) {
|
|
311
|
+
constructor(host, ajv, registryOptions, contentTypeParserMap, registryOpenApiJson, registryOpenApiHash, sdkPathMap) {
|
|
280
312
|
this.host = host;
|
|
281
313
|
this.ajv = ajv;
|
|
282
314
|
this.registryOptions = registryOptions;
|
|
283
315
|
this.contentTypeParserMap = contentTypeParserMap;
|
|
284
316
|
this.registryOpenApiJson = registryOpenApiJson;
|
|
285
317
|
this.registryOpenApiHash = registryOpenApiHash;
|
|
318
|
+
this.sdkPathMap = sdkPathMap;
|
|
286
319
|
}
|
|
287
320
|
/**
|
|
288
321
|
* Creates an instance of UniversalSdk.
|
|
@@ -293,9 +326,11 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
293
326
|
const refreshResult = await refreshOpenApi(host, registryOptions);
|
|
294
327
|
let registryOpenApiJson;
|
|
295
328
|
let registryOpenApiHash;
|
|
329
|
+
let sdkPathMap;
|
|
296
330
|
if (refreshResult.updateRequired) {
|
|
297
331
|
registryOpenApiJson = refreshResult.registryOpenApiJson;
|
|
298
332
|
registryOpenApiHash = refreshResult.registryOpenApiHash;
|
|
333
|
+
sdkPathMap = refreshResult.sdkPathMap;
|
|
299
334
|
}
|
|
300
335
|
const ajv = new Ajv({
|
|
301
336
|
coerceTypes: true,
|
|
@@ -309,18 +344,11 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
309
344
|
registryOptions,
|
|
310
345
|
contentTypeParserMap,
|
|
311
346
|
registryOpenApiJson,
|
|
312
|
-
registryOpenApiHash
|
|
347
|
+
registryOpenApiHash,
|
|
348
|
+
sdkPathMap
|
|
313
349
|
);
|
|
314
350
|
}
|
|
315
|
-
|
|
316
|
-
* Executes an HTTP request.
|
|
317
|
-
*
|
|
318
|
-
* @param {string} route - The route path for the request.
|
|
319
|
-
* @param {'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'} method - The HTTP method.
|
|
320
|
-
* @param {RequestType} [request] - The request object.
|
|
321
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
322
|
-
*/
|
|
323
|
-
async execute(route, method, request) {
|
|
351
|
+
async executeFetchCall(path, request) {
|
|
324
352
|
if (!this.host) {
|
|
325
353
|
throw new Error("Host not initialized, please run .create(..) first");
|
|
326
354
|
}
|
|
@@ -332,9 +360,53 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
332
360
|
if (refreshResult.updateRequired) {
|
|
333
361
|
this.registryOpenApiJson = refreshResult.registryOpenApiJson;
|
|
334
362
|
this.registryOpenApiHash = refreshResult.registryOpenApiHash;
|
|
363
|
+
this.sdkPathMap = refreshResult.sdkPathMap;
|
|
364
|
+
}
|
|
365
|
+
return this.execute(path, request?.method ?? "get", request);
|
|
366
|
+
}
|
|
367
|
+
async executeSdkCall(sdkPath, request) {
|
|
368
|
+
if (!this.host) {
|
|
369
|
+
throw new Error("Host not initialized, please run .create(..) first");
|
|
370
|
+
}
|
|
371
|
+
const refreshResult = await refreshOpenApi(
|
|
372
|
+
this.host,
|
|
373
|
+
this.registryOptions,
|
|
374
|
+
this.registryOpenApiHash
|
|
375
|
+
);
|
|
376
|
+
if (refreshResult.updateRequired) {
|
|
377
|
+
this.registryOpenApiJson = refreshResult.registryOpenApiJson;
|
|
378
|
+
this.registryOpenApiHash = refreshResult.registryOpenApiHash;
|
|
379
|
+
this.sdkPathMap = refreshResult.sdkPathMap;
|
|
380
|
+
}
|
|
381
|
+
if (this.sdkPathMap == null) {
|
|
382
|
+
throw new Error(
|
|
383
|
+
"Sdk path map not initialized, please run .create(..) first"
|
|
384
|
+
);
|
|
335
385
|
}
|
|
386
|
+
const fullSdkPath = sdkPath.split(".");
|
|
387
|
+
while (fullSdkPath.length > 0) {
|
|
388
|
+
fullSdkPath.shift();
|
|
389
|
+
if (fullSdkPath.join(".") in this.sdkPathMap) {
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (fullSdkPath.length === 0) {
|
|
394
|
+
throw new Error(`Sdk path not found: ${sdkPath}`);
|
|
395
|
+
}
|
|
396
|
+
const { method, path } = this.sdkPathMap?.[fullSdkPath.join(".")] || {};
|
|
397
|
+
return this.execute(path, method, request);
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Executes an HTTP request.
|
|
401
|
+
*
|
|
402
|
+
* @param {string} route - The route path for the request.
|
|
403
|
+
* @param {'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'} method - The HTTP method.
|
|
404
|
+
* @param {RequestType} [request] - The request object.
|
|
405
|
+
* @returns {Promise<ResponseType>} - The response object.
|
|
406
|
+
*/
|
|
407
|
+
async execute(path, method, request) {
|
|
336
408
|
const { params, body, query, headers } = request || {};
|
|
337
|
-
let url = getSdkPath(this.host +
|
|
409
|
+
let url = getSdkPath(this.host + path);
|
|
338
410
|
if (params) {
|
|
339
411
|
for (const key in params) {
|
|
340
412
|
url = url.replace(`:${key}`, encodeURIComponent(params[key]));
|
|
@@ -343,7 +415,10 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
343
415
|
let defaultContentType = "application/json";
|
|
344
416
|
let parsedBody;
|
|
345
417
|
if (body != null) {
|
|
346
|
-
if (
|
|
418
|
+
if (body instanceof File || body instanceof Blob) {
|
|
419
|
+
defaultContentType = "application/octet-stream";
|
|
420
|
+
parsedBody = body;
|
|
421
|
+
} else if ("schema" in body && body.schema != null) {
|
|
347
422
|
defaultContentType = "application/json";
|
|
348
423
|
parsedBody = safeStringify(body.schema);
|
|
349
424
|
} else if ("json" in body && body.json != null) {
|
|
@@ -354,7 +429,7 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
354
429
|
parsedBody = body.text;
|
|
355
430
|
} else if ("file" in body && body.file != null) {
|
|
356
431
|
defaultContentType = "application/octet-stream";
|
|
357
|
-
parsedBody =
|
|
432
|
+
parsedBody = body.file;
|
|
358
433
|
} else if ("multipartForm" in body && body.multipartForm != null) {
|
|
359
434
|
defaultContentType = "multipart/form-data";
|
|
360
435
|
const formData = new FormData();
|
|
@@ -395,17 +470,17 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
395
470
|
url += queryString ? `?${queryString}` : "";
|
|
396
471
|
}
|
|
397
472
|
const response = await fetch(encodeURI(url), {
|
|
398
|
-
method: method
|
|
473
|
+
method: method?.toUpperCase(),
|
|
399
474
|
headers: {
|
|
400
475
|
...headers,
|
|
401
476
|
...defaultContentType != "multipart/form-data" ? { "Content-Type": body?.contentType ?? defaultContentType } : {}
|
|
402
477
|
},
|
|
403
478
|
body: parsedBody
|
|
404
479
|
});
|
|
405
|
-
const responseOpenApi = this.registryOpenApiJson?.paths?.[
|
|
480
|
+
const responseOpenApi = path != null && method != null ? this.registryOpenApiJson?.paths?.[openApiCompliantPath(path)]?.[method?.toLowerCase()]?.responses?.[response.status] : null;
|
|
406
481
|
if (responseOpenApi == null) {
|
|
407
482
|
throw new Error(
|
|
408
|
-
`Response ${response.status} not found in OpenAPI spec for
|
|
483
|
+
`Response ${response.status} not found in OpenAPI spec for ${path} with method ${method}`
|
|
409
484
|
);
|
|
410
485
|
}
|
|
411
486
|
const contentType = (response.headers.get("content-type") || response.headers.get("Content-Type"))?.split(";")[0];
|
|
@@ -530,78 +605,6 @@ var UniversalSdk = class _UniversalSdk {
|
|
|
530
605
|
headers: response.headers
|
|
531
606
|
};
|
|
532
607
|
}
|
|
533
|
-
/**
|
|
534
|
-
* Executes a request with path parameters.
|
|
535
|
-
*
|
|
536
|
-
* @param {string} route - The route path for the request.
|
|
537
|
-
* @param {'GET' | 'DELETE'} method - The HTTP method.
|
|
538
|
-
* @param {RequestType} [request] - The request object.
|
|
539
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
540
|
-
*/
|
|
541
|
-
async pathParamRequest(route, method, request) {
|
|
542
|
-
return this.execute(route, method, request);
|
|
543
|
-
}
|
|
544
|
-
/**
|
|
545
|
-
* Executes a request with a body.
|
|
546
|
-
*
|
|
547
|
-
* @param {string} route - The route path for the request.
|
|
548
|
-
* @param {'POST' | 'PUT' | 'PATCH'} method - The HTTP method.
|
|
549
|
-
* @param {RequestType} [request] - The request object.
|
|
550
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
551
|
-
*/
|
|
552
|
-
async bodyRequest(route, method, request) {
|
|
553
|
-
return this.execute(route, method, request);
|
|
554
|
-
}
|
|
555
|
-
/**
|
|
556
|
-
* Executes a GET request.
|
|
557
|
-
*
|
|
558
|
-
* @param {string} route - The route path for the request.
|
|
559
|
-
* @param {RequestType} [request] - The request object.
|
|
560
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
561
|
-
*/
|
|
562
|
-
async get(route, request) {
|
|
563
|
-
return this.pathParamRequest(route, "get", request);
|
|
564
|
-
}
|
|
565
|
-
/**
|
|
566
|
-
* Executes a POST request.
|
|
567
|
-
*
|
|
568
|
-
* @param {string} route - The route path for the request.
|
|
569
|
-
* @param {RequestType} [request] - The request object.
|
|
570
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
571
|
-
*/
|
|
572
|
-
async post(route, request) {
|
|
573
|
-
return this.bodyRequest(route, "post", request);
|
|
574
|
-
}
|
|
575
|
-
/**
|
|
576
|
-
* Executes a PUT request.
|
|
577
|
-
*
|
|
578
|
-
* @param {string} route - The route path for the request.
|
|
579
|
-
* @param {RequestType} [request] - The request object.
|
|
580
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
581
|
-
*/
|
|
582
|
-
async put(route, request) {
|
|
583
|
-
return this.bodyRequest(route, "put", request);
|
|
584
|
-
}
|
|
585
|
-
/**
|
|
586
|
-
* Executes a PATCH request.
|
|
587
|
-
*
|
|
588
|
-
* @param {string} route - The route path for the request.
|
|
589
|
-
* @param {RequestType} [request] - The request object.
|
|
590
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
591
|
-
*/
|
|
592
|
-
async patch(route, request) {
|
|
593
|
-
return this.bodyRequest(route, "patch", request);
|
|
594
|
-
}
|
|
595
|
-
/**
|
|
596
|
-
* Executes a DELETE request.
|
|
597
|
-
*
|
|
598
|
-
* @param {string} route - The route path for the request.
|
|
599
|
-
* @param {RequestType} [request] - The request object.
|
|
600
|
-
* @returns {Promise<ResponseType>} - The response object.
|
|
601
|
-
*/
|
|
602
|
-
async delete(route, request) {
|
|
603
|
-
return this.pathParamRequest(route, "delete", request);
|
|
604
|
-
}
|
|
605
608
|
};
|
|
606
609
|
|
|
607
610
|
// index.ts
|
|
@@ -616,6 +619,9 @@ var universalSdk = async (options) => {
|
|
|
616
619
|
if (prop === "then" || prop === "catch" || prop === "finally") {
|
|
617
620
|
return void 0;
|
|
618
621
|
}
|
|
622
|
+
if (prop === "fetch") {
|
|
623
|
+
return sdkInternal.executeFetchCall;
|
|
624
|
+
}
|
|
619
625
|
if (typeof prop === "string" && prop in target) {
|
|
620
626
|
const value = target[prop];
|
|
621
627
|
if (typeof value === "function") {
|
|
@@ -623,33 +629,34 @@ var universalSdk = async (options) => {
|
|
|
623
629
|
}
|
|
624
630
|
return value;
|
|
625
631
|
}
|
|
626
|
-
return
|
|
627
|
-
}, {
|
|
628
|
-
get(_innerTarget, innerProp) {
|
|
629
|
-
if (typeof innerProp === "string" && innerProp in target) {
|
|
630
|
-
const value = target[innerProp];
|
|
631
|
-
if (typeof value === "function") {
|
|
632
|
-
return value.bind(target);
|
|
633
|
-
}
|
|
634
|
-
return value;
|
|
635
|
-
}
|
|
636
|
-
return new Proxy(() => {
|
|
637
|
-
}, {
|
|
638
|
-
get(__innerTarget, deepProp) {
|
|
639
|
-
if (typeof deepProp === "string" && deepProp in target) {
|
|
640
|
-
const value = target[deepProp];
|
|
641
|
-
if (typeof value === "function") {
|
|
642
|
-
return value.bind(target);
|
|
643
|
-
}
|
|
644
|
-
return value;
|
|
645
|
-
}
|
|
646
|
-
return void 0;
|
|
647
|
-
}
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
});
|
|
632
|
+
return createSdkProxy([prop]);
|
|
651
633
|
}
|
|
652
634
|
});
|
|
635
|
+
function createSdkProxy(path) {
|
|
636
|
+
return new Proxy(() => {
|
|
637
|
+
}, {
|
|
638
|
+
get(_target, prop) {
|
|
639
|
+
if (prop === "then" || prop === "catch" || prop === "finally") {
|
|
640
|
+
return void 0;
|
|
641
|
+
}
|
|
642
|
+
if (typeof prop === "string" && prop in sdkInternal) {
|
|
643
|
+
const value = sdkInternal[prop];
|
|
644
|
+
if (typeof value === "function") {
|
|
645
|
+
return value.bind(sdkInternal);
|
|
646
|
+
}
|
|
647
|
+
return value;
|
|
648
|
+
}
|
|
649
|
+
const newPath = [...path, prop];
|
|
650
|
+
if (prop === Symbol.toPrimitive || prop === "valueOf" || prop === "toString") {
|
|
651
|
+
return () => sdkInternal.executeSdkCall(path.join("."));
|
|
652
|
+
}
|
|
653
|
+
return createSdkProxy(newPath);
|
|
654
|
+
},
|
|
655
|
+
apply(_target, _thisArg, args) {
|
|
656
|
+
return sdkInternal.executeSdkCall(path.join("."), ...args);
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
}
|
|
653
660
|
return proxyInternal;
|
|
654
661
|
};
|
|
655
662
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forklaunch/universal-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Cross runtime fetch library for forklaunch router sdks",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fetch",
|
|
@@ -33,18 +33,18 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"ajv": "^8.17.1",
|
|
35
35
|
"ajv-formats": "^3.0.1",
|
|
36
|
-
"@forklaunch/common": "0.
|
|
36
|
+
"@forklaunch/common": "0.4.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@types/node": "^24.0.
|
|
40
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
39
|
+
"@types/node": "^24.0.7",
|
|
40
|
+
"@typescript/native-preview": "7.0.0-dev.20250630.1",
|
|
41
41
|
"fetch-mock": "^12.5.3",
|
|
42
|
-
"jest": "^30.0.
|
|
43
|
-
"openapi3-ts": "^4.
|
|
44
|
-
"prettier": "^3.
|
|
42
|
+
"jest": "^30.0.3",
|
|
43
|
+
"openapi3-ts": "^4.5.0",
|
|
44
|
+
"prettier": "^3.6.2",
|
|
45
45
|
"ts-jest": "^29.4.0",
|
|
46
46
|
"tsup": "^8.5.0",
|
|
47
|
-
"typedoc": "^0.28.
|
|
47
|
+
"typedoc": "^0.28.7"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "tsgo --noEmit && tsup index.ts --format cjs,esm --no-splitting --dts --tsconfig tsconfig.json --out-dir lib --clean",
|