@accelbyte/codegen 0.0.0-dev-20240828032938

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/.eslintrc.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "plugins": ["unused-imports"],
3
+ "rules": {
4
+ "unused-imports/no-unused-imports": "error"
5
+ }
6
+ }
package/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ AccelByte Development Code License
2
+
3
+ This development code license agreement (“Agreement”) is between you and AccelByte, Inc. ("AccelByte"), and governs your use of the library, sample code or other software that is accompanied by this license (the "Licensed Software"). By using the Licensed Software, you agree to be bound by the terms of this Agreement. If you do not agree to the terms of this Agreement, do not use the Licensed Software.
4
+
5
+ 1. License Grant. AccelByte hereby grants you a revocable, non-exclusive, non-sublicensable, non-transferrable license to use the Licensed Software, solely to develop your own games that are designed to operate on the AccelByte platform (available under a separate agreement), and solely as needed to enable that operation.
6
+
7
+ 2. Restrictions. Except as expressly permitted in this Agreement, you may not: (a) copy, modify, or create derivative works of the Licensed Software; (b) distribute, sublicense, lease, rent, loan, or otherwise transfer the Licensed Software or any rights granted under this Agreement; (c) reverse engineer, decompile, or disassemble the Licensed Software; or (d) make the functionality of the Licensed Software available to any third party.
8
+
9
+ 3. Termination. This Agreement will remain in effect until terminated by you or AccelByte. AccelByte may terminate this Agreement at any time for any reason. Upon termination of this Agreement, you must cease all use of the Licensed Software and destroy all copies of the Licensed Software in your possession or control.
10
+
11
+ 4. Proprietary Rights. The Licensed Software is owned and copyrighted by AccelByte. Your license to use the Licensed Software does not grant you any right, title, or interest in or to the Licensed Software, except for the limited rights expressly granted in this Agreement.
12
+
13
+ 5. Disclaimer of Warranties. THE LICENSED SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, ACCELBYTE DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS, IMPLIED, OR STATUTORY, INCLUDING THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
14
+
15
+ 6. Limitation of Liability. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL ACCELBYTE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES, OR ANY OTHER DAMAGES OF ANY KIND, ARISING FROM OR RELATED TO THIS AGREEMENT OR THE SDK, WHETHER IN CONTRACT, TORT, OR OTHERWISE, EVEN IF ACCELBYTE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
16
+
17
+ 7. Governing Law. This Agreement will be governed by and construed in accordance with the laws of the state of Washington in the United States of America, without regard to its conflict of law provisions.
18
+
19
+ 8. Contact Information. If you have any questions about this Agreement, please contact AccelByte at: hello@accelbyte.io. Last updated: October 26, 2022
package/PATCHING.md ADDED
@@ -0,0 +1,137 @@
1
+ # Code Generator Patching
2
+
3
+ This document outlines the steps required when patching an Open API specs.
4
+
5
+ ## JSON Patch
6
+
7
+ Inside the directory `packages/od-codegen/src/swaggers`, there are also JSON Patch that will patch the Swagger document. The patches will adjust the endpoints so that it will produce the proper functions to match the actual backend service.
8
+ We use https://github.com/Starcounter-Jack/JSON-Patch library that follow https://jsonpatch.com/ format
9
+
10
+ ### Operations
11
+
12
+ #### Add
13
+ ```
14
+ { "op": "add", "path": "/biscuits/1", "value": { "name": "Ginger Nut" } }
15
+ ```
16
+ Adds a value to an object or inserts it into an array. In the case of an array, the value is inserted before the given index. The - character can be used instead of an index to insert at the end of an array.
17
+
18
+ #### Remove
19
+ ```
20
+ { "op": "remove", "path": "/biscuits" }
21
+ ```
22
+ Removes a value from an object or array.
23
+ ```
24
+ { "op": "remove", "path": "/biscuits/0" }
25
+ ```
26
+ Removes the first element of the array at biscuits (or just removes the “0” key if biscuits is an object)
27
+
28
+ #### Replace
29
+ ```
30
+ { "op": "replace", "path": "/biscuits/0/name", "value": "Chocolate Digestive" }
31
+ ```
32
+ Replaces a value. Equivalent to a “remove” followed by an “add”.
33
+
34
+ #### Copy
35
+ ```
36
+ { "op": "copy", "from": "/biscuits/0", "path": "/best_biscuit" }
37
+ ```
38
+ Copies a value from one location to another within the JSON document. Both from and path are JSON Pointers.
39
+
40
+ #### Move
41
+ ```
42
+ { "op": "move", "from": "/biscuits", "path": "/cookies" }
43
+ ```
44
+ Moves a value from one location to the other. Both from and path are JSON Pointers.
45
+
46
+ #### Test
47
+ ```
48
+ { "op": "test", "path": "/best_biscuit/name", "value": "Choco Leibniz" }
49
+ ```
50
+ Tests that the specified value is set in the document. If the test fails, then the patch as a whole should not apply.
51
+
52
+ ### Example
53
+ For example, take a look at the this object
54
+ ```oauthmodel.TokenResponseV3": {
55
+ "required": [
56
+ "access_token",
57
+ "refresh_token",
58
+ "expires_in",
59
+ "token_type",
60
+ "roles",
61
+ "permissions",
62
+ "bans",
63
+ "user_id",
64
+ "display_name",
65
+ "namespace",
66
+ "namespace_roles",
67
+ "refresh_expires_in",
68
+ "scope",
69
+ "xuid"
70
+ ],
71
+ // ...
72
+ }
73
+ ```
74
+
75
+ This definition says that `TokenResponseV3` will always give out `xuid`. Yet at the moment, that property shouldn't always appear in the current IAM and the Swagger JSON is mistakenly written that way. If we kept the `xuid` property there, the response validation in the TypeScript SDK will throw error and say the response missed the `xuid` property. Therefore, the JSON Patches are created, and it looks like this
76
+
77
+ ```
78
+ {
79
+ "op": "remove",
80
+ "path": "/definitions/oauthmodel.TokenResponseV3/required/13"
81
+ }
82
+ ```
83
+
84
+ #### NOTE
85
+ Be careful if we want to use remove multiple array the results will be different from what is expected because at the first opportunity it will change the array order
86
+
87
+ for example the original json:
88
+ ```
89
+ "required": [
90
+ "validateOnly",
91
+ "code",
92
+ "contactType",
93
+ "languageTag"
94
+ ]
95
+ ```
96
+
97
+ what we expect:
98
+ ```
99
+ "required": [
100
+ "code",
101
+ "languageTag"
102
+ ]
103
+ ```
104
+
105
+ patch:
106
+ ```
107
+ {
108
+ "op": "remove",
109
+ "path": "/required/0"
110
+ },
111
+ {
112
+ "op": "remove",
113
+ "path": "/required/2"
114
+ }
115
+ ```
116
+
117
+ result:
118
+ ```
119
+ "required": [
120
+ "code",
121
+ "contactType"
122
+ ]
123
+ ```
124
+
125
+ So instead of doing multiple removes on array it's better to use replace operation
126
+
127
+ patch:
128
+ ```
129
+ {
130
+ "op": "replace",
131
+ "path": "/required",
132
+ "value": [
133
+ "code",
134
+ "languageTag"
135
+ ]
136
+ }
137
+ ```
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # AccelByte TypeScript SDK Code Generator
2
+
3
+ AccelByte Code Generator is a CLI tool that facilitates creating an AccelByte TypeScript SDK from AccelByte OpenAPI definitions.
4
+
5
+ ## CLI
6
+ This codegen build a CLI called `accelbyte-codegen` that will be used to generate code from given config.
7
+
8
+ ```
9
+ Commands:
10
+ accelbyte-codegen download-swaggers Download swaggers JSON files
11
+ accelbyte-codegen generate-code Generate code based on downloaded swagger
12
+ files
13
+
14
+ Options:
15
+ --version Show version number [boolean]
16
+ --config Config file providing backend services URL. [string] [required]
17
+ --swaggersOutput Output path for downloaded swaggers JSON files. [string] [required]
18
+ --output Output path for generated code. Required for generate-code [string]
19
+ --admin Only generate /admin endpoints. [boolean] [default: false]
20
+ --help Show help [boolean]
21
+ ```
22
+
23
+ ### Config file
24
+ Provide swaggers url you wish to generate, store it in .json format file.
25
+
26
+ ```
27
+ [
28
+ ["iam", "Iam", "iam.json", "https://example.com/iam/apidocs/api.json"]
29
+ ]
30
+ ```
31
+
32
+ ## How to Generate
33
+
34
+ **Step 1: Set Up Your Node.js Environment** Make sure you have Node.js and npm (Node Package Manager) installed on your system. You can download and install them from the official website: https://nodejs.org/en/
35
+
36
+ __*It is recommended__ to use [nvm](https://github.com/nvm-sh/nvm) or [fnm](https://github.com/Schniz/fnm) to install Node.js so you can switch between Node versions more easily
37
+
38
+ **Step 2: Create a New Node.js Project (if needed)** If you are starting a new project, create a new directory and initialize it as a Node.js project. You can do this using the following commands:
39
+ ```
40
+ mkdir my-project
41
+ cd my-project
42
+ npm init
43
+ ```
44
+ Follow the prompts to set up your project's package.json file.
45
+
46
+ **Step 3: Install the Package** To use `@accelbyte/codegen`, you need to install it as a dependency for your project. Run the following command within your project directory:
47
+ ```
48
+ npm install @accelbyte/codegen
49
+ # Or, with yarn:
50
+ yarn add @accelbyte/codegen
51
+ ```
52
+ **Step 4: Configure the Package** Check the documentation or the README of the package for specific configuration instructions.
53
+ 1. Prepare The `CHANGELOG.md` file, create the Changelog file in the root project with `CHANGELOG.md` file name.
54
+ 2. Prepare Config file, Provide the swaggers URL you wish to generate with the format of an Array of array detailed services, so we can add multiple services at the same time, by adding an Array of detailed services into `Config.json` Array like this:
55
+ ```
56
+ [
57
+ [serviceName, aliasName, swaggerFileOutput, swaggerURL],
58
+ [serviceName2, aliasName2, swaggerFileOutput2, swaggerURL2],
59
+ ...
60
+ ]
61
+ ```
62
+ and then store it in .json format file (we suggest placing the file in the root directory). example:
63
+ ```
64
+ [
65
+ ["iam", "Iam", "iam.json", "https://example.com/iam/apidocs/api.json"]
66
+ ]
67
+ ```
68
+ for the Accelbyte Demo environment, this will look like this
69
+ ```
70
+ [
71
+ ["iam", "Iam", "iam.json", "https://demo.accelbyte.io/iam/apidocs/api.json"]
72
+ ]
73
+ ```
74
+
75
+ **Step 5: Download Swagger Files** download the swagger file to the project by executing this command
76
+ ```
77
+ npm exec -- accelbyte-codegen download-swaggers --config ./config.json --swaggersOutput ./swaggers
78
+ # Or, with yarn:
79
+ yarn accelbyte-codegen download-swaggers --config ./config.json --swaggersOutput ./swaggers
80
+ ```
81
+ *note: please adjust the `--config` flag with the path of config.json file that was already set up before, and please specify the swagger output directory by using `--swaggersOutput` flag.
82
+
83
+ **Step 6: Generate Code from Swagger Files** after the swagger file has already been downloaded we can proceed to generating TypeScript SDK code from the Swagger File using this command :
84
+ ```
85
+ npm exec -- accelbyte-codegen generate-code --config ./config.json --swaggersOutput ./swaggers --output ./sdk
86
+ ```
87
+ *note: please adjust the `--config` flag with the path of config.json file that was already set up before, and please specify for the swagger output directory by using `--swaggersOutput` flag, and the directory output of generated SDK using `--output` flag.
88
+ if it is successful the result will look like this, and the WebSDK code should be generated under the/sdk directory
89
+
90
+ ```
91
+ ----------
92
+ Generating API: { title: 'justice-iam-service', version: '7.4.0' }
93
+ !!!! Missing x-version ...
94
+ COMPLETED
95
+ ----------
96
+ ```
97
+
98
+ **Step 7: Prettify the files (Optional)**
99
+
100
+ To prettify the code file using the prettier tool, please install the plugin first by doing this:
101
+ ```
102
+ npm install prettier
103
+ # Or, with yarn:
104
+ yarn add prettier
105
+ ```
106
+ after installing, execute prettier as below
107
+ ```
108
+ npm exec prettier --write swaggers/*.json && prettier --write sdk/**/*
109
+ # Or, with yarn:
110
+ yarn prettier --write swaggers/*.json && prettier --write sdk/**/*
111
+ ```
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@accelbyte/codegen",
3
+ "version": "0.0.0-dev-20240828032938",
4
+ "author": "AccelByte Inc",
5
+ "license": "SEE LICENSE IN LICENSE",
6
+ "main": "dist/accelbyte-codegen.js",
7
+ "module": "dist/accelbyte-codegen.mjs",
8
+ "scripts": {
9
+ "build": "tsup && yarn set-permissions",
10
+ "set-permissions": "cd dist && ls *.* && chmod 700 *.* || echo 'No matching files'",
11
+ "prettier": "prettier --write sdk/.",
12
+ "test": "vitest run --testTimeout=15000",
13
+ "test:watch": "vitest",
14
+ "clean": "npx rimraf dist && npx rimraf node_modules"
15
+ },
16
+ "bin": {
17
+ "accelbyte-codegen": "dist/accelbyte-codegen.js"
18
+ },
19
+ "dependencies": {
20
+ "@apidevtools/swagger-parser": "10.1.0",
21
+ "axios": "1.3.6",
22
+ "eslint": "8.56.0",
23
+ "eslint-plugin-unused-imports": "3.0.0",
24
+ "fast-json-patch": "3.1.1",
25
+ "lodash": "4.17.21",
26
+ "rimraf": "4.1.2",
27
+ "semver": "7.5.4",
28
+ "swagger-parser": "10.0.3",
29
+ "validator": "13.7.0",
30
+ "yargs": "17.6.2",
31
+ "zod": "3.17.3"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "22.3.0",
35
+ "@types/yargs": "17.0.14",
36
+ "tsup": "8.2.4",
37
+ "vitest": "2.0.5"
38
+ }
39
+ }
@@ -0,0 +1,105 @@
1
+ // @ts-check
2
+ import fs from 'fs/promises'
3
+ import path from 'path'
4
+
5
+ // The objective of this script is so that we could trim down the IAM Swagger.
6
+ // We want to test our Swagger parser and generator, in some ways so that we could be sure
7
+ // that when we do something, nothing breaks.
8
+ //
9
+ // And having the entire IAM Swagger JSON might be overkill.
10
+ // Hence, wh at we're doing in the `INCLUDED_ENDPOINTS` is that, we want to make sure
11
+ // to cover the scenarios. For example, function naming, deprecated endpoints exclusion.
12
+ const PATH_TO_IAM_SAMPLE = 'src/helpers/test-resources/swagger-iam-sample.json'
13
+
14
+ const INCLUDED_ENDPOINTS = [
15
+ // These are deprecated endpoints, should be automatically excluded.
16
+ '/iam/bans',
17
+ '/iam/roles',
18
+ // These are the normal ones.
19
+ '/iam/v3/admin/bans',
20
+ '/iam/v3/admin/roles',
21
+ '/iam/v3/admin/users/me',
22
+ '/iam/v3/public/users/me',
23
+ '/iam/v3/admin/namespaces/{namespace}/clients/{clientId}/permissions/{resource}/{action}',
24
+ // For array definitions test.
25
+ '/iam/v3/admin/namespaces/{namespace}/users/{userId}/platforms/justice'
26
+ ]
27
+
28
+ async function main() {
29
+ const content = await fs.readFile(path.join(process.cwd(), PATH_TO_IAM_SAMPLE), 'utf-8')
30
+ const json = JSON.parse(content)
31
+
32
+ const newPaths = {}
33
+ const modelsSet = new Set()
34
+ const newDefinitions = {}
35
+
36
+ for (const key in json.paths) {
37
+ // Only include the endpoints set above.
38
+ if (INCLUDED_ENDPOINTS.includes(key)) {
39
+ newPaths[key] = json.paths[key]
40
+
41
+ for (const methodKey in json.paths[key]) {
42
+ const { parameters = [], responses = {} } = json.paths[key][methodKey]
43
+
44
+ // Get the request body schema, if any.
45
+ for (const parameter of parameters) {
46
+ const { schema } = parameter
47
+ if (!schema) continue
48
+
49
+ const ref = getEffectiveRef(schema)
50
+ if (ref) modelsSet.add(ref)
51
+ }
52
+
53
+ // Get the resposne body schema, if any.
54
+ for (const responseStatus in responses) {
55
+ const { schema } = responses[responseStatus]
56
+ if (!schema) continue
57
+
58
+ const ref = getEffectiveRef(schema)
59
+ if (ref) modelsSet.add(ref)
60
+ }
61
+ }
62
+ }
63
+ }
64
+
65
+ for (const model of modelsSet) {
66
+ // Recursively add definitions (including definitions inside definitions).
67
+ recursivelyAddToNewDefinitions(newDefinitions, json.definitions, model)
68
+ }
69
+
70
+ json.paths = newPaths
71
+ json.definitions = newDefinitions
72
+
73
+ // Re-write the old Swagger into the new Swagger.
74
+ await fs.writeFile(PATH_TO_IAM_SAMPLE, JSON.stringify(json, null, 2), 'utf-8')
75
+ }
76
+
77
+ main()
78
+
79
+ // Helper functions.
80
+ function getEffectiveRef(schema) {
81
+ let ref = schema['$ref']
82
+ if (!ref) {
83
+ ref = schema.items?.['$ref']
84
+ }
85
+
86
+ return ref?.slice('#/definitions/'.length)
87
+ }
88
+
89
+ function recursivelyAddToNewDefinitions(newDefinitions, definitions, modelName) {
90
+ // Store the definition in the new definitions.
91
+ const currentDefinition = definitions[modelName]
92
+ newDefinitions[modelName] = currentDefinition
93
+
94
+ // From the definition, check the properties.
95
+ // See if they have "nested" definitions, so we can traverse them recursively.
96
+ for (const propertyKey in currentDefinition.properties) {
97
+ const propertySchema = currentDefinition.properties[propertyKey]
98
+ const ref = getEffectiveRef(propertySchema)
99
+
100
+ if (ref) {
101
+ newDefinitions[ref] = definitions[ref]
102
+ recursivelyAddToNewDefinitions(newDefinitions, definitions, ref)
103
+ }
104
+ }
105
+ }
@@ -0,0 +1,54 @@
1
+ import fs, { readFileSync, writeFileSync } from 'fs'
2
+ import path from 'path'
3
+ import { fileURLToPath } from 'url'
4
+
5
+ const __filename = fileURLToPath(import.meta.url)
6
+ const __dirname = path.dirname(__filename)
7
+
8
+ /* node ./packages/codegen/scripts/get-swaggers-configs.mjs */
9
+
10
+ const rootDir = path.resolve(path.join(__dirname, '../../'))
11
+
12
+ function findSwaggerFiles(dir) {
13
+ const files = fs.readdirSync(dir)
14
+ const swaggerFiles = []
15
+
16
+ files.forEach(file => {
17
+ const filePath = path.join(dir, file)
18
+ const stat = fs.statSync(filePath)
19
+
20
+ if (stat.isDirectory() && file.startsWith('sdk-')) {
21
+ const swaggerPath = path.join(filePath, 'swaggers.json')
22
+ if (fs.existsSync(swaggerPath)) {
23
+ swaggerFiles.push(swaggerPath)
24
+ }
25
+ }
26
+ })
27
+
28
+ return swaggerFiles
29
+ }
30
+
31
+ function parseSwaggerFiles(swaggerFiles) {
32
+ const result = {}
33
+
34
+ swaggerFiles.forEach(swaggerPath => {
35
+ const dirName = swaggerPath.match(/\/(sdk-[^\/]*)\//)?.[1]
36
+ const content = JSON.parse(readFileSync(swaggerPath, 'utf8'))
37
+
38
+ result[dirName] = content[0]
39
+ })
40
+
41
+ return result
42
+ }
43
+
44
+ function writeSwaggersConfigToFile(data) {
45
+ const filePath = path.resolve('./packages/codegen/src/helpers/test-resources/swaggersConfig.ts')
46
+ const fileContent = `const swaggersConfig = ${JSON.stringify(data, null, 2)};\n\nexport default swaggersConfig;\n`
47
+
48
+ writeFileSync(filePath, fileContent, 'utf8')
49
+ console.log(`swaggersConfig.js file created successfully at ${filePath}`)
50
+ }
51
+
52
+ const swaggerFiles = findSwaggerFiles(rootDir)
53
+ const parsedData = parseSwaggerFiles(swaggerFiles)
54
+ writeSwaggersConfigToFile(parsedData)