diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f90b1db81cf48ab5df465acf4e715eaa5c49c14b..557a9e3168dfd2c7116064300e8aff7036dd74d6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,8 +3,7 @@ stages: - replay-and-sync - test - test-report-aggregate - - deploy-mainnet - - deploy-mirrornet + - deploy - publish - cleanup @@ -97,12 +96,38 @@ mirrornet-haf-binaries-extraction: - public-runner-docker - hived-for-tests -docker-build-auth: - extends: .docker_build_template +# helper job just to prepare extended version of production image additionally holding .env file specific to test environment +.docker-build-testenv-image: + extends: .docker_image_builder_job_template variables: - TURBO_APP_SCOPE: '@hive/auth' - TURBO_APP_PATH: '/apps/auth' - TURBO_APP_NAME: 'auth' + TURBO_APP_NAME: "" + BASE_IMAGE_NAME: "" + ENV_FILE_PATHNAME: "./apps/${TURBO_APP_NAME}/.env.testing" + IMAGE_SUFFIX: "testenv" + script: + - | + echo -e "\e[0Ksection_start:$(date +%s):login[collapsed=true]\r\e[0KLogging to Docker registry..." + docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY + echo -e "\e[0Ksection_end:$(date +%s):login\r\e[0K" + + export NEW_IMAGE_TAGNAME="${CI_REGISTRY_IMAGE}/${TURBO_APP_NAME}-${IMAGE_SUFFIX}:${CI_COMMIT_SHA}" + + docker buildx build \ + --push \ + -t "${NEW_IMAGE_TAGNAME}" -f- . << EOF + FROM $BASE_IMAGE_NAME AS production + COPY "${ENV_FILE_PATHNAME}" /app/apps/.env + EOF + echo "DENSER_${TURBO_APP_NAME^^}_IMAGE_NAME=${NEW_IMAGE_TAGNAME}" > docker-build-testenv-${TURBO_APP_NAME}-image.env + artifacts: + paths: + - docker-build-testenv-${TURBO_APP_NAME}-image.env + reports: + dotenv: docker-build-testenv-${TURBO_APP_NAME}-image.env + when: always # This ensures artifacts are created even if job fails + tags: + - public-runner-docker + - hived-for-tests docker-build-blog: extends: .docker_build_template @@ -118,6 +143,42 @@ docker-build-wallet: TURBO_APP_PATH: '/apps/wallet' TURBO_APP_NAME: 'wallet' +docker-build-blog-testenv: + extends: .docker-build-testenv-image + needs: + - docker-build-blog + variables: + TURBO_APP_NAME: 'blog' + BASE_IMAGE_NAME: ${BLOG_IMAGE_NAME} + +docker-build-wallet-testenv: + extends: .docker-build-testenv-image + needs: + - docker-build-wallet + variables: + TURBO_APP_NAME: 'wallet' + BASE_IMAGE_NAME: ${WALLET_IMAGE_NAME} + +docker-build-blog-mirrornet-testenv: + extends: .docker-build-testenv-image + needs: + - docker-build-blog + variables: + TURBO_APP_NAME: 'blog' + BASE_IMAGE_NAME: ${BLOG_IMAGE_NAME} + ENV_FILE_PATHNAME: "./apps/${TURBO_APP_NAME}/.env.mirrornet-testing" + IMAGE_SUFFIX: "mirrornet-testenv" + +docker-build-wallet-mirrornet-testenv: + extends: .docker-build-testenv-image + needs: + - docker-build-wallet + variables: + TURBO_APP_NAME: 'wallet' + BASE_IMAGE_NAME: ${WALLET_IMAGE_NAME} + ENV_FILE_PATHNAME: "./apps/${TURBO_APP_NAME}/.env.mirrornet-testing" + IMAGE_SUFFIX: "mirrornet-testenv" + # Hived binary built as a part of HAF requires an additional # library to function. This library has to be extracted from # the image and passed to job extended_block_log_creation. @@ -253,6 +314,7 @@ mirrornet-haf-node-replay: FF_NETWORK_PER_BUILD: 1 REACT_APP_API_ENDPOINT: https://api.hive.blog REACT_APP_IMAGES_ENDPOINT: https://images.hive.blog/ + DENSER_SERVER_ENV_DUMP: true DENSER_URL: https://caddy parallel: matrix: @@ -288,16 +350,15 @@ mirrornet-based-tests: - .node-job needs: - mirrornet-haf-binaries-extraction - - docker-build-auth - - docker-build-blog - - docker-build-wallet + - docker-build-blog-mirrornet-testenv + - docker-build-wallet-mirrornet-testenv - mirrornet-replay-data-copy - block_log_processing image: 'mcr.microsoft.com/playwright:${PLAYWRIGHT_TAG}' allow_failure: true services: - !reference [.haf_api_node_test, services] - - name: $BLOG_IMAGE_NAME + - name: $DENSER_BLOG_IMAGE_NAME alias: denser-blog variables: HEALTHCHECK_TCP_PORT: '3000' @@ -314,7 +375,7 @@ mirrornet-based-tests: - --from=https://caddy-blog - --to=denser-blog:3000 - --internal-certs - - name: $WALLET_IMAGE_NAME + - name: $DENSER_WALLET_IMAGE_NAME alias: denser-wallet variables: HEALTHCHECK_TCP_PORT: '4000' @@ -331,22 +392,6 @@ mirrornet-based-tests: - --from=https://caddy-wallet - --to=denser-wallet:4000 - --internal-certs - - name: $AUTH_IMAGE_NAME - alias: denser-auth - variables: - HEALTHCHECK_TCP_PORT: '5000' - PORT: '5000' - REACT_APP_SITE_DOMAIN: 'https://caddy-auth.local' - TURBO_APP_SCOPE: '@hive/auth' - TURBO_APP_PATH: '/apps/auth' - - name: caddy:${CADDY_TAG} - alias: caddy-auth - command: - - caddy - - reverse-proxy - - --from=https://caddy-auth - - --to=denser-auth:5000 - - --internal-certs variables: GIT_STRATEGY: 'clone' CI_DEBUG_SERVICES: 'false' @@ -372,23 +417,25 @@ mirrornet-based-tests: - '*.log' - 'logs/' - '*.env' - - 'playwright-report/' - - 'test-results/' - - 'junit/' + - './apps/blog/playwright-report/' + - './apps/blog/test-results/' + - './apps/blog/junit/' reports: - junit: 'junit/results.xml' + junit: 'apps/blog/junit/results.xml' tags: - data-cache-storage e2e-tests-blog: extends: .e2e_tests_template needs: - - docker-build-blog + - docker-build-blog-testenv + services: - - name: $BLOG_IMAGE_NAME + - name: $DENSER_BLOG_IMAGE_NAME alias: denser variables: HEALTHCHECK_TCP_PORT: '3000' + - name: caddy:${CADDY_TAG} command: - caddy @@ -404,12 +451,14 @@ e2e-tests-blog: e2e-tests-wallet: extends: .e2e_tests_template needs: - - docker-build-wallet + - docker-build-wallet-testenv + services: - - name: $WALLET_IMAGE_NAME + - name: $DENSER_WALLET_IMAGE_NAME alias: denser variables: HEALTHCHECK_TCP_PORT: '4000' + - name: caddy:${CADDY_TAG} command: - caddy @@ -492,9 +541,9 @@ publish: tags: - public-runner-docker -.deploy_template_mainnet: +.deploy_template: extends: .job-defaults - stage: deploy-mainnet + stage: deploy before_script: - | echo -e "\e[0Ksection_start:$(date +%s):login[collapsed=true]\r\e[0KLogging to Docker registry..." @@ -502,70 +551,31 @@ publish: echo -e "\e[0Ksection_end:$(date +%s):login\r\e[0K" script: - | + # credits of solution for gitlab bug: https://gitlab.com/gitlab-org/gitlab/-/issues/294292#note_1070210709 + export DEPLOYMENT_ENV_FILE=${!DEPLOYMENT_ENV_FILE} + # Make visible all vars in the bash env + source "${DEPLOYMENT_ENV_FILE}" + scripts/run_instance.sh \ --image="$IMAGE_NAME" \ - --app-scope="$TURBO_APP_SCOPE" \ - --app-path="$TURBO_APP_PATH" \ - --api-endpoint="https://api.hive.blog" \ - --chain-id="beeab0de00000000000000000000000000000000000000000000000000000000" \ - --images-endpoint="https://images.hive.blog/" \ --name="$CONTAINER_NAME" \ --port=$PORT \ + --env-file="${DEPLOYMENT_ENV_FILE}" \ --detach tags: - hs-denser -.deploy_template_mirrornet: - extends: .deploy_template_mainnet - stage: deploy-mirrornet - script: - - | - scripts/run_instance.sh \ - --image="$IMAGE_NAME" \ - --app-scope="$TURBO_APP_SCOPE" \ - --app-path="$TURBO_APP_PATH" \ - --api-endpoint="https://api.fake.openhive.network/" \ - --chain-id="42" \ - --images-endpoint="https://images.hive.blog/" \ - --name="$CONTAINER_NAME" \ - --port=$PORT \ - --detach - # Main branch deployments (manual) -main:deploy-auth-mainnet: - extends: .deploy_template_mainnet - needs: - - docker-build-auth - variables: - CONTAINER_NAME: denser-main-auth - PORT: 9133 - TURBO_APP_SCOPE: '@hive/auth' - TURBO_APP_PATH: '/apps/auth' - SITE_DOMAIN: https://auth.openhive.network - EXPLORER_DOMAIN: https://explore.openhive.network - IMAGE_NAME: $AUTH_IMAGE_NAME - rules: - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - when: manual - environment: - name: main-auth-mainnet - url: https://auth.openhive.network - on_stop: main:stop-auth-mainnet - main:deploy-blog-mainnet: - extends: .deploy_template_mainnet + extends: .deploy_template needs: - docker-build-blog - e2e-tests-blog variables: CONTAINER_NAME: denser-main-blog PORT: 9111 - TURBO_APP_SCOPE: '@hive/blog' - TURBO_APP_PATH: '/apps/blog' - SITE_DOMAIN: https://blog.openhive.network - WALLET_ENDPOINT: https://wallet.openhive.network - EXPLORER_DOMAIN: https://explore.openhive.network IMAGE_NAME: $BLOG_IMAGE_NAME + DEPLOYMENT_ENV_FILE: "MAINNET_PROD_DEPLOYMENT_ENV" rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH when: manual @@ -575,19 +585,15 @@ main:deploy-blog-mainnet: on_stop: main:stop-blog-mainnet main:deploy-wallet-mainnet: - extends: .deploy_template_mainnet + extends: .deploy_template needs: - docker-build-wallet - e2e-tests-wallet variables: CONTAINER_NAME: denser-main-wallet PORT: 9122 - TURBO_APP_SCOPE: '@hive/wallet' - TURBO_APP_PATH: '/apps/wallet' - SITE_DOMAIN: https://wallet.openhive.network - BLOG_DOMAIN: https://blog.openhive.network - EXPLORER_DOMAIN: https://explore.openhive.network IMAGE_NAME: $WALLET_IMAGE_NAME + DEPLOYMENT_ENV_FILE: "MAINNET_PROD_DEPLOYMENT_ENV" rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH when: manual @@ -596,28 +602,8 @@ main:deploy-wallet-mainnet: url: https://wallet.openhive.network on_stop: main:stop-wallet-mainnet -main:deploy-auth-mirrornet: - extends: .deploy_template_mirrornet - needs: - - docker-build-auth - variables: - CONTAINER_NAME: denser-main-auth-mirror - PORT: 9233 - TURBO_APP_SCOPE: '@hive/auth' - TURBO_APP_PATH: '/apps/auth' - SITE_DOMAIN: https://auth.fake.openhive.network - EXPLORER_DOMAIN: https://testexplorer.openhive.network - IMAGE_NAME: $AUTH_IMAGE_NAME - rules: - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - when: manual - environment: - name: main-auth-mirrornet - url: https://auth.fake.openhive.network - on_stop: main:stop-auth-mirrornet - main:deploy-blog-mirrornet: - extends: .deploy_template_mirrornet + extends: .deploy_template needs: - docker-build-blog - e2e-tests-blog @@ -639,7 +625,7 @@ main:deploy-blog-mirrornet: on_stop: main:stop-blog-mirrornet main:deploy-wallet-mirrornet: - extends: .deploy_template_mirrornet + extends: .deploy_template needs: - docker-build-wallet - e2e-tests-wallet @@ -674,21 +660,6 @@ main:deploy-wallet-mirrornet: - hs-denser # Stop jobs for main deployments -main:stop-auth-mainnet: - extends: .stop_template - needs: - - job: main:deploy-auth-mainnet - optional: true - variables: - CONTAINER_NAME: denser-main-auth - rules: - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - when: manual - allow_failure: true - environment: - name: main-auth-mainnet - action: stop - main:stop-blog-mainnet: extends: .stop_template needs: @@ -719,21 +690,6 @@ main:stop-wallet-mainnet: name: main-wallet-mainnet action: stop -main:stop-auth-mirrornet: - extends: .stop_template - needs: - - job: main:deploy-auth-mirrornet - optional: true - variables: - CONTAINER_NAME: denser-main-auth-mirror - rules: - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - when: manual - allow_failure: true - environment: - name: main-auth-mirrornet - action: stop - main:stop-blog-mirrornet: extends: .stop_template needs: @@ -765,60 +721,34 @@ main:stop-wallet-mirrornet: action: stop # Develop branch deployments -develop:deploy-auth-mainnet: - extends: .deploy_template_mainnet - needs: - - docker-build-auth - variables: - CONTAINER_NAME: denser-dev-auth - PORT: 8133 - TURBO_APP_SCOPE: '@hive/auth' - TURBO_APP_PATH: '/apps/auth' - SITE_DOMAIN: https://auth.dev.openhive.network - EXPLORER_DOMAIN: https://explore.openhive.network - IMAGE_NAME: $AUTH_IMAGE_NAME - rules: - - if: $CI_COMMIT_BRANCH == "develop" - environment: - name: develop-auth-mainnet - url: https://auth.dev.openhive.network - on_stop: develop:stop-auth-mainnet develop:deploy-blog-mainnet: - extends: .deploy_template_mainnet + extends: .deploy_template needs: - docker-build-blog - e2e-tests-blog variables: CONTAINER_NAME: denser-dev-blog PORT: 8111 - TURBO_APP_SCOPE: '@hive/blog' - TURBO_APP_PATH: '/apps/blog' - SITE_DOMAIN: https://blog.dev.openhive.network - WALLET_ENDPOINT: https://wallet.dev.openhive.network - EXPLORER_DOMAIN: https://explore.openhive.network IMAGE_NAME: $BLOG_IMAGE_NAME + DEPLOYMENT_ENV_FILE: "MAINNET_DEV_DEPLOYMENT_ENV" rules: - - if: $CI_COMMIT_BRANCH == "develop" + - if: $CI_COMMIT_BRANCH == "bw_eliminate_private_secrets" environment: name: develop-blog-mainnet url: https://blog.dev.openhive.network on_stop: develop:stop-blog-mainnet develop:deploy-wallet-mainnet: - extends: .deploy_template_mainnet + extends: .deploy_template needs: - docker-build-wallet - e2e-tests-wallet variables: CONTAINER_NAME: denser-dev-wallet PORT: 8122 - TURBO_APP_SCOPE: '@hive/wallet' - TURBO_APP_PATH: '/apps/wallet' - SITE_DOMAIN: https://wallet.dev.openhive.network - BLOG_DOMAIN: https://blog.dev.openhive.network - EXPLORER_DOMAIN: https://explore.openhive.network IMAGE_NAME: $WALLET_IMAGE_NAME + DEPLOYMENT_ENV_FILE: "MAINNET_DEV_DEPLOYMENT_ENV" rules: - if: $CI_COMMIT_BRANCH == "develop" environment: @@ -826,60 +756,33 @@ develop:deploy-wallet-mainnet: url: https://wallet.dev.openhive.network on_stop: develop:stop-wallet-mainnet -develop:deploy-auth-mirrornet: - extends: .deploy_template_mirrornet - needs: - - docker-build-auth - variables: - CONTAINER_NAME: denser-dev-auth-mirror - PORT: 8233 - TURBO_APP_SCOPE: '@hive/auth' - TURBO_APP_PATH: '/apps/auth' - SITE_DOMAIN: https://auth.dev.fake.openhive.network - EXPLORER_DOMAIN: https://testexplorer.openhive.network - IMAGE_NAME: $AUTH_IMAGE_NAME - rules: - - if: $CI_COMMIT_BRANCH == "develop" - environment: - name: develop-auth-mirrornet - url: https://auth.dev.fake.openhive.network - on_stop: develop:stop-auth-mirrornet - develop:deploy-blog-mirrornet: - extends: .deploy_template_mirrornet + extends: .deploy_template needs: - docker-build-blog - e2e-tests-blog variables: CONTAINER_NAME: denser-dev-blog-mirror PORT: 8211 - TURBO_APP_SCOPE: '@hive/blog' - TURBO_APP_PATH: '/apps/blog' - SITE_DOMAIN: https://blog.dev.fake.openhive.network - WALLET_ENDPOINT: https://wallet.dev.fake.openhive.network - EXPLORER_DOMAIN: https://testexplorer.openhive.network IMAGE_NAME: $BLOG_IMAGE_NAME + DEPLOYMENT_ENV_FILE: "MIRRORNET_DEV_DEPLOYMENT_ENV" rules: - - if: $CI_COMMIT_BRANCH == "develop" + - if: $CI_COMMIT_BRANCH == "bw_eliminate_private_secrets" environment: name: develop-blog-mirrornet url: https://blog.dev.fake.openhive.network on_stop: develop:stop-blog-mirrornet develop:deploy-wallet-mirrornet: - extends: .deploy_template_mirrornet + extends: .deploy_template needs: - docker-build-wallet - e2e-tests-wallet variables: CONTAINER_NAME: denser-dev-wallet-mirror PORT: 8222 - TURBO_APP_SCOPE: '@hive/wallet' - TURBO_APP_PATH: '/apps/wallet' - SITE_DOMAIN: https://wallet.dev.fake.openhive.network - BLOG_DOMAIN: https://blog.dev.fake.openhive.network - EXPLORER_DOMAIN: https://testexplorer.openhive.network IMAGE_NAME: $WALLET_IMAGE_NAME + DEPLOYMENT_ENV_FILE: "MIRRORNET_DEV_DEPLOYMENT_ENV" rules: - if: $CI_COMMIT_BRANCH == "develop" environment: @@ -888,20 +791,6 @@ develop:deploy-wallet-mirrornet: on_stop: develop:stop-wallet-mirrornet # Stop jobs for develop deployments -develop:stop-auth-mainnet: - extends: .stop_template - needs: - - job: develop:deploy-auth-mainnet - optional: true - variables: - CONTAINER_NAME: denser-dev-auth - rules: - - if: $CI_COMMIT_BRANCH == "develop" - when: manual - allow_failure: true - environment: - name: develop-auth-mainnet - action: stop develop:stop-blog-mainnet: extends: .stop_template @@ -911,7 +800,7 @@ develop:stop-blog-mainnet: variables: CONTAINER_NAME: denser-dev-blog rules: - - if: $CI_COMMIT_BRANCH == "develop" + - if: $CI_COMMIT_BRANCH == "bw_eliminate_private_secrets" when: manual allow_failure: true environment: @@ -933,21 +822,6 @@ develop:stop-wallet-mainnet: name: develop-wallet-mainnet action: stop -develop:stop-auth-mirrornet: - extends: .stop_template - needs: - - job: develop:deploy-auth-mirrornet - optional: true - variables: - CONTAINER_NAME: denser-dev-auth-mirror - rules: - - if: $CI_COMMIT_BRANCH == "develop" - when: manual - allow_failure: true - environment: - name: develop-auth-mirrornet - action: stop - develop:stop-blog-mirrornet: extends: .stop_template needs: diff --git a/Dockerfile b/Dockerfile index be8a2c107f964b2129fa2543b8e9234edffe9c98..0239bdf93a57a712b0233dfcf30905f75cf8b5e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,102 +1,104 @@ -# syntax=docker/dockerfile:1.5 -FROM node:20.17-alpine AS base -ENV PNPM_HOME="/pnpm" -ENV PATH="$PNPM_HOME:$PATH" -ENV TURBO_VERSION=2.1.1 - -# Install and configure corepack/pnpm -RUN apk add --no-cache libc6-compat && \ - corepack enable && \ - corepack prepare pnpm@9.6.0 --activate && \ - pnpm config set store-dir /pnpm/store - -FROM base AS builder -ARG TURBO_APP_SCOPE -RUN apk add --no-cache libc6-compat -RUN apk update - -## Set working directory for an App -WORKDIR /app -COPY . . -## prepare files only for docker and optimise -RUN pnpm dlx turbo prune --scope=${TURBO_APP_SCOPE} --docker - -# Add lockfile and package.json's of isolated subworkspace -# TODO: Remove python3 installation after getting rid of dhive -FROM base AS installer -ARG TURBO_APP_SCOPE -RUN apk add --no-cache libc6-compat -RUN apk update -WORKDIR /app - -# First install the dependencies (as they change less often) -COPY --from=builder /app/out/json/ . -COPY --from=builder /app/out/pnpm-lock.yaml ./pnpm-lock.yaml -RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile - -# Build the project -COPY --from=builder /app/out/full/ . -RUN pnpm run lint -RUN pnpm dlx turbo run build --filter=${TURBO_APP_SCOPE} - -FROM base AS runner -ARG TURBO_APP_PATH -ARG TURBO_APP_NAME -ARG BUILD_TIME -ARG GIT_COMMIT_SHA -ARG GIT_CURRENT_BRANCH -ARG GIT_LAST_LOG_MESSAGE -ARG GIT_LAST_COMMITTER -ARG GIT_LAST_COMMIT_DATE -LABEL org.opencontainers.image.created="$BUILD_TIME" -LABEL org.opencontainers.image.url="https://hive.io/" -LABEL org.opencontainers.image.documentation="https://gitlab.syncad.com/hive/denser" -LABEL org.opencontainers.image.source="https://gitlab.syncad.com/hive/denser" -#LABEL org.opencontainers.image.version="${VERSION}" -LABEL org.opencontainers.image.revision="$GIT_COMMIT_SHA" -LABEL org.opencontainers.image.licenses="MIT" -LABEL org.opencontainers.image.ref.name="Denser $TURBO_APP_NAME" -LABEL org.opencontainers.image.title="Denser $TURBO_APP_NAME Image" -LABEL org.opencontainers.image.description="Runs Denser $TURBO_APP_NAME application" -LABEL io.hive.image.branch="$GIT_CURRENT_BRANCH" -LABEL io.hive.image.commit.log_message="$GIT_LAST_LOG_MESSAGE" -LABEL io.hive.image.commit.author="$GIT_LAST_COMMITTER" -LABEL io.hive.image.commit.date="$GIT_LAST_COMMIT_DATE" - -WORKDIR /app -RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm add -g @beam-australia/react-env@3.1.1 -RUN apk add --no-cache tini -# COPY --from=trajano/alpine-libfaketime:latest /faketime.so /lib/faketime.so - -# Don't run production as root -RUN addgroup --system --gid 1001 nodejs -RUN adduser --system --uid 1001 nextjs -USER nextjs - -COPY --from=builder /app/docker/docker-entrypoint.sh . -COPY --from=installer /app${TURBO_APP_PATH}/next.config.js . -COPY --from=installer /app${TURBO_APP_PATH}/package.json . -COPY --from=installer /app/node_modules ./node_modules -COPY --from=installer /app/node_modules/@beam-australia/react-env ./node_modules/@beam-australia/react-env -ENV PATH="/app/node_modules/.bin:$PATH" - -# Automatically leverage output traces to reduce image size -# https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --from=installer --chown=nextjs:nodejs /app${TURBO_APP_PATH}/public .${TURBO_APP_PATH}/public -COPY --from=installer --chown=nextjs:nodejs /app${TURBO_APP_PATH}/.next/standalone ./ -COPY --from=installer --chown=nextjs:nodejs /app${TURBO_APP_PATH}/.next/static .${TURBO_APP_PATH}/.next/static -COPY --from=installer --chown=nextjs:nodejs /app${TURBO_APP_PATH}/.env* ./ -COPY --from=installer --chown=nextjs:nodejs /app${TURBO_APP_PATH}/li[b]/markdown[s]/ .${TURBO_APP_PATH}/lib/markdowns/ - -ENV BLOG_PORT=3000 -ENV WALLET_PORT=4000 -ENV AUTH_PORT=5000 - -# Expose ports 3000 and 4000 for the sake of GitLab CI healthcheck -EXPOSE 3000 4000 -EXPOSE $BLOG_PORT -EXPOSE $WALLET_PORT -EXPOSE $AUTH_PORT - -ENTRYPOINT ["/sbin/tini", "--", "/app/docker-entrypoint.sh"] -CMD node .${TURBO_APP_PATH}/server.js \ No newline at end of file +# syntax=docker/dockerfile:1.5 +FROM node:20.17-alpine AS base +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +ENV TURBO_VERSION=2.1.1 + +# Install and configure corepack/pnpm +RUN apk add --no-cache libc6-compat && \ + corepack enable && \ + corepack prepare pnpm@10.0.0 --activate && \ + pnpm config set store-dir /pnpm/store + +FROM base AS builder +ARG TURBO_APP_SCOPE +RUN apk add --no-cache libc6-compat +RUN apk update + +## Set working directory for an App +WORKDIR /app +COPY . . +## prepare files only for docker and optimise +RUN pnpm dlx turbo prune --scope=${TURBO_APP_SCOPE} --docker + +# Add lockfile and package.json's of isolated subworkspace +# TODO: Remove python3 installation after getting rid of dhive +FROM base AS installer +ARG TURBO_APP_SCOPE +RUN apk add --no-cache libc6-compat +RUN apk update +WORKDIR /app + +# First install the dependencies (as they change less often) +COPY --from=builder /app/out/json/ . +COPY --from=builder /app/out/pnpm-lock.yaml ./pnpm-lock.yaml +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile + +# Build the project +COPY --from=builder /app/out/full/ . +RUN pnpm run lint +RUN pnpm dlx turbo run build --filter=${TURBO_APP_SCOPE} + +FROM base AS runner +ARG TURBO_APP_PATH +ARG TURBO_APP_NAME +ENV TURBO_APP_PATH=${TURBO_APP_PATH} +ENV TURBO_APP_NAME=${TURBO_APP_NAME} + +ARG BUILD_TIME +ARG GIT_COMMIT_SHA +ARG GIT_CURRENT_BRANCH +ARG GIT_LAST_LOG_MESSAGE +ARG GIT_LAST_COMMITTER +ARG GIT_LAST_COMMIT_DATE +LABEL org.opencontainers.image.created="$BUILD_TIME" +LABEL org.opencontainers.image.url="https://hive.io/" +LABEL org.opencontainers.image.documentation="https://gitlab.syncad.com/hive/denser" +LABEL org.opencontainers.image.source="https://gitlab.syncad.com/hive/denser" +#LABEL org.opencontainers.image.version="${VERSION}" +LABEL org.opencontainers.image.revision="$GIT_COMMIT_SHA" +LABEL org.opencontainers.image.licenses="MIT" +LABEL org.opencontainers.image.ref.name="Denser $TURBO_APP_NAME" +LABEL org.opencontainers.image.title="Denser $TURBO_APP_NAME Image" +LABEL org.opencontainers.image.description="Runs Denser $TURBO_APP_NAME application" +LABEL io.hive.image.branch="$GIT_CURRENT_BRANCH" +LABEL io.hive.image.commit.log_message="$GIT_LAST_LOG_MESSAGE" +LABEL io.hive.image.commit.author="$GIT_LAST_COMMITTER" +LABEL io.hive.image.commit.date="$GIT_LAST_COMMIT_DATE" + +WORKDIR /app +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm add -g @beam-australia/react-env@3.1.1 +RUN apk add --no-cache tini +# COPY --from=trajano/alpine-libfaketime:latest /faketime.so /lib/faketime.so + +# Don't run production as root +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs +USER nextjs + +COPY --from=builder /app/docker/docker-entrypoint.sh . +COPY --from=installer /app${TURBO_APP_PATH}/next.config.js . +COPY --from=installer /app${TURBO_APP_PATH}/package.json . +COPY --from=installer /app/node_modules ./node_modules +COPY --from=installer /app/node_modules/@beam-australia/react-env ./node_modules/@beam-australia/react-env +ENV PATH="/app/node_modules/.bin:$PATH" + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=installer --chown=nextjs:nodejs /app${TURBO_APP_PATH}/public .${TURBO_APP_PATH}/public +COPY --from=installer --chown=nextjs:nodejs /app${TURBO_APP_PATH}/.next/standalone ./ +COPY --from=installer --chown=nextjs:nodejs /app${TURBO_APP_PATH}/.next/static .${TURBO_APP_PATH}/.next/static +COPY --from=installer --chown=nextjs:nodejs /app${TURBO_APP_PATH}/li[b]/markdown[s]/ .${TURBO_APP_PATH}/lib/markdowns/ + +ENV BLOG_PORT=3000 +ENV WALLET_PORT=4000 +ENV AUTH_PORT=5000 + +# Expose ports 3000 and 4000 for the sake of GitLab CI healthcheck +EXPOSE 3000 4000 +EXPOSE $BLOG_PORT +EXPOSE $WALLET_PORT +EXPOSE $AUTH_PORT + +ENTRYPOINT ["/sbin/tini", "--", "/app/docker-entrypoint.sh"] +CMD node .${TURBO_APP_PATH}/server.js diff --git a/apps/blog/.env b/apps/blog/.env deleted file mode 100644 index 10aa54aa98f7d2e34888ad627432815fc6a2bc17..0000000000000000000000000000000000000000 --- a/apps/blog/.env +++ /dev/null @@ -1,48 +0,0 @@ -# -# Main environment file for application. -# -# See [README](https://gitlab.syncad.com/hive/denser#passing-environment-variables-to-application) -# - -# -# Server and browser (use prefix `REACT_APP_`). -# Server only (use prefix `DENSER_SERVER_`). -# - -REACT_APP_APP_NAME="blog" -REACT_APP_API_ENDPOINT="https://api.hive.blog" -REACT_APP_CHAIN_ID="beeab0de00000000000000000000000000000000000000000000000000000000" -REACT_APP_IMAGES_ENDPOINT="https://images.hive.blog/" -REACT_APP_LOGGING_BROWSER_ENABLED="false" -REACT_APP_LOGGING_LOG_LEVEL="debug" -REACT_APP_WALLET_ENDPOINT="https://wallet.openhive.network" -REACT_APP_SITE_DOMAIN="https://blog.openhive.network" -REACT_APP_EXPLORER_DOMAIN='https://explore.openhive.network' -REACT_APP_AI_DOMAIN='https://api.dev.openhive.network' - -REACT_APP_ALLOW_NON_STRICT_LOGIN="yes" -REACT_APP_LOGIN_AUTHENTICATE_ON_BACKEND="no" - -DENSER_SERVER_COOKIE_NAME_PREFIX="auth_" -DENSER_SERVER_SECRET_COOKIE_PASSWORD="2gyZ3GDw3LHZKCMEPmPDL3sjREVRXPr1" - - -#### OAUTH (OIDC) server #### - -DENSER_SERVER_OIDC_ENABLED="yes" -DENSER_SERVER_OIDC_COOKIES_KEYS="secret-devel-key" -DENSER_SERVER_OIDC_CLIENTS='[{"client_id":"foo","client_secret":"bar","token_endpoint_auth_method":"none","client_name":"Foo Application","client_uri":"https://rocket-chat.local.angala.pl","logo_uri":"https://rocket-chat.local.angala.pl/images/logo/logo.svg","policy_uri":"https://rocket-chat.local.angala.pl/privacy-policy","tos_uri":"https://rocket-chat.local.angala.pl/terms-of-service","redirect_uris":["https://oidcdebugger.com/debug"],"grant_types":["authorization_code"],"scope":"openid","urn:custom:client:allowed-cors-origins":["https://oidcdebugger.com"]},{"client_id":"openhive_chat","client_secret":"openhive_chat_secret","client_name":"OpenHive.Chat","client_uri":"https://rocket-chat.local.angala.pl","logo_uri":"https://rocket-chat.local.angala.pl/images/logo/logo.svg","policy_uri":"https://rocket-chat.local.angala.pl/privacy-policy","tos_uri":"https://rocket-chat.local.angala.pl/terms-of-service","redirect_uris":["https://rocket-chat.local.angala.pl/_oauth/denserblog"],"grant_types":["authorization_code"],"scope":"openid profile","urn:custom:client:allowed-cors-origins":["https://rocket-chat.local.angala.pl"],"urn:custom:client:allow-non-strict-login":false}]' -DENSER_SERVER_OIDC_JWKS_KEYS='[{"p":"8rFZLdP0vHjdMuWPE0A_haq1FqcgdRVBTgVTbrx1B3z6UqRmLTt-Ok_9JaMlRdahurZ1KE_3z6aZH44MVzMmB_tpxQs6W49T8TIyxbzW4VxIB-kkTdxS7qnTUZed3DL2kx-t6kNFy1yP2DhZcHkIe7zM-R7NTGQzh1uuK7uWgjM","kty":"RSA","q":"udbJFJEbcgBwOOnekc8AjGpZ8YR1vlrcmM6AG9SucIBPRvUKyXf8khaEY8ldTBjkkHnUFsgZ6vO2PLVfciwbLoHKEAtCDpDKqi-x88sLpUyvvC9tYenhJcnR-NpuDlwKyKs0YPL0VfcWROZuBuDii8pfOaL_yTTXCE8wd1uqm2k","d":"Baiiy5MOJQ_AJ70_GBwm-_hs7s_p6R-zJNHfX0k8GARd8JnSpHaWlTGWPfYTf_bnp7OxIx-u4uNzsKavHqLf4qV59ReIDhABueyrQR0MwZlfmVCdg_xIhVDD6BeND_xwy35V9G-Bee23pUw9YYUminfxiPNbBZDcww6AQyXrotft5RXRIsNbLWfESf9tZQEl49WkuGdyVKRiT3k29nGwJxF0QKA-9r1pz5ML4x-5ynzp28nI1SidYRo26SqT9i6XPt8zMksZQMM72iyDQGRQhAy5lLGI04cU2GnehQaYeAc9X9v2tzPC7UHvfhMhH6sbBTPY6JAu6iDWKj1p0I_r0Q","e":"AQAB","use":"sig","kid":"mShU1yBPX9yrb8m96VMb-7Bhh6HtXl_SHf9ToNtcjzk","qi":"mu3j_sQaYfAB2li2zOEAp3gn1tJ1ICqaQWFSSktwsHaLGBF5_h85iPSnVieX8RSaQbJyZ7QDYAFFdsDRxK0mQIvY0ahd5X2TlY312_crXli00fRXhcEJhTz21xm0MUJ60LsAsj8WydKxil8O26oP4qIIpRrhDmPXw8qodCUMpYQ","dp":"rx4rJDdR3AE2UzhzgceVTmT8ICld8T3yDlMnfbr8kveqRKGdnLvV_EuldVgAWCFkN67aYMk7HhmvWaaM3wroQVA3ZNgSNuj4AA1ht27oelq1GwguiwQUz2O5OKG3ZaFcbJKqUmRSY0gZ_0HBv7eF2ItGN-fy6VFQITaVObc1BiM","alg":"RS256","dq":"WR8E_YT9OXW2W8TkRN6Vr8EM80MHyEsAwZM-YppjMXaHDktTafzNti1wPf6CbIz_h721FVvO-hr4STLd2_4E5w-9HGaZvix31Jfc6kJ0ikg1erTv6uXjYGDh_kqaPu6rCUL5cojw3g0Js-8h0tCkNE_PzO87ZX2epdB8OLFQJwk","n":"sC3IU2jrdhNc-T0H06Py4WceMIF8id1AJ4blBU2i_rfgf2yCpkap_dThLShurL4o777qksSICQpoW75MxzR6xelz9-lGm-sOdr6Xv9L8jVUnm9CryzHNW_nTG0wmX8W4PTA20hXhSL_bZUqh9lXeJQephMpdRPEUyU4doaYZodLR_bNfiAbPV3ySFyWTHO_p01RriSENoF0DogcovzAwczTXwSX_surffhT9lkxw4d4kW2qF3f3ZdWlEG7ZaL8U3o88FjPmff2dJOFhuudDhbeRiXkTEdNTmipiie2zIN6Zweqi31ZnbZnuEnbMPGjg3mn5NUa7cO7ts5RJzqG5H6w"}]' - -#### Rocket Chat Widget #### - -REACT_APP_OPENHIVE_CHAT_CLIENT_ID="openhive_chat" -REACT_APP_OPENHIVE_CHAT_API_URI="https://your-chat/api/v1" -REACT_APP_OPENHIVE_CHAT_URI="https://your-chat" -REACT_APP_OPENHIVE_CHAT_IFRAME_INTEGRATION_ENABLE="no" -REACT_APP_OPENHIVE_CHAT_IFRAME_VISIBLE="yes" -REACT_APP_OPENHIVE_CHAT_ALLOW_NON_STRICT_LOGIN="no" -DENSER_SERVER_OPENHIVE_CHAT_ADMIN_USER_ID="your-admin-user-id" -DENSER_SERVER_OPENHIVE_CHAT_ADMIN_USER_TOKEN="your-admin-user-token" - -ESLINT_USE_FLAT_CONFIG=false diff --git a/apps/blog/.env.mirrornet-testing b/apps/blog/.env.mirrornet-testing new file mode 100644 index 0000000000000000000000000000000000000000..01ee5ca8c842adbe6ffff15736700a7e7f514208 --- /dev/null +++ b/apps/blog/.env.mirrornet-testing @@ -0,0 +1,27 @@ +DENSER_SERVER_ENV_DUMP=true +REACT_APP_APP_NAME="blog" +REACT_APP_API_ENDPOINT="https://dind/" +REACT_APP_CHAIN_ID="44" +REACT_APP_IMAGES_ENDPOINT="https://images.hive.blog/" +REACT_APP_LOGGING_BROWSER_ENABLED="true" +REACT_APP_LOGGING_LOG_LEVEL="debug" +REACT_APP_WALLET_ENDPOINT="https://caddy-wallet" +REACT_APP_SITE_DOMAIN="https://caddy-blog.local" +REACT_APP_BLOG_DOMAIN="https://caddy-blog" +REACT_APP_EXPLORER_DOMAIN='https://explore.openhive.network' +REACT_APP_AI_DOMAIN='https://api.dev.openhive.network' +REACT_APP_ALLOW_NON_STRICT_LOGIN="yes" +REACT_APP_LOGIN_AUTHENTICATE_ON_BACKEND="no" +DENSER_SERVER_COOKIE_NAME_PREFIX="auth_" +DENSER_SERVER_SECRET_COOKIE_PASSWORD="SomeValueForTestingPurposesOnly" +DENSER_SERVER_OIDC_ENABLED="yes" +DENSER_SERVER_OIDC_COOKIES_KEYS="secret-devel-key" +REACT_APP_OPENHIVE_CHAT_CLIENT_ID="openhive_chat" +REACT_APP_OPENHIVE_CHAT_API_URI="https://your-chat/api/v1" +REACT_APP_OPENHIVE_CHAT_URI="https://your-chat" +REACT_APP_OPENHIVE_CHAT_IFRAME_INTEGRATION_ENABLE="no" +REACT_APP_OPENHIVE_CHAT_IFRAME_VISIBLE="yes" +REACT_APP_OPENHIVE_CHAT_ALLOW_NON_STRICT_LOGIN="no" +DENSER_SERVER_OPENHIVE_CHAT_ADMIN_USER_ID="your-admin-user-id" +DENSER_SERVER_OPENHIVE_CHAT_ADMIN_USER_TOKEN="your-admin-user-token" +ESLINT_USE_FLAT_CONFIG=false diff --git a/apps/blog/.env.testing b/apps/blog/.env.testing new file mode 100644 index 0000000000000000000000000000000000000000..32097581246dea2158a4f7fb8335ce10281d166b --- /dev/null +++ b/apps/blog/.env.testing @@ -0,0 +1,27 @@ +DENSER_SERVER_ENV_DUMP=true +REACT_APP_APP_NAME="blog" +REACT_APP_API_ENDPOINT="https://api.hive.blog" +REACT_APP_CHAIN_ID="beeab0de00000000000000000000000000000000000000000000000000000000" +REACT_APP_IMAGES_ENDPOINT="https://images.hive.blog/" +REACT_APP_LOGGING_BROWSER_ENABLED="false" +REACT_APP_LOGGING_LOG_LEVEL="debug" +REACT_APP_WALLET_ENDPOINT="https://wallet.openhive.network" +REACT_APP_SITE_DOMAIN="https://blog.openhive.network" +REACT_APP_BLOG_DOMAIN="https://blog.openhive.network" +REACT_APP_EXPLORER_DOMAIN='https://explore.openhive.network' +REACT_APP_AI_DOMAIN='https://api.dev.openhive.network' +REACT_APP_ALLOW_NON_STRICT_LOGIN="yes" +REACT_APP_LOGIN_AUTHENTICATE_ON_BACKEND="no" +DENSER_SERVER_COOKIE_NAME_PREFIX="auth_" +DENSER_SERVER_SECRET_COOKIE_PASSWORD="SomeValueForTestingPurposesOnly" +DENSER_SERVER_OIDC_ENABLED="yes" +DENSER_SERVER_OIDC_COOKIES_KEYS="secret-devel-key" +REACT_APP_OPENHIVE_CHAT_CLIENT_ID="openhive_chat" +REACT_APP_OPENHIVE_CHAT_API_URI="https://your-chat/api/v1" +REACT_APP_OPENHIVE_CHAT_URI="https://your-chat" +REACT_APP_OPENHIVE_CHAT_IFRAME_INTEGRATION_ENABLE="no" +REACT_APP_OPENHIVE_CHAT_IFRAME_VISIBLE="yes" +REACT_APP_OPENHIVE_CHAT_ALLOW_NON_STRICT_LOGIN="no" +DENSER_SERVER_OPENHIVE_CHAT_ADMIN_USER_ID="your-admin-user-id" +DENSER_SERVER_OPENHIVE_CHAT_ADMIN_USER_TOKEN="your-admin-user-token" +ESLINT_USE_FLAT_CONFIG=false \ No newline at end of file diff --git a/apps/blog/components/md-editor.tsx b/apps/blog/components/md-editor.tsx index 900c26c5223d78d5ad5b4d6f8707bf8d990511ea..f776fc06761b89b5e39a1be5510ca0e9b253a36c 100644 --- a/apps/blog/components/md-editor.tsx +++ b/apps/blog/components/md-editor.tsx @@ -11,11 +11,12 @@ import { useState } from 'react'; import * as commands from '@uiw/react-md-editor/commands'; -import env from '@beam-australia/react-env'; import { useUser } from '@smart-signer/lib/auth/use-user'; import { Signer } from '@smart-signer/lib/signer/signer'; import { ICommand, TextAreaTextApi } from '@uiw/react-md-editor'; import { getLogger } from '@ui/lib/logging'; +import { configuredImagesEndpoint } from '@hive/ui/config/public-vars'; + import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@ui/components/tooltip'; import { useTranslation } from 'next-i18next'; import imageUserBlocklist from '@ui/config/lists/image-user-blocklist'; @@ -69,7 +70,7 @@ const uploadImg = async (file: File, username: string, signer: Signer): Promise< const imageOwner = signer.authorityUsername || signer.username; - const postUrl = `${env('IMAGES_ENDPOINT')}${imageOwner}/${sig}`; + const postUrl = `${configuredImagesEndpoint}${imageOwner}/${sig}`; const response = await fetch(postUrl, { method: 'POST', body: formData }); const resJSON = await response.json(); diff --git a/apps/blog/components/notification-list-item.tsx b/apps/blog/components/notification-list-item.tsx index b28d4ef8056cfe74134f9e308e0117a1b0bc78ca..180da045f896472186ccfeebd603072e049079e2 100644 --- a/apps/blog/components/notification-list-item.tsx +++ b/apps/blog/components/notification-list-item.tsx @@ -7,8 +7,10 @@ import { useTranslation } from 'next-i18next'; import { useSiteParams } from '@ui/components/hooks/use-site-params'; import { useUser } from '@smart-signer/lib/auth/use-user'; import { getLogger } from '@ui/lib/logging'; +import { configuredImagesEndpoint } from '@hive/ui/config/public-vars'; + import { Avatar, AvatarFallback, AvatarImage } from '@ui/components'; -import env from '@beam-australia/react-env'; + import Image from 'next/image'; import TimeAgo from '@hive/ui/components/time-ago'; @@ -40,7 +42,7 @@ const NotificationListItem = ({ date, msg, score, type, url, lastRead }: IAccoun default: icon = ; } - const imageHosterUrl = env('IMAGES_ENDPOINT'); + const imageHosterUrl = configuredImagesEndpoint; const participants = mentions ? mentions.map((m: string) => ( diff --git a/apps/blog/components/site-header.tsx b/apps/blog/components/site-header.tsx index 78cebdb76e0d70a915d896ae7c539d6fb29a5325..8685c168bc94fc098ed78466cc5e71797952ac96 100644 --- a/apps/blog/components/site-header.tsx +++ b/apps/blog/components/site-header.tsx @@ -4,6 +4,7 @@ import Sidebar from './sidebar'; import { MainNav } from './main-nav'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@ui/components/tooltip'; import { siteConfig } from '@ui/config/site'; +import { configuredImagesEndpoint } from '@hive/ui/config/public-vars'; import Link from 'next/link'; import React, { useState, FC, useEffect } from 'react'; import clsx from 'clsx'; @@ -19,7 +20,7 @@ import LangToggle from './lang-toggle'; import { PieChart, Pie } from 'recharts'; import useManabars from './hooks/useManabars'; import { hoursAndMinutes } from '../lib/utils'; -import env from '@beam-australia/react-env'; + import { getAccount } from '@transaction/lib/hive'; import TooltipContainer from '@ui/components/tooltip-container'; import { ModeSwitchInput } from '@ui/components/mode-switch-input'; @@ -232,7 +233,7 @@ const SiteHeader: FC = () => { className="h-full w-full object-cover" src={ profile?.profile?.profile_image || - `${env('IMAGES_ENDPOINT')}/u/${user.username}/avatar` + `${configuredImagesEndpoint}/u/${user.username}/avatar` } alt="Profile picture" /> diff --git a/apps/blog/instrumentation.ts b/apps/blog/instrumentation.ts new file mode 100644 index 0000000000000000000000000000000000000000..018446c9bc218fc248164c2fe790bdf7bb655abb --- /dev/null +++ b/apps/blog/instrumentation.ts @@ -0,0 +1,5 @@ +import {commonRegister} from '@hive/ui/lib/common-instrumentation'; + +export async function register(): Promise { + await commonRegister('blog'); +} diff --git a/apps/blog/lib/proxify-images.ts b/apps/blog/lib/proxify-images.ts index 8d59a43cc2250154bf294314d148caab1db51d92..5cf1f95f75217930d9757b081909e1bb747f8b33 100644 --- a/apps/blog/lib/proxify-images.ts +++ b/apps/blog/lib/proxify-images.ts @@ -1,9 +1,10 @@ import querystring from 'querystring'; import multihash from 'multihashes'; -import env from '@beam-australia/react-env'; + +import { configuredImagesEndpoint } from '@hive/ui/config/public-vars'; // Change this when we have images.hive.blog working -let proxyBase = `${env('IMAGES_ENDPOINT')}`; +let proxyBase = `${configuredImagesEndpoint}`; export function setProxyBase(p: string): void { proxyBase = p; diff --git a/apps/blog/lib/renderer.ts b/apps/blog/lib/renderer.ts index 1554fbcfe3068de053147fda9dbd677c48d488eb..265c57cb723bcd5936bf757e8ef41d973d840fa9 100644 --- a/apps/blog/lib/renderer.ts +++ b/apps/blog/lib/renderer.ts @@ -1,11 +1,13 @@ import { DefaultRenderer, InstagramPlugin, TablePlugin, TwitterPlugin } from '@hive/renderer'; import { getDoubleSize, proxifyImageUrl } from '@ui/lib/old-profixy'; -import env from '@beam-australia/react-env'; + import imageUserBlocklist from '@hive/ui/config/lists/image-user-blocklist'; import { isUrlWhitelisted } from '@hive/ui/config/lists/phishing'; +import { configuredSiteDomain, configuredImagesEndpoint } from '@hive/ui/config/public-vars'; + const renderDefaultOptions = { - baseUrl: `${env('SITE_DOMAIN')}/`, + baseUrl: `${configuredSiteDomain}/`, breaks: true, skipSanitization: false, allowInsecureScriptTags: false, @@ -22,14 +24,14 @@ const renderDefaultOptions = { usertagUrlFn: (account: string) => '/@' + account, hashtagUrlFn: (hashtag: string) => '/trending/' + hashtag, isLinkSafeFn: (url: string) => - !!url.match(`^(/(?!/)|${env('IMAGES_ENDPOINT')})`) || - !!url.match(`^(/(?!/)|${env('SITE_DOMAIN')})`) || + !!url.match(`^(/(?!/)|${configuredImagesEndpoint})`) || + !!url.match(`^(/(?!/)|${configuredSiteDomain})`) || !!url.match(`^(/(?!/)|#)`) || isUrlWhitelisted(url), addExternalCssClassToMatchingLinksFn: (url: string) => - !url.match(`^(/(?!/)|${env('IMAGES_ENDPOINT')})`) && - !url.match(`^(/(?!/)|${env('SITE_DOMAIN')})`) && + !url.match(`^(/(?!/)|${configuredImagesEndpoint})`) && + !url.match(`^(/(?!/)|${configuredSiteDomain})`) && !url.match(`^(/(?!/)|#)`) && !isUrlWhitelisted(url) }; diff --git a/apps/blog/middleware.ts b/apps/blog/middleware.ts index fe7381e346d38e4a5f6ac55f5313826ed220f5d1..bb1866f9afd6d59ac82ff6a5d02444cb7881aed9 100644 --- a/apps/blog/middleware.ts +++ b/apps/blog/middleware.ts @@ -1,119 +1,14 @@ -import { NextResponse } from 'next/server'; -import type { NextRequest } from 'next/server'; -import { setLoginChallengeCookies } from '@smart-signer/lib/middleware-challenge-cookies'; -import { createWaxFoundation } from '@hiveio/wax'; +import {commonMiddleware} from '@hive/ui/lib/common-middleware'; +import { type NextRequest, NextResponse } from 'next/server'; -export const config = { - runtime: 'nodejs' -}; - -// Initialize WAX lazily only when needed -let waxInstance: any = null; -const getWax = async () => { - if (!waxInstance) { - try { - waxInstance = await createWaxFoundation(); - } catch (error) { - console.error('Failed to initialize WAX:', error); - return null; - } - } - return waxInstance; -}; - -const parseAuthCookie = async (cookie: string) => { - if (!cookie) return null; - - const wax = await getWax(); - if (!wax) return null; - - try { - const binary = Buffer.from(cookie, 'base64').toString('utf-8'); - return wax.convertTransactionFromBinaryForm(binary); - } catch (error) { - console.error('Failed to parse auth cookie:', error); - return null; - } -}; - -export async function middleware(request: NextRequest) { +export async function middleware(request: NextRequest): Promise { const { pathname } = request.nextUrl; - // Early return for static files and API routes - if ( - pathname.startsWith('/_next') || - pathname.startsWith('/api') || - pathname.startsWith('/static') || - pathname.includes('favicon.ico') - ) { - return NextResponse.next(); - } + const result = await commonMiddleware(request); - // Handle root redirect - if (pathname === '/') { + /// In blog, let's redirect root path to /trending + if (pathname === '/') return NextResponse.redirect(new URL('/trending', request.url)); - } - - const res = NextResponse.next(); - // Handle auth cookie parsing - try { - const authCookie = request.cookies.get('data')?.value; - if (authCookie) { - const tx = await parseAuthCookie(authCookie); - console.log('tx:', tx); - } - } catch (error) { - console.error('Auth cookie parsing error:', error); - } - - // Handle @username/permlink redirects - const tempArr = pathname.split('/'); - if (tempArr.length === 3 && tempArr[1].startsWith('@')) { - const author = tempArr[1].slice(1); - const permlink = tempArr[2]; - - try { - const resp = await fetch('https://api.hive.blog', { - method: 'POST', - body: JSON.stringify({ - jsonrpc: '2.0', - method: 'bridge.get_post', - params: { author, permlink, observer: '' }, - id: 1 - }) - }); - - const entry = await resp.json(); - if (entry?.result?.community) { - const newUrl = new URL(`/${entry.result.community}/@${entry.result.author}/${entry.result.permlink}`, request.url); - // Check if we're not already at the target URL to prevent loops - if (newUrl.pathname !== pathname) { - return NextResponse.redirect(newUrl); - } - } - } catch (error) { - console.error('Failed to fetch post:', error); - } - } - - // Set login challenge cookies for non-excluded paths - if (pathname.match('/((?!api|_next/static|_next/image|favicon.ico).*)')) { - setLoginChallengeCookies(request, res); - } - - return res; + return result; } - -// export const config = { -// matcher: [ -// /* -// * Match all paths except for: -// * 1. /api routes -// * 2. /_next (Next.js internals) -// * 3. /_static (inside /public) -// * 4. all root files inside /public (e.g. /favicon.ico) -// */ -// '/((?!api/|_next/|_static/|_vercel|[\\w-]+.\\w+).*)' -// ] -// }; diff --git a/apps/blog/next.config.js b/apps/blog/next.config.js index 563fdb2dbf0ea5952727bd5217d0a9cec7eabedf..19528014b80b74f4f9f88437ae7719175e783fa3 100644 --- a/apps/blog/next.config.js +++ b/apps/blog/next.config.js @@ -13,7 +13,8 @@ const nextConfig = { output: 'standalone', swcMinify: false, experimental: { - outputFileTracingRoot: path.join(__dirname, '../..') + outputFileTracingRoot: path.join(__dirname, '../..'), + instrumentationHook: true }, /// According to notes: https://nextjs.org/docs/app/guides/progressive-web-apps#8-securing-your-application async headers() { diff --git a/apps/blog/pages/[param]/settings.tsx b/apps/blog/pages/[param]/settings.tsx index 1a1342334b8110b4bc1538228fc3351cf7784f73..df8309bd876564af0bf8ea6f470ab7d581b80aed 100644 --- a/apps/blog/pages/[param]/settings.tsx +++ b/apps/blog/pages/[param]/settings.tsx @@ -18,6 +18,7 @@ import { GetServerSideProps } from 'next'; import { useParams } from 'next/navigation'; import { useUser } from '@smart-signer/lib/auth/use-user'; import { cn } from '@ui/lib/utils'; +import { configuredImagesEndpoint } from '@hive/ui/config/public-vars'; import { hiveChainService } from '@transaction/lib/hive-chain-service'; import { useFollowListQuery } from '@/blog/components/hooks/use-follow-list'; import { hbauthService } from '@smart-signer/lib/hbauth-service'; @@ -26,7 +27,7 @@ import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'next-i18next'; import { TFunction } from 'i18next'; import { MutableRefObject, useEffect, useRef, useState } from 'react'; -import env from '@beam-australia/react-env'; + import { Signer } from '@smart-signer/lib/signer/signer'; import { getLogger } from '@ui/lib/logging'; import { toast } from '@ui/components/hooks/use-toast'; @@ -117,7 +118,7 @@ const uploadImg = async (file: File, username: string, signer: Signer): Promise< password: '' }); - const postUrl = `${env('IMAGES_ENDPOINT')}${username}/${sig}`; + const postUrl = `${configuredImagesEndpoint}${username}/${sig}`; const response = await fetch(postUrl, { method: 'POST', body: formData }); const resJSON = await response.json(); diff --git a/apps/wallet/.env b/apps/wallet/.env deleted file mode 100644 index 0983653278b20c3a91f12b73b1dc2c600509e729..0000000000000000000000000000000000000000 --- a/apps/wallet/.env +++ /dev/null @@ -1,28 +0,0 @@ -# -# Main environment file for application. -# -# See [README](https://gitlab.syncad.com/hive/denser#passing-environment-variables-to-application) -# - -# -# Server and browser (use prefix `REACT_APP_`). -# - -REACT_APP_APP_NAME="wallet" -REACT_APP_API_ENDPOINT="https://api.hive.blog" -REACT_APP_CHAIN_ID="beeab0de00000000000000000000000000000000000000000000000000000000" -REACT_APP_IMAGES_ENDPOINT="https://images.hive.blog/" -REACT_APP_SITE_DOMAIN="https://wallet.openhive.network" -REACT_APP_BLOG_DOMAIN="https://blog.openhive.network" -REACT_APP_EXPLORER_DOMAIN='https://explore.openhive.network' -REACT_APP_LOGGING_BROWSER_ENABLED="false" -REACT_APP_LOGGING_LOG_LEVEL="info" - -# -# Server only (use prefix `DENSER_SERVER_`). -# - -# DENSER_SERVER_HIDDEN_SECRET=hidden_secret -DENSER_SERVER_SECRET_COOKIE_PASSWORD="2gyZ3GDw3LHZKCMEPmPDL3sjREVRXPr3" - -ESLINT_USE_FLAT_CONFIG=false \ No newline at end of file diff --git a/apps/wallet/.env.mirrornet-testing b/apps/wallet/.env.mirrornet-testing new file mode 100644 index 0000000000000000000000000000000000000000..13d921887dffca3736a87f6b6a36ad55c0207a78 --- /dev/null +++ b/apps/wallet/.env.mirrornet-testing @@ -0,0 +1,27 @@ +DENSER_SERVER_ENV_DUMP=true +REACT_APP_APP_NAME="wallet" +REACT_APP_API_ENDPOINT="https://dind/" +REACT_APP_CHAIN_ID="44" +REACT_APP_IMAGES_ENDPOINT="https://images.hive.blog/" +REACT_APP_LOGGING_BROWSER_ENABLED="true" +REACT_APP_LOGGING_LOG_LEVEL="debug" +REACT_APP_WALLET_ENDPOINT="https://caddy-wallet" +REACT_APP_SITE_DOMAIN="https://caddy-wallet.local" +REACT_APP_BLOG_DOMAIN="https://caddy-blog" +REACT_APP_EXPLORER_DOMAIN='https://explore.openhive.network' +REACT_APP_AI_DOMAIN='https://api.dev.openhive.network' +REACT_APP_ALLOW_NON_STRICT_LOGIN="yes" +REACT_APP_LOGIN_AUTHENTICATE_ON_BACKEND="no" +DENSER_SERVER_COOKIE_NAME_PREFIX="auth_" +DENSER_SERVER_SECRET_COOKIE_PASSWORD="SomeValueForTestingPurposesOnly" +DENSER_SERVER_OIDC_ENABLED="yes" +DENSER_SERVER_OIDC_COOKIES_KEYS="secret-devel-key" +REACT_APP_OPENHIVE_CHAT_CLIENT_ID="openhive_chat" +REACT_APP_OPENHIVE_CHAT_API_URI="https://your-chat/api/v1" +REACT_APP_OPENHIVE_CHAT_URI="https://your-chat" +REACT_APP_OPENHIVE_CHAT_IFRAME_INTEGRATION_ENABLE="no" +REACT_APP_OPENHIVE_CHAT_IFRAME_VISIBLE="yes" +REACT_APP_OPENHIVE_CHAT_ALLOW_NON_STRICT_LOGIN="no" +DENSER_SERVER_OPENHIVE_CHAT_ADMIN_USER_ID="your-admin-user-id" +DENSER_SERVER_OPENHIVE_CHAT_ADMIN_USER_TOKEN="your-admin-user-token" +ESLINT_USE_FLAT_CONFIG=false diff --git a/apps/wallet/.env.testing b/apps/wallet/.env.testing new file mode 100644 index 0000000000000000000000000000000000000000..a528937f6510d215be10d54ed8e87f3ece2af726 --- /dev/null +++ b/apps/wallet/.env.testing @@ -0,0 +1,26 @@ +DENSER_SERVER_ENV_DUMP=true +REACT_APP_APP_NAME="wallet" +REACT_APP_API_ENDPOINT="https://api.hive.blog" +REACT_APP_CHAIN_ID="beeab0de00000000000000000000000000000000000000000000000000000000" +REACT_APP_IMAGES_ENDPOINT="https://images.hive.blog/" +REACT_APP_LOGGING_BROWSER_ENABLED="false" +REACT_APP_LOGGING_LOG_LEVEL="debug" +REACT_APP_SITE_DOMAIN="https://wallet.openhive.network" +REACT_APP_BLOG_DOMAIN="https://blog.openhive.network" +REACT_APP_EXPLORER_DOMAIN='https://explore.openhive.network' +REACT_APP_AI_DOMAIN='https://api.dev.openhive.network' +REACT_APP_ALLOW_NON_STRICT_LOGIN="yes" +REACT_APP_LOGIN_AUTHENTICATE_ON_BACKEND="no" +DENSER_SERVER_COOKIE_NAME_PREFIX="auth_" +DENSER_SERVER_SECRET_COOKIE_PASSWORD="SomeValueForTestingPurposesOnly" +DENSER_SERVER_OIDC_ENABLED="yes" +DENSER_SERVER_OIDC_COOKIES_KEYS="secret-devel-key" +REACT_APP_OPENHIVE_CHAT_CLIENT_ID="openhive_chat" +REACT_APP_OPENHIVE_CHAT_API_URI="https://your-chat/api/v1" +REACT_APP_OPENHIVE_CHAT_URI="https://your-chat" +REACT_APP_OPENHIVE_CHAT_IFRAME_INTEGRATION_ENABLE="no" +REACT_APP_OPENHIVE_CHAT_IFRAME_VISIBLE="yes" +REACT_APP_OPENHIVE_CHAT_ALLOW_NON_STRICT_LOGIN="no" +DENSER_SERVER_OPENHIVE_CHAT_ADMIN_USER_ID="your-admin-user-id" +DENSER_SERVER_OPENHIVE_CHAT_ADMIN_USER_TOKEN="your-admin-user-token" +ESLINT_USE_FLAT_CONFIG=false diff --git a/apps/wallet/instrumentation.ts b/apps/wallet/instrumentation.ts new file mode 100644 index 0000000000000000000000000000000000000000..3b2cbf0aed6145d69c844fa75f66592500f6fd08 --- /dev/null +++ b/apps/wallet/instrumentation.ts @@ -0,0 +1,5 @@ +import {commonRegister} from '@hive/ui/lib/common-instrumentation'; + +export async function register(): Promise { + await commonRegister('wallet'); +} diff --git a/apps/wallet/lib/utils.ts b/apps/wallet/lib/utils.ts index 30f36b7df769669166b37072163ec79e911eb66b..bdbb2eb29c2fc07821d22dd52ebe754c813b7511 100644 --- a/apps/wallet/lib/utils.ts +++ b/apps/wallet/lib/utils.ts @@ -5,6 +5,7 @@ import { TransferFilters } from '@/wallet/components/transfers-history-filter'; import { useUpdateAuthorityOperationMutation } from '../components/hooks/use-update-authority-mutation'; import { SavingsWithdrawals, IFollow, IDynamicGlobalProperties } from '@transaction/lib/extended-hive.chain'; import { numberWithCommas } from '@ui/lib/utils'; +import { configuredBlogDomain } from '@ui/config/public-vars'; import Big from 'big.js'; import { HIVE_NAI_STRING, VESTS_PRECISION } from '@transaction/lib/utils'; @@ -123,7 +124,7 @@ export const getAmountFromWithdrawal = (withdrawal: SavingsWithdrawals['withdraw // The default is the blog domain export const getExternalLink = (path: string, baseUrl?: string) => { if (!baseUrl) { - const envBlogUrl = (window as any).__ENV?.REACT_APP_BLOG_DOMAIN; + const envBlogUrl = configuredBlogDomain; if (!envBlogUrl) { throw new Error('No default blog domain found'); diff --git a/apps/wallet/middleware.ts b/apps/wallet/middleware.ts index a4ee84d3a65cbce9ccca690a5e87bfa7b4c33184..f450545593acd9787157c2617f93ac65a731fb3a 100644 --- a/apps/wallet/middleware.ts +++ b/apps/wallet/middleware.ts @@ -1,60 +1,6 @@ -import { NextResponse } from 'next/server'; -import type { NextRequest } from 'next/server'; -import { setLoginChallengeCookies } from '@smart-signer/lib/middleware-challenge-cookies'; +import {commonMiddleware} from '@hive/ui/lib/common-middleware'; +import type { NextRequest, NextResponse } from 'next/server'; -export async function middleware(request: NextRequest) { - - const { pathname } = request.nextUrl; - const res = NextResponse.next(); - - const tempArr = pathname.split('/'); - let entry: any = null; - if (tempArr.length === 3 && tempArr[1].startsWith('@')) { - let author = tempArr[1].slice(1); - let permlink = tempArr[2]; - try { - const resp = await fetch('https://api.hive.blog', { - method: 'POST', - body: JSON.stringify({ - jsonrpc: '2.0', - method: 'bridge.get_post', - params: { author: author, permlink: permlink, observer: '' }, - id: 1 - }) - }); - entry = await resp.json(); - return NextResponse.redirect( - new URL(`/${entry.result.community}/@${entry.result.author}/${entry.result.permlink}`, request.url) - ); - } catch (e: any) { - console.log(e.message); - } - } - - /* - Set cookies with loginChallenge value set to random string (UID). - * Match all request paths except for the ones starting with: - * - api (API routes) - * - _next/static (static files) - * - _next/image (image optimization files) - * - favicon.ico (favicon file) - */ - if (pathname.match('/((?!api|_next/static|_next/image|favicon.ico).*)')) { - setLoginChallengeCookies(request, res); - } - - return res; +export async function middleware(request: NextRequest): Promise { + return await commonMiddleware(request); } - -// export const config = { -// matcher: [ -// /* -// * Match all paths except for: -// * 1. /api routes -// * 2. /_next (Next.js internals) -// * 3. /_static (inside /public) -// * 4. all root files inside /public (e.g. /favicon.ico) -// */ -// '/((?!api/|_next/|_static/|_vercel|[\\w-]+.\\w+).*)' -// ] -// }; diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index 8944e81c8420e1a3250c4faa1f1b64af0623bebf..60d634b2562685bf02e4c06805b840da1f425756 100755 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -2,6 +2,9 @@ set -e +# point default .env file +ln -sf "${APP_ENV_FILE_PATH:-"/app/apps/.env"}" /app${TURBO_APP_PATH}/.env + echo "Setting environment..." DIR=$(pwd) cd ".${TURBO_APP_PATH}" diff --git a/packages/ui/config/public-vars.ts b/packages/ui/config/public-vars.ts new file mode 100644 index 0000000000000000000000000000000000000000..7a721963f9f4c629d4b08f831ec4c2e8a59c2c9b --- /dev/null +++ b/packages/ui/config/public-vars.ts @@ -0,0 +1,8 @@ +import env from '@beam-australia/react-env'; + +/// Contains list of public variables which can have safely set defaults and allow application build without explicit env. definition + +export const configuredSiteDomain = env('SITE_DOMAIN') ?? 'https://hive.blog/'; +export const configuredImagesEndpoint = env('IMAGES_ENDPOINT') ?? 'https://images.hive.blog/'; +export const configuredApiEndpoint = env('API_ENDPOINT') ?? 'https://api.hive.blog/'; +export const configuredBlogDomain = env('BLOG_DOMAIN') ?? 'https://hive.blog/'; \ No newline at end of file diff --git a/packages/ui/config/site.ts b/packages/ui/config/site.ts index bac304fe19d92592a29629bf6db1da2b5bc7deb4..358f2345ac6b251bc8dd002011f75146025c03b0 100644 --- a/packages/ui/config/site.ts +++ b/packages/ui/config/site.ts @@ -1,5 +1,7 @@ import env from '@beam-australia/react-env'; +import { configuredApiEndpoint, configuredSiteDomain } from '@hive/ui/config/public-vars'; + const SERVER_VAR_PREFIX = 'DENSER_SERVER_'; const MAINNET_CHAIN_ID = 'beeab0de00000000000000000000000000000000000000000000000000000000'; @@ -16,8 +18,8 @@ const chainEnv: Record = { const chainId = env('CHAIN_ID') ? env('CHAIN_ID') : MAINNET_CHAIN_ID; export const siteConfig = { name: 'Hive Blog', - url: env('SITE_DOMAIN') || 'https://hive.blog', - endpoint: `${env('API_ENDPOINT') ? env('API_ENDPOINT') : 'https://api.hive.blog'}`, + url: configuredSiteDomain, + endpoint: configuredApiEndpoint, chainId, chainEnv: chainEnv[chainId] || chainEnv['testnet'], ogImage: '', diff --git a/packages/ui/lib/common-instrumentation.ts b/packages/ui/lib/common-instrumentation.ts new file mode 100644 index 0000000000000000000000000000000000000000..7b4c0dcdafff0ba22a134deeb87e52f1d670f273 --- /dev/null +++ b/packages/ui/lib/common-instrumentation.ts @@ -0,0 +1,34 @@ +const dumpStartupEnvironment = () => { + const executionEnv = process.env.NODE_ENV ?? 'test'; + const isProduction = executionEnv === 'production'; + const doDump = (process.env.DENSER_SERVER_ENV_DUMP ?? 'false') === 'true' ; + + if (isProduction && doDump === false) { + console.log('Missing DENSER_SERVER_ENV_DUMP variable or set to false, skipping environment dump in production mode.'); + return; + } + + console.log('Attempting to dump Denser specific environment variables (you can skip it by unsetting DENSER_SERVER_ENV_DUMP variable or set it to false'); + + const vars = Object.keys(process.env); + const filteredVars = vars.filter((key) => { + return key.startsWith('DENSER_') || key.startsWith('HIVE_') || key.startsWith('NEXT_PUBLIC_') || key.startsWith('REACT_APP_'); + }); + + const env = filteredVars.sort().forEach((key) => { + const value = process.env[key]; + if (value) { + console.log(`${key}: ${value}`); + } else { + console.log(`Variable ${key} is !!!`); + } + }); + + console.log('Denser startup environment variables dump finsihed'); +}; + +export async function commonRegister(appName: string): Promise { + console.log(`Starting up the '${appName}' application server...`); + dumpStartupEnvironment(); +} + diff --git a/packages/ui/lib/common-middleware.ts b/packages/ui/lib/common-middleware.ts new file mode 100644 index 0000000000000000000000000000000000000000..3681e7f903ae6150a1cbc45c2e04915c06910fd9 --- /dev/null +++ b/packages/ui/lib/common-middleware.ts @@ -0,0 +1,61 @@ +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; +import { setLoginChallengeCookies } from '@smart-signer/lib/middleware-challenge-cookies'; +import { configuredApiEndpoint } from '@hive/ui/config/public-vars'; + +export async function commonMiddleware(request: NextRequest) { + + const { pathname } = request.nextUrl; + const res = NextResponse.next(); + + const tempArr = pathname.split('/'); + let entry: any = null; + if (tempArr.length === 3 && tempArr[1].startsWith('@')) { + let author = tempArr[1].slice(1); + let permlink = tempArr[2]; + try { + const resp = await fetch(configuredApiEndpoint, { + method: 'POST', + body: JSON.stringify({ + jsonrpc: '2.0', + method: 'bridge.get_post', + params: { author: author, permlink: permlink, observer: '' }, + id: 1 + }) + }); + entry = await resp.json(); + return NextResponse.redirect( + new URL(`/${entry.result.community}/@${entry.result.author}/${entry.result.permlink}`, request.url) + ); + } catch (e: any) { + console.log(e.message); + } + } + + /* + Set cookies with loginChallenge value set to random string (UID). + * Match all request paths except for the ones starting with: + * - api (API routes) + * - _next/static (static files) + * - _next/image (image optimization files) + * - favicon.ico (favicon file) + */ + if (pathname.match('/((?!api|_next/static|_next/image|favicon.ico).*)')) { + setLoginChallengeCookies(request, res); + } + + return res; +} + +// export const config = { +// matcher: [ +// /* +// * Match all paths except for: +// * 1. /api routes +// * 2. /_next (Next.js internals) +// * 3. /_static (inside /public) +// * 4. all root files inside /public (e.g. /favicon.ico) +// */ +// '/((?!api/|_next/|_static/|_vercel|[\\w-]+.\\w+).*)' +// ] +// }; diff --git a/packages/ui/lib/old-profixy.ts b/packages/ui/lib/old-profixy.ts index 5001cff36d204a90e8dce4121ebfbddea47ee254..ce52289dcaf0df60a2cc1629837463bfeb862a32 100644 --- a/packages/ui/lib/old-profixy.ts +++ b/packages/ui/lib/old-profixy.ts @@ -1,4 +1,4 @@ -import env from '@beam-australia/react-env'; +import { configuredImagesEndpoint } from '@hive/ui/config/public-vars'; /** * this regular expression should capture all possible proxy domains @@ -15,7 +15,7 @@ const NATURAL_SIZE = '0x0/'; const CAPPED_SIZE = '768x0/'; const DOUBLE_CAPPED_SIZE = '1536x0/'; -export const imageProxy = () => `${env('IMAGES_ENDPOINT')}`; +export const imageProxy = () => `${configuredImagesEndpoint}`; export const defaultSrcSet = (url: string) => { return `${url} 1x, ${url.replace(CAPPED_SIZE, DOUBLE_CAPPED_SIZE)} 2x`; }; @@ -46,7 +46,7 @@ export const proxifyImageUrl = (url: string, dimensions: string | boolean) => { const lastProxy = proxyList[proxyList.length - 1]; respUrl = url.substring(url.lastIndexOf(lastProxy) + lastProxy.length); } - if (dimensions && `${env('IMAGES_ENDPOINT')}`) { + if (dimensions && `${configuredImagesEndpoint}`) { let dims = dimensions + '/'; if (typeof dimensions !== 'string') { // @ts-ignore @@ -60,7 +60,7 @@ export const proxifyImageUrl = (url: string, dimensions: string | boolean) => { } if ((NATURAL_SIZE !== dims && CAPPED_SIZE !== dims) || !rProxyDomain.test(respUrl)) { - return `${env('IMAGES_ENDPOINT')}` + dims + respUrl; + return `${configuredImagesEndpoint}` + dims + respUrl; } } return respUrl; diff --git a/scripts/run_instance.sh b/scripts/run_instance.sh index 78d0714835fe4ce4fbbdefee3f9ab2e677957528..5fa25bc7d30c7e7448c22288f40c83cd30f76634 100755 --- a/scripts/run_instance.sh +++ b/scripts/run_instance.sh @@ -9,90 +9,27 @@ Usage: $0 [OPTION[=VALUE]]... Run a Denser Docker instance OPTIONS: --image=IMAGE Docker image to run (default: 'registry.gitlab.syncad.com/hive/denser:latest') - --api-endpoint=URL API endpoint to be used by the new instance (default: 'https://api.hive.blog') - --wallet-endpoint=WALLET_ENDPOINT Wallet endpoint to be used by the new instance (default: 'https://wallet.hive.blog') - --site-domain=SITE_DOMAIN Site domain to be used by the new instance (default: 'https://blog.hive.blog') - --blog-domain=BLOG_DOMAIN Blog domain to be used by the new instance (default: 'https://blog.hive.blog') - --explorer-domain=EXPLORER_DOMAIN Explorer domain to be used by the new instance (default: 'https://explore.hive.blog') - --ai-domain=AI_DOMAIN AI domain to be used by the new instance (default: 'https://api.dev.openhive.network') - --openhive-chat-uri=OPENHIVE_CHAT_URI Chat URI to be used by the new instance (default: 'http://openhive.chat') - --chain-id=CHAIN_ID Chain ID to be used by the new instance (default: 'beeab0de00000000000000000000000000000000000000000000000000000000') - --images-endpoint=URL IMAGES endpoint to be used by the new instance (default: 'https://images.hive.blog/') - --app-scope=SCOPE App scope (eg. '@hive/auth') - --app-path=PATH App path (eg. '/apps/auth) --port=PORT Port to be exposed (default: 3000) --name=NAME Container name to be used (default: denser) + --env-file=deployment.env Obligatory path to a file containing environment variables to override i.e. deployment secrets --detach Run in detached mode --help|-h|-? Display this help screen and exit EOF } IMAGE_NAME=${IMAGE_NAME:-"registry.gitlab.syncad.com/hive/denser:latest"} -API_ENDPOINT=${API_ENDPOINT:-"https://api.hive.blog"} -WALLET_ENDPOINT=${WALLET_ENDPOINT:-"https://wallet.hive.blog"} -SITE_DOMAIN=${SITE_DOMAIN:-"https://blog.hive.blog"} -BLOG_DOMAIN=${BLOG_DOMAIN:-"https://blog.hive.blog"} -EXPLORER_DOMAIN=${EXPLORER_DOMAIN:-"https://explore.openhive.network"} -AI_DOMAIN=${AI_DOMAIN:-"https://api.dev.openhive.network"} -OPENHIVE_CHAT_URI=${OPENHIVE_CHAT_URI:-"http://openhive.chat"} -CHAIN_ID=${CHAIN_ID:-"beeab0de00000000000000000000000000000000000000000000000000000000"} -IMAGES_ENDPOINT=${IMAGES_ENDPOINT:="https://images.hive.blog/"} -TURBO_APP_SCOPE=${TURBO_APP_SCOPE:-} -TURBO_APP_PATH=${TURBO_APP_PATH:-} PORT=${PORT:-"3000"} CONTAINER_NAME=${CONTAINER_NAME:-"denser"} DETACH=${DETACH:-false} +CUSTOM_ENV_FILE='' + while [ $# -gt 0 ]; do case "$1" in --image=*) arg="${1#*=}" IMAGE_NAME="$arg" ;; - --api-endpoint=*) - arg="${1#*=}" - API_ENDPOINT="$arg" - ;; - --wallet-endpoint=*) - arg="${1#*=}" - WALLET_ENDPOINT="$arg" - ;; - --site-domain=*) - arg="${1#*=}" - SITE_DOMAIN="$arg" - ;; - --blog-domain=*) - arg="${1#*=}" - BLOG_DOMAIN="$arg" - ;; - --openhive-chat-uri=*) - arg="${1#*=}" - OPENHIVE_CHAT_URI="$arg" - ;; - --explorer-domain=*) - arg="${1#*=}" - EXPLORER_DOMAIN="$arg" - ;; - --ai-domain=*) - arg="${1#*=}" - AI_DOMAIN="$arg" - ;; - --chain-id=*) - arg="${1#*=}" - CHAIN_ID="$arg" - ;; - --images-endpoint=*) - arg="${1#*=}" - IMAGES_ENDPOINT="$arg" - ;; - --app-scope=*) - arg="${1#*=}" - TURBO_APP_SCOPE="$arg" - ;; - --app-path=*) - arg="${1#*=}" - TURBO_APP_PATH="$arg" - ;; --port=*) arg="${1#*=}" PORT="$arg" @@ -103,7 +40,16 @@ while [ $# -gt 0 ]; do ;; --detach) DETACH=true - ;; + ;; + --env-file=*) + arg="${1#*=}" + if [ -f "${arg}" ]; then + CUSTOM_ENV_FILE="${arg}" + else + echo "ERROR: File '${arg}' not found" + exit 2 + fi + ;; --help|-?) print_help exit 0 @@ -120,26 +66,24 @@ done (docker ps -q --filter "name=$CONTAINER_NAME" | grep -q . && docker stop "$CONTAINER_NAME") || true +docker container rm --force "$CONTAINER_NAME" || true + RUN_OPTIONS=( "--rm" "--publish" "$PORT:$PORT" "--env" "PORT=$PORT" - "--env" "REACT_APP_API_ENDPOINT=$API_ENDPOINT" - "--env" "REACT_APP_BLOG_DOMAIN=$BLOG_DOMAIN" - "--env" "REACT_APP_IMAGES_ENDPOINT=$IMAGES_ENDPOINT" - "--env" "REACT_APP_WALLET_ENDPOINT=$WALLET_ENDPOINT" - "--env" "REACT_APP_EXPLORER_DOMAIN=$EXPLORER_DOMAIN" - "--env" "REACT_APP_AI_DOMAIN=$AI_DOMAIN" - "--env" "REACT_APP_OPENHIVE_CHAT_URI=$OPENHIVE_CHAT_URI" - "--env" "REACT_APP_SITE_DOMAIN=$SITE_DOMAIN" - "--env" "REACT_APP_CHAIN_ID=$CHAIN_ID" - "--env" "TURBO_APP_SCOPE=$TURBO_APP_SCOPE" - "--env" "TURBO_APP_PATH=$TURBO_APP_PATH" "--name" "$CONTAINER_NAME" ) +if [ -n "${CUSTOM_ENV_FILE}" ]; then + RUN_OPTIONS+=("-v" "${CUSTOM_ENV_FILE}:/app/apps/.env") +else + echo "ERROR: Env file must be specified at command line using option: --env-file" + exit 2 +fi + if [[ "$DETACH" == "true" ]]; then RUN_OPTIONS+=("--detach") fi -docker run "${RUN_OPTIONS[@]}" "$IMAGE_NAME" \ No newline at end of file +docker run "${RUN_OPTIONS[@]}" "$IMAGE_NAME"