diff --git a/.github/workflows-off/Deploy.yml b/.github/workflows-off/Deploy.yml new file mode 100644 index 0000000..71a918e --- /dev/null +++ b/.github/workflows-off/Deploy.yml @@ -0,0 +1,57 @@ +name: Deploy + +on: + push: + branches: + - main + +jobs: + Deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 9 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + + - name: Install dependencies + run: pnpm install + + - name: Build all + run: pnpm build + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: sa-east-1 + + - name: SAM Build + run: sam build + + - name: SAM Deploy + run: | + sam deploy --stack-name ${{env.STACK_NAME}} --parameter-overrides StackName='${{ env.STACK_NAME }}' DomainName='${{env.UI_DOMAIN}}' + + - name: Deploy UI to s3 + working-directory: ./packages/ui + run: | + aws s3 sync dist s3://${{ env.STACK_NAME }}.${{env.UI_DOMAIN}}/ + + - name: Invalidate UI Cloudfront Distribution + run: | + DISTRIBUTION_ID=$(aws cloudformation describe-stacks --stack-name ${{ env.STACK_NAME }} --query "Stacks[0].Outputs[?OutputKey=='CloudFrontDistributionId'].OutputValue" --output text) + aws cloudfront create-invalidation --distribution-id ${{env.DISTRIBUTION_ID}} --paths "/*" + + - name: Deploy Api + uses: serverless/github-action@v3.2 + with: + args: deploy --stage develop -c serverless-api.yml + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index a52370e..4cdc9e1 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,5 @@ dist-ssr /coverage /coverage.json -.serverless \ No newline at end of file +.serverless +*-lock* \ No newline at end of file diff --git a/README.md b/README.md index b25774b..518caff 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,18 @@ Execute the following command in your terminal: ```shell npx serverless config credentials --provider aws --key --secret ``` + +## Useful information if you fork this monorepo + +### Package lock is git ignored +Intended in order to avoid merge conflicts on this repo + +**Don't forget to remove it from git ignore!** +Package versions should always be defined specifically (without the simbol ^) +This ensures that even if the lock is deleted, same versions would be reinstalled. + +Having the lock inside your repo is useful for CI package caching and to avoid version diff on fresh install. + +### Github workflow is deactivated +We don't want to trigger the workflow here, but you probably want to. +You should rename the .github/workflows-off folder to **.github/workflow** \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index e69de29..0000000 diff --git a/package.json b/package.json index 1b74432..d86bba9 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,10 @@ "name": "react-monorepo-template", "version": "0.0.0", "type": "module", - "workspaces": [ - "packages/*" - ], "scripts": { "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", - "dev": "concurrently --kill-others \"npm run dev -w packages/api\" \"npm run dev -w packages/ui\"", - "build": "npm run build -w packages/ui && npm run build -w packages/api" + "dev": "concurrently --kill-others \"pnpm --filter api run dev\" \"pnpm --filter ui run dev\"", + "build": "pnpm -r run build" }, "keywords": [], "author": "", @@ -22,7 +19,6 @@ "eslint-plugin-react-hooks": "4.6.0", "eslint-plugin-react-refresh": "0.4.6", "serverless": "3.38.0", - "serverless-cloudfront-invalidate": "1.12.2", "serverless-plugin-common-excludes": "4.0.0", "serverless-plugin-include-dependencies": "6.0.0", "serverless-s3-sync": "3.3.0" diff --git a/packages/api/package.json b/packages/api/package.json index 93b1ae3..769c595 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,5 +1,5 @@ { - "name": "@react-monorepo-template/api", + "name": "api", "version": "0.0.0", "type": "module", "main": "dist/app.js", @@ -16,10 +16,10 @@ "@types/express": "4.17.21", "@types/morgan": "1.9.9", "rimraf": "5.0.5", - "ts-patch": "^3.1.2", - "tsx": "^4.11.0", + "ts-patch": "3.1.2", + "tsx": "4.11.0", "typescript": "5.4.4", - "typescript-transform-paths": "^3.4.7" + "typescript-transform-paths": "3.4.7" }, "dependencies": { "cors": "2.8.5", diff --git a/packages/ui/package.json b/packages/ui/package.json index b9bf069..9088cdf 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,5 +1,5 @@ { - "name": "@react-monorepo-template/ui", + "name": "ui", "private": true, "version": "0.0.0", "type": "module", @@ -20,13 +20,13 @@ "@types/react": "18.2.66", "@types/react-dom": "18.2.22", "@vitejs/plugin-react-swc": "3.5.0", - "autoprefixer": "^10.4.19", - "daisyui": "^4.11.1", - "postcss": "^8.4.38", - "tailwindcss": "^3.4.3", + "autoprefixer": "10.4.19", + "daisyui": "4.11.1", + "postcss": "8.4.38", + "tailwindcss": "3.4.3", "typescript": "5.2.2", "vite": "5.2.0", - "vite-tsconfig-paths": "^4.3.2" + "vite-tsconfig-paths": "4.3.2" }, "optionalDependencies": { "@rollup/rollup-linux-x64-gnu": "4.14.2" diff --git a/packages/ui/template.yml b/packages/ui/template.yml new file mode 100644 index 0000000..08098d6 --- /dev/null +++ b/packages/ui/template.yml @@ -0,0 +1,136 @@ +AWSTemplateFormatVersion: "2010-09-09" +Transform: AWS::Serverless-2016-10-31 +Description: UI + +Parameters: + StackName: # must be lower case + Type: String + DomainName: + Type: String + +Resources: + SecurityHeadersPolicy: + Type: AWS::CloudFront::ResponseHeadersPolicy + Properties: + ResponseHeadersPolicyConfig: + Name: !Sub "${StackName}CustomSecurityHeadersPolicy" + Comment: Security headers for CloudFront distribution + #Enable if cors issues + # CorsConfig: + # CorsBehavior: + # AccessControlAllowCredentials: true + # AccessControlAllowOrigins: + # Items: + # - "*" + # AccessControlAllowHeaders: + # Items: + # - "*" + # AccessControlAllowMethods: + # - GET + # - POST + # - OPTIONS + # - PUT + # - DELETE + # - PATCH + # AccessControlMaxAgeSec: 600 + # OriginOverride: true + SecurityHeadersConfig: + StrictTransportSecurity: + AccessControlMaxAgeSec: 63072000 + IncludeSubdomains: true + Override: true + Preload: true + ContentTypeOptions: + Override: true + FrameOptions: + FrameOption: DENY + Override: true + ReferrerPolicy: + ReferrerPolicy: no-referrer + Override: true + XSSProtection: + Protection: true + ModeBlock: true + Override: true + + S3Bucket: + Type: AWS::S3::Bucket + Properties: + BucketName: !Sub "${StackName}.${DomainName}" + WebsiteConfiguration: + IndexDocument: index.html + ErrorDocument: index.html + PublicAccessBlockConfiguration: + BlockPublicAcls: false + BlockPublicPolicy: false + IgnorePublicAcls: false + RestrictPublicBuckets: false + + S3BucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref S3Bucket + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: "*" + Action: s3:GetObject + Resource: !Sub "arn:aws:s3:::${S3Bucket}/*" + + CloudFrontDistribution: + Type: AWS::CloudFront::Distribution + Properties: + DistributionConfig: + DefaultRootObject: index.html + Origins: + - DomainName: !Sub "${StackName}.${DomainName}.s3-website-${AWS::Region}.amazonaws.com" + Id: !Sub "${StackName}S3Origin" + CustomOriginConfig: + OriginProtocolPolicy: http-only + ViewerCertificate: + CloudFrontDefaultCertificate: true + DefaultCacheBehavior: + TargetOriginId: !Sub "${StackName}S3Origin" + ViewerProtocolPolicy: redirect-to-https + AllowedMethods: + - HEAD + - GET + CachedMethods: + - HEAD + - GET + Compress: true + CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 + ResponseHeadersPolicyId: !Ref SecurityHeadersPolicy + CacheBehaviors: + - PathPattern: index.html + TargetOriginId: !Sub "${StackName}S3Origin" + ViewerProtocolPolicy: redirect-to-https + AllowedMethods: + - HEAD + - GET + CachedMethods: + - HEAD + - GET + Compress: true + CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad + ResponseHeadersPolicyId: !Ref SecurityHeadersPolicy #Comentar si la seguridad en index.html rompe + - PathPattern: /static/js/*.js + TargetOriginId: !Sub "${StackName}S3Origin" + ViewerProtocolPolicy: redirect-to-https + AllowedMethods: + - HEAD + - GET + CachedMethods: + - HEAD + - GET + Compress: true + CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 + ResponseHeadersPolicyId: !Ref SecurityHeadersPolicy + Enabled: true + PriceClass: PriceClass_All + +Outputs: + CloudFrontDistributionId: + Description: "CloudFront Distribution ID" + Value: !Ref CloudFrontDistribution \ No newline at end of file diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..4340350 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - 'packages/*' \ No newline at end of file diff --git a/samconfig.toml b/samconfig.toml new file mode 100644 index 0000000..cb3f222 --- /dev/null +++ b/samconfig.toml @@ -0,0 +1,9 @@ +version = 0.1 +[default] +[default.deploy] +[default.deploy.parameters] +region = "sa-east-1" +resolve_s3 = true +confirm_changeset = true +capabilities = "CAPABILITY_IAM CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND" + diff --git a/template.yml b/template.yml new file mode 100644 index 0000000..dec3c6f --- /dev/null +++ b/template.yml @@ -0,0 +1,24 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + Arbitrum Transaction Enforcer template + +Parameters: + StackName: + Type: String + DomainName: + Type: String + +Resources: + UI: + Type: AWS::CloudFormation::Stack + Properties: + TemplateURL: packages/ui/template.yml + Parameters: + StackName: !Ref StackName + DomainName: !Ref DomainName + +Outputs: + CloudFrontDistributionId: + Description: "CloudFront Distribution ID from the UI stack" + Value: !GetAtt UI.Outputs.CloudFrontDistributionId \ No newline at end of file