From b089c20a5ddebca25f21601ae02a36da1b53d5ee Mon Sep 17 00:00:00 2001 From: Mats Jun Date: Tue, 21 Nov 2023 13:36:42 +0100 Subject: [PATCH] Create deploy tool for deploying AWS Lambda Docker containers (#731) Shorthand tool for: 1. Logging into ECR 2. Building the Docker image 3. Pushing the Docker image to ECR 4. Updating the lambda code with the image ## Usage From the root directory, invoke Ship and specify which app to deploy. It will read the ship.json config file in the target directory. ```sh pnpm ship deploy apps/dispatcher-auth --env dev ``` Example ship.json configuration ```json { "imageName": "dispatcher-auth", "version": "latest", "environments": [ { "name": "dev", "ecrRepository": "891459268445.dkr.ecr.eu-north-1.amazonaws.com/dispatcher-auth-dev", "functionName": "dispatcher-auth-dev", "dockerfile": "apps/dispatcher-auth/Dockerfile" } ] } ``` --- .dockerignore | 4 + apps/dispatcher-auth/package.json | 3 - apps/dispatcher-auth/ship.json | 12 + package.json | 3 +- packages/logger/src/index.ts | 3 +- pnpm-lock.yaml | 755 ++++++++++++++++++++++-------- tools/ship/package.json | 29 ++ tools/ship/src/aws.ts | 43 ++ tools/ship/src/config.ts | 76 +++ tools/ship/src/docker.ts | 65 +++ tools/ship/src/index.ts | 37 ++ tools/ship/src/logger.ts | 3 + tools/ship/tsconfig.json | 3 + 13 files changed, 836 insertions(+), 200 deletions(-) create mode 100644 apps/dispatcher-auth/ship.json create mode 100644 tools/ship/package.json create mode 100644 tools/ship/src/aws.ts create mode 100644 tools/ship/src/config.ts create mode 100644 tools/ship/src/docker.ts create mode 100644 tools/ship/src/index.ts create mode 100644 tools/ship/src/logger.ts create mode 100644 tools/ship/tsconfig.json diff --git a/.dockerignore b/.dockerignore index 555328ee3..21470865c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,6 +4,10 @@ .next .turbo .react-email +.git + +.dockerignore +.env* node_modules infra diff --git a/apps/dispatcher-auth/package.json b/apps/dispatcher-auth/package.json index 1be3a5c3a..3b484e799 100644 --- a/apps/dispatcher-auth/package.json +++ b/apps/dispatcher-auth/package.json @@ -8,9 +8,6 @@ "build": "tsup src/lambda.ts && echo '{\"type\":\"module\"}' > dist/package.json", "lint": "eslint --max-warnings 0 .", "lint:fix": "eslint --fix .", - "docker:build": "docker build --platform linux/amd64 -t dispatcher-auth:latest -f Dockerfile ../..", - "docker:push:dev": "docker tag dispatcher-auth:latest 891459268445.dkr.ecr.eu-north-1.amazonaws.com/dispatcher-auth-dev:latest && docker push 891459268445.dkr.ecr.eu-north-1.amazonaws.com/dispatcher-auth-dev:latest", - "lambda:update:dev": "aws lambda update-function-code --function-name dispatcher-auth-dev --image-uri 891459268445.dkr.ecr.eu-north-1.amazonaws.com/dispatcher-auth-dev:latest", "type-check": "tsc --noEmit" }, "dependencies": { diff --git a/apps/dispatcher-auth/ship.json b/apps/dispatcher-auth/ship.json new file mode 100644 index 000000000..efa216a4e --- /dev/null +++ b/apps/dispatcher-auth/ship.json @@ -0,0 +1,12 @@ +{ + "imageName": "dispatcher-auth", + "version": "latest", + "environments": [ + { + "name": "dev", + "ecrRepository": "891459268445.dkr.ecr.eu-north-1.amazonaws.com/dispatcher-auth-dev", + "functionName": "dispatcher-auth-dev", + "dockerfile": "apps/dispatcher-auth/Dockerfile" + } + ] +} diff --git a/package.json b/package.json index 3e64c1299..9636a690a 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "type-check": "turbo run type-check", "clean": "turbo run clean", "docker:login": "aws ecr get-login-password --region eu-north-1 | docker login --username AWS --password-stdin 891459268445.dkr.ecr.eu-north-1.amazonaws.com", - "docker:login:public": "aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws" + "docker:login:public": "aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws", + "ship": "pnpm --filter=@dotkomonline/ship ship" }, "workspaces": [ "packages/*", diff --git a/packages/logger/src/index.ts b/packages/logger/src/index.ts index b98d4d729..1915ebfe8 100644 --- a/packages/logger/src/index.ts +++ b/packages/logger/src/index.ts @@ -1,11 +1,10 @@ import winston, { format } from "winston" -import { env } from "@dotkomonline/env" export type { Logger } from "winston" export const getLogger = (path: string) => winston.createLogger({ level: "info", - silent: env.NODE_ENV === "test", + silent: process.env.NODE_ENV === "test", format: format.json(), transports: [ new winston.transports.Console({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b00dc973b..142247f1e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -109,10 +109,10 @@ importers: version: 1.11.10 next: specifier: ^14.0.2 - version: 14.0.2(react-dom@18.2.0)(react@18.2.0) + version: 14.0.3(react-dom@18.2.0)(react@18.2.0) next-auth: specifier: ^4.24.5 - version: 4.24.5(next@14.0.2)(react-dom@18.2.0)(react@18.2.0) + version: 4.24.5(next@14.0.3)(react-dom@18.2.0)(react@18.2.0) pg-native: specifier: file:./stubs/pg-native version: file:apps/dashboard/stubs/pg-native @@ -155,7 +155,7 @@ importers: version: 8.53.0 eslint-config-next: specifier: ^14.0.2 - version: 14.0.2(eslint@8.53.0)(typescript@5.2.2) + version: 14.0.3(eslint@8.53.0)(typescript@5.2.2) open-color: specifier: ^1.9.1 version: 1.9.1 @@ -265,7 +265,7 @@ importers: version: 2.0.0 next: specifier: ^14.0.2 - version: 14.0.2(react-dom@18.2.0)(react@18.2.0) + version: 14.0.3(react-dom@18.2.0)(react@18.2.0) react: specifier: ^18.2.0 version: 18.2.0 @@ -302,7 +302,7 @@ importers: version: 8.53.0 eslint-config-next: specifier: ^14.0.2 - version: 14.0.2(eslint@8.53.0)(typescript@5.2.2) + version: 14.0.3(eslint@8.53.0)(typescript@5.2.2) postcss: specifier: ^8.4.31 version: 8.4.31 @@ -323,7 +323,7 @@ importers: dependencies: '@sanity/vision': specifier: ^3.19.3 - version: 3.19.3(@babel/runtime@7.23.2)(@codemirror/lint@6.4.0)(@codemirror/state@6.2.1)(@codemirror/theme-one-dark@6.1.2)(@lezer/common@1.0.3)(codemirror@6.0.1)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(styled-components@6.1.1) + version: 3.20.0(@babel/runtime@7.23.2)(@codemirror/lint@6.4.0)(@codemirror/state@6.2.1)(@codemirror/theme-one-dark@6.1.2)(@lezer/common@1.0.3)(codemirror@6.0.1)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(styled-components@6.1.1) react: specifier: ^18.2.0 version: 18.2.0 @@ -335,7 +335,7 @@ importers: version: 18.2.0 sanity: specifier: ^3.19.3 - version: 3.19.3(@types/node@18.18.9)(react-dom@18.2.0)(react@18.2.0)(styled-components@6.1.1) + version: 3.20.0(@types/node@18.18.9)(react-dom@18.2.0)(react@18.2.0)(styled-components@6.1.1) styled-components: specifier: ^6.1.1 version: 6.1.1(react-dom@18.2.0)(react@18.2.0) @@ -378,7 +378,7 @@ importers: version: link:../../packages/ui '@next/env': specifier: ^14.0.2 - version: 14.0.2 + version: 14.0.3 '@portabletext/react': specifier: ^3.0.11 version: 3.0.11(react@18.2.0) @@ -417,7 +417,7 @@ importers: version: 10.43.3(@trpc/server@10.43.3) '@trpc/next': specifier: ^10.43.3 - version: 10.43.3(@tanstack/react-query@4.36.1)(@trpc/client@10.43.3)(@trpc/react-query@10.43.3)(@trpc/server@10.43.3)(next@14.0.2)(react-dom@18.2.0)(react@18.2.0) + version: 10.43.3(@tanstack/react-query@4.36.1)(@trpc/client@10.43.3)(@trpc/react-query@10.43.3)(@trpc/server@10.43.3)(next@14.0.3)(react-dom@18.2.0)(react@18.2.0) '@trpc/react-query': specifier: ^10.43.3 version: 10.43.3(@tanstack/react-query@4.36.1)(@trpc/client@10.43.3)(@trpc/server@10.43.3)(react-dom@18.2.0)(react@18.2.0) @@ -438,16 +438,16 @@ importers: version: 2.30.0 next: specifier: ^14.0.2 - version: 14.0.2(react-dom@18.2.0)(react@18.2.0) + version: 14.0.3(react-dom@18.2.0)(react@18.2.0) next-auth: specifier: ^4.24.5 - version: 4.24.5(next@14.0.2)(react-dom@18.2.0)(react@18.2.0) + version: 4.24.5(next@14.0.3)(react-dom@18.2.0)(react@18.2.0) next-superjson-plugin: specifier: ^0.5.10 - version: 0.5.10(next@14.0.2)(superjson@1.13.3) + version: 0.5.10(next@14.0.3)(superjson@1.13.3) next-themes: specifier: ^0.2.1 - version: 0.2.1(next@14.0.2)(react-dom@18.2.0)(react@18.2.0) + version: 0.2.1(next@14.0.3)(react-dom@18.2.0)(react@18.2.0) pg: specifier: ^8.11.3 version: 8.11.3 @@ -508,7 +508,7 @@ importers: version: 8.53.0 eslint-config-next: specifier: ^14.0.2 - version: 14.0.2(eslint@8.53.0)(typescript@5.2.2) + version: 14.0.3(eslint@8.53.0)(typescript@5.2.2) jsdom: specifier: ^22.1.0 version: 22.1.0 @@ -541,10 +541,10 @@ importers: version: link:../env next: specifier: ^14.0.2 - version: 14.0.2(react-dom@18.2.0)(react@18.2.0) + version: 14.0.3(react-dom@18.2.0)(react@18.2.0) next-auth: specifier: ^4.24.5 - version: 4.24.5(next@14.0.2)(react-dom@18.2.0)(react@18.2.0) + version: 4.24.5(next@14.0.3)(react-dom@18.2.0)(react@18.2.0) react: specifier: ^18.2.0 version: 18.2.0 @@ -578,7 +578,7 @@ importers: version: 8.53.0 eslint-config-next: specifier: ^14.0.2 - version: 14.0.2(eslint@8.53.0)(typescript@5.2.2) + version: 14.0.3(eslint@8.53.0)(typescript@5.2.2) eslint-config-prettier: specifier: ^9.0.0 version: 9.0.0(eslint@8.53.0) @@ -644,7 +644,7 @@ importers: version: 0.26.3 next: specifier: ^14.0.2 - version: 14.0.2(react-dom@18.2.0)(react@18.2.0) + version: 14.0.3(react-dom@18.2.0)(react@18.2.0) stripe: specifier: ^13.11.0 version: 13.11.0 @@ -762,7 +762,7 @@ importers: version: link:../db next: specifier: ^14.0.2 - version: 14.0.2(react-dom@18.2.0)(react@18.2.0) + version: 14.0.3(react-dom@18.2.0)(react@18.2.0) stripe: specifier: ^13.11.0 version: 13.11.0 @@ -796,10 +796,10 @@ importers: version: 10.43.3 next: specifier: ^14.0.2 - version: 14.0.2(react-dom@18.2.0)(react@18.2.0) + version: 14.0.3(react-dom@18.2.0)(react@18.2.0) next-auth: specifier: ^4.24.5 - version: 4.24.5(next@14.0.2)(react-dom@18.2.0)(react@18.2.0) + version: 4.24.5(next@14.0.3)(react-dom@18.2.0)(react@18.2.0) superjson: specifier: ^1.13.3 version: 1.13.3 @@ -988,6 +988,58 @@ importers: specifier: ^5.2.2 version: 5.2.2 + tools/ship: + dependencies: + '@aws-sdk/client-ecr': + specifier: ^3.451.0 + version: 3.451.0 + '@aws-sdk/client-lambda': + specifier: ^3.451.0 + version: 3.451.0 + '@dotkomonline/env': + specifier: workspace:* + version: link:../../packages/env + chalk: + specifier: ^5.3.0 + version: 5.3.0 + commander: + specifier: ^11.1.0 + version: 11.1.0 + dockerode: + specifier: ^4.0.0 + version: 4.0.0 + ignore-walk: + specifier: ^6.0.3 + version: 6.0.3 + tiny-invariant: + specifier: ^1.3.1 + version: 1.3.1 + zod: + specifier: ^3.22.4 + version: 3.22.4 + devDependencies: + '@dotkomonline/logger': + specifier: workspace:* + version: link:../../packages/logger + '@types/dockerode': + specifier: ^3.3.23 + version: 3.3.23 + '@types/eslint': + specifier: ^8.44.6 + version: 8.44.7 + '@types/ignore-walk': + specifier: ^4.0.3 + version: 4.0.3 + eslint: + specifier: ^8.52.0 + version: 8.53.0 + tsx: + specifier: ^3.14.0 + version: 3.14.0 + typescript: + specifier: ^5.2.2 + version: 5.2.2 + packages: /@aashutoshrathi/word-wrap@1.2.6: @@ -1122,6 +1174,106 @@ packages: - aws-crt dev: false + /@aws-sdk/client-ecr@3.451.0: + resolution: {integrity: sha512-VDyf3Ov3xVUAk7iBDuv5w9ZVl8RurXN0nkZe9Pgw4SsCdh56ntoR82QrJPCfbNrCLEVJcSIrY2+I/jZdFyidIQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.451.0 + '@aws-sdk/core': 3.451.0 + '@aws-sdk/credential-provider-node': 3.451.0 + '@aws-sdk/middleware-host-header': 3.451.0 + '@aws-sdk/middleware-logger': 3.451.0 + '@aws-sdk/middleware-recursion-detection': 3.451.0 + '@aws-sdk/middleware-signing': 3.451.0 + '@aws-sdk/middleware-user-agent': 3.451.0 + '@aws-sdk/region-config-resolver': 3.451.0 + '@aws-sdk/types': 3.451.0 + '@aws-sdk/util-endpoints': 3.451.0 + '@aws-sdk/util-user-agent-browser': 3.451.0 + '@aws-sdk/util-user-agent-node': 3.451.0 + '@smithy/config-resolver': 2.0.18 + '@smithy/fetch-http-handler': 2.2.6 + '@smithy/hash-node': 2.0.15 + '@smithy/invalid-dependency': 2.0.13 + '@smithy/middleware-content-length': 2.0.15 + '@smithy/middleware-endpoint': 2.2.0 + '@smithy/middleware-retry': 2.0.20 + '@smithy/middleware-serde': 2.0.13 + '@smithy/middleware-stack': 2.0.7 + '@smithy/node-config-provider': 2.1.5 + '@smithy/node-http-handler': 2.1.9 + '@smithy/protocol-http': 3.0.9 + '@smithy/smithy-client': 2.1.15 + '@smithy/types': 2.5.0 + '@smithy/url-parser': 2.0.13 + '@smithy/util-base64': 2.0.1 + '@smithy/util-body-length-browser': 2.0.0 + '@smithy/util-body-length-node': 2.1.0 + '@smithy/util-defaults-mode-browser': 2.0.19 + '@smithy/util-defaults-mode-node': 2.0.25 + '@smithy/util-endpoints': 1.0.4 + '@smithy/util-retry': 2.0.6 + '@smithy/util-utf8': 2.0.2 + '@smithy/util-waiter': 2.0.13 + tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/client-lambda@3.451.0: + resolution: {integrity: sha512-fQcNDG7XRak05GV2zmEQ7mDymOTl3YFYLWT4Ua5VkACw1N0/Y0V7ekpzTSmGHUHr5EJvLGqwH24G+SLrRb75hw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.451.0 + '@aws-sdk/core': 3.451.0 + '@aws-sdk/credential-provider-node': 3.451.0 + '@aws-sdk/middleware-host-header': 3.451.0 + '@aws-sdk/middleware-logger': 3.451.0 + '@aws-sdk/middleware-recursion-detection': 3.451.0 + '@aws-sdk/middleware-signing': 3.451.0 + '@aws-sdk/middleware-user-agent': 3.451.0 + '@aws-sdk/region-config-resolver': 3.451.0 + '@aws-sdk/types': 3.451.0 + '@aws-sdk/util-endpoints': 3.451.0 + '@aws-sdk/util-user-agent-browser': 3.451.0 + '@aws-sdk/util-user-agent-node': 3.451.0 + '@smithy/config-resolver': 2.0.18 + '@smithy/eventstream-serde-browser': 2.0.13 + '@smithy/eventstream-serde-config-resolver': 2.0.13 + '@smithy/eventstream-serde-node': 2.0.13 + '@smithy/fetch-http-handler': 2.2.6 + '@smithy/hash-node': 2.0.15 + '@smithy/invalid-dependency': 2.0.13 + '@smithy/middleware-content-length': 2.0.15 + '@smithy/middleware-endpoint': 2.2.0 + '@smithy/middleware-retry': 2.0.20 + '@smithy/middleware-serde': 2.0.13 + '@smithy/middleware-stack': 2.0.7 + '@smithy/node-config-provider': 2.1.5 + '@smithy/node-http-handler': 2.1.9 + '@smithy/protocol-http': 3.0.9 + '@smithy/smithy-client': 2.1.15 + '@smithy/types': 2.5.0 + '@smithy/url-parser': 2.0.13 + '@smithy/util-base64': 2.0.1 + '@smithy/util-body-length-browser': 2.0.0 + '@smithy/util-body-length-node': 2.1.0 + '@smithy/util-defaults-mode-browser': 2.0.19 + '@smithy/util-defaults-mode-node': 2.0.25 + '@smithy/util-endpoints': 1.0.4 + '@smithy/util-retry': 2.0.6 + '@smithy/util-stream': 2.0.20 + '@smithy/util-utf8': 2.0.2 + '@smithy/util-waiter': 2.0.13 + tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/client-s3@3.451.0: resolution: {integrity: sha512-wDQjG/5jEswus1JclfcWeTIwrAXfAFSPz1tvwo7mRrfDNH8UPFjKKBI9ArBBwwaWUj4ou++56CHFKhKX4ytaQw==} engines: {node: '>=14.0.0'} @@ -1341,7 +1493,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.451.0 - '@smithy/property-provider': 2.0.13 + '@smithy/property-provider': 2.0.14 '@smithy/types': 2.5.0 tslib: 2.6.2 dev: false @@ -1355,9 +1507,9 @@ packages: '@aws-sdk/credential-provider-sso': 3.451.0 '@aws-sdk/credential-provider-web-identity': 3.451.0 '@aws-sdk/types': 3.451.0 - '@smithy/credential-provider-imds': 2.0.18 - '@smithy/property-provider': 2.0.13 - '@smithy/shared-ini-file-loader': 2.2.2 + '@smithy/credential-provider-imds': 2.1.1 + '@smithy/property-provider': 2.0.14 + '@smithy/shared-ini-file-loader': 2.2.4 '@smithy/types': 2.5.0 tslib: 2.6.2 transitivePeerDependencies: @@ -1374,9 +1526,9 @@ packages: '@aws-sdk/credential-provider-sso': 3.451.0 '@aws-sdk/credential-provider-web-identity': 3.451.0 '@aws-sdk/types': 3.451.0 - '@smithy/credential-provider-imds': 2.0.18 - '@smithy/property-provider': 2.0.13 - '@smithy/shared-ini-file-loader': 2.2.2 + '@smithy/credential-provider-imds': 2.1.1 + '@smithy/property-provider': 2.0.14 + '@smithy/shared-ini-file-loader': 2.2.4 '@smithy/types': 2.5.0 tslib: 2.6.2 transitivePeerDependencies: @@ -1388,8 +1540,8 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.451.0 - '@smithy/property-provider': 2.0.13 - '@smithy/shared-ini-file-loader': 2.2.2 + '@smithy/property-provider': 2.0.14 + '@smithy/shared-ini-file-loader': 2.2.4 '@smithy/types': 2.5.0 tslib: 2.6.2 dev: false @@ -1401,8 +1553,8 @@ packages: '@aws-sdk/client-sso': 3.451.0 '@aws-sdk/token-providers': 3.451.0 '@aws-sdk/types': 3.451.0 - '@smithy/property-provider': 2.0.13 - '@smithy/shared-ini-file-loader': 2.2.2 + '@smithy/property-provider': 2.0.14 + '@smithy/shared-ini-file-loader': 2.2.4 '@smithy/types': 2.5.0 tslib: 2.6.2 transitivePeerDependencies: @@ -1414,7 +1566,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.451.0 - '@smithy/property-provider': 2.0.13 + '@smithy/property-provider': 2.0.14 '@smithy/types': 2.5.0 tslib: 2.6.2 dev: false @@ -1614,9 +1766,9 @@ packages: '@smithy/middleware-stack': 2.0.7 '@smithy/node-config-provider': 2.1.5 '@smithy/node-http-handler': 2.1.9 - '@smithy/property-provider': 2.0.13 + '@smithy/property-provider': 2.0.14 '@smithy/protocol-http': 3.0.9 - '@smithy/shared-ini-file-loader': 2.2.2 + '@smithy/shared-ini-file-loader': 2.2.4 '@smithy/smithy-client': 2.1.15 '@smithy/types': 2.5.0 '@smithy/url-parser': 2.0.13 @@ -1718,6 +1870,13 @@ packages: '@babel/highlight': 7.22.20 chalk: 2.4.2 + /@babel/code-frame@7.22.5: + resolution: {integrity: sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.22.20 + dev: true + /@babel/compat-data@7.22.9: resolution: {integrity: sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==} engines: {node: '>=6.9.0'} @@ -1727,15 +1886,15 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.22.13 - '@babel/generator': 7.23.0 - '@babel/helper-compilation-targets': 7.22.15 - '@babel/helper-module-transforms': 7.23.0(@babel/core@7.22.9) - '@babel/helpers': 7.23.1 - '@babel/parser': 7.23.0 - '@babel/template': 7.22.15 + '@babel/code-frame': 7.22.5 + '@babel/generator': 7.22.9 + '@babel/helper-compilation-targets': 7.22.9(@babel/core@7.22.9) + '@babel/helper-module-transforms': 7.22.9(@babel/core@7.22.9) + '@babel/helpers': 7.22.6 + '@babel/parser': 7.22.7 + '@babel/template': 7.22.5 '@babel/traverse': 7.23.0 - '@babel/types': 7.23.0 + '@babel/types': 7.22.5 convert-source-map: 1.9.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -1781,6 +1940,16 @@ packages: semver: 6.3.1 dev: true + /@babel/generator@7.22.9: + resolution: {integrity: sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.0 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.18 + jsesc: 2.5.2 + dev: true + /@babel/generator@7.23.0: resolution: {integrity: sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==} engines: {node: '>=6.9.0'} @@ -1814,6 +1983,20 @@ packages: lru-cache: 5.1.1 semver: 6.3.1 + /@babel/helper-compilation-targets@7.22.9(@babel/core@7.22.9): + resolution: {integrity: sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/compat-data': 7.22.9 + '@babel/core': 7.22.9 + '@babel/helper-validator-option': 7.22.15 + browserslist: 4.21.11 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + /@babel/helper-create-class-features-plugin@7.22.9(@babel/core@7.22.9): resolution: {integrity: sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ==} engines: {node: '>=6.9.0'} @@ -1854,7 +2037,7 @@ packages: '@babel/helper-plugin-utils': 7.22.5 debug: 4.3.4 lodash.debounce: 4.0.8 - resolve: 1.22.8 + resolve: 1.22.3 transitivePeerDependencies: - supports-color dev: true @@ -1889,6 +2072,20 @@ packages: dependencies: '@babel/types': 7.23.0 + /@babel/helper-module-transforms@7.22.9(@babel/core@7.22.9): + resolution: {integrity: sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + /@babel/helper-module-transforms@7.23.0(@babel/core@7.22.9): resolution: {integrity: sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==} engines: {node: '>=6.9.0'} @@ -1982,6 +2179,11 @@ packages: resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==} engines: {node: '>=6.9.0'} + /@babel/helper-validator-option@7.22.5: + resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-wrap-function@7.22.9: resolution: {integrity: sha512-sZ+QzfauuUEfxSEjKFmi3qDSHgLsTPK/pEpoD/qonZKOtTPTLbf59oabPQ4rKekt9lFcj/hTZaOhWwFYrgjk+Q==} engines: {node: '>=6.9.0'} @@ -1991,6 +2193,17 @@ packages: '@babel/types': 7.23.0 dev: true + /@babel/helpers@7.22.6: + resolution: {integrity: sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.0 + '@babel/types': 7.23.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helpers@7.23.1: resolution: {integrity: sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==} engines: {node: '>=6.9.0'} @@ -2009,6 +2222,14 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 + /@babel/parser@7.22.7: + resolution: {integrity: sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.23.0 + dev: true + /@babel/parser@7.23.0: resolution: {integrity: sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==} engines: {node: '>=6.0.0'} @@ -2841,9 +3062,9 @@ packages: dependencies: '@babel/compat-data': 7.22.9 '@babel/core': 7.22.9 - '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-compilation-targets': 7.22.9(@babel/core@7.22.9) '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.22.15 + '@babel/helper-validator-option': 7.22.5 '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.22.5(@babel/core@7.22.9) '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.22.5(@babel/core@7.22.9) '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.22.9) @@ -2914,7 +3135,7 @@ packages: '@babel/plugin-transform-unicode-regex': 7.22.5(@babel/core@7.22.9) '@babel/plugin-transform-unicode-sets-regex': 7.22.5(@babel/core@7.22.9) '@babel/preset-modules': 0.1.6(@babel/core@7.22.9) - '@babel/types': 7.23.0 + '@babel/types': 7.22.5 babel-plugin-polyfill-corejs2: 0.4.5(@babel/core@7.22.9) babel-plugin-polyfill-corejs3: 0.8.3(@babel/core@7.22.9) babel-plugin-polyfill-regenerator: 0.5.2(@babel/core@7.22.9) @@ -2976,6 +3197,15 @@ packages: '@babel/parser': 7.23.0 '@babel/types': 7.23.0 + /@babel/template@7.22.5: + resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/parser': 7.23.0 + '@babel/types': 7.23.0 + dev: true + /@babel/traverse@7.23.0: resolution: {integrity: sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==} engines: {node: '>=6.9.0'} @@ -2993,6 +3223,15 @@ packages: transitivePeerDependencies: - supports-color + /@babel/types@7.22.5: + resolution: {integrity: sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: true + /@babel/types@7.23.0: resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==} engines: {node: '>=6.9.0'} @@ -3003,7 +3242,6 @@ packages: /@balena/dockerignore@1.0.2: resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} - dev: true /@codemirror/autocomplete@6.9.0(@codemirror/language@6.8.0)(@codemirror/state@6.2.1)(@codemirror/view@6.15.3)(@lezer/common@1.0.3): resolution: {integrity: sha512-Fbwm0V/Wn3BkEJZRhr0hi5BhCo5a7eBL6LYaliPjOSwCyfOpnjXY59HruSxOUNV+1OYer0Tgx1zRNQttjXyDog==} @@ -4232,18 +4470,18 @@ packages: - supports-color dev: true - /@next/env@14.0.2: - resolution: {integrity: sha512-HAW1sljizEaduEOes/m84oUqeIDAUYBR1CDwu2tobNlNDFP3cSm9d6QsOsGeNlIppU1p/p1+bWbYCbvwjFiceA==} + /@next/env@14.0.3: + resolution: {integrity: sha512-7xRqh9nMvP5xrW4/+L0jgRRX+HoNRGnfJpD+5Wq6/13j3dsdzxO3BCXn7D3hMqsDb+vjZnJq+vI7+EtgrYZTeA==} dev: false - /@next/eslint-plugin-next@14.0.2: - resolution: {integrity: sha512-APrYFsXfAhnysycqxHcpg6Y4i7Ukp30GzVSZQRKT3OczbzkqGjt33vNhScmgoOXYBU1CfkwgtXmNxdiwv1jKmg==} + /@next/eslint-plugin-next@14.0.3: + resolution: {integrity: sha512-j4K0n+DcmQYCVnSAM+UByTVfIHnYQy2ODozfQP+4RdwtRDfobrIvKq1K4Exb2koJ79HSSa7s6B2SA8T/1YR3RA==} dependencies: glob: 7.1.7 dev: true - /@next/swc-darwin-arm64@14.0.2: - resolution: {integrity: sha512-i+jQY0fOb8L5gvGvojWyZMfQoQtDVB2kYe7fufOEiST6sicvzI2W5/EXo4lX5bLUjapHKe+nFxuVv7BA+Pd7LQ==} + /@next/swc-darwin-arm64@14.0.3: + resolution: {integrity: sha512-64JbSvi3nbbcEtyitNn2LEDS/hcleAFpHdykpcnrstITFlzFgB/bW0ER5/SJJwUPj+ZPY+z3e+1jAfcczRLVGw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -4251,8 +4489,8 @@ packages: dev: false optional: true - /@next/swc-darwin-x64@14.0.2: - resolution: {integrity: sha512-zRCAO0d2hW6gBEa4wJaLn+gY8qtIqD3gYd9NjruuN98OCI6YyelmhWVVLlREjS7RYrm9OUQIp/iVJFeB6kP1hg==} + /@next/swc-darwin-x64@14.0.3: + resolution: {integrity: sha512-RkTf+KbAD0SgYdVn1XzqE/+sIxYGB7NLMZRn9I4Z24afrhUpVJx6L8hsRnIwxz3ERE2NFURNliPjJ2QNfnWicQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -4260,8 +4498,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-gnu@14.0.2: - resolution: {integrity: sha512-tSJmiaon8YaKsVhi7GgRizZoV0N1Sx5+i+hFTrCKKQN7s3tuqW0Rov+RYdPhAv/pJl4qiG+XfSX4eJXqpNg3dA==} + /@next/swc-linux-arm64-gnu@14.0.3: + resolution: {integrity: sha512-3tBWGgz7M9RKLO6sPWC6c4pAw4geujSwQ7q7Si4d6bo0l6cLs4tmO+lnSwFp1Tm3lxwfMk0SgkJT7EdwYSJvcg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -4269,8 +4507,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-musl@14.0.2: - resolution: {integrity: sha512-dXJLMSEOwqJKcag1BeX1C+ekdPPJ9yXbWIt3nAadhbLx5CjACoB2NQj9Xcqu2tmdr5L6m34fR+fjGPs+ZVPLzA==} + /@next/swc-linux-arm64-musl@14.0.3: + resolution: {integrity: sha512-v0v8Kb8j8T23jvVUWZeA2D8+izWspeyeDGNaT2/mTHWp7+37fiNfL8bmBWiOmeumXkacM/AB0XOUQvEbncSnHA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -4278,8 +4516,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-gnu@14.0.2: - resolution: {integrity: sha512-WC9KAPSowj6as76P3vf1J3mf2QTm3Wv3FBzQi7UJ+dxWjK3MhHVWsWUo24AnmHx9qDcEtHM58okgZkXVqeLB+Q==} + /@next/swc-linux-x64-gnu@14.0.3: + resolution: {integrity: sha512-VM1aE1tJKLBwMGtyBR21yy+STfl0MapMQnNrXkxeyLs0GFv/kZqXS5Jw/TQ3TSUnbv0QPDf/X8sDXuMtSgG6eg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -4287,8 +4525,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-musl@14.0.2: - resolution: {integrity: sha512-KSSAwvUcjtdZY4zJFa2f5VNJIwuEVnOSlqYqbQIawREJA+gUI6egeiRu290pXioQXnQHYYdXmnVNZ4M+VMB7KQ==} + /@next/swc-linux-x64-musl@14.0.3: + resolution: {integrity: sha512-64EnmKy18MYFL5CzLaSuUn561hbO1Gk16jM/KHznYP3iCIfF9e3yULtHaMy0D8zbHfxset9LTOv6cuYKJgcOxg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -4296,8 +4534,8 @@ packages: dev: false optional: true - /@next/swc-win32-arm64-msvc@14.0.2: - resolution: {integrity: sha512-2/O0F1SqJ0bD3zqNuYge0ok7OEWCQwk55RPheDYD0va5ij7kYwrFkq5ycCRN0TLjLfxSF6xI5NM6nC5ux7svEQ==} + /@next/swc-win32-arm64-msvc@14.0.3: + resolution: {integrity: sha512-WRDp8QrmsL1bbGtsh5GqQ/KWulmrnMBgbnb+59qNTW1kVi1nG/2ndZLkcbs2GX7NpFLlToLRMWSQXmPzQm4tog==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -4305,8 +4543,8 @@ packages: dev: false optional: true - /@next/swc-win32-ia32-msvc@14.0.2: - resolution: {integrity: sha512-vJI/x70Id0oN4Bq/R6byBqV1/NS5Dl31zC+lowO8SDu1fHmUxoAdILZR5X/sKbiJpuvKcCrwbYgJU8FF/Gh50Q==} + /@next/swc-win32-ia32-msvc@14.0.3: + resolution: {integrity: sha512-EKffQeqCrj+t6qFFhIFTRoqb2QwX1mU7iTOvMyLbYw3QtqTw9sMwjykyiMlZlrfm2a4fA84+/aeW+PMg1MjuTg==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -4314,8 +4552,8 @@ packages: dev: false optional: true - /@next/swc-win32-x64-msvc@14.0.2: - resolution: {integrity: sha512-Ut4LXIUvC5m8pHTe2j0vq/YDnTEyq6RSR9vHYPqnELrDapPhLNz9Od/L5Ow3J8RNDWpEnfCiQXuVdfjlNEJ7ug==} + /@next/swc-win32-x64-msvc@14.0.3: + resolution: {integrity: sha512-ERhKPSJ1vQrPiwrs15Pjz/rvDHZmkmvbf/BjPN/UCOI++ODftT0GtasDPi0j+y6PPJi5HsXw+dpRaXUaw4vjuQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -5676,15 +5914,15 @@ packages: rxjs: 7.8.1 dev: false - /@sanity/block-tools@3.19.3: - resolution: {integrity: sha512-m4+p8OXor+hufy8yd5ZcuJKFNb7zYAlNp77GQl6LV+6DcfFGxDGN+2R/5qwh1Fot9ufIiGRkRTl5aWYrd2PUVg==} + /@sanity/block-tools@3.20.0: + resolution: {integrity: sha512-h8XN+9Q3IbUQAUVLqcTb4lu1GaGog0eSba/qafzsfP/cUBhu5X3V8XmOhOUxnm0KYh/G7rOiyiTFlM8QH5PE6Q==} dependencies: get-random-values-esm: 1.0.0 lodash: 4.17.21 dev: false - /@sanity/cli@3.19.3: - resolution: {integrity: sha512-DoekRfYh1ihJJ7Oeuju0kkpGnqas0xl5Yugu1JJ+snW/tRG8+0legigY0SHkjyPbJoFChvK1sKZE8xP12Cc7Fw==} + /@sanity/cli@3.20.0: + resolution: {integrity: sha512-1rvEw4owMSsqeq+5R5hb8moDTrMtrktx2L6p/PWJu2Sb+Iwctm51G+XOTjH9On0o3jhLQPG0BPLE6rXEUlcPyA==} engines: {node: '>=18'} hasBin: true dependencies: @@ -5731,8 +5969,8 @@ packages: engines: {node: '>=14.18'} dev: false - /@sanity/diff@3.19.3: - resolution: {integrity: sha512-stzVGEBGUP4Gytkukad/zQJ8QOVXQjKwJzhbI5LnPcRgQI5bccAYYY9mJkPWkjIerolyo/4bc3qYB48RaQBVPg==} + /@sanity/diff@3.20.0: + resolution: {integrity: sha512-0VV3gIK5SEWCQ3oINZECqGGfRNuMN0Rk3wOENaZG/n44RRf7F5yQy9wABBXiRsODDPyHu5IUOfqbE0ozT610/Q==} engines: {node: '>=18'} dependencies: '@sanity/diff-match-patch': 3.1.1 @@ -5767,8 +6005,8 @@ packages: eventsource: 2.0.2 dev: false - /@sanity/export@3.19.3: - resolution: {integrity: sha512-DrDfHJS7oybIynKNiRthiqg4zJT/CzfgyydQXfkVUPquxjO629VeDXLDfvhvNLrF1ZqNZTtdrF6ngggfXoDZzw==} + /@sanity/export@3.20.0: + resolution: {integrity: sha512-D3Qp8DZxi5fTGeySH7hRA3TsU13UVwjTfWt8id+jfjZ5a4dJYy7Xd/skfT1srHIbI3R/7RtU92l3Roozpg8PaA==} engines: {node: '>=18'} dependencies: archiver: 5.3.2 @@ -5787,6 +6025,16 @@ packages: resolution: {integrity: sha512-wtMYcV5GIDIhVyF/jjmdwq1GdlK07dRL40XMns73VbrFI7FteRltxv48bhYVZPcLkRXb0SHjpDS/icj9/yzbVA==} dev: false + /@sanity/groq-store@5.0.1-experimental(@sanity/client@6.8.6): + resolution: {integrity: sha512-3qKQVxQW7j0n4DbmiFzEhC9jLK51u2F0d1xGYUWn0dUU5wrot2BfdlINGdCFze9FjvoPrOkihD6rc51Gfnk2xg==} + engines: {node: '>=18'} + peerDependencies: + '@sanity/client': ^6.8.6 + dependencies: + '@sanity/client': 6.8.6 + mnemonist: 0.39.5 + dev: false + /@sanity/icons@2.7.0(react@18.2.0): resolution: {integrity: sha512-vW/G8CB3+R1gww8C8ZjNchhpXrXSDLIJ0KnWy9iDlSWaFEnUrbi18yzCCrHRMFzXTPl2QtqZhjtE+A5Gyhf2QA==} engines: {node: '>=14.0.0'} @@ -5801,13 +6049,13 @@ packages: engines: {node: '>=10.0.0'} dev: false - /@sanity/import@3.19.3: - resolution: {integrity: sha512-9uXanchWewUVtMMVCFGWI3vhULb48LZBa+pq6AMDnqLcWl4+SmjGthx7gmUf2re8A2Fy6bl0H74uqAEMzCpLCg==} + /@sanity/import@3.20.0: + resolution: {integrity: sha512-fFkl+AgvRL5Bcl9OLhyXmxh02+zLZYI9BxtxUjPB+mz7kk3LdaxgEo+3pKQaawv/USQl8d/2IkHSa1ofX0LFzQ==} engines: {node: '>=18'} dependencies: '@sanity/asset-utils': 1.3.0 '@sanity/generate-help-url': 3.0.0 - '@sanity/mutator': 3.19.3 + '@sanity/mutator': 3.20.0 '@sanity/uuid': 3.0.2 debug: 3.2.7 file-url: 2.0.2 @@ -5838,8 +6086,8 @@ packages: react: 18.2.0 dev: false - /@sanity/mutator@3.19.3: - resolution: {integrity: sha512-BdTz4m5Q757/A024DrNJMtFaeRQYApX6yMAU5GyQjBH/NEF94ZXglZ9AiEgqZ7U+b9R6cAouCH/k4dsbJn0Sbg==} + /@sanity/mutator@3.20.0: + resolution: {integrity: sha512-BGdFRAWqDpB3iriBYq5SZCnF1B+u1/pR4URuHOIxRraRbO7MXDhVbpe8MBEo3CPCTakCP+FfdF+WhznMc8bPEQ==} dependencies: '@sanity/diff-match-patch': 3.1.1 '@sanity/uuid': 3.0.2 @@ -5849,18 +6097,18 @@ packages: - supports-color dev: false - /@sanity/portable-text-editor@3.19.3(react-dom@18.2.0)(react@18.2.0)(rxjs@7.8.1)(styled-components@6.1.1): - resolution: {integrity: sha512-9a92Uv8RaIqIx98ODR/wmGBFqkxxII0MEySKs0Xh4OW/c/7k0Uax6CiZswOZtJqErMqQyfCiH5gf/uRSJmcbZQ==} + /@sanity/portable-text-editor@3.20.0(react-dom@18.2.0)(react@18.2.0)(rxjs@7.8.1)(styled-components@6.1.1): + resolution: {integrity: sha512-Udl4K3uGmybnZSbCunNC2d6YN+ELY94ron4J5zSuXV5ULD4paKgU8HkOdOJtN0AfLmgd0OBcn8GOtrjXd9ZtHQ==} engines: {node: '>=18'} peerDependencies: react: ^16.9 || ^17 || ^18 rxjs: ^7 styled-components: ^5.2 || ^6 dependencies: - '@sanity/block-tools': 3.19.3 - '@sanity/schema': 3.19.3 - '@sanity/types': 3.19.3 - '@sanity/util': 3.19.3 + '@sanity/block-tools': 3.20.0 + '@sanity/schema': 3.20.0 + '@sanity/types': 3.20.0 + '@sanity/util': 3.20.0 debug: 3.2.7 is-hotkey: 0.1.8 lodash: 4.17.21 @@ -5874,11 +6122,50 @@ packages: - supports-color dev: false - /@sanity/schema@3.19.3: - resolution: {integrity: sha512-KQfNuSRAPuRpft7H3X+L3rLtF8zjbIs/d/3jbrRZHqYPxhe1oTtqlf2X3En389Kym4DSSlQ625yZ/zmJYJDVIQ==} + /@sanity/presentation@1.0.3(@sanity/client@6.8.6)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(sanity@3.20.0)(styled-components@6.1.1): + resolution: {integrity: sha512-1+vKL9HPRV5ew9rzU4Gorgcw1OLhTVTeoYjy4zJjs41w9rNCFnBNd5GVvy6qYLiyAG47h8VtOwZG95wm27bJxA==} + engines: {node: '>=16.14'} + peerDependencies: + '@sanity/client': ^6.8.6 + react: ^18.2.0 + react-dom: ^18.2.0 + sanity: ^3.19.3 + styled-components: ^6.1.1 + dependencies: + '@sanity/client': 6.8.6 + '@sanity/groq-store': 5.0.1-experimental(@sanity/client@6.8.6) + '@sanity/icons': 2.7.0(react@18.2.0) + '@sanity/preview-url-secret': 1.0.2(@sanity/client@6.8.6) + '@sanity/ui': 1.9.3(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(styled-components@6.1.1) + '@types/lodash.isequal': 4.5.8 + framer-motion: 10.16.5(react-dom@18.2.0)(react@18.2.0) + lodash.isequal: 4.5.0 + mendoza: 3.0.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + rxjs: 7.8.1 + sanity: 3.20.0(@types/node@18.18.9)(react-dom@18.2.0)(react@18.2.0)(styled-components@6.1.1) + styled-components: 6.1.1(react-dom@18.2.0)(react@18.2.0) + suspend-react: 0.1.3(react@18.2.0) + transitivePeerDependencies: + - react-is + dev: false + + /@sanity/preview-url-secret@1.0.2(@sanity/client@6.8.6): + resolution: {integrity: sha512-+Im3HdXdFZk0ZCYbeeDUC7ns30NijcBS7ldsxOPNn3+NTmZ5Cw8VvHZ3OLOnA/6ddhR4T2y+CLwsduQz09PHTg==} + engines: {node: '>=18'} + peerDependencies: + '@sanity/client': ^6.8.6 + dependencies: + '@sanity/client': 6.8.6 + '@sanity/uuid': 3.0.2 + dev: false + + /@sanity/schema@3.20.0: + resolution: {integrity: sha512-eYsG/L+k1l6fZcZ5XTETjisxuCDNKf0Td0ywdloq4AvVpXCDYDmsYw81UHzvoviuWZ7zejo1lvs5LnIeOl1gzQ==} dependencies: '@sanity/generate-help-url': 3.0.0 - '@sanity/types': 3.19.3 + '@sanity/types': 3.20.0 arrify: 1.0.1 humanize-list: 1.0.1 leven: 3.1.0 @@ -5888,8 +6175,8 @@ packages: - supports-color dev: false - /@sanity/types@3.19.3: - resolution: {integrity: sha512-yiAwDqn058GD4rGl7hGVNH21rqR5hQlk0LBLB2BX4qnrxrqZ30+xFHwjgRM8EYFN51VspEbtov2jQmCijlIOpg==} + /@sanity/types@3.20.0: + resolution: {integrity: sha512-EhSTVaG91yYAayMg11N8rm35vzOvwMWeBRv3mia1cIf/KfXnlClCnSDiqLkkdrdSq6N+G6gmjcpSP/zNd9e0gg==} dependencies: '@sanity/client': 6.8.6 '@types/react': 18.2.37 @@ -5918,11 +6205,11 @@ packages: styled-components: 6.1.1(react-dom@18.2.0)(react@18.2.0) dev: false - /@sanity/util@3.19.3: - resolution: {integrity: sha512-70VE9Xy8DZS5hHatu54nhU/qv4orrelV7/C3M/EoXyhTTOcvUoWXTTKzasqBGSUNASxKkNX9GuGoj7tUtPWCVQ==} + /@sanity/util@3.20.0: + resolution: {integrity: sha512-9/NOG+fIn0N3Jv6G39ldjW+sX3Cz5rncw3G+ufrOIU4BjDPfwzAGqL+paQWKmPm/RiTU/AaVn62nVfkqj33dAA==} engines: {node: '>=18'} dependencies: - '@sanity/types': 3.19.3 + '@sanity/types': 3.20.0 get-random-values-esm: 1.0.0 moment: 2.29.4 transitivePeerDependencies: @@ -5936,8 +6223,8 @@ packages: uuid: 8.3.2 dev: false - /@sanity/vision@3.19.3(@babel/runtime@7.23.2)(@codemirror/lint@6.4.0)(@codemirror/state@6.2.1)(@codemirror/theme-one-dark@6.1.2)(@lezer/common@1.0.3)(codemirror@6.0.1)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(styled-components@6.1.1): - resolution: {integrity: sha512-Bc3yhM8zMHakwxscNuz7PMG7+MvTreU6W97yX8+IuWBsdg4a6P5nOEgDvaPod6krCyGrr3f4MmwHWmLRqH9+Qw==} + /@sanity/vision@3.20.0(@babel/runtime@7.23.2)(@codemirror/lint@6.4.0)(@codemirror/state@6.2.1)(@codemirror/theme-one-dark@6.1.2)(@lezer/common@1.0.3)(codemirror@6.0.1)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(styled-components@6.1.1): + resolution: {integrity: sha512-QNgr4Ihrdwo06J4ch57rJfAdFFYAYEJBBaBqNIS8e3DDrtvp8BZLjKj8pUVxNBqpFQ8+eB1H+ZbqPjvPOmyGXg==} peerDependencies: react: ^18 styled-components: ^5.2 || ^6 @@ -6023,17 +6310,6 @@ packages: tslib: 2.6.2 dev: false - /@smithy/credential-provider-imds@2.0.18: - resolution: {integrity: sha512-QnPBi6D2zj6AHJdUTo5zXmk8vwHJ2bNevhcVned1y+TZz/OI5cizz5DsYNkqFUIDn8tBuEyKNgbmKVNhBbuY3g==} - engines: {node: '>=14.0.0'} - dependencies: - '@smithy/node-config-provider': 2.1.5 - '@smithy/property-provider': 2.0.13 - '@smithy/types': 2.5.0 - '@smithy/url-parser': 2.0.13 - tslib: 2.6.2 - dev: false - /@smithy/credential-provider-imds@2.1.1: resolution: {integrity: sha512-gw5G3FjWC6sNz8zpOJgPpH5HGKrpoVFQpToNAwLwJVyI/LJ2jDJRjSKEsM6XI25aRpYjMSE/Qptxx305gN1vHw==} engines: {node: '>=14.0.0'} @@ -6279,14 +6555,6 @@ packages: '@smithy/types': 2.5.0 dev: false - /@smithy/shared-ini-file-loader@2.2.2: - resolution: {integrity: sha512-noyQUPn7b1M8uB0GEXc/Zyxq+5K2b7aaqWnLp+hgJ7+xu/FCvtyWy5eWLDjQEsHnAet2IZhS5QF8872OR69uNg==} - engines: {node: '>=14.0.0'} - dependencies: - '@smithy/types': 2.5.0 - tslib: 2.6.2 - dev: false - /@smithy/shared-ini-file-loader@2.2.4: resolution: {integrity: sha512-9dRknGgvYlRIsoTcmMJXuoR/3ekhGwhRq4un3ns2/byre4Ql5hyUN4iS0x8eITohjU90YOnUCsbRwZRvCkbRfw==} engines: {node: '>=14.0.0'} @@ -6725,7 +6993,7 @@ packages: '@trpc/server': 10.43.3 dev: false - /@trpc/next@10.43.3(@tanstack/react-query@4.36.1)(@trpc/client@10.43.3)(@trpc/react-query@10.43.3)(@trpc/server@10.43.3)(next@14.0.2)(react-dom@18.2.0)(react@18.2.0): + /@trpc/next@10.43.3(@tanstack/react-query@4.36.1)(@trpc/client@10.43.3)(@trpc/react-query@10.43.3)(@trpc/server@10.43.3)(next@14.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-ioOqV5zJNi9iFibCfz0KqKNJsrONjBfF+JB3y845I+MKGZt7vhpBAJJucioLzhvnRwbwy4My3LTdjcyOsUtYUQ==} peerDependencies: '@tanstack/react-query': ^4.18.0 @@ -6740,7 +7008,7 @@ packages: '@trpc/client': 10.43.3(@trpc/server@10.43.3) '@trpc/react-query': 10.43.3(@tanstack/react-query@4.36.1)(@trpc/client@10.43.3)(@trpc/server@10.43.3)(react-dom@18.2.0)(react@18.2.0) '@trpc/server': 10.43.3 - next: 14.0.2(react-dom@18.2.0)(react@18.2.0) + next: 14.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-ssr-prepass: 1.5.0(react@18.2.0) @@ -6839,6 +7107,20 @@ packages: '@types/ms': 0.7.33 dev: true + /@types/docker-modem@3.0.6: + resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==} + dependencies: + '@types/node': 18.18.9 + '@types/ssh2': 0.5.52 + dev: true + + /@types/dockerode@3.3.23: + resolution: {integrity: sha512-Lz5J+NFgZS4cEVhquwjIGH4oQwlVn2h7LXD3boitujBnzOE5o7s9H8hchEjoDK2SlRsJTogdKnQeiJgPPKLIEw==} + dependencies: + '@types/docker-modem': 3.0.6 + '@types/node': 18.18.9 + dev: true + /@types/eslint@8.44.7: resolution: {integrity: sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ==} dependencies: @@ -6882,12 +7164,18 @@ packages: '@types/unist': 3.0.1 dev: true - /@types/is-hotkey@0.1.7: - resolution: {integrity: sha512-yB5C7zcOM7idwYZZ1wKQ3pTfjA9BbvFqRWvKB46GFddxnJtHwi/b9y84ykQtxQPg5qhdpg4Q/kWU3EGoCTmLzQ==} + /@types/ignore-walk@4.0.3: + resolution: {integrity: sha512-6V7wDsk0nz8LtRC7qeC0GfXadFLT4FdCtVbXhxoIGRdkn2kLr20iMLupRGiBhlZ79WWWqaObIdR3nkXfUrBPdQ==} + dependencies: + '@types/node': 18.18.9 + dev: true + + /@types/is-hotkey@0.1.10: + resolution: {integrity: sha512-RvC8KMw5BCac1NvRRyaHgMMEtBaZ6wh0pyPTBu7izn4Sj/AX9Y4aXU5c7rX8PnM/knsuUpC1IeoBkANtxBypsQ==} dev: false - /@types/is-hotkey@0.1.9: - resolution: {integrity: sha512-ZUK9mvsjXXZo4YtGcEVBVhyN80mbuqId0evT9ni+anA3C291IPIzxU+1JFJ9/vvU0qZhydeuJIpUCn6d0rnsCw==} + /@types/is-hotkey@0.1.7: + resolution: {integrity: sha512-yB5C7zcOM7idwYZZ1wKQ3pTfjA9BbvFqRWvKB46GFddxnJtHwi/b9y84ykQtxQPg5qhdpg4Q/kWU3EGoCTmLzQ==} dev: false /@types/js-levenshtein@1.1.2: @@ -6910,8 +7198,18 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true - /@types/lodash@4.14.201: - resolution: {integrity: sha512-y9euML0cim1JrykNxADLfaG0FgD1g/yTHwUs/Jg9ZIU7WKj2/4IW9Lbb1WZbvck78W/lfGXFfe+u2EGfIJXdLQ==} + /@types/lodash.isequal@4.5.8: + resolution: {integrity: sha512-uput6pg4E/tj2LGxCZo9+y27JNyB2OZuuI/T5F+ylVDYuqICLG2/ktjxx0v6GvVntAf8TvEzeQLcV0ffRirXuA==} + dependencies: + '@types/lodash': 4.14.196 + dev: false + + /@types/lodash@4.14.196: + resolution: {integrity: sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ==} + dev: false + + /@types/lodash@4.14.202: + resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==} dev: false /@types/mdast@3.0.14: @@ -7727,6 +8025,16 @@ packages: get-intrinsic: 1.2.1 dev: true + /array.prototype.flat@1.3.1: + resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.1 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 + dev: true + /array.prototype.flat@1.3.2: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} @@ -7788,7 +8096,6 @@ packages: resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} dependencies: safer-buffer: 2.1.2 - dev: true /assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} @@ -7919,7 +8226,6 @@ packages: resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} dependencies: tweetnacl: 0.14.5 - dev: true /before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} @@ -8044,7 +8350,6 @@ packages: resolution: {integrity: sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==} engines: {node: '>=10.0.0'} requiresBuild: true - dev: true optional: true /bundle-name@3.0.0: @@ -8092,7 +8397,7 @@ packages: /call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: - function-bind: 1.1.2 + function-bind: 1.1.1 get-intrinsic: 1.2.1 /callsites@3.1.0: @@ -8510,7 +8815,6 @@ packages: dependencies: buildcheck: 0.0.6 nan: 2.18.0 - dev: true optional: true /crc-32@1.2.2: @@ -8890,6 +9194,18 @@ packages: - supports-color dev: true + /docker-modem@5.0.1: + resolution: {integrity: sha512-vqrE/nrweCyzmCpVpdFRC41qS+tfTF+IoUKlTZr52O82urbUqdfyJBGWMvT01pYUprWepLr8IkyVTEWJKRTQSg==} + engines: {node: '>= 8.0'} + dependencies: + debug: 4.3.4 + readable-stream: 3.6.2 + split-ca: 1.0.1 + ssh2: 1.14.0 + transitivePeerDependencies: + - supports-color + dev: false + /dockerode@3.3.5: resolution: {integrity: sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA==} engines: {node: '>= 8.0'} @@ -8901,6 +9217,17 @@ packages: - supports-color dev: true + /dockerode@4.0.0: + resolution: {integrity: sha512-3LF7/3MPz5+9RsUo91rD0MCcx0yxjC9bnbtgtVjOLKyKxlZSJ7/Kk3OPAgARlwlWHqXwAGYhmkAHYx7IwD0tJQ==} + engines: {node: '>= 8.0'} + dependencies: + '@balena/dockerignore': 1.0.2 + docker-modem: 5.0.1 + tar-fs: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + /doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -9296,8 +9623,8 @@ packages: source-map: 0.6.1 dev: false - /eslint-config-next@14.0.2(eslint@8.53.0)(typescript@5.2.2): - resolution: {integrity: sha512-CasWThlsyIcg/a+clU6KVOMTieuDhTztsrqvniP6AsRki9v7FnojTa7vKQOYM8QSOsQdZ/aElLD1Y2Oc8/PsIg==} + /eslint-config-next@14.0.3(eslint@8.53.0)(typescript@5.2.2): + resolution: {integrity: sha512-IKPhpLdpSUyKofmsXUfrvBC49JMUTdeaD8ZIH4v9Vk0sC1X6URTuTJCLtA0Vwuj7V/CQh0oISuSTvNn5//Buew==} peerDependencies: eslint: ^7.23.0 || ^8.0.0 typescript: '>=3.3.1' @@ -9305,7 +9632,7 @@ packages: typescript: optional: true dependencies: - '@next/eslint-plugin-next': 14.0.2 + '@next/eslint-plugin-next': 14.0.3 '@rushstack/eslint-patch': 1.4.0 '@typescript-eslint/parser': 6.9.1(eslint@8.53.0)(typescript@5.2.2) eslint: 8.53.0 @@ -9481,8 +9808,8 @@ packages: dependencies: '@babel/runtime': 7.23.2 aria-query: 5.3.0 - array-includes: 3.1.6 - array.prototype.flatmap: 1.3.1 + array-includes: 3.1.7 + array.prototype.flatmap: 1.3.2 ast-types-flow: 0.0.7 axe-core: 4.8.2 axobject-query: 3.2.1 @@ -9494,7 +9821,7 @@ packages: language-tags: 1.0.5 minimatch: 3.1.2 object.entries: 1.1.6 - object.fromentries: 2.0.6 + object.fromentries: 2.0.7 semver: 6.3.1 dev: true @@ -9561,8 +9888,8 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: - array-includes: 3.1.7 - array.prototype.flatmap: 1.3.2 + array-includes: 3.1.6 + array.prototype.flatmap: 1.3.1 array.prototype.tosorted: 1.1.1 doctrine: 2.1.0 eslint: 8.53.0 @@ -9570,9 +9897,9 @@ packages: jsx-ast-utils: 3.3.5 minimatch: 3.1.2 object.entries: 1.1.6 - object.fromentries: 2.0.7 + object.fromentries: 2.0.6 object.hasown: 1.1.2 - object.values: 1.1.7 + object.values: 1.1.6 prop-types: 15.8.1 resolve: 2.0.0-next.4 semver: 6.3.1 @@ -9585,8 +9912,8 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: - array-includes: 3.1.6 - array.prototype.flatmap: 1.3.1 + array-includes: 3.1.7 + array.prototype.flatmap: 1.3.2 array.prototype.tosorted: 1.1.1 doctrine: 2.1.0 es-iterator-helpers: 1.0.15 @@ -9595,9 +9922,9 @@ packages: jsx-ast-utils: 3.3.5 minimatch: 3.1.2 object.entries: 1.1.6 - object.fromentries: 2.0.6 + object.fromentries: 2.0.7 object.hasown: 1.1.2 - object.values: 1.1.6 + object.values: 1.1.7 prop-types: 15.8.1 resolve: 2.0.0-next.4 semver: 6.3.1 @@ -10044,6 +10371,24 @@ packages: '@emotion/is-prop-valid': 0.8.8 dev: false + /framer-motion@10.16.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-GEzVjOYP2MIpV9bT/GbhcsBNoImG3/2X3O/xVNWmktkv9MdJ7P/44zELm/7Fjb+O3v39SmKFnoDQB32giThzpg==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tslib: 2.6.2 + optionalDependencies: + '@emotion/is-prop-valid': 0.8.8 + dev: false + /fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} @@ -10111,7 +10456,6 @@ packages: /function-bind@1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - dev: true /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -10149,7 +10493,7 @@ packages: /get-intrinsic@1.2.1: resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} dependencies: - function-bind: 1.1.2 + function-bind: 1.1.1 has: 1.0.3 has-proto: 1.0.1 has-symbols: 1.0.3 @@ -10478,7 +10822,7 @@ packages: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} dependencies: - function-bind: 1.1.2 + function-bind: 1.1.1 /hashlru@2.3.0: resolution: {integrity: sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A==} @@ -10767,6 +11111,13 @@ packages: /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + /ignore-walk@6.0.3: + resolution: {integrity: sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + minimatch: 9.0.3 + dev: false + /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} @@ -10940,7 +11291,6 @@ packages: resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} dependencies: has: 1.0.3 - dev: true /is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} @@ -11417,10 +11767,10 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} dependencies: - array-includes: 3.1.7 - array.prototype.flat: 1.3.2 + array-includes: 3.1.6 + array.prototype.flat: 1.3.1 object.assign: 4.1.4 - object.values: 1.1.7 + object.values: 1.1.6 dev: true /keygrip@1.1.0: @@ -11605,6 +11955,10 @@ packages: /lodash.flatten@4.4.0: resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + /lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + dev: false + /lodash.isplainobject@4.0.6: resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} @@ -12353,7 +12707,6 @@ packages: engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 - dev: true /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -12400,6 +12753,12 @@ packages: ufo: 1.2.0 dev: true + /mnemonist@0.39.5: + resolution: {integrity: sha512-FPUtkhtJ0efmEFGpU14x7jGbTB+s18LrzRL2KgoWz9YvcY3cPomz8tih01GbHwnGk/OmkOKfqd/RAQoc8Lm7DQ==} + dependencies: + obliterator: 2.0.4 + dev: false + /module-alias@2.2.3: resolution: {integrity: sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==} dev: false @@ -12478,7 +12837,6 @@ packages: /nan@2.18.0: resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==} requiresBuild: true - dev: true optional: true /nano-pubsub@2.0.1: @@ -12503,7 +12861,7 @@ packages: engines: {node: '>= 0.6'} dev: true - /next-auth@4.24.5(next@14.0.2)(react-dom@18.2.0)(react@18.2.0): + /next-auth@4.24.5(next@14.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-3RafV3XbfIKk6rF6GlLE4/KxjTcuMCifqrmD+98ejFq73SRoj2rmzoca8u764977lH/Q7jo6Xu6yM+Re1Mz/Og==} peerDependencies: next: ^12.2.5 || ^13 || ^14 @@ -12518,7 +12876,7 @@ packages: '@panva/hkdf': 1.1.1 cookie: 0.5.0 jose: 4.14.4 - next: 14.0.2(react-dom@18.2.0)(react@18.2.0) + next: 14.0.3(react-dom@18.2.0)(react@18.2.0) oauth: 0.9.15 openid-client: 5.4.3 preact: 10.16.0 @@ -12528,31 +12886,31 @@ packages: uuid: 8.3.2 dev: false - /next-superjson-plugin@0.5.10(next@14.0.2)(superjson@1.13.3): + /next-superjson-plugin@0.5.10(next@14.0.3)(superjson@1.13.3): resolution: {integrity: sha512-y3vAKlZfZP6iEDb0R+XQ6UQ7YYDxbsZ0iZlV50/Hvw0Fzl+ScQJj+CbXdcl+ETugK9JbhCS7G7hMCGIjiGkgXQ==} peerDependencies: next: ^13.0 || ^14.0 superjson: ^1 dependencies: hoist-non-react-statics: 3.3.2 - next: 14.0.2(react-dom@18.2.0)(react@18.2.0) + next: 14.0.3(react-dom@18.2.0)(react@18.2.0) superjson: 1.13.3 dev: false - /next-themes@0.2.1(next@14.0.2)(react-dom@18.2.0)(react@18.2.0): + /next-themes@0.2.1(next@14.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==} peerDependencies: next: '*' react: '*' react-dom: '*' dependencies: - next: 14.0.2(react-dom@18.2.0)(react@18.2.0) + next: 14.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /next@14.0.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-jsAU2CkYS40GaQYOiLl9m93RTv2DA/tTJ0NRlmZIBIL87YwQ/xR8k796z7IqgM3jydI8G25dXvyYMC9VDIevIg==} + /next@14.0.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-AbYdRNfImBr3XGtvnwOxq8ekVCwbFTv/UJoLwmaX89nk9i051AEY4/HAWzU0YpaTDw8IofUpmuIlvzWF13jxIw==} engines: {node: '>=18.17.0'} hasBin: true peerDependencies: @@ -12566,7 +12924,7 @@ packages: sass: optional: true dependencies: - '@next/env': 14.0.2 + '@next/env': 14.0.3 '@swc/helpers': 0.5.2 busboy: 1.6.0 caniuse-lite: 1.0.30001538 @@ -12576,15 +12934,15 @@ packages: styled-jsx: 5.1.1(react@18.2.0) watchpack: 2.4.0 optionalDependencies: - '@next/swc-darwin-arm64': 14.0.2 - '@next/swc-darwin-x64': 14.0.2 - '@next/swc-linux-arm64-gnu': 14.0.2 - '@next/swc-linux-arm64-musl': 14.0.2 - '@next/swc-linux-x64-gnu': 14.0.2 - '@next/swc-linux-x64-musl': 14.0.2 - '@next/swc-win32-arm64-msvc': 14.0.2 - '@next/swc-win32-ia32-msvc': 14.0.2 - '@next/swc-win32-x64-msvc': 14.0.2 + '@next/swc-darwin-arm64': 14.0.3 + '@next/swc-darwin-x64': 14.0.3 + '@next/swc-linux-arm64-gnu': 14.0.3 + '@next/swc-linux-arm64-musl': 14.0.3 + '@next/swc-linux-x64-gnu': 14.0.3 + '@next/swc-linux-x64-musl': 14.0.3 + '@next/swc-win32-arm64-msvc': 14.0.3 + '@next/swc-win32-ia32-msvc': 14.0.3 + '@next/swc-win32-x64-msvc': 14.0.3 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -12632,7 +12990,7 @@ packages: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.8 + resolve: 1.22.3 semver: 5.7.2 validate-npm-package-license: 3.0.4 @@ -12775,6 +13133,10 @@ packages: es-abstract: 1.22.1 dev: true + /obliterator@2.0.4: + resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} + dev: false + /observable-callback@1.0.2(rxjs@7.8.1): resolution: {integrity: sha512-Fb7qVUHqr8jl32NyJffTiqf76NObRvmzaSPgGtaAGH+Wfh45tiGWjrvUsNgEuCa86SUzGZZpoSN0hpGtldoSDg==} peerDependencies: @@ -14000,7 +14362,7 @@ packages: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} engines: {node: '>= 0.10'} dependencies: - resolve: 1.22.8 + resolve: 1.22.3 dev: true /reflect.getprototypeof@1.0.4: @@ -14153,7 +14515,7 @@ packages: resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} hasBin: true dependencies: - is-core-module: 2.13.1 + is-core-module: 2.13.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -14161,7 +14523,7 @@ packages: resolution: {integrity: sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==} hasBin: true dependencies: - is-core-module: 2.13.1 + is-core-module: 2.13.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -14308,8 +14670,8 @@ packages: '@sanity/diff-match-patch': 3.1.1 dev: false - /sanity@3.19.3(@types/node@18.18.9)(react-dom@18.2.0)(react@18.2.0)(styled-components@6.1.1): - resolution: {integrity: sha512-Lz8yynVaZZrtzGcPiWZlZ8wml8xBOnw9O4n/0Nq7dcSeg43kaGIHi0pUSFs3Ft0D7KkgT8fdGCoKN4HabDeZBA==} + /sanity@3.20.0(@types/node@18.18.9)(react-dom@18.2.0)(react@18.2.0)(styled-components@6.1.1): + resolution: {integrity: sha512-mGe9+pn3Y7HrIT5mgCwzEv4OHGJ6C9YlovyQE7gR5XY1p9YJNPonbWUOfhM7D3dVMfG0/OuilH1MmTc1bGnb8w==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -14326,25 +14688,26 @@ packages: '@rexxars/react-json-inspector': 8.0.1(react@18.2.0) '@sanity/asset-utils': 1.3.0 '@sanity/bifur-client': 0.3.1 - '@sanity/block-tools': 3.19.3 - '@sanity/cli': 3.19.3 + '@sanity/block-tools': 3.20.0 + '@sanity/cli': 3.20.0 '@sanity/client': 6.8.6 '@sanity/color': 2.2.5 - '@sanity/diff': 3.19.3 + '@sanity/diff': 3.20.0 '@sanity/diff-match-patch': 3.1.1 '@sanity/eventsource': 5.0.0 - '@sanity/export': 3.19.3 + '@sanity/export': 3.20.0 '@sanity/generate-help-url': 3.0.0 '@sanity/icons': 2.7.0(react@18.2.0) '@sanity/image-url': 1.0.2 - '@sanity/import': 3.19.3 + '@sanity/import': 3.20.0 '@sanity/logos': 2.1.2(@sanity/color@2.2.5)(react@18.2.0) - '@sanity/mutator': 3.19.3 - '@sanity/portable-text-editor': 3.19.3(react-dom@18.2.0)(react@18.2.0)(rxjs@7.8.1)(styled-components@6.1.1) - '@sanity/schema': 3.19.3 - '@sanity/types': 3.19.3 + '@sanity/mutator': 3.20.0 + '@sanity/portable-text-editor': 3.20.0(react-dom@18.2.0)(react@18.2.0)(rxjs@7.8.1)(styled-components@6.1.1) + '@sanity/presentation': 1.0.3(@sanity/client@6.8.6)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(sanity@3.20.0)(styled-components@6.1.1) + '@sanity/schema': 3.20.0 + '@sanity/types': 3.20.0 '@sanity/ui': 1.9.3(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(styled-components@6.1.1) - '@sanity/util': 3.19.3 + '@sanity/util': 3.20.0 '@sanity/uuid': 3.0.2 '@tanstack/react-virtual': 3.0.0-beta.54(react@18.2.0) '@types/is-hotkey': 0.1.7 @@ -14591,8 +14954,8 @@ packages: slate: '>=0.99.0' dependencies: '@juggle/resize-observer': 3.4.0 - '@types/is-hotkey': 0.1.9 - '@types/lodash': 4.14.201 + '@types/is-hotkey': 0.1.10 + '@types/lodash': 4.14.202 direction: 1.0.4 is-hotkey: 0.2.0 is-plain-object: 5.0.0 @@ -14676,7 +15039,6 @@ packages: /split-ca@1.0.1: resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} - dev: true /split-on-first@3.0.0: resolution: {integrity: sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==} @@ -14720,7 +15082,6 @@ packages: optionalDependencies: cpu-features: 0.0.9 nan: 2.18.0 - dev: true /stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} @@ -15005,6 +15366,14 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + /suspend-react@0.1.3(react@18.2.0): + resolution: {integrity: sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==} + peerDependencies: + react: '>=17.0' + dependencies: + react: 18.2.0 + dev: false + /symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -15112,7 +15481,6 @@ packages: mkdirp-classic: 0.5.3 pump: 3.0.0 tar-stream: 2.2.0 - dev: true /tar-fs@2.1.1: resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} @@ -15594,7 +15962,6 @@ packages: /tweetnacl@0.14.5: resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} - dev: true /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} diff --git a/tools/ship/package.json b/tools/ship/package.json new file mode 100644 index 000000000..0ee5c41b5 --- /dev/null +++ b/tools/ship/package.json @@ -0,0 +1,29 @@ +{ + "name": "@dotkomonline/ship", + "type": "module", + "dependencies": { + "@aws-sdk/client-ecr": "^3.451.0", + "@aws-sdk/client-lambda": "^3.451.0", + "@dotkomonline/env": "workspace:*", + "chalk": "^5.3.0", + "commander": "^11.1.0", + "dockerode": "^4.0.0", + "ignore-walk": "^6.0.3", + "tiny-invariant": "^1.3.1", + "zod": "^3.22.4" + }, + "devDependencies": { + "@dotkomonline/logger": "workspace:*", + "@types/dockerode": "^3.3.23", + "@types/eslint": "^8.44.6", + "@types/ignore-walk": "^4.0.3", + "eslint": "^8.52.0", + "tsx": "^3.14.0", + "typescript": "^5.2.2" + }, + "scripts": { + "ship": "tsx ./src/index.ts", + "lint": "eslint --max-warnings 0 .", + "lint:fix": "eslint --fix ." + } +} diff --git a/tools/ship/src/aws.ts b/tools/ship/src/aws.ts new file mode 100644 index 000000000..0a2736438 --- /dev/null +++ b/tools/ship/src/aws.ts @@ -0,0 +1,43 @@ +import { ECRClient, GetAuthorizationTokenCommand } from "@aws-sdk/client-ecr" +import invariant from "tiny-invariant" +import { LambdaClient, UpdateFunctionCodeCommand } from "@aws-sdk/client-lambda" +import { type Context } from "./config" +import { getResolvedRepositoryTag } from "./docker" +import { logger } from "./logger" + +export interface ClientContext { + ecr: ECRClient + lambda: LambdaClient +} + +export const createClientContext = async (): Promise => ({ + ecr: new ECRClient({ region: "eu-north-1" }), + lambda: new LambdaClient({ region: "eu-north-1" }), +}) + +export type ECRCredential = Awaited> + +export const getEcrAuthorizationToken = async (client: ClientContext) => { + const cmd = new GetAuthorizationTokenCommand({}) + const response = await client.ecr.send(cmd) + + invariant(response.authorizationData !== undefined, "Expected authorization data not to be undefined") + invariant(response.authorizationData.length !== 0, "Expected authorization data to include at least one credential") + + const token = response.authorizationData[0].authorizationToken + const endpoint = response.authorizationData[0].proxyEndpoint + + invariant(token !== undefined, "Token must not be undefined") + invariant(endpoint !== undefined, "Proxy endpoint must not be undefined") + + return { token, endpoint } +} + +export const updateFunctionImage = async (client: ClientContext, context: Context) => { + const cmd = new UpdateFunctionCodeCommand({ + FunctionName: context.environment.functionName, + ImageUri: getResolvedRepositoryTag(context), + }) + const response = await client.lambda.send(cmd) + logger.info(`Function image update status: ${response.State}`) +} diff --git a/tools/ship/src/config.ts b/tools/ship/src/config.ts new file mode 100644 index 000000000..5722584f1 --- /dev/null +++ b/tools/ship/src/config.ts @@ -0,0 +1,76 @@ +import fs from "node:fs/promises" +import path from "node:path" +import process from "node:process" +import { z } from "zod" +import invariant from "tiny-invariant" +import { logger } from "./logger" + +export type EnvironmentName = DeployEnvironment["name"] +export type DeployEnvironment = z.infer +export const DeployEnvironment = z.object({ + name: z.enum(["dev", "stg", "prd"]), + ecrRepository: z.string().min(1, "ECR Repository name cannot be empty"), + functionName: z.string().min(1, "AWS Lambda function name cannot be empty"), + dockerfile: z.string(), +}) + +export type Config = z.infer +export const Config = z.object({ + imageName: z.string().min(1, "Docker image name cannot be empty"), + version: z.string().default("latest"), + environments: z + .array(DeployEnvironment) + .nonempty("Configuration file does not contain any environment configurations"), +}) + +export interface Context { + buildRoot: string + basePath: string + config: Config + environment: DeployEnvironment +} + +/** + * Get the resolved configuration file path for a project. + * + * If a directory is passed, for example apps/web, then we will attempt to resolve apps/web/ship.json, + * otherwise try to resolve the file path. + */ +const getConfigurationFile = async (basePath: string): Promise => { + const stat = await fs.stat(path.resolve(basePath)) + if (stat.isDirectory()) { + return path.join(basePath, "ship.json") + } + invariant( + stat.isFile() || stat.isSymbolicLink(), + "Path cannot point to a file descriptor that is not a file or a symbolic link" + ) + return basePath +} + +const readConfiguration = async (basePath: string): Promise => { + const file = await getConfigurationFile(basePath) + logger.info(`Resolved configuration file ${file}`) + const content = await fs.readFile(file, "utf-8") + try { + const json = await JSON.parse(content) + const result = Config.safeParse(json) + invariant(result.success, "JSON did not match schema") + return result.data + } catch (err) { + logger.error(`File contents of ${file} did not contain valid JSON`) + throw process.exit(1) + } +} + +export const resolveContext = async (basePath: string, buildRoot: string, env: EnvironmentName): Promise => { + const config = await readConfiguration(basePath) + const match = config.environments.find((e) => e.name === env) + invariant(match !== undefined, `Found no environment named ${env} in configuration`) + return { + environment: match, + config, + buildRoot, + basePath, + } +} diff --git a/tools/ship/src/docker.ts b/tools/ship/src/docker.ts new file mode 100644 index 000000000..0d6e2af6d --- /dev/null +++ b/tools/ship/src/docker.ts @@ -0,0 +1,65 @@ +import path from "node:path" +import Docker from "dockerode" +import walk from "ignore-walk" +import { type Context } from "./config" +import { logger } from "./logger" +import { type ECRCredential } from "./aws" + +export const docker = new Docker({}) + +const getBuildContext = (buildRoot: string): string[] => { + const dockerignore = path.join(buildRoot, ".dockerignore") + logger.info(`Reading .dockerignore list from ${dockerignore}`) + return walk.sync({ + path: buildRoot, + ignoreFiles: [".dockerignore"], + follow: true, + }) +} + +export const getResolvedTag = (context: Context) => `${context.config.imageName}:${context.config.version}` +export const getResolvedRepositoryTag = (context: Context) => + `${context.environment.ecrRepository}:${context.config.version}` + +export const build = async (context: Context) => { + const files = getBuildContext(context.buildRoot) + const output = await docker.buildImage( + { + context: context.buildRoot, + src: files, + }, + { + t: getResolvedTag(context), + dockerfile: context.environment.dockerfile, + } + ) + output.pipe(process.stdout) + await new Promise((resolve, reject) => { + docker.modem.followProgress(output, (err, res) => (err ? reject(err) : resolve(res))) + }) +} + +export const tag = async (context: Context) => { + const builtImage = docker.getImage(getResolvedTag(context)) + await builtImage.tag({ + repo: context.environment.ecrRepository, + tag: context.config.version, + }) +} + +export const push = async (context: Context, credentials: ECRCredential) => { + const builtImage = docker.getImage(getResolvedRepositoryTag(context)) + const jwt = Buffer.from(credentials.token, "base64").toString().split(":")[1] + const output = await builtImage.push({ + authconfig: { + username: "AWS", + password: jwt, + serveraddress: credentials.endpoint, + }, + tag: context.config.version, + }) + output.pipe(process.stdout) + await new Promise((resolve, reject) => { + docker.modem.followProgress(output, (err, res) => (err ? reject(err) : resolve(res))) + }) +} diff --git a/tools/ship/src/index.ts b/tools/ship/src/index.ts new file mode 100644 index 000000000..32e50403d --- /dev/null +++ b/tools/ship/src/index.ts @@ -0,0 +1,37 @@ +import path from "node:path" +import process from "node:process" +import { Command } from "commander" +import { logger } from "./logger" +import { type EnvironmentName, resolveContext } from "./config" +import { build, getResolvedTag, push, tag } from "./docker" +import { createClientContext, getEcrAuthorizationToken, updateFunctionImage } from "./aws" + +const program = new Command("ship") + +interface DeployOptions { + env: EnvironmentName +} + +program + .command("deploy") + .argument("directory") + .option("-e, --env", "Environment to deploy", /^(?:dev|stg|prd)$/, "dev") + .action(async (directory, options: DeployOptions) => { + const relativePath = path.resolve("../../", directory) + const buildRoot = path.resolve("../../") + logger.info(`Deploying application at path: ${relativePath}`) + logger.info(`Deploying to environment: ${options.env}`) + const context = await resolveContext(relativePath, buildRoot, options.env) + logger.info("Authenticating to AWS ECR Repository") + const aws = await createClientContext() + const credentials = await getEcrAuthorizationToken(aws) + logger.info(`Building Docker image with tag '${getResolvedTag(context)}'`) + await build(context) + logger.info("Pushing Docker image to AWS ECR Repository") + await tag(context) + await push(context, credentials) + logger.info("Updating Lambda Function Code with latest image") + await updateFunctionImage(aws, context) + }) + +program.parse(process.argv) diff --git a/tools/ship/src/logger.ts b/tools/ship/src/logger.ts new file mode 100644 index 000000000..6f6442c12 --- /dev/null +++ b/tools/ship/src/logger.ts @@ -0,0 +1,3 @@ +import { getLogger } from "@dotkomonline/logger" + +export const logger = getLogger("ship") diff --git a/tools/ship/tsconfig.json b/tools/ship/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/tools/ship/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +}