diff --git a/.github/_tocleanup/-build.yml b/.github/_tocleanup/-build.yml new file mode 100644 index 0000000..5827903 --- /dev/null +++ b/.github/_tocleanup/-build.yml @@ -0,0 +1,85 @@ +# name: Build Framework + +# on: +# pull_request: +# push: +# branches: +# - "**" +# - "!develop" +# - "!master" +# tags-ignore: +# - "**" + +# jobs: +# build-framework-nodejs: +# runs-on: ubuntu-latest + +# strategy: +# matrix: +# node-version: [18.x, 20.x] + +# steps: +# - uses: actions/checkout@v4 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: nodejs/package-lock.json + +# - run: npm i -g typescript ts-node +# working-directory: ./nodejs +# - run: tsc -v ; ts-node -v +# working-directory: ./nodejs +# - run: npm ci +# working-directory: ./nodejs +# - run: npm run build +# working-directory: ./nodejs +# - run: npm run test +# working-directory: ./nodejs + +# - name: Test Report ${{ matrix.node-version }} +# uses: dorny/test-reporter@v1.5.0 +# with: +# name: Tests +# path: nodejs/junit.json +# reporter: mocha-json + +# - name: Upload coverage reports to Codecov +# if: contains(matrix.node-version, '20.x') +# uses: codecov/codecov-action@v3 +# with: +# token: ${{ secrets.CODECOV_TOKEN }} +# directory: nodejs/coverage + +# - name: cleanup +# if: always() +# run: rm -f ~/.npmrc ; rm -f ./.npmrc; + +# docs_build_: +# runs-on: ubuntu-latest + +# strategy: +# matrix: +# node-version: [20.x] +# # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + +# steps: +# - name: Checkout +# uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: documentation/package-lock.json + +# - run: npm ci +# working-directory: documentation/ + +# - run: npm run build +# working-directory: documentation/ diff --git a/.github/_tocleanup/-develop.yml b/.github/_tocleanup/-develop.yml new file mode 100644 index 0000000..881d607 --- /dev/null +++ b/.github/_tocleanup/-develop.yml @@ -0,0 +1,181 @@ +# name: Build and Publish (EA) + +# on: +# push: +# branches: +# - "develop" + +# jobs: +# build_and_publish_ea_nodejs: +# runs-on: ubuntu-latest + +# strategy: +# matrix: +# node-version: [18.x, 20.x] +# #experimental: [false] +# #include: +# # - node-version: 19.x +# # experimental: true + +# #continue-on-error: ${{ matrix.experimental }} + +# outputs: +# version: ${{ steps.semver.outputs.version }} +# steps: +# - uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: nodejs/package-lock.json + +# - run: npm i -g typescript ts-node +# working-directory: ./nodejs +# - run: tsc -v ; ts-node -v +# working-directory: ./nodejs +# - run: npm ci +# working-directory: ./nodejs + +# - name: semver +# id: semver +# uses: paulhatch/semantic-version@v5.3.0 +# with: +# tag_prefix: "v" +# branch: develop +# major_pattern: "(MAJOR)" +# minor_pattern: "(MINOR)" +# format: "${major}.${minor}.${patch}-ea.${increment}" +# change_path: "./" +# bump_each_commit: true +# namespace: "" + +# - run: rm -f ~/.npmrc ; rm -f ./.npmrc ; echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM2_TOKEN_PUB }}" > ./.npmrc +# working-directory: ./nodejs +# - run: | +# git config user.name "${{ secrets.NPM_NAME }}"; +# git config user.email "${{ secrets.NPM_EMAIL }}"; +# echo "Hello $(git config --get user.name)"; + +# - name: output version +# run: | +# echo "Setting version too: ${{ steps.semver.outputs.version }}"; + +# - run: npm version ${{ steps.semver.outputs.version }} +# working-directory: ./nodejs +# - run: npm run build +# working-directory: ./nodejs +# - run: npm run test +# working-directory: ./nodejs + +# - name: Test Report ${{ matrix.node-version }} +# uses: dorny/test-reporter@v1.5.0 +# with: +# name: Tests +# path: nodejs/junit.json +# reporter: mocha-json + +# - name: Upload coverage reports to Codecov +# if: contains(matrix.node-version, '20.x') +# uses: codecov/codecov-action@v3 +# with: +# token: ${{ secrets.CODECOV_TOKEN }} +# directory: nodejs/coverage + +# - run: cp README.md ./nodejs/README.md + +# - run: npm publish --tag ea +# working-directory: ./nodejs +# if: contains(matrix.node-version, '20.x') + +# - run: npm pack +# working-directory: ./nodejs +# if: contains(matrix.node-version, '20.x') + +# - uses: actions/upload-artifact@v2 +# if: contains(matrix.node-version, '20.x') +# with: +# name: published-package +# path: ./nodejs/*.tgz + +# - name: cleanup +# if: always() +# run: rm -f ~/.npmrc ; rm -f ./.npmrc; + +# docker_build_ea_nodejs: +# needs: [build_and_publish_ea_nodejs, docs_build_ea] +# runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v2 + +# - uses: actions/download-artifact@v2 +# with: +# name: published-package +# path: ./nodejs + +# - name: Set up QEMU +# uses: docker/setup-qemu-action@master +# with: +# platforms: all + +# - name: Set up Docker Buildx +# id: buildx +# uses: docker/setup-buildx-action@master + +# - name: Login to DockerHub +# if: github.event_name != 'pull_request' +# uses: docker/login-action@v1 +# with: +# username: ${{ secrets.DOCKER_HUB_USER }} +# password: ${{ secrets.DOCKER_HUB_TOKEN }} + +# - name: Build +# uses: docker/build-push-action@v2 +# with: +# builder: ${{ steps.buildx.outputs.name }} +# context: ./nodejs/ +# file: ./nodejs/Dockerfile +# platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x +# push: true +# tags: | +# betterweb/service-base:ea-node +# betterweb/service-base:node-${{ needs.build_and_publish_ea_nodejs.outputs.version }} + +# docs_build_ea: +# runs-on: ubuntu-latest +# needs: [build_and_publish_ea_nodejs] + +# strategy: +# matrix: +# node-version: [20.x] +# # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + +# steps: +# - name: Checkout +# uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: documentation/package-lock.json + +# - run: npm ci +# working-directory: documentation/ + +# - run: npm run build +# working-directory: documentation/ + +# - name: Update site +# uses: cloudflare/wrangler-action@2.0.0 +# with: +# apiToken: ${{ secrets.CF_API_TOKEN }} +# accountId: ${{ secrets.CF_ACCOUNT_ID }} +# command: pages publish documentation/.vuepress/dist --project-name=bsb-documentation --commit-dirty=true --branch=ea diff --git a/.github/_tocleanup/-master.yml b/.github/_tocleanup/-master.yml new file mode 100644 index 0000000..7aa312a --- /dev/null +++ b/.github/_tocleanup/-master.yml @@ -0,0 +1,181 @@ +# name: Build and Publish (RC) + +# on: +# push: +# branches: +# - "master" + +# jobs: +# build_and_publish_rc_nodejs: +# runs-on: ubuntu-latest + +# strategy: +# matrix: +# node-version: [18.x, 20.x] +# #experimental: [false] +# #include: +# # - node-version: 19.x +# # experimental: true + +# #continue-on-error: ${{ matrix.experimental }} + +# outputs: +# version: ${{ steps.semver.outputs.version }} +# steps: +# - uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: nodejs/package-lock.json + +# - run: npm i -g typescript ts-node +# working-directory: ./nodejs +# - run: tsc -v ; ts-node -v +# working-directory: ./nodejs +# - run: npm ci +# working-directory: ./nodejs + +# - name: semver +# id: semver +# uses: paulhatch/semantic-version@v5.3.0 +# with: +# tag_prefix: "v" +# branch: master +# major_pattern: "(MAJOR)" +# minor_pattern: "(MINOR)" +# format: "${major}.${minor}.${patch}-rc.${increment}" +# change_path: "./" +# bump_each_commit: true +# namespace: "" + +# - run: rm -f ~/.npmrc ; rm -f ./.npmrc ; echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM2_TOKEN_PUB }}" > ./.npmrc +# working-directory: ./nodejs +# - run: | +# git config user.name "${{ secrets.NPM_NAME }}"; +# git config user.email "${{ secrets.NPM_EMAIL }}"; +# echo "Hello $(git config --get user.name)"; + +# - name: output version +# run: | +# echo "Setting version too: ${{ steps.semver.outputs.version }}"; + +# - run: npm version ${{ steps.semver.outputs.version }} +# working-directory: ./nodejs +# - run: npm run build +# working-directory: ./nodejs +# - run: npm run test +# working-directory: ./nodejs + +# - name: Test Report ${{ matrix.node-version }} +# uses: dorny/test-reporter@v1.5.0 +# with: +# name: Tests +# path: nodejs/junit.json +# reporter: mocha-json + +# - name: Upload coverage reports to Codecov +# if: contains(matrix.node-version, '20.x') +# uses: codecov/codecov-action@v3 +# with: +# token: ${{ secrets.CODECOV_TOKEN }} +# directory: nodejs/coverage + +# - run: cp README.md ./nodejs/README.md + +# - run: npm publish --tag rc +# working-directory: ./nodejs +# if: contains(matrix.node-version, '20.x') + +# - run: npm pack +# working-directory: ./nodejs +# if: contains(matrix.node-version, '20.x') + +# - uses: actions/upload-artifact@v2 +# if: contains(matrix.node-version, '20.x') +# with: +# name: published-package +# path: nodejs/bettercorp-service-base-*.tgz + +# - name: cleanup +# if: always() +# run: rm -f ~/.npmrc ; rm -f ./.npmrc; + +# docker_build_rc_nodejs: +# needs: [build_and_publish_rc_nodejs, docs_build_rc] +# runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v2 + +# - uses: actions/download-artifact@v2 +# with: +# name: published-package +# path: ./nodejs + +# - name: Set up QEMU +# uses: docker/setup-qemu-action@master +# with: +# platforms: all + +# - name: Set up Docker Buildx +# id: buildx +# uses: docker/setup-buildx-action@master + +# - name: Login to DockerHub +# if: github.event_name != 'pull_request' +# uses: docker/login-action@v1 +# with: +# username: ${{ secrets.DOCKER_HUB_USER }} +# password: ${{ secrets.DOCKER_HUB_TOKEN }} + +# - name: Build +# uses: docker/build-push-action@v2 +# with: +# builder: ${{ steps.buildx.outputs.name }} +# context: ./nodejs/ +# file: ./nodejs/Dockerfile +# platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x +# push: true +# tags: | +# betterweb/service-base:rc-node +# betterweb/service-base:node-${{ needs.build_and_publish_rc_nodejs.outputs.version }} + +# docs_build_rc: +# runs-on: ubuntu-latest +# needs: [build_and_publish_rc_nodejs] + +# strategy: +# matrix: +# node-version: [20.x] +# # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + +# steps: +# - name: Checkout +# uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: documentation/package-lock.json + +# - run: npm ci +# working-directory: documentation/ + +# - run: npm run build +# working-directory: documentation/ + +# - name: Update site +# uses: cloudflare/wrangler-action@2.0.0 +# with: +# apiToken: ${{ secrets.CF_API_TOKEN }} +# accountId: ${{ secrets.CF_ACCOUNT_ID }} +# command: pages publish documentation/.vuepress/dist --project-name=bsb-documentation --commit-dirty=true --branch=master diff --git a/.github/_tocleanup/-tags.yml b/.github/_tocleanup/-tags.yml new file mode 100644 index 0000000..89d24b2 --- /dev/null +++ b/.github/_tocleanup/-tags.yml @@ -0,0 +1,178 @@ +# name: Build and Publish (LIVE) + +# on: +# create: +# tags: +# - "*" +# workflow_dispatch: + +# jobs: +# build_and_publish_prod_nodejs: +# runs-on: ubuntu-latest + +# strategy: +# matrix: +# node-version: [18.x, 20.x] +# #experimental: [false] +# #include: +# # - node-version: 19.x +# # experimental: true + +# #continue-on-error: ${{ matrix.experimental }} + +# outputs: +# version: ${{ steps.semver.outputs.version }} +# major: ${{ steps.semver.outputs.major }} +# steps: +# - uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: nodejs/package-lock.json + +# - run: npm i -g typescript ts-node +# working-directory: ./nodejs +# - run: tsc -v ; ts-node -v +# working-directory: ./nodejs +# - run: npm ci +# working-directory: ./nodejs + +# - name: semver +# id: semver +# uses: paulhatch/semantic-version@v5.3.0 +# with: +# tag_prefix: "v" +# # branch: master +# major_pattern: "(MAJOR)" +# minor_pattern: "(MINOR)" +# format: "${major}.${minor}.${patch}" +# change_path: "./" +# bump_each_commit: true +# namespace: "" + +# - run: rm -f ~/.npmrc ; rm -f ./.npmrc ; echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM2_TOKEN_PUB }}" > ./.npmrc +# working-directory: ./nodejs +# - run: | +# git config user.name "${{ secrets.NPM_NAME }}"; +# git config user.email "${{ secrets.NPM_EMAIL }}"; +# echo "Hello $(git config --get user.name)"; + +# - name: output version +# run: | +# echo "Setting version too: ${{ steps.semver.outputs.version }}"; + +# - run: npm version --no-git-tag-version ${{ steps.semver.outputs.version }} +# working-directory: ./nodejs +# - run: npm run build +# working-directory: ./nodejs +# - run: npm run test +# working-directory: ./nodejs + +# - name: Test Report ${{ matrix.node-version }} +# uses: dorny/test-reporter@v1.5.0 +# with: +# name: Tests +# path: nodejs/junit.json +# reporter: mocha-json + +# - run: cp README.md ./nodejs/README.md + +# - run: npm publish +# working-directory: ./nodejs +# if: contains(matrix.node-version, '20.x') + +# - run: npm pack +# working-directory: ./nodejs +# if: contains(matrix.node-version, '20.x') + +# - uses: actions/upload-artifact@v2 +# if: contains(matrix.node-version, '20.x') +# with: +# name: published-package +# path: nodejs/bettercorp-service-base-*.tgz + +# - name: cleanup +# if: always() +# run: rm -f ~/.npmrc ; rm -f ./.npmrc; + +# docker_build_prod_nodejs: +# needs: [build_and_publish_prod_nodejs, docs_build_prod] +# runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v2 + +# - uses: actions/download-artifact@v2 +# with: +# name: published-package +# path: ./nodejs + +# - name: Set up QEMU +# uses: docker/setup-qemu-action@master +# with: +# platforms: all + +# - name: Set up Docker Buildx +# id: buildx +# uses: docker/setup-buildx-action@master + +# - name: Login to DockerHub +# if: github.event_name != 'pull_request' +# uses: docker/login-action@v1 +# with: +# username: ${{ secrets.DOCKER_HUB_USER }} +# password: ${{ secrets.DOCKER_HUB_TOKEN }} + +# - name: Build +# uses: docker/build-push-action@v2 +# with: +# builder: ${{ steps.buildx.outputs.name }} +# context: ./nodejs/ +# file: ./nodejs/Dockerfile +# platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x +# push: true +# tags: | +# betterweb/service-base:latest-node +# betterweb/service-base:node +# betterweb/service-base:node-${{ needs.build_and_publish_prod_nodejs.outputs.version }} +# betterweb/service-base:node-v${{ needs.build_and_publish_prod_nodejs.outputs.major }} + +# docs_build_prod: +# runs-on: ubuntu-latest +# needs: [build_and_publish_prod_nodejs] + +# strategy: +# matrix: +# node-version: [20.x] +# # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + +# steps: +# - name: Checkout +# uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: documentation/package-lock.json + +# - run: npm ci +# working-directory: documentation/ + +# - run: npm run build +# working-directory: documentation/ + +# - name: Update site +# uses: cloudflare/wrangler-action@2.0.0 +# with: +# apiToken: ${{ secrets.CF_API_TOKEN }} +# accountId: ${{ secrets.CF_ACCOUNT_ID }} +# command: pages publish documentation/.vuepress/dist --project-name=bsb-documentation --commit-dirty=true --branch=master diff --git a/.github/_tocleanup/-updatePlugins.yml b/.github/_tocleanup/-updatePlugins.yml new file mode 100644 index 0000000..c63ff90 --- /dev/null +++ b/.github/_tocleanup/-updatePlugins.yml @@ -0,0 +1,59 @@ +# name: Update documentation plugins + +# on: +# push: +# branches: +# - "master" +# # - "documentation" # Specifically disabled to stop infinite build loop +# - "develop" +# create: +# tags: +# - "*" +# schedule: +# - cron: "0 0/6 1/1 * *" +# workflow_dispatch: +# branches: [documentation] + +# jobs: +# build_and_update_plugins: +# runs-on: ubuntu-latest + +# strategy: +# matrix: +# node-version: [20.x] + +# steps: +# - uses: actions/checkout@v4 +# with: +# fetch-depth: 0 +# ref: documentation + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} + +# - name: Plugin def generation +# id: plugin_generation +# run: node generatePluginData.js + +# - uses: EndBug/add-and-commit@v9 # You can change this to use a specific version. +# if: ${{ steps.plugin_generation.outputs.changes == 'true' }} +# with: +# add: "plugins.json" +# committer_name: GitHub Actions +# committer_email: actions@github.com +# message: "Updated known plugins" +# pull: "" +# push: true + +# - run: mkdir _tempCDN +# - run: cp ./plugins.json _tempCDN/plugins.json + +# - name: Update site +# if: ${{ steps.plugin_generation.outputs.changes == 'true' }} +# uses: cloudflare/wrangler-action@2.0.0 +# with: +# apiToken: ${{ secrets.CF_API_TOKEN }} +# accountId: ${{ secrets.CF_ACCOUNT_ID }} +# command: pages publish _tempCDN --project-name=bsb-cdn --commit-dirty=true --branch=master diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1ae01be..278bddc 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,9 +1,14 @@ version: 2 updates: -- package-ecosystem: npm - directory: "/ui" - target-branch: "develop" - schedule: - interval: monthly - time: "03:00" - open-pull-requests-limit: 10 + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + time: "04:00" + - package-ecosystem: npm + directory: "/nodejs" + target-branch: "develop" + schedule: + interval: weekly + time: "03:00" + open-pull-requests-limit: 3 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 48f2558..671e47b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,85 +1,54 @@ -name: Build Framework +name: Build Plugin on: pull_request: - push: - branches: - - "**" - - "!develop" - - "!master" - tags-ignore: - - "**" + workflow_dispatch: jobs: - build-framework-nodejs: + build_nodejs_plugin: + uses: BetterCorp/service-base-build-workflows/.github/workflows/node.yml@master + with: + WORKING_DIR: ./nodejs + PUBLISH: false + + docker_nodejs_plugin: + needs: [build_nodejs_plugin] runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [16.x, 18.x] - steps: - - uses: actions/checkout@v3 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: nodejs/package-lock.json + - name: Checkout + uses: actions/checkout@v2 - - run: npm i -g typescript ts-node - working-directory: ./nodejs - - run: tsc -v ; ts-node -v - working-directory: ./nodejs - - run: npm ci - working-directory: ./nodejs - - run: npm run build - working-directory: ./nodejs - - run: npm run test + - run: ./ci-build-dist working-directory: ./nodejs - - name: Test Report ${{ matrix.node-version }} - uses: dorny/test-reporter@v1.5.0 + - name: Download artifact + uses: actions/download-artifact@v2 with: - name: Tests - path: nodejs/junit.json - reporter: mocha-json + name: node-${{ needs.build_nodejs_plugin.outputs.tag }}-${{ needs.build_nodejs_plugin.outputs.version }} + path: ./nodejs/ci-build-dist/ - - name: Upload coverage reports to Codecov - if: contains(matrix.node-version, '18.x') - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: nodejs/coverage - - - name: cleanup - if: always() - run: rm -f ~/.npmrc ; rm -f ./.npmrc; - - docs_build_: - runs-on: ubuntu-latest + - name: Extract artifact + working-directory: ./nodejs + run: | + tar -xzf ./ci-build-dist/as-built.tar.gz -C ./ - strategy: - matrix: - node-version: [16.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + - run: rm -rfv ./ci-build-dist + working-directory: ./nodejs - steps: - - name: Checkout - uses: actions/checkout@v3 + - name: Set up QEMU + uses: docker/setup-qemu-action@master with: - fetch-depth: 0 + platforms: all - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: documentation/package-lock.json - - - run: npm ci - working-directory: documentation/ + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@master - - run: npm run build - working-directory: documentation/ + - name: Build + uses: docker/build-push-action@v2 + with: + builder: ${{ steps.buildx.outputs.name }} + context: ./nodejs/ + file: ./nodejs/Dockerfile + platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + push: false diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 7be83a7..b10f84b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -38,7 +38,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml deleted file mode 100644 index 9e514ed..0000000 --- a/.github/workflows/develop.yml +++ /dev/null @@ -1,181 +0,0 @@ -name: Build and Publish (EA) - -on: - push: - branches: - - "develop" - -jobs: - build_and_publish_ea_nodejs: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [16.x, 18.x] - #experimental: [false] - #include: - # - node-version: 19.x - # experimental: true - - #continue-on-error: ${{ matrix.experimental }} - - outputs: - version: ${{ steps.semver.outputs.version }} - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: nodejs/package-lock.json - - - run: npm i -g typescript ts-node - working-directory: ./nodejs - - run: tsc -v ; ts-node -v - working-directory: ./nodejs - - run: npm ci - working-directory: ./nodejs - - - name: semver - id: semver - uses: paulhatch/semantic-version@v4.0.3 - with: - tag_prefix: "v" - branch: develop - major_pattern: "(MAJOR)" - minor_pattern: "(MINOR)" - format: "${major}.${minor}.${patch}-ea.${increment}" - change_path: "./" - bump_each_commit: true - namespace: "" - - - run: rm -f ~/.npmrc ; rm -f ./.npmrc ; echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM2_TOKEN_PUB }}" > ./.npmrc - working-directory: ./nodejs - - run: | - git config user.name "${{ secrets.NPM_NAME }}"; - git config user.email "${{ secrets.NPM_EMAIL }}"; - echo "Hello $(git config --get user.name)"; - - - name: output version - run: | - echo "Setting version too: ${{ steps.semver.outputs.version }}"; - - - run: npm version ${{ steps.semver.outputs.version }} - working-directory: ./nodejs - - run: npm run build - working-directory: ./nodejs - - run: npm run test - working-directory: ./nodejs - - - name: Test Report ${{ matrix.node-version }} - uses: dorny/test-reporter@v1.5.0 - with: - name: Tests - path: nodejs/junit.json - reporter: mocha-json - - - name: Upload coverage reports to Codecov - if: contains(matrix.node-version, '18.x') - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: nodejs/coverage - - - run: cp README.md ./nodejs/README.md - - - run: npm publish --tag ea - working-directory: ./nodejs - if: contains(matrix.node-version, '18.x') - - - run: npm pack - working-directory: ./nodejs - if: contains(matrix.node-version, '18.x') - - - uses: actions/upload-artifact@v2 - if: contains(matrix.node-version, '18.x') - with: - name: published-package - path: ./nodejs/*.tgz - - - name: cleanup - if: always() - run: rm -f ~/.npmrc ; rm -f ./.npmrc; - - docker_build_ea_nodejs: - needs: [build_and_publish_ea_nodejs, docs_build_ea] - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - uses: actions/download-artifact@v2 - with: - name: published-package - path: ./nodejs - - - name: Set up QEMU - uses: docker/setup-qemu-action@master - with: - platforms: all - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@master - - - name: Login to DockerHub - if: github.event_name != 'pull_request' - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_HUB_USER }} - password: ${{ secrets.DOCKER_HUB_TOKEN }} - - - name: Build - uses: docker/build-push-action@v2 - with: - builder: ${{ steps.buildx.outputs.name }} - context: ./nodejs/ - file: ./nodejs/Dockerfile - platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x - push: true - tags: | - betterweb/service-base:ea-node - betterweb/service-base:node-${{ needs.build_and_publish_ea_nodejs.outputs.version }} - - docs_build_ea: - runs-on: ubuntu-latest - needs: [build_and_publish_ea_nodejs] - - strategy: - matrix: - node-version: [16.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: documentation/package-lock.json - - - run: npm ci - working-directory: documentation/ - - - run: npm run build - working-directory: documentation/ - - - name: Update site - uses: cloudflare/wrangler-action@2.0.0 - with: - apiToken: ${{ secrets.CF_API_TOKEN }} - accountId: ${{ secrets.CF_ACCOUNT_ID }} - command: pages publish documentation/.vuepress/dist --project-name=bsb-documentation --commit-dirty=true --branch=ea diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml deleted file mode 100644 index af36366..0000000 --- a/.github/workflows/master.yml +++ /dev/null @@ -1,181 +0,0 @@ -name: Build and Publish (RC) - -on: - push: - branches: - - "master" - -jobs: - build_and_publish_rc_nodejs: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [16.x, 18.x] - #experimental: [false] - #include: - # - node-version: 19.x - # experimental: true - - #continue-on-error: ${{ matrix.experimental }} - - outputs: - version: ${{ steps.semver.outputs.version }} - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: nodejs/package-lock.json - - - run: npm i -g typescript ts-node - working-directory: ./nodejs - - run: tsc -v ; ts-node -v - working-directory: ./nodejs - - run: npm ci - working-directory: ./nodejs - - - name: semver - id: semver - uses: paulhatch/semantic-version@v4.0.3 - with: - tag_prefix: "v" - branch: master - major_pattern: "(MAJOR)" - minor_pattern: "(MINOR)" - format: "${major}.${minor}.${patch}-rc.${increment}" - change_path: "./" - bump_each_commit: true - namespace: "" - - - run: rm -f ~/.npmrc ; rm -f ./.npmrc ; echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM2_TOKEN_PUB }}" > ./.npmrc - working-directory: ./nodejs - - run: | - git config user.name "${{ secrets.NPM_NAME }}"; - git config user.email "${{ secrets.NPM_EMAIL }}"; - echo "Hello $(git config --get user.name)"; - - - name: output version - run: | - echo "Setting version too: ${{ steps.semver.outputs.version }}"; - - - run: npm version ${{ steps.semver.outputs.version }} - working-directory: ./nodejs - - run: npm run build - working-directory: ./nodejs - - run: npm run test - working-directory: ./nodejs - - - name: Test Report ${{ matrix.node-version }} - uses: dorny/test-reporter@v1.5.0 - with: - name: Tests - path: nodejs/junit.json - reporter: mocha-json - - - name: Upload coverage reports to Codecov - if: contains(matrix.node-version, '18.x') - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: nodejs/coverage - - - run: cp README.md ./nodejs/README.md - - - run: npm publish --tag rc - working-directory: ./nodejs - if: contains(matrix.node-version, '18.x') - - - run: npm pack - working-directory: ./nodejs - if: contains(matrix.node-version, '18.x') - - - uses: actions/upload-artifact@v2 - if: contains(matrix.node-version, '18.x') - with: - name: published-package - path: nodejs/bettercorp-service-base-*.tgz - - - name: cleanup - if: always() - run: rm -f ~/.npmrc ; rm -f ./.npmrc; - - docker_build_rc_nodejs: - needs: [build_and_publish_rc_nodejs, docs_build_rc] - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - uses: actions/download-artifact@v2 - with: - name: published-package - path: ./nodejs - - - name: Set up QEMU - uses: docker/setup-qemu-action@master - with: - platforms: all - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@master - - - name: Login to DockerHub - if: github.event_name != 'pull_request' - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_HUB_USER }} - password: ${{ secrets.DOCKER_HUB_TOKEN }} - - - name: Build - uses: docker/build-push-action@v2 - with: - builder: ${{ steps.buildx.outputs.name }} - context: ./nodejs/ - file: ./nodejs/Dockerfile - platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x - push: true - tags: | - betterweb/service-base:rc-node - betterweb/service-base:node-${{ needs.build_and_publish_rc_nodejs.outputs.version }} - - docs_build_rc: - runs-on: ubuntu-latest - needs: [build_and_publish_rc_nodejs] - - strategy: - matrix: - node-version: [16.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: documentation/package-lock.json - - - run: npm ci - working-directory: documentation/ - - - run: npm run build - working-directory: documentation/ - - - name: Update site - uses: cloudflare/wrangler-action@2.0.0 - with: - apiToken: ${{ secrets.CF_API_TOKEN }} - accountId: ${{ secrets.CF_ACCOUNT_ID }} - command: pages publish documentation/.vuepress/dist --project-name=bsb-documentation --commit-dirty=true --branch=master diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..5a158c0 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,95 @@ +name: Build and Publish Plugin + +on: + create: + tags: + - "*" + push: + branches: + - "**" + tags-ignore: + - "**" + +jobs: + build_nodejs_plugin_release: + uses: BetterCorp/service-base-build-workflows/.github/workflows/node.yml@master + with: + PUBLISH: true + WORKING_DIR: ./nodejs + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + NPM_PUBLISH_TOKEN: ${{ secrets.NPM2_TOKEN_PUB }} + NPM_EMAIL: ${{ secrets.NPM_EMAIL }} + NPM_NAME: ${{ secrets.NPM_NAME }} + + docker_nodejs_plugin_release: + needs: [build_nodejs_plugin_release] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + # - run: mkdir ./ci-build-dist + # working-directory: ./nodejs + + # - name: Download artifact + # uses: actions/download-artifact@v4 + # with: + # name: node-${{ needs.build_nodejs_plugin_release.outputs.tag }}-${{ needs.build_nodejs_plugin_release.outputs.version }} + # path: ./nodejs/ci-build-dist/ + + # - name: Extract artifact + # working-directory: ./nodejs + # run: | + # tar -xzf ./ci-build-dist/as-built.tar.gz -C ./ + + # - run: rm -rfv ./ci-build-dist + # working-directory: ./nodejs + + - name: Set up QEMU + uses: docker/setup-qemu-action@master + with: + platforms: all + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@master + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USER }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + - name: Build + uses: docker/build-push-action@v5 + if: needs.build_nodejs_plugin_release.outputs.tag != 'latest' + with: + build-args: | + BSB_VERSION=${{ needs.build_nodejs_plugin_release.outputs.version }} + builder: ${{ steps.buildx.outputs.name }} + context: ./nodejs/ + file: ./nodejs/Dockerfile + #platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + # amd64, arm32v6, arm32v7, arm64v8, ppc64le, s390x + platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8 + push: true + tags: | + betterweb/service-base:node-${{ needs.build_nodejs_plugin_release.outputs.tag }} + betterweb/service-base:node-${{ needs.build_nodejs_plugin_release.outputs.version }} + + - name: Build Latest + uses: docker/build-push-action@v5 + if: needs.build_nodejs_plugin_release.outputs.tag == 'latest' + with: + build-args: | + BSB_VERSION=${{ needs.build_nodejs_plugin_release.outputs.version }} + builder: ${{ steps.buildx.outputs.name }} + context: ./nodejs/ + file: ./nodejs/Dockerfile + platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8 + push: true + tags: | + betterweb/service-base:node-${{ needs.build_nodejs_plugin_release.outputs.tag }} + betterweb/service-base:node-${{ needs.build_nodejs_plugin_release.outputs.version }} + betterweb/service-base:node diff --git a/.github/workflows/tags.yml b/.github/workflows/tags.yml deleted file mode 100644 index 3006b10..0000000 --- a/.github/workflows/tags.yml +++ /dev/null @@ -1,178 +0,0 @@ -name: Build and Publish (LIVE) - -on: - create: - tags: - - "*" - workflow_dispatch: - -jobs: - build_and_publish_prod_nodejs: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [16.x, 18.x] - #experimental: [false] - #include: - # - node-version: 19.x - # experimental: true - - #continue-on-error: ${{ matrix.experimental }} - - outputs: - version: ${{ steps.semver.outputs.version }} - major: ${{ steps.semver.outputs.major }} - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: nodejs/package-lock.json - - - run: npm i -g typescript ts-node - working-directory: ./nodejs - - run: tsc -v ; ts-node -v - working-directory: ./nodejs - - run: npm ci - working-directory: ./nodejs - - - name: semver - id: semver - uses: paulhatch/semantic-version@v4.0.3 - with: - tag_prefix: "v" - # branch: master - major_pattern: "(MAJOR)" - minor_pattern: "(MINOR)" - format: "${major}.${minor}.${patch}" - change_path: "./" - bump_each_commit: true - namespace: "" - - - run: rm -f ~/.npmrc ; rm -f ./.npmrc ; echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM2_TOKEN_PUB }}" > ./.npmrc - working-directory: ./nodejs - - run: | - git config user.name "${{ secrets.NPM_NAME }}"; - git config user.email "${{ secrets.NPM_EMAIL }}"; - echo "Hello $(git config --get user.name)"; - - - name: output version - run: | - echo "Setting version too: ${{ steps.semver.outputs.version }}"; - - - run: npm version --no-git-tag-version ${{ steps.semver.outputs.version }} - working-directory: ./nodejs - - run: npm run build - working-directory: ./nodejs - - run: npm run test - working-directory: ./nodejs - - - name: Test Report ${{ matrix.node-version }} - uses: dorny/test-reporter@v1.5.0 - with: - name: Tests - path: nodejs/junit.json - reporter: mocha-json - - - run: cp README.md ./nodejs/README.md - - - run: npm publish - working-directory: ./nodejs - if: contains(matrix.node-version, '18.x') - - - run: npm pack - working-directory: ./nodejs - if: contains(matrix.node-version, '18.x') - - - uses: actions/upload-artifact@v2 - if: contains(matrix.node-version, '18.x') - with: - name: published-package - path: nodejs/bettercorp-service-base-*.tgz - - - name: cleanup - if: always() - run: rm -f ~/.npmrc ; rm -f ./.npmrc; - - docker_build_prod_nodejs: - needs: [build_and_publish_prod_nodejs, docs_build_prod] - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - uses: actions/download-artifact@v2 - with: - name: published-package - path: ./nodejs - - - name: Set up QEMU - uses: docker/setup-qemu-action@master - with: - platforms: all - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@master - - - name: Login to DockerHub - if: github.event_name != 'pull_request' - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_HUB_USER }} - password: ${{ secrets.DOCKER_HUB_TOKEN }} - - - name: Build - uses: docker/build-push-action@v2 - with: - builder: ${{ steps.buildx.outputs.name }} - context: ./nodejs/ - file: ./nodejs/Dockerfile - platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x - push: true - tags: | - betterweb/service-base:latest-node - betterweb/service-base:node - betterweb/service-base:node-${{ needs.build_and_publish_prod_nodejs.outputs.version }} - betterweb/service-base:node-v${{ needs.build_and_publish_prod_nodejs.outputs.major }} - - docs_build_prod: - runs-on: ubuntu-latest - needs: [build_and_publish_prod_nodejs] - - strategy: - matrix: - node-version: [16.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: documentation/package-lock.json - - - run: npm ci - working-directory: documentation/ - - - run: npm run build - working-directory: documentation/ - - - name: Update site - uses: cloudflare/wrangler-action@2.0.0 - with: - apiToken: ${{ secrets.CF_API_TOKEN }} - accountId: ${{ secrets.CF_ACCOUNT_ID }} - command: pages publish documentation/.vuepress/dist --project-name=bsb-documentation --commit-dirty=true --branch=master diff --git a/.github/workflows/updatePlugins.yml b/.github/workflows/updatePlugins.yml deleted file mode 100644 index a358380..0000000 --- a/.github/workflows/updatePlugins.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Update documentation plugins - -on: - push: - branches: - - "master" - # - "documentation" # Specifically disabled to stop infinite build loop - - "develop" - create: - tags: - - "*" - schedule: - - cron: "0 0/6 1/1 * *" - workflow_dispatch: - branches: [documentation] - -jobs: - build_and_update_plugins: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [18.x] - - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - ref: documentation - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - - name: Plugin def generation - id: plugin_generation - run: node generatePluginData.js - - - uses: EndBug/add-and-commit@v9 # You can change this to use a specific version. - if: ${{ steps.plugin_generation.outputs.changes == 'true' }} - with: - add: "plugins.json" - committer_name: GitHub Actions - committer_email: actions@github.com - message: "Updated known plugins" - pull: "" - push: true - - - run: mkdir _tempCDN - - run: cp ./plugins.json _tempCDN/plugins.json - - - name: Update site - if: ${{ steps.plugin_generation.outputs.changes == 'true' }} - uses: cloudflare/wrangler-action@2.0.0 - with: - apiToken: ${{ secrets.CF_API_TOKEN }} - accountId: ${{ secrets.CF_ACCOUNT_ID }} - command: pages publish _tempCDN --project-name=bsb-cdn --commit-dirty=true --branch=master diff --git a/.gitignore b/.gitignore index 2752735..73cc8a3 100644 --- a/.gitignore +++ b/.gitignore @@ -14,11 +14,15 @@ node_modules /coverage /junit.json /sec.config.json +/sec.config.yaml /nodejs/junit.json /nodejs/sec.config.json +/nodejs/sec.config.yaml /nodejs/node_modules /nodejs/.nyc_output /nodejs/lib +/nodejs/coverage +/nodejs/development/tsconfig.json /dotnet/[Dd]ebug/ /dotnet/[Dd]ebugPublic/ /dotnet/[Rr]elease/ diff --git a/README.md b/README.md index f945ea4..4f4e2d5 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,52 @@ -[![Docker Image Size](https://img.shields.io/docker/image-size/betterweb/service-base/latest)](https://hub.docker.com/r/betterweb/service-base) -[![Docker Pulls](https://img.shields.io/docker/pulls/betterweb/service-base)](https://hub.docker.com/r/betterweb/service-base) -[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/betterweb/service-base?sort=semver)](https://hub.docker.com/r/betterweb/service-base) -[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) -[![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) -[![GitHub last commit (branch)](https://img.shields.io/github/last-commit/bettercorp/better-service-base/develop)](https://github.com/BetterCorp/better-service-base) -[![GitHub Repo stars](https://img.shields.io/github/stars/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) -[![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/pulls) -[![GitHub issues](https://img.shields.io/github/issues-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/issues) +# About + +BSB (Better-Service-Base) is an event-bus based microservice framework. +It is completely opensource and can work as a single node, or geo-scaled cluster. +Simplicity, flexibility and expandability were the key points when developing this framework. +*(currently only in nodejs, however it is ready for several other languages)* + +[![Intro 1](http://img.youtube.com/vi/-ulXL44D_ZI/0.jpg)](http://www.youtube.com/watch?v=-ulXL44D_ZI) +`#Sales pitch` + +## Source/Github +[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) +[![GitHub Repo stars](https://img.shields.io/github/stars/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) +[![GitHub issues](https://img.shields.io/github/issues-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/issues) +[![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/pulls) +[![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) +[![GitHub last commit (branch)](https://img.shields.io/github/last-commit/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) +[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/BetterCorp/better-service-base/Build%20and%20Publish%20Containers%20(LIVE))](https://github.com/BetterCorp/better-service-base/actions/workflows/tags.yml) [![Build and Publish (EA)](https://github.com/BetterCorp/better-service-base/actions/workflows/develop.yml/badge.svg?branch=develop)](https://github.com/BetterCorp/better-service-base/actions/workflows/develop.yml) [![Build and Publish (RC)](https://github.com/BetterCorp/better-service-base/actions/workflows/master.yml/badge.svg?branch=master)](https://github.com/BetterCorp/better-service-base/actions/workflows/master.yml) -[![codecov](https://codecov.io/gh/BetterCorp/better-service-base/branch/master/graph/badge.svg)](https://codecov.io/gh/BetterCorp/better-service-base) -[![node-current (scoped)](https://img.shields.io/node/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![npm](https://img.shields.io/npm/dt/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![npm bundle size (scoped)](https://img.shields.io/bundlephobia/min/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![npm (scoped)](https://img.shields.io/npm/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![Docker Sponsored Open Source](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIUAAAAYCAYAAADUIj6hAAAAAXNSR0IArs4c6QAAB2hJREFUaEPtmgFInOcZx3+JVzmpoJRLd9BQG044yGEVDpSg4yDSGHCktCkYzHDMBCV2IcPQ0najpaWSMaksbZYQaepmptTNLFgmzIUEbmsRBUFbrnAQWSwKt9VkOr7ViznreHy/1/u8XL77TppUknvh8OO+93ve533e//d//s/jbVtdXV1lk2N1BVaW4ds7INer327SUO6x7z0C27bDtjzY/hhs2wwoBACJJVi5/b3vJefAfYhA1qBYicOd/90HT3Imt0wEsgKFsEPimy3je86R+xQBx6DYDEPMTCa9XozBs/vv0y5yZr/TCDgChWiI2wvZrSuA6Gvf+EyRF0oq4EevZmcrN/vBRsARKO4YzkTlX34NAoaX+9UmhB2s4/MR+MfvQcDx4y71Nze2XgQygiIblhBm0KCQAxdQCBCKfqAAICwh3/3BZBANnrRhWYap8zAWhnkDCndB+U8hVAl8Ae+fAEM/mA+eMqhqhfJS9WXiKwifh8gkxPPhqRDUHgVvYfL5uB+az4AnjzVjfS/ATCW0d4Dbbn2H9tf9K1D+VR+HwFMwfxG6e+7edVB86YGRCXXPVQTeSqg+Cr4d6cEzOwjXhiD2NbglRk0Q2mPOzbAHYwJGemDmOiQKzBi1OihJsxGXcuD67RdGkI91/PAnIB+Z99tGpTHulUqm34OBYSgOgu9pmAtDzIBQN1QvKlAkdkMgACxANAxGETRcAN8KDLVAZBF21kCRAdFxcAWhuROKLaAqOQmH6+8GxZzd+kXO7Gv/Ev9W/sVLofkcuPoVKDwhKHnSjNB2eOZ5MN6DkUnwHYDCWzD9KRheaDgHPgG0ZcT6ofdDcJWCzw83RyG2CMFOqKsA2xjmQW8LzOaDfy+45yAyDu79DkCx/F/VnMo0Pv9rUkhqxkj3jAZCaqpJnfvZMQjPwcFB8OdDYhwGPgbPi1BXpEDhPgwtR9STs+eg909Q3glV16H7PJT8HA4fUPejp+DSFQiehjosTLMDDl4APxuZYsJm/eCcM/tW/yZeUYddNwglnyhQiK/1wY07X5v3BTz/CQTyYUHm/gY8rdDcYJm7BEONECmExm54pgD4Cj46AvMV0NYJUzZ7qAW63gTPUWhuVHYn3oXIigNQ3P5P5k6lFpU6HQgL2I3DXequgEeuJa2kjtjv4KNeKK6EqkMQqAC3nmS+6etBN2DsXbg6AVVnwNsHQ6NQ2w9VJu0mwtD1thnc3QoU7Ba0gOslaDkEAy8l08eCzfqRN53Z1/4lYjD8CkQMaBiAogEFCv+rUFtmbqoAip+AVFBwC/oaYCYI7b+yxCAKZ38G8f3QfjIZvXALfBaDhsvw+EWbGN6CS0fWtk/gEFQ9B94nlJ2MmiJ+MxNHKB0hByygkGthAbshKUOAIOCR67Sl6grcGIC/faw0hcsLwTaorUmjKczFCvdAUwdMt8PIl1A/COWacseh6zUobIKWYJJpqmfVAYc64YZoIq0pbNafcGh/XVOIf0LTJ+Hgc+k1hWsvtP8SplKYgmW4dACifmg7DcU6sJPwfju4GqCtNRntsRNwNWoyTZ5NDEUX/ROufgBTk5DIA+9e2Hf8OwKFpA4BwhvXkgDJBArRHnZMsf78MsyOwlgPRGNQfQZCSxs1hSsfiv0QqFFv0vqbfBGqzAonHVPIm9y8H/pbYL4UCr+EeQ0K7UCa9T29JlNksL+mKfwwPQyGH1rMQ9VCs6QJKnaphQT0fn8WTHEdzh6zZwqfCGgZ6WJoCnK5HRc98WcIXwZCDkCRTfqQVFDsVQxgN6yMItd3laaGorY5qQ7eAXnZE1eg6xR4j0NT6d2awrrewgCcPQ87Ze4L6k46TaHpXaeqtYl7oP11GLZZ/8BydvY3rF2WZApHmuIydH+wMffrgx5qgEgBNF6waAoBeBm0vQUjNnvYZ8AfhyDwlpnCVuDqERgzHIDCidBMrSaENYQ90g0tNFPL19S5U7+A4VGl0H1eiIVhJgblXVCfZw8KFlOqgyWIjgIV0NwFnlRNsqRAMCV9FQFFB0Tt1t+VpX0RvsdgoRLaOiBulqR6b4oqYGe9pfp4EYpvmlVVpupjF/h2w+I4zN6C8g6orwS7GNblQ/cJWNgBgRC4v4bINUhUOACF05JUVxOiEYQtdKPKetgaEFqD3FNPyEMGTPWYfYpFcAu9HoLaenCnHmoa9KX2Kbw1sLcVdlr6FNbqwLgC3acgboLCbbd+mj5FJvtTr8HwBFSfg8DoPfoUp0FS03qfohA8lRBqvXef4sYg/F33KZ6GgPQpatYwZh9DqeTHIdwH01GI54EnCLVONIXT5pW1KaWFpHwnAFj8Fzxbp9KEBoQITV2F2Ceb3N0HHYGM1Yc45LTNbQWGHHrZPsUaMhZi8GmvAoWAQwPnQW84t17mCDgChVO2kOV0azu1myn3BAzCGNLVzI2tGwFHoBD3s/3XuU4dGgzyN12TauuG5tH1zDEoJEROReejG86HY+dZgWIzjPFwhOnR2kXWoJDw5H64+3CDZFOg0CHJ/cT/4QGH9Sf+/wfwNRIsZmF1xgAAAABJRU5ErkJggg==)](https://hub.docker.com/r/betterweb/service-base) - -# Better-Service-base for distributed Micro-Services -This base allows for easy distributed service platform development. +## Container/Docker +[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) +[![Docker Image Size](https://img.shields.io/docker/image-size/betterweb/service-base/latest)](https://hub.docker.com/r/betterweb/service-base) +[![Docker Pulls](https://img.shields.io/docker/pulls/betterweb/service-base)](https://hub.docker.com/r/betterweb/service-base) +[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/betterweb/service-base?sort=semver)](https://hub.docker.com/r/betterweb/service-base) -## Getting started +## NodeJS +[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) +[![codecov](https://codecov.io/gh/BetterCorp/better-service-base/branch/master/graph/badge.svg)](https://codecov.io/gh/BetterCorp/better-service-base) +[![node-current (scoped)](https://img.shields.io/node/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) +[![npm](https://img.shields.io/npm/dt/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) +[![npm bundle size (scoped)](https://img.shields.io/bundlephobia/min/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) +[![npm (scoped)](https://img.shields.io/npm/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) +### - Plugins +[![NodeJS Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.total&label=NodeJS%20Plugins)](https://bsbcode.dev/Market/) +[![Service Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.services&label=Service%20Plugins&color=a200ff)](https://bsbcode.dev/Market/Service/) +[![Config Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.config&label=Config%20Plugins&color=03A9F4)](https://bsbcode.dev/Market/Config/) +[![Events Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.events&label=Events%20Plugins&color=FB8C00)](https://bsbcode.dev/Market/Events/) +[![Logging Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.logging&label=Logging%20Plugins&color=43A047)](https://bsbcode.dev/Market/Logging/) -View the docs here: [https://bsbcode.dev/](https://bsbcode.dev/) ## Sponsors +[![Static Badge](https://img.shields.io/badge/BetterCorp-Open%20Source%20Initiative-19b5fe?logo)](https://bettercorp.dev/?ref=better-service-base-s-os) +[![Static Badge](https://img.shields.io/badge/Docker-Sponsored%20Open%20Source-0db7ed)](https://hub.docker.com/r/betterweb/service-base?ref=better-service-base-s-os) +[![Static Badge](https://img.shields.io/badge/BrowserStack-Sponsored%20Open%20Source-0070F0?logo=browserstack)](https://www.browserstack.com/?ref=better-service-base-s-os) + + + +## Documentation/Usage -[BetterCorp](https://www.bettercorp.dev) -[Docker](https://www.docker.com) -[BrowserStack](https://www.browserstack.com/) \ No newline at end of file +See [Getting Started](https://bsbcode.dev/GettingStarted/) for more details \ No newline at end of file diff --git a/documentation/Deployment/README.md b/documentation/Deployment/README.md deleted file mode 100644 index e7c313f..0000000 --- a/documentation/Deployment/README.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -lang: en-US -title: Deployment -description: BSB Deployment -footer: Copyright © 2016-present BetterCorp (PTY) Ltd - All rights reserved ---- - -# BSB Deployment - -## Docker - -[betterweb/service-base](https://hub.docker.com/r/betterweb/service-base) - -This is the base docker image. -This image contains basically nothing except the default plugins (log-default, events-default, config-default) - - -### Environment variables - -- BSB_SEC_JSON = `./sec.config.json` -Specifically define the location to the `default-config` `sec.config.json` file - -- BSB_PROFILE = `default` -Sets the deployment profile of the service. -This defines the specific containers profile and what service(s) that will be running in the container. - -- BSB_CONFIG_PLUGIN = ` ` (not set) -Defines the config plugin to use. -When not set, it will use the `sec.config.json` file. -The config plugin is the only plugin that may have additional environment variables to set. -The rest of the plugins configuration is set in the config plugins definition. *(see config plugin docs for more info)* - -- BSB_PLUGINS = ` ` (comma seperated list of plugins) -If defined, we'll automatically install the plugins if not already installed. -What this allows you to do is have a seperate container to manage deployments/versions, and then a lightweight main container for the actual services themselves. -Or for a simpler deployment (like below), a single container that will set itself up if the plugins aren't setup/installed. - - -## Deployment - -An example docker compose file for a service. - -```yaml - service: - image: betterweb/service-base:node - volumes: - - /etc/localtime:/etc/localtime:ro - - /home/bsb/config.json:/home/bsb/sec.config.json:ro - environment: - - BSB_PROFILE=my-service - - BSB_PLUGINS=@bettercorp/service-base-plugin-web-server - deploy: - replicas: 2 - update_config: - parallelism: 1 - order: start-first -``` - -This installs web-server plugin on boot. However it doesn't do much else *(we'll add a demo plugin in the future)* -You can list your plugins, or have a seperate container to do the installation of your plugins. - -## Requirements - -- A server running docker (docker swarm/kubernetes/nomad) -- An events service (should you want to run more than 1 service...) - - Example: RabbitMQ/Pubnub/Kafka - - -## Directories (in the container) - -- `/home/bsb/sec.config.json` - The config file - -- `/mnt/bsb-plugins` - package like directory which will contain all the installed plugins. -This allows you to mount the dir for multiple containers (or use a shared volume) thus allowing the saving of storage space and A/B testing. - - - \ No newline at end of file diff --git a/documentation/Development/README.md b/documentation/Development/README.md deleted file mode 100644 index cb54853..0000000 --- a/documentation/Development/README.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -lang: en-US -title: Getting Started -description: Using the BSB -footer: Copyright © 2016-present BetterCorp (PTY) Ltd - All rights reserved ---- - -# BSB Getting Started - -## About - -The BSB is designed to be setup in a blank repo/project and cannot be added to an existing project. - -## Getting started - -
THIS DOCUMENTATION IS A WORK IN PROGRESS
- -We've just removed the old docs as they no longer pertain to v8. - -You can look at the source of one of the plugins in the plugin marketplace for reference for now. \ No newline at end of file diff --git a/documentation/README.md b/documentation/README.md deleted file mode 100644 index f5c3a8e..0000000 --- a/documentation/README.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -home: true -heroText: Better-Service-Base -tagline: A simple yet scalable microservice base -features: -- title: Start Simple - details: Get started quickly, expand infinitely -- title: Event Based - details: BSB is completely event based. Choose the event broker that suites your needs, or build one if it doesn't exist yet. -- title: Scalable - details: Services are designed to be containerized and scaled to meet demand. -footer: Copyright © 2016-present BetterCorp (PTY) Ltd - All rights reserved ---- - -
THIS DOCUMENTATION IS A WORK IN PROGRESS
- -[![Docker Image Size](https://img.shields.io/docker/image-size/betterweb/service-base/latest)](https://hub.docker.com/r/betterweb/service-base) -[![Docker Pulls](https://img.shields.io/docker/pulls/betterweb/service-base)](https://hub.docker.com/r/betterweb/service-base) -[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/betterweb/service-base?sort=semver)](https://hub.docker.com/r/betterweb/service-base) -[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) -[![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) -[![GitHub last commit (branch)](https://img.shields.io/github/last-commit/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) -[![GitHub Repo stars](https://img.shields.io/github/stars/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) -[![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/pulls) -[![GitHub issues](https://img.shields.io/github/issues-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/issues) -[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/BetterCorp/better-service-base/Build%20and%20Publish%20Containers%20(LIVE))](https://github.com/BetterCorp/better-service-base/actions/workflows/tags.yml) -[![Build and Publish (EA)](https://github.com/BetterCorp/better-service-base/actions/workflows/develop.yml/badge.svg?branch=develop)](https://github.com/BetterCorp/better-service-base/actions/workflows/develop.yml) -[![Build and Publish (RC)](https://github.com/BetterCorp/better-service-base/actions/workflows/master.yml/badge.svg?branch=master)](https://github.com/BetterCorp/better-service-base/actions/workflows/master.yml) -[![codecov](https://codecov.io/gh/BetterCorp/better-service-base/branch/master/graph/badge.svg)](https://codecov.io/gh/BetterCorp/better-service-base) -[![node-current (scoped)](https://img.shields.io/node/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![npm](https://img.shields.io/npm/dt/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![npm bundle size (scoped)](https://img.shields.io/bundlephobia/min/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![npm (scoped)](https://img.shields.io/npm/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![Docker Sponsored Open Source](./assets/hub.docker.com_r_betterweb_service-base.png)](https://hub.docker.com/r/betterweb/service-base) - -## About - -BSB was designed to be a simple, expandable and server agnostic platform for simple, scalable microservice projects. - -From v8 of the BSB, a single container can be deployed with a linked volume to minize the storage space required for deployment. -See [Docker Deployment](/Deployment) for deployment configurations - - -## Getting started - -- run the docker image with the required configuration. - -Look at the [Market](/Market) for a list of active plugins and how to use them - - -## Sponsors - -[BetterCorp](https://www.bettercorp.dev) -[Docker](https://www.docker.com) -[BrowserStack](https://www.browserstack.com/) \ No newline at end of file diff --git a/documentation/_index.en.md b/documentation/_index.en.md new file mode 100644 index 0000000..9f22e75 --- /dev/null +++ b/documentation/_index.en.md @@ -0,0 +1,37 @@ +--- +# banner +banner : + title : "Event-bus based microservice framework." + subtitle : "Simplicity, flexibility and expandability were the key points when developing this framework. " + #image : "images/BSB-Def-1.drawio.svg" + image : "https://content.betterweb.co.za/better-service-base/bsb-intro-1.gif" + statements : + - https://img.shields.io/github/license/BetterCorp/better-service-base + - https://img.shields.io/github/stars/BetterCorp/better-service-base + - https://img.shields.io/github/issues-raw/BetterCorp/better-service-base + - https://img.shields.io/github/issues-pr-raw/BetterCorp/better-service-base + - https://img.shields.io/github/last-commit/bettercorp/better-service-base/master + - https://img.shields.io/docker/image-size/betterweb/service-base/latest + - https://codecov.io/gh/BetterCorp/better-service-base/branch/master/graph/badge.svg + - https://img.shields.io/node/v/@bettercorp/service-base + - https://img.shields.io/npm/dt/@bettercorp/service-base + - https://img.shields.io/bundlephobia/min/@bettercorp/service-base + - https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.total&label=Plugins + +banner_button : + enable : "true" + label : "Get Started" + link : "get-started/" + +# call to action +call_to_action : + enable : true + title : "Simplicity over complexity" + image : "images/AdobeStock_587427658.svg" + content : "Think of kubernetes vs nomad, we're nomad for simplicity" + + button : + enable : "true" + label : "Get started" + link : "get-started/" +--- diff --git a/documentation/get-started/_index.en.md b/documentation/get-started/_index.en.md new file mode 100644 index 0000000..8218ab7 --- /dev/null +++ b/documentation/get-started/_index.en.md @@ -0,0 +1,15 @@ +--- +title: "Get Started" +date: 2023-07-27T13:03:00+02:00 +weight: 1 +draft: false +type : "docs" +--- + +BSB (Better-Service-Base) is an event-bus based microservice framework. +It is completely opensource and can work as a single node, or geo-scaled cluster. +Simplicity, flexibility and expandability were the key points when developing this framework. +_(currently only in nodejs, however it is ready for several other languages)_ + +![Intro 1](https://content.betterweb.co.za/better-service-base/bsb-intro-1.gif "image") + diff --git a/documentation/get-started/architecture/_index.en.md b/documentation/get-started/architecture/_index.en.md new file mode 100644 index 0000000..a74a73a --- /dev/null +++ b/documentation/get-started/architecture/_index.en.md @@ -0,0 +1,35 @@ +--- +title: "Architecture" +date: 2023-07-27T13:03:00+02:00 +weight: 2 +draft: false +type : "docs" +--- + +##### Single container/service +![Arch 1](https://content.betterweb.co.za/better-service-base/BSB-def-2.drawio.svg) + +
+
+
+ +##### 3 container cluster +Frontend contains the entrypoint/API +The scheduler never scales to more than 1 running container - this handles all the scheduled tasks +The backend container handles the logic, so called backend code +![Arch 1](https://content.betterweb.co.za/better-service-base/BSB-Def-1.drawio.svg) + +
+
+
+ +##### Fully scaled cluster +Each container has a single service and can be individually scaled up/down + +![Arch 1](https://content.betterweb.co.za/better-service-base/BSB-def-3.drawio.svg) + +
+
+ +Example with scaled containers (`4x frontend containers`) +![Arch 1](https://content.betterweb.co.za/better-service-base/BSB-def-4.drawio.svg) diff --git a/documentation/get-started/basics/_index.en.md b/documentation/get-started/basics/_index.en.md new file mode 100644 index 0000000..a763842 --- /dev/null +++ b/documentation/get-started/basics/_index.en.md @@ -0,0 +1,40 @@ +--- +title: "Basics" +date: 2023-07-27T13:03:00+02:00 +weight: 1 +draft: false +type : "single" +--- + +###### Events plugins + +These plugins are used to connect the BSB to your events broker. +An example would be: `rabbitMQ` + +###### Logging plugins + +These plugins are used to connect an external logging platform. +An example would be: `graylog` + +###### Config plugins + +These plugins allow you to connect an external configuration service for the BSB. +An example would be: `1password` + + +###### Service plugins + +These plugins are the main code, the secret sauce of the BSB. +You'll write your code in these for the actual logic. +An example would be: `fastify` or `express` + + +###### PDK + +PDK is the Plugin Development Kit + + +{{< notice "tip" >}} +The PDK is an app to configure and manage the BSB. +We did this because it is much easier than doing it in a CLI because of the options/choices available. - [see more](/pdk) +{{< /notice >}} diff --git a/documentation/languages/_index.en.md b/documentation/languages/_index.en.md new file mode 100644 index 0000000..23dbb19 --- /dev/null +++ b/documentation/languages/_index.en.md @@ -0,0 +1,12 @@ +--- +title: "Languages" +date: 2023-07-27T13:03:00+02:00 +weight: 3 +draft: false +type : "docs" +--- + +[NodeJS](/get-started/languages/nodejs) +dot NET `(coming soon)` +go `(coming soon)` +python `(coming soon)` \ No newline at end of file diff --git a/documentation/languages/nodejs/_index.en.md b/documentation/languages/nodejs/_index.en.md new file mode 100644 index 0000000..9919937 --- /dev/null +++ b/documentation/languages/nodejs/_index.en.md @@ -0,0 +1,22 @@ +--- +title: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 1 +draft: false +type : "docs" +--- + +##### Write your own service plugin +[Step 1: Write your service](/get-started/languages/nodejs/step1) + +##### Then select the config plugin (or use the default one) +[Step 2 : Select your config platform](/get-started/languages/nodejs/step2) + +##### Then select the events plugin (or use the default one) +[Step 3 : Select your events platform](/get-started/languages/nodejs/step3) + +##### Then select the logging/stats plugin (or use the default one) +[Step 4 : Select your log/stats platform](/get-started/languages/nodejs/step4) + +##### Send your platform live +[Step 5 : Deploy your platform](/get-started/languages/nodejs/step5) diff --git a/documentation/languages/nodejs/prerequisites/_index.en.md b/documentation/languages/nodejs/prerequisites/_index.en.md new file mode 100644 index 0000000..f37149b --- /dev/null +++ b/documentation/languages/nodejs/prerequisites/_index.en.md @@ -0,0 +1,15 @@ +--- +title: "Prerequisites" +subsection: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 1 +draft: false +type : "single" +--- + +###### NodeJS + +You need to have NodeJS, NPM installed on your machine. + +Node min version: `18` +NPM min version: `9` \ No newline at end of file diff --git a/documentation/languages/nodejs/step1/_index.en.md b/documentation/languages/nodejs/step1/_index.en.md new file mode 100644 index 0000000..076be40 --- /dev/null +++ b/documentation/languages/nodejs/step1/_index.en.md @@ -0,0 +1,8 @@ +--- +title: "Write your service" +subsection: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 2 +draft: false +type : "single" +--- diff --git a/documentation/languages/nodejs/step2/_index.en.md b/documentation/languages/nodejs/step2/_index.en.md new file mode 100644 index 0000000..8381bc0 --- /dev/null +++ b/documentation/languages/nodejs/step2/_index.en.md @@ -0,0 +1,8 @@ +--- +title: "Select your config platform" +subsection: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 4 +draft: false +type : "single" +--- diff --git a/documentation/languages/nodejs/step3/_index.en.md b/documentation/languages/nodejs/step3/_index.en.md new file mode 100644 index 0000000..41ad837 --- /dev/null +++ b/documentation/languages/nodejs/step3/_index.en.md @@ -0,0 +1,8 @@ +--- +title: "Select your events platform" +subsection: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 3 +draft: false +type : "single" +--- diff --git a/documentation/languages/nodejs/step4/_index.en.md b/documentation/languages/nodejs/step4/_index.en.md new file mode 100644 index 0000000..b8d8796 --- /dev/null +++ b/documentation/languages/nodejs/step4/_index.en.md @@ -0,0 +1,8 @@ +--- +title: "Select your log/stats platform" +subsection: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 5 +draft: false +type : "single" +--- diff --git a/documentation/languages/nodejs/step5/_index.en.md b/documentation/languages/nodejs/step5/_index.en.md new file mode 100644 index 0000000..aa2c5d5 --- /dev/null +++ b/documentation/languages/nodejs/step5/_index.en.md @@ -0,0 +1,8 @@ +--- +title: "Deploy your platform" +subsection: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 6 +draft: false +type: "single" +--- diff --git a/documentation/package-lock.json b/documentation/package-lock.json index 47224ec..ae644c5 100644 --- a/documentation/package-lock.json +++ b/documentation/package-lock.json @@ -13,9 +13,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.13.tgz", - "integrity": "sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", "bin": { "parser": "bin/babel-parser.js" }, @@ -353,6 +353,11 @@ "node": ">=12" } }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, "node_modules/@mdit-vue/plugin-component": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/@mdit-vue/plugin-component/-/plugin-component-0.11.2.tgz", @@ -464,9 +469,9 @@ } }, "node_modules/@types/debug": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", - "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "dependencies": { "@types/ms": "*" } @@ -480,14 +485,14 @@ } }, "node_modules/@types/hash-sum": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/hash-sum/-/hash-sum-1.0.0.tgz", - "integrity": "sha512-FdLBT93h3kcZ586Aee66HPCVJ6qvxVjBlDWNmxSGSbCZe9hTsjRKdSsl4y1T+3zfujxo9auykQMnFsfyHWD7wg==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw==" }, "node_modules/@types/linkify-it": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", - "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==" + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", + "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==" }, "node_modules/@types/markdown-it": { "version": "12.2.3", @@ -499,27 +504,30 @@ } }, "node_modules/@types/markdown-it-emoji": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/markdown-it-emoji/-/markdown-it-emoji-2.0.2.tgz", - "integrity": "sha512-2ln8Wjbcj/0oRi/6VnuMeWEHHuK8uapFttvcLmDIe1GKCsFBLOLBX+D+xhDa9oWOQV0IpvxwrSfKKssAqqroog==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/markdown-it-emoji/-/markdown-it-emoji-2.0.4.tgz", + "integrity": "sha512-H6ulk/ZmbDxOayPwI/leJzrmoW1YKX1Z+MVSCHXuYhvqckV4I/c+hPTf6UiqJyn2avWugfj30XroheEb6/Ekqg==", "dependencies": { "@types/markdown-it": "*" } }, "node_modules/@types/mdurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", - "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", + "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==" }, "node_modules/@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" + "version": "20.10.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz", + "integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==", + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/web-bluetooth": { "version": "0.0.16", @@ -527,123 +535,123 @@ "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" }, "node_modules/@vitejs/plugin-vue": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.0.0.tgz", - "integrity": "sha512-e0X4jErIxAB5oLtDqbHvHpJe/uWNkdpYV83AOG2xo2tEVSzCzewgJMtREZM30wXnM5ls90hxiOtAuVU6H5JgbA==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.5.2.tgz", + "integrity": "sha512-UGR3DlzLi/SaVBPX0cnSyE37vqxU3O6chn8l0HJNzQzDia6/Au2A4xKv+iIJW8w2daf80G7TYHhi1pAUjdZ0bQ==", "engines": { "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.0.0", + "vite": "^4.0.0 || ^5.0.0", "vue": "^3.2.25" } }, "node_modules/@vue/compiler-core": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz", - "integrity": "sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.11.tgz", + "integrity": "sha512-h97/TGWBilnLuRaj58sxNrsUU66fwdRKLOLQ9N/5iNDfp+DZhYH9Obhe0bXxhedl8fjAgpRANpiZfbgWyruQ0w==", "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.45", + "@babel/parser": "^7.23.5", + "@vue/shared": "3.3.11", "estree-walker": "^2.0.2", - "source-map": "^0.6.1" + "source-map-js": "^1.0.2" } }, "node_modules/@vue/compiler-dom": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz", - "integrity": "sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.11.tgz", + "integrity": "sha512-zoAiUIqSKqAJ81WhfPXYmFGwDRuO+loqLxvXmfUdR5fOitPoUiIeFI9cTTyv9MU5O1+ZZglJVTusWzy+wfk5hw==", "dependencies": { - "@vue/compiler-core": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/compiler-core": "3.3.11", + "@vue/shared": "3.3.11" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz", - "integrity": "sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==", - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.45", - "@vue/compiler-dom": "3.2.45", - "@vue/compiler-ssr": "3.2.45", - "@vue/reactivity-transform": "3.2.45", - "@vue/shared": "3.2.45", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.11.tgz", + "integrity": "sha512-U4iqPlHO0KQeK1mrsxCN0vZzw43/lL8POxgpzcJweopmqtoYy9nljJzWDIQS3EfjiYhfdtdk9Gtgz7MRXnz3GA==", + "dependencies": { + "@babel/parser": "^7.23.5", + "@vue/compiler-core": "3.3.11", + "@vue/compiler-dom": "3.3.11", + "@vue/compiler-ssr": "3.3.11", + "@vue/reactivity-transform": "3.3.11", + "@vue/shared": "3.3.11", "estree-walker": "^2.0.2", - "magic-string": "^0.25.7", - "postcss": "^8.1.10", - "source-map": "^0.6.1" + "magic-string": "^0.30.5", + "postcss": "^8.4.32", + "source-map-js": "^1.0.2" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz", - "integrity": "sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.11.tgz", + "integrity": "sha512-Zd66ZwMvndxRTgVPdo+muV4Rv9n9DwQ4SSgWWKWkPFebHQfVYRrVjeygmmDmPewsHyznCNvJ2P2d6iOOhdv8Qg==", "dependencies": { - "@vue/compiler-dom": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/compiler-dom": "3.3.11", + "@vue/shared": "3.3.11" } }, "node_modules/@vue/devtools-api": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz", - "integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==" + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.1.tgz", + "integrity": "sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==" }, "node_modules/@vue/reactivity": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz", - "integrity": "sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.11.tgz", + "integrity": "sha512-D5tcw091f0nuu+hXq5XANofD0OXnBmaRqMYl5B3fCR+mX+cXJIGNw/VNawBqkjLNWETrFW0i+xH9NvDbTPVh7g==", "dependencies": { - "@vue/shared": "3.2.45" + "@vue/shared": "3.3.11" } }, "node_modules/@vue/reactivity-transform": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz", - "integrity": "sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.11.tgz", + "integrity": "sha512-fPGjH0wqJo68A0wQ1k158utDq/cRyZNlFoxGwNScE28aUFOKFEnCBsvyD8jHn+0kd0UKVpuGuaZEQ6r9FJRqCg==", "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.45", - "@vue/shared": "3.2.45", + "@babel/parser": "^7.23.5", + "@vue/compiler-core": "3.3.11", + "@vue/shared": "3.3.11", "estree-walker": "^2.0.2", - "magic-string": "^0.25.7" + "magic-string": "^0.30.5" } }, "node_modules/@vue/runtime-core": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.45.tgz", - "integrity": "sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.11.tgz", + "integrity": "sha512-g9ztHGwEbS5RyWaOpXuyIVFTschclnwhqEbdy5AwGhYOgc7m/q3NFwr50MirZwTTzX55JY8pSkeib9BX04NIpw==", "dependencies": { - "@vue/reactivity": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/reactivity": "3.3.11", + "@vue/shared": "3.3.11" } }, "node_modules/@vue/runtime-dom": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz", - "integrity": "sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.11.tgz", + "integrity": "sha512-OlhtV1PVpbgk+I2zl+Y5rQtDNcCDs12rsRg71XwaA2/Rbllw6mBLMi57VOn8G0AjOJ4Mdb4k56V37+g8ukShpQ==", "dependencies": { - "@vue/runtime-core": "3.2.45", - "@vue/shared": "3.2.45", - "csstype": "^2.6.8" + "@vue/runtime-core": "3.3.11", + "@vue/shared": "3.3.11", + "csstype": "^3.1.2" } }, "node_modules/@vue/server-renderer": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.45.tgz", - "integrity": "sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.11.tgz", + "integrity": "sha512-AIWk0VwwxCAm4wqtJyxBylRTXSy1wCLOKbWxHaHiu14wjsNYtiRCSgVuqEPVuDpErOlRdNnuRgipQfXRLjLN5A==", "dependencies": { - "@vue/compiler-ssr": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/compiler-ssr": "3.3.11", + "@vue/shared": "3.3.11" }, "peerDependencies": { - "vue": "3.2.45" + "vue": "3.3.11" } }, "node_modules/@vue/shared": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz", - "integrity": "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==" + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.11.tgz", + "integrity": "sha512-u2G8ZQ9IhMWTMXaWqZycnK4UthG1fA238CD+DP4Dm4WJi5hdUKKLg0RMRaRpDPNMdkTwIDkp7WtD0Rd9BH9fLw==" }, "node_modules/@vuepress/bundler-vite": { "version": "2.0.0-beta.60", @@ -907,13 +915,13 @@ } }, "node_modules/@vueuse/core": { - "version": "9.11.1", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.11.1.tgz", - "integrity": "sha512-E/cizD1w9ILkq4axYjZrXLkKaBfzloaby2n3NMjUfd6yI/jkfTVgc6iwy/Cw2e++Ld4LphGbO+3MhzizvwUslQ==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", "dependencies": { "@types/web-bluetooth": "^0.0.16", - "@vueuse/metadata": "9.11.1", - "@vueuse/shared": "9.11.1", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", "vue-demi": "*" }, "funding": { @@ -921,9 +929,9 @@ } }, "node_modules/@vueuse/core/node_modules/vue-demi": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", - "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", "hasInstallScript": true, "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", @@ -946,17 +954,17 @@ } }, "node_modules/@vueuse/metadata": { - "version": "9.11.1", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.11.1.tgz", - "integrity": "sha512-ABjkrG+VXggNhjfGyw5e/sekxTZfXTwjrYXkkWQmQ7Biyv+Gq9UD6IDNfeGvQZEINI0Qzw6nfuO2UFCd3hlrxQ==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==", "funding": { "url": "https://github.com/sponsors/antfu" } }, "node_modules/@vueuse/shared": { - "version": "9.11.1", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.11.1.tgz", - "integrity": "sha512-UTZYGAjT96hWn4buf4wstZbeheBVNcKPQuej6qpoSkjF1atdaeCD6kqm9uGL2waHfisSgH9mq0qCRiBOk5C/2w==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", "dependencies": { "vue-demi": "*" }, @@ -965,9 +973,9 @@ } }, "node_modules/@vueuse/shared/node_modules/vue-demi": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", - "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", "hasInstallScript": true, "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", @@ -1021,9 +1029,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.13", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", - "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "version": "10.4.16", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", + "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", "funding": [ { "type": "opencollective", @@ -1032,12 +1040,16 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "browserslist": "^4.21.4", - "caniuse-lite": "^1.0.30001426", - "fraction.js": "^4.2.0", + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001538", + "fraction.js": "^4.3.6", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", "postcss-value-parser": "^4.2.0" @@ -1101,9 +1113,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", "funding": [ { "type": "opencollective", @@ -1112,13 +1124,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -1159,9 +1175,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001446", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001446.tgz", - "integrity": "sha512-fEoga4PrImGcwUUGEol/PoFCSBnSkA9drgdkxXkJLsUBOnJ8rs3zDv6ApqYXGQFOyMPsjh79naWhF4DAxbF8rw==", + "version": "1.0.30001570", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz", + "integrity": "sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==", "funding": [ { "type": "opencollective", @@ -1170,13 +1186,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, "node_modules/chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -1225,9 +1245,9 @@ } }, "node_modules/cli-spinners": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", - "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "engines": { "node": ">=6" }, @@ -1265,9 +1285,9 @@ } }, "node_modules/csstype": { - "version": "2.6.21", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", - "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/debug": { "version": "4.3.4", @@ -1308,9 +1328,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + "version": "1.4.612", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.612.tgz", + "integrity": "sha512-dM8BMtXtlH237ecSMnYdYuCkib2QHq0kpWfUnavjdYsyr/6OsAwg5ZGUfnQ9KD1Ga4QgB2sqXlB2NT8zy2GnVg==" }, "node_modules/entities": { "version": "3.0.1", @@ -1324,9 +1344,9 @@ } }, "node_modules/envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", + "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", "bin": { "envinfo": "dist/cli.js" }, @@ -1429,9 +1449,9 @@ } }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -1463,21 +1483,21 @@ } }, "node_modules/fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "engines": { "node": "*" }, "funding": { "type": "patreon", - "url": "https://www.patreon.com/infusion" + "url": "https://github.com/sponsors/rawify" } }, "node_modules/fs-extra": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", - "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -1488,9 +1508,9 @@ } }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "hasInstallScript": true, "optional": true, "os": [ @@ -1501,9 +1521,12 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-stream": { "version": "6.0.1", @@ -1528,13 +1551,13 @@ } }, "node_modules/globby": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", - "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", "dependencies": { "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", "merge2": "^1.4.1", "slash": "^4.0.0" }, @@ -1546,9 +1569,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/gray-matter": { "version": "4.0.3", @@ -1564,22 +1587,22 @@ "node": ">=6.0" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/hash-sum": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==" }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/human-signals": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", @@ -1608,17 +1631,17 @@ ] }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "engines": { "node": ">= 4" } }, "node_modules/immutable": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.2.tgz", - "integrity": "sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==" + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" }, "node_modules/inherits": { "version": "2.0.4", @@ -1637,11 +1660,11 @@ } }, "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1752,11 +1775,11 @@ } }, "node_modules/lilconfig": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", - "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", "engines": { - "node": ">=10" + "node": ">=14" } }, "node_modules/linkify-it": { @@ -1783,17 +1806,20 @@ } }, "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", "dependencies": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" } }, "node_modules/markdown-it": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz", - "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==", + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz", + "integrity": "sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==", "dependencies": { "argparse": "^2.0.1", "entities": "~3.0.1", @@ -1806,9 +1832,9 @@ } }, "node_modules/markdown-it-anchor": { - "version": "8.6.6", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.6.tgz", - "integrity": "sha512-jRW30YGywD2ESXDc+l17AiritL0uVaSnWsb26f+68qaW9zgbIIr1f4v2Nsvc0+s0Z2N3uX6t/yAw7BwCQ1wMsA==", + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", "peerDependencies": { "@types/markdown-it": "*", "markdown-it": "*" @@ -1835,9 +1861,9 @@ "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" }, "node_modules/medium-zoom": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.0.8.tgz", - "integrity": "sha512-CjFVuFq/IfrdqesAXfg+hzlDKu6A2n80ZIq0Kl9kWjoHh9j1N9Uvk5X0/MmN0hOfm5F9YBswlClhcwnmtwz7gA==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.1.0.tgz", + "integrity": "sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ==" }, "node_modules/merge-stream": { "version": "2.0.0", @@ -1881,9 +1907,15 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -1892,9 +1924,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", - "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==" + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -1952,17 +1984,17 @@ } }, "node_modules/ora": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/ora/-/ora-6.1.2.tgz", - "integrity": "sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-6.3.1.tgz", + "integrity": "sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ==", "dependencies": { - "bl": "^5.0.0", "chalk": "^5.0.0", "cli-cursor": "^4.0.0", "cli-spinners": "^2.6.1", "is-interactive": "^2.0.0", "is-unicode-supported": "^1.1.0", "log-symbols": "^5.1.0", + "stdin-discarder": "^0.1.0", "strip-ansi": "^7.0.1", "wcwidth": "^1.0.1" }, @@ -2011,9 +2043,9 @@ } }, "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", "funding": [ { "type": "opencollective", @@ -2022,10 +2054,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -2034,20 +2070,26 @@ } }, "node_modules/postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" }, "engines": { "node": ">= 14" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" @@ -2094,9 +2136,9 @@ ] }, "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -2118,11 +2160,11 @@ } }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -2180,9 +2222,9 @@ } }, "node_modules/rollup": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.10.1.tgz", - "integrity": "sha512-3Er+yel3bZbZX1g2kjVM+FW+RUWDxbG87fcqFM5/9HbPCTpbVp6JOLn7jlxnNlbu7s/N/uDA4EV/91E2gWnxzw==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "bin": { "rollup": "dist/bin/rollup" }, @@ -2236,9 +2278,9 @@ ] }, "node_modules/sass": { - "version": "1.57.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.57.1.tgz", - "integrity": "sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==", + "version": "1.69.5", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.5.tgz", + "integrity": "sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -2248,7 +2290,7 @@ "sass": "sass.js" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/section-matter": { @@ -2298,14 +2340,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -2314,17 +2348,25 @@ "node": ">=0.10.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead" - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, + "node_modules/stdin-discarder": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", + "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", + "dependencies": { + "bl": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -2334,9 +2376,9 @@ } }, "node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -2398,10 +2440,15 @@ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "engines": { "node": ">= 10.0.0" } @@ -2416,9 +2463,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "funding": [ { "type": "opencollective", @@ -2427,6 +2474,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { @@ -2434,7 +2485,7 @@ "picocolors": "^1.0.0" }, "bin": { - "browserslist-lint": "cli.js" + "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" @@ -2494,23 +2545,31 @@ } }, "node_modules/vue": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.45.tgz", - "integrity": "sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.11.tgz", + "integrity": "sha512-d4oBctG92CRO1cQfVBZp6WJAs0n8AK4Xf5fNjQCBeKCvMI1efGQ5E3Alt1slFJS9fZuPcFoiAiqFvQlv1X7t/w==", "dependencies": { - "@vue/compiler-dom": "3.2.45", - "@vue/compiler-sfc": "3.2.45", - "@vue/runtime-dom": "3.2.45", - "@vue/server-renderer": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/compiler-dom": "3.3.11", + "@vue/compiler-sfc": "3.3.11", + "@vue/runtime-dom": "3.3.11", + "@vue/server-renderer": "3.3.11", + "@vue/shared": "3.3.11" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/vue-router": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz", - "integrity": "sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz", + "integrity": "sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==", "dependencies": { - "@vue/devtools-api": "^6.4.5" + "@vue/devtools-api": "^6.5.0" }, "funding": { "url": "https://github.com/sponsors/posva" @@ -2572,9 +2631,9 @@ } }, "node_modules/yaml": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", - "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", "engines": { "node": ">= 14" } diff --git a/documentation/pdk/_index.en.md b/documentation/pdk/_index.en.md new file mode 100644 index 0000000..a6121f4 --- /dev/null +++ b/documentation/pdk/_index.en.md @@ -0,0 +1,12 @@ +--- +title: "PDK" +description: "BSB PDK is the Better-Service-Base Plugin-Development-Kit" +date: 2023-07-27T13:03:00+02:00 +weight: 2 +draft: false +type : "single" +--- + +### BSB Plugin Development Kit + +We've built a PDK app to help with managing your BSB plugins, generating/building new plugins \ No newline at end of file diff --git a/documentation/pdk/get-started/_index.en.md b/documentation/pdk/get-started/_index.en.md new file mode 100644 index 0000000..05200bd --- /dev/null +++ b/documentation/pdk/get-started/_index.en.md @@ -0,0 +1,9 @@ +--- +title: "Getting started" +date: 2023-07-27T13:03:00+02:00 +weight: 1 +draft: false +type : "docs" +--- + +##### Single container/service \ No newline at end of file diff --git a/dotnet/.dockerignore b/dotnet/.dockerignore new file mode 100644 index 0000000..38bece4 --- /dev/null +++ b/dotnet/.dockerignore @@ -0,0 +1,25 @@ +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/.idea +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/dotnet/.idea/.idea.BSB/.idea/.gitignore b/dotnet/.idea/.idea.BSB/.idea/.gitignore new file mode 100644 index 0000000..b5b97e7 --- /dev/null +++ b/dotnet/.idea/.idea.BSB/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/projectSettingsUpdater.xml +/.idea.BSB.iml +/modules.xml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/dotnet/.idea/.idea.BSB/.idea/.name b/dotnet/.idea/.idea.BSB/.idea/.name new file mode 100644 index 0000000..41e2ca1 --- /dev/null +++ b/dotnet/.idea/.idea.BSB/.idea/.name @@ -0,0 +1 @@ +BSB \ No newline at end of file diff --git a/dotnet/.idea/.idea.BSB/.idea/encodings.xml b/dotnet/.idea/.idea.BSB/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/dotnet/.idea/.idea.BSB/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dotnet/.idea/.idea.BSB/.idea/indexLayout.xml b/dotnet/.idea/.idea.BSB/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/dotnet/.idea/.idea.BSB/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/dotnet/.idea/.idea.BSB/.idea/vcs.xml b/dotnet/.idea/.idea.BSB/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/dotnet/.idea/.idea.BSB/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/dotnet/BSB.sln b/dotnet/BSB.sln new file mode 100644 index 0000000..bce70b8 --- /dev/null +++ b/dotnet/BSB.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BSB", "BSB\BSB.csproj", "{B613E86E-57C5-49ED-9AE4-56B2F5CC9E52}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BetterServiceBase", "BetterServiceBase\BetterServiceBase.csproj", "{8F3AD3A2-8E2D-488F-ACA3-B16518C2A4EE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B613E86E-57C5-49ED-9AE4-56B2F5CC9E52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B613E86E-57C5-49ED-9AE4-56B2F5CC9E52}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B613E86E-57C5-49ED-9AE4-56B2F5CC9E52}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B613E86E-57C5-49ED-9AE4-56B2F5CC9E52}.Release|Any CPU.Build.0 = Release|Any CPU + {8F3AD3A2-8E2D-488F-ACA3-B16518C2A4EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F3AD3A2-8E2D-488F-ACA3-B16518C2A4EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F3AD3A2-8E2D-488F-ACA3-B16518C2A4EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F3AD3A2-8E2D-488F-ACA3-B16518C2A4EE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/dotnet/BSB/BSB.csproj b/dotnet/BSB/BSB.csproj new file mode 100644 index 0000000..eb2460e --- /dev/null +++ b/dotnet/BSB/BSB.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/dotnet/BSB/Class1.cs b/dotnet/BSB/Class1.cs new file mode 100644 index 0000000..f468f22 --- /dev/null +++ b/dotnet/BSB/Class1.cs @@ -0,0 +1,5 @@ +namespace BSB; + +public class Class1 +{ +} \ No newline at end of file diff --git a/dotnet/BSB/obj/BSB.csproj.nuget.dgspec.json b/dotnet/BSB/obj/BSB.csproj.nuget.dgspec.json new file mode 100644 index 0000000..98933b5 --- /dev/null +++ b/dotnet/BSB/obj/BSB.csproj.nuget.dgspec.json @@ -0,0 +1,71 @@ +{ + "format": 1, + "restore": { + "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj": {} + }, + "projects": { + "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj", + "projectName": "BSB", + "projectPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj", + "packagesPath": "/home/mitchellr/.nuget/packages/", + "outputPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/home/mitchellr/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + } + ], + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/lib64/dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/dotnet/BSB/obj/BSB.csproj.nuget.g.props b/dotnet/BSB/obj/BSB.csproj.nuget.g.props new file mode 100644 index 0000000..027c5df --- /dev/null +++ b/dotnet/BSB/obj/BSB.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /home/mitchellr/.nuget/packages/ + /home/mitchellr/.nuget/packages/ + PackageReference + 6.8.0 + + + + + \ No newline at end of file diff --git a/dotnet/BSB/obj/BSB.csproj.nuget.g.targets b/dotnet/BSB/obj/BSB.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/dotnet/BSB/obj/BSB.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/dotnet/BSB/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs b/dotnet/BSB/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs new file mode 100644 index 0000000..f795be5 --- /dev/null +++ b/dotnet/BSB/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] diff --git a/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfo.cs b/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfo.cs new file mode 100644 index 0000000..c17b5f3 --- /dev/null +++ b/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("BSB")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("BSB")] +[assembly: System.Reflection.AssemblyTitleAttribute("BSB")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfoInputs.cache b/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfoInputs.cache new file mode 100644 index 0000000..2079379 --- /dev/null +++ b/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +2085b2250a84c1a9be6acaafd097d28d33ef39aa77ab12890538e72b283745b8 diff --git a/dotnet/BSB/obj/Debug/net6.0/BSB.GeneratedMSBuildEditorConfig.editorconfig b/dotnet/BSB/obj/Debug/net6.0/BSB.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..22c25e0 --- /dev/null +++ b/dotnet/BSB/obj/Debug/net6.0/BSB.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,13 @@ +is_global = true +build_property.TargetFramework = net6.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = BSB +build_property.ProjectDir = /home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = diff --git a/dotnet/BSB/obj/Debug/net6.0/BSB.GlobalUsings.g.cs b/dotnet/BSB/obj/Debug/net6.0/BSB.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/dotnet/BSB/obj/Debug/net6.0/BSB.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/dotnet/BSB/obj/Debug/net6.0/BSB.assets.cache b/dotnet/BSB/obj/Debug/net6.0/BSB.assets.cache new file mode 100644 index 0000000..d83dd60 Binary files /dev/null and b/dotnet/BSB/obj/Debug/net6.0/BSB.assets.cache differ diff --git a/dotnet/BSB/obj/project.assets.json b/dotnet/BSB/obj/project.assets.json new file mode 100644 index 0000000..ff91902 --- /dev/null +++ b/dotnet/BSB/obj/project.assets.json @@ -0,0 +1,76 @@ +{ + "version": 3, + "targets": { + "net6.0": {} + }, + "libraries": {}, + "projectFileDependencyGroups": { + "net6.0": [] + }, + "packageFolders": { + "/home/mitchellr/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj", + "projectName": "BSB", + "projectPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj", + "packagesPath": "/home/mitchellr/.nuget/packages/", + "outputPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/home/mitchellr/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + } + ], + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/lib64/dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/dotnet/BSB/obj/project.nuget.cache b/dotnet/BSB/obj/project.nuget.cache new file mode 100644 index 0000000..674b07d --- /dev/null +++ b/dotnet/BSB/obj/project.nuget.cache @@ -0,0 +1,11 @@ +{ + "version": 2, + "dgSpecHash": "m/mmZmgs6qi/4eqAiuSIdbou0BI1C15Z5VAJ274ZbPbs/O2jjmEhryyyoIOMW/uat6AecIhRT+0RvyiiWJABwQ==", + "success": true, + "projectFilePath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj", + "expectedPackageFiles": [ + "/home/mitchellr/.nuget/packages/microsoft.netcore.app.ref/6.0.25/microsoft.netcore.app.ref.6.0.25.nupkg.sha512", + "/home/mitchellr/.nuget/packages/microsoft.aspnetcore.app.ref/6.0.25/microsoft.aspnetcore.app.ref.6.0.25.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/dotnet/BSB/obj/project.packagespec.json b/dotnet/BSB/obj/project.packagespec.json new file mode 100644 index 0000000..95f26ab --- /dev/null +++ b/dotnet/BSB/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj","projectName":"BSB","projectPath":"/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj","outputPath":"/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net6.0"],"sources":{"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net6.0":{"targetAlias":"net6.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]}}"frameworks":{"net6.0":{"targetAlias":"net6.0","imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/home/mitchellr/.dotnet/sdk/6.0.404/RuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/dotnet/BSB/obj/rider.project.restore.info b/dotnet/BSB/obj/rider.project.restore.info new file mode 100644 index 0000000..4a89f78 --- /dev/null +++ b/dotnet/BSB/obj/rider.project.restore.info @@ -0,0 +1 @@ +16993920343007420 \ No newline at end of file diff --git a/dotnet/BetterServiceBase.csproj b/dotnet/BetterServiceBase.csproj deleted file mode 100644 index bafd05b..0000000 --- a/dotnet/BetterServiceBase.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - - net6.0 - enable - enable - - - diff --git a/dotnet/BetterServiceBase/BetterServiceBase.csproj b/dotnet/BetterServiceBase/BetterServiceBase.csproj new file mode 100644 index 0000000..ec44a9e --- /dev/null +++ b/dotnet/BetterServiceBase/BetterServiceBase.csproj @@ -0,0 +1,17 @@ + + + + Exe + net6.0 + enable + enable + Linux + + + + + .dockerignore + + + + diff --git a/dotnet/BetterServiceBase/Dockerfile b/dotnet/BetterServiceBase/Dockerfile new file mode 100644 index 0000000..b912583 --- /dev/null +++ b/dotnet/BetterServiceBase/Dockerfile @@ -0,0 +1,18 @@ +FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src +COPY ["BetterServiceBase/BetterServiceBase.csproj", "BetterServiceBase/"] +RUN dotnet restore "BetterServiceBase/BetterServiceBase.csproj" +COPY . . +WORKDIR "/src/BetterServiceBase" +RUN dotnet build "BetterServiceBase.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "BetterServiceBase.csproj" -c Release -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "BetterServiceBase.dll"] diff --git a/dotnet/BetterServiceBase/Program.cs b/dotnet/BetterServiceBase/Program.cs new file mode 100644 index 0000000..e5dff12 --- /dev/null +++ b/dotnet/BetterServiceBase/Program.cs @@ -0,0 +1,3 @@ +// See https://aka.ms/new-console-template for more information + +Console.WriteLine("Hello, World!"); \ No newline at end of file diff --git a/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase new file mode 100755 index 0000000..c288946 Binary files /dev/null and b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase differ diff --git a/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.deps.json b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.deps.json new file mode 100644 index 0000000..78e150b --- /dev/null +++ b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.deps.json @@ -0,0 +1,23 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v6.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v6.0": { + "BetterServiceBase/1.0.0": { + "runtime": { + "BetterServiceBase.dll": {} + } + } + } + }, + "libraries": { + "BetterServiceBase/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.dll b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.dll new file mode 100644 index 0000000..0141408 Binary files /dev/null and b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.dll differ diff --git a/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.pdb b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.pdb new file mode 100644 index 0000000..4290dec Binary files /dev/null and b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.pdb differ diff --git a/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.runtimeconfig.json b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.runtimeconfig.json new file mode 100644 index 0000000..4986d16 --- /dev/null +++ b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.runtimeconfig.json @@ -0,0 +1,9 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + } + } +} \ No newline at end of file diff --git a/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.dgspec.json b/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.dgspec.json new file mode 100644 index 0000000..2bd714c --- /dev/null +++ b/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.dgspec.json @@ -0,0 +1,75 @@ +{ + "format": 1, + "restore": { + "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj": {} + }, + "projects": { + "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", + "projectName": "BetterServiceBase", + "projectPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", + "packagesPath": "/home/mitchellr/.nuget/packages/", + "outputPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/home/mitchellr/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + }, + { + "name": "Microsoft.NETCore.App.Host.linux-x64", + "version": "[6.0.25, 6.0.25]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + } + ], + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/lib64/dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.props b/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.props new file mode 100644 index 0000000..027c5df --- /dev/null +++ b/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /home/mitchellr/.nuget/packages/ + /home/mitchellr/.nuget/packages/ + PackageReference + 6.8.0 + + + + + \ No newline at end of file diff --git a/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.targets b/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs b/dotnet/BetterServiceBase/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs new file mode 100644 index 0000000..f795be5 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfo.cs b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfo.cs new file mode 100644 index 0000000..b60dc30 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("BetterServiceBase")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("BetterServiceBase")] +[assembly: System.Reflection.AssemblyTitleAttribute("BetterServiceBase")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfoInputs.cache b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfoInputs.cache new file mode 100644 index 0000000..98ea8e3 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +e7e3a6a74e3831cb483e5b6d4f4da9eb38d87e11319a20fef308246f7b07ad29 diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GeneratedMSBuildEditorConfig.editorconfig b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..869834c --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,13 @@ +is_global = true +build_property.TargetFramework = net6.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = BetterServiceBase +build_property.ProjectDir = /home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GlobalUsings.g.cs b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.assets.cache b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.assets.cache new file mode 100644 index 0000000..3e0cbad Binary files /dev/null and b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.assets.cache differ diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.CoreCompileInputs.cache b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..bfb0f84 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +e8bb740154712d00dcb2031232868fc210f0e54b diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.FileListAbsolute.txt b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..039a136 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.FileListAbsolute.txt @@ -0,0 +1,15 @@ +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.deps.json +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.runtimeconfig.json +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.dll +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.pdb +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.AssemblyReference.cache +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GeneratedMSBuildEditorConfig.editorconfig +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfoInputs.cache +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfo.cs +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.CoreCompileInputs.cache +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.dll +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/refint/BetterServiceBase.dll +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.pdb +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.genruntimeconfig.cache +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/ref/BetterServiceBase.dll diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.dll b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.dll new file mode 100644 index 0000000..0141408 Binary files /dev/null and b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.dll differ diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.genruntimeconfig.cache b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.genruntimeconfig.cache new file mode 100644 index 0000000..da9474c --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.genruntimeconfig.cache @@ -0,0 +1 @@ +fc5a832e61a040bcac8ca24dde02dd8107c0af3e diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.pdb b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.pdb new file mode 100644 index 0000000..4290dec Binary files /dev/null and b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.pdb differ diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/apphost b/dotnet/BetterServiceBase/obj/Debug/net6.0/apphost new file mode 100755 index 0000000..c288946 Binary files /dev/null and b/dotnet/BetterServiceBase/obj/Debug/net6.0/apphost differ diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/ref/BetterServiceBase.dll b/dotnet/BetterServiceBase/obj/Debug/net6.0/ref/BetterServiceBase.dll new file mode 100644 index 0000000..32cd7b8 Binary files /dev/null and b/dotnet/BetterServiceBase/obj/Debug/net6.0/ref/BetterServiceBase.dll differ diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/refint/BetterServiceBase.dll b/dotnet/BetterServiceBase/obj/Debug/net6.0/refint/BetterServiceBase.dll new file mode 100644 index 0000000..32cd7b8 Binary files /dev/null and b/dotnet/BetterServiceBase/obj/Debug/net6.0/refint/BetterServiceBase.dll differ diff --git a/dotnet/BetterServiceBase/obj/project.assets.json b/dotnet/BetterServiceBase/obj/project.assets.json new file mode 100644 index 0000000..6d2c9ae --- /dev/null +++ b/dotnet/BetterServiceBase/obj/project.assets.json @@ -0,0 +1,80 @@ +{ + "version": 3, + "targets": { + "net6.0": {} + }, + "libraries": {}, + "projectFileDependencyGroups": { + "net6.0": [] + }, + "packageFolders": { + "/home/mitchellr/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", + "projectName": "BetterServiceBase", + "projectPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", + "packagesPath": "/home/mitchellr/.nuget/packages/", + "outputPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/home/mitchellr/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + }, + { + "name": "Microsoft.NETCore.App.Host.linux-x64", + "version": "[6.0.25, 6.0.25]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + } + ], + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/lib64/dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/dotnet/BetterServiceBase/obj/project.nuget.cache b/dotnet/BetterServiceBase/obj/project.nuget.cache new file mode 100644 index 0000000..e4eca4d --- /dev/null +++ b/dotnet/BetterServiceBase/obj/project.nuget.cache @@ -0,0 +1,12 @@ +{ + "version": 2, + "dgSpecHash": "SW8YGRI76SDK6Rzixpf1lnLQTQcTM4BP9qYzPPFryONlPOp6Z3dM/zeNTcfSTKfEQFHXckkCwaRCXWRcRxgYCA==", + "success": true, + "projectFilePath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", + "expectedPackageFiles": [ + "/home/mitchellr/.nuget/packages/microsoft.netcore.app.ref/6.0.25/microsoft.netcore.app.ref.6.0.25.nupkg.sha512", + "/home/mitchellr/.nuget/packages/microsoft.aspnetcore.app.ref/6.0.25/microsoft.aspnetcore.app.ref.6.0.25.nupkg.sha512", + "/home/mitchellr/.nuget/packages/microsoft.netcore.app.host.linux-x64/6.0.25/microsoft.netcore.app.host.linux-x64.6.0.25.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/dotnet/BetterServiceBase/obj/project.packagespec.json b/dotnet/BetterServiceBase/obj/project.packagespec.json new file mode 100644 index 0000000..11a81e0 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj","projectName":"BetterServiceBase","projectPath":"/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj","outputPath":"/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net6.0"],"sources":{"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net6.0":{"targetAlias":"net6.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]}}"frameworks":{"net6.0":{"targetAlias":"net6.0","imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/home/mitchellr/.dotnet/sdk/6.0.404/RuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/dotnet/BetterServiceBase/obj/rider.project.restore.info b/dotnet/BetterServiceBase/obj/rider.project.restore.info new file mode 100644 index 0000000..b052fc6 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/rider.project.restore.info @@ -0,0 +1 @@ +16993920754842324 \ No newline at end of file diff --git a/dotnet/Class1.cs b/dotnet/Class1.cs deleted file mode 100644 index 0abd266..0000000 --- a/dotnet/Class1.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace BetterServiceBase; -public class Class1 -{ - -} diff --git a/nodejs/.npmignore b/nodejs/.npmignore new file mode 100644 index 0000000..ce6e312 --- /dev/null +++ b/nodejs/.npmignore @@ -0,0 +1,7 @@ +/junit.json +/sec.config.json +/sec.config.yaml +/node_modules +/.nyc_output +/lib/plugins/service- +/src \ No newline at end of file diff --git a/nodejs/Dockerfile b/nodejs/Dockerfile index 3deafe0..8531901 100644 --- a/nodejs/Dockerfile +++ b/nodejs/Dockerfile @@ -1,8 +1,28 @@ -FROM betterweb/node:latest -# RUN npm i -g typescript ts-node +# BSB Build +# Using 18 until nodejs fixes a bug with v20 - https://github.com/nodejs/docker-node/issues/1829 +FROM betterweb/node:18 as builder + +ARG BSB_VERSION=0.0.0 + +RUN set -eux && mkdir /home/bsb && npm i -g typescript ts-node + +WORKDIR /home/bsb + +ADD tsconfig-release.json /home/bsb/tsconfig-release.json +ADD package.json /home/bsb/package.json +ADD package-lock.json /home/bsb/package-lock.json +ADD src/ /home/bsb/src/ +RUN npm ci && npm version $BSB_VERSION --allow-same-version --no-git-tag-version && npm run build-release + +# Final image +FROM betterweb/node:18 + +COPY --from=builder /home/bsb/lib /home/bsb/lib +COPY --from=builder /home/bsb/node_modules /home/bsb/node_modules +COPY --from=builder /home/bsb/package.json /home/bsb/package.json +COPY --from=builder /home/bsb/package-lock.json /home/bsb/package-lock.json VOLUME /mnt/bsb-plugins -RUN mkdir /home/bsb WORKDIR /home/bsb ENV NODE_ENV production @@ -10,33 +30,9 @@ ENV BSB_LIVE true ENV BSB_CONTAINER true ENV BSB_PLUGIN_DIR /mnt/bsb-plugins -# NPM repo defaults -#RUN pnpm config set auto-install-peers true -RUN npm init -y -RUN echo '{"deploymentProfiles":{"default":{}},"plugins":{}}' >> ./sec.config.json -# RUN pushd /mnt/bsb-plugins && npm init -y && pushd - -# Add core BSB lib (from local) -RUN mkdir /home/bsb-build -COPY *.tgz /home/bsb-build/ -COPY entrypoint.sh /root/entrypoint.sh -COPY entrypoint.js /root/entrypoint.js -RUN chmod 550 /root/entrypoint.sh - -# Default plugins/setup -RUN ls -la /home/bsb-build/ -RUN pnpm add "/home/bsb-build/$(ls /home/bsb-build/ | grep .tgz | head -1)" -# RUN pnpm i --prod --fix-lockfile "/home/bsb-build/$(ls /home/bsb-build/ | grep .tgz | head -1)" -RUN node ./node_modules/@bettercorp/service-base/postinstall.js --cwd=$(pwd) - -RUN cat ./package.json - -# Cleanup -RUN rm -rfv /home/bsb-build +COPY entrypoint.sh /home/bsb/entrypoint.sh -RUN chown -R root:node /home/bsb -RUN chmod -R 650 /home/bsb -RUN chown node:node /home/bsb/sec.config.json +RUN addgroup node dialout && chown -R node:node /home/bsb && chmod -R 440 /home/bsb && chmod 111 /home/bsb/entrypoint.sh -ENTRYPOINT [ "/root/entrypoint.sh" ] -CMD node node_modules/@bettercorp/service-base/lib/cli.js \ No newline at end of file +ENTRYPOINT [ "/home/bsb/entrypoint.sh" ] +CMD - \ No newline at end of file diff --git a/nodejs/LICENSE b/nodejs/LICENSE new file mode 100644 index 0000000..1f84167 --- /dev/null +++ b/nodejs/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. \ No newline at end of file diff --git a/nodejs/development/nodemon.json b/nodejs/development/nodemon.json index de7f160..9539f27 100644 --- a/nodejs/development/nodemon.json +++ b/nodejs/development/nodemon.json @@ -4,14 +4,14 @@ ".git", "lib", "node_modules", - "src/plugins/-*/**/*.ts", - "sec.config.json" + "src/plugins/-*/**/*.ts" ], "delay": 2000, "signal": "SIGHUP", "exec": "ts-node node_modules/@bettercorp/service-base/lib/dev.js", "watch": [ - "src/**/*.ts" + "src/**/*.ts", + "sec-config.yaml" ], - "ext": "ts,json" + "ext": "ts,json,yaml" } \ No newline at end of file diff --git a/nodejs/development/tsconfig-release.json b/nodejs/development/tsconfig-release.json new file mode 100644 index 0000000..e879a0c --- /dev/null +++ b/nodejs/development/tsconfig-release.json @@ -0,0 +1,38 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": ["types/*"] + }, + "module": "commonjs", + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "sourceMap": true, + "outDir": "lib", + "rootDir": "src", + "strict": true, + "target": "es2021", + "lib": ["es2021"], + "declaration": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node" + }, + "linterOptions": { + "exclude": ["src/plugins/-*/**/*.*", "src/tests/**/*.*"] + }, + "compileOnSave": true, + "include": ["src"], + "exclude": [ + "node_modules/**", + "src/plugins/*-test*/**/*.*", + "src/plugins/-*/**/*.*", + "src/tests/**/*.*" + ] +} diff --git a/nodejs/entrypoint.sh b/nodejs/entrypoint.sh index f2a9d72..f4504c5 100644 --- a/nodejs/entrypoint.sh +++ b/nodejs/entrypoint.sh @@ -1,20 +1,33 @@ #!/bin/sh -if [ "$BSB_CONTAINER" == "true" ]; then - cd /mnt/bsb-plugins - node /root/entrypoint.js - cd /home/bsb - # node ./node_modules/@bettercorp/service-base/postinstall.js --cwd=$(pwd) -fi +# if [ "$BSB_CONTAINER" == "true" ]; then +# cd /mnt/bsb-plugins +# node /root/entrypoint.js +# cd /home/bsb +# # node ./node_modules/@bettercorp/service-base/postinstall.js --cwd=$(pwd) +# fi -if [ "$BSB_DIALOUT" == "true" ]; then - addgroup node dialout; -fi +mkdir /home/bsb/.temp -chown -R root:node /home/bsb -chmod -R 650 /home/bsb -chown node:node /home/bsb/sec.config.json -chown -R root:node /mnt/bsb-plugins -chmod -R 650 /mnt/bsb-plugins +chown -R node:node /home/bsb +chown -R node:node /mnt/bsb-plugins -exec gosu node "$@" +chmod -R 444 /home/bsb +chmod -R 644 /home/bsb/.temp +chmod -R 444 /mnt/bsb-plugins +chmod 600 /home/bsb/sec-config.yaml + +# Check if the first argument is BSBDEBUG for debugging purposes +if [ "$1" = "BSBDEBUG" ]; then + shift + echo "WARNING: RUNNING IN DEBUG MODE" + echo "IN THIS MODE, ANY COMMAND CAN BE RUN" + echo "IT WILL BE RUN AS THE NODE USER" + echo "DO NOT USE IN PRODUCTION" + echo " - THERE WILL BE A 15s DELAY NOW" + sleep 15s + echo " - RUNNING YOUR COMMAND [$@]" + exec gosu node:node "$@" +else + exec gosu node:node node lib/cli.js +fi diff --git a/nodejs/nodemon.json b/nodejs/nodemon.json index a30b845..a1e9b31 100644 --- a/nodejs/nodemon.json +++ b/nodejs/nodemon.json @@ -4,14 +4,14 @@ ".git", "lib", "node_modules", - "src/plugins/-*/**/*.ts", - "sec.config.json" + "src/plugins/-*/**/*.ts" ], "delay": 2000, "signal": "SIGHUP", - "exec": "ts-node src/dev.ts", + "exec": "ts-node src/cli.ts", "watch": [ - "src/**/*.ts" + "src/**/*.ts", + "sec-config.yaml" ], - "ext": "ts,json" + "ext": "ts,json,yaml" } \ No newline at end of file diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 4e036a6..6924df8 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -1,38 +1,53 @@ { "name": "@bettercorp/service-base", - "version": "8.4.0-rc", + "version": "9.0.4-beta", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bettercorp/service-base", - "version": "8.4.0-rc", - "hasInstallScript": true, + "version": "9.0.4-beta", "license": "AGPL-3.0-only", "dependencies": { - "@bettercorp/tools": "^2.0.20220714140658" + "@bettercorp/tools": "^3.7.0", + "yaml": "^2.3.4", + "yargs": "^17.7.2", + "zod": "^3.22.4" }, "bin": { - "bsb": "lib/bootstrap.js" + "bsb": "lib/cli.js" }, "devDependencies": { - "@types/assert": "^1.5.6", - "@types/chai": "^4.3.3", - "@types/mocha": "^9.1.1", - "@types/node": "^18.7.16", - "@types/yargs": "^17.0.12", - "@typescript-eslint/eslint-plugin": "^5.31.0", - "@typescript-eslint/parser": "^5.31.0", - "eslint": "^8.20.0", - "mocha": "^10.0.0", + "@ts-ast-parser/core": "^0.6.3", + "@types/assert": "^1.5.10", + "@types/chai": "^4.3.11", + "@types/mocha": "^10.0.6", + "@types/node": "^20.10.6", + "@types/yargs": "^17.0.32", + "@typescript-eslint/eslint-plugin": "^6.15.0", + "@typescript-eslint/parser": "^6.15.0", + "chai": "^4.3.10", + "eslint": "^8.56.0", + "install": "^0.13.0", + "mocha": "^10.2.0", + "npm": "^10.2.5", "nyc": "^15.1.0", - "ts-node": "^10.9.1", - "typescript": "^4.7.4", - "yargs": "^17.5.1" + "ts-morph": "^21.0.1", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" }, "engines": { - "node": ">=16.0.0", - "npm": ">=8.0.0" + "node": ">=18.0.0", + "npm": ">=9.0.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/@ampproject/remapping": { @@ -49,47 +64,119 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/compat-data": { - "version": "7.21.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.7.tgz", - "integrity": "sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.21.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz", - "integrity": "sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", + "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.5", - "@babel/helper-compilation-targets": "^7.21.5", - "@babel/helper-module-transforms": "^7.21.5", - "@babel/helpers": "^7.21.5", - "@babel/parser": "^7.21.8", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -99,22 +186,28 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.5.tgz", - "integrity": "sha512-SrKK/sRv8GesIW1bDagf9cCG38IOMYZusoe1dfg0D8aiUe3Amvoj1QtjTPAWcfrZFvIwlleLb0gxzQidL9w14w==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, "dependencies": { - "@babel/types": "^7.21.5", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -124,171 +217,168 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.5.tgz", - "integrity": "sha512-1RkbFGUKex4lvsB9yhIfWltJM5cZKUftB2eNajaDv3dCMEp49iBG0K14uH8NnX9IPux2+mK7JGEOB0jn48/J6w==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.21.5", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", "lru-cache": "^5.1.1", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.21.5.tgz", - "integrity": "sha512-IYl4gZ3ETsWocUWgsFZLM5i1BYx9SoemminVEXadgLBa9TdeorzgLKm8wWLA6J1N/kT3Kch8XIk1laNzYoHKvQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dev": true, "dependencies": { - "@babel/types": "^7.21.4" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.5.tgz", - "integrity": "sha512-bI2Z9zBGY2q5yMHoBvJ2a9iX3ZOAzJPm7Q8Yz6YeoUjU/Cvhmi2G4QyTNyPBqqXSgTjUxRg3L0xV45HvkNWWBw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.21.5", - "@babel/helper-module-imports": "^7.21.4", - "@babel/helper-simple-access": "^7.21.5", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5" + "@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" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.21.5.tgz", - "integrity": "sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dev": true, "dependencies": { - "@babel/types": "^7.21.5" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz", - "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.5.tgz", - "integrity": "sha512-BSY+JSlHxOmGsPTydUkPf1MdMQ3M81x5xGCOVgWM3G8XH77sJ292Y2oqcp0CbbgxhqBuI46iUz1tT7hqP7EfgA==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.7.tgz", + "integrity": "sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==", "dev": true, "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5" + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -367,9 +457,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.8.tgz", - "integrity": "sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -379,34 +469,34 @@ } }, "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.5.tgz", - "integrity": "sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.5", - "@babel/helper-environment-visitor": "^7.21.5", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.5", - "@babel/types": "^7.21.5", - "debug": "^4.1.0", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", + "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -423,13 +513,13 @@ } }, "node_modules/@babel/types": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.5.tgz", - "integrity": "sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.21.5", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -437,14 +527,11 @@ } }, "node_modules/@bettercorp/tools": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/@bettercorp/tools/-/tools-2.1.30.tgz", - "integrity": "sha512-MrRB57PQJ5bgz6D+jCTbcizH7A8PfKuyqu3MucekQN0qJ+E2ltdHeV5+3LapOqq5RZJH0N8gmf9qx3kzzy3CPw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@bettercorp/tools/-/tools-3.7.0.tgz", + "integrity": "sha512-UJQeelcmwq0De1J7N6pIKAL93xx/ABC1p0au0h/lmPEiOPXFRIaS3xH1Yq8/GBMqVbbHzi7gjbTCiF0Hfsju6A==", "dependencies": { - "@types/node": "^18.11.10", - "crypto-js": "^4.1.1", - "just-clone": "^6.1.1", - "moment": "^2.29.4" + "just-clone": "^6.2.0" } }, "node_modules/@cspotcode/source-map-support": { @@ -485,23 +572,23 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -516,22 +603,44 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz", - "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -539,6 +648,28 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -553,9 +684,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { @@ -681,9 +812,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true, "engines": { "node": ">=6.0.0" @@ -705,21 +836,15 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -755,6 +880,60 @@ "node": ">= 8" } }, + "node_modules/@sindresorhus/merge-streams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-1.0.0.tgz", + "integrity": "sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ts-ast-parser/comment": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@ts-ast-parser/comment/-/comment-0.1.0.tgz", + "integrity": "sha512-SLN5vUMcu0FwhsW7ngVFhwCI9p5r5MGIRT1nGyVKlrXSXMHGcKnU9oulH5Gz9s6epRQooA2TJmU/4hW9z8zy9A==", + "dev": true, + "dependencies": { + "tslib": "^2.6.1" + }, + "engines": { + "node": "^16.0.0 || ^18.0.0 || ^20.0.0" + } + }, + "node_modules/@ts-ast-parser/core": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@ts-ast-parser/core/-/core-0.6.3.tgz", + "integrity": "sha512-tRBa6eoiAUx/fNIEkxbYLYJlGur1JvKJc/6hGjlILlw9QPo9kS/Ae/dBnSLBkJV8rhOvl33TE1YmQDsNe4PdLg==", + "dev": true, + "dependencies": { + "@ts-ast-parser/comment": "0.1.0", + "globby": "^14.0.0", + "package-json-type": "^1.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0" + }, + "peerDependencies": { + "typescript": "^4.6.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x" + } + }, + "node_modules/@ts-morph/common": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.22.0.tgz", + "integrity": "sha512-HqNBuV/oIlMKdkLshXd1zKBqNQCsuPEsgQOkfFQ/eUKjRlwndXW1AjN9LVkBEIukm00gGXSRmfkl0Wv5VXLnlw==", + "dev": true, + "dependencies": { + "fast-glob": "^3.3.2", + "minimatch": "^9.0.3", + "mkdirp": "^3.0.1", + "path-browserify": "^1.0.1" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -780,82 +959,87 @@ "dev": true }, "node_modules/@types/assert": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/@types/assert/-/assert-1.5.6.tgz", - "integrity": "sha512-Y7gDJiIqb9qKUHfBQYOWGngUpLORtirAVPuj/CWJrU2C6ZM4/y3XLwuwfGMF8s7QzW746LQZx23m0+1FSgjfug==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/@types/assert/-/assert-1.5.10.tgz", + "integrity": "sha512-qEO+AUgYab7GVbeDDgUNCU3o0aZUoIMpNAe+w5LDbRxfxQX7vQAdDgwj1AroX+i8KaV56FWg0srXlSZROnsrIQ==", "dev": true }, "node_modules/@types/chai": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", - "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", + "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/mocha": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", - "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", + "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", "dev": true }, "node_modules/@types/node": { - "version": "18.16.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.13.tgz", - "integrity": "sha512-uZRomboV1vBL61EBXneL4j9/hEn+1Yqa4LQdpGrKmXFyJmVfWc9JV9+yb2AlnOnuaDnb2PDO3hC6/LKmzJxP1A==" + "version": "20.10.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", + "integrity": "sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, "node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.6.tgz", - "integrity": "sha512-sXtOgJNEuRU5RLwPUb1jxtToZbgvq3M6FPpY4QENxoOggK+UpTxUBpj6tD8+Qh2g46Pi9We87E+eHnUw8YcGsw==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.0.tgz", + "integrity": "sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.6", - "@typescript-eslint/type-utils": "5.59.6", - "@typescript-eslint/utils": "5.59.6", + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/type-utils": "6.18.0", + "@typescript-eslint/utils": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -864,25 +1048,26 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.6.tgz", - "integrity": "sha512-7pCa6al03Pv1yf/dUg/s1pXz/yGMUBAw5EeWqNTFiSueKvRNonze3hma3lhdsOrQcaOXhbk5gKu2Fludiho9VA==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.0.tgz", + "integrity": "sha512-v6uR68SFvqhNQT41frCMCQpsP+5vySy6IdgjlzUWoo7ALCnpaWYcz/Ij2k4L8cEsL0wkvOviCMpjmtRtHNOKzA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.59.6", - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/typescript-estree": "5.59.6", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -891,16 +1076,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.6.tgz", - "integrity": "sha512-gLbY3Le9Dxcb8KdpF0+SJr6EQ+hFGYFl6tVY8VxLPFDfUZC7BHFw+Vq7bM5lE9DwWPfx4vMWWTLGXgpc0mAYyQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.0.tgz", + "integrity": "sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/visitor-keys": "5.59.6" + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -908,25 +1093,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.6.tgz", - "integrity": "sha512-A4tms2Mp5yNvLDlySF+kAThV9VTBPCvGf0Rp8nl/eoDX9Okun8byTKoj3fJ52IJitjWOk0fKPNQhXEB++eNozQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.0.tgz", + "integrity": "sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.59.6", - "@typescript-eslint/utils": "5.59.6", + "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/utils": "6.18.0", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -935,12 +1120,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.6.tgz", - "integrity": "sha512-tH5lBXZI7T2MOUgOWFdVNUILsI02shyQvfzG9EJkoONWugCG77NDDa1EeDGw7oJ5IvsTAAGVV8I3Tk2PNu9QfA==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.0.tgz", + "integrity": "sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -948,21 +1133,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.6.tgz", - "integrity": "sha512-vW6JP3lMAs/Tq4KjdI/RiHaaJSO7IUsbkz17it/Rl9Q+WkQ77EOuOnlbaU8kKfVIOJxMhnRiBG+olE7f3M16DA==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.0.tgz", + "integrity": "sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/visitor-keys": "5.59.6", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -974,53 +1160,87 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/@typescript-eslint/utils": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.6.tgz", - "integrity": "sha512-vzaaD6EXbTS29cVH0JjXBdzMt6VBlv+hE31XktDRMX1j3462wZCJa7VzO2AxXEXcIl8GQqZPcOPuW/Z1tZVogg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.0.tgz", + "integrity": "sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.6", - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/typescript-estree": "5.59.6", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.0", + "semver": "^7.5.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.6.tgz", - "integrity": "sha512-zEfbFLzB9ETcEJ4HZEEsCR9HHeNku5/Qw1jSS5McYJv5BR+ftYXwFFAH5Al+xkGaZEqowMwl7uoJjQb1YSPF8Q==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.0.tgz", + "integrity": "sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.6", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "6.18.0", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1039,9 +1259,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", "dev": true, "engines": { "node": ">=0.4.0" @@ -1089,7 +1309,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -1098,7 +1317,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -1161,6 +1379,15 @@ "node": ">=8" } }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1177,13 +1404,12 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -1205,9 +1431,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", "dev": true, "funding": [ { @@ -1217,13 +1443,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -1266,9 +1496,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001488", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001488.tgz", - "integrity": "sha512-NORIQuuL4xGpIy6iCCQGN4iFjlBXtfKWIenlUuyZJumLRIindLb7wXM+GO8erEhb7vXfcnf4BAg2PrSDN5TNLQ==", + "version": "1.0.30001574", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001574.tgz", + "integrity": "sha512-BtYEK4r/iHt/txm81KBudCUcTy7t+s9emrIaHqjYurQ10x71zJ5VQ9x1dYPcz/b+pKSp4y/v1xSI67A+LzpNyg==", "dev": true, "funding": [ { @@ -1285,6 +1515,24 @@ } ] }, + "node_modules/chai": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.0.tgz", + "integrity": "sha512-x9cHNq1uvkCdU+5xTkNh5WtgD4e4yDFCsp9jVc7N7qVeKeftv3gO/ZrviX5d+3ZfxdYnZXZYujjRInu1RogU6A==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1301,6 +1549,18 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -1353,7 +1613,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -1363,11 +1622,16 @@ "node": ">=12" } }, + "node_modules/code-block-writer": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-12.0.0.tgz", + "integrity": "sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==", + "dev": true + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -1378,8 +1642,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/commondir": { "version": "1.0.1", @@ -1419,11 +1682,6 @@ "node": ">= 8" } }, - "node_modules/crypto-js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", - "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1450,9 +1708,21 @@ "node": ">=0.10.0" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, @@ -1492,6 +1762,15 @@ "node": ">=8" } }, + "node_modules/dir-glob/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -1505,16 +1784,15 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.402", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.402.tgz", - "integrity": "sha512-gWYvJSkohOiBE6ecVYXkrDgNaUjo47QEKK0kQzmWyhkH+yoYiG44bwuicTGNSIQRG3WDMsWVZJLRnJnLNkbWvA==", + "version": "1.4.623", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.623.tgz", + "integrity": "sha512-lKoz10iCYlP1WtRYdh5MvocQPWVRoI7ysp6qf18bmeBgR8abE6+I2CsfyNKztRDZvhdWc+krKT6wS7Neg8sw3A==", "dev": true }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/es6-error": { "version": "4.1.1", @@ -1526,7 +1804,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } @@ -1544,27 +1821,28 @@ } }, "node_modules/eslint": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", - "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.41.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -1574,7 +1852,6 @@ "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", @@ -1584,9 +1861,8 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -1600,22 +1876,25 @@ } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1624,38 +1903,35 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=4.0" + "node": "*" } }, "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" }, @@ -1691,15 +1967,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -1712,7 +1979,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -1721,15 +1988,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -1746,9 +2004,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -1786,9 +2044,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -1861,12 +2119,13 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.9", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { @@ -1874,9 +2133,9 @@ } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, "node_modules/foreground-child": { @@ -1919,9 +2178,9 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -1945,11 +2204,19 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -1991,10 +2258,32 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2007,20 +2296,20 @@ } }, "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.0.tgz", + "integrity": "sha512-/1WM/LNHRAOH9lZta77uGbq0dAEQM+XjNesWwhlERDVenqothRbnzTrL3/LrIoEPPjeUHC3vrS6TwoyxeHs7MQ==", "dev": true, "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "@sindresorhus/merge-streams": "^1.0.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2032,12 +2321,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -2094,9 +2377,9 @@ "dev": true }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "dev": true, "engines": { "node": ">= 4" @@ -2152,6 +2435,15 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/install": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/install/-/install-0.13.0.tgz", + "integrity": "sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -2177,7 +2469,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -2267,9 +2558,9 @@ "dev": true }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "engines": { "node": ">=8" @@ -2303,9 +2594,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -2329,17 +2620,32 @@ } }, "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "dependencies": { "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", + "make-dir": "^4.0.0", "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/istanbul-lib-source-maps": { @@ -2357,9 +2663,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -2399,6 +2705,12 @@ "node": ">=4" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -2428,6 +2740,15 @@ "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-6.2.0.tgz", "integrity": "sha512-1IynUYEc/HAwxhi3WDpIpxJbZpMCvvrrmZVqvj9EhpvbH8lls7HhdhiByjL7DkAaWlLIzpC0Xc/VPvy/UxLNjA==" }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2484,6 +2805,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -2509,9 +2839,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -2546,15 +2876,33 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mocha": { @@ -2597,15 +2945,6 @@ "url": "https://opencollective.com/mochajs" } }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/mocha/node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -2668,14 +3007,6 @@ "node": ">=10" } }, - "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "engines": { - "node": "*" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -2700,12 +3031,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -2719,9 +3044,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.11.tgz", - "integrity": "sha512-+M0PwXeU80kRohZ3aT4J/OnR+l9/KD2nVLNNoRgFtnf+umQVFdGBAO2N8+nCnEi0xlh/Wk3zOGC+vNNx+uM79Q==", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, "node_modules/normalize-path": { @@ -2733,93 +3058,3060 @@ "node": ">=0.10.0" } }, - "node_modules/nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "node_modules/npm": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.2.5.tgz", + "integrity": "sha512-lXdZ7titEN8CH5YJk9C/aYRU9JeDxQ4d8rwIIDsvH3SMjLjHTukB2CFstMiB30zXs4vCrPN2WH6cDq1yHBeJAw==", + "bundleDependencies": [ + "@isaacs/string-locale-compare", + "@npmcli/arborist", + "@npmcli/config", + "@npmcli/fs", + "@npmcli/map-workspaces", + "@npmcli/package-json", + "@npmcli/promise-spawn", + "@npmcli/run-script", + "@sigstore/tuf", + "abbrev", + "archy", + "cacache", + "chalk", + "ci-info", + "cli-columns", + "cli-table3", + "columnify", + "fastest-levenshtein", + "fs-minipass", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmhook", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minimatch", + "minipass", + "minipass-pipeline", + "ms", + "node-gyp", + "nopt", + "normalize-package-data", + "npm-audit-report", + "npm-install-checks", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "npmlog", + "p-map", + "pacote", + "parse-conflict-json", + "proc-log", + "qrcode-terminal", + "read", + "semver", + "spdx-expression-parse", + "ssri", + "strip-ansi", + "supports-color", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which", + "write-file-atomic" + ], "dev": true, "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^7.2.1", + "@npmcli/config": "^8.0.2", + "@npmcli/fs": "^3.1.0", + "@npmcli/map-workspaces": "^3.0.4", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.2", + "@sigstore/tuf": "^2.2.0", + "abbrev": "^2.0.0", + "archy": "~1.0.0", + "cacache": "^18.0.1", + "chalk": "^5.3.0", + "ci-info": "^4.0.0", + "cli-columns": "^4.0.0", + "cli-table3": "^0.6.3", + "columnify": "^1.6.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.3", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^7.0.1", + "ini": "^4.1.1", + "init-package-json": "^6.0.0", + "is-cidr": "^5.0.3", + "json-parse-even-better-errors": "^3.0.1", + "libnpmaccess": "^8.0.1", + "libnpmdiff": "^6.0.3", + "libnpmexec": "^7.0.4", + "libnpmfund": "^5.0.1", + "libnpmhook": "^10.0.0", + "libnpmorg": "^6.0.1", + "libnpmpack": "^6.0.3", + "libnpmpublish": "^9.0.2", + "libnpmsearch": "^7.0.0", + "libnpmteam": "^6.0.0", + "libnpmversion": "^5.0.1", + "make-fetch-happen": "^13.0.0", + "minimatch": "^9.0.3", + "minipass": "^7.0.4", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^10.0.1", + "nopt": "^7.2.0", + "normalize-package-data": "^6.0.0", + "npm-audit-report": "^5.0.0", + "npm-install-checks": "^6.3.0", + "npm-package-arg": "^11.0.1", + "npm-pick-manifest": "^9.0.0", + "npm-profile": "^9.0.0", + "npm-registry-fetch": "^16.1.0", + "npm-user-validate": "^2.0.0", + "npmlog": "^7.0.1", + "p-map": "^4.0.0", + "pacote": "^17.0.5", + "parse-conflict-json": "^3.0.1", + "proc-log": "^3.0.0", + "qrcode-terminal": "^0.12.0", + "read": "^2.1.0", + "semver": "^7.5.4", + "spdx-expression-parse": "^3.0.1", + "ssri": "^10.0.5", + "strip-ansi": "^7.1.0", + "supports-color": "^9.4.0", + "tar": "^6.2.0", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^5.0.0", + "which": "^4.0.0", + "write-file-atomic": "^5.0.1" }, "bin": { - "nyc": "bin/nyc.js" + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" }, "engines": { - "node": ">=8.9" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/nyc/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "node_modules/npm/node_modules/@colors/colors": { + "version": "1.5.0", "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" } }, - "node_modules/nyc/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/npm/node_modules/@isaacs/cliui": { + "version": "8.0.2", "dev": true, + "inBundle": true, + "license": "ISC", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/nyc/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } + "inBundle": true, + "license": "MIT" }, - "node_modules/nyc/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", "dev": true, + "inBundle": true, + "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/agent": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/arborist": { + "version": "7.2.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^3.1.0", + "@npmcli/installed-package-contents": "^2.0.2", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/metavuln-calculator": "^7.0.0", + "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/query": "^3.0.1", + "@npmcli/run-script": "^7.0.2", + "bin-links": "^4.0.1", + "cacache": "^18.0.0", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^7.0.1", + "json-parse-even-better-errors": "^3.0.0", + "json-stringify-nice": "^1.1.4", + "minimatch": "^9.0.0", + "nopt": "^7.0.0", + "npm-install-checks": "^6.2.0", + "npm-package-arg": "^11.0.1", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "npmlog": "^7.0.1", + "pacote": "^17.0.4", + "parse-conflict-json": "^3.0.0", + "proc-log": "^3.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.2", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^10.0.5", + "treeverse": "^3.0.0", + "walk-up-path": "^3.0.1" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/config": { + "version": "8.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/map-workspaces": "^3.0.2", + "ci-info": "^4.0.0", + "ini": "^4.1.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.5", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/disparity-colors": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ansi-styles": "^4.3.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/disparity-colors/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/@npmcli/fs": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/git": { + "version": "5.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0", + "read-package-json-fast": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cacache": "^18.0.0", + "json-parse-even-better-errors": "^3.0.0", + "pacote": "^17.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/query": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/@sigstore/bundle": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@sigstore/protobuf-specs": { + "version": "0.2.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@sigstore/sign": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^2.1.0", + "@sigstore/protobuf-specs": "^0.2.1", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@sigstore/tuf": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.1", + "tuf-js": "^2.1.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@tufjs/models": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/abbrev": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/abort-controller": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/npm/node_modules/agent-base": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/aggregate-error": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/npm/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/aproba": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/are-we-there-yet": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^4.1.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/base64-js": { + "version": "1.5.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/bin-links": { + "version": "4.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "read-cmd-shim": "^4.0.0", + "write-file-atomic": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/binary-extensions": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm/node_modules/buffer": { + "version": "6.0.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/npm/node_modules/builtins": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/npm/node_modules/cacache": { + "version": "18.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ci-info": { + "version": "4.0.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cidr-regex": { + "version": "4.0.3", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "ip-regex": "^5.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/clean-stack": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/cli-columns": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/cli-columns/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cli-columns/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cli-table3": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/npm/node_modules/clone": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/npm/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/color-support": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/npm/node_modules/columnify": { + "version": "1.6.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/npm/node_modules/columnify/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/columnify/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/common-ancestor-path": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/console-control-strings": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/cssesc": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/debug": { + "version": "4.3.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/defaults": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/delegates": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/diff": { + "version": "5.1.0", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/npm/node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/encoding": { + "version": "0.1.13", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/err-code": { + "version": "2.0.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/event-target-shim": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/events": { + "version": "3.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/npm/node_modules/exponential-backoff": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.16", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/npm/node_modules/foreground-child": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/fs-minipass": { + "version": "3.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/function-bind": { + "version": "1.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/npm/node_modules/gauge": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^4.0.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/glob": { + "version": "10.3.10", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/has-unicode": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/hasown": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/npm/node_modules/hosted-git-info": { + "version": "7.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/http-proxy-agent": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/ieee754": { + "version": "1.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/npm/node_modules/ignore-walk": { + "version": "6.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/npm/node_modules/indent-string": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ini": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/init-package-json": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^11.0.0", + "promzard": "^1.0.0", + "read": "^2.0.0", + "read-package-json": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/ip": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/ip-regex": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/is-cidr": { + "version": "5.0.3", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "cidr-regex": "4.0.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/is-core-module": { + "version": "2.13.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/npm/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/is-lambda": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/jackspeak": { + "version": "2.3.6", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff-apply": { + "version": "5.5.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmdiff": { + "version": "6.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/disparity-colors": "^3.0.0", + "@npmcli/installed-package-contents": "^2.0.2", + "binary-extensions": "^2.2.0", + "diff": "^5.1.0", + "minimatch": "^9.0.0", + "npm-package-arg": "^11.0.1", + "pacote": "^17.0.4", + "tar": "^6.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmexec": { + "version": "7.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/run-script": "^7.0.2", + "ci-info": "^4.0.0", + "npm-package-arg": "^11.0.1", + "npmlog": "^7.0.1", + "pacote": "^17.0.4", + "proc-log": "^3.0.0", + "read": "^2.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmfund": { + "version": "5.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^7.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmhook": { + "version": "10.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmorg": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmpack": { + "version": "6.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/run-script": "^7.0.2", + "npm-package-arg": "^11.0.1", + "pacote": "^17.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmpublish": { + "version": "9.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ci-info": "^4.0.0", + "normalize-package-data": "^6.0.0", + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7", + "sigstore": "^2.1.0", + "ssri": "^10.0.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmsearch": { + "version": "7.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmteam": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmversion": { + "version": "5.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^5.0.3", + "@npmcli/run-script": "^7.0.2", + "json-parse-even-better-errors": "^3.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/lru-cache": { + "version": "10.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "13.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/minipass": { + "version": "7.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-collect": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-fetch": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/npm/node_modules/minipass-flush": { + "version": "1.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-json-stream": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/npm/node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minizlib": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/mkdirp": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/negotiator": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "10.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/nopt": { + "version": "7.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/normalize-package-data": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-audit-report": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-bundled": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-install-checks": { + "version": "6.3.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "11.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-packlist": { + "version": "8.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^6.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-profile": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "16.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npmlog": { + "version": "7.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^4.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^5.0.0", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/p-map": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/pacote": { + "version": "17.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/parse-conflict-json": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/path-scurry": { + "version": "1.10.1", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/postcss-selector-parser": { + "version": "6.0.13", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/proc-log": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/process": { + "version": "0.11.10", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-call-limit": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-inflight": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/promise-retry": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/promzard": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "read": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/read": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "~1.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/read-package-json": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/read-package-json-fast": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/readable-stream": { + "version": "4.4.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/npm/node_modules/semver": { + "version": "7.5.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/set-blocking": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/sigstore": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^2.1.0", + "@sigstore/protobuf-specs": "^0.2.1", + "@sigstore/sign": "^2.1.0", + "@sigstore/tuf": "^2.1.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks": { + "version": "2.7.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/spdx-correct": { + "version": "3.2.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.3.0", + "dev": true, + "inBundle": true, + "license": "CC-BY-3.0" + }, + "node_modules/npm/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.16", + "dev": true, + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npm/node_modules/ssri": { + "version": "10.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/npm/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/supports-color": { + "version": "9.4.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "6.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "1.3.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/treeverse": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/tuf-js": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/unique-filename": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/unique-slug": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/walk-up-path": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/wcwidth": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/npm/node_modules/which": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/npm/node_modules/wide-align": { + "version": "1.1.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/npm/node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/write-file-atomic": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2911,17 +6203,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -2993,6 +6285,12 @@ "node": ">=8" } }, + "node_modules/package-json-type": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/package-json-type/-/package-json-type-1.0.3.tgz", + "integrity": "sha512-Bey4gdRuOwDbS8Fj1qA3/pTq5r8pqiI5E3tjSqCdhaLSsyGG364VFzXLTIexN5AaNGe/vgdBzLfoKdr7EVg2KQ==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3005,6 +6303,12 @@ "node": ">=6" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -3033,12 +6337,24 @@ } }, "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" } }, "node_modules/picocolors": { @@ -3145,9 +6461,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -3210,7 +6526,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3299,9 +6614,9 @@ ] }, "node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -3374,12 +6689,15 @@ "dev": true }, "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/source-map": { @@ -3418,7 +6736,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -3432,7 +6749,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -3487,6 +6803,28 @@ "node": ">=8" } }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -3514,10 +6852,32 @@ "node": ">=8.0" } }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-morph": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-21.0.1.tgz", + "integrity": "sha512-dbDtVdEAncKctzrVZ+Nr7kHpHkv+0JDJb2MjjpBaj8bFeCkePU9rHfMklmhuLFnpeq/EJZk2IhStY6NzqgjOkg==", + "dev": true, + "dependencies": { + "@ts-morph/common": "~0.22.0", + "code-block-writer": "^12.0.0" + } + }, "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -3567,26 +6927,11 @@ } }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -3599,6 +6944,15 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -3621,22 +6975,40 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "dev": true, "funding": [ { @@ -3708,15 +7080,6 @@ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "dev": true }, - "node_modules/word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/workerpool": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", @@ -3727,7 +7090,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -3762,7 +7124,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "engines": { "node": ">=10" } @@ -3773,11 +7134,18 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -3843,7 +7211,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, "engines": { "node": ">=12" } @@ -3868,6 +7235,14 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/nodejs/package.json b/nodejs/package.json index d1037b1..647ccbc 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -5,48 +5,120 @@ "url": "https://github.com/BetterCorp/better-service-base" }, "engines": { - "npm": ">=8.0.0", - "node": ">=16.0.0" + "npm": ">=9.0.0", + "node": ">=18.0.0" }, "scripts": { "dev": "nodemon --config ./nodemon.json", "start": "node lib/cli.js", - "build": "tsc", - "postinstall": "node ./postinstall.js", + "build": "rm -rfv ./lib && tsc && npm run testDev", + "build-release": "rm -rfv ./lib && tsc --p ./tsconfig-release.json && npm run build-release-tsconfig", + "build-release-tsconfig": "rm -fv ./development/tsconfig.json && cp ./tsconfig.json ./development/tsconfig.json", "lint": "eslint src/ --ext .js,.jsx,.ts,.tsx", "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js --reporter json --reporter lcov ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts' --reporter json --reporter-options output=junit.json", "testDev": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts'" }, "bin": { - "bsb": "lib/bootstrap.js" + "bsb": "lib/cli.js" }, "files": [ "lib/**/*", "development/**/*", - "tsconfig.json", - "postinstall.js", - "build-lib-clients.js", - "README.md" + "README.md", + "LICENSE" ], "main": "lib/index.js", - "version": "8.4.0-rc", + "version": "9.0.4-beta", + "bsb_project": true, + "bsbInit": { + "project": { + "dependencies": { + "@bettercorp/tools": "latest" + }, + "devDependencies": { + "@types/assert": "^1.5.6", + "@types/chai": "^4.3.3", + "@types/mocha": "^9.1.1", + "@types/node": "^18.7.16", + "@typescript-eslint/eslint-plugin": "^5.31.0", + "@typescript-eslint/parser": "^5.31.0", + "eslint": "^8.20.0", + "mocha": "^10.0.0", + "nyc": "^15.1.0", + "ts-node": "^10.9.1", + "typescript": "^4.7.4" + }, + "files": [ + "lib/**/*" + ], + "scripts": { + "build": "npm run build-plugin && npm run build-clients", + "build-plugin": "rm -rfv ./lib && tsc", + "build-clients": "node node_modules/@bettercorp/service-base/build-lib-clients.js", + "dev": "nodemon --config node_modules/@bettercorp/service-base/development/nodemon.json", + "start": "ts-node node_modules/@bettercorp/service-base/lib/cli.js", + "lint": "eslint src/ --ext .js,.jsx,.ts,.tsx", + "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js --reporter json --reporter lcov ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts' --reporter json --reporter-options output=junit.json", + "testDev": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts'" + }, + "main": "lib/index.js" + }, + "gitignore": [ + "/lib", + "/node_modules", + "/sec.config.json", + "/junit.xml", + "/test-file-*", + "/dist-clients" + ], + "files": [ + { + "src": "build/tsconfig.json", + "dst": "tsconfig.json", + "canOverwrite": true + }, + { + "src": "build/eslintrc.js", + "dst": ".eslintrc.js", + "canOverwrite": true + }, + { + "src": "build/eslintignore", + "dst": ".eslintignore", + "canOverwrite": true + } + ], + "directories": [ + "src", + "src/clients", + "src/plugins", + "src/shared", + "src/tests" + ] + }, "devDependencies": { - "@types/assert": "^1.5.6", - "@types/chai": "^4.3.3", - "@types/mocha": "^9.1.1", - "@types/node": "^18.7.16", - "@types/yargs": "^17.0.12", - "@typescript-eslint/eslint-plugin": "^5.31.0", - "@typescript-eslint/parser": "^5.31.0", - "eslint": "^8.20.0", - "mocha": "^10.0.0", + "@ts-ast-parser/core": "^0.6.3", + "@types/assert": "^1.5.10", + "@types/chai": "^4.3.11", + "@types/mocha": "^10.0.6", + "@types/node": "^20.10.6", + "@types/yargs": "^17.0.32", + "@typescript-eslint/eslint-plugin": "^6.15.0", + "@typescript-eslint/parser": "^6.15.0", + "chai": "^4.3.10", + "eslint": "^8.56.0", + "install": "^0.13.0", + "mocha": "^10.2.0", + "npm": "^10.2.5", "nyc": "^15.1.0", - "ts-node": "^10.9.1", - "typescript": "^4.7.4", - "yargs": "^17.5.1" + "ts-morph": "^21.0.1", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" }, "dependencies": { - "@bettercorp/tools": "^2.0.20220714140658" - }, - "bsb_project": true + "@bettercorp/tools": "^3.7.0", + "yaml": "^2.3.4", + "yargs": "^17.7.2", + "zod": "^3.22.4" + } } diff --git a/nodejs/postinstall.js b/nodejs/postinstall.js deleted file mode 100644 index 378ede0..0000000 --- a/nodejs/postinstall.js +++ /dev/null @@ -1,37 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const process = require("process"); - -if (`${process.env.BSB_CONTAINER || ''}` !== '') return console.warn('Building in BSB container, not running default setup process.'); - -let cwd = process.cwd(); -let hardSetCWD = false; - -for (let argv of process.argv) { - if (argv.indexOf("--cwd=") === 0) { - cwd = argv.split("=")[1].trim(); - hardSetCWD = true; - } -} - -console.log("BSB Post Install: " + cwd); -if (fs.existsSync(path.join(cwd, "./.bsb.local"))) { - console.log("BSB Post Install: Ignore"); -} else { - console.log("BSB Post Install: Run"); - if (cwd.indexOf("/node_modules/") > 0 && hardSetCWD === false) { - console.log("BSB Post Install: Search - we`re in node_modules dir."); - const argSpl = cwd.indexOf('/') >= 0 ? '/' : '\\'; - cwd = cwd.split(`${argSpl}node_modules${argSpl}`)[0]; - console.log("BSB Post Install: Try " + cwd); - } - const bsbBase = path.join(cwd, "./node_modules/@bettercorp/service-base"); - if (!fs.existsSync(bsbBase)) { - console.log("BSB Post Install: Bypass - cannot find service-base."); - process.exit(0); - } - const installer = require(path.join(bsbBase, "./lib/postinstall.js")).default; - //console.log(fs.readdirSync("./build/")); - installer(cwd); - console.log("BSB Post Install: Complete"); -} diff --git a/nodejs/sec-config.yaml b/nodejs/sec-config.yaml new file mode 100644 index 0000000..c3975f4 --- /dev/null +++ b/nodejs/sec-config.yaml @@ -0,0 +1,23 @@ +default: + logging: + events: + rabbit: + plugin: events-rabbitMQ + package: "@bettercorp/bsb-rabbitmq" + enabled: false + services: + service-default0X: + plugin: service-default0 + enabled: true + config: + testa: 5 + testb: 6 + service-default1X: + plugin: service-default1 + enabled: true + service-default2X: + plugin: service-default2 + enabled: true + service-default3X: + plugin: service-default3 + enabled: true diff --git a/nodejs/src/ServiceBase.ts b/nodejs/src/ServiceBase.ts deleted file mode 100644 index e5fa452..0000000 --- a/nodejs/src/ServiceBase.ts +++ /dev/null @@ -1,3 +0,0 @@ -// import { IPluginLogger, LogMeta } from "./interfaces/logger"; -// import { LoggerBase } from "./logger/logger"; -// import { Plugins } from "./plugins/plugins"; diff --git a/nodejs/src/base/PluginEvents.ts b/nodejs/src/base/PluginEvents.ts new file mode 100644 index 0000000..56f2c68 --- /dev/null +++ b/nodejs/src/base/PluginEvents.ts @@ -0,0 +1,498 @@ +import { Readable } from "stream"; +import { DynamicallyReferencedMethodType } from "@bettercorp/tools/lib/Interfaces"; +import { BSBService, BSBServiceClient } from "./index"; +import { + ServiceEventsBase, + DEBUG_MODE, + DynamicallyReferencedMethodOnIEvents, + DynamicallyReferencedMethodEmitIEvents, + DynamicallyReferencedMethodEmitEARIEvents, +} from "../interfaces"; +import { SBEvents } from "../serviceBase"; + +export abstract class BSBPluginEvents { + public abstract onEvents: ServiceEventsBase; + public abstract emitEvents: ServiceEventsBase; + public abstract onReturnableEvents: ServiceEventsBase; + public abstract emitReturnableEvents: ServiceEventsBase; + public abstract onBroadcast: ServiceEventsBase; + public abstract emitBroadcast: ServiceEventsBase; +} + +export class PluginEvents< + onEvents = ServiceEventsBase, + emitEvents = ServiceEventsBase, + onReturnableEvents = ServiceEventsBase, + emitReturnableEvents = ServiceEventsBase, + onBroadcast = ServiceEventsBase, + emitBroadcast = ServiceEventsBase +> { + private events: SBEvents; + private service: BSBService | BSBServiceClient; + constructor( + mode: DEBUG_MODE, + events: SBEvents, + context: BSBService | BSBServiceClient + ) { + this.events = events; + this.service = context; + } + /** + * Listens for events that are emitted by other plugins + * Broadcast events are emitted and received by all plugins + * + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using broadcast events + * ```ts + * /// Plugin that emits a broadcast event + * await this.emitBroadcast('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a broadcast event + * await this.onBroadcast('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + * ``` + */ + public async onBroadcast( + ...args: DynamicallyReferencedMethodOnIEvents< + DynamicallyReferencedMethodType, + TA, + false + > + ): Promise { + const event = args.splice(0, 1)[0] as string; + await this.events.onBroadcast( + this.service, + this.service.pluginName, + event, + args[0] as unknown as (...args: any[]) => void | Promise + ); + } + /** + * Emits a broadcast event that is received by all plugins that are listening for that event + * + * @param event - The event to emit + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted + * + * @example + * Basic example of using broadcast events + * ```ts + * /// Plugin that emits a broadcast event + * await this.emitBroadcast('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a broadcast event + * await this.onBroadcast('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ + async emitBroadcast( + ...args: DynamicallyReferencedMethodEmitIEvents< + DynamicallyReferencedMethodType, + TA + > + ): Promise { + const event = args.splice(0, 1)[0] as string; + await this.events.emitBroadcast(this.service.pluginName, event, ...args); + } + + /** + * Listens for events that are emitted by other plugins (the first plugin to receive the event will handle it) + * + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using events + * ```ts + * /// Plugin that emits an event + * await this.emitEvent('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives an event + * await this.onEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ + public async onEvent( + ...args: DynamicallyReferencedMethodOnIEvents< + DynamicallyReferencedMethodType, + TA, + false + > + ): Promise { + const event = args.splice(0, 1)[0] as string; + await this.events.onEvent( + this.service, + this.service.pluginName, + event, + args[0] as unknown as (...args: any[]) => void | Promise + ); + } + /** + * Emits an event that is received by the first plugin that is listening for that event (depends on events service) + * + * @param event - The event to emit + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted + * + * @example + * Basic example of using events + * ```ts + * /// Plugin that emits an event + * await this.emitEvent('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives an event + * await this.onEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ + public async emitEvent( + ...args: DynamicallyReferencedMethodEmitIEvents< + DynamicallyReferencedMethodType, + TA + > + ): Promise { + const event = args.splice(0, 1)[0] as string; + await this.events.emitEvent(this.service.pluginName, event, ...args); + } + + /** + * Listens for events that are emitted by other plugins (the first plugin to receive the event will handle it) + * The serverId allows for the event to be handled by a specific plugin + * + * @param serverId - The server ID to listen for the event on + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using events + * ```ts + * /// Plugin that emits an event + * await this.emitEventSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives an event + * await this.onEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ + public async onEventSpecific( + serverId: string, + ...args: DynamicallyReferencedMethodOnIEvents< + DynamicallyReferencedMethodType, + TA, + false + > + ): Promise { + const event = args.splice(0, 1)[0] as string; + await this.events.onEventSpecific( + serverId, + this.service, + this.service.pluginName, + event, + args[0] as unknown as (...args: any[]) => void | Promise + ); + } + /** + * Emits an event that is received by the first plugin that is listening for that event (depends on events service) + * The serverId allows for the event to be handled by a specific plugin + * + * @param serverId - The server ID to emit the event on + * @param event - The event to emit + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted + * + * @example + * Basic example of using events + * ```ts + * /// Plugin that emits an event + * await this.emitEventSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives an event + * await this.onEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ + public async emitEventSpecific( + serverId: string, + ...args: DynamicallyReferencedMethodEmitIEvents< + DynamicallyReferencedMethodType, + TA + > + ): Promise { + const event = args.splice(0, 1)[0] as string; + await this.events.emitEventSpecific( + serverId, + this.service.pluginName, + event, + ...args + ); + } + + /** + * Listens for events and retuns a value to the plugin that emitted the event + * + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * - @returns The value to return to the plugin that emitted the event + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using returnable events + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturn('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a returnable event + * await this.onReturnableEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ + public async onReturnableEvent( + ...args: DynamicallyReferencedMethodOnIEvents< + DynamicallyReferencedMethodType, + TA, + true + > + ): Promise { + const event = args.splice(0, 1)[0] as string; + return await this.events.onReturnableEvent( + this.service, + this.service.pluginName, + event, + args[0] as unknown as (...args: any[]) => void | Promise + ); + } + /** + * Emits a returnable event that is received by the first plugin that is listening for that event (depends on events service) + * + * @param event - The event listen to + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted and the value has been returned + * + * @example + * Basic example of using returnable events + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturn('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a returnable event + * await this.onReturnableEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ + public async emitEventAndReturn( + ...args: DynamicallyReferencedMethodEmitEARIEvents< + DynamicallyReferencedMethodType, + TA, + true //, + //false + > + ): Promise< + DynamicallyReferencedMethodEmitEARIEvents< + DynamicallyReferencedMethodType, + TA, + false + > + > { + const event = args.splice(0, 1)[0] as string; + const timeoutSeconds = + args.length > 0 ? (args.splice(0, 1)[0] as number) : 5; + return await this.events.emitEventAndReturn( + this.service.pluginName, + event, + timeoutSeconds, + ...args + ); + } + + /** + * Listens for events and retuns a value to the plugin that emitted the event + * The serverId allows for the event to be handled by a specific plugin + * + * @param serverId - The server ID to listen for the event on + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using returnable events + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturnSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a returnable event + * await this.onReturnableEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ + public async onReturnableEventSpecific( + serverId: string, + ...args: DynamicallyReferencedMethodOnIEvents< + DynamicallyReferencedMethodType, + TA, + true + > + ): Promise { + const event = args.splice(0, 1)[0] as string; + return await this.events.onReturnableEventSpecific( + serverId, + this.service, + this.service.pluginName, + event, + args[0] as unknown as (...args: any[]) => void | Promise + ); + } + /** + * Emits a returnable event that is received by the first plugin that is listening for that event (depends on events service) + * The serverId allows for the event to be handled by a specific plugin + * + * @param serverId - The server ID to emit the event on + * @param event - The event emit + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted and the value has been returned + * + * @example + * Basic example of using returnable events + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturnSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a returnable event + * await this.onReturnableEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ + public async emitEventAndReturnSpecific< + TA extends keyof emitReturnableEvents + >( + serverId: string, + ...args: DynamicallyReferencedMethodEmitEARIEvents< + DynamicallyReferencedMethodType, + TA, + true /*, + false*/ + > + ): Promise< + DynamicallyReferencedMethodEmitEARIEvents< + DynamicallyReferencedMethodType, + TA, + false + > + > { + const event = args.splice(0, 1)[0] as string; + const timeoutSeconds = + args.length > 0 ? (args.splice(0, 1)[0] as number) : 5; + return await this.events.emitEventAndReturnSpecific( + serverId, + this.service.pluginName, + event, + timeoutSeconds, + ...args + ); + } + + /** + * Gets a stream ID for another plugin to stream data to it. + * + * @param listener - Function that is called when the stream is received + * @param timeoutSeconds - How long to wait for the stream to be fully received before timing out + * @returns The stream ID that the other plugin should use to stream data to this plugin + * + * @example + * Basic example of using streams + * ```ts + * /// Plugin that receives a stream + * let streamId = await this.receiveStream( + * async (err: Error | null, stream: Readable) => { + * pipeline(stream, fs.createWriteStream('./fileout.txt'), (errf) => { + * if (errf) throw errf; + * }); + * }, + * 5 // seconds + * ); + * /// Send stream ID to other plugin + * /// you can use emitEventAndReturn to send the stream ID to the other plugin and await for the stream to finish + * + * /// Plugin that sends a stream + * /// This would listen to the event that the other plugin emits + * await this.sendStream(streamId, fs.createReadStream('./filein.txt')); + * /// and then returns OK to the other plugin + * ``` + */ + public async receiveStream( + event: string, + listener: { (error: Error | null, stream: Readable): Promise }, + timeoutSeconds?: number + ): Promise { + return await this.events.receiveStream( + this.service, + this.service.pluginName, + event, + listener, + timeoutSeconds + ); + } + + /** + * Sends a stream to another plugin + * + * @param streamId - The stream ID to stream data too + * @param stream - The stream to send + * @returns Promise that resolves when the stream has been fully sent + * + * @example + * Basic example of using streams + * ```ts + * /// Plugin that receives a stream + * let streamId = await this.receiveStream( + * async (err: Error | null, stream: Readable) => { + * pipeline(stream, fs.createWriteStream('./fileout.txt'), (errf) => { + * if (errf) throw errf; + * }); + * }, + * 5 // seconds + * ); + * /// Send stream ID to other plugin + * /// you can use emitEventAndReturn to send the stream ID to the other plugin and await for the stream to finish + * + * /// Plugin that sends a stream + * /// This would listen to the event that the other plugin emits + * await this.sendStream(streamId, fs.createReadStream('./filein.txt')); + * /// and then returns OK to the other plugin + * ``` + */ + public async sendStream( + event: string, + streamId: string, + stream: Readable + ): Promise { + return await this.events.sendStream( + this.service.pluginName, + event, + streamId, + stream + ); + } +} + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBPluginEventsRef extends BSBPluginEvents { + public onEvents: ServiceEventsBase = {}; + public emitEvents: ServiceEventsBase = {}; + public onReturnableEvents: ServiceEventsBase = {}; + public emitReturnableEvents: ServiceEventsBase = {}; + public onBroadcast: ServiceEventsBase = {}; + public emitBroadcast: ServiceEventsBase = {}; +} diff --git a/nodejs/src/base/PluginLogger.ts b/nodejs/src/base/PluginLogger.ts new file mode 100644 index 0000000..0b33140 --- /dev/null +++ b/nodejs/src/base/PluginLogger.ts @@ -0,0 +1,42 @@ +import { SBLogging } from "../serviceBase"; +import { DEBUG_MODE, SmartLogMeta, IPluginLogger } from "../interfaces"; + +export class PluginLogger implements IPluginLogger { + private logging: SBLogging; + private pluginName: string; + private canDebug = false; + constructor(mode: DEBUG_MODE, plugin: string, logging: SBLogging) { + this.logging = logging; + this.pluginName = plugin; + if (mode !== "production") { + this.canDebug = true; + } + } + public debug(message: T, ...meta: SmartLogMeta): void { + if (this.canDebug) + this.logging.logBus.emit("debug", this.pluginName, message, meta[0]); + } + public reportStat(key: string, value: number): void { + this.logging.logBus.emit("reportStat", this.pluginName, key, value); + } + public reportTextStat( + message: T, + ...meta: SmartLogMeta + ): void { + this.logging.logBus.emit( + "reportTextStat", + this.pluginName, + message, + meta[0] + ); + } + public info(message: T, ...meta: SmartLogMeta): void { + this.logging.logBus.emit("info", this.pluginName, message, meta[0]); + } + public warn(message: T, ...meta: SmartLogMeta): void { + this.logging.logBus.emit("warn", this.pluginName, message, meta[0]); + } + public error(message: T, ...meta: SmartLogMeta): void { + this.logging.logBus.emit("error", this.pluginName, message, meta[0]); + } +} diff --git a/nodejs/src/base/base.ts b/nodejs/src/base/base.ts new file mode 100644 index 0000000..5a5f228 --- /dev/null +++ b/nodejs/src/base/base.ts @@ -0,0 +1,175 @@ +import { DEBUG_MODE, IPluginLogger } from "../interfaces"; +import { SBLogging } from "../serviceBase"; +import { BSBReferenceConfigType, PluginLogger } from "./index"; + +export interface MainBaseConfig { + appId: string; + mode: DEBUG_MODE; + pluginName: string; + cwd: string; + pluginCwd: string; +} +export abstract class MainBase { + /** + * The unique app id of the app that is running + * @readonly + * @type {string} + */ + protected readonly appId: string = "tbd"; + + /** + * The mode the app is running in + * @readonly + * @type {DEBUG_MODE} + * @example production (production mode - no debug) + * @example production-debug (production mode - debug) + * @example development (development mode - debug) + */ + protected readonly mode: DEBUG_MODE = "development"; + /** + * The current working directory of the app + */ + protected readonly cwd: string; + /** + * The current working directory of the plugin + */ + protected readonly pluginCwd: string; + /** + * The name of the plugin + * This is also the mapped name, or the name defined in the config rather than it's original defined name + */ + public readonly pluginName!: string; + + constructor(config: MainBaseConfig) { + this.appId = config.appId; + this.mode = config.mode; + if (config.pluginName !== "") this.pluginName = config.pluginName; + this.cwd = config.cwd; + this.pluginCwd = config.pluginCwd; + } + + /** + * Dispose + * Optional function to be called when the plugin is being disposed + * + * @example dispose?(): void; //to not use it + * @example dispose() { your code here }; + */ + dispose?(): void; +} + +export abstract class Base extends MainBase { + constructor(config: MainBaseConfig) { + super(config); + } + + /** + * Dispose + * Optional function to be called when the plugin is being disposed + * + * @example dispose?(): void; //to not use it + * @example dispose() { your code here }; + */ + abstract dispose?(): void; + + /** + * Init + * Optional function to be called when the plugin is being initialized + * Can be sync or async + * + * @example init?(): void; //to not use it + * @example init() { your code here }; + * @example async init() { await your code here }; + */ + abstract init?(): Promise | void; + + /** + * Run + * Optional function to be called when the plugin is being run + * Can be sync or async + * + * @example run?(): void; //to not use it + * @example run() { your code here }; + * @example async run() { await your code here }; + */ + abstract run?(): Promise | void; +} + +export type ConfigPropertyTypeSafe< + ReferencedConfig extends BSBReferenceConfigType +> = ReferencedConfig extends undefined + ? undefined + : ReferencedConfig extends null + ? undefined + : ReferencedConfig; + +export interface BaseWithConfigConfig< + ReferencedConfig extends BSBReferenceConfigType +> extends MainBaseConfig { + config: ConfigPropertyTypeSafe; +} + +// used by logging plugins (does not need events or logging since logging logs its own logs) +export abstract class BaseWithConfig< + ReferencedConfig extends BSBReferenceConfigType +> extends Base { + /** + * The config of the plugin + * @type {PluginConfig} + * @readonly + */ + protected readonly config: ConfigPropertyTypeSafe; + + constructor(config: BaseWithConfigConfig) { + super(config); + this.config = config.config; + } +} + +export interface BaseWithLoggingConfig extends MainBaseConfig { + sbLogging: SBLogging; +} +// used by config plugins (does not need events) +export abstract class BaseWithLogging extends Base { + protected log: IPluginLogger; + //protected createNewLogger: { (plugin: string): IPluginLogger }; + + constructor(config: BaseWithLoggingConfig) { + super(config); + this.log = new PluginLogger( + config.mode, + config.pluginName, + config.sbLogging + ); + /*this.createNewLogger = (plugin: string) => + new PluginLogger(mode, `${pluginName}-${plugin}`, sbLogging);*/ + } +} + +export interface BaseWithLoggingAndConfigConfig< + ReferencedConfig extends BSBReferenceConfigType +> extends BaseWithLoggingConfig, + BaseWithConfigConfig {} + +// used by events plugins (does not need events) +export abstract class BaseWithLoggingAndConfig< + ReferencedConfig extends BSBReferenceConfigType +> extends BaseWithConfig { + protected log: IPluginLogger; + protected createNewLogger: { (plugin: string): IPluginLogger }; + + constructor(config: BaseWithLoggingAndConfigConfig) { + super(config); + this.log = new PluginLogger( + config.mode, + config.pluginName, + config.sbLogging + ); + this.createNewLogger = (plugin: string) => + new PluginLogger( + config.mode, + `${config.pluginName}-${plugin}`, + config.sbLogging + ); + } +} diff --git a/nodejs/src/base/config.ts b/nodejs/src/base/config.ts new file mode 100644 index 0000000..9889fa1 --- /dev/null +++ b/nodejs/src/base/config.ts @@ -0,0 +1,97 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { + LoggingConfig, + EventsConfig, + PluginDefition, + PluginType, +} from "../interfaces"; +import { + BaseWithLogging, + BaseWithLoggingConfig, + BSB_ERROR_METHOD_NOT_IMPLEMENTED, +} from "./index"; + +export interface BSBConfigConstructor extends BaseWithLoggingConfig {} + +/** + * Abstract class representing the configuration for the Better Service Base. + * @template T - The type of config for the plugin + */ +export abstract class BSBConfig extends BaseWithLogging { + constructor(config: BSBConfigConstructor) { + super(config); + } + /** + * This function is never used for events plugins. + * @ignore @deprecated + */ + public run() {} + + /** + * Returns the logging plugins configuration. + * @returns Promise resolving to an object containing the logging configuration for each plugin. + */ + abstract getLoggingPlugins(): Promise>; + + /** + * Returns the events plugins configuration. + * @returns Promise resolving to an object containing the events configuration for each plugin. + */ + abstract getEventsPlugins(): Promise>; + + /** + * Returns the service plugins configuration. + * @returns Promise resolving to an object containing the configuration for each plugin. + */ + abstract getServicePlugins(): Promise>; + + /** + * Returns a mapped plugin name and whether the plugin is enabled or not + * @returns string of the plugin name and if it is enabled or not + */ + abstract getServicePluginDefinition( + pluginName: string + ): Promise<{ name: string; enabled: boolean }>; + + /** + * Returns the configuration for a specific plugin. + * @template T - The type of the configuration object. + * @param plugin - The name of the plugin to retrieve the configuration for. + * @returns Promise resolving to the configuration object for the specified plugin, or null if the plugin is not found. + */ + abstract getPluginConfig( + pluginType: PluginType, + plugin: string + ): Promise; +} + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBConfigRef extends BSBConfig { + getLoggingPlugins(): Promise> { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBConfigRef", "getLoggingPlugins"); + } + getEventsPlugins(): Promise> { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBConfigRef", "getEventsPlugins"); + } + getServicePlugins(): Promise> { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBConfigRef", "getServicePlugins"); + } + getPluginConfig( + pluginType: PluginType, + plugin: string + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBConfigRef", "getPluginConfig"); + } + getServicePluginDefinition( + pluginName: string + ): Promise<{ name: string; enabled: boolean }> { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED( + "BSBConfigRef", + "getServicePluginName" + ); + } + dispose?(): void; + init?(): void; +} diff --git a/nodejs/src/base/errorMessages.ts b/nodejs/src/base/errorMessages.ts new file mode 100644 index 0000000..2c725d3 --- /dev/null +++ b/nodejs/src/base/errorMessages.ts @@ -0,0 +1,39 @@ +import { LogFormatter } from "./index"; +import { LogMeta } from "../interfaces"; + +export class BSBError extends Error { + constructor(errorKey: string, message: T, meta: LogMeta); + constructor(message: T, meta: LogMeta); + constructor( + errorKeyOrMessage: string | T, + messageOrMeta: T | LogMeta, + meta?: LogMeta + ) { + const formatter = new LogFormatter(); + if (meta === undefined && typeof messageOrMeta === "object") { + super(formatter.formatLog(errorKeyOrMessage, messageOrMeta)); + this.name = "BSBError-Generic"; + } else if (typeof messageOrMeta === "string" && typeof meta === "object") { + super(formatter.formatLog(messageOrMeta, meta)); + this.name = "BSBError-" + errorKeyOrMessage; + } + } + + public toString(): string { + return this.message; + } +} + +export function BSB_ERROR_METHOD_NOT_IMPLEMENTED( + className: string, + method: string +) { + return new BSBError( + "INCORRECT_REFERENCE", + "Method not implemented: {class}.{method}", + { + class: className, + method: method, + } + ); +} diff --git a/nodejs/src/base/events.ts b/nodejs/src/base/events.ts new file mode 100644 index 0000000..7b33abc --- /dev/null +++ b/nodejs/src/base/events.ts @@ -0,0 +1,254 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { Readable } from "stream"; +import { + BaseWithLoggingAndConfig, + BaseWithLoggingAndConfigConfig, + BSBReferencePluginConfigType, + BSBReferencePluginConfigDefinition, + BSB_ERROR_METHOD_NOT_IMPLEMENTED, +} from "./index"; + +export interface BSBEventsConstructor< + ReferencedConfig extends BSBReferencePluginConfigType = any +> extends BaseWithLoggingAndConfigConfig< + ReferencedConfig extends null + ? null + : BSBReferencePluginConfigDefinition + > {} + +export abstract class BSBEvents< + ReferencedConfig extends BSBReferencePluginConfigType = any +> extends BaseWithLoggingAndConfig< + ReferencedConfig extends null + ? null + : BSBReferencePluginConfigDefinition +> { + constructor(config: BSBEventsConstructor) { + super(config); + } + + /** + * This function is never used for events plugins. + * @ignore @deprecated + */ + public run() {} + + /** + * Listens for events that are emitted by other plugins + * Broadcast events are emitted and received by all plugins + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param pluginName - The name of the plugin that is being listened to + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ + public abstract onBroadcast( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise; + + /** + * Emits an event that is received by all plugins + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param pluginName - The name of the plugin that is emitting the event + * @param event - The event to emit + * @param args - The arguments to pass to the event listener + * @returns Promise that resolves when the event has been emitted + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ + public abstract emitBroadcast( + pluginName: string, + event: string, + args: Array + ): Promise; + + /** + * Listens for events that are emitted by other plugins + * Events are emitted and received by a single plugin + * Make sure to use the built in tests + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param pluginName - The name of the plugin that is being listened to + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ + public abstract onEvent( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise; + + /** + * Emits an event that is received by a single plugin + * Make sure to use the built in tests + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param pluginName - The name of the plugin that is emitting the event + * @param event - The event to emit + * @param args - The arguments to pass to the event listener + * @returns Promise that resolves when the event has been emitted + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ + public abstract emitEvent( + pluginName: string, + event: string, + args: Array + ): Promise; + + /** + * Listens for events that are emitted by other plugins and return a value + * Events are emitted and received by a single plugin + * Make sure to use the built in tests + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param pluginName - The name of the plugin that is being listened to + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ + public abstract onReturnableEvent( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise; + + /** + * Emits an event that is received by a single plugin and returns a value + * Make sure to use the built in tests + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param pluginName - The name of the plugin that is emitting the event + * @param event - The event to emit + * @param timeoutSeconds - The number of seconds to wait for the value to be returned + * @param args - The arguments to pass to the event listener + * @returns Promise that resolves when the event has been emitted and the value has been returned + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ + public abstract emitEventAndReturn( + pluginName: string, + event: string, + timeoutSeconds: number, + args: Array + ): Promise; + + /** + * Sets up a receive stream to receive a stream from another plugin + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param listener - The function to call when the stream is received + * @param timeoutSeconds - The number of seconds to wait for the stream to be received + * @returns Promise that resolves with the stream id that can be used to stream data to the listener + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ + public abstract receiveStream( + event: string, + listener: (error: Error | null, stream: Readable) => Promise, + timeoutSeconds?: number + ): Promise; + + /** + * Sets up a send stream to send a stream to another plugin that created a receive stream + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param streamId - The id of the stream to send data to + * @param stream - The stream to send data from + * @returns Promise that resolves when the stream has been sent + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ + public abstract sendStream( + event: string, + streamId: string, + stream: Readable + ): Promise; +} + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBEventsRef extends BSBEvents { + public onBroadcast( + pluginName: string, + event: string, + listener: (args: any[]) => Promise + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "onBroadcast"); + } + public emitBroadcast( + pluginName: string, + event: string, + args: any[] + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "emitBroadcast"); + } + public onEvent( + pluginName: string, + event: string, + listener: (args: any[]) => Promise + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "onEvent"); + } + public emitEvent( + pluginName: string, + event: string, + args: any[] + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "emitEvent"); + } + public onReturnableEvent( + pluginName: string, + event: string, + listener: (args: any[]) => Promise + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "onReturnableEvent"); + } + public emitEventAndReturn( + pluginName: string, + event: string, + timeoutSeconds: number, + args: any[] + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED( + "BSBEventsRef", + "emitEventAndReturn" + ); + } + public receiveStream( + event: string, + listener: (error: Error | null, stream: Readable) => Promise, + timeoutSeconds?: number | undefined + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "receiveStream"); + } + public sendStream( + event: string, + streamId: string, + stream: Readable + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "sendStream"); + } + dispose?(): void; + init?(): void | Promise; +} diff --git a/nodejs/src/base/functions.ts b/nodejs/src/base/functions.ts new file mode 100644 index 0000000..1918f43 --- /dev/null +++ b/nodejs/src/base/functions.ts @@ -0,0 +1,35 @@ +import { BSBError } from "./index"; + +type SmartFunctionCallFunc = { + [Symbol.toStringTag]?: string; + (...args: any[]): any; +}; +export async function SmartFunctionCallAsync( + context: any, + input: T | undefined, + ...params: Parameters +): Promise | void> { + if (typeof input !== "function") return; + if (typeof context !== "object") + throw new BSBError( + "INCORRECT_REFERENCE", + "SmartFunctionCallAsync: context is not an object" + ); + if (input[Symbol.toStringTag] === "AsyncFunction") { + return await input.call(context, ...params); + } + return input.call(context, ...params); +} +export function SmartFunctionCallSync( + context: any, + input: T | undefined, + ...params: Parameters +): ReturnType | void { + if (typeof input !== "function") return; + if (typeof context !== "object") + throw new BSBError( + "INCORRECT_REFERENCE", + "SmartFunctionCallSync: context is not an object" + ); + return input.call(context, ...params); +} diff --git a/nodejs/src/base/index.ts b/nodejs/src/base/index.ts new file mode 100644 index 0000000..c5cc759 --- /dev/null +++ b/nodejs/src/base/index.ts @@ -0,0 +1,11 @@ +export * from "./base"; +export * from "./config"; +export * from "./errorMessages"; +export * from "./events"; +export * from "./logFormatter"; +export * from "./logging"; +export * from "./PluginEvents"; +export * from "./PluginLogger"; +export * from "./service"; +export * from "./serviceClient"; +export * from "./pluginConfig"; diff --git a/nodejs/src/base/logFormatter.ts b/nodejs/src/base/logFormatter.ts new file mode 100644 index 0000000..9c42a06 --- /dev/null +++ b/nodejs/src/base/logFormatter.ts @@ -0,0 +1,50 @@ +import { Tools } from "@bettercorp/tools/lib/Tools"; +import { LogMeta, SafeLogData, UnsafeLogData } from "../interfaces"; + +export class LogFormatter { + private isUnsafeLogData(value: any): value is UnsafeLogData { + return Tools.isObject(value) && !Tools.isNullOrUndefined(value.safeValue); + } + private getSafeData(data: LogMeta, key: string) { + if (Tools.isNullOrUndefined(data)) return null; + const dataFromKeyVP = (data as Record)[ + key + ]; + if (this.isUnsafeLogData(dataFromKeyVP)) return dataFromKeyVP.safeValue; + return dataFromKeyVP; + } + private formatData(meta: any, key: string) { + const referencedVar = this.getSafeData(meta, key); + if (Tools.isNullOrUndefined(referencedVar)) return "*null/undefined*"; + if (Tools.isDate(referencedVar)) return referencedVar.toISOString(); + if (Tools.isString(referencedVar)) return referencedVar; + if (Tools.isArray(referencedVar)) + return (referencedVar as Array) + .map((x) => + Tools.isSimpleType(x) + ? Tools.isString(x) + ? x + : x.toString() + : JSON.stringify(x) + ) + .join(","); + /*if ( + Tools.isObject(referencedVar) && + Tools.isFunction(referencedVar.toString) + ) + return referencedVar.toString();*/ + return JSON.stringify(referencedVar); + } + public formatLog(message: T, meta?: LogMeta): string { + //console.log(`_${message}:${Tools.isObject(meta)}`); + if (!Tools.isObject(meta)) return message; + + const dataToParse = message.split("{"); + let outString = dataToParse[0]; + for (let i = 1; i < dataToParse.length; i++) { + const removedVar = dataToParse[i].split("}"); + outString += this.formatData(meta, removedVar[0]) + removedVar[1]; + } + return outString; + } +} diff --git a/nodejs/src/base/logging.ts b/nodejs/src/base/logging.ts new file mode 100644 index 0000000..1f33595 --- /dev/null +++ b/nodejs/src/base/logging.ts @@ -0,0 +1,191 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { LogMeta } from "../interfaces"; +import { + BaseWithConfig, + BaseWithConfigConfig, + BSB_ERROR_METHOD_NOT_IMPLEMENTED, + BSBReferencePluginConfigDefinition, + BSBReferencePluginConfigType, +} from "./index"; + +export interface BSBLoggingConstructor< + ReferencedConfig extends BSBReferencePluginConfigType = any +> extends BaseWithConfigConfig< + ReferencedConfig extends null + ? null + : BSBReferencePluginConfigDefinition + > {} + +export abstract class BSBLogging< + ReferencedConfig extends BSBReferencePluginConfigType = any +> extends BaseWithConfig< + ReferencedConfig extends null + ? null + : BSBReferencePluginConfigDefinition +> { + constructor(config: BSBLoggingConstructor) { + super(config); + } + + /** + * This function is never used for events plugins. + * @ignore @deprecated + */ + public run() {} + + /** + * Report stat + * Reports a value(number) to the logging system + * + * @param plugin - The name of the plugin that wants to report a stat + * @param key - The key of the stat to report + * @param value - The value of the stat to report + * @returns nothing + * + * @see BSB logging-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/logging-default | Default Logging Plugin} + */ + public abstract reportStat( + plugin: string, + key: string, + value: number + ): Promise | void; + + /** + * Report text stat + * Reports a value(string) to the logging system with additional information that is interpolateable + * Like a log, but for stats + * + * @param plugin - The name of the plugin that wants to report a stat + * @param message - The stat to report + * @param meta - Additional information to report with the stat + * @returns nothing + * + * @see BSB logging-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/logging-default | Default Logging Plugin} + */ + public abstract reportTextStat( + plugin: string, + message: T, + meta?: LogMeta + ): Promise | void; + + /** + * Debug + * Logs an debug message + * + * @param plugin - The name of the plugin that wants to log + * @param message - The message to log + * @param meta - Additional information to log with the message + * @returns nothing + * + * @see BSB logging-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/logging-default | Default Logging Plugin} + */ + public abstract debug( + plugin: string, + message: T, + meta?: LogMeta + ): Promise | void; + + /** + * Info + * Logs an info message + * + * @param plugin - The name of the plugin that wants to log + * @param message - The message to log + * @param meta - Additional information to log with the message + * @returns nothing + * + * @see BSB logging-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/logging-default | Default Logging Plugin} + */ + public abstract info( + plugin: string, + message: T, + meta?: LogMeta + ): Promise | void; + + /** + * Warn + * Logs an warn message + * + * @param plugin - The name of the plugin that wants to log + * @param message - The message to log + * @param meta - Additional information to log with the message + * @returns nothing + * + * @see BSB logging-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/logging-default | Default Logging Plugin} + */ + public abstract warn( + plugin: string, + message: T, + meta?: LogMeta + ): Promise | void; + + /** + * Error + * Logs an error message + * + * @param plugin - The name of the plugin that wants to log + * @param message - The message to log + * @param meta - Additional information to log with the message + * @returns nothing + * + * @see BSB logging-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/logging-default | Default Logging Plugin} + */ + public abstract error( + plugin: string, + message: T, + meta?: LogMeta + ): Promise | void; +} + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBLoggingRef extends BSBLogging { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public reportStat(plugin: string, key: string, value: number): void { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "reportStat"); + } + public reportTextStat( + plugin: string, + message: T, + meta?: LogMeta | undefined + ): void { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "reportTextStat"); + } + public debug( + plugin: string, + message: T, + meta?: LogMeta | undefined + ): void { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "debug"); + } + public info( + plugin: string, + message: T, + meta?: LogMeta | undefined + ): void { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "info"); + } + public warn( + plugin: string, + message: T, + meta?: LogMeta | undefined + ): void { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "warn"); + } + public error( + plugin: string, + message: T, + meta?: LogMeta | undefined + ): void { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "error"); + } + dispose?(): void; + init?(): void; +} diff --git a/nodejs/src/base/pluginConfig.ts b/nodejs/src/base/pluginConfig.ts new file mode 100644 index 0000000..4890c1e --- /dev/null +++ b/nodejs/src/base/pluginConfig.ts @@ -0,0 +1,95 @@ +import { z } from "zod"; +import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./index"; + +/** + * The definition of the config with zod validation + * @example + * const configDefinition = z.object({ + * a: z.string(), + * }); + */ +export type BSBPluginConfigType = z.ZodTypeAny | undefined; +export type BSBPluginConfigDefinition = BSBPluginConfig; + +/** + * Config migration handler, allows for config migrations when the plugin version changes or a new plugin setup is done + * @example simple version change and basic setup + * const configMigration = async (versionFrom: string | null, versionTo: string, existingConfig?: z.infer) => { + * if (versionFrom === null) { + * return { + * a: "a", + * }; + * } + * return { + * a: "b", + * }; + * @example basic setup and no version change handling + * const configMigration = async (versionFrom: string | null, versionTo: string, existingConfig?: z.infer) => { + * if (versionFrom === null || existingConfig === undefined) { + * return { + * a: "a", + * }; + * } + * return existingConfig; + */ +export type BSBConfigMigration = ( + versionFrom: string | null, + versionTo: string, + existingConfig?: z.infer> +) => Promise>>; + +export type BSBConfigDefintionReference< + T extends BSBPluginConfigType, + AS = undefined +> = T extends undefined ? AS : z.infer>; + +export type BSBReferenceConfigType = BSBPluginConfigType | null; +export type BSBReferencePluginConfigType = BSBPluginConfigDefinition | null; +export type BSBReferenceConfigDefinition< + ReferencedConfig extends BSBReferenceConfigType +> = ReferencedConfig extends null ? null : ReferencedConfig; +export type BSBReferencePluginConfigDefinition< + ReferencedConfig extends BSBReferencePluginConfigType +> = ReferencedConfig extends null + ? null + : ReferencedConfig extends BSBPluginConfigDefinition + ? z.infer + : null; + +export abstract class BSBPluginConfig< + MyPluginConfig extends Exclude | null = null +> { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + constructor(cwd: string, pluginCwd: string, pluginName: string) {} + public abstract validationSchema: MyPluginConfig; + /** + * Migrate the config from one version to another + * + * @todo Future feature - not implemented yet + * @todo write your migration code if you do make changes you'd like to have migratable + */ + public abstract migrate?( + toVersion: string, + fromVersion: string | null, + fromConfig: any | null + ): MyPluginConfig extends BSBPluginConfigType + ? z.infer + : null; +} + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBPluginConfigRef extends BSBPluginConfig { + public validationSchema = {}; + public migrate?( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + toVersion: string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + fromVersion: string | null, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + fromConfig: any + ) { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBPluginConfigRef", "migrate"); + } +} diff --git a/nodejs/src/base/service.ts b/nodejs/src/base/service.ts new file mode 100644 index 0000000..93c5d45 --- /dev/null +++ b/nodejs/src/base/service.ts @@ -0,0 +1,77 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { ServiceEventsBase } from "../interfaces"; +import { SBEvents } from "../serviceBase"; +import { + BaseWithLoggingAndConfig, + BaseWithLoggingAndConfigConfig, + BSBPluginEvents, + BSBPluginEventsRef, + PluginEvents, + BSBServiceClient, + BSBReferencePluginConfigType, + BSBReferencePluginConfigDefinition, +} from "./index"; + +export interface BSBServiceConstructor< + ReferencedConfig extends BSBReferencePluginConfigType = any +> extends BaseWithLoggingAndConfigConfig< + ReferencedConfig extends null + ? null + : BSBReferencePluginConfigDefinition + > { + sbEvents: SBEvents; +} + +export abstract class BSBService< + ReferencedConfig extends BSBReferencePluginConfigType = any, + Events extends BSBPluginEvents = BSBPluginEventsRef +> extends BaseWithLoggingAndConfig< + ReferencedConfig extends null + ? null + : BSBReferencePluginConfigDefinition +> { + public abstract readonly initBeforePlugins?: Array; + public abstract readonly initAfterPlugins?: Array; + public abstract readonly runBeforePlugins?: Array; + public abstract readonly runAfterPlugins?: Array; + public abstract readonly methods: ServiceEventsBase; + public readonly _virtual_internal_events: { + onEvents: Events["onEvents"]; + emitEvents: Events["emitEvents"]; + onReturnableEvents: Events["onReturnableEvents"]; + emitReturnableEvents: Events["emitReturnableEvents"]; + onBroadcast: Events["onBroadcast"]; + emitBroadcast: Events["emitBroadcast"]; + } = {} as any; + public readonly events: PluginEvents< + Events["onEvents"], + Events["emitEvents"], + Events["onReturnableEvents"], + Events["emitReturnableEvents"], + Events["onBroadcast"], + Events["emitBroadcast"] + >; + public _clients: Array = []; + + constructor(config: BSBServiceConstructor) { + super(config); + this.events = new PluginEvents(config.mode, config.sbEvents, this); + } +} + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBServiceRef extends BSBService { + public methods = {}; + public initBeforePlugins?: string[] | undefined; + public initAfterPlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + dispose?(): void; + init?(): void | Promise; + run?(): void | Promise; + constructor(config: BSBServiceConstructor) { + super(config); + } +} diff --git a/nodejs/src/base/serviceClient.ts b/nodejs/src/base/serviceClient.ts new file mode 100644 index 0000000..6efb92f --- /dev/null +++ b/nodejs/src/base/serviceClient.ts @@ -0,0 +1,68 @@ +import { + IPluginLogger, + DynamicallyReferencedMethodCallable, +} from "../interfaces"; +import { BSBService, BSBError, PluginEvents } from "./index"; +import { DynamicallyReferencedMethodType } from "@bettercorp/tools/lib/Interfaces"; + +export abstract class BSBServiceClient { + protected readonly log!: IPluginLogger; + protected readonly events!: PluginEvents< + Service["_virtual_internal_events"]["emitEvents"], + Service["_virtual_internal_events"]["onEvents"], + Service["_virtual_internal_events"]["emitReturnableEvents"], + Service["_virtual_internal_events"]["onReturnableEvents"], + Service["_virtual_internal_events"]["emitBroadcast"], + Service["_virtual_internal_events"]["onBroadcast"] + >; + public callMethod( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ...args: DynamicallyReferencedMethodCallable< + DynamicallyReferencedMethodType, + TA + > + ): DynamicallyReferencedMethodCallable< + DynamicallyReferencedMethodType, + TA, + false + > { + throw new BSBError( + "The plugin {plugin} is not enabled so you cannot call methods from it", + { + plugin: this.pluginName, + } + ); + } + constructor(context: BSBService) { + context._clients.push(this); + } + public abstract readonly pluginName: string; + public abstract readonly initBeforePlugins?: Array; + public abstract readonly initAfterPlugins?: Array; + public abstract readonly runBeforePlugins?: Array; + public abstract readonly runAfterPlugins?: Array; + + public abstract dispose?(): void; + public abstract init?(): Promise; + public abstract run?(): Promise; +} + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBServiceClientRef extends BSBServiceClient { + public pluginName: string = ""; + public initBeforePlugins?: string[] | undefined; + public initAfterPlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public dispose?(): void { + throw new Error("Method not implemented."); + } + public init?(): Promise { + throw new Error("Method not implemented."); + } + public run?(): Promise { + throw new Error("Method not implemented."); + } +} diff --git a/nodejs/src/cli.ts b/nodejs/src/cli.ts index 36b5aa9..2149e73 100644 --- a/nodejs/src/cli.ts +++ b/nodejs/src/cli.ts @@ -1,15 +1,9 @@ -import {ServiceBase} from "./serviceBase/serviceBase"; +import { ServiceBase } from "./serviceBase/serviceBase"; + const runApp = async () => { const CWD = process.env.APP_DIR || process.cwd(); - const SB = new ServiceBase(false, false, CWD); - await SB.setupSelf(); - await SB.setupPlugins(CWD, true); - await SB.setupConfig(); - await SB.setupLogger(); - await SB.setupEvents(); - await SB.setupServices(); - await SB.initPlugins(); - await SB.runPlugins(); + const SB = new ServiceBase(false, true, CWD); + await SB.init(); await SB.run(); }; -runApp(); \ No newline at end of file +runApp(); diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts new file mode 100644 index 0000000..829b6bc --- /dev/null +++ b/nodejs/src/client.ts @@ -0,0 +1,99 @@ +import { + BSBConfig, + BSBConfigConstructor, + BSBService, + BSBServiceClient, + BSBServiceConstructor, +} from "./base"; +import { + LoggingConfig, + EventsConfig, + PluginDefition, + PluginType, +} from "./interfaces"; +import { ServiceBase } from "./serviceBase"; +import { randomUUID } from "crypto"; + +export class SBClient { + private serviceBase: ServiceBase; + public client!: Client; + + private useDefaultConfigPlugin: boolean; + private configSetup: boolean = false; + constructor(useDefaultConfigPlugin: boolean = false) { + this.useDefaultConfigPlugin = useDefaultConfigPlugin; + const CWD = process.env.APP_DIR || process.cwd(); + this.serviceBase = new ServiceBase(false, true, CWD); + } + + public async addClient(client: typeof BSBServiceClient, ...args: any[]) { + if (!this.useDefaultConfigPlugin && !this.configSetup) { + this.configSetup = true; + this.serviceBase.setConfigPlugin( + "config-bsb-internal-client", + FakeServiceConfig + ); + } + const service = this.serviceBase.addService( + "service-bsb-internal-client-" + randomUUID(), + FakeServiceClient, + {} + ); + return new (client as any)(service, ...args); + } + + public async init() { + await this.serviceBase.init(); + } + public async run() { + await this.serviceBase.run(); + } +} + +export class FakeServiceClient extends BSBService { + public initBeforePlugins?: string[] | undefined; + public initAfterPlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public methods = {}; + dispose?(): void; + init?(): void | Promise { + throw new Error("Method not implemented."); + } + run?(): void | Promise { + throw new Error("Method not implemented."); + } + constructor(config: BSBServiceConstructor) { + super(config); + } +} + +export class FakeServiceConfig extends BSBConfig { + constructor(config: BSBConfigConstructor) { + super(config); + } + async getLoggingPlugins(): Promise> { + return {}; + } + async getEventsPlugins(): Promise> { + return {}; + } + async getServicePlugins(): Promise> { + return {}; + } + async getServicePluginDefinition( + pluginName: string + ): Promise<{ name: string; enabled: boolean }> { + return { name: pluginName, enabled: false }; + } + async getPluginConfig( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + pluginType: PluginType, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + plugin: string + ): Promise { + return null; + } + dispose?(): void; + init?(): void; +} diff --git a/nodejs/src/config/config.ts b/nodejs/src/config/config.ts deleted file mode 100644 index 805dba4..0000000 --- a/nodejs/src/config/config.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Tools } from "@bettercorp/tools/lib/Tools"; -import { - DeploymentProfile, - IPluginConfig, - IConfig, -} from "../interfaces/config"; -import { IPluginLogger } from "../interfaces/logger"; -import { DefaultBase } from '../interfaces/base'; -import { ErrorMessages } from '../interfaces/static'; - -export class ConfigBase -extends DefaultBase implements IConfig { - readonly _deploymentProfile: string; - constructor(pluginName: string, cwd: string, pluginCwd: string, log: IPluginLogger, deploymentProfile: string) { - super(pluginName, cwd, pluginCwd, log); - this._deploymentProfile = deploymentProfile; - } - async createAppConfig(listOfKnownPlugins: Array): Promise { - throw ErrorMessages.ConfigNotImplementedProperly; - } - async migrateAppPluginConfig( - pluginName: string, - mappedPluginName: string, - config: IPluginConfig - ): Promise { - throw ErrorMessages.ConfigNotImplementedProperly; - } - public async getAppMappedPluginConfig( - mappedPluginName: string - ): Promise { - throw ErrorMessages.ConfigNotImplementedProperly; - } - public async getAppPluginDeploymentProfile( - pluginName: string - ): Promise { - throw ErrorMessages.ConfigNotImplementedProperly; - } - public async getAppMappedPluginDeploymentProfile( - mappedPluginName: string - ): Promise { - throw ErrorMessages.ConfigNotImplementedProperly; - } - public async getAppPluginMappedName(pluginName: string): Promise { - const mappedDeploymentProfile = await this.getAppPluginDeploymentProfile( - pluginName - ); - if (Tools.isNullOrUndefined(mappedDeploymentProfile)) return pluginName; - return mappedDeploymentProfile.mappedName || pluginName; - } - public async getAppPluginState(pluginName: string): Promise { - return (await this.getAppPluginDeploymentProfile(pluginName)).enabled || false; - } - public async getAppMappedPluginState(mappedPluginName: string): Promise { - return (await this.getAppMappedPluginDeploymentProfile(mappedPluginName)).enabled || false; - } -} diff --git a/nodejs/src/dev.ts b/nodejs/src/dev.ts index 8f22205..9da4e29 100644 --- a/nodejs/src/dev.ts +++ b/nodejs/src/dev.ts @@ -1,15 +1,9 @@ import { ServiceBase } from "./serviceBase/serviceBase"; + const runApp = async () => { const CWD = process.env.APP_DIR || process.cwd(); const SB = new ServiceBase(true, false, CWD); - await SB.setupSelf(); - await SB.setupPlugins(CWD); - await SB.setupConfig(); - await SB.setupLogger(); - await SB.setupEvents(); - await SB.setupServices(); - await SB.initPlugins(); - await SB.runPlugins(); + await SB.init(); await SB.run(); }; runApp(); diff --git a/nodejs/src/events/events.ts b/nodejs/src/events/events.ts deleted file mode 100644 index 043bc4d..0000000 --- a/nodejs/src/events/events.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { IPluginLogger } from "../interfaces/logger"; -import { Readable } from "stream"; -import { IPluginConfig } from "../interfaces/config"; -import { DefaultBase } from "../interfaces/base"; -import { ErrorMessages } from "../interfaces/static"; - -export class EventsBase - extends DefaultBase -{ - constructor(pluginName: string, cwd: string,pluginCwd: string, log: IPluginLogger) { - super(pluginName, cwd, pluginCwd, log); - } - public async onBroadcast( - callerPluginName: string, - pluginName: string, - event: string, - listener: { (args: Array): Promise } - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } - public async emitBroadcast( - callerPluginName: string, - pluginName: string, - event: string, - args: Array - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } - public async onEvent( - callerPluginName: string, - pluginName: string, - event: string, - listener: { (args: Array): Promise } - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } - public async emitEvent( - callerPluginName: string, - pluginName: string, - event: string, - args: Array - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } - public async onReturnableEvent( - callerPluginName: string, - pluginName: string, - event: string, - listener: { (args: Array): Promise } - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } - public async emitEventAndReturn( - callerPluginName: string, - pluginName: string, - event: string, - timeoutSeconds: number, - args: Array - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } - public async receiveStream( - callerPluginName: string, - listener: (error: Error | null, stream: Readable) => Promise, - timeoutSeconds?: number - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } - sendStream( - callerPluginName: string, - streamId: string, - stream: Readable - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } -} diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts index 1899c4a..9e2b55e 100644 --- a/nodejs/src/index.ts +++ b/nodejs/src/index.ts @@ -1,14 +1,4 @@ -export { SecConfig } from "./interfaces/serviceConfig"; -export { - ServiceConfig, - DeploymentProfiles, - DeploymentProfile, - IPluginConfig, -} from "./interfaces/config"; -export { IPluginLogger, LogMeta } from "./interfaces/logger"; -export { ConfigBase } from "./config/config"; -export { EventsBase } from "./events/events"; -export { LoggerBase } from "./logger/logger"; -export { ServiceCallable } from "./service/base"; -export { ServicesBase } from "./service/service"; -export { ServicesClient } from "./service/serviceClient"; +export * from "./base/index"; +export * from "./interfaces/index"; +export * from "./serviceBase/index"; +export { SBClient } from "./client"; diff --git a/nodejs/src/initAppConfig.ts b/nodejs/src/initAppConfig.ts deleted file mode 100644 index 3484a7b..0000000 --- a/nodejs/src/initAppConfig.ts +++ /dev/null @@ -1,25 +0,0 @@ -import * as fs from "fs"; -import { cwd } from 'process'; -import * as path from 'path'; - -(async () => { - const SBBaseDir = path.join(cwd(), "./node_modules/@bettercorp/service-base"); - const secConfigFile = path.join(path.join(cwd(), './sec.config.json')); - if (!fs.existsSync(secConfigFile)) { - console.log("INIT: Copy new sec.config.json"); - fs.copyFileSync(path.join(SBBaseDir, 'templates', 'sec.config.json'), secConfigFile); - console.log("INIT: Copy new sec.config.json - Completed"); - - await (new Promise((r) => setTimeout(r, 1000))); - - const installer = path.join(SBBaseDir, "./lib/ServiceBase.js"); - console.log("INSTALL FINAL : AUTOLOAD: " + installer); - const ServiceBase = require(installer); // eslint-disable-line @typescript-eslint/no-var-requires - const SB = new ServiceBase.default(cwd()); - SB.config().then(() => console.log("INSTALL COMPLETE FOR @bettercorp/service-base")).catch(() => process.exit(1)); - - console.log(`sec.config.json ready to go`); - } else { - console.warn('sec.config.json already found... we`re not going to do anything'); - } -})(); \ No newline at end of file diff --git a/nodejs/src/install.ts b/nodejs/src/install.ts deleted file mode 100644 index 96609d5..0000000 --- a/nodejs/src/install.ts +++ /dev/null @@ -1,244 +0,0 @@ -//import { Tools } from "@bettercorp/tools/lib/Tools"; -import * as fs from "fs"; -//import * as crypto from "crypto"; -import * as path from "path"; -import * as os from "os"; -export default (CWD: string) => { - console.log(`Install CWD: ${ CWD }`); - - if (CWD.indexOf("@bettercorp") >= 0) { - CWD = path.join(CWD, "../../../"); - } - - console.log(`INSTALL SCRIPT FOR @bettercorp/service-base in ${ CWD }`); - - /*const srcDir = path.join(CWD, `./src`); - if (!fs.existsSync(srcDir)) { - console.log(`Creating src dir... (${ srcDir })`); - fs.mkdirSync(srcDir); - } - - const pluginsDir = path.join(CWD, `./src/plugins`); - if (!fs.existsSync(pluginsDir)) { - console.log(`Creating plugins dir... (${ pluginsDir })`); - fs.mkdirSync(pluginsDir); - } - - const filesToCopyToDest = [ - { - src: path.join(CWD, './node_modules/@bettercorp/service-base/build/gitlab-ci.yml'), - dst: path.join(CWD, './.gitlab-ci.yml'), - name: 'gitlab-ci' - }, - { - src: path.join(CWD, './node_modules/@bettercorp/service-base/build/eslintignore'), - dst: path.join(CWD, './.eslintignore'), - name: 'eslintignore' - }, - { - src: path.join(CWD, './node_modules/@bettercorp/service-base/build/eslintrc.js'), - dst: path.join(CWD, './.eslintrc.js'), - name: 'eslintrc' - }, - { - src: path.join(CWD, './node_modules/@bettercorp/service-base/build/tsconfig.json'), - dst: path.join(CWD, './tsconfig.json'), - name: 'tsconfig' - }, - { - src: path.join(CWD, './node_modules/@bettercorp/service-base/build/gitignore'), - dst: path.join(CWD, './.gitignore'), - name: '.gitignore', - merge: true - }, - - // old build files - { - dst: path.join(CWD, './tslint.json'), - remove: true - } - ]; - - for (const fileInfo of filesToCopyToDest) { - if (fileInfo.remove === true) { - if (fs.existsSync(fileInfo.dst)) - fs.unlinkSync(fileInfo.dst); - } else { - if (!fs.existsSync(fileInfo.dst)) { - console.log(`Creating ${ fileInfo.name } build file... (${ fileInfo.src } -> ${ fileInfo.dst })`); - fs.copyFileSync(fileInfo.src!, fileInfo.dst!); - } - if (fileInfo.merge === true) { - const srcBuffer = fs.readFileSync(fileInfo.src!).toString().split('\n'); - const dstBuffer = fs.readFileSync(fileInfo.dst!).toString().split('\n'); - for (let line of dstBuffer) { - if (srcBuffer.indexOf(line) >= 0) - srcBuffer.splice(srcBuffer.indexOf(line), 1); - } - for (let line of srcBuffer) { - dstBuffer.push(line); - } - fs.writeFileSync(fileInfo.dst!, dstBuffer.join('\n')); - } else { - const srcBuffer = fs.readFileSync(fileInfo.src!); - const srcHash = crypto.createHash('sha256'); - srcHash.update(srcBuffer); - const dstBuffer = fs.readFileSync(fileInfo.dst!); - const dstHash = crypto.createHash('sha256'); - dstHash.update(dstBuffer); - if (srcHash.digest('hex') !== dstHash.digest('hex')) { - console.log(`Updating ${ fileInfo.name } build file... (${ fileInfo.src } -> ${ fileInfo.dst })`); - fs.copyFileSync(fileInfo.src!, fileInfo.dst!); - } - } - } - }*/ - - if (process.env.NODE_ENV === 'production') { - const packaggeJSONFile = path.join(CWD, "./package.json"); - console.log(`Updating package scripts... (${ packaggeJSONFile })`); - const readPackageJsonFile = JSON.parse(fs.readFileSync(packaggeJSONFile).toString()); - readPackageJsonFile.scripts = readPackageJsonFile.scripts || {}; - readPackageJsonFile.scripts.start = "node node_modules/@bettercorp/service-base/lib/index.js"; - fs.writeFileSync(packaggeJSONFile, JSON.stringify(readPackageJsonFile)); - } - - /*const defaultScripts: any = { - build: "tsc", - dev: "nodemon --config node_modules/@bettercorp/service-base/build/nodemon.json", - start: "ts-node node_modules/@bettercorp/service-base/lib/index.js", - create: "ts-node node_modules/@bettercorp/service-base/lib/bootstrap.js $0", - version: "node ./node_modules/@bettercorp/service-base/build/version-ci.js $0", - }; - const internalAppScripts: any = { - ...defaultScripts, - version: "node ./node_modules/@bettercorp/service-base/build/version-internal.js $0" - }; - const bcorpLibScripts: any = { - ...defaultScripts, - version: "node ./node_modules/@bettercorp/service-base/build/version-bcorp.js $0" - }; - - let coreAppInstall = false; - let libInstall = false; - let selfInstall = false; - - const packaggeJSONFile = path.join(CWD, "./package.json"); - let todoList: Array = []; - if (fs.existsSync(packaggeJSONFile)) { - const readPackageJsonFile = JSON.parse(fs.readFileSync(packaggeJSONFile).toString()); - - const arrOfDevDepts = Object.keys(readPackageJsonFile.devDependencies || {}); - let paksToRemove: Array = ['tslint']; - let devPaksToInstall: Array = ['eslint', 'typescript', '@typescript-eslint/parser', '@typescript-eslint/eslint-plugin']; - for (let i = paksToRemove.length - 1; i >= 0; i--) - if (arrOfDevDepts.indexOf(paksToRemove[i]) < 0) { - paksToRemove.splice(i, 1); - } - for (let i = devPaksToInstall.length - 1; i >= 0; i--) - if (arrOfDevDepts.indexOf(devPaksToInstall[i]) >= 0) { - devPaksToInstall.splice(i, 1); - } - - if (paksToRemove.length > 0 || devPaksToInstall.length > 0) { - todoList.push('You are missing some packages / have depreciated ones. Please run the following commands to clean things up:'); - if (paksToRemove.length > 0) - todoList.push(`npm remove ${ paksToRemove.join(' ') }`); - if (devPaksToInstall.length > 0) - todoList.push(`npm install --save-dev ${ devPaksToInstall.join(' ') }`); - } - - if (readPackageJsonFile.name == "@bettercorp/service-base") { - console.log("Self install. ignoring install script."); - process.exit(0); - } - - if (readPackageJsonFile.name.indexOf("@bettercorp/core-internal-") === 0) - coreAppInstall = true; - if (readPackageJsonFile.name.indexOf("@bettercorp/service-base-") === 0) - libInstall = true; - if (readPackageJsonFile.name === "@bettercorp/service-base") - selfInstall = true; - - let scripts = defaultScripts; - if (coreAppInstall) { - scripts = internalAppScripts; - } else if (libInstall) { - scripts = bcorpLibScripts; - } - if (Tools.isNullOrUndefined(readPackageJsonFile.scripts)) { - readPackageJsonFile.scripts = {}; - } - let pakUpdates = false; - for (const key of Object.keys(scripts)) { - if (Tools.isNullOrUndefined(scripts[key])) continue; - - if (readPackageJsonFile.scripts[key] !== scripts[key]) { - readPackageJsonFile.scripts[key] = scripts[key]; - pakUpdates = true; - } - } - if (Tools.isNullOrUndefined(readPackageJsonFile.files)) { - readPackageJsonFile.files = ["lib/**[REMOVE" "this]/*"]; - pakUpdates = true; - } - if (readPackageJsonFile.scripts.publish !== undefined && readPackageJsonFile.scripts.publish.indexOf("npm publish") >= 0) { - pakUpdates = true; - if (readPackageJsonFile.scripts.publish == "npm publish") - delete readPackageJsonFile.scripts.publish; - else - readPackageJsonFile.scripts.publish = `${ readPackageJsonFile.scripts.publish }`.replace("npm publish", ""); - } - if (typeof readPackageJsonFile.bsb_project !== "boolean") { - readPackageJsonFile.bsb_project = true; - pakUpdates = true; - } - if (pakUpdates) { - console.log(`Updating package scripts for you... (${ packaggeJSONFile })`); - fs.writeFileSync(packaggeJSONFile, JSON.stringify(readPackageJsonFile)); - } - - if (selfInstall) { - console.log("Package install. ignoring app install script."); - process.exit(0); - } - }*/ - - const configFile = path.join(CWD, "./sec.config.json"); - if (!fs.existsSync(configFile)) { - console.log(`Creating config file... (${ configFile })`); - fs.writeFileSync(configFile, `{"identity":"${ os.hostname }","debug":true,"deploymentProfiles": {"default":{}}, "plugins": {}}`); - } else { - const tSec = JSON.parse(fs.readFileSync(configFile).toString()); - const tBefore = JSON.stringify(tSec); - tSec.identity = tSec.identity || os.hostname; - tSec.debug = tSec.debug || true; - tSec.deploymentProfiles = tSec.deploymentProfiles || {}; - tSec.plugins = tSec.plugins || {}; - const tAfter = JSON.stringify(tSec); - if (tBefore != tAfter) - fs.writeFileSync(configFile, tAfter); - } - const installer = path.join(CWD, "./node_modules/@bettercorp/service-base/lib/ServiceBase.js"); - console.log("INSTALL FINAL : AUTOLOAD: " + installer); - const ServiceBase = require(installer); // eslint-disable-line @typescript-eslint/no-var-requires - const SB = new ServiceBase.default(CWD); - let completedInstaller = false; - SB.config().then(() => { - console.log("INSTALL COMPLETE FOR @bettercorp/service-base"); - - console.log(""); - console.log(""); - console.log(""); - - //for (const todoItem of todoList) console.warn(todoItem); - completedInstaller = true; - }).catch((e: any) => { - console.error(e); - process.exit(1); - }); - let timeoutHandle = setTimeout(() => { - if (completedInstaller) - clearTimeout(timeoutHandle); - }, 100); -}; diff --git a/nodejs/src/interfaces/base.ts b/nodejs/src/interfaces/base.ts deleted file mode 100644 index 7a427be..0000000 --- a/nodejs/src/interfaces/base.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { IPluginConfig } from "./config"; -import { IPluginLogger } from "./logger"; -import { ErrorMessages } from "./static"; - -export interface FakeConfigBase { - appId: string; - runningDebug: boolean; - runningLive: boolean; - getPluginConfig(): Promise; - getPluginState(): Promise; -} - -export class DefaultBaseCore { - protected readonly appId: string = "tbd"; - protected readonly runningDebug: boolean = true; - protected readonly runningLive: boolean = false; - public readonly pluginName: string; - public log: IPluginLogger; - protected cwd: string; - protected pluginCwd: string; - - constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - log: IPluginLogger - ) { - this.pluginName = pluginName; - this.cwd = cwd; - this.pluginCwd = pluginCwd; - this.log = log; - } - - dispose() {} - async init(): Promise {} -} - -export class DefaultBase< - PluginConfigType extends IPluginConfig = any -> extends DefaultBaseCore { - protected getPluginConfig(): Promise { - throw ErrorMessages.BSBNotInit; - } - protected async getPluginState(): Promise { - throw ErrorMessages.BSBNotInit; - } -} diff --git a/nodejs/src/interfaces/config.ts b/nodejs/src/interfaces/config.ts deleted file mode 100644 index 81b7f8c..0000000 --- a/nodejs/src/interfaces/config.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { IDictionary } from "@bettercorp/tools/lib/Interfaces"; - -export interface IPluginConfig {} // eslint-disable-line @typescript-eslint/no-empty-interface - -export interface DeploymentProfiles extends IDictionary { - default: T; -} -export interface ServiceConfig { - plugins: IDictionary; - deploymentProfiles: DeploymentProfiles>; -} - -export interface DeploymentProfile { - mappedName: string; - enabled: boolean; -} - -export interface IConfig { - createAppConfig(listOfKnownPlugins: Array): Promise; - migrateAppPluginConfig( - pluginName: string, - mappedPluginName: string, - config: IPluginConfig - ): Promise; - getAppMappedPluginConfig( - mappedPluginName: string - ): Promise; - getAppPluginDeploymentProfile(pluginName: string): Promise; - getAppMappedPluginDeploymentProfile( - mappedPluginName: string - ): Promise; - getAppPluginMappedName(pluginName: string): Promise; - getAppPluginState(pluginName: string): Promise; - getAppMappedPluginState(mappedPluginName: string): Promise; -} diff --git a/nodejs/src/interfaces/events.ts b/nodejs/src/interfaces/events.ts index 7f2293d..e27481a 100644 --- a/nodejs/src/interfaces/events.ts +++ b/nodejs/src/interfaces/events.ts @@ -1,162 +1,79 @@ -import { - DynamicallyReferencedMethodBase, - DynamicallyReferencedMethodType, -} from "@bettercorp/tools/lib/Interfaces"; -import { Readable } from "stream"; +import { DynamicallyReferencedMethodBase } from "@bettercorp/tools/lib/Interfaces"; + +export type DynamicallyReferencedMethodCallable< + Interface extends DynamicallyReferencedMethodBase, + Method extends keyof Interface, + ArgsReference extends boolean = true + //ShowTimeout extends boolean = true +> = ArgsReference extends true +// eslint-disable-next-line @typescript-eslint/no-unused-vars + ? Interface[Method] extends (...a: infer Arguments) => infer Return + ? [event: Method, ...a: Arguments] + : [event: Method, noMatchingEvent: never] + : Interface[Method] extends (...a: infer Arguments) => infer Return + ? Return extends Promise + ? Return + : Promise + : Promise; export type DynamicallyReferencedMethodOnIEvents< Interface extends DynamicallyReferencedMethodBase, - Method extends string, + Method extends keyof Interface, hasReturnable extends boolean = false > = Interface[Method] extends (...a: infer Arguments) => infer Return ? [ event: Method, listener: { - (...a: Arguments): hasReturnable extends true ? Return : Promise; + (...a: Arguments): hasReturnable extends true + ? Return + : void | Promise; } ] : [event: Method, noMatchingEvent: never]; export type DynamicallyReferencedMethodEmitIEvents< Interface extends DynamicallyReferencedMethodBase, - Method extends string + Method extends keyof Interface + // eslint-disable-next-line @typescript-eslint/no-unused-vars > = Interface[Method] extends (...a: infer Arguments) => infer Return ? [event: Method, ...a: Arguments] - : [noMatchingEvent: never]; + : [event: Method, noMatchingEvent: never]; export type DynamicallyReferencedMethodEmitEARIEvents< Interface extends DynamicallyReferencedMethodBase, - Method extends string, - ArgsReference extends boolean = true, - ShowTimeout extends boolean = true + Method extends keyof Interface, + ArgsReference extends boolean = true + //ShowTimeout extends boolean = true > = ArgsReference extends true +// eslint-disable-next-line @typescript-eslint/no-unused-vars ? Interface[Method] extends (...a: infer Arguments) => infer Return - ? ShowTimeout extends true - ? [ - event: Method, - timeoutSeconds?: number, - ...a: Arguments - ] - : [event: Method, ...a: Arguments] - : [event: Method, noMatchingEvent: never] + ? //? ShowTimeout extends true + [event: Method, timeoutSeconds?: number, ...a: Arguments] + : //: [event: Method, ...a: Arguments] + [event: Method, noMatchingEvent: never] : Interface[Method] extends (...a: infer Arguments) => infer Return ? Return extends Promise ? Return : Promise : Promise; -export interface IServiceEvents< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - onBroadcast, - emitBroadcast, -> { - onBroadcast( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise; - emitBroadcast( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise; - onEvent( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise; - onEventSpecific(serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise; - emitEvent( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise; - emitEventSpecific(serverId: string, - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise; - onReturnableEvent( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise; - onReturnableEventSpecific(serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise; - emitEventAndReturn( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - >; - emitEventAndReturnSpecific(serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - >; - emitEventAndReturnTimed( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - >; - emitEventAndReturnTimedSpecific(serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - >; - receiveStream( - listener: { (error: Error | null, stream: Readable): Promise }, - timeoutSeconds?: number - ): Promise; - sendStream(streamId: string, stream: Readable): Promise; -} +export const EventsEventTypesBase = { + onBroadcast: "onBroadcast", + emitBroadcast: "emitBroadcast", + onEvent: "onEvent", + emitEvent: "emitEvent", + onReturnableEvent: "onReturnableEvent", + emitEventAndReturn: "emitEventAndReturn", + emitEventAndReturnTimed: "emitEventAndReturnTimed", + receiveStream: "receiveStream", + sendStream: "sendStream", +} as const; +export type EventsEventBaseTypes = + (typeof EventsEventTypesBase)[keyof typeof EventsEventTypesBase]; +export type EventsEventTypes = + | "onEventSpecific" + | "emitEventSpecific" + | "onReturnableEventSpecific" + | "emitEventAndReturnSpecific" + | "emitEventAndReturnTimedSpecific" + | EventsEventBaseTypes; diff --git a/nodejs/src/interfaces/index.ts b/nodejs/src/interfaces/index.ts new file mode 100644 index 0000000..1d667c8 --- /dev/null +++ b/nodejs/src/interfaces/index.ts @@ -0,0 +1,4 @@ +export * from "./events"; +export * from "./logging"; +export * from "./plugins"; +export * from "./service"; diff --git a/nodejs/src/interfaces/logger.ts b/nodejs/src/interfaces/logger.ts deleted file mode 100644 index 3f1e262..0000000 --- a/nodejs/src/interfaces/logger.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { ParamsFromString } from "@bettercorp/tools/lib/Interfaces"; - -export type LogMeta = Record< - ParamsFromString, - string | number | boolean | Array ->; - -export interface IPluginLogger { - reportStat(key: string, value: number): Promise; - reportTextStat( - message: T, - meta?: LogMeta, - hasPIData?: boolean): Promise; - info( - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - warn( - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - debug( - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - error( - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - error(error: Error): Promise; - fatal( - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - fatal(error: Error): Promise; -} - -export interface ILogger { - init?(): Promise; - reportStat(plugin: string, key: string, value: number): Promise; - reportTextStat( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean): Promise; - info( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - warn( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - error( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - error(plugin: string, error: Error): Promise; - debug( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; -} diff --git a/nodejs/src/interfaces/logging.ts b/nodejs/src/interfaces/logging.ts new file mode 100644 index 0000000..d7ad871 --- /dev/null +++ b/nodejs/src/interfaces/logging.ts @@ -0,0 +1,50 @@ +import { ParamsFromString } from "@bettercorp/tools/lib/Interfaces"; + +export type DEBUG_MODE = "production" | "production-debug" | "development"; + +export type SafeLogData = + | string + | number + | boolean + | Array + | Object; +export type UnsafeLogData = { + value: string | number | boolean | Array | Object; // Unsafe and unsanitized data + safeValue: SafeLogData; // Safe and sanitized data +}; // Data can contain sensitive information + +export type LogMeta = Record< + ParamsFromString, + UnsafeLogData | SafeLogData +>; + +/** + * If you are going to make an object or something, use LogMeta instead. + */ +export type SmartLogMeta = ParamsFromString extends never + ? [undefined?] + : [meta: Record, UnsafeLogData | SafeLogData>]; + +export interface IPluginLogger { + reportStat(key: string, value: number): void; + reportTextStat(message: T, ...meta: SmartLogMeta): void; + info(message: T, ...meta: SmartLogMeta): void; + warn(message: T, ...meta: SmartLogMeta): void; + debug(message: T, ...meta: SmartLogMeta): void; + error(message: T, ...meta: SmartLogMeta): void; +} + +export const LoggingEventTypesBase = { + reportStat: "reportStat", + reportTextStat: "reportTextStat", + debug: "debug", + info: "info", + warn: "warn", + error: "error", +} as const; +export type LoggingEventTypesExlReportStat = Exclude< + LoggingEventTypes, + "reportStat" +>; +export type LoggingEventTypes = + (typeof LoggingEventTypesBase)[keyof typeof LoggingEventTypesBase]; diff --git a/nodejs/src/interfaces/plugins.ts b/nodejs/src/interfaces/plugins.ts new file mode 100644 index 0000000..e5d30a2 --- /dev/null +++ b/nodejs/src/interfaces/plugins.ts @@ -0,0 +1,116 @@ +import { + BSBService, + BSBLogging, + BSBConfig, + BSBEvents, + BSBServiceRef, + BSBLoggingRef, + BSBConfigRef, + BSBEventsRef, + BSBPluginConfig, +} from "../base"; +import { LoggingEventTypes, EventsEventTypes } from "./index"; + +export const PluginTypes = { + config: "config", + events: "events", + logging: "logging", + service: "service", +} as const; +export type PluginType = (typeof PluginTypes)[keyof typeof PluginTypes]; + +export type DeepReadonly = { + readonly [P in keyof T]: T[P] extends (infer R)[] + ? DeepReadonlyArray + : T[P] extends Function + ? T[P] + : T[P] extends object + ? DeepReadonly + : T[P]; +}; +export interface DeepReadonlyArray extends ReadonlyArray> {} +export interface IPluginDefinition { + package?: string | null; + plugin: string; + name: string; + version: string; +} +export interface IPluginBuilder { + name: string; + pluginName: string; + version: string; + pluginFile: string; + pluginDir: string; + installerFile: string | null; +} +export type PluginTypeDefinition = + T extends typeof PluginTypes.service + ? BSBService + : T extends typeof PluginTypes.logging + ? BSBLogging + : T extends typeof PluginTypes.config + ? BSBConfig + : T extends typeof PluginTypes.events + ? BSBEvents + : never; +export type PluginTypeDefinitionRef = + T extends typeof PluginTypes.service + ? typeof BSBServiceRef + : T extends typeof PluginTypes.logging + ? typeof BSBLoggingRef + : T extends typeof PluginTypes.config + ? typeof BSBConfigRef + : T extends typeof PluginTypes.events + ? typeof BSBEventsRef + : never; + +export interface IPluginBuit extends IPluginBuilder { + config: any; + plugin: PluginTypeDefinition; +} +export interface PluginDefition { + package?: string | null; + plugin: string; + //name: string; + enabled: boolean; +} +export type FilterDetailed = Record< + T, + { + plugins: Array; + enabled: boolean; + } +>; +export type LoggingFilterDetailed = FilterDetailed; +export type LoggingFilter = + | LoggingFilterDetailed // eventsDetailed + | Record // eventsState + | Record> // eventsPlugins + | Array; // events +export interface LoggingConfig extends PluginDefition { + filter?: LoggingFilter; +} +export type EventsFilterDetailed = FilterDetailed; +export type EventsFilter = + | EventsFilterDetailed // eventsDetailed + | Record // eventsState + | Record> // eventsPlugins + | Array; // events +export interface EventsConfig extends PluginDefition { + filter?: EventsFilter; +} +export type FilterOnType = // see EventsFilter and LoggingFilter for more details + "all" | "events" | "eventsState" | "eventsPlugins" | "eventsDetailed"; + +export interface LoadedPlugin< + NamedType extends PluginType, + ClassType extends PluginTypeDefinitionRef = PluginTypeDefinitionRef +> { + name: string; + ref: string; + version: string; + serviceConfig: BSBPluginConfig | null; + plugin: ClassType; + pluginCWD: string; + pluginPath: string; +} diff --git a/nodejs/src/interfaces/service.ts b/nodejs/src/interfaces/service.ts index 13d081d..446c3ff 100644 --- a/nodejs/src/interfaces/service.ts +++ b/nodejs/src/interfaces/service.ts @@ -1,39 +1,6 @@ -import { IServiceEvents } from "./events"; - -export interface IService< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - onBroadcast, - emitBroadcast -> extends IServiceEvents< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - onBroadcast, - emitBroadcast - > { - initIndex?: number; - init?(): Promise; - loadedIndex?: number; - loaded?(): Promise; +export interface ServiceEventsBase { + [key: string]: (...args: any[]) => Promise | any; } - -export enum IPluginDefinition { - config = "config", - events = "events", - logging = "logging", - service = "service", -} - -export interface IReadyPlugin { - pluginDefinition: IPluginDefinition; - name: string; - mappedName: string; - version: string; - pluginFile: string; - pluginDir: string; - installerFile: string | null; +export interface ServiceEventsDefault { + [key: string]: () => never; } diff --git a/nodejs/src/interfaces/serviceConfig.ts b/nodejs/src/interfaces/serviceConfig.ts deleted file mode 100644 index 0feb548..0000000 --- a/nodejs/src/interfaces/serviceConfig.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ErrorMessages } from "./static"; -import { IPluginConfig } from "./config"; - -export class pluginConfig { - static getConfig( - pluginName: string, - existingConfig: IPluginConfig - ): IPluginConfig { - throw ErrorMessages.PluginConfigNotSetupToGenerateConfig; - } -} - -export class SecConfig { - public migrate( - mappedPluginName: string, - existingConfig: MyPluginConfig - ): MyPluginConfig { - throw ErrorMessages.BSBNotInit; - } -} diff --git a/nodejs/src/interfaces/static.ts b/nodejs/src/interfaces/static.ts deleted file mode 100644 index 722a41f..0000000 --- a/nodejs/src/interfaces/static.ts +++ /dev/null @@ -1,57 +0,0 @@ -export class ErrorMessages { - // [BSB-E000001] The method/get property is initialized when the BSB starts up and is overridden. So if you are seeing this error, it means the function was not overridden correctly. - public static get BSBNotInit() { - return new Error( - "[BSB-E000001] Plugins aren`t being initialized properly or you`re trying to call this function directly" - ); - } - - // [BSB-E000002] The events plugin in use does not implement all methods required for the BSB to function normally. - public static get EventsNotImplementedProperly() { - return new Error( - "[BSB-E000002] Events plugin not properly implementing all methods." - ); - } - - // [BSB-E000003] A plugin in use does not implement all methods required for the BSB to function normally. - public static get PluginNotImplementedProperly() { - return new Error( - "[BSB-E000003] Plugin not properly implementing all methods." - ); - } - - // [BSB-E000004] The logger plugin in use does not implement all methods required for the BSB to function normally. - public static get LoggerNotImplementedProperly() { - return new Error( - "[BSB-E000004] Logger plugin not properly implementing all methods." - ); - } - - // [BSB-E000005] The config plugin in use does not implement all methods required for the BSB to function normally. - public static get ConfigNotImplementedProperly() { - return new Error( - "[BSB-E000005] Config plugin not properly implementing all methods." - ); - } - - // [BSB-E000006] The logger plugin in use does not implement all methods required for the BSB to function normally. - public static get PluginClientNotImplementedProperly() { - return new Error( - "[BSB-E000006] An extended plugin client must call this.construct(plugin); in the constructor!" - ); - } - - // [BSB-E000007] Plugin sec.config not interfaced correctly - public static get PluginConfigNotSetupToGenerateConfig() { - return new Error( - "[BSB-E000007] Plugin sec.config not interfaced correctly" - ); - } - - // [BSB-E000008] Cannot call service plugin method because plugin is not running, or setup to handle it - public static get ServicePluginNotCallableMethod() { - return new Error( - "[BSB-E000008] Cannot call service plugin method because plugin is not running, or setup to handle it" - ); - } -} diff --git a/nodejs/src/logger/logger.ts b/nodejs/src/logger/logger.ts deleted file mode 100644 index 099485e..0000000 --- a/nodejs/src/logger/logger.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { Tools } from "@bettercorp/tools/lib/Tools"; -import { ErrorMessages } from "../interfaces/static"; -import { DefaultBase } from "../interfaces/base"; -import { IPluginConfig } from "../interfaces/config"; -import { ILogger, IPluginLogger, LogMeta } from "../interfaces/logger"; - -export class LoggerBase - extends DefaultBase - implements ILogger -{ - protected formatLog(message: T, meta?: LogMeta): string { - //console.log(`_${message}:${Tools.isObject(meta)}`); - if (!Tools.isObject(meta)) return message; - - let dataToParse = message.split("{"); - let outString = dataToParse[0]; - for (let i = 1; i < dataToParse.length; i++) { - let removedVar = dataToParse[i].split("}"); - let referencedVar = Tools.GetValueFromObjectBasedOnStringPath( - meta, - removedVar[0] - ); - //console.log(`:${removedVar[0]}:${referencedVar}`, meta); - if (Tools.isNullOrUndefined(referencedVar)) - referencedVar = "*null/undefined*"; - else if (Tools.isArray(referencedVar)) - referencedVar = (referencedVar as Array) - .map((x) => - Tools.isSimpleType(x) ? x.toString() : JSON.stringify(x) - ) - .join(","); - else if (Tools.isDate(referencedVar)) - referencedVar = (referencedVar as Date).toISOString(); - else if ( - Tools.isObject(referencedVar) || - !Tools.isFunction(referencedVar.toString) - ) - referencedVar = JSON.stringify(referencedVar); - else { - referencedVar = referencedVar.toString(); - } - outString += referencedVar + removedVar[1]; - } - return outString; - } - - constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - defaultLogger: IPluginLogger - ) { - super(pluginName, cwd, pluginCwd, defaultLogger); - } - - public async reportStat( - plugin: string, - key: string, - value: number - ): Promise { - throw ErrorMessages.LoggerNotImplementedProperly; - } - public async reportTextStat( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - throw ErrorMessages.LoggerNotImplementedProperly; - } - public async debug( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - throw ErrorMessages.LoggerNotImplementedProperly; - } - public async info( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - throw ErrorMessages.LoggerNotImplementedProperly; - } - public async warn( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - throw ErrorMessages.LoggerNotImplementedProperly; - } - public async error( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - throw ErrorMessages.LoggerNotImplementedProperly; - } -} diff --git a/nodejs/src/plugins/config-default/interfaces.ts b/nodejs/src/plugins/config-default/interfaces.ts new file mode 100644 index 0000000..2507712 --- /dev/null +++ b/nodejs/src/plugins/config-default/interfaces.ts @@ -0,0 +1,84 @@ +import { + LoggingConfig, + EventsConfig, + PluginDefition as ServiceConfig, +} from "../../"; + +export interface DeploymentProfile { + /** + * @name NPM Package name + * @description The NPM package that holds the plugin + * @example @bettercorp/service-base-plugin-web-server + * @example @bettercorp/service-base-plugin-graphql + */ + package: string; + /** + * @name NPM Package version + * @description The NPM package version that holds the plugin + * @example 1.0.0 + * @example 1.0.1 + */ + //version: string; + /** + * @name Plugin name + * @description The name of the plugin + * @example service-fastify + * @example service-graphql + * @example logging-graylog + */ + plugin: string; + /** + * @name Plugin enabled + * @description If the plugin is enabled or not + * @example true + * @example false + */ + enabled: boolean; +} + +/** + * @name Plugin name + * @description The name of the plugin + * @example service-fastify + */ +export type PluginName = string; + +/** + * @name Deployment profile name + * @description The name of the deployment profile + * @example default + * @example server1 + * @example frontend + * @example backend + */ +export type DeploymentProfileName = string; + +export interface DeploymentProfiles extends Record { + /** + * @name Default deployment profile + * @description The default deployment profile + */ + default: T; +} +export interface ExtendedConfig { + config: any | undefined; +} +export interface ConfigProfile { + logging: Record; + events: Record; + services: Record; +} +export interface DefaultProfile { + default: ConfigProfile; +} +export interface ConfigDefinition + extends Record, + DefaultProfile {} + +// export interface PluginConfig { +// package?: string | null; +// plugin: string; +// name: string; +// enabled: boolean; +// config: INCLCONF extends true ? any : never; +// } diff --git a/nodejs/src/plugins/config-default/plugin.ts b/nodejs/src/plugins/config-default/plugin.ts index ac5163c..8427bbd 100644 --- a/nodejs/src/plugins/config-default/plugin.ts +++ b/nodejs/src/plugins/config-default/plugin.ts @@ -1,172 +1,205 @@ import * as path from "path"; import * as fs from "fs"; +import { parse } from "yaml"; +import { Tools } from "@bettercorp/tools/lib/Tools"; import { - ServiceConfig, - DeploymentProfiles, - DeploymentProfile, - IPluginConfig, -} from "../../interfaces/config"; -import { IPluginLogger } from "../../interfaces/logger"; -import { ConfigBase } from "../../config/config"; -import { PluginConfig } from "./sec.config"; -import { IDictionary } from "@bettercorp/tools/lib/Interfaces"; + BSBConfig, + BSBConfigConstructor, + EventsConfig, + LoggingConfig, + PluginDefition, + PluginType, + PluginTypes, + BSBError, +} from "../../"; +import { ConfigDefinition } from "./interfaces"; -export class Config extends ConfigBase { - public readonly hehe = "I am a string"; - private _appConfig!: ServiceConfig; - private _secConfigFilePath!: string; - private _canWriteChanges: boolean = false; +export class Plugin extends BSBConfig { + async getServicePluginDefinition( + pluginName: string + ): Promise<{ name: string; enabled: boolean }> { + const keydPlugins = Object.keys( + this._appConfig[this._deploymentProfile].services ?? {} + ); + const keydWithMap = keydPlugins.map((x) => { + return { + mappedName: x, + ...this._appConfig[this._deploymentProfile].services[x], + }; + }); + let plugin = keydWithMap.find((x) => { + return x.plugin === pluginName && x.enabled === true; + }); + if (plugin !== undefined) { + return { + name: plugin.mappedName, + enabled: plugin.enabled, + }; + } + plugin = keydWithMap.find((x) => { + return x.plugin === pluginName; + }); + if (plugin !== undefined) { + return { + name: plugin.mappedName, + enabled: plugin.enabled, + }; + } - constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - log: IPluginLogger, - deploymentProfile: string - ) { - super(pluginName, cwd, pluginCwd, log, deploymentProfile); - } - private get activeDeploymentProfile(): DeploymentProfiles { - return (this._appConfig.deploymentProfiles as IDictionary)[ - this._deploymentProfile - ]; + throw new BSBError( + "DEFAULT_CONFIG_GET_SERVICE_PLUGIN_NAME", + "Cannot find the plugin {plugin} in the config", + { + plugin: pluginName, + } + ); } - public override async getAppPluginDeploymentProfile( - pluginName: string - ): Promise { - return this.activeDeploymentProfile[pluginName!]; + async getLoggingPlugins(): Promise> { + const plugins = Object.keys( + this._appConfig[this._deploymentProfile].logging ?? {} + ).filter((x) => { + return ( + this._appConfig[this._deploymentProfile].logging[x].enabled === true + ); + }); + return plugins.reduce((acc, x) => { + acc[x] = { + //name: this._appConfig[this._deploymentProfile].logging[x].name, + plugin: this._appConfig[this._deploymentProfile].logging[x].plugin, + package: this._appConfig[this._deploymentProfile].logging[x].package, + enabled: this._appConfig[this._deploymentProfile].logging[x].enabled, + filter: this._appConfig[this._deploymentProfile].logging[x].filter, + }; + return acc; + }, {} as Record); } - - public override async getAppMappedPluginConfig( - mappedPluginName: string - ): Promise { - return (this._appConfig.plugins[mappedPluginName] || {}) as T; + async getEventsPlugins(): Promise> { + const plugins = Object.keys( + this._appConfig[this._deploymentProfile].events ?? {} + ).filter((x) => { + return ( + this._appConfig[this._deploymentProfile].events[x].enabled === true + ); + }); + return plugins.reduce((acc, x) => { + acc[x] = { + //name: this._appConfig[this._deploymentProfile].events[x].name, + plugin: this._appConfig[this._deploymentProfile].events[x].plugin, + package: this._appConfig[this._deploymentProfile].events[x].package, + enabled: this._appConfig[this._deploymentProfile].events[x].enabled, + filter: this._appConfig[this._deploymentProfile].events[x].filter, + }; + return acc; + }, {} as Record); } - public override async getAppMappedPluginDeploymentProfile( - mappedPluginName: string - ): Promise { - for (let dpPlugin of Object.keys(this.activeDeploymentProfile)) { - if ( - this.activeDeploymentProfile[dpPlugin].mappedName === mappedPluginName - ) - return this.activeDeploymentProfile[dpPlugin]; - } - await this.log.fatal("Cannot find mapped plugin {mappedPluginName}", { - mappedPluginName, + async getServicePlugins(): Promise> { + const plugins = Object.keys( + this._appConfig[this._deploymentProfile].services ?? {} + ).filter((x) => { + return ( + this._appConfig[this._deploymentProfile].services[x].enabled === true + ); }); - return undefined as any; // will not reach + return plugins.reduce((acc, x) => { + acc[x] = { + //name: this._appConfig[this._deploymentProfile].services[x].name, + plugin: this._appConfig[this._deploymentProfile].services[x].plugin, + package: this._appConfig[this._deploymentProfile].services[x].package, + enabled: this._appConfig[this._deploymentProfile].services[x].enabled, + }; + return acc; + }, {} as Record); } - - public override async getAppPluginMappedName( - pluginName: string - ): Promise { + async getPluginConfig( + pluginType: PluginType, + plugin: string + ): Promise { + if (pluginType === PluginTypes.config) return null; + let configKey: "services" | "logging" | "events" = "services"; + if (pluginType === PluginTypes.events) configKey = "events"; + if (pluginType === PluginTypes.logging) configKey = "logging"; return ( - (this.activeDeploymentProfile[pluginName] || {}).mappedName || pluginName + this._appConfig[this._deploymentProfile][configKey][plugin].config ?? null ); } - public override async getAppPluginState( - pluginName: string - ): Promise { - return (this.activeDeploymentProfile[pluginName] || {}).enabled || false; - } - public override async getAppMappedPluginState( - mappedPluginName: string - ): Promise { - return (await this.getAppMappedPluginDeploymentProfile(mappedPluginName)) - .enabled; + dispose() { + this._appConfig = undefined!; } + private _appConfig!: ConfigDefinition; + private _secConfigFilePath: string; + private _deploymentProfile: string = "default"; - public override async createAppConfig( - listOfKnownPlugins: Array - ): Promise { - const config = await this.getPluginConfig(); + constructor(config: BSBConfigConstructor) { + super(config); + this._secConfigFilePath = path.join(this.cwd, "./sec-config.yaml"); + } - this._secConfigFilePath = - config.ConfigFile.indexOf(".") === 0 - ? path.join(this.cwd, config.ConfigFile) - : config.ConfigFile; - let defConfig: ServiceConfig = { - deploymentProfiles: { - default: {}, + init(): void { + if ( + Tools.isString(process.env.BSB_PROFILE) && + process.env.BSB_PROFILE.length > 2 + ) { + this._deploymentProfile = process.env.BSB_PROFILE!; + } + if ( + Tools.isString(process.env.BSB_CONFIG_FILE) && + process.env.BSB_CONFIG_FILE.length > 2 + ) { + this._secConfigFilePath = process.env.BSB_CONFIG_FILE!; + } + this._appConfig = { + default: { + logging: {}, + events: {}, + services: {}, }, - plugins: {}, }; if (fs.existsSync(this._secConfigFilePath)) { - defConfig = JSON.parse( - fs.readFileSync(this._secConfigFilePath, "utf8").toString() - ) as ServiceConfig; - defConfig.plugins = defConfig.plugins || {}; - defConfig.deploymentProfiles = defConfig.deploymentProfiles || {}; - defConfig.deploymentProfiles.default = - defConfig.deploymentProfiles.default || {}; + this._appConfig = + parse(fs.readFileSync(this._secConfigFilePath, "utf8").toString()) ?? + this._appConfig; } else { - await this.log.debug( - "! sec.config.json CAN`T BE FOUND ... we will try create one / work in memory! {secFile}", - { secFile: this._secConfigFilePath } + throw new BSBError( + "DEFAULT_CONFIG_SETUP_CONFIG", + "Cannot find config file at {filepath}", + { + filepath: this._secConfigFilePath, + } ); } - - let existingDefinedPlugins = Object.keys( - defConfig.deploymentProfiles.default - ); - let pluginsToAdd = listOfKnownPlugins.filter( - (x) => existingDefinedPlugins.indexOf(x) < 0 - ); - for (let pluginName of pluginsToAdd) { - defConfig.deploymentProfiles.default[pluginName] = { - mappedName: pluginName, - enabled: false, - }; - } - - this._appConfig = defConfig; - if (!this.runningLive) { - try { - if (fs.existsSync(this._secConfigFilePath)) - fs.accessSync(this._secConfigFilePath, fs.constants.W_OK); - fs.writeFileSync( - this._secConfigFilePath, - JSON.stringify(this._appConfig, "" as any, 2) // todo: replace this with typesafe formatting version - ); - this._canWriteChanges = true; - } catch (e) { - await this.log.warn( - "We're running non-production, but {secFile} is not writable, not we're not going to create it.", - { secFile: this._secConfigFilePath } - ); - } - } - } - public override async migrateAppPluginConfig( - pluginName: string, - mappedPluginName: string, - config: IPluginConfig - ): Promise { - this._appConfig.deploymentProfiles[this._deploymentProfile][pluginName] = - this._appConfig.deploymentProfiles[this._deploymentProfile][ - pluginName - ] || { - mappedName: mappedPluginName, - enabled: true, - }; - this._appConfig.deploymentProfiles[this._deploymentProfile][ - pluginName - ].enabled = true; - this._appConfig.plugins[mappedPluginName] = config; - if (!this._canWriteChanges) { - if (!this.runningLive) - return await this.log.warn( - "We're running non-production, but {secFile} is not writable, not we're not going to change it.", - { secFile: this._secConfigFilePath } - ); - return await this.log.debug( - "We're running production, we're not going to write to {secFile}.", - { secFile: this._secConfigFilePath } + if (Tools.isNullOrUndefined(this._appConfig[this._deploymentProfile])) { + throw new BSBError( + "DEFAULT_CONFIG_SETUP_DEFINITION", + "unknown deployment profile ({deploymentProfile}), please create it first.", + { + deploymentProfile: this._deploymentProfile, + } ); } - fs.writeFileSync( - this._secConfigFilePath, - JSON.stringify(this._appConfig, "" as any, 2) // todo: replace this with typesafe formatting version + this.log.debug("Config ready, using profile: {profile}", { + profile: this._deploymentProfile, + }); + } + async getPlugins(): Promise< + { + npmPackage: string | undefined | null; + plugin: string; + name: string; + enabled: boolean; + }[] + > { + return Object.keys(this._appConfig[this._deploymentProfile].services).map( + (x) => { + return { + npmPackage: + this._appConfig[this._deploymentProfile].services[x].package, + plugin: this._appConfig[this._deploymentProfile].services[x].plugin, + name: x, + enabled: + this._appConfig[this._deploymentProfile].services[x].enabled === + true, + }; + } ); } } diff --git a/nodejs/src/plugins/config-default/sec.config.ts b/nodejs/src/plugins/config-default/sec.config.ts deleted file mode 100644 index 431612b..0000000 --- a/nodejs/src/plugins/config-default/sec.config.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { SecConfig } from "../../interfaces/serviceConfig"; -import { IPluginConfig } from "../../interfaces/config"; - -export interface PluginConfig extends IPluginConfig { - ConfigFile: string; -} - -export class Config extends SecConfig { - public override migrate( - mappedPluginName: string, - existingConfig: PluginConfig - ): PluginConfig { - return { - ConfigFile: - existingConfig.ConfigFile || - process.env.BSB_SEC_JSON || - "./sec.config.json", - }; - } -} diff --git a/nodejs/src/plugins/events-default/events/broadcast.ts b/nodejs/src/plugins/events-default/events/broadcast.ts index b35e854..4553132 100644 --- a/nodejs/src/plugins/events-default/events/broadcast.ts +++ b/nodejs/src/plugins/events-default/events/broadcast.ts @@ -1,7 +1,7 @@ import { EventEmitter } from "events"; -import { IPluginLogger } from '../../../interfaces/logger'; +import { IPluginLogger } from "../../../"; -export default class broadcast extends EventEmitter { +export class broadcast extends EventEmitter { private log: IPluginLogger; constructor(log: IPluginLogger) { @@ -13,28 +13,26 @@ export default class broadcast extends EventEmitter { } public async onBroadcast( - callerPluginName: string, pluginName: string, event: string, listener: { (args: Array): Promise } ): Promise { - await this.log.debug( - "onBroadcast: {callerPluginName} listening to {pluginName}-{event}", - { callerPluginName, pluginName, event } - ); + this.log.debug("onBroadcast:listening to {pluginName}-{event}", { + pluginName, + event, + }); this.on(`${pluginName}-${event}`, listener); } public async emitBroadcast( - callerPluginName: string, pluginName: string, event: string, args: Array ): Promise { - await this.log.debug( - "emitBroadcast: {callerPluginName} emitting {pluginName}-{event}", - { callerPluginName, pluginName, event } - ); + this.log.debug("emitBroadcast: emitting {pluginName}-{event}", { + pluginName, + event, + }); this.emit(`${pluginName}-${event}`, args); } } diff --git a/nodejs/src/plugins/events-default/events/emit.ts b/nodejs/src/plugins/events-default/events/emit.ts index f736dde..eeec9f0 100644 --- a/nodejs/src/plugins/events-default/events/emit.ts +++ b/nodejs/src/plugins/events-default/events/emit.ts @@ -1,8 +1,8 @@ import { EventEmitter } from "events"; -import { IPluginLogger } from "../../../interfaces/logger"; +import { IPluginLogger } from "../../../"; import { randomUUID } from "crypto"; -export default class emit extends EventEmitter { +export class emit extends EventEmitter { private log: IPluginLogger; private _lastReceivedMessageIds: Array = []; private set lastReceivedMessageIds(value: string) { @@ -22,15 +22,14 @@ export default class emit extends EventEmitter { } public async onEvent( - callerPluginName: string, pluginName: string, event: string, listener: { (args: Array): Promise } ): Promise { - await this.log.debug( - "onEvent: {callerPluginName} listening to {pluginName}-{event}", - { callerPluginName, pluginName, event } - ); + this.log.debug("onEvent: listening to {pluginName}-{event}", { + pluginName, + event, + }); this.on(`${pluginName}-${event}`, (args: any) => { if (this._lastReceivedMessageIds.includes(args.msgID)) { return; @@ -41,15 +40,14 @@ export default class emit extends EventEmitter { } public async emitEvent( - callerPluginName: string, pluginName: string, event: string, args: Array ): Promise { - await this.log.debug( - "emitEvent: {callerPluginName} emitting {pluginName}-{event}", - { callerPluginName, pluginName, event } - ); + this.log.debug("emitEvent: emitting {pluginName}-{event}", { + pluginName, + event, + }); this.emit(`${pluginName}-${event}`, { msgID: randomUUID(), data: args, diff --git a/nodejs/src/plugins/events-default/events/emitAndReturn.ts b/nodejs/src/plugins/events-default/events/emitAndReturn.ts index 153f304..9dc0a76 100644 --- a/nodejs/src/plugins/events-default/events/emitAndReturn.ts +++ b/nodejs/src/plugins/events-default/events/emitAndReturn.ts @@ -1,7 +1,7 @@ import { EventEmitter } from "events"; -import { IPluginLogger } from "../../../interfaces/logger"; +import { IPluginLogger } from "../../../"; -export default class emitAndReturn extends EventEmitter { +export class emitAndReturn extends EventEmitter { private log: IPluginLogger; constructor(log: IPluginLogger) { @@ -13,15 +13,14 @@ export default class emitAndReturn extends EventEmitter { } public async onReturnableEvent( - callerPluginName: string, pluginName: string, event: string, listener: { (args: Array): Promise } ): Promise { - await this.log.debug( - "onReturnableEvent: {callerPluginName} listening to {pluginName}-{event}", - { callerPluginName, pluginName, event } - ); + this.log.debug("onReturnableEvent: listening to {pluginName}-{event}", { + pluginName, + event, + }); this.on(event, async (resolve, reject, data) => { try { resolve(await listener(data)); @@ -32,19 +31,18 @@ export default class emitAndReturn extends EventEmitter { } public async emitEventAndReturn( - callerPluginName: string, pluginName: string, event: string, timeoutSeconds: number, args: Array ): Promise { - await this.log.debug( - "emitReturnableEvent: {callerPluginName} emitting {pluginName}-{event}", - { callerPluginName, pluginName, event } - ); + this.log.debug("emitReturnableEvent: emitting {pluginName}-{event}", { + pluginName, + event, + }); const self = this; return new Promise((resolve, reject) => { - let timeoutHandler = setTimeout(() => { + const timeoutHandler = setTimeout(() => { reject("Timeout"); }, timeoutSeconds * 1000); self.emit( diff --git a/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts b/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts index b0a4d16..a478bdd 100644 --- a/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts +++ b/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts @@ -1,9 +1,9 @@ import { EventEmitter } from "events"; import { Readable } from "stream"; import { randomUUID } from "crypto"; -import { IPluginLogger } from '../../../interfaces/logger'; +import { IPluginLogger } from "../../../"; -export default class emitStreamAndReceiveStream extends EventEmitter { +export class emitStreamAndReceiveStream extends EventEmitter { // If we try receive or send a stream and the other party is not ready for some reason, we will automatically timeout in 5s. private readonly staticCommsTimeout = 1000; private log: IPluginLogger; @@ -17,21 +17,17 @@ export default class emitStreamAndReceiveStream extends EventEmitter { } async receiveStream( - callerPluginName: string, + event: string, listener: { (error: Error | null, stream: Readable): Promise }, timeoutSeconds: number = 60 ): Promise { const streamId = `${randomUUID()}=${timeoutSeconds}`; - await this.log.debug( - "receiveStream: {callerPluginName} listening to {streamId}", - { - callerPluginName, - streamId, - } - ); + this.log.debug("receiveStream: listening to {streamId}", { + streamId, + }); const self = this; return new Promise((resolve) => { - let receiptTimeoutHandler: NodeJS.Timeout = setTimeout(() => { + const receiptTimeoutHandler: NodeJS.Timeout = setTimeout(() => { const err = new Error("Receive Receipt Timeout"); listener(err, null!); self.emit(`${streamId}-error`, err); @@ -53,15 +49,12 @@ export default class emitStreamAndReceiveStream extends EventEmitter { } async sendStream( - callerPluginName: string, + event: string, streamId: string, stream: Readable ): Promise { const self = this; - await this.log.debug( - "sendStream: {callerPluginName} emitting _self-{streamId}", - { callerPluginName, streamId } - ); + this.log.debug("sendStream: emitting _self-{streamId}", { streamId }); return new Promise((resolve, rejectI) => { const timeout = Number.parseInt(streamId.split("=")[1]); const clearSessions = (e?: Error) => { @@ -80,7 +73,7 @@ export default class emitStreamAndReceiveStream extends EventEmitter { let receiptTimeoutHandler: NodeJS.Timeout | null = setTimeout(() => { reject(new Error("Send Receipt Timeout")); }, self.staticCommsTimeout); - let timeoutHandler = setTimeout(() => { + const timeoutHandler = setTimeout(() => { reject(new Error("Stream Timeout")); }, timeout * 1000); self.once(`${streamId}-emit`, () => { diff --git a/nodejs/src/plugins/events-default/events/index.ts b/nodejs/src/plugins/events-default/events/index.ts new file mode 100644 index 0000000..e9f72fa --- /dev/null +++ b/nodejs/src/plugins/events-default/events/index.ts @@ -0,0 +1,4 @@ +export { emit } from "./emit"; +export { emitAndReturn } from "./emitAndReturn"; +export { emitStreamAndReceiveStream } from "./emitStreamAndReceiveStream"; +export { broadcast } from "./broadcast"; diff --git a/nodejs/src/plugins/events-default/plugin.ts b/nodejs/src/plugins/events-default/plugin.ts index 82dcf1e..01debd8 100644 --- a/nodejs/src/plugins/events-default/plugin.ts +++ b/nodejs/src/plugins/events-default/plugin.ts @@ -1,30 +1,26 @@ -import { IPluginLogger } from "../../interfaces/logger"; import { Readable } from "stream"; -import emit from "./events/emit"; -import emitAndReturn from "./events/emitAndReturn"; -import emitStreamAndReceiveStream from "./events/emitStreamAndReceiveStream"; -import { EventsBase } from "../../events/events"; -import { PluginConfig } from "./sec.config"; -import broadcast from './events/broadcast'; +import { + emit, + broadcast, + emitAndReturn, + emitStreamAndReceiveStream, +} from "./events"; +import { BSBEvents, BSBEventsConstructor } from "../../"; -export class Events extends EventsBase { +export class Plugin extends BSBEvents { + init?(): void; protected broadcast!: broadcast; protected emit!: emit; protected ear!: emitAndReturn; protected eas!: emitStreamAndReceiveStream; - constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - log: IPluginLogger - ) { - super(pluginName, cwd, pluginCwd, log); + constructor(config: BSBEventsConstructor) { + super(config); - this.broadcast = new broadcast(log); - this.emit = new emit(log); - this.ear = new emitAndReturn(log); - this.eas = new emitStreamAndReceiveStream(log); + this.broadcast = new broadcast(this.createNewLogger("broadcast")); + this.emit = new emit(this.createNewLogger("emit")); + this.ear = new emitAndReturn(this.createNewLogger("emitAndReturn")); + this.eas = new emitStreamAndReceiveStream(this.createNewLogger("stream")); } public dispose() { @@ -35,61 +31,49 @@ export class Events extends EventsBase { } public async onBroadcast( - callerPluginName: string, pluginName: string, event: string, listener: { (args: Array): Promise } ): Promise { - await this.broadcast.onBroadcast(callerPluginName, pluginName, event, listener); + await this.broadcast.onBroadcast(pluginName, event, listener); } public async emitBroadcast( - callerPluginName: string, pluginName: string, event: string, args: Array ): Promise { - await this.broadcast.emitBroadcast(callerPluginName, pluginName, event, args); + await this.broadcast.emitBroadcast(pluginName, event, args); } public async onEvent( - callerPluginName: string, pluginName: string, event: string, listener: { (args: Array): Promise } ): Promise { - await this.emit.onEvent(callerPluginName, pluginName, event, listener); + await this.emit.onEvent(pluginName, event, listener); } public async emitEvent( - callerPluginName: string, pluginName: string, event: string, args: Array ): Promise { - await this.emit.emitEvent(callerPluginName, pluginName, event, args); + await this.emit.emitEvent(pluginName, event, args); } public async onReturnableEvent( - callerPluginName: string, pluginName: string, event: string, listener: { (args: Array): Promise } ): Promise { - await this.ear.onReturnableEvent( - callerPluginName, - pluginName, - event, - listener - ); + await this.ear.onReturnableEvent(pluginName, event, listener); } public async emitEventAndReturn( - callerPluginName: string, pluginName: string, event: string, timeoutSeconds: number, args: Array ): Promise { return await this.ear.emitEventAndReturn( - callerPluginName, pluginName, event, timeoutSeconds, @@ -98,17 +82,17 @@ export class Events extends EventsBase { } public async receiveStream( - callerPluginName: string, + event: string, listener: { (error: Error | null, stream: Readable): Promise }, timeoutSeconds?: number ): Promise { - return this.eas.receiveStream(callerPluginName, listener, timeoutSeconds); + return this.eas.receiveStream(event, listener, timeoutSeconds); } public async sendStream( - callerPluginName: string, + event: string, streamId: string, stream: Readable ): Promise { - return this.eas.sendStream(callerPluginName, streamId, stream); + return this.eas.sendStream(event, streamId, stream); } } diff --git a/nodejs/src/plugins/events-default/sec.config.ts b/nodejs/src/plugins/events-default/sec.config.ts deleted file mode 100644 index 300c3a9..0000000 --- a/nodejs/src/plugins/events-default/sec.config.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { SecConfig } from "../../interfaces/serviceConfig"; -import { IPluginConfig } from "../../interfaces/config"; - -export interface PluginConfig extends IPluginConfig {} - -export class Config extends SecConfig { - migrate( - mappedPluginName: string, - existingConfig: PluginConfig - ): PluginConfig { - return {}; - } -} diff --git a/nodejs/src/plugins/events-test/events/broadcast.ts b/nodejs/src/plugins/events-test/events/broadcast.ts new file mode 100644 index 0000000..1749e53 --- /dev/null +++ b/nodejs/src/plugins/events-test/events/broadcast.ts @@ -0,0 +1,38 @@ +import { EventEmitter } from "events"; +import { IPluginLogger } from "../../../interfaces/logging"; + +export default class broadcast extends EventEmitter { + private log: IPluginLogger; + + constructor(log: IPluginLogger) { + super(); + this.log = log; + } + public dispose() { + this.removeAllListeners(); + } + + public async onBroadcast( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + this.log.debug("onBroadcast:listening to {pluginName}-{event}", { + pluginName, + event, + }); + this.on(`${pluginName}-${event}`, listener); + } + + public async emitBroadcast( + pluginName: string, + event: string, + args: Array + ): Promise { + this.log.debug("emitBroadcast: emitting {pluginName}-{event}", { + pluginName, + event, + }); + this.emit(`${pluginName}-${event}`, args); + } +} diff --git a/nodejs/src/plugins/events-test/events/emit.ts b/nodejs/src/plugins/events-test/events/emit.ts new file mode 100644 index 0000000..b5fbc9a --- /dev/null +++ b/nodejs/src/plugins/events-test/events/emit.ts @@ -0,0 +1,56 @@ +import { EventEmitter } from "events"; +import { IPluginLogger } from "../../../interfaces/logging"; +import { randomUUID } from "crypto"; + +export default class emit extends EventEmitter { + private log: IPluginLogger; + private _lastReceivedMessageIds: Array = []; + private set lastReceivedMessageIds(value: string) { + // remove after 50 messages + if (this._lastReceivedMessageIds.length > 50) { + this._lastReceivedMessageIds.shift(); + } + this._lastReceivedMessageIds.push(value); + } + + constructor(log: IPluginLogger) { + super(); + this.log = log; + } + public dispose() { + this.removeAllListeners(); + } + + public async onEvent( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + this.log.debug("onEvent: listening to {pluginName}-{event}", { + pluginName, + event, + }); + this.on(`${pluginName}-${event}`, (args: any) => { + if (this._lastReceivedMessageIds.includes(args.msgID)) { + return; + } + this.lastReceivedMessageIds = args.msgID; + listener(args.data); + }); + } + + public async emitEvent( + pluginName: string, + event: string, + args: Array + ): Promise { + this.log.debug("emitEvent: emitting {pluginName}-{event}", { + pluginName, + event, + }); + this.emit(`${pluginName}-${event}`, { + msgID: randomUUID(), + data: args, + }); + } +} diff --git a/nodejs/src/plugins/events-test/events/emitAndReturn.ts b/nodejs/src/plugins/events-test/events/emitAndReturn.ts new file mode 100644 index 0000000..fb36bbe --- /dev/null +++ b/nodejs/src/plugins/events-test/events/emitAndReturn.ts @@ -0,0 +1,62 @@ +import { EventEmitter } from "events"; +import { IPluginLogger } from "../../../interfaces/logging"; + +export default class emitAndReturn extends EventEmitter { + private log: IPluginLogger; + + constructor(log: IPluginLogger) { + super(); + this.log = log; + } + public dispose() { + this.removeAllListeners(); + } + + public async onReturnableEvent( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + this.log.debug( + "onReturnableEvent: listening to {pluginName}-{event}", + { pluginName, event } + ); + this.on(event, async (resolve, reject, data) => { + try { + resolve(await listener(data)); + } catch (exc) { + reject(exc); + } + }); + } + + public async emitEventAndReturn( + pluginName: string, + event: string, + timeoutSeconds: number, + args: Array + ): Promise { + this.log.debug("emitReturnableEvent: emitting {pluginName}-{event}", { + pluginName, + event, + }); + const self = this; + return new Promise((resolve, reject) => { + const timeoutHandler = setTimeout(() => { + reject("Timeout"); + }, timeoutSeconds * 1000); + self.emit( + event, + (args: any) => { + clearTimeout(timeoutHandler); + resolve(args); + }, + (args: any) => { + clearTimeout(timeoutHandler); + reject(args); + }, + args + ); + }); + } +} diff --git a/nodejs/src/plugins/events-test/events/emitStreamAndReceiveStream.ts b/nodejs/src/plugins/events-test/events/emitStreamAndReceiveStream.ts new file mode 100644 index 0000000..19e1784 --- /dev/null +++ b/nodejs/src/plugins/events-test/events/emitStreamAndReceiveStream.ts @@ -0,0 +1,91 @@ +import { EventEmitter } from "events"; +import { Readable } from "stream"; +import { randomUUID } from "crypto"; +import { IPluginLogger } from "../../../interfaces/logging"; + +export default class emitStreamAndReceiveStream extends EventEmitter { + // If we try receive or send a stream and the other party is not ready for some reason, we will automatically timeout in 5s. + private readonly staticCommsTimeout = 1000; + private log: IPluginLogger; + + constructor(log: IPluginLogger) { + super(); + this.log = log; + } + public dispose() { + this.removeAllListeners(); + } + + async receiveStream( + event: string, + listener: { (error: Error | null, stream: Readable): Promise }, + timeoutSeconds: number = 60 + ): Promise { + const streamId = `${randomUUID()}=${timeoutSeconds}`; + this.log.debug("receiveStream: listening to {streamId}", { + streamId, + }); + const self = this; + return new Promise((resolve) => { + const receiptTimeoutHandler: NodeJS.Timeout = setTimeout(() => { + const err = new Error("Receive Receipt Timeout"); + listener(err, null!); + self.emit(`${streamId}-error`, err); + self.removeAllListeners(streamId); + }, self.staticCommsTimeout); + self.once(streamId, (stream: Readable): void => { + clearTimeout(receiptTimeoutHandler); + self.emit(`${streamId}-emit`); + stream.on("error", (e) => { + self.emit(`${streamId}-error`, e); + }); + stream.on("end", () => { + self.emit(`${streamId}-end`); + }); + listener(null, stream); + }); + resolve(streamId); + }); + } + + async sendStream( + event: string, + streamId: string, + stream: Readable + ): Promise { + const self = this; + this.log.debug("sendStream: emitting _self-{streamId}", { streamId }); + return new Promise((resolve, rejectI) => { + const timeout = Number.parseInt(streamId.split("=")[1]); + const clearSessions = (e?: Error) => { + stream.destroy(e); + if (receiptTimeoutHandler !== null) clearTimeout(receiptTimeoutHandler); + receiptTimeoutHandler = null; + clearTimeout(timeoutHandler); + self.removeAllListeners(`${streamId}-emit`); + self.removeAllListeners(`${streamId}-end`); + self.removeAllListeners(`${streamId}-error`); + }; + const reject = (e: Error) => { + clearSessions(e); + rejectI(e); + }; + let receiptTimeoutHandler: NodeJS.Timeout | null = setTimeout(() => { + reject(new Error("Send Receipt Timeout")); + }, self.staticCommsTimeout); + const timeoutHandler = setTimeout(() => { + reject(new Error("Stream Timeout")); + }, timeout * 1000); + self.once(`${streamId}-emit`, () => { + if (receiptTimeoutHandler !== null) clearTimeout(receiptTimeoutHandler); + receiptTimeoutHandler = null; + }); + self.once(`${streamId}-end`, () => { + clearSessions(); + resolve(); + }); + self.once(`${streamId}-error`, (e: Error) => reject(e)); + self.emit(streamId, stream); + }); + } +} diff --git a/nodejs/src/plugins/events-test/plugin.ts b/nodejs/src/plugins/events-test/plugin.ts new file mode 100644 index 0000000..ee4fc9c --- /dev/null +++ b/nodejs/src/plugins/events-test/plugin.ts @@ -0,0 +1,96 @@ +import { Readable } from "stream"; +import emit from "./events/emit"; +import emitAndReturn from "./events/emitAndReturn"; +import emitStreamAndReceiveStream from "./events/emitStreamAndReceiveStream"; +import broadcast from "./events/broadcast"; +import { BSBEvents, BSBEventsConstructor } from "../../base/events"; + +export class Plugin extends BSBEvents { + init?(): void; + protected broadcast!: broadcast; + protected emit!: emit; + protected ear!: emitAndReturn; + protected eas!: emitStreamAndReceiveStream; + + constructor(config: BSBEventsConstructor) { + super(config); + + this.broadcast = new broadcast(this.createNewLogger("broadcast")); + this.emit = new emit(this.createNewLogger("emit")); + this.ear = new emitAndReturn(this.createNewLogger("emitAndReturn")); + this.eas = new emitStreamAndReceiveStream(this.createNewLogger("stream")); + } + + public dispose() { + this.broadcast.dispose(); + this.emit.dispose(); + this.ear.dispose(); + this.eas.dispose(); + } + + public async onBroadcast( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + await this.broadcast.onBroadcast(pluginName, event, listener); + } + public async emitBroadcast( + pluginName: string, + event: string, + args: Array + ): Promise { + await this.broadcast.emitBroadcast(pluginName, event, args); + } + + public async onEvent( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + await this.emit.onEvent(pluginName, event, listener); + } + public async emitEvent( + pluginName: string, + event: string, + args: Array + ): Promise { + await this.emit.emitEvent(pluginName, event, args); + } + + public async onReturnableEvent( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + await this.ear.onReturnableEvent(pluginName, event, listener); + } + public async emitEventAndReturn( + pluginName: string, + event: string, + timeoutSeconds: number, + args: Array + ): Promise { + return await this.ear.emitEventAndReturn( + pluginName, + event, + timeoutSeconds, + args + ); + } + + public async receiveStream( + event: string, + listener: { (error: Error | null, stream: Readable): Promise }, + timeoutSeconds?: number + ): Promise { + return this.eas.receiveStream(event, listener, timeoutSeconds); + } + public async sendStream( + event: string, + streamId: string, + stream: Readable + ): Promise { + return this.eas.sendStream(event, streamId, stream); + } +} diff --git a/nodejs/src/plugins/log-default/colours.ts b/nodejs/src/plugins/log-default/colours.ts deleted file mode 100644 index a0bceaf..0000000 --- a/nodejs/src/plugins/log-default/colours.ts +++ /dev/null @@ -1,27 +0,0 @@ -export enum ConsoleColours { - Reset = "\x1b[0m", - Bright = "\x1b[1m", - Dim = "\x1b[2m", - Underscore = "\x1b[4m", - Blink = "\x1b[5m", - Reverse = "\x1b[7m", - Hidden = "\x1b[8m", - - FgBlack = "\x1b[30m", - FgRed = "\x1b[31m", - FgGreen = "\x1b[32m", - FgYellow = "\x1b[33m", - FgBlue = "\x1b[34m", - FgMagenta = "\x1b[35m", - FgCyan = "\x1b[36m", - FgWhite = "\x1b[37m", - - BgBlack = "\x1b[40m", - BgRed = "\x1b[41m", - BgGreen = "\x1b[42m", - BgYellow = "\x1b[43m", - BgBlue = "\x1b[44m", - BgMagenta = "\x1b[45m", - BgCyan = "\x1b[46m", - BgWhite = "\x1b[47m", -} diff --git a/nodejs/src/plugins/log-default/plugin.ts b/nodejs/src/plugins/log-default/plugin.ts deleted file mode 100644 index ec11a34..0000000 --- a/nodejs/src/plugins/log-default/plugin.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { IPluginLogger, LogMeta } from "../../interfaces/logger"; -import { LoggerBase } from "../../logger/logger"; -import { ConsoleColours } from "./colours"; -import { PluginConfig } from "./sec.config"; - -export enum LogLevels { - TSTAT = -3, - STAT = -2, - DEBUG = -1, - INFO = 0, - WARN = 1, - ERROR = 2, -} -export class Logger extends LoggerBase { - private _mockedConsole?: { (level: number, message: string): void }; - private _mockConsole: boolean = false; - constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - defaultLogger: IPluginLogger, - mockConsole?: { (level: number, message: string): void } - ) { - super(pluginName, cwd, pluginCwd, defaultLogger); - this._mockedConsole = mockConsole; - if (this._mockedConsole !== undefined) this._mockConsole = true; - } - - private logEvent( - level: LogLevels, - plugin: string, - message: T, - meta?: LogMeta - ) { - let formattedMessage = this.formatLog(message, meta); - formattedMessage = `[${plugin.toUpperCase()}] ${formattedMessage}`; - let func: any = console.debug; - let colour: Array = [ - ConsoleColours.BgBlack, - ConsoleColours.FgWhite, - ]; - if (level === LogLevels.STAT) { - formattedMessage = `[STAT] ${formattedMessage}`; - colour = [ConsoleColours.BgYellow, ConsoleColours.FgBlack]; - } - if (level === LogLevels.TSTAT) { - formattedMessage = `[STAT] ${formattedMessage}`; - colour = [ConsoleColours.BgCyan, ConsoleColours.FgWhite]; - } - if (level === LogLevels.DEBUG) { - formattedMessage = `[DEBUG] ${formattedMessage}`; - colour = [ConsoleColours.BgBlue, ConsoleColours.FgWhite]; - } - if (level === LogLevels.INFO) { - formattedMessage = `[INFO] ${formattedMessage}`; - func = console.log; - colour = []; - } - if (level === LogLevels.WARN) { - formattedMessage = `[WARN] ${formattedMessage}`; - func = console.warn; - colour = [ConsoleColours.BgBlack, ConsoleColours.FgRed]; - } - if (level === LogLevels.ERROR) { - formattedMessage = `[ERROR] ${formattedMessage}`; - func = console.error; - colour = [ConsoleColours.BgRed, ConsoleColours.FgBlack]; - } - if (this._mockConsole) return this._mockedConsole!(level, formattedMessage); - func(colour.join("") + "%s" + ConsoleColours.Reset, formattedMessage); - } - - public async reportStat( - plugin: string, - key: string, - value: number - ): Promise { - if (!this.runningDebug) return; - this.logEvent(LogLevels.STAT, plugin, "[{key}={value}]", { key, value }); - } - public async reportTextStat( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - if (!this.runningDebug) return; - this.logEvent(LogLevels.TSTAT, plugin, message as T, meta); - } - public async debug( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - if (!this.runningDebug) return; - this.logEvent(LogLevels.DEBUG, plugin, message as T, meta); - } - public async info( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - if (this.runningLive && hasPIData === true) return; - this.logEvent(LogLevels.INFO, plugin, message as T, meta); - } - public async warn( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - if (this.runningLive && hasPIData === true) return; - this.logEvent(LogLevels.WARN, plugin, message as T, meta); - } - public async error( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - public async error(plugin: string, error: Error): Promise; - public async error( - plugin: string, - messageOrError: T | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - let message = - typeof messageOrError === "string" - ? messageOrError - : messageOrError.message; - if (this.runningLive && hasPIData === true) return; - this.logEvent(LogLevels.ERROR, plugin, message as T, meta); - if ( - typeof messageOrError !== "string" && - messageOrError.stack !== undefined - ) { - console.error(messageOrError.stack.toString()); - } - } -} diff --git a/nodejs/src/plugins/log-default/sec.config.ts b/nodejs/src/plugins/log-default/sec.config.ts deleted file mode 100644 index 300c3a9..0000000 --- a/nodejs/src/plugins/log-default/sec.config.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { SecConfig } from "../../interfaces/serviceConfig"; -import { IPluginConfig } from "../../interfaces/config"; - -export interface PluginConfig extends IPluginConfig {} - -export class Config extends SecConfig { - migrate( - mappedPluginName: string, - existingConfig: PluginConfig - ): PluginConfig { - return {}; - } -} diff --git a/nodejs/src/plugins/logging-default/colours.ts b/nodejs/src/plugins/logging-default/colours.ts new file mode 100644 index 0000000..c88c5e0 --- /dev/null +++ b/nodejs/src/plugins/logging-default/colours.ts @@ -0,0 +1,29 @@ +export const CONSOLE_COLOURS = { + Reset: "\x1b[0m", + Bright: "\x1b[1m", + Dim: "\x1b[2m", + Underscore: "\x1b[4m", + Blink: "\x1b[5m", + Reverse: "\x1b[7m", + Hidden: "\x1b[8m", + + FgBlack: "\x1b[30m", + FgRed: "\x1b[31m", + FgGreen: "\x1b[32m", + FgYellow: "\x1b[33m", + FgBlue: "\x1b[34m", + FgMagenta: "\x1b[35m", + FgCyan: "\x1b[36m", + FgWhite: "\x1b[37m", + + BgBlack: "\x1b[40m", + BgRed: "\x1b[41m", + BgGreen: "\x1b[42m", + BgYellow: "\x1b[43m", + BgBlue: "\x1b[44m", + BgMagenta: "\x1b[45m", + BgCyan: "\x1b[46m", + BgWhite: "\x1b[47m", +} as const; +export type ConsoleColours = + (typeof CONSOLE_COLOURS)[keyof typeof CONSOLE_COLOURS]; diff --git a/nodejs/src/plugins/logging-default/plugin.ts b/nodejs/src/plugins/logging-default/plugin.ts new file mode 100644 index 0000000..fadc0f2 --- /dev/null +++ b/nodejs/src/plugins/logging-default/plugin.ts @@ -0,0 +1,137 @@ +import { + LogMeta, + BSBLogging, + BSBLoggingConstructor, + LogFormatter, +} from "../../"; +import { CONSOLE_COLOURS, ConsoleColours } from "./colours"; + +export const LOG_LEVELS = { + TSTAT: "Text Statistic", + STAT: "Statistic", + DEBUG: "Debug", + INFO: "Info", + WARN: "Warn", + ERROR: "Error", +} as const; +export type LogLevels = (typeof LOG_LEVELS)[keyof typeof LOG_LEVELS]; + +export class Plugin extends BSBLogging { + dispose?(): void; + init?(): void; + private _mockedConsole?: { (level: LogLevels, message: string): void }; + private _mockConsole: boolean = false; + private logFormatter: LogFormatter = new LogFormatter(); + + //private mode: DEBUG_MODE = "development"; + constructor( + config: BSBLoggingConstructor, + mockConsole?: { (level: LogLevels, message: string): void } + ) { + super(config); + this._mockedConsole = mockConsole; + if (this._mockedConsole !== undefined) this._mockConsole = true; + } + + private logEvent( + level: LogLevels, + plugin: string, + message: T, + meta?: LogMeta + ) { + let formattedMessage = this.logFormatter.formatLog(message, meta); + formattedMessage = `[${plugin.toUpperCase()}] ${formattedMessage}`; + let func: any = console.debug; + let colour: Array = [ + CONSOLE_COLOURS.BgBlack, + CONSOLE_COLOURS.FgWhite, + ]; + if (level === LOG_LEVELS.STAT) { + formattedMessage = `[STAT] ${formattedMessage}`; + colour = [CONSOLE_COLOURS.BgYellow, CONSOLE_COLOURS.FgBlack]; + } + if (level === LOG_LEVELS.TSTAT) { + formattedMessage = `[STAT] ${formattedMessage}`; + colour = [CONSOLE_COLOURS.BgCyan, CONSOLE_COLOURS.FgWhite]; + } + if (level === LOG_LEVELS.DEBUG) { + formattedMessage = `[DEBUG] ${formattedMessage}`; + colour = [CONSOLE_COLOURS.BgBlue, CONSOLE_COLOURS.FgWhite]; + } + if (level === LOG_LEVELS.INFO) { + formattedMessage = `[INFO] ${formattedMessage}`; + func = console.log; + colour = []; + } + if (level === LOG_LEVELS.WARN) { + formattedMessage = `[WARN] ${formattedMessage}`; + func = console.warn; + colour = [CONSOLE_COLOURS.BgBlack, CONSOLE_COLOURS.FgRed]; + } + if (level === LOG_LEVELS.ERROR) { + formattedMessage = `[ERROR] ${formattedMessage}`; + func = console.error; + colour = [CONSOLE_COLOURS.BgRed, CONSOLE_COLOURS.FgBlack]; + } + if (this._mockConsole) return this._mockedConsole!(level, formattedMessage); + func(colour.join("") + "%s" + CONSOLE_COLOURS.Reset, formattedMessage); + } + + public reportStat(plugin: string, key: string, value: number): void { + if (!this.mode) return; + this.logEvent(LOG_LEVELS.STAT, plugin, "[{key}={value}]", { key, value }); + } + public reportTextStat( + plugin: string, + message: T, + meta: LogMeta + ): void { + if (!this.mode) return; + this.logEvent(LOG_LEVELS.TSTAT, plugin, message as T, meta); + } + public debug( + plugin: string, + message: T, + meta: LogMeta + ): void { + if (this.mode === "production") return; + this.logEvent(LOG_LEVELS.DEBUG, plugin, message as T, meta); + } + public info( + plugin: string, + message: T, + meta: LogMeta + ): void { + this.logEvent(LOG_LEVELS.INFO, plugin, message as T, meta); + } + public warn( + plugin: string, + message: T, + meta: LogMeta + ): void { + this.logEvent(LOG_LEVELS.WARN, plugin, message as T, meta); + } + public error( + plugin: string, + message: T, + meta: LogMeta + ): void; + public error(plugin: string, error: Error): void; + public error( + plugin: string, + messageOrError: T | Error, + meta?: LogMeta + ): void { + const message = + typeof messageOrError === "string" + ? messageOrError + : messageOrError.message; + this.logEvent(LOG_LEVELS.ERROR, plugin, message as T, meta); + if ( + typeof messageOrError !== "string" && + messageOrError.stack !== undefined + ) { + console.error(messageOrError.stack.toString()); + } + } +} diff --git a/nodejs/src/plugins/service-default0/plugin.ts b/nodejs/src/plugins/service-default0/plugin.ts index e979e93..f85640d 100644 --- a/nodejs/src/plugins/service-default0/plugin.ts +++ b/nodejs/src/plugins/service-default0/plugin.ts @@ -1,18 +1,72 @@ -import { IPluginLogger } from '../../interfaces/logger'; -import { ServicesBase } from "../../service/service"; -import { testClient } from "../service-default1/plugin"; +import { BSBService, BSBServiceConstructor, BSBPluginConfig } from "../../"; +import { testClient } from "../service-default1"; +import { z } from "zod"; -export class Service extends ServicesBase { - public override initAfterPlugins: string[] = ["service-default3"]; +export const secSchema = z.object({ + testa: z.number(), + testb: z.number(), +}); +export class Config extends BSBPluginConfig { + validationSchema = secSchema; + + migrate( + toVersion: string, + fromVersion: string | null, + fromConfig: any | null + ) { + if (fromConfig === null) { + // defaults + return { + testa: 1, + testb: 2, + }; + } else { + // migrate + return { + testa: fromConfig.testa, + testb: fromConfig.testb, + }; + } + } +} + +export interface Events { + emitEvents: { + test: (a: string, b: string) => Promise; + }; + onEvents: {}; + emitReturnableEvents: {}; + onReturnableEvents: {}; + emitBroadcast: {}; + onBroadcast: {}; +} + +export class Plugin extends BSBService { + public initBeforePlugins?: string[] | undefined; + //public initAfterPlugins: string[] = ["service-default3"]; + public initAfterPlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public init?(): Promise; + public dispose?(): void; + public readonly methods = { + abc: async () => { + console.log("abc called"); + }, + }; private testClient: testClient; - constructor(pluginName: string, cwd: string, pluginCwd: string, log: IPluginLogger) { - super(pluginName, cwd, pluginCwd, log); + constructor(config: BSBServiceConstructor) { + super(config); this.testClient = new testClient(this); } - public override async init() { - await this.testClient.init(); - } - public override async run() { - await this.testClient.abc(); + public async run() { + this.log.info("aa"); + this.events.emitEvent("test", "test", "test"); + await this.testClient.abc( + this.config.testa, + this.config.testb, + this.config.testa, + this.config.testb + ); } } diff --git a/nodejs/src/plugins/service-default0/sec.config.ts b/nodejs/src/plugins/service-default0/sec.config.ts deleted file mode 100644 index ecd2525..0000000 --- a/nodejs/src/plugins/service-default0/sec.config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { SecConfig } from "../../interfaces/serviceConfig"; -import { IPluginConfig } from "../../interfaces/config"; - -export interface PluginConfig extends IPluginConfig { - testa: number - testb: number -} - -export class Config extends SecConfig { - migrate( - mappedPluginName: string, - existingConfig: PluginConfig - ): PluginConfig { - return { - testa: existingConfig.testa || 6, // this value gets a default value - testb: 5 // this value is unchangable - }; - } -} diff --git a/nodejs/src/plugins/service-default1/index.ts b/nodejs/src/plugins/service-default1/index.ts new file mode 100644 index 0000000..26dcc6b --- /dev/null +++ b/nodejs/src/plugins/service-default1/index.ts @@ -0,0 +1,36 @@ +import { BSBServiceClient } from "../../"; +import { Plugin } from "./plugin"; + +export class testClient extends BSBServiceClient { + public initBeforePlugins?: string[] | undefined; + public initAfterPlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public dispose?(): void; + public run?(): Promise; + public readonly pluginName: string = "service-default1"; + private count = 0; + public async init(): Promise { + this.events.onEvent("onEmittable", async (a: number, b: number) => { + this.log.warn("onEmittable ({a},{b})", { a, b }); + }); + this.events.onReturnableEvent( + "onReverseReturnable", + async (a: number, b: number) => { + this.count++; + console.log("called: " + this.count); + this.log.warn("onReverseReturnable ({a},{b})", { a, b }); + return a * b; + } + ); + await this.events.emitEvent("onReceivable", 56, 7); + } + async abc(a: number, b: number, c: number, d: number): Promise { + this.log.warn("TESTING ABC CALL ({result})", { + result: await this.callMethod("callableMethod", a, b), + }); + this.log.warn("TESTING onReturnable ({result})", { + result: await this.events.emitEventAndReturn("onReturnable", 5, c, d), + }); + } +} diff --git a/nodejs/src/plugins/service-default1/plugin.ts b/nodejs/src/plugins/service-default1/plugin.ts index b59bb29..03117b5 100644 --- a/nodejs/src/plugins/service-default1/plugin.ts +++ b/nodejs/src/plugins/service-default1/plugin.ts @@ -1,89 +1,61 @@ -import { ServiceCallable } from "../../service/base"; -import { ServicesBase } from "../../service/service"; -import { ServicesClient } from "../../service/serviceClient"; +import { BSBService, BSBPluginEvents } from "../../"; -export interface testCallable extends ServiceCallable { - callableMethod(a: number, b: number): Promise; +export interface Events extends BSBPluginEvents { + emitEvents: { + onEmittable(a: number, b: number): Promise; + }; + onEvents: { + onReceivable(a: number, b: number): Promise; + }; + emitReturnableEvents: { + onReverseReturnable(a: number, b: number): Promise; + }; + onReturnableEvents: { + onReturnable(a: number, b: number): Promise; + }; + emitBroadcast: {}; + onBroadcast: {}; } -export interface testEvents extends ServiceCallable { - onReceivable(a: number, b: number): Promise; -} -export interface testEmitEvents extends ServiceCallable { - onEmittable(a: number, b: number): Promise; -} - -export interface testRetEvents extends ServiceCallable { - onReturnable(a: number, b: number): Promise; -} -export interface testEmitRetEvents extends ServiceCallable { - onReverseReturnable(a: number, b: number): Promise; -} +export class Plugin extends BSBService { + public initBeforePlugins?: string[] | undefined; + public initAfterPlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public methods = { + callableMethod: async (a: number, b: number) => { + this.log.warn("callableMethod ({a},{b})", { a, b }); + this.events.emitEvent("onEmittable", a, b); + return a * b; + }, + }; + dispose?(): void; + run?(): void | Promise; -export class Service - extends ServicesBase< - testEvents, - testEmitEvents, - testRetEvents, - testEmitRetEvents, - testCallable, - any - > - implements testCallable -{ - async callableMethod(a: number, b: number): Promise { - await this.log.warn("RECEIVED CALL ({a},{b})", { a, b }); - this.emitEvent("onEmittable", a, b); - return a * b; - } + private count = 0; public override async init() { - const self = this; - this.onEvent("onReceivable", async (a: number, b: number) => { - await self.log.warn("received onReceivable ({a},{b}", { a, b }); + this.log.info("INIT SERVICE"); + this.events.onEvent("onReceivable", async (a: number, b: number) => { + this.count++; + console.log("calledI: " + this.count); + this.log.warn("received onReceivable ({a},{b}", { a, b }); + //process.exit(3); }); - this.onReturnableEvent("onReturnable", async (a: number, b: number) => { - await self.log.warn("RECEIVED onReturnable ({a},{b})", { a, b }); - let result = await self.emitEventAndReturn("onReverseReturnable", a, b); - await self.log.warn("RETURNED onReverseReturnable ({result})", { result }); - return result; - }); - } -} - -export class testClient extends ServicesClient< - testEvents, - testEmitEvents, - testRetEvents, - testEmitRetEvents, - testCallable, - any -> { - public readonly _pluginName: string = "service-default1"; - constructor( - self: ServicesBase - ) { - super(self); - } - public async init(): Promise { - const self = this; - this._plugin.onEvent("onEmittable", async (a: number, b: number) => { - await self._plugin.log.warn("onEmittable ({a},{b})", { a, b }); - }); - this._plugin.onReturnableEvent( - "onReverseReturnable", + this.events.onReturnableEvent( + "onReturnable", async (a: number, b: number) => { - await self._plugin.log.warn("onReverseReturnable ({a},{b})", { a, b }); - return a * b; + this.log.warn("RECEIVED onReturnable ({a},{b})", { a, b }); + const result = await this.events.emitEventAndReturn( + "onReverseReturnable", + 5, + a, + b + ); + this.log.warn("RETURNED onReverseReturnable ({result})", { + result, + }); + return result; } ); - this._plugin.emitEvent("onReceivable", 56, 7); - } - async abc(): Promise { - await this._plugin.log.warn("TESTING ABC CALL ({result})", { - result: await this._plugin.callPluginMethod("callableMethod", 5, 8), - }); - await this._plugin.log.warn("TESTING onReturnable ({result})", { - result: await this._plugin.emitEventAndReturn("onReturnable", 12, 8), - }); } } diff --git a/nodejs/src/plugins/service-default2/plugin.ts b/nodejs/src/plugins/service-default2/plugin.ts index 406d044..eeb15f5 100644 --- a/nodejs/src/plugins/service-default2/plugin.ts +++ b/nodejs/src/plugins/service-default2/plugin.ts @@ -1,18 +1,20 @@ -import { IPluginLogger } from '../../interfaces/logger'; -import { ServicesBase } from "../../service/service"; -import { testClient } from "../service-default1/plugin"; +import { BSBService, BSBServiceConstructor } from "../../"; +import { testClient } from "../service-default1"; -export class Service extends ServicesBase { +export class Plugin extends BSBService { + public initBeforePlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public methods = {}; + dispose?(): void; + init?(): void | Promise; public override initAfterPlugins: string[] = ["service-default1"]; private testClient: testClient; - constructor(pluginName: string, cwd: string, pluginCwd: string, log: IPluginLogger) { - super(pluginName, cwd, pluginCwd, log); + constructor(config: BSBServiceConstructor) { + super(config); this.testClient = new testClient(this); } - public override async init() { - await this.testClient.init(); - } public override async run() { - await this.testClient.abc(); + await this.testClient.abc(10, 12, 11, 13); } } diff --git a/nodejs/src/plugins/service-default2/sec.config.ts b/nodejs/src/plugins/service-default2/sec.config.ts deleted file mode 100644 index ecd2525..0000000 --- a/nodejs/src/plugins/service-default2/sec.config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { SecConfig } from "../../interfaces/serviceConfig"; -import { IPluginConfig } from "../../interfaces/config"; - -export interface PluginConfig extends IPluginConfig { - testa: number - testb: number -} - -export class Config extends SecConfig { - migrate( - mappedPluginName: string, - existingConfig: PluginConfig - ): PluginConfig { - return { - testa: existingConfig.testa || 6, // this value gets a default value - testb: 5 // this value is unchangable - }; - } -} diff --git a/nodejs/src/plugins/service-default3/plugin.ts b/nodejs/src/plugins/service-default3/plugin.ts index e44914f..12f5a9a 100644 --- a/nodejs/src/plugins/service-default3/plugin.ts +++ b/nodejs/src/plugins/service-default3/plugin.ts @@ -1,18 +1,20 @@ -import { IPluginLogger } from '../../interfaces/logger'; -import { ServicesBase } from "../../service/service"; -import { testClient } from "../service-default1/plugin"; +import { BSBService, BSBServiceConstructor } from "../../"; +import { testClient } from "../service-default1"; -export class Service extends ServicesBase { +export class Plugin extends BSBService { + public initBeforePlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public methods = {}; + dispose?(): void; + init?(): void | Promise; public override initAfterPlugins: string[] = ["service-default2"]; private testClient: testClient; - constructor(pluginName: string, cwd: string, pluginCwd: string, log: IPluginLogger) { - super(pluginName, cwd, pluginCwd, log); + constructor(config: BSBServiceConstructor) { + super(config); this.testClient = new testClient(this); } - public override async init() { - await this.testClient.init(); - } public override async run() { - await this.testClient.abc(); + await this.testClient.abc(18, 19, 20, 21); } } diff --git a/nodejs/src/plugins/service-default3/sec.config.ts b/nodejs/src/plugins/service-default3/sec.config.ts deleted file mode 100644 index ecd2525..0000000 --- a/nodejs/src/plugins/service-default3/sec.config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { SecConfig } from "../../interfaces/serviceConfig"; -import { IPluginConfig } from "../../interfaces/config"; - -export interface PluginConfig extends IPluginConfig { - testa: number - testb: number -} - -export class Config extends SecConfig { - migrate( - mappedPluginName: string, - existingConfig: PluginConfig - ): PluginConfig { - return { - testa: existingConfig.testa || 6, // this value gets a default value - testb: 5 // this value is unchangable - }; - } -} diff --git a/nodejs/src/postinstall.ts b/nodejs/src/postinstall.ts index 70a9314..bb08a1e 100644 --- a/nodejs/src/postinstall.ts +++ b/nodejs/src/postinstall.ts @@ -1,13 +1,13 @@ -import { ServiceBase } from "./serviceBase/serviceBase"; -const runApp = async () => { - const CWD = process.env.APP_DIR || process.cwd(); - const SB = new ServiceBase(true, false, CWD); - await SB.setupSelf(); - await SB.setupPlugins(CWD); - await SB.setupConfig(); - await SB.setupLogger(); - await SB.setupEvents(); - await SB.setupServices(); - SB.dispose(0, "OK") -}; -runApp(); +// import { ServiceBase } from "./serviceBase/serviceBase"; +// const runApp = async () => { +// const CWD = process.env.APP_DIR || process.cwd(); +// const SB = new ServiceBase(true, false, CWD); +// await SB.setupSelf(); +// await SB.setupPlugins(CWD); +// await SB.setupConfig(); +// await SB.setupLogger(); +// await SB.setupEvents(); +// await SB.setupServices(); +// SB.dispose(0, "OK") +// }; +// runApp(); diff --git a/nodejs/src/service/base.ts b/nodejs/src/service/base.ts deleted file mode 100644 index 93ce375..0000000 --- a/nodejs/src/service/base.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface ServiceEvents {} -export interface ServiceBroadcasts {} -export interface ServiceReturnableEvents {} -export interface ServiceCallable {} diff --git a/nodejs/src/service/service.ts b/nodejs/src/service/service.ts deleted file mode 100644 index d0fe198..0000000 --- a/nodejs/src/service/service.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { IPluginConfig } from "../interfaces/config"; -import { IPluginLogger } from "../interfaces/logger"; -import { IService } from "../interfaces/service"; -import { Readable } from "stream"; -import { DefaultBase } from "../interfaces/base"; -import { RegisteredPlugin, ServicesClient } from "./serviceClient"; -import { ErrorMessages } from "../interfaces/static"; -import { DynamicallyReferencedMethodType } from "@bettercorp/tools/lib/Interfaces"; -import { - DynamicallyReferencedMethodOnIEvents, - DynamicallyReferencedMethodEmitIEvents, - DynamicallyReferencedMethodEmitEARIEvents, -} from "../interfaces/events"; -import { - ServiceCallable, - ServiceEvents, - ServiceBroadcasts, - ServiceReturnableEvents, -} from "./base"; - -export class ServicesBase< - onEvents = ServiceEvents, - emitEvents = ServiceEvents, - onReturnableEvents = ServiceReturnableEvents, - emitReturnableEvents = ServiceReturnableEvents, - callableMethods = ServiceCallable, - pluginConfigType extends IPluginConfig = any, - onBroadcast = ServiceBroadcasts, - emitBroadcast = ServiceBroadcasts - > - extends DefaultBase - implements - IService< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - onBroadcast, - emitBroadcast - > -{ - public readonly initBeforePlugins?: Array; - public readonly initAfterPlugins?: Array; - public readonly runBeforePlugins?: Array; - public readonly runAfterPlugins?: Array; - - async run(): Promise {} - - public registerPluginClient< - pluginClientOnEvents, - pluginClientEmitEvents, - pluginClientOnReturnableEvents, - pluginClientEmitReturnableEvents, - pluginCallableMethods, - pluginClientConfigType extends IPluginConfig, - pluginClientOnBroadcast, - pluginClientEmitBroadcast - >( - pluginName: string - ): Promise< - RegisteredPlugin< - pluginClientOnEvents, - pluginClientEmitEvents, - pluginClientOnReturnableEvents, - pluginClientEmitReturnableEvents, - pluginCallableMethods, - pluginClientConfigType, - pluginClientOnBroadcast, - pluginClientEmitBroadcast - > - > { - throw ErrorMessages.BSBNotInit; - } - - protected _clients: Array = []; - constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - log: IPluginLogger - ) { - super(pluginName, cwd, pluginCwd, log); - } - receiveStream( - listener: (error: Error | null, stream: Readable) => Promise, - timeoutSeconds?: number - ): Promise { - throw ErrorMessages.BSBNotInit; - } - sendStream(streamId: string, stream: Readable): Promise { - throw ErrorMessages.BSBNotInit; - } - onBroadcast( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - emitBroadcast( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - onEvent( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - onEventSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - emitEvent( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - emitEventSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - onReturnableEvent( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - onReturnableEventSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - emitEventAndReturn( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } - emitEventAndReturnSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } - emitEventAndReturnTimed( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } - emitEventAndReturnTimedSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } -} diff --git a/nodejs/src/service/serviceClient.ts b/nodejs/src/service/serviceClient.ts deleted file mode 100644 index 5244f6c..0000000 --- a/nodejs/src/service/serviceClient.ts +++ /dev/null @@ -1,250 +0,0 @@ -import { - DynamicallyReferencedMethodEmitEARIEvents, - DynamicallyReferencedMethodEmitIEvents, - DynamicallyReferencedMethodOnIEvents, - IServiceEvents, -} from "../interfaces/events"; -import { ServicesBase } from "./service"; -import { Readable } from "stream"; -import { IPluginConfig } from "../interfaces/config"; -import { DefaultBase } from "../interfaces/base"; -import { ErrorMessages } from "../interfaces/static"; -import { - DynamicallyReferencedMethod, - DynamicallyReferencedMethodType, -} from "@bettercorp/tools/lib/Interfaces"; -import { - ServiceEvents, - ServiceReturnableEvents, - ServiceCallable, - ServiceBroadcasts, -} from "./base"; - -export class RegisteredPlugin< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - callableMethods, - PluginConfigType extends IPluginConfig, - onBroadcast, - emitBroadcast - > - extends DefaultBase - implements - IServiceEvents< - emitEvents, - onEvents, - emitReturnableEvents, - onReturnableEvents, - emitBroadcast, - onBroadcast - > -{ - receiveStream( - listener: (error: Error | null, stream: Readable) => Promise, - timeoutSeconds?: number - ): Promise { - throw ErrorMessages.BSBNotInit; - } - sendStream(streamId: string, stream: Readable): Promise { - throw ErrorMessages.BSBNotInit; - } - onBroadcast( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - emitBroadcast( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - onEvent( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - onEventSpecific(serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - emitEvent( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - emitEventSpecific(serverId: string, - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - onReturnableEvent( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - onReturnableEventSpecific(serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - emitEventAndReturn( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } - emitEventAndReturnSpecific(serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } - emitEventAndReturnTimed( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } - emitEventAndReturnTimedSpecific(serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } - callPluginMethod( - ...args: DynamicallyReferencedMethod< - DynamicallyReferencedMethodType, - TA - > - ): DynamicallyReferencedMethod< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } -} - -export class ServicesClient< - onEvents = ServiceEvents, - emitEvents = ServiceEvents, - onReturnableEvents = ServiceReturnableEvents, - emitReturnableEvents = ServiceReturnableEvents, - callableMethods = ServiceCallable, - onBroadcast = ServiceBroadcasts, - emitBroadcast = ServiceBroadcasts -> { - public readonly _pluginName!: string; - public readonly initBeforePlugins?: Array; - public readonly initAfterPlugins?: Array; - public readonly runBeforePlugins?: Array; - public readonly runAfterPlugins?: Array; - - private _referencedPlugin: ServicesBase; - protected _plugin!: RegisteredPlugin< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - callableMethods, - any, - onBroadcast, - emitBroadcast - >; - protected async _register(): Promise { - // We must add the inits/runs list to the referenced service in order to change the init and run order - (this._referencedPlugin as any).initBeforePlugins = ( - this._referencedPlugin.initBeforePlugins || [] - ).concat(this.initBeforePlugins || []); - (this._referencedPlugin as any).initAfterPlugins = ( - this._referencedPlugin.initAfterPlugins || [] - ).concat(this.initAfterPlugins || []); - (this._referencedPlugin as any).runBeforePlugins = ( - this._referencedPlugin.runBeforePlugins || [] - ).concat(this.runBeforePlugins || []); - (this._referencedPlugin as any).runAfterPlugins = ( - this._referencedPlugin.runAfterPlugins || [] - ).concat(this.runAfterPlugins || []); - if (this._plugin === undefined) { - this._plugin = await this._referencedPlugin.registerPluginClient< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - callableMethods, - any, - onBroadcast, - emitBroadcast - >(this._pluginName); - } - } - - constructor(self: ServicesBase) { - this._referencedPlugin = self; - (self as any)._clients.push(this); - } -} diff --git a/nodejs/src/serviceBase/base.ts b/nodejs/src/serviceBase/base.ts deleted file mode 100644 index e726307..0000000 --- a/nodejs/src/serviceBase/base.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { ServicesBase } from "../service/service"; -import { ConfigBase } from "../config/config"; -import { DefaultBase, FakeConfigBase } from "../interfaces/base"; -import { IPluginConfig } from "../interfaces/config"; -import { IServiceEvents } from "../interfaces/events"; -import { RegisteredPlugin } from "../service/serviceClient"; -import { IPluginLogger } from "../interfaces/logger"; -import { - DynamicallyReferencedMethod, - DynamicallyReferencedMethodType, -} from "@bettercorp/tools/lib/Interfaces"; - -export class SBBase { - static setupPlugin( - appId: string, - runningDebug: boolean, - runningLive: boolean, - plugin: DefaultBase, - config: ConfigBase - ): void { - (plugin as unknown as FakeConfigBase).appId = appId; - (plugin as unknown as FakeConfigBase).runningDebug = runningDebug; - (plugin as unknown as FakeConfigBase).runningLive = runningLive; - (plugin as unknown as FakeConfigBase).getPluginConfig = - async (): Promise => { - return await config.getAppMappedPluginConfig(plugin.pluginName); - }; - (plugin as unknown as FakeConfigBase).getPluginState = - async (): Promise => { - return await config.getAppMappedPluginState(plugin.pluginName); - }; - } - - static setupServicePluginSpecific< - PluginConfigType extends IPluginConfig = any - >( - plugin: - | ServicesBase - | RegisteredPlugin, - events: IServiceEvents - ): void { - ( - plugin as unknown as IServiceEvents - ).emitBroadcast = events.emitBroadcast; - ( - plugin as unknown as IServiceEvents - ).onBroadcast = events.onBroadcast; - ( - plugin as unknown as IServiceEvents - ).emitEvent = events.emitEvent; - ( - plugin as unknown as IServiceEvents - ).emitEventSpecific = events.emitEventSpecific; - ( - plugin as unknown as IServiceEvents - ).onEvent = events.onEvent; - ( - plugin as unknown as IServiceEvents - ).onEventSpecific = events.onEventSpecific; - ( - plugin as unknown as IServiceEvents - ).emitEventAndReturnTimed = events.emitEventAndReturnTimed; - ( - plugin as unknown as IServiceEvents - ).emitEventAndReturnTimedSpecific = events.emitEventAndReturnTimedSpecific; - ( - plugin as unknown as IServiceEvents - ).emitEventAndReturn = events.emitEventAndReturn; - ( - plugin as unknown as IServiceEvents - ).emitEventAndReturnSpecific = events.emitEventAndReturnSpecific; - ( - plugin as unknown as IServiceEvents - ).onReturnableEvent = events.onReturnableEvent; - ( - plugin as unknown as IServiceEvents - ).onReturnableEventSpecific = events.onReturnableEventSpecific; - ( - plugin as unknown as IServiceEvents - ).receiveStream = events.receiveStream; - ( - plugin as unknown as IServiceEvents - ).sendStream = events.sendStream; - } - static setupServicePlugin( - plugin: ServicesBase, - events: IServiceEvents, - config: ConfigBase, - cwd: string, - pluginCwd: string, - generateEventsForService: ( - pluginName: string, - mappedPluginName: string - ) => IServiceEvents, - generateLoggerForPlugin: { (pluginName: string): IPluginLogger }, - log: IPluginLogger, - callPluginMethod: { - (pluginName: string, method: string, args: Array): Promise; - } - ): void { - SBBase.setupServicePluginSpecific(plugin, events); - (plugin as unknown as ServicesBase).registerPluginClient = async ( - pluginName: string - ): Promise> => { - let mappedPluginName = await config.getAppPluginMappedName(pluginName); - await log.debug( - "Registering new plugin client in {callerPlugin} for {pluginName} as {mappedPluginName}", - { - callerPlugin: plugin.pluginName, - pluginName, - mappedPluginName, - } - ); - let tPlugin = new RegisteredPlugin< - any, - any, - any, - any, - any, - any, - any, - any - >( - pluginName, - cwd, - pluginCwd, - generateLoggerForPlugin(pluginName + "-client") - ); - SBBase.setupServicePluginSpecific( - tPlugin, - generateEventsForService(pluginName, mappedPluginName) - ); - ( - tPlugin as unknown as RegisteredPlugin< - any, - any, - any, - any, - any, - any, - any, - any - > - ).callPluginMethod = async ( - ...args: DynamicallyReferencedMethod< - DynamicallyReferencedMethodType, - TA - > - ) => { - const method = args.splice(0, 1)[0] as string; - return await callPluginMethod(mappedPluginName, method, args); - }; - return tPlugin; - }; - } -} diff --git a/nodejs/src/serviceBase/config.ts b/nodejs/src/serviceBase/config.ts index b2a676a..46eb160 100644 --- a/nodejs/src/serviceBase/config.ts +++ b/nodejs/src/serviceBase/config.ts @@ -1,260 +1,142 @@ +import { DEBUG_MODE, IPluginLogger } from "../interfaces/logging"; +import { Plugin as DefaultConfig } from "../plugins/config-default/plugin"; +import { SBPlugins } from "./plugins"; +import { SBLogging } from "./logging"; +import { PluginLogger } from "../base/PluginLogger"; +import { BSBConfig } from "../base/config"; +import { + SmartFunctionCallSync, + SmartFunctionCallAsync, +} from "../base/functions"; +import { + EventsConfig, + LoadedPlugin, + LoggingConfig, + PluginDefition, + PluginType, +} from "../interfaces/plugins"; import { Tools } from "@bettercorp/tools/lib/Tools"; -import { existsSync, readFileSync } from "fs"; -import { join } from "path"; -import { IPluginDefinition, IReadyPlugin } from "../interfaces/service"; -import { IPluginLogger } from "../interfaces/logger"; -import { ConfigBase } from "../config/config"; -import { SecConfig } from "../interfaces/serviceConfig"; -import { SBBase } from "./base"; export class SBConfig { + private mode: DEBUG_MODE = "development"; + private appId: string; + private cwd: string; + private sbPlugins: SBPlugins; + private sbLogging: SBLogging; private log: IPluginLogger; - private cwd!: string; - private configPlugin!: { - plugin: IReadyPlugin; - deploymentProfile: string; - }; - public appConfig!: ConfigBase; - constructor(log: IPluginLogger, cwd: string) { - this.log = log; + private configPlugin: BSBConfig; + constructor( + appId: string, + mode: DEBUG_MODE, + cwd: string, + sbLogging: SBLogging, + sbPlugins: SBPlugins + ) { + this.appId = appId; + this.mode = mode; this.cwd = cwd; + this.sbLogging = sbLogging; + this.sbPlugins = sbPlugins; + this.log = new PluginLogger(mode, "sb-config", sbLogging); + this.configPlugin = new DefaultConfig({ + appId, + mode, + pluginName: "sb-config", + cwd, + pluginCwd: cwd, + sbLogging, + }); } - public dispose() { - this.appConfig.dispose(); + public async getPluginConfig(pluginType: PluginType, name: string) { + return await this.configPlugin.getPluginConfig(pluginType, name); } - - public async findConfigPlugin(plugins: Array): Promise { - let deploymentProfile = "default"; - if (!Tools.isNullOrUndefined(process.env.BSB_PROFILE)) { - deploymentProfile = process.env.BSB_PROFILE!; - } - - await this.log.info( - "config load with profile: {deploymentProfile}, against {len} plugins", - { - deploymentProfile, - len: plugins.length, - } - ); - let pluginName = "config-default"; - if ( - (!Tools.isNullOrUndefined(process.env.BSB_CONFIG_PLUGIN) && - process.env.BSB_CONFIG_PLUGIN !== "") || - existsSync(join(this.cwd, "./BSB_CONFIG_PLUGIN")) - ) { - pluginName = - process.env.BSB_CONFIG_PLUGIN || - readFileSync(join(this.cwd, "./BSB_CONFIG_PLUGIN")).toString() || - "config-default"; - } - await this.log.info(`PLUGIN {pluginName} check`, { - pluginName, - }); - for (const plugin of plugins) { - if (plugin.pluginDefinition === IPluginDefinition.config) { - if (pluginName !== plugin.name) continue; - await this.log.info(`PLUGIN {name}v{version}`, { - name: plugin.name, - version: plugin.version, - }); - this.configPlugin = { - deploymentProfile, - plugin, - }; - await this.log.info(`PLUGIN {name}v{version} [SETUP FOR CONFIG]`, { - name: plugin!.name, - version: plugin.version, - }); - return; - } - } - - await this.log.fatal("Unable to setup default config plugin."); + public async getServicePlugins(): Promise> { + return await this.configPlugin.getServicePlugins(); } - - public async mapPlugins( - _plugins: Array - ): Promise> { - let mappedPlugins: Array = []; - - for (let plugin of _plugins) { - if (plugin.pluginDefinition !== IPluginDefinition.config) continue; - if (plugin.name !== this.configPlugin.plugin.name) continue; - mappedPlugins.push(plugin); - } - - for (let plugin of _plugins) { - if ( - plugin.pluginDefinition === IPluginDefinition.config || - plugin.pluginDefinition === IPluginDefinition.service - ) - continue; - //if (!await this.appConfig.getAppPluginState(plugin.name)) continue; - plugin.mappedName = await this.appConfig.getAppPluginMappedName( - plugin.name - ); - mappedPlugins.push(plugin); - } - - for (let plugin of _plugins) { - if (plugin.pluginDefinition !== IPluginDefinition.service) continue; - if (!(await this.appConfig.getAppPluginState(plugin.name))) continue; - plugin.mappedName = await this.appConfig.getAppPluginMappedName( - plugin.name - ); - mappedPlugins.push(plugin); - } - - return mappedPlugins; + public async getEventsPlugins(): Promise> { + return await this.configPlugin.getEventsPlugins(); } - - public async findPluginByType( - plugins: Array, - defaultPlugin: string, - type: IPluginDefinition - ): Promise { - for (const plugin of plugins) { - if (plugin.pluginDefinition === type) { - if (await this.appConfig.getAppPluginState(plugin.name)) return plugin; - } - } - for (const plugin of plugins) { - if (plugin.name === defaultPlugin) { - return plugin; - } - } - await this.log.fatal( - "Cannot find plugin type {type} or default {defaultPlugin}", - { - type, - defaultPlugin, - } - ); - return undefined as any; // should not reach this + public async getLoggingPlugins(): Promise> { + return await this.configPlugin.getLoggingPlugins(); } - - public getPluginName(): string { - return this.configPlugin.plugin.name; + public async getServicePluginDefinition( + pluginName: string + ): Promise<{ name: string; enabled: boolean }> { + return await this.configPlugin.getServicePluginDefinition(pluginName); + } + public dispose() { + SmartFunctionCallSync(this.configPlugin, this.configPlugin.dispose); } - public async setupConfigPlugin( - logger: IPluginLogger, - appId: string, - runningDebug: boolean, - runningLive: boolean, - plugins: Array - ): Promise { - let appConfig: ConfigBase | undefined = undefined; - - await this.log.debug(`Import config plugin: {name} from {file}`, { - name: this.configPlugin.plugin.name, - file: this.configPlugin.plugin!.pluginFile, + private configPackage: string | undefined; + private configPluginName = "config-default"; + + public async setConfigPlugin(reference: LoadedPlugin<"config">) { + this.configPlugin = new reference.plugin({ + appId: this.appId, + mode: this.mode, + pluginName: reference.name, + cwd: this.cwd, + pluginCwd: reference.pluginCWD, + sbLogging: this.sbLogging, }); - const importedPlugin = await import(this.configPlugin.plugin!.pluginFile); - - await this.log.debug(`Construct config plugin: {name}`, { - name: this.configPlugin.plugin.name, + this.log.info("Adding {pluginName} as config", { + pluginName: reference.name, }); - appConfig = new (importedPlugin.Config as unknown as typeof ConfigBase)( - this.configPlugin.plugin.mappedName, - this.cwd, - this.configPlugin.plugin.pluginDir, - logger, - this.configPlugin.deploymentProfile - ); - await this.log.debug(`Create config plugin: {name}`, { - name: this.configPlugin.plugin.name, + this.log.debug(`Init: {name}`, { + name: this.configPluginName, }); + await SmartFunctionCallAsync(this.configPlugin, this.configPlugin.init); - let pluginInstaller: SecConfig | null = - await this.ImportAndCreatePluginConfig(this.configPlugin.plugin); - let pluginConfig = {}; - if (pluginInstaller !== null) { - pluginConfig = pluginInstaller.migrate( - this.configPlugin.plugin.name, - pluginConfig - ); - } - - SBBase.setupPlugin(appId, runningDebug, runningLive, appConfig, { - getAppMappedPluginConfig: async () => { - return pluginConfig; - }, - getAppMappedPluginState: async () => { - return true; - }, - } as any); - await appConfig.createAppConfig(plugins.map((x) => x.name)); - this.appConfig = appConfig!; - await appConfig.init(); - await this.log.info(`Config plugin ready: {name}`, { - name: this.configPlugin.plugin.name, + this.log.info(`Init: {name}: OK`, { + name: this.configPluginName, }); - } - public async ImportAndMigratePluginConfig(plugin: IReadyPlugin) { - let existingConfig = await this.appConfig.getAppMappedPluginConfig( - plugin.mappedName - ); - let secConfig = await this.ImportAndCreatePluginConfig(plugin); - let config = - secConfig !== null - ? secConfig.migrate(plugin.mappedName, existingConfig || {}) - : {}; - await this.appConfig.migrateAppPluginConfig( - plugin.name, - plugin.mappedName, - config - ); - return config; + return this.configPlugin; } - private async ImportAndCreatePluginConfig( - plugin: IReadyPlugin - ): Promise { - let config: SecConfig | null = null; + public async init(): Promise { + if ( + Tools.isString(process.env.BSB_LOGGER_PLUGIN) && + process.env.BSB_LOGGER_PLUGIN.startsWith("config-") + ) { + this.configPluginName = process.env.BSB_LOGGER_PLUGIN; + if (Tools.isString(process.env.BSB_LOGGER_PLUGIN_PACKAGE)) { + this.configPackage = process.env.BSB_LOGGER_PLUGIN_PACKAGE; + } + } + this.log.debug("Add config {name} from ({package})", { + package: this.configPackage ?? "this project", + name: this.configPluginName, + }); + if (this.configPluginName === "config-default") { + await SmartFunctionCallAsync(this.configPlugin, this.configPlugin.init); + return; + } + this.log.debug(`Import config plugin: {name} from ({package})`, { + package: this.configPackage ?? "this project", + name: this.configPluginName, + }); - if (plugin.installerFile !== null && existsSync(plugin.installerFile)) { - await this.log.debug( - `Import plugin config (sec.config.ts/js): {name} -> {installerFile}`, + const newPlugin = await this.sbPlugins.loadPlugin<"config">( + this.log, + this.configPackage ?? null, + this.configPluginName, + this.configPluginName + ); + if (newPlugin === null) { + this.log.error( + "Failed to import config plugin: {name} from ({package})", { - name: plugin.name, - installerFile: plugin.installerFile, + package: this.configPackage ?? "this project", + name: this.configPluginName, } ); - const importedInstaller = await import(plugin.installerFile); - await this.log.debug(`Create plugin config (sec.config.ts/js): {name}`, { - name: plugin.name, - }); - config = new (importedInstaller.Config as unknown as typeof SecConfig)(); - } else { - await this.log.debug(`No plugin config (sec.config.ts/js): {name}`, { - name: plugin.name, - }); + return; } - return config; - } - /*public async configAllPlugins(): Promise { - await this._coreLogger.info(`CONFIG: {length} plugins`, { - length: this._plugins.length, - }); - for (const plugin of this._plugins) { - if (plugin.pluginDefinition === IPluginDefinition.config) continue; - const mappedPlugin = await this._appConfig.getMappedPluginName( - plugin.name - ); - await this._coreLogger.info( - `CONFIG: PLUGIN {name}v{version} AS {mappedPlugin}`, - { name: plugin.name, version: plugin.version, mappedPlugin } - ); - this.getReadyPluginConfig(plugin.pluginDefinition, plugin, mappedPlugin); - await this._coreLogger.info( - `CONFIG: PLUGIN {name}v{version} [CONFIGURED]`, - { name: plugin!.name, version: plugin.version } - ); - } - }*/ + await this.setConfigPlugin(newPlugin); + } } diff --git a/nodejs/src/serviceBase/events.ts b/nodejs/src/serviceBase/events.ts index 54e20a3..7f83caa 100644 --- a/nodejs/src/serviceBase/events.ts +++ b/nodejs/src/serviceBase/events.ts @@ -1,467 +1,751 @@ -import { IPluginLogger } from "../interfaces/logger"; -import { SBBase } from "./base"; -import { ConfigBase } from "../config/config"; -import { IReadyPlugin } from "../interfaces/service"; -import { EventsBase } from "../events/events"; -import { - DynamicallyReferencedMethodEmitEARIEvents, - DynamicallyReferencedMethodEmitIEvents, - DynamicallyReferencedMethodOnIEvents, - IServiceEvents, -} from "../interfaces/events"; -import { DynamicallyReferencedMethodType } from "@bettercorp/tools/lib/Interfaces"; +import { DEBUG_MODE, IPluginLogger } from "../interfaces/logging"; +import { PluginLogger } from "../base/PluginLogger"; import { Readable } from "stream"; -import { MS_PER_NS, NS_PER_SEC } from "./serviceBase"; +import { Plugin as DefaultEvents } from "../plugins/events-default/plugin"; +import { + EventsFilter, + EventsFilterDetailed, + FilterOnType, + IPluginDefinition, +} from "../interfaces/plugins"; +import { SBPlugins } from "./plugins"; +import { SBConfig } from "./config"; +import { + SmartFunctionCallAsync, + SmartFunctionCallSync, +} from "../base/functions"; +import { BSBEvents } from "../base/events"; +import { SBLogging } from "./logging"; +import { EventsEventTypes, EventsEventTypesBase } from "../interfaces/events"; +import { BSBError } from "../base/errorMessages"; +import { NS_PER_SEC, MS_PER_NS } from "./serviceBase"; +import { BSBService } from "../base/service"; +import { BSBServiceClient } from "../base/serviceClient"; +import { LoadedPlugin } from "../interfaces"; +import { Tools } from "@bettercorp/tools/lib/Tools"; export class SBEvents { + private events: Array<{ + name: string; + plugin: BSBEvents; + on?: EventsFilter; + onTypeof: FilterOnType; + }> = []; + private mode: DEBUG_MODE = "development"; + private appId: string; + private cwd: string; + private sbPlugins: SBPlugins; private log: IPluginLogger; - private _activeEvents: EventsBase | undefined; - constructor(log: IPluginLogger) { - this.log = log; + + constructor( + appId: string, + mode: DEBUG_MODE, + cwd: string, + sbPlugins: SBPlugins, + sbLogging: SBLogging + ) { + this.appId = appId; + this.mode = mode; + this.cwd = cwd; + this.sbPlugins = sbPlugins; + const eventsPluginName = "core-events"; + this.log = new PluginLogger(this.mode, eventsPluginName, sbLogging); } public dispose() { - if (this._activeEvents !== undefined) this._activeEvents.dispose(); + for (let eventsIndex = 0; eventsIndex < this.events.length; eventsIndex++) { + if (this.events[eventsIndex].plugin.dispose !== undefined) + SmartFunctionCallSync( + this.events[eventsIndex].plugin, + this.events[eventsIndex].plugin.dispose + ); + } } - async setupEvents( - appId: string, - runningDebug: boolean, - runningLive: boolean, - cwd: string, - config: ConfigBase, - plugin: IReadyPlugin, - pluginLog: IPluginLogger + private getPluginsMatchingTriggerEvent( + event: EventsEventTypes, + plugin: string ) { - await this.log.debug(`Import events plugin: {name} from {file}`, { - name: plugin.name, - file: plugin.pluginFile, + return this.events.find((eventPlugin) => { + if (Tools.isNullOrUndefined(eventPlugin.plugin)) return false; + if (Tools.isNullOrUndefined(eventPlugin.on)) return true; + switch (eventPlugin.onTypeof) { + case "all": + return true; + case "events": + return (eventPlugin.on as Array).includes(event); + case "eventsState": + if ( + Tools.isNullOrUndefined( + (eventPlugin.on as Record)[event] + ) + ) + return false; + return (eventPlugin.on as Record)[event]; + case "eventsPlugins": + if ( + Tools.isNullOrUndefined( + (eventPlugin.on as Record>)[event] + ) + ) + return false; + return (eventPlugin.on as Record>)[ + event + ].includes(plugin); + case "eventsDetailed": + if ( + Tools.isNullOrUndefined( + (eventPlugin.on as EventsFilterDetailed)[event] + ) + ) + return false; + if ((eventPlugin.on as EventsFilterDetailed)[event].enabled !== true) + return false; + return (eventPlugin.on as EventsFilterDetailed)[ + event + ].plugins.includes(plugin); + } }); - const importedPlugin = await import(plugin.pluginFile); + } - await this.log.debug(`Construct events plugin: {name}`, { + private getPluginForEvent( + eventAs: EventsEventTypes, + plugin: string, + event: string + ): { + pluginName: string; + plugin: BSBEvents; + } { + const matchingEvent = this.getPluginsMatchingTriggerEvent(eventAs, plugin); + if (matchingEvent === undefined) + throw new BSBError( + "SBEvents-triggerEvent", + "No plugins found to match event: plugin: {plugin} - eventAs: {eventAs} - event: {event}", + { eventAs, plugin, event } + ); + return { + plugin: matchingEvent.plugin, + pluginName: matchingEvent.name, + }; + } + public async init(sbConfig: SBConfig, sbLogging: SBLogging) { + this.log.debug("INIT SBEvents"); + const plugins = await sbConfig.getEventsPlugins(); + for (const plugin of Object.keys(plugins)) { + await this.addEvents( + sbConfig, + sbLogging, + { + name: plugin, + package: plugins[plugin].package, + plugin: plugins[plugin].plugin, + version: "", + }, + plugins[plugin].filter + ); + } + this.log.info('Adding "events-default" as events'); + this.events.push({ + name: "events-default", + plugin: new DefaultEvents({ + appId: this.appId, + mode: this.mode, + pluginName: "events-default", + cwd: this.cwd, + pluginCwd: this.cwd, + config: null, + sbLogging, + }), + on: undefined, + onTypeof: "all", + }); + } + public async run() { + if (this.events.length === 1) return; + // we want to see if any plugins (ignore events-default) are listening to all events - it so, there is no reason to keep the events-default plugin, so we can dispose and remove it + const events = this.events.filter((x) => x.name !== "events-default"); + const allEvents = events.filter((x) => x.onTypeof === "all"); + if (allEvents.length > 0) { + const defaultEvents = this.events.find( + (x) => x.name === "events-default" + ); + if (defaultEvents !== undefined) { + if (defaultEvents.plugin.dispose !== undefined) + SmartFunctionCallSync( + defaultEvents.plugin, + defaultEvents.plugin.dispose + ); + this.events = this.events.filter((x) => x.name !== "events-default"); + } + } + } + + public async addPlugin( + sbLogging: SBLogging, + plugin: IPluginDefinition, + reference: LoadedPlugin<"events">, + config: any, + filter?: EventsFilter + ) { + this.log.debug(`Get plugin config: {name}`, { name: plugin.name, }); - let eventsPlugin = - new (importedPlugin.Events as unknown as typeof EventsBase)( - plugin.mappedName, - cwd, - plugin.pluginDir, - pluginLog - ); - await this.log.debug(`Create events plugin: {name}`, { + this.log.debug(`Construct events plugin: {name}`, { name: plugin.name, }); - await this.log.info( - "Setting up {pluginName} ({mappedName}) as new base events platform", - { - pluginName: plugin.name, - mappedName: plugin.mappedName, - } - ); - await this.log.info("Builing {pluginName} as new base events platform", { + const eventsPlugin = new reference.plugin({ + appId: this.appId, + mode: this.mode, + pluginName: reference.name, + cwd: this.cwd, + pluginCwd: reference.pluginCWD, + config: config, + sbLogging, + }); + this.log.info("Adding {pluginName} as events with filter: ", { pluginName: plugin.name, + //filters: filter }); - SBBase.setupPlugin(appId, runningDebug, runningLive, eventsPlugin, config); + let eventAsType: FilterOnType = "all"; - this._activeEvents = eventsPlugin; - await this._activeEvents.init(); - await this.log.info( - "Ready {pluginName} ({mappedName}) as new base events platform", - { - pluginName: plugin.name, - mappedName: plugin.mappedName, + if (filter) { + if (Array.isArray(filter)) { + eventAsType = "events"; + } else if (typeof filter === "object") { + const methods = Object.keys(EventsEventTypesBase); + for (const method of methods) { + if ( + (filter as unknown as Record)[method] !== undefined + ) { + const methodValue = filter[method as keyof typeof filter]; + if (typeof methodValue === "boolean") { + eventAsType = "eventsState"; + } else if (Array.isArray(methodValue)) { + eventAsType = "eventsPlugins"; + } else if (typeof methodValue === "object") { + eventAsType = "eventsDetailed"; + } + } + } } + } + this.events.unshift({ + plugin: eventsPlugin, + on: filter, + onTypeof: eventAsType, + name: plugin.name, + }); + + this.log.info("Ready {pluginName} ({mappedName})", { + pluginName: plugin.plugin, + mappedName: plugin.name, + }); + + await SmartFunctionCallAsync(eventsPlugin, eventsPlugin.init); + + return eventsPlugin; + } + + private async addEvents( + sbConfig: SBConfig, + sbLogging: SBLogging, + plugin: IPluginDefinition, + filter?: EventsFilter + ) { + this.log.debug("Add events {name} from ({package}){file}", { + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, + }); + if (plugin.name === "events-default") return; + this.log.debug(`Import events plugin: {name} from ({package}){file}`, { + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, + }); + + const newPlugin = await this.sbPlugins.loadPlugin<"events">( + this.log, + plugin.package ?? null, + plugin.plugin, + plugin.name ); - if (this._activeEvents === null) { - console.log("x"); + if (newPlugin === null) { + this.log.error( + "Failed to import events plugin: {name} from ({package}){file}", + { + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, + } + ); + return; + } + + let pluginConfig = + (await sbConfig.getPluginConfig("events", plugin.name)) ?? null; + + if ( + this.mode !== "production" && + !Tools.isNullOrUndefined(newPlugin) && + !Tools.isNullOrUndefined(newPlugin.serviceConfig) && + Tools.isObject(newPlugin.serviceConfig) && + !Tools.isNullOrUndefined(newPlugin.serviceConfig.validationSchema) + ) { + this.log.debug("Validate plugin config: {name}", { name: plugin.name }); + pluginConfig = + newPlugin.serviceConfig.validationSchema.parse(pluginConfig); } + + await this.addPlugin(sbLogging, plugin, newPlugin, pluginConfig, filter); } - generateEventsForService( + private async handleOnBroadcast( + eventsPluginName: string, + pluginName: string, + event: string, + context: BSBService | BSBServiceClient, + listener: { (...args: Array): Promise | void }, + iargs: Array + ) { + const start = process.hrtime(); + try { + await SmartFunctionCallAsync(context, listener, ...iargs); + const diff = process.hrtime(start); + this.log.reportStat( + `on-broadcast-${eventsPluginName}-${pluginName}-${event}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + } catch (exc: any) { + this.log.reportStat( + `on-broadcast-${eventsPluginName}-${pluginName}-${event}`, + -1 + ); + this.log.error("handleOnBroadcast error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } + } + public async onBroadcast( + context: BSBService | BSBServiceClient, pluginName: string, - mappedPluginName: string - ): IServiceEvents { + event: string, + listener: { (...args: Array): Promise | void } + ): Promise { const self = this; - return { - onBroadcast: async ( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise => { - await self._activeEvents!.onBroadcast( + const plugin = await this.getPluginForEvent( + "onBroadcast", + pluginName, + event + ); + plugin.plugin.onBroadcast(pluginName, event, async (iargs: Array) => + self.handleOnBroadcast.call( + self, + plugin.pluginName, + pluginName, + event, + context, + listener, + iargs + ) + ); + } + + public async emitBroadcast( + pluginName: string, + event: string, + ...args: Array + ): Promise { + const plugin = await this.getPluginForEvent( + "emitBroadcast", + pluginName, + event + ); + this.log.reportStat( + `emit-broadcast-${plugin.pluginName}-${pluginName}-${event}`, + 1 + ); + await SmartFunctionCallAsync( + plugin.plugin, + plugin.plugin.emitBroadcast, + pluginName, + event, + args + ); + } + + private async handleOnEvent( + eventsPluginName: string, + pluginName: string, + event: string, + context: BSBService | BSBServiceClient, + listener: { (...args: Array): Promise | void }, + iargs: Array + ) { + const start = process.hrtime(); + try { + //console.log("CALL ON EVENT", context, listener, iargs); + await SmartFunctionCallAsync(context, listener, ...iargs); + const diff = process.hrtime(start); + this.log.reportStat( + `on-event-${eventsPluginName}-${pluginName}-${event}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + } catch (exc: any) { + this.log.reportStat( + `on-event-${eventsPluginName}-${pluginName}-${event}`, + -1 + ); + this.log.error("handleOnEvent error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } + } + public async onEvent( + context: BSBService | BSBServiceClient, + pluginName: string, + event: string, + listener: { (...args: Array): Promise | void } + ): Promise { + const self = this; + const plugin = await this.getPluginForEvent("onEvent", pluginName, event); + plugin.plugin.onEvent(pluginName, event, async (iargs: Array) => + self.handleOnEvent.call( + self, + plugin.pluginName, + pluginName, + event, + context, + listener, + iargs + ) + ); + } + public async onEventSpecific( + serverId: string, + context: BSBService | BSBServiceClient, + pluginName: string, + event: string, + listener: { (...args: Array): Promise | void } + ): Promise { + const self = this; + const plugin = await this.getPluginForEvent("onEvent", pluginName, event); + plugin.plugin.onEvent( + pluginName, + event + "-" + serverId, + async (iargs: Array) => + self.handleOnEvent.call( + self, + plugin.pluginName, pluginName, - mappedPluginName, - args[0], - async (iargs: Array) => { - const start = process.hrtime(); - try { - await args[1](...iargs); - let diff = process.hrtime(start); - await self.log.reportStat( - `on-broadcast-${mappedPluginName}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - } catch (exc: any) { - await self.log.reportStat( - `on-broadcast-${mappedPluginName}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - } - ); - }, - emitBroadcast: async ( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise => { - let event = args.splice(0, 1)[0] as string; - await self._activeEvents!.emitBroadcast( + event + "-" + serverId, + context, + listener, + iargs + ) + ); + } + + public async emitEvent( + pluginName: string, + event: string, + ...args: Array + ): Promise { + const plugin = await this.getPluginForEvent("emitEvent", pluginName, event); + this.log.reportStat( + `emit-event-${plugin.pluginName}-${pluginName}-${event}`, + 1 + ); + await SmartFunctionCallAsync( + plugin.plugin, + plugin.plugin.emitEvent, + pluginName, + event, + args + ); + } + public async emitEventSpecific( + serverId: string, + pluginName: string, + event: string, + ...args: Array + ): Promise { + const plugin = await this.getPluginForEvent("emitEvent", pluginName, event); + this.log.reportStat( + `emit-event-${plugin.pluginName}-${pluginName}-${event}-${serverId}`, + 1 + ); + await SmartFunctionCallAsync( + plugin.plugin, + plugin.plugin.emitEvent, + pluginName, + event + "-" + serverId, + args + ); + } + + private async handleOnReturnableEvent( + eventsPluginName: string, + pluginName: string, + event: string, + context: BSBService | BSBServiceClient, + listener: { (...args: Array): Promise | any }, + iargs: Array + ) { + const start = process.hrtime(); + try { + const resp = await SmartFunctionCallAsync(context, listener, ...iargs); + const diff = process.hrtime(start); + this.log.reportStat( + `on-returnableevent-${eventsPluginName}-${pluginName}-${event}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + return resp; + } catch (exc: any) { + this.log.reportStat( + `on-returnableevent-${eventsPluginName}-${pluginName}-${event}`, + -1 + ); + this.log.error("handleOnReturnableEvent error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } + } + public async onReturnableEvent( + context: BSBService | BSBServiceClient, + pluginName: string, + event: string, + listener: { (...args: Array): Promise | void } + ): Promise { + const self = this; + const plugin = await this.getPluginForEvent( + "onReturnableEvent", + pluginName, + event + ); + plugin.plugin.onReturnableEvent( + pluginName, + event, + async (iargs: Array) => + self.handleOnReturnableEvent.call( + self, + plugin.pluginName, pluginName, - mappedPluginName, event, - args - ); - }, - onEvent: async ( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise => { - await self._activeEvents!.onEvent( - pluginName, - mappedPluginName, - args[0], - async (iargs: Array) => { - const start = process.hrtime(); - try { - await args[1](...iargs); - let diff = process.hrtime(start); - await self.log.reportStat( - `on-event-${mappedPluginName}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - } catch (exc: any) { - await self.log.reportStat( - `on-event-${mappedPluginName}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - } - ); - }, - onEventSpecific: async (serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise => { - await self._activeEvents!.onEvent( - pluginName, - `${mappedPluginName}-${serverId}`, - args[0], - async (iargs: Array) => { - const start = process.hrtime(); - try { - await args[1](...iargs); - let diff = process.hrtime(start); - await self.log.reportStat( - `on-event-${mappedPluginName}-${serverId}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - } catch (exc: any) { - await self.log.reportStat( - `on-event-${mappedPluginName}-${serverId}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - } - ); - }, - emitEvent: async ( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise => { - let event = args.splice(0, 1)[0] as string; - await self._activeEvents!.emitEvent( + context, + listener, + iargs + ) + ); + } + public async onReturnableEventSpecific( + serverId: string, + context: BSBService | BSBServiceClient, + pluginName: string, + event: string, + listener: { (...args: Array): Promise | void } + ): Promise { + const self = this; + const plugin = await this.getPluginForEvent( + "onReturnableEvent", + pluginName, + event + ); + plugin.plugin.onReturnableEvent( + pluginName, + event + "-" + serverId, + async (iargs: Array) => + self.handleOnReturnableEvent.call( + self, + plugin.pluginName, pluginName, - mappedPluginName, - event, - args - ); - }, - emitEventSpecific: async (serverId: string, - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise => { - let event = args.splice(0, 1)[0] as string; - await self._activeEvents!.emitEvent( + event + "-" + serverId, + context, + listener, + iargs + ) + ); + } + public async emitEventAndReturn( + pluginName: string, + event: string, + timeoutSeconds: number, + ...args: Array + ): Promise { + const start = process.hrtime(); + const plugin = await this.getPluginForEvent( + "emitEventAndReturn", + pluginName, + event + ); + try { + const resp = await SmartFunctionCallAsync( + plugin.plugin, + plugin.plugin.emitEventAndReturn, + pluginName, + event, + timeoutSeconds, + args + ); + const diff = process.hrtime(start); + this.log.reportStat( + `emit-eventandreturn-${plugin.pluginName}-${pluginName}-${event}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + return resp; + } catch (exc: any) { + this.log.reportStat( + `emit-eventandreturn-${plugin.pluginName}-${pluginName}-${event}`, + -1 + ); + this.log.error("emitEventAndReturn error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } + } + public async emitEventAndReturnSpecific( + serverId: string, + pluginName: string, + event: string, + timeoutSeconds: number, + ...args: Array + ): Promise { + const start = process.hrtime(); + const plugin = await this.getPluginForEvent( + "emitEventAndReturn", + pluginName, + event + ); + try { + const resp = await SmartFunctionCallAsync( + plugin.plugin, + plugin.plugin.emitEventAndReturn, + pluginName, + event + "-" + serverId, + timeoutSeconds, + args + ); + const diff = process.hrtime(start); + this.log.reportStat( + `emit-eventandreturn-${plugin.pluginName}-${pluginName}-${event}-${serverId}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + return resp; + } catch (exc: any) { + this.log.reportStat( + `emit-eventandreturn-${plugin.pluginName}-${pluginName}-${event}-${serverId}`, + -1 + ); + this.log.error("emitEventAndReturnSpecific error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } + } + + private async handleOnReceiveStream( + eventsPluginName: string, + pluginName: string, + event: string, + context: BSBService | BSBServiceClient, + listener: { (error: Error | null, stream: Readable): Promise }, + error: Error | null, + stream: Readable + ) { + const start = process.hrtime(); + try { + const resp = await SmartFunctionCallAsync( + context, + listener, + error, + stream + ); + const diff = process.hrtime(start); + this.log.reportStat( + `receivestream-${eventsPluginName}-${pluginName}-${event}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + return resp; + } catch (exc: any) { + this.log.reportStat( + `receivestream-${eventsPluginName}-${pluginName}-${event}`, + -1 + ); + this.log.error("handleOnReceiveStream error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } + } + public async receiveStream( + context: BSBService | BSBServiceClient, + pluginName: string, + event: string, + listener: { (error: Error | null, stream: Readable): Promise }, + timeoutSeconds?: number + ): Promise { + const self = this; + const plugin = await this.getPluginForEvent( + "receiveStream", + pluginName, + event + ); + return await plugin.plugin.receiveStream( + event, + async (error: Error | null, stream: Readable) => + self.handleOnReceiveStream.call( + self, + plugin.pluginName, pluginName, - `${mappedPluginName}-${serverId}`, event, - args - ); - }, - onReturnableEvent: async ( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise => { - this._activeEvents!.onReturnableEvent( - pluginName, - mappedPluginName, - args[0], - async (iargs: Array) => { - const start = process.hrtime(); - try { - const data = await args[1](...iargs); - let diff = process.hrtime(start); - await self.log.reportStat( - `on-revent-${mappedPluginName}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat( - `on-revent-${mappedPluginName}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - } - ); - }, - onReturnableEventSpecific: async (serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise => { - this._activeEvents!.onReturnableEvent( - pluginName, - `${mappedPluginName}-${serverId}`, - args[0], - async (iargs: Array) => { - const start = process.hrtime(); - try { - const data = await args[1](...iargs); - let diff = process.hrtime(start); - await self.log.reportStat( - `on-revent-${mappedPluginName}-${serverId}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat( - `on-revent-${mappedPluginName}-${serverId}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - } - ); - }, - emitEventAndReturn: async ( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): Promise => { - const start = process.hrtime(); - try { - let event = args.splice(0, 1)[0] as string; - const data = this._activeEvents!.emitEventAndReturn( - pluginName, - mappedPluginName, - event, - 15, - args - ); - let diff = process.hrtime(start); - await self.log.reportStat( - `emit-revent-${mappedPluginName}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat( - `emit-revent-${mappedPluginName}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - }, - emitEventAndReturnSpecific: async (serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): Promise => { - const start = process.hrtime(); - try { - let event = args.splice(0, 1)[0] as string; - const data = this._activeEvents!.emitEventAndReturn( - pluginName, - `${mappedPluginName}-${serverId}`, - event, - 15, - args - ); - let diff = process.hrtime(start); - await self.log.reportStat( - `emit-revent-${mappedPluginName}-${serverId}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat( - `emit-revent-${mappedPluginName}-${serverId}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - }, - emitEventAndReturnTimed: async ( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): Promise => { - const start = process.hrtime(); - try { - let event = args.splice(0, 1)[0] as string; - let timeoutSeconds = args.splice(0, 1)[0] as number; - const data = this._activeEvents!.emitEventAndReturn( - pluginName, - mappedPluginName, - event, - timeoutSeconds, - args - ); - let diff = process.hrtime(start); - await self.log.reportStat( - `emit-rtevent-${mappedPluginName}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat( - `emit-rtevent-${mappedPluginName}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - }, - emitEventAndReturnTimedSpecific: async (serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): Promise => { - const start = process.hrtime(); - try { - let event = args.splice(0, 1)[0] as string; - let timeoutSeconds = args.splice(0, 1)[0] as number; - const data = this._activeEvents!.emitEventAndReturn( - pluginName, - `${mappedPluginName}-${serverId}`, - event, - timeoutSeconds, - args - ); - let diff = process.hrtime(start); - await self.log.reportStat( - `emit-rtevent-${mappedPluginName}-${serverId}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat( - `emit-rtevent-${mappedPluginName}-${serverId}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - }, - receiveStream: async ( - listener: { (error: Error | null, stream: Readable): Promise }, - timeoutSeconds?: number - ): Promise => { - const start = process.hrtime(); - try { - const data = await self._activeEvents!.receiveStream( - mappedPluginName, - listener, - timeoutSeconds - ); - let diff = process.hrtime(start); - await self.log.reportStat( - `receive-stream-${mappedPluginName}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat(`receive-stream-${mappedPluginName}`, -1); - await self.log.error(exc); - throw exc; - } - }, - sendStream: async (streamId: string, stream: Readable): Promise => { - const start = process.hrtime(); - try { - await self._activeEvents!.sendStream( - mappedPluginName, - streamId, - stream - ); - let diff = process.hrtime(start); - await self.log.reportStat( - `receive-stream-${mappedPluginName}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return; - } catch (exc: any) { - await self.log.reportStat(`receive-stream-${mappedPluginName}`, -1); - await self.log.error(exc); - throw exc; - } - }, - }; + context, + listener, + error, + stream + ), + timeoutSeconds + ); + } + public async sendStream( + pluginName: string, + event: string, + streamId: string, + stream: Readable + ): Promise { + const start = process.hrtime(); + const plugin = await this.getPluginForEvent( + "sendStream", + pluginName, + event + ); + try { + await SmartFunctionCallAsync( + plugin.plugin, + plugin.plugin.sendStream, + event, + streamId, + stream + ); + const diff = process.hrtime(start); + this.log.reportStat( + `sendstream-${plugin.pluginName}-${pluginName}-${event}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + } catch (exc: any) { + this.log.reportStat( + `sendstream-${plugin.pluginName}-${pluginName}-${event}`, + -1 + ); + this.log.error("sendStream error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } } } diff --git a/nodejs/src/serviceBase/index.ts b/nodejs/src/serviceBase/index.ts new file mode 100644 index 0000000..db215d0 --- /dev/null +++ b/nodejs/src/serviceBase/index.ts @@ -0,0 +1,7 @@ +export * from "./config"; +export * from "./events"; +export * from "../base/functions"; +export * from "./logging"; +export * from "./plugins"; +export * from "./serviceBase"; +export * from "./services"; diff --git a/nodejs/src/serviceBase/logger.ts b/nodejs/src/serviceBase/logger.ts deleted file mode 100644 index 59d0982..0000000 --- a/nodejs/src/serviceBase/logger.ts +++ /dev/null @@ -1,252 +0,0 @@ -import { LoggerBase } from "../logger/logger"; -import { IPluginLogger, LogMeta } from "../interfaces/logger"; -import { Logger as DefaultLogger } from "../plugins/log-default/plugin"; -import { SBBase } from "./base"; -import { ConfigBase } from "../config/config"; -import { Events as DefaultEvents } from "../plugins/events-default/plugin"; -import { IReadyPlugin } from "../interfaces/service"; - -export class SBLogger { - private log: IPluginLogger; - private _logger: DefaultLogger; - public _loggerEvents: DefaultEvents; - private _activeLogger: LoggerBase | undefined; - constructor( - appId: string, - runningDebug: boolean, - runningLive: boolean, - CORE_PLUGIN_NAME: string - ) { - this._logger = new DefaultLogger("default-logger", "./", "./", undefined!); - SBBase.setupPlugin( - appId, - runningDebug, - runningLive, - this._logger, - {} as any - ); - this._loggerEvents = new DefaultEvents( - "default-logger-events", - "./", - "./", - this.generateNullLoggerForPlugin() - ); - this.log = this.generateLoggerForPlugin(`${CORE_PLUGIN_NAME}-logger`); - } - - public dispose() { - if (this._activeLogger !== undefined) this._activeLogger.dispose(); - this._logger.dispose(); - } - - public async setupSelf() { - const self = this; - this._loggerEvents.onEvent( - "d", - "l", - "reportStat", - async (args: Array) => { - await (self._activeLogger || self._logger).reportStat( - args[0], - args[1], - args[2] - ); - } - ); - this._loggerEvents.onEvent( - "d", - "l", - "textStat", - async (args: Array) => { - await (self._activeLogger || self._logger).reportTextStat( - args[0], - args[1], - args[2], - args[3] - ); - } - ); - this._loggerEvents.onEvent("d", "l", "debug", async (args: Array) => { - await (self._activeLogger || self._logger).debug( - args[0], - args[1], - args[2], - args[3] - ); - }); - this._loggerEvents.onEvent("d", "l", "info", async (args: Array) => { - await (self._activeLogger || self._logger).info( - args[0], - args[1], - args[2], - args[3] - ); - }); - this._loggerEvents.onEvent("d", "l", "warn", async (args: Array) => { - await (self._activeLogger || self._logger).warn( - args[0], - args[1], - args[2], - args[3] - ); - }); - this._loggerEvents.onEvent("d", "l", "error", async (args: Array) => { - await (self._activeLogger || self._logger).error( - args[0], - args[1], - args[2], - args[3] - ); - }); - this._loggerEvents.onReturnableEvent( - "d", - "l", - "fatal", - async (args: Array) => { - await (self._activeLogger || self._logger).error( - args[0], - args[1], - args[2], - args[3] - ); - console.error("FATAL: EXIT"); - self._loggerEvents.emitEvent("d", "l", "fatal-e", []); - } - ); - await this.log.info("Logger event core ready."); - } - - async setupLogger( - appId: string, - runningDebug: boolean, - runningLive: boolean, - cwd: string, - config: ConfigBase, - plugin: IReadyPlugin - ) { - if (plugin.name === "log-default") return; - await this.log.debug(`Import logging plugin: {name} from {file}`, { - name: plugin.name, - file: plugin.pluginFile, - }); - const importedPlugin = await import(plugin.pluginFile); - - await this.log.debug(`Construct logging plugin: {name}`, { - name: plugin.name, - }); - - let loggerPlugin = - new (importedPlugin.Logger as unknown as typeof LoggerBase)( - plugin.mappedName, - cwd, - plugin.pluginDir, - this.generateLoggerForPlugin(plugin.mappedName) - ); - await this.log.debug(`Create logging plugin: {name}`, { - name: plugin.name, - }); - //const importedPlugin = await import(plugin.pluginFile); - await this.log.info( - "Setting up {pluginName} ({mappedName}) as new base logging platform", - { - pluginName: plugin.name, - mappedName: plugin.mappedName, - } - ); - await this.log.info("Builing {pluginName} as new base logging platform", { - pluginName: plugin.name, - }); - SBBase.setupPlugin(appId, runningDebug, runningLive, loggerPlugin, config); - - this._activeLogger = loggerPlugin; - await this._activeLogger.init(); - await this.log.info( - "Ready {pluginName} ({mappedName}) as new base logging platform", - { - pluginName: plugin.name, - mappedName: plugin.mappedName, - } - ); - } - private generateNullLoggerForPlugin(): IPluginLogger { - return { - reportStat: async (key, value): Promise => {}, - reportTextStat: async (message, meta, hasPIData): Promise => {}, - info: async (message, meta, hasPIData): Promise => {}, - warn: async (message, meta, hasPIData): Promise => {}, - error: async ( - message: any, - meta?: any, - hasPIData?: any - ): Promise => {}, - fatal: async ( - message: any, - meta?: any, - hasPIData?: any - ): Promise => {}, - debug: async (message, meta, hasPIData): Promise => {}, - }; - } - generateLoggerForPlugin(pluginName: string): IPluginLogger { - const self = this; - return { - reportStat: async (key, value): Promise => - await self._loggerEvents.emitEvent("d", "l", "reportStat", [ - pluginName, - key, - value, - ]), - reportTextStat: async (message, meta, hasPIData): Promise => - await self._loggerEvents.emitEvent("d", "l", "textStat", [ - pluginName, - message, - meta, - hasPIData, - ]), - info: async (message, meta, hasPIData): Promise => - await self._loggerEvents.emitEvent("d", "l", "info", [ - pluginName, - message, - meta, - hasPIData, - ]), - warn: async (message, meta, hasPIData): Promise => - await self._loggerEvents.emitEvent("d", "l", "warn", [ - pluginName, - message, - meta, - hasPIData, - ]), - error: async ( - messageOrError: string | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise => - await self._loggerEvents.emitEvent("d", "l", "error", [ - pluginName, - messageOrError, - meta, - hasPIData, - ]), - fatal: async ( - messageOrError: string | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise => { - await self._loggerEvents.emitEventAndReturn("d", "l", "fatal", 5, [ - pluginName, - messageOrError, - meta, - hasPIData, - ]); - }, - debug: async (message, meta, hasPIData): Promise => - await self._loggerEvents.emitEvent("d", "l", "debug", [ - pluginName, - message, - meta, - hasPIData, - ]), - }; - } -} diff --git a/nodejs/src/serviceBase/logging.ts b/nodejs/src/serviceBase/logging.ts new file mode 100644 index 0000000..5bb8cd9 --- /dev/null +++ b/nodejs/src/serviceBase/logging.ts @@ -0,0 +1,370 @@ +import { + DEBUG_MODE, + IPluginLogger, + LogMeta, + LoggingEventTypes, + LoggingEventTypesBase, + LoggingEventTypesExlReportStat, + BSBLogging, + PluginLogger, + FilterOnType, + IPluginDefinition, + LoggingFilter, + LoggingFilterDetailed, + SBPlugins, + SBConfig, + SmartFunctionCallAsync, + SmartFunctionCallSync, + LoadedPlugin, +} from "../"; +import { Plugin as DefaultLogger } from "../plugins/logging-default/plugin"; +import { EventEmitter } from "stream"; +import { Tools } from "@bettercorp/tools/lib/Tools"; + +export class SBLogging { + private loggers: Array<{ + plugin: BSBLogging; + on?: LoggingFilter; + onTypeof: FilterOnType; + }> = []; + public logBus: EventEmitter = new EventEmitter(); + private mode: DEBUG_MODE = "development"; + private appId: string; + private cwd: string; + private sbPlugins: SBPlugins; + private log: IPluginLogger; + + constructor( + appId: string, + mode: DEBUG_MODE, + cwd: string, + sbPlugins: SBPlugins + ) { + this.appId = appId; + this.mode = mode; + this.cwd = cwd; + this.sbPlugins = sbPlugins; + this.loggers.push({ + plugin: new DefaultLogger({ + appId: this.appId, + mode: this.mode, + pluginName: "logging-default", + cwd: this.cwd, + pluginCwd: this.cwd, + config: null, + }), + onTypeof: "all", + }); + const loggingPluginName = "core-logging"; + this.log = new PluginLogger(this.mode, loggingPluginName, this); + + if (this.mode !== "production") { + this.logBus.on("debug", (plugin, message, meta) => { + this.triggerLogEvent("debug", plugin, message, meta); + }); + } + this.logBus.on("reportStat", (plugin, key, value) => { + this.triggerLogEvent("reportStat", plugin, key, value); + }); + this.logBus.on("reportTextStat", (plugin, message, meta) => { + this.triggerLogEvent("reportTextStat", plugin, message, meta); + }); + this.logBus.on("info", (plugin, message, meta) => { + this.triggerLogEvent("info", plugin, message, meta); + }); + this.logBus.on("warn", (plugin, message, meta) => { + this.triggerLogEvent("warn", plugin, message, meta); + }); + this.logBus.on("error", (plugin, message, meta) => { + this.triggerLogEvent("error", plugin, message, meta); + }); + } + + public dispose() { + for ( + let loggerIndex = 0; + loggerIndex < this.loggers.length; + loggerIndex++ + ) { + if (this.loggers[loggerIndex].plugin.dispose !== undefined) + SmartFunctionCallSync( + this.loggers[loggerIndex].plugin, + this.loggers[loggerIndex].plugin.dispose + ); + } + this.logBus.removeAllListeners(); + } + + private getPluginsMatchingLogEvent(log: LoggingEventTypes, plugin: string) { + return this.loggers.filter((logger) => { + if (Tools.isNullOrUndefined(logger.plugin)) return false; + if (Tools.isNullOrUndefined(logger.on)) return true; + switch (logger.onTypeof) { + case "all": + return true; + case "events": + return (logger.on as Array).includes(log); + case "eventsState": + if ( + Tools.isNullOrUndefined( + (logger.on as Record)[log] + ) + ) + return false; + return (logger.on as Record)[log]; + case "eventsPlugins": + if ( + Tools.isNullOrUndefined( + (logger.on as Record>)[log] + ) + ) + return false; + return (logger.on as Record>)[ + log + ].includes(plugin); + case "eventsDetailed": + if ( + Tools.isNullOrUndefined((logger.on as LoggingFilterDetailed)[log]) + ) + return false; + if ((logger.on as LoggingFilterDetailed)[log].enabled !== true) + return false; + return (logger.on as LoggingFilterDetailed)[log].plugins.includes( + plugin + ); + } + }); + } + + private async triggerLogEventReportStat( + loggerPlugin: BSBLogging, + plugin: string, + key: string, + value: number + ): Promise { + await SmartFunctionCallAsync( + loggerPlugin, + loggerPlugin.reportStat, + plugin, + key, + value + ); + } + + private async triggerLogEvent( + logAs: "reportStat", + plugin: string, + key: string, + value: number + ): Promise; + private async triggerLogEvent( + logAs: LoggingEventTypesExlReportStat, + plugin: string, + message: T, + meta: LogMeta + ): Promise; + private async triggerLogEvent( + logAs: LoggingEventTypes, + plugin: string, + messageOrKey: T | string, + metaOrValue: LogMeta | number + ): Promise { + for (const logger of this.getPluginsMatchingLogEvent(logAs, plugin)) { + if (logAs === "reportStat") { + await this.triggerLogEventReportStat( + logger.plugin, + plugin, + messageOrKey as string, + metaOrValue as number + ); + continue; + } + + let method; + switch (logAs) { + case "reportTextStat": + method = logger.plugin.reportTextStat; + break; + case "debug": + method = logger.plugin.debug; + break; + case "info": + method = logger.plugin.info; + break; + case "warn": + method = logger.plugin.warn; + break; + case "error": + method = logger.plugin.error; + break; + } + + if (method) { + await SmartFunctionCallAsync( + logger.plugin, + method, + plugin, + messageOrKey as string, + metaOrValue as LogMeta + ); + } + } + } + public async init(sbConfig: SBConfig) { + this.log.debug("INIT SBLogging"); + const plugins = await sbConfig.getLoggingPlugins(); + for (const plugin of Object.keys(plugins)) { + await this.addLogger( + sbConfig, + { + name: plugin, + package: plugins[plugin].package, + plugin: plugins[plugin].plugin, + version: "", + }, + plugins[plugin].filter + ); + } + } + + public async run() { + if (this.loggers.length === 1) return; + // we want to see if any plugins (ignore logging-default) are listening to all logs - it so, there is no reason to keep the logging-default plugin, so we can dispose and remove it + const pluginsListeningToAll = this.loggers.filter((logger) => { + if (Tools.isNullOrUndefined(logger.on)) return false; + if (logger.onTypeof === "all") return true; + return false; + }); + if (pluginsListeningToAll.length > 0) { + const loggerIndex = this.loggers.findIndex((logger) => { + return logger.plugin.pluginName === "logging-default"; + }); + if (loggerIndex !== -1) { + if (this.loggers[loggerIndex].plugin.dispose !== undefined) + SmartFunctionCallSync( + this.loggers[loggerIndex].plugin, + this.loggers[loggerIndex].plugin.dispose + ); + this.loggers.splice(loggerIndex, 1); + } + } + } + + public async addPlugin( + plugin: IPluginDefinition, + reference: LoadedPlugin<"logging">, + config: any, + filter?: LoggingFilter + ) { + this.log.debug(`Construct logging plugin: {name}`, { + name: plugin.name, + }); + + const loggerPlugin = new reference.plugin({ + appId: this.appId, + mode: this.mode, + pluginName: reference.name, + cwd: this.cwd, + pluginCwd: reference.pluginCWD, + config: config, + }); + this.log.info("Adding {pluginName} as logger with filter: ", { + pluginName: plugin.name, + //filters: filter + }); + let logAsType: FilterOnType = "all"; + + if (filter) { + if (Array.isArray(filter)) { + logAsType = "events"; + } else if (typeof filter === "object") { + const methods = Object.keys(LoggingEventTypesBase); + for (const method of methods) { + if ( + (filter as unknown as Record)[method] !== undefined + ) { + const methodValue = filter[method as keyof typeof filter]; + if (typeof methodValue === "boolean") { + logAsType = "eventsState"; + } else if (Array.isArray(methodValue)) { + logAsType = "eventsPlugins"; + } else if (typeof methodValue === "object") { + logAsType = "eventsDetailed"; + } + } + } + } + } + this.loggers.push({ + plugin: loggerPlugin, + on: filter, + onTypeof: logAsType, + }); + + this.log.info("Ready {pluginName} ({mappedName})", { + pluginName: plugin.plugin, + mappedName: plugin.name, + }); + + await SmartFunctionCallAsync(loggerPlugin, loggerPlugin.init); + + return loggerPlugin; + } + + private async addLogger( + sbConfig: SBConfig, + plugin: IPluginDefinition, + filter?: LoggingFilter + ) { + this.log.debug("Add logger {name} from ({package}){file}", { + package: plugin.package ?? "-", + name: plugin.name, + file: plugin.plugin, + }); + if (plugin.name === "logging-default") return; + this.log.debug(`Import logging plugin: {name} from ({package}){file}`, { + package: plugin.package ?? "-", + name: plugin.name, + file: plugin.plugin, + }); + + const newPlugin = await this.sbPlugins.loadPlugin<"logging">( + this.log, + plugin.package ?? null, + plugin.plugin, + plugin.name + ); + if (newPlugin === null) { + this.log.error( + "Failed to import logging plugin: {name} from ({package}){file}", + { + package: plugin.package ?? "-", + name: plugin.name, + file: plugin.plugin, + } + ); + return; + } + + this.log.debug(`Get plugin config: {name}`, { + name: plugin.name, + }); + + let pluginConfig = + (await sbConfig.getPluginConfig("logging", plugin.name)) ?? null; + + if ( + this.mode !== "production" && + !Tools.isNullOrUndefined(newPlugin) && + !Tools.isNullOrUndefined(newPlugin.serviceConfig) && + Tools.isObject(newPlugin.serviceConfig) && + !Tools.isNullOrUndefined(newPlugin.serviceConfig.validationSchema) + ) { + this.log.debug("Validate plugin config: {name}", { name: plugin.name }); + pluginConfig = + newPlugin.serviceConfig.validationSchema.parse(pluginConfig); + } + + await this.addPlugin(plugin, newPlugin, pluginConfig, filter); + } +} diff --git a/nodejs/src/serviceBase/plugins.ts b/nodejs/src/serviceBase/plugins.ts index 0e1ebc4..bf9ff5d 100644 --- a/nodejs/src/serviceBase/plugins.ts +++ b/nodejs/src/serviceBase/plugins.ts @@ -1,233 +1,125 @@ -import { readdirSync, statSync, existsSync, readFileSync } from "fs"; +import { existsSync, readFileSync } from "fs"; import { join } from "path"; -import { IPluginLogger } from "../interfaces/logger"; -import { IPluginDefinition, IReadyPlugin } from "../interfaces/service"; +import { + PluginType, + PluginTypeDefinitionRef, + IPluginLogger, + BSBError, + LoadedPlugin, + BSBPluginConfig, + BSBPluginConfigRef, +} from "../"; export class SBPlugins { - public static getPluginType(name: string): IPluginDefinition | null { - const pluginLow = name.toLowerCase(); - if (pluginLow.indexOf("service-") === 0) return IPluginDefinition.service; - if (pluginLow.indexOf("config-") === 0) return IPluginDefinition.config; - if (pluginLow.indexOf("events-") === 0) return IPluginDefinition.events; - if (pluginLow.indexOf("log-") === 0 || pluginLow.indexOf("logs-") === 0) - return IPluginDefinition.logging; - return null; - } + protected cwd: string; + protected pluginDir: string; + protected devMode: boolean; - private static async findPluginsFiles( - coreLogger: IPluginLogger, - path: string, - version: string, - libOnly = false, - pluginDir: string - ): Promise> { - const arrOfPlugins: Array = []; + constructor(cwd: string, devMode: boolean) { + this.cwd = cwd; + this.devMode = devMode; + if ( + typeof process.env.BSB_PLUGIN_DIR == "string" && + process.env.BSB_PLUGIN_DIR.length > 3 + ) { + this.pluginDir = process.env.BSB_PLUGIN_DIR; + } else { + this.pluginDir = join(this.cwd, "./node_modules/"); + } + } - await coreLogger.debug(`FIND: FIND plugins in [{path}]`, { path }); - for (const dirPluginFolderName of readdirSync(path)) { - const thisFullPath = join(path, dirPluginFolderName); - if (!statSync(thisFullPath).isDirectory()) { - await coreLogger.debug(`FIND: IGNORE [{thisFullPath}] Not a DIR`, { - thisFullPath, - }); - continue; - } - if (dirPluginFolderName.indexOf("-") === 0) { - await coreLogger.debug( - `FIND: IGNORE [{thisFullPath}] Defined disabled`, - { thisFullPath } - ); - continue; - } - if (libOnly) { - if (dirPluginFolderName.indexOf("-test") >= 0) { - await coreLogger.debug( - `FIND: IGNORE [{thisFullPath}] Defined test plugin to ignore`, - { thisFullPath } - ); - continue; - } + public async loadPlugin< + NamedType extends PluginType, + ClassType extends PluginTypeDefinitionRef = PluginTypeDefinitionRef + >( + log: IPluginLogger, + npmPackage: string | null, + plugin: string, + name: string + ): Promise | null> { + log.debug(`PLUGIN {name} from {package} try load as {pluginName}`, { + name: plugin, + pluginName: name, + package: npmPackage ?? "self", + }); + const nodeModulesLib = npmPackage !== null; + let pluginPath = ""; + let pluginCWD = this.cwd; + let version = "0.0.0"; + if (!nodeModulesLib) { + if (this.devMode) { + pluginPath = join(this.cwd, "./src/plugins/" + plugin); + if (!existsSync(pluginPath)) pluginPath = ""; } - - let pluginDef = SBPlugins.getPluginType(dirPluginFolderName); - if (pluginDef === null) { - await coreLogger.debug( - `FIND: NOT VALID [{dirPluginFolderName}] in: {thisFullPath}`, - { dirPluginFolderName, thisFullPath } - ); - continue; + if (pluginPath == "") { + pluginPath = join(this.cwd, "./lib/plugins/" + plugin); } + } else { + pluginCWD = join(this.pluginDir, npmPackage); + pluginPath = join(pluginCWD, "./lib/plugins/", plugin); - let pluginFile = join(thisFullPath, "plugin.js"); - if (!existsSync(pluginFile)) pluginFile = join(thisFullPath, "plugin.ts"); - - if (!existsSync(pluginFile)) { - await coreLogger.debug( - `FIND: IGNORE [{thisFullPath}] Not a valid plugin`, - { thisFullPath } - ); - continue; - } - - let pluginInstallerFile: string | null = join( - thisFullPath, - "sec.config.js" - ); - - if (!existsSync(pluginInstallerFile)) - pluginInstallerFile = join(thisFullPath, "sec.config.ts"); - - if (!existsSync(pluginInstallerFile)) pluginInstallerFile = null; - await coreLogger.debug( - `FIND: READY [{dirPluginFolderName}] in: {thisFullPath}`, - { dirPluginFolderName, thisFullPath } + const packageJsonPath = join(pluginCWD, "./package.json"); + const packageJSON = JSON.parse( + readFileSync(packageJsonPath, "utf-8").toString() ); - arrOfPlugins.push({ - pluginDefinition: pluginDef, - name: dirPluginFolderName, - mappedName: dirPluginFolderName, - version: version, - pluginFile, - installerFile: pluginInstallerFile, - pluginDir: pluginDir, + version = packageJSON.version; + } + if (!existsSync(pluginPath)) { + log.error(`PLUGIN {name} in {package} not found`, { + name: plugin, + package: npmPackage ?? "self", }); + return null; } - return arrOfPlugins; - } - private static async findPluginsInBase( - coreLogger: IPluginLogger, - path: string, - libOnly = false - ): Promise> { - const pluginJson = JSON.parse( - readFileSync(join(path, "./package.json"), "utf8").toString() - ); - if (pluginJson.bsb_project !== true) { - await coreLogger.debug("FIND: IGNORE AS NOT BSB PROJECT"); - return []; - } + log.debug(`Plugin {name}: attempt to load from {path} as {pluginName}`, { + name: plugin, + path: pluginPath, + pluginName: name, + }); - let innerPluginLib = join(path, "./src"); - if ( - libOnly || - !existsSync(innerPluginLib) || - !statSync(innerPluginLib).isDirectory() - ) { - innerPluginLib = join(path, "./lib"); - } - if ( - !existsSync(innerPluginLib) || - !statSync(innerPluginLib).isDirectory() - ) { - await coreLogger.debug( - `FIND: IGNORE [{innerPluginLib}] No src/lib dir in package`, - { innerPluginLib } - ); - return []; - } - const innerPluginLibPlugin = join(innerPluginLib, "./plugins"); - if ( - !existsSync(innerPluginLibPlugin) || - !statSync(innerPluginLibPlugin).isDirectory() - ) { - await coreLogger.debug( - `FIND: IGNORE [{innerPluginLibPlugin}] No inner plugins dir`, - { innerPluginLibPlugin } - ); - return []; + let pluginFile = join(pluginPath, "./plugin.js"); + let serviceConfigDef: BSBPluginConfig | null = null; + //if (this.devMode) { + const tsPluginFile = join(pluginPath, "./plugin.ts"); + if (existsSync(tsPluginFile)) { + log.debug("PLUGIN {pluginName} running in development mode", { + pluginName: name, + }); + pluginFile = tsPluginFile; } - const packageVersion = pluginJson.version; - return await SBPlugins.findPluginsFiles( - coreLogger, - innerPluginLibPlugin, - packageVersion, - libOnly, - path - ); - } - - public static async findNPMPlugins( - coreLogger: IPluginLogger, - cwd: string - ): Promise> { - let arrOfPlugins: Array = []; - - if (!existsSync(join(cwd, "./package.json"))) { - await coreLogger.error(`Unable to find package.json in {pakDir}`, { - pakDir: join(cwd, "./package.json"), + if (!existsSync(pluginFile)) + throw new BSBError("PLUGIN {pluginName} not found at {location}", { + pluginName: name, + location: pluginFile, }); - return []; - } - const npmPluginsDir = join(cwd, "./node_modules"); - await coreLogger.info(`FIND: NPM plugins in: {npmPluginsDir}`, { - npmPluginsDir, - }); - if (!existsSync(npmPluginsDir)) { - await coreLogger.error( - `FIND: NPM plugins dir does not exist: {npmPluginsDir}`, - { npmPluginsDir } - ); - return []; - } - for (const dirFileWhat of readdirSync(npmPluginsDir)) { - try { - const pluginPath = join(npmPluginsDir, dirFileWhat); - if (dirFileWhat.indexOf(".") === 0) { - continue; - } - if (dirFileWhat.indexOf("@") === 0) { - await coreLogger.debug(`FIND: GROUP [{dirFileWhat}] {pluginPath}`, { - dirFileWhat, - pluginPath, - }); - for (const groupPluginName of readdirSync(pluginPath)) { - if (groupPluginName.indexOf(".") === 0) { - continue; - } - const groupPluginPath = join(pluginPath, groupPluginName); - await coreLogger.debug( - `FIND: CHECK [{dirFileWhat}/{groupPluginName}] {groupPluginPath}`, - { dirFileWhat, groupPluginName, groupPluginPath } - ); - if (statSync(groupPluginPath).isDirectory()) { - arrOfPlugins = arrOfPlugins.concat( - await SBPlugins.findPluginsInBase( - coreLogger, - groupPluginPath, - true - ) - ); - } - } - } else { - await coreLogger.debug(`FIND: CHECK [{dirFileWhat}] {pluginPath}`, { - dirFileWhat, - pluginPath, - }); - if (statSync(pluginPath).isDirectory()) { - arrOfPlugins = arrOfPlugins.concat( - await SBPlugins.findPluginsInBase(coreLogger, pluginPath, true) - ); - } - } - } catch (err: any) { - await coreLogger.error("{message}", { - message: err.message || err.toString(), - }); - } - } + const importedPlugin = await import(pluginFile); - return arrOfPlugins; - } + if (importedPlugin.Plugin === undefined) + throw new BSBError( + "PLUGIN {pluginName} does not export a Plugin class - so possibly not a valid BSB Plugin", + { + pluginName: name, + } + ); + if (importedPlugin.Config !== undefined) + serviceConfigDef = + new (importedPlugin.Config as typeof BSBPluginConfigRef)( + this.cwd, + pluginCWD, + name + ); - public static async findLocalPlugins( - coreLogger: IPluginLogger, - cwd: string, - CLIONLY: boolean - ): Promise> { - return await SBPlugins.findPluginsInBase(coreLogger, cwd, CLIONLY); + return { + name: name, + ref: plugin, + version: version, + serviceConfig: serviceConfigDef, + plugin: importedPlugin.Plugin, + pluginCWD: pluginCWD, + pluginPath: pluginPath, + }; } } diff --git a/nodejs/src/serviceBase/serviceBase.ts b/nodejs/src/serviceBase/serviceBase.ts index d241c99..6c11af8 100644 --- a/nodejs/src/serviceBase/serviceBase.ts +++ b/nodejs/src/serviceBase/serviceBase.ts @@ -1,63 +1,68 @@ -import { IPluginLogger, LogMeta } from "../interfaces/logger"; -import { SBLogger } from "./logger"; -import { IPluginDefinition, IReadyPlugin } from "../interfaces/service"; -import { SBPlugins } from "./plugins"; -import { SBServices } from "./services"; -import { IDictionary } from "@bettercorp/tools/lib/Interfaces"; -import { SBConfig } from "./config"; -import path from "path"; -import fs from "fs"; -import { SBEvents } from "./events"; +import { + DEBUG_MODE, + IPluginLogger, + LogMeta, + SBLogging, + SBPlugins, + SBServices, + SBConfig, + PluginLogger, + SmartFunctionCallSync, + SBEvents, + PluginTypeDefinitionRef, + BSBConfig, + BSBError, + BSBLogging, + BSBEvents, + BSBService, +} from "../"; +import { Tools } from "@bettercorp/tools/lib/Tools"; import { randomUUID } from "crypto"; import { hostname } from "os"; -import { Tools } from "@bettercorp/tools/lib/Tools"; +import { IDictionary } from "@bettercorp/tools/lib/Interfaces"; -export enum BOOT_STAT_KEYS { - BSB = "BSB", - SELF = "SELF", - PLUGINS = "PLUGINS", - CONFIG = "CONFIG", - LOGGER = "LOGGER", - EVENTS = "EVENTS", - SERVICES = "SERVICES", - INIT = "INIT", - RUN = "RUN", -} +export const BOOT_STAT_KEYS = { + BSB: "BSB", + SELF: "SELF", + PLUGINS: "PLUGINS", + CONFIG: "CONFIG", + LOGGING: "LOGGER", + EVENTS: "EVENTS", + SERVICES: "SERVICES", + INIT: "INIT", + RUN: "RUN", +} as const; +export type BootStatKeys = (typeof BOOT_STAT_KEYS)[keyof typeof BOOT_STAT_KEYS]; export const NS_PER_SEC = 1e9; export const MS_PER_NS = 1e-6; const TIMEKEEPLOG = "[TIMER] {timerName} took ({nsTime}ns) ({msTime}ms)"; export class ServiceBase { - private _packJsonFile!: string; - private _bsbPackJsonFile!: string; - private _appVersion: string = "0.0.1-debug"; - private _bsbVersion: string = "0.0.1-debug"; - - private _runningDebug: boolean = true; - private _runningLive: boolean = false; + private mode: DEBUG_MODE = "development"; private readonly _CORE_PLUGIN_NAME = "core"; private readonly _appId; - private _logger: SBLogger; - private _config!: SBConfig; - private _events!: SBEvents; - private _services!: SBServices; - - private plugins: Array = []; + private logging: SBLogging; + private plugins: SBPlugins; + private config: SBConfig; + private events: SBEvents; + private log: IPluginLogger; + private services!: SBServices; private cwd!: string; - private log!: IPluginLogger; - private _keeps: IDictionary<[number, number]> = {}; - private _heartbeat!: NodeJS.Timer; - private _startKeep(stepName: BOOT_STAT_KEYS) { + private _keeps: IDictionary<[number, number]> = { + BSB: process.hrtime(), + }; + private _heartbeat!: ReturnType; + private _startKeep(stepName: BootStatKeys) { if (this.log !== undefined) this.log.debug("Starting timer for {log}", { log: stepName }); this._keeps[stepName] = process.hrtime(); } - private async _outputKeep(stepName: BOOT_STAT_KEYS) { - let diff = process.hrtime(this._keeps[stepName] || undefined); - let logMeta: LogMeta = { + private async _outputKeep(stepName: BootStatKeys) { + const diff = process.hrtime(this._keeps[stepName] || undefined); + const logMeta: LogMeta = { nsTime: diff[0] * NS_PER_SEC + diff[1], msTime: (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS, timerName: stepName, @@ -65,19 +70,53 @@ export class ServiceBase { await this.log.info(TIMEKEEPLOG, logMeta); await this.log.reportStat(stepName, logMeta.nsTime as number); } - constructor(debug: boolean = true, live: boolean = false, cwd: string) { + constructor( + debug: boolean = true, // Enable debug logging (true): disabled debug logging + live: boolean = false, // Disable development mode (true): changes the way plugins are imported + cwd: string, // Current working directory: The current directory where you are running from + config: typeof SBConfig = SBConfig, // Config handler: Allows you to override default behavour, + plugins: typeof SBPlugins = SBPlugins, // Plugins handler: Allows you to override default behavour, + logging: typeof SBLogging = SBLogging, // Logging handler: Allows you to override default behavour, + events: typeof SBEvents = SBEvents, // Events handler: Allows you to override default behavour, + services: typeof SBServices = SBServices // Services handler: Allows you to override default behavour + ) { + this._startKeep(BOOT_STAT_KEYS.SELF); this.cwd = cwd; - this._runningDebug = debug; - this._runningLive = live; + if (live === false) this.mode = "development"; + else if (debug === true) this.mode = "production-debug"; + else this.mode = "production"; + this._appId = `${hostname()}-${randomUUID()}`; - this._startKeep(BOOT_STAT_KEYS.BSB); - // Initial boot will use the default logger which doesn't require anything special. - // Once plugin search has been completed, then we can find the defined logger, or re-create the default logger with the correct config definition. - this._logger = new SBLogger( + + this.plugins = new plugins(this.cwd, this.mode === "development"); + this.logging = new logging(this._appId, this.mode, this.cwd, this.plugins); + this.events = new events( this._appId, - this._runningDebug, - this._runningLive, - this._CORE_PLUGIN_NAME + this.mode, + this.cwd, + this.plugins, + this.logging + ); + this.config = new config( + this._appId, + this.mode, + this.cwd, + this.logging, + this.plugins + ); + + this.log = new PluginLogger( + this.mode, + this._CORE_PLUGIN_NAME, + this.logging + ); + this.log.info("Starting BSB"); + this.services = new services( + this._appId, + this.mode, + this.cwd, + this.plugins, + this.logging ); process.stdin.resume(); //so the program will not close instantly @@ -98,200 +137,56 @@ export class ServiceBase { process.on("uncaughtException", (e) => self.dispose(3, "uncaught exception", e) ); - } - public async setupSelf() { - this._startKeep(BOOT_STAT_KEYS.SELF); - await this._logger.setupSelf(); - const self = this; - await this._logger._loggerEvents.onEvent("d", "l", "fatal-e", async () => - self.dispose(4, "fatal event") - ); - this.log = this._logger.generateLoggerForPlugin(this._CORE_PLUGIN_NAME); - this._config = new SBConfig(this.log, this.cwd); - this._events = new SBEvents( - this._logger.generateLoggerForPlugin(this._CORE_PLUGIN_NAME + "-events") - ); - this._services = new SBServices( - this._logger.generateLoggerForPlugin(this._CORE_PLUGIN_NAME + "-services") - ); - await this.log.info("BOOT IN: {local}", { local: this.cwd }); - - this._packJsonFile = path.join(this.cwd, "./package.json"); - if (!fs.existsSync(this._packJsonFile)) { - await this.log.fatal("PACKAGE.JSON FILE NOT FOUND IN {cwd}", { cwd: this.cwd }); - return; - } - this._appVersion = JSON.parse( - fs.readFileSync(this._packJsonFile, "utf8").toString() - ).version; - - this._bsbPackJsonFile = path.join( - this.cwd, - "./node_modules/@bettercorp/service-base/package.json" - ); - if (fs.existsSync(this._bsbPackJsonFile)) { - this._bsbVersion = JSON.parse( - fs.readFileSync(this._bsbPackJsonFile, "utf8").toString() - ).version; - } - - await this.log.info( - `BOOT UP: @{version} with BSB@{BSBVersion} and debugging {debugMode} while running {runningLive}`, - { - version: this._appVersion, - BSBVersion: this._bsbVersion, - debugMode: this._runningDebug, - runningLive: this._runningLive, - } - ); this._outputKeep(BOOT_STAT_KEYS.SELF); } - public async setupPlugins(cwd: string, CLIONLY = false): Promise { - this._startKeep(BOOT_STAT_KEYS.PLUGINS); - await this.log.info("INIT PLUGIN LOCATOR"); - let dirsToSearch: Array = [this.cwd]; - this.plugins = []; - if ( - process.env.BSB_CONTAINER == "true" && - `${process.env.BSB_PLUGIN_DIR || ""}` !== "" - ) { - await this.log.info( - "NOTE: RUNNING IN BSB CONTAINER - PLUGIN LOCATION ALTERED" - ); - dirsToSearch = dirsToSearch.concat( - (process.env.BSB_PLUGIN_DIR || "").split(",") - ); - } - if (dirsToSearch.length > 0) { - await this.log.info("Find all plugins: {dirs}", { - dirs: dirsToSearch, - }); - - for (let dir of dirsToSearch) { - await this.log.info("Find plugins: {dir}", { dir }); - this.plugins = this.plugins.concat( - await SBPlugins.findNPMPlugins(this.log, dir) - ); - } - } - await this.log.info(`Performing a node_modules local search.`); - this.plugins = this.plugins.concat( - await SBPlugins.findLocalPlugins(this.log, cwd, CLIONLY) - ); - - await this.log.info(`{len} plugins found: {plugins}`, { - len: this.plugins.length, - plugins: this.plugins.map((x) => x.name).join(","), - }); - for (let plugin of this.plugins) { - await this.log.debug(`Plugin {pluginName}: {pluginDir}`, { - pluginName: plugin.name, - pluginDir: plugin.pluginDir, - }); - } - - this._outputKeep(BOOT_STAT_KEYS.PLUGINS); - this.cwd = cwd; - } - - public async setupConfig() { + public async init() { this._startKeep(BOOT_STAT_KEYS.CONFIG); - await this._config.findConfigPlugin(this.plugins); - let configPluginName = this._config.getPluginName(); - await this._config.setupConfigPlugin( - this._logger.generateLoggerForPlugin(configPluginName), - this._appId, - this._runningDebug, - this._runningLive, - this.plugins - ); - this.plugins = await this._config.mapPlugins(this.plugins); + await this.config.init(); this._outputKeep(BOOT_STAT_KEYS.CONFIG); - } - public async setupLogger() { - this._startKeep(BOOT_STAT_KEYS.LOGGER); - let loggingPlugin = await this._config.findPluginByType( - this.plugins, - "log-default", - IPluginDefinition.logging - ); - await this._config.ImportAndMigratePluginConfig(loggingPlugin); - await this._logger.setupLogger( - this._appId, - this._runningDebug, - this._runningLive, - this.cwd, - this._config.appConfig, - loggingPlugin - ); - this._outputKeep(BOOT_STAT_KEYS.LOGGER); - } - public async setupEvents() { + this._startKeep(BOOT_STAT_KEYS.LOGGING); + await this.logging.init(this.config); + this._outputKeep(BOOT_STAT_KEYS.LOGGING); this._startKeep(BOOT_STAT_KEYS.EVENTS); - let eventsPlugin = await this._config.findPluginByType( - this.plugins, - "events-default", - IPluginDefinition.events - ); - await this._config.ImportAndMigratePluginConfig(eventsPlugin); - await this._events.setupEvents( - this._appId, - this._runningDebug, - this._runningLive, - this.cwd, - this._config.appConfig, - eventsPlugin, - this._logger.generateLoggerForPlugin(eventsPlugin.mappedName) - ); + await this.events.init(this.config, this.logging); this._outputKeep(BOOT_STAT_KEYS.EVENTS); - } - public async setupServices() { + // SERVICES ORDERING this._startKeep(BOOT_STAT_KEYS.SERVICES); - const self = this; - await this._services.setupServicePlugins( - this._appId, - this._runningDebug, - this._runningLive, - this.cwd, - this.plugins, - this._config.appConfig, - (a) => self._config.ImportAndMigratePluginConfig(a), - (a, b) => self._events.generateEventsForService(a, b), - (a) => self._logger.generateLoggerForPlugin(a) - ); + await this.services.setup(this.config, this.logging, this.events); this._outputKeep(BOOT_STAT_KEYS.SERVICES); - } - public async initPlugins() { this._startKeep(BOOT_STAT_KEYS.INIT); - await this._services.servicesInit(this._config.appConfig); + await this.services.init(this.config); this._outputKeep(BOOT_STAT_KEYS.INIT); } - public async runPlugins() { + public async run() { this._startKeep(BOOT_STAT_KEYS.RUN); - await this._services.servicesRun(this._config.appConfig); + await this.logging.run(); + await this.events.run(); + await this.services.run(this.config); + this.log.info("Disposing config for memory cleanup and safety"); + this.config.dispose(); this._outputKeep(BOOT_STAT_KEYS.RUN); + + this._heartbeat = setInterval( + async () => await this.heartBeat(), + 60 * 60 * 1000 + ); + await this.heartBeat(); + this._outputKeep(BOOT_STAT_KEYS.BSB); } private async heartBeat() { - await this.log.debug("[HEARTBEAT] ({appId}) ({time})", { + this.log.debug("[HEARTBEAT] ({appId}) ({time})", { appId: this._appId, time: new Date().toISOString(), }); } - async run() { - const self = this; - this._heartbeat = setInterval( - async () => await self.heartBeat(), - 60 * 60 * 1000 - ); - await self.heartBeat(); - this._outputKeep(BOOT_STAT_KEYS.BSB); - } + private _disposing: boolean = false; async dispose(eCode: number = 0, reason: string, extraData?: any) { + console.error(reason, extraData); if (this._disposing) return; this._disposing = true; @@ -316,18 +211,18 @@ export class ServiceBase { reason, } ); - if (!Tools.isNullOrUndefined(extraData)) await this.log.error(extraData); + //if (!Tools.isNullOrUndefined(extraData)) this.log.error(extraData); } clearInterval(this._heartbeat); try { await this.log.warn("Disposing services"); - this._services.dispose(); + SmartFunctionCallSync(this.services, this.services.dispose); await this.log.warn("Disposing events"); - this._events.dispose(); + //this.events.dispose(); await this.log.warn("Disposing config"); - this._config.dispose(); + //SmartFunctionCall(this.config.dispose); await this.log.warn("Disposing logger"); - this._logger.dispose(); + //SmartFunctionCall(this.logging.dispose); } catch (exc) { console.error(exc); console.error("Disposing forcefully!"); @@ -336,5 +231,116 @@ export class ServiceBase { console.warn("BSB Disposed successfully. exiting code " + eCode); process.exit(eCode); } + + public async setConfigPlugin(name: string, reference: typeof BSBConfig) { + if (this._keeps[BOOT_STAT_KEYS.CONFIG] !== undefined) + throw new BSBError( + "Cannot add config plugin as config already initialized", + {} + ); + return this.config.setConfigPlugin({ + serviceConfig: null, + plugin: reference as unknown as PluginTypeDefinitionRef<"config">, + pluginCWD: this.cwd, + pluginPath: "", + version: "0.0.0", + ref: name, + name, + }); + } + + public async addService( + name: string, + plugin: typeof BSBService, + config: object | any + ) { + if (this._keeps[BOOT_STAT_KEYS.SERVICES] !== undefined) + throw new BSBError( + "Cannot add service plugin as service already called", + {} + ); + return await this.services.addPlugin( + this.config, + this.logging, + this.events, + { + name, + plugin: name, + package: null, + version: "0.0.0", + }, + { + serviceConfig: config, + plugin: plugin as unknown as PluginTypeDefinitionRef<"service">, + pluginCWD: this.cwd, + pluginPath: "", + version: "0.0.0", + ref: name, + name, + }, + config + ); + } + + public async addEvents( + name: string, + plugin: typeof BSBEvents, + config: object | any + ) { + if (this._keeps[BOOT_STAT_KEYS.EVENTS] !== undefined) + throw new BSBError( + "Cannot add events plugin as events already initialized", + {} + ); + return await this.events.addPlugin( + this.logging, + { + name, + plugin: name, + package: null, + version: "0.0.0", + }, + { + serviceConfig: config, + plugin: plugin as unknown as PluginTypeDefinitionRef<"events">, + pluginCWD: this.cwd, + pluginPath: "", + version: "0.0.0", + ref: name, + name, + }, + config + ); + } + + public async addLogging( + name: string, + plugin: typeof BSBLogging, + config: object | any + ) { + if (this._keeps[BOOT_STAT_KEYS.LOGGING] !== undefined) + throw new BSBError( + "Cannot add logging plugin as logging already initialized", + {} + ); + return await this.logging.addPlugin( + { + name, + plugin: name, + package: null, + version: "0.0.0", + }, + { + serviceConfig: config, + plugin: plugin as unknown as PluginTypeDefinitionRef<"logging">, + pluginCWD: this.cwd, + pluginPath: "", + version: "0.0.0", + ref: name, + name, + }, + config + ); + } } export default ServiceBase; diff --git a/nodejs/src/serviceBase/services.ts b/nodejs/src/serviceBase/services.ts index 0c4c7cf..dabaddd 100644 --- a/nodejs/src/serviceBase/services.ts +++ b/nodejs/src/serviceBase/services.ts @@ -1,149 +1,325 @@ -import { IPluginLogger } from "../interfaces/logger"; -import { IPluginDefinition, IReadyPlugin } from "../interfaces/service"; -import { IServiceEvents } from "../interfaces/events"; -import { SBBase } from "./base"; -import { ServicesBase } from "../service/service"; -import { ConfigBase } from "../config/config"; -import { ErrorMessages } from "../interfaces/static"; +import { + BSBService, + PluginLogger, + IPluginLogger, + DEBUG_MODE, + SBConfig, + SBEvents, + SmartFunctionCallAsync, + SmartFunctionCallSync, + SBLogging, + SBPlugins, + IPluginDefinition, + BSBError, + BSBServiceClient, + PluginEvents, + LoadedPlugin, +} from "../"; +import { Tools } from "@bettercorp/tools/lib/Tools"; export class SBServices { - private _activeServices: Array = []; + private _activeServices: Array = []; + + private mode: DEBUG_MODE = "development"; + private appId: string; + private cwd: string; + private sbPlugins: SBPlugins; private log: IPluginLogger; - constructor(log: IPluginLogger) { - this.log = log; + constructor( + appId: string, + mode: DEBUG_MODE, + cwd: string, + sbPlugins: SBPlugins, + sbLogging: SBLogging + ) { + this.appId = appId; + this.mode = mode; + this.cwd = cwd; + this.sbPlugins = sbPlugins; + const eventsPluginName = "core-services"; + this.log = new PluginLogger(this.mode, eventsPluginName, sbLogging); } + public dispose() { - for (let service of this._activeServices) { + for (const service of this._activeServices) { this.log.warn("disposing {service}", { service: service.pluginName }); - if (service !== undefined) service.dispose(); + for (const client of service._clients) { + SmartFunctionCallSync(client, client.dispose); + } + SmartFunctionCallSync(service, service.dispose); } } - async setupServicePlugins( - appId: string, - runningDebug: boolean, - runningLive: boolean, - cwd: string, - plugins: Array, - appConfig: ConfigBase, - ImportAndMigratePluginConfig: { (plugin: IReadyPlugin): Promise }, - generateEventsForService: { - (pluginName: string, mappedPluginName: string): IServiceEvents< - any, - any, - any, - any, - any, - any - >; - }, - generateLoggerForPlugin: { (pluginName: string): IPluginLogger } + public async setup( + sbConfig: SBConfig, + sbLogging: SBLogging, + sbEvents: SBEvents ) { - for (let plugin of plugins) { - if (plugin.pluginDefinition !== IPluginDefinition.service) continue; - - await this.log.debug(`Import service plugin: {name} from {file}`, { - name: plugin.name, - file: plugin.pluginFile, + this.log.debug("SETUP SBServices"); + const plugins = await sbConfig.getServicePlugins(); + for (const plugin of Object.keys(plugins)) { + await this.addService(sbConfig, sbLogging, sbEvents, { + name: plugin, + package: plugins[plugin].package, + plugin: plugins[plugin].plugin, + version: "", }); - const importedPlugin = await import(plugin.pluginFile); + } + this.log.debug("SETUP SBServices: Completed"); + } - await this.log.debug(`Construct service plugin: {name}`, { - name: plugin.name, - }); + private setupPluginClient = async ( + sbConfig: SBConfig, + sbLogging: SBLogging, + sbEvents: SBEvents, + context: BSBService, + clientContext: BSBServiceClient + ): Promise => { + const contextPlugin = await sbConfig.getServicePluginDefinition( + clientContext.pluginName + ); + (clientContext as any)._pluginName = clientContext.pluginName; + (clientContext as any).pluginName = contextPlugin.name; + (clientContext as any).pluginEnabled = contextPlugin.enabled; + (clientContext as any).log = new PluginLogger( + this.mode, + contextPlugin.name, + sbLogging + ); + (clientContext as any).events = new PluginEvents( + this.mode, + sbEvents, + clientContext + ); + (context as any).initBeforePlugins = ( + context.initBeforePlugins ?? [] + ).concat(clientContext.initBeforePlugins ?? []); + (context as any).initAfterPlugins = (context.initAfterPlugins ?? []).concat( + clientContext.initAfterPlugins ?? [] + ); + (context as any).runBeforePlugins = (context.runBeforePlugins ?? []).concat( + clientContext.runBeforePlugins ?? [] + ); + (context as any).runAfterPlugins = (context.runAfterPlugins ?? []).concat( + clientContext.runAfterPlugins ?? [] + ); + }; - let servicePlugin = - new (importedPlugin.Service as unknown as typeof ServicesBase)( - plugin.mappedName, - cwd, - plugin.pluginDir, - generateLoggerForPlugin(plugin.mappedName) - ); - await this.log.debug(`Create service plugin: {name}`, { - name: plugin.name, - }); - //const importedPlugin = await import(plugin.pluginFile); - await this.log.info( - "Setting up {pluginName} ({mappedName}) as new base service platform", - { - pluginName: plugin.name, - mappedName: plugin.mappedName, - } - ); - await this.log.info("Builing {pluginName} as new base service platform", { + private async mapServicePlugins( + sbConfig: SBConfig, + referencedPluginName: string, + ...sourcePluginsList: Array | undefined> + ): Promise> { + const outlist = []; + for (const pluginArr of sourcePluginsList.filter((x) => x !== undefined)) { + for (const plugin of pluginArr!) { + const pluginDef = await sbConfig.getServicePluginDefinition(plugin); + if (pluginDef.enabled !== true) + throw new BSBError( + "PLUGIN_NOT_ENABLED", + "The plugin {plugin} is not enabled for {pluginNeeded} to work.", + { + plugin: plugin, + pluginNeeded: referencedPluginName, + } + ); + outlist.push(pluginDef.name); + } + } + return outlist; + } + public async addPlugin( + sbConfig: SBConfig, + sbLogging: SBLogging, + sbEvents: SBEvents, + plugin: IPluginDefinition, + reference: LoadedPlugin<"service">, + config: any + ) { + this.log.debug(`Construct service plugin: {name}`, { + name: plugin.name, + }); + + const servicePlugin = new reference.plugin({ + appId: this.appId, + mode: this.mode, + pluginName: reference.name, + cwd: this.cwd, + pluginCwd: reference.pluginCWD, + config: config, + sbLogging: sbLogging, + sbEvents: sbEvents, + }); + this.log.debug("Adding {pluginName} as service", { + pluginName: plugin.name, + }); + + for (const client of servicePlugin._clients) { + this.log.debug("Construct {pluginName} client {clientName}", { pluginName: plugin.name, + clientName: client.pluginName, }); - const self = this; - SBBase.setupPlugin( - appId, - runningDebug, - runningLive, + await this.setupPluginClient( + sbConfig, + sbLogging, + sbEvents, servicePlugin, - appConfig + client ); - await SBBase.setupServicePlugin( - servicePlugin, - await generateEventsForService(plugin.name, plugin.mappedName), - appConfig, - cwd, - plugin.pluginDir, - generateEventsForService, - generateLoggerForPlugin, - this.log, - async (pluginName: string, method: string, args: Array) => { - for (let plugin of self._activeServices) { - if (plugin.pluginName === pluginName) { - return await (plugin as any)[method](...args); - } - } - await self.log.error( - "Enable {pluginName} in order to call ({method}) from it", - { pluginName, method } - ); - throw ErrorMessages.ServicePluginNotCallableMethod; - } - ); - - await this.log.info( - "Setup {pluginName} ({mappedName}) referenced clients", + this.log.debug( + "Setup {pluginName} client {asOriginalPluginName} as {clientName}", { pluginName: plugin.name, - mappedName: plugin.mappedName, + clientName: client.pluginName, + asOriginalPluginName: (client as any)._pluginName, } ); + } - for (let client of (servicePlugin as any)._clients) { - await this.log.info( - "Setup {pluginName} ({mappedName}) references {clientPlugin}", - { - pluginName: plugin.name, - mappedName: plugin.mappedName, - clientPlugin: client._pluginName, - } - ); - await client._register(); - } + this._activeServices.push(servicePlugin); + + this.log.info("Ready {pluginName} ({mappedName})", { + pluginName: plugin.plugin, + mappedName: plugin.name, + }); + + return servicePlugin; + } + + private async addService( + sbConfig: SBConfig, + sbLogging: SBLogging, + sbEvents: SBEvents, + plugin: IPluginDefinition + ) { + this.log.debug("Add service {name} from ({package}){file}", { + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, + }); + this.log.debug(`Import service plugin: {name} from ({package}){file}`, { + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, + }); - await this.log.info( - "Ready {pluginName} ({mappedName}) as new base service platform", + const newPlugin = await this.sbPlugins.loadPlugin<"service">( + this.log, + plugin.package ?? null, + plugin.plugin, + plugin.name + ); + if (newPlugin === null) { + this.log.error( + "Failed to import service plugin: {name} from ({package}){file}", { - pluginName: plugin.name, - mappedName: plugin.mappedName, + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, } ); + return; + } - await ImportAndMigratePluginConfig(plugin); + this.log.debug(`Get plugin config: {name}`, { + name: plugin.name, + }); + + let pluginConfig = + (await sbConfig.getPluginConfig("service", plugin.name)) ?? null; - this._activeServices.push(servicePlugin); + if ( + this.mode !== "production" && + !Tools.isNullOrUndefined(newPlugin) && + !Tools.isNullOrUndefined(newPlugin.serviceConfig) && + Tools.isObject(newPlugin.serviceConfig) && + !Tools.isNullOrUndefined(newPlugin.serviceConfig.validationSchema) + ) { + this.log.debug("Validate plugin config: {name}", { name: plugin.name }); + pluginConfig = + newPlugin.serviceConfig.validationSchema.parse(pluginConfig); } + + await this.addPlugin( + sbConfig, + sbLogging, + sbEvents, + plugin, + newPlugin, + pluginConfig + ); } - public async servicesInit(config: ConfigBase) { - await this.log.info("Init all services"); - let orderOfPlugins = await this.makeAfterRequired( - config, + private initPluginClient = async ( + sbConfig: SBConfig, + clientContext: BSBServiceClient + ): Promise => { + const contextPlugin = await sbConfig.getServicePluginDefinition( + (clientContext as any)._pluginName + ); + if (contextPlugin.enabled) { + const referencedServiceContext = this._activeServices.find( + (x) => x.pluginName === contextPlugin.name + ) as BSBService; + if (referencedServiceContext === undefined) { + throw new BSBError( + "The plugin {plugin} is not enabled so you cannot call methods from it", + { + plugin: contextPlugin.name, + } + ); + } + if (referencedServiceContext.methods === null) { + throw new BSBError( + "The plugin {plugin} does not have any callable methods", + { + plugin: contextPlugin.name, + } + ); + } + (clientContext as any).callMethod = async ( + method: string, + ...args: Array + ) => { + if (referencedServiceContext.methods[method] === undefined) { + throw new BSBError( + "The plugin {plugin} does not have a method called {method}", + { + plugin: contextPlugin.name, + method, + } + ); + } + return SmartFunctionCallAsync( + referencedServiceContext, + referencedServiceContext.methods[method], + ...args + ); + }; + } + await SmartFunctionCallSync(clientContext, clientContext.init); + }; + + public async init(sbConfig: SBConfig) { + this.log.info("Init all services"); + for (const service of this._activeServices) { + this.log.debug("Mapping required plugins list for {plugin}", { + plugin: service.pluginName, + }); + (service as any).initBeforePlugins = await this.mapServicePlugins( + sbConfig, + service.pluginName, + service.initBeforePlugins + ); + (service as any).initAfterPlugins = await this.mapServicePlugins( + sbConfig, + service.pluginName, + service.initAfterPlugins ?? [] + ); + } + this.log.info("Defining service order"); + const orderOfPlugins = await this.makeAfterRequired( await this.makeBeforeRequired( - config, this._activeServices.map((x) => { return { name: x.pluginName, @@ -154,7 +330,7 @@ export class SBServices { }) ) ); - await this.log.debug("Services init default order: {initOrder}", { + this.log.debug("Services init default order: {initOrder}", { initOrder: this._activeServices .map( (x) => @@ -164,34 +340,33 @@ export class SBServices { ) .join(","), }); - await this.log.debug("Services init order: {initOrder}", { + this.log.debug("Services init order: {initOrder}", { initOrder: orderOfPlugins .map((x) => `[(${x.after.join(",")})${x.name}(${x.before.join(",")})]`) .join(","), }); - for (let service of orderOfPlugins) { - await this.log.debug(`{plugin} init`, { + for (const service of orderOfPlugins) { + this.log.debug(`Init {plugin}`, { plugin: service.name, }); - await service.ref.init(); + for (const client of service.ref._clients) { + await this.initPluginClient(sbConfig, client); + } + SmartFunctionCallAsync(service.ref, service.ref.init); } } public async makeBeforeRequired( - config: ConfigBase, orderOfPlugins: { name: string; after: string[]; before: string[]; - ref: ServicesBase; + ref: BSBService; }[] ) { for (let i = 0; i < orderOfPlugins.length; i++) { if (orderOfPlugins[i].before.length === 0) continue; - for (let bPlugin of await this.parsePluginNamesToMappedNames( - config, - orderOfPlugins[i].before - )) + for (const bPlugin of orderOfPlugins[i].before) for (let j = 0; j < orderOfPlugins.length; j++) { if (orderOfPlugins[j].name == bPlugin) { orderOfPlugins[j].after.push(orderOfPlugins[i].name); @@ -200,38 +375,17 @@ export class SBServices { } return orderOfPlugins; } - private async parsePluginNamesToMappedNames( - config: ConfigBase, - plugins: Array - ): Promise> { - for (let pIndex = 0; pIndex < plugins.length; pIndex++) { - plugins[pIndex] = await config.getAppPluginMappedName(plugins[pIndex]); - } - return plugins; - } public async makeAfterRequired( - config: ConfigBase, orderOfPlugins: { name: string; after: string[]; before: string[]; - ref: ServicesBase; + ref: BSBService; }[] ) { for (let i = 0; i < orderOfPlugins.length - 1; i++) { for (let j = i + 1; j < orderOfPlugins.length; j++) { - if ( - ( - await this.parsePluginNamesToMappedNames( - config, - orderOfPlugins[i].after - ) - ).indexOf(orderOfPlugins[j].name) >= 0 - ) { - await this.log.debug(`{plugin} run after {reqName}`, { - plugin: orderOfPlugins[i].name, - reqName: orderOfPlugins[j].name, - }); + if (orderOfPlugins[i].after.indexOf(orderOfPlugins[j].name) >= 0) { const temp = orderOfPlugins[i]; orderOfPlugins[i] = orderOfPlugins[j]; orderOfPlugins[j] = temp; @@ -241,42 +395,59 @@ export class SBServices { return orderOfPlugins; } - public async servicesRun(config: ConfigBase) { - await this.log.info("Run all services"); - let orderOfPlugins = await this.makeAfterRequired( - config, + public async run(sbConfig: SBConfig) { + this.log.info("Run all services"); + for (const service of this._activeServices) { + this.log.debug("Mapping required plugins list for {plugin}", { + plugin: service.pluginName, + }); + (service as any).runBeforePlugins = await this.mapServicePlugins( + sbConfig, + service.pluginName, + service.runBeforePlugins ?? [] + ); + (service as any).runAfterPlugins = await this.mapServicePlugins( + sbConfig, + service.pluginName, + service.runAfterPlugins ?? [] + ); + } + this.log.info("Defining service order"); + const orderOfPlugins = await this.makeAfterRequired( await this.makeBeforeRequired( - config, this._activeServices.map((x) => { return { name: x.pluginName, - after: x.runAfterPlugins || [], - before: x.runBeforePlugins || [], + after: x.runBeforePlugins || [], + before: x.runAfterPlugins || [], ref: x, }; }) ) ); - await this.log.debug("Services run default order: {initOrder}", { - initOrder: this._activeServices + this.log.debug("Services run default order: {runOrder}", { + runOrder: this._activeServices .map( (x) => - `[(${(x.runAfterPlugins || []).join(",")})${x.pluginName}(${( - x.runBeforePlugins || [] + `[(${(x.runBeforePlugins || []).join(",")})${x.pluginName}(${( + x.runAfterPlugins || [] ).join(",")})]` ) .join(","), }); - await this.log.debug("Services run order: {initOrder}", { - initOrder: orderOfPlugins - .map((x) => `[${x.after.join(",")}=>${x.name}=>${x.before.join(",")}]`) + this.log.debug("Services run order: {runOrder}", { + runOrder: orderOfPlugins + .map((x) => `[(${x.after.join(",")})${x.name}(${x.before.join(",")})]`) .join(","), }); - for (let service of orderOfPlugins) { - await this.log.debug(`{plugin} run`, { + for (const service of orderOfPlugins) { + this.log.debug(`Run {plugin}`, { plugin: service.name, }); - await service.ref.run(); + for (const client of service.ref._clients) { + SmartFunctionCallAsync(client, client.run); + } + SmartFunctionCallAsync(service.ref, service.ref.run); } } } diff --git a/nodejs/src/tests.ts b/nodejs/src/tests.ts new file mode 100644 index 0000000..ee6a258 --- /dev/null +++ b/nodejs/src/tests.ts @@ -0,0 +1 @@ +export * from "./tests/sb/plugins/events/plugin"; diff --git a/nodejs/src/tests/base/PluginEvents.ts b/nodejs/src/tests/base/PluginEvents.ts new file mode 100644 index 0000000..f7f61f6 --- /dev/null +++ b/nodejs/src/tests/base/PluginEvents.ts @@ -0,0 +1,42 @@ +// import { PluginEvents, BSBService } from '../../base'; +// import { SBEvents } from '../../serviceBase'; + + +// describe('PluginEvents', () => { +// let pluginEvents: PluginEvents; +// let sbEvents: SBEvents; +// let bsbService: BSBService; + +// beforeEach(() => { +// // Initialize your SBEvents and BSBService here +// sbEvents = new SBEvents(); +// bsbService = new BSBService(); +// pluginEvents = new PluginEvents("development",); +// }); + +// describe('onBroadcast', () => { +// it('should register an event listener', async () => { +// const event = 'testEvent'; +// const listener = async () => {}; + +// await pluginEvents.onBroadcast(event, listener); + +// // Here you need to check if the listener has been registered correctly +// // This depends on your implementation of SBEvents and BSBService +// }); +// }); + +// describe('emitBroadcast', () => { +// it('should emit an event', async () => { +// const event = 'testEvent'; +// const args = ['arg1', 'arg2']; + +// await pluginEvents.emitBroadcast(event, ...args); + +// // Here you need to check if the event has been emitted correctly +// // This depends on your implementation of SBEvents and BSBService +// }); +// }); + +// // Similar tests can be written for onEvent, emitEvent, onEventSpecific, emitEventSpecific +// }); diff --git a/nodejs/src/tests/events.x.ts.txt b/nodejs/src/tests/events.x.ts.txt deleted file mode 100644 index 632e2e4..0000000 --- a/nodejs/src/tests/events.x.ts.txt +++ /dev/null @@ -1,91 +0,0 @@ -import { DynamicallyReferencedMethodType } from '@bettercorp/tools/lib/Interfaces'; -import { DynamicPluginsList } from '../src/interfaces/DynamicPluginsList'; -import { IPluginEvents, DynamicallyReferencedMethodOnIEvents, DynamicallyReferencedMethodEmitIEvents, DynamicallyReferencedMethodEmitEARIEvents } from '../src/interfaces/events'; - -interface testEmit { - sendEvent(a: boolean): Promise; -} -interface testEmit2 { - onSend(a: boolean): Promise; -} -interface testEmit3 { - onEar(a: boolean): Promise; -} -interface testEmi23 { - eEar(a: boolean): Promise; -} - -class aaa { - events: IPluginEvents = { - onEvent: async ( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ) => {}, - onReturnableEvent: async ( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ) => {}, - emitEvent: async ( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ) => {}, - emitEventAndReturn: ( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ) => { - return 1 as any; - }, - emitEventAndReturnTimed: ( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ) => { - return 1 as any; - }, - receiveStream: async ( - listener: { (error: Error | null, stream: any): Promise }, - timeoutSeconds?: number - ): Promise => { - return ""; - }, - sendStream: async (streamId: string, stream: any): Promise => {}, - }; - - public async testt() { - this.events.emitEvent(DynamicPluginsList.bsbDemoPlugin, "sendEvent", false); - this.events.onEvent( - DynamicPluginsList.bsbDemoPlugin, - "onSend", - async (a: boolean): Promise => { - return; - } - ); - this.events.onReturnableEvent( - DynamicPluginsList.bsbDemoPlugin, - "onEar", - async (a: boolean): Promise => { - return true; - } - ); - await this.events.emitEventAndReturn( - DynamicPluginsList.bsbDemoPlugin, - "eEar", - true - ); - } -} diff --git a/nodejs/src/tests/events/events.ts b/nodejs/src/tests/events/events.ts new file mode 100644 index 0000000..14a4c72 --- /dev/null +++ b/nodejs/src/tests/events/events.ts @@ -0,0 +1,103 @@ +// import assert from "assert"; + +// describe("EventsBase", function () { +// describe("Constructor", async function () { +// it("Should construct correctly [pluginName]", async () => { +// let myobj = new EventsBase("pluginNameX", "cwd", "pluginCwd", {} as any); +// assert.strictEqual(myobj.pluginName, "pluginNameX"); +// }); +// it("Should construct correctly [cwd]", async () => { +// let myobj = new EventsBase("pluginNameX", "cwdD", "pluginCwd", {} as any); +// assert.strictEqual((myobj as any).cwd, "cwdD"); +// }); +// it("Should construct correctly [pluginCwd]", async () => { +// let myobj = new EventsBase( +// "pluginNameX", +// "cwdD", +// "pluginCwdY", +// {} as any +// ); +// assert.strictEqual((myobj as any).pluginCwd, "pluginCwdY"); +// }); +// it("Should construct correctly [logger]", async () => { +// let myobj = new EventsBase("pluginNameX", "cwdD", "pluginCwdY", { +// alog: true, +// } as any); +// assert.strictEqual((myobj as any).log.alog, true); +// }); +// }); +// describe("Default methods", function () { +// it("onBroadcast should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.onBroadcast("a", "b", "c", async () => {}); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("emitBroadcast should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.emitBroadcast("a", "b", "c", []); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("onEvent should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.onEvent("a", "b", "c", async () => {}); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("emitEvent should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.emitEvent("a", "b", "c", []); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("onReturnableEvent should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.onReturnableEvent("a", "b", "c", async () => {}); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("emitEventAndReturn should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.emitEventAndReturn("a", "b", "c", 1, []); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("receiveStream should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.receiveStream("a", async () => {}); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("sendStream should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.sendStream("a", "", {} as any); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// }); +// }); diff --git a/nodejs/src/tests/interfaces/base.ts b/nodejs/src/tests/interfaces/base.ts new file mode 100644 index 0000000..6dc8623 --- /dev/null +++ b/nodejs/src/tests/interfaces/base.ts @@ -0,0 +1,26 @@ +// import assert from "assert"; +// import { BaseWithLogging } from "../../base/base"; +// import { ErrorMessages } from "../../base/errorMessages"; + +// describe("DefaultBase", function () { +// describe("Default methods", function () { +// it("getPluginConfig should throw", async () => { +// try { +// let myobj = new BaseWithLogging("a", "b", "c", {} as any); +// (myobj as any).getPluginConfig(); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.BSBNotInit); +// } +// }); +// it("getPluginState should throw", async () => { +// try { +// let myobj = new BaseWithLogging("a", "b", "c", {} as any); +// await (myobj as any).getPluginState(); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.BSBNotInit); +// } +// }); +// }); +// }); diff --git a/nodejs/src/tests/interfaces/static.ts b/nodejs/src/tests/interfaces/static.ts new file mode 100644 index 0000000..4abb119 --- /dev/null +++ b/nodejs/src/tests/interfaces/static.ts @@ -0,0 +1,63 @@ +// import assert from "assert"; +// import { ErrorMessages } from "../../base/errorMessages"; + +// describe("ErrorMessages", function () { +// describe("Throw errors", async function () { +// it("BSBNotInit should throw", async () => { +// try { +// throw ErrorMessages.BSBNotInit; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.BSBNotInit); +// } +// }); +// it("EventsNotImplementedProperly should throw", async () => { +// try { +// throw ErrorMessages.EventsNotImplementedProperly; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("PluginNotImplementedProperly should throw", async () => { +// try { +// throw ErrorMessages.PluginNotImplementedProperly; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.PluginNotImplementedProperly); +// } +// }); +// it("LoggerNotImplementedProperly should throw", async () => { +// try { +// throw ErrorMessages.LoggerNotImplementedProperly; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// it("ConfigNotImplementedProperly should throw", async () => { +// try { +// throw ErrorMessages.ConfigNotImplementedProperly; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.ConfigNotImplementedProperly); +// } +// }); +// it("PluginClientNotImplementedProperly should throw", async () => { +// try { +// throw ErrorMessages.PluginClientNotImplementedProperly; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.PluginClientNotImplementedProperly); +// } +// }); +// it("PluginConfigNotSetupToGenerateConfig should throw", async () => { +// try { +// throw ErrorMessages.PluginConfigNotSetupToGenerateConfig; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.PluginConfigNotSetupToGenerateConfig); +// } +// }); +// it("ServicePluginNotCallableMethod should throw", async () => { +// try { +// throw ErrorMessages.ServicePluginNotCallableMethod; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.ServicePluginNotCallableMethod); +// } +// }); +// }); +// }); diff --git a/nodejs/src/tests/logger.js b/nodejs/src/tests/logger.js deleted file mode 100644 index ff2b7f4..0000000 --- a/nodejs/src/tests/logger.js +++ /dev/null @@ -1,43 +0,0 @@ -const events = require('../lib/events/events').Events; - -const logger_Def = require("../lib/logger/logger").Logger; -const testogger = require('./virt-clientLogger.ts.txt').testogger; -const emit = require('./events/emit').default; -const emitAndReturn = require('./events/emitAndReturn').default; -const emitStreamAndReceiveStream = require('./events/emitStreamAndReceiveStream').default; - -const fakeLogger = new testogger('test-plugin', process.cwd(), - new logger_Def('test-plugin', process.cwd(), null, { - runningInDebug: false - }), null, { - error: (e) => assert.fail(new Error(e)), - fatal: (e) => assert.fail(new Error(e)) - }); - -describe('Logger', () => { - emit(async () => { - const refP = new events('test-plugin', process.cwd(), fakeLogger, { - runningInDebug: true - }); - if (refP.init !== undefined) - await refP.init(); - return refP; - }, 10); - emitAndReturn(async () => { - const refP = new events('test-plugin', process.cwd(), fakeLogger, { - runningInDebug: true - }); - if (refP.init !== undefined) - await refP.init(); - return refP; - }, 10); - emitStreamAndReceiveStream(async () => { - const refP = new events('test-plugin', process.cwd(), fakeLogger, { - runningInDebug: true - }); - if (refP.init !== undefined) - await refP.init(); - refP.eas.staticCommsTimeout = 25; - return refP; - }, 50); -}); \ No newline at end of file diff --git a/nodejs/src/tests/logger/logFormatter.ts b/nodejs/src/tests/logger/logFormatter.ts new file mode 100644 index 0000000..c768dca --- /dev/null +++ b/nodejs/src/tests/logger/logFormatter.ts @@ -0,0 +1,119 @@ +import { assert } from "chai"; +import { LogFormatter } from "../../base"; + +describe("logFormatter", function () { + describe("formatLog", function () { + it("Should return string when meta is undefined", async () => { + const ojb = new LogFormatter(); + assert.strictEqual(ojb.formatLog("TEST"), "TEST"); + }); + it("Should return string when meta is null", async () => { + const ojb = new LogFormatter(); + assert.strictEqual(ojb.formatLog("TEST", null as any), "TEST"); // ts picks up this issue + }); + it("Should return string when meta is a string", async () => { + const ojb = new LogFormatter(); + assert.strictEqual(ojb.formatLog("TEST", ""), "TEST"); + }); + it("Should return string when meta is a number", async () => { + const ojb = new LogFormatter(); + assert.strictEqual(ojb.formatLog("TEST", 5), "TEST"); + }); + it("Should format correctly", async () => { + const ojb = new LogFormatter(); + assert.strictEqual(ojb.formatLog("HTEST {a}", { a: "B" }), "HTEST B"); + }); + it("Should format *null/undefined* when a value found doesnt exist", async () => { + const ojb = new LogFormatter(); + assert.strictEqual( + ojb.formatLog("HTEST {a}", {} as any), // ts picks up this issue + "HTEST *null/undefined*" + ); + }); + it("Should format *null/undefined* when a value found is undefined", async () => { + const ojb = new LogFormatter(); + assert.strictEqual( + ojb.formatLog("HTEST {a}", { a: undefined } as any), // ts picks up this issue + "HTEST *null/undefined*" + ); + }); + it("Should format DT in ISO when a value found is a date", async () => { + const ojb = new LogFormatter(); + const dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f}", { f: dt }), + "HTEST 2023-07-22T15:38:30.000Z" + ); + }); + it("Should format DT in ISO when a value found is a date 2", async () => { + const ojb = new LogFormatter(); + const dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f}@{e}", { e: "DD", f: dt }), + "HTEST 2023-07-22T15:38:30.000Z@DD" + ); + }); + it("Should fail to format DT when a value found is inside an object", async () => { + const ojb = new LogFormatter(); + const dt = new Date(1689694710000); // 18 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f.y}@{e}", { e: "DD", f: { y: dt } } as any), // ts picks up this issue + "HTEST *null/undefined*@DD" + ); + }); + // it("Should format DT in ISO when a value found is a date 4", async () => { + // let ojb = new LogFormatter(); + // let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + // let dt2 = new Date(1689694710000); // 18 Jul 2023 15:38:30 GMT + // assert.strictEqual( + // ojb.formatLog("HTEST {f.y}@{e}:{a.0}:{a.1}", { + // a: ["E", dt2], + // e: "DD", + // f: { y: dt }, + // } as any), + // "HTEST 2023-07-22T15:38:30.000Z@DD:E:2023-07-18T15:38:30.000Z" + // ); // ts picks up this issue + // }); + it("Should format json when a value found is an object", async () => { + const ojb = new LogFormatter(); + const dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f}@{e}", { e: "DD", f: { y: dt } }), + 'HTEST {"y":"2023-07-22T15:38:30.000Z"}@DD' + ); + }); + it("Should format direct date", async () => { + const ojb = new LogFormatter(); + const dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("{y}", { y: dt }), + "2023-07-22T15:38:30.000Z" + ); + }); + it("Should format iso date", async () => { + const isIsoDate = (str: string) => { + if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(str)) + return false; + const d = new Date(str); + return ( + d instanceof Date && !isNaN(d.getTime()) && d.toISOString() === str + ); // valid date + }; + const ojb = new LogFormatter(); + const dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual(isIsoDate(ojb.formatLog("{y}", { y: dt })), true); + }); + it("Should format json when a value found is an array", async () => { + const ojb = new LogFormatter(); + const dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f}@{e}:{a}", { + a: ["E", "F"], + e: "DD", + f: { y: dt }, + } as any), + 'HTEST {"y":"2023-07-22T15:38:30.000Z"}@DD:E,F' + ); // ts picks up this issue + }); + }); +}); diff --git a/nodejs/src/tests/logger/logger.ts b/nodejs/src/tests/logger/logger.ts new file mode 100644 index 0000000..4381b17 --- /dev/null +++ b/nodejs/src/tests/logger/logger.ts @@ -0,0 +1,62 @@ +// import assert from "assert"; +// import { LoggerBase } from "../../../src/logger/logger"; +// import { ErrorMessages } from "../../base/errorMessages"; + +// describe("LoggerBase", function () { +// describe("Default methods", function () { +// it("reportStat should throw", async () => { +// try { +// let myobj = new LoggerBase("a", "b", "c", {} as any); +// await myobj.reportStat("a", "b", 1); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// it("reportTextStat should throw", async () => { +// try { +// let myobj = new LoggerBase("a", "b", "c", {} as any); +// await myobj.reportTextStat("a", "b", 1); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// it("debug should throw", async () => { +// try { +// let myobj = new LoggerBase("a", "b", "c", {} as any); +// await myobj.debug("a", "b", 1); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// it("info should throw", async () => { +// try { +// let myobj = new LoggerBase("a", "b", "c", {} as any); +// await myobj.info("a", "b", 1); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// it("warn should throw", async () => { +// try { +// let myobj = new LoggerBase("a", "b", "c", {} as any); +// await myobj.warn("a", "b", 1); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// it("error should throw", async () => { +// try { +// let myobj = new LoggerBase("a", "b", "c", {} as any); +// await myobj.error("a", "b", 1); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// }); +// }); diff --git a/nodejs/src/tests/plugins/events-default/plugin.ts b/nodejs/src/tests/plugins/events-default/plugin.ts new file mode 100644 index 0000000..df18275 --- /dev/null +++ b/nodejs/src/tests/plugins/events-default/plugin.ts @@ -0,0 +1,70 @@ +import assert from "assert"; +import { Plugin } from "../../../plugins/events-default/plugin"; +import { emit as emitDirect } from "../../../plugins/events-default/events/emit"; +import { randomUUID } from "crypto"; +import { + RunEventsPluginTests, + generateNullLogging, +} from "../../../tests/sb/plugins/events/plugin"; + +describe("plugins/events-default", () => { + describe("Events Emit", async () => { + it("_lastReceivedMessageIds should be empty on init", async () => { + const emit = new emitDirect(generateNullLogging()); + assert.equal((emit as any)._lastReceivedMessageIds.length, 0); + }); + it("_lastReceivedMessageIds should contain latest emit ID", async () => { + const emit = new emitDirect(generateNullLogging()); + await emit.onEvent("b", "c", async () => {}); + await emit.emitEvent("b", "c", []); + assert.equal((emit as any)._lastReceivedMessageIds.length, 1); + }); + it("_lastReceivedMessageIds should call only once", async () => { + const emit = new emitDirect(generateNullLogging()); + const testID = randomUUID(); + let called = 0; + await emit.onEvent("b", "c", async () => { + called++; + }); + emit.emit(`b-c`, { + msgID: testID, + data: [], + }); + assert.equal(called, 1); + }); + it("_lastReceivedMessageIds should call only once, per id", async () => { + const emit = new emitDirect(generateNullLogging()); + const testID1 = randomUUID(); + const testID2 = randomUUID(); + let called = 0; + await emit.onEvent("b", "c", async () => { + called++; + }); + emit.emit(`b-c`, { + msgID: testID1, + data: [], + }); + emit.emit(`b-c`, { + msgID: testID2, + data: [], + }); + assert.equal(called, 2); + }); + it("_lastReceivedMessageIds should cycle ids > 50", async () => { + const emit = new emitDirect(generateNullLogging()); + const testIDs: Array = "." + .repeat(100) + .split("") + .map(() => randomUUID()); + await emit.onEvent("b", "c", async () => {}); + for (const emitID of testIDs) + emit.emit(`b-c`, { + msgID: emitID, + data: [], + }); + assert.equal((emit as any)._lastReceivedMessageIds.length, 51); + }); + }); + + RunEventsPluginTests(Plugin); +}); diff --git a/nodejs/src/tests/plugins/events/plugin.ts b/nodejs/src/tests/plugins/events/plugin.ts deleted file mode 100644 index a53b0ae..0000000 --- a/nodejs/src/tests/plugins/events/plugin.ts +++ /dev/null @@ -1,84 +0,0 @@ -import assert from "assert"; -//import { Logger } from "./test-logger"; -import { Events as events } from "../../../plugins/events-default/plugin"; -import { broadcast } from "./events/broadcast"; -import { emit } from "./events/emit"; -import { emitAndReturn } from "./events/emitAndReturn"; -import { emitStreamAndReceiveStream } from "./events/emitStreamAndReceiveStream"; -import { IPluginLogger, LogMeta } from "../../../interfaces/logger"; - -//const fakeCLogger = new Logger("test-plugin", process.cwd(), {} as any); -//const debug = console.log; -//const debug = console.log; -const debug = (...a: any) => {}; -const fakeLogger: IPluginLogger = { - reportStat: async (key, value): Promise => {}, - reportTextStat: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, - info: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, - warn: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, - error: async ( - messageOrError: string | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise => { - debug(messageOrError, meta); - assert.fail( - typeof messageOrError === "string" - ? new Error(messageOrError) - : messageOrError - ); - }, - fatal: async ( - messageOrError: string | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise => { - debug(messageOrError, meta); - assert.fail( - typeof messageOrError === "string" - ? new Error(messageOrError) - : messageOrError - ); - }, - debug: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, -}; - -const getPluginConfig = async () => { - return {}; -} - -describe("plugins/events-default", () => { - broadcast(async () => { - const refP = new events("test-plugin", process.cwd(), process.cwd(), fakeLogger); - (refP as any).getPluginConfig = getPluginConfig; - if (refP.init !== undefined) await refP.init(); - return refP; - }, 10); - emit(async () => { - const refP = new events("test-plugin", process.cwd(), process.cwd(), fakeLogger); - (refP as any).getPluginConfig = getPluginConfig; - if (refP.init !== undefined) await refP.init(); - return refP; - }, 10); - emitAndReturn(async () => { - const refP = new events("test-plugin", process.cwd(), process.cwd(), fakeLogger); - (refP as any).getPluginConfig = getPluginConfig; - if (refP.init !== undefined) await refP.init(); - return refP; - }, 10); - emitStreamAndReceiveStream(async () => { - const refP = new events("test-plugin", process.cwd(), process.cwd(), fakeLogger); - (refP as any).getPluginConfig = getPluginConfig; - if (refP.init !== undefined) await refP.init(); - //refP.eas.staticCommsTimeout = 25; - return refP; - }, 50); -}); diff --git a/nodejs/src/tests/plugins/log-default/plugin.ts b/nodejs/src/tests/plugins/logging-default/plugin.ts similarity index 55% rename from nodejs/src/tests/plugins/log-default/plugin.ts rename to nodejs/src/tests/plugins/logging-default/plugin.ts index 03c3dc5..781845c 100644 --- a/nodejs/src/tests/plugins/log-default/plugin.ts +++ b/nodejs/src/tests/plugins/logging-default/plugin.ts @@ -1,9 +1,28 @@ import assert from "assert"; -import { Logger, LogLevels } from "../../../plugins/log-default/plugin"; +import { + Plugin, + LOG_LEVELS, + LogLevels, +} from "../../../plugins/logging-default/plugin"; +import { BSBLoggingConstructor } from "../../../base"; +import { DEBUG_MODE } from "../../../interfaces"; -describe("plugins/log-default", () => { +const getLoggingConstructorConfig = ( + mode: DEBUG_MODE = "development" +): BSBLoggingConstructor => { + return { + appId: "test-app", + pluginCwd: process.cwd(), + cwd: process.cwd(), + mode: mode, + pluginName: "test-plugin", + config: undefined, + }; +}; + +describe("plugins/logging-default", () => { describe("console.x", () => { - let tempCCStore: any = { + const tempCCStore: any = { log: null, error: null, warn: null, @@ -18,37 +37,37 @@ describe("plugins/log-default", () => { expectMessageContent?: Array ) => { consoleEventCalled = 0; - for (let consol of listOfConsoles) + for (const consol of listOfConsoles) tempCCStore[consol] = (console as any)[consol]; if (expectMessageContent !== undefined) { consoleExpectMessageContent = { expectMessageContent, logs: [], }; - for (let consol of listOfConsoles.filter((x) => x !== expect)) + for (const consol of listOfConsoles.filter((x) => x !== expect)) (console as any)[consol] = () => { consoleEventCalled = 1; assert.fail("Invalid console called!: " + consol); }; - for (let consol of listOfConsoles.filter((x) => x === expect)) + for (const consol of listOfConsoles.filter((x) => x === expect)) (console as any)[consol] = (...data: Array) => { consoleEventCalled = 1; consoleExpectMessageContent.logs.push(data); }; } else if (expectMessage === undefined) { consoleEventCalled = 1; - for (let consol of listOfConsoles) + for (const consol of listOfConsoles) (console as any)[consol] = () => { consoleEventCalled = 0; assert.fail("Invalid console called!: " + consol); }; } else { - for (let consol of listOfConsoles.filter((x) => x !== expect)) + for (const consol of listOfConsoles.filter((x) => x !== expect)) (console as any)[consol] = () => { consoleEventCalled = 1; assert.fail("Invalid console called!: " + consol); }; - for (let consol of listOfConsoles.filter((x) => x === expect)) + for (const consol of listOfConsoles.filter((x) => x === expect)) (console as any)[consol] = (...data: Array) => { consoleEventCalled = 1; assert.equal(data.length, expectMessage.length); @@ -60,7 +79,7 @@ describe("plugins/log-default", () => { } }; const restoreConsole = () => { - for (let consol of listOfConsoles as any) + for (const consol of listOfConsoles as any) (console as any)[consol] = tempCCStore[consol]; if (consoleEventCalled === -1) assert.fail("Console not setup!"); if (consoleEventCalled === 0) assert.fail("No console called!"); @@ -71,7 +90,7 @@ describe("plugins/log-default", () => { xx++ ) { let has = false; - for (let item of consoleExpectMessageContent.logs) { + for (const item of consoleExpectMessageContent.logs) { if ( item .toString() @@ -95,25 +114,25 @@ describe("plugins/log-default", () => { consoleExpectMessageContent = null; }; it("should console a stat event", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("debug", [null, "[STAT] [DEFAULT-STAT] [val=2]"]); await plugin.reportStat("default-stat", "val", 2); restoreConsole(); }); it("should console a text stat event", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("debug", [null, "[STAT] [DEFAULT-DBG] My Msg"]); - await plugin.reportTextStat("default-DbG", "My Msg"); + await plugin.reportTextStat("default-DbG", "My Msg", undefined as any); restoreConsole(); }); it("should console a debug event", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("debug", [null, "[DEBUG] [DEFAULT-DBG] My Msg"]); - await plugin.debug("default-DbG", "My Msg"); + await plugin.debug("default-DbG", "My Msg", undefined as any); restoreConsole(); }); it("should console a debug event (meta)", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("debug", [ null, "[DEBUG] [DEFAULT-DBG] My Msg cHEESE and a,b (5)", @@ -127,13 +146,13 @@ describe("plugins/log-default", () => { }); it("should console a info event", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("log", [null, "[INFO] [INFO-DBG] My Msg"]); - await plugin.info("info-DbG", "My Msg"); + await plugin.info("info-DbG", "My Msg", undefined as any); restoreConsole(); }); it("should console a info event (meta)", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("log", [ null, "[INFO] [INFO-DBG] My Msg cHEESE and a,b (5)", @@ -147,13 +166,13 @@ describe("plugins/log-default", () => { }); it("should console a error event", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("error", [null, "[ERROR] [INFEE-DBG] My Msg"]); - await plugin.error("infee-DbG", "My Msg"); + await plugin.error("infee-DbG", "My Msg", undefined as any); restoreConsole(); }); it("should console a error event (meta)", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("error", [ null, "[ERROR] [INFE-DBG] My Msg cHEESE and a,b (5)", @@ -167,13 +186,13 @@ describe("plugins/log-default", () => { }); it("should console a warn event", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("warn", [null, "[WARN] [INFOW-DBG] My Msg"]); - await plugin.warn("infoW-DbG", "My Msg"); + await plugin.warn("infoW-DbG", "My Msg", undefined as any); restoreConsole(); }); it("should console a warn event (meta)", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("warn", [ null, "[WARN] [INFW-DBG] My Msg cHEESE and a,b (5)", @@ -187,9 +206,7 @@ describe("plugins/log-default", () => { }); it("running debug, should debug everything", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = true; - (plugin as any).runningLive = false; + const plugin = new Plugin(getLoggingConstructorConfig("development")); storeConsole("debug", [ null, "[DEBUG] [DEFAULT-DBG] My Msg cHEESE and a,b (5)", @@ -202,9 +219,7 @@ describe("plugins/log-default", () => { restoreConsole(); }); it("running non-debug, should not debug anything", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = false; - (plugin as any).runningLive = false; + const plugin = new Plugin(getLoggingConstructorConfig("production")); storeConsole("debug"); await plugin.debug("infW-DbG", "My Msg {che} and {chi} ({te})", { che: "cHEESE", @@ -213,11 +228,14 @@ describe("plugins/log-default", () => { }); restoreConsole(); }); - it("running live-debug, should not debug anything", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = false; - (plugin as any).runningLive = true; - storeConsole("debug"); + it("running live-debug, should debug", async () => { + const plugin = new Plugin( + getLoggingConstructorConfig("production-debug") + ); + storeConsole("debug", [ + null, + "[DEBUG] [INFW-DBG] My Msg cHEESE and a,b (5)", + ]); await plugin.debug("infW-DbG", "My Msg {che} and {chi} ({te})", { che: "cHEESE", chi: ["a", "b"], @@ -226,72 +244,49 @@ describe("plugins/log-default", () => { restoreConsole(); }); - it("running non-debug, should not stat anything", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + /*it("running non-debug, should not stat anything", async () => { + const plugin = new Plugin(getLoggingConstructorConfig("")); (plugin as any).runningDebug = false; (plugin as any).runningLive = false; storeConsole("debug"); await plugin.reportStat("infW-DbG", "a", 3); restoreConsole(); - }); - it("running live, should not output PI info", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = false; - (plugin as any).runningLive = true; - storeConsole("log"); - await plugin.info( - "infW-DbG", - "My Msg {che} and {chi} ({te})", - { - che: "cHEESE", - chi: ["a", "b"], - te: 5, - }, - true - ); - restoreConsole(); - }); - it("running live, should not output PI warn", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = false; - (plugin as any).runningLive = true; - storeConsole("warn"); - await plugin.warn( - "infW-DbG", - "My Msg {che} and {chi} ({te})", - { - che: "cHEESE", - chi: ["a", "b"], - te: 5, - }, - true - ); - restoreConsole(); - }); - it("running live, should not output PI error", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = false; - (plugin as any).runningLive = true; - storeConsole("error"); - await plugin.error( - "infW-DbG", - "My Msg {che} and {chi} ({te})", - { - che: "cHEESE", - chi: ["a", "b"], - te: 5, - }, - true - ); - restoreConsole(); - }); + });*/ + // it("running live, should not output PI info", async () => { + // const plugin = new Plugin(getLoggingConstructorConfig("production")); + // storeConsole("log"); + // await plugin.info("infW-DbG", "My Msg {che} and {chi} ({te})", { + // che: "cHEESE", + // chi: ["a", "b"], + // te: 5, + // }); + // restoreConsole(); + // }); + // it("running live, should not output PI warn", async () => { + // const plugin = new Plugin(getLoggingConstructorConfig("production")); + // storeConsole("warn"); + // await plugin.warn("infW-DbG", "My Msg {che} and {chi} ({te})", { + // che: "cHEESE", + // chi: ["a", "b"], + // te: 5, + // }); + // restoreConsole(); + // }); + // it("running live, should not output PI error", async () => { + // const plugin = new Plugin(getLoggingConstructorConfig("production")); + // storeConsole("error"); + // await plugin.error("infW-DbG", "My Msg {che} and {chi} ({te})", { + // che: "cHEESE", + // chi: ["a", "b"], + // te: 5, + // }); + // restoreConsole(); + // }); it("Stack report", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = true; - (plugin as any).runningLive = false; + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("error", undefined, [ "test-error", - "src/tests/plugins/log-default/plugin.ts:", + "src/tests/plugins/logging-default/plugin.ts:", ]); await plugin.error("infW-DbG", new Error("test-error")); restoreConsole(); @@ -299,52 +294,34 @@ describe("plugins/log-default", () => { }); describe("console mocked/overriden", () => { it("should mocked a stat event", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.STAT) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.STAT) return assert.fail(new Error(message)); assert.equal(message, "[STAT] [DEFAULT-STAT] [val=2]"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); await plugin.reportStat("default-stat", "val", 2); }); it("should mocked a debug event", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.DEBUG) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.DEBUG) return assert.fail(new Error(message)); assert.equal(message, "[DEBUG] [DEFAULT-DBG] My Msg"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); - await plugin.debug("default-DbG", "My Msg"); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); + await plugin.debug("default-DbG", "My Msg", undefined as any); }); it("should mocked a debug event (meta)", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.DEBUG) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.DEBUG) return assert.fail(new Error(message)); assert.equal( message, "[DEBUG] [DEFAULT-DBG] My Msg cHEESE and a,b (5)" ); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); await plugin.debug("default-DbG", "My Msg {che} and {chi} ({te})", { che: "cHEESE", chi: ["a", "b"], @@ -353,33 +330,21 @@ describe("plugins/log-default", () => { }); it("should mocked a info event", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.INFO) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.INFO) return assert.fail(new Error(message)); assert.equal(message, "[INFO] [INFO-DBG] My Msg"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); - await plugin.info("info-DbG", "My Msg"); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); + await plugin.info("info-DbG", "My Msg", undefined as any); }); it("should mocked a info event (meta)", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.INFO) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.INFO) return assert.fail(new Error(message)); assert.equal(message, "[INFO] [INFO-DBG] My Msg cHEESE and a,b (5)"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); await plugin.info("info-DbG", "My Msg {che} and {chi} ({te})", { che: "cHEESE", chi: ["a", "b"], @@ -388,33 +353,21 @@ describe("plugins/log-default", () => { }); it("should mocked a error event", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.ERROR) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.ERROR) return assert.fail(new Error(message)); assert.equal(message, "[ERROR] [INFEE-DBG] My Msg"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); - await plugin.error("infee-DbG", "My Msg"); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); + await plugin.error("infee-DbG", "My Msg", undefined as any); }); it("should mocked a error event (meta)", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.ERROR) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.ERROR) return assert.fail(new Error(message)); assert.equal(message, "[ERROR] [INFE-DBG] My Msg cHEESE and a,b (5)"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); await plugin.error("infe-DbG", "My Msg {che} and {chi} ({te})", { che: "cHEESE", chi: ["a", "b"], @@ -423,33 +376,21 @@ describe("plugins/log-default", () => { }); it("should mocked a warn event", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.WARN) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.WARN) return assert.fail(new Error(message)); assert.equal(message, "[WARN] [INFOW-DBG] My Msg"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); - await plugin.warn("infoW-DbG", "My Msg"); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); + await plugin.warn("infoW-DbG", "My Msg", undefined as any); }); it("should mocked a warn event (meta)", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.WARN) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.WARN) return assert.fail(new Error(message)); assert.equal(message, "[WARN] [INFW-DBG] My Msg cHEESE and a,b (5)"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); await plugin.warn("infW-DbG", "My Msg {che} and {chi} ({te})", { che: "cHEESE", chi: ["a", "b"], diff --git a/nodejs/src/tests/plugins/events/events/broadcast.ts b/nodejs/src/tests/sb/plugins/events/broadcast.ts similarity index 57% rename from nodejs/src/tests/plugins/events/events/broadcast.ts rename to nodejs/src/tests/sb/plugins/events/broadcast.ts index 2130ea2..4c0b049 100644 --- a/nodejs/src/tests/plugins/events/events/broadcast.ts +++ b/nodejs/src/tests/sb/plugins/events/broadcast.ts @@ -1,19 +1,19 @@ -import { EventsBase } from "../../../../events/events"; import assert from "assert"; import { randomUUID } from "crypto"; +import { BSBEvents, SmartFunctionCallSync } from "../../../.."; const randomName = () => randomUUID(); export function broadcast( - genNewPlugin: { (): Promise }, + genNewPlugin: { (): Promise }, maxTimeoutToExpectAResponse: number ) { - let emitter: EventsBase; + let emitter: BSBEvents; beforeEach(async () => { emitter = await genNewPlugin(); }); afterEach(function () { - emitter.dispose(); + SmartFunctionCallSync(emitter, emitter.dispose); }); describe("EmitBroadcast", async function () { this.timeout(maxTimeoutToExpectAResponse + 10); @@ -21,54 +21,35 @@ export function broadcast( describe("emitBroadcast", async () => { const emitData = true; it("all plugins should receive the event", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); //console.log(emitter) let receiveCounter = 0; setTimeout(() => { - if (receiveCounter === 2) return assert.ok(receiveCounter); + if (receiveCounter === 2) return assert.ok(receiveCounter); if (receiveCounter === 0) return assert.fail("Event not received"); assert.fail("Received " + receiveCounter + " events"); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - receiveCounter++; - } - ); - await emitter.onBroadcast( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - receiveCounter++; - } - ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent, [emitData]); + await emitter.onBroadcast(thisPlugin, thisEvent, async () => { + receiveCounter++; + }); + await emitter.onBroadcast(thisPlugin, thisEvent, async () => { + receiveCounter++; + }); + await emitter.emitBroadcast(thisPlugin, thisEvent, [emitData]); }); it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); //console.log(emitter) const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); - assert.ok(data[0]); - } - ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent, [ - emitData, - ]); + await emitter.onBroadcast(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); + assert.ok(data[0]); + }); + await emitter.emitBroadcast(thisPlugin, thisEvent, [emitData]); }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); @@ -77,19 +58,12 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.ok(data[0]); - } - ); - await emitter.emitBroadcast(thisCaller, thisCaller, thisEvent, [ - emitData, - ]); + assert.ok(data[0]); + }); + await emitter.emitBroadcast(thisCaller, thisEvent, [emitData]); }); it("should be able to emit to events with self multi-args", async () => { const thisCaller = randomName(); @@ -98,28 +72,17 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], 0); - assert.deepEqual(data[1], 1); - assert.deepEqual(data[2], 2); - assert.deepEqual(data[3], 3); - } - ); - await emitter.emitBroadcast( - thisCaller, - thisCaller, - thisEvent, - [0, 1, 2, 3] - ); + assert.deepEqual(data[0], 0); + assert.deepEqual(data[1], 1); + assert.deepEqual(data[2], 2); + assert.deepEqual(data[3], 3); + }); + await emitter.emitBroadcast(thisCaller, thisEvent, [0, 1, 2, 3]); }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); @@ -127,19 +90,12 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisPlugin, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent2, [ - emitData, - ]); + assert.fail("Event received"); + }); + await emitter.emitBroadcast(thisPlugin, thisEvent2, [emitData]); }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); @@ -149,44 +105,29 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisCaller, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitBroadcast(thisCaller, thisCaller, thisEvent2, [ - emitData, - ]); + assert.fail("Event received"); + }); + await emitter.emitBroadcast(thisCaller, thisEvent2, [emitData]); }); }); describe("onBroadcast", async () => { const emitData = "ABCD"; it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], emitData); - } - ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent, [ - emitData, - ]); + assert.deepEqual(data[0], emitData); + }); + await emitter.emitBroadcast(thisPlugin, thisEvent, [emitData]); }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); @@ -195,22 +136,14 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], emitData); - } - ); - await emitter.emitBroadcast(thisCaller, thisCaller, thisEvent, [ - emitData, - ]); + assert.deepEqual(data[0], emitData); + }); + await emitter.emitBroadcast(thisCaller, thisEvent, [emitData]); }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); @@ -218,19 +151,12 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisPlugin, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent2, [ - emitData, - ]); + assert.fail("Event received"); + }); + await emitter.emitBroadcast(thisPlugin, thisEvent2, [emitData]); }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); @@ -240,19 +166,12 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisCaller, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitBroadcast(thisCaller, thisCaller, thisEvent2, [ - emitData, - ]); + assert.fail("Event received"); + }); + await emitter.emitBroadcast(thisCaller, thisEvent2, [emitData]); }); }); const typesToTest = [ @@ -296,10 +215,9 @@ export function broadcast( }, }, ]; - for (let typeToTest of typesToTest) + for (const typeToTest of typesToTest) describe(`emitBroadcast ${typeToTest.name}`, async () => { it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); @@ -307,7 +225,6 @@ export function broadcast( assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); await emitter.onBroadcast( - thisCaller, thisPlugin, thisEvent, async (data: any) => { @@ -316,9 +233,7 @@ export function broadcast( assert.deepEqual(data[0], typeToTest.data); } ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent, [ - typeToTest.data, - ]); + await emitter.emitBroadcast(thisPlugin, thisEvent, [typeToTest.data]); }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); @@ -328,7 +243,6 @@ export function broadcast( assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); await emitter.onBroadcast( - thisCaller, thisCaller, thisEvent, async (data: any) => { @@ -337,12 +251,9 @@ export function broadcast( assert.deepEqual(data[0], typeToTest.data); } ); - await emitter.emitBroadcast(thisCaller, thisCaller, thisEvent, [ - typeToTest.data, - ]); + await emitter.emitBroadcast(thisCaller, thisEvent, [typeToTest.data]); }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); @@ -350,17 +261,12 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisPlugin, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent2, [ + assert.fail("Event received"); + }); + await emitter.emitBroadcast(thisPlugin, thisEvent2, [ typeToTest.data, ]); }); @@ -372,17 +278,12 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisCaller, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitBroadcast(thisCaller, thisCaller, thisEvent2, [ + assert.fail("Event received"); + }); + await emitter.emitBroadcast(thisCaller, thisEvent2, [ typeToTest.data, ]); }); diff --git a/nodejs/src/tests/plugins/events/events/emit.ts b/nodejs/src/tests/sb/plugins/events/emit.ts similarity index 55% rename from nodejs/src/tests/plugins/events/events/emit.ts rename to nodejs/src/tests/sb/plugins/events/emit.ts index 073d6a2..6094773 100644 --- a/nodejs/src/tests/plugins/events/events/emit.ts +++ b/nodejs/src/tests/sb/plugins/events/emit.ts @@ -1,19 +1,19 @@ -import { EventsBase } from "../../../../events/events"; import assert from "assert"; import { randomUUID } from "crypto"; +import { BSBEvents, SmartFunctionCallSync } from "../../../.."; const randomName = () => randomUUID(); export function emit( - genNewPlugin: { (): Promise }, + genNewPlugin: { (): Promise }, maxTimeoutToExpectAResponse: number ) { - let emitter: EventsBase; + let emitter: BSBEvents; beforeEach(async () => { emitter = await genNewPlugin(); }); afterEach(function () { - emitter.dispose(); + SmartFunctionCallSync(emitter, emitter.dispose); }); describe("Emit", async function () { this.timeout(maxTimeoutToExpectAResponse + 10); @@ -21,7 +21,6 @@ export function emit( describe("emitEvent", async () => { const emitData = true; it("only one plugin should receive the event", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); //console.log(emitter) @@ -31,42 +30,26 @@ export function emit( if (receiveCounter === 0) return assert.fail("Event not received"); assert.fail("Received " + receiveCounter + " events"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - receiveCounter++; - } - ); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - receiveCounter++; - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent, [emitData]); + await emitter.onEvent(thisPlugin, thisEvent, async () => { + receiveCounter++; + }); + await emitter.onEvent(thisPlugin, thisEvent, async () => { + receiveCounter++; + }); + await emitter.emitEvent(thisPlugin, thisEvent, [emitData]); }); it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); //console.log(emitter) const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); - assert.ok(data[0]); - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent, [emitData]); + await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); + assert.ok(data[0]); + }); + await emitter.emitEvent(thisPlugin, thisEvent, [emitData]); }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); @@ -75,17 +58,12 @@ export function emit( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.ok(data[0]); - } - ); - await emitter.emitEvent(thisCaller, thisCaller, thisEvent, [emitData]); + assert.ok(data[0]); + }); + await emitter.emitEvent(thisCaller, thisEvent, [emitData]); }); it("should be able to emit to events with self multi-args", async () => { const thisCaller = randomName(); @@ -94,28 +72,17 @@ export function emit( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], 0); - assert.deepEqual(data[1], 1); - assert.deepEqual(data[2], 2); - assert.deepEqual(data[3], 3); - } - ); - await emitter.emitEvent( - thisCaller, - thisCaller, - thisEvent, - [0, 1, 2, 3] - ); + assert.deepEqual(data[0], 0); + assert.deepEqual(data[1], 1); + assert.deepEqual(data[2], 2); + assert.deepEqual(data[3], 3); + }); + await emitter.emitEvent(thisCaller, thisEvent, [0, 1, 2, 3]); }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); @@ -123,17 +90,12 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisPlugin, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent2, [emitData]); + assert.fail("Event received"); + }); + await emitter.emitEvent(thisPlugin, thisEvent2, [emitData]); }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); @@ -143,40 +105,29 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitEvent(thisCaller, thisCaller, thisEvent2, [emitData]); + assert.fail("Event received"); + }); + await emitter.emitEvent(thisCaller, thisEvent2, [emitData]); }); }); describe("onEvent", async () => { const emitData = "ABCD"; it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], emitData); - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent, [emitData]); + assert.deepEqual(data[0], emitData); + }); + await emitter.emitEvent(thisPlugin, thisEvent, [emitData]); }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); @@ -185,20 +136,14 @@ export function emit( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], emitData); - } - ); - await emitter.emitEvent(thisCaller, thisCaller, thisEvent, [emitData]); + assert.deepEqual(data[0], emitData); + }); + await emitter.emitEvent(thisCaller, thisEvent, [emitData]); }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); @@ -206,17 +151,12 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisPlugin, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent2, [emitData]); + assert.fail("Event received"); + }); + await emitter.emitEvent(thisPlugin, thisEvent2, [emitData]); }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); @@ -226,17 +166,12 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitEvent(thisCaller, thisCaller, thisEvent2, [emitData]); + assert.fail("Event received"); + }); + await emitter.emitEvent(thisCaller, thisEvent2, [emitData]); }); }); const typesToTest = [ @@ -280,29 +215,21 @@ export function emit( }, }, ]; - for (let typeToTest of typesToTest) + for (const typeToTest of typesToTest) describe(`emitEvent ${typeToTest.name}`, async () => { it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], typeToTest.data); - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent, [ - typeToTest.data, - ]); + assert.deepEqual(data[0], typeToTest.data); + }); + await emitter.emitEvent(thisPlugin, thisEvent, [typeToTest.data]); }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); @@ -311,22 +238,14 @@ export function emit( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], typeToTest.data); - } - ); - await emitter.emitEvent(thisCaller, thisCaller, thisEvent, [ - typeToTest.data, - ]); + assert.deepEqual(data[0], typeToTest.data); + }); + await emitter.emitEvent(thisCaller, thisEvent, [typeToTest.data]); }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); @@ -334,19 +253,12 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisPlugin, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent2, [ - typeToTest.data, - ]); + assert.fail("Event received"); + }); + await emitter.emitEvent(thisPlugin, thisEvent2, [typeToTest.data]); }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); @@ -356,19 +268,12 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitEvent(thisCaller, thisCaller, thisEvent2, [ - typeToTest.data, - ]); + assert.fail("Event received"); + }); + await emitter.emitEvent(thisCaller, thisEvent2, [typeToTest.data]); }); }); }); diff --git a/nodejs/src/tests/plugins/events/events/emitAndReturn.ts b/nodejs/src/tests/sb/plugins/events/emitAndReturn.ts similarity index 76% rename from nodejs/src/tests/plugins/events/events/emitAndReturn.ts rename to nodejs/src/tests/sb/plugins/events/emitAndReturn.ts index 7880ba7..a52e15a 100644 --- a/nodejs/src/tests/plugins/events/events/emitAndReturn.ts +++ b/nodejs/src/tests/sb/plugins/events/emitAndReturn.ts @@ -1,52 +1,41 @@ -import { EventsBase } from '../../../../events/events'; +import { BSBEvents, SmartFunctionCallSync } from "../../../.."; import assert from "assert"; import { randomUUID } from "crypto"; const randomName = () => randomUUID(); export function emitAndReturn( - genNewPlugin: { (): Promise }, - maxTimeoutToExpectAResponse: number, - a = true, - b = true + genNewPlugin: { (): Promise }, + maxTimeoutToExpectAResponse: number ) { - let emitter: EventsBase; + let emitter: BSBEvents; beforeEach(async () => { emitter = await genNewPlugin(); }); afterEach(function () { - emitter.dispose(); + SmartFunctionCallSync(emitter, emitter.dispose); }); describe("EmitAndReturn", async () => { - //if (a) this.timeout(maxTimeoutToExpectAResponse + 20); - //if (b) this.afterEach(done => setTimeout(done, maxTimeoutToExpectAResponse)); const timermaxTimeoutToExpectAResponse = maxTimeoutToExpectAResponse + 10; describe("emitEventAndReturn", async () => { const emitData = true; const emitData2 = false; it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: Array) => { - setTimeout(() => { - console.log("Received onEvent"); - assert.ok(true, "Received onEvent"); - }, 1); - return emitData2; - } - ); + await emitter.onReturnableEvent(thisPlugin, thisEvent, async () => { + setTimeout(() => { + console.log("Received onEvent"); + assert.ok(true, "Received onEvent"); + }, 1); + return emitData2; + }); console.log("!!Received onEvent"); await emitter.emitEventAndReturn( - thisCaller, thisPlugin, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -55,26 +44,19 @@ export function emitAndReturn( console.log("++Received onEvent"); clearTimeout(emitTimeout); assert.ok(true, "Received Response"); - }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: Array) => { - assert.ok(true, "Received onEvent"); - return emitData2; - } - ); + await emitter.onReturnableEvent(thisCaller, thisEvent, async () => { + assert.ok(true, "Received onEvent"); + return emitData2; + }); await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -82,28 +64,20 @@ export function emitAndReturn( ); clearTimeout(emitTimeout); assert.ok(true, "Received Response"); - }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); - + const emitTimeout = setTimeout(() => { assert.ok(true); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisPlugin, - thisEvent, - (data: Array) => { - assert.fail("EEAR MSG Received"); - } - ); + await emitter.onReturnableEvent(thisPlugin, thisEvent, () => { + assert.fail("EEAR MSG Received"); + }); try { await emitter.emitEventAndReturn( - thisCaller, thisPlugin, thisEvent2, maxTimeoutToExpectAResponse / 1000, @@ -115,27 +89,20 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); - + const emitTimeout = setTimeout(() => { assert.ok(true); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisCaller, - thisEvent, - (data: Array) => { - assert.fail("EEAR MSG Received"); - } - ); + await emitter.onReturnableEvent(thisCaller, thisEvent, () => { + assert.fail("EEAR MSG Received"); + }); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent2, maxTimeoutToExpectAResponse / 1000, @@ -147,24 +114,17 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should timeout correctly", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: Array) => {} - ); + await emitter.onReturnableEvent(thisCaller, thisEvent, async () => {}); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -176,26 +136,19 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should response error correctly", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisCaller, - thisEvent, - (data: Array) => { - throw "THISISANERROR"; - } - ); + await emitter.onReturnableEvent(thisCaller, thisEvent, () => { + throw "THISISANERROR"; + }); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -208,7 +161,6 @@ export function emitAndReturn( assert.ok("EEAR"); assert.strictEqual(exc, "THISISANERROR"); } - }); }); const typesToTest = [ @@ -257,26 +209,21 @@ export function emitAndReturn( }, }, ]; - for (let typeToTest of typesToTest) { + for (const typeToTest of typesToTest) { describe(`emitEventAndReturn ${typeToTest.name}`, async () => { it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: Array) => { - return typeToTest.rData !== undefined ? typeToTest.rData: typeToTest.data; - } - ); + await emitter.onReturnableEvent(thisPlugin, thisEvent, async () => { + return typeToTest.rData !== undefined + ? typeToTest.rData + : typeToTest.data; + }); const resp = await emitter.emitEventAndReturn( - thisCaller, thisPlugin, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -285,21 +232,21 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.strictEqual( JSON.stringify(resp), - JSON.stringify(typeToTest.rData !== undefined - ? typeToTest.rData - : typeToTest.data) + JSON.stringify( + typeToTest.rData !== undefined + ? typeToTest.rData + : typeToTest.data + ) ); - }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received - timeout"); }, timermaxTimeoutToExpectAResponse); await emitter.onReturnableEvent( - thisCaller, thisCaller, thisEvent, async (data: Array) => { @@ -315,7 +262,6 @@ export function emitAndReturn( assert.strictEqual( JSON.stringify( await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -326,28 +272,20 @@ export function emitAndReturn( "Returned data" ); clearTimeout(emitTimeout); - }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); - + const emitTimeout = setTimeout(() => { assert.ok(true); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisPlugin, - thisEvent, - (data: Array) => { - assert.fail("EEAR MSG Received"); - } - ); + await emitter.onReturnableEvent(thisPlugin, thisEvent, () => { + assert.fail("EEAR MSG Received"); + }); try { await emitter.emitEventAndReturn( - thisCaller, thisPlugin, thisEvent2, maxTimeoutToExpectAResponse / 1000, @@ -359,27 +297,20 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); - + const emitTimeout = setTimeout(() => { assert.ok(true); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisCaller, - thisEvent, - (data: Array) => { - assert.fail("EEAR MSG Received"); - } - ); + await emitter.onReturnableEvent(thisCaller, thisEvent, () => { + assert.fail("EEAR MSG Received"); + }); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent2, maxTimeoutToExpectAResponse / 1000, @@ -391,24 +322,21 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should timeout correctly - general timeout", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse + 10); await emitter.onReturnableEvent( - thisCaller, thisCaller, thisEvent, - async (data: Array) => {} + async () => {} ); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -420,18 +348,16 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should timeout correctly - no receipt", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse + 10); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -443,26 +369,19 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should response error correctly", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisCaller, - thisEvent, - (data: Array) => { - throw typeToTest.rData || typeToTest.data; - } - ); + await emitter.onReturnableEvent(thisCaller, thisEvent, () => { + throw typeToTest.rData || typeToTest.data; + }); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -478,7 +397,6 @@ export function emitAndReturn( JSON.stringify(typeToTest.rData || typeToTest.data) ); } - }); }); } diff --git a/nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts b/nodejs/src/tests/sb/plugins/events/emitStreamAndReceiveStream.ts similarity index 89% rename from nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts rename to nodejs/src/tests/sb/plugins/events/emitStreamAndReceiveStream.ts index d40fd5b..1a9fce9 100644 --- a/nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts +++ b/nodejs/src/tests/sb/plugins/events/emitStreamAndReceiveStream.ts @@ -3,12 +3,12 @@ import * as crypto from "crypto"; import { exec } from "child_process"; import { pipeline } from "stream"; import assert from "assert"; -import { EventsBase } from '../../../../events/events'; +import { BSBEvents, SmartFunctionCallSync } from "../../../.."; const randomName = () => crypto.randomUUID(); const mockBareFakeStream = () => { - let obj: any = { + const obj: any = { listeners: {}, emit: (name: any, data?: any) => { if (obj.listeners[name] !== undefined) obj.listeners[name](data); @@ -23,9 +23,9 @@ const mockBareFakeStream = () => { const getFileHash = (filename: any) => new Promise((resolve, reject) => { - var fd = fs.createReadStream(filename); + const fd = fs.createReadStream(filename); // deepcode ignore InsecureHash/test: not production, just using to verify the files hash - var hash = crypto.createHash("sha1"); + const hash = crypto.createHash("sha1"); hash.setEncoding("hex"); fd.on("error", reject); @@ -73,15 +73,15 @@ const convertBytes = ( }; export function emitStreamAndReceiveStream( - genNewPlugin: { (): Promise }, + genNewPlugin: { (): Promise }, maxTimeoutToExpectAResponse: number ) { - let emitter: EventsBase; + let emitter: BSBEvents; beforeEach(async () => { emitter = await genNewPlugin(); }); afterEach(function () { - emitter.dispose(); + SmartFunctionCallSync(emitter, emitter.dispose); }); describe("EmitStreamAndReceiveStream", async () => { //this.timeout(maxTimeoutToExpectAResponse + 20); @@ -90,7 +90,7 @@ export function emitStreamAndReceiveStream( it("receiveStream creates a should generate a valid string", async () => { const thisCaller = randomName(); - let uuid = await emitter.receiveStream( + const uuid = await emitter.receiveStream( thisCaller, async () => {}, maxTimeoutToExpectAResponse @@ -114,7 +114,7 @@ export function emitStreamAndReceiveStream( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - let uuid = await emitter.receiveStream( + const uuid = await emitter.receiveStream( thisCaller, async (err: any, stream: { emit: (arg0: string) => void }) => { clearTimeout(emitTimeout); @@ -125,7 +125,8 @@ export function emitStreamAndReceiveStream( ); try { await emitter.sendStream(thisCaller, uuid, mockBareFakeStream()); - console.log('endededed') + console.log("endededed"); + // eslint-disable-next-line no-empty } catch (xx) {} }); describe("sendStream triggers receiveStream listener passing in the stream", async () => { @@ -135,7 +136,7 @@ export function emitStreamAndReceiveStream( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - let uuid = await emitter.receiveStream( + const uuid = await emitter.receiveStream( thisCaller, async (err: any, stream: { emit: (arg0: string) => void }) => { clearTimeout(emitTimeout); @@ -146,6 +147,7 @@ export function emitStreamAndReceiveStream( ); try { await emitter.sendStream(thisCaller, uuid, mockBareFakeStream()); + // eslint-disable-next-line no-empty } catch (xx) {} }); it("should call the listener with a stream", async () => { @@ -154,7 +156,7 @@ export function emitStreamAndReceiveStream( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - let uuid = await emitter.receiveStream( + const uuid = await emitter.receiveStream( thisCaller, async (err: any, stream: { emit: (arg0: string) => void }) => { clearTimeout(emitTimeout); @@ -169,6 +171,7 @@ export function emitStreamAndReceiveStream( ); try { await emitter.sendStream(thisCaller, uuid, mockBareFakeStream()); + // eslint-disable-next-line no-empty } catch (xx) {} }); }); @@ -179,8 +182,8 @@ export function emitStreamAndReceiveStream( this.timeout(120000); const thisCaller = randomName(); const now = new Date().getTime(); - let fileName = `./test-file-${size}`; - let fileNameOut = fileName + "-out"; + const fileName = `./test-file-${size}`; + const fileNameOut = fileName + "-out"; try { await runCMD( `dd if=/dev/urandom of=${fileName} bs=${size} count=${count}` @@ -196,14 +199,14 @@ export function emitStreamAndReceiveStream( const fileBytes = fs.statSync(fileName).size; const fullBytes = convertBytes(fileBytes); console.log(` ${size} act size: ${fullBytes}`); - let srcFileHash = await getFileHash(fileName); + const srcFileHash = await getFileHash(fileName); const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - let uuid = await emitter.receiveStream( + const uuid = await emitter.receiveStream( thisCaller, - async (err: any, stream: any):Promise => { + async (err: any, stream: any): Promise => { if (err) return assert.fail(err); clearTimeout(emitTimeout); pipeline(stream, fs.createWriteStream(fileNameOut), (errf) => { @@ -246,8 +249,8 @@ export function emitStreamAndReceiveStream( runTest("512KB"); runTest("1MB"); runTest("16MB"); - runTest("128MB", 1); - + //runTest("128MB", 1); + //runTest("128MB", 4); //runTest('512MB', 16); //runTest('1GB', 32); diff --git a/nodejs/src/tests/sb/plugins/events/plugin.ts b/nodejs/src/tests/sb/plugins/events/plugin.ts new file mode 100644 index 0000000..4f3a456 --- /dev/null +++ b/nodejs/src/tests/sb/plugins/events/plugin.ts @@ -0,0 +1,68 @@ +import { broadcast } from "./broadcast"; +import { emit } from "./emit"; +import { emitAndReturn } from "./emitAndReturn"; +import { emitStreamAndReceiveStream } from "./emitStreamAndReceiveStream"; +import { + BSBEventsConstructor, + BSBEventsRef, + PluginLogger, +} from "../../../../base"; +import { SBLogging, SmartFunctionCallSync } from "../../../../serviceBase"; + +export const newSBLogging = () => { + const sbLogging = new SBLogging( + "test-app", + "development", + process.cwd(), + {} as any + ); + for (const logger of (sbLogging as any).loggers) { + SmartFunctionCallSync(logger, logger.dispose); + } + (sbLogging as any).loggers = []; + return sbLogging; +}; +export const generateNullLogging = () => { + const sbLogging = newSBLogging(); + return new PluginLogger("development", "test-plugin", sbLogging); +}; +export const getEventsConstructorConfig = ( + config: any +): BSBEventsConstructor => { + return { + appId: "test-app", + pluginCwd: process.cwd(), + cwd: process.cwd(), + mode: "development", + pluginName: "test-plugin", + sbLogging: newSBLogging(), + config: config, + }; +}; + +export const RunEventsPluginTests = ( + eventsPlugin: typeof BSBEventsRef, + config: any = undefined +) => { + broadcast(async () => { + const refP = new eventsPlugin(getEventsConstructorConfig(config)); + if (refP.init !== undefined) await refP.init(); + return refP; + }, 10); + emit(async () => { + const refP = new eventsPlugin(getEventsConstructorConfig(config)); + if (refP.init !== undefined) await refP.init(); + return refP; + }, 10); + emitAndReturn(async () => { + const refP = new eventsPlugin(getEventsConstructorConfig(config)); + if (refP.init !== undefined) await refP.init(); + return refP; + }, 10); + emitStreamAndReceiveStream(async () => { + const refP = new eventsPlugin(getEventsConstructorConfig(config)); + if (refP.init !== undefined) await refP.init(); + //refP.eas.staticCommsTimeout = 25; + return refP; + }, 50); +}; diff --git a/nodejs/src/tests/serviceBase/services.ts b/nodejs/src/tests/serviceBase/services.ts deleted file mode 100644 index 4caefb0..0000000 --- a/nodejs/src/tests/serviceBase/services.ts +++ /dev/null @@ -1,271 +0,0 @@ -import assert from "assert"; -import { IPluginLogger, LogMeta } from "../../interfaces/logger"; -import { ServicesBase } from "../../service/service"; -import { SBServices } from "../../serviceBase/services"; - -//const debug = console.log; -const debug = (...a: any) => {}; -const fakeLogger: IPluginLogger = { - reportStat: async (key, value): Promise => {}, - reportTextStat: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, - info: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, - warn: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, - error: async ( - messageOrError: string | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise => { - debug(messageOrError, meta); - assert.fail( - typeof messageOrError === "string" - ? new Error(messageOrError) - : messageOrError - ); - }, - fatal: async ( - messageOrError: string | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise => { - debug(messageOrError, meta); - assert.fail( - typeof messageOrError === "string" - ? new Error(messageOrError) - : messageOrError - ); - }, - debug: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, -}; - -describe("serviceBase/services", () => { - it("Should re-order plugins that require other plugins", async () => { - let services = new SBServices(fakeLogger); - let plugins: { - name: string; - after: string[]; - before: string[]; - ref: ServicesBase; - }[] = [ - { - name: "plugin1", - after: ["plugin2"], - before: [], - ref: {} as any, - }, - { - name: "plugin2", - after: [], - before: [], - ref: {} as any, - }, - { - name: "plugin3", - after: [], - before: [], - ref: {} as any, - }, - ]; - plugins = await services.makeAfterRequired( - { - getAppPluginMappedName: async (x: string) => { - return x; - }, - } as any, - plugins - ); - services.dispose(); - assert.equal(plugins[0].name, "plugin2"); - assert.equal(plugins[1].name, "plugin1"); - assert.equal(plugins[2].name, "plugin3"); - }); - it("Should re-order plugins that before other plugins", async () => { - let services = new SBServices(fakeLogger); - let plugins: { - name: string; - after: string[]; - before: string[]; - ref: ServicesBase; - }[] = [ - { - name: "plugin1", - after: ["plugin2"], - before: [], - ref: {} as any, - }, - { - name: "plugin2", - after: [], - before: [], - ref: {} as any, - }, - { - name: "plugin3", - after: [], - before: ["plugin1"], - ref: {} as any, - }, - ]; - plugins = await services.makeBeforeRequired( - { - getAppPluginMappedName: async (x: string) => { - return x; - }, - } as any, - plugins - ); - assert.equal(plugins[0].after.length, 2); - assert.equal(plugins[0].after[0], "plugin2"); - assert.equal(plugins[0].after[1], "plugin3"); - assert.equal(plugins[1].after.length, 0); - assert.equal(plugins[2].after.length, 0); - plugins = await services.makeAfterRequired( - { - getAppPluginMappedName: async (x: string) => { - return x; - }, - } as any, - plugins - ); - services.dispose(); - assert.equal(plugins[0].name, "plugin2"); - assert.equal(plugins[1].name, "plugin3"); - assert.equal(plugins[2].name, "plugin1"); - }); - it("Should re-order plugins that before or require other plugins", async () => { - let services = new SBServices(fakeLogger); - let plugins: { - name: string; - after: string[]; - before: string[]; - ref: ServicesBase; - }[] = [ - { - name: "plugin1", - after: ["plugin2"], - before: [], - ref: {} as any, - }, - { - name: "plugin2", - after: [], - before: [], - ref: {} as any, - }, - { - name: "plugin3", - after: [], - before: ["plugin1"], - ref: {} as any, - }, - { - name: "plugin4", - after: ["plugin3"], - before: ["plugin1"], - ref: {} as any, - }, - ]; - plugins = await services.makeBeforeRequired( - { - getAppPluginMappedName: async (x: string) => { - return x; - }, - } as any, - plugins - ); - plugins = await services.makeAfterRequired( - { - getAppPluginMappedName: async (x: string) => { - return x; - }, - } as any, - plugins - ); - services.dispose(); - assert.equal(plugins[3].name, "plugin1", "plugin 1 not last"); - assert.equal(plugins[3].after.length, 3, "length of after does not match"); - assert.equal(plugins[3].after[0], "plugin2", "plugin 1 required plugin 2"); - assert.equal(plugins[3].after[1], "plugin3", "plugin 1 required plugin 3"); - assert.equal(plugins[3].after[2], "plugin4", "plugin 1 required plugin 4"); - assert.equal(plugins[0].after.length, 0, "plugin 2 after nothing"); - assert.equal(plugins[1].after.length, 0, "plugin 3 after nothing"); - assert.equal(plugins[0].name, "plugin2"); - assert.equal(plugins[1].name, "plugin3"); - assert.equal(plugins[2].name, "plugin4"); - assert.equal(plugins[3].name, "plugin1"); - }); - - it("Should re-order plugins that before or require other plugins (mapped names)", async () => { - let services = new SBServices(fakeLogger); - let plugins: { - name: string; - after: string[]; - before: string[]; - ref: ServicesBase; - _mappedName: string; - }[] = [ - { - name: "pligin1", - after: ["plugin2"], - before: [], - ref: {} as any, - _mappedName: "plugin1", - }, - { - name: "pligin2", - after: [], - before: [], - ref: {} as any, - _mappedName: "plugin2", - }, - { - name: "pligin3", - after: [], - before: ["plugin1"], - ref: {} as any, - _mappedName: "plugin3", - }, - { - name: "pligin4", - after: ["plugin3"], - before: ["plugin1"], - ref: {} as any, - _mappedName: "plugin4", - }, - ]; - const appConfigPass = { - getAppPluginMappedName: async (x: string) => { - for (let plugin of plugins) { - if (plugin._mappedName === x) { - return plugin.name; - } - } - return x; - }, - } as any; - plugins = (await services.makeBeforeRequired( - appConfigPass, - plugins - )) as any; - plugins = (await services.makeAfterRequired(appConfigPass, plugins)) as any; - services.dispose(); - assert.equal(plugins[3].name, "pligin1", "plugin 1 not last"); - assert.equal(plugins[3].after.length, 3, "length of after does not match"); - assert.equal(plugins[3].after[0], "pligin2", "plugin 1 required plugin 2"); - assert.equal(plugins[3].after[1], "pligin3", "plugin 1 required plugin 3"); - assert.equal(plugins[3].after[2], "pligin4", "plugin 1 required plugin 4"); - assert.equal(plugins[0].after.length, 0, "plugin 2 after nothing"); - assert.equal(plugins[1].after.length, 0, "plugin 3 after nothing"); - assert.equal(plugins[0].name, "pligin2"); - assert.equal(plugins[1].name, "pligin3"); - assert.equal(plugins[2].name, "pligin4"); - assert.equal(plugins[3].name, "pligin1"); - }); -}); diff --git a/nodejs/src/tests/test-logger.ts b/nodejs/src/tests/test-logger.ts deleted file mode 100644 index dae6519..0000000 --- a/nodejs/src/tests/test-logger.ts +++ /dev/null @@ -1,46 +0,0 @@ -import assert from "assert"; -import { IPluginLogger, LogMeta } from "../interfaces/logger"; -import { LoggerBase } from "../logger/logger"; - -export class Logger extends LoggerBase { - constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - defaultLogger: IPluginLogger - ) { - super(pluginName, cwd, pluginCwd, defaultLogger); - } - - public async reportStat( - plugin: string, - key: string, - value: number - ): Promise {} - public async debug( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise {} - public async info( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise {} - public async warn( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise {} - public async error( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - assert.fail(new Error(message)); - } -} diff --git a/nodejs/src/tests/virt-clientLogger.ts.txt b/nodejs/src/tests/virt-clientLogger.ts.txt deleted file mode 100644 index 469d68a..0000000 --- a/nodejs/src/tests/virt-clientLogger.ts.txt +++ /dev/null @@ -1,34 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { - value: true -}); -const logger_1 = require("../lib/interfaces/logger"); -class Logger extends logger_1.CLogger { - events = {}; - constructor(pluginName, cwd, log, appConfig, events) { - super(pluginName, cwd, log, appConfig); - this.events = events; - } - async thisLog(key, plugin, ...data) { - if (this.events[key] !== undefined) - this.events[key](...data); - else - await this.log[key](plugin, ...data); - } - async debug(plugin, ...data) { - await this.thisLog('debug', plugin, `[DEBUG][${plugin.toUpperCase()}]`, data); - } - async info(plugin, ...data) { - await this.thisLog('debug', plugin, `[${plugin.toUpperCase()}]`, data); - } - async warn(plugin, ...data) { - await this.thisLog('warn', plugin, `[${plugin.toUpperCase()}]`, data); - } - async error(plugin, ...data) { - await this.thisLog('error', plugin, `[${plugin.toUpperCase()}]`, data); - } - async fatal(plugin, ...data) { - await this.thisLog('fatal', plugin, 'FATAL', ...data); - } -} -exports.testogger = Logger; \ No newline at end of file diff --git a/nodejs/templates/events.ts b/nodejs/templates/events.ts index 3338508..8056d37 100644 --- a/nodejs/templates/events.ts +++ b/nodejs/templates/events.ts @@ -1,23 +1,135 @@ -import { CEvents } from "@bettercorp/service-base/lib/interfaces/events"; -import { MyPluginConfig } from './sec.config'; +import { EventsBase, IPluginLogger } from "@bettercorp/service-base"; +import { Readable } from "stream"; +import { PluginConfig } from "./sec.config"; -export class Events extends CEvents { - init(): Promise { - return new Promise((resolve) => { - resolve(); - }); +export class Events extends EventsBase { + constructor( + pluginName: string, + cwd: string, + pluginCwd: string, + log: IPluginLogger + ) { + super(pluginName, cwd, pluginCwd, log); + /** + * Add any other constructor code here } - async onEvent(callerPluginName: string, pluginName: string, event: string, listener: { (data: ArgsDataType): Promise; }): Promise { - throw 'onEvent not setup'; + public dispose() { + /** + * TODO: dispose of all events + * + * Cleanup/close connections that are not needed. + */ } - async emitEvent(callerPluginName: string, pluginName: string, event: string, data?: ArgsDataType): Promise { - throw 'emitEvent not setup'; + + public override async onBroadcast( + callerPluginName: string, + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to listen to events that are emitted by other plugins + * The difference between an emitEvent and an emitBroadcast is that an emitEvent is only + * handled by a single plugin whereas an emitBroadcast is handled by all plugins listening + * for that event + */ + } + public override async emitBroadcast( + callerPluginName: string, + pluginName: string, + event: string, + args: Array + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to emit an event that is handled by all plugins listening + * for that event + */ + } + + public override async onEvent( + callerPluginName: string, + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to listen to events that are emitted by other plugins + * The difference between an emitEvent and an emitBroadcast is that an emitEvent is only + * handled by a single plugin + */ + } + + public override async emitEvent( + callerPluginName: string, + pluginName: string, + event: string, + args: Array + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to emit an event that is handled by a single plugin + */ } - async onReturnableEvent(callerPluginName: string, pluginName: string, event: string, listener: { (data: ArgsDataType): Promise; }): Promise { - throw 'onReturnableEvent not setup'; + + public override async onReturnableEvent( + callerPluginName: string, + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to listen to events that are emitted by other plugins + * and return a value to the caller + */ + } + + public override async emitEventAndReturn( + callerPluginName: string, + pluginName: string, + event: string, + timeoutSeconds: number, + args: Array + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to emit an event that is handled by a single plugin + * and returns a value to the caller + */ } - async emitEventAndReturn(callerPluginName: string, pluginName: string, event: string, data?: ArgsDataType, timeoutSeconds?: number): Promise { - throw 'emitEventAndReturn not setup'; + + public override async receiveStream( + callerPluginName: string, + listener: { (error: Error | null, stream: Readable): Promise }, + timeoutSeconds?: number + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to receive a stream from another plugin + * and returns a streamId that can be used to send data back to the caller + */ + } + + public override async sendStream( + callerPluginName: string, + streamId: string, + stream: Readable + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to send a stream to another plugin + */ } } diff --git a/nodejs/templates/logger.ts b/nodejs/templates/logger.ts index e39f61a..3df4cd6 100644 --- a/nodejs/templates/logger.ts +++ b/nodejs/templates/logger.ts @@ -1,20 +1,99 @@ -import { CLogger } from "@bettercorp/service-base/lib/interfaces/logger"; -import { MyPluginConfig } from './sec.config'; +import { LoggerBase, IPluginLogger, LogMeta } from "@bettercorp/service-base"; +import { PluginConfig } from './sec.config'; -export class Logger extends CLogger { - async debug(plugin: string, ...data: any[]): Promise { - throw 'debug not setup'; +export class Logger extends LoggerBase { + constructor( + pluginName: string, + cwd: string, + pluginCwd: string, + defaultLogger: IPluginLogger + ) { + super(pluginName, cwd, pluginCwd, defaultLogger); } - async info(plugin: string, ...data: any[]): Promise { - throw 'info not setup'; + + public async reportStat( + plugin: string, + key: string, + value: number + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to report a stat to your logging platform + */ + } + + public async reportTextStat( + plugin: string, + message: T, + meta?: LogMeta, + hasPIData?: boolean + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to report a stat in text to your logging platform + */ + } + + public async debug( + plugin: string, + message: T, + meta?: LogMeta, + hasPIData?: boolean + ): Promise { + if (!this.runningDebug) return; + /** + * TODO: implement + * + * This function allows for a plugin to report a debug message to your logging platform + */ } - async warn(plugin: string, ...data: any[]): Promise { - throw 'warn not setup'; + + public async info( + plugin: string, + message: T, + meta?: LogMeta, + hasPIData?: boolean + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to report an info message to your logging platform + */ } - async error(plugin: string, ...data: any[]): Promise { - throw 'error not setup'; + + public async warn( + plugin: string, + message: T, + meta?: LogMeta, + hasPIData?: boolean + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to report a warning message to your logging platform + */ } - async fatal(plugin: string, ...data: any[]): Promise { - throw 'fatal not setup'; + + public async error( + plugin: string, + message: T, + meta?: LogMeta, + hasPIData?: boolean + ): Promise; + public async error(plugin: string, error: Error): Promise; + public async error( + plugin: string, + messageOrError: T | Error, + meta?: LogMeta, + hasPIData?: boolean + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to report an error message to your logging platform + * log.fatal() calls this method first before terminating the process + */ } -} \ No newline at end of file +} diff --git a/nodejs/templates/plugin.ts b/nodejs/templates/plugin.ts index b5468a0..540140c 100644 --- a/nodejs/templates/plugin.ts +++ b/nodejs/templates/plugin.ts @@ -1,32 +1,69 @@ -import { CPlugin, CPluginClient } from "@bettercorp/service-base/lib/interfaces/plugins"; -import { MyPluginConfig } from './sec.config'; +import { ServicesBase } from "../src/index"; //"@bettercorp/service-base"; +import { + ServiceBroadcasts, + ServiceCallable, + ServiceEvents, + ServiceReturnableEvents, +} from "../src/service/base"; +import { PluginConfig } from "./sec.config"; -export class demo extends CPluginClient { - public readonly _pluginName: string = "demo"; +/// TODO: Move these interfaces to your index.ts file so your client plugins can reference them +/// The reason for the index.ts file is if you are publishing any dist-clients, they will need to reference these interfaces +export interface OnEvents extends ServiceEvents {} +export interface EmitEvents extends ServiceEvents {} +export interface OnReturnableEvents extends ServiceReturnableEvents {} +export interface EmitReturnableEvents extends ServiceReturnableEvents {} +export interface CallableMethods extends ServiceCallable {} +export interface OnBroadcastEvents extends ServiceBroadcasts {} +export interface EmitBroadcastEvents extends ServiceBroadcasts {} +/// TODO: Move these interfaces to your index.ts file so your client plugins can reference them - async triggerServerOnEvent(data: any): Promise { - await this.emitEvent("exampleOnEvent", data); - } - async triggerServerMethod(data: any): Promise { - return this.emitEventAndReturn("exampleServerMethod", data); - } -} - -export class Plugin extends CPlugin { - async init(): Promise { - await this.onEvent(null, "exampleOnEvent", x => self.exampleOnEvent(x)); - await this.onReturnableEvent(null, "exampleServerMethod", self.exampleServerMethod); - } +export class Plugin + extends ServicesBase< + PluginConfig, + OnEvents, + EmitEvents, + OnReturnableEvents, + EmitReturnableEvents, + CallableMethods, + OnBroadcastEvents, + EmitBroadcastEvents + > + implements CallableMethods +{ + /** + * initAfterPlugins is a list of plugins that must be initialized before this plugin + * This is useful if you need to initialize a plugin before/after another plugin + * For example, if you have a plugin that requires a database connection, you can + * add the database plugin to this list so that it is initialized before your plugin + * is initialized + */ + public override initAfterPlugins: string[] = []; + /** + * initBeforePlugins is a list of plugins that must be initialized after this plugin + * This is useful if you need to initialize a plugin before/after another plugin + * For example, another plugin may require your plugin to be initialized before it + * is initialized + */ + public override initBeforePlugins: string[] = []; + /** + * runAfterPlugins is a list of plugins that must be run before this plugin + */ + public override runAfterPlugins: string[] = []; + /** + * runBeforePlugins is a list of plugins that must be run after this plugin + */ + public override runBeforePlugins: string[] = []; - async exampleOnEvent(data: any): Promise { - this.log.info("Received exampleOnEvent"); - } + /** + * This method is called to setup the plugin + * Add all your on event handlers here + * Init is called before run + */ + public override async init(): Promise {} - async exampleServerMethod(data: any): Promise { - return data; - }; - - async loaded(): Promise { - await this.emitEvent('another-plugin-name', 'another-plugin-on-event', '0'); - } -} \ No newline at end of file + /** + * This method is called once the plugin is loaded and ready to run + */ + public override async run(): Promise {} +} diff --git a/nodejs/templates/pluginClient.ts b/nodejs/templates/pluginClient.ts new file mode 100644 index 0000000..7de695c --- /dev/null +++ b/nodejs/templates/pluginClient.ts @@ -0,0 +1,12 @@ +import { ServicesClient } from '../src/index' //"@bettercorp/service-base"; + +export class demo extends ServicesClient { + public readonly pluginName: string = "demo"; + + async triggerServerOnEvent(data: any): Promise { + await this.emitEvent("exampleOnEvent", data); + } + async triggerServerMethod(data: any): Promise { + return this.emitEventAndReturn("exampleServerMethod", data); + } +} diff --git a/nodejs/templates/sec.config.json b/nodejs/templates/sec.config.json deleted file mode 100644 index da3c32f..0000000 --- a/nodejs/templates/sec.config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "plugins": {}, - "deploymentProfiles": { - "default": {} - } -} \ No newline at end of file diff --git a/nodejs/templates/sec.config.ts b/nodejs/templates/sec.config.ts index b701205..4e6244c 100644 --- a/nodejs/templates/sec.config.ts +++ b/nodejs/templates/sec.config.ts @@ -1,9 +1,9 @@ -export interface MyPluginConfig { +export interface PluginConfig { } -export default (pluginName: string, existingPluginConfig: any): MyPluginConfig => { - let newConfig: MyPluginConfig = { +export default (pluginName: string, existingPluginConfig: any): PluginConfig => { + let newConfig: PluginConfig = { }; return newConfig; diff --git a/nodejs/templates/sec.config.yaml b/nodejs/templates/sec.config.yaml new file mode 100644 index 0000000..df3d5ef --- /dev/null +++ b/nodejs/templates/sec.config.yaml @@ -0,0 +1,14 @@ +deploymentProfiles: + default: + config-default: + mappedName: config-default + enabled: true + events-default: + mappedName: events-default + enabled: true + log-default: + mappedName: log-default + enabled: true +plugins: + log-default: {} + events-default: {} diff --git a/nodejs/tsconfig-release.json b/nodejs/tsconfig-release.json new file mode 100644 index 0000000..1874362 --- /dev/null +++ b/nodejs/tsconfig-release.json @@ -0,0 +1,45 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": ["types/*"] + }, + "module": "commonjs", + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "sourceMap": true, + "outDir": "lib", + "rootDir": "src", + "strict": true, + "target": "es2021", + "lib": ["es2021"], + "declaration": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node" + }, + "linterOptions": { + "exclude": [ + "src/plugins/-*/**/*.*", + "src/tests/**/*.*" + ] + }, + "compileOnSave": true, + "include": [ + "src", + "src/tests/sb/**/*.*" + ], + "exclude": [ + "node_modules/**", + "src/plugins/*-test*/**/*.*", + "src/plugins/-*/**/*.*", + "src/plugins/service-*/**/*.*", + "src/tests/**/*.*" + ] +} \ No newline at end of file diff --git a/nodejs/tsconfig.json b/nodejs/tsconfig.json index fe15773..95cf69a 100644 --- a/nodejs/tsconfig.json +++ b/nodejs/tsconfig.json @@ -25,18 +25,13 @@ "moduleResolution": "node" }, "linterOptions": { - "exclude": [ - "src/plugins/-*/**/*.*" - ] + "exclude": ["src/plugins/-*/**/*.*"] }, "compileOnSave": true, - "include": [ - "src" - ], + "include": ["src"], "exclude": [ "node_modules/**", "src/plugins/*-test*/**/*.*", - "src/plugins/-*/**/*.*", - "src/plugins/service-*/**/*.*" + "src/plugins/-*/**/*.*" ] -} \ No newline at end of file +}