diff --git a/serverless/serverless.yaml b/serverless/serverless.yaml index 3f1bba23..b798b2f4 100644 --- a/serverless/serverless.yaml +++ b/serverless/serverless.yaml @@ -6,18 +6,26 @@ plugins: - serverless-offline provider: - timeout: 150 - name: aws - runtime: nodejs18.x - stage: ${opt:stage, 'prd'} - region: ${opt:region, 'us-west-2'} - apiGateway: - minimumCompressionSize: 1024 - shouldStartNameWithService: true - environment: - DEBUG: '*' - AWS_STAGE: ${self:provider.stage} - AWS_NODEJS_CONNECTION_REUSE_ENABLED: 1 + timeout: 150 + name: aws + runtime: nodejs18.x + stage: ${opt:stage, 'prd'} + region: ${opt:region, 'us-west-2'} + apiGateway: + minimumCompressionSize: 1024 + shouldStartNameWithService: true + environment: + DEBUG: '*' + AWS_STAGE: ${self:provider.stage} + AWS_NODEJS_CONNECTION_REUSE_ENABLED: 1 + httpApi: + cors: + allowedOrigins: '*' + headers: '*' + allowedMethods: + - POST + allowCredentials: false + maxAge: 6000 # In seconds layers: TopicAwsNodeModules: @@ -27,23 +35,29 @@ layers: TopicPrismaAwsPrismaClient: path: lambda-layers-prisma-client -package: { - patterns: ["dist/**/*.prisma", "**/libquery_engine-rhel-openssl-1.0.x.so.node", "dist/serverless/.env", '!node_modules/**'], -} +package: + { + patterns: + [ + 'dist/**/*.prisma', + '**/libquery_engine-rhel-openssl-1.0.x.so.node', + 'dist/serverless/.env', + '!node_modules/**', + ], + } custom: esbuild: bundle: true minify: true sourcemap: false - exclude: + exclude: - 'aws-sdk' target: 'node18' platform: 'node' concurrency: 10 functions: - submitBuildInfo: # Deployment: handler: ./dist/src/functions/builds/handler.submitBuildInfo # TODO This will not work, need to change to nfa-serverless/dist/serverless/src/functions/builds/handler.submitBuildInfo @@ -53,13 +67,12 @@ functions: - http: path: build method: post - cors: true - environment: # TODO They won't be loaded from the shell environment, need to find a way to pass them from the deployment script + cors: + origin: '*' + headers: '*' + allowCredentials: false + environment: NODE_ENV: production - # DATABASE_URL: ${env:DATABASE_URL} - # CONTRACT_ADDRESS: ${env:CONTRACT_ADDRESS} - # PRIVATE_KEY: ${env:PRIVATE_KEY} - # JSON_RPC: ${env:JSON_RPC} layers: - { Ref: TopicAwsNodeModulesLambdaLayer } - { Ref: TopicAwsLibsLambdaLayer } @@ -74,25 +87,31 @@ functions: - http: path: mint method: post - cors: true - environment: # TODO They won't be loaded from the shell environment, need to find a way to pass them from the deployment script + cors: + origin: '*' + headers: '*' + allowCredentials: false + environment: NODE_ENV: production - # DATABASE_URL: ${env:DATABASE_URL} - # CONTRACT_ADDRESS: ${env:CONTRACT_ADDRESS} - # PRIVATE_KEY: ${env:PRIVATE_KEY} - # JSON_RPC: ${env:JSON_RPC} layers: - { Ref: TopicAwsNodeModulesLambdaLayer } - { Ref: TopicAwsLibsLambdaLayer } - { Ref: TopicPrismaAwsPrismaClientLambdaLayer } - verifyAccessPoint: + verifyApp: handler: ./dist/src/functions/apps/handler.verifyApp events: - http: path: verifyApp method: post - cors: true + cors: + origin: '*' + headers: '*' + allowCredentials: false + layers: + - { Ref: TopicAwsNodeModulesLambdaLayer } + - { Ref: TopicAwsLibsLambdaLayer } + - { Ref: TopicPrismaAwsPrismaClientLambdaLayer } submitAppInfo: handler: ./dist/src/functions/apps/handler.submitAppInfo @@ -100,4 +119,11 @@ functions: - http: path: app method: post - cors: true + cors: + origin: '*' + headers: '*' + allowCredentials: false + layers: + - { Ref: TopicAwsNodeModulesLambdaLayer } + - { Ref: TopicAwsLibsLambdaLayer } + - { Ref: TopicPrismaAwsPrismaClientLambdaLayer } diff --git a/serverless/src/functions/apps/handler.ts b/serverless/src/functions/apps/handler.ts index 382a74b5..f557ef7b 100644 --- a/serverless/src/functions/apps/handler.ts +++ b/serverless/src/functions/apps/handler.ts @@ -18,9 +18,9 @@ export const verifyApp = async ( // Check the parameters and environment variables dotenv.config(); if (event.body === null || process.env.BUNNY_CDN_ACCESS_KEY === undefined) { - return formatJSONResponse({ - status: 422, - message: 'Required parameters were not passed.', + return formatJSONResponse(422, { + message: + 'Required parameters were not passed. Please check the request body and the environment variables.', }); } @@ -38,8 +38,7 @@ export const verifyApp = async ( process.env.FE_SIGNING_KEY ) ) { - return formatJSONResponse({ - status: 401, + return formatJSONResponse(401, { message: 'Unauthorized', }); } @@ -54,12 +53,11 @@ export const verifyApp = async ( await bunnyCdn.loadFreeCertificate(args); - return formatJSONResponse({ - status: true, + return formatJSONResponse(200, { + message: 'The hostname was verified successfully.', }); } catch (e) { - return formatJSONResponse({ - status: 500, + return formatJSONResponse(500, { message: e, }); } @@ -72,9 +70,9 @@ export const submitAppInfo = async ( // Check the parameters and environment variables dotenv.config(); if (event.body === null || process.env.BUNNY_CDN_ACCESS_KEY === undefined) { - return formatJSONResponse({ - status: 422, - message: 'Required parameters were not passed.', + return formatJSONResponse(422, { + message: + 'Required parameters were not passed. Please check the request body and the environment variables.', }); } @@ -92,9 +90,8 @@ export const submitAppInfo = async ( process.env.FE_SIGNING_KEY ) ) { - return formatJSONResponse({ - status: 401, - message: 'Unauthorized', + return formatJSONResponse(401, { + message: 'Unauthorized.', }); } @@ -102,7 +99,7 @@ export const submitAppInfo = async ( const bunnyCdn = new BunnyCdn(process.env.BUNNY_CDN_ACCESS_KEY); const data = JSON.parse(event.body); const appInfo = { - apId: 'null', + appId: 'null', createdAt: new Date().toISOString(), sourceDomain: data.sourceDomain, hostname: data.targetDomain, @@ -116,6 +113,7 @@ export const submitAppInfo = async ( hostname?: string; }; + let errorOccurred = false; do { let id = v4(); let requestArgs: CreatePullZoneMethodArgs = { @@ -125,8 +123,10 @@ export const submitAppInfo = async ( try { pullZone = await bunnyCdn.createPullZone(requestArgs); - appInfo.apId = id; + appInfo.appId = id; + break; // Exit the loop since catch block was not triggered } catch (error) { + errorOccurred = true; maxTries -= 1; if ( error instanceof BunnyCdnError && @@ -139,7 +139,7 @@ export const submitAppInfo = async ( throw error; } } - } while (maxTries > 0); + } while (maxTries > 0 && errorOccurred); // Create custom hostname await bunnyCdn @@ -155,7 +155,7 @@ export const submitAppInfo = async ( const zoneRecord = await prisma.zones.findMany({ where: { zoneId: pullZone!.id, - name: appInfo.apId, + name: appInfo.appId, sourceDomain: appInfo.sourceDomain, }, }); @@ -164,19 +164,18 @@ export const submitAppInfo = async ( await prisma.zones.create({ data: { zoneId: pullZone!.id, - name: appInfo.apId, + name: appInfo.appId, hostname: appInfo.hostname, sourceDomain: appInfo.sourceDomain, }, }); } - return formatJSONResponse({ + return formatJSONResponse(200, { appInfo, }); } catch (e) { - return formatJSONResponse({ - status: 500, + return formatJSONResponse(500, { message: e, }); } diff --git a/serverless/src/functions/builds/handler.ts b/serverless/src/functions/builds/handler.ts index d2652678..bab1f1ae 100644 --- a/serverless/src/functions/builds/handler.ts +++ b/serverless/src/functions/builds/handler.ts @@ -9,9 +9,8 @@ export const submitBuildInfo = async ( ): Promise => { try { if (event.body === null) { - return formatJSONResponse({ - status: 422, - message: 'Required parameters were not passed.', + return formatJSONResponse(422, { + message: 'The request body is not configured properly.', }); } @@ -39,7 +38,6 @@ export const submitBuildInfo = async ( }); if (buildRecord.length == 0) { - await prisma.builds.create({ data: { githubRepository: buildInfo.githubRepository, @@ -83,12 +81,11 @@ export const submitBuildInfo = async ( }); } - return formatJSONResponse({ + return formatJSONResponse(200, { buildInfo, }); } catch (e) { - return formatJSONResponse({ - status: 500, + return formatJSONResponse(500, { message: e, }); } diff --git a/serverless/src/functions/mints/handler.ts b/serverless/src/functions/mints/handler.ts index 90705a75..43fbe932 100644 --- a/serverless/src/functions/mints/handler.ts +++ b/serverless/src/functions/mints/handler.ts @@ -16,8 +16,7 @@ export const submitMintInfo = async ( ): Promise => { try { if (event.body === null || event.body === undefined) { - return formatJSONResponse({ - status: 422, + return formatJSONResponse(422, { message: 'Required parameters were not passed.', }); } @@ -36,8 +35,7 @@ export const submitMintInfo = async ( process.env.ALCHEMY_SIGNING_KEY ) ) { - return formatJSONResponse({ - status: 401, + return formatJSONResponse(401, { message: 'Unauthorized', }); } @@ -216,12 +214,11 @@ export const submitMintInfo = async ( }); } - return formatJSONResponse({ + return formatJSONResponse(200, { mintInfo, }); } catch (e) { - return formatJSONResponse({ - status: 500, + return formatJSONResponse(500, { message: e, }); } diff --git a/serverless/src/libs/api-gateway.ts b/serverless/src/libs/api-gateway.ts index c1a43c54..bfc3c324 100644 --- a/serverless/src/libs/api-gateway.ts +++ b/serverless/src/libs/api-gateway.ts @@ -1,8 +1,15 @@ // QUESTION: should we add back in schema verification? -export const formatJSONResponse = (response: Record) => { +export const formatJSONResponse = ( + code: number, + response: Record +) => { return { - statusCode: 200, + statusCode: code, + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Credentials': true, + }, body: JSON.stringify(response), }; }; diff --git a/subgraph/schema.graphql b/subgraph/schema.graphql index ad347fe7..a41d2702 100644 --- a/subgraph/schema.graphql +++ b/subgraph/schema.graphql @@ -81,16 +81,17 @@ type Token @entity { verifier: Verifier # Address verified: Boolean! createdAt: BigInt! - builds: [Build!]! + builds: [Build!]! @derivedFrom(field: "token") } type Build @entity { - id: Bytes! # Token ID + id: Bytes! # Build number + number: Int! gitRepository: GitRepository! commitHash: String! ipfsHash: String! domain: String! - token: Token! @derivedFrom(field: "builds") + token: Token! } # Owner entity for collection, access points, and tokens diff --git a/subgraph/src/metadata-update.ts b/subgraph/src/metadata-update.ts index faba2b3a..55412e23 100644 --- a/subgraph/src/metadata-update.ts +++ b/subgraph/src/metadata-update.ts @@ -81,9 +81,16 @@ export function handleMetadataUpdateWithMultipleStringValues( entity.save(); + // LOAD THE BUILD LIST + let token = Token.load( + Bytes.fromByteArray(Bytes.fromBigInt(event.params._tokenId)) + ); + if (!token) { + return; + } // CREATE BUILD const build = new Build( - Bytes.fromByteArray(Bytes.fromBigInt(event.params._tokenId)) + Bytes.fromByteArray(Bytes.fromI32(token.builds.length)) ); if (event.params.key == 'build') { let gitRepositoryEntity = GitRepositoryEntity.load(event.params.value[1]); @@ -91,10 +98,12 @@ export function handleMetadataUpdateWithMultipleStringValues( // Create a new gitRepository entity gitRepositoryEntity = new GitRepositoryEntity(event.params.value[1]); } + build.number = token.builds.length; build.commitHash = event.params.value[0]; build.gitRepository = event.params.value[1]; build.ipfsHash = event.params.value[2]; build.domain = event.params.value[3]; + build.token = Bytes.fromByteArray(Bytes.fromBigInt(event.params._tokenId)); build.save(); gitRepositoryEntity.save(); } diff --git a/subgraph/src/mint.ts b/subgraph/src/mint.ts index eb1c5770..8cf26bc4 100644 --- a/subgraph/src/mint.ts +++ b/subgraph/src/mint.ts @@ -11,6 +11,7 @@ import { GitRepository, Collection, Verifier, + Build, } from '../generated/schema'; export function handleNewMint(event: NewMintEvent): void { @@ -92,6 +93,16 @@ export function handleNewMint(event: NewMintEvent): void { repository = new GitRepository(gitRepository); } + // Populate GitRepository entity + let build = new Build(Bytes.fromByteArray(Bytes.fromI32(0))); + build.number = 0; + build.commitHash = commitHash; + build.ipfsHash = ipfsHash; + build.domain = externalURL; + build.gitRepository = gitRepository; + build.token = Bytes.fromByteArray(Bytes.fromBigInt(tokenId)); + build.save(); + // Increase total tokens counter const collection = Collection.load(event.address); if (collection) {