@accelbyte/codegen 4.0.1 → 4.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 +10 -8
- package/dist/accelbyte-codegen.js +432 -60
- package/dist/accelbyte-codegen.js.map +1 -1
- package/dist/accelbyte-codegen.mjs +432 -60
- package/dist/accelbyte-codegen.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
+
import path7 from "path";
|
|
4
5
|
import yargs from "yargs";
|
|
5
|
-
import path6 from "path";
|
|
6
6
|
|
|
7
7
|
// src/CliParser.ts
|
|
8
8
|
import fs from "fs";
|
|
@@ -55,6 +55,12 @@ var CliParser = class _CliParser {
|
|
|
55
55
|
static isGenerateSnippetOnly = () => {
|
|
56
56
|
return _CliParser.instance().argv.snippetOnly;
|
|
57
57
|
};
|
|
58
|
+
static getWebSocketSchemaPath = () => {
|
|
59
|
+
return _CliParser.instance().argv.webSocketSchema;
|
|
60
|
+
};
|
|
61
|
+
static isGenerateWebSocket = () => {
|
|
62
|
+
return !!_CliParser.getWebSocketSchemaPath();
|
|
63
|
+
};
|
|
58
64
|
};
|
|
59
65
|
|
|
60
66
|
// src/CodeGenerator.ts
|
|
@@ -301,15 +307,15 @@ export enum Key_${classNameWithoutApi} {
|
|
|
301
307
|
`;
|
|
302
308
|
};
|
|
303
309
|
function filterUsedImports(importArr, body) {
|
|
304
|
-
return importArr.filter((
|
|
305
|
-
const start =
|
|
306
|
-
const end =
|
|
310
|
+
return importArr.filter((path8) => {
|
|
311
|
+
const start = path8.indexOf("{") + 1;
|
|
312
|
+
const end = path8.indexOf("}");
|
|
307
313
|
if (start > 0 && end > start) {
|
|
308
|
-
const importName =
|
|
314
|
+
const importName = path8.slice(start, end).trim();
|
|
309
315
|
return body.includes(importName);
|
|
310
316
|
}
|
|
311
317
|
return false;
|
|
312
|
-
}).map((
|
|
318
|
+
}).map((path8) => path8).join("\n") + "\n";
|
|
313
319
|
}
|
|
314
320
|
|
|
315
321
|
// src/ParserUtils.ts
|
|
@@ -326,8 +332,8 @@ var REMOVED_KEYWORDS = [
|
|
|
326
332
|
"/{namespace}/"
|
|
327
333
|
];
|
|
328
334
|
var ParserUtils = class _ParserUtils {
|
|
329
|
-
static getVersionSuffixFromPath(
|
|
330
|
-
const version2_3_4_etc =
|
|
335
|
+
static getVersionSuffixFromPath(path8) {
|
|
336
|
+
const version2_3_4_etc = path8.match(/\/v([2-9]|[1-9]\d+)\/+/);
|
|
331
337
|
const methodSuffix = version2_3_4_etc ? `_v${version2_3_4_etc[1]}` : "";
|
|
332
338
|
return methodSuffix;
|
|
333
339
|
}
|
|
@@ -522,14 +528,14 @@ var ParserUtils = class _ParserUtils {
|
|
|
522
528
|
* to this
|
|
523
529
|
* `createGenerateByRequestIdByUserId`
|
|
524
530
|
*/
|
|
525
|
-
static generateNaturalLangMethod = ({ servicePrefix, path:
|
|
526
|
-
let path_ =
|
|
531
|
+
static generateNaturalLangMethod = ({ servicePrefix, path: path8, httpMethod, isForm, existingMethods, permissionType }) => {
|
|
532
|
+
let path_ = path8;
|
|
527
533
|
path_ = path_.replace(`/${servicePrefix}/`, "/");
|
|
528
534
|
REMOVED_KEYWORDS.forEach((prefix) => {
|
|
529
535
|
path_ = path_.replace(prefix, "/");
|
|
530
536
|
});
|
|
531
537
|
path_ = path_.substring(1);
|
|
532
|
-
const isPlural = httpMethod === "get" && !(
|
|
538
|
+
const isPlural = httpMethod === "get" && !(path8.slice(-1) === "}");
|
|
533
539
|
if (!isPlural) {
|
|
534
540
|
path_ = _ParserUtils.replaceAll(path_, "ies/", "y/");
|
|
535
541
|
path_ = _ParserUtils.replaceAll(path_, "s/", "/");
|
|
@@ -572,9 +578,9 @@ var ParserUtils = class _ParserUtils {
|
|
|
572
578
|
const genPath = _.upperFirst(lastWords) + "/" + listBeforeLastWords.join("/") + listByParams.reverse().join("/");
|
|
573
579
|
let generatedMethod = _.camelCase(mappedMethod(httpMethod, isForm, permissionType) + genPath);
|
|
574
580
|
generatedMethod = _ParserUtils.replaceAll(generatedMethod, "Byword", "_By");
|
|
575
|
-
const testedGeneratedMethod = generatedMethod + _ParserUtils.getVersionSuffixFromPath(
|
|
576
|
-
generatedMethod = resolveConflicts({ path:
|
|
577
|
-
generatedMethod = generatedMethod + _ParserUtils.getVersionSuffixFromPath(
|
|
581
|
+
const testedGeneratedMethod = generatedMethod + _ParserUtils.getVersionSuffixFromPath(path8);
|
|
582
|
+
generatedMethod = resolveConflicts({ path: path8, generatedMethod, testedGeneratedMethod, existingMethods });
|
|
583
|
+
generatedMethod = generatedMethod + _ParserUtils.getVersionSuffixFromPath(path8);
|
|
578
584
|
return generatedMethod;
|
|
579
585
|
};
|
|
580
586
|
static filterBodyParams(parameters) {
|
|
@@ -729,8 +735,8 @@ var ParserUtils = class _ParserUtils {
|
|
|
729
735
|
*/
|
|
730
736
|
${content}`;
|
|
731
737
|
};
|
|
732
|
-
static sortPathParamsByPath = (pathParams,
|
|
733
|
-
const params =
|
|
738
|
+
static sortPathParamsByPath = (pathParams, path8) => {
|
|
739
|
+
const params = path8.match(/{\w*}/g) || [];
|
|
734
740
|
const cleanParams = params.map((param) => param.replace("{", "").replace("}", ""));
|
|
735
741
|
return pathParams.sort((a, b) => cleanParams.indexOf(a.name) - cleanParams.indexOf(b.name));
|
|
736
742
|
};
|
|
@@ -754,30 +760,30 @@ var mappedMethod = (httpMethod, isForm, permissionType) => {
|
|
|
754
760
|
return "delete";
|
|
755
761
|
}
|
|
756
762
|
};
|
|
757
|
-
var resolveConflicts = ({ path:
|
|
763
|
+
var resolveConflicts = ({ path: path8, generatedMethod, testedGeneratedMethod, existingMethods }) => {
|
|
758
764
|
let _testedGenMethod = testedGeneratedMethod;
|
|
759
765
|
try {
|
|
760
|
-
testConflict(
|
|
766
|
+
testConflict(path8, _testedGenMethod, existingMethods);
|
|
761
767
|
} catch (e) {
|
|
762
|
-
if (
|
|
768
|
+
if (path8.indexOf("/namespaces/") >= 0) {
|
|
763
769
|
generatedMethod += "_ByNS";
|
|
764
770
|
_testedGenMethod += "_ByNS";
|
|
765
771
|
}
|
|
766
772
|
}
|
|
767
773
|
try {
|
|
768
|
-
testConflict(
|
|
774
|
+
testConflict(path8, _testedGenMethod, existingMethods);
|
|
769
775
|
} catch (e) {
|
|
770
|
-
if (
|
|
776
|
+
if (path8.indexOf("/admin/") >= 0) {
|
|
771
777
|
generatedMethod += "_admin";
|
|
772
778
|
_testedGenMethod += "_admin";
|
|
773
779
|
}
|
|
774
780
|
}
|
|
775
|
-
testConflict(
|
|
781
|
+
testConflict(path8, _testedGenMethod, existingMethods);
|
|
776
782
|
return generatedMethod;
|
|
777
783
|
};
|
|
778
|
-
var testConflict = (
|
|
784
|
+
var testConflict = (path8, generatedMethod, existingMethods) => {
|
|
779
785
|
if (existingMethods[generatedMethod]) {
|
|
780
|
-
const conflictingMethod = { path:
|
|
786
|
+
const conflictingMethod = { path: path8, generatedMethod };
|
|
781
787
|
throw Error(
|
|
782
788
|
`Duplicate method conflict in ${JSON.stringify(conflictingMethod)},
|
|
783
789
|
existingMethods: ${JSON.stringify(existingMethods, null, 2)}`
|
|
@@ -894,7 +900,7 @@ var OpenApiSpec = z2.object({
|
|
|
894
900
|
var templateApiMethod = ({
|
|
895
901
|
classMethod,
|
|
896
902
|
httpMethod,
|
|
897
|
-
path:
|
|
903
|
+
path: path8,
|
|
898
904
|
pathParams,
|
|
899
905
|
bodyParams,
|
|
900
906
|
responseClasses,
|
|
@@ -903,12 +909,12 @@ var templateApiMethod = ({
|
|
|
903
909
|
methodParamsNoTypes,
|
|
904
910
|
xSecurity
|
|
905
911
|
}) => {
|
|
906
|
-
let newPath = `'${
|
|
912
|
+
let newPath = `'${path8}'`;
|
|
907
913
|
let snippetMethod = "";
|
|
908
914
|
for (const pathParam of pathParams) {
|
|
909
915
|
const type = ParserUtils.parseType(pathParam);
|
|
910
916
|
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
911
|
-
if (
|
|
917
|
+
if (path8.match(`{${pathParam.name}}`)) {
|
|
912
918
|
if (type === "string") {
|
|
913
919
|
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
914
920
|
} else {
|
|
@@ -916,9 +922,9 @@ var templateApiMethod = ({
|
|
|
916
922
|
}
|
|
917
923
|
}
|
|
918
924
|
}
|
|
919
|
-
const snippetShellArgs = ["--location --request", `${httpMethod} '__DOMAIN__${
|
|
925
|
+
const snippetShellArgs = ["--location --request", `${httpMethod} '__DOMAIN__${path8}'`, "--header 'accept: application/json'"];
|
|
920
926
|
const snippetApiArgs = [];
|
|
921
|
-
if (xSecurity !== void 0 ||
|
|
927
|
+
if (xSecurity !== void 0 || path8.includes("/admin")) {
|
|
922
928
|
snippetShellArgs.push("--header 'Authorization: Bearer {access_token}'");
|
|
923
929
|
snippetApiArgs.push("{ axiosConfig: { request: { headers: { Authorization: 'Bearer {access_token}' } } } }".trim());
|
|
924
930
|
}
|
|
@@ -956,7 +962,7 @@ var templateMethod = ({
|
|
|
956
962
|
classMethod,
|
|
957
963
|
description,
|
|
958
964
|
httpMethod,
|
|
959
|
-
path:
|
|
965
|
+
path: path8,
|
|
960
966
|
pathParams,
|
|
961
967
|
bodyParams,
|
|
962
968
|
queryParams,
|
|
@@ -966,9 +972,9 @@ var templateMethod = ({
|
|
|
966
972
|
}) => {
|
|
967
973
|
let methodParams = "";
|
|
968
974
|
let methodParamsNoTypes = "";
|
|
969
|
-
let newPath = `'${
|
|
975
|
+
let newPath = `'${path8}'`;
|
|
970
976
|
let importStatements = [];
|
|
971
|
-
const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams,
|
|
977
|
+
const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams, path8);
|
|
972
978
|
for (const pathParam of sortedPathParams) {
|
|
973
979
|
const type = ParserUtils.parseType(pathParam);
|
|
974
980
|
if (pathParam.name !== "namespace") {
|
|
@@ -976,7 +982,7 @@ var templateMethod = ({
|
|
|
976
982
|
methodParamsNoTypes += pathParam.name + ", ";
|
|
977
983
|
}
|
|
978
984
|
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
979
|
-
if (
|
|
985
|
+
if (path8.match(`{${pathParam.name}}`)) {
|
|
980
986
|
if (type === "string") {
|
|
981
987
|
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
982
988
|
} else {
|
|
@@ -1041,7 +1047,7 @@ var POST_FETCH_INCLUDES_PATH = ["/table-query/"];
|
|
|
1041
1047
|
var templateQueryMethod = ({
|
|
1042
1048
|
classMethod,
|
|
1043
1049
|
httpMethod,
|
|
1044
|
-
path:
|
|
1050
|
+
path: path8,
|
|
1045
1051
|
pathParams,
|
|
1046
1052
|
responseClasses,
|
|
1047
1053
|
methodParams,
|
|
@@ -1049,14 +1055,14 @@ var templateQueryMethod = ({
|
|
|
1049
1055
|
description,
|
|
1050
1056
|
deprecated
|
|
1051
1057
|
}) => {
|
|
1052
|
-
const isPostFetch = httpMethod === "post" && (POST_FETCH_INCLUDES_PATH.some((p) =>
|
|
1058
|
+
const isPostFetch = httpMethod === "post" && (POST_FETCH_INCLUDES_PATH.some((p) => path8.includes(p)) || path8.endsWith("/list"));
|
|
1053
1059
|
const isFetch = classMethod.startsWith("fetch");
|
|
1054
1060
|
const isGet = httpMethod === "get" || isPostFetch || isFetch;
|
|
1055
1061
|
const queryMethod = isGet ? "useQuery" : "useMutation";
|
|
1056
1062
|
let mParams = "";
|
|
1057
1063
|
let mParamsNoTypes = "";
|
|
1058
|
-
let newPath = `'${
|
|
1059
|
-
const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams,
|
|
1064
|
+
let newPath = `'${path8}'`;
|
|
1065
|
+
const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams, path8);
|
|
1060
1066
|
for (const pathParam of sortedPathParams) {
|
|
1061
1067
|
const type = ParserUtils.parseType(pathParam);
|
|
1062
1068
|
if (pathParam.name !== "namespace") {
|
|
@@ -1064,7 +1070,7 @@ var templateQueryMethod = ({
|
|
|
1064
1070
|
mParamsNoTypes += pathParam.name + ", ";
|
|
1065
1071
|
}
|
|
1066
1072
|
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
1067
|
-
if (
|
|
1073
|
+
if (path8.match(`{${pathParam.name}}`)) {
|
|
1068
1074
|
if (type === "string") {
|
|
1069
1075
|
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
1070
1076
|
} else {
|
|
@@ -1203,7 +1209,7 @@ import { ${serviceNameTitle} } from '@accelbyte/sdk-${serviceNameTitle.toLowerCa
|
|
|
1203
1209
|
|
|
1204
1210
|
const sdk = AccelByte.SDK({
|
|
1205
1211
|
coreConfig: {
|
|
1206
|
-
baseURL: '
|
|
1212
|
+
baseURL: '__DOMAIN__',
|
|
1207
1213
|
clientId: '77f88506b6174c3ea4d925f5b4096ce8',
|
|
1208
1214
|
namespace: 'accelbyte',
|
|
1209
1215
|
redirectURI: 'http://localhost:3030'
|
|
@@ -1233,7 +1239,7 @@ var normalizeMethodSnippet = (methodInput, splitWord) => {
|
|
|
1233
1239
|
};
|
|
1234
1240
|
|
|
1235
1241
|
// src/helpers/SwaggerReaderHelpers.ts
|
|
1236
|
-
var GIT_URL = "https://github.com/AccelByte/accelbyte-
|
|
1242
|
+
var GIT_URL = "https://github.com/AccelByte/accelbyte-typescript-sdk/blob/main/packages";
|
|
1237
1243
|
var SwaggerReaderHelpers = class _SwaggerReaderHelpers {
|
|
1238
1244
|
static getServicePrefix = (servicePaths) => servicePaths[servicePaths.length - 1].split("/")[1];
|
|
1239
1245
|
static parseAllEndpoints = async ({
|
|
@@ -1280,11 +1286,11 @@ var SwaggerReaderHelpers = class _SwaggerReaderHelpers {
|
|
|
1280
1286
|
admin: {},
|
|
1281
1287
|
public: {}
|
|
1282
1288
|
};
|
|
1283
|
-
for (const [
|
|
1284
|
-
if (
|
|
1289
|
+
for (const [path8, operation] of sortedPathsByLength) {
|
|
1290
|
+
if (path8.indexOf("/healthz") >= 0) {
|
|
1285
1291
|
continue;
|
|
1286
1292
|
}
|
|
1287
|
-
const isAdminEndpoint =
|
|
1293
|
+
const isAdminEndpoint = path8.indexOf("/admin/") > -1;
|
|
1288
1294
|
const picked = isAdminEndpoint ? result.admin : result.public;
|
|
1289
1295
|
const {
|
|
1290
1296
|
arrayDefinitions,
|
|
@@ -1302,25 +1308,25 @@ var SwaggerReaderHelpers = class _SwaggerReaderHelpers {
|
|
|
1302
1308
|
const httpMethods = Object.keys(operation);
|
|
1303
1309
|
for (const httpMethod of httpMethods) {
|
|
1304
1310
|
const endpoint = await Endpoint.parseAsync(operation[httpMethod]).catch((error) => {
|
|
1305
|
-
console.error(JSON.stringify({ path:
|
|
1311
|
+
console.error(JSON.stringify({ path: path8, httpMethod }, null, 2));
|
|
1306
1312
|
throw error;
|
|
1307
1313
|
});
|
|
1308
1314
|
if (!endpoint.tags) continue;
|
|
1309
1315
|
const [tag] = endpoint.tags;
|
|
1310
|
-
const pathWithBase = `${api.basePath ?? ""}${
|
|
1316
|
+
const pathWithBase = `${api.basePath ?? ""}${path8}`;
|
|
1311
1317
|
const permissionType = getPermissionType(getPermission(endpoint));
|
|
1312
1318
|
tagToClassMethodsMapByType[tag] = tagToClassMethodsMapByType[tag] ? tagToClassMethodsMapByType[tag] : {};
|
|
1313
1319
|
const isForm = endpoint.consumes && endpoint.consumes[0] === "application/x-www-form-urlencoded";
|
|
1314
1320
|
const classMethod = ParserUtils.generateNaturalLangMethod({
|
|
1315
1321
|
servicePrefix,
|
|
1316
|
-
path:
|
|
1322
|
+
path: path8,
|
|
1317
1323
|
httpMethod,
|
|
1318
1324
|
isForm,
|
|
1319
1325
|
existingMethods: tagToClassMethodsMapByType[tag],
|
|
1320
1326
|
permissionType
|
|
1321
1327
|
});
|
|
1322
|
-
tagToClassMethodsMapByType[tag][classMethod] = `${
|
|
1323
|
-
generatedMethods[`${
|
|
1328
|
+
tagToClassMethodsMapByType[tag][classMethod] = `${path8} ${httpMethod}`;
|
|
1329
|
+
generatedMethods[`${path8} ${httpMethod}`] = `${classMethod}`;
|
|
1324
1330
|
if (!snippetMap[pathWithBase]) {
|
|
1325
1331
|
snippetMap[pathWithBase] = {};
|
|
1326
1332
|
}
|
|
@@ -1419,7 +1425,7 @@ var SwaggerReaderHelpers = class _SwaggerReaderHelpers {
|
|
|
1419
1425
|
};
|
|
1420
1426
|
|
|
1421
1427
|
// src/templates/template-api-index.ts
|
|
1422
|
-
var templateApiIndex = (serviceNameTitle, apiList) => {
|
|
1428
|
+
var templateApiIndex = (serviceNameTitle, apiList, isGenerateWebSocket = false) => {
|
|
1423
1429
|
let imports = "";
|
|
1424
1430
|
let returnStatement = "";
|
|
1425
1431
|
for (const cl of apiList) {
|
|
@@ -1428,6 +1434,12 @@ var templateApiIndex = (serviceNameTitle, apiList) => {
|
|
|
1428
1434
|
import { ${cl} } from './${dir}/${cl}.js'`;
|
|
1429
1435
|
returnStatement += `
|
|
1430
1436
|
${cl}, `;
|
|
1437
|
+
}
|
|
1438
|
+
if (isGenerateWebSocket) {
|
|
1439
|
+
imports += `
|
|
1440
|
+
import { WebSocketClass } from './generated-websocket/WebSocketClass.js'`;
|
|
1441
|
+
returnStatement += `
|
|
1442
|
+
WebSocket: WebSocketClass, `;
|
|
1431
1443
|
}
|
|
1432
1444
|
return `/**
|
|
1433
1445
|
* AUTO GENERATED
|
|
@@ -1733,7 +1745,9 @@ var CodeGenerator = class _CodeGenerator {
|
|
|
1733
1745
|
const queryImportsSet = /* @__PURE__ */ new Set();
|
|
1734
1746
|
const apiInfo = { ...api.info, "x-version": api["x-version"]?.version };
|
|
1735
1747
|
console.log("----------\nGenerating API:", { title: apiInfo.title, version: apiInfo.version });
|
|
1736
|
-
|
|
1748
|
+
if (!CliParser.isGenerateSnippetOnly()) {
|
|
1749
|
+
ParserUtils.writeXVersion(_CodeGenerator.srcFolder(), api["x-version"], api.info);
|
|
1750
|
+
}
|
|
1737
1751
|
const parsedInformation = await SwaggerReaderHelpers.parseAllEndpoints({ api, sdkName, serviceName });
|
|
1738
1752
|
if (CliParser.getSnippetOutputPath()) {
|
|
1739
1753
|
try {
|
|
@@ -1848,7 +1862,8 @@ var CodeGenerator = class _CodeGenerator {
|
|
|
1848
1862
|
};
|
|
1849
1863
|
generatePublicOrAdmin(true);
|
|
1850
1864
|
generatePublicOrAdmin(false);
|
|
1851
|
-
const
|
|
1865
|
+
const isGenerateWebSocket = CliParser.isGenerateWebSocket();
|
|
1866
|
+
const apiIndexBuff = templateApiIndex(serviceNameTitle, mainApiList, isGenerateWebSocket);
|
|
1852
1867
|
ParserUtils.writeApiMainFile(_CodeGenerator.srcFolder(), serviceNameTitle, apiIndexBuff);
|
|
1853
1868
|
console.log("\nCOMPLETED\n----------\n\n");
|
|
1854
1869
|
return { indexImports: indexImportsSet, queryImports: queryImportsSet };
|
|
@@ -1919,25 +1934,373 @@ var SwaggerDownloader = class _SwaggerDownloader {
|
|
|
1919
1934
|
};
|
|
1920
1935
|
};
|
|
1921
1936
|
|
|
1937
|
+
// src/WebsocketGenerator.ts
|
|
1938
|
+
import fs6 from "fs";
|
|
1939
|
+
import path6 from "path";
|
|
1940
|
+
|
|
1941
|
+
// src/templates/template-ws-class.ts
|
|
1942
|
+
var definitionToFunctionName = (type) => {
|
|
1943
|
+
if (type.endsWith("Request")) {
|
|
1944
|
+
return "send" + capitalize(type.slice(0, type.length - 7));
|
|
1945
|
+
}
|
|
1946
|
+
return type;
|
|
1947
|
+
};
|
|
1948
|
+
var renderSendFunction = (name, definition) => {
|
|
1949
|
+
const functionName = definitionToFunctionName(name);
|
|
1950
|
+
return `const ${functionName} = (data: Omit<Definitions.${capitalize(name)}, 'type'>) => {
|
|
1951
|
+
send({ type: '${name}', ...data })
|
|
1952
|
+
}`;
|
|
1953
|
+
};
|
|
1954
|
+
var templateWebsocketClass = (name, path8, definitions) => {
|
|
1955
|
+
const requestDefinitions = Object.keys(definitions).filter((key) => {
|
|
1956
|
+
const val = definitions[key];
|
|
1957
|
+
return val["x-type"] == "request";
|
|
1958
|
+
}).map((key) => [key, definitions[key]]);
|
|
1959
|
+
return `/* eslint-disable camelcase */
|
|
1960
|
+
/* eslint-disable no-inner-declarations */
|
|
1961
|
+
// @ts-ignore -> ts-expect-error TS6133
|
|
1962
|
+
import { AccelByteSDK, RefreshToken, SdkSetConfigParam } from '@accelbyte/sdk'
|
|
1963
|
+
import * as Definitions from './WebSocketDefinitions'
|
|
1964
|
+
|
|
1965
|
+
const messageParser = (data: string) => {
|
|
1966
|
+
const toVal = (str?: string) => {
|
|
1967
|
+
if (str) {
|
|
1968
|
+
if (str.startsWith('[') && str.endsWith(']')) {
|
|
1969
|
+
return str
|
|
1970
|
+
.slice(1, str.length - 1)
|
|
1971
|
+
.split(',')
|
|
1972
|
+
.filter(v => v !== '')
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
return str
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
const entries = data.split('\\n')
|
|
1979
|
+
.filter(line => line !== '')
|
|
1980
|
+
.map(line => {
|
|
1981
|
+
const [key, valStr] = line.split(': ')
|
|
1982
|
+
return [key, toVal(valStr)]
|
|
1983
|
+
})
|
|
1984
|
+
|
|
1985
|
+
return Object.fromEntries(entries)
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
const messageSerializer = (data: Record<string, any>) => {
|
|
1989
|
+
return Object.keys(data)
|
|
1990
|
+
.map(key => {
|
|
1991
|
+
const toStr = (val: any) => {
|
|
1992
|
+
// array
|
|
1993
|
+
if (Array.isArray(val)) {
|
|
1994
|
+
return \`[\${String(val)}]\`
|
|
1995
|
+
}
|
|
1996
|
+
// null, undefined
|
|
1997
|
+
if (!val) {
|
|
1998
|
+
return ''
|
|
1999
|
+
}
|
|
2000
|
+
return String(val)
|
|
2001
|
+
}
|
|
2002
|
+
const val = data[key]
|
|
2003
|
+
const valStr = toStr(val)
|
|
2004
|
+
|
|
2005
|
+
return \`\${key}: \${valStr}\`
|
|
2006
|
+
})
|
|
2007
|
+
.join('\\n')
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
export function WebSocketClass(sdk: AccelByteSDK, args?: SdkSetConfigParam) {
|
|
2011
|
+
const sdkAssembly = sdk.assembly()
|
|
2012
|
+
const baseURL = (args?.coreConfig?.baseURL ?? sdkAssembly.coreConfig.baseURL).replace('http', 'ws')
|
|
2013
|
+
const path = '${path8}'
|
|
2014
|
+
const url = baseURL + path
|
|
2015
|
+
let ws: WebSocket | null = null
|
|
2016
|
+
let isDisconnectManually = false
|
|
2017
|
+
const allowReconnect = sdkAssembly.webSocketConfig.allowReconnect ?? true
|
|
2018
|
+
const maxReconnectAttempts = sdkAssembly.webSocketConfig.maxReconnectAttempts ?? 0
|
|
2019
|
+
let reconnectAttempts = maxReconnectAttempts
|
|
2020
|
+
|
|
2021
|
+
const connect = () => {
|
|
2022
|
+
const token = sdk.getToken()
|
|
2023
|
+
|
|
2024
|
+
if (!token.accessToken) {
|
|
2025
|
+
console.warn('No access token, please login first')
|
|
2026
|
+
return
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
if (!ws) {
|
|
2030
|
+
ws = new WebSocket(url, token.accessToken)
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
const refreshToken = async () => {
|
|
2035
|
+
const { refreshToken } = sdk.getToken()
|
|
2036
|
+
if (refreshToken) {
|
|
2037
|
+
const refresh = new RefreshToken({
|
|
2038
|
+
config: {
|
|
2039
|
+
axiosConfig: sdkAssembly.axiosConfig.request,
|
|
2040
|
+
clientId: sdkAssembly.coreConfig.clientId,
|
|
2041
|
+
refreshToken
|
|
2042
|
+
}
|
|
2043
|
+
})
|
|
2044
|
+
const result = await refresh.runWithLock()
|
|
2045
|
+
if (result) {
|
|
2046
|
+
sdk.setToken({
|
|
2047
|
+
accessToken: result.access_token,
|
|
2048
|
+
refreshToken: result.refresh_token
|
|
2049
|
+
})
|
|
2050
|
+
return true
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
return false
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
const handleReconnect = async (ev: CloseEvent) => {
|
|
2057
|
+
if (!allowReconnect || isDisconnectManually || !sdk.getToken().accessToken) return
|
|
2058
|
+
// token revoked
|
|
2059
|
+
if (ev.code === 4020) {
|
|
2060
|
+
await refreshToken()
|
|
2061
|
+
reconnectAttempts--
|
|
2062
|
+
connect()
|
|
2063
|
+
} else if (ev.code >= 1001 && ev.code <= 2999) {
|
|
2064
|
+
// Only reconnect if codes in range 1001-2999
|
|
2065
|
+
if (!ws || ws.readyState !== ws.OPEN) return
|
|
2066
|
+
|
|
2067
|
+
if (maxReconnectAttempts === 0) {
|
|
2068
|
+
setTimeout(() => {
|
|
2069
|
+
connect()
|
|
2070
|
+
}, 1000)
|
|
2071
|
+
} else if (reconnectAttempts !== 0) {
|
|
2072
|
+
setTimeout(() => {
|
|
2073
|
+
reconnectAttempts--
|
|
2074
|
+
connect()
|
|
2075
|
+
}, 1000)
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
const disconnect = (code?: number, reason?: string) => {
|
|
2081
|
+
if (ws) {
|
|
2082
|
+
ws.close(code, reason)
|
|
2083
|
+
isDisconnectManually = true
|
|
2084
|
+
ws = null
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
const send = (message: Definitions.WebSocketRequest) => {
|
|
2089
|
+
if (ws) {
|
|
2090
|
+
ws.send(messageSerializer(message))
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
const sendRaw = (rawMessage: string) => {
|
|
2095
|
+
if (ws) {
|
|
2096
|
+
ws.send(rawMessage)
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
const onOpen = (cb: () => any) => {
|
|
2101
|
+
if (ws) {
|
|
2102
|
+
function listener(this: WebSocket, _ev: Event) {
|
|
2103
|
+
isDisconnectManually = false
|
|
2104
|
+
reconnectAttempts = maxReconnectAttempts
|
|
2105
|
+
cb()
|
|
2106
|
+
}
|
|
2107
|
+
ws.addEventListener('open', listener)
|
|
2108
|
+
return {
|
|
2109
|
+
removeEventListener: () => ws?.removeEventListener('open', listener)
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
return {}
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
const onClose = (cb: (ev: CloseEvent) => any) => {
|
|
2116
|
+
if (ws) {
|
|
2117
|
+
function listener(this: WebSocket, ev: CloseEvent) {
|
|
2118
|
+
handleReconnect(ev)
|
|
2119
|
+
cb(ev)
|
|
2120
|
+
}
|
|
2121
|
+
ws.addEventListener('close', listener)
|
|
2122
|
+
return {
|
|
2123
|
+
removeEventListener: () => ws?.removeEventListener('close', listener)
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
return {}
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
const onMessage = (cb: (message: Definitions.WebSocketResponseOrNotification | string) => any, raw: boolean = false) => {
|
|
2130
|
+
if (ws) {
|
|
2131
|
+
function listener(this: WebSocket, ev: MessageEvent<any>) {
|
|
2132
|
+
if (raw) {
|
|
2133
|
+
cb(ev.data)
|
|
2134
|
+
} else {
|
|
2135
|
+
const result = Definitions.WebSocketResponseOrNotification.parse(messageParser(ev.data))
|
|
2136
|
+
cb(result)
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
ws.addEventListener('message', listener)
|
|
2140
|
+
return {
|
|
2141
|
+
removeEventListener: () => ws?.removeEventListener('message', listener)
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
return {}
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
const onError = (cb: (err: any) => any) => {
|
|
2148
|
+
if (ws) {
|
|
2149
|
+
function listener(this: WebSocket, err: any) {
|
|
2150
|
+
cb(err)
|
|
2151
|
+
}
|
|
2152
|
+
ws.addEventListener('error', listener)
|
|
2153
|
+
return {
|
|
2154
|
+
removeEventListener: () => ws?.removeEventListener('error', listener)
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
return {}
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
${requestDefinitions.map(([name2, definition]) => renderSendFunction(name2, definition)).join(`
|
|
2161
|
+
|
|
2162
|
+
`)}
|
|
2163
|
+
|
|
2164
|
+
return {
|
|
2165
|
+
instance: ws,
|
|
2166
|
+
connect,
|
|
2167
|
+
disconnect,
|
|
2168
|
+
send,
|
|
2169
|
+
sendRaw,
|
|
2170
|
+
onOpen,
|
|
2171
|
+
onClose,
|
|
2172
|
+
onMessage,
|
|
2173
|
+
onError,
|
|
2174
|
+
${requestDefinitions.map(([name2, _2]) => definitionToFunctionName(name2)).join(",\n ")}
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
`;
|
|
2179
|
+
};
|
|
2180
|
+
|
|
2181
|
+
// src/templates/template-ws-defintions.ts
|
|
2182
|
+
var renderZod = (property) => {
|
|
2183
|
+
switch (property.type) {
|
|
2184
|
+
case "string":
|
|
2185
|
+
return `z.coerce.string()`;
|
|
2186
|
+
case "integer":
|
|
2187
|
+
return `z.coerce.number()`;
|
|
2188
|
+
case "boolean":
|
|
2189
|
+
return `z.boolean()`;
|
|
2190
|
+
case "array":
|
|
2191
|
+
return `z.array(${renderZod(property.items)})`;
|
|
2192
|
+
default:
|
|
2193
|
+
return `z.any()`;
|
|
2194
|
+
}
|
|
2195
|
+
};
|
|
2196
|
+
var renderProperty = (name, type, property, required) => {
|
|
2197
|
+
const isRequired = required && required.includes(name);
|
|
2198
|
+
return `${name}: ${renderZod(property)}${isRequired || type != "request" ? "" : ".optional()"}`;
|
|
2199
|
+
};
|
|
2200
|
+
var renderDefinition = (name, definition) => {
|
|
2201
|
+
const capitalizedName = capitalize(name);
|
|
2202
|
+
if (definition.properties) {
|
|
2203
|
+
const properties = Object.entries(definition.properties);
|
|
2204
|
+
return `export const ${capitalizedName} = z.object({
|
|
2205
|
+
type: z.literal("${name}"),
|
|
2206
|
+
${properties.map(([name2, property]) => renderProperty(name2, definition["x-type"], property, definition.required)).join(",\n ")}
|
|
2207
|
+
})
|
|
2208
|
+
|
|
2209
|
+
export type ${capitalizedName} = z.infer<typeof ${capitalizedName}>
|
|
2210
|
+
`;
|
|
2211
|
+
}
|
|
2212
|
+
return "";
|
|
2213
|
+
};
|
|
2214
|
+
var renderAllDefinitions = (definitions) => {
|
|
2215
|
+
if (definitions) {
|
|
2216
|
+
const definitionEntries = Object.entries(definitions);
|
|
2217
|
+
return definitionEntries.map(([name, definition]) => renderDefinition(name, definition)).join("\n\n");
|
|
2218
|
+
}
|
|
2219
|
+
return "";
|
|
2220
|
+
};
|
|
2221
|
+
var renderUnion = (type, definitions) => {
|
|
2222
|
+
if (definitions) {
|
|
2223
|
+
let capitalizedType = "";
|
|
2224
|
+
if (typeof type === "string") {
|
|
2225
|
+
capitalizedType = capitalize(type);
|
|
2226
|
+
} else {
|
|
2227
|
+
capitalizedType = type.map((t) => capitalize(t)).join("Or");
|
|
2228
|
+
}
|
|
2229
|
+
const filteredDefinitions = Object.entries(definitions).filter(([_2, def]) => {
|
|
2230
|
+
if (typeof type === "string") {
|
|
2231
|
+
return def["x-type"] === type;
|
|
2232
|
+
} else {
|
|
2233
|
+
return type.includes(def["x-type"]);
|
|
2234
|
+
}
|
|
2235
|
+
}).map(([name, _2]) => capitalize(name));
|
|
2236
|
+
return `export const WebSocket${capitalizedType} = z.discriminatedUnion("type", [
|
|
2237
|
+
${filteredDefinitions.join(",\n ")}
|
|
2238
|
+
])
|
|
2239
|
+
|
|
2240
|
+
export type WebSocket${capitalizedType} = z.infer<typeof WebSocket${capitalizedType}>`;
|
|
2241
|
+
}
|
|
2242
|
+
return "";
|
|
2243
|
+
};
|
|
2244
|
+
var templateWebsocketDefinitions = (definitions) => {
|
|
2245
|
+
return `/**
|
|
2246
|
+
* AUTO GENERATED
|
|
2247
|
+
*/
|
|
2248
|
+
|
|
2249
|
+
import { z } from 'zod'
|
|
2250
|
+
|
|
2251
|
+
${renderAllDefinitions(definitions)}
|
|
2252
|
+
|
|
2253
|
+
${renderUnion("request", definitions)}
|
|
2254
|
+
|
|
2255
|
+
${renderUnion(["response", "notification"], definitions)}
|
|
2256
|
+
`;
|
|
2257
|
+
};
|
|
2258
|
+
|
|
2259
|
+
// src/WebsocketGenerator.ts
|
|
2260
|
+
var WebsocketGenerator = class {
|
|
2261
|
+
static srcFolder = () => CliParser.getOutputPath();
|
|
2262
|
+
static outputFolder = () => path6.join(this.srcFolder(), "generated-websocket");
|
|
2263
|
+
static schemaContent = () => {
|
|
2264
|
+
const fileContent = JSON.parse(fs6.readFileSync(CliParser.getWebSocketSchemaPath(), "utf8"));
|
|
2265
|
+
return fileContent;
|
|
2266
|
+
};
|
|
2267
|
+
static prepareDirs = () => {
|
|
2268
|
+
ParserUtils.mkdirIfNotExist(this.outputFolder());
|
|
2269
|
+
};
|
|
2270
|
+
static main = () => {
|
|
2271
|
+
const { name, path: wsPath, definitions } = this.schemaContent();
|
|
2272
|
+
const templateDefinitions = templateWebsocketDefinitions(definitions);
|
|
2273
|
+
this.prepareDirs();
|
|
2274
|
+
const filePath = path6.join(this.outputFolder(), "WebSocketDefinitions.ts");
|
|
2275
|
+
fs6.writeFileSync(filePath, templateDefinitions, "utf8");
|
|
2276
|
+
const templateClass2 = templateWebsocketClass(name, wsPath, definitions);
|
|
2277
|
+
const filePathClass = path6.join(this.outputFolder(), "WebSocketClass.ts");
|
|
2278
|
+
fs6.writeFileSync(filePathClass, templateClass2, "utf8");
|
|
2279
|
+
};
|
|
2280
|
+
};
|
|
2281
|
+
|
|
1922
2282
|
// src/cli.ts
|
|
1923
2283
|
var generateSdk = async () => {
|
|
1924
2284
|
const arrayOfSets = await Promise.all(CliParser.getConfigFile().map((config) => CodeGenerator.main(config)));
|
|
1925
2285
|
if (CliParser.isGenerateSnippetOnly()) {
|
|
1926
2286
|
return;
|
|
1927
2287
|
}
|
|
2288
|
+
if (CliParser.isGenerateWebSocket()) {
|
|
2289
|
+
WebsocketGenerator.main();
|
|
2290
|
+
}
|
|
1928
2291
|
const indexImportsSet = /* @__PURE__ */ new Set();
|
|
1929
2292
|
const queryImportsSet = /* @__PURE__ */ new Set();
|
|
1930
2293
|
const filenamesSet = /* @__PURE__ */ new Set();
|
|
1931
2294
|
for (const set of arrayOfSets) {
|
|
1932
2295
|
set.indexImports.forEach((value) => {
|
|
1933
|
-
const fileName =
|
|
2296
|
+
const fileName = path7.basename(value);
|
|
1934
2297
|
if (!filenamesSet.has(fileName)) {
|
|
1935
2298
|
indexImportsSet.add(value);
|
|
1936
2299
|
filenamesSet.add(fileName);
|
|
1937
2300
|
}
|
|
1938
2301
|
});
|
|
1939
2302
|
set.queryImports.forEach((value) => {
|
|
1940
|
-
const fileName =
|
|
2303
|
+
const fileName = path7.basename(value);
|
|
1941
2304
|
if (!filenamesSet.has(fileName)) {
|
|
1942
2305
|
queryImportsSet.add(value);
|
|
1943
2306
|
}
|
|
@@ -1958,30 +2321,39 @@ yargs.command("download-swaggers", "Download swaggers JSON files", (yargs2) => {
|
|
|
1958
2321
|
CliParser.createInstance(yargs2);
|
|
1959
2322
|
SwaggerDownloader.main();
|
|
1960
2323
|
}).command("generate-code", "Generate code based on downloaded swagger files", async (yargs2) => {
|
|
1961
|
-
yargs2.check(({ output }) => {
|
|
1962
|
-
if (!output?.trim()) {
|
|
2324
|
+
yargs2.check(({ output, snippetOnly, snippetOutput }) => {
|
|
2325
|
+
if (!output?.trim() && !snippetOnly) {
|
|
1963
2326
|
throw new Error("output is required for generate-code");
|
|
1964
2327
|
}
|
|
2328
|
+
if (snippetOnly && !snippetOutput) {
|
|
2329
|
+
throw new Error("snippetOutput is required when generating snippets.");
|
|
2330
|
+
}
|
|
1965
2331
|
return true;
|
|
1966
2332
|
});
|
|
1967
2333
|
CliParser.createInstance(yargs2);
|
|
1968
2334
|
await generateSdk();
|
|
1969
2335
|
}).option("config", {
|
|
1970
|
-
description: "
|
|
2336
|
+
description: "Path to the config file with backend service URLs.",
|
|
1971
2337
|
type: "string",
|
|
1972
2338
|
demandOption: true
|
|
1973
2339
|
}).option("swaggersOutput", {
|
|
1974
|
-
description: "
|
|
2340
|
+
description: "Directory to save the downloaded Swagger JSON files.",
|
|
1975
2341
|
type: "string",
|
|
1976
2342
|
demandOption: true
|
|
1977
2343
|
}).option("output", {
|
|
1978
|
-
description: "
|
|
2344
|
+
description: "Directory for the generated code. Required when using the generate-code command.",
|
|
1979
2345
|
type: "string"
|
|
1980
2346
|
}).option("skipReactQuery", {
|
|
1981
|
-
description: "
|
|
2347
|
+
description: "Disable React Query code generation.",
|
|
1982
2348
|
type: "boolean"
|
|
1983
2349
|
}).option("snippetOnly", {
|
|
1984
|
-
description: "
|
|
2350
|
+
description: "Generate only code snippets.",
|
|
1985
2351
|
type: "boolean"
|
|
2352
|
+
}).option("snippetOutput", {
|
|
2353
|
+
description: "Directory for the generated code snippets. Required when generating snippets.",
|
|
2354
|
+
type: "string"
|
|
2355
|
+
}).option("webSocketSchema", {
|
|
2356
|
+
description: "Path to the WebSocket schema file (schema.json). If provided, WebSocket methods will be generated based on the schema.",
|
|
2357
|
+
type: "string"
|
|
1986
2358
|
}).demandCommand(1).help().argv;
|
|
1987
2359
|
//# sourceMappingURL=accelbyte-codegen.mjs.map
|