constructor()

in provision/lib/provision-stack.ts [18:314]


  constructor(scope: cdk.Construct, id: string, props: ProvisionStackProps) {
    super(scope, id, props);
    let {
      ambHttpEndpoint,
      contractAddress,
    } = props;

    if (!ambHttpEndpoint) {
      throw new Error(`Environment variable AMB_HTTP_ENDPOINT is not set.
\`\`\`
export AMB_HTTP_ENDPOINT=https://<node id>.ethereum.managedblockchain.<region>.amazonaws.com
\`\`\`
`)
    }

    if (!contractAddress) {
      throw new Error(`Environment variable CONTRACT_ADDRESS is not set.
\`\`\`
export CONTRACT_ADDRESS=0x...
\`\`\`
`)
    }
    const assetBucket = new s3.Bucket(this, 'AssetBucket', {
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      cors: [
        {
          allowedMethods: [
            s3.HttpMethods.HEAD,
            s3.HttpMethods.GET,
            s3.HttpMethods.PUT,
            s3.HttpMethods.POST,
            s3.HttpMethods.DELETE,
          ],
          allowedOrigins: ['*'],
          allowedHeaders: ['*'],
        },
      ],
    });

    const distribution = new cfn.Distribution(this, 'AssetDistribution', {
      defaultBehavior: {
        origin: new origins.S3Origin(assetBucket),
      },
      additionalBehaviors: {
        '/assets/*': {
          origin: new origins.S3Origin(assetBucket),
        },
      },
    });

    const userPool = new cognito.UserPool(this, 'UserPool', {
      selfSignUpEnabled: true,
      signInAliases: {
        username: true,
        email: true
      },
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });

    const client = userPool.addClient('WebClient', {
      userPoolClientName: 'webClient',
      idTokenValidity: cdk.Duration.days(1),
      accessTokenValidity: cdk.Duration.days(1),
      authFlows: {
        userPassword: true,
        userSrp: true,
        custom: true,
      },
    });

    const privateKeyTable = new dynamodb.Table(this, 'PrivateKeyTable', {
      partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
      encryption: dynamodb.TableEncryption.AWS_MANAGED,
    });

    const assetTable = new dynamodb.Table(this, 'AssetTable', {
      partitionKey: { name: 'key', type: dynamodb.AttributeType.STRING },
    });

    const jobTable = new dynamodb.Table(this, 'JobTable', {
      partitionKey: { name: 'jobId', type: dynamodb.AttributeType.STRING },
    });

    const defaultFuncProps = {
      handler: 'handler',
      runtime: lambda.Runtime.NODEJS_14_X,
      timeout: cdk.Duration.minutes(1),
      tracing: lambda.Tracing.ACTIVE,
      bundling: {
        commandHooks: {
          afterBundling(inputDir: string, outputDir: string): string[] {
            return [
              `cp -r ${inputDir}/lambda/contracts ${outputDir}`,
            ]
          },
          beforeBundling(_inputDir: string, _outputDir: string): string[] {
            return [];
          },
          beforeInstall(_inputDir: string, _outputDir: string): string[] {
            return [];
          },
        },
      },
    };

    const defaultFuncEnvironments = {
      AMB_HTTP_ENDPOINT: ambHttpEndpoint,
      CONTRACT_ADDRESS: contractAddress,
      TABLE_PRIVATE_KEY: privateKeyTable.tableName,
      TABLE_ASSET: assetTable.tableName,
      TABLE_JOB: jobTable.tableName,
      ASSET_DOMAIN: distribution.distributionDomainName,
      BUCKET_NAME: assetBucket.bucketName,
    };

    const createAccount = new lambdaNodejs.NodejsFunction(this, 'CreateAccount', {
      ...defaultFuncProps,
      entry: './lambda/createAccount.ts',
      environment: {
        ...defaultFuncEnvironments,
      },
    });

    privateKeyTable.grantWriteData(createAccount);

    userPool.addTrigger(cognito.UserPoolOperation.POST_CONFIRMATION, createAccount);

    const getAccount = new lambdaNodejs.NodejsFunction(this, 'GetAccount', {
      ...defaultFuncProps,
      entry: './lambda/getAccount.ts',
      environment: {
        ...defaultFuncEnvironments,
      },
    });

    privateKeyTable.grantReadData(getAccount);

    const createItemJob = new lambdaNodejs.NodejsFunction(this, 'CreateItemJob', {
      ...defaultFuncProps,
      entry: './lambda/createItemJob.ts',
      environment: {
        ...defaultFuncEnvironments,
      },
    });

    privateKeyTable.grantReadData(createItemJob);
    jobTable.grantWriteData(createItemJob);

    const createItem = new lambdaNodejs.NodejsFunction(this, 'CreateItem', {
      ...defaultFuncProps,
      entry: './lambda/createItem.ts',
      environment: {
        CREATE_ITEM_JOB_NAME: createItemJob.functionName,
        ...defaultFuncEnvironments,
      },
    });

    jobTable.grantWriteData(createItem);
    createItemJob.grantInvoke(createItem);

    const transferJob = new lambdaNodejs.NodejsFunction(this, 'TransferJob', {
      ...defaultFuncProps,
      entry: './lambda/transferJob.ts',
      environment: {
        ...defaultFuncEnvironments,
      },
    });

    privateKeyTable.grantReadData(transferJob);
    jobTable.grantWriteData(transferJob);

    const transfer = new lambdaNodejs.NodejsFunction(this, 'Transfer', {
      ...defaultFuncProps,
      entry: './lambda/transfer.ts',
      environment: {
        TRANSFER_JOB_NAME: transferJob.functionName,
        ...defaultFuncEnvironments,
      },
    });

    jobTable.grantWriteData(transfer);
    transferJob.grantInvoke(transfer);

    const getItem = new lambdaNodejs.NodejsFunction(this, 'GetItem', {
      ...defaultFuncProps,
      entry: './lambda/getItem.ts',
      environment: {
        ...defaultFuncEnvironments,
      },
    });

    privateKeyTable.grantReadData(getItem);

    const createUploadUrl = new lambdaNodejs.NodejsFunction(this, 'CreateUploadUrl', {
      ...defaultFuncProps,
      entry: './lambda/createUploadUrl.ts',
      environment: {
        ...defaultFuncEnvironments,
      },
    });

    assetBucket.grantReadWrite(createUploadUrl);

    const createAsset = new lambdaNodejs.NodejsFunction(this, 'CreateAsset', {
      ...defaultFuncProps,
      entry: './lambda/createAsset.ts',
      environment: {
        ...defaultFuncEnvironments,
      },
    });

    assetTable.grantWriteData(createAsset);

    const getAsset = new lambdaNodejs.NodejsFunction(this, 'GetAsset', {
      ...defaultFuncProps,
      entry: './lambda/getAsset.ts',
      environment: {
        ...defaultFuncEnvironments,
      },
    });

    assetTable.grantReadData(getAsset);

    const getJob = new lambdaNodejs.NodejsFunction(this, 'GetJob', {
      ...defaultFuncProps,
      entry: './lambda/getJob.ts',
      environment: {
        ...defaultFuncEnvironments,
      },
    });

    jobTable.grantReadData(getJob);

    this.addAMBFullAccess(createAccount);
    this.addAMBFullAccess(getAccount);
    this.addAMBFullAccess(createItemJob);
    this.addAMBFullAccess(getItem);
    this.addAMBFullAccess(transferJob);

    const authorizer = new agw.CognitoUserPoolsAuthorizer(this, 'Authorizer', {
      cognitoUserPools: [userPool],
    });

    const api = new agw.RestApi(this, 'NftApi', {
      defaultCorsPreflightOptions: {
        allowOrigins: agw.Cors.ALL_ORIGINS,
        allowMethods: agw.Cors.ALL_METHODS
      }
    });

    const account = api.root.addResource('account');
    const upload = api.root.addResource('upload');
    const assets = api.root.addResource('assets');
    const assetsKey = assets.addResource('{key}');
    const item = api.root.addResource('item');
    const itemId = item.addResource('{id}');
    const job = api.root.addResource('job');
    const jobId = job.addResource('{jobId}');

    this.defineAPIRoute('GET', account, getAccount, authorizer);
    this.defineAPIRoute('GET', upload, createUploadUrl, authorizer);
    this.defineAPIRoute('POST', assets, createAsset, authorizer);
    this.defineAPIRoute('GET', assetsKey, getAsset);
    this.defineAPIRoute('POST', item, createItem, authorizer);
    this.defineAPIRoute('GET', itemId, getItem, authorizer);
    this.defineAPIRoute('POST', itemId, transfer, authorizer);
    this.defineAPIRoute('GET', jobId, getJob, authorizer);

    api.addGatewayResponse('Api4xx', {
      type: agw.ResponseType.DEFAULT_4XX,
      responseHeaders: {
        'Access-Control-Allow-Origin': "'*'",
      },
    });

    api.addGatewayResponse('Api5xx', {
      type: agw.ResponseType.DEFAULT_5XX,
      responseHeaders: {
        'Access-Control-Allow-Origin': "'*'",
      },
    });

    new cdk.CfnOutput(this, 'UserPoolId', {
      value: userPool.userPoolId,
      exportName: 'UserPoolId',
    });

    new cdk.CfnOutput(this, 'UserPoolClientId', {
      value: client.userPoolClientId,
      exportName: 'UserPoolClientId',
    });

    new cdk.CfnOutput(this, 'NftApiEndpoint', {
      value: api.url,
      exportName: 'NftApiEndpoint',
    });
  }