├── src ├── script │ ├── .nvmrc │ ├── .clasp.json │ ├── spec │ │ ├── index.ts │ │ ├── token_storage.spec.ts │ │ └── esi_client.spec.ts │ ├── tsconfig.json │ ├── src │ │ ├── authorize.html │ │ ├── appsscript.json │ │ ├── token_storage.ts │ │ ├── esi_client.ts │ │ ├── gesi.ts │ │ └── functions.ts │ └── package.json └── parser │ ├── shard.yml │ ├── GESI.cr │ └── eve_swagger.cr ├── googled99f4784502ed4c9.html ├── .gitignore ├── .editorconfig ├── LICENSE.txt ├── LICENSE └── README.md /src/script/.nvmrc: -------------------------------------------------------------------------------- 1 | 22 2 | -------------------------------------------------------------------------------- /googled99f4784502ed4c9.html: -------------------------------------------------------------------------------- 1 | google-site-verification: googled99f4784502ed4c9.html 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ 3 | 4 | src/parser/bin 5 | src/parser/lib 6 | src/parser/shard.lock 7 | -------------------------------------------------------------------------------- /src/script/.clasp.json: -------------------------------------------------------------------------------- 1 | { 2 | "scriptId":"1KjnRVVFr2KiHH55sqBfHcZ-yXweJ7iv89V99ubaLy4A7B_YH8rB5u0s3", 3 | "rootDir": "./src" 4 | } 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | 11 | [*.{json,html}] 12 | indent_size = 4 13 | -------------------------------------------------------------------------------- /src/script/spec/index.ts: -------------------------------------------------------------------------------- 1 | import 'jest-ts-auto-mock'; 2 | import { createMock } from 'ts-auto-mock'; 3 | 4 | // Mock AppScript types 5 | global.Utilities = createMock(); 6 | global.PropertiesService = createMock(); 7 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GESI only requires access to spreadsheets it is enabled on in order to operate. 2 | GESI uses the spreadsheet's ID for error logging, and the current user's temporary anonymous key for analytics. 3 | GESI does not store, use, share, or access any other data related to your Google account. 4 | -------------------------------------------------------------------------------- /src/parser/shard.yml: -------------------------------------------------------------------------------- 1 | name: GESI 2 | 3 | version: 11.0.0 4 | 5 | crystal: '>=0.34.0' 6 | 7 | license: MIT 8 | 9 | description: | 10 | Google Sheets™ ESI Add-on 11 | 12 | authors: 13 | - George Dietrich 14 | 15 | targets: 16 | gesi: 17 | main: ./GESI.cr 18 | 19 | development_dependencies: 20 | ameba: 21 | github: crystal-ameba/ameba 22 | version: ~> 1.0.0 23 | -------------------------------------------------------------------------------- /src/script/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2019", 5 | "sourceMap": true, 6 | "noUnusedLocals": true, 7 | "noUnusedParameters": true, 8 | "strict": true, 9 | "rootDir": "src", 10 | "experimentalDecorators": true, 11 | "removeComments": false, 12 | "plugins": [ 13 | { 14 | "transform": "ts-auto-mock/transformer", 15 | "cacheBetweenTests": false 16 | } 17 | ] 18 | }, 19 | "include": [ 20 | "src/*" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /src/script/src/authorize.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Authorize Character 6 | 11 | 12 | 13 |

Click the link below to authorize a character for use in GESI:

