@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
|
@@ -23,8 +23,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
));
|
|
24
24
|
|
|
25
25
|
// src/cli.ts
|
|
26
|
+
var import_path5 = __toESM(require("path"));
|
|
26
27
|
var import_yargs = __toESM(require("yargs"));
|
|
27
|
-
var import_path4 = __toESM(require("path"));
|
|
28
28
|
|
|
29
29
|
// src/CliParser.ts
|
|
30
30
|
var import_fs = __toESM(require("fs"));
|
|
@@ -77,6 +77,12 @@ var CliParser = class _CliParser {
|
|
|
77
77
|
static isGenerateSnippetOnly = () => {
|
|
78
78
|
return _CliParser.instance().argv.snippetOnly;
|
|
79
79
|
};
|
|
80
|
+
static getWebSocketSchemaPath = () => {
|
|
81
|
+
return _CliParser.instance().argv.webSocketSchema;
|
|
82
|
+
};
|
|
83
|
+
static isGenerateWebSocket = () => {
|
|
84
|
+
return !!_CliParser.getWebSocketSchemaPath();
|
|
85
|
+
};
|
|
80
86
|
};
|
|
81
87
|
|
|
82
88
|
// src/CodeGenerator.ts
|
|
@@ -323,15 +329,15 @@ export enum Key_${classNameWithoutApi} {
|
|
|
323
329
|
`;
|
|
324
330
|
};
|
|
325
331
|
function filterUsedImports(importArr, body) {
|
|
326
|
-
return importArr.filter((
|
|
327
|
-
const start =
|
|
328
|
-
const end =
|
|
332
|
+
return importArr.filter((path8) => {
|
|
333
|
+
const start = path8.indexOf("{") + 1;
|
|
334
|
+
const end = path8.indexOf("}");
|
|
329
335
|
if (start > 0 && end > start) {
|
|
330
|
-
const importName =
|
|
336
|
+
const importName = path8.slice(start, end).trim();
|
|
331
337
|
return body.includes(importName);
|
|
332
338
|
}
|
|
333
339
|
return false;
|
|
334
|
-
}).map((
|
|
340
|
+
}).map((path8) => path8).join("\n") + "\n";
|
|
335
341
|
}
|
|
336
342
|
|
|
337
343
|
// src/ParserUtils.ts
|
|
@@ -348,8 +354,8 @@ var REMOVED_KEYWORDS = [
|
|
|
348
354
|
"/{namespace}/"
|
|
349
355
|
];
|
|
350
356
|
var ParserUtils = class _ParserUtils {
|
|
351
|
-
static getVersionSuffixFromPath(
|
|
352
|
-
const version2_3_4_etc =
|
|
357
|
+
static getVersionSuffixFromPath(path8) {
|
|
358
|
+
const version2_3_4_etc = path8.match(/\/v([2-9]|[1-9]\d+)\/+/);
|
|
353
359
|
const methodSuffix = version2_3_4_etc ? `_v${version2_3_4_etc[1]}` : "";
|
|
354
360
|
return methodSuffix;
|
|
355
361
|
}
|
|
@@ -544,14 +550,14 @@ var ParserUtils = class _ParserUtils {
|
|
|
544
550
|
* to this
|
|
545
551
|
* `createGenerateByRequestIdByUserId`
|
|
546
552
|
*/
|
|
547
|
-
static generateNaturalLangMethod = ({ servicePrefix, path:
|
|
548
|
-
let path_ =
|
|
553
|
+
static generateNaturalLangMethod = ({ servicePrefix, path: path8, httpMethod, isForm, existingMethods, permissionType }) => {
|
|
554
|
+
let path_ = path8;
|
|
549
555
|
path_ = path_.replace(`/${servicePrefix}/`, "/");
|
|
550
556
|
REMOVED_KEYWORDS.forEach((prefix) => {
|
|
551
557
|
path_ = path_.replace(prefix, "/");
|
|
552
558
|
});
|
|
553
559
|
path_ = path_.substring(1);
|
|
554
|
-
const isPlural = httpMethod === "get" && !(
|
|
560
|
+
const isPlural = httpMethod === "get" && !(path8.slice(-1) === "}");
|
|
555
561
|
if (!isPlural) {
|
|
556
562
|
path_ = _ParserUtils.replaceAll(path_, "ies/", "y/");
|
|
557
563
|
path_ = _ParserUtils.replaceAll(path_, "s/", "/");
|
|
@@ -594,9 +600,9 @@ var ParserUtils = class _ParserUtils {
|
|
|
594
600
|
const genPath = import_lodash.default.upperFirst(lastWords) + "/" + listBeforeLastWords.join("/") + listByParams.reverse().join("/");
|
|
595
601
|
let generatedMethod = import_lodash.default.camelCase(mappedMethod(httpMethod, isForm, permissionType) + genPath);
|
|
596
602
|
generatedMethod = _ParserUtils.replaceAll(generatedMethod, "Byword", "_By");
|
|
597
|
-
const testedGeneratedMethod = generatedMethod + _ParserUtils.getVersionSuffixFromPath(
|
|
598
|
-
generatedMethod = resolveConflicts({ path:
|
|
599
|
-
generatedMethod = generatedMethod + _ParserUtils.getVersionSuffixFromPath(
|
|
603
|
+
const testedGeneratedMethod = generatedMethod + _ParserUtils.getVersionSuffixFromPath(path8);
|
|
604
|
+
generatedMethod = resolveConflicts({ path: path8, generatedMethod, testedGeneratedMethod, existingMethods });
|
|
605
|
+
generatedMethod = generatedMethod + _ParserUtils.getVersionSuffixFromPath(path8);
|
|
600
606
|
return generatedMethod;
|
|
601
607
|
};
|
|
602
608
|
static filterBodyParams(parameters) {
|
|
@@ -751,8 +757,8 @@ var ParserUtils = class _ParserUtils {
|
|
|
751
757
|
*/
|
|
752
758
|
${content}`;
|
|
753
759
|
};
|
|
754
|
-
static sortPathParamsByPath = (pathParams,
|
|
755
|
-
const params =
|
|
760
|
+
static sortPathParamsByPath = (pathParams, path8) => {
|
|
761
|
+
const params = path8.match(/{\w*}/g) || [];
|
|
756
762
|
const cleanParams = params.map((param) => param.replace("{", "").replace("}", ""));
|
|
757
763
|
return pathParams.sort((a, b) => cleanParams.indexOf(a.name) - cleanParams.indexOf(b.name));
|
|
758
764
|
};
|
|
@@ -776,30 +782,30 @@ var mappedMethod = (httpMethod, isForm, permissionType) => {
|
|
|
776
782
|
return "delete";
|
|
777
783
|
}
|
|
778
784
|
};
|
|
779
|
-
var resolveConflicts = ({ path:
|
|
785
|
+
var resolveConflicts = ({ path: path8, generatedMethod, testedGeneratedMethod, existingMethods }) => {
|
|
780
786
|
let _testedGenMethod = testedGeneratedMethod;
|
|
781
787
|
try {
|
|
782
|
-
testConflict(
|
|
788
|
+
testConflict(path8, _testedGenMethod, existingMethods);
|
|
783
789
|
} catch (e) {
|
|
784
|
-
if (
|
|
790
|
+
if (path8.indexOf("/namespaces/") >= 0) {
|
|
785
791
|
generatedMethod += "_ByNS";
|
|
786
792
|
_testedGenMethod += "_ByNS";
|
|
787
793
|
}
|
|
788
794
|
}
|
|
789
795
|
try {
|
|
790
|
-
testConflict(
|
|
796
|
+
testConflict(path8, _testedGenMethod, existingMethods);
|
|
791
797
|
} catch (e) {
|
|
792
|
-
if (
|
|
798
|
+
if (path8.indexOf("/admin/") >= 0) {
|
|
793
799
|
generatedMethod += "_admin";
|
|
794
800
|
_testedGenMethod += "_admin";
|
|
795
801
|
}
|
|
796
802
|
}
|
|
797
|
-
testConflict(
|
|
803
|
+
testConflict(path8, _testedGenMethod, existingMethods);
|
|
798
804
|
return generatedMethod;
|
|
799
805
|
};
|
|
800
|
-
var testConflict = (
|
|
806
|
+
var testConflict = (path8, generatedMethod, existingMethods) => {
|
|
801
807
|
if (existingMethods[generatedMethod]) {
|
|
802
|
-
const conflictingMethod = { path:
|
|
808
|
+
const conflictingMethod = { path: path8, generatedMethod };
|
|
803
809
|
throw Error(
|
|
804
810
|
`Duplicate method conflict in ${JSON.stringify(conflictingMethod)},
|
|
805
811
|
existingMethods: ${JSON.stringify(existingMethods, null, 2)}`
|
|
@@ -916,7 +922,7 @@ var OpenApiSpec = import_zod2.z.object({
|
|
|
916
922
|
var templateApiMethod = ({
|
|
917
923
|
classMethod,
|
|
918
924
|
httpMethod,
|
|
919
|
-
path:
|
|
925
|
+
path: path8,
|
|
920
926
|
pathParams,
|
|
921
927
|
bodyParams,
|
|
922
928
|
responseClasses,
|
|
@@ -925,12 +931,12 @@ var templateApiMethod = ({
|
|
|
925
931
|
methodParamsNoTypes,
|
|
926
932
|
xSecurity
|
|
927
933
|
}) => {
|
|
928
|
-
let newPath = `'${
|
|
934
|
+
let newPath = `'${path8}'`;
|
|
929
935
|
let snippetMethod = "";
|
|
930
936
|
for (const pathParam of pathParams) {
|
|
931
937
|
const type = ParserUtils.parseType(pathParam);
|
|
932
938
|
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
933
|
-
if (
|
|
939
|
+
if (path8.match(`{${pathParam.name}}`)) {
|
|
934
940
|
if (type === "string") {
|
|
935
941
|
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
936
942
|
} else {
|
|
@@ -938,9 +944,9 @@ var templateApiMethod = ({
|
|
|
938
944
|
}
|
|
939
945
|
}
|
|
940
946
|
}
|
|
941
|
-
const snippetShellArgs = ["--location --request", `${httpMethod} '__DOMAIN__${
|
|
947
|
+
const snippetShellArgs = ["--location --request", `${httpMethod} '__DOMAIN__${path8}'`, "--header 'accept: application/json'"];
|
|
942
948
|
const snippetApiArgs = [];
|
|
943
|
-
if (xSecurity !== void 0 ||
|
|
949
|
+
if (xSecurity !== void 0 || path8.includes("/admin")) {
|
|
944
950
|
snippetShellArgs.push("--header 'Authorization: Bearer {access_token}'");
|
|
945
951
|
snippetApiArgs.push("{ axiosConfig: { request: { headers: { Authorization: 'Bearer {access_token}' } } } }".trim());
|
|
946
952
|
}
|
|
@@ -978,7 +984,7 @@ var templateMethod = ({
|
|
|
978
984
|
classMethod,
|
|
979
985
|
description,
|
|
980
986
|
httpMethod,
|
|
981
|
-
path:
|
|
987
|
+
path: path8,
|
|
982
988
|
pathParams,
|
|
983
989
|
bodyParams,
|
|
984
990
|
queryParams,
|
|
@@ -988,9 +994,9 @@ var templateMethod = ({
|
|
|
988
994
|
}) => {
|
|
989
995
|
let methodParams = "";
|
|
990
996
|
let methodParamsNoTypes = "";
|
|
991
|
-
let newPath = `'${
|
|
997
|
+
let newPath = `'${path8}'`;
|
|
992
998
|
let importStatements = [];
|
|
993
|
-
const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams,
|
|
999
|
+
const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams, path8);
|
|
994
1000
|
for (const pathParam of sortedPathParams) {
|
|
995
1001
|
const type = ParserUtils.parseType(pathParam);
|
|
996
1002
|
if (pathParam.name !== "namespace") {
|
|
@@ -998,7 +1004,7 @@ var templateMethod = ({
|
|
|
998
1004
|
methodParamsNoTypes += pathParam.name + ", ";
|
|
999
1005
|
}
|
|
1000
1006
|
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
1001
|
-
if (
|
|
1007
|
+
if (path8.match(`{${pathParam.name}}`)) {
|
|
1002
1008
|
if (type === "string") {
|
|
1003
1009
|
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
1004
1010
|
} else {
|
|
@@ -1063,7 +1069,7 @@ var POST_FETCH_INCLUDES_PATH = ["/table-query/"];
|
|
|
1063
1069
|
var templateQueryMethod = ({
|
|
1064
1070
|
classMethod,
|
|
1065
1071
|
httpMethod,
|
|
1066
|
-
path:
|
|
1072
|
+
path: path8,
|
|
1067
1073
|
pathParams,
|
|
1068
1074
|
responseClasses,
|
|
1069
1075
|
methodParams,
|
|
@@ -1071,14 +1077,14 @@ var templateQueryMethod = ({
|
|
|
1071
1077
|
description,
|
|
1072
1078
|
deprecated
|
|
1073
1079
|
}) => {
|
|
1074
|
-
const isPostFetch = httpMethod === "post" && (POST_FETCH_INCLUDES_PATH.some((p) =>
|
|
1080
|
+
const isPostFetch = httpMethod === "post" && (POST_FETCH_INCLUDES_PATH.some((p) => path8.includes(p)) || path8.endsWith("/list"));
|
|
1075
1081
|
const isFetch = classMethod.startsWith("fetch");
|
|
1076
1082
|
const isGet = httpMethod === "get" || isPostFetch || isFetch;
|
|
1077
1083
|
const queryMethod = isGet ? "useQuery" : "useMutation";
|
|
1078
1084
|
let mParams = "";
|
|
1079
1085
|
let mParamsNoTypes = "";
|
|
1080
|
-
let newPath = `'${
|
|
1081
|
-
const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams,
|
|
1086
|
+
let newPath = `'${path8}'`;
|
|
1087
|
+
const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams, path8);
|
|
1082
1088
|
for (const pathParam of sortedPathParams) {
|
|
1083
1089
|
const type = ParserUtils.parseType(pathParam);
|
|
1084
1090
|
if (pathParam.name !== "namespace") {
|
|
@@ -1086,7 +1092,7 @@ var templateQueryMethod = ({
|
|
|
1086
1092
|
mParamsNoTypes += pathParam.name + ", ";
|
|
1087
1093
|
}
|
|
1088
1094
|
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
1089
|
-
if (
|
|
1095
|
+
if (path8.match(`{${pathParam.name}}`)) {
|
|
1090
1096
|
if (type === "string") {
|
|
1091
1097
|
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
1092
1098
|
} else {
|
|
@@ -1225,7 +1231,7 @@ import { ${serviceNameTitle} } from '@accelbyte/sdk-${serviceNameTitle.toLowerCa
|
|
|
1225
1231
|
|
|
1226
1232
|
const sdk = AccelByte.SDK({
|
|
1227
1233
|
coreConfig: {
|
|
1228
|
-
baseURL: '
|
|
1234
|
+
baseURL: '__DOMAIN__',
|
|
1229
1235
|
clientId: '77f88506b6174c3ea4d925f5b4096ce8',
|
|
1230
1236
|
namespace: 'accelbyte',
|
|
1231
1237
|
redirectURI: 'http://localhost:3030'
|
|
@@ -1255,7 +1261,7 @@ var normalizeMethodSnippet = (methodInput, splitWord) => {
|
|
|
1255
1261
|
};
|
|
1256
1262
|
|
|
1257
1263
|
// src/helpers/SwaggerReaderHelpers.ts
|
|
1258
|
-
var GIT_URL = "https://github.com/AccelByte/accelbyte-
|
|
1264
|
+
var GIT_URL = "https://github.com/AccelByte/accelbyte-typescript-sdk/blob/main/packages";
|
|
1259
1265
|
var SwaggerReaderHelpers = class _SwaggerReaderHelpers {
|
|
1260
1266
|
static getServicePrefix = (servicePaths) => servicePaths[servicePaths.length - 1].split("/")[1];
|
|
1261
1267
|
static parseAllEndpoints = async ({
|
|
@@ -1302,11 +1308,11 @@ var SwaggerReaderHelpers = class _SwaggerReaderHelpers {
|
|
|
1302
1308
|
admin: {},
|
|
1303
1309
|
public: {}
|
|
1304
1310
|
};
|
|
1305
|
-
for (const [
|
|
1306
|
-
if (
|
|
1311
|
+
for (const [path8, operation] of sortedPathsByLength) {
|
|
1312
|
+
if (path8.indexOf("/healthz") >= 0) {
|
|
1307
1313
|
continue;
|
|
1308
1314
|
}
|
|
1309
|
-
const isAdminEndpoint =
|
|
1315
|
+
const isAdminEndpoint = path8.indexOf("/admin/") > -1;
|
|
1310
1316
|
const picked = isAdminEndpoint ? result.admin : result.public;
|
|
1311
1317
|
const {
|
|
1312
1318
|
arrayDefinitions,
|
|
@@ -1324,25 +1330,25 @@ var SwaggerReaderHelpers = class _SwaggerReaderHelpers {
|
|
|
1324
1330
|
const httpMethods = Object.keys(operation);
|
|
1325
1331
|
for (const httpMethod of httpMethods) {
|
|
1326
1332
|
const endpoint = await Endpoint.parseAsync(operation[httpMethod]).catch((error) => {
|
|
1327
|
-
console.error(JSON.stringify({ path:
|
|
1333
|
+
console.error(JSON.stringify({ path: path8, httpMethod }, null, 2));
|
|
1328
1334
|
throw error;
|
|
1329
1335
|
});
|
|
1330
1336
|
if (!endpoint.tags) continue;
|
|
1331
1337
|
const [tag] = endpoint.tags;
|
|
1332
|
-
const pathWithBase = `${api.basePath ?? ""}${
|
|
1338
|
+
const pathWithBase = `${api.basePath ?? ""}${path8}`;
|
|
1333
1339
|
const permissionType = getPermissionType(getPermission(endpoint));
|
|
1334
1340
|
tagToClassMethodsMapByType[tag] = tagToClassMethodsMapByType[tag] ? tagToClassMethodsMapByType[tag] : {};
|
|
1335
1341
|
const isForm = endpoint.consumes && endpoint.consumes[0] === "application/x-www-form-urlencoded";
|
|
1336
1342
|
const classMethod = ParserUtils.generateNaturalLangMethod({
|
|
1337
1343
|
servicePrefix,
|
|
1338
|
-
path:
|
|
1344
|
+
path: path8,
|
|
1339
1345
|
httpMethod,
|
|
1340
1346
|
isForm,
|
|
1341
1347
|
existingMethods: tagToClassMethodsMapByType[tag],
|
|
1342
1348
|
permissionType
|
|
1343
1349
|
});
|
|
1344
|
-
tagToClassMethodsMapByType[tag][classMethod] = `${
|
|
1345
|
-
generatedMethods[`${
|
|
1350
|
+
tagToClassMethodsMapByType[tag][classMethod] = `${path8} ${httpMethod}`;
|
|
1351
|
+
generatedMethods[`${path8} ${httpMethod}`] = `${classMethod}`;
|
|
1346
1352
|
if (!snippetMap[pathWithBase]) {
|
|
1347
1353
|
snippetMap[pathWithBase] = {};
|
|
1348
1354
|
}
|
|
@@ -1441,7 +1447,7 @@ var SwaggerReaderHelpers = class _SwaggerReaderHelpers {
|
|
|
1441
1447
|
};
|
|
1442
1448
|
|
|
1443
1449
|
// src/templates/template-api-index.ts
|
|
1444
|
-
var templateApiIndex = (serviceNameTitle, apiList) => {
|
|
1450
|
+
var templateApiIndex = (serviceNameTitle, apiList, isGenerateWebSocket = false) => {
|
|
1445
1451
|
let imports = "";
|
|
1446
1452
|
let returnStatement = "";
|
|
1447
1453
|
for (const cl of apiList) {
|
|
@@ -1450,6 +1456,12 @@ var templateApiIndex = (serviceNameTitle, apiList) => {
|
|
|
1450
1456
|
import { ${cl} } from './${dir}/${cl}.js'`;
|
|
1451
1457
|
returnStatement += `
|
|
1452
1458
|
${cl}, `;
|
|
1459
|
+
}
|
|
1460
|
+
if (isGenerateWebSocket) {
|
|
1461
|
+
imports += `
|
|
1462
|
+
import { WebSocketClass } from './generated-websocket/WebSocketClass.js'`;
|
|
1463
|
+
returnStatement += `
|
|
1464
|
+
WebSocket: WebSocketClass, `;
|
|
1453
1465
|
}
|
|
1454
1466
|
return `/**
|
|
1455
1467
|
* AUTO GENERATED
|
|
@@ -1755,7 +1767,9 @@ var CodeGenerator = class _CodeGenerator {
|
|
|
1755
1767
|
const queryImportsSet = /* @__PURE__ */ new Set();
|
|
1756
1768
|
const apiInfo = { ...api.info, "x-version": api["x-version"]?.version };
|
|
1757
1769
|
console.log("----------\nGenerating API:", { title: apiInfo.title, version: apiInfo.version });
|
|
1758
|
-
|
|
1770
|
+
if (!CliParser.isGenerateSnippetOnly()) {
|
|
1771
|
+
ParserUtils.writeXVersion(_CodeGenerator.srcFolder(), api["x-version"], api.info);
|
|
1772
|
+
}
|
|
1759
1773
|
const parsedInformation = await SwaggerReaderHelpers.parseAllEndpoints({ api, sdkName, serviceName });
|
|
1760
1774
|
if (CliParser.getSnippetOutputPath()) {
|
|
1761
1775
|
try {
|
|
@@ -1870,7 +1884,8 @@ var CodeGenerator = class _CodeGenerator {
|
|
|
1870
1884
|
};
|
|
1871
1885
|
generatePublicOrAdmin(true);
|
|
1872
1886
|
generatePublicOrAdmin(false);
|
|
1873
|
-
const
|
|
1887
|
+
const isGenerateWebSocket = CliParser.isGenerateWebSocket();
|
|
1888
|
+
const apiIndexBuff = templateApiIndex(serviceNameTitle, mainApiList, isGenerateWebSocket);
|
|
1874
1889
|
ParserUtils.writeApiMainFile(_CodeGenerator.srcFolder(), serviceNameTitle, apiIndexBuff);
|
|
1875
1890
|
console.log("\nCOMPLETED\n----------\n\n");
|
|
1876
1891
|
return { indexImports: indexImportsSet, queryImports: queryImportsSet };
|
|
@@ -1941,25 +1956,373 @@ var SwaggerDownloader = class _SwaggerDownloader {
|
|
|
1941
1956
|
};
|
|
1942
1957
|
};
|
|
1943
1958
|
|
|
1959
|
+
// src/WebsocketGenerator.ts
|
|
1960
|
+
var import_fs5 = __toESM(require("fs"));
|
|
1961
|
+
var import_path4 = __toESM(require("path"));
|
|
1962
|
+
|
|
1963
|
+
// src/templates/template-ws-class.ts
|
|
1964
|
+
var definitionToFunctionName = (type) => {
|
|
1965
|
+
if (type.endsWith("Request")) {
|
|
1966
|
+
return "send" + capitalize(type.slice(0, type.length - 7));
|
|
1967
|
+
}
|
|
1968
|
+
return type;
|
|
1969
|
+
};
|
|
1970
|
+
var renderSendFunction = (name, definition) => {
|
|
1971
|
+
const functionName = definitionToFunctionName(name);
|
|
1972
|
+
return `const ${functionName} = (data: Omit<Definitions.${capitalize(name)}, 'type'>) => {
|
|
1973
|
+
send({ type: '${name}', ...data })
|
|
1974
|
+
}`;
|
|
1975
|
+
};
|
|
1976
|
+
var templateWebsocketClass = (name, path8, definitions) => {
|
|
1977
|
+
const requestDefinitions = Object.keys(definitions).filter((key) => {
|
|
1978
|
+
const val = definitions[key];
|
|
1979
|
+
return val["x-type"] == "request";
|
|
1980
|
+
}).map((key) => [key, definitions[key]]);
|
|
1981
|
+
return `/* eslint-disable camelcase */
|
|
1982
|
+
/* eslint-disable no-inner-declarations */
|
|
1983
|
+
// @ts-ignore -> ts-expect-error TS6133
|
|
1984
|
+
import { AccelByteSDK, RefreshToken, SdkSetConfigParam } from '@accelbyte/sdk'
|
|
1985
|
+
import * as Definitions from './WebSocketDefinitions'
|
|
1986
|
+
|
|
1987
|
+
const messageParser = (data: string) => {
|
|
1988
|
+
const toVal = (str?: string) => {
|
|
1989
|
+
if (str) {
|
|
1990
|
+
if (str.startsWith('[') && str.endsWith(']')) {
|
|
1991
|
+
return str
|
|
1992
|
+
.slice(1, str.length - 1)
|
|
1993
|
+
.split(',')
|
|
1994
|
+
.filter(v => v !== '')
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
return str
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
const entries = data.split('\\n')
|
|
2001
|
+
.filter(line => line !== '')
|
|
2002
|
+
.map(line => {
|
|
2003
|
+
const [key, valStr] = line.split(': ')
|
|
2004
|
+
return [key, toVal(valStr)]
|
|
2005
|
+
})
|
|
2006
|
+
|
|
2007
|
+
return Object.fromEntries(entries)
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
const messageSerializer = (data: Record<string, any>) => {
|
|
2011
|
+
return Object.keys(data)
|
|
2012
|
+
.map(key => {
|
|
2013
|
+
const toStr = (val: any) => {
|
|
2014
|
+
// array
|
|
2015
|
+
if (Array.isArray(val)) {
|
|
2016
|
+
return \`[\${String(val)}]\`
|
|
2017
|
+
}
|
|
2018
|
+
// null, undefined
|
|
2019
|
+
if (!val) {
|
|
2020
|
+
return ''
|
|
2021
|
+
}
|
|
2022
|
+
return String(val)
|
|
2023
|
+
}
|
|
2024
|
+
const val = data[key]
|
|
2025
|
+
const valStr = toStr(val)
|
|
2026
|
+
|
|
2027
|
+
return \`\${key}: \${valStr}\`
|
|
2028
|
+
})
|
|
2029
|
+
.join('\\n')
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
export function WebSocketClass(sdk: AccelByteSDK, args?: SdkSetConfigParam) {
|
|
2033
|
+
const sdkAssembly = sdk.assembly()
|
|
2034
|
+
const baseURL = (args?.coreConfig?.baseURL ?? sdkAssembly.coreConfig.baseURL).replace('http', 'ws')
|
|
2035
|
+
const path = '${path8}'
|
|
2036
|
+
const url = baseURL + path
|
|
2037
|
+
let ws: WebSocket | null = null
|
|
2038
|
+
let isDisconnectManually = false
|
|
2039
|
+
const allowReconnect = sdkAssembly.webSocketConfig.allowReconnect ?? true
|
|
2040
|
+
const maxReconnectAttempts = sdkAssembly.webSocketConfig.maxReconnectAttempts ?? 0
|
|
2041
|
+
let reconnectAttempts = maxReconnectAttempts
|
|
2042
|
+
|
|
2043
|
+
const connect = () => {
|
|
2044
|
+
const token = sdk.getToken()
|
|
2045
|
+
|
|
2046
|
+
if (!token.accessToken) {
|
|
2047
|
+
console.warn('No access token, please login first')
|
|
2048
|
+
return
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
if (!ws) {
|
|
2052
|
+
ws = new WebSocket(url, token.accessToken)
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
const refreshToken = async () => {
|
|
2057
|
+
const { refreshToken } = sdk.getToken()
|
|
2058
|
+
if (refreshToken) {
|
|
2059
|
+
const refresh = new RefreshToken({
|
|
2060
|
+
config: {
|
|
2061
|
+
axiosConfig: sdkAssembly.axiosConfig.request,
|
|
2062
|
+
clientId: sdkAssembly.coreConfig.clientId,
|
|
2063
|
+
refreshToken
|
|
2064
|
+
}
|
|
2065
|
+
})
|
|
2066
|
+
const result = await refresh.runWithLock()
|
|
2067
|
+
if (result) {
|
|
2068
|
+
sdk.setToken({
|
|
2069
|
+
accessToken: result.access_token,
|
|
2070
|
+
refreshToken: result.refresh_token
|
|
2071
|
+
})
|
|
2072
|
+
return true
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
return false
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
const handleReconnect = async (ev: CloseEvent) => {
|
|
2079
|
+
if (!allowReconnect || isDisconnectManually || !sdk.getToken().accessToken) return
|
|
2080
|
+
// token revoked
|
|
2081
|
+
if (ev.code === 4020) {
|
|
2082
|
+
await refreshToken()
|
|
2083
|
+
reconnectAttempts--
|
|
2084
|
+
connect()
|
|
2085
|
+
} else if (ev.code >= 1001 && ev.code <= 2999) {
|
|
2086
|
+
// Only reconnect if codes in range 1001-2999
|
|
2087
|
+
if (!ws || ws.readyState !== ws.OPEN) return
|
|
2088
|
+
|
|
2089
|
+
if (maxReconnectAttempts === 0) {
|
|
2090
|
+
setTimeout(() => {
|
|
2091
|
+
connect()
|
|
2092
|
+
}, 1000)
|
|
2093
|
+
} else if (reconnectAttempts !== 0) {
|
|
2094
|
+
setTimeout(() => {
|
|
2095
|
+
reconnectAttempts--
|
|
2096
|
+
connect()
|
|
2097
|
+
}, 1000)
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
const disconnect = (code?: number, reason?: string) => {
|
|
2103
|
+
if (ws) {
|
|
2104
|
+
ws.close(code, reason)
|
|
2105
|
+
isDisconnectManually = true
|
|
2106
|
+
ws = null
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
const send = (message: Definitions.WebSocketRequest) => {
|
|
2111
|
+
if (ws) {
|
|
2112
|
+
ws.send(messageSerializer(message))
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
const sendRaw = (rawMessage: string) => {
|
|
2117
|
+
if (ws) {
|
|
2118
|
+
ws.send(rawMessage)
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
const onOpen = (cb: () => any) => {
|
|
2123
|
+
if (ws) {
|
|
2124
|
+
function listener(this: WebSocket, _ev: Event) {
|
|
2125
|
+
isDisconnectManually = false
|
|
2126
|
+
reconnectAttempts = maxReconnectAttempts
|
|
2127
|
+
cb()
|
|
2128
|
+
}
|
|
2129
|
+
ws.addEventListener('open', listener)
|
|
2130
|
+
return {
|
|
2131
|
+
removeEventListener: () => ws?.removeEventListener('open', listener)
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
return {}
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2137
|
+
const onClose = (cb: (ev: CloseEvent) => any) => {
|
|
2138
|
+
if (ws) {
|
|
2139
|
+
function listener(this: WebSocket, ev: CloseEvent) {
|
|
2140
|
+
handleReconnect(ev)
|
|
2141
|
+
cb(ev)
|
|
2142
|
+
}
|
|
2143
|
+
ws.addEventListener('close', listener)
|
|
2144
|
+
return {
|
|
2145
|
+
removeEventListener: () => ws?.removeEventListener('close', listener)
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
return {}
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
const onMessage = (cb: (message: Definitions.WebSocketResponseOrNotification | string) => any, raw: boolean = false) => {
|
|
2152
|
+
if (ws) {
|
|
2153
|
+
function listener(this: WebSocket, ev: MessageEvent<any>) {
|
|
2154
|
+
if (raw) {
|
|
2155
|
+
cb(ev.data)
|
|
2156
|
+
} else {
|
|
2157
|
+
const result = Definitions.WebSocketResponseOrNotification.parse(messageParser(ev.data))
|
|
2158
|
+
cb(result)
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
ws.addEventListener('message', listener)
|
|
2162
|
+
return {
|
|
2163
|
+
removeEventListener: () => ws?.removeEventListener('message', listener)
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
return {}
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
const onError = (cb: (err: any) => any) => {
|
|
2170
|
+
if (ws) {
|
|
2171
|
+
function listener(this: WebSocket, err: any) {
|
|
2172
|
+
cb(err)
|
|
2173
|
+
}
|
|
2174
|
+
ws.addEventListener('error', listener)
|
|
2175
|
+
return {
|
|
2176
|
+
removeEventListener: () => ws?.removeEventListener('error', listener)
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
return {}
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
${requestDefinitions.map(([name2, definition]) => renderSendFunction(name2, definition)).join(`
|
|
2183
|
+
|
|
2184
|
+
`)}
|
|
2185
|
+
|
|
2186
|
+
return {
|
|
2187
|
+
instance: ws,
|
|
2188
|
+
connect,
|
|
2189
|
+
disconnect,
|
|
2190
|
+
send,
|
|
2191
|
+
sendRaw,
|
|
2192
|
+
onOpen,
|
|
2193
|
+
onClose,
|
|
2194
|
+
onMessage,
|
|
2195
|
+
onError,
|
|
2196
|
+
${requestDefinitions.map(([name2, _2]) => definitionToFunctionName(name2)).join(",\n ")}
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
`;
|
|
2201
|
+
};
|
|
2202
|
+
|
|
2203
|
+
// src/templates/template-ws-defintions.ts
|
|
2204
|
+
var renderZod = (property) => {
|
|
2205
|
+
switch (property.type) {
|
|
2206
|
+
case "string":
|
|
2207
|
+
return `z.coerce.string()`;
|
|
2208
|
+
case "integer":
|
|
2209
|
+
return `z.coerce.number()`;
|
|
2210
|
+
case "boolean":
|
|
2211
|
+
return `z.boolean()`;
|
|
2212
|
+
case "array":
|
|
2213
|
+
return `z.array(${renderZod(property.items)})`;
|
|
2214
|
+
default:
|
|
2215
|
+
return `z.any()`;
|
|
2216
|
+
}
|
|
2217
|
+
};
|
|
2218
|
+
var renderProperty = (name, type, property, required) => {
|
|
2219
|
+
const isRequired = required && required.includes(name);
|
|
2220
|
+
return `${name}: ${renderZod(property)}${isRequired || type != "request" ? "" : ".optional()"}`;
|
|
2221
|
+
};
|
|
2222
|
+
var renderDefinition = (name, definition) => {
|
|
2223
|
+
const capitalizedName = capitalize(name);
|
|
2224
|
+
if (definition.properties) {
|
|
2225
|
+
const properties = Object.entries(definition.properties);
|
|
2226
|
+
return `export const ${capitalizedName} = z.object({
|
|
2227
|
+
type: z.literal("${name}"),
|
|
2228
|
+
${properties.map(([name2, property]) => renderProperty(name2, definition["x-type"], property, definition.required)).join(",\n ")}
|
|
2229
|
+
})
|
|
2230
|
+
|
|
2231
|
+
export type ${capitalizedName} = z.infer<typeof ${capitalizedName}>
|
|
2232
|
+
`;
|
|
2233
|
+
}
|
|
2234
|
+
return "";
|
|
2235
|
+
};
|
|
2236
|
+
var renderAllDefinitions = (definitions) => {
|
|
2237
|
+
if (definitions) {
|
|
2238
|
+
const definitionEntries = Object.entries(definitions);
|
|
2239
|
+
return definitionEntries.map(([name, definition]) => renderDefinition(name, definition)).join("\n\n");
|
|
2240
|
+
}
|
|
2241
|
+
return "";
|
|
2242
|
+
};
|
|
2243
|
+
var renderUnion = (type, definitions) => {
|
|
2244
|
+
if (definitions) {
|
|
2245
|
+
let capitalizedType = "";
|
|
2246
|
+
if (typeof type === "string") {
|
|
2247
|
+
capitalizedType = capitalize(type);
|
|
2248
|
+
} else {
|
|
2249
|
+
capitalizedType = type.map((t) => capitalize(t)).join("Or");
|
|
2250
|
+
}
|
|
2251
|
+
const filteredDefinitions = Object.entries(definitions).filter(([_2, def]) => {
|
|
2252
|
+
if (typeof type === "string") {
|
|
2253
|
+
return def["x-type"] === type;
|
|
2254
|
+
} else {
|
|
2255
|
+
return type.includes(def["x-type"]);
|
|
2256
|
+
}
|
|
2257
|
+
}).map(([name, _2]) => capitalize(name));
|
|
2258
|
+
return `export const WebSocket${capitalizedType} = z.discriminatedUnion("type", [
|
|
2259
|
+
${filteredDefinitions.join(",\n ")}
|
|
2260
|
+
])
|
|
2261
|
+
|
|
2262
|
+
export type WebSocket${capitalizedType} = z.infer<typeof WebSocket${capitalizedType}>`;
|
|
2263
|
+
}
|
|
2264
|
+
return "";
|
|
2265
|
+
};
|
|
2266
|
+
var templateWebsocketDefinitions = (definitions) => {
|
|
2267
|
+
return `/**
|
|
2268
|
+
* AUTO GENERATED
|
|
2269
|
+
*/
|
|
2270
|
+
|
|
2271
|
+
import { z } from 'zod'
|
|
2272
|
+
|
|
2273
|
+
${renderAllDefinitions(definitions)}
|
|
2274
|
+
|
|
2275
|
+
${renderUnion("request", definitions)}
|
|
2276
|
+
|
|
2277
|
+
${renderUnion(["response", "notification"], definitions)}
|
|
2278
|
+
`;
|
|
2279
|
+
};
|
|
2280
|
+
|
|
2281
|
+
// src/WebsocketGenerator.ts
|
|
2282
|
+
var WebsocketGenerator = class {
|
|
2283
|
+
static srcFolder = () => CliParser.getOutputPath();
|
|
2284
|
+
static outputFolder = () => import_path4.default.join(this.srcFolder(), "generated-websocket");
|
|
2285
|
+
static schemaContent = () => {
|
|
2286
|
+
const fileContent = JSON.parse(import_fs5.default.readFileSync(CliParser.getWebSocketSchemaPath(), "utf8"));
|
|
2287
|
+
return fileContent;
|
|
2288
|
+
};
|
|
2289
|
+
static prepareDirs = () => {
|
|
2290
|
+
ParserUtils.mkdirIfNotExist(this.outputFolder());
|
|
2291
|
+
};
|
|
2292
|
+
static main = () => {
|
|
2293
|
+
const { name, path: wsPath, definitions } = this.schemaContent();
|
|
2294
|
+
const templateDefinitions = templateWebsocketDefinitions(definitions);
|
|
2295
|
+
this.prepareDirs();
|
|
2296
|
+
const filePath = import_path4.default.join(this.outputFolder(), "WebSocketDefinitions.ts");
|
|
2297
|
+
import_fs5.default.writeFileSync(filePath, templateDefinitions, "utf8");
|
|
2298
|
+
const templateClass2 = templateWebsocketClass(name, wsPath, definitions);
|
|
2299
|
+
const filePathClass = import_path4.default.join(this.outputFolder(), "WebSocketClass.ts");
|
|
2300
|
+
import_fs5.default.writeFileSync(filePathClass, templateClass2, "utf8");
|
|
2301
|
+
};
|
|
2302
|
+
};
|
|
2303
|
+
|
|
1944
2304
|
// src/cli.ts
|
|
1945
2305
|
var generateSdk = async () => {
|
|
1946
2306
|
const arrayOfSets = await Promise.all(CliParser.getConfigFile().map((config) => CodeGenerator.main(config)));
|
|
1947
2307
|
if (CliParser.isGenerateSnippetOnly()) {
|
|
1948
2308
|
return;
|
|
1949
2309
|
}
|
|
2310
|
+
if (CliParser.isGenerateWebSocket()) {
|
|
2311
|
+
WebsocketGenerator.main();
|
|
2312
|
+
}
|
|
1950
2313
|
const indexImportsSet = /* @__PURE__ */ new Set();
|
|
1951
2314
|
const queryImportsSet = /* @__PURE__ */ new Set();
|
|
1952
2315
|
const filenamesSet = /* @__PURE__ */ new Set();
|
|
1953
2316
|
for (const set of arrayOfSets) {
|
|
1954
2317
|
set.indexImports.forEach((value) => {
|
|
1955
|
-
const fileName =
|
|
2318
|
+
const fileName = import_path5.default.basename(value);
|
|
1956
2319
|
if (!filenamesSet.has(fileName)) {
|
|
1957
2320
|
indexImportsSet.add(value);
|
|
1958
2321
|
filenamesSet.add(fileName);
|
|
1959
2322
|
}
|
|
1960
2323
|
});
|
|
1961
2324
|
set.queryImports.forEach((value) => {
|
|
1962
|
-
const fileName =
|
|
2325
|
+
const fileName = import_path5.default.basename(value);
|
|
1963
2326
|
if (!filenamesSet.has(fileName)) {
|
|
1964
2327
|
queryImportsSet.add(value);
|
|
1965
2328
|
}
|
|
@@ -1980,30 +2343,39 @@ import_yargs.default.command("download-swaggers", "Download swaggers JSON files"
|
|
|
1980
2343
|
CliParser.createInstance(yargs2);
|
|
1981
2344
|
SwaggerDownloader.main();
|
|
1982
2345
|
}).command("generate-code", "Generate code based on downloaded swagger files", async (yargs2) => {
|
|
1983
|
-
yargs2.check(({ output }) => {
|
|
1984
|
-
if (!output?.trim()) {
|
|
2346
|
+
yargs2.check(({ output, snippetOnly, snippetOutput }) => {
|
|
2347
|
+
if (!output?.trim() && !snippetOnly) {
|
|
1985
2348
|
throw new Error("output is required for generate-code");
|
|
1986
2349
|
}
|
|
2350
|
+
if (snippetOnly && !snippetOutput) {
|
|
2351
|
+
throw new Error("snippetOutput is required when generating snippets.");
|
|
2352
|
+
}
|
|
1987
2353
|
return true;
|
|
1988
2354
|
});
|
|
1989
2355
|
CliParser.createInstance(yargs2);
|
|
1990
2356
|
await generateSdk();
|
|
1991
2357
|
}).option("config", {
|
|
1992
|
-
description: "
|
|
2358
|
+
description: "Path to the config file with backend service URLs.",
|
|
1993
2359
|
type: "string",
|
|
1994
2360
|
demandOption: true
|
|
1995
2361
|
}).option("swaggersOutput", {
|
|
1996
|
-
description: "
|
|
2362
|
+
description: "Directory to save the downloaded Swagger JSON files.",
|
|
1997
2363
|
type: "string",
|
|
1998
2364
|
demandOption: true
|
|
1999
2365
|
}).option("output", {
|
|
2000
|
-
description: "
|
|
2366
|
+
description: "Directory for the generated code. Required when using the generate-code command.",
|
|
2001
2367
|
type: "string"
|
|
2002
2368
|
}).option("skipReactQuery", {
|
|
2003
|
-
description: "
|
|
2369
|
+
description: "Disable React Query code generation.",
|
|
2004
2370
|
type: "boolean"
|
|
2005
2371
|
}).option("snippetOnly", {
|
|
2006
|
-
description: "
|
|
2372
|
+
description: "Generate only code snippets.",
|
|
2007
2373
|
type: "boolean"
|
|
2374
|
+
}).option("snippetOutput", {
|
|
2375
|
+
description: "Directory for the generated code snippets. Required when generating snippets.",
|
|
2376
|
+
type: "string"
|
|
2377
|
+
}).option("webSocketSchema", {
|
|
2378
|
+
description: "Path to the WebSocket schema file (schema.json). If provided, WebSocket methods will be generated based on the schema.",
|
|
2379
|
+
type: "string"
|
|
2008
2380
|
}).demandCommand(1).help().argv;
|
|
2009
2381
|
//# sourceMappingURL=accelbyte-codegen.js.map
|