├── .gitignore ├── .env.tmpl ├── requirements.txt ├── package.json ├── README.md ├── src ├── using-leiapix-storage.ts ├── using-leiapix-storage.py ├── using-custom-storage.ts └── using-custom-storage.py └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env 4 | env 5 | src/*.js 6 | demoenv 7 | -------------------------------------------------------------------------------- /.env.tmpl: -------------------------------------------------------------------------------- 1 | export ORIGINAL_IMAGE_URL="https://images.pexels.com/photos/38771/pexels-photo-38771.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" 2 | export BACKEND_CLIENT_ID= 3 | export BACKEND_CLIENT_SECRET= 4 | export S3_BUCKET_NAME= 5 | export S3_BUCKET_REGION= 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | boto3==1.26.148 2 | botocore==1.29.148 3 | certifi==2023.5.7 4 | charset-normalizer==3.1.0 5 | deprecation==2.1.0 6 | ecdsa==0.18.0 7 | idna==3.4 8 | jmespath==1.0.1 9 | packaging==23.1 10 | pyasn1==0.5.0 11 | python-dateutil==2.8.2 12 | python-jose==3.3.0 13 | requests==2.31.0 14 | requests-toolbelt==1.0.0 15 | rsa==4.9 16 | s3transfer==0.6.1 17 | six==1.16.0 18 | urllib3==1.26.16 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "restapidemo", 3 | "version": "1.0.1", 4 | "description": "Demo App", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc", 8 | "start": "node ./dist/index.js", 9 | "start:nodejs-provided": "npm run build && source .env && ORIGINAL_IMAGE_URL=$ORIGINAL_IMAGE_URL BACKEND_CLIENT_ID=$BACKEND_CLIENT_ID BACKEND_CLIENT_SECRET=$BACKEND_CLIENT_SECRET node dist/using-leiapix-storage.js", 10 | "start:python-provided": "source .env && ORIGINAL_IMAGE_URL=$ORIGINAL_IMAGE_URL BACKEND_CLIENT_ID=$BACKEND_CLIENT_ID BACKEND_CLIENT_SECRET=$BACKEND_CLIENT_SECRET python3 src/using-leiapix-storage.py", 11 | "start:nodejs-custom": "npm run build && source .env && ORIGINAL_IMAGE_URL=$ORIGINAL_IMAGE_URL BACKEND_CLIENT_ID=$BACKEND_CLIENT_ID BACKEND_CLIENT_SECRET=$BACKEND_CLIENT_SECRET S3_BUCKET_NAME=$S3_BUCKET_NAME S3_BUCKET_REGION=$S3_BUCKET_REGION node dist/using-custom-storage.js", 12 | "start:python-custom": "source .env && ORIGINAL_IMAGE_URL=$ORIGINAL_IMAGE_URL BACKEND_CLIENT_ID=$BACKEND_CLIENT_ID BACKEND_CLIENT_SECRET=$BACKEND_CLIENT_SECRET S3_BUCKET_NAME=$S3_BUCKET_NAME S3_BUCKET_REGION=$S3_BUCKET_REGION python3 src/using-custom-storage.py", 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "author": "", 16 | "license": "ISC", 17 | "devDependencies": { 18 | "@types/node": "^20.1.7", 19 | "@types/uuid": "^9.0.1", 20 | "typescript": "^5.0.4" 21 | }, 22 | "dependencies": { 23 | "@aws-sdk/client-s3": "^3.332.0", 24 | "@aws-sdk/credential-provider-node": "^3.332.0", 25 | "@aws-sdk/s3-request-presigner": "^3.332.0", 26 | "axios": "^1.4.0", 27 | "uuid": "^9.0.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Leia Media Cloud REST API Demo app 2 | 3 | This repo contains examples of backend integration with Media Cloud REST API. 4 | 5 | The examples are provided for two use cases: 6 | * using LeiaPix temporary storage API. Please refer to [NodeJS](src/using-leiapix-storage.ts) and [Python3](src/using-leiapix-storage.py) files to see the code integration examples for each corresponding language. 7 | * using your own S3 storage. Please refer to [NodeJS](src/using-custom-storage.ts) and [Python3](src/using-custom-storage.py) files to see the code integration examples for each corresponding language. 8 | 9 | # Using LeiaPix temporary storage 10 | 11 | ## Configuration 12 | In order to run this script, a set of credentials is used: 13 | `Leia Backend Client ID` and `Leia Backend Client Secret` - to access Leia Media Cloud API. Can be acquired in Leia Account API Section. 14 | 15 | ### Configuring Leia Media Cloud credentials and other parameters (required for both NodeJS and Python3 examples) 16 | Rename `.env.tmpl` into `.env`. Put next env vars in `.env` at root folder. The package.json `start:` script will read these values to be used in the script. 17 | * `ORIGINAL_IMAGE_URL=` - URL of the image to convert to animation or to generate disparity map from 18 | * `BACKEND_CLIENT_ID=` - Leia Backend Client ID 19 | * `BACKEND_CLIENT_SECRET=` - Leia Backend Client Secret 20 | 21 | ### Configuring node.js example 22 | Before running the `npm run start:nodejs-provided`, you need to install npm dependencies: `npm i`. 23 | 24 | #### Running node.js example 25 | After the configuration is done, you can run this script with `npm run start:nodejs-provided`. 26 | 27 | ### Configuring python3 example 28 | Before running the `npm run start:python-provided`, you would want to configure `virtualenv` for a python project: 29 | 1. Make sure you have python3 installed 30 | 2. Run `python3 -m venv demoenv` in the root directory of the demo project. This will create local virtual env for this project. 31 | 3. Run `source demoenv/bin/activate` from the root directory. This will make current virtual env an active virtual env, preventing polluting global dependencies space with this project dependencies. 32 | 4. Run `pip install -r requirements.txt` from the root directory. This will install all the project dependencies in the currently active virtual env. 33 | 34 | #### Running python3 example 35 | After the configuration of virtual env is completed, you may run the python example script with `npm run start:python-provided`. Running this command instead of running a file directly with `python3 src/using-leiapix-storage.py` will read env values from `.env` and make them available as ENV vars during script execution. 36 | 37 | # Using your own custom s3 storage 38 | 39 | ## Configuration 40 | In order to run this script, two sets of credentials are used: 41 | 1. `AWS Access Key ID` and `AWS Secret Access Key` (so that script can generate AWS S3 pre-signed URLs) 42 | 2. `Leia Backend Client ID` and `Leia Backend Client Secret` - to access Leia Media Cloud API. Can be acquired in Leia Account API Section. 43 | 44 | ### Configure AWS CLI (required for both NodeJS and Python3 examples) 45 | These scripts are intended for demonstration purposes only. Because of this, they rely on a [configured AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html#cli-configure-files-methods) so that they can be run from a CLI. After this is done, the `@aws-sdk/credential-provider-node` and `boto3` packages used in these scripts will handle auth with AWS. 46 | 47 | Real production integration should be done with secrets properly managed via CI/CD, and accessed in application environment instead. 48 | 49 | ### Configuring Leia Media Cloud credentials and other parameters (required for both NodeJS and Python3 examples) 50 | Rename `.env.tmpl` into `.env`. Put next env vars in `.env` at root folder. The package.json `start:` script will read these values to be used in the script. 51 | * `ORIGINAL_IMAGE_URL=` - URL of the image to convert to animation or to generate disparity map from 52 | * `BACKEND_CLIENT_ID=` - Leia Backend Client ID 53 | * `BACKEND_CLIENT_SECRET=` - Leia Backend Client Secret 54 | * `S3_BUCKET_NAME=` - AWS S3 bucket name to generate pre-signed URLs for 55 | * `S3_BUCKET_REGION=` - AWS S3 bucket region to generate pre-signed URLs for (Recommended value is `us-east-1`) 56 | 57 | ### Configuring node.js example 58 | Before running the `npm run start:nodejs-custom`, you need to install npm dependencies: `npm i`. 59 | 60 | #### Running node.js example 61 | After the configuration is done, you can run this script with `npm run start:nodejs-custom`. 62 | 63 | ### Configuring python3 example 64 | Before running the `npm run start:python-custom`, you would want to configure `virtualenv` for a python project: 65 | 1. Make sure you have python3 installed 66 | 2. Run `python3 -m venv demoenv` in the root directory of the demo project. This will create local virtual env for this project. 67 | 3. Run `source demoenv/bin/activate` from the root directory. This will make current virtual env an active virtual env, preventing polluting global dependencies space with this project dependencies. 68 | 4. Run `pip install -r requirements.txt` from the root directory. This will install all the project dependencies in the currently active virtual env. 69 | 70 | #### Running python3 example 71 | After the configuration of virtual env is completed, you may run the python example script with `npm run start:python-custom`. Running this command instead of running a file directly with `python3 src/using-custom-storage.py` will read env values from `.env` and make them available as ENV vars during script execution. 72 | 73 | ### Leia Media Cloud APIs 74 | * `https://api.leiapix.com/api/v1/disparity` 75 | * `https://api.leiapix.com/api/v1/animation` 76 | -------------------------------------------------------------------------------- /src/using-leiapix-storage.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { v4 as uuidv4 } from 'uuid'; 3 | 4 | /** 5 | * Reading configuration from environment 6 | */ 7 | 8 | const CLIENT_ID = process.env.BACKEND_CLIENT_ID; 9 | const CLIENT_SECRET = process.env.BACKEND_CLIENT_SECRET; 10 | 11 | if (!CLIENT_ID || !CLIENT_SECRET) { 12 | console.error('Error. In order to authenticate against Leia Media Cloud' + 13 | ' API, you need to provide BACKEND_CLIENT_ID and BACKEND_CLIENT_SECRET ' + 14 | 'env vars'); 15 | process.exit(1); 16 | } 17 | 18 | /** 19 | * Needs to be configured before running a script; 20 | */ 21 | const MEDIA_CLOUD_REST_API_BASE_URL = 'https://api.leiapix.com'; 22 | const LEIA_LOGIN_OPENID_TOKEN_URL = 'https://auth.leialoft.com/auth/realms/leialoft/protocol/openid-connect/token'; 23 | 24 | const ORIGINAL_IMAGE_URL = (process.env.ORIGINAL_IMAGE_URL && process.env.ORIGINAL_IMAGE_URL !== '') 25 | ? process.env.ORIGINAL_IMAGE_URL 26 | : 'https://images.pexels.com/photos/38771/pexels-photo-38771.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1'; 27 | 28 | const TWENTY_FOUR_HRS_IN_S = 24 * 60 * 60; 29 | const THREE_MIN_IN_MS = 3 * 60 * 1000; 30 | 31 | (async () => { 32 | try { 33 | 34 | /** 35 | * First, we need to authenticate against Leia Login with Client 36 | * credentials and acquire a temporary access token. 37 | * 38 | * You can generate ClientID and Client Secret in Leia Login API Section. 39 | */ 40 | 41 | console.log('Acquiring access token from LeiaLogin...'); 42 | 43 | const tokenResponse = await axios.post(LEIA_LOGIN_OPENID_TOKEN_URL, { 44 | client_id: CLIENT_ID, 45 | client_secret: CLIENT_SECRET, 46 | grant_type: 'client_credentials', 47 | }, { 48 | headers: { 49 | 'Content-Type': 'application/x-www-form-urlencoded' 50 | }, 51 | timeout: THREE_MIN_IN_MS, 52 | }); 53 | 54 | const accessToken = tokenResponse.data.access_token; 55 | 56 | console.log(`\nLeiaLogin AccessToken acquired: ${accessToken}`); 57 | 58 | /** 59 | * Now that we have an oidc access token we can call the API. First, let's 60 | * generate a disparity map for our image. 61 | */ 62 | 63 | // OPTIONAL. We start with preparing a correlationId. This might be an 64 | // internal ID which you use in your system for the entity represented 65 | // by the image/etc, or, as we do now, we can just generate new UUIDv4. 66 | // If not provided, we will generate one for you automatically. 67 | let correlationId = uuidv4(); 68 | console.log(`\nGenerating Disparity with correlationId: ${correlationId}...`); 69 | 70 | // Before you'll to be able to create an animation, you want to generate a 71 | // disparity map for your image and store it somewhere. 72 | 73 | // Here we will provide only required parameters: a correlationId and the 74 | // URL of the image for which we want to generate the disparity map. 75 | // You can find all available parameters in the documentation 76 | // on https://cloud.leiapix.com 77 | let disparityGenerationResult = await axios.post(`${MEDIA_CLOUD_REST_API_BASE_URL}/api/v1/disparity`, { 78 | correlationId, //OPTIONAL 79 | inputImageUrl: ORIGINAL_IMAGE_URL 80 | }, { 81 | headers: { 82 | Authorization: `Bearer ${accessToken}` 83 | }, 84 | timeout: THREE_MIN_IN_MS, 85 | }); 86 | 87 | // We omit the error handling in this example for simplicity, but 88 | // you should always check for a returned status & errors from the API 89 | // in real code. 90 | 91 | // The result of the call contains a short-lived GET pre-signed URL 92 | // to download the resulting disparity image: 93 | 94 | const getDisparityPresignedUrl = disparityGenerationResult.data.resultPresignedUrl; 95 | 96 | console.log('\nDisparity has been uploaded to the temporary storage.' + 97 | `To view it, use this GET URL: ${getDisparityPresignedUrl}`); 98 | 99 | // If you're interested not only in a disparity map, but you also want 100 | // to generate an animation, you would need to make another request to 101 | // the service. The steps are very similar to how we called a disparity 102 | // map endpoint: first we (OPTIONALLY) acquire correlationId... 103 | correlationId = uuidv4(); 104 | console.log(`\nGenerating mp4 animation with correlationId: ${correlationId}...`); 105 | 106 | // Then we make a request. This time we need two required inputs: 107 | // original image we want to animate (which was used for 108 | // disparity map generation); and an uploadable url for the result animation. 109 | // OPTIONALLY, you can provide the URL of the disparity map obtained from 110 | // the previous step. Otherwise, a new disparity map will be generated 111 | // automatically. 112 | // You can find all available parameters in the 113 | // documentation on https://cloud.leiapix.com 114 | let animationGenerationResult = await axios.post(`${MEDIA_CLOUD_REST_API_BASE_URL}/api/v1/animation`, { 115 | inputImageUrl: ORIGINAL_IMAGE_URL, 116 | animationLength: 5, 117 | //OPTIONALLY: 118 | correlationId, 119 | inputDisparityUrl: getDisparityPresignedUrl 120 | }, { 121 | headers: { 122 | Authorization: `Bearer ${accessToken}` 123 | }, 124 | timeout: THREE_MIN_IN_MS, 125 | }); 126 | 127 | // The resulting file is accessible via the pre-signed GET URL, that you 128 | // can find included in the response to the animation request: 129 | const getMP4PresignedUrl = animationGenerationResult.data.resultPresignedUrl; 130 | // Please note that the pre-signed GET URL has a relatively short 131 | // expiration period, so make sure to download the file as soon as possible. 132 | 133 | console.log('\nMP4 Animation has been uploaded to the temporary storage.' + 134 | `To download, please use this GET URL:: ${getMP4PresignedUrl}`); 135 | 136 | } catch (e: any) { 137 | if (e.hasOwnProperty('message') || e.hasOwnProperty('response')) { 138 | console.error(`Error. Unhandled exception: ${JSON.stringify(e.message)}`); 139 | console.error(`Error body: ${JSON.stringify(e.response?.data)}`); 140 | } else { 141 | console.error(`Error. Unhandled exception: ${JSON.stringify(e)}`); 142 | } 143 | } 144 | })(); 145 | -------------------------------------------------------------------------------- /src/using-leiapix-storage.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import uuid 4 | import requests 5 | 6 | # print("\n".join(sys.path)) 7 | # Reading configuration from environment 8 | if sys.prefix == sys.base_prefix: 9 | print('Error. You should run application in virtualenv to not pollute global dependencies. Please refer to ' 10 | 'README.md for instructions on how to set it up', file=sys.stderr) 11 | print(f'sys.prefix: {sys.prefix}') 12 | print(f'sys.base_prefix: {sys.base_prefix}') 13 | exit(1) 14 | 15 | # Get the environment variables 16 | CLIENT_ID = os.getenv('BACKEND_CLIENT_ID') 17 | CLIENT_SECRET = os.getenv('BACKEND_CLIENT_SECRET') 18 | 19 | # Check that they are all set 20 | if not CLIENT_ID or not CLIENT_SECRET: 21 | print('Error. In order to authenticate against Leia Media Cloud API, you need to provide BACKEND_CLIENT_ID and ' 22 | 'BACKEND_CLIENT_SECRET env vars', file=sys.stderr) 23 | exit(1) 24 | 25 | MEDIA_CLOUD_REST_API_BASE_URL = 'https://api.leiapix.com' 26 | LEIA_LOGIN_OPENID_TOKEN_URL = 'https://auth.leialoft.com/auth/realms/leialoft/protocol/openid-connect/token' 27 | 28 | 29 | DEFAULT_ORIGINAL_IMAGE_URL = 'https://images.pexels.com/photos/38771/pexels-photo-38771.jpeg?auto=compress&cs' \ 30 | '=tinysrgb&w=1260&h=750&dpr=1' 31 | ORIGINAL_IMAGE_URL = os.getenv('ORIGINAL_IMAGE_URL', DEFAULT_ORIGINAL_IMAGE_URL) 32 | ORIGINAL_IMAGE_URL = DEFAULT_ORIGINAL_IMAGE_URL if ORIGINAL_IMAGE_URL == '' else ORIGINAL_IMAGE_URL 33 | 34 | 35 | TWENTY_FOUR_HRS_IN_S = 24 * 60 * 60 36 | THREE_MIN_IN_S = 3 * 60 37 | 38 | 39 | try: 40 | """ 41 | * First, we need to authenticate against Leia Login with Client 42 | * credentials and acquire a temporary access token. 43 | * 44 | * You can generate ClientID and Client Secret in Leia Login API Section. 45 | """ 46 | print('Acquiring access token from LeiaLogin...') 47 | token_response = requests.post(LEIA_LOGIN_OPENID_TOKEN_URL, data={ 48 | 'client_id': CLIENT_ID, 49 | 'client_secret': CLIENT_SECRET, 50 | 'grant_type': 'client_credentials' 51 | }).json() 52 | access_token = token_response['access_token'] 53 | print(f'\nLeiaLogin AccessToken acquired: {access_token}') 54 | 55 | """ 56 | * Now that we have an oidc access token we can call the API. First, let's 57 | * generate a disparity map for our image. 58 | """ 59 | 60 | # OPTIONAL. We start with preparing a correlationId. This might be an 61 | # internal ID which you use in your system for the entity represented 62 | # by the image/etc, or, as we do now, we can just generate new UUIDv4. 63 | # If not provided, we will generate one for you automatically. 64 | correlation_id = str(uuid.uuid4()) 65 | print(f'\nGenerating Disparity with correlationId: {correlation_id}...') 66 | 67 | # Before you'll to be able to create an animation, you want to generate a 68 | # disparity map for your image and store it somewhere. 69 | 70 | # Here we will provide only required parameters: a correlationId and the 71 | # URL of the image for which we want to generate the disparity map. 72 | # You can find all available parameters in the documentation 73 | # on https://cloud.leiapix.com 74 | response = requests.post( 75 | f'{MEDIA_CLOUD_REST_API_BASE_URL}/api/v1/disparity', 76 | headers={ 77 | 'Authorization': f'Bearer {access_token}' 78 | }, 79 | json={ 80 | 'inputImageUrl': ORIGINAL_IMAGE_URL, 81 | # OPTIONALLY: 82 | 'correlationId': correlation_id, 83 | }, 84 | timeout=THREE_MIN_IN_S 85 | ) 86 | if not response.status_code == 201: 87 | raise Exception(f"Request returned with an error {response.status_code}. " 88 | f"The full response is: {response.content}") 89 | 90 | # We omit the error handling in this example for simplicity, but 91 | # you should always check for a returned status & errors from the API 92 | # in real code. 93 | 94 | # The result of the call contains a short-lived GET pre-signed URL 95 | # to download the resulting disparity image: 96 | get_disparity_presigned_url = response.json()['resultPresignedUrl'] 97 | 98 | print(f'\nDisparity has been uploaded to the temporary storage. ' 99 | f'To view it, use this GET URL: {get_disparity_presigned_url}') 100 | 101 | # If you're interested not only in a disparity map, but you also want 102 | # to generate an animation, you would need to make another request to 103 | # the service. The steps are very similar to how we called a disparity 104 | # map endpoint: first we (OPTIONALLY) acquire correlationId... 105 | correlation_id = str(uuid.uuid4()) 106 | print(f'\nGenerating mp4 animation with correlationId: {correlation_id}...') 107 | 108 | # Then we make a request. This time we need two required inputs: 109 | # original image we want to animate (which was used for 110 | # disparity map generation); and an uploadable url for the result animation. 111 | # OPTIONALLY, you can provide the URL of the disparity map obtained from 112 | # the previous step. Otherwise, a new disparity map will be generated 113 | # automatically. 114 | # You can find all available parameters in the 115 | # documentation on https://cloud.leiapix.com 116 | response = requests.post( 117 | f'{MEDIA_CLOUD_REST_API_BASE_URL}/api/v1/animation', 118 | headers={ 119 | 'Authorization': f'Bearer {access_token}' 120 | }, 121 | json={ 122 | 'inputImageUrl': ORIGINAL_IMAGE_URL, 123 | 'animationLength': 5, 124 | # OPTIONALLY: 125 | 'correlationId': correlation_id, 126 | 'resultPresignedUrl': get_disparity_presigned_url, 127 | }, 128 | timeout=THREE_MIN_IN_S 129 | ) 130 | if not response.status_code == 201: 131 | raise Exception(f"Request returned with an error {response.status_code}. " 132 | f"The full response is: {response.content}") 133 | 134 | # The resulting file is accessible via the pre-signed GET URL, that you 135 | # can find included in the response to the animation request: 136 | get_mp4_presigned_url = response.json()['resultPresignedUrl'] 137 | # This step is optional. We generate a presigned url to download the 138 | # results of the animation call for convenience. 139 | 140 | print(f'\nMP4 Animation has been uploaded to the temporary storage. ' 141 | f'To download, please use this GET URL: {get_mp4_presigned_url}') 142 | 143 | except Exception as e: 144 | print('Error. Unhandled exception: ' + str(e), file=sys.stderr) 145 | -------------------------------------------------------------------------------- /src/using-custom-storage.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { v4 as uuidv4 } from 'uuid'; 3 | import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; 4 | import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3'; 5 | import { defaultProvider } from '@aws-sdk/credential-provider-node'; 6 | 7 | /** 8 | * Reading configuration from environment 9 | */ 10 | 11 | const CLIENT_ID = process.env.BACKEND_CLIENT_ID; 12 | const CLIENT_SECRET = process.env.BACKEND_CLIENT_SECRET; 13 | 14 | if (!CLIENT_ID || !CLIENT_SECRET) { 15 | console.error('Error. In order to authenticate against Leia Media Cloud' + 16 | ' API, you need to provide BACKEND_CLIENT_ID and BACKEND_CLIENT_SECRET ' + 17 | 'env vars'); 18 | process.exit(1); 19 | } 20 | 21 | const S3_BUCKET_NAME = process.env.S3_BUCKET_NAME || ''; 22 | const S3_BUCKET_REGION = process.env.S3_BUCKET_REGION 23 | || 'us-east-1'; 24 | 25 | if (!S3_BUCKET_NAME || !S3_BUCKET_REGION) { 26 | console.error('Error. In order to use Leia Media Cloud API, you need to' + 27 | ' provide S3_BUCKET_NAME and S3_BUCKET_REGION env ' + 28 | 'vars'); 29 | process.exit(1); 30 | } 31 | 32 | /** 33 | * Needs to be configured before running a script; 34 | */ 35 | const MEDIA_CLOUD_REST_API_BASE_URL = 'https://api.leiapix.com'; 36 | const LEIA_LOGIN_OPENID_TOKEN_URL = 'https://auth.leialoft.com/auth/realms/leialoft/protocol/openid-connect/token'; 37 | 38 | const ORIGINAL_IMAGE_URL = (process.env.ORIGINAL_IMAGE_URL && process.env.ORIGINAL_IMAGE_URL !== '') 39 | ? process.env.ORIGINAL_IMAGE_URL 40 | : 'https://images.pexels.com/photos/38771/pexels-photo-38771.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1'; 41 | 42 | const TWENTY_FOUR_HRS_IN_S = 24 * 60 * 60; 43 | const THREE_MIN_IN_MS = 3 * 60 * 1000; 44 | 45 | const S3_DISPARITY_MAP_PATH = 'public/leiapixcloud/disparity.jpg'; 46 | const S3_MP4_PATH = 'public/leiapixcloud/animation.mp4'; 47 | 48 | const awsClient = new S3Client({ 49 | region: S3_BUCKET_REGION, 50 | credentials: defaultProvider(), // read AWS credentials from shell 51 | }); 52 | 53 | (async () => { 54 | try { 55 | 56 | /** 57 | * First, we need to authenticate against Leia Login with Client 58 | * credentials and acquire a temporary access token. 59 | * 60 | * You can generate ClientID and Client Secret in Leia Login API Section. 61 | */ 62 | 63 | console.log('Acquiring access token from LeiaLogin...'); 64 | 65 | const tokenResponse = await axios.post(LEIA_LOGIN_OPENID_TOKEN_URL, { 66 | client_id: CLIENT_ID, 67 | client_secret: CLIENT_SECRET, 68 | grant_type: 'client_credentials', 69 | }, { 70 | headers: { 71 | 'Content-Type': 'application/x-www-form-urlencoded' 72 | }, 73 | timeout: THREE_MIN_IN_MS, 74 | }); 75 | 76 | const accessToken = tokenResponse.data.access_token; 77 | 78 | console.log(`\nLeiaLogin AccessToken acquired: ${accessToken}`); 79 | 80 | /** 81 | * Now that we have an oidc access token we can call the API. First, let's 82 | * generate a disparity map for our image. 83 | */ 84 | 85 | // We start with preparing a correlationId. This might be an internal 86 | // ID which you use in your system for this image/entity represented 87 | // by the image/etc, or, as we do now, we can just generate new UUIDv4. 88 | let correlationId = uuidv4(); 89 | 90 | // You probably want to store the image somewhere. You need to provide 91 | // an uploadable URL where Leia Media Cloud API will PUT the result of a 92 | // call. Here we use AWS S3 pre-signed URLs as uploadable url. The url 93 | // needs to support HTTP PUT command. 94 | const putDisparityCommand = new PutObjectCommand({ 95 | Bucket: S3_BUCKET_NAME, 96 | Key: S3_DISPARITY_MAP_PATH 97 | }); 98 | const putDisparityPresignedUrl = await getSignedUrl( 99 | awsClient, 100 | putDisparityCommand, 101 | { expiresIn: TWENTY_FOUR_HRS_IN_S }, 102 | ); 103 | 104 | console.log(`\nGenerating Disparity: ${correlationId}...`); 105 | 106 | // Now we're ready to call the API. We provide only required parameters: a 107 | // correlationId, URL of the image for which we want to generate 108 | // disparity map, and the result url where disparity map will be 109 | // uploaded. You can find all available parameters in the documentation 110 | // on https://cloud.leiapix.com 111 | await axios.post(`${MEDIA_CLOUD_REST_API_BASE_URL}/api/v1/disparity`, { 112 | correlationId, 113 | inputImageUrl: ORIGINAL_IMAGE_URL, 114 | resultPresignedUrl: putDisparityPresignedUrl 115 | }, { 116 | headers: { 117 | Authorization: `Bearer ${accessToken}` 118 | }, 119 | timeout: THREE_MIN_IN_MS, 120 | }); 121 | 122 | // At this point, the disparity map should be uploaded to the upload 123 | // url. We omit the error handling in this example for simplicity, but 124 | // you should always check for a returned status & errors from the API 125 | // in real code. 126 | 127 | // To demonstrate that the upload was successful, we generate a GET 128 | // presigned URL to output it to be used. This URL will also be used 129 | // later in the script as an input for an animation call - but it is 130 | // optional if the disparity map is the only result you need. 131 | const getDisparityCommand = new GetObjectCommand({ 132 | Bucket: S3_BUCKET_NAME, 133 | Key: S3_DISPARITY_MAP_PATH 134 | }); 135 | const getDisparityPresignedUrl = await getSignedUrl( 136 | awsClient, 137 | getDisparityCommand, { expiresIn: TWENTY_FOUR_HRS_IN_S }, 138 | ); 139 | 140 | console.log('\nDisparity has been uploaded to specified AWS S3 bucket.' + 141 | `To view it, use this GET URL: ${getDisparityPresignedUrl}`); 142 | 143 | // If you're interested not only in a disparity map, but you also want 144 | // to generate an animation, you would need to make another request to 145 | // the service. The steps are very similar to how we called a disparity 146 | // map endpoint: first we acquire correlationId... 147 | correlationId = uuidv4(); 148 | 149 | // ...then we prepare an uploadable url... 150 | const putMP4Command = new PutObjectCommand({ 151 | Bucket: S3_BUCKET_NAME, 152 | Key: S3_MP4_PATH 153 | }); 154 | const putMP4PresignedUrl = await getSignedUrl( 155 | awsClient, 156 | putMP4Command, 157 | { expiresIn: TWENTY_FOUR_HRS_IN_S }, 158 | ); 159 | 160 | console.log(`\nGenerating mp4 animation: ${correlationId}...`); 161 | 162 | // ...and we make a request. This time we need four required inputs: a 163 | // correlationId; original image we want to animate (which was used for 164 | // disparity map generation); the downloadable URL for a disparity map 165 | // from previous step (this URL needs to support HTTP GET verb); and an 166 | // uploadable url for the result animation. You can find all available 167 | // parameters in the documentation on https://cloud.leiapix.com 168 | await axios.post(`${MEDIA_CLOUD_REST_API_BASE_URL}/api/v1/animation`, { 169 | correlationId, 170 | inputImageUrl: ORIGINAL_IMAGE_URL, 171 | inputDisparityUrl: getDisparityPresignedUrl, 172 | resultPresignedUrl: putMP4PresignedUrl, 173 | animationLength: 5 174 | }, { 175 | headers: { 176 | Authorization: `Bearer ${accessToken}` 177 | }, 178 | timeout: THREE_MIN_IN_MS, 179 | }); 180 | 181 | // At this point, the video should be uploaded to a specified upload URL. 182 | 183 | // This step is optional. We generate a presigned url to download the 184 | // results of the animation call for convenience. 185 | const getMP4Command = new GetObjectCommand({ 186 | Bucket: S3_BUCKET_NAME, 187 | Key: S3_MP4_PATH 188 | }); 189 | const getMP4PresignedUrl = await getSignedUrl( 190 | awsClient, 191 | getMP4Command, 192 | { expiresIn: TWENTY_FOUR_HRS_IN_S } 193 | ); 194 | 195 | console.log('\nMP4 Animation has been uploaded to specified AWS S3 bucket.' + 196 | `To download, please use this GET URL:: ${getMP4PresignedUrl}`); 197 | 198 | } catch (e: any) { 199 | if (e.hasOwnProperty('message') || e.hasOwnProperty('response')) { 200 | console.error(`Error. Unhandled exception: ${JSON.stringify(e.message)}`); 201 | console.error(`Error body: ${JSON.stringify(e.response?.data)}`); 202 | } else { 203 | console.error(`Error. Unhandled exception: ${JSON.stringify(e)}`); 204 | } 205 | } 206 | })(); 207 | -------------------------------------------------------------------------------- /src/using-custom-storage.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import uuid 4 | import boto3 5 | from botocore.exceptions import NoCredentialsError 6 | import requests 7 | 8 | # print("\n".join(sys.path)) 9 | # Reading configuration from environment 10 | if sys.prefix == sys.base_prefix: 11 | print('Error. You should run application in virtualenv to not pollute global dependencies. Please refer to ' 12 | 'README.md for instructions on how to set it up', file=sys.stderr) 13 | print(f'sys.prefix: {sys.prefix}') 14 | print(f'sys.base_prefix: {sys.base_prefix}') 15 | exit(1) 16 | 17 | # Get the environment variables 18 | CLIENT_ID = os.getenv('BACKEND_CLIENT_ID') 19 | CLIENT_SECRET = os.getenv('BACKEND_CLIENT_SECRET') 20 | S3_BUCKET_NAME = os.getenv('S3_BUCKET_NAME') 21 | S3_BUCKET_REGION = os.getenv('S3_BUCKET_REGION') 22 | 23 | # Check that they are all set 24 | if not CLIENT_ID or not CLIENT_SECRET: 25 | print('Error. In order to authenticate against Leia Media Cloud API, you need to provide BACKEND_CLIENT_ID and ' 26 | 'BACKEND_CLIENT_SECRET env vars', file=sys.stderr) 27 | exit(1) 28 | 29 | if not S3_BUCKET_NAME or not S3_BUCKET_REGION: 30 | print('Error. In order to use Leia Media Cloud API, you need to provide S3_BUCKET_NAME and ' 31 | 'S3_BUCKET_REGION env vars', file=sys.stderr) 32 | exit(1) 33 | 34 | MEDIA_CLOUD_REST_API_BASE_URL = 'https://api.leiapix.com' 35 | LEIA_LOGIN_OPENID_TOKEN_URL = 'https://auth.leialoft.com/auth/realms/leialoft/protocol/openid-connect/token' 36 | 37 | 38 | DEFAULT_ORIGINAL_IMAGE_URL = 'https://images.pexels.com/photos/38771/pexels-photo-38771.jpeg?auto=compress&cs' \ 39 | '=tinysrgb&w=1260&h=750&dpr=1' 40 | ORIGINAL_IMAGE_URL = os.getenv('ORIGINAL_IMAGE_URL', DEFAULT_ORIGINAL_IMAGE_URL) 41 | ORIGINAL_IMAGE_URL = DEFAULT_ORIGINAL_IMAGE_URL if ORIGINAL_IMAGE_URL == '' else ORIGINAL_IMAGE_URL 42 | 43 | 44 | TWENTY_FOUR_HRS_IN_S = 24 * 60 * 60 45 | THREE_MIN_IN_S = 3 * 60 46 | 47 | S3_DISPARITY_PATH = 'public/leiapixcloud/disparity.jpg' 48 | S3_MP4_PATH = 'public/leiapixcloud/animation.mp4' 49 | 50 | # Initiate the s3 client 51 | s3 = boto3.client('s3', region_name=S3_BUCKET_REGION) 52 | 53 | 54 | def get_presigned_url(bucket, key, method): 55 | try: 56 | return s3.generate_presigned_url(ClientMethod=method, 57 | Params={'Bucket': bucket, 'Key': key}, 58 | ExpiresIn=TWENTY_FOUR_HRS_IN_S) 59 | except NoCredentialsError: 60 | print('Error. No AWS credentials found', file=sys.stderr) 61 | return None 62 | 63 | 64 | try: 65 | """ 66 | * First, we need to authenticate against Leia Login with Client 67 | * credentials and acquire a temporary access token. 68 | * 69 | * You can generate ClientID and Client Secret in Leia Login API Section. 70 | """ 71 | print('Acquiring access token from LeiaLogin...') 72 | token_response = requests.post(LEIA_LOGIN_OPENID_TOKEN_URL, data={ 73 | 'client_id': CLIENT_ID, 74 | 'client_secret': CLIENT_SECRET, 75 | 'grant_type': 'client_credentials' 76 | }).json() 77 | access_token = token_response['access_token'] 78 | print(f'\nLeiaLogin AccessToken acquired: {access_token}') 79 | 80 | """ 81 | * Now that we have an oidc access token we can call the API. First, let's 82 | * generate a disparity map for our image. 83 | """ 84 | 85 | # We start with preparing a correlationId. This might be an internal 86 | # ID which you use in your system for this image/entity represented 87 | # by the image/etc, or, as we do now, we can just generate new UUIDv4. 88 | correlation_id = str(uuid.uuid4()) 89 | 90 | # You probably want to store the image somewhere. You need to provide 91 | # an uploadable URL where Leia Media Cloud API will PUT the result of a 92 | # call. Here we use AWS S3 pre-signed URLs as uploadable url. The url 93 | # needs to support HTTP PUT command. 94 | put_disparity_presigned_url = get_presigned_url( 95 | S3_BUCKET_NAME, 96 | S3_DISPARITY_PATH, 97 | 'put_object' 98 | ) 99 | 100 | print(f'\nGenerating Disparity: {correlation_id}...') 101 | 102 | # Now we're ready to call the API. We provide only required parameters: a 103 | # correlationId, URL of the image for which we want to generate 104 | # disparity map, and the result url where disparity map will be uploaded. 105 | # You can find all available parameters in the documentation on 106 | # https://cloud.leiapix.com 107 | response = requests.post( 108 | f'{MEDIA_CLOUD_REST_API_BASE_URL}/api/v1/disparity', 109 | headers={ 110 | 'Authorization': f'Bearer {access_token}' 111 | }, 112 | json={ 113 | 'correlationId': correlation_id, 114 | 'inputImageUrl': ORIGINAL_IMAGE_URL, 115 | 'resultPresignedUrl': put_disparity_presigned_url 116 | }, 117 | timeout=THREE_MIN_IN_S 118 | ) 119 | if not response.status_code == 201: 120 | raise Exception(f"Request returned with an error {response.status_code}. " 121 | f"The full response is: {response.content}") 122 | 123 | # At this point, the disparity map should be uploaded to the upload 124 | # url. We omit the error handling in this example for simplicity, but 125 | # you should always check for a returned status & errors from the API 126 | # in real code. 127 | 128 | # To demonstrate that the upload was successful, we generate a GET 129 | # presigned URL to output it to be used. This URL will also be used 130 | # later in the script as an input for an animation call - but it is 131 | # optional if the disparity map is the only result you need. 132 | get_disparity_presigned_url = get_presigned_url( 133 | S3_BUCKET_NAME, 134 | S3_DISPARITY_PATH, 135 | 'get_object' 136 | ) 137 | 138 | print(f'\nDisparity has been uploaded to specified AWS S3 bucket. ' 139 | f'To view it, use this GET URL: {get_disparity_presigned_url}') 140 | 141 | # If you're interested not only in a disparity map, but you also want 142 | # to generate an animation, you would need to make another request to 143 | # the service. The steps are very similar to how we called a disparity 144 | # map endpoint: first we acquire correlationId... 145 | correlation_id = str(uuid.uuid4()) 146 | 147 | # ...then we prepare an uploadable url... 148 | put_mp4_presigned_url = get_presigned_url( 149 | S3_BUCKET_NAME, 150 | S3_MP4_PATH, 151 | 'put_object' 152 | ) 153 | 154 | print(f'\nGenerating mp4 animation: {correlation_id}...') 155 | 156 | # ...and we make a request. This time we need four required inputs: a 157 | # correlationId; original image we want to animate (which was used for 158 | # disparity map generation); the downloadable URL for a disparity map 159 | # from previous step (this URL needs to support HTTP GET verb); and an 160 | # uploadable url for the result animation. You can find all available 161 | # parameters in the documentation on https://cloud.leiapix.com 162 | response = requests.post( 163 | f'{MEDIA_CLOUD_REST_API_BASE_URL}/api/v1/animation', 164 | headers={ 165 | 'Authorization': f'Bearer {access_token}' 166 | }, 167 | json={ 168 | 'correlationId': correlation_id, 169 | 'inputImageUrl': ORIGINAL_IMAGE_URL, 170 | 'inputDisparityUrl': get_disparity_presigned_url, 171 | 'resultPresignedUrl': put_mp4_presigned_url, 172 | 'animationLength': 5 173 | }, 174 | timeout=THREE_MIN_IN_S 175 | ) 176 | if not response.status_code == 201: 177 | raise Exception(f"Request returned with an error {response.status_code}. " 178 | f"The full response is: {response.content}") 179 | 180 | # At this point, the video should be uploaded to a specified upload URL. 181 | 182 | # This step is optional. We generate a presigned url to download the 183 | # results of the animation call for convenience. 184 | get_mp4_presigned_url = get_presigned_url( 185 | S3_BUCKET_NAME, 186 | S3_MP4_PATH, 187 | 'get_object' 188 | ) 189 | 190 | print(f'\nMP4 Animation has been uploaded to specified AWS S3 bucket. ' 191 | f'To download, please use this GET URL: {get_mp4_presigned_url}') 192 | 193 | except Exception as e: 194 | print('Error. Unhandled exception: ' + str(e), file=sys.stderr) 195 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs", /* Specify what module code is generated. */ 29 | // "rootDir": "./", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "nodenext", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 42 | // "resolveJsonModule": true, /* Enable importing .json files. */ 43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 45 | 46 | /* JavaScript Support */ 47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 50 | 51 | /* Emit */ 52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 57 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 58 | "outDir": "./dist", /* Specify an output folder for all emitted files. */ 59 | // "removeComments": true, /* Disable emitting comments. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 68 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 75 | 76 | /* Interop Constraints */ 77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 78 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 80 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 82 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 83 | 84 | /* Type Checking */ 85 | "strict": true, /* Enable all strict type-checking options. */ 86 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 91 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 104 | 105 | /* Completeness */ 106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 108 | } 109 | } 110 | --------------------------------------------------------------------------------