14 | Authorize with EVE SSO 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/script/src/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "Etc/GMT", 3 | "dependencies": { 4 | "libraries": [{ 5 | "userSymbol": "OAuth2", 6 | "libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF", 7 | "version": "41" 8 | }] 9 | }, 10 | "exceptionLogging": "NONE", 11 | "oauthScopes": ["https://www.googleapis.com/auth/script.container.ui", "https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/script.scriptapp", "https://www.googleapis.com/auth/spreadsheets.currentonly"], 12 | "urlFetchWhitelist": ["https://login.eveonline.com/", "https://esi.evetech.net/", "https://www.fuzzwork.co.uk/"], 13 | "runtimeVersion": "V8" 14 | } 15 | -------------------------------------------------------------------------------- /src/parser/GESI.cr: -------------------------------------------------------------------------------- 1 | require "./eve_swagger" 2 | 3 | # Load and parse the swagger spec 4 | base = EveSwagger.load 5 | 6 | # Save the function list 7 | File.open("#{EveSwagger::DIST_DIR}/functions.ts", "w") do |file| 8 | base.endpoints.join(file, "\n") { |endpoint, io| endpoint.to_function io } 9 | end 10 | 11 | # Save the endpoint list 12 | File.open("#{EveSwagger::DIST_DIR}/endpoints.ts", "w") do |file| 13 | file.puts "function getScopes(): string[] {" 14 | file << " return " 15 | 16 | base.scopes.to_pretty_json file 17 | 18 | file.puts 19 | 20 | file.print "}\n\n" 21 | 22 | keys = base.endpoints.map &.name 23 | file.puts "function getEndpoints(): IEndpointList {" 24 | file << " return " 25 | 26 | Hash.zip(keys, base.endpoints).to_pretty_json file 27 | 28 | file.puts 29 | 30 | file.puts "}" 31 | end 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 George Dietrich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/script/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesi", 3 | "version": "11.0.0", 4 | "description": "Google Sheets ESI Add-on", 5 | "scripts": { 6 | "test": "jest", 7 | "push": "sed -E -e '/^(export|import)/ s|^/*|//|' -i src/*.ts && npx clasp push && sed -E -e '/^(\\/\\/export|\\/\\/import)/ s|^/*||' -i src/*.ts" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/Blacksmoke16/GESI.git" 12 | }, 13 | "keywords": [ 14 | "eve", 15 | "eve-online", 16 | "esi", 17 | "crystal", 18 | "typescript" 19 | ], 20 | "author": "George Dietrich", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/Blacksmoke16/GESI/issues" 24 | }, 25 | "homepage": "https://github.com/Blacksmoke16/GESI#readme", 26 | "devDependencies": { 27 | "@google/clasp": "2.4.*", 28 | "@types/google-apps-script-oauth2": "38.0.0", 29 | "@types/jest": "~27.4.1", 30 | "jest": "~27.5.1", 31 | "jest-ts-auto-mock": "~2.1.0", 32 | "ts-auto-mock": "~3.5.0", 33 | "ts-jest": "~27.1.4", 34 | "ttypescript": "~1.5.13", 35 | "typescript": "~4.6.3" 36 | }, 37 | "jest": { 38 | "preset": "ts-jest", 39 | "testEnvironment": "node", 40 | "verbose": false, 41 | "setupFiles": [ 42 | "./spec/index.ts" 43 | ], 44 | "globals": { 45 | "ts-jest": { 46 | "compiler": "ttypescript" 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/script/src/token_storage.ts: -------------------------------------------------------------------------------- 1 | import Properties = GoogleAppsScript.Properties.Properties; 2 | import Cache = GoogleAppsScript.Cache.Cache; 3 | 4 | class TokenStorage implements Properties { 5 | static readonly TOKEN_TTL = 1140; // 19 minutes in seconds 6 | 7 | public constructor( 8 | private documentProperties: Properties, 9 | private documentCache: Cache 10 | ) { } 11 | 12 | public deleteAllProperties(): Properties { 13 | this.documentProperties.deleteAllProperties(); 14 | return this; 15 | } 16 | 17 | public deleteProperty(key: string): Properties { 18 | this.documentProperties.deleteProperty(key); 19 | this.documentCache.remove(key); 20 | 21 | return this; 22 | } 23 | 24 | public getKeys(): string[] { 25 | return this.documentProperties.getKeys(); 26 | } 27 | 28 | public getProperties(): { [p: string]: string } { 29 | return this.documentProperties.getProperties(); 30 | } 31 | 32 | public getProperty(key: string): string | null { 33 | const data = this.documentProperties.getProperty(key); 34 | 35 | if (null === data) { 36 | return null; 37 | } 38 | 39 | let jsonData; 40 | 41 | try { 42 | jsonData = JSON.parse(data); 43 | } catch (e) { 44 | // Stored value wasn't JSON encoded 45 | if (e instanceof SyntaxError) { 46 | return data; 47 | } 48 | 49 | throw e; 50 | } 51 | 52 | // If the fetch value is our token object, add back the access token from cache. 53 | if (jsonData.hasOwnProperty('token_type')) { 54 | jsonData.access_token = this.documentCache.get(key); 55 | } 56 | 57 | return JSON.stringify(jsonData); 58 | } 59 | 60 | public setProperties(properties: { [p: string]: string }): Properties; 61 | public setProperties(properties: { [p: string]: string }, deleteAllOthers: boolean): Properties; 62 | public setProperties(_properties: { [p: string]: string }, _deleteAllOthers?: boolean): Properties { 63 | throw new Error('setProperties is not implemented.'); 64 | } 65 | 66 | public setProperty(key: string, value: string): Properties { 67 | if (null === value) { 68 | return this.documentProperties.setProperty(key, value); 69 | } 70 | 71 | let jsonData; 72 | 73 | try { 74 | jsonData = JSON.parse(value); 75 | } catch (e) { 76 | // Stored value wasn't JSON encoded 77 | if (e instanceof SyntaxError) { 78 | return this.documentProperties.setProperty(key, value); 79 | } 80 | 81 | throw e; 82 | } 83 | 84 | if (!jsonData.hasOwnProperty('access_token')) { 85 | return this.documentProperties.setProperty(key, value); 86 | } 87 | 88 | 89 | const token = jsonData.access_token; 90 | delete jsonData.access_token; 91 | 92 | this.documentProperties.setProperty(key, JSON.stringify(jsonData)); 93 | this.documentCache.put(key!, token, TokenStorage.TOKEN_TTL); 94 | 95 | return this; 96 | } 97 | } 98 | 99 | export { TokenStorage } 100 | -------------------------------------------------------------------------------- /src/script/spec/token_storage.spec.ts: -------------------------------------------------------------------------------- 1 | import { createMock } from 'ts-auto-mock'; 2 | import { TokenStorage } from '../src/token_storage'; 3 | import Properties = GoogleAppsScript.Properties.Properties; 4 | import Cache = GoogleAppsScript.Cache.Cache; 5 | 6 | describe('TokenStorage', () => { 7 | let tokenStorage: TokenStorage; 8 | 9 | let documentPropertiesMock: Properties; 10 | let documentCacheMock: Cache; 11 | 12 | beforeEach(() => { 13 | documentPropertiesMock = createMock(); 14 | documentCacheMock = createMock(); 15 | 16 | tokenStorage = new TokenStorage( 17 | documentPropertiesMock, 18 | documentCacheMock, 19 | ); 20 | }); 21 | 22 | describe('#deleteAllProperties', () => { 23 | beforeEach(() => { 24 | tokenStorage.deleteAllProperties(); 25 | }); 26 | 27 | it('delegates to decorated properties store', () => { 28 | expect(documentPropertiesMock.deleteAllProperties).toHaveBeenCalled(); 29 | }); 30 | }); 31 | 32 | describe('#deleteProperty', () => { 33 | beforeEach(() => { 34 | tokenStorage.deleteProperty('foo'); 35 | }); 36 | 37 | it('delegates to decorated properties and cache stores', () => { 38 | expect(documentPropertiesMock.deleteProperty).toHaveBeenCalledWith('foo'); 39 | expect(documentCacheMock.remove).toHaveBeenCalledWith('foo'); 40 | }); 41 | }); 42 | 43 | describe('#getKeys', () => { 44 | let result: string[]; 45 | 46 | beforeEach(() => { 47 | documentPropertiesMock.getKeys = jest.fn().mockReturnValueOnce(['foo', 'bar']); 48 | result = tokenStorage.getKeys(); 49 | }); 50 | 51 | it('delegates to decorated properties store', () => { 52 | expect(result).toEqual(['foo', 'bar']); 53 | }); 54 | }); 55 | 56 | describe('#getProperties', () => { 57 | let result: { [p: string]: string }; 58 | 59 | beforeEach(() => { 60 | documentPropertiesMock.getProperties = jest.fn().mockReturnValueOnce({ foo: 'bar' }); 61 | result = tokenStorage.getProperties(); 62 | }); 63 | 64 | it('delegates to decorated properties store', () => { 65 | expect(result).toEqual({ foo: 'bar' }); 66 | }); 67 | }); 68 | 69 | describe('#getProperty', () => { 70 | let result: string | null; 71 | 72 | describe('and there is no property with that key', () => { 73 | beforeEach(() => { 74 | documentPropertiesMock.getProperty = jest.fn().mockReturnValueOnce(null); 75 | result = tokenStorage.getProperty('foo'); 76 | }); 77 | 78 | it('should return null', function () { 79 | expect(documentPropertiesMock.getProperty).toHaveBeenCalledWith('foo'); 80 | expect(documentCacheMock.get).not.toHaveBeenCalled(); 81 | expect(result).toBeNull(); 82 | }); 83 | }); 84 | 85 | describe('and there is a invalid JSON value string', () => { 86 | beforeEach(() => { 87 | documentPropertiesMock.getProperty = jest.fn().mockReturnValueOnce('bar'); 88 | result = tokenStorage.getProperty('foo'); 89 | }); 90 | 91 | it('should return the value as is', function () { 92 | expect(documentPropertiesMock.getProperty).toHaveBeenCalledWith('foo'); 93 | expect(documentCacheMock.get).not.toHaveBeenCalled(); 94 | expect(result).toBe('bar') 95 | }); 96 | }); 97 | 98 | describe('and the value is not the token object', () => { 99 | beforeEach(() => { 100 | documentPropertiesMock.getProperty = jest.fn().mockReturnValueOnce('{"foo":"bar"}'); 101 | result = tokenStorage.getProperty('foo'); 102 | }); 103 | 104 | it('should return the JSON string without `access_token`', function () { 105 | expect(documentPropertiesMock.getProperty).toHaveBeenCalledWith('foo'); 106 | expect(documentCacheMock.get).not.toHaveBeenCalled(); 107 | expect(result).toBe('{"foo":"bar"}') 108 | }); 109 | }); 110 | 111 | describe('and the value is the token object', () => { 112 | beforeEach(() => { 113 | documentPropertiesMock.getProperty = jest.fn().mockReturnValueOnce('{"token_type":"Bearer"}'); 114 | documentCacheMock.get = jest.fn().mockReturnValueOnce('TOKEN'); 115 | result = tokenStorage.getProperty('foo'); 116 | }); 117 | 118 | it('should return the JSON string without `access_token`', function () { 119 | expect(documentPropertiesMock.getProperty).toHaveBeenCalledWith('foo'); 120 | expect(documentCacheMock.get).toHaveBeenCalledWith('foo'); 121 | expect(result).toBe('{"token_type":"Bearer","access_token":"TOKEN"}') 122 | }); 123 | }); 124 | }); 125 | 126 | describe('#setProperty', () => { 127 | describe('and the value is `null`', () => { 128 | beforeEach(() => { 129 | // @ts-ignore 130 | tokenStorage.setProperty('foo', null); 131 | }); 132 | 133 | it('should delegate to decorated properties store', function () { 134 | expect(documentPropertiesMock.setProperty).toHaveBeenCalledWith('foo', null); 135 | expect(documentCacheMock.put).not.toHaveBeenCalled(); 136 | }); 137 | }); 138 | 139 | describe('and there is a invalid JSON value string', () => { 140 | beforeEach(() => { 141 | tokenStorage.setProperty('foo', 'bar'); 142 | }); 143 | 144 | it('should delegate to decorated properties store', function () { 145 | expect(documentPropertiesMock.setProperty).toHaveBeenCalledWith('foo', 'bar'); 146 | expect(documentCacheMock.put).not.toHaveBeenCalled(); 147 | }); 148 | }); 149 | 150 | describe('and the value is a JSON string without an `access_token`', () => { 151 | beforeEach(() => { 152 | tokenStorage.setProperty('foo', '{"foo":"bar"}'); 153 | }); 154 | 155 | it('should delegate to decorated properties store', function () { 156 | expect(documentPropertiesMock.setProperty).toHaveBeenCalledWith('foo', '{"foo":"bar"}'); 157 | expect(documentCacheMock.put).not.toHaveBeenCalled(); 158 | }); 159 | }); 160 | 161 | describe('and the value is a JSON string with an `access_token`', () => { 162 | beforeEach(() => { 163 | tokenStorage.setProperty('foo', '{"token_type":"Bearer","access_token":"TOKEN"}'); 164 | }); 165 | 166 | it('should delegate to decorated properties store', function () { 167 | expect(documentPropertiesMock.setProperty).toHaveBeenCalledWith('foo', '{"token_type":"Bearer"}'); 168 | expect(documentCacheMock.put).toHaveBeenCalledWith('foo', 'TOKEN', 1140) 169 | }); 170 | }); 171 | }); 172 | }); 173 | -------------------------------------------------------------------------------- /src/script/src/esi_client.ts: -------------------------------------------------------------------------------- 1 | import URLFetchRequest = GoogleAppsScript.URL_Fetch.URLFetchRequest; 2 | import HTTPResponse = GoogleAppsScript.URL_Fetch.HTTPResponse; 3 | import OAuth2Service = GoogleAppsScriptOAuth2.OAuth2Service; 4 | import Properties = GoogleAppsScript.Properties.Properties; 5 | import { getEndpoints } from './endpoints'; 6 | import { getScriptProperties_, IAccessTokenData, IAuthenticatedCharacter, IEndpoint, IFunctionParams, IHeader, IParameter, IToken, SheetsArray } from './gesi'; 7 | 8 | interface IEndpointProvider { 9 | hasEndpoint(name: string): boolean; 10 | getEndpoint(name: string): IEndpoint; 11 | } 12 | 13 | interface IHTTPClient { 14 | fetchAll(requests: URLFetchRequest[]): HTTPResponse[]; 15 | } 16 | 17 | class ESIClient { 18 | private static readonly BASE_URL = 'https://esi.evetech.net'; 19 | private static readonly AUDIENCE = 'EVE Online'; 20 | private static readonly ISSUERS = [ 21 | 'login.eveonline.com', 22 | 'https://login.eveonline.com' 23 | ]; 24 | 25 | public static addQueryParam(path: string, paramName: string, paramValue: any): string { 26 | path += path.includes('?') ? '&' : '?'; 27 | path += paramName + '=' + (Array.isArray(paramValue) ? paramValue.join(',') : paramValue); 28 | return path; 29 | } 30 | 31 | public static parseToken(access_token: string): IAccessTokenData { 32 | const jwtToken: IAccessTokenData = JSON.parse(Utilities.newBlob(Utilities.base64DecodeWebSafe(access_token.split('.')[1])).getDataAsString()); 33 | const clientId: string = getScriptProperties_().getProperty('CLIENT_ID')!; 34 | 35 | if (!ESIClient.ISSUERS.includes(jwtToken.iss)) throw 'Access token validation error: invalid issuer'; 36 | if (jwtToken.aud[0] !== clientId || jwtToken.aud[1] !== ESIClient.AUDIENCE) throw 'Access token validation error: invalid audience'; 37 | if (jwtToken.azp !== clientId) throw 'Access token validation error: invalid authorized party'; 38 | return jwtToken; 39 | } 40 | 41 | #oauthClient: OAuth2Service; 42 | private endpoint?: IEndpoint; 43 | private endpointProvider: IEndpointProvider; 44 | private httpClient: IHTTPClient; 45 | 46 | constructor( 47 | oauthClient: OAuth2Service, 48 | private characterData: IAuthenticatedCharacter, 49 | private documentProperties: Properties, 50 | endpointProvider?: IEndpointProvider, 51 | httpClient?: IHTTPClient, 52 | ) { 53 | this.#oauthClient = oauthClient; 54 | 55 | if (undefined === endpointProvider) { 56 | this.endpointProvider = { 57 | hasEndpoint(name: string): boolean { 58 | return getEndpoints().hasOwnProperty(name); 59 | }, 60 | getEndpoint(name: string): IEndpoint { 61 | return getEndpoints()[name]; 62 | }, 63 | }; 64 | } else { 65 | this.endpointProvider = endpointProvider; 66 | } 67 | 68 | if (undefined === httpClient) { 69 | this.httpClient = { 70 | fetchAll(requests: URLFetchRequest[]): HTTPResponse[] { 71 | return UrlFetchApp.fetchAll(requests); 72 | }, 73 | } 74 | } else { 75 | this.httpClient = httpClient; 76 | } 77 | } 78 | 79 | /** 80 | * Sets the endpoint to use for future methods calls. 81 | * 82 | * @param {string} functionName The name of the endpoint that should be invoked 83 | * @return {ESIClient} For chaining 84 | * @customfunction 85 | */ 86 | public setFunction(functionName: string): ESIClient { 87 | if (!this.endpointProvider?.hasEndpoint(functionName)) { 88 | throw new Error(`Unknown endpoint: '${functionName}'`); 89 | } 90 | 91 | this.endpoint = this.endpointProvider.getEndpoint(functionName); 92 | 93 | return this; 94 | } 95 | 96 | /** 97 | * @return {string} The access_token associated with this ESIClient. 98 | * @customfunction 99 | */ 100 | public getAccessToken(): string { 101 | return this.#oauthClient.getAccessToken(); 102 | } 103 | 104 | /** 105 | * @return {string} The refresh_token associated with this ESIClient. 106 | * @customfunction 107 | */ 108 | public getRefreshToken(): string { 109 | return this.getToken().refresh_token; 110 | } 111 | 112 | /** 113 | * @return {IToken} The full token object related to this ESIClient. 114 | * @customfunction 115 | */ 116 | public getToken(): IToken { 117 | return this.#oauthClient.getToken() as IToken; 118 | } 119 | 120 | /** 121 | * Deauthorizes the character related to this ESIClient. 122 | * 123 | * @customfunction 124 | */ 125 | public reset(): void { 126 | this.#oauthClient.reset(); 127 | this.documentProperties.deleteProperty(`character.${this.characterData.name}`); 128 | } 129 | 130 | /** 131 | * Executes an ESI request with the given params. 132 | * 133 | * @return {SheetsArray} The results. 134 | * @customfunction 135 | */ 136 | public execute(params: IFunctionParams = {} as IFunctionParams): SheetsArray { 137 | const endpoint = this.checkEndpoint(); 138 | const data: any = this.doRequest(params); 139 | 140 | let result: SheetsArray = []; 141 | 142 | if (params.show_column_headings !== undefined && typeof params.show_column_headings !== 'boolean') { 143 | throw new Error(`Expected optional argument show_column_headings to be a boolean, but got a ${typeof params.show_column_headings}.`); 144 | } 145 | 146 | // Add the header row if its not set, or set to true 147 | if (params.show_column_headings) result.push(endpoint.headers.map((header: IHeader) => header.name)); 148 | 149 | if (Array.isArray(data) && isFinite(data[0])) { 150 | result = result.concat(data); 151 | } else if (Array.isArray(data) && data instanceof Object) { 152 | result = result.concat( 153 | data.map((obj) => { 154 | return endpoint.headers.map((header: IHeader) => typeof (obj[header.name]) === 'object' ? JSON.stringify(obj[header.name]) : obj[header.name]); 155 | }), 156 | ); 157 | } else if (data instanceof Object) { 158 | result.push(endpoint.headers.map((header: IHeader) => typeof (data[header.name]) === 'object' ? JSON.stringify(data[header.name]) : data[header.name])); 159 | } else if (isFinite(data)) { 160 | result.push([data]); 161 | } 162 | 163 | return result; 164 | } 165 | 166 | /** 167 | * Executes an ESI request with the given params. 168 | * 169 | * @return {object | object[]} The parsed raw JSON result. 170 | * @customfunction 171 | */ 172 | public executeRaw(params: IFunctionParams = {} as IFunctionParams): T { 173 | this.checkEndpoint(); 174 | return this.doRequest(params); 175 | } 176 | 177 | /** 178 | * Builds a URLFetchRequest object with the given params. 179 | * 180 | * @return {URLFetchRequest} The built request. 181 | * @customfunction 182 | */ 183 | public buildRequest(params: IFunctionParams = {} as IFunctionParams): URLFetchRequest { 184 | const endpoint = this.checkEndpoint(); 185 | 186 | let path = endpoint.path; 187 | let payload: any = null; 188 | 189 | // Process this endpoint's parameters 190 | endpoint.parameters.forEach((param: IParameter) => { 191 | let paramValue = params[param.name]; 192 | const required = param.required ? 'required' : 'optional'; 193 | 194 | if (param.required && !paramValue && false !== paramValue) { 195 | throw new Error(`Argument ${param.name} is required.`); 196 | } else if (!param.required && !paramValue && false !== paramValue) { 197 | return; 198 | } 199 | 200 | let paramType = param.type; 201 | let paramValueType = typeof paramValue; 202 | let isArrayType = false; 203 | 204 | if (paramType.endsWith('[]')) { 205 | paramType = paramType.slice(0, -2); 206 | isArrayType = true; 207 | } 208 | 209 | if (isArrayType && 'string' === paramType && '#NAME?' === paramValue) { 210 | throw new Error(`Expected ${required} argument ${param.name} to be a string|string[], but got invalid named range. Put the value(s) in double quotes.`); 211 | } else if (!isArrayType && 'string' === paramType && '#NAME?' === paramValue) { 212 | throw new Error(`Expected ${required} argument ${param.name} to be a string, but got invalid named range. Put the value in double quotes.`); 213 | } else if (!isArrayType && '#NAME?' === paramValue) { 214 | throw new Error(`Expected ${required} argument ${param.name} to be a ${param.type}, but got invalid named range.`); 215 | } else if (isArrayType && (!Array.isArray(paramValue) && paramValueType !== paramType)) { 216 | throw new Error(`Expected ${required} argument ${param.name} to be a ${paramType}|${paramType}[], but got a ${paramValueType}.`); 217 | } else if (!isArrayType && (paramValueType !== paramType)) { 218 | throw new Error(`Expected ${required} argument ${param.name} to be a ${paramType}, but got a ${paramValueType}.`); 219 | } 220 | 221 | if (isArrayType) { 222 | paramValue = !Array.isArray(paramValue) ? 223 | [paramValue] : 224 | Array.isArray(paramValue[0]) ? 225 | paramValue.filter((item: any) => item[0]).map((item: any) => item[0]) : 226 | paramValue; 227 | 228 | if (isArrayType && !paramValue.every((i: any) => typeof i === paramType)) { 229 | throw new Error(`Expected ${required} argument ${param.name} to be a ${paramType}|${paramType}[], but not every item in the array is a ${paramType}.`); 230 | } 231 | } 232 | 233 | if (param.in === 'path') { 234 | path = path.replace(`{${param.name}}`, paramValue); 235 | } else if (param.in === 'query') { 236 | path = ESIClient.addQueryParam(path, param.name, paramValue); 237 | } else if (param.in === 'body') { 238 | if (isArrayType) { 239 | payload = paramValue; 240 | } else { 241 | throw param.type + ' is an unexpected body type.'; 242 | } 243 | } 244 | }); 245 | 246 | // Add the page param if set 247 | if (params.page) { 248 | path = ESIClient.addQueryParam(path, 'page', params.page); 249 | } 250 | 251 | if (endpoint.scope) { 252 | if (this.characterData.alliance_id && path.includes('{alliance_id}')) path = path.replace('{alliance_id}', this.characterData.alliance_id!.toString()); 253 | if (path.includes('{character_id}')) path = path.replace('{character_id}', this.characterData.character_id.toString()); 254 | if (path.includes('{corporation_id}')) path = path.replace('{corporation_id}', this.characterData.corporation_id.toString()); 255 | } 256 | 257 | const request: URLFetchRequest = { 258 | method: endpoint.method, 259 | url: `${ESIClient.BASE_URL}${path.replace('{version}', params.version || endpoint.version)}`, 260 | headers: { 261 | 'user-agent': `GESI User ${this.characterData.character_id}`, 262 | }, 263 | contentType: 'application/json', 264 | muteHttpExceptions: true, 265 | }; 266 | 267 | if (payload) request.payload = JSON.stringify(payload); 268 | if (endpoint.scope) request.headers!['authorization'] = `Bearer ${this.#oauthClient.getAccessToken()}`; 269 | 270 | return request; 271 | } 272 | 273 | private doRequest(params: IFunctionParams): T { 274 | const request = this.buildRequest(params); 275 | const response: HTTPResponse = this.httpClient.fetchAll([request])[0]; 276 | const headers = response.getHeaders() as { [k: string]: string }; 277 | 278 | // If the request was not successful, raise an error 279 | if (response.getResponseCode() !== 200) { 280 | throw new Error(response.getContentText()); 281 | } 282 | 283 | // Log a warning if a route returns a warning 284 | if (headers.hasOwnProperty('Warning')) console.warn(headers['Warning']); 285 | 286 | // If the route is not paginated, or is paginated but only has one page, just return it 287 | if (!headers.hasOwnProperty('x-pages') || (headers.hasOwnProperty('x-pages') && parseInt(headers['x-pages']) === 1)) return JSON.parse(response.getContentText()); 288 | 289 | // Otherwise, if there are more than 1 page, issue additional requests to fetch all the pages 290 | const result = JSON.parse(response.getContentText()); 291 | 292 | const totalPages = parseInt(headers['x-pages']); 293 | const requests = []; 294 | 295 | for (let p = 2; p <= totalPages; p++) { 296 | params.page = p; 297 | requests.push(this.buildRequest(params)); 298 | } 299 | 300 | return result.concat(...this.httpClient.fetchAll(requests).map((response: HTTPResponse) => { 301 | if (response.getResponseCode() !== 200) { 302 | throw new Error(response.getContentText()); 303 | } 304 | 305 | return JSON.parse(response.getContentText()) 306 | })); 307 | } 308 | 309 | private checkEndpoint(): IEndpoint { 310 | if (!this.endpoint) { 311 | throw new Error('Endpoint name has not been set on client.'); 312 | } 313 | 314 | return this.endpoint; 315 | } 316 | } 317 | 318 | export { ESIClient, IEndpointProvider, IHTTPClient }; 319 | -------------------------------------------------------------------------------- /src/parser/eve_swagger.cr: -------------------------------------------------------------------------------- 1 | require "json" 2 | require "http/client" 3 | 4 | module EveSwagger 5 | DIST_DIR = "../script/src" 6 | # Base url for the swagger spec 7 | ESI_HOST = "https://esi.evetech.net" 8 | IGNORE_PARAMS = %w(user_agent X-User-Agent token If-None-Match Accept-Language datasource) 9 | 10 | class_getter! parameters : Hash(String, Parameter) 11 | 12 | def self.load : Base 13 | json = HTTP::Client.get("#{ESI_HOST}/_latest/swagger.json").body 14 | @@parameters = Hash(String, Parameter).from_json json, root: "parameters" 15 | Base.from_json json 16 | end 17 | 18 | module RefConverter 19 | def self.from_json(pull : JSON::PullParser) : Array(Parameter) 20 | arr = [] of Parameter 21 | pull.read_array do 22 | param = JSON.parse(pull.read_raw).as_h 23 | 24 | if param.has_key? "$ref" 25 | param_name = param["$ref"].as_s.split('/').last 26 | next if EveSwagger::IGNORE_PARAMS.includes? param_name 27 | 28 | arr << EveSwagger.parameters[param_name] 29 | else 30 | arr << Parameter.from_json param.to_json 31 | end 32 | end 33 | arr 34 | end 35 | end 36 | 37 | module ScopeConverter 38 | def self.from_json(pull : JSON::PullParser) : String? 39 | scope = nil 40 | 41 | pull.read_array do 42 | pull.read_object do 43 | pull.read_array do 44 | if scope.nil? 45 | scope = pull.read_string 46 | else 47 | raise "BUG: Path scope is already set" 48 | end 49 | end 50 | end 51 | end 52 | 53 | scope 54 | end 55 | end 56 | 57 | record Header, name : String, sub_headers : Array(String)? = nil do 58 | include JSON::Serializable 59 | include Comparable(Header) 60 | 61 | def <=>(other : self) : Int32? 62 | @name <=> other.name 63 | end 64 | end 65 | 66 | struct Endpoint 67 | include JSON::Serializable 68 | include Comparable(Endpoint) 69 | 70 | getter description : String 71 | getter headers : Array(Header) 72 | getter method : String 73 | 74 | @[JSON::Field(ignore: true)] 75 | getter name : String 76 | getter paginated : Bool 77 | getter parameters : Array(Parameter) 78 | getter path : String 79 | getter scope : String? 80 | getter summary : String 81 | getter version : String 82 | 83 | # ameba:disable Metrics/CyclomaticComplexity 84 | def initialize( 85 | @name : String, 86 | @method : String, 87 | @description : String, 88 | @summary : String, 89 | parameters : Array(Parameter), 90 | @scope : String?, 91 | @headers : Array(Header), 92 | @paginated : Bool, 93 | path_url : String 94 | ) 95 | # Extract the endpoint version and replace with placeholder to allow user to define what version they wish to use 96 | @version = path_url.match(/\/(v\d)\//).not_nil![1] 97 | @path = path_url.sub(/v\d/, "{version}") 98 | 99 | # Prepare the passed parameters, converting types to TS type 100 | # and removing items/schema so it doesn't get serialized 101 | @parameters = parameters.compact_map do |param| 102 | # Remove character/corporation/alliance_id param if they are an authed endpoint 103 | # They will be auto filled in based on the authing character 104 | next if @scope && param.name.in? "character_id", "corporation_id", "alliance_id" 105 | 106 | param_type = if schema = param.schema 107 | type = schema.type 108 | if items = schema.items 109 | type = type == "array" ? items.type + "[]" : items.type 110 | end 111 | type = type.includes?("integer") ? type.sub("integer", "number") : type 112 | elsif item = param.items 113 | type = item.type 114 | if sub_items = item.items 115 | type = sub_items.type 116 | end 117 | (type == "integer" ? "number" : type) + "[]" 118 | else 119 | param.type 120 | end 121 | 122 | param.copy_with(type: param_type == "integer" ? "number" : param_type, schema: nil, items: nil) 123 | end 124 | 125 | # Sort the prams so the required ones are first 126 | @parameters.sort! 127 | end 128 | 129 | def to_function(io : IO) 130 | parameters = @parameters.dup 131 | 132 | # Add in name parameter if this endpoint is authed 133 | parameters << Parameter.new "Name of the character used for auth. Defaults to the first authenticated character.", "parameters", "name", "string" if @scope 134 | 135 | # Add in common params 136 | parameters << Parameter.new "If column headings should be shown.", "parameters", "show_column_headings", "boolean", required: nil, default_value: "true" 137 | parameters << Parameter.new "Which ESI version to use for the request.", "parameters", "version", "string", required: nil, default_value: @version.dump 138 | 139 | io.puts "/**" 140 | io.puts " * #{@description}" 141 | io.puts " *" 142 | parameters.join(io, "") { |param, join_io| param.to_doc_s join_io } 143 | io.puts " * @customfunction" 144 | io.puts " */" 145 | io << "function #{@name}(" 146 | parameters.join(io, ", ") { |param, join_io| param.to_s join_io } 147 | io.puts "): SheetsArray {" 148 | 149 | parameters.each do |p| 150 | p.to_function io 151 | end 152 | 153 | io << " return invoke('#{@name}', { " 154 | 155 | parameters.join(io, ", ") { |param, join_io| param.name.to_s join_io } 156 | 157 | io << " });" 158 | 159 | io.puts "\n}" 160 | end 161 | 162 | def <=>(other : self) : Int32? 163 | @name <=> other.name 164 | end 165 | end 166 | 167 | struct Base 168 | include JSON::Serializable 169 | 170 | getter paths : Hash(String, Method) 171 | 172 | @[JSON::Field(ignore: true)] 173 | getter endpoints : Array(Endpoint) = Array(Endpoint).new 174 | 175 | @[JSON::Field(key: "securityDefinitions")] 176 | @security_definitions : SecurityDefinitions 177 | 178 | @parameters : Hash(String, Parameter) 179 | 180 | def scopes : Array(String) 181 | @security_definitions.evesso.scopes.keys.sort! 182 | end 183 | 184 | def parse : Nil 185 | @paths.each do |path_url, responses| 186 | route = responses.route 187 | 188 | # A non GET/POST route 189 | next if route.nil? 190 | 191 | # A non 200 status route 192 | next unless (success = route.responses.success) 193 | 194 | endpoint_name = route.operation_id.gsub(/^post_|^get_|_id/, "") 195 | 196 | # Rename universes to universe_ids due to regex matching `_ids` 197 | endpoint_name = "universe_ids" if endpoint_name == "universes" 198 | 199 | # Rename status endpoint to not conflict with lib dom function 200 | endpoint_name = "eve_status" if endpoint_name == "status" 201 | 202 | @endpoints << Endpoint.new( 203 | endpoint_name, 204 | responses.method, 205 | route.description, 206 | route.summary, 207 | route.parameters, 208 | route.scope, 209 | self.get_headers(success.schema), 210 | route.paginated?, 211 | path_url 212 | ) 213 | end 214 | end 215 | 216 | def after_initialize 217 | self.parse 218 | @endpoints.sort! 219 | end 220 | 221 | # ameba:disable Metrics/CyclomaticComplexity 222 | private def get_headers(schema : Schema?) 223 | headers = [] of Header 224 | 225 | return headers if schema.nil? 226 | 227 | # Array 228 | if items = schema.items 229 | # of objects 230 | if properties = items.properties 231 | properties.each do |k, v| 232 | # sub array 233 | sub_headers = parse_items(v.items.not_nil!) if v.type == "array" 234 | # sub object 235 | sub_headers = v.properties.not_nil!.keys if v.type == "object" 236 | headers << Header.new(k, sub_headers) 237 | end 238 | else 239 | # of single type 240 | if title = items.title 241 | headers << Header.new(title.includes?('_') ? title.match(/.*_(.*)_200_ok/).not_nil![1].chomp('s') + "_ids" : title + 's') 242 | end 243 | end 244 | # Single object 245 | elsif properties = schema.properties 246 | properties.each do |k, v| 247 | # sub array 248 | sub_headers = parse_items(v.items.not_nil!) if v.type == "array" 249 | # sub object 250 | sub_headers = v.properties.not_nil!.keys if v.type == "object" 251 | headers << Header.new(k, sub_headers) 252 | end 253 | else 254 | if schema.description == "200 ok integer" 255 | title = schema.title.match(/.*_(\w+_\w+)_ok$/).not_nil![1] 256 | title = title.sub("s_", '_') 257 | else 258 | title = schema.description.underscore.sub(' ', '_') 259 | end 260 | headers << Header.new(title) 261 | end 262 | headers.sort! 263 | end 264 | 265 | private def parse_items(item : Item) 266 | item.properties.nil? ? [item.title.not_nil!.match(/.*_(.*_.*)/).not_nil![1] + 's'] : item.properties.not_nil!.keys 267 | end 268 | end 269 | 270 | struct Path 271 | include JSON::Serializable 272 | 273 | @description : String 274 | 275 | @[JSON::Field(converter: EveSwagger::ScopeConverter, key: "security")] 276 | getter scope : String? 277 | 278 | @[JSON::Field(converter: EveSwagger::RefConverter)] 279 | getter parameters : Array(Parameter) 280 | 281 | @[JSON::Field(key: "operationId")] 282 | getter operation_id : String 283 | 284 | getter summary : String 285 | 286 | getter responses : ResponseCode 287 | 288 | getter? paginated : Bool = false 289 | 290 | def description : String 291 | @description.each_line.first 292 | end 293 | 294 | def after_initialize 295 | @paginated = @parameters.any? &.name.==("page") 296 | 297 | # If the path is paginated, remove the page parameter 298 | @parameters.reject! &.name.==("page") if @paginated 299 | end 300 | end 301 | 302 | struct ResponseCode 303 | include JSON::Serializable 304 | 305 | @[JSON::Field(key: "200")] 306 | getter success : Response? 307 | end 308 | 309 | record Response, description : String, schema : Schema? do 310 | include JSON::Serializable 311 | end 312 | 313 | record Method, get : Path?, post : Path? do 314 | include JSON::Serializable 315 | 316 | def route : Path? 317 | @get || @post 318 | end 319 | 320 | def method : String 321 | @get ? "get" : "post" 322 | end 323 | end 324 | 325 | record Parameter, description : String, in : String, name : String, type : String?, items : Item? = nil, schema : Schema? = nil, required : Bool? = false, default_value : String? = nil do 326 | include JSON::Serializable 327 | include Comparable(Parameter) 328 | 329 | @[JSON::Field(ignore: true)] 330 | @default_value : String? 331 | 332 | setter type : String? 333 | setter schema : Schema? 334 | setter items : Item? 335 | 336 | def to_s(io : IO) : Nil 337 | io << @name 338 | 339 | @required.try do |required| 340 | io << '?' unless required 341 | end 342 | 343 | io << ':' << ' ' << self.type_string 344 | 345 | @default_value.try do |default| 346 | io << ' ' << '=' << ' ' 347 | 348 | default.to_s io 349 | end 350 | end 351 | 352 | def type_string : String 353 | return "" unless (type = @type) 354 | 355 | type.ends_with?("[]") ? "#{type[0..-3]}|#{type}" : type 356 | end 357 | 358 | def to_doc_s(io : IO) : Nil 359 | io << " * @param {#{self.type_string}} #{@name} - " 360 | 361 | io.puts @description 362 | end 363 | 364 | def to_function(io : IO) : Nil 365 | io.puts " if (!#{@name}) throw new Error(`#{@name} is required.`);" if @required 366 | end 367 | 368 | def <=>(other : self) : Int32? 369 | @required.try do |required| 370 | return -1 if required 371 | return 1 unless required 372 | end 373 | 374 | 0 375 | end 376 | 377 | def after_initialize : Nil 378 | @required = !!@required 379 | end 380 | end 381 | 382 | record Schema, type : String, items : Item?, properties : Hash(String, Item)?, description : String, title : String do 383 | include JSON::Serializable 384 | end 385 | 386 | class Item 387 | include JSON::Serializable 388 | 389 | getter type : String 390 | getter items : Item? = nil 391 | getter properties : Hash(String, Item)? 392 | getter title : String? 393 | end 394 | 395 | record EVESSO, scopes : Hash(String, String) do 396 | include JSON::Serializable 397 | end 398 | 399 | record SecurityDefinitions, evesso : EVESSO do 400 | include JSON::Serializable 401 | end 402 | end 403 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GESI 2 | 3 | Google Sheets™ add-on for interacting with EVE ESI API. GESI provides an EVE Online SSO flow to authorize your character(s), as well as a wrapper around ESI in order to access your EVE Online data within Google Sheets™; much like `=importXML()` worked with the old XML API. 4 | 5 | ## Setup: 6 | 7 | 1. Install the add-on. From within Google Sheets™: Go to `Add-Ons` => `Get add-ons` => Search for `GESI`, click on it, and click `Install`. 8 | 1. Give the script access to what it needs. 9 | 1. There will now be a GESI option under the `Add-Ons` option in the menu bar. Click it and then click `GESI => Authorize Character`. 10 | 1. Click the EVE SSO button in the modal. Login => select what character you want to authorize => Authorize. 11 | 1. (Optional) Repeat step 4 to authorize other characters. 12 | 1. Done. 13 | 14 | ### Script Editor 15 | 16 | By default, one does not have access to GESI functions for use in custom functions in the script editor. In order to gain access to these functions for custom logic, add GESI as a library to your script: 17 | 18 | 1. Install the add-on, follow the [setup instructions](#setup). 19 | 1. Within the script editor, click the `+` icon next to the `Libraries` heading. 20 | 1. Paste in `1KjnRVVFr2KiHH55sqBfHcZ-yXweJ7iv89V99ubaLy4A7B_YH8rB5u0s3` into the `Script ID` box and click `Look up`. 21 | 1. Select the most recent version that is _NOT_ `HEAD`, and click `Add`. 22 | 23 | In order to use this, functions must be perpended with `GESI`, which maps to the `Identifier` field in the Libraries modal. For example, `GESI.universe_types();` 24 | 25 | **NOTE:** Libraries _do not_ update on their own. When a new version of GESI is released, click on `GESI` under the `Libraries` heading and select the most recent version that is _NOT_ `HEAD`. 26 | 27 | ## Usage 28 | 29 | GESI works by defining custom functions that map to ESI routes. For example, if you wanted to get a list of your assets, you would use [this](https://esi.evetech.net/ui/#/Assets/get_characters_character_id_assets) endpoint; `GET https://esi.evetech.net/v5/characters/{character_id}/assets/`. In GESI, this would be `=characters_character_assets()` within the sheet. 30 | 31 | Arguments can also be passed to the functions, `=universe_types_type(34)`, would return type information for `Tritanium`. In addition to arguments specific to a function, GESI also defines some arguments that are common between all functions. 32 | 33 | * `{string} name` - Name of the character used for authentication. Defaults to the first authenticated character 34 | * Only present on functions that map to authenticated endpoints 35 | * See [this](#how-do-i-get-data-from-a-specific-character) for some additional information 36 | * `{boolean} show_column_headings` - If column headings should be shown. Defaults to `true`. 37 | * Mostly for use within the sheet. Determines if the column headings are displayed, such as `location_id`, or `type_id`, etc. 38 | * `{string} version` - Which ESI version to use for the request. Defaults to the latest stable version. 39 | * See [this](#what-if-i-want-to-use-a-specific-esi-route-version) for some additional information 40 | 41 | The common arguments have defaults, you do not need to provide them if your values are the same as the defaults. I.e. `=characters_character_assets("MyMainCharacter", true, "latest")` is the same as `=characters_character_assets()`. 42 | 43 | ### Using The Autocomplete/Tooltip Window 44 | 45 | Google Sheets includes autocomplete for all custom functions, from both within the sheet and script editor. This is a super helpful tool for getting an idea of what each function does. 46 | 47 | ![image-20200507125913620](https://i.imgur.com/tPuD4i8.png) 48 | 49 | Each specific function also has a tooltip window that provides a summary of a function, what arguments it takes, etc. 50 | 51 | ![image-20200507125913620](https://i.imgur.com/9e5c6JW.png) 52 | 53 | The `EXAMPLE` section includes a sample function call, with the expected types included. See [this](#what-do-the-function-parameter-types-mean) for a breakdown of what those types mean. 54 | 55 | > **NOTE:** If the tooltip window is missing, you may need to expand it by clicking the little arrow next to the `X`. 56 | 57 | ## Advanced Usage 58 | 59 | The previous section goes over how to use GESI in its most basic form, getting data from ESI into a spreadsheet; much like `=importXML()` worked with the old XML API. However, GESI can also be used within Google App Scripts to enable creation of more advanced/complex logic via JavaScript. 60 | 61 | > **NOTE:** Be sure to complete the [script editor](#script-editor) setup instructions. 62 | 63 | ### Built-In Functions 64 | 65 | In addition to the ESI related functions, GESI also provides some methods intended to be used within the script editor. 66 | 67 | * `invokeMultiple()`/`invokeMultipleRaw()` - See [this section](#using-functions-with-multiple-characters) for details. 68 | * `getAuthenticatedCharacters()` - Returns an object representing the characters that have been authenticated. Keyed by character name, value being an object including their character, corporation, and alliance ids. 69 | * `getAuthenticatedCharacterNames()` - Returns an array of character names that have authenticated, or null if none have been. 70 | * `getCharacterData(characterName: string)` - Returns an object with data related to the given *characterName*. Essentially is equivalent to ``getAuthenticatedCharacters()[characterName]`. 71 | * `invoke(functionName: string, params: IFunctionParams = { show_column_headings: true })` - Invokes the *functionName* with the given *params*. Returns sheet formatted data (2D array). E.x. `invoke("universe_types_type", { type_id: 34 })`. Essentially the same as `universe_types_type(34)` but allows calling functions based on JS variables. 72 | * `invokeRaw(functionName: string, params = { show_column_headings: false } as IFunctionParams)` - Same as `invoke`, but returns the raw JSON data from the ESI request. 73 | * `getClient(characterName?: string)` - Returns an `ESIClient` for the given *characterName*. Defaults to the main character if no character name is provided. See the next section for details. 74 | 75 | ### ESIClient 76 | 77 | Internally, each function call results in the creation of an `ESIClient` for a specific character. The client is used to build and execute the request, parse the response, and format the data to return to the sheet. The creation of a client has some overhead (~0.3s) when created. While this normally does not have any noticeable impact when invoking a single request for a single character; it can become a problem when wanting to do a series of requests based for the same character/endpoint. An example of this could be fetching price history data for a list of `type_ids`. 78 | 79 | Normally one would call `markets_region_history(type_id, region_id)` in a loop, adding results to some other array for processing later. The problem with this is that each invocation of `markets_region_history` would result in the creation of a new `ESIClient`. Fetching 100 ids would take a minimum of 30 seconds (0.3 * 100), when the total time of making those requests is less than 1 second. 80 | 81 | The `ESIClient` can be used by advanced users who are developing advanced/complex sheets in order to increase performance. It can also be used by those who are building on top of GESI, using GESI more as a way to handle authentication while implementing the ESI interactions on their own. 82 | 83 | `getClient` accepts an optional character name argument. This is the character who the client will be tied to, i.e. who the ESI requests will be made on behalf of. If no character name is given, it defaults to the main character. Before the client can be used, it must be initialized with a function name. For example: 84 | 85 | ```js 86 | var client = GESI.getClient().setFunction('characters_character_assets'); 87 | ``` 88 | 89 | Any future calls to the client will be in the context of this function. 90 | 91 | #### execute / executeRaw 92 | 93 | These methods are essentially the same as `invoke` and `invokeRaw` mentioned within the [Built-In Functions](#built-in-functions) section. However, the API is slightly different. Since they are methods of the `ESIClient`, only the params need to be provided, since the function name is set directly on the client. 94 | 95 | ```js 96 | var client = GESI.getClient().setFunction('universe_types_type'); 97 | var type_data = client.executeRaw({ type_id: 34 }); 98 | ``` 99 | 100 | #### buildRequest 101 | 102 | The `ESIClient` also exposes a method that can be used to build a request object given a set of parameters. The most common use case for this would be to build out an array of requests before executing them manually via [UrlFetchApp.fetchAll](https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetchAll(Object)). This way, the user is able to have full control over the ESI data, while not having to worry about authentication, etc. 103 | 104 | > **NOTE:** There is no validation of arguments before executing the requests. Be sure to provide all required arguments, of the correct types etc. 105 | 106 | ```js 107 | var client = GESI.getClient().setFunction('markets_region_history'); 108 | 109 | var type_ids = [34, 35, 36]; 110 | var requests = type_ids.map(function(type_id) { return client.buildRequest({ type_id: type_id, region_id: 10000002 }); }); 111 | 112 | var responses = UrlFetchApp.fetchAll(requests); 113 | 114 | // Process the responses 115 | ``` 116 | 117 | ## FAQ 118 | 119 | ### How do I know if I have the latest version of GESI? 120 | 121 | GESI will automatically update when a new version is released. To see what changed visit the [forum thread](https://forums.eveonline.com/t/6-5-0-gesi-google-sheets-esi-library-now-with-some-post-endpoints/13406) or the [Github Releases](https://github.com/Blacksmoke16/GESI/releases) page. 122 | 123 | > **NOTE: Changes in the ESI spec, such as adding/removing columns, name changes etc. may break your sheet.** 124 | 125 | ### How do I know what functions are available? 126 | 127 | Check out [functions.ts](https://github.com/Blacksmoke16/GESI/blob/master/src/script/src/functions.ts). This file lists all the available functions, as well as a description of what they return and the available parameters. 128 | 129 | ### What if I want to use a specific ESI route version? 130 | 131 | By default GESI uses the version currently on the `latest` label. If you wish to use a different version, use the `version` parameter. `=characters_character_wallet_journal("Blacksmoke16", true, "v10")`. The version can either be a specific version like `"v4"` or a label: `"dev"`, `"legacy"`, or `"latest"`. 132 | 133 | ### The `Authorize Character` option in the add-on menu is missing? 134 | 135 | This happens when `GESI` is not authorized to run in the current document. This can be solved by: 136 | 137 | 1. Go to `Add-Ons => Manage add-ons` 138 | 2. Click on the three dots towards the top right of the GESI block 139 | 3. Make sure `Use in this document` is checked 140 | 4. Refresh the sheet and should be good 141 | 142 | ### How do I get data from a specific character? 143 | 144 | Each authenticated endpoint that has a `name` property that can be used to specify which character's token should be used in that request. 145 | 146 | The first character that you authenticate gets set as your main character which will be used if you do not provide a value for the `name` argument for an authenticated endpoint. 147 | 148 | For example `=characters_character_assets()` would get the assets for the first character that you authenticated, i.e. your `MAIN_CHARACTER`. `=characters_character_assets("My Other Character")` would get assets for `My Other Character`. The `getMainCharacter()` function can be used to get the name of the current main character. The main character can be updated via `Add-Ons` => `GESI` => `Set Main Character`. 149 | 150 | ### What do the function parameter types mean? 151 | 152 | | Type | Sample | 153 | | ------- | ---------------------------------- | 154 | | boolean | `true` or `false` | 155 | | number | `12` | 156 | | string | `"foo"` Notice the _double_ quotes | 157 | 158 | Array types are denoted with a `[]` following the data type of the parameter. An example of an array type could be `number[]` where a value for that would be `A1:A10` where this range is a column of numbers. 159 | 160 | ### Why does this cell contain all this random data? 161 | 162 | As of now if an endpoint returns a property that is an array of objects nested inside the response, I am JSON stringifying it and displaying it in the column. The `parseArray` allows you to parse that array of values and output it like an endpoint function does, wherever you want to. You supply it with the name of the function the data is from, the column you are parsing, and the cell with the array data. 163 | 164 | An example of this would be `parseArray("characters_character_skills", "skills", B2)` where `B2` is the cell that contains the data. 165 | 166 | ### How can I limit what scopes are used? 167 | 168 | There is not built-in way to do this currently, however it is possible. 169 | 170 | 1. Open the `Authorize Characters` modal 171 | 2. Right click on the SSO button and click `Copy link address` 172 | 3. Paste this link into notepad or some text editor 173 | 4. Within the URL there is query param like `&scopes=`, which is set to a list of all ESI scopes separated by `+` signs 174 | 5. Remove all the scopes that you do not want, or add ones that are not added by default 175 | 6. Copy the URL and paste it into your browser 176 | 7. Follow SSO flow as normal 177 | 8. Characters authed using this modified URL will not be able to use any function that requires a scope that was not requested. 178 | 9. Repeat for additional characters if desired 179 | 180 | ### Using functions with multiple characters 181 | 182 | A common use case is wanting to get the same data from multiple characters. For example, getting the industry jobs of multiple characters into a nice, easy to manage format. This can be achieved by using the `invokeMultiple` method. `=invokeMultiple("characters_character_assets", characterNames)`. *characterNames* can either be a comma separated string like `"Character1,Character2"`, a vertical range like `A1:A10`, or the result of `getAuthenticatedCharacterNames()`, or some other array of strings. 183 | 184 | This method can be used directly in the sheet. However, if it requires arguments, then it should be wrapped in a custom function: 185 | 186 | ```js 187 | function getJobs() { 188 | return GESI.invokeMultiple("characters_character_industry_jobs", GESI.getAuthenticatedCharacterNames(), { include_completed: true }) 189 | } 190 | ``` 191 | 192 | `invokeMultipleRaw` is also available. It works the same as `invokeMultiple`, but returns an array of raw JSON data for the provided *characterNames* instead sheets formatted data (2D array). 193 | 194 | ### Working with the raw ESI data 195 | 196 | Google Sheets uses 2D arrays to represent data within a sheet. When working on custom functions or scripts, this format is less than ideal to work with. the `invokeRaw(functionName, params)` function can be used to return the raw ESI JSON data for a given endpoint. The function accepts a name of a function, and an optional object that includes any arguments that should be used. Examples: 197 | 198 | * `invokeRaw("universe_types")` 199 | * `invokeRaw("universe_types_type", { type_id: 34 })` 200 | 201 | This method is meant to be used within custom functions and scripts. 202 | 203 | See the [advanced usage](#advanced-usage) section for more details on working within the script editor. 204 | 205 | ### Your Login session has expired 206 | 207 | See [this issue](https://github.com/esi/esi-issues/issues/519#issuecomment-323892188). 208 | 209 | ### How do I know my EVE data isn't being misused? 210 | 211 | In order to provide GESI, developers have to agree to the [EVE Developer License Agreement](https://developers.eveonline.com/resource/license-agreement). Section 2.3 explicitly prohibits it. 212 | 213 | ## Contact Info 214 | 215 | In-game: Blacksmoke16 216 | 217 | Discord: Blacksmoke16#0016 218 | 219 | Discord Server: https://discordapp.com/invite/eEAH2et 220 | 221 | ## Copyright 222 | 223 | EVE Online and the EVE logo are the registered trademarks of CCP hf. All rights are reserved worldwide. All other 224 | trademarks are the property of their respective owners. EVE Online, the EVE logo, EVE and all associated logos and designs are the intellectual property of CCP hf. All artwork, screenshots, characters, vehicles, storylines, world facts or other recognizable features of the intellectual property relating to these trademarks are likewise the intellectual property of CCP hf. CCP hf. has granted permission to GESI to use EVE Online and all associated logos and designs for promotional and information purposes on its website but does not endorse, and is not in any way affiliated with, the GESI. CCP is in no way responsible for the content on or functioning of this website, nor can it be liable for any damage arising from the use of this website. 225 | 226 | ## Privacy Policy 227 | 228 | GESI only requires access to spreadsheets it is enabled on in order to operate. 229 | GESI uses the spreadsheet's ID for error logging, and the current user's temporary anonymous key for analytics. 230 | GESI does not store, use, share, or access any other data related to your Google account. 231 | -------------------------------------------------------------------------------- /src/script/src/gesi.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @OnlyCurrentDoc 3 | * Google ESI (GESI) 4 | * /u/blacksmoke16 @ Reddit 5 | * @Blacksmoke16#0016 @ Discord 6 | * https://discord.gg/eEAH2et 7 | */ 8 | import AppsScriptHttpRequestEvent = GoogleAppsScript.Events.AppsScriptHttpRequestEvent; 9 | import HtmlOutput = GoogleAppsScript.HTML.HtmlOutput; 10 | import Properties = GoogleAppsScript.Properties.Properties; 11 | import OAuth2Service = GoogleAppsScriptOAuth2.OAuth2Service; 12 | import HttpMethod = GoogleAppsScript.URL_Fetch.HttpMethod; 13 | import { getEndpoints, getScopes } from './endpoints'; 14 | import { ESIClient } from './esi_client'; 15 | import { TokenStorage } from './token_storage'; 16 | 17 | function getScriptProperties_(): Properties { 18 | return PropertiesService.getScriptProperties(); 19 | } 20 | 21 | function getDocumentProperties_(): Properties { 22 | return PropertiesService.getDocumentProperties(); 23 | } 24 | 25 | function getDocumentCache_(): GoogleAppsScript.Cache.Cache { 26 | const cache = CacheService.getDocumentCache(); 27 | 28 | if (!cache) { 29 | throw new Error('BUG: Null cache'); 30 | } 31 | 32 | return cache; 33 | } 34 | 35 | // region UI 36 | 37 | // @ts-ignore 38 | function onInstall(): void { 39 | onOpen(); 40 | } 41 | 42 | // @ts-ignore 43 | function onOpen(): void { 44 | SpreadsheetApp 45 | .getUi() 46 | .createAddonMenu() 47 | .addItem('Authorize Character', 'showSSOModal') 48 | .addItem('Deauthorize Character', 'deauthorizeCharacter') 49 | .addItem('Set Main Character', 'setMainCharacter') 50 | .addItem('Reset', 'reset') 51 | .addToUi(); 52 | } 53 | 54 | // @ts-ignore 55 | function showSSOModal(): void { 56 | const template = HtmlService.createTemplateFromFile('authorize'); 57 | template.authorizationUrl = getOAuthService_(Utilities.getUuid()).getAuthorizationUrl(); 58 | SpreadsheetApp.getUi().showModalDialog(template.evaluate().setWidth(400).setHeight(250), 'GESI EVE SSO'); 59 | } 60 | 61 | // @ts-ignore 62 | function deauthorizeCharacter(): void { 63 | const ui = SpreadsheetApp.getUi(); 64 | const response = ui.prompt('Deauthorize Character', 'Enter the name of the character you wish to deauthorize.', ui.ButtonSet.OK_CANCEL); 65 | 66 | if (response.getSelectedButton() !== ui.Button.OK) return; 67 | 68 | const character = getCharacterData(response.getResponseText()); 69 | 70 | getClient(character.name).reset(); 71 | 72 | ui.alert(`Successfully deauthorized ${character.name}.`); 73 | } 74 | 75 | // @ts-ignore 76 | function setMainCharacter() { 77 | const ui = SpreadsheetApp.getUi(); 78 | const response = ui.prompt('Set Main Character', 'Enter the name of the character you wish to use as your main.', ui.ButtonSet.OK_CANCEL); 79 | 80 | if (response.getSelectedButton() !== ui.Button.OK) return; 81 | 82 | const character = getCharacterData(response.getResponseText()); 83 | 84 | setMainCharacter_(character.name); 85 | 86 | ui.alert(`${character.name} is now your main character.`); 87 | } 88 | 89 | // @ts-ignore 90 | function reset() { 91 | const ui = SpreadsheetApp.getUi(); 92 | 93 | const response = ui.alert('Reset?', 'Are you sure you want to reset the authentication data of ALL characters on this sheet, including those added by other users?', ui.ButtonSet.YES_NO); 94 | 95 | if (response !== ui.Button.YES) { return; } 96 | 97 | const authenticatedCharacters = getAuthenticatedCharacters(); 98 | const numChars = Object.keys(authenticatedCharacters).length; 99 | 100 | if (0 === numChars) { 101 | ui.alert('There are no characters authenticated.'); 102 | return; 103 | } 104 | 105 | const reallySure = ui.prompt('Verify full reset', `Continuing will result in ${numChars} character(s) being wiped. To confirm, enter the number of characters that will be reset:`, ui.ButtonSet.OK_CANCEL); 106 | 107 | if (reallySure.getSelectedButton() !== ui.Button.OK) return; 108 | 109 | if (reallySure.getResponseText() !== numChars.toString()) { ui.alert('Incorrect response received. RESET aborted.'); return; } 110 | 111 | Object.keys(authenticatedCharacters).forEach((characterName: string) => { 112 | getClient(characterName).reset(); 113 | }); 114 | 115 | getDocumentProperties_().deleteAllProperties(); 116 | ui.alert('Reset performed successfully'); 117 | } 118 | 119 | // endregion 120 | 121 | /** 122 | * Parses array data into more readable format 123 | * 124 | * @param {string} endpointName (Required) Name of the endpoint data to be parsed is from. 125 | * @param {string} columnName (Required) Name of the column to be parsed. 126 | * @param {string} data (Required) Cell that holds the data to be parsed. 127 | * @param {boolean} show_column_headers Default: True, Boolean if column headings should be listed or not. 128 | * @return Parsed array data. 129 | * @customfunction 130 | */ 131 | function parseArray(endpointName: string, columnName: string, data: string, show_column_headers: boolean = true): SheetsArray { 132 | let result: SheetsArray = []; 133 | const endpoint_header: IHeader = getEndpoints()[endpointName].headers.find((eh: IHeader) => eh.name === columnName)!; 134 | if (show_column_headers) result.push(endpoint_header ? endpoint_header.sub_headers! : [columnName.slice(0, -1) + '_id']); 135 | 136 | // Kinda a hack but it works for now :shrug: 137 | if (!endpoint_header || !endpoint_header.hasOwnProperty('sub_headers')) { 138 | JSON.parse(data).forEach((o: any) => result.push([o])); 139 | } else { 140 | JSON.parse(data).forEach((o: any) => { 141 | result.push( 142 | endpoint_header.sub_headers!.map((k: string) => { 143 | return Array.isArray(o[k]) ? JSON.stringify(o[k]) : o[k]; 144 | }), 145 | ); 146 | }); 147 | } 148 | 149 | return result; 150 | } 151 | 152 | /** 153 | * @return The character that will be used by default for authenticated endpoints. 154 | * @customfunction 155 | */ 156 | function getMainCharacter(): string | null { 157 | return getDocumentProperties_().getProperty('MAIN_CHARACTER'); 158 | } 159 | 160 | /** 161 | * @return {ICharacterMap} An object representing the characters that have been authenticated 162 | * @customfunction 163 | */ 164 | function getAuthenticatedCharacters(): ICharacterMap { 165 | const properties = getDocumentProperties_().getProperties(); 166 | const characterMap: ICharacterMap = {}; 167 | 168 | Object.keys(properties).forEach((key: string) => { 169 | if (key.startsWith('character.')) { 170 | characterMap[key.replace('character.', '')] = JSON.parse(properties[key]); 171 | } 172 | }); 173 | 174 | return characterMap; 175 | } 176 | 177 | /** 178 | * @return {string[] | null} An array of character names that have authenticated, or null if none have been. 179 | * @customfunction 180 | */ 181 | function getAuthenticatedCharacterNames(): string[] | null { 182 | const characters = Object.keys(getAuthenticatedCharacters()); 183 | return characters.length === 0 ? null : characters; 184 | } 185 | 186 | /** 187 | * @param {string} characterName The name of the character 188 | * @return {IAuthenticatedCharacter} A metadata object for this character 189 | * @customfunction 190 | */ 191 | function getCharacterData(characterName: string | null): IAuthenticatedCharacter { 192 | const characterMap = getAuthenticatedCharacters(); 193 | if (!characterName) throw new Error('No characters have been authenticated. Visit Add-ons => GEST => Authorize Character to do so.'); 194 | if (!characterMap.hasOwnProperty(characterName)) throw new Error(`${characterName} is not authed, or is misspelled.`); 195 | return characterMap[characterName]; 196 | } 197 | 198 | /** 199 | * Return the sheets formatted data related for the given functionName. 200 | * 201 | * @param {string} functionName The name of the endpoint that should be invoked 202 | * @param {object} params Any extra parameters that should be included in the ESI call 203 | * @return The data from the provided functionName 204 | * @customfunction 205 | */ 206 | function invoke(functionName: string, params: IFunctionParams = { show_column_headings: true }): SheetsArray { 207 | return getClient(params.name).setFunction(functionName).execute(params); 208 | } 209 | 210 | /** 211 | * Return the raw JSON data related to an ESI call 212 | * 213 | * @param {string} functionName The name of the endpoint that should be invoked 214 | * @param {object} params Any extra parameters that should be included in the ESI call 215 | * @return The raw JSON response from the provided functionName 216 | * @customfunction 217 | */ 218 | function invokeRaw(functionName: string, params: IFunctionParams = { show_column_headings: false } as IFunctionParams): any { 219 | return getClient(params.name).setFunction(functionName).executeRaw(params); 220 | } 221 | 222 | /** 223 | * Returns an ESIClient for the given characterName. 224 | * Can be used by advanced users for custom functions/scripts. 225 | * 226 | * @param characterName 227 | * @return {ESIClient} 228 | * @customfunction 229 | */ 230 | function getClient(characterName?: string): ESIClient { 231 | if (characterName !== undefined && typeof characterName !== 'string') { 232 | throw new Error(`Expected optional argument name to be a string, but got ${typeof characterName}.`); 233 | } 234 | 235 | const characterData = getCharacterData(characterName || getMainCharacter()); 236 | const oauthService = getOAuthService_(characterData.id); 237 | return new ESIClient(oauthService, characterData, getDocumentProperties_()); 238 | } 239 | 240 | /** 241 | * Returns the data from the provided functionName for each character as one list for use within a sheet. 242 | * 243 | * @param {string} functionName The name of the endpoint that should be invoked 244 | * @param {string | string[]} characterNames A single, comma separated, or vertical range of character names 245 | * @param {object} params Any extra parameters that should be included in the ESI call 246 | * @return 247 | * @customfunction 248 | */ 249 | function invokeMultiple(functionName: string, characterNames: string | string[] | string[][], params: IFunctionParams = { show_column_headings: true }): SheetsArray { 250 | const normalizedNames = normalizeNames_(characterNames); 251 | const firstCharacter = normalizedNames.shift(); 252 | 253 | const result = invoke(functionName, { ...params, name: firstCharacter }); 254 | 255 | if (params.show_column_headings) { 256 | const headers = result[0]; 257 | headers.push('character_name'); 258 | } 259 | 260 | result.forEach((item: any, idx: number) => { 261 | if (idx > 0 || !params.show_column_headings) item.push(firstCharacter); 262 | }); 263 | 264 | normalizedNames.forEach((name: string) => { 265 | const subResults = invoke(functionName, { ...params, name, show_column_headings: false }); 266 | 267 | subResults.forEach((item: any) => { 268 | item.push(name); 269 | result.push(item); 270 | }); 271 | }); 272 | 273 | return result; 274 | } 275 | 276 | /** 277 | * Returns the data from the provided functionName for each character as one list for use within custom functions/scripts. 278 | * 279 | * @param {string} functionName The name of the endpoint that should be invoked 280 | * @param {string | string[]} characterNames A single, comma separated, or vertical range of character names 281 | * @param {object} params Any extra parameters that should be included in the ESI call 282 | * @return 283 | * @customfunction 284 | */ 285 | function invokeMultipleRaw(functionName: string, characterNames: string | string[] | string[][], params: IFunctionParams = { show_column_headings: false }): SheetsArray { 286 | const normalizedNames = normalizeNames_(characterNames); 287 | const firstCharacter = normalizedNames.shift(); 288 | 289 | const result = normalizeResult_(invokeRaw(functionName, { ...params, name: firstCharacter })); 290 | 291 | result.forEach((item: any) => { 292 | item.character_name = firstCharacter; 293 | }); 294 | 295 | normalizedNames.forEach((name: string) => { 296 | const subResults = normalizeResult_(invokeRaw(functionName, { ...params, name: name })); 297 | 298 | subResults.forEach((item: any) => { 299 | item.character_name = name; 300 | result.push(item); 301 | }); 302 | }); 303 | 304 | return result; 305 | } 306 | 307 | // region oauth 308 | 309 | // @ts-ignore 310 | function authCallback(request: AppsScriptHttpRequestEvent): HtmlOutput { 311 | const id: string = request.parameter.serviceName; 312 | 313 | // Fetch the oauthService used for this flow 314 | const oauthService = getOAuthService_(id); 315 | 316 | // Complete the OAuth flow 317 | oauthService.handleCallback(request); 318 | 319 | // Parse the JWT access token for some basic information about this character 320 | const jwtToken = ESIClient.parseToken(oauthService.getAccessToken()); 321 | const characterId = parseInt(jwtToken.sub.split(':')[2]); 322 | 323 | // Fetch additional data about this character 324 | const affiliationData = getCharacterAffiliation_(characterId, oauthService); 325 | 326 | // If this character was previously authorized 327 | // update the ID of this character and reset the old service 328 | const characterData: string | null = getDocumentProperties_().getProperty(`character.${jwtToken.name}`); 329 | 330 | // If this character is already in the map, 331 | // Reset previous oauthService and delete character data 332 | if (characterData) { 333 | getClient(jwtToken.name).reset() 334 | } 335 | 336 | setCharacterData_(jwtToken.name, { 337 | id, 338 | alliance_id: affiliationData.alliance_id || null, 339 | character_id: affiliationData.character_id, 340 | corporation_id: affiliationData.corporation_id, 341 | name: jwtToken.name, 342 | }); 343 | 344 | // Set the main character if there is not one already 345 | if (!getMainCharacter()) setMainCharacter_(jwtToken.name); 346 | 347 | return HtmlService.createHtmlOutput(`Thank you for using GESI ${jwtToken.name}! You may close this tab.`); 348 | } 349 | 350 | // @ts-ignore 351 | function getCharacterAffiliation_(characterId: number, oauthClient: OAuth2Service): ICharacterAffiliation { 352 | return (new ESIClient(oauthClient, {} as IAuthenticatedCharacter, getDocumentProperties_())).setFunction('characters_affiliation').executeRaw({ characters: [[characterId]], show_column_headings: false })[0]; 353 | } 354 | 355 | // @ts-ignore 356 | function getOAuthService_(id: string): OAuth2Service { 357 | return OAuth2.createService(id) 358 | .setAuthorizationBaseUrl(getScriptProperties_().getProperty('AUTHORIZE_URL')!) 359 | .setTokenUrl(getScriptProperties_().getProperty('TOKEN_URL')!) 360 | .setClientId(getScriptProperties_().getProperty('CLIENT_ID')!) 361 | .setClientSecret(getScriptProperties_().getProperty('CLIENT_SECRET')!) 362 | .setCallbackFunction('authCallback') 363 | .setParam('access_type', 'offline') 364 | .setParam('prompt', 'consent') 365 | .setScope(getScopes()) 366 | .setPropertyStore( 367 | new TokenStorage(getDocumentProperties_(), getDocumentCache_()) 368 | ); 369 | } 370 | 371 | // endregion 372 | 373 | // @ts-ignore 374 | function setCharacterData_(characterName: string, characterData: IAuthenticatedCharacter): void { 375 | getDocumentProperties_().setProperty(`character.${characterName}`, JSON.stringify(characterData)); 376 | } 377 | 378 | // @ts-ignore 379 | function setMainCharacter_(characterName: string): void { 380 | getDocumentProperties_().setProperty('MAIN_CHARACTER', characterName); 381 | } 382 | 383 | // @ts-ignore 384 | function normalizeResult_(result: any): any[] { 385 | return Array.isArray(result) ? result : [result]; 386 | } 387 | 388 | // @ts-ignore 389 | function normalizeNames_(characterNames: string | string[] | string[][]): string[] { 390 | let normalizedNames: string[]; 391 | 392 | if (Array.isArray(characterNames)) { 393 | // @ts-ignore 394 | normalizedNames = Array.isArray(characterNames[0]) ? characterNames.map((row: any) => row[0]) : characterNames; 395 | } else { 396 | normalizedNames = characterNames.split(','); 397 | } 398 | 399 | if (!normalizedNames || normalizedNames.length === 0) { 400 | throw new Error('characterNames must not be empty.'); 401 | } 402 | 403 | return normalizedNames.map(name => name.trim()); 404 | } 405 | 406 | interface IHeader { 407 | readonly name: string; 408 | readonly sub_headers?: string[]; 409 | } 410 | 411 | type ParameterType = 'path' | 'parameters' | 'body' | 'query'; 412 | 413 | interface IParameter { 414 | readonly description: string; 415 | readonly in: ParameterType; 416 | readonly name: string; 417 | readonly type: string; 418 | readonly required: boolean; 419 | } 420 | 421 | interface IEndpoint { 422 | /** @description Long description of the endpoint */ 423 | readonly description: string; 424 | 425 | /** @description The column headers that endpoint returns. Are ordered alphabetically */ 426 | readonly headers: IHeader[]; 427 | 428 | /** @description The HTTP method this endpoint uses */ 429 | readonly method: HttpMethod; 430 | 431 | /** @description Whether this endpoint is paginated */ 432 | readonly paginated: boolean; 433 | 434 | /** @description The parameters this endpoint accepts */ 435 | readonly parameters: IParameter[]; 436 | 437 | /** @description The path, including parameters, of this endpoint */ 438 | readonly path: string; 439 | 440 | /** @description An optional required scope if this endpoint is authenticated */ 441 | readonly scope?: string; 442 | 443 | /** @description Short description of the endpoint */ 444 | readonly summary: string; 445 | 446 | /** @description The default version of this endpoint */ 447 | readonly version: string; 448 | } 449 | 450 | interface IEndpointList { 451 | [key: string]: IEndpoint; 452 | } 453 | 454 | interface IFunctionParams { 455 | show_column_headings: boolean; 456 | version?: string; 457 | name?: string; 458 | page?: number; 459 | 460 | [param: string]: any; 461 | } 462 | 463 | interface ICharacterData { 464 | readonly alliance_id: number | null; 465 | readonly character_id: number; 466 | readonly corporation_id: number; 467 | } 468 | 469 | interface IAuthenticatedCharacter extends ICharacterData { 470 | readonly id: string; 471 | readonly name: string; 472 | } 473 | 474 | interface ICharacterMap { 475 | [characterName: string]: IAuthenticatedCharacter; 476 | } 477 | 478 | type SheetsArray = any[][] 479 | 480 | interface IToken { 481 | readonly token_type: string; 482 | readonly refresh_token: string; 483 | readonly granted_time: number; 484 | readonly expires_in: number; 485 | readonly access_token: string | null; 486 | } 487 | 488 | interface IAccessTokenData { 489 | readonly azp: string; 490 | readonly aud: string[]; 491 | readonly exp: number; 492 | readonly iss: string; 493 | readonly name: string; 494 | readonly owner: string; 495 | readonly sub: string; 496 | } 497 | 498 | interface ICharacterAffiliation { 499 | readonly alliance_id?: number; 500 | readonly character_id: number; 501 | readonly corporation_id: number; 502 | readonly faction_id?: number; 503 | } 504 | 505 | export { IAuthenticatedCharacter, IFunctionParams, SheetsArray, IToken, IHeader, IEndpoint, IAccessTokenData, IParameter, IEndpointList, parseArray, getScriptProperties_, getClient, invoke, invokeRaw, invokeMultiple, invokeMultipleRaw, getAuthenticatedCharacters, getAuthenticatedCharacterNames } 506 | -------------------------------------------------------------------------------- /src/script/spec/esi_client.spec.ts: -------------------------------------------------------------------------------- 1 | import { createMock } from 'ts-auto-mock'; 2 | import { ESIClient, IEndpointProvider } from '../src/esi_client'; 3 | import { IAuthenticatedCharacter, IEndpoint, IFunctionParams, IParameter } from '../src/gesi'; 4 | import OAuth2Service = GoogleAppsScriptOAuth2.OAuth2Service; 5 | import HTTPResponse = GoogleAppsScript.URL_Fetch.HTTPResponse; 6 | import Properties = GoogleAppsScript.Properties.Properties; 7 | import URLFetchRequest = GoogleAppsScript.URL_Fetch.URLFetchRequest; 8 | 9 | describe('EsiClient', () => { 10 | let esiClient: ESIClient; 11 | 12 | let oauthServiceMock: OAuth2Service; 13 | let mockCharacterData: IAuthenticatedCharacter; 14 | let documentProperties: Properties; 15 | let endpointProvider: IEndpointProvider; 16 | 17 | let endpoint: IEndpoint; 18 | let responses: HTTPResponse[]; 19 | 20 | beforeEach(() => { 21 | oauthServiceMock = createMock(); 22 | mockCharacterData = createMock({ 23 | name: 'Blacksmoke16', 24 | character_id: 2047918291, 25 | corporation_id: 98019139, 26 | alliance_id: 1900696668, 27 | }); 28 | documentProperties = createMock(); 29 | 30 | esiClient = new ESIClient( 31 | oauthServiceMock, 32 | mockCharacterData, 33 | documentProperties, 34 | endpointProvider = { 35 | hasEndpoint(_name: string): boolean { 36 | return true; 37 | }, 38 | getEndpoint(_name: string): IEndpoint { 39 | return endpoint; 40 | }, 41 | }, 42 | { 43 | fetchAll(_requests: URLFetchRequest[]): HTTPResponse[] { 44 | return responses; 45 | }, 46 | }, 47 | ); 48 | }); 49 | 50 | describe('.addQueryParam', () => { 51 | it('without any existing params', () => { 52 | expect(ESIClient.addQueryParam('/path/', 'name', 'foo')).toBe('/path/?name=foo'); 53 | }); 54 | 55 | it('with existing param', () => { 56 | expect(ESIClient.addQueryParam('/path/?name=foo', 'name', 'bar')).toBe('/path/?name=foo&name=bar'); 57 | }); 58 | 59 | it('with an array value', () => { 60 | expect(ESIClient.addQueryParam('/path/', 'name', ['foo', 'bar'])).toBe('/path/?name=foo,bar'); 61 | }); 62 | }); 63 | 64 | describe('.parseToken', () => { 65 | beforeEach(() => { 66 | global.PropertiesService.getScriptProperties = jest.fn().mockReturnValueOnce( 67 | createMock({ 68 | getProperty(): string { 69 | return 'CLIENT_ID'; 70 | }, 71 | }), 72 | ); 73 | }); 74 | 75 | it('with valid token', () => { 76 | global.Utilities.newBlob = jest.fn().mockReturnValueOnce( 77 | createMock({ 78 | getDataAsString(): string { 79 | return '{"aud": ["CLIENT_ID", "EVE Online"], "azp": "CLIENT_ID", "iss": "login.eveonline.com"}'; 80 | }, 81 | }), 82 | ); 83 | 84 | expect(ESIClient.parseToken('HEADER.BODY.SIG')).toEqual({ 85 | aud: ['CLIENT_ID', 'EVE Online'], 86 | azp: 'CLIENT_ID', 87 | iss: 'login.eveonline.com', 88 | }); 89 | expect(global.Utilities.base64DecodeWebSafe).toHaveBeenCalledWith('BODY'); 90 | }); 91 | 92 | it('with new issuer', () => { 93 | global.Utilities.newBlob = jest.fn().mockReturnValueOnce( 94 | createMock({ 95 | getDataAsString(): string { 96 | return '{"aud": ["CLIENT_ID", "EVE Online"], "azp": "CLIENT_ID", "iss": "https://login.eveonline.com"}'; 97 | }, 98 | }), 99 | ); 100 | 101 | expect(ESIClient.parseToken('HEADER.BODY.SIG')).toEqual({ 102 | aud: ['CLIENT_ID', 'EVE Online'], 103 | azp: 'CLIENT_ID', 104 | iss: 'https://login.eveonline.com', 105 | }); 106 | expect(global.Utilities.base64DecodeWebSafe).toHaveBeenCalledWith('BODY'); 107 | }); 108 | 109 | it('with invalid issuer', () => { 110 | global.Utilities.newBlob = jest.fn().mockReturnValueOnce( 111 | createMock({ 112 | getDataAsString(): string { 113 | return '{"aud": ["CLIENT_ID", "EVE Online"], "azp": "CLIENT_ID", "iss": "login.eveonline.net"}'; 114 | }, 115 | }), 116 | ); 117 | 118 | expect(() => ESIClient.parseToken('HEADER.BODY.SIG')).toThrow('Access token validation error: invalid issuer'); 119 | expect(global.Utilities.base64DecodeWebSafe).toHaveBeenCalledWith('BODY'); 120 | }); 121 | }); 122 | 123 | describe('#setFunction', () => { 124 | beforeEach(() => { 125 | endpointProvider.hasEndpoint = jest.fn().mockReturnValueOnce(false); 126 | }); 127 | 128 | it('it should raise when the function does not exist work', () => { 129 | expect(() => esiClient.setFunction('foo')).toThrow('Unknown endpoint: \'foo\''); 130 | }); 131 | }); 132 | 133 | describe('#reset', () => { 134 | beforeEach(() => { 135 | esiClient.reset(); 136 | }); 137 | 138 | it('should clear the underlying property and oauth service', () => { 139 | expect(oauthServiceMock.reset).toHaveBeenCalled(); 140 | expect(documentProperties.deleteProperty).toHaveBeenCalledWith('character.Blacksmoke16'); 141 | }); 142 | }); 143 | 144 | describe('#buildRequest', () => { 145 | let result: URLFetchRequest; 146 | 147 | describe('without parameters', () => { 148 | describe('public endpoint', () => { 149 | beforeEach(() => { 150 | endpoint = { 151 | path: '/{version}/route/', 152 | version: 'v1', 153 | method: 'get', 154 | parameters: [] as IParameter[], 155 | } as IEndpoint; 156 | esiClient.setFunction('foo'); 157 | result = esiClient.buildRequest(); 158 | }); 159 | 160 | it('should return the proper request', () => { 161 | expect(result).toEqual({ 162 | method: 'get', 163 | url: 'https://esi.evetech.net/v1/route/', 164 | headers: { 165 | 'user-agent': 'GESI User 2047918291', 166 | }, 167 | contentType: 'application/json', 168 | muteHttpExceptions: true, 169 | }); 170 | }); 171 | }); 172 | 173 | describe('public endpoint, paginated', () => { 174 | beforeEach(() => { 175 | endpoint = { 176 | path: '/{version}/route/', 177 | version: 'v1', 178 | method: 'get', 179 | parameters: [] as IParameter[], 180 | } as IEndpoint; 181 | esiClient.setFunction('foo'); 182 | result = esiClient.buildRequest({ page: 3 } as IFunctionParams); 183 | }); 184 | 185 | it('should return the proper request', () => { 186 | expect(result).toEqual({ 187 | method: 'get', 188 | url: 'https://esi.evetech.net/v1/route/?page=3', 189 | headers: { 190 | 'user-agent': 'GESI User 2047918291', 191 | }, 192 | contentType: 'application/json', 193 | muteHttpExceptions: true, 194 | }); 195 | }); 196 | }); 197 | 198 | describe('public endpoint, custom version', () => { 199 | beforeEach(() => { 200 | endpoint = { 201 | path: '/{version}/route/', 202 | version: 'v1', 203 | method: 'get', 204 | parameters: [] as IParameter[], 205 | } as IEndpoint; 206 | esiClient.setFunction('foo'); 207 | result = esiClient.buildRequest({ version: 'v3' } as IFunctionParams); 208 | }); 209 | 210 | it('should return the proper request', () => { 211 | expect(result).toEqual({ 212 | method: 'get', 213 | url: 'https://esi.evetech.net/v3/route/', 214 | headers: { 215 | 'user-agent': 'GESI User 2047918291', 216 | }, 217 | contentType: 'application/json', 218 | muteHttpExceptions: true, 219 | }); 220 | }); 221 | }); 222 | 223 | describe('private endpoint, placeholders', () => { 224 | beforeEach(() => { 225 | oauthServiceMock.getAccessToken = jest.fn().mockReturnValueOnce('TOKEN'); 226 | 227 | endpoint = { 228 | path: '/{version}/route/{character_id}/{corporation_id}/{alliance_id}/', 229 | scope: 'SCOPE', 230 | version: 'v1', 231 | method: 'get', 232 | parameters: [] as IParameter[], 233 | } as IEndpoint; 234 | esiClient.setFunction('foo'); 235 | result = esiClient.buildRequest(); 236 | }); 237 | 238 | it('should return the proper request', () => { 239 | expect(result).toEqual({ 240 | method: 'get', 241 | url: 'https://esi.evetech.net/v1/route/2047918291/98019139/1900696668/', 242 | headers: { 243 | 'user-agent': 'GESI User 2047918291', 244 | 'authorization': 'Bearer TOKEN', 245 | }, 246 | contentType: 'application/json', 247 | muteHttpExceptions: true, 248 | }); 249 | }); 250 | }); 251 | }); 252 | 253 | describe('with parameters', () => { 254 | describe('type validation', () => { 255 | describe('non array', () => { 256 | describe('required number param without a value', () => { 257 | it('should throw the proper error', () => { 258 | endpoint = { 259 | path: '/{version}/route/', 260 | parameters: [ 261 | { 262 | name: 'param', 263 | type: 'number', 264 | required: true, 265 | }, 266 | ], 267 | } as IEndpoint; 268 | esiClient.setFunction('foo'); 269 | 270 | expect(() => esiClient.buildRequest()) 271 | .toThrow('Argument param is required.'); 272 | }); 273 | }); 274 | 275 | describe('required number param with boolean', () => { 276 | it('should throw the proper error', () => { 277 | endpoint = { 278 | path: '/{version}/route/', 279 | parameters: [ 280 | { 281 | name: 'param', 282 | type: 'number', 283 | required: true, 284 | }, 285 | ], 286 | } as IEndpoint; 287 | esiClient.setFunction('foo'); 288 | 289 | expect(() => esiClient.buildRequest({ param: false, show_column_headings: false } as IFunctionParams)) 290 | .toThrow('Expected required argument param to be a number, but got a boolean.'); 291 | }); 292 | }); 293 | 294 | describe('required boolean with false', () => { 295 | it('replace the placeholder with false', () => { 296 | endpoint = { 297 | path: '/{version}/route/{param}/', 298 | version: 'v1', 299 | method: 'get', 300 | parameters: [ 301 | { 302 | in: 'path', 303 | name: 'param', 304 | type: 'boolean', 305 | required: true, 306 | }, 307 | ], 308 | } as IEndpoint; 309 | esiClient.setFunction('foo'); 310 | 311 | expect(esiClient.buildRequest({ param: false, show_column_headings: false } as IFunctionParams)).toEqual({ 312 | url: 'https://esi.evetech.net/v1/route/false/', 313 | method: 'get', 314 | headers: { 315 | 'user-agent': 'GESI User 2047918291', 316 | }, 317 | contentType: 'application/json', 318 | muteHttpExceptions: true, 319 | }); 320 | }); 321 | }); 322 | 323 | describe('string param with invalid range value', () => { 324 | it('should throw the proper error', () => { 325 | endpoint = { 326 | path: '/{version}/route/', 327 | parameters: [ 328 | { 329 | name: 'param', 330 | type: 'string', 331 | }, 332 | ], 333 | } as IEndpoint; 334 | esiClient.setFunction('foo'); 335 | 336 | expect(() => esiClient.buildRequest({ param: '#NAME?', show_column_headings: false } as IFunctionParams)) 337 | .toThrow('Expected optional argument param to be a string, but got invalid named range. Put the value in double quotes.'); 338 | }); 339 | }); 340 | 341 | describe('string param with null value', () => { 342 | it('should throw the proper error', () => { 343 | endpoint = { 344 | path: '/{version}/route/{param}/', 345 | version: 'v1', 346 | method: 'get', 347 | parameters: [ 348 | { 349 | in: 'path', 350 | name: 'param', 351 | type: 'string', 352 | }, 353 | ], 354 | } as IEndpoint; 355 | esiClient.setFunction('foo'); 356 | 357 | expect(esiClient.buildRequest({ param: null, show_column_headings: false } as IFunctionParams)).toEqual({ 358 | url: 'https://esi.evetech.net/v1/route/{param}/', 359 | method: 'get', 360 | headers: { 361 | 'user-agent': 'GESI User 2047918291', 362 | }, 363 | contentType: 'application/json', 364 | muteHttpExceptions: true, 365 | }); 366 | }); 367 | }); 368 | 369 | describe('string param with empty string value', () => { 370 | it('should be skipped', () => { 371 | endpoint = { 372 | path: '/{version}/route/{param}/', 373 | version: 'v1', 374 | method: 'get', 375 | parameters: [ 376 | { 377 | in: 'path', 378 | name: 'param', 379 | type: 'string', 380 | }, 381 | ], 382 | } as IEndpoint; 383 | esiClient.setFunction('foo'); 384 | 385 | expect(esiClient.buildRequest({ param: '', show_column_headings: false } as IFunctionParams)).toEqual({ 386 | method: 'get', 387 | url: 'https://esi.evetech.net/v1/route/{param}/', 388 | headers: { 389 | 'user-agent': 'GESI User 2047918291', 390 | }, 391 | contentType: 'application/json', 392 | muteHttpExceptions: true, 393 | }); 394 | }); 395 | }); 396 | 397 | describe('string param with undefined value', () => { 398 | it('should be skipped', () => { 399 | endpoint = { 400 | path: '/{version}/route/{param}/', 401 | version: 'v1', 402 | method: 'get', 403 | parameters: [ 404 | { 405 | in: 'path', 406 | name: 'param', 407 | type: 'string', 408 | }, 409 | ], 410 | } as IEndpoint; 411 | esiClient.setFunction('foo'); 412 | 413 | expect(esiClient.buildRequest({ param: undefined, show_column_headings: false } as IFunctionParams)).toEqual({ 414 | method: 'get', 415 | url: 'https://esi.evetech.net/v1/route/{param}/', 416 | headers: { 417 | 'user-agent': 'GESI User 2047918291', 418 | }, 419 | contentType: 'application/json', 420 | muteHttpExceptions: true, 421 | }); 422 | }); 423 | }); 424 | 425 | describe('boolean param with boolean value', () => { 426 | it('should be skipped', () => { 427 | endpoint = { 428 | path: '/{version}/route/{param}/', 429 | version: 'v1', 430 | method: 'get', 431 | parameters: [ 432 | { 433 | in: 'path', 434 | name: 'param', 435 | type: 'boolean', 436 | }, 437 | ], 438 | } as IEndpoint; 439 | esiClient.setFunction('foo'); 440 | 441 | expect(esiClient.buildRequest({ param: false, show_column_headings: false } as IFunctionParams)).toEqual({ 442 | method: 'get', 443 | url: 'https://esi.evetech.net/v1/route/false/', 444 | headers: { 445 | 'user-agent': 'GESI User 2047918291', 446 | }, 447 | contentType: 'application/json', 448 | muteHttpExceptions: true, 449 | }); 450 | }); 451 | }); 452 | 453 | describe('string param with number value', () => { 454 | it('should throw the proper error', () => { 455 | endpoint = { 456 | path: '/{version}/route/', 457 | parameters: [ 458 | { 459 | name: 'param', 460 | type: 'string', 461 | }, 462 | ], 463 | } as IEndpoint; 464 | esiClient.setFunction('foo'); 465 | 466 | expect(() => esiClient.buildRequest({ param: 100, show_column_headings: false } as IFunctionParams)) 467 | .toThrow('Expected optional argument param to be a string, but got a number.'); 468 | }); 469 | }); 470 | 471 | describe('number param with invalid range value', () => { 472 | it('should throw the proper error', () => { 473 | endpoint = { 474 | path: '/{version}/route/', 475 | parameters: [ 476 | { 477 | name: 'param', 478 | type: 'number', 479 | }, 480 | ], 481 | } as IEndpoint; 482 | esiClient.setFunction('foo'); 483 | 484 | expect(() => esiClient.buildRequest({ param: '#NAME?', show_column_headings: false } as IFunctionParams)) 485 | .toThrow('Expected optional argument param to be a number, but got invalid named range.'); 486 | }); 487 | }); 488 | 489 | describe('optional bool param that\'s undefined', () => { 490 | it('should throw the proper error', () => { 491 | endpoint = { 492 | path: '/{version}/route/', 493 | parameters: [ 494 | { 495 | name: 'param', 496 | type: 'boolean', 497 | }, 498 | ], 499 | } as IEndpoint; 500 | esiClient.setFunction('foo'); 501 | 502 | expect(() => esiClient.buildRequest({ param: undefined, show_column_headings: false } as IFunctionParams)) 503 | .not.toThrow(); 504 | }); 505 | }); 506 | }); 507 | 508 | describe('array type', () => { 509 | describe('required number array param with boolean', () => { 510 | it('should throw the proper error', () => { 511 | endpoint = { 512 | path: '/{version}/route/', 513 | parameters: [ 514 | { 515 | name: 'param', 516 | type: 'number[]', 517 | required: true, 518 | }, 519 | ], 520 | } as IEndpoint; 521 | esiClient.setFunction('foo'); 522 | 523 | expect(() => esiClient.buildRequest({ param: false, show_column_headings: false } as IFunctionParams)) 524 | .toThrow('Expected required argument param to be a number|number[], but got a boolean.'); 525 | }); 526 | }); 527 | 528 | describe('string array param with invalid range value', () => { 529 | it('should throw the proper error', () => { 530 | endpoint = { 531 | path: '/{version}/route/', 532 | parameters: [ 533 | { 534 | name: 'param', 535 | type: 'string[]', 536 | }, 537 | ], 538 | } as IEndpoint; 539 | esiClient.setFunction('foo'); 540 | 541 | expect(() => esiClient.buildRequest({ param: '#NAME?', show_column_headings: false } as IFunctionParams)) 542 | .toThrow('Expected optional argument param to be a string|string[], but got invalid named range. Put the value(s) in double quotes.'); 543 | }); 544 | }); 545 | 546 | describe('string array param with number', () => { 547 | it('should throw the proper error', () => { 548 | endpoint = { 549 | path: '/{version}/route/', 550 | parameters: [ 551 | { 552 | name: 'param', 553 | type: 'string[]', 554 | }, 555 | ], 556 | } as IEndpoint; 557 | esiClient.setFunction('foo'); 558 | 559 | expect(() => esiClient.buildRequest({ param: 100, show_column_headings: false } as IFunctionParams)) 560 | .toThrow('Expected optional argument param to be a string|string[], but got a number.'); 561 | }); 562 | }); 563 | 564 | describe('string array param with a number array', () => { 565 | it('should throw the proper error', () => { 566 | endpoint = { 567 | path: '/{version}/route/', 568 | parameters: [ 569 | { 570 | in: 'body', 571 | name: 'param', 572 | type: 'string[]', 573 | }, 574 | ], 575 | } as IEndpoint; 576 | esiClient.setFunction('foo'); 577 | 578 | expect(() => esiClient.buildRequest({ param: [1, 2, 3], show_column_headings: false } as IFunctionParams)) 579 | .toThrow('Expected optional argument param to be a string|string[], but not every item in the array is a string.'); 580 | }); 581 | }); 582 | 583 | describe('string array param with a single number', () => { 584 | it('should throw the proper error', () => { 585 | endpoint = { 586 | path: '/{version}/route/', 587 | parameters: [ 588 | { 589 | in: 'body', 590 | name: 'param', 591 | type: 'string[]', 592 | }, 593 | ], 594 | } as IEndpoint; 595 | esiClient.setFunction('foo'); 596 | 597 | expect(() => esiClient.buildRequest({ param: ['1', 2, '3'], show_column_headings: false } as IFunctionParams)) 598 | .toThrow('Expected optional argument param to be a string|string[], but not every item in the array is a string.'); 599 | }); 600 | }); 601 | 602 | describe('string array param with all strings', () => { 603 | it('should throw the proper error', () => { 604 | endpoint = { 605 | path: '/{version}/route/', 606 | parameters: [ 607 | { 608 | in: 'body', 609 | name: 'param', 610 | type: 'string[]', 611 | }, 612 | ], 613 | } as IEndpoint; 614 | esiClient.setFunction('foo'); 615 | 616 | expect(() => esiClient.buildRequest({ param: ['1', '2', '3'], show_column_headings: false } as IFunctionParams)) 617 | .not.toThrow(); 618 | }); 619 | }); 620 | 621 | describe('string array param with null', () => { 622 | it('should throw the proper error', () => { 623 | endpoint = { 624 | path: '/{version}/route/', 625 | parameters: [ 626 | { 627 | in: 'body', 628 | name: 'param', 629 | type: 'string[]', 630 | }, 631 | ], 632 | } as IEndpoint; 633 | esiClient.setFunction('foo'); 634 | 635 | expect(() => esiClient.buildRequest({ param: null, show_column_headings: false } as IFunctionParams)) 636 | .not.toThrow(); 637 | }); 638 | }); 639 | }); 640 | }); 641 | 642 | describe('path param', () => { 643 | beforeEach(() => { 644 | endpoint = { 645 | path: '/{version}/route/{param}/', 646 | version: 'v1', 647 | method: 'get', 648 | parameters: [ 649 | { 650 | in: 'path', 651 | name: 'param', 652 | type: 'number', 653 | }, 654 | ], 655 | } as IEndpoint; 656 | esiClient.setFunction('foo'); 657 | result = esiClient.buildRequest({ param: 10, show_column_headings: false } as IFunctionParams); 658 | }); 659 | 660 | it('should sub the param into the path', () => { 661 | expect(result).toEqual({ 662 | method: 'get', 663 | url: 'https://esi.evetech.net/v1/route/10/', 664 | headers: { 665 | 'user-agent': 'GESI User 2047918291', 666 | }, 667 | contentType: 'application/json', 668 | muteHttpExceptions: true, 669 | }); 670 | }); 671 | }); 672 | 673 | describe('query param', () => { 674 | beforeEach(() => { 675 | endpoint = { 676 | path: '/{version}/route/', 677 | version: 'v1', 678 | method: 'get', 679 | parameters: [ 680 | { 681 | in: 'query', 682 | name: 'param', 683 | type: 'number', 684 | }, 685 | ], 686 | } as IEndpoint; 687 | esiClient.setFunction('foo'); 688 | result = esiClient.buildRequest({ param: 10, show_column_headings: false } as IFunctionParams); 689 | }); 690 | 691 | it('add the value as a query param', () => { 692 | expect(result).toEqual({ 693 | method: 'get', 694 | url: 'https://esi.evetech.net/v1/route/?param=10', 695 | headers: { 696 | 'user-agent': 'GESI User 2047918291', 697 | }, 698 | contentType: 'application/json', 699 | muteHttpExceptions: true, 700 | }); 701 | }); 702 | }); 703 | 704 | describe('body param', () => { 705 | beforeEach(() => { 706 | endpoint = { 707 | path: '/{version}/route/', 708 | version: 'v1', 709 | method: 'get', 710 | parameters: [ 711 | { 712 | in: 'body', 713 | name: 'param', 714 | type: 'number[]', 715 | }, 716 | ], 717 | } as IEndpoint; 718 | esiClient.setFunction('foo'); 719 | result = esiClient.buildRequest({ param: 10, show_column_headings: false } as IFunctionParams); 720 | }); 721 | 722 | it('add the payload as a JSON encoded value', () => { 723 | expect(result).toEqual({ 724 | method: 'get', 725 | url: 'https://esi.evetech.net/v1/route/', 726 | payload: '[10]', 727 | headers: { 728 | 'user-agent': 'GESI User 2047918291', 729 | }, 730 | contentType: 'application/json', 731 | muteHttpExceptions: true, 732 | }); 733 | }); 734 | }); 735 | }); 736 | }); 737 | 738 | describe('execute', () => { 739 | it('invalid show_column_headings type', () => { 740 | endpoint = { 741 | path: '/{version}/route/', 742 | version: 'v1', 743 | method: 'get', 744 | parameters: [] as IParameter[], 745 | } as IEndpoint; 746 | esiClient.setFunction('foo'); 747 | 748 | responses = [ 749 | { 750 | getContentText() { 751 | return '{"id":10}'; 752 | }, 753 | getHeaders() { 754 | return {}; 755 | }, 756 | getResponseCode() { 757 | return 200; 758 | }, 759 | }, 760 | ] as HTTPResponse[]; 761 | esiClient.setFunction('foo'); 762 | 763 | // @ts-ignore 764 | expect(() => esiClient.execute({ show_column_headings: 10 })) 765 | .toThrow('Expected optional argument show_column_headings to be a boolean, but got a number.'); 766 | }); 767 | 768 | it('adds headers if desired', () => { 769 | endpoint = { 770 | path: '/{version}/route/', 771 | version: 'v1', 772 | method: 'get', 773 | headers: [ 774 | { name: 'foo' }, 775 | { name: 'bar' }, 776 | { name: 'baz' }, 777 | ], 778 | parameters: [] as IParameter[], 779 | } as IEndpoint; 780 | esiClient.setFunction('foo'); 781 | 782 | responses = [ 783 | { 784 | getContentText() { 785 | return '[]'; 786 | }, 787 | getHeaders() { 788 | return {}; 789 | }, 790 | getResponseCode() { 791 | return 200; 792 | }, 793 | }, 794 | ] as HTTPResponse[]; 795 | esiClient.setFunction('foo'); 796 | 797 | expect(esiClient.execute({ show_column_headings: true })).toEqual([ 798 | ['foo', 'bar', 'baz'], 799 | ]); 800 | }); 801 | 802 | it('does not add headers if not desired', () => { 803 | endpoint = { 804 | path: '/{version}/route/', 805 | version: 'v1', 806 | method: 'get', 807 | headers: [ 808 | { name: 'foo' }, 809 | { name: 'bar' }, 810 | { name: 'baz' }, 811 | ], 812 | parameters: [] as IParameter[], 813 | } as IEndpoint; 814 | esiClient.setFunction('foo'); 815 | 816 | responses = [ 817 | { 818 | getContentText() { 819 | return '[]'; 820 | }, 821 | getHeaders() { 822 | return {}; 823 | }, 824 | getResponseCode() { 825 | return 200; 826 | }, 827 | }, 828 | ] as HTTPResponse[]; 829 | esiClient.setFunction('foo'); 830 | 831 | expect(esiClient.execute()).toEqual([]); 832 | }); 833 | 834 | it('concats an array of numbers', () => { 835 | endpoint = { 836 | path: '/{version}/route/', 837 | version: 'v1', 838 | method: 'get', 839 | headers: [ 840 | { name: 'foo' }, 841 | { name: 'bar' }, 842 | { name: 'baz' }, 843 | ], 844 | parameters: [] as IParameter[], 845 | } as IEndpoint; 846 | esiClient.setFunction('foo'); 847 | 848 | responses = [ 849 | { 850 | getContentText() { 851 | return '[1, 2, 3]'; 852 | }, 853 | getHeaders() { 854 | return {}; 855 | }, 856 | getResponseCode() { 857 | return 200; 858 | }, 859 | }, 860 | ] as HTTPResponse[]; 861 | esiClient.setFunction('foo'); 862 | 863 | expect(esiClient.execute()).toEqual([1, 2, 3]); 864 | }); 865 | 866 | it('concats an array of singly nested objects', () => { 867 | endpoint = { 868 | path: '/{version}/route/', 869 | version: 'v1', 870 | method: 'get', 871 | headers: [ 872 | { name: 'id' }, 873 | ], 874 | parameters: [] as IParameter[], 875 | } as IEndpoint; 876 | esiClient.setFunction('foo'); 877 | 878 | responses = [ 879 | { 880 | getContentText() { 881 | return '[{"id":1},{"id":2}]'; 882 | }, 883 | getHeaders() { 884 | return {}; 885 | }, 886 | getResponseCode() { 887 | return 200; 888 | }, 889 | }, 890 | ] as HTTPResponse[]; 891 | esiClient.setFunction('foo'); 892 | 893 | expect(esiClient.execute()).toEqual([[1], [2]]); 894 | }); 895 | 896 | it('concats an array of singly doubly nested objects', () => { 897 | endpoint = { 898 | path: '/{version}/route/', 899 | version: 'v1', 900 | method: 'get', 901 | headers: [ 902 | { name: 'id' }, 903 | { name: 'extra', sub_headers: ['subId'] }, 904 | ], 905 | parameters: [] as IParameter[], 906 | } as IEndpoint; 907 | esiClient.setFunction('foo'); 908 | 909 | responses = [ 910 | { 911 | getContentText() { 912 | return '[{"id":1,"extra":{"subId":3}},{"id":2,"extra":{"subId":4}}]'; 913 | }, 914 | getHeaders() { 915 | return {}; 916 | }, 917 | getResponseCode() { 918 | return 200; 919 | }, 920 | }, 921 | ] as HTTPResponse[]; 922 | esiClient.setFunction('foo'); 923 | 924 | expect(esiClient.execute()).toEqual([[1, '{"subId":3}'], [2, '{"subId":4}']]); 925 | }); 926 | 927 | it('handles a single object', () => { 928 | endpoint = { 929 | path: '/{version}/route/', 930 | version: 'v1', 931 | method: 'get', 932 | headers: [ 933 | { name: 'id' }, 934 | ], 935 | parameters: [] as IParameter[], 936 | } as IEndpoint; 937 | esiClient.setFunction('foo'); 938 | 939 | responses = [ 940 | { 941 | getContentText() { 942 | return '{"id":1}'; 943 | }, 944 | getHeaders() { 945 | return {}; 946 | }, 947 | getResponseCode() { 948 | return 200; 949 | }, 950 | }, 951 | ] as HTTPResponse[]; 952 | esiClient.setFunction('foo'); 953 | 954 | expect(esiClient.execute()).toEqual([[1]]); 955 | }); 956 | 957 | it('single object with nested data', () => { 958 | endpoint = { 959 | path: '/{version}/route/', 960 | version: 'v1', 961 | method: 'get', 962 | headers: [ 963 | { name: 'id' }, 964 | { name: 'extra', sub_headers: ['subId'] }, 965 | ], 966 | parameters: [] as IParameter[], 967 | } as IEndpoint; 968 | esiClient.setFunction('foo'); 969 | 970 | responses = [ 971 | { 972 | getContentText() { 973 | return '{"id":1,"extra":{"subId":3}}'; 974 | }, 975 | getHeaders() { 976 | return {}; 977 | }, 978 | getResponseCode() { 979 | return 200; 980 | }, 981 | }, 982 | ] as HTTPResponse[]; 983 | esiClient.setFunction('foo'); 984 | 985 | expect(esiClient.execute()).toEqual([[1, '{"subId":3}']]); 986 | }); 987 | 988 | it('handles a value', () => { 989 | endpoint = { 990 | path: '/{version}/route/', 991 | version: 'v1', 992 | method: 'get', 993 | headers: [ 994 | { name: 'id' }, 995 | ], 996 | parameters: [] as IParameter[], 997 | } as IEndpoint; 998 | esiClient.setFunction('foo'); 999 | 1000 | responses = [ 1001 | { 1002 | getContentText() { 1003 | return '10'; 1004 | }, 1005 | getHeaders() { 1006 | return {}; 1007 | }, 1008 | getResponseCode() { 1009 | return 200; 1010 | }, 1011 | }, 1012 | ] as HTTPResponse[]; 1013 | esiClient.setFunction('foo'); 1014 | 1015 | expect(esiClient.execute()).toEqual([[10]]); 1016 | }); 1017 | }); 1018 | 1019 | // Also used to test doRequest 1020 | describe('#executeRaw', () => { 1021 | let result: any; 1022 | 1023 | describe('and the response is a non 200 status', () => { 1024 | beforeEach(() => { 1025 | endpoint = { 1026 | path: '/{version}/route/', 1027 | version: 'v1', 1028 | method: 'get', 1029 | parameters: [] as IParameter[], 1030 | } as IEndpoint; 1031 | esiClient.setFunction('foo'); 1032 | 1033 | responses = [ 1034 | { 1035 | getContentText() { 1036 | return 'ERR'; 1037 | }, 1038 | getHeaders() { 1039 | return {}; 1040 | }, 1041 | getResponseCode() { 1042 | return 500; 1043 | }, 1044 | }, 1045 | ] as HTTPResponse[]; 1046 | }); 1047 | 1048 | it('should raise if the response is not 200', function () { 1049 | expect(() => esiClient.executeRaw()).toThrow('ERR'); 1050 | }); 1051 | }); 1052 | 1053 | describe('and the response does not have an x-pages header', () => { 1054 | beforeEach(() => { 1055 | endpoint = { 1056 | path: '/{version}/route/', 1057 | version: 'v1', 1058 | method: 'get', 1059 | parameters: [] as IParameter[], 1060 | } as IEndpoint; 1061 | esiClient.setFunction('foo'); 1062 | 1063 | responses = [ 1064 | { 1065 | getContentText() { 1066 | return '{"foo":"bar"}'; 1067 | }, 1068 | getHeaders() { 1069 | return {}; 1070 | }, 1071 | getResponseCode() { 1072 | return 200; 1073 | }, 1074 | }, 1075 | ] as HTTPResponse[]; 1076 | 1077 | result = esiClient.executeRaw(); 1078 | }); 1079 | 1080 | it('should that object as is', function () { 1081 | expect(result).toEqual({ foo: 'bar' }); 1082 | }); 1083 | }); 1084 | 1085 | describe('and the response only has 1 page', () => { 1086 | beforeEach(() => { 1087 | endpoint = { 1088 | path: '/{version}/route/', 1089 | version: 'v1', 1090 | method: 'get', 1091 | parameters: [] as IParameter[], 1092 | } as IEndpoint; 1093 | esiClient.setFunction('foo'); 1094 | 1095 | responses = [ 1096 | { 1097 | getContentText() { 1098 | return '{"foo":"bar"}'; 1099 | }, 1100 | getHeaders() { 1101 | return { 1102 | 'x-pages': 1, 1103 | }; 1104 | }, 1105 | getResponseCode() { 1106 | return 200; 1107 | }, 1108 | }, 1109 | ] as HTTPResponse[]; 1110 | 1111 | result = esiClient.executeRaw(); 1112 | }); 1113 | 1114 | it('should that object as is', function () { 1115 | expect(result).toEqual({ foo: 'bar' }); 1116 | }); 1117 | }); 1118 | 1119 | describe('and the response has more than 1 page', () => { 1120 | beforeEach(() => { 1121 | endpoint = { 1122 | path: '/{version}/route/', 1123 | version: 'v1', 1124 | method: 'get', 1125 | parameters: [] as IParameter[], 1126 | } as IEndpoint; 1127 | esiClient.setFunction('foo'); 1128 | 1129 | responses = [ 1130 | { 1131 | getContentText() { 1132 | return '[{"foo":"bar"}]'; 1133 | }, 1134 | getHeaders() { 1135 | return { 1136 | 'x-pages': 3, 1137 | }; 1138 | }, 1139 | getResponseCode() { 1140 | return 200; 1141 | }, 1142 | }, 1143 | { 1144 | getContentText() { 1145 | return '[{"biz":"baz"}]'; 1146 | }, 1147 | getHeaders() { 1148 | return { 1149 | 'x-pages': 3, 1150 | }; 1151 | }, 1152 | getResponseCode() { 1153 | return 200; 1154 | }, 1155 | }, 1156 | ] as HTTPResponse[]; 1157 | 1158 | result = esiClient.executeRaw(); 1159 | }); 1160 | 1161 | it('should return a concatenated array of the results', function () { 1162 | expect(result).toEqual([{ foo: 'bar' }, { foo: 'bar' }, { biz: 'baz' }]); 1163 | }); 1164 | }); 1165 | 1166 | describe('and one of the subsequent requests a non 200 response', () => { 1167 | beforeEach(() => { 1168 | endpoint = { 1169 | path: '/{version}/route/', 1170 | version: 'v1', 1171 | method: 'get', 1172 | parameters: [] as IParameter[], 1173 | } as IEndpoint; 1174 | esiClient.setFunction('foo'); 1175 | 1176 | responses = [ 1177 | { 1178 | getContentText() { 1179 | return '[{"foo":"bar"}]'; 1180 | }, 1181 | getHeaders() { 1182 | return { 1183 | 'x-pages': 3, 1184 | }; 1185 | }, 1186 | getResponseCode() { 1187 | return 200; 1188 | }, 1189 | }, 1190 | { 1191 | getContentText() { 1192 | return 'ERR'; 1193 | }, 1194 | getHeaders() { 1195 | return { 1196 | 'x-pages': 3, 1197 | }; 1198 | }, 1199 | getResponseCode() { 1200 | return 500; 1201 | }, 1202 | }, 1203 | ] as HTTPResponse[]; 1204 | }); 1205 | 1206 | it('should return a concatenated array of the results', function () { 1207 | expect(() => esiClient.executeRaw()).toThrow('ERR'); 1208 | }); 1209 | }); 1210 | }); 1211 | }) 1212 | ; 1213 | -------------------------------------------------------------------------------- /src/script/src/functions.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * List all active player alliances 3 | * 4 | * @param {boolean} show_column_headings - If column headings should be shown. 5 | * @param {string} version - Which ESI version to use for the request. 6 | * @customfunction 7 | */ 8 | function alliances(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 9 | return invoke('alliances', { show_column_headings, version }); 10 | } 11 | 12 | /** 13 | * Public information about an alliance 14 | * 15 | * @param {number} alliance_id - An EVE alliance ID 16 | * @param {boolean} show_column_headings - If column headings should be shown. 17 | * @param {string} version - Which ESI version to use for the request. 18 | * @customfunction 19 | */ 20 | function alliances_alliance(alliance_id: number, show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 21 | if (!alliance_id) throw new Error(`alliance_id is required.`); 22 | return invoke('alliances_alliance', { alliance_id, show_column_headings, version }); 23 | } 24 | 25 | /** 26 | * Return contacts of an alliance 27 | * 28 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 29 | * @param {boolean} show_column_headings - If column headings should be shown. 30 | * @param {string} version - Which ESI version to use for the request. 31 | * @customfunction 32 | */ 33 | function alliances_alliance_contacts(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 34 | return invoke('alliances_alliance_contacts', { name, show_column_headings, version }); 35 | } 36 | 37 | /** 38 | * Return custom labels for an alliance's contacts 39 | * 40 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 41 | * @param {boolean} show_column_headings - If column headings should be shown. 42 | * @param {string} version - Which ESI version to use for the request. 43 | * @customfunction 44 | */ 45 | function alliances_alliance_contacts_labels(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 46 | return invoke('alliances_alliance_contacts_labels', { name, show_column_headings, version }); 47 | } 48 | 49 | /** 50 | * List all current member corporations of an alliance 51 | * 52 | * @param {number} alliance_id - An EVE alliance ID 53 | * @param {boolean} show_column_headings - If column headings should be shown. 54 | * @param {string} version - Which ESI version to use for the request. 55 | * @customfunction 56 | */ 57 | function alliances_alliance_corporations(alliance_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 58 | if (!alliance_id) throw new Error(`alliance_id is required.`); 59 | return invoke('alliances_alliance_corporations', { alliance_id, show_column_headings, version }); 60 | } 61 | 62 | /** 63 | * Get the icon urls for a alliance 64 | * 65 | * @param {number} alliance_id - An EVE alliance ID 66 | * @param {boolean} show_column_headings - If column headings should be shown. 67 | * @param {string} version - Which ESI version to use for the request. 68 | * @customfunction 69 | */ 70 | function alliances_alliance_icons(alliance_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 71 | if (!alliance_id) throw new Error(`alliance_id is required.`); 72 | return invoke('alliances_alliance_icons', { alliance_id, show_column_headings, version }); 73 | } 74 | 75 | /** 76 | * Bulk lookup of character IDs to corporation, alliance and faction 77 | * 78 | * @param {number|number[]} characters - The character IDs to fetch affiliations for. All characters must exist, or none will be returned 79 | * @param {boolean} show_column_headings - If column headings should be shown. 80 | * @param {string} version - Which ESI version to use for the request. 81 | * @customfunction 82 | */ 83 | function characters_affiliation(characters: number|number[], show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 84 | if (!characters) throw new Error(`characters is required.`); 85 | return invoke('characters_affiliation', { characters, show_column_headings, version }); 86 | } 87 | 88 | /** 89 | * Public information about a character 90 | * 91 | * @param {number} character_id - An EVE character ID 92 | * @param {boolean} show_column_headings - If column headings should be shown. 93 | * @param {string} version - Which ESI version to use for the request. 94 | * @customfunction 95 | */ 96 | function characters_character(character_id: number, show_column_headings: boolean = true, version: string = "v5"): SheetsArray { 97 | if (!character_id) throw new Error(`character_id is required.`); 98 | return invoke('characters_character', { character_id, show_column_headings, version }); 99 | } 100 | 101 | /** 102 | * Return a list of agents research information for a character. The formula for finding the current research points with an agent is: currentPoints = remainderPoints + pointsPerDay * days(currentTime - researchStartDate) 103 | * 104 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 105 | * @param {boolean} show_column_headings - If column headings should be shown. 106 | * @param {string} version - Which ESI version to use for the request. 107 | * @customfunction 108 | */ 109 | function characters_character_agents_research(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 110 | return invoke('characters_character_agents_research', { name, show_column_headings, version }); 111 | } 112 | 113 | /** 114 | * Return a list of the characters assets 115 | * 116 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 117 | * @param {boolean} show_column_headings - If column headings should be shown. 118 | * @param {string} version - Which ESI version to use for the request. 119 | * @customfunction 120 | */ 121 | function characters_character_assets(name?: string, show_column_headings: boolean = true, version: string = "v5"): SheetsArray { 122 | return invoke('characters_character_assets', { name, show_column_headings, version }); 123 | } 124 | 125 | /** 126 | * Return locations for a set of item ids, which you can get from character assets endpoint. Coordinates for items in hangars or stations are set to (0,0,0) 127 | * 128 | * @param {number|number[]} item_ids - A list of item ids 129 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 130 | * @param {boolean} show_column_headings - If column headings should be shown. 131 | * @param {string} version - Which ESI version to use for the request. 132 | * @customfunction 133 | */ 134 | function characters_character_assets_locations(item_ids: number|number[], name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 135 | if (!item_ids) throw new Error(`item_ids is required.`); 136 | return invoke('characters_character_assets_locations', { item_ids, name, show_column_headings, version }); 137 | } 138 | 139 | /** 140 | * Return names for a set of item ids, which you can get from character assets endpoint. Typically used for items that can customize names, like containers or ships. 141 | * 142 | * @param {number|number[]} item_ids - A list of item ids 143 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 144 | * @param {boolean} show_column_headings - If column headings should be shown. 145 | * @param {string} version - Which ESI version to use for the request. 146 | * @customfunction 147 | */ 148 | function characters_character_assets_names(item_ids: number|number[], name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 149 | if (!item_ids) throw new Error(`item_ids is required.`); 150 | return invoke('characters_character_assets_names', { item_ids, name, show_column_headings, version }); 151 | } 152 | 153 | /** 154 | * Return attributes of a character 155 | * 156 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 157 | * @param {boolean} show_column_headings - If column headings should be shown. 158 | * @param {string} version - Which ESI version to use for the request. 159 | * @customfunction 160 | */ 161 | function characters_character_attributes(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 162 | return invoke('characters_character_attributes', { name, show_column_headings, version }); 163 | } 164 | 165 | /** 166 | * Return a list of blueprints the character owns 167 | * 168 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 169 | * @param {boolean} show_column_headings - If column headings should be shown. 170 | * @param {string} version - Which ESI version to use for the request. 171 | * @customfunction 172 | */ 173 | function characters_character_blueprints(name?: string, show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 174 | return invoke('characters_character_blueprints', { name, show_column_headings, version }); 175 | } 176 | 177 | /** 178 | * Get 50 event summaries from the calendar. If no from_event ID is given, the resource will return the next 50 chronological event summaries from now. If a from_event ID is specified, it will return the next 50 chronological event summaries from after that event 179 | * 180 | * @param {number} from_event - The event ID to retrieve events from 181 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 182 | * @param {boolean} show_column_headings - If column headings should be shown. 183 | * @param {string} version - Which ESI version to use for the request. 184 | * @customfunction 185 | */ 186 | function characters_character_calendar(from_event?: number, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 187 | return invoke('characters_character_calendar', { from_event, name, show_column_headings, version }); 188 | } 189 | 190 | /** 191 | * Get all the information for a specific event 192 | * 193 | * @param {number} event_id - The id of the event requested 194 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 195 | * @param {boolean} show_column_headings - If column headings should be shown. 196 | * @param {string} version - Which ESI version to use for the request. 197 | * @customfunction 198 | */ 199 | function characters_character_calendar_event(event_id: number, name?: string, show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 200 | if (!event_id) throw new Error(`event_id is required.`); 201 | return invoke('characters_character_calendar_event', { event_id, name, show_column_headings, version }); 202 | } 203 | 204 | /** 205 | * Get all invited attendees for a given event 206 | * 207 | * @param {number} event_id - The id of the event requested 208 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 209 | * @param {boolean} show_column_headings - If column headings should be shown. 210 | * @param {string} version - Which ESI version to use for the request. 211 | * @customfunction 212 | */ 213 | function characters_character_calendar_event_attendees(event_id: number, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 214 | if (!event_id) throw new Error(`event_id is required.`); 215 | return invoke('characters_character_calendar_event_attendees', { event_id, name, show_column_headings, version }); 216 | } 217 | 218 | /** 219 | * A list of the character's clones 220 | * 221 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 222 | * @param {boolean} show_column_headings - If column headings should be shown. 223 | * @param {string} version - Which ESI version to use for the request. 224 | * @customfunction 225 | */ 226 | function characters_character_clones(name?: string, show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 227 | return invoke('characters_character_clones', { name, show_column_headings, version }); 228 | } 229 | 230 | /** 231 | * Return contacts of a character 232 | * 233 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 234 | * @param {boolean} show_column_headings - If column headings should be shown. 235 | * @param {string} version - Which ESI version to use for the request. 236 | * @customfunction 237 | */ 238 | function characters_character_contacts(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 239 | return invoke('characters_character_contacts', { name, show_column_headings, version }); 240 | } 241 | 242 | /** 243 | * Return custom labels for a character's contacts 244 | * 245 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 246 | * @param {boolean} show_column_headings - If column headings should be shown. 247 | * @param {string} version - Which ESI version to use for the request. 248 | * @customfunction 249 | */ 250 | function characters_character_contacts_labels(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 251 | return invoke('characters_character_contacts_labels', { name, show_column_headings, version }); 252 | } 253 | 254 | /** 255 | * Returns contracts available to a character, only if the character is issuer, acceptor or assignee. Only returns contracts no older than 30 days, or if the status is "in_progress". 256 | * 257 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 258 | * @param {boolean} show_column_headings - If column headings should be shown. 259 | * @param {string} version - Which ESI version to use for the request. 260 | * @customfunction 261 | */ 262 | function characters_character_contracts(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 263 | return invoke('characters_character_contracts', { name, show_column_headings, version }); 264 | } 265 | 266 | /** 267 | * Lists bids on a particular auction contract 268 | * 269 | * @param {number} contract_id - ID of a contract 270 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 271 | * @param {boolean} show_column_headings - If column headings should be shown. 272 | * @param {string} version - Which ESI version to use for the request. 273 | * @customfunction 274 | */ 275 | function characters_character_contracts_contract_bids(contract_id: number, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 276 | if (!contract_id) throw new Error(`contract_id is required.`); 277 | return invoke('characters_character_contracts_contract_bids', { contract_id, name, show_column_headings, version }); 278 | } 279 | 280 | /** 281 | * Lists items of a particular contract 282 | * 283 | * @param {number} contract_id - ID of a contract 284 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 285 | * @param {boolean} show_column_headings - If column headings should be shown. 286 | * @param {string} version - Which ESI version to use for the request. 287 | * @customfunction 288 | */ 289 | function characters_character_contracts_contract_items(contract_id: number, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 290 | if (!contract_id) throw new Error(`contract_id is required.`); 291 | return invoke('characters_character_contracts_contract_items', { contract_id, name, show_column_headings, version }); 292 | } 293 | 294 | /** 295 | * Get a list of all the corporations a character has been a member of 296 | * 297 | * @param {number} character_id - An EVE character ID 298 | * @param {boolean} show_column_headings - If column headings should be shown. 299 | * @param {string} version - Which ESI version to use for the request. 300 | * @customfunction 301 | */ 302 | function characters_character_corporationhistory(character_id: number, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 303 | if (!character_id) throw new Error(`character_id is required.`); 304 | return invoke('characters_character_corporationhistory', { character_id, show_column_headings, version }); 305 | } 306 | 307 | /** 308 | * Return a character's jump activation and fatigue information 309 | * 310 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 311 | * @param {boolean} show_column_headings - If column headings should be shown. 312 | * @param {string} version - Which ESI version to use for the request. 313 | * @customfunction 314 | */ 315 | function characters_character_fatigue(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 316 | return invoke('characters_character_fatigue', { name, show_column_headings, version }); 317 | } 318 | 319 | /** 320 | * Return fittings of a character 321 | * 322 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 323 | * @param {boolean} show_column_headings - If column headings should be shown. 324 | * @param {string} version - Which ESI version to use for the request. 325 | * @customfunction 326 | */ 327 | function characters_character_fittings(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 328 | return invoke('characters_character_fittings', { name, show_column_headings, version }); 329 | } 330 | 331 | /** 332 | * Return the fleet ID the character is in, if any. 333 | * 334 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 335 | * @param {boolean} show_column_headings - If column headings should be shown. 336 | * @param {string} version - Which ESI version to use for the request. 337 | * @customfunction 338 | */ 339 | function characters_character_fleet(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 340 | return invoke('characters_character_fleet', { name, show_column_headings, version }); 341 | } 342 | 343 | /** 344 | * Statistical overview of a character involved in faction warfare 345 | * 346 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 347 | * @param {boolean} show_column_headings - If column headings should be shown. 348 | * @param {string} version - Which ESI version to use for the request. 349 | * @customfunction 350 | */ 351 | function characters_character_fw_stats(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 352 | return invoke('characters_character_fw_stats', { name, show_column_headings, version }); 353 | } 354 | 355 | /** 356 | * Return implants on the active clone of a character 357 | * 358 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 359 | * @param {boolean} show_column_headings - If column headings should be shown. 360 | * @param {string} version - Which ESI version to use for the request. 361 | * @customfunction 362 | */ 363 | function characters_character_implants(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 364 | return invoke('characters_character_implants', { name, show_column_headings, version }); 365 | } 366 | 367 | /** 368 | * List industry jobs placed by a character 369 | * 370 | * @param {boolean} include_completed - Whether to retrieve completed character industry jobs. Only includes jobs from the past 90 days 371 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 372 | * @param {boolean} show_column_headings - If column headings should be shown. 373 | * @param {string} version - Which ESI version to use for the request. 374 | * @customfunction 375 | */ 376 | function characters_character_industry_jobs(include_completed?: boolean, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 377 | return invoke('characters_character_industry_jobs', { include_completed, name, show_column_headings, version }); 378 | } 379 | 380 | /** 381 | * Return a list of a character's kills and losses going back 90 days 382 | * 383 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 384 | * @param {boolean} show_column_headings - If column headings should be shown. 385 | * @param {string} version - Which ESI version to use for the request. 386 | * @customfunction 387 | */ 388 | function characters_character_killmails_recent(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 389 | return invoke('characters_character_killmails_recent', { name, show_column_headings, version }); 390 | } 391 | 392 | /** 393 | * Information about the characters current location. Returns the current solar system id, and also the current station or structure ID if applicable 394 | * 395 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 396 | * @param {boolean} show_column_headings - If column headings should be shown. 397 | * @param {string} version - Which ESI version to use for the request. 398 | * @customfunction 399 | */ 400 | function characters_character_location(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 401 | return invoke('characters_character_location', { name, show_column_headings, version }); 402 | } 403 | 404 | /** 405 | * Return a list of loyalty points for all corporations the character has worked for 406 | * 407 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 408 | * @param {boolean} show_column_headings - If column headings should be shown. 409 | * @param {string} version - Which ESI version to use for the request. 410 | * @customfunction 411 | */ 412 | function characters_character_loyalty_points(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 413 | return invoke('characters_character_loyalty_points', { name, show_column_headings, version }); 414 | } 415 | 416 | /** 417 | * Return the 50 most recent mail headers belonging to the character that match the query criteria. Queries can be filtered by label, and last_mail_id can be used to paginate backwards 418 | * 419 | * @param {number|number[]} labels - Fetch only mails that match one or more of the given labels 420 | * @param {number} last_mail_id - List only mail with an ID lower than the given ID, if present 421 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 422 | * @param {boolean} show_column_headings - If column headings should be shown. 423 | * @param {string} version - Which ESI version to use for the request. 424 | * @customfunction 425 | */ 426 | function characters_character_mail(labels?: number|number[], last_mail_id?: number, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 427 | return invoke('characters_character_mail', { labels, last_mail_id, name, show_column_headings, version }); 428 | } 429 | 430 | /** 431 | * Return a list of the users mail labels, unread counts for each label and a total unread count. 432 | * 433 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 434 | * @param {boolean} show_column_headings - If column headings should be shown. 435 | * @param {string} version - Which ESI version to use for the request. 436 | * @customfunction 437 | */ 438 | function characters_character_mail_labels(name?: string, show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 439 | return invoke('characters_character_mail_labels', { name, show_column_headings, version }); 440 | } 441 | 442 | /** 443 | * Return all mailing lists that the character is subscribed to 444 | * 445 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 446 | * @param {boolean} show_column_headings - If column headings should be shown. 447 | * @param {string} version - Which ESI version to use for the request. 448 | * @customfunction 449 | */ 450 | function characters_character_mail_lists(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 451 | return invoke('characters_character_mail_lists', { name, show_column_headings, version }); 452 | } 453 | 454 | /** 455 | * Return the contents of an EVE mail 456 | * 457 | * @param {number} mail_id - An EVE mail ID 458 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 459 | * @param {boolean} show_column_headings - If column headings should be shown. 460 | * @param {string} version - Which ESI version to use for the request. 461 | * @customfunction 462 | */ 463 | function characters_character_mail_mail(mail_id: number, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 464 | if (!mail_id) throw new Error(`mail_id is required.`); 465 | return invoke('characters_character_mail_mail', { mail_id, name, show_column_headings, version }); 466 | } 467 | 468 | /** 469 | * Return a list of medals the character has 470 | * 471 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 472 | * @param {boolean} show_column_headings - If column headings should be shown. 473 | * @param {string} version - Which ESI version to use for the request. 474 | * @customfunction 475 | */ 476 | function characters_character_medals(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 477 | return invoke('characters_character_medals', { name, show_column_headings, version }); 478 | } 479 | 480 | /** 481 | * Paginated record of all mining done by a character for the past 30 days 482 | * 483 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 484 | * @param {boolean} show_column_headings - If column headings should be shown. 485 | * @param {string} version - Which ESI version to use for the request. 486 | * @customfunction 487 | */ 488 | function characters_character_mining(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 489 | return invoke('characters_character_mining', { name, show_column_headings, version }); 490 | } 491 | 492 | /** 493 | * Return character notifications 494 | * 495 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 496 | * @param {boolean} show_column_headings - If column headings should be shown. 497 | * @param {string} version - Which ESI version to use for the request. 498 | * @customfunction 499 | */ 500 | function characters_character_notifications(name?: string, show_column_headings: boolean = true, version: string = "v5"): SheetsArray { 501 | return invoke('characters_character_notifications', { name, show_column_headings, version }); 502 | } 503 | 504 | /** 505 | * Return notifications about having been added to someone's contact list 506 | * 507 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 508 | * @param {boolean} show_column_headings - If column headings should be shown. 509 | * @param {string} version - Which ESI version to use for the request. 510 | * @customfunction 511 | */ 512 | function characters_character_notifications_contacts(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 513 | return invoke('characters_character_notifications_contacts', { name, show_column_headings, version }); 514 | } 515 | 516 | /** 517 | * Checks if the character is currently online 518 | * 519 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 520 | * @param {boolean} show_column_headings - If column headings should be shown. 521 | * @param {string} version - Which ESI version to use for the request. 522 | * @customfunction 523 | */ 524 | function characters_character_online(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 525 | return invoke('characters_character_online', { name, show_column_headings, version }); 526 | } 527 | 528 | /** 529 | * List open market orders placed by a character 530 | * 531 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 532 | * @param {boolean} show_column_headings - If column headings should be shown. 533 | * @param {string} version - Which ESI version to use for the request. 534 | * @customfunction 535 | */ 536 | function characters_character_orders(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 537 | return invoke('characters_character_orders', { name, show_column_headings, version }); 538 | } 539 | 540 | /** 541 | * List cancelled and expired market orders placed by a character up to 90 days in the past. 542 | * 543 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 544 | * @param {boolean} show_column_headings - If column headings should be shown. 545 | * @param {string} version - Which ESI version to use for the request. 546 | * @customfunction 547 | */ 548 | function characters_character_orders_history(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 549 | return invoke('characters_character_orders_history', { name, show_column_headings, version }); 550 | } 551 | 552 | /** 553 | * Returns a list of all planetary colonies owned by a character. 554 | * 555 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 556 | * @param {boolean} show_column_headings - If column headings should be shown. 557 | * @param {string} version - Which ESI version to use for the request. 558 | * @customfunction 559 | */ 560 | function characters_character_planets(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 561 | return invoke('characters_character_planets', { name, show_column_headings, version }); 562 | } 563 | 564 | /** 565 | * Returns full details on the layout of a single planetary colony, including links, pins and routes. Note: Planetary information is only recalculated when the colony is viewed through the client. Information will not update until this criteria is met. 566 | * 567 | * @param {number} planet_id - Planet id of the target planet 568 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 569 | * @param {boolean} show_column_headings - If column headings should be shown. 570 | * @param {string} version - Which ESI version to use for the request. 571 | * @customfunction 572 | */ 573 | function characters_character_planets_planet(planet_id: number, name?: string, show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 574 | if (!planet_id) throw new Error(`planet_id is required.`); 575 | return invoke('characters_character_planets_planet', { planet_id, name, show_column_headings, version }); 576 | } 577 | 578 | /** 579 | * Get portrait urls for a character 580 | * 581 | * @param {number} character_id - An EVE character ID 582 | * @param {boolean} show_column_headings - If column headings should be shown. 583 | * @param {string} version - Which ESI version to use for the request. 584 | * @customfunction 585 | */ 586 | function characters_character_portrait(character_id: number, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 587 | if (!character_id) throw new Error(`character_id is required.`); 588 | return invoke('characters_character_portrait', { character_id, show_column_headings, version }); 589 | } 590 | 591 | /** 592 | * Returns a character's corporation roles 593 | * 594 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 595 | * @param {boolean} show_column_headings - If column headings should be shown. 596 | * @param {string} version - Which ESI version to use for the request. 597 | * @customfunction 598 | */ 599 | function characters_character_roles(name?: string, show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 600 | return invoke('characters_character_roles', { name, show_column_headings, version }); 601 | } 602 | 603 | /** 604 | * Search for entities that match a given sub-string. 605 | * 606 | * @param {string} search - The string to search on 607 | * @param {string|string[]} categories - Type of entities to search for 608 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 609 | * @param {boolean} strict - Whether the search should be a strict match 610 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 611 | * @param {boolean} show_column_headings - If column headings should be shown. 612 | * @param {string} version - Which ESI version to use for the request. 613 | * @customfunction 614 | */ 615 | function characters_character_search(search: string, categories: string|string[], language?: string, strict?: boolean, name?: string, show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 616 | if (!search) throw new Error(`search is required.`); 617 | if (!categories) throw new Error(`categories is required.`); 618 | return invoke('characters_character_search', { search, categories, language, strict, name, show_column_headings, version }); 619 | } 620 | 621 | /** 622 | * Get the current ship type, name and id 623 | * 624 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 625 | * @param {boolean} show_column_headings - If column headings should be shown. 626 | * @param {string} version - Which ESI version to use for the request. 627 | * @customfunction 628 | */ 629 | function characters_character_ship(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 630 | return invoke('characters_character_ship', { name, show_column_headings, version }); 631 | } 632 | 633 | /** 634 | * List the configured skill queue for the given character 635 | * 636 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 637 | * @param {boolean} show_column_headings - If column headings should be shown. 638 | * @param {string} version - Which ESI version to use for the request. 639 | * @customfunction 640 | */ 641 | function characters_character_skillqueue(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 642 | return invoke('characters_character_skillqueue', { name, show_column_headings, version }); 643 | } 644 | 645 | /** 646 | * List all trained skills for the given character 647 | * 648 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 649 | * @param {boolean} show_column_headings - If column headings should be shown. 650 | * @param {string} version - Which ESI version to use for the request. 651 | * @customfunction 652 | */ 653 | function characters_character_skills(name?: string, show_column_headings: boolean = true, version: string = "v4"): SheetsArray { 654 | return invoke('characters_character_skills', { name, show_column_headings, version }); 655 | } 656 | 657 | /** 658 | * Return character standings from agents, NPC corporations, and factions 659 | * 660 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 661 | * @param {boolean} show_column_headings - If column headings should be shown. 662 | * @param {string} version - Which ESI version to use for the request. 663 | * @customfunction 664 | */ 665 | function characters_character_standings(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 666 | return invoke('characters_character_standings', { name, show_column_headings, version }); 667 | } 668 | 669 | /** 670 | * Returns a character's titles 671 | * 672 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 673 | * @param {boolean} show_column_headings - If column headings should be shown. 674 | * @param {string} version - Which ESI version to use for the request. 675 | * @customfunction 676 | */ 677 | function characters_character_titles(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 678 | return invoke('characters_character_titles', { name, show_column_headings, version }); 679 | } 680 | 681 | /** 682 | * Returns a character's wallet balance 683 | * 684 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 685 | * @param {boolean} show_column_headings - If column headings should be shown. 686 | * @param {string} version - Which ESI version to use for the request. 687 | * @customfunction 688 | */ 689 | function characters_character_wallet(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 690 | return invoke('characters_character_wallet', { name, show_column_headings, version }); 691 | } 692 | 693 | /** 694 | * Retrieve the given character's wallet journal going 30 days back 695 | * 696 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 697 | * @param {boolean} show_column_headings - If column headings should be shown. 698 | * @param {string} version - Which ESI version to use for the request. 699 | * @customfunction 700 | */ 701 | function characters_character_wallet_journal(name?: string, show_column_headings: boolean = true, version: string = "v6"): SheetsArray { 702 | return invoke('characters_character_wallet_journal', { name, show_column_headings, version }); 703 | } 704 | 705 | /** 706 | * Get wallet transactions of a character 707 | * 708 | * @param {number} from_id - Only show transactions happened before the one referenced by this id 709 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 710 | * @param {boolean} show_column_headings - If column headings should be shown. 711 | * @param {string} version - Which ESI version to use for the request. 712 | * @customfunction 713 | */ 714 | function characters_character_wallet_transactions(from_id?: number, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 715 | return invoke('characters_character_wallet_transactions', { from_id, name, show_column_headings, version }); 716 | } 717 | 718 | /** 719 | * Lists bids on a public auction contract 720 | * 721 | * @param {number} contract_id - ID of a contract 722 | * @param {boolean} show_column_headings - If column headings should be shown. 723 | * @param {string} version - Which ESI version to use for the request. 724 | * @customfunction 725 | */ 726 | function contracts_public_bids_contract(contract_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 727 | if (!contract_id) throw new Error(`contract_id is required.`); 728 | return invoke('contracts_public_bids_contract', { contract_id, show_column_headings, version }); 729 | } 730 | 731 | /** 732 | * Lists items of a public contract 733 | * 734 | * @param {number} contract_id - ID of a contract 735 | * @param {boolean} show_column_headings - If column headings should be shown. 736 | * @param {string} version - Which ESI version to use for the request. 737 | * @customfunction 738 | */ 739 | function contracts_public_items_contract(contract_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 740 | if (!contract_id) throw new Error(`contract_id is required.`); 741 | return invoke('contracts_public_items_contract', { contract_id, show_column_headings, version }); 742 | } 743 | 744 | /** 745 | * Returns a paginated list of all public contracts in the given region 746 | * 747 | * @param {number} region_id - An EVE region id 748 | * @param {boolean} show_column_headings - If column headings should be shown. 749 | * @param {string} version - Which ESI version to use for the request. 750 | * @customfunction 751 | */ 752 | function contracts_public_region(region_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 753 | if (!region_id) throw new Error(`region_id is required.`); 754 | return invoke('contracts_public_region', { region_id, show_column_headings, version }); 755 | } 756 | 757 | /** 758 | * Extraction timers for all moon chunks being extracted by refineries belonging to a corporation. 759 | * 760 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 761 | * @param {boolean} show_column_headings - If column headings should be shown. 762 | * @param {string} version - Which ESI version to use for the request. 763 | * @customfunction 764 | */ 765 | function corporation_corporation_mining_extractions(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 766 | return invoke('corporation_corporation_mining_extractions', { name, show_column_headings, version }); 767 | } 768 | 769 | /** 770 | * Paginated list of all entities capable of observing and recording mining for a corporation 771 | * 772 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 773 | * @param {boolean} show_column_headings - If column headings should be shown. 774 | * @param {string} version - Which ESI version to use for the request. 775 | * @customfunction 776 | */ 777 | function corporation_corporation_mining_observers(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 778 | return invoke('corporation_corporation_mining_observers', { name, show_column_headings, version }); 779 | } 780 | 781 | /** 782 | * Paginated record of all mining seen by an observer 783 | * 784 | * @param {number} observer_id - A mining observer id 785 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 786 | * @param {boolean} show_column_headings - If column headings should be shown. 787 | * @param {string} version - Which ESI version to use for the request. 788 | * @customfunction 789 | */ 790 | function corporation_corporation_mining_observers_observer(observer_id: number, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 791 | if (!observer_id) throw new Error(`observer_id is required.`); 792 | return invoke('corporation_corporation_mining_observers_observer', { observer_id, name, show_column_headings, version }); 793 | } 794 | 795 | /** 796 | * Public information about a corporation 797 | * 798 | * @param {number} corporation_id - An EVE corporation ID 799 | * @param {boolean} show_column_headings - If column headings should be shown. 800 | * @param {string} version - Which ESI version to use for the request. 801 | * @customfunction 802 | */ 803 | function corporations_corporation(corporation_id: number, show_column_headings: boolean = true, version: string = "v5"): SheetsArray { 804 | if (!corporation_id) throw new Error(`corporation_id is required.`); 805 | return invoke('corporations_corporation', { corporation_id, show_column_headings, version }); 806 | } 807 | 808 | /** 809 | * Get a list of all the alliances a corporation has been a member of 810 | * 811 | * @param {number} corporation_id - An EVE corporation ID 812 | * @param {boolean} show_column_headings - If column headings should be shown. 813 | * @param {string} version - Which ESI version to use for the request. 814 | * @customfunction 815 | */ 816 | function corporations_corporation_alliancehistory(corporation_id: number, show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 817 | if (!corporation_id) throw new Error(`corporation_id is required.`); 818 | return invoke('corporations_corporation_alliancehistory', { corporation_id, show_column_headings, version }); 819 | } 820 | 821 | /** 822 | * Return a list of the corporation assets 823 | * 824 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 825 | * @param {boolean} show_column_headings - If column headings should be shown. 826 | * @param {string} version - Which ESI version to use for the request. 827 | * @customfunction 828 | */ 829 | function corporations_corporation_assets(name?: string, show_column_headings: boolean = true, version: string = "v5"): SheetsArray { 830 | return invoke('corporations_corporation_assets', { name, show_column_headings, version }); 831 | } 832 | 833 | /** 834 | * Return locations for a set of item ids, which you can get from corporation assets endpoint. Coordinates for items in hangars or stations are set to (0,0,0) 835 | * 836 | * @param {number|number[]} item_ids - A list of item ids 837 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 838 | * @param {boolean} show_column_headings - If column headings should be shown. 839 | * @param {string} version - Which ESI version to use for the request. 840 | * @customfunction 841 | */ 842 | function corporations_corporation_assets_locations(item_ids: number|number[], name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 843 | if (!item_ids) throw new Error(`item_ids is required.`); 844 | return invoke('corporations_corporation_assets_locations', { item_ids, name, show_column_headings, version }); 845 | } 846 | 847 | /** 848 | * Return names for a set of item ids, which you can get from corporation assets endpoint. Only valid for items that can customize names, like containers or ships 849 | * 850 | * @param {number|number[]} item_ids - A list of item ids 851 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 852 | * @param {boolean} show_column_headings - If column headings should be shown. 853 | * @param {string} version - Which ESI version to use for the request. 854 | * @customfunction 855 | */ 856 | function corporations_corporation_assets_names(item_ids: number|number[], name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 857 | if (!item_ids) throw new Error(`item_ids is required.`); 858 | return invoke('corporations_corporation_assets_names', { item_ids, name, show_column_headings, version }); 859 | } 860 | 861 | /** 862 | * Returns a list of blueprints the corporation owns 863 | * 864 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 865 | * @param {boolean} show_column_headings - If column headings should be shown. 866 | * @param {string} version - Which ESI version to use for the request. 867 | * @customfunction 868 | */ 869 | function corporations_corporation_blueprints(name?: string, show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 870 | return invoke('corporations_corporation_blueprints', { name, show_column_headings, version }); 871 | } 872 | 873 | /** 874 | * Return contacts of a corporation 875 | * 876 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 877 | * @param {boolean} show_column_headings - If column headings should be shown. 878 | * @param {string} version - Which ESI version to use for the request. 879 | * @customfunction 880 | */ 881 | function corporations_corporation_contacts(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 882 | return invoke('corporations_corporation_contacts', { name, show_column_headings, version }); 883 | } 884 | 885 | /** 886 | * Return custom labels for a corporation's contacts 887 | * 888 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 889 | * @param {boolean} show_column_headings - If column headings should be shown. 890 | * @param {string} version - Which ESI version to use for the request. 891 | * @customfunction 892 | */ 893 | function corporations_corporation_contacts_labels(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 894 | return invoke('corporations_corporation_contacts_labels', { name, show_column_headings, version }); 895 | } 896 | 897 | /** 898 | * Returns logs recorded in the past seven days from all audit log secure containers (ALSC) owned by a given corporation 899 | * 900 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 901 | * @param {boolean} show_column_headings - If column headings should be shown. 902 | * @param {string} version - Which ESI version to use for the request. 903 | * @customfunction 904 | */ 905 | function corporations_corporation_containers_logs(name?: string, show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 906 | return invoke('corporations_corporation_containers_logs', { name, show_column_headings, version }); 907 | } 908 | 909 | /** 910 | * Returns contracts available to a corporation, only if the corporation is issuer, acceptor or assignee. Only returns contracts no older than 30 days, or if the status is "in_progress". 911 | * 912 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 913 | * @param {boolean} show_column_headings - If column headings should be shown. 914 | * @param {string} version - Which ESI version to use for the request. 915 | * @customfunction 916 | */ 917 | function corporations_corporation_contracts(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 918 | return invoke('corporations_corporation_contracts', { name, show_column_headings, version }); 919 | } 920 | 921 | /** 922 | * Lists bids on a particular auction contract 923 | * 924 | * @param {number} contract_id - ID of a contract 925 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 926 | * @param {boolean} show_column_headings - If column headings should be shown. 927 | * @param {string} version - Which ESI version to use for the request. 928 | * @customfunction 929 | */ 930 | function corporations_corporation_contracts_contract_bids(contract_id: number, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 931 | if (!contract_id) throw new Error(`contract_id is required.`); 932 | return invoke('corporations_corporation_contracts_contract_bids', { contract_id, name, show_column_headings, version }); 933 | } 934 | 935 | /** 936 | * Lists items of a particular contract 937 | * 938 | * @param {number} contract_id - ID of a contract 939 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 940 | * @param {boolean} show_column_headings - If column headings should be shown. 941 | * @param {string} version - Which ESI version to use for the request. 942 | * @customfunction 943 | */ 944 | function corporations_corporation_contracts_contract_items(contract_id: number, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 945 | if (!contract_id) throw new Error(`contract_id is required.`); 946 | return invoke('corporations_corporation_contracts_contract_items', { contract_id, name, show_column_headings, version }); 947 | } 948 | 949 | /** 950 | * List customs offices owned by a corporation 951 | * 952 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 953 | * @param {boolean} show_column_headings - If column headings should be shown. 954 | * @param {string} version - Which ESI version to use for the request. 955 | * @customfunction 956 | */ 957 | function corporations_corporation_customs_offices(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 958 | return invoke('corporations_corporation_customs_offices', { name, show_column_headings, version }); 959 | } 960 | 961 | /** 962 | * Return corporation hangar and wallet division names, only show if a division is not using the default name 963 | * 964 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 965 | * @param {boolean} show_column_headings - If column headings should be shown. 966 | * @param {string} version - Which ESI version to use for the request. 967 | * @customfunction 968 | */ 969 | function corporations_corporation_divisions(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 970 | return invoke('corporations_corporation_divisions', { name, show_column_headings, version }); 971 | } 972 | 973 | /** 974 | * Return a corporation's facilities 975 | * 976 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 977 | * @param {boolean} show_column_headings - If column headings should be shown. 978 | * @param {string} version - Which ESI version to use for the request. 979 | * @customfunction 980 | */ 981 | function corporations_corporation_facilities(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 982 | return invoke('corporations_corporation_facilities', { name, show_column_headings, version }); 983 | } 984 | 985 | /** 986 | * Statistics about a corporation involved in faction warfare 987 | * 988 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 989 | * @param {boolean} show_column_headings - If column headings should be shown. 990 | * @param {string} version - Which ESI version to use for the request. 991 | * @customfunction 992 | */ 993 | function corporations_corporation_fw_stats(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 994 | return invoke('corporations_corporation_fw_stats', { name, show_column_headings, version }); 995 | } 996 | 997 | /** 998 | * Get the icon urls for a corporation 999 | * 1000 | * @param {number} corporation_id - An EVE corporation ID 1001 | * @param {boolean} show_column_headings - If column headings should be shown. 1002 | * @param {string} version - Which ESI version to use for the request. 1003 | * @customfunction 1004 | */ 1005 | function corporations_corporation_icons(corporation_id: number, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1006 | if (!corporation_id) throw new Error(`corporation_id is required.`); 1007 | return invoke('corporations_corporation_icons', { corporation_id, show_column_headings, version }); 1008 | } 1009 | 1010 | /** 1011 | * List industry jobs run by a corporation 1012 | * 1013 | * @param {boolean} include_completed - Whether to retrieve completed corporation industry jobs. Only includes jobs from the past 90 days 1014 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1015 | * @param {boolean} show_column_headings - If column headings should be shown. 1016 | * @param {string} version - Which ESI version to use for the request. 1017 | * @customfunction 1018 | */ 1019 | function corporations_corporation_industry_jobs(include_completed?: boolean, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1020 | return invoke('corporations_corporation_industry_jobs', { include_completed, name, show_column_headings, version }); 1021 | } 1022 | 1023 | /** 1024 | * Get a list of a corporation's kills and losses going back 90 days 1025 | * 1026 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1027 | * @param {boolean} show_column_headings - If column headings should be shown. 1028 | * @param {string} version - Which ESI version to use for the request. 1029 | * @customfunction 1030 | */ 1031 | function corporations_corporation_killmails_recent(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1032 | return invoke('corporations_corporation_killmails_recent', { name, show_column_headings, version }); 1033 | } 1034 | 1035 | /** 1036 | * Returns a corporation's medals 1037 | * 1038 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1039 | * @param {boolean} show_column_headings - If column headings should be shown. 1040 | * @param {string} version - Which ESI version to use for the request. 1041 | * @customfunction 1042 | */ 1043 | function corporations_corporation_medals(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1044 | return invoke('corporations_corporation_medals', { name, show_column_headings, version }); 1045 | } 1046 | 1047 | /** 1048 | * Returns medals issued by a corporation 1049 | * 1050 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1051 | * @param {boolean} show_column_headings - If column headings should be shown. 1052 | * @param {string} version - Which ESI version to use for the request. 1053 | * @customfunction 1054 | */ 1055 | function corporations_corporation_medals_issued(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1056 | return invoke('corporations_corporation_medals_issued', { name, show_column_headings, version }); 1057 | } 1058 | 1059 | /** 1060 | * Return the current member list of a corporation, the token's character need to be a member of the corporation. 1061 | * 1062 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1063 | * @param {boolean} show_column_headings - If column headings should be shown. 1064 | * @param {string} version - Which ESI version to use for the request. 1065 | * @customfunction 1066 | */ 1067 | function corporations_corporation_members(name?: string, show_column_headings: boolean = true, version: string = "v4"): SheetsArray { 1068 | return invoke('corporations_corporation_members', { name, show_column_headings, version }); 1069 | } 1070 | 1071 | /** 1072 | * Return a corporation's member limit, not including CEO himself 1073 | * 1074 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1075 | * @param {boolean} show_column_headings - If column headings should be shown. 1076 | * @param {string} version - Which ESI version to use for the request. 1077 | * @customfunction 1078 | */ 1079 | function corporations_corporation_members_limit(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1080 | return invoke('corporations_corporation_members_limit', { name, show_column_headings, version }); 1081 | } 1082 | 1083 | /** 1084 | * Returns a corporation's members' titles 1085 | * 1086 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1087 | * @param {boolean} show_column_headings - If column headings should be shown. 1088 | * @param {string} version - Which ESI version to use for the request. 1089 | * @customfunction 1090 | */ 1091 | function corporations_corporation_members_titles(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1092 | return invoke('corporations_corporation_members_titles', { name, show_column_headings, version }); 1093 | } 1094 | 1095 | /** 1096 | * Returns additional information about a corporation's members which helps tracking their activities 1097 | * 1098 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1099 | * @param {boolean} show_column_headings - If column headings should be shown. 1100 | * @param {string} version - Which ESI version to use for the request. 1101 | * @customfunction 1102 | */ 1103 | function corporations_corporation_membertracking(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1104 | return invoke('corporations_corporation_membertracking', { name, show_column_headings, version }); 1105 | } 1106 | 1107 | /** 1108 | * List open market orders placed on behalf of a corporation 1109 | * 1110 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1111 | * @param {boolean} show_column_headings - If column headings should be shown. 1112 | * @param {string} version - Which ESI version to use for the request. 1113 | * @customfunction 1114 | */ 1115 | function corporations_corporation_orders(name?: string, show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 1116 | return invoke('corporations_corporation_orders', { name, show_column_headings, version }); 1117 | } 1118 | 1119 | /** 1120 | * List cancelled and expired market orders placed on behalf of a corporation up to 90 days in the past. 1121 | * 1122 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1123 | * @param {boolean} show_column_headings - If column headings should be shown. 1124 | * @param {string} version - Which ESI version to use for the request. 1125 | * @customfunction 1126 | */ 1127 | function corporations_corporation_orders_history(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1128 | return invoke('corporations_corporation_orders_history', { name, show_column_headings, version }); 1129 | } 1130 | 1131 | /** 1132 | * Return the roles of all members if the character has the personnel manager role or any grantable role. 1133 | * 1134 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1135 | * @param {boolean} show_column_headings - If column headings should be shown. 1136 | * @param {string} version - Which ESI version to use for the request. 1137 | * @customfunction 1138 | */ 1139 | function corporations_corporation_roles(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1140 | return invoke('corporations_corporation_roles', { name, show_column_headings, version }); 1141 | } 1142 | 1143 | /** 1144 | * Return how roles have changed for a coporation's members, up to a month 1145 | * 1146 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1147 | * @param {boolean} show_column_headings - If column headings should be shown. 1148 | * @param {string} version - Which ESI version to use for the request. 1149 | * @customfunction 1150 | */ 1151 | function corporations_corporation_roles_history(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1152 | return invoke('corporations_corporation_roles_history', { name, show_column_headings, version }); 1153 | } 1154 | 1155 | /** 1156 | * Return the current shareholders of a corporation. 1157 | * 1158 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1159 | * @param {boolean} show_column_headings - If column headings should be shown. 1160 | * @param {string} version - Which ESI version to use for the request. 1161 | * @customfunction 1162 | */ 1163 | function corporations_corporation_shareholders(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1164 | return invoke('corporations_corporation_shareholders', { name, show_column_headings, version }); 1165 | } 1166 | 1167 | /** 1168 | * Return corporation standings from agents, NPC corporations, and factions 1169 | * 1170 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1171 | * @param {boolean} show_column_headings - If column headings should be shown. 1172 | * @param {string} version - Which ESI version to use for the request. 1173 | * @customfunction 1174 | */ 1175 | function corporations_corporation_standings(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1176 | return invoke('corporations_corporation_standings', { name, show_column_headings, version }); 1177 | } 1178 | 1179 | /** 1180 | * Returns list of corporation starbases (POSes) 1181 | * 1182 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1183 | * @param {boolean} show_column_headings - If column headings should be shown. 1184 | * @param {string} version - Which ESI version to use for the request. 1185 | * @customfunction 1186 | */ 1187 | function corporations_corporation_starbases(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1188 | return invoke('corporations_corporation_starbases', { name, show_column_headings, version }); 1189 | } 1190 | 1191 | /** 1192 | * Returns various settings and fuels of a starbase (POS) 1193 | * 1194 | * @param {number} system_id - The solar system this starbase (POS) is located in, 1195 | * @param {number} starbase_id - An EVE starbase (POS) ID 1196 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1197 | * @param {boolean} show_column_headings - If column headings should be shown. 1198 | * @param {string} version - Which ESI version to use for the request. 1199 | * @customfunction 1200 | */ 1201 | function corporations_corporation_starbases_starbase(system_id: number, starbase_id: number, name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1202 | if (!system_id) throw new Error(`system_id is required.`); 1203 | if (!starbase_id) throw new Error(`starbase_id is required.`); 1204 | return invoke('corporations_corporation_starbases_starbase', { system_id, starbase_id, name, show_column_headings, version }); 1205 | } 1206 | 1207 | /** 1208 | * Get a list of corporation structures. This route's version includes the changes to structures detailed in this blog: https://www.eveonline.com/article/upwell-2.0-structures-changes-coming-on-february-13th 1209 | * 1210 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1211 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1212 | * @param {boolean} show_column_headings - If column headings should be shown. 1213 | * @param {string} version - Which ESI version to use for the request. 1214 | * @customfunction 1215 | */ 1216 | function corporations_corporation_structures(language?: string, name?: string, show_column_headings: boolean = true, version: string = "v4"): SheetsArray { 1217 | return invoke('corporations_corporation_structures', { language, name, show_column_headings, version }); 1218 | } 1219 | 1220 | /** 1221 | * Returns a corporation's titles 1222 | * 1223 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1224 | * @param {boolean} show_column_headings - If column headings should be shown. 1225 | * @param {string} version - Which ESI version to use for the request. 1226 | * @customfunction 1227 | */ 1228 | function corporations_corporation_titles(name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1229 | return invoke('corporations_corporation_titles', { name, show_column_headings, version }); 1230 | } 1231 | 1232 | /** 1233 | * Get a corporation's wallets 1234 | * 1235 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1236 | * @param {boolean} show_column_headings - If column headings should be shown. 1237 | * @param {string} version - Which ESI version to use for the request. 1238 | * @customfunction 1239 | */ 1240 | function corporations_corporation_wallets(name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1241 | return invoke('corporations_corporation_wallets', { name, show_column_headings, version }); 1242 | } 1243 | 1244 | /** 1245 | * Retrieve the given corporation's wallet journal for the given division going 30 days back 1246 | * 1247 | * @param {number} division - Wallet key of the division to fetch journals from 1248 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1249 | * @param {boolean} show_column_headings - If column headings should be shown. 1250 | * @param {string} version - Which ESI version to use for the request. 1251 | * @customfunction 1252 | */ 1253 | function corporations_corporation_wallets_division_journal(division: number, name?: string, show_column_headings: boolean = true, version: string = "v4"): SheetsArray { 1254 | if (!division) throw new Error(`division is required.`); 1255 | return invoke('corporations_corporation_wallets_division_journal', { division, name, show_column_headings, version }); 1256 | } 1257 | 1258 | /** 1259 | * Get wallet transactions of a corporation 1260 | * 1261 | * @param {number} division - Wallet key of the division to fetch journals from 1262 | * @param {number} from_id - Only show journal entries happened before the transaction referenced by this id 1263 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1264 | * @param {boolean} show_column_headings - If column headings should be shown. 1265 | * @param {string} version - Which ESI version to use for the request. 1266 | * @customfunction 1267 | */ 1268 | function corporations_corporation_wallets_division_transactions(division: number, from_id?: number, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1269 | if (!division) throw new Error(`division is required.`); 1270 | return invoke('corporations_corporation_wallets_division_transactions', { division, from_id, name, show_column_headings, version }); 1271 | } 1272 | 1273 | /** 1274 | * Get a list of npc corporations 1275 | * 1276 | * @param {boolean} show_column_headings - If column headings should be shown. 1277 | * @param {string} version - Which ESI version to use for the request. 1278 | * @customfunction 1279 | */ 1280 | function corporations_npccorps(show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1281 | return invoke('corporations_npccorps', { show_column_headings, version }); 1282 | } 1283 | 1284 | /** 1285 | * Get a list of dogma attribute ids 1286 | * 1287 | * @param {boolean} show_column_headings - If column headings should be shown. 1288 | * @param {string} version - Which ESI version to use for the request. 1289 | * @customfunction 1290 | */ 1291 | function dogma_attributes(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1292 | return invoke('dogma_attributes', { show_column_headings, version }); 1293 | } 1294 | 1295 | /** 1296 | * Get information on a dogma attribute 1297 | * 1298 | * @param {number} attribute_id - A dogma attribute ID 1299 | * @param {boolean} show_column_headings - If column headings should be shown. 1300 | * @param {string} version - Which ESI version to use for the request. 1301 | * @customfunction 1302 | */ 1303 | function dogma_attributes_attribute(attribute_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1304 | if (!attribute_id) throw new Error(`attribute_id is required.`); 1305 | return invoke('dogma_attributes_attribute', { attribute_id, show_column_headings, version }); 1306 | } 1307 | 1308 | /** 1309 | * Returns info about a dynamic item resulting from mutation with a mutaplasmid. 1310 | * 1311 | * @param {number} type_id - type_id integer 1312 | * @param {number} item_id - item_id integer 1313 | * @param {boolean} show_column_headings - If column headings should be shown. 1314 | * @param {string} version - Which ESI version to use for the request. 1315 | * @customfunction 1316 | */ 1317 | function dogma_dynamic_items_type_item(type_id: number, item_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1318 | if (!type_id) throw new Error(`type_id is required.`); 1319 | if (!item_id) throw new Error(`item_id is required.`); 1320 | return invoke('dogma_dynamic_items_type_item', { type_id, item_id, show_column_headings, version }); 1321 | } 1322 | 1323 | /** 1324 | * Get a list of dogma effect ids 1325 | * 1326 | * @param {boolean} show_column_headings - If column headings should be shown. 1327 | * @param {string} version - Which ESI version to use for the request. 1328 | * @customfunction 1329 | */ 1330 | function dogma_effects(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1331 | return invoke('dogma_effects', { show_column_headings, version }); 1332 | } 1333 | 1334 | /** 1335 | * Get information on a dogma effect 1336 | * 1337 | * @param {number} effect_id - A dogma effect ID 1338 | * @param {boolean} show_column_headings - If column headings should be shown. 1339 | * @param {string} version - Which ESI version to use for the request. 1340 | * @customfunction 1341 | */ 1342 | function dogma_effects_effect(effect_id: number, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1343 | if (!effect_id) throw new Error(`effect_id is required.`); 1344 | return invoke('dogma_effects_effect', { effect_id, show_column_headings, version }); 1345 | } 1346 | 1347 | /** 1348 | * EVE Server status 1349 | * 1350 | * @param {boolean} show_column_headings - If column headings should be shown. 1351 | * @param {string} version - Which ESI version to use for the request. 1352 | * @customfunction 1353 | */ 1354 | function eve_status(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1355 | return invoke('eve_status', { show_column_headings, version }); 1356 | } 1357 | 1358 | /** 1359 | * Return details about a fleet 1360 | * 1361 | * @param {number} fleet_id - ID for a fleet 1362 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1363 | * @param {boolean} show_column_headings - If column headings should be shown. 1364 | * @param {string} version - Which ESI version to use for the request. 1365 | * @customfunction 1366 | */ 1367 | function fleets_fleet(fleet_id: number, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1368 | if (!fleet_id) throw new Error(`fleet_id is required.`); 1369 | return invoke('fleets_fleet', { fleet_id, name, show_column_headings, version }); 1370 | } 1371 | 1372 | /** 1373 | * Return information about fleet members 1374 | * 1375 | * @param {number} fleet_id - ID for a fleet 1376 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1377 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1378 | * @param {boolean} show_column_headings - If column headings should be shown. 1379 | * @param {string} version - Which ESI version to use for the request. 1380 | * @customfunction 1381 | */ 1382 | function fleets_fleet_members(fleet_id: number, language?: string, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1383 | if (!fleet_id) throw new Error(`fleet_id is required.`); 1384 | return invoke('fleets_fleet_members', { fleet_id, language, name, show_column_headings, version }); 1385 | } 1386 | 1387 | /** 1388 | * Return information about wings in a fleet 1389 | * 1390 | * @param {number} fleet_id - ID for a fleet 1391 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1392 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1393 | * @param {boolean} show_column_headings - If column headings should be shown. 1394 | * @param {string} version - Which ESI version to use for the request. 1395 | * @customfunction 1396 | */ 1397 | function fleets_fleet_wings(fleet_id: number, language?: string, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1398 | if (!fleet_id) throw new Error(`fleet_id is required.`); 1399 | return invoke('fleets_fleet_wings', { fleet_id, language, name, show_column_headings, version }); 1400 | } 1401 | 1402 | /** 1403 | * Top 4 leaderboard of factions for kills and victory points separated by total, last week and yesterday 1404 | * 1405 | * @param {boolean} show_column_headings - If column headings should be shown. 1406 | * @param {string} version - Which ESI version to use for the request. 1407 | * @customfunction 1408 | */ 1409 | function fw_leaderboards(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1410 | return invoke('fw_leaderboards', { show_column_headings, version }); 1411 | } 1412 | 1413 | /** 1414 | * Top 100 leaderboard of pilots for kills and victory points separated by total, last week and yesterday 1415 | * 1416 | * @param {boolean} show_column_headings - If column headings should be shown. 1417 | * @param {string} version - Which ESI version to use for the request. 1418 | * @customfunction 1419 | */ 1420 | function fw_leaderboards_characters(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1421 | return invoke('fw_leaderboards_characters', { show_column_headings, version }); 1422 | } 1423 | 1424 | /** 1425 | * Top 10 leaderboard of corporations for kills and victory points separated by total, last week and yesterday 1426 | * 1427 | * @param {boolean} show_column_headings - If column headings should be shown. 1428 | * @param {string} version - Which ESI version to use for the request. 1429 | * @customfunction 1430 | */ 1431 | function fw_leaderboards_corporations(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1432 | return invoke('fw_leaderboards_corporations', { show_column_headings, version }); 1433 | } 1434 | 1435 | /** 1436 | * Statistical overviews of factions involved in faction warfare 1437 | * 1438 | * @param {boolean} show_column_headings - If column headings should be shown. 1439 | * @param {string} version - Which ESI version to use for the request. 1440 | * @customfunction 1441 | */ 1442 | function fw_stats(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1443 | return invoke('fw_stats', { show_column_headings, version }); 1444 | } 1445 | 1446 | /** 1447 | * An overview of the current ownership of faction warfare solar systems 1448 | * 1449 | * @param {boolean} show_column_headings - If column headings should be shown. 1450 | * @param {string} version - Which ESI version to use for the request. 1451 | * @customfunction 1452 | */ 1453 | function fw_systems(show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1454 | return invoke('fw_systems', { show_column_headings, version }); 1455 | } 1456 | 1457 | /** 1458 | * Data about which NPC factions are at war 1459 | * 1460 | * @param {boolean} show_column_headings - If column headings should be shown. 1461 | * @param {string} version - Which ESI version to use for the request. 1462 | * @customfunction 1463 | */ 1464 | function fw_wars(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1465 | return invoke('fw_wars', { show_column_headings, version }); 1466 | } 1467 | 1468 | /** 1469 | * Return a list of current incursions 1470 | * 1471 | * @param {boolean} show_column_headings - If column headings should be shown. 1472 | * @param {string} version - Which ESI version to use for the request. 1473 | * @customfunction 1474 | */ 1475 | function incursions(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1476 | return invoke('incursions', { show_column_headings, version }); 1477 | } 1478 | 1479 | /** 1480 | * Return a list of industry facilities 1481 | * 1482 | * @param {boolean} show_column_headings - If column headings should be shown. 1483 | * @param {string} version - Which ESI version to use for the request. 1484 | * @customfunction 1485 | */ 1486 | function industry_facilities(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1487 | return invoke('industry_facilities', { show_column_headings, version }); 1488 | } 1489 | 1490 | /** 1491 | * Return cost indices for solar systems 1492 | * 1493 | * @param {boolean} show_column_headings - If column headings should be shown. 1494 | * @param {string} version - Which ESI version to use for the request. 1495 | * @customfunction 1496 | */ 1497 | function industry_systems(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1498 | return invoke('industry_systems', { show_column_headings, version }); 1499 | } 1500 | 1501 | /** 1502 | * Return available insurance levels for all ship types 1503 | * 1504 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1505 | * @param {boolean} show_column_headings - If column headings should be shown. 1506 | * @param {string} version - Which ESI version to use for the request. 1507 | * @customfunction 1508 | */ 1509 | function insurance_prices(language?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1510 | return invoke('insurance_prices', { language, show_column_headings, version }); 1511 | } 1512 | 1513 | /** 1514 | * Return a single killmail from its ID and hash 1515 | * 1516 | * @param {number} killmail_id - The killmail ID to be queried 1517 | * @param {string} killmail_hash - The killmail hash for verification 1518 | * @param {boolean} show_column_headings - If column headings should be shown. 1519 | * @param {string} version - Which ESI version to use for the request. 1520 | * @customfunction 1521 | */ 1522 | function killmails_killmail_killmail_hash(killmail_id: number, killmail_hash: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1523 | if (!killmail_id) throw new Error(`killmail_id is required.`); 1524 | if (!killmail_hash) throw new Error(`killmail_hash is required.`); 1525 | return invoke('killmails_killmail_killmail_hash', { killmail_id, killmail_hash, show_column_headings, version }); 1526 | } 1527 | 1528 | /** 1529 | * Return a list of offers from a specific corporation's loyalty store 1530 | * 1531 | * @param {number} corporation_id - An EVE corporation ID 1532 | * @param {boolean} show_column_headings - If column headings should be shown. 1533 | * @param {string} version - Which ESI version to use for the request. 1534 | * @customfunction 1535 | */ 1536 | function loyalty_stores_corporation_offers(corporation_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1537 | if (!corporation_id) throw new Error(`corporation_id is required.`); 1538 | return invoke('loyalty_stores_corporation_offers', { corporation_id, show_column_headings, version }); 1539 | } 1540 | 1541 | /** 1542 | * Get a list of item groups 1543 | * 1544 | * @param {boolean} show_column_headings - If column headings should be shown. 1545 | * @param {string} version - Which ESI version to use for the request. 1546 | * @customfunction 1547 | */ 1548 | function markets_groups(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1549 | return invoke('markets_groups', { show_column_headings, version }); 1550 | } 1551 | 1552 | /** 1553 | * Get information on an item group 1554 | * 1555 | * @param {number} market_group_id - An Eve item group ID 1556 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1557 | * @param {boolean} show_column_headings - If column headings should be shown. 1558 | * @param {string} version - Which ESI version to use for the request. 1559 | * @customfunction 1560 | */ 1561 | function markets_groups_market_group(market_group_id: number, language?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1562 | if (!market_group_id) throw new Error(`market_group_id is required.`); 1563 | return invoke('markets_groups_market_group', { market_group_id, language, show_column_headings, version }); 1564 | } 1565 | 1566 | /** 1567 | * Return a list of prices 1568 | * 1569 | * @param {boolean} show_column_headings - If column headings should be shown. 1570 | * @param {string} version - Which ESI version to use for the request. 1571 | * @customfunction 1572 | */ 1573 | function markets_prices(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1574 | return invoke('markets_prices', { show_column_headings, version }); 1575 | } 1576 | 1577 | /** 1578 | * Return a list of historical market statistics for the specified type in a region 1579 | * 1580 | * @param {number} type_id - Return statistics for this type 1581 | * @param {number} region_id - Return statistics in this region 1582 | * @param {boolean} show_column_headings - If column headings should be shown. 1583 | * @param {string} version - Which ESI version to use for the request. 1584 | * @customfunction 1585 | */ 1586 | function markets_region_history(type_id: number, region_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1587 | if (!type_id) throw new Error(`type_id is required.`); 1588 | if (!region_id) throw new Error(`region_id is required.`); 1589 | return invoke('markets_region_history', { type_id, region_id, show_column_headings, version }); 1590 | } 1591 | 1592 | /** 1593 | * Return a list of orders in a region 1594 | * 1595 | * @param {number} region_id - Return orders in this region 1596 | * @param {string} order_type - Filter buy/sell orders, return all orders by default. If you query without type_id, we always return both buy and sell orders 1597 | * @param {number} type_id - Return orders only for this type 1598 | * @param {boolean} show_column_headings - If column headings should be shown. 1599 | * @param {string} version - Which ESI version to use for the request. 1600 | * @customfunction 1601 | */ 1602 | function markets_region_orders(region_id: number, order_type: string, type_id?: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1603 | if (!region_id) throw new Error(`region_id is required.`); 1604 | if (!order_type) throw new Error(`order_type is required.`); 1605 | return invoke('markets_region_orders', { region_id, order_type, type_id, show_column_headings, version }); 1606 | } 1607 | 1608 | /** 1609 | * Return a list of type IDs that have active orders in the region, for efficient market indexing. 1610 | * 1611 | * @param {number} region_id - Return statistics in this region 1612 | * @param {boolean} show_column_headings - If column headings should be shown. 1613 | * @param {string} version - Which ESI version to use for the request. 1614 | * @customfunction 1615 | */ 1616 | function markets_region_types(region_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1617 | if (!region_id) throw new Error(`region_id is required.`); 1618 | return invoke('markets_region_types', { region_id, show_column_headings, version }); 1619 | } 1620 | 1621 | /** 1622 | * Return all orders in a structure 1623 | * 1624 | * @param {number} structure_id - Return orders in this structure 1625 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1626 | * @param {boolean} show_column_headings - If column headings should be shown. 1627 | * @param {string} version - Which ESI version to use for the request. 1628 | * @customfunction 1629 | */ 1630 | function markets_structures_structure(structure_id: number, name?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1631 | if (!structure_id) throw new Error(`structure_id is required.`); 1632 | return invoke('markets_structures_structure', { structure_id, name, show_column_headings, version }); 1633 | } 1634 | 1635 | /** 1636 | * Get the systems between origin and destination 1637 | * 1638 | * @param {number} origin - origin solar system ID 1639 | * @param {number} destination - destination solar system ID 1640 | * @param {number|number[]} avoid - avoid solar system ID(s) 1641 | * @param {number|number[]} connections - connected solar system pairs 1642 | * @param {string} flag - route security preference 1643 | * @param {boolean} show_column_headings - If column headings should be shown. 1644 | * @param {string} version - Which ESI version to use for the request. 1645 | * @customfunction 1646 | */ 1647 | function route_origin_destination(origin: number, destination: number, avoid?: number|number[], connections?: number|number[], flag?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1648 | if (!origin) throw new Error(`origin is required.`); 1649 | if (!destination) throw new Error(`destination is required.`); 1650 | return invoke('route_origin_destination', { origin, destination, avoid, connections, flag, show_column_headings, version }); 1651 | } 1652 | 1653 | /** 1654 | * Shows sovereignty data for campaigns. 1655 | * 1656 | * @param {boolean} show_column_headings - If column headings should be shown. 1657 | * @param {string} version - Which ESI version to use for the request. 1658 | * @customfunction 1659 | */ 1660 | function sovereignty_campaigns(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1661 | return invoke('sovereignty_campaigns', { show_column_headings, version }); 1662 | } 1663 | 1664 | /** 1665 | * Shows sovereignty information for solar systems 1666 | * 1667 | * @param {boolean} show_column_headings - If column headings should be shown. 1668 | * @param {string} version - Which ESI version to use for the request. 1669 | * @customfunction 1670 | */ 1671 | function sovereignty_map(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1672 | return invoke('sovereignty_map', { show_column_headings, version }); 1673 | } 1674 | 1675 | /** 1676 | * Shows sovereignty data for structures. 1677 | * 1678 | * @param {boolean} show_column_headings - If column headings should be shown. 1679 | * @param {string} version - Which ESI version to use for the request. 1680 | * @customfunction 1681 | */ 1682 | function sovereignty_structures(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1683 | return invoke('sovereignty_structures', { show_column_headings, version }); 1684 | } 1685 | 1686 | /** 1687 | * Get all character ancestries 1688 | * 1689 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1690 | * @param {boolean} show_column_headings - If column headings should be shown. 1691 | * @param {string} version - Which ESI version to use for the request. 1692 | * @customfunction 1693 | */ 1694 | function universe_ancestries(language?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1695 | return invoke('universe_ancestries', { language, show_column_headings, version }); 1696 | } 1697 | 1698 | /** 1699 | * Get information on an asteroid belt 1700 | * 1701 | * @param {number} asteroid_belt_id - asteroid_belt_id integer 1702 | * @param {boolean} show_column_headings - If column headings should be shown. 1703 | * @param {string} version - Which ESI version to use for the request. 1704 | * @customfunction 1705 | */ 1706 | function universe_asteroid_belts_asteroid_belt(asteroid_belt_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1707 | if (!asteroid_belt_id) throw new Error(`asteroid_belt_id is required.`); 1708 | return invoke('universe_asteroid_belts_asteroid_belt', { asteroid_belt_id, show_column_headings, version }); 1709 | } 1710 | 1711 | /** 1712 | * Get a list of bloodlines 1713 | * 1714 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1715 | * @param {boolean} show_column_headings - If column headings should be shown. 1716 | * @param {string} version - Which ESI version to use for the request. 1717 | * @customfunction 1718 | */ 1719 | function universe_bloodlines(language?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1720 | return invoke('universe_bloodlines', { language, show_column_headings, version }); 1721 | } 1722 | 1723 | /** 1724 | * Get a list of item categories 1725 | * 1726 | * @param {boolean} show_column_headings - If column headings should be shown. 1727 | * @param {string} version - Which ESI version to use for the request. 1728 | * @customfunction 1729 | */ 1730 | function universe_categories(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1731 | return invoke('universe_categories', { show_column_headings, version }); 1732 | } 1733 | 1734 | /** 1735 | * Get information of an item category 1736 | * 1737 | * @param {number} category_id - An Eve item category ID 1738 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1739 | * @param {boolean} show_column_headings - If column headings should be shown. 1740 | * @param {string} version - Which ESI version to use for the request. 1741 | * @customfunction 1742 | */ 1743 | function universe_categories_category(category_id: number, language?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1744 | if (!category_id) throw new Error(`category_id is required.`); 1745 | return invoke('universe_categories_category', { category_id, language, show_column_headings, version }); 1746 | } 1747 | 1748 | /** 1749 | * Get a list of constellations 1750 | * 1751 | * @param {boolean} show_column_headings - If column headings should be shown. 1752 | * @param {string} version - Which ESI version to use for the request. 1753 | * @customfunction 1754 | */ 1755 | function universe_constellations(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1756 | return invoke('universe_constellations', { show_column_headings, version }); 1757 | } 1758 | 1759 | /** 1760 | * Get information on a constellation 1761 | * 1762 | * @param {number} constellation_id - constellation_id integer 1763 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1764 | * @param {boolean} show_column_headings - If column headings should be shown. 1765 | * @param {string} version - Which ESI version to use for the request. 1766 | * @customfunction 1767 | */ 1768 | function universe_constellations_constellation(constellation_id: number, language?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1769 | if (!constellation_id) throw new Error(`constellation_id is required.`); 1770 | return invoke('universe_constellations_constellation', { constellation_id, language, show_column_headings, version }); 1771 | } 1772 | 1773 | /** 1774 | * Get a list of factions 1775 | * 1776 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1777 | * @param {boolean} show_column_headings - If column headings should be shown. 1778 | * @param {string} version - Which ESI version to use for the request. 1779 | * @customfunction 1780 | */ 1781 | function universe_factions(language?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1782 | return invoke('universe_factions', { language, show_column_headings, version }); 1783 | } 1784 | 1785 | /** 1786 | * Get a list of graphics 1787 | * 1788 | * @param {boolean} show_column_headings - If column headings should be shown. 1789 | * @param {string} version - Which ESI version to use for the request. 1790 | * @customfunction 1791 | */ 1792 | function universe_graphics(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1793 | return invoke('universe_graphics', { show_column_headings, version }); 1794 | } 1795 | 1796 | /** 1797 | * Get information on a graphic 1798 | * 1799 | * @param {number} graphic_id - graphic_id integer 1800 | * @param {boolean} show_column_headings - If column headings should be shown. 1801 | * @param {string} version - Which ESI version to use for the request. 1802 | * @customfunction 1803 | */ 1804 | function universe_graphics_graphic(graphic_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1805 | if (!graphic_id) throw new Error(`graphic_id is required.`); 1806 | return invoke('universe_graphics_graphic', { graphic_id, show_column_headings, version }); 1807 | } 1808 | 1809 | /** 1810 | * Get a list of item groups 1811 | * 1812 | * @param {boolean} show_column_headings - If column headings should be shown. 1813 | * @param {string} version - Which ESI version to use for the request. 1814 | * @customfunction 1815 | */ 1816 | function universe_groups(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1817 | return invoke('universe_groups', { show_column_headings, version }); 1818 | } 1819 | 1820 | /** 1821 | * Get information on an item group 1822 | * 1823 | * @param {number} group_id - An Eve item group ID 1824 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1825 | * @param {boolean} show_column_headings - If column headings should be shown. 1826 | * @param {string} version - Which ESI version to use for the request. 1827 | * @customfunction 1828 | */ 1829 | function universe_groups_group(group_id: number, language?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1830 | if (!group_id) throw new Error(`group_id is required.`); 1831 | return invoke('universe_groups_group', { group_id, language, show_column_headings, version }); 1832 | } 1833 | 1834 | /** 1835 | * Resolve a set of names to IDs in the following categories: agents, alliances, characters, constellations, corporations factions, inventory_types, regions, stations, and systems. Only exact matches will be returned. All names searched for are cached for 12 hours 1836 | * 1837 | * @param {string|string[]} names - The names to resolve 1838 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1839 | * @param {boolean} show_column_headings - If column headings should be shown. 1840 | * @param {string} version - Which ESI version to use for the request. 1841 | * @customfunction 1842 | */ 1843 | function universe_ids(names: string|string[], language?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1844 | if (!names) throw new Error(`names is required.`); 1845 | return invoke('universe_ids', { names, language, show_column_headings, version }); 1846 | } 1847 | 1848 | /** 1849 | * Get information on a moon 1850 | * 1851 | * @param {number} moon_id - moon_id integer 1852 | * @param {boolean} show_column_headings - If column headings should be shown. 1853 | * @param {string} version - Which ESI version to use for the request. 1854 | * @customfunction 1855 | */ 1856 | function universe_moons_moon(moon_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1857 | if (!moon_id) throw new Error(`moon_id is required.`); 1858 | return invoke('universe_moons_moon', { moon_id, show_column_headings, version }); 1859 | } 1860 | 1861 | /** 1862 | * Resolve a set of IDs to names and categories. Supported ID's for resolving are: Characters, Corporations, Alliances, Stations, Solar Systems, Constellations, Regions, Types, Factions 1863 | * 1864 | * @param {number|number[]} ids - The ids to resolve 1865 | * @param {boolean} show_column_headings - If column headings should be shown. 1866 | * @param {string} version - Which ESI version to use for the request. 1867 | * @customfunction 1868 | */ 1869 | function universe_names(ids: number|number[], show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 1870 | if (!ids) throw new Error(`ids is required.`); 1871 | return invoke('universe_names', { ids, show_column_headings, version }); 1872 | } 1873 | 1874 | /** 1875 | * Get information on a planet 1876 | * 1877 | * @param {number} planet_id - planet_id integer 1878 | * @param {boolean} show_column_headings - If column headings should be shown. 1879 | * @param {string} version - Which ESI version to use for the request. 1880 | * @customfunction 1881 | */ 1882 | function universe_planets_planet(planet_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1883 | if (!planet_id) throw new Error(`planet_id is required.`); 1884 | return invoke('universe_planets_planet', { planet_id, show_column_headings, version }); 1885 | } 1886 | 1887 | /** 1888 | * Get a list of character races 1889 | * 1890 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1891 | * @param {boolean} show_column_headings - If column headings should be shown. 1892 | * @param {string} version - Which ESI version to use for the request. 1893 | * @customfunction 1894 | */ 1895 | function universe_races(language?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1896 | return invoke('universe_races', { language, show_column_headings, version }); 1897 | } 1898 | 1899 | /** 1900 | * Get a list of regions 1901 | * 1902 | * @param {boolean} show_column_headings - If column headings should be shown. 1903 | * @param {string} version - Which ESI version to use for the request. 1904 | * @customfunction 1905 | */ 1906 | function universe_regions(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1907 | return invoke('universe_regions', { show_column_headings, version }); 1908 | } 1909 | 1910 | /** 1911 | * Get information on a region 1912 | * 1913 | * @param {number} region_id - region_id integer 1914 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 1915 | * @param {boolean} show_column_headings - If column headings should be shown. 1916 | * @param {string} version - Which ESI version to use for the request. 1917 | * @customfunction 1918 | */ 1919 | function universe_regions_region(region_id: number, language?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1920 | if (!region_id) throw new Error(`region_id is required.`); 1921 | return invoke('universe_regions_region', { region_id, language, show_column_headings, version }); 1922 | } 1923 | 1924 | /** 1925 | * Get information on a planetary factory schematic 1926 | * 1927 | * @param {number} schematic_id - A PI schematic ID 1928 | * @param {boolean} show_column_headings - If column headings should be shown. 1929 | * @param {string} version - Which ESI version to use for the request. 1930 | * @customfunction 1931 | */ 1932 | function universe_schematics_schematic(schematic_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1933 | if (!schematic_id) throw new Error(`schematic_id is required.`); 1934 | return invoke('universe_schematics_schematic', { schematic_id, show_column_headings, version }); 1935 | } 1936 | 1937 | /** 1938 | * Get information on a stargate 1939 | * 1940 | * @param {number} stargate_id - stargate_id integer 1941 | * @param {boolean} show_column_headings - If column headings should be shown. 1942 | * @param {string} version - Which ESI version to use for the request. 1943 | * @customfunction 1944 | */ 1945 | function universe_stargates_stargate(stargate_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1946 | if (!stargate_id) throw new Error(`stargate_id is required.`); 1947 | return invoke('universe_stargates_stargate', { stargate_id, show_column_headings, version }); 1948 | } 1949 | 1950 | /** 1951 | * Get information on a star 1952 | * 1953 | * @param {number} star_id - star_id integer 1954 | * @param {boolean} show_column_headings - If column headings should be shown. 1955 | * @param {string} version - Which ESI version to use for the request. 1956 | * @customfunction 1957 | */ 1958 | function universe_stars_star(star_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1959 | if (!star_id) throw new Error(`star_id is required.`); 1960 | return invoke('universe_stars_star', { star_id, show_column_headings, version }); 1961 | } 1962 | 1963 | /** 1964 | * Get information on a station 1965 | * 1966 | * @param {number} station_id - station_id integer 1967 | * @param {boolean} show_column_headings - If column headings should be shown. 1968 | * @param {string} version - Which ESI version to use for the request. 1969 | * @customfunction 1970 | */ 1971 | function universe_stations_station(station_id: number, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1972 | if (!station_id) throw new Error(`station_id is required.`); 1973 | return invoke('universe_stations_station', { station_id, show_column_headings, version }); 1974 | } 1975 | 1976 | /** 1977 | * List all public structures 1978 | * 1979 | * @param {string} filter - Only list public structures that have this service online 1980 | * @param {boolean} show_column_headings - If column headings should be shown. 1981 | * @param {string} version - Which ESI version to use for the request. 1982 | * @customfunction 1983 | */ 1984 | function universe_structures(filter?: string, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 1985 | return invoke('universe_structures', { filter, show_column_headings, version }); 1986 | } 1987 | 1988 | /** 1989 | * Returns information on requested structure if you are on the ACL. Otherwise, returns "Forbidden" for all inputs. 1990 | * 1991 | * @param {number} structure_id - An Eve structure ID 1992 | * @param {string} name - Name of the character used for auth. Defaults to the first authenticated character. 1993 | * @param {boolean} show_column_headings - If column headings should be shown. 1994 | * @param {string} version - Which ESI version to use for the request. 1995 | * @customfunction 1996 | */ 1997 | function universe_structures_structure(structure_id: number, name?: string, show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 1998 | if (!structure_id) throw new Error(`structure_id is required.`); 1999 | return invoke('universe_structures_structure', { structure_id, name, show_column_headings, version }); 2000 | } 2001 | 2002 | /** 2003 | * Get the number of jumps in solar systems within the last hour ending at the timestamp of the Last-Modified header, excluding wormhole space. Only systems with jumps will be listed 2004 | * 2005 | * @param {boolean} show_column_headings - If column headings should be shown. 2006 | * @param {string} version - Which ESI version to use for the request. 2007 | * @customfunction 2008 | */ 2009 | function universe_system_jumps(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 2010 | return invoke('universe_system_jumps', { show_column_headings, version }); 2011 | } 2012 | 2013 | /** 2014 | * Get the number of ship, pod and NPC kills per solar system within the last hour ending at the timestamp of the Last-Modified header, excluding wormhole space. Only systems with kills will be listed 2015 | * 2016 | * @param {boolean} show_column_headings - If column headings should be shown. 2017 | * @param {string} version - Which ESI version to use for the request. 2018 | * @customfunction 2019 | */ 2020 | function universe_system_kills(show_column_headings: boolean = true, version: string = "v2"): SheetsArray { 2021 | return invoke('universe_system_kills', { show_column_headings, version }); 2022 | } 2023 | 2024 | /** 2025 | * Get a list of solar systems 2026 | * 2027 | * @param {boolean} show_column_headings - If column headings should be shown. 2028 | * @param {string} version - Which ESI version to use for the request. 2029 | * @customfunction 2030 | */ 2031 | function universe_systems(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 2032 | return invoke('universe_systems', { show_column_headings, version }); 2033 | } 2034 | 2035 | /** 2036 | * Get information on a solar system. 2037 | * 2038 | * @param {number} system_id - system_id integer 2039 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 2040 | * @param {boolean} show_column_headings - If column headings should be shown. 2041 | * @param {string} version - Which ESI version to use for the request. 2042 | * @customfunction 2043 | */ 2044 | function universe_systems_system(system_id: number, language?: string, show_column_headings: boolean = true, version: string = "v4"): SheetsArray { 2045 | if (!system_id) throw new Error(`system_id is required.`); 2046 | return invoke('universe_systems_system', { system_id, language, show_column_headings, version }); 2047 | } 2048 | 2049 | /** 2050 | * Get a list of type ids 2051 | * 2052 | * @param {boolean} show_column_headings - If column headings should be shown. 2053 | * @param {string} version - Which ESI version to use for the request. 2054 | * @customfunction 2055 | */ 2056 | function universe_types(show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 2057 | return invoke('universe_types', { show_column_headings, version }); 2058 | } 2059 | 2060 | /** 2061 | * Get information on a type 2062 | * 2063 | * @param {number} type_id - An Eve item type ID 2064 | * @param {string} language - Language to use in the response, takes precedence over Accept-Language 2065 | * @param {boolean} show_column_headings - If column headings should be shown. 2066 | * @param {string} version - Which ESI version to use for the request. 2067 | * @customfunction 2068 | */ 2069 | function universe_types_type(type_id: number, language?: string, show_column_headings: boolean = true, version: string = "v3"): SheetsArray { 2070 | if (!type_id) throw new Error(`type_id is required.`); 2071 | return invoke('universe_types_type', { type_id, language, show_column_headings, version }); 2072 | } 2073 | 2074 | /** 2075 | * Return a list of wars 2076 | * 2077 | * @param {number} max_war_id - Only return wars with ID smaller than this 2078 | * @param {boolean} show_column_headings - If column headings should be shown. 2079 | * @param {string} version - Which ESI version to use for the request. 2080 | * @customfunction 2081 | */ 2082 | function wars(max_war_id?: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 2083 | return invoke('wars', { max_war_id, show_column_headings, version }); 2084 | } 2085 | 2086 | /** 2087 | * Return details about a war 2088 | * 2089 | * @param {number} war_id - ID for a war 2090 | * @param {boolean} show_column_headings - If column headings should be shown. 2091 | * @param {string} version - Which ESI version to use for the request. 2092 | * @customfunction 2093 | */ 2094 | function wars_war(war_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 2095 | if (!war_id) throw new Error(`war_id is required.`); 2096 | return invoke('wars_war', { war_id, show_column_headings, version }); 2097 | } 2098 | 2099 | /** 2100 | * Return a list of kills related to a war 2101 | * 2102 | * @param {number} war_id - A valid war ID 2103 | * @param {boolean} show_column_headings - If column headings should be shown. 2104 | * @param {string} version - Which ESI version to use for the request. 2105 | * @customfunction 2106 | */ 2107 | function wars_war_killmails(war_id: number, show_column_headings: boolean = true, version: string = "v1"): SheetsArray { 2108 | if (!war_id) throw new Error(`war_id is required.`); 2109 | return invoke('wars_war_killmails', { war_id, show_column_headings, version }); 2110 | } 2111 | --------------------------------------------------------------------------------