diff --git a/.github/workflows/re_test-integration-azure.yml b/.github/workflows/re_test-integration-azure.yml index 5e0c4c3f3f..9d8b0f4c94 100644 --- a/.github/workflows/re_test-integration-azure.yml +++ b/.github/workflows/re_test-integration-azure.yml @@ -7,7 +7,7 @@ on: workflow_call: inputs: azure-region: - default: 'East US' + default: 'East US 2' required: false type: string azure-publisher-email: diff --git a/.github/workflows/re_test-integration-prepare.yml b/.github/workflows/re_test-integration-prepare.yml index bb1709f9dd..0b2fa8a3ba 100644 --- a/.github/workflows/re_test-integration-prepare.yml +++ b/.github/workflows/re_test-integration-prepare.yml @@ -58,6 +58,7 @@ jobs: name: integration-test-dependencies-${{ inputs.command_sha }} path: packages/framework-integration-tests/.booster retention-days: 1 + include-hidden-files: true - name: Upload integration test dependencies uses: actions/upload-artifact@v4 @@ -67,3 +68,4 @@ jobs: name: integration-test-dependencies-${{ github.sha }} path: packages/framework-integration-tests/.booster retention-days: 1 + include-hidden-files: true diff --git a/.github/workflows/wf_test-integration.yml b/.github/workflows/wf_test-integration.yml index 1eb21bba09..cb9349d771 100644 --- a/.github/workflows/wf_test-integration.yml +++ b/.github/workflows/wf_test-integration.yml @@ -13,7 +13,7 @@ on: required: false type: string azure-region: - default: 'East US' + default: 'East US 2' required: false type: string azure-publisher-email: diff --git a/common/changes/@boostercloud/framework-core/graphql_union_types_for_queries_2024-12-08-21-50.json b/common/changes/@boostercloud/framework-core/graphql_union_types_for_queries_2024-12-08-21-50.json new file mode 100644 index 0000000000..453ce380a5 --- /dev/null +++ b/common/changes/@boostercloud/framework-core/graphql_union_types_for_queries_2024-12-08-21-50.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@boostercloud/framework-core", + "comment": "Added graphql union types to query return type generation", + "type": "patch" + } + ], + "packageName": "@boostercloud/framework-core" +} \ No newline at end of file diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 1cce552fa1..520e0f23c2 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -8,8 +8,8 @@ importers: ../../packages/application-tester: specifiers: '@apollo/client': 3.7.13 - '@boostercloud/eslint-config': workspace:^2.11.0 - '@boostercloud/framework-types': workspace:^2.11.0 + '@boostercloud/eslint-config': workspace:^2.18.7 + '@boostercloud/framework-types': workspace:^2.18.7 '@effect-ts/core': ^0.60.4 '@types/jsonwebtoken': 9.0.1 '@types/node': ^18.18.2 @@ -35,52 +35,51 @@ importers: subscriptions-transport-ws: 0.11.0 tslib: ^2.4.0 typescript: 5.1.6 - ws: 8.12.0 + ws: 8.17.1 dependencies: - '@apollo/client': 3.7.13_sphwu2tmthkxbmhoomzrsl4p7y + '@apollo/client': 3.7.13_pvbge6vplei5rx3k4pxg27es3y '@boostercloud/framework-types': link:../framework-types '@effect-ts/core': 0.60.5 '@types/sinon': 10.0.0 cross-fetch: 3.1.5 - graphql: 16.8.1 + graphql: 16.9.0 jsonwebtoken: 9.0.1 sinon: 9.2.3 - subscriptions-transport-ws: 0.11.0_graphql@16.8.1 - tslib: 2.6.2 - ws: 8.12.0 + subscriptions-transport-ws: 0.11.0_graphql@16.9.0 + tslib: 2.8.1 + ws: 8.17.1 devDependencies: '@boostercloud/eslint-config': link:../../tools/eslint-config '@types/jsonwebtoken': 9.0.1 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/ws': 8.5.4 - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi chai: 4.2.0 chai-as-promised: 7.1.1_chai@4.2.0 - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 - fast-check: 3.17.1 + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 + fast-check: 3.23.1 prettier: 2.3.0 - rimraf: 5.0.5 + rimraf: 5.0.10 sinon-chai: 3.5.0_chai@4.2.0+sinon@9.2.3 typescript: 5.1.6 ../../packages/cli: specifiers: - '@boostercloud/application-tester': workspace:^2.11.0 - '@boostercloud/eslint-config': workspace:^2.11.0 - '@boostercloud/framework-core': workspace:^2.11.0 - '@boostercloud/framework-types': workspace:^2.11.0 + '@boostercloud/application-tester': workspace:^2.18.7 + '@boostercloud/eslint-config': workspace:^2.18.7 + '@boostercloud/framework-core': workspace:^2.18.7 + '@boostercloud/framework-types': workspace:^2.18.7 '@effect-ts/core': ^0.60.4 '@oclif/core': 3.15.0 '@oclif/plugin-help': ^5 '@oclif/test': ^3.0.3 '@types/chai': 4.2.18 '@types/chai-as-promised': 7.1.4 - '@types/child-process-promise': ^2.2.1 '@types/faker': 5.1.5 '@types/fs-extra': ^9.0.13 '@types/inflected': 1.1.29 @@ -96,7 +95,6 @@ importers: chai: 4.2.0 chai-as-promised: 7.1.1 chalk: ^2.4.2 - child-process-promise: ^2.2.1 copyfiles: ^2.3.0 eslint: ^8.23.1 eslint-config-prettier: 8.3.0 @@ -129,66 +127,64 @@ importers: '@boostercloud/framework-types': link:../framework-types '@effect-ts/core': 0.60.5 '@oclif/core': 3.15.0_typescript@5.1.6 - '@oclif/plugin-help': 5.2.20_cwiqw7fmejhb47wvqtchhjxme4 + '@oclif/plugin-help': 5.2.20_qnvbopyuzco2g5z7jdoebgqlma chalk: 2.4.2 - child-process-promise: 2.2.1 execa: 2.1.0 - fp-ts: 2.16.5 + fp-ts: 2.16.9 fs-extra: 8.1.0 inflected: 2.1.0 inquirer: 7.3.3 mustache: 4.1.0 ora: 3.4.0 ts-morph: 19.0.0 - tslib: 2.6.2 + tslib: 2.8.1 devDependencies: '@boostercloud/application-tester': link:../application-tester '@boostercloud/eslint-config': link:../../tools/eslint-config - '@oclif/test': 3.2.10 + '@oclif/test': 3.2.15 '@types/chai': 4.2.18 '@types/chai-as-promised': 7.1.4 - '@types/child-process-promise': 2.2.6 '@types/faker': 5.1.5 '@types/fs-extra': 9.0.13 '@types/inflected': 1.1.29 '@types/inquirer': 6.5.0 '@types/mocha': 10.0.1 '@types/mustache': 4.1.0 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/rewire': 2.5.30 '@types/sinon': 10.0.0 '@types/sinon-chai': 3.2.5 - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi chai: 4.2.0 chai-as-promised: 7.1.1_chai@4.2.0 copyfiles: 2.4.1 - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 faker: 5.1.0 - fancy-test: 3.0.14 + fancy-test: 3.0.16 mocha: 10.2.0 nyc: 15.1.0 prettier: 2.3.0 rewire: 5.0.0 - rimraf: 5.0.5 + rimraf: 5.0.10 sinon: 9.2.3 sinon-chai: 3.5.0_chai@4.2.0+sinon@9.2.3 - ts-node: 10.9.2_cwiqw7fmejhb47wvqtchhjxme4 + ts-node: 10.9.2_qnvbopyuzco2g5z7jdoebgqlma ts-patch: 3.1.2 typescript: 5.1.6 ../../packages/framework-common-helpers: specifiers: - '@boostercloud/eslint-config': workspace:^2.11.0 - '@boostercloud/framework-types': workspace:^2.11.0 + '@boostercloud/eslint-config': workspace:^2.18.7 + '@boostercloud/framework-types': workspace:^2.18.7 '@effect-ts/core': ^0.60.4 '@types/chai': 4.2.18 '@types/chai-as-promised': 7.1.4 - '@types/child-process-promise': ^2.2.1 + '@types/faker': 5.1.5 '@types/mocha': 10.0.1 '@types/node': ^18.18.2 '@types/rewire': ^2.5.28 @@ -199,13 +195,14 @@ importers: '@typescript-eslint/parser': ^5.0.0 chai: 4.2.0 chai-as-promised: 7.1.1 - child-process-promise: ^2.2.1 class-transformer: ~0.5.1 eslint: ^8.23.1 eslint-config-prettier: 8.3.0 eslint-plugin-import: ^2.26.0 eslint-plugin-prettier: 3.4.0 eslint-plugin-unicorn: ~44.0.2 + execa: ^2.0.3 + faker: 5.1.0 mocha: 10.2.0 nyc: ^15.1.0 prettier: 2.3.0 @@ -219,45 +216,46 @@ importers: dependencies: '@boostercloud/framework-types': link:../framework-types '@effect-ts/core': 0.60.5 - child-process-promise: 2.2.1 class-transformer: 0.5.1 - tslib: 2.6.2 + execa: 2.1.0 + tslib: 2.8.1 devDependencies: '@boostercloud/eslint-config': link:../../tools/eslint-config '@types/chai': 4.2.18 '@types/chai-as-promised': 7.1.4 - '@types/child-process-promise': 2.2.6 + '@types/faker': 5.1.5 '@types/mocha': 10.0.1 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/rewire': 2.5.30 '@types/sinon': 10.0.0 '@types/sinon-chai': 3.2.5 '@types/uuid': 8.3.0 - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi chai: 4.2.0 chai-as-promised: 7.1.1_chai@4.2.0 - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 + faker: 5.1.0 mocha: 10.2.0 nyc: 15.1.0 prettier: 2.3.0 rewire: 5.0.0 - rimraf: 5.0.5 + rimraf: 5.0.10 sinon: 9.2.3 sinon-chai: 3.5.0_chai@4.2.0+sinon@9.2.3 - ts-node: 10.9.2_cwiqw7fmejhb47wvqtchhjxme4 + ts-node: 10.9.2_qnvbopyuzco2g5z7jdoebgqlma typescript: 5.1.6 ../../packages/framework-core: specifiers: - '@boostercloud/eslint-config': workspace:^2.11.0 - '@boostercloud/framework-common-helpers': workspace:^2.11.0 - '@boostercloud/framework-types': workspace:^2.11.0 - '@boostercloud/metadata-booster': workspace:^2.11.0 + '@boostercloud/eslint-config': workspace:^2.18.7 + '@boostercloud/framework-common-helpers': workspace:^2.18.7 + '@boostercloud/framework-types': workspace:^2.18.7 + '@boostercloud/metadata-booster': workspace:^2.18.7 '@effect/cli': 0.35.26 '@effect/platform': 0.48.24 '@effect/platform-node': 0.45.26 @@ -310,30 +308,30 @@ importers: tslib: ^2.4.0 typescript: 5.1.6 validator: 13.7.0 - ws: 8.12.0 + ws: 8.17.1 dependencies: '@boostercloud/framework-common-helpers': link:../framework-common-helpers '@boostercloud/framework-types': link:../framework-types '@effect/cli': 0.35.26_q3uix5ylsud7xnsn3vpzgrghwu - '@effect/platform': 0.48.24_dyvpp6bxxcuou3trhs4x4ygr5y + '@effect/platform': 0.48.24_aixcdyfeuz2zct7jthaihye4ri '@effect/platform-node': 0.45.26_cahjalgelcnk6vcj6x2oc46m3a '@effect/printer': 0.32.2_67ibgamlfqfgywvgecp7hwrxja '@effect/printer-ansi': 0.32.26_67ibgamlfqfgywvgecp7hwrxja - '@effect/schema': 0.64.18_jsi5r7dvmbit34siukqkgq3mea + '@effect/schema': 0.64.18_k5iqzw5vszbbtmhrto2doihvji '@effect/typeclass': 0.23.17_effect@2.4.17 effect: 2.4.17 - fast-check: 3.17.1 - fp-ts: 2.16.5 - graphql-scalars: 1.23.0_graphql@16.8.1 - graphql-subscriptions: 2.0.0_graphql@16.8.1 + fast-check: 3.23.1 + fp-ts: 2.16.9 + graphql-scalars: 1.24.0_graphql@16.9.0 + graphql-subscriptions: 2.0.0_graphql@16.9.0 inflected: 2.1.0 iterall: 1.3.0 jsonwebtoken: 9.0.1 jwks-rsa: 3.0.1 reflect-metadata: 0.1.13 - tslib: 2.6.2 + tslib: 2.8.1 validator: 13.7.0 - ws: 8.12.0 + ws: 8.17.1 devDependencies: '@boostercloud/eslint-config': link:../../tools/eslint-config '@boostercloud/metadata-booster': link:../metadata-booster @@ -343,50 +341,50 @@ importers: '@types/inflected': 1.1.29 '@types/jsonwebtoken': 9.0.1 '@types/mocha': 10.0.1 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/sinon': 10.0.0 '@types/sinon-chai': 3.2.5 '@types/validator': 13.1.3 - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi chai: 4.2.0 chai-as-promised: 7.1.1_chai@4.2.0 cross-env: 7.0.3 - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 faker: 5.1.0 - graphql: 16.8.1 + graphql: 16.9.0 mocha: 10.2.0 mock-jwks: 1.0.3_nock@11.8.2 nock: 11.8.2 nyc: 15.1.0 prettier: 2.3.0 - rimraf: 5.0.5 + rimraf: 5.0.10 sinon: 9.2.3 sinon-chai: 3.5.0_chai@4.2.0+sinon@9.2.3 - ts-node: 10.9.2_cwiqw7fmejhb47wvqtchhjxme4 + ts-node: 10.9.2_qnvbopyuzco2g5z7jdoebgqlma ts-patch: 3.1.2 typescript: 5.1.6 ../../packages/framework-integration-tests: specifiers: '@apollo/client': 3.7.13 - '@boostercloud/application-tester': workspace:^2.11.0 - '@boostercloud/cli': workspace:^2.11.0 - '@boostercloud/eslint-config': workspace:^2.11.0 - '@boostercloud/framework-common-helpers': workspace:^2.11.0 - '@boostercloud/framework-core': workspace:^2.11.0 - '@boostercloud/framework-provider-aws': workspace:^2.11.0 - '@boostercloud/framework-provider-aws-infrastructure': workspace:^2.11.0 - '@boostercloud/framework-provider-azure': workspace:^2.11.0 - '@boostercloud/framework-provider-azure-infrastructure': workspace:^2.11.0 - '@boostercloud/framework-provider-local': workspace:^2.11.0 - '@boostercloud/framework-provider-local-infrastructure': workspace:^2.11.0 - '@boostercloud/framework-types': workspace:^2.11.0 - '@boostercloud/metadata-booster': workspace:^2.11.0 + '@boostercloud/application-tester': workspace:^2.18.7 + '@boostercloud/cli': workspace:^2.18.7 + '@boostercloud/eslint-config': workspace:^2.18.7 + '@boostercloud/framework-common-helpers': workspace:^2.18.7 + '@boostercloud/framework-core': workspace:^2.18.7 + '@boostercloud/framework-provider-aws': workspace:^2.18.7 + '@boostercloud/framework-provider-aws-infrastructure': workspace:^2.18.7 + '@boostercloud/framework-provider-azure': workspace:^2.18.7 + '@boostercloud/framework-provider-azure-infrastructure': workspace:^2.18.7 + '@boostercloud/framework-provider-local': workspace:^2.18.7 + '@boostercloud/framework-provider-local-infrastructure': workspace:^2.18.7 + '@boostercloud/framework-types': workspace:^2.18.7 + '@boostercloud/metadata-booster': workspace:^2.18.7 '@effect-ts/core': ^0.60.4 '@effect/cli': 0.35.26 '@effect/platform': 0.48.24 @@ -400,7 +398,6 @@ importers: '@types/chai': 4.2.18 '@types/chai-arrays': 2.0.0 '@types/chai-as-promised': 7.1.4 - '@types/child-process-promise': ^2.2.1 '@types/faker': 5.1.5 '@types/jsonwebtoken': 9.0.1 '@types/mocha': 10.0.1 @@ -415,7 +412,6 @@ importers: cdktf-cli: 0.19.2 chai: 4.2.0 chai-as-promised: 7.1.1 - child-process-promise: ^2.2.1 concurrently: ~8.2.2 constructs: ^10.0.0 cross-fetch: 3.1.5 @@ -425,6 +421,7 @@ importers: eslint-plugin-import: ^2.26.0 eslint-plugin-prettier: 3.4.0 eslint-plugin-unicorn: ~44.0.2 + execa: ^2.0.3 express: ^4.19.2 express-unless: 2.1.3 faker: 5.1.0 @@ -449,7 +446,7 @@ importers: ts-patch: 3.1.2 tslib: ^2.4.0 typescript: 5.1.6 - ws: 8.12.0 + ws: 8.17.1 dependencies: '@boostercloud/framework-common-helpers': link:../framework-common-helpers '@boostercloud/framework-core': link:../framework-core @@ -459,22 +456,23 @@ importers: '@boostercloud/framework-types': link:../framework-types '@effect-ts/core': 0.60.5 '@effect/cli': 0.35.26_q3uix5ylsud7xnsn3vpzgrghwu - '@effect/platform': 0.48.24_dyvpp6bxxcuou3trhs4x4ygr5y + '@effect/platform': 0.48.24_aixcdyfeuz2zct7jthaihye4ri '@effect/platform-node': 0.45.26_cahjalgelcnk6vcj6x2oc46m3a '@effect/printer': 0.32.2_67ibgamlfqfgywvgecp7hwrxja '@effect/printer-ansi': 0.32.26_67ibgamlfqfgywvgecp7hwrxja - '@effect/schema': 0.64.18_jsi5r7dvmbit34siukqkgq3mea + '@effect/schema': 0.64.18_k5iqzw5vszbbtmhrto2doihvji '@effect/typeclass': 0.23.17_effect@2.4.17 aws-sdk: 2.853.0 effect: 2.4.17 - express: 4.19.2 + execa: 2.1.0 + express: 4.21.2 express-unless: 2.1.3 - fast-check: 3.17.1 - graphql: 16.8.1 - tslib: 2.6.2 - ws: 8.12.0 + fast-check: 3.23.1 + graphql: 16.9.0 + tslib: 2.8.1 + ws: 8.17.1 devDependencies: - '@apollo/client': 3.7.13_c5ukhmnf6fm7wz7ctna5fqkm6e + '@apollo/client': 3.7.13_jxorufveymi4xbrutgakjkp5wa '@boostercloud/application-tester': link:../application-tester '@boostercloud/cli': link:../cli '@boostercloud/eslint-config': link:../../tools/eslint-config @@ -487,31 +485,29 @@ importers: '@types/chai': 4.2.18 '@types/chai-arrays': 2.0.0 '@types/chai-as-promised': 7.1.4 - '@types/child-process-promise': 2.2.6 '@types/faker': 5.1.5 '@types/jsonwebtoken': 9.0.1 '@types/mocha': 10.0.1 '@types/nedb': 1.8.16 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/sinon': 10.0.0 '@types/sinon-chai': 3.2.5 - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry - cdktf: 0.19.2_constructs@10.3.0 + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi + cdktf: 0.19.2_constructs@10.4.2 cdktf-cli: 0.19.2_ink@3.2.0+react@17.0.2 chai: 4.2.0 chai-as-promised: 7.1.1_chai@4.2.0 - child-process-promise: 2.2.1 concurrently: 8.2.2 - constructs: 10.3.0 + constructs: 10.4.2 cross-fetch: 3.1.5 - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 faker: 5.1.0 - graphology-types: 0.24.7 + graphology-types: 0.24.8 ink: 3.2.0_react@17.0.2 jsonwebtoken: 9.0.1 jwks-rsa: 3.0.1 @@ -521,20 +517,20 @@ importers: prettier: 2.3.0 react: 17.0.2 reflect-metadata: 0.1.13 - rimraf: 5.0.5 + rimraf: 5.0.10 serverless: 3.8.0 serverless-artillery: 0.5.2 sinon: 9.2.3 - subscriptions-transport-ws: 0.11.0_graphql@16.8.1 - ts-node: 10.9.2_cwiqw7fmejhb47wvqtchhjxme4 + subscriptions-transport-ws: 0.11.0_graphql@16.9.0 + ts-node: 10.9.2_qnvbopyuzco2g5z7jdoebgqlma ts-patch: 3.1.2 typescript: 5.1.6 ../../packages/framework-provider-aws: specifiers: - '@boostercloud/eslint-config': workspace:^2.11.0 - '@boostercloud/framework-common-helpers': workspace:^2.11.0 - '@boostercloud/framework-types': workspace:^2.11.0 + '@boostercloud/eslint-config': workspace:^2.18.7 + '@boostercloud/framework-common-helpers': workspace:^2.18.7 + '@boostercloud/framework-types': workspace:^2.18.7 '@effect-ts/core': ^0.60.4 '@types/aws-lambda': 8.10.48 '@types/chai': 4.2.18 @@ -573,7 +569,7 @@ importers: '@boostercloud/framework-common-helpers': link:../framework-common-helpers '@boostercloud/framework-types': link:../framework-types '@effect-ts/core': 0.60.5 - tslib: 2.6.2 + tslib: 2.8.1 devDependencies: '@boostercloud/eslint-config': link:../../tools/eslint-config '@types/aws-lambda': 8.10.48 @@ -582,30 +578,30 @@ importers: '@types/chai-as-promised': 7.1.4 '@types/faker': 5.1.5 '@types/mocha': 10.0.1 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/rewire': 2.5.30 '@types/sinon': 10.0.0 '@types/sinon-chai': 3.2.5 - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi aws-sdk: 2.853.0 chai: 4.2.0 chai-arrays: 2.2.0 chai-as-promised: 7.1.1_chai@4.2.0 - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 faker: 5.1.0 mocha: 10.2.0 nyc: 15.1.0 prettier: 2.3.0 rewire: 5.0.0 - rimraf: 5.0.5 + rimraf: 5.0.10 sinon: 9.2.3 sinon-chai: 3.5.0_chai@4.2.0+sinon@9.2.3 - ts-node: 10.9.2_cwiqw7fmejhb47wvqtchhjxme4 + ts-node: 10.9.2_qnvbopyuzco2g5z7jdoebgqlma typescript: 5.1.6 velocityjs: 2.0.6 @@ -628,10 +624,10 @@ importers: '@aws-cdk/core': ^1.170.0 '@aws-cdk/custom-resources': ^1.170.0 '@aws-cdk/cx-api': ^1.170.0 - '@boostercloud/eslint-config': workspace:^2.11.0 - '@boostercloud/framework-common-helpers': workspace:^2.11.0 - '@boostercloud/framework-provider-aws': workspace:^2.11.0 - '@boostercloud/framework-types': workspace:^2.11.0 + '@boostercloud/eslint-config': workspace:^2.18.7 + '@boostercloud/framework-common-helpers': workspace:^2.18.7 + '@boostercloud/framework-provider-aws': workspace:^2.18.7 + '@boostercloud/framework-types': workspace:^2.18.7 '@effect-ts/core': ^0.60.4 '@types/archiver': 5.1.0 '@types/aws-lambda': 8.10.48 @@ -676,20 +672,20 @@ importers: dependencies: '@aws-cdk/assets': 1.204.0_uszt2j4mor3yrbm3tre3az4zvy '@aws-cdk/aws-apigateway': 1.204.0_cs2gnbp3a35i2p5l5u5a3t4624 - '@aws-cdk/aws-apigatewayv2': 1.204.0_xbmlyikxd4zabyotfrt4oo4gli - '@aws-cdk/aws-cloudfront': 1.204.0_xbmlyikxd4zabyotfrt4oo4gli + '@aws-cdk/aws-apigatewayv2': 1.204.0_knsptffnex2lyiy4uxr2qfndt4 + '@aws-cdk/aws-cloudfront': 1.204.0_knsptffnex2lyiy4uxr2qfndt4 '@aws-cdk/aws-dynamodb': 1.204.0_ea3k7xy2kixjvb2em7ltbqbgym '@aws-cdk/aws-events': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm '@aws-cdk/aws-events-targets': 1.204.0_cboae2e2djj6552nyu56pbamie '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm - '@aws-cdk/aws-lambda-event-sources': 1.204.0_yl5g6fuosfeqtat6z7imtengha + '@aws-cdk/aws-lambda-event-sources': 1.204.0_6ewijctynstfo6zas4hwstt4zy '@aws-cdk/aws-logs': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu '@aws-cdk/aws-s3': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/aws-s3-deployment': 1.204.0_vowuuig2yoedxxl4xtk74a3sma '@aws-cdk/cloudformation-diff': 1.203.0 '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam - '@aws-cdk/custom-resources': 1.204.0_c23kgzmvfhgnr6qpzzlbsfzuc4 + '@aws-cdk/custom-resources': 1.204.0_575fyf2i7umbzongv3ijfqjgle '@aws-cdk/cx-api': 1.203.0 '@boostercloud/framework-common-helpers': link:../framework-common-helpers '@boostercloud/framework-provider-aws': link:../framework-provider-aws @@ -702,7 +698,7 @@ importers: colors: 1.4.0 constructs: 3.4.344 promptly: 3.2.0 - tslib: 2.6.2 + tslib: 2.8.1 yaml: 1.10.2 devDependencies: '@boostercloud/eslint-config': link:../../tools/eslint-config @@ -713,28 +709,28 @@ importers: '@types/chai-as-promised': 7.1.4 '@types/faker': 5.1.5 '@types/mocha': 10.0.1 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/rewire': 2.5.30 '@types/sinon': 10.0.0 '@types/sinon-chai': 3.2.5 - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi chai: 4.2.0 chai-as-promised: 7.1.1_chai@4.2.0 - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 faker: 5.1.0 mocha: 10.2.0 nyc: 15.1.0 prettier: 2.3.0 rewire: 5.0.0 - rimraf: 5.0.5 + rimraf: 5.0.10 sinon: 9.2.3 sinon-chai: 3.5.0_chai@4.2.0+sinon@9.2.3 - ts-node: 10.9.2_cwiqw7fmejhb47wvqtchhjxme4 + ts-node: 10.9.2_qnvbopyuzco2g5z7jdoebgqlma typescript: 5.1.6 velocityjs: 2.0.6 @@ -745,9 +741,9 @@ importers: '@azure/functions': ^1.2.2 '@azure/identity': ~2.1.0 '@azure/web-pubsub': ~1.1.0 - '@boostercloud/eslint-config': workspace:^2.11.0 - '@boostercloud/framework-common-helpers': workspace:^2.11.0 - '@boostercloud/framework-types': workspace:^2.11.0 + '@boostercloud/eslint-config': workspace:^2.18.7 + '@boostercloud/framework-common-helpers': workspace:^2.18.7 + '@boostercloud/framework-types': workspace:^2.18.7 '@effect-ts/core': ^0.60.4 '@types/chai': 4.2.18 '@types/chai-as-promised': 7.1.4 @@ -776,41 +772,41 @@ importers: tslib: ^2.4.0 typescript: 5.1.6 dependencies: - '@azure/cosmos': 4.0.0 + '@azure/cosmos': 4.2.0 '@azure/event-hubs': 5.11.1 '@azure/functions': 1.2.3 '@azure/identity': 2.1.0 - '@azure/web-pubsub': 1.1.1 + '@azure/web-pubsub': 1.1.3 '@boostercloud/framework-common-helpers': link:../framework-common-helpers '@boostercloud/framework-types': link:../framework-types '@effect-ts/core': 0.60.5 - tslib: 2.6.2 + tslib: 2.8.1 devDependencies: '@boostercloud/eslint-config': link:../../tools/eslint-config '@types/chai': 4.2.18 '@types/chai-as-promised': 7.1.4 '@types/faker': 5.1.5 '@types/mocha': 10.0.1 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/sinon': 10.0.0 '@types/sinon-chai': 3.2.5 - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi chai: 4.2.0 chai-as-promised: 7.1.1_chai@4.2.0 - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 faker: 5.1.0 mocha: 10.2.0 nyc: 15.1.0 prettier: 2.3.0 - rimraf: 5.0.5 + rimraf: 5.0.10 sinon: 9.2.3 sinon-chai: 3.5.0_chai@4.2.0+sinon@9.2.3 - ts-node: 10.9.2_cwiqw7fmejhb47wvqtchhjxme4 + ts-node: 10.9.2_qnvbopyuzco2g5z7jdoebgqlma typescript: 5.1.6 ../../packages/framework-provider-azure-infrastructure: @@ -819,12 +815,12 @@ importers: '@azure/arm-resources': ^5.0.1 '@azure/cosmos': ^4.0.0 '@azure/identity': ~2.1.0 - '@boostercloud/eslint-config': workspace:^2.11.0 - '@boostercloud/framework-common-helpers': workspace:^2.11.0 - '@boostercloud/framework-core': workspace:^2.11.0 - '@boostercloud/framework-provider-azure': workspace:^2.11.0 - '@boostercloud/framework-types': workspace:^2.11.0 - '@cdktf/provider-azurerm': 11.2.0 + '@boostercloud/eslint-config': workspace:^2.18.7 + '@boostercloud/framework-common-helpers': workspace:^2.18.7 + '@boostercloud/framework-core': workspace:^2.18.7 + '@boostercloud/framework-provider-azure': workspace:^2.18.7 + '@boostercloud/framework-types': workspace:^2.18.7 + '@cdktf/provider-azurerm': 13.3.0 '@cdktf/provider-time': 9.0.2 '@effect-ts/core': ^0.60.4 '@types/archiver': 5.1.0 @@ -873,23 +869,23 @@ importers: dependencies: '@azure/arm-appservice': 13.0.3 '@azure/arm-resources': 5.2.0 - '@azure/cosmos': 4.0.0 + '@azure/cosmos': 4.2.0 '@azure/identity': 2.1.0 '@boostercloud/framework-common-helpers': link:../framework-common-helpers '@boostercloud/framework-core': link:../framework-core '@boostercloud/framework-provider-azure': link:../framework-provider-azure '@boostercloud/framework-types': link:../framework-types - '@cdktf/provider-azurerm': 11.2.0_5k7lg6pu6lyti4sdnvep4rdzly - '@cdktf/provider-time': 9.0.2_5k7lg6pu6lyti4sdnvep4rdzly + '@cdktf/provider-azurerm': 13.3.0_eykofocqnxaowlkqmvzbold3ry + '@cdktf/provider-time': 9.0.2_eykofocqnxaowlkqmvzbold3ry '@effect-ts/core': 0.60.5 '@types/archiver': 5.1.0 '@types/needle': 2.5.3 archiver: 5.3.0 - cdktf: 0.19.2_constructs@10.3.0 + cdktf: 0.19.2_constructs@10.4.2 cdktf-cli: 0.19.2_ink@3.2.0+react@17.0.2 chai: 4.2.0 chai-as-promised: 7.1.1_chai@4.2.0 - constructs: 10.3.0 + constructs: 10.4.2 copyfiles: 2.4.1 fs-extra: 8.1.0 ink: 3.2.0_react@17.0.2 @@ -898,7 +894,7 @@ importers: ora: 3.4.0 react: 17.0.2 sinon-chai: 3.5.0_chai@4.2.0+sinon@9.2.3 - tslib: 2.6.2 + tslib: 2.8.1 uuid: 8.3.2 devDependencies: '@boostercloud/eslint-config': link:../../tools/eslint-config @@ -908,31 +904,31 @@ importers: '@types/fs-extra': 9.0.13 '@types/mocha': 10.0.1 '@types/mustache': 4.1.0 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/sinon': 10.0.0 '@types/sinon-chai': 3.2.5 '@types/uuid': 8.3.0 - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 faker: 5.1.0 mocha: 10.2.0 nyc: 15.1.0 prettier: 2.3.0 - rimraf: 5.0.5 + rimraf: 5.0.10 sinon: 9.2.3 - ts-node: 10.9.2_cwiqw7fmejhb47wvqtchhjxme4 + ts-node: 10.9.2_qnvbopyuzco2g5z7jdoebgqlma typescript: 5.1.6 ../../packages/framework-provider-local: specifiers: - '@boostercloud/eslint-config': workspace:^2.11.0 - '@boostercloud/framework-common-helpers': workspace:^2.11.0 - '@boostercloud/framework-types': workspace:^2.11.0 + '@boostercloud/eslint-config': workspace:^2.18.7 + '@boostercloud/framework-common-helpers': workspace:^2.18.7 + '@boostercloud/framework-types': workspace:^2.18.7 '@effect-ts/core': ^0.60.4 '@seald-io/nedb': 4.0.2 '@types/chai': 4.2.18 @@ -966,14 +962,14 @@ importers: ts-node: ^10.9.1 tslib: ^2.4.0 typescript: 5.1.6 - ws: 8.12.0 + ws: 8.17.1 dependencies: '@boostercloud/framework-common-helpers': link:../framework-common-helpers '@boostercloud/framework-types': link:../framework-types '@effect-ts/core': 0.60.5 '@seald-io/nedb': 4.0.2 - tslib: 2.6.2 - ws: 8.12.0 + tslib: 2.8.1 + ws: 8.17.1 devDependencies: '@boostercloud/eslint-config': link:../../tools/eslint-config '@types/chai': 4.2.18 @@ -981,38 +977,38 @@ importers: '@types/express': 4.17.21 '@types/faker': 5.1.5 '@types/mocha': 10.0.1 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/sinon': 10.0.0 '@types/sinon-chai': 3.2.5 '@types/sinon-express-mock': 1.3.12 '@types/ws': 8.5.4 - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi chai: 4.2.0 chai-as-promised: 7.1.1_chai@4.2.0 - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 - express: 4.19.2 + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 + express: 4.21.2 faker: 5.1.0 mocha: 10.2.0 nyc: 15.1.0 prettier: 2.3.0 - rimraf: 5.0.5 + rimraf: 5.0.10 sinon: 9.2.3 sinon-chai: 3.5.0_chai@4.2.0+sinon@9.2.3 sinon-express-mock: 2.2.1_sinon@9.2.3 - ts-node: 10.9.2_cwiqw7fmejhb47wvqtchhjxme4 + ts-node: 10.9.2_qnvbopyuzco2g5z7jdoebgqlma typescript: 5.1.6 ../../packages/framework-provider-local-infrastructure: specifiers: - '@boostercloud/eslint-config': workspace:^2.11.0 - '@boostercloud/framework-common-helpers': workspace:^2.11.0 - '@boostercloud/framework-provider-local': workspace:^2.11.0 - '@boostercloud/framework-types': workspace:^2.11.0 + '@boostercloud/eslint-config': workspace:^2.18.7 + '@boostercloud/framework-common-helpers': workspace:^2.18.7 + '@boostercloud/framework-provider-local': workspace:^2.18.7 + '@boostercloud/framework-types': workspace:^2.18.7 '@effect-ts/core': ^0.60.4 '@types/chai': 4.2.18 '@types/chai-as-promised': 7.1.4 @@ -1054,9 +1050,9 @@ importers: '@boostercloud/framework-types': link:../framework-types '@effect-ts/core': 0.60.5 cors: 2.8.5 - express: 4.19.2 + express: 4.21.2 node-schedule: 2.1.1 - tslib: 2.6.2 + tslib: 2.8.1 devDependencies: '@boostercloud/eslint-config': link:../../tools/eslint-config '@types/chai': 4.2.18 @@ -1065,35 +1061,35 @@ importers: '@types/express': 4.17.21 '@types/faker': 5.1.5 '@types/mocha': 10.0.1 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/node-schedule': 1.3.2 '@types/sinon': 10.0.0 '@types/sinon-chai': 3.2.5 '@types/sinon-express-mock': 1.3.12 - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi chai: 4.2.0 chai-as-promised: 7.1.1_chai@4.2.0 - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 faker: 5.1.0 mocha: 10.2.0 nyc: 15.1.0 prettier: 2.3.0 - rimraf: 5.0.5 + rimraf: 5.0.10 sinon: 9.2.3 sinon-chai: 3.5.0_chai@4.2.0+sinon@9.2.3 sinon-express-mock: 2.2.1_sinon@9.2.3 - ts-node: 10.9.2_cwiqw7fmejhb47wvqtchhjxme4 + ts-node: 10.9.2_qnvbopyuzco2g5z7jdoebgqlma typescript: 5.1.6 ../../packages/framework-types: specifiers: - '@boostercloud/eslint-config': workspace:^2.11.0 - '@boostercloud/metadata-booster': workspace:^2.11.0 + '@boostercloud/eslint-config': workspace:^2.18.7 + '@boostercloud/metadata-booster': workspace:^2.18.7 '@effect-ts/core': ^0.60.4 '@effect-ts/node': ~0.39.0 '@effect/cli': 0.35.26 @@ -1131,53 +1127,53 @@ importers: typescript: 5.1.6 uuid: 8.3.2 web-streams-polyfill: ~3.3.2 - ws: 8.12.0 + ws: 8.17.1 dependencies: '@effect-ts/core': 0.60.5 '@effect-ts/node': 0.39.0_@effect-ts+core@0.60.5 '@effect/cli': 0.35.26_q3uix5ylsud7xnsn3vpzgrghwu - '@effect/platform': 0.48.24_dyvpp6bxxcuou3trhs4x4ygr5y + '@effect/platform': 0.48.24_aixcdyfeuz2zct7jthaihye4ri '@effect/printer': 0.32.2_67ibgamlfqfgywvgecp7hwrxja '@effect/printer-ansi': 0.32.26_67ibgamlfqfgywvgecp7hwrxja - '@effect/schema': 0.64.18_jsi5r7dvmbit34siukqkgq3mea + '@effect/schema': 0.64.18_k5iqzw5vszbbtmhrto2doihvji '@effect/typeclass': 0.23.17_effect@2.4.17 effect: 2.4.17 - tslib: 2.6.2 + tslib: 2.8.1 uuid: 8.3.2 web-streams-polyfill: 3.3.3 - ws: 8.12.0 + ws: 8.17.1 devDependencies: '@boostercloud/eslint-config': link:../../tools/eslint-config '@boostercloud/metadata-booster': link:../metadata-booster '@types/chai': 4.2.18 '@types/chai-as-promised': 7.1.4 '@types/mocha': 10.0.1 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/sinon': 10.0.0 '@types/sinon-chai': 3.2.5 '@types/uuid': 8.3.0 - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi chai: 4.2.0 chai-as-promised: 7.1.1_chai@4.2.0 - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 - fast-check: 3.17.1 - graphql: 16.8.1 + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 + fast-check: 3.23.1 + graphql: 16.9.0 mocha: 10.2.0 nyc: 15.1.0 prettier: 2.3.0 - rimraf: 5.0.5 + rimraf: 5.0.10 sinon: 9.2.3 sinon-chai: 3.5.0_chai@4.2.0+sinon@9.2.3 typescript: 5.1.6 ../../packages/metadata-booster: specifiers: - '@boostercloud/eslint-config': workspace:^2.11.0 + '@boostercloud/eslint-config': workspace:^2.18.7 '@effect-ts/core': ^0.60.4 '@types/node': ^18.18.2 '@typescript-eslint/eslint-plugin': ^5.0.0 @@ -1200,21 +1196,21 @@ importers: '@effect-ts/core': 0.60.5 reflect-metadata: 0.1.13 ts-morph: 19.0.0 - tslib: 2.6.2 + tslib: 2.8.1 devDependencies: '@boostercloud/eslint-config': link:../../tools/eslint-config - '@types/node': 18.19.31 - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 + '@types/node': 18.19.68 + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 prettier: 2.3.0 - rimraf: 5.0.5 + rimraf: 5.0.10 sinon: 9.2.3 - ts-node: 10.9.2_cwiqw7fmejhb47wvqtchhjxme4 + ts-node: 10.9.2_qnvbopyuzco2g5z7jdoebgqlma ts-patch: 3.1.2 typescript: 5.1.6 @@ -1230,14 +1226,14 @@ importers: prettier: 2.3.0 typescript: 5.1.6 dependencies: - '@typescript-eslint/eslint-plugin': 5.62.0_isoa4rovreaplj6y6c4wy6pss4 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 - eslint-plugin-import: 2.29.1_eslint@8.57.0 - eslint-plugin-prettier: 3.4.0_ddm2pio5nc2sobczsauzpxvcae + '@typescript-eslint/eslint-plugin': 5.62.0_uve4wv4elfpx2l3zvshgwzvkay + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 + eslint-plugin-import: 2.31.0_eslint@8.57.1 + eslint-plugin-prettier: 3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y devDependencies: - eslint-plugin-unicorn: 44.0.2_eslint@8.57.0 + eslint-plugin-unicorn: 44.0.2_eslint@8.57.1 prettier: 2.3.0 typescript: 5.1.6 @@ -1250,19 +1246,15 @@ packages: es5-ext: 0.10.64 dev: true - /@aashutoshrathi/word-wrap/1.2.6: - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} - engines: {node: '>=0.10.0'} - /@ampproject/remapping/2.3.0: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 dev: true - /@apollo/client/3.7.13_c5ukhmnf6fm7wz7ctna5fqkm6e: + /@apollo/client/3.7.13_jxorufveymi4xbrutgakjkp5wa: resolution: {integrity: sha512-wi63WnO2mhb6uHGB/8x1qIOL4ZtZocrxdHS0VBQ9KwBDkwoP/TdVVgZ29J2WkiAPmJ0SK07ju4R2AjHor1gPxQ==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 @@ -1280,25 +1272,25 @@ packages: subscriptions-transport-ws: optional: true dependencies: - '@graphql-typed-document-node/core': 3.2.0_graphql@16.8.1 + '@graphql-typed-document-node/core': 3.2.0_graphql@16.9.0 '@wry/context': 0.7.4 '@wry/equality': 0.5.7 '@wry/trie': 0.3.2 - graphql: 16.8.1 - graphql-tag: 2.12.6_graphql@16.8.1 + graphql: 16.9.0 + graphql-tag: 2.12.6_graphql@16.9.0 hoist-non-react-statics: 3.3.2 optimism: 0.16.2 prop-types: 15.8.1 react: 17.0.2 response-iterator: 0.2.6 - subscriptions-transport-ws: 0.11.0_graphql@16.8.1 + subscriptions-transport-ws: 0.11.0_graphql@16.9.0 symbol-observable: 4.0.0 ts-invariant: 0.10.3 - tslib: 2.6.2 + tslib: 2.8.1 zen-observable-ts: 1.2.5 dev: true - /@apollo/client/3.7.13_sphwu2tmthkxbmhoomzrsl4p7y: + /@apollo/client/3.7.13_pvbge6vplei5rx3k4pxg27es3y: resolution: {integrity: sha512-wi63WnO2mhb6uHGB/8x1qIOL4ZtZocrxdHS0VBQ9KwBDkwoP/TdVVgZ29J2WkiAPmJ0SK07ju4R2AjHor1gPxQ==} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 @@ -1316,20 +1308,20 @@ packages: subscriptions-transport-ws: optional: true dependencies: - '@graphql-typed-document-node/core': 3.2.0_graphql@16.8.1 + '@graphql-typed-document-node/core': 3.2.0_graphql@16.9.0 '@wry/context': 0.7.4 '@wry/equality': 0.5.7 '@wry/trie': 0.3.2 - graphql: 16.8.1 - graphql-tag: 2.12.6_graphql@16.8.1 + graphql: 16.9.0 + graphql-tag: 2.12.6_graphql@16.9.0 hoist-non-react-statics: 3.3.2 optimism: 0.16.2 prop-types: 15.8.1 response-iterator: 0.2.6 - subscriptions-transport-ws: 0.11.0_graphql@16.8.1 + subscriptions-transport-ws: 0.11.0_graphql@16.9.0 symbol-observable: 4.0.0 ts-invariant: 0.10.3 - tslib: 2.6.2 + tslib: 2.8.1 zen-observable-ts: 1.2.5 dev: false @@ -1387,8 +1379,8 @@ packages: '@aws-cdk/aws-certificatemanager': 1.204.0_xtqk4litqxecxsqs3sd6ajo2ja '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm '@aws-cdk/aws-cognito': 1.204.0_jhanj7vnhseo3o4cwsyzgiowqa - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a - '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_duidta2ijoio5sg5x7jqysldja + '@aws-cdk/aws-ec2': 1.204.0_7otc2o26uplt6z4h6rudhovj5u + '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_vsyp5evbazeuvbvzpddjsx7f6m '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm '@aws-cdk/aws-logs': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu @@ -1404,7 +1396,7 @@ packages: - '@aws-cdk/custom-resources' dev: false - /@aws-cdk/aws-apigatewayv2/1.204.0_xbmlyikxd4zabyotfrt4oo4gli: + /@aws-cdk/aws-apigatewayv2/1.204.0_knsptffnex2lyiy4uxr2qfndt4: resolution: {integrity: sha512-FGRznk2yph7ZyC7JHfVMKyDuFTT6p/HZDys1biY4lz+T7hqMaDC2ik+b+mO7ptwY5ebyPT4KePR0wmp3jJshIg==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -1420,15 +1412,15 @@ packages: dependencies: '@aws-cdk/aws-certificatemanager': 1.204.0_xtqk4litqxecxsqs3sd6ajo2ja '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_ugogvenjbszrmlbofftt72igsy '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-s3': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam constructs: 3.4.344 transitivePeerDependencies: - - '@aws-cdk/assets' - '@aws-cdk/aws-lambda' - '@aws-cdk/aws-logs' + - '@aws-cdk/aws-s3-assets' - '@aws-cdk/custom-resources' - '@aws-cdk/cx-api' dev: false @@ -1490,7 +1482,7 @@ packages: '@aws-cdk/core': 1.204.0 constructs: ^3.3.69 dependencies: - '@aws-cdk/aws-autoscaling': 1.204.0_cs2gnbp3a35i2p5l5u5a3t4624 + '@aws-cdk/aws-autoscaling': 1.204.0_i3jljv3de5uztyiwnf4vt3h3ue '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm @@ -1501,7 +1493,7 @@ packages: constructs: 3.4.344 dev: false - /@aws-cdk/aws-autoscaling/1.204.0_cs2gnbp3a35i2p5l5u5a3t4624: + /@aws-cdk/aws-autoscaling/1.204.0_i3jljv3de5uztyiwnf4vt3h3ue: resolution: {integrity: sha512-LVQK84GR6U0RXfPbxZauWDCfcgBgH4bofOHx1sfr6yz7FTSYYkYM2tMJl81SmVc6ueSJzfhFtIcWhSpMBH9yig==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -1516,19 +1508,51 @@ packages: dependencies: '@aws-cdk/aws-autoscaling-common': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_7otc2o26uplt6z4h6rudhovj5u '@aws-cdk/aws-elasticloadbalancing': 1.204.0_s2iwowsvskkmujjbrmx4g5hlsi - '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_duidta2ijoio5sg5x7jqysldja + '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_vsyp5evbazeuvbvzpddjsx7f6m + '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu + '@aws-cdk/aws-sns': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi + '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam + constructs: 3.4.344 + transitivePeerDependencies: + - '@aws-cdk/aws-events' + - '@aws-cdk/aws-lambda' + - '@aws-cdk/aws-logs' + - '@aws-cdk/aws-s3' + - '@aws-cdk/aws-s3-assets' + - '@aws-cdk/custom-resources' + - '@aws-cdk/cx-api' + dev: false + + /@aws-cdk/aws-autoscaling/1.204.0_lfphwgzs6h44cq466n6cmpwpbq: + resolution: {integrity: sha512-LVQK84GR6U0RXfPbxZauWDCfcgBgH4bofOHx1sfr6yz7FTSYYkYM2tMJl81SmVc6ueSJzfhFtIcWhSpMBH9yig==} + engines: {node: '>= 14.15.0'} + deprecated: |- + AWS CDK v1 has reached End-of-Support on 2023-06-01. + This package is no longer being updated, and users should migrate to AWS CDK v2. + + For more information on how to migrate, see https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html + peerDependencies: + '@aws-cdk/aws-iam': 1.204.0 + '@aws-cdk/core': 1.204.0 + constructs: ^3.3.69 + dependencies: + '@aws-cdk/aws-autoscaling-common': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm + '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm + '@aws-cdk/aws-ec2': 1.204.0_ugogvenjbszrmlbofftt72igsy + '@aws-cdk/aws-elasticloadbalancing': 1.204.0_s2iwowsvskkmujjbrmx4g5hlsi + '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_knsptffnex2lyiy4uxr2qfndt4 '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-sns': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam constructs: 3.4.344 transitivePeerDependencies: - - '@aws-cdk/assets' - '@aws-cdk/aws-events' - '@aws-cdk/aws-lambda' - '@aws-cdk/aws-logs' - '@aws-cdk/aws-s3' + - '@aws-cdk/aws-s3-assets' - '@aws-cdk/custom-resources' - '@aws-cdk/cx-api' dev: false @@ -1587,7 +1611,7 @@ packages: - '@aws-cdk/aws-events' dev: false - /@aws-cdk/aws-cloudfront/1.204.0_xbmlyikxd4zabyotfrt4oo4gli: + /@aws-cdk/aws-cloudfront/1.204.0_knsptffnex2lyiy4uxr2qfndt4: resolution: {integrity: sha512-bgqGsImVjFQJihDvLg0hWRtmq2b+HVj94Fngz/zo4PsB5kTt1QZvHOk2HNBkozNhDK8LXysHtdKvmzpaK29TJQ==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -1605,7 +1629,7 @@ packages: dependencies: '@aws-cdk/aws-certificatemanager': 1.204.0_xtqk4litqxecxsqs3sd6ajo2ja '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_ugogvenjbszrmlbofftt72igsy '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm @@ -1615,8 +1639,8 @@ packages: '@aws-cdk/cx-api': 1.203.0 constructs: 3.4.344 transitivePeerDependencies: - - '@aws-cdk/assets' - '@aws-cdk/aws-logs' + - '@aws-cdk/aws-s3-assets' - '@aws-cdk/custom-resources' dev: false @@ -1659,7 +1683,7 @@ packages: '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm '@aws-cdk/aws-codecommit': 1.204.0_scjupxxta56mdpzkdveav52ufq '@aws-cdk/aws-codestarnotifications': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_7otc2o26uplt6z4h6rudhovj5u '@aws-cdk/aws-ecr': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/aws-ecr-assets': 1.204.0_scjupxxta56mdpzkdveav52ufq '@aws-cdk/aws-events': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm @@ -1668,11 +1692,10 @@ packages: '@aws-cdk/aws-logs': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu '@aws-cdk/aws-s3': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/aws-s3-assets': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu - '@aws-cdk/aws-secretsmanager': 1.204.0_2o53qceqenzlpxe4mjswmsqfiq + '@aws-cdk/aws-secretsmanager': 1.204.0_tozf65cx46f236bynayszxjyoy '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam '@aws-cdk/region-info': 1.204.0 constructs: 3.4.344 - yaml: 1.10.2 transitivePeerDependencies: - '@aws-cdk/aws-lambda' - '@aws-cdk/cx-api' @@ -1786,9 +1809,8 @@ packages: '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam - '@aws-cdk/custom-resources': 1.204.0_c23kgzmvfhgnr6qpzzlbsfzuc4 + '@aws-cdk/custom-resources': 1.204.0_575fyf2i7umbzongv3ijfqjgle constructs: 3.4.344 - punycode: 2.3.1 transitivePeerDependencies: - '@aws-cdk/aws-ec2' - '@aws-cdk/aws-logs' @@ -1819,14 +1841,14 @@ packages: '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam - '@aws-cdk/custom-resources': 1.204.0_c23kgzmvfhgnr6qpzzlbsfzuc4 + '@aws-cdk/custom-resources': 1.204.0_575fyf2i7umbzongv3ijfqjgle constructs: 3.4.344 transitivePeerDependencies: - '@aws-cdk/aws-logs' - '@aws-cdk/cx-api' dev: false - /@aws-cdk/aws-ec2/1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a: + /@aws-cdk/aws-ec2/1.204.0_7otc2o26uplt6z4h6rudhovj5u: resolution: {integrity: sha512-SoqZEgzdfPW0aa+FQ0CjzbDG+X+sDu6/BnLL2O10lxpa+9Dc1iyArAqNKFJG5KXGJe9ibvQXyNQqEjeGRFc22Q==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -1835,9 +1857,11 @@ packages: For more information on how to migrate, see https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html peerDependencies: + '@aws-cdk/aws-cloudwatch': 1.204.0 '@aws-cdk/aws-iam': 1.204.0 '@aws-cdk/aws-logs': 1.204.0 '@aws-cdk/aws-s3': 1.204.0 + '@aws-cdk/aws-s3-assets': 1.204.0 '@aws-cdk/core': 1.204.0 '@aws-cdk/cx-api': 1.204.0 constructs: ^3.3.69 @@ -1854,8 +1878,98 @@ packages: '@aws-cdk/cx-api': 1.203.0 '@aws-cdk/region-info': 1.204.0 constructs: 3.4.344 - transitivePeerDependencies: - - '@aws-cdk/assets' + dev: false + + /@aws-cdk/aws-ec2/1.204.0_piacgwift44a2rmzffkfjqxufa: + resolution: {integrity: sha512-SoqZEgzdfPW0aa+FQ0CjzbDG+X+sDu6/BnLL2O10lxpa+9Dc1iyArAqNKFJG5KXGJe9ibvQXyNQqEjeGRFc22Q==} + engines: {node: '>= 14.15.0'} + deprecated: |- + AWS CDK v1 has reached End-of-Support on 2023-06-01. + This package is no longer being updated, and users should migrate to AWS CDK v2. + + For more information on how to migrate, see https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html + peerDependencies: + '@aws-cdk/aws-cloudwatch': 1.204.0 + '@aws-cdk/aws-iam': 1.204.0 + '@aws-cdk/aws-logs': 1.204.0 + '@aws-cdk/aws-s3': 1.204.0 + '@aws-cdk/aws-s3-assets': 1.204.0 + '@aws-cdk/core': 1.204.0 + '@aws-cdk/cx-api': 1.204.0 + constructs: ^3.3.69 + dependencies: + '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu + '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y + '@aws-cdk/aws-logs': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu + '@aws-cdk/aws-s3': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi + '@aws-cdk/aws-s3-assets': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu + '@aws-cdk/aws-ssm': 1.204.0_cttdkzy7hngahjug7jmkfylr2y + '@aws-cdk/cloud-assembly-schema': 1.204.0 + '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam + '@aws-cdk/cx-api': 1.203.0 + '@aws-cdk/region-info': 1.204.0 + constructs: 3.4.344 + dev: false + + /@aws-cdk/aws-ec2/1.204.0_ugogvenjbszrmlbofftt72igsy: + resolution: {integrity: sha512-SoqZEgzdfPW0aa+FQ0CjzbDG+X+sDu6/BnLL2O10lxpa+9Dc1iyArAqNKFJG5KXGJe9ibvQXyNQqEjeGRFc22Q==} + engines: {node: '>= 14.15.0'} + deprecated: |- + AWS CDK v1 has reached End-of-Support on 2023-06-01. + This package is no longer being updated, and users should migrate to AWS CDK v2. + + For more information on how to migrate, see https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html + peerDependencies: + '@aws-cdk/aws-cloudwatch': 1.204.0 + '@aws-cdk/aws-iam': 1.204.0 + '@aws-cdk/aws-logs': 1.204.0 + '@aws-cdk/aws-s3': 1.204.0 + '@aws-cdk/aws-s3-assets': 1.204.0 + '@aws-cdk/core': 1.204.0 + '@aws-cdk/cx-api': 1.204.0 + constructs: ^3.3.69 + dependencies: + '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm + '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu + '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y + '@aws-cdk/aws-logs': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu + '@aws-cdk/aws-s3': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi + '@aws-cdk/aws-ssm': 1.204.0_cttdkzy7hngahjug7jmkfylr2y + '@aws-cdk/cloud-assembly-schema': 1.204.0 + '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam + '@aws-cdk/cx-api': 1.203.0 + '@aws-cdk/region-info': 1.204.0 + constructs: 3.4.344 + dev: false + + /@aws-cdk/aws-ec2/1.204.0_xko3xkmfscpwz76mf7mobwjaoa: + resolution: {integrity: sha512-SoqZEgzdfPW0aa+FQ0CjzbDG+X+sDu6/BnLL2O10lxpa+9Dc1iyArAqNKFJG5KXGJe9ibvQXyNQqEjeGRFc22Q==} + engines: {node: '>= 14.15.0'} + deprecated: |- + AWS CDK v1 has reached End-of-Support on 2023-06-01. + This package is no longer being updated, and users should migrate to AWS CDK v2. + + For more information on how to migrate, see https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html + peerDependencies: + '@aws-cdk/aws-cloudwatch': 1.204.0 + '@aws-cdk/aws-iam': 1.204.0 + '@aws-cdk/aws-logs': 1.204.0 + '@aws-cdk/aws-s3': 1.204.0 + '@aws-cdk/aws-s3-assets': 1.204.0 + '@aws-cdk/core': 1.204.0 + '@aws-cdk/cx-api': 1.204.0 + constructs: ^3.3.69 + dependencies: + '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu + '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y + '@aws-cdk/aws-logs': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu + '@aws-cdk/aws-s3': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi + '@aws-cdk/aws-ssm': 1.204.0_cttdkzy7hngahjug7jmkfylr2y + '@aws-cdk/cloud-assembly-schema': 1.204.0 + '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam + '@aws-cdk/cx-api': 1.203.0 + '@aws-cdk/region-info': 1.204.0 + constructs: 3.4.344 dev: false /@aws-cdk/aws-ecr-assets/1.204.0_scjupxxta56mdpzkdveav52ufq: @@ -1926,25 +2040,25 @@ packages: constructs: ^3.3.69 dependencies: '@aws-cdk/aws-applicationautoscaling': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm - '@aws-cdk/aws-autoscaling': 1.204.0_cs2gnbp3a35i2p5l5u5a3t4624 + '@aws-cdk/aws-autoscaling': 1.204.0_i3jljv3de5uztyiwnf4vt3h3ue '@aws-cdk/aws-autoscaling-hooktargets': 1.204.0_qzqhemkg7ucx2bjh2ugcivnnei '@aws-cdk/aws-certificatemanager': 1.204.0_xtqk4litqxecxsqs3sd6ajo2ja '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_7otc2o26uplt6z4h6rudhovj5u '@aws-cdk/aws-ecr': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/aws-ecr-assets': 1.204.0_scjupxxta56mdpzkdveav52ufq '@aws-cdk/aws-elasticloadbalancing': 1.204.0_s2iwowsvskkmujjbrmx4g5hlsi - '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_duidta2ijoio5sg5x7jqysldja + '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_vsyp5evbazeuvbvzpddjsx7f6m '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm '@aws-cdk/aws-logs': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu '@aws-cdk/aws-route53': 1.204.0_i3vim6rlintxrbha4iep76yf5u - '@aws-cdk/aws-route53-targets': 1.204.0_yvzacxtkufuieelzdl2p47lu74 + '@aws-cdk/aws-route53-targets': 1.204.0_bumtmw6o2rwlthudo752xxrr5u '@aws-cdk/aws-s3': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/aws-s3-assets': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu - '@aws-cdk/aws-secretsmanager': 1.204.0_2o53qceqenzlpxe4mjswmsqfiq - '@aws-cdk/aws-servicediscovery': 1.204.0_duidta2ijoio5sg5x7jqysldja + '@aws-cdk/aws-secretsmanager': 1.204.0_tozf65cx46f236bynayszxjyoy + '@aws-cdk/aws-servicediscovery': 1.204.0_2pbhnqzqa55byia6sq3bvevyma '@aws-cdk/aws-sns': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/aws-sqs': 1.204.0_cttdkzy7hngahjug7jmkfylr2y '@aws-cdk/aws-ssm': 1.204.0_cttdkzy7hngahjug7jmkfylr2y @@ -1960,7 +2074,7 @@ packages: - '@aws-cdk/custom-resources' dev: false - /@aws-cdk/aws-efs/1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a: + /@aws-cdk/aws-efs/1.204.0_7otc2o26uplt6z4h6rudhovj5u: resolution: {integrity: sha512-FB6nHgCuzYF5K9ywqYPEPjL2G1ATLIR9dJp1p4ydcEUuXDb4KSEVN4Bgx+q1e7EkWGIq+9glr+ckheEcTvETgw==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -1974,7 +2088,7 @@ packages: '@aws-cdk/cx-api': 1.204.0 constructs: ^3.3.69 dependencies: - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_7otc2o26uplt6z4h6rudhovj5u '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y '@aws-cdk/cloud-assembly-schema': 1.204.0 @@ -1982,9 +2096,38 @@ packages: '@aws-cdk/cx-api': 1.203.0 constructs: 3.4.344 transitivePeerDependencies: - - '@aws-cdk/assets' + - '@aws-cdk/aws-cloudwatch' - '@aws-cdk/aws-logs' - '@aws-cdk/aws-s3' + - '@aws-cdk/aws-s3-assets' + dev: false + + /@aws-cdk/aws-efs/1.204.0_piacgwift44a2rmzffkfjqxufa: + resolution: {integrity: sha512-FB6nHgCuzYF5K9ywqYPEPjL2G1ATLIR9dJp1p4ydcEUuXDb4KSEVN4Bgx+q1e7EkWGIq+9glr+ckheEcTvETgw==} + engines: {node: '>= 14.15.0'} + deprecated: |- + AWS CDK v1 has reached End-of-Support on 2023-06-01. + This package is no longer being updated, and users should migrate to AWS CDK v2. + + For more information on how to migrate, see https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html + peerDependencies: + '@aws-cdk/aws-iam': 1.204.0 + '@aws-cdk/core': 1.204.0 + '@aws-cdk/cx-api': 1.204.0 + constructs: ^3.3.69 + dependencies: + '@aws-cdk/aws-ec2': 1.204.0_piacgwift44a2rmzffkfjqxufa + '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu + '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y + '@aws-cdk/cloud-assembly-schema': 1.204.0 + '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam + '@aws-cdk/cx-api': 1.203.0 + constructs: 3.4.344 + transitivePeerDependencies: + - '@aws-cdk/aws-cloudwatch' + - '@aws-cdk/aws-logs' + - '@aws-cdk/aws-s3' + - '@aws-cdk/aws-s3-assets' dev: false /@aws-cdk/aws-elasticloadbalancing/1.204.0_s2iwowsvskkmujjbrmx4g5hlsi: @@ -2000,12 +2143,12 @@ packages: '@aws-cdk/core': 1.204.0 constructs: ^3.3.69 dependencies: - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_ugogvenjbszrmlbofftt72igsy '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam constructs: 3.4.344 dev: false - /@aws-cdk/aws-elasticloadbalancingv2/1.204.0_duidta2ijoio5sg5x7jqysldja: + /@aws-cdk/aws-elasticloadbalancingv2/1.204.0_knsptffnex2lyiy4uxr2qfndt4: resolution: {integrity: sha512-/43kzUTU3w9jimPuD5QZxoBN74+9QnOdhAcqIMVCFLPMkVLAxx3vg5g5MWWG+3j6rUoSecrtrP1AP7thZuo5wA==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -2023,6 +2166,7 @@ packages: dependencies: '@aws-cdk/aws-certificatemanager': 1.204.0_xtqk4litqxecxsqs3sd6ajo2ja '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm + '@aws-cdk/aws-ec2': 1.204.0_ugogvenjbszrmlbofftt72igsy '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm '@aws-cdk/aws-route53': 1.204.0_i3vim6rlintxrbha4iep76yf5u @@ -2033,8 +2177,42 @@ packages: '@aws-cdk/region-info': 1.204.0 constructs: 3.4.344 transitivePeerDependencies: - - '@aws-cdk/aws-ec2' - '@aws-cdk/aws-logs' + - '@aws-cdk/aws-s3-assets' + - '@aws-cdk/custom-resources' + dev: false + + /@aws-cdk/aws-elasticloadbalancingv2/1.204.0_vsyp5evbazeuvbvzpddjsx7f6m: + resolution: {integrity: sha512-/43kzUTU3w9jimPuD5QZxoBN74+9QnOdhAcqIMVCFLPMkVLAxx3vg5g5MWWG+3j6rUoSecrtrP1AP7thZuo5wA==} + engines: {node: '>= 14.15.0'} + deprecated: |- + AWS CDK v1 has reached End-of-Support on 2023-06-01. + This package is no longer being updated, and users should migrate to AWS CDK v2. + + For more information on how to migrate, see https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html + peerDependencies: + '@aws-cdk/aws-iam': 1.204.0 + '@aws-cdk/aws-lambda': 1.204.0 + '@aws-cdk/aws-s3': 1.204.0 + '@aws-cdk/core': 1.204.0 + '@aws-cdk/cx-api': 1.204.0 + constructs: ^3.3.69 + dependencies: + '@aws-cdk/aws-certificatemanager': 1.204.0_xtqk4litqxecxsqs3sd6ajo2ja + '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm + '@aws-cdk/aws-ec2': 1.204.0_7otc2o26uplt6z4h6rudhovj5u + '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu + '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm + '@aws-cdk/aws-route53': 1.204.0_i3vim6rlintxrbha4iep76yf5u + '@aws-cdk/aws-s3': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi + '@aws-cdk/cloud-assembly-schema': 1.204.0 + '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam + '@aws-cdk/cx-api': 1.203.0 + '@aws-cdk/region-info': 1.204.0 + constructs: 3.4.344 + transitivePeerDependencies: + - '@aws-cdk/aws-logs' + - '@aws-cdk/aws-s3-assets' - '@aws-cdk/custom-resources' dev: false @@ -2057,15 +2235,15 @@ packages: constructs: ^3.3.69 dependencies: '@aws-cdk/aws-apigateway': 1.204.0_cs2gnbp3a35i2p5l5u5a3t4624 - '@aws-cdk/aws-autoscaling': 1.204.0_cs2gnbp3a35i2p5l5u5a3t4624 + '@aws-cdk/aws-autoscaling': 1.204.0_lfphwgzs6h44cq466n6cmpwpbq '@aws-cdk/aws-codebuild': 1.204.0_c23kgzmvfhgnr6qpzzlbsfzuc4 '@aws-cdk/aws-codepipeline': 1.204.0_ldv6hsy33vwn5o5qdxjyvusahm - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_xko3xkmfscpwz76mf7mobwjaoa '@aws-cdk/aws-ecs': 1.204.0_iu2vquo67t63xu6vdymsg3ufny '@aws-cdk/aws-events': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-kinesis': 1.204.0_wjonshyx7y7bmdnucjgcglchqq - '@aws-cdk/aws-kinesisfirehose': 1.204.0_2o53qceqenzlpxe4mjswmsqfiq + '@aws-cdk/aws-kinesisfirehose': 1.204.0_5ibbjioat6x2j3azupdfkiw2di '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm '@aws-cdk/aws-logs': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu @@ -2074,12 +2252,14 @@ packages: '@aws-cdk/aws-sqs': 1.204.0_cttdkzy7hngahjug7jmkfylr2y '@aws-cdk/aws-stepfunctions': 1.204.0_5s7psvfm6hmailsvkk6x3wncsq '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam - '@aws-cdk/custom-resources': 1.204.0_c23kgzmvfhgnr6qpzzlbsfzuc4 + '@aws-cdk/custom-resources': 1.204.0_575fyf2i7umbzongv3ijfqjgle constructs: 3.4.344 transitivePeerDependencies: - '@aws-cdk/assets' - '@aws-cdk/aws-cloudfront' + - '@aws-cdk/aws-cloudwatch' - '@aws-cdk/aws-s3' + - '@aws-cdk/aws-s3-assets' - '@aws-cdk/cx-api' dev: false @@ -2115,9 +2295,9 @@ packages: '@aws-cdk/custom-resources': 1.204.0 constructs: ^3.3.69 dependencies: - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_7otc2o26uplt6z4h6rudhovj5u '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam - '@aws-cdk/custom-resources': 1.204.0_c23kgzmvfhgnr6qpzzlbsfzuc4 + '@aws-cdk/custom-resources': 1.204.0_575fyf2i7umbzongv3ijfqjgle constructs: 3.4.344 dev: false @@ -2163,7 +2343,7 @@ packages: - '@aws-cdk/cx-api' dev: false - /@aws-cdk/aws-kinesisfirehose/1.204.0_2o53qceqenzlpxe4mjswmsqfiq: + /@aws-cdk/aws-kinesisfirehose/1.204.0_5ibbjioat6x2j3azupdfkiw2di: resolution: {integrity: sha512-RZtVh1AiWbTtygNAaymoiOWWY41uk1ZRApMVJ+4wF0UTKMhDbcYMgoeTjgyg5ZQk1nzfI1iinNPEp/VggJTjuA==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -2180,7 +2360,7 @@ packages: constructs: ^3.3.69 dependencies: '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_ugogvenjbszrmlbofftt72igsy '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-kinesis': 1.204.0_wjonshyx7y7bmdnucjgcglchqq '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y @@ -2191,7 +2371,7 @@ packages: '@aws-cdk/region-info': 1.204.0 constructs: 3.4.344 transitivePeerDependencies: - - '@aws-cdk/assets' + - '@aws-cdk/aws-s3-assets' - '@aws-cdk/cx-api' dev: false @@ -2216,7 +2396,7 @@ packages: constructs: 3.4.344 dev: false - /@aws-cdk/aws-lambda-event-sources/1.204.0_yl5g6fuosfeqtat6z7imtengha: + /@aws-cdk/aws-lambda-event-sources/1.204.0_6ewijctynstfo6zas4hwstt4zy: resolution: {integrity: sha512-gH36hbc7cB5/CeDRHZ794bTjryls9O0tYLJJWDKphujIOlOZysPSGL8vqOujMkxJ1kHujBLt6PudbyqLaacQ9Q==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -2236,22 +2416,23 @@ packages: dependencies: '@aws-cdk/aws-apigateway': 1.204.0_cs2gnbp3a35i2p5l5u5a3t4624 '@aws-cdk/aws-dynamodb': 1.204.0_ea3k7xy2kixjvb2em7ltbqbgym - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_xko3xkmfscpwz76mf7mobwjaoa '@aws-cdk/aws-events': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-kinesis': 1.204.0_wjonshyx7y7bmdnucjgcglchqq '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm '@aws-cdk/aws-s3': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/aws-s3-notifications': 1.204.0_xguspq3b5n56mo6dsez57f32qa - '@aws-cdk/aws-secretsmanager': 1.204.0_2o53qceqenzlpxe4mjswmsqfiq + '@aws-cdk/aws-secretsmanager': 1.204.0_5ibbjioat6x2j3azupdfkiw2di '@aws-cdk/aws-sns': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/aws-sns-subscriptions': 1.204.0_bpkznh2gsccwq6qpaogbkb4psu '@aws-cdk/aws-sqs': 1.204.0_cttdkzy7hngahjug7jmkfylr2y '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam constructs: 3.4.344 transitivePeerDependencies: - - '@aws-cdk/assets' + - '@aws-cdk/aws-cloudwatch' - '@aws-cdk/aws-logs' + - '@aws-cdk/aws-s3-assets' - '@aws-cdk/cx-api' dev: false @@ -2275,10 +2456,10 @@ packages: '@aws-cdk/aws-applicationautoscaling': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm '@aws-cdk/aws-cloudwatch': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm '@aws-cdk/aws-codeguruprofiler': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_7otc2o26uplt6z4h6rudhovj5u '@aws-cdk/aws-ecr': 1.204.0_bi2u42js5xhxqcsg5gqefde4xi '@aws-cdk/aws-ecr-assets': 1.204.0_scjupxxta56mdpzkdveav52ufq - '@aws-cdk/aws-efs': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-efs': 1.204.0_7otc2o26uplt6z4h6rudhovj5u '@aws-cdk/aws-events': 1.204.0_w2xl3dexbzdynnzeafah4cuzfm '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y @@ -2322,7 +2503,7 @@ packages: - '@aws-cdk/aws-s3' dev: false - /@aws-cdk/aws-route53-targets/1.204.0_yvzacxtkufuieelzdl2p47lu74: + /@aws-cdk/aws-route53-targets/1.204.0_bumtmw6o2rwlthudo752xxrr5u: resolution: {integrity: sha512-JyILJz/HGRMilpFxrDk/VXv+TN24DoG5Gfdfh8SJoJpptokowN8blaQ2ibf6N0JnFqWSBrs7gMMWB2dR/sXoTQ==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -2340,11 +2521,11 @@ packages: constructs: ^3.3.69 dependencies: '@aws-cdk/aws-apigateway': 1.204.0_cs2gnbp3a35i2p5l5u5a3t4624 - '@aws-cdk/aws-cloudfront': 1.204.0_xbmlyikxd4zabyotfrt4oo4gli + '@aws-cdk/aws-cloudfront': 1.204.0_knsptffnex2lyiy4uxr2qfndt4 '@aws-cdk/aws-cognito': 1.204.0_jhanj7vnhseo3o4cwsyzgiowqa - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_7otc2o26uplt6z4h6rudhovj5u '@aws-cdk/aws-elasticloadbalancing': 1.204.0_s2iwowsvskkmujjbrmx4g5hlsi - '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_duidta2ijoio5sg5x7jqysldja + '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_vsyp5evbazeuvbvzpddjsx7f6m '@aws-cdk/aws-globalaccelerator': 1.204.0_u3bt2hwm6nh6yzg6d6qalghehq '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-route53': 1.204.0_i3vim6rlintxrbha4iep76yf5u @@ -2355,6 +2536,7 @@ packages: transitivePeerDependencies: - '@aws-cdk/aws-lambda' - '@aws-cdk/aws-logs' + - '@aws-cdk/aws-s3-assets' - '@aws-cdk/custom-resources' - '@aws-cdk/cx-api' dev: false @@ -2375,12 +2557,12 @@ packages: '@aws-cdk/custom-resources': 1.204.0 constructs: ^3.3.69 dependencies: - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_7otc2o26uplt6z4h6rudhovj5u '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-logs': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu '@aws-cdk/cloud-assembly-schema': 1.204.0 '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam - '@aws-cdk/custom-resources': 1.204.0_c23kgzmvfhgnr6qpzzlbsfzuc4 + '@aws-cdk/custom-resources': 1.204.0_575fyf2i7umbzongv3ijfqjgle constructs: 3.4.344 dev: false @@ -2426,9 +2608,9 @@ packages: '@aws-cdk/core': 1.204.0 constructs: ^3.3.69 dependencies: - '@aws-cdk/aws-cloudfront': 1.204.0_xbmlyikxd4zabyotfrt4oo4gli - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a - '@aws-cdk/aws-efs': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-cloudfront': 1.204.0_knsptffnex2lyiy4uxr2qfndt4 + '@aws-cdk/aws-ec2': 1.204.0_piacgwift44a2rmzffkfjqxufa + '@aws-cdk/aws-efs': 1.204.0_piacgwift44a2rmzffkfjqxufa '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm '@aws-cdk/aws-logs': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu @@ -2436,10 +2618,10 @@ packages: '@aws-cdk/aws-s3-assets': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam '@aws-cdk/lambda-layer-awscli': 1.204.0_e7ybiu4yrrtvf3zlvzrvcjkvyy - case: 1.6.3 constructs: 3.4.344 transitivePeerDependencies: - '@aws-cdk/assets' + - '@aws-cdk/aws-cloudwatch' - '@aws-cdk/cx-api' dev: false bundledDependencies: @@ -2512,7 +2694,7 @@ packages: constructs: 3.4.344 dev: false - /@aws-cdk/aws-secretsmanager/1.204.0_2o53qceqenzlpxe4mjswmsqfiq: + /@aws-cdk/aws-secretsmanager/1.204.0_5ibbjioat6x2j3azupdfkiw2di: resolution: {integrity: sha512-ykpjYmP6qVOFbHtkaQBu3Xk7xp2UTR0ouzk7pb+zrEHKGmRvzGq+8J0IU+qXBJgQIVwFAPf2IgOSTzj6FJPdyA==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -2527,7 +2709,7 @@ packages: '@aws-cdk/cx-api': 1.204.0 constructs: ^3.3.69 dependencies: - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_xko3xkmfscpwz76mf7mobwjaoa '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm @@ -2536,12 +2718,43 @@ packages: '@aws-cdk/cx-api': 1.203.0 constructs: 3.4.344 transitivePeerDependencies: - - '@aws-cdk/assets' + - '@aws-cdk/aws-cloudwatch' + - '@aws-cdk/aws-logs' + - '@aws-cdk/aws-s3' + - '@aws-cdk/aws-s3-assets' + dev: false + + /@aws-cdk/aws-secretsmanager/1.204.0_tozf65cx46f236bynayszxjyoy: + resolution: {integrity: sha512-ykpjYmP6qVOFbHtkaQBu3Xk7xp2UTR0ouzk7pb+zrEHKGmRvzGq+8J0IU+qXBJgQIVwFAPf2IgOSTzj6FJPdyA==} + engines: {node: '>= 14.15.0'} + deprecated: |- + AWS CDK v1 has reached End-of-Support on 2023-06-01. + This package is no longer being updated, and users should migrate to AWS CDK v2. + + For more information on how to migrate, see https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html + peerDependencies: + '@aws-cdk/aws-iam': 1.204.0 + '@aws-cdk/aws-lambda': 1.204.0 + '@aws-cdk/core': 1.204.0 + '@aws-cdk/cx-api': 1.204.0 + constructs: ^3.3.69 + dependencies: + '@aws-cdk/aws-ec2': 1.204.0_7otc2o26uplt6z4h6rudhovj5u + '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu + '@aws-cdk/aws-kms': 1.204.0_cttdkzy7hngahjug7jmkfylr2y + '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm + '@aws-cdk/aws-sam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu + '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam + '@aws-cdk/cx-api': 1.203.0 + constructs: 3.4.344 + transitivePeerDependencies: + - '@aws-cdk/aws-cloudwatch' - '@aws-cdk/aws-logs' - '@aws-cdk/aws-s3' + - '@aws-cdk/aws-s3-assets' dev: false - /@aws-cdk/aws-servicediscovery/1.204.0_duidta2ijoio5sg5x7jqysldja: + /@aws-cdk/aws-servicediscovery/1.204.0_2pbhnqzqa55byia6sq3bvevyma: resolution: {integrity: sha512-K1ckza6oAj3DntEAYmolm2JafkxJ0ekWb+DCl9hkm9l+546j28Qpb4cm8VkgGteNBN4JYACxrIuIxVC2zBLsCg==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -2554,8 +2767,8 @@ packages: '@aws-cdk/core': 1.204.0 constructs: ^3.3.69 dependencies: - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a - '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_duidta2ijoio5sg5x7jqysldja + '@aws-cdk/aws-ec2': 1.204.0_7otc2o26uplt6z4h6rudhovj5u + '@aws-cdk/aws-elasticloadbalancingv2': 1.204.0_vsyp5evbazeuvbvzpddjsx7f6m '@aws-cdk/aws-route53': 1.204.0_i3vim6rlintxrbha4iep76yf5u '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam constructs: 3.4.344 @@ -2564,6 +2777,7 @@ packages: - '@aws-cdk/aws-lambda' - '@aws-cdk/aws-logs' - '@aws-cdk/aws-s3' + - '@aws-cdk/aws-s3-assets' - '@aws-cdk/custom-resources' - '@aws-cdk/cx-api' dev: false @@ -2715,9 +2929,6 @@ packages: /@aws-cdk/cloud-assembly-schema/1.203.0: resolution: {integrity: sha512-r252InZ8Oh7q7ztriaA3n6F48QOFVfNcT/KO4XOlYyt1xDWRMENDYf+D+DVr6O5klcaa3ivvvDT7DRuW3xdVOQ==} engines: {node: '>= 14.15.0'} - dependencies: - jsonschema: 1.4.1 - semver: 7.6.0 dev: false bundledDependencies: - jsonschema @@ -2731,9 +2942,6 @@ packages: This package is no longer being updated, and users should migrate to AWS CDK v2. For more information on how to migrate, see https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html - dependencies: - jsonschema: 1.4.1 - semver: 7.6.0 dev: false bundledDependencies: - jsonschema @@ -2742,9 +2950,6 @@ packages: /@aws-cdk/cloud-assembly-schema/2.39.1: resolution: {integrity: sha512-lSVaaedXWeK08uoq0IXDCspz9U/H4qIERemdsMQrMUDTiUe/JBby7vtmyMvOdEscE8GMAmiOzoPmAE0Uf+yw5A==} engines: {node: '>= 14.15.0'} - dependencies: - jsonschema: 1.4.1 - semver: 7.6.0 dev: false bundledDependencies: - jsonschema @@ -2760,7 +2965,7 @@ packages: diff: 5.2.0 fast-deep-equal: 3.1.3 string-width: 4.2.3 - table: 6.8.2 + table: 6.9.0 dev: false /@aws-cdk/core/1.204.0_hol6usdabdbzhugfw355k4ebam: @@ -2778,11 +2983,7 @@ packages: '@aws-cdk/cloud-assembly-schema': 1.204.0 '@aws-cdk/cx-api': 1.203.0 '@aws-cdk/region-info': 1.204.0 - '@balena/dockerignore': 1.0.2 constructs: 3.4.344 - fs-extra: 9.1.0 - ignore: 5.3.1 - minimatch: 3.1.2 dev: false bundledDependencies: - fs-extra @@ -2790,7 +2991,7 @@ packages: - '@balena/dockerignore' - ignore - /@aws-cdk/custom-resources/1.204.0_c23kgzmvfhgnr6qpzzlbsfzuc4: + /@aws-cdk/custom-resources/1.204.0_575fyf2i7umbzongv3ijfqjgle: resolution: {integrity: sha512-0w3oi7LnAtMZpf7uUBDH6aT2Oo1EBQrqD+VTvPZDX8PJFAox8ol7buZ9sSTpIXgv9j/GK9yaPTIHt4m8ok9kVQ==} engines: {node: '>= 14.15.0'} deprecated: |- @@ -2806,7 +3007,7 @@ packages: constructs: ^3.3.69 dependencies: '@aws-cdk/aws-cloudformation': 1.204.0_xguspq3b5n56mo6dsez57f32qa - '@aws-cdk/aws-ec2': 1.204.0_r4d2a6r7lnkv26zjzkdsvuam2a + '@aws-cdk/aws-ec2': 1.204.0_xko3xkmfscpwz76mf7mobwjaoa '@aws-cdk/aws-iam': 1.204.0_add7c2jq5lcc6idtuigbkwnzeu '@aws-cdk/aws-lambda': 1.204.0_afnjft5qr3fswieaeg3dwwhnvm '@aws-cdk/aws-logs': 1.204.0_l4ztnfmrjykhsbk6ow7yhidayu @@ -2814,9 +3015,10 @@ packages: '@aws-cdk/core': 1.204.0_hol6usdabdbzhugfw355k4ebam constructs: 3.4.344 transitivePeerDependencies: - - '@aws-cdk/assets' + - '@aws-cdk/aws-cloudwatch' - '@aws-cdk/aws-events' - '@aws-cdk/aws-s3' + - '@aws-cdk/aws-s3-assets' - '@aws-cdk/cx-api' dev: false @@ -2825,7 +3027,6 @@ packages: engines: {node: '>= 14.15.0'} dependencies: '@aws-cdk/cloud-assembly-schema': 1.203.0 - semver: 7.6.0 dev: false bundledDependencies: - semver @@ -2840,7 +3041,6 @@ packages: For more information on how to migrate, see https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html dependencies: '@aws-cdk/cloud-assembly-schema': 1.204.0 - semver: 7.6.0 dev: false bundledDependencies: - semver @@ -2850,7 +3050,6 @@ packages: engines: {node: '>= 14.15.0'} dependencies: '@aws-cdk/cloud-assembly-schema': 2.39.1 - semver: 7.6.0 dev: false bundledDependencies: - semver @@ -2887,14 +3086,14 @@ packages: resolution: {integrity: sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==} engines: {node: '>=12.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/abort-controller/2.1.2: resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} engines: {node: '>=18.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/arm-appservice/13.0.3: @@ -2902,12 +3101,12 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.7.2 + '@azure/core-auth': 1.9.0 '@azure/core-client': 1.9.2 '@azure/core-lro': 2.7.2 '@azure/core-paging': 1.6.2 - '@azure/core-rest-pipeline': 1.15.2 - tslib: 2.6.2 + '@azure/core-rest-pipeline': 1.18.1 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false @@ -2917,12 +3116,12 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.7.2 + '@azure/core-auth': 1.9.0 '@azure/core-client': 1.9.2 '@azure/core-lro': 2.7.2 '@azure/core-paging': 1.6.2 - '@azure/core-rest-pipeline': 1.15.2 - tslib: 2.6.2 + '@azure/core-rest-pipeline': 1.18.1 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false @@ -2932,28 +3131,28 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.7.2 - '@azure/core-util': 1.9.0 - '@azure/logger': 1.1.2 + '@azure/core-auth': 1.9.0 + '@azure/core-util': 1.11.0 + '@azure/logger': 1.1.4 buffer: 6.0.3 events: 3.3.0 jssha: 3.3.1 process: 0.11.10 - rhea: 3.0.2 - rhea-promise: 3.0.1 - tslib: 2.6.2 + rhea: 3.0.3 + rhea-promise: 3.0.3 + tslib: 2.8.1 util: 0.12.5 transitivePeerDependencies: - supports-color dev: false - /@azure/core-auth/1.7.2: - resolution: {integrity: sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==} + /@azure/core-auth/1.9.0: + resolution: {integrity: sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==} engines: {node: '>=18.0.0'} dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-util': 1.9.0 - tslib: 2.6.2 + '@azure/core-util': 1.11.0 + tslib: 2.8.1 dev: false /@azure/core-client/1.9.2: @@ -2961,12 +3160,12 @@ packages: engines: {node: '>=18.0.0'} dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.7.2 - '@azure/core-rest-pipeline': 1.15.2 - '@azure/core-tracing': 1.1.2 - '@azure/core-util': 1.9.0 - '@azure/logger': 1.1.2 - tslib: 2.6.2 + '@azure/core-auth': 1.9.0 + '@azure/core-rest-pipeline': 1.18.1 + '@azure/core-tracing': 1.2.0 + '@azure/core-util': 1.11.0 + '@azure/logger': 1.1.4 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false @@ -2976,66 +3175,63 @@ packages: engines: {node: '>=18.0.0'} dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-util': 1.9.0 - '@azure/logger': 1.1.2 - tslib: 2.6.2 + '@azure/core-util': 1.11.0 + '@azure/logger': 1.1.4 + tslib: 2.8.1 dev: false /@azure/core-paging/1.6.2: resolution: {integrity: sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==} engines: {node: '>=18.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: false - /@azure/core-rest-pipeline/1.15.2: - resolution: {integrity: sha512-BmWfpjc/QXc2ipHOh6LbUzp3ONCaa6xzIssTU0DwH9bbYNXJlGUL6tujx5TrbVd/QQknmS+vlQJGrCq2oL1gZA==} + /@azure/core-rest-pipeline/1.18.1: + resolution: {integrity: sha512-/wS73UEDrxroUEVywEm7J0p2c+IIiVxyfigCGfsKvCxxCET4V/Hef2aURqltrXMRjNmdmt5IuOgIpl8f6xdO5A==} engines: {node: '>=18.0.0'} dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.7.2 - '@azure/core-tracing': 1.1.2 - '@azure/core-util': 1.9.0 - '@azure/logger': 1.1.2 + '@azure/core-auth': 1.9.0 + '@azure/core-tracing': 1.2.0 + '@azure/core-util': 1.11.0 + '@azure/logger': 1.1.4 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.4 - tslib: 2.6.2 + https-proxy-agent: 7.0.6 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false - /@azure/core-tracing/1.1.2: - resolution: {integrity: sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==} + /@azure/core-tracing/1.2.0: + resolution: {integrity: sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==} engines: {node: '>=18.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: false - /@azure/core-util/1.9.0: - resolution: {integrity: sha512-AfalUQ1ZppaKuxPPMsFEUdX6GZPB3d9paR9d/TTL7Ow2De8cJaC7ibi7kWVlFAVPCYo31OcnGymc0R89DX8Oaw==} + /@azure/core-util/1.11.0: + resolution: {integrity: sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g==} engines: {node: '>=18.0.0'} dependencies: '@azure/abort-controller': 2.1.2 - tslib: 2.6.2 + tslib: 2.8.1 dev: false - /@azure/cosmos/4.0.0: - resolution: {integrity: sha512-/Z27p1+FTkmjmm8jk90zi/HrczPHw2t8WecFnsnTe4xGocWl0Z4clP0YlLUTJPhRLWYa5upwD9rMvKJkS1f1kg==} - engines: {node: '>=14.0.0'} + /@azure/cosmos/4.2.0: + resolution: {integrity: sha512-acfAQTYLxgB/iZK7XvTVYe9NPk6DECEgcIXDQhyn7Uo4dGxeeW5D3YqLjLJrrzND5Iawer3eUQ5/iiLWvTGAxQ==} + engines: {node: '>=18.0.0'} dependencies: - '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.7.2 - '@azure/core-rest-pipeline': 1.15.2 - '@azure/core-tracing': 1.1.2 - debug: 4.3.4 + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.9.0 + '@azure/core-rest-pipeline': 1.18.1 + '@azure/core-tracing': 1.2.0 + '@azure/core-util': 1.11.0 fast-json-stable-stringify: 2.1.0 - jsbi: 3.2.5 - node-abort-controller: 3.1.1 - priorityqueuejs: 1.0.0 + jsbi: 4.3.0 + priorityqueuejs: 2.0.0 semaphore: 1.1.0 - tslib: 2.6.2 - universal-user-agent: 6.0.1 - uuid: 8.3.2 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false @@ -3046,16 +3242,16 @@ packages: dependencies: '@azure/abort-controller': 1.1.0 '@azure/core-amqp': 3.3.0 - '@azure/core-auth': 1.7.2 - '@azure/core-tracing': 1.1.2 - '@azure/core-util': 1.9.0 - '@azure/logger': 1.1.2 + '@azure/core-auth': 1.9.0 + '@azure/core-tracing': 1.2.0 + '@azure/core-util': 1.11.0 + '@azure/logger': 1.1.4 buffer: 6.0.3 is-buffer: 2.0.5 jssha: 3.3.1 process: 0.11.10 - rhea-promise: 3.0.1 - tslib: 2.6.2 + rhea-promise: 3.0.3 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false @@ -3069,37 +3265,37 @@ packages: engines: {node: '>=12.0.0'} dependencies: '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.7.2 + '@azure/core-auth': 1.9.0 '@azure/core-client': 1.9.2 - '@azure/core-rest-pipeline': 1.15.2 - '@azure/core-tracing': 1.1.2 - '@azure/core-util': 1.9.0 - '@azure/logger': 1.1.2 - '@azure/msal-browser': 2.38.4 + '@azure/core-rest-pipeline': 1.18.1 + '@azure/core-tracing': 1.2.0 + '@azure/core-util': 1.11.0 + '@azure/logger': 1.1.4 + '@azure/msal-browser': 2.39.0 '@azure/msal-common': 7.6.0 '@azure/msal-node': 1.18.4 events: 3.3.0 jws: 4.0.0 open: 8.4.2 stoppable: 1.1.0 - tslib: 2.6.2 + tslib: 2.8.1 uuid: 8.3.2 transitivePeerDependencies: - supports-color dev: false - /@azure/logger/1.1.2: - resolution: {integrity: sha512-l170uE7bsKpIU6B/giRc9i4NI0Mj+tANMMMxf7Zi/5cKzEqPayP7+X1WPrG7e+91JgY8N+7K7nF2WOi7iVhXvg==} + /@azure/logger/1.1.4: + resolution: {integrity: sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ==} engines: {node: '>=18.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: false - /@azure/msal-browser/2.38.4: - resolution: {integrity: sha512-d1qSanWO9fRKurrxhiyMOIj2jMoGw+2pHb51l2PXNwref7xQO+UeOP2q++5xfHQoUmgTtNuERhitynHla+dvhQ==} + /@azure/msal-browser/2.39.0: + resolution: {integrity: sha512-kks/n2AJzKUk+DBqZhiD+7zeQGBl+WpSOQYzWy6hff3bU0ZrYFqr4keFLlzB5VKuKZog0X59/FGHb1RPBDZLVg==} engines: {node: '>=0.8.0'} dependencies: - '@azure/msal-common': 13.3.1 + '@azure/msal-common': 13.3.3 dev: false /@azure/msal-common/13.3.1: @@ -3107,6 +3303,11 @@ packages: engines: {node: '>=0.8.0'} dev: false + /@azure/msal-common/13.3.3: + resolution: {integrity: sha512-n278DdCXKeiWhLwhEL7/u9HRMyzhUXLefeajiknf6AmEedoiOiv2r5aRJ7LXdT3NGPyubkdIbthaJlVtmuEqvA==} + engines: {node: '>=0.8.0'} + dev: false + /@azure/msal-common/7.6.0: resolution: {integrity: sha512-XqfbglUTVLdkHQ8F9UQJtKseRr3sSnr9ysboxtoswvaMVaEfvyLtMoHv9XdKUfOc0qKGzNgRFd9yRjIWVepl6Q==} engines: {node: '>=0.8.0'} @@ -3122,49 +3323,50 @@ packages: uuid: 8.3.2 dev: false - /@azure/web-pubsub/1.1.1: - resolution: {integrity: sha512-YqPVPv3KX36LIsboNOlF2qjTj1HMWExcFOOH1QIFpbv9ptXI2McIrr5goScgLTtDWO0JIFJjz0sKSWucWPgb1w==} - engines: {node: '>=14.0.0'} + /@azure/web-pubsub/1.1.3: + resolution: {integrity: sha512-l1HHPcFCRhZ8P6oQ8C/8A2eElHWqmG7CxVUlDcXi3Fs9SUr8GYKv5euYJWS5uboaokudjAiqJ6u/oM6h+pQ4+w==} + engines: {node: '>=18.0.0'} dependencies: - '@azure/core-auth': 1.7.2 + '@azure/core-auth': 1.9.0 '@azure/core-client': 1.9.2 - '@azure/core-rest-pipeline': 1.15.2 - '@azure/core-tracing': 1.1.2 - '@azure/logger': 1.1.2 + '@azure/core-rest-pipeline': 1.18.1 + '@azure/core-tracing': 1.2.0 + '@azure/logger': 1.1.4 jsonwebtoken: 9.0.1 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false - /@babel/code-frame/7.24.2: - resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} + /@babel/code-frame/7.26.2: + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.24.2 - picocolors: 1.0.0 + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 - /@babel/compat-data/7.24.4: - resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==} + /@babel/compat-data/7.26.3: + resolution: {integrity: sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==} engines: {node: '>=6.9.0'} dev: true - /@babel/core/7.24.4: - resolution: {integrity: sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==} + /@babel/core/7.26.0: + resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.24.2 - '@babel/generator': 7.24.4 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3_@babel+core@7.24.4 - '@babel/helpers': 7.24.4 - '@babel/parser': 7.24.4 - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.1 - '@babel/types': 7.24.0 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.3 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-module-transforms': 7.26.0_@babel+core@7.26.0 + '@babel/helpers': 7.26.0 + '@babel/parser': 7.26.3 + '@babel/template': 7.25.9 + '@babel/traverse': 7.26.4 + '@babel/types': 7.26.3 convert-source-map: 2.0.0 - debug: 4.3.4 + debug: 4.4.0 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -3172,163 +3374,115 @@ packages: - supports-color dev: true - /@babel/generator/7.24.4: - resolution: {integrity: sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==} + /@babel/generator/7.26.3: + resolution: {integrity: sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 - '@jridgewell/gen-mapping': 0.3.5 + '@babel/parser': 7.26.3 + '@babel/types': 7.26.3 + '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 - jsesc: 2.5.2 + jsesc: 3.1.0 - /@babel/helper-compilation-targets/7.23.6: - resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + /@babel/helper-compilation-targets/7.25.9: + resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/compat-data': 7.24.4 - '@babel/helper-validator-option': 7.23.5 - browserslist: 4.23.0 + '@babel/compat-data': 7.26.3 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.2 lru-cache: 5.1.1 semver: 6.3.1 dev: true - /@babel/helper-environment-visitor/7.22.20: - resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-function-name/7.23.0: - resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.24.0 - '@babel/types': 7.24.0 - dev: true - - /@babel/helper-hoist-variables/7.22.5: - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - dev: true - - /@babel/helper-module-imports/7.24.3: - resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} + /@babel/helper-module-imports/7.25.9: + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 + '@babel/traverse': 7.26.4 + '@babel/types': 7.26.3 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-module-transforms/7.23.3_@babel+core@7.24.4: - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + /@babel/helper-module-transforms/7.26.0_@babel+core@7.26.0: + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.4 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.24.3 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 - dev: true - - /@babel/helper-simple-access/7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - dev: true - - /@babel/helper-split-export-declaration/7.22.6: - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.26.4 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-string-parser/7.24.1: - resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} + /@babel/helper-string-parser/7.25.9: + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-identifier/7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + /@babel/helper-validator-identifier/7.25.9: + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-option/7.23.5: - resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + /@babel/helper-validator-option/7.25.9: + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} engines: {node: '>=6.9.0'} dev: true - /@babel/helpers/7.24.4: - resolution: {integrity: sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==} + /@babel/helpers/7.26.0: + resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.1 - '@babel/types': 7.24.0 - transitivePeerDependencies: - - supports-color + '@babel/template': 7.25.9 + '@babel/types': 7.26.3 dev: true - /@babel/highlight/7.24.2: - resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 - picocolors: 1.0.0 - - /@babel/parser/7.24.4: - resolution: {integrity: sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==} + /@babel/parser/7.26.3: + resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==} engines: {node: '>=6.0.0'} hasBin: true + dependencies: + '@babel/types': 7.26.3 - /@babel/runtime/7.24.5: - resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==} + /@babel/runtime/7.26.0: + resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 dev: true - /@babel/template/7.24.0: - resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} + /@babel/template/7.25.9: + resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.24.2 - '@babel/parser': 7.24.4 - '@babel/types': 7.24.0 + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.26.3 + '@babel/types': 7.26.3 - /@babel/traverse/7.24.1: - resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==} + /@babel/traverse/7.26.4: + resolution: {integrity: sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.24.2 - '@babel/generator': 7.24.4 - '@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.24.4 - '@babel/types': 7.24.0 - debug: 4.3.4 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.3 + '@babel/parser': 7.26.3 + '@babel/template': 7.25.9 + '@babel/types': 7.26.3 + debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/types/7.24.0: - resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} + /@babel/types/7.26.3: + resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.24.1 - '@babel/helper-validator-identifier': 7.22.20 - to-fast-properties: 2.0.0 - - /@balena/dockerignore/1.0.2: - resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} - dev: false + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 /@cdktf/cli-core/0.19.2_react@17.0.2: resolution: {integrity: sha512-kjgEUhrHx3kUPfL7KsTo6GrurVUPT77FmOUf7wWXt7ajNE5zCPvx/HKGmQruzt0n6eLZp1aKT+r/D6YRfXcIGA==} @@ -3338,20 +3492,20 @@ packages: '@cdktf/hcl2json': 0.19.2 '@cdktf/node-pty-prebuilt-multiarch': 0.10.1-pre.11 '@cdktf/provider-schema': 0.19.2 - '@sentry/node': 7.110.1 + '@sentry/node': 7.120.2 archiver: 5.3.2 - cdktf: 0.19.2_constructs@10.3.0 + cdktf: 0.19.2_constructs@10.4.2 chalk: 4.1.2 chokidar: 3.6.0 cli-spinners: 2.7.0 - codemaker: 1.97.0 - constructs: 10.3.0 + codemaker: 1.105.0 + constructs: 10.4.2 cross-fetch: 3.1.5 - cross-spawn: 7.0.3 - detect-port: 1.5.1 + cross-spawn: 7.0.6 + detect-port: 1.6.1 execa: 5.1.1 extract-zip: 2.0.1 - follow-redirects: 1.15.6 + follow-redirects: 1.15.9 fs-extra: 8.1.0 https-proxy-agent: 5.0.1 indent-string: 4.0.0 @@ -3360,9 +3514,9 @@ packages: ink-spinner: 4.0.3_ink@3.2.0+react@17.0.2 ink-testing-library: 2.1.0 ink-use-stdout-dimensions: 1.0.5_ink@3.2.0+react@17.0.2 - jsii: 5.4.3 - jsii-pacmak: 1.97.0 - jsii-srcmak: 0.1.1039 + jsii: 5.7.1 + jsii-pacmak: 1.105.0 + jsii-srcmak: 0.1.1308 lodash.isequal: 4.5.0 log4js: 6.9.1 minimatch: 5.1.6 @@ -3370,9 +3524,9 @@ packages: open: 7.4.2 parse-gitignore: 1.0.1 pkg-up: 3.1.0 - semver: 7.6.0 + semver: 7.6.3 sscaff: 1.2.274 - stream-buffers: 3.0.2 + stream-buffers: 3.0.3 strip-ansi: 6.0.1 tunnel-agent: 0.6.0 uuid: 8.3.2 @@ -3380,12 +3534,13 @@ packages: xstate: 4.38.3 yargs: 17.7.2 yoga-layout-prebuilt: 1.10.0 - zod: 3.22.4 + zod: 3.24.1 transitivePeerDependencies: - '@types/react' - bufferutil - debug - encoding + - jsii-rosetta - react - supports-color - utf-8-validate @@ -3393,13 +3548,13 @@ packages: /@cdktf/commons/0.19.2: resolution: {integrity: sha512-5rOeb0cSREHQa5XVsGFEV6Ce8Zwo2WxE8GIhmGd/JzeSAByhK8scHFlD3+eENl83W/8lwIkm/nSl9oDHEkENIg==} dependencies: - '@sentry/node': 7.110.1 - cdktf: 0.19.2_constructs@10.3.0 + '@sentry/node': 7.120.2 + cdktf: 0.19.2_constructs@10.4.2 ci-info: 3.9.0 - codemaker: 1.97.0 - constructs: 10.3.0 - cross-spawn: 7.0.3 - follow-redirects: 1.15.6 + codemaker: 1.105.0 + constructs: 10.4.2 + cross-spawn: 7.0.6 + follow-redirects: 1.15.9 fs-extra: 11.2.0 is-valid-domain: 0.1.6 log4js: 6.9.1 @@ -3411,22 +3566,22 @@ packages: /@cdktf/hcl2cdk/0.19.2: resolution: {integrity: sha512-v0UNRvvzuCi3SnmSAgBFAnWavT0ybR1AzkK8ndgfbB5JLDoNm0iJV0MOTURZF+I0O3V9u4RZsw4DVNPdil2EEA==} dependencies: - '@babel/generator': 7.24.4 - '@babel/template': 7.24.0 - '@babel/types': 7.24.0 + '@babel/generator': 7.26.3 + '@babel/template': 7.25.9 + '@babel/types': 7.26.3 '@cdktf/commons': 0.19.2 '@cdktf/hcl2json': 0.19.2 '@cdktf/provider-generator': 0.19.2 '@cdktf/provider-schema': 0.19.2 camelcase: 6.3.0 deep-equal: 2.2.3 - glob: 10.3.12 - graphology: 0.25.4_graphology-types@0.24.7 - graphology-types: 0.24.7 - jsii-rosetta: 5.4.2 + glob: 10.4.5 + graphology: 0.25.4_graphology-types@0.24.8 + graphology-types: 0.24.8 + jsii-rosetta: 5.7.1 prettier: 2.8.8 reserved-words: 0.1.2 - zod: 3.22.4 + zod: 3.24.1 transitivePeerDependencies: - debug - supports-color @@ -3440,18 +3595,18 @@ packages: resolution: {integrity: sha512-qvga/nzEtdCJMu/6jJfDqpzbRejvXtNhWFnbubfuYyN5nMNORNXX+POT4j+mQSDQar5bIQ1a812szw/zr47cfw==} requiresBuild: true dependencies: - nan: 2.19.0 + nan: 2.22.0 prebuild-install: 7.1.2 - /@cdktf/provider-azurerm/11.2.0_5k7lg6pu6lyti4sdnvep4rdzly: - resolution: {integrity: sha512-1YpDrScd4YckEVKBPnXUI9yGeRmv7SiQdAj6Mq9eBXWgP1bemRk4mkQlqGm2pe9h5BECLEMZyAg5Cv/JGJX0Uw==} + /@cdktf/provider-azurerm/13.3.0_eykofocqnxaowlkqmvzbold3ry: + resolution: {integrity: sha512-gXxAJYTpEMwxSteqJvZEQ8WpCot+E58sW5u/za0drc5zgkrYO3vTEsOByj8Vcxn7MWXrZFacnktgtU1UkPZs4w==} engines: {node: '>= 18.12.0'} peerDependencies: - cdktf: ^0.19.0 + cdktf: ^0.20.0 constructs: ^10.3.0 dependencies: - cdktf: 0.19.2_constructs@10.3.0 - constructs: 10.3.0 + cdktf: 0.19.2_constructs@10.4.2 + constructs: 10.4.2 dev: false /@cdktf/provider-generator/0.19.2: @@ -3461,10 +3616,10 @@ packages: '@cdktf/hcl2json': 0.19.2 '@cdktf/provider-schema': 0.19.2 '@types/node': 18.18.8 - codemaker: 1.97.0 + codemaker: 1.105.0 deepmerge: 4.3.1 fs-extra: 8.1.0 - jsii-srcmak: 0.1.1039 + jsii-srcmak: 0.1.1308 transitivePeerDependencies: - debug - supports-color @@ -3478,15 +3633,15 @@ packages: - debug - supports-color - /@cdktf/provider-time/9.0.2_5k7lg6pu6lyti4sdnvep4rdzly: + /@cdktf/provider-time/9.0.2_eykofocqnxaowlkqmvzbold3ry: resolution: {integrity: sha512-I0BS+/Gs/2fWXqGcmDsUvWqiCXDYcYH0OKvVvUf1RrGc8678uCeyqVqnwdy+UkIwjUGwk3L9pfJKX3dsun8OUQ==} engines: {node: '>= 18.12.0'} peerDependencies: cdktf: ^0.19.0 constructs: ^10.3.0 dependencies: - cdktf: 0.19.2_constructs@10.3.0 - constructs: 10.3.0 + cdktf: 0.19.2_constructs@10.4.2 + constructs: 10.4.2 dev: false /@cspotcode/source-map-support/0.8.1: @@ -3522,26 +3677,26 @@ packages: '@effect/schema': ^0.64.18 effect: ^2.4.17 dependencies: - '@effect/platform': 0.48.24_dyvpp6bxxcuou3trhs4x4ygr5y + '@effect/platform': 0.48.24_aixcdyfeuz2zct7jthaihye4ri '@effect/printer': 0.32.2_67ibgamlfqfgywvgecp7hwrxja '@effect/printer-ansi': 0.32.26_67ibgamlfqfgywvgecp7hwrxja - '@effect/schema': 0.64.18_jsi5r7dvmbit34siukqkgq3mea + '@effect/schema': 0.64.18_k5iqzw5vszbbtmhrto2doihvji effect: 2.4.17 - ini: 4.1.2 + ini: 4.1.3 toml: 3.0.0 - yaml: 2.4.1 + yaml: 2.6.1 dev: false - /@effect/platform-node-shared/0.3.28_cahjalgelcnk6vcj6x2oc46m3a: - resolution: {integrity: sha512-7OBftCRgRSp5y2A0vUTaN4XsIpKRGbU10JPrv8oX29ppOe6K3xupCAu+vehkhfRxr2fWr5PhUb4F4K/xuptizA==} + /@effect/platform-node-shared/0.3.29_cahjalgelcnk6vcj6x2oc46m3a: + resolution: {integrity: sha512-wP5tO8AX0FX969RLiFVUHbrpRqycNUYOjYiMRv+SQ3Tfv24LMIxksKItlmz3EV2cXk5tk5d1iLN+5d60/92wPw==} peerDependencies: - '@effect/platform': ^0.48.28 + '@effect/platform': ^0.48.29 effect: ^2.4.19 dependencies: - '@effect/platform': 0.48.24_dyvpp6bxxcuou3trhs4x4ygr5y - '@parcel/watcher': 2.4.1 + '@effect/platform': 0.48.24_aixcdyfeuz2zct7jthaihye4ri + '@parcel/watcher': 2.5.0 effect: 2.4.17 - multipasta: 0.2.0 + multipasta: 0.2.5 dev: false /@effect/platform-node/0.45.26_cahjalgelcnk6vcj6x2oc46m3a: @@ -3550,28 +3705,28 @@ packages: '@effect/platform': ^0.48.24 effect: ^2.4.17 dependencies: - '@effect/platform': 0.48.24_dyvpp6bxxcuou3trhs4x4ygr5y - '@effect/platform-node-shared': 0.3.28_cahjalgelcnk6vcj6x2oc46m3a + '@effect/platform': 0.48.24_aixcdyfeuz2zct7jthaihye4ri + '@effect/platform-node-shared': 0.3.29_cahjalgelcnk6vcj6x2oc46m3a effect: 2.4.17 mime: 3.0.0 - undici: 6.13.0 - ws: 8.16.0 + undici: 6.21.0 + ws: 8.17.1 transitivePeerDependencies: - bufferutil - utf-8-validate dev: false - /@effect/platform/0.48.24_dyvpp6bxxcuou3trhs4x4ygr5y: + /@effect/platform/0.48.24_aixcdyfeuz2zct7jthaihye4ri: resolution: {integrity: sha512-3XQSYTNnaWZfhomBbwYlSlb0iVVwArN5ZZzJYRkm3gTDKjzhnlVD3oWbfvjeCdZ5OYCY5AAjjG/OEK8/EY7UXg==} peerDependencies: '@effect/schema': ^0.64.18 effect: ^2.4.17 dependencies: - '@effect/schema': 0.64.18_jsi5r7dvmbit34siukqkgq3mea + '@effect/schema': 0.64.18_k5iqzw5vszbbtmhrto2doihvji effect: 2.4.17 - find-my-way-ts: 0.1.1 - isomorphic-ws: 5.0.0_ws@8.12.0 - multipasta: 0.2.0 + find-my-way-ts: 0.1.5 + isomorphic-ws: 5.0.0_ws@8.17.1 + multipasta: 0.2.5 path-browserify: 1.0.1 transitivePeerDependencies: - ws @@ -3598,14 +3753,14 @@ packages: effect: 2.4.17 dev: false - /@effect/schema/0.64.18_jsi5r7dvmbit34siukqkgq3mea: + /@effect/schema/0.64.18_k5iqzw5vszbbtmhrto2doihvji: resolution: {integrity: sha512-utMVAjcKqmNlkJ8hzdXf3FWBOsekKbe3xhYzWLLLFCpdbTMkCFeN52l1QRXTk7rla87sNTYdMA+xcES9maOEog==} peerDependencies: effect: ^2.4.17 fast-check: ^3.13.2 dependencies: effect: 2.4.17 - fast-check: 3.17.1 + fast-check: 3.23.1 dev: false /@effect/typeclass/0.23.17_effect@2.4.17: @@ -3616,17 +3771,17 @@ packages: effect: 2.4.17 dev: false - /@eslint-community/eslint-utils/4.4.0_eslint@8.57.0: - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + /@eslint-community/eslint-utils/4.4.1_eslint@8.57.1: + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.57.0 + eslint: 8.57.1 eslint-visitor-keys: 3.4.3 - /@eslint-community/regexpp/4.10.0: - resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + /@eslint-community/regexpp/4.12.1: + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} /@eslint/eslintrc/2.1.4: @@ -3634,10 +3789,10 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.3.4 + debug: 4.4.0 espree: 9.6.1 globals: 13.24.0 - ignore: 5.3.1 + ignore: 5.3.2 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -3645,23 +3800,24 @@ packages: transitivePeerDependencies: - supports-color - /@eslint/js/8.57.0: - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + /@eslint/js/8.57.1: + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - /@graphql-typed-document-node/core/3.2.0_graphql@16.8.1: + /@graphql-typed-document-node/core/3.2.0_graphql@16.9.0: resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: - graphql: 16.8.1 + graphql: 16.9.0 - /@humanwhocodes/config-array/0.11.14: - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + /@humanwhocodes/config-array/0.13.0: + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.4 + debug: 4.4.0 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -3672,13 +3828,14 @@ packages: /@humanwhocodes/object-schema/2.0.3: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead /@inquirer/checkbox/1.5.2: resolution: {integrity: sha512-CifrkgQjDkUkWexmgYYNyB5603HhTHI91vLFeQXh6qrTKiCMVASol01Rs1cv6LP/A2WccZSRlJKZhbaBIs/9ZA==} engines: {node: '>=14.18.0'} dependencies: '@inquirer/core': 6.0.0 - '@inquirer/type': 1.3.0 + '@inquirer/type': 1.5.5 ansi-escapes: 4.3.2 chalk: 4.1.2 figures: 3.2.0 @@ -3688,16 +3845,16 @@ packages: engines: {node: '>=14.18.0'} dependencies: '@inquirer/core': 6.0.0 - '@inquirer/type': 1.3.0 + '@inquirer/type': 1.5.5 chalk: 4.1.2 /@inquirer/core/2.3.1: resolution: {integrity: sha512-faYAYnIfdEuns3jGKykaog5oUqFiEVbCx9nXGZfUhyEEpKcHt5bpJfZTb3eOBQKo8I/v4sJkZeBHmFlSZQuBCw==} engines: {node: '>=14.18.0'} dependencies: - '@inquirer/type': 1.3.0 + '@inquirer/type': 1.5.5 '@types/mute-stream': 0.0.1 - '@types/node': 20.12.7 + '@types/node': 20.17.10 '@types/wrap-ansi': 3.0.0 ansi-escapes: 4.3.2 chalk: 4.1.2 @@ -3714,9 +3871,9 @@ packages: resolution: {integrity: sha512-fKi63Khkisgda3ohnskNf5uZJj+zXOaBvOllHsOkdsXRA/ubQLJQrZchFFi57NKbZzkTunXiBMdvWOv71alonw==} engines: {node: '>=14.18.0'} dependencies: - '@inquirer/type': 1.3.0 + '@inquirer/type': 1.5.5 '@types/mute-stream': 0.0.4 - '@types/node': 20.12.7 + '@types/node': 20.17.10 '@types/wrap-ansi': 3.0.0 ansi-escapes: 4.3.2 chalk: 4.1.2 @@ -3734,7 +3891,7 @@ packages: engines: {node: '>=14.18.0'} dependencies: '@inquirer/core': 6.0.0 - '@inquirer/type': 1.3.0 + '@inquirer/type': 1.5.5 chalk: 4.1.2 external-editor: 3.1.0 @@ -3743,7 +3900,7 @@ packages: engines: {node: '>=14.18.0'} dependencies: '@inquirer/core': 6.0.0 - '@inquirer/type': 1.3.0 + '@inquirer/type': 1.5.5 chalk: 4.1.2 figures: 3.2.0 @@ -3752,7 +3909,7 @@ packages: engines: {node: '>=14.18.0'} dependencies: '@inquirer/core': 6.0.0 - '@inquirer/type': 1.3.0 + '@inquirer/type': 1.5.5 chalk: 4.1.2 /@inquirer/password/1.1.16: @@ -3760,7 +3917,7 @@ packages: engines: {node: '>=14.18.0'} dependencies: '@inquirer/core': 6.0.0 - '@inquirer/type': 1.3.0 + '@inquirer/type': 1.5.5 ansi-escapes: 4.3.2 chalk: 4.1.2 @@ -3783,7 +3940,7 @@ packages: engines: {node: '>=14.18.0'} dependencies: '@inquirer/core': 6.0.0 - '@inquirer/type': 1.3.0 + '@inquirer/type': 1.5.5 chalk: 4.1.2 /@inquirer/select/1.3.3: @@ -3791,14 +3948,16 @@ packages: engines: {node: '>=14.18.0'} dependencies: '@inquirer/core': 6.0.0 - '@inquirer/type': 1.3.0 + '@inquirer/type': 1.5.5 ansi-escapes: 4.3.2 chalk: 4.1.2 figures: 3.2.0 - /@inquirer/type/1.3.0: - resolution: {integrity: sha512-RW4Zf6RCTnInRaOZuRHTqAUl+v6VJuQGglir7nW2BkT3OXOphMhkIFhvFRjorBx2l0VwtC/M4No8vYR65TdN9Q==} + /@inquirer/type/1.5.5: + resolution: {integrity: sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==} engines: {node: '>=18'} + dependencies: + mute-stream: 1.0.0 /@isaacs/cliui/8.0.2: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -3827,12 +3986,12 @@ packages: engines: {node: '>=8'} dev: true - /@jridgewell/gen-mapping/0.3.5: - resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + /@jridgewell/gen-mapping/0.3.8: + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 /@jridgewell/resolve-uri/3.1.2: @@ -3843,45 +4002,38 @@ packages: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} - /@jridgewell/sourcemap-codec/1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + /@jridgewell/sourcemap-codec/1.5.0: + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} /@jridgewell/trace-mapping/0.3.25: resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 /@jridgewell/trace-mapping/0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - - /@jsii/check-node/1.96.0: - resolution: {integrity: sha512-1EZudLi9wMg6d8JYu8t5s0B+WhyAJvOezhdmFv+PTrTc1Eze7NRY7uZuvBRRkBvqvOWlKkCfBByyeZJnLcxNMA==} - engines: {node: '>= 14.17.0'} - dependencies: - chalk: 4.1.2 - semver: 7.6.0 + '@jridgewell/sourcemap-codec': 1.5.0 - /@jsii/check-node/1.97.0: - resolution: {integrity: sha512-n7t4p2JNyr6iBkAv/+9pDPU6hV/sa3Kqdp6oPw5v4/TqNyopGSGtxyOtNXtsBcN6zMibAVXmvhzZA+OBaX1FiQ==} + /@jsii/check-node/1.105.0: + resolution: {integrity: sha512-7QIzioc9//TwRjLhGMllcTBfIvJ0h6OeGVUEYdXB1DpCNtMbr8Xcj5KaeKHRAF9iRjB1d0IGzKm4A8fRUzIf+Q==} engines: {node: '>= 14.17.0'} dependencies: chalk: 4.1.2 - semver: 7.6.0 + semver: 7.6.3 - /@jsii/spec/1.97.0: - resolution: {integrity: sha512-5YIq1fgOtToH6eUyTNlqAXuZzUzTD6wBukE7m5DpsxHjQlbR7TVP750FcPqH9qCitCwaePPl5IdCZJ/AS0IwEA==} + /@jsii/spec/1.105.0: + resolution: {integrity: sha512-pLy8JyPT9Vv5UTxtM4ZHm/iisWzU62m3/dn9TPW2oANI5TLiBpjLlJw/iF+KRjYAeQnFASUfXtWTXgbN4xp9Rw==} engines: {node: '>= 14.17.0'} dependencies: - ajv: 8.12.0 + ajv: 8.17.1 /@kwsites/file-exists/1.1.1_supports-color@8.1.1: resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} dependencies: - debug: 4.3.4_supports-color@8.1.1 + debug: 4.4.0_supports-color@8.1.1 transitivePeerDependencies: - supports-color dev: true @@ -3908,18 +4060,18 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - /@oclif/core/2.16.0_cwiqw7fmejhb47wvqtchhjxme4: + /@oclif/core/2.16.0_qnvbopyuzco2g5z7jdoebgqlma: resolution: {integrity: sha512-dL6atBH0zCZl1A1IXCKJgLPrM/wR7K+Wi401E/IvqsK8m2iCHW+0TEOGrans/cuN3oTW+uxIyJFHJ8Im0k4qBw==} engines: {node: '>=14.0.0'} dependencies: - '@types/cli-progress': 3.11.5 + '@types/cli-progress': 3.11.6 ansi-escapes: 4.3.2 ansi-styles: 4.3.0 cardinal: 2.1.1 chalk: 4.1.2 clean-stack: 3.0.1 cli-progress: 3.12.0 - debug: 4.3.4_supports-color@8.1.1 + debug: 4.4.0_supports-color@8.1.1 ejs: 3.1.10 get-package-type: 0.1.0 globby: 11.1.0 @@ -3935,8 +4087,8 @@ packages: strip-ansi: 6.0.1 supports-color: 8.1.1 supports-hyperlinks: 2.3.0 - ts-node: 10.9.2_cwiqw7fmejhb47wvqtchhjxme4 - tslib: 2.6.2 + ts-node: 10.9.2_qnvbopyuzco2g5z7jdoebgqlma + tslib: 2.8.1 widest-line: 3.1.0 wordwrap: 1.0.0 wrap-ansi: 7.0.0 @@ -3958,7 +4110,7 @@ packages: clean-stack: 3.0.1 cli-progress: 3.12.0 color: 4.2.3 - debug: 4.3.4_supports-color@8.1.1 + debug: 4.4.0_supports-color@8.1.1 ejs: 3.1.10 get-package-type: 0.1.0 globby: 11.1.0 @@ -3974,7 +4126,7 @@ packages: strip-ansi: 6.0.1 supports-color: 8.1.1 supports-hyperlinks: 2.3.0 - tsconfck: 3.0.3_typescript@5.1.6 + tsconfck: 3.1.4_typescript@5.1.6 widest-line: 3.1.0 wordwrap: 1.0.0 wrap-ansi: 7.0.0 @@ -3982,11 +4134,11 @@ packages: - typescript dev: false - /@oclif/core/3.26.3: - resolution: {integrity: sha512-e6Vwu+cb2Sn4qFFpmY1fQLRWIY5ugruMuN94xb7+kyUzxrirYjJATPhuCT1G5xj9Dk+hTMH+Sp6XcHcVTS1lHg==} + /@oclif/core/3.27.0: + resolution: {integrity: sha512-Fg93aNFvXzBq5L7ztVHFP2nYwWU1oTCq48G0TjF/qC1UN36KWa2H5Hsm72kERd5x/sjy2M2Tn4kDEorUlpXOlw==} engines: {node: '>=18.0.0'} dependencies: - '@types/cli-progress': 3.11.5 + '@types/cli-progress': 3.11.6 ansi-escapes: 4.3.2 ansi-styles: 4.3.0 cardinal: 2.1.1 @@ -3994,7 +4146,7 @@ packages: clean-stack: 3.0.1 cli-progress: 3.12.0 color: 4.2.3 - debug: 4.3.4_supports-color@8.1.1 + debug: 4.4.0_supports-color@8.1.1 ejs: 3.1.10 get-package-type: 0.1.0 globby: 11.1.0 @@ -4002,7 +4154,7 @@ packages: indent-string: 4.0.0 is-wsl: 2.2.0 js-yaml: 3.14.1 - minimatch: 9.0.4 + minimatch: 9.0.5 natural-orderby: 2.0.3 object-treeify: 1.1.33 password-prompt: 1.1.3 @@ -4016,11 +4168,11 @@ packages: wrap-ansi: 7.0.0 dev: true - /@oclif/plugin-help/5.2.20_cwiqw7fmejhb47wvqtchhjxme4: + /@oclif/plugin-help/5.2.20_qnvbopyuzco2g5z7jdoebgqlma: resolution: {integrity: sha512-u+GXX/KAGL9S10LxAwNUaWdzbEBARJ92ogmM7g3gDVud2HioCmvWQCDohNRVZ9GYV9oKwZ/M8xwd6a1d95rEKQ==} engines: {node: '>=12.0.0'} dependencies: - '@oclif/core': 2.16.0_cwiqw7fmejhb47wvqtchhjxme4 + '@oclif/core': 2.16.0_qnvbopyuzco2g5z7jdoebgqlma transitivePeerDependencies: - '@swc/core' - '@swc/wasm' @@ -4028,19 +4180,19 @@ packages: - typescript dev: false - /@oclif/test/3.2.10: - resolution: {integrity: sha512-9h6rMHnFS7zf0CLmfqtbAmdDSLpYF8otu25YpeqQXOX3b9TYeyfOvD61TkkxJ2T3zpqnrViNzifsF6gfM6xanQ==} + /@oclif/test/3.2.15: + resolution: {integrity: sha512-XqG3RosozNqySkxSXInU12Xec2sPSOkqYHJDfdFZiWG3a8Cxu4dnPiAQvms+BJsOlLQmfEQlSHqiyVUKOMHhXA==} engines: {node: '>=18.0.0'} dependencies: - '@oclif/core': 3.26.3 - chai: 4.4.1 - fancy-test: 3.0.14 + '@oclif/core': 3.27.0 + chai: 4.5.0 + fancy-test: 3.0.16 transitivePeerDependencies: - supports-color dev: true - /@parcel/watcher-android-arm64/2.4.1: - resolution: {integrity: sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==} + /@parcel/watcher-android-arm64/2.5.0: + resolution: {integrity: sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [android] @@ -4048,8 +4200,8 @@ packages: dev: false optional: true - /@parcel/watcher-darwin-arm64/2.4.1: - resolution: {integrity: sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==} + /@parcel/watcher-darwin-arm64/2.5.0: + resolution: {integrity: sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [darwin] @@ -4057,8 +4209,8 @@ packages: dev: false optional: true - /@parcel/watcher-darwin-x64/2.4.1: - resolution: {integrity: sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==} + /@parcel/watcher-darwin-x64/2.5.0: + resolution: {integrity: sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [darwin] @@ -4066,8 +4218,8 @@ packages: dev: false optional: true - /@parcel/watcher-freebsd-x64/2.4.1: - resolution: {integrity: sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==} + /@parcel/watcher-freebsd-x64/2.5.0: + resolution: {integrity: sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [freebsd] @@ -4075,8 +4227,8 @@ packages: dev: false optional: true - /@parcel/watcher-linux-arm-glibc/2.4.1: - resolution: {integrity: sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==} + /@parcel/watcher-linux-arm-glibc/2.5.0: + resolution: {integrity: sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] @@ -4084,8 +4236,17 @@ packages: dev: false optional: true - /@parcel/watcher-linux-arm64-glibc/2.4.1: - resolution: {integrity: sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==} + /@parcel/watcher-linux-arm-musl/2.5.0: + resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-arm64-glibc/2.5.0: + resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] @@ -4093,8 +4254,8 @@ packages: dev: false optional: true - /@parcel/watcher-linux-arm64-musl/2.4.1: - resolution: {integrity: sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==} + /@parcel/watcher-linux-arm64-musl/2.5.0: + resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] @@ -4102,8 +4263,8 @@ packages: dev: false optional: true - /@parcel/watcher-linux-x64-glibc/2.4.1: - resolution: {integrity: sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==} + /@parcel/watcher-linux-x64-glibc/2.5.0: + resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] @@ -4111,8 +4272,8 @@ packages: dev: false optional: true - /@parcel/watcher-linux-x64-musl/2.4.1: - resolution: {integrity: sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==} + /@parcel/watcher-linux-x64-musl/2.5.0: + resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] @@ -4120,8 +4281,8 @@ packages: dev: false optional: true - /@parcel/watcher-win32-arm64/2.4.1: - resolution: {integrity: sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==} + /@parcel/watcher-win32-arm64/2.5.0: + resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [win32] @@ -4129,8 +4290,8 @@ packages: dev: false optional: true - /@parcel/watcher-win32-ia32/2.4.1: - resolution: {integrity: sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==} + /@parcel/watcher-win32-ia32/2.5.0: + resolution: {integrity: sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==} engines: {node: '>= 10.0.0'} cpu: [ia32] os: [win32] @@ -4138,8 +4299,8 @@ packages: dev: false optional: true - /@parcel/watcher-win32-x64/2.4.1: - resolution: {integrity: sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==} + /@parcel/watcher-win32-x64/2.5.0: + resolution: {integrity: sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [win32] @@ -4147,27 +4308,29 @@ packages: dev: false optional: true - /@parcel/watcher/2.4.1: - resolution: {integrity: sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==} + /@parcel/watcher/2.5.0: + resolution: {integrity: sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==} engines: {node: '>= 10.0.0'} + requiresBuild: true dependencies: detect-libc: 1.0.3 is-glob: 4.0.3 - micromatch: 4.0.5 - node-addon-api: 7.1.0 + micromatch: 4.0.8 + node-addon-api: 7.1.1 optionalDependencies: - '@parcel/watcher-android-arm64': 2.4.1 - '@parcel/watcher-darwin-arm64': 2.4.1 - '@parcel/watcher-darwin-x64': 2.4.1 - '@parcel/watcher-freebsd-x64': 2.4.1 - '@parcel/watcher-linux-arm-glibc': 2.4.1 - '@parcel/watcher-linux-arm64-glibc': 2.4.1 - '@parcel/watcher-linux-arm64-musl': 2.4.1 - '@parcel/watcher-linux-x64-glibc': 2.4.1 - '@parcel/watcher-linux-x64-musl': 2.4.1 - '@parcel/watcher-win32-arm64': 2.4.1 - '@parcel/watcher-win32-ia32': 2.4.1 - '@parcel/watcher-win32-x64': 2.4.1 + '@parcel/watcher-android-arm64': 2.5.0 + '@parcel/watcher-darwin-arm64': 2.5.0 + '@parcel/watcher-darwin-x64': 2.5.0 + '@parcel/watcher-freebsd-x64': 2.5.0 + '@parcel/watcher-linux-arm-glibc': 2.5.0 + '@parcel/watcher-linux-arm-musl': 2.5.0 + '@parcel/watcher-linux-arm64-glibc': 2.5.0 + '@parcel/watcher-linux-arm64-musl': 2.5.0 + '@parcel/watcher-linux-x64-glibc': 2.5.0 + '@parcel/watcher-linux-x64-musl': 2.5.0 + '@parcel/watcher-win32-arm64': 2.5.0 + '@parcel/watcher-win32-ia32': 2.5.0 + '@parcel/watcher-win32-x64': 2.5.0 dev: false /@pkgjs/parseargs/0.11.0: @@ -4176,6 +4339,9 @@ packages: requiresBuild: true optional: true + /@rtsao/scc/1.1.0: + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + /@seald-io/binary-search-tree/1.0.3: resolution: {integrity: sha512-qv3jnwoakeax2razYaMsGI/luWdliBLHTdC6jU55hQt1hcFqzauH/HsBollQ7IR4ySTtYhT+xyHoijpA16C+tA==} @@ -4186,39 +4352,49 @@ packages: localforage: 1.10.0 util: 0.12.5 - /@sentry-internal/tracing/7.110.1: - resolution: {integrity: sha512-4kTd6EM0OP1SVWl2yLn3KIwlCpld1lyhNDeR8G1aKLm1PN+kVsR6YB/jy9KPPp4Q3lN3W9EkTSES3qhP4jVffQ==} + /@sentry-internal/tracing/7.120.2: + resolution: {integrity: sha512-eo2F8cP6X+vr54Mp6vu+NoQEDz0M5O24Tz8jPY0T1CpiWdwCmHb7Sln+oLXeQ3/LlWdVQihBfKDBZfBdUfsBTg==} engines: {node: '>=8'} dependencies: - '@sentry/core': 7.110.1 - '@sentry/types': 7.110.1 - '@sentry/utils': 7.110.1 + '@sentry/core': 7.120.2 + '@sentry/types': 7.120.2 + '@sentry/utils': 7.120.2 - /@sentry/core/7.110.1: - resolution: {integrity: sha512-yC1yeUFQlmHj9u/KxKmwOMVanBmgfX+4MZnZU31QPqN95adyZTwpaYFZl4fH5kDVnz7wXJI0qRP8SxuMePtqhw==} + /@sentry/core/7.120.2: + resolution: {integrity: sha512-eurLBFQJC7WWWYoEna25Z9I/GJjqAmH339tv52XP8sqXV7B5hRcHDcfrsT/UGHpU316M24p3lWhj0eimtCZ0SQ==} engines: {node: '>=8'} dependencies: - '@sentry/types': 7.110.1 - '@sentry/utils': 7.110.1 + '@sentry/types': 7.120.2 + '@sentry/utils': 7.120.2 - /@sentry/node/7.110.1: - resolution: {integrity: sha512-n6sNzZJ/ChfyCI1FxuGWgloeevC8j2vax3vXM4IZrSIm5hS1d9L2oCJ4HEPuxGUxCkQ1f4kXPcdmNaQsWH0JBw==} + /@sentry/integrations/7.120.2: + resolution: {integrity: sha512-bMvL2fD3TGLM5YAUoQ2Qz6bYeVU8f7YRFNSjKNxK4EbvFgAU9j1FD6EKg0V0RNOJYnJjGIZYMmcWTXBbVTJL6w==} engines: {node: '>=8'} dependencies: - '@sentry-internal/tracing': 7.110.1 - '@sentry/core': 7.110.1 - '@sentry/types': 7.110.1 - '@sentry/utils': 7.110.1 + '@sentry/core': 7.120.2 + '@sentry/types': 7.120.2 + '@sentry/utils': 7.120.2 + localforage: 1.10.0 - /@sentry/types/7.110.1: - resolution: {integrity: sha512-sZxOpM5gfyxvJeWVvNpHnxERTnlqcozjqNcIv29SZ6wonlkekmxDyJ3uCuPv85VO54WLyA4uzskPKnNFHacI8A==} + /@sentry/node/7.120.2: + resolution: {integrity: sha512-ZnW9gpIGaoU+vYZyVZca9dObfmWYiXEWIMUM/JXaFb8AhP1OXvYweNiU0Pe/gNrz4oGAogU8scJc70ar7Vj0ww==} engines: {node: '>=8'} + dependencies: + '@sentry-internal/tracing': 7.120.2 + '@sentry/core': 7.120.2 + '@sentry/integrations': 7.120.2 + '@sentry/types': 7.120.2 + '@sentry/utils': 7.120.2 - /@sentry/utils/7.110.1: - resolution: {integrity: sha512-eibLo2m1a7sHkOHxYYmRujr3D7ek2l9sv26F1SLoQBVDF7Afw5AKyzPmtA1D+4M9P/ux1okj7cGj3SaBrVpxXA==} + /@sentry/types/7.120.2: + resolution: {integrity: sha512-FWVoiblHQJ892GaOqdXx/5/n5XDLF28z81vJ0lCY49PMh8waz8LJ0b9RSmt9tasSDl0OQ7eUlPl1xu1jTrv1NA==} + engines: {node: '>=8'} + + /@sentry/utils/7.120.2: + resolution: {integrity: sha512-jgnQlw11mRfQrQRAXbq4zEd+tbYwHel5eqeS/oU6EImXRjmHNtS79nB8MHvJeQu1FMCpFs1Ymrrs5FICwS6VeQ==} engines: {node: '>=8'} dependencies: - '@sentry/types': 7.110.1 + '@sentry/types': 7.120.2 /@serverless/dashboard-plugin/6.4.0_supports-color@8.1.1: resolution: {integrity: sha512-2yJQym94sXZhEFbcOVRMJgJ4a2H9Qly94UeUesPwf8bfWCxtiB4l5rxLnCB2aLTuUf/djcuD5/VrNPY1pRU7DA==} @@ -4234,14 +4410,14 @@ packages: js-yaml: 4.1.0 jszip: 3.10.1 lodash: 4.17.21 - memoizee: 0.4.15 + memoizee: 0.4.17 ncjsm: 4.3.2 node-dir: 0.1.17 node-fetch: 2.7.0 open: 7.4.2 - semver: 7.6.0 - simple-git: 3.24.0_supports-color@8.1.1 - type: 2.7.2 + semver: 7.6.3 + simple-git: 3.27.0_supports-color@8.1.1 + type: 2.7.3 uuid: 8.3.2 yamljs: 0.3.0 transitivePeerDependencies: @@ -4255,7 +4431,7 @@ packages: /@serverless/event-mocks/1.1.1: resolution: {integrity: sha512-YAV5V/y+XIOfd+HEVeXfPWZb8C6QLruFk9tBivoX2roQLWVq145s4uxf8D0QioCueuRzkukHUS4JIj+KVoS34A==} dependencies: - '@types/lodash': 4.17.0 + '@types/lodash': 4.17.13 lodash: 4.17.21 dev: true @@ -4263,21 +4439,21 @@ packages: resolution: {integrity: sha512-XltmO/029X76zi0LUFmhsnanhE2wnqH1xf+WBt5K8gumQA9LnrfwLgPxj+VA+mm6wQhy+PCp7H5SS0ZPu7F2Cw==} engines: {node: '>=10.0'} dependencies: - adm-zip: 0.5.12 + adm-zip: 0.5.16 archiver: 5.3.0 - axios: 1.6.8 + axios: 1.7.9 fast-glob: 3.3.2 https-proxy-agent: 5.0.1_supports-color@8.1.1 - ignore: 5.3.1 - isomorphic-ws: 4.0.1_ws@7.5.9 + ignore: 5.3.2 + isomorphic-ws: 4.0.1_ws@7.5.10 js-yaml: 3.14.1 jwt-decode: 2.2.0 minimatch: 3.1.2 querystring: 0.2.1 run-parallel-limit: 1.1.0 throat: 5.0.0 - traverse: 0.6.9 - ws: 7.5.9 + traverse: 0.6.10 + ws: 7.5.10 transitivePeerDependencies: - bufferutil - debug @@ -4307,18 +4483,18 @@ packages: js-yaml: 4.1.0 jwt-decode: 3.1.2 lodash: 4.17.21 - log: 6.3.1 - log-node: 8.0.3_log@6.3.1 + log: 6.3.2 + log-node: 8.0.3_log@6.3.2 make-dir: 4.0.0 - memoizee: 0.4.15 + memoizee: 0.4.17 ms: 2.1.3 ncjsm: 4.3.2 node-fetch: 2.7.0 open: 8.4.2 p-event: 4.2.0 supports-color: 8.1.1 - timers-ext: 0.1.7 - type: 2.7.2 + timers-ext: 0.1.8 + type: 2.7.3 uni-global: 1.0.0 uuid: 8.3.2 write-file-atomic: 4.0.2 @@ -4336,12 +4512,6 @@ packages: dependencies: type-detect: 4.0.8 - /@sinonjs/commons/2.0.0: - resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} - dependencies: - type-detect: 4.0.8 - dev: true - /@sinonjs/commons/3.0.1: resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} dependencies: @@ -4354,8 +4524,8 @@ packages: '@sinonjs/commons': 3.0.1 dev: true - /@sinonjs/fake-timers/11.2.2: - resolution: {integrity: sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==} + /@sinonjs/fake-timers/11.3.1: + resolution: {integrity: sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==} dependencies: '@sinonjs/commons': 3.0.1 dev: true @@ -4375,18 +4545,18 @@ packages: dependencies: '@sinonjs/commons': 1.8.6 lodash.get: 4.4.2 - type-detect: 4.0.8 + type-detect: 4.1.0 - /@sinonjs/samsam/8.0.0: - resolution: {integrity: sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==} + /@sinonjs/samsam/8.0.2: + resolution: {integrity: sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==} dependencies: - '@sinonjs/commons': 2.0.0 + '@sinonjs/commons': 3.0.1 lodash.get: 4.4.2 - type-detect: 4.0.8 + type-detect: 4.1.0 dev: true - /@sinonjs/text-encoding/0.7.2: - resolution: {integrity: sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==} + /@sinonjs/text-encoding/0.7.3: + resolution: {integrity: sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==} /@szmarczak/http-timer/4.0.6: resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} @@ -4440,14 +4610,14 @@ packages: resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} dependencies: '@types/connect': 3.4.38 - '@types/node': 18.19.31 + '@types/node': 18.19.68 /@types/cacheable-request/6.0.3: resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/responselike': 1.0.3 dev: true @@ -4467,33 +4637,27 @@ packages: resolution: {integrity: sha512-rS27+EkB/RE1Iz3u0XtVL5q36MGDWbgYe7zWiodyKNUnthxY0rukK5V36eiUCtCisB7NN8zKYH6DO2M37qxFEQ==} dev: true - /@types/child-process-promise/2.2.6: - resolution: {integrity: sha512-g0pOHijr6Trug43D2bV0PLSIsSHa/xHEES2HeX5BAlduq1vW0nZcq27Zeud5lgmNB+kPYYVqiMap32EHGTco/w==} + /@types/cli-progress/3.11.6: + resolution: {integrity: sha512-cE3+jb9WRlu+uOSAugewNpITJDt1VF8dHOopPO4IABFc3SXYL5WE/+PTz/FCdZRRfIujiWW3n3aMbv1eIGVRWA==} dependencies: - '@types/node': 18.19.31 - dev: true - - /@types/cli-progress/3.11.5: - resolution: {integrity: sha512-D4PbNRbviKyppS5ivBGyFO29POlySLmA2HyUFE4p5QGazAMM3CwkKWcvTl8gvElSuxRh6FPKL8XmidX873ou4g==} - dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 /@types/connect/3.4.38: resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 /@types/cors/2.8.17: resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 dev: true - /@types/express-serve-static-core/4.19.0: - resolution: {integrity: sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==} + /@types/express-serve-static-core/4.19.6: + resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} dependencies: - '@types/node': 18.19.31 - '@types/qs': 6.9.14 + '@types/node': 18.19.68 + '@types/qs': 6.9.17 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -4501,8 +4665,8 @@ packages: resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} dependencies: '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 4.19.0 - '@types/qs': 6.9.14 + '@types/express-serve-static-core': 4.19.6 + '@types/qs': 6.9.17 '@types/serve-static': 1.15.7 /@types/faker/5.1.5: @@ -4512,14 +4676,14 @@ packages: /@types/fs-extra/9.0.13: resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 dev: true /@types/glob/8.1.0: resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 18.19.31 + '@types/node': 18.19.68 /@types/http-cache-semantics/4.0.4: resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} @@ -4548,16 +4712,16 @@ packages: /@types/jsonwebtoken/9.0.1: resolution: {integrity: sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==} dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 /@types/keyv/3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 dev: true - /@types/lodash/4.17.0: - resolution: {integrity: sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==} + /@types/lodash/4.17.13: + resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==} dev: true /@types/mime/1.3.5: @@ -4577,29 +4741,29 @@ packages: /@types/mute-stream/0.0.1: resolution: {integrity: sha512-0yQLzYhCqGz7CQPE3iDmYjhb7KMBFOP+tBkyw+/Y2YyDI5wpS7itXXxneN1zSsUwWx3Ji6YiVYrhAnpQGS/vkw==} dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 /@types/mute-stream/0.0.4: resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==} dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 /@types/nedb/1.8.16: resolution: {integrity: sha512-ND+uzwAZk7ZI9byOvHGOcZe2R9XUcLF698yDJKn00trFvh+GaemkX3gQKCSKtObjDpv8Uuou+k8v4x4scPr4TA==} dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 dev: true /@types/needle/2.5.3: resolution: {integrity: sha512-RwgTwMRaedfyCBe5SSWMpm1Yqzc5UPZEMw0eAd09OSyV93nLRj9/evMGZmgFeHKzUOd4xxtHvgtc+rjcBjI1Qg==} dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 dev: false /@types/node-schedule/1.3.2: resolution: {integrity: sha512-Y0CqdAr+lCpArT8CJJjJq4U2v8Bb5e7ru2nV/NhDdaptCMCRdOL3Y7tAhen39HluQMaIKWvPbDuiFBUQpg7Srw==} dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 dev: true /@types/node/10.17.60: @@ -4611,22 +4775,22 @@ packages: dependencies: undici-types: 5.26.5 - /@types/node/18.19.31: - resolution: {integrity: sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==} + /@types/node/18.19.68: + resolution: {integrity: sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw==} dependencies: undici-types: 5.26.5 - /@types/node/20.12.7: - resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} + /@types/node/20.17.10: + resolution: {integrity: sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==} dependencies: - undici-types: 5.26.5 + undici-types: 6.19.8 /@types/normalize-package-data/2.4.4: resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} dev: true - /@types/qs/6.9.14: - resolution: {integrity: sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==} + /@types/qs/6.9.17: + resolution: {integrity: sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==} /@types/range-parser/1.2.7: resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} @@ -4634,7 +4798,7 @@ packages: /@types/responselike/1.0.3: resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 dev: true /@types/rewire/2.5.30: @@ -4648,13 +4812,13 @@ packages: resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} dependencies: '@types/mime': 1.3.5 - '@types/node': 18.19.31 + '@types/node': 18.19.68 /@types/serve-static/1.15.7: resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} dependencies: '@types/http-errors': 2.0.4 - '@types/node': 18.19.31 + '@types/node': 18.19.68 '@types/send': 0.17.4 /@types/sinon-chai/3.2.5: @@ -4679,7 +4843,7 @@ packages: /@types/through/0.0.33: resolution: {integrity: sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==} dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 dev: true /@types/uuid/8.3.0: @@ -4696,20 +4860,20 @@ packages: /@types/ws/8.5.4: resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==} dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 dev: true /@types/yauzl/2.10.3: resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} requiresBuild: true dependencies: - '@types/node': 18.19.31 + '@types/node': 18.19.68 optional: true /@types/yoga-layout/1.9.2: resolution: {integrity: sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==} - /@typescript-eslint/eslint-plugin/5.62.0_isoa4rovreaplj6y6c4wy6pss4: + /@typescript-eslint/eslint-plugin/5.62.0_uve4wv4elfpx2l3zvshgwzvkay: resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -4720,23 +4884,23 @@ packages: typescript: optional: true dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 5.62.0_trrslaohprr5r73nykufww5lry + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/type-utils': 5.62.0_trrslaohprr5r73nykufww5lry - '@typescript-eslint/utils': 5.62.0_trrslaohprr5r73nykufww5lry - debug: 4.3.4 - eslint: 8.57.0 + '@typescript-eslint/type-utils': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi + '@typescript-eslint/utils': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi + debug: 4.4.0 + eslint: 8.57.1 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 natural-compare-lite: 1.4.0 - semver: 7.6.0 + semver: 7.6.3 tsutils: 3.21.0_typescript@5.1.6 typescript: 5.1.6 transitivePeerDependencies: - supports-color - /@typescript-eslint/parser/5.62.0_trrslaohprr5r73nykufww5lry: + /@typescript-eslint/parser/5.62.0_cfup2jodhmurb5mm6vjw5usxmi: resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -4749,8 +4913,8 @@ packages: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0_typescript@5.1.6 - debug: 4.3.4 - eslint: 8.57.0 + debug: 4.4.0 + eslint: 8.57.1 typescript: 5.1.6 transitivePeerDependencies: - supports-color @@ -4762,7 +4926,7 @@ packages: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - /@typescript-eslint/type-utils/5.62.0_trrslaohprr5r73nykufww5lry: + /@typescript-eslint/type-utils/5.62.0_cfup2jodhmurb5mm6vjw5usxmi: resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -4773,9 +4937,9 @@ packages: optional: true dependencies: '@typescript-eslint/typescript-estree': 5.62.0_typescript@5.1.6 - '@typescript-eslint/utils': 5.62.0_trrslaohprr5r73nykufww5lry - debug: 4.3.4 - eslint: 8.57.0 + '@typescript-eslint/utils': 5.62.0_cfup2jodhmurb5mm6vjw5usxmi + debug: 4.4.0 + eslint: 8.57.1 tsutils: 3.21.0_typescript@5.1.6 typescript: 5.1.6 transitivePeerDependencies: @@ -4796,30 +4960,30 @@ packages: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4 + debug: 4.4.0 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.6.0 + semver: 7.6.3 tsutils: 3.21.0_typescript@5.1.6 typescript: 5.1.6 transitivePeerDependencies: - supports-color - /@typescript-eslint/utils/5.62.0_trrslaohprr5r73nykufww5lry: + /@typescript-eslint/utils/5.62.0_cfup2jodhmurb5mm6vjw5usxmi: resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0_eslint@8.57.0 + '@eslint-community/eslint-utils': 4.4.1_eslint@8.57.1 '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0_typescript@5.1.6 - eslint: 8.57.0 + eslint: 8.57.1 eslint-scope: 5.1.1 - semver: 7.6.0 + semver: 7.6.3 transitivePeerDependencies: - supports-color - typescript @@ -4831,30 +4995,30 @@ packages: '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 - /@ungap/structured-clone/1.2.0: - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + /@ungap/structured-clone/1.2.1: + resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==} /@wry/context/0.7.4: resolution: {integrity: sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==} engines: {node: '>=8'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 /@wry/equality/0.5.7: resolution: {integrity: sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==} engines: {node: '>=8'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 /@wry/trie/0.3.2: resolution: {integrity: sha512-yRTyhWSls2OY/pYLfwff867r8ekooZ4UI+/gxot5Wj8EFwSf2rG+n+Mo/6LoLQm1TKA4GRj2+LCpbfS937dClQ==} engines: {node: '>=8'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 - /@xmldom/xmldom/0.8.10: - resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} - engines: {node: '>=10.0.0'} + /@xmldom/xmldom/0.9.6: + resolution: {integrity: sha512-Su4xcxR0CPGwlDHNmVP09fqET9YxbyDXHaSob6JlBH7L6reTYaeim6zbk9o08UarO0L5GTRo3uzl0D+9lSxmvw==} + engines: {node: '>=14.6'} /accepts/1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} @@ -4871,16 +5035,18 @@ packages: acorn: 7.4.1 dev: true - /acorn-jsx/5.3.2_acorn@8.11.3: + /acorn-jsx/5.3.2_acorn@8.14.0: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.11.3 + acorn: 8.14.0 - /acorn-walk/8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + /acorn-walk/8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} + dependencies: + acorn: 8.14.0 /acorn/7.4.1: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} @@ -4888,8 +5054,8 @@ packages: hasBin: true dev: true - /acorn/8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + /acorn/8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} engines: {node: '>=0.4.0'} hasBin: true @@ -4897,16 +5063,16 @@ packages: resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} engines: {node: '>= 10.0.0'} - /adm-zip/0.5.12: - resolution: {integrity: sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ==} - engines: {node: '>=6.0'} + /adm-zip/0.5.16: + resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} + engines: {node: '>=12.0'} dev: true /agent-base/6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.3.4 + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -4914,18 +5080,14 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.3.4_supports-color@8.1.1 + debug: 4.4.0_supports-color@8.1.1 transitivePeerDependencies: - supports-color dev: true - - /agent-base/7.1.1: - resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} - engines: {node: '>= 14'} - dependencies: - debug: 4.3.4 - transitivePeerDependencies: - - supports-color + + /agent-base/7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + engines: {node: '>= 14'} dev: false /aggregate-error/3.1.0: @@ -4942,7 +5104,7 @@ packages: ajv: optional: true dependencies: - ajv: 8.12.0 + ajv: 8.17.1 dev: true /ajv/6.12.6: @@ -4953,13 +5115,13 @@ packages: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - /ajv/8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + /ajv/8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} dependencies: fast-deep-equal: 3.1.3 + fast-uri: 3.0.3 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - uri-js: 4.4.1 /ansi-colors/4.1.1: resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} @@ -4980,8 +5142,8 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - /ansi-regex/6.0.1: - resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + /ansi-regex/6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} engines: {node: '>=12'} /ansi-styles/3.2.1: @@ -5059,7 +5221,7 @@ packages: engines: {node: '>= 10'} dependencies: archiver-utils: 2.1.0 - async: 3.2.5 + async: 3.2.6 buffer-crc32: 0.2.13 readable-stream: 3.6.2 readdir-glob: 1.1.3 @@ -5071,7 +5233,7 @@ packages: engines: {node: '>= 10'} dependencies: archiver-utils: 2.1.0 - async: 3.2.5 + async: 3.2.6 buffer-crc32: 0.2.13 readable-stream: 3.6.2 readdir-glob: 1.1.3 @@ -5101,7 +5263,7 @@ packages: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 is-array-buffer: 3.0.4 /array-flatten/1.1.1: @@ -5111,12 +5273,12 @@ packages: resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-object-atoms: 1.0.0 - get-intrinsic: 1.2.4 - is-string: 1.0.7 + get-intrinsic: 1.2.6 + is-string: 1.1.0 /array-union/2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} @@ -5126,9 +5288,9 @@ packages: resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-errors: 1.3.0 es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 @@ -5137,18 +5299,18 @@ packages: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-shim-unscopables: 1.0.2 /array.prototype.flatmap/1.3.2: resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-shim-unscopables: 1.0.2 /arraybuffer.prototype.slice/1.0.3: @@ -5156,11 +5318,11 @@ packages: engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 @@ -5184,8 +5346,8 @@ packages: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} - /async/3.2.5: - resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + /async/3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} /asynckit/0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -5213,8 +5375,8 @@ packages: fsevents: 2.3.2 dev: false - /aws-sdk/2.1599.0: - resolution: {integrity: sha512-jPb1LAN+s1TLTK+VR3TTJLr//sb3AhhT60Bm9jxB5G/fVeeRczXtBtixNpQ00gksQdkstILYLc9S6MuKMsksxA==} + /aws-sdk/2.1692.0: + resolution: {integrity: sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw==} engines: {node: '>= 10.0.0'} requiresBuild: true dependencies: @@ -5243,11 +5405,11 @@ packages: uuid: 3.3.2 xml2js: 0.4.19 - /axios/1.6.8: - resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} + /axios/1.7.9: + resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==} dependencies: - follow-redirects: 1.15.6 - form-data: 4.0.0 + follow-redirects: 1.15.9 + form-data: 4.0.1 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -5289,8 +5451,8 @@ packages: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} dev: true - /body-parser/1.20.2: - resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} + /body-parser/1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} dependencies: bytes: 3.1.2 @@ -5301,7 +5463,7 @@ packages: http-errors: 2.0.0 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.11.0 + qs: 6.13.0 raw-body: 2.5.2 type-is: 1.6.18 unpipe: 1.0.0 @@ -5317,25 +5479,25 @@ packages: dependencies: balanced-match: 1.0.2 - /braces/3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + /braces/3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} dependencies: - fill-range: 7.0.1 + fill-range: 7.1.1 /browser-stdout/1.3.1: resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} dev: true - /browserslist/4.23.0: - resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + /browserslist/4.24.2: + resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001610 - electron-to-chromium: 1.4.736 - node-releases: 2.0.14 - update-browserslist-db: 1.0.13_browserslist@4.23.0 + caniuse-lite: 1.0.30001688 + electron-to-chromium: 1.5.73 + node-releases: 2.0.19 + update-browserslist-db: 1.1.1_browserslist@4.24.2 dev: true /buffer-alloc-unsafe/1.1.0: @@ -5425,16 +5587,29 @@ packages: write-file-atomic: 3.0.3 dev: true - /call-bind/1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + /call-bind-apply-helpers/1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} engines: {node: '>= 0.4'} dependencies: - es-define-property: 1.0.0 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 + + /call-bind/1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + get-intrinsic: 1.2.6 set-function-length: 1.2.2 + /call-bound/1.0.2: + resolution: {integrity: sha512-0lk0PHFe/uz0vl527fG9CgdE9WdafjDbCXvBbs+LUv000TVt2Jjhqbs4Jwm8gz070w8xXyEAxrPOMullsxXeGg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + get-intrinsic: 1.2.6 + /callsites/3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -5442,13 +5617,14 @@ packages: /camelcase/5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} + dev: true /camelcase/6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - /caniuse-lite/1.0.30001610: - resolution: {integrity: sha512-QFutAY4NgaelojVMjY63o6XlZyORPaLfyMnsl3HgnWdJUcX6K0oaJymHjH8PT5Gk7sTm8rvC/c5COUQKXqmOMA==} + /caniuse-lite/1.0.30001688: + resolution: {integrity: sha512-Nmqpru91cuABu/DTCXbM2NSRHzM2uVHfPnhJ/1zEAJx/ILBRVmz3pzH4N7DZqbdG0gWClsCC05Oj0mJ/1AWMbA==} dev: true /cardinal/2.1.1: @@ -5470,7 +5646,7 @@ packages: '@aws-cdk/cloud-assembly-schema': 2.39.1 '@aws-cdk/cx-api': 2.39.1 archiver: 5.3.2 - aws-sdk: 2.1599.0 + aws-sdk: 2.1692.0 glob: 7.2.3 mime: 2.6.0 yargs: 16.2.0 @@ -5485,17 +5661,17 @@ packages: '@cdktf/hcl2cdk': 0.19.2 '@cdktf/hcl2json': 0.19.2 '@inquirer/prompts': 2.3.1 - '@sentry/node': 7.110.1 - cdktf: 0.19.2_constructs@10.3.0 + '@sentry/node': 7.120.2 + cdktf: 0.19.2_constructs@10.4.2 ci-info: 3.9.0 - codemaker: 1.97.0 - constructs: 10.3.0 - cross-spawn: 7.0.3 + codemaker: 1.105.0 + constructs: 10.4.2 + cross-spawn: 7.0.6 https-proxy-agent: 5.0.1 ink-select-input: 4.2.2_ink@3.2.0+react@17.0.2 ink-table: 3.1.0_ink@3.2.0+react@17.0.2 - jsii: 5.4.3 - jsii-pacmak: 1.97.0 + jsii: 5.7.1 + jsii-pacmak: 1.105.0 minimatch: 5.1.6 node-fetch: 2.7.0 pidtree: 0.6.0 @@ -5504,26 +5680,24 @@ packages: xml-js: 1.6.11 yargs: 17.7.2 yoga-layout-prebuilt: 1.10.0 - zod: 3.22.4 + zod: 3.24.1 transitivePeerDependencies: - '@types/react' - bufferutil - debug - encoding - ink + - jsii-rosetta - react - supports-color - utf-8-validate - /cdktf/0.19.2_constructs@10.3.0: + /cdktf/0.19.2_constructs@10.4.2: resolution: {integrity: sha512-FHOERDO7i2g/+pUaaZCVDKsbXEBtWYOgELL1UKjNp37DyEmtFlltdsgutVfouoil0C7W5za2IydD6sSeoH5aUw==} peerDependencies: constructs: ^10.0.25 dependencies: - archiver: 5.3.2 - constructs: 10.3.0 - json-stable-stringify: 1.1.1 - semver: 7.6.0 + constructs: 10.4.2 bundledDependencies: - archiver - json-stable-stringify @@ -5551,19 +5725,19 @@ packages: deep-eql: 3.0.1 get-func-name: 2.0.2 pathval: 1.1.1 - type-detect: 4.0.8 + type-detect: 4.1.0 - /chai/4.4.1: - resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} + /chai/4.5.0: + resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} engines: {node: '>=4'} dependencies: assertion-error: 1.1.0 check-error: 1.0.3 - deep-eql: 4.1.3 + deep-eql: 4.1.4 get-func-name: 2.0.2 loupe: 2.3.7 pathval: 1.1.1 - type-detect: 4.0.8 + type-detect: 4.1.0 dev: true /chalk/2.4.2: @@ -5596,9 +5770,9 @@ packages: /child-process-ext/2.1.1: resolution: {integrity: sha512-0UQ55f51JBkOFa+fvR76ywRzxiPwQS3Xe8oe5bZRphpv+dIMeerW5Zn5e4cUy4COJwVtJyU0R79RMnw+aCqmGA==} dependencies: - cross-spawn: 6.0.5 + cross-spawn: 6.0.6 es5-ext: 0.10.64 - log: 6.3.1 + log: 6.3.2 split2: 3.2.2 stream-promise: 3.2.0 dev: true @@ -5607,26 +5781,19 @@ packages: resolution: {integrity: sha512-oBePsLbQpTJFxzwyCvs9yWWF0OEM6vGGepHwt1stqmX7QQqOuDc8j2ywdvAs9Tvi44TT7d9ackqhR4Q10l1u8w==} engines: {node: '>=8.0'} dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 es5-ext: 0.10.64 - log: 6.3.1 + log: 6.3.2 split2: 3.2.2 stream-promise: 3.2.0 dev: true - /child-process-promise/2.2.1: - resolution: {integrity: sha512-Fi4aNdqBsr0mv+jgWxcZ/7rAIC2mgihrptyVI4foh/rrjY/3BNjfP9+oaiFx/fzim+1ZyCNBae0DlyfQhSugog==} - dependencies: - cross-spawn: 4.0.2 - node-version: 1.2.0 - promise-polyfill: 6.1.0 - /chokidar/3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} dependencies: anymatch: 3.1.3 - braces: 3.0.2 + braces: 3.0.3 glob-parent: 5.1.2 is-binary-path: 2.1.0 is-glob: 4.0.3 @@ -5641,7 +5808,7 @@ packages: engines: {node: '>= 8.10.0'} dependencies: anymatch: 3.1.3 - braces: 3.0.2 + braces: 3.0.3 glob-parent: 5.1.2 is-binary-path: 2.1.0 is-glob: 4.0.3 @@ -5698,8 +5865,8 @@ packages: d: 1.0.2 es5-ext: 0.10.64 es6-iterator: 2.0.3 - memoizee: 0.4.15 - timers-ext: 0.1.7 + memoizee: 0.4.17 + timers-ext: 0.1.8 dev: true /cli-cursor/2.1.0: @@ -5724,8 +5891,8 @@ packages: es5-ext: 0.10.64 mute-stream: 0.0.8 process-utils: 4.0.0 - timers-ext: 0.1.7 - type: 2.7.2 + timers-ext: 0.1.8 + type: 2.7.3 dev: true /cli-progress/3.12.0: @@ -5748,7 +5915,7 @@ packages: dependencies: cli-color: 2.0.4 es5-ext: 0.10.64 - sprintf-kit: 2.0.1 + sprintf-kit: 2.0.2 supports-color: 6.1.0 dev: true @@ -5781,6 +5948,7 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 6.2.0 + dev: true /cliui/7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} @@ -5821,8 +5989,8 @@ packages: dependencies: convert-to-spaces: 1.0.2 - /codemaker/1.97.0: - resolution: {integrity: sha512-24ocuOL6bD9imoQqrYJOwPuL05HlEgdD8NyrtLWDUk2T94I3jwvw9pEmaj9Q4nW9tj9EEM3Ko1zV8mvPr0+mcA==} + /codemaker/1.105.0: + resolution: {integrity: sha512-eTePuHlpXNDD4P1vdEv61j+O4f7cnzTSXfbl5bsz+dp8TC95B4YKUS7A/MfR39/CMfqjPn3+KjnCubRbqv5RMA==} engines: {node: '>= 14.17.0'} dependencies: camelcase: 6.3.0 @@ -5884,23 +6052,13 @@ packages: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} dev: true - /commonmark/0.30.0: - resolution: {integrity: sha512-j1yoUo4gxPND1JWV9xj5ELih0yMv1iCWDG6eEQIPLSWLxzCXiFoyS7kvB+WwU+tZMf4snwJMMtaubV0laFpiBA==} - hasBin: true - dependencies: - entities: 2.0.3 - mdurl: 1.0.1 - minimist: 1.2.8 - string.prototype.repeat: 0.2.0 - - /commonmark/0.31.0: - resolution: {integrity: sha512-nuDsQ34gjmgAqjyIz6mbRWBW/XPE9wsBempAMBk2V/AA88ekztjTM46oi07J6c6Y/2Y8TdYCZi9L0pIBt/oMZw==} + /commonmark/0.31.2: + resolution: {integrity: sha512-2fRLTyb9r/2835k5cwcAwOj0DEc44FARnMp5veGsJ+mEAZdi52sNopLu07ZyElQUz058H43whzlERDIaaSw4rg==} hasBin: true dependencies: entities: 3.0.1 mdurl: 1.0.1 minimist: 1.2.8 - string.prototype.repeat: 1.0.0 /component-emitter/1.3.1: resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} @@ -5927,16 +6085,15 @@ packages: date-fns: 2.30.0 lodash: 4.17.21 rxjs: 7.8.1 - shell-quote: 1.8.1 + shell-quote: 1.8.2 spawn-command: 0.0.2 supports-color: 8.1.1 tree-kill: 1.2.2 yargs: 17.7.2 dev: true - /constructs/10.3.0: - resolution: {integrity: sha512-vbK8i3rIb/xwZxSpTjz3SagHn1qq9BChLEfy5Hf6fB3/2eFbrwt2n9kHwQcS0CPTRBesreeAcsJfMq2229FnbQ==} - engines: {node: '>= 16.14.0'} + /constructs/10.4.2: + resolution: {integrity: sha512-wsNxBlAott2qg8Zv87q3eYZYgheb9lchtBfjHzzLHtXbttwSrHPs1NNQbBrmbb1YZvYg2+Vh0Dor76w4mFxJkA==} /constructs/3.4.344: resolution: {integrity: sha512-Qq3upn44oGdvgasHUKWVFsrynyYrtVRd9fd8ko9cJOrFzx9eCm3iI4bhBryQqaISdausbTYUOXmoEe/YSJ16Nw==} @@ -5968,8 +6125,8 @@ packages: /cookie-signature/1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - /cookie/0.6.0: - resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + /cookie/0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} engines: {node: '>= 0.6'} /cookiejar/2.1.4: @@ -6018,7 +6175,7 @@ packages: resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==} engines: {node: '>=12.0.0'} dependencies: - luxon: 3.4.4 + luxon: 3.5.0 dev: false /cross-env/7.0.3: @@ -6026,7 +6183,7 @@ packages: engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} hasBin: true dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 dev: true /cross-fetch/3.1.5: @@ -6036,14 +6193,8 @@ packages: transitivePeerDependencies: - encoding - /cross-spawn/4.0.2: - resolution: {integrity: sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==} - dependencies: - lru-cache: 4.1.5 - which: 1.3.1 - - /cross-spawn/6.0.5: - resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} + /cross-spawn/6.0.6: + resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==} engines: {node: '>=4.8'} dependencies: nice-try: 1.0.5 @@ -6053,8 +6204,8 @@ packages: which: 1.3.1 dev: true - /cross-spawn/7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + /cross-spawn/7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} dependencies: path-key: 3.1.1 @@ -6070,46 +6221,46 @@ packages: engines: {node: '>=0.12'} dependencies: es5-ext: 0.10.64 - type: 2.7.2 + type: 2.7.3 dev: true /data-view-buffer/1.0.1: resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 - is-data-view: 1.0.1 + is-data-view: 1.0.2 /data-view-byte-length/1.0.1: resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 - is-data-view: 1.0.1 + is-data-view: 1.0.2 /data-view-byte-offset/1.0.0: resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 - is-data-view: 1.0.1 + is-data-view: 1.0.2 /date-fns/2.30.0: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} dependencies: - '@babel/runtime': 7.24.5 + '@babel/runtime': 7.26.0 dev: true /date-format/4.0.14: resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==} engines: {node: '>=4.0'} - /dayjs/1.11.10: - resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} + /dayjs/1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} dev: true /debug/2.6.9: @@ -6122,7 +6273,7 @@ packages: dependencies: ms: 2.1.3 - /debug/4.3.4: + /debug/4.3.4_supports-color@8.1.1: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} peerDependencies: @@ -6132,9 +6283,11 @@ packages: optional: true dependencies: ms: 2.1.2 + supports-color: 8.1.1 + dev: true - /debug/4.3.4_supports-color@8.1.1: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + /debug/4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -6142,12 +6295,24 @@ packages: supports-color: optional: true dependencies: - ms: 2.1.2 + ms: 2.1.3 + + /debug/4.4.0_supports-color@8.1.1: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 supports-color: 8.1.1 /decamelize/1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} + dev: true /decamelize/4.0.0: resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} @@ -6221,13 +6386,13 @@ packages: resolution: {integrity: sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==} engines: {node: '>=0.12'} dependencies: - type-detect: 4.0.8 + type-detect: 4.1.0 - /deep-eql/4.1.3: - resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + /deep-eql/4.1.4: + resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} engines: {node: '>=6'} dependencies: - type-detect: 4.0.8 + type-detect: 4.1.0 dev: true /deep-equal/2.2.3: @@ -6235,23 +6400,23 @@ packages: engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 + call-bind: 1.0.8 es-get-iterator: 1.1.3 - get-intrinsic: 1.2.4 - is-arguments: 1.1.1 + get-intrinsic: 1.2.6 + is-arguments: 1.2.0 is-array-buffer: 3.0.4 - is-date-object: 1.0.5 - is-regex: 1.1.4 + is-date-object: 1.1.0 + is-regex: 1.2.1 is-shared-array-buffer: 1.0.3 isarray: 2.0.5 object-is: 1.1.6 object-keys: 1.1.1 object.assign: 4.1.5 - regexp.prototype.flags: 1.5.2 - side-channel: 1.0.6 - which-boxed-primitive: 1.0.2 + regexp.prototype.flags: 1.5.3 + side-channel: 1.1.0 + which-boxed-primitive: 1.1.0 which-collection: 1.0.2 - which-typed-array: 1.1.15 + which-typed-array: 1.1.16 /deep-extend/0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} @@ -6288,16 +6453,16 @@ packages: es5-ext: 0.10.64 event-emitter: 0.3.5 next-tick: 1.1.0 - timers-ext: 0.1.7 + timers-ext: 0.1.8 dev: true /define-data-property/1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} dependencies: - es-define-property: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 - gopd: 1.0.1 + gopd: 1.2.0 /define-lazy-prop/2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} @@ -6342,12 +6507,13 @@ packages: resolution: {integrity: sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==} engines: {node: '>=0.10.0'} - /detect-port/1.5.1: - resolution: {integrity: sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==} + /detect-port/1.6.1: + resolution: {integrity: sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==} + engines: {node: '>= 4.0.0'} hasBin: true dependencies: address: 1.2.2 - debug: 4.3.4 + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -6403,13 +6569,13 @@ packages: engines: {node: '>=10'} dev: true - /downlevel-dts/0.11.0: - resolution: {integrity: sha512-vo835pntK7kzYStk7xUHDifiYJvXxVhUapt85uk2AI94gUUAQX9HNRtrcMHNSc3YHJUEHGbYIGsM99uIbgAtxw==} - hasBin: true + /dunder-proto/1.0.0: + resolution: {integrity: sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==} + engines: {node: '>= 0.4'} dependencies: - semver: 7.6.0 - shelljs: 0.8.5 - typescript: 5.6.0-dev.20240604 + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 /duration/0.2.2: resolution: {integrity: sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==} @@ -6438,10 +6604,10 @@ packages: engines: {node: '>=0.10.0'} hasBin: true dependencies: - jake: 10.8.7 + jake: 10.9.2 - /electron-to-chromium/1.4.736: - resolution: {integrity: sha512-Rer6wc3ynLelKNM4lOCg7/zPQj8tPOCB2hzD32PX9wd3hgRRi9MxEbmkFCokzcEhRVMiOVLjnL9ig9cefJ+6+Q==} + /electron-to-chromium/1.5.73: + resolution: {integrity: sha512-8wGNxG9tAG5KhGd3eeA0o6ixhiNdgr0DcHWm85XPCphwZgD1lIEoi6t3VERayWao7SF7AAZTw6oARGJeVjH8Kg==} dev: true /emoji-regex/7.0.3: @@ -6458,14 +6624,15 @@ packages: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} + /encodeurl/2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + /end-of-stream/1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} dependencies: once: 1.4.0 - /entities/2.0.3: - resolution: {integrity: sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==} - /entities/3.0.1: resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==} engines: {node: '>=0.12'} @@ -6476,62 +6643,60 @@ packages: is-arrayish: 0.2.1 dev: true - /es-abstract/1.23.3: - resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + /es-abstract/1.23.5: + resolution: {integrity: sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==} engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.1 arraybuffer.prototype.slice: 1.0.3 available-typed-arrays: 1.0.7 - call-bind: 1.0.7 + call-bind: 1.0.8 data-view-buffer: 1.0.1 data-view-byte-length: 1.0.1 data-view-byte-offset: 1.0.0 - es-define-property: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 es-object-atoms: 1.0.0 es-set-tostringtag: 2.0.3 - es-to-primitive: 1.2.1 + es-to-primitive: 1.3.0 function.prototype.name: 1.1.6 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 get-symbol-description: 1.0.2 - globalthis: 1.0.3 - gopd: 1.0.1 + globalthis: 1.0.4 + gopd: 1.2.0 has-property-descriptors: 1.0.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 + has-proto: 1.2.0 + has-symbols: 1.1.0 hasown: 2.0.2 internal-slot: 1.0.7 is-array-buffer: 3.0.4 is-callable: 1.2.7 - is-data-view: 1.0.1 + is-data-view: 1.0.2 is-negative-zero: 2.0.3 - is-regex: 1.1.4 + is-regex: 1.2.1 is-shared-array-buffer: 1.0.3 - is-string: 1.0.7 + is-string: 1.1.0 is-typed-array: 1.1.13 is-weakref: 1.0.2 - object-inspect: 1.13.1 + object-inspect: 1.13.3 object-keys: 1.1.1 object.assign: 4.1.5 - regexp.prototype.flags: 1.5.2 - safe-array-concat: 1.1.2 - safe-regex-test: 1.0.3 - string.prototype.trim: 1.2.9 - string.prototype.trimend: 1.0.8 + regexp.prototype.flags: 1.5.3 + safe-array-concat: 1.1.3 + safe-regex-test: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 string.prototype.trimstart: 1.0.8 typed-array-buffer: 1.0.2 typed-array-byte-length: 1.0.1 - typed-array-byte-offset: 1.0.2 - typed-array-length: 1.0.6 + typed-array-byte-offset: 1.0.3 + typed-array-length: 1.0.7 unbox-primitive: 1.0.2 - which-typed-array: 1.1.15 + which-typed-array: 1.1.16 - /es-define-property/1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + /es-define-property/1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.4 /es-errors/1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} @@ -6540,13 +6705,13 @@ packages: /es-get-iterator/1.1.3: resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - is-arguments: 1.1.1 + call-bind: 1.0.8 + get-intrinsic: 1.2.6 + has-symbols: 1.1.0 + is-arguments: 1.2.0 is-map: 2.0.3 is-set: 2.0.3 - is-string: 1.0.7 + is-string: 1.1.0 isarray: 2.0.5 stop-iteration-iterator: 1.0.0 @@ -6560,7 +6725,7 @@ packages: resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 has-tostringtag: 1.0.2 hasown: 2.0.2 @@ -6569,13 +6734,13 @@ packages: dependencies: hasown: 2.0.2 - /es-to-primitive/1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + /es-to-primitive/1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} dependencies: is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.0.4 + is-date-object: 1.1.0 + is-symbol: 1.1.1 /es5-ext/0.10.64: resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} @@ -6609,7 +6774,7 @@ packages: es6-iterator: 2.0.3 es6-symbol: 3.1.4 event-emitter: 0.3.5 - type: 2.7.2 + type: 2.7.3 dev: true /es6-symbol/3.1.4: @@ -6629,8 +6794,8 @@ packages: es6-symbol: 3.1.4 dev: true - /escalade/3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + /escalade/3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} /escape-html/1.0.3: @@ -6648,23 +6813,23 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - /eslint-config-prettier/8.3.0_eslint@8.57.0: + /eslint-config-prettier/8.3.0_eslint@8.57.1: resolution: {integrity: sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.57.0 + eslint: 8.57.1 /eslint-import-resolver-node/0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: debug: 3.2.7 - is-core-module: 2.13.1 + is-core-module: 2.15.1 resolve: 1.22.8 - /eslint-module-utils/2.8.1_eslint@8.57.0: - resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} + /eslint-module-utils/2.12.0_eslint@8.57.1: + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} peerDependencies: eslint: '*' @@ -6673,34 +6838,36 @@ packages: optional: true dependencies: debug: 3.2.7 - eslint: 8.57.0 + eslint: 8.57.1 - /eslint-plugin-import/2.29.1_eslint@8.57.0: - resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} + /eslint-plugin-import/2.31.0_eslint@8.57.1: + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} engines: {node: '>=4'} peerDependencies: - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 dependencies: + '@rtsao/scc': 1.1.0 array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.57.0 + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1_eslint@8.57.0 + eslint-module-utils: 2.12.0_eslint@8.57.1 hasown: 2.0.2 - is-core-module: 2.13.1 + is-core-module: 2.15.1 is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.8 object.groupby: 1.0.3 object.values: 1.2.0 semver: 6.3.1 + string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 - /eslint-plugin-prettier/3.4.0_ddm2pio5nc2sobczsauzpxvcae: + /eslint-plugin-prettier/3.4.0_vlkgbgdgpnhgz7gjlll7w26l7y: resolution: {integrity: sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==} engines: {node: '>=6.0.0'} peerDependencies: @@ -6711,23 +6878,23 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.57.0 - eslint-config-prettier: 8.3.0_eslint@8.57.0 + eslint: 8.57.1 + eslint-config-prettier: 8.3.0_eslint@8.57.1 prettier: 2.3.0 prettier-linter-helpers: 1.0.0 - /eslint-plugin-unicorn/44.0.2_eslint@8.57.0: + /eslint-plugin-unicorn/44.0.2_eslint@8.57.1: resolution: {integrity: sha512-GLIDX1wmeEqpGaKcnMcqRvMVsoabeF0Ton0EX4Th5u6Kmf7RM9WBl705AXFEsns56ESkEs0uyelLuUTvz9Tr0w==} engines: {node: '>=14.18'} peerDependencies: eslint: '>=8.23.1' dependencies: - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.25.9 ci-info: 3.9.0 clean-regexp: 1.0.0 - eslint: 8.57.0 - eslint-utils: 3.0.0_eslint@8.57.0 - esquery: 1.5.0 + eslint: 8.57.1 + eslint-utils: 3.0.0_eslint@8.57.1 + esquery: 1.6.0 indent-string: 4.0.0 is-builtin-module: 3.2.1 lodash: 4.17.21 @@ -6735,7 +6902,7 @@ packages: read-pkg-up: 7.0.1 regexp-tree: 0.1.27 safe-regex: 2.1.1 - semver: 7.6.0 + semver: 7.6.3 strip-indent: 3.0.0 dev: true @@ -6760,13 +6927,13 @@ packages: eslint-visitor-keys: 1.3.0 dev: true - /eslint-utils/3.0.0_eslint@8.57.0: + /eslint-utils/3.0.0_eslint@8.57.1: resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: - eslint: 8.57.0 + eslint: 8.57.1 eslint-visitor-keys: 2.1.0 dev: true @@ -6787,19 +6954,20 @@ packages: /eslint/6.8.0: resolution: {integrity: sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==} engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true dependencies: - '@babel/code-frame': 7.24.2 + '@babel/code-frame': 7.26.2 ajv: 6.12.6 chalk: 2.4.2 - cross-spawn: 6.0.5 - debug: 4.3.4 + cross-spawn: 6.0.6 + debug: 4.4.0 doctrine: 3.0.0 eslint-scope: 5.1.1 eslint-utils: 1.4.3 eslint-visitor-keys: 1.3.0 espree: 6.2.1 - esquery: 1.5.0 + esquery: 1.6.0 esutils: 2.0.3 file-entry-cache: 5.0.1 functional-red-black-tree: 1.0.1 @@ -6830,29 +6998,30 @@ packages: - supports-color dev: true - /eslint/8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + /eslint/8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0_eslint@8.57.0 - '@eslint-community/regexpp': 4.10.0 + '@eslint-community/eslint-utils': 4.4.1_eslint@8.57.1 + '@eslint-community/regexpp': 4.12.1 '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 + '@ungap/structured-clone': 1.2.1 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 + cross-spawn: 7.0.6 + debug: 4.4.0 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.5.0 + esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 @@ -6860,7 +7029,7 @@ packages: glob-parent: 6.0.2 globals: 13.24.0 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 @@ -6870,7 +7039,7 @@ packages: lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.3 + optionator: 0.9.4 strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: @@ -6891,7 +7060,7 @@ packages: d: 1.0.2 es5-ext: 0.10.64 event-emitter: 0.3.5 - type: 2.7.2 + type: 2.7.3 dev: true /espree/6.2.1: @@ -6907,8 +7076,8 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2_acorn@8.11.3 + acorn: 8.14.0 + acorn-jsx: 5.3.2_acorn@8.14.0 eslint-visitor-keys: 3.4.3 /esprima/4.0.1: @@ -6916,8 +7085,8 @@ packages: engines: {node: '>=4'} hasBin: true - /esquery/1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + /esquery/1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} dependencies: estraverse: 5.3.0 @@ -6972,7 +7141,7 @@ packages: resolution: {integrity: sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==} engines: {node: ^8.12.0 || >=9.7.0} dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 get-stream: 5.2.0 is-stream: 2.0.1 merge-stream: 2.0.0 @@ -6987,7 +7156,7 @@ packages: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 get-stream: 6.0.1 human-signals: 2.1.0 is-stream: 2.0.1 @@ -7005,36 +7174,36 @@ packages: resolution: {integrity: sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ==} dev: false - /express/4.19.2: - resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} + /express/4.21.2: + resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.2 + body-parser: 1.20.3 content-disposition: 0.5.4 content-type: 1.0.5 - cookie: 0.6.0 + cookie: 0.7.1 cookie-signature: 1.0.6 debug: 2.6.9 depd: 2.0.0 - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 1.2.0 + finalhandler: 1.3.1 fresh: 0.5.2 http-errors: 2.0.0 - merge-descriptors: 1.0.1 + merge-descriptors: 1.0.3 methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 - path-to-regexp: 0.1.7 + path-to-regexp: 0.1.12 proxy-addr: 2.0.7 - qs: 6.11.0 + qs: 6.13.0 range-parser: 1.2.1 safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 + send: 0.19.0 + serve-static: 1.16.2 setprototypeof: 1.2.0 statuses: 2.0.1 type-is: 1.6.18 @@ -7045,7 +7214,7 @@ packages: resolution: {integrity: sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==} engines: {node: '>=0.10.0'} dependencies: - mime-db: 1.52.0 + mime-db: 1.53.0 dev: true /ext-name/5.0.0: @@ -7059,7 +7228,7 @@ packages: /ext/1.7.0: resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} dependencies: - type: 2.7.2 + type: 2.7.3 dev: true /external-editor/3.1.0: @@ -7075,7 +7244,7 @@ packages: engines: {node: '>= 10.17.0'} hasBin: true dependencies: - debug: 4.3.4 + debug: 4.4.0 get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -7087,33 +7256,30 @@ packages: resolution: {integrity: sha512-RrWKFSSA/aNLP0g3o2WW1Zez7/MnMr7xkiZmoCfAGZmdkDQZ6l2KtuXHN5XjdvpRjDl8+3vf+Rrtl06Z352+Mw==} dev: true - /fancy-test/3.0.14: - resolution: {integrity: sha512-FkiDltQA8PBZzw5tUnMrP1QtwIdNQWxxbZK5C22M9wu6HfFNciwkG3D9siT4l4s1fBTDaEG+Fdkbpi9FDTxtrg==} + /fancy-test/3.0.16: + resolution: {integrity: sha512-y1xZFpyYbE2TMiT+agOW2Emv8gr73zvDrKKbcXc8L+gMyIVJFn71cc4ICfzu2zEXjHirpHpdDJN0JBX99wwDXQ==} engines: {node: '>=18.0.0'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. dependencies: '@types/chai': 4.2.18 - '@types/lodash': 4.17.0 - '@types/node': 18.19.31 + '@types/lodash': 4.17.13 + '@types/node': 18.19.68 '@types/sinon': 10.0.0 lodash: 4.17.21 mock-stdin: 1.0.0 - nock: 13.5.4 + nock: 13.5.6 sinon: 16.1.3 stdout-stderr: 0.1.13 transitivePeerDependencies: - supports-color dev: true - /fast-check/3.17.1: - resolution: {integrity: sha512-jIKXJVe6ZO0SpwEgVtEVujTf8TwjI9wMXFJCjsDHUB3RroUbXBgF4kOSz3A7MW0UR26aqsoB8i9O2mjtjERAiA==} + /fast-check/3.23.1: + resolution: {integrity: sha512-u/MudsoQEgBUZgR5N1v87vEgybeVYus9VnDVaIkxkkGP2jt54naghQ3PCQHJiogS8U/GavZCUPFfx3Xkp+NaHw==} engines: {node: '>=8.0.0'} dependencies: pure-rand: 6.1.0 - /fast-decode-uri-component/1.0.1: - resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} - dev: false - /fast-deep-equal/3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -7128,7 +7294,7 @@ packages: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.8 /fast-json-stable-stringify/2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -7136,16 +7302,13 @@ packages: /fast-levenshtein/2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - /fast-querystring/1.1.2: - resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} - dependencies: - fast-decode-uri-component: 1.0.1 - dev: false - /fast-safe-stringify/2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} dev: true + /fast-uri/3.0.3: + resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==} + /fastest-levenshtein/1.0.16: resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} engines: {node: '>= 4.9.1'} @@ -7233,18 +7396,18 @@ packages: engines: {node: '>= 0.4.0'} dev: true - /fill-range/7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + /fill-range/7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 - /finalhandler/1.2.0: - resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} + /finalhandler/1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} dependencies: debug: 2.6.9 - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 parseurl: 1.3.3 @@ -7260,10 +7423,8 @@ packages: pkg-dir: 4.2.0 dev: true - /find-my-way-ts/0.1.1: - resolution: {integrity: sha512-nXUdq29JRQ1tYa1/n+DHTVChMARJHz+gi7sDZibwQukzHP7Hrr6s+sxKbaIM8xB3LzhSBJy5yLb0JhIUmHmOiA==} - dependencies: - fast-querystring: 1.1.2 + /find-my-way-ts/0.1.5: + resolution: {integrity: sha512-4GOTMrpGQVzsCH2ruUn2vmwzV/02zF4q+ybhCIrw/Rkt3L8KWcycdC6aJMctJzwN4fXD4SD5F/4B9Sksh5rE0A==} dev: false /find-requires/1.0.0: @@ -7286,6 +7447,7 @@ packages: dependencies: locate-path: 5.0.0 path-exists: 4.0.0 + dev: true /find-up/5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} @@ -7307,7 +7469,7 @@ packages: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: - flatted: 3.3.1 + flatted: 3.3.2 keyv: 4.5.4 rimraf: 3.0.2 @@ -7320,11 +7482,11 @@ packages: resolution: {integrity: sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==} dev: true - /flatted/3.3.1: - resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + /flatted/3.3.2: + resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} - /follow-redirects/1.15.6: - resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + /follow-redirects/1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -7341,19 +7503,19 @@ packages: resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} engines: {node: '>=8.0.0'} dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 signal-exit: 3.0.7 dev: true - /foreground-child/3.1.1: - resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + /foreground-child/3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 signal-exit: 4.1.0 - /form-data/4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + /form-data/4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} engines: {node: '>= 6'} dependencies: asynckit: 0.4.0 @@ -7367,15 +7529,15 @@ packages: dezalgo: 1.0.4 hexoid: 1.0.0 once: 1.4.0 - qs: 6.12.1 + qs: 6.13.1 dev: true /forwarded/0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} - /fp-ts/2.16.5: - resolution: {integrity: sha512-N8T8PwMSeTKKtkm9lkj/zSTAnPC/aJIIrQhnHxxkL0KLsRCNUPANksJOlMXxcKKCo7H1ORP3No9EMD+fP0tsdA==} + /fp-ts/2.16.9: + resolution: {integrity: sha512-+I2+FnVB+tVaxcYyQkHUq7ZdKScaBlX53A41mxQtpIccsfyv8PzdzP7fzp2AY832T4aoK6UZ5WRX/ebGd8uZuQ==} dev: false /fresh/0.5.2: @@ -7432,17 +7594,18 @@ packages: /fs.realpath/1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - /fs2/0.3.9: - resolution: {integrity: sha512-WsOqncODWRlkjwll+73bAxVW3JPChDgaPX3DT4iTTm73UmG4VgALa7LaFblP232/DN60itkOrPZ8kaP1feksGQ==} + /fs2/0.3.15: + resolution: {integrity: sha512-T684iG2bR/3g5byqXvYYnJyqkXA7MQdlJx5DvCe0BJ5CH9aMRRc4C11bl75D1MnypvERdJ7Cft5BFpU/eClCMw==} engines: {node: '>=6'} dependencies: d: 1.0.2 deferred: 0.7.11 es5-ext: 0.10.64 event-emitter: 0.3.5 - ignore: 5.3.1 - memoizee: 0.4.15 - type: 2.7.2 + ext: 1.7.0 + ignore: 5.3.2 + memoizee: 0.4.17 + type: 2.7.3 dev: true /fsevents/2.3.2: @@ -7467,9 +7630,9 @@ packages: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 functions-have-names: 1.2.3 /functional-red-black-tree/1.0.1: @@ -7491,15 +7654,20 @@ packages: /get-func-name/2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - /get-intrinsic/1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + /get-intrinsic/1.2.6: + resolution: {integrity: sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==} engines: {node: '>= 0.4'} dependencies: + call-bind-apply-helpers: 1.0.1 + dunder-proto: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 + es-object-atoms: 1.0.0 function-bind: 1.1.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 + gopd: 1.2.0 + has-symbols: 1.1.0 hasown: 2.0.2 + math-intrinsics: 1.0.0 /get-package-type/0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} @@ -7527,7 +7695,7 @@ packages: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} dependencies: - pump: 3.0.0 + pump: 3.0.2 /get-stream/6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} @@ -7537,9 +7705,9 @@ packages: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 /github-from-package/0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} @@ -7556,19 +7724,20 @@ packages: dependencies: is-glob: 4.0.3 - /glob/10.3.12: - resolution: {integrity: sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==} - engines: {node: '>=16 || 14 >=14.17'} + /glob/10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true dependencies: - foreground-child: 3.1.1 - jackspeak: 2.3.6 - minimatch: 9.0.4 - minipass: 7.0.4 - path-scurry: 1.10.2 + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 /glob/7.2.0: resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + deprecated: Glob versions prior to v9 are no longer supported dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -7580,6 +7749,7 @@ packages: /glob/7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -7615,11 +7785,12 @@ packages: dependencies: type-fest: 0.20.2 - /globalthis/1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + /globalthis/1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} dependencies: define-properties: 1.2.1 + gopd: 1.2.0 /globby/11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} @@ -7628,14 +7799,13 @@ packages: array-union: 2.1.0 dir-glob: 3.0.1 fast-glob: 3.3.2 - ignore: 5.3.1 + ignore: 5.3.2 merge2: 1.4.1 slash: 3.0.0 - /gopd/1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} - dependencies: - get-intrinsic: 1.2.4 + /gopd/1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} /got/11.8.6: resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} @@ -7666,48 +7836,48 @@ packages: lodash: 4.17.21 dev: true - /graphology-types/0.24.7: - resolution: {integrity: sha512-tdcqOOpwArNjEr0gNQKCXwaNCWnQJrog14nJNQPeemcLnXQUUGrsCWpWkVKt46zLjcS6/KGoayeJfHHyPDlvwA==} + /graphology-types/0.24.8: + resolution: {integrity: sha512-hDRKYXa8TsoZHjgEaysSRyPdT6uB78Ci8WnjgbStlQysz7xR52PInxNsmnB7IBOM1BhikxkNyCVEFgmPKnpx3Q==} - /graphology/0.25.4_graphology-types@0.24.7: + /graphology/0.25.4_graphology-types@0.24.8: resolution: {integrity: sha512-33g0Ol9nkWdD6ulw687viS8YJQBxqG5LWII6FI6nul0pq6iM2t5EKquOTFDbyTblRB3O9I+7KX4xI8u5ffekAQ==} peerDependencies: graphology-types: '>=0.24.0' dependencies: events: 3.3.0 - graphology-types: 0.24.7 + graphology-types: 0.24.8 obliterator: 2.0.4 - /graphql-scalars/1.23.0_graphql@16.8.1: - resolution: {integrity: sha512-YTRNcwitkn8CqYcleKOx9IvedA8JIERn8BRq21nlKgOr4NEcTaWEG0sT+H92eF3ALTFbPgsqfft4cw+MGgv0Gg==} + /graphql-scalars/1.24.0_graphql@16.9.0: + resolution: {integrity: sha512-olbFN39m0XsHHESACUdd7jWU/lGxMMS1B7NZ8XqpqhKZrjBxzeGYAnQ4Ax//huYds771wb7gCznA+65QDuUa+g==} engines: {node: '>=10'} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 dependencies: - graphql: 16.8.1 - tslib: 2.6.2 + graphql: 16.9.0 + tslib: 2.8.1 dev: false - /graphql-subscriptions/2.0.0_graphql@16.8.1: + /graphql-subscriptions/2.0.0_graphql@16.9.0: resolution: {integrity: sha512-s6k2b8mmt9gF9pEfkxsaO1lTxaySfKoEJzEfmwguBbQ//Oq23hIXCfR1hm4kdh5hnR20RdwB+s3BCb+0duHSZA==} peerDependencies: graphql: ^15.7.2 || ^16.0.0 dependencies: - graphql: 16.8.1 + graphql: 16.9.0 iterall: 1.3.0 dev: false - /graphql-tag/2.12.6_graphql@16.8.1: + /graphql-tag/2.12.6_graphql@16.9.0: resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} engines: {node: '>=10'} peerDependencies: graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 dependencies: - graphql: 16.8.1 - tslib: 2.6.2 + graphql: 16.9.0 + tslib: 2.8.1 - /graphql/16.8.1: - resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==} + /graphql/16.9.0: + resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} /has-bigints/1.0.2: @@ -7724,21 +7894,23 @@ packages: /has-property-descriptors/1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} dependencies: - es-define-property: 1.0.0 + es-define-property: 1.0.1 - /has-proto/1.0.3: - resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + /has-proto/1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.0 - /has-symbols/1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + /has-symbols/1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} /has-tostringtag/1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} dependencies: - has-symbols: 1.0.3 + has-symbols: 1.1.0 /hasha/5.2.2: resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} @@ -7795,8 +7967,8 @@ packages: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} dependencies: - agent-base: 7.1.1 - debug: 4.3.4 + agent-base: 7.1.3 + debug: 4.4.0 transitivePeerDependencies: - supports-color dev: false @@ -7814,7 +7986,7 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -7823,17 +7995,17 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2_supports-color@8.1.1 - debug: 4.3.4_supports-color@8.1.1 + debug: 4.4.0_supports-color@8.1.1 transitivePeerDependencies: - supports-color dev: true - /https-proxy-agent/7.0.4: - resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} + /https-proxy-agent/7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} dependencies: - agent-base: 7.1.1 - debug: 4.3.4 + agent-base: 7.1.3 + debug: 4.4.0 transitivePeerDependencies: - supports-color dev: false @@ -7863,8 +8035,8 @@ packages: engines: {node: '>= 4'} dev: true - /ignore/5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + /ignore/5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} /immediate/3.0.6: @@ -7891,6 +8063,7 @@ packages: /inflight/1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. dependencies: once: 1.4.0 wrappy: 1.0.2 @@ -7901,8 +8074,8 @@ packages: /ini/1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - /ini/4.1.2: - resolution: {integrity: sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==} + /ini/4.1.3: + resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dev: false @@ -7990,7 +8163,7 @@ packages: type-fest: 0.12.0 widest-line: 3.1.0 wrap-ansi: 6.2.0 - ws: 7.5.9 + ws: 7.5.10 yoga-layout-prebuilt: 1.10.0 transitivePeerDependencies: - bufferutil @@ -8041,29 +8214,25 @@ packages: dependencies: es-errors: 1.3.0 hasown: 2.0.2 - side-channel: 1.0.6 - - /interpret/1.4.0: - resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} - engines: {node: '>= 0.10'} + side-channel: 1.1.0 /ipaddr.js/1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} - /is-arguments/1.1.1: - resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + /is-arguments/1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bound: 1.0.2 has-tostringtag: 1.0.2 /is-array-buffer/3.0.4: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bind: 1.0.8 + get-intrinsic: 1.2.6 /is-arrayish/0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -8072,8 +8241,15 @@ packages: /is-arrayish/0.3.2: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - /is-bigint/1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + /is-async-function/2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + + /is-bigint/1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} dependencies: has-bigints: 1.0.2 @@ -8083,11 +8259,11 @@ packages: dependencies: binary-extensions: 2.3.0 - /is-boolean-object/1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + /is-boolean-object/1.2.1: + resolution: {integrity: sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bound: 1.0.2 has-tostringtag: 1.0.2 /is-buffer/1.1.6: @@ -8116,21 +8292,25 @@ packages: dependencies: ci-info: 2.0.0 - /is-core-module/2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + /is-core-module/2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} dependencies: hasown: 2.0.2 - /is-data-view/1.0.1: - resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + /is-data-view/1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} engines: {node: '>= 0.4'} dependencies: + call-bound: 1.0.2 + get-intrinsic: 1.2.6 is-typed-array: 1.1.13 - /is-date-object/1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + /is-date-object/1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} dependencies: + call-bound: 1.0.2 has-tostringtag: 1.0.2 /is-docker/2.2.1: @@ -8142,6 +8322,12 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + /is-finalizationregistry/1.1.0: + resolution: {integrity: sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + /is-fullwidth-code-point/2.0.0: resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} engines: {node: '>=4'} @@ -8180,10 +8366,11 @@ packages: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} - /is-number-object/1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + /is-number-object/1.1.0: + resolution: {integrity: sha512-KVSZV0Dunv9DTPkhXwcZ3Q+tUc9TsaE1ZwX5J2WMvsSGS6Md8TFPun5uwh0yRdrNerI6vf/tbJxqSx4c1ZI1Lw==} engines: {node: '>= 0.4'} dependencies: + call-bind: 1.0.8 has-tostringtag: 1.0.2 /is-number/7.0.0: @@ -8208,12 +8395,14 @@ packages: resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} dev: true - /is-regex/1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + /is-regex/1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bound: 1.0.2 + gopd: 1.2.0 has-tostringtag: 1.0.2 + hasown: 2.0.2 /is-set/2.0.3: resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} @@ -8223,7 +8412,7 @@ packages: resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 /is-stream/1.1.0: resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} @@ -8234,23 +8423,26 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - /is-string/1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + /is-string/1.1.0: + resolution: {integrity: sha512-PlfzajuF9vSo5wErv3MJAKD/nqf9ngAs1NFQYm16nUYFO2IzxJ2hcm+IOCg+EEopdykNNUhVq5cz35cAUxU8+g==} engines: {node: '>= 0.4'} dependencies: + call-bind: 1.0.8 has-tostringtag: 1.0.2 - /is-symbol/1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + /is-symbol/1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} engines: {node: '>= 0.4'} dependencies: - has-symbols: 1.0.3 + call-bound: 1.0.2 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 /is-typed-array/1.1.13: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} dependencies: - which-typed-array: 1.1.15 + which-typed-array: 1.1.16 /is-typedarray/1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} @@ -8273,14 +8465,14 @@ packages: /is-weakref/1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 /is-weakset/2.0.3: resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bind: 1.0.8 + get-intrinsic: 1.2.6 /is-windows/1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} @@ -8305,20 +8497,20 @@ packages: /isexe/2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - /isomorphic-ws/4.0.1_ws@7.5.9: + /isomorphic-ws/4.0.1_ws@7.5.10: resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} peerDependencies: ws: '*' dependencies: - ws: 7.5.9 + ws: 7.5.10 dev: true - /isomorphic-ws/5.0.0_ws@8.12.0: + /isomorphic-ws/5.0.0_ws@8.17.1: resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} peerDependencies: ws: '*' dependencies: - ws: 8.12.0 + ws: 8.17.1 dev: false /istanbul-lib-coverage/3.2.2: @@ -8337,7 +8529,7 @@ packages: resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.26.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -8350,7 +8542,7 @@ packages: engines: {node: '>=8'} dependencies: archy: 1.0.0 - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 istanbul-lib-coverage: 3.2.2 p-map: 3.0.0 rimraf: 3.0.2 @@ -8370,7 +8562,7 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: - debug: 4.3.4 + debug: 4.4.0 istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -8388,20 +8580,19 @@ packages: /iterall/1.3.0: resolution: {integrity: sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==} - /jackspeak/2.3.6: - resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} - engines: {node: '>=14'} + /jackspeak/3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: '@pkgjs/parseargs': 0.11.0 - /jake/10.8.7: - resolution: {integrity: sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==} + /jake/10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} engines: {node: '>=10'} hasBin: true dependencies: - async: 3.2.5 + async: 3.2.6 chalk: 4.1.2 filelist: 1.0.4 minimatch: 3.1.2 @@ -8414,8 +8605,8 @@ packages: resolution: {integrity: sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==} engines: {node: '>= 0.6.0'} - /jose/4.15.5: - resolution: {integrity: sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==} + /jose/4.15.9: + resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==} /js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -8433,160 +8624,118 @@ packages: dependencies: argparse: 2.0.1 - /jsbi/3.2.5: - resolution: {integrity: sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ==} + /jsbi/4.3.0: + resolution: {integrity: sha512-SnZNcinB4RIcnEyZqFPdGPVgrg2AcnykiBy0sHVJQKHYeaLUvi3Exj+iaPpLnFVkDPZIV4U0yvgC9/R4uEAZ9g==} dev: false - /jsesc/2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} + /jsesc/3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} hasBin: true - /jsii-pacmak/1.97.0: - resolution: {integrity: sha512-ehaQS/hrWN+alBDN6BaYMocuIbZno1OiXhemW0tqQw0RZeH3noFaBIus78cbVz2uE0JXpWCqZf89VF32Uu5jeQ==} + /jsii-pacmak/1.105.0: + resolution: {integrity: sha512-oTQSoCfBite5cb+gwu2N6SWoJY/vteQSiCI24flo9UqR+PdGBlFDIJGPciPS6ZEC2v20et4YSJYyHFXFGfMQsQ==} engines: {node: '>= 14.17.0'} hasBin: true + peerDependencies: + jsii-rosetta: ^1.105.0 || ~5.2.0 || ~5.3.0 || ~5.4.0 || ~5.5.0 || ~5.6.0 dependencies: - '@jsii/check-node': 1.97.0 - '@jsii/spec': 1.97.0 + '@jsii/check-node': 1.105.0 + '@jsii/spec': 1.105.0 clone: 2.1.2 - codemaker: 1.97.0 - commonmark: 0.30.0 + codemaker: 1.105.0 + commonmark: 0.31.2 escape-string-regexp: 4.0.0 fs-extra: 10.1.0 - jsii-reflect: 1.97.0 - jsii-rosetta: 1.97.0 - semver: 7.6.0 + jsii-reflect: 1.105.0 + semver: 7.6.3 spdx-license-list: 6.9.0 xmlbuilder: 15.1.1 yargs: 16.2.0 - transitivePeerDependencies: - - supports-color - /jsii-reflect/1.97.0: - resolution: {integrity: sha512-E1oV/kliliFiqR9TxX2H5jgUObtq300Jk0kXBJKq06A/kXQk1rmCIoxnV5VFAxyhnPkmhgudpUIuzWh6STUdJg==} + /jsii-pacmak/1.105.0_jsii-rosetta@5.7.1: + resolution: {integrity: sha512-oTQSoCfBite5cb+gwu2N6SWoJY/vteQSiCI24flo9UqR+PdGBlFDIJGPciPS6ZEC2v20et4YSJYyHFXFGfMQsQ==} engines: {node: '>= 14.17.0'} hasBin: true + peerDependencies: + jsii-rosetta: ^1.105.0 || ~5.2.0 || ~5.3.0 || ~5.4.0 || ~5.5.0 || ~5.6.0 dependencies: - '@jsii/check-node': 1.97.0 - '@jsii/spec': 1.97.0 - chalk: 4.1.2 + '@jsii/check-node': 1.105.0 + '@jsii/spec': 1.105.0 + clone: 2.1.2 + codemaker: 1.105.0 + commonmark: 0.31.2 + escape-string-regexp: 4.0.0 fs-extra: 10.1.0 - oo-ascii-tree: 1.97.0 + jsii-reflect: 1.105.0 + jsii-rosetta: 5.7.1 + semver: 7.6.3 + spdx-license-list: 6.9.0 + xmlbuilder: 15.1.1 yargs: 16.2.0 - /jsii-rosetta/1.97.0: - resolution: {integrity: sha512-cxHGvwMrH7lt+O24afEI2ljMbCOtTBCRwQU7Bia87nLkYNpysfFrrz+vUGZ1yi/7DOxhQShm1i4VGJJ8UhvEAg==} + /jsii-reflect/1.105.0: + resolution: {integrity: sha512-YzlU3VJ0sBfsEqdVFYlzCB3MhW1J/3KuGec2MwBXZ8XMrZ69OODBtnDnoSTyRsnigqCnkuYTD27JhNcEic8v9g==} engines: {node: '>= 14.17.0'} hasBin: true dependencies: - '@jsii/check-node': 1.97.0 - '@jsii/spec': 1.97.0 - '@xmldom/xmldom': 0.8.10 - commonmark: 0.30.0 - fast-glob: 3.3.2 - jsii: 1.97.0 - semver: 7.6.0 - semver-intersect: 1.5.0 - stream-json: 1.8.0 - typescript: 3.9.10 - workerpool: 6.5.1 + '@jsii/check-node': 1.105.0 + '@jsii/spec': 1.105.0 + chalk: 4.1.2 + fs-extra: 10.1.0 + oo-ascii-tree: 1.105.0 yargs: 16.2.0 - transitivePeerDependencies: - - supports-color - /jsii-rosetta/5.4.2: - resolution: {integrity: sha512-Bo+8lLuRQ0YiXiNImJ6XLrmAY/GzildnYd1B5MLlc+IpjbgFbynhFIyGjYAVf4+/VLFJRoOCJtZ40sM+ua8Ecw==} + /jsii-rosetta/5.7.1: + resolution: {integrity: sha512-joxTYrpaYYUFpDYwNhf0lHyp1i6ZfXjpl2AkSCEd6vd0FvmK00tKbWu8UnY/dA7ryI1hvDkm1MTi6f4s36ZzZg==} engines: {node: '>= 18.12.0'} hasBin: true dependencies: - '@jsii/check-node': 1.97.0 - '@jsii/spec': 1.97.0 - '@xmldom/xmldom': 0.8.10 + '@jsii/check-node': 1.105.0 + '@jsii/spec': 1.105.0 + '@xmldom/xmldom': 0.9.6 chalk: 4.1.2 - commonmark: 0.31.0 + commonmark: 0.31.2 fast-glob: 3.3.2 - jsii: 5.4.3 - semver: 7.6.0 + jsii: 5.7.1 + semver: 7.6.3 semver-intersect: 1.5.0 - stream-json: 1.8.0 - typescript: 5.4.5 + stream-json: 1.9.1 + typescript: 5.7.2 workerpool: 6.5.1 yargs: 17.7.2 transitivePeerDependencies: - supports-color - /jsii-srcmak/0.1.1039: - resolution: {integrity: sha512-3lBjyxBy5UpPGK8bXFmVRzaoK6caDQ5DO40Qbyv3LOWtrsuUQmuVI2/5wRwNtfg6sFzOFD3+kE3LZuNXo7QE/Q==} + /jsii-srcmak/0.1.1308: + resolution: {integrity: sha512-+jSOHWXE/nmA5c2B3tQ3bsuaXXVWnvFq3bq+2cbNCHjX6wiJggNfJ6WEm9LVvCeOg4eJAaJV8NgeT/nE83zOlw==} hasBin: true dependencies: fs-extra: 9.1.0 - jsii: 5.3.34 - jsii-pacmak: 1.97.0 + jsii: 5.7.1 + jsii-pacmak: 1.105.0_jsii-rosetta@5.7.1 + jsii-rosetta: 5.7.1 ncp: 2.0.0 - yargs: 15.4.1 - transitivePeerDependencies: - - supports-color - - /jsii/1.97.0: - resolution: {integrity: sha512-C3GA2Q50DkHnFozg7HKel7ZaBMCUKb/dzgH2ykfrbuJ/C/KebkPkqY/XRf95zGB42mzagPfawSLDFQiGGueQ9w==} - engines: {node: '>= 14.17.0'} - hasBin: true - dependencies: - '@jsii/check-node': 1.97.0 - '@jsii/spec': 1.97.0 - case: 1.6.3 - chalk: 4.1.2 - fast-deep-equal: 3.1.3 - fs-extra: 10.1.0 - log4js: 6.9.1 - semver: 7.6.0 - semver-intersect: 1.5.0 - sort-json: 2.0.1 - spdx-license-list: 6.9.0 - typescript: 3.9.10 - yargs: 16.2.0 - transitivePeerDependencies: - - supports-color - - /jsii/5.3.34: - resolution: {integrity: sha512-vJc+DwAdkr1k66vn2YlybJyyv7fiCV8jOccXmdazZ7Ob+lbED0UTYZDTGFwnqj2feP17maIj1R0MaiDqxjsjKw==} - engines: {node: '>= 18.12.0'} - hasBin: true - dependencies: - '@jsii/check-node': 1.96.0 - '@jsii/spec': 1.97.0 - case: 1.6.3 - chalk: 4.1.2 - downlevel-dts: 0.11.0 - fast-deep-equal: 3.1.3 - log4js: 6.9.1 - semver: 7.6.0 - semver-intersect: 1.5.0 - sort-json: 2.0.1 - spdx-license-list: 6.9.0 - typescript: 5.3.3 yargs: 17.7.2 transitivePeerDependencies: - supports-color - /jsii/5.4.3: - resolution: {integrity: sha512-+alxW2wfBQBCjesy2kvMl6yML8m7hD/buIkVVQNSGt0R0ObhsLvlanS2lRWpNkdfVtDnNk/ke5UFmMSfJ/vy0Q==} + /jsii/5.7.1: + resolution: {integrity: sha512-EQ9HWmzD+Xpe+yciMQUx3i3Rm1ZVVeIXADbA53KSCDDbd9tqHvZ9kTOrFXakCXcaWIOqXFro+2TLiIIx5HtJhQ==} engines: {node: '>= 18.12.0'} hasBin: true dependencies: - '@jsii/check-node': 1.97.0 - '@jsii/spec': 1.97.0 + '@jsii/check-node': 1.105.0 + '@jsii/spec': 1.105.0 case: 1.6.3 chalk: 4.1.2 - downlevel-dts: 0.11.0 fast-deep-equal: 3.1.3 log4js: 6.9.1 - semver: 7.6.0 + semver: 7.6.3 semver-intersect: 1.5.0 sort-json: 2.0.1 spdx-license-list: 6.9.0 - typescript: 5.4.5 + typescript: 5.7.2 yargs: 17.7.2 transitivePeerDependencies: - supports-color @@ -8629,15 +8778,6 @@ packages: /json-stable-stringify-without-jsonify/1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - /json-stable-stringify/1.1.1: - resolution: {integrity: sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - isarray: 2.0.5 - jsonify: 0.0.1 - object-keys: 1.1.1 - /json-stringify-safe/5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} dev: true @@ -8666,13 +8806,6 @@ packages: optionalDependencies: graceful-fs: 4.2.11 - /jsonify/0.0.1: - resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} - - /jsonschema/1.4.1: - resolution: {integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==} - dev: false - /jsonwebtoken/8.5.1: resolution: {integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==} engines: {node: '>=4', npm: '>=1.4.28'} @@ -8696,7 +8829,7 @@ packages: jws: 3.2.2 lodash: 4.17.21 ms: 2.1.3 - semver: 7.6.0 + semver: 7.6.3 /jssha/3.3.1: resolution: {integrity: sha512-VCMZj12FCFMQYcFLPRm/0lOBbLi8uM2BhXPTqw3U4YAfs4AZfiApOoBLoN8cQE60Z50m1MYMTQVCfgF/KaCVhQ==} @@ -8739,10 +8872,10 @@ packages: dependencies: '@types/express': 4.17.21 '@types/jsonwebtoken': 9.0.1 - debug: 4.3.4 - jose: 4.15.5 + debug: 4.4.0 + jose: 4.15.9 limiter: 1.1.5 - lru-memoizer: 2.2.0 + lru-memoizer: 2.3.0 transitivePeerDependencies: - supports-color @@ -8833,6 +8966,7 @@ packages: engines: {node: '>=8'} dependencies: p-locate: 4.1.0 + dev: true /locate-path/6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} @@ -8902,7 +9036,7 @@ packages: /lodash/4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - /log-node/8.0.3_log@6.3.1: + /log-node/8.0.3_log@6.3.2: resolution: {integrity: sha512-1UBwzgYiCIDFs8A0rM2QdBFo8Wd8UQ0HrSTu/MNI+/2zN3NoHRj2fhplurAyuxTYUXu3Oohugq1jAn5s05u1MQ==} engines: {node: '>=10.0'} peerDependencies: @@ -8913,10 +9047,10 @@ packages: cli-sprintf-format: 1.1.1 d: 1.0.2 es5-ext: 0.10.64 - log: 6.3.1 - sprintf-kit: 2.0.1 + log: 6.3.2 + sprintf-kit: 2.0.2 supports-color: 8.1.1 - type: 2.7.2 + type: 2.7.3 dev: true /log-symbols/2.2.0: @@ -8934,15 +9068,16 @@ packages: is-unicode-supported: 0.1.0 dev: true - /log/6.3.1: - resolution: {integrity: sha512-McG47rJEWOkXTDioZzQNydAVvZNeEkSyLJ1VWkFwfW+o1knW+QSi8D1KjPn/TnctV+q99lkvJNe1f0E1IjfY2A==} + /log/6.3.2: + resolution: {integrity: sha512-ek8NRg/OPvS9ISOJNWNAz5vZcpYacWNFDWNJjj5OXsc6YuKacfey6wF04cXz/tOJIVrZ2nGSkHpAY5qKtF6ISg==} + engines: {node: '>=0.12'} dependencies: d: 1.0.2 duration: 0.2.2 es5-ext: 0.10.64 event-emitter: 0.3.5 - sprintf-kit: 2.0.1 - type: 2.7.2 + sprintf-kit: 2.0.2 + type: 2.7.3 uni-global: 1.0.0 dev: true @@ -8951,9 +9086,9 @@ packages: engines: {node: '>=8.0'} dependencies: date-format: 4.0.14 - debug: 4.3.4 - flatted: 3.3.1 - rfdc: 1.3.1 + debug: 4.4.0 + flatted: 3.3.2 + rfdc: 1.4.1 streamroller: 3.1.5 transitivePeerDependencies: - supports-color @@ -8979,21 +9114,8 @@ packages: engines: {node: '>=8'} dev: true - /lru-cache/10.2.0: - resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} - engines: {node: 14 || >=16.14} - - /lru-cache/4.0.2: - resolution: {integrity: sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==} - dependencies: - pseudomap: 1.0.2 - yallist: 2.1.2 - - /lru-cache/4.1.5: - resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} - dependencies: - pseudomap: 1.0.2 - yallist: 2.1.2 + /lru-cache/10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} /lru-cache/5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -9007,11 +9129,11 @@ packages: dependencies: yallist: 4.0.0 - /lru-memoizer/2.2.0: - resolution: {integrity: sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==} + /lru-memoizer/2.3.0: + resolution: {integrity: sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==} dependencies: lodash.clonedeep: 4.5.0 - lru-cache: 4.0.2 + lru-cache: 6.0.0 /lru-queue/0.1.0: resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} @@ -9019,8 +9141,8 @@ packages: es5-ext: 0.10.64 dev: true - /luxon/3.4.4: - resolution: {integrity: sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==} + /luxon/3.5.0: + resolution: {integrity: sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==} engines: {node: '>=12'} dev: false @@ -9042,12 +9164,16 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} dependencies: - semver: 7.6.0 + semver: 7.6.3 dev: true /make-error/1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + /math-intrinsics/1.0.0: + resolution: {integrity: sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA==} + engines: {node: '>= 0.4'} + /md5/2.3.0: resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} dependencies: @@ -9063,8 +9189,9 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} - /memoizee/0.4.15: - resolution: {integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==} + /memoizee/0.4.17: + resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==} + engines: {node: '>=0.12'} dependencies: d: 1.0.2 es5-ext: 0.10.64 @@ -9073,11 +9200,11 @@ packages: is-promise: 2.2.2 lru-queue: 0.1.0 next-tick: 1.1.0 - timers-ext: 0.1.7 + timers-ext: 0.1.8 dev: true - /merge-descriptors/1.0.1: - resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} + /merge-descriptors/1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} /merge-stream/2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -9090,17 +9217,22 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} - /micromatch/4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + /micromatch/4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} dependencies: - braces: 3.0.2 + braces: 3.0.3 picomatch: 2.3.1 /mime-db/1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + /mime-db/1.53.0: + resolution: {integrity: sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==} + engines: {node: '>= 0.6'} + dev: true + /mime-types/2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} @@ -9171,8 +9303,8 @@ packages: brace-expansion: 2.0.1 dev: false - /minimatch/9.0.4: - resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} + /minimatch/9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 @@ -9192,8 +9324,8 @@ packages: engines: {node: '>=8'} dev: true - /minipass/7.0.4: - resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + /minipass/7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} /minizlib/2.1.2: @@ -9278,12 +9410,13 @@ packages: /ms/2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true /ms/2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - /multipasta/0.2.0: - resolution: {integrity: sha512-MNAym1D9GTpY0/CKYJFDmaJ3TfhblfsQyyipCCSsgasMZCAyR2fCNDJhR7lACfJ0YMwQSDi5RHeIdJcsze6WMg==} + /multipasta/0.2.5: + resolution: {integrity: sha512-c8eMDb1WwZcE02WVjHoOmUVk7fnKU/RmUcosHACglrWAuPQsEJv+E8430sXj6jNc1jHw0zrS16aCjQh4BcEb4A==} dev: false /mustache/4.1.0: @@ -9298,8 +9431,8 @@ packages: resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - /nan/2.19.0: - resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} + /nan/2.22.0: + resolution: {integrity: sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==} /nanoid/2.1.11: resolution: {integrity: sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==} @@ -9336,8 +9469,8 @@ packages: es6-set: 0.1.6 ext: 1.7.0 find-requires: 1.0.0 - fs2: 0.3.9 - type: 2.7.2 + fs2: 0.3.15 + type: 2.7.3 dev: true /ncp/2.0.0: @@ -9351,7 +9484,7 @@ packages: dependencies: debug: 3.2.7 iconv-lite: 0.4.24 - sax: 1.3.0 + sax: 1.4.1 dev: false /negotiator/0.6.3: @@ -9371,25 +9504,25 @@ packages: dependencies: '@sinonjs/commons': 1.8.6 '@sinonjs/fake-timers': 6.0.1 - '@sinonjs/text-encoding': 0.7.2 + '@sinonjs/text-encoding': 0.7.3 just-extend: 4.2.1 - path-to-regexp: 1.8.0 + path-to-regexp: 1.9.0 /nise/5.1.9: resolution: {integrity: sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==} dependencies: '@sinonjs/commons': 3.0.1 - '@sinonjs/fake-timers': 11.2.2 - '@sinonjs/text-encoding': 0.7.2 + '@sinonjs/fake-timers': 11.3.1 + '@sinonjs/text-encoding': 0.7.3 just-extend: 6.2.0 - path-to-regexp: 6.2.2 + path-to-regexp: 6.3.0 dev: true /nock/11.8.2: resolution: {integrity: sha512-udrFXJ/aqPM9NmrKOcNJ67lvrs/zroNq2sbumhaMPW5JLNy/6LsWiZEwU9DiQIUHOcOCR4MPeqIG7uQNbDGExA==} engines: {node: '>= 8.0'} dependencies: - debug: 4.3.4 + debug: 4.4.0 json-stringify-safe: 5.0.1 lodash: 4.17.21 mkdirp: 0.5.6 @@ -9398,30 +9531,25 @@ packages: - supports-color dev: true - /nock/13.5.4: - resolution: {integrity: sha512-yAyTfdeNJGGBFxWdzSKCBYxs5FxLbCg5X5Q4ets974hcQzG1+qCxvIyOo4j2Ry6MUlhWVMX4OoYDefAIIwupjw==} + /nock/13.5.6: + resolution: {integrity: sha512-o2zOYiCpzRqSzPj0Zt/dQ/DqZeYoaQ7TUonc/xUPjCGl9WeHpNbxgVvOquXYAaJzI0M9BXV3HTzG0p8IUAbBTQ==} engines: {node: '>= 10.13'} dependencies: - debug: 4.3.4 + debug: 4.4.0 json-stringify-safe: 5.0.1 propagate: 2.0.1 transitivePeerDependencies: - supports-color dev: true - /node-abi/3.57.0: - resolution: {integrity: sha512-Dp+A9JWxRaKuHP35H77I4kCKesDy5HUDEmScia2FyncMTOXASMyg251F5PhFoDA5uqBrDDffiLpbqnrZmNXW+g==} + /node-abi/3.71.0: + resolution: {integrity: sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==} engines: {node: '>=10'} dependencies: - semver: 7.6.0 - - /node-abort-controller/3.1.1: - resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - dev: false + semver: 7.6.3 - /node-addon-api/7.1.0: - resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==} - engines: {node: ^16 || ^18 || >= 20} + /node-addon-api/7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} dev: false /node-dir/0.1.17: @@ -9462,11 +9590,11 @@ packages: resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==} engines: {node: '>=8'} dependencies: - process-on-spawn: 1.0.0 + process-on-spawn: 1.1.0 dev: true - /node-releases/2.0.14: - resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + /node-releases/2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} dev: true /node-rsa/0.4.2: @@ -9484,10 +9612,6 @@ packages: sorted-array-functions: 1.3.0 dev: false - /node-version/1.2.0: - resolution: {integrity: sha512-ma6oU4Sk0qOoKEAymVoTvk8EdXEobdS7m/mAGhDJ8Rouugho48crHBORAmy5BoOcv8wraPM6xumapQp5hl4iIQ==} - engines: {node: '>=6.0.0'} - /noms/0.0.0: resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} dependencies: @@ -9517,11 +9641,11 @@ packages: engines: {node: '>=12.0'} dependencies: ext: 1.7.0 - fs2: 0.3.9 - memoizee: 0.4.15 + fs2: 0.3.15 + memoizee: 0.4.17 node-fetch: 2.7.0 - semver: 7.6.0 - type: 2.7.2 + semver: 7.6.3 + type: 2.7.3 validate-npm-package-name: 3.0.0 transitivePeerDependencies: - encoding @@ -9565,7 +9689,7 @@ packages: make-dir: 3.1.0 node-preload: 0.2.1 p-map: 3.0.0 - process-on-spawn: 1.0.0 + process-on-spawn: 1.1.0 resolve-from: 5.0.0 rimraf: 3.0.2 signal-exit: 3.0.7 @@ -9584,14 +9708,15 @@ packages: resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} engines: {node: '>= 6'} - /object-inspect/1.13.1: - resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + /object-inspect/1.13.3: + resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} + engines: {node: '>= 0.4'} /object-is/1.1.6: resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 /object-keys/1.1.1: @@ -9606,33 +9731,33 @@ packages: resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - has-symbols: 1.0.3 + has-symbols: 1.1.0 object-keys: 1.1.1 /object.fromentries/2.0.8: resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-object-atoms: 1.0.0 /object.groupby/1.0.3: resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 /object.values/1.2.0: resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-object-atoms: 1.0.0 @@ -9663,8 +9788,8 @@ packages: dependencies: mimic-fn: 2.1.0 - /oo-ascii-tree/1.97.0: - resolution: {integrity: sha512-LVwQ1J6icSJ2buccnLCWdDtxxTwB0HXoB7PLPap4u90T9pAs2HqE35DpV6nV/6O1aVEO4OzwDeE2gLCUCkoGWQ==} + /oo-ascii-tree/1.105.0: + resolution: {integrity: sha512-fz4QixX/ImVEMbABqCJxxSwvJGfw9vfq2121RMq/qtCv7BiarY4ZPpheHheOTBvEnhqy81dyMpxiXAY8U3rPjA==} engines: {node: '>= 14.17.0'} /open/7.4.2: @@ -9700,16 +9825,16 @@ packages: word-wrap: 1.2.5 dev: true - /optionator/0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + /optionator/0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} dependencies: - '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 + word-wrap: 1.2.5 /ora/3.4.0: resolution: {integrity: sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==} @@ -9787,6 +9912,7 @@ packages: engines: {node: '>=8'} dependencies: p-limit: 2.3.0 + dev: true /p-locate/5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} @@ -9822,6 +9948,9 @@ packages: release-zalgo: 1.0.0 dev: true + /package-json-from-dist/1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + /pako/1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} dev: true @@ -9840,7 +9969,7 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.24.2 + '@babel/code-frame': 7.26.2 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -9854,7 +9983,7 @@ packages: resolution: {integrity: sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw==} dependencies: ansi-escapes: 4.3.2 - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 /patch-console/1.0.0: resolution: {integrity: sha512-nxl9nrnLQmh64iTzMfyylSlRozL7kAXIaxw1fVcLYdyhNkJCRUzirRZTikXGJsg+hc4fqpneTK6iU2H1Q8THSA==} @@ -9897,23 +10026,23 @@ packages: /path-parse/1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - /path-scurry/1.10.2: - resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==} - engines: {node: '>=16 || 14 >=14.17'} + /path-scurry/1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} dependencies: - lru-cache: 10.2.0 - minipass: 7.0.4 + lru-cache: 10.4.3 + minipass: 7.1.2 - /path-to-regexp/0.1.7: - resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + /path-to-regexp/0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} - /path-to-regexp/1.8.0: - resolution: {integrity: sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==} + /path-to-regexp/1.9.0: + resolution: {integrity: sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==} dependencies: isarray: 0.0.1 - /path-to-regexp/6.2.2: - resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} + /path-to-regexp/6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} dev: true /path-type/4.0.0: @@ -9935,8 +10064,8 @@ packages: /pend/1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - /picocolors/1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + /picocolors/1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} /picomatch/2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -10008,8 +10137,8 @@ packages: minimist: 1.2.8 mkdirp-classic: 0.5.3 napi-build-utils: 1.0.2 - node-abi: 3.57.0 - pump: 3.0.0 + node-abi: 3.71.0 + pump: 3.0.2 rc: 1.2.8 simple-get: 4.0.1 tar-fs: 2.1.1 @@ -10040,15 +10169,15 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - /priorityqueuejs/1.0.0: - resolution: {integrity: sha512-lg++21mreCEOuGWTbO5DnJKAdxfjrdN0S9ysoW9SzdSJvbkWpkaDdpG/cdsPCsEnoLUwmd9m3WcZhngW7yKA2g==} + /priorityqueuejs/2.0.0: + resolution: {integrity: sha512-19BMarhgpq3x4ccvVi8k2QpJZcymo/iFUcrhPd4V96kYGovOdTsWwy7fxChYi4QY+m2EnGBWSX9Buakz+tWNQQ==} dev: false /process-nextick-args/2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - /process-on-spawn/1.0.0: - resolution: {integrity: sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==} + /process-on-spawn/1.1.0: + resolution: {integrity: sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==} engines: {node: '>=8'} dependencies: fromentries: 1.3.2 @@ -10059,9 +10188,9 @@ packages: engines: {node: '>=10.0'} dependencies: ext: 1.7.0 - fs2: 0.3.9 - memoizee: 0.4.15 - type: 2.7.2 + fs2: 0.3.15 + memoizee: 0.4.17 + type: 2.7.3 dev: true /process/0.11.10: @@ -10074,9 +10203,6 @@ packages: engines: {node: '>=0.4.0'} dev: true - /promise-polyfill/6.1.0: - resolution: {integrity: sha512-g0LWaH0gFsxovsU7R5LrrhHhWAWiHRnh1GPrhXnPgYsDkIqjRYUYSZEsej/wtleDrz5xVSIDbeKfidztp2XHFQ==} - /promise-queue/2.2.5: resolution: {integrity: sha512-p/iXrPSVfnqPft24ZdNNLECw/UrtLTpT3jpAAMzl/o5/rDsGCPo3/CQS2611flL6LkoEJ3oQZw7C8Q80ZISXRQ==} engines: {node: '>= 0.8.0'} @@ -10111,11 +10237,8 @@ packages: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: true - /pseudomap/1.0.2: - resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} - - /pump/3.0.0: - resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + /pump/3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} dependencies: end-of-stream: 1.4.4 once: 1.4.0 @@ -10130,17 +10253,17 @@ packages: /pure-rand/6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - /qs/6.11.0: - resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} + /qs/6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} dependencies: - side-channel: 1.0.6 + side-channel: 1.1.0 - /qs/6.12.1: - resolution: {integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==} + /qs/6.13.1: + resolution: {integrity: sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==} engines: {node: '>=0.6'} dependencies: - side-channel: 1.0.6 + side-channel: 1.1.0 dev: true /querystring/0.2.0: @@ -10193,8 +10316,8 @@ packages: /react-devtools-core/4.28.5: resolution: {integrity: sha512-cq/o30z9W2Wb4rzBefjv5fBalHU0rJGZCHAkf/RHSBWSSYwh8PlQTqqOJmgIIbBtpj27T6FIPXeomIjZtCNVqA==} dependencies: - shell-quote: 1.8.1 - ws: 7.5.9 + shell-quote: 1.8.2 + ws: 7.5.10 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -10291,12 +10414,6 @@ packages: dependencies: picomatch: 2.3.1 - /rechoir/0.6.2: - resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} - engines: {node: '>= 0.10'} - dependencies: - resolve: 1.22.8 - /redeyed/2.1.1: resolution: {integrity: sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==} dependencies: @@ -10305,6 +10422,19 @@ packages: /reflect-metadata/0.1.13: resolution: {integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==} + /reflect.getprototypeof/1.0.8: + resolution: {integrity: sha512-B5dj6usc5dkk8uFliwjwDHM8To5/QwdKz9JcBZ8Ic4G1f0YmeeJTtE/ZTdgRFPAfxZFiUaPhZ1Jcs4qeagItGQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + dunder-proto: 1.0.0 + es-abstract: 1.23.5 + es-errors: 1.3.0 + get-intrinsic: 1.2.6 + gopd: 1.2.0 + which-builtin-type: 1.2.1 + /regenerator-runtime/0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} dev: true @@ -10314,11 +10444,11 @@ packages: hasBin: true dev: true - /regexp.prototype.flags/1.5.2: - resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + /regexp.prototype.flags/1.5.3: + resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-errors: 1.3.0 set-function-name: 2.0.2 @@ -10345,6 +10475,7 @@ packages: /require-main-filename/2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + dev: true /reserved-words/0.1.2: resolution: {integrity: sha512-0S5SrIUJ9LfpbVl4Yzij6VipUdafHrOTzvmfazSw/jeZrZtQK303OPZW+obtkaw7jQlTQppy0UvZWm9872PbRw==} @@ -10366,7 +10497,7 @@ packages: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true dependencies: - is-core-module: 2.13.1 + is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -10407,29 +10538,30 @@ packages: - supports-color dev: true - /rfdc/1.3.1: - resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} + /rfdc/1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - /rhea-promise/3.0.1: - resolution: {integrity: sha512-Fcqgml7lgoyi7fH1ClsSyFr/xwToijEN3rULFgrIcL+7EHeduxkWogFxNHjFzHf2YGScAckJDaDxS1RdlTUQYw==} + /rhea-promise/3.0.3: + resolution: {integrity: sha512-a875P5YcMkePSTEWMsnmCQS7Y4v/XvIw7ZoMtJxqtQRZsqSA6PsZxuz4vktyRykPuUgdNsA6F84dS3iEXZoYnQ==} dependencies: - debug: 3.2.7 - rhea: 3.0.2 - tslib: 2.6.2 + debug: 4.4.0 + rhea: 3.0.3 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false - /rhea/3.0.2: - resolution: {integrity: sha512-0G1ZNM9yWin8VLvTxyISKH6KfR6gl1TW/1+5yMKPf2r1efhkzTLze09iFtT2vpDjuWIVtSmXz8r18lk/dO8qwQ==} + /rhea/3.0.3: + resolution: {integrity: sha512-Y7se0USZQu6dErWSZ7eCmSVTMscyVfz/0+jjhBF7f9PqYfEXdIoQpPkC9Strks6wF9WytuBhn8w8Nz/tmBWpgA==} dependencies: - debug: 4.3.4 + debug: 4.4.0 transitivePeerDependencies: - supports-color dev: false /rimraf/2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true dependencies: glob: 7.2.3 @@ -10437,6 +10569,7 @@ packages: /rimraf/2.7.1: resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true dependencies: glob: 7.2.3 @@ -10444,16 +10577,16 @@ packages: /rimraf/3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true dependencies: glob: 7.2.3 - /rimraf/5.0.5: - resolution: {integrity: sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==} - engines: {node: '>=14'} + /rimraf/5.0.10: + resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} hasBin: true dependencies: - glob: 10.3.12 + glob: 10.4.5 dev: true /run-async/2.4.1: @@ -10484,16 +10617,17 @@ packages: /rxjs/7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: true - /safe-array-concat/1.1.2: - resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + /safe-array-concat/1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 + call-bind: 1.0.8 + call-bound: 1.0.2 + get-intrinsic: 1.2.6 + has-symbols: 1.1.0 isarray: 2.0.5 /safe-buffer/5.1.2: @@ -10502,13 +10636,13 @@ packages: /safe-buffer/5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - /safe-regex-test/1.0.3: - resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + /safe-regex-test/1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bound: 1.0.2 es-errors: 1.3.0 - is-regex: 1.1.4 + is-regex: 1.2.1 /safe-regex/2.1.1: resolution: {integrity: sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==} @@ -10522,8 +10656,8 @@ packages: /sax/1.2.1: resolution: {integrity: sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==} - /sax/1.3.0: - resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} + /sax/1.4.1: + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} /scheduler/0.20.2: resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==} @@ -10557,15 +10691,13 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - /semver/7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + /semver/7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} hasBin: true - dependencies: - lru-cache: 6.0.0 - /send/0.18.0: - resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} + /send/0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} dependencies: debug: 2.6.9 @@ -10588,14 +10720,14 @@ packages: randombytes: 2.1.0 dev: true - /serve-static/1.15.0: - resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} + /serve-static/1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} dependencies: - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 0.18.0 + send: 0.19.0 /serverless-artillery/0.5.2: resolution: {integrity: sha512-RD3ezSJrleXbSOC4PV2WGXz0JfEvn7IWZuv010z7tzYwxohOe7ja3fju0xKnQfeo9MFa8bF+YWH87pnjg+qkTg==} @@ -10625,10 +10757,10 @@ packages: '@serverless/dashboard-plugin': 6.4.0_supports-color@8.1.1 '@serverless/platform-client': 4.5.1_supports-color@8.1.1 '@serverless/utils': 6.15.0 - ajv: 8.12.0 + ajv: 8.17.1 ajv-formats: 2.1.1 archiver: 5.3.0 - aws-sdk: 2.1599.0 + aws-sdk: 2.1692.0 bluebird: 3.7.2 cachedir: 2.4.0 chalk: 4.1.2 @@ -10636,7 +10768,7 @@ packages: ci-info: 3.9.0 cli-progress-footer: 2.3.3 d: 1.0.2 - dayjs: 1.11.10 + dayjs: 1.11.13 decompress: 4.2.1 dotenv: 10.0.0 dotenv-expand: 5.1.0 @@ -10655,8 +10787,8 @@ packages: json-cycle: 1.5.0 json-refs: 3.0.15_supports-color@8.1.1 lodash: 4.17.21 - memoizee: 0.4.15 - micromatch: 4.0.5 + memoizee: 0.4.17 + micromatch: 4.0.8 node-fetch: 2.7.0 npm-registry-utilities: 1.0.0 object-hash: 2.2.0 @@ -10665,13 +10797,13 @@ packages: process-utils: 4.0.0 promise-queue: 2.2.5 require-from-string: 2.0.2 - semver: 7.6.0 + semver: 7.6.3 signal-exit: 3.0.7 strip-ansi: 6.0.1 supports-color: 8.1.1 tar: 6.2.1 - timers-ext: 0.1.7 - type: 2.7.2 + timers-ext: 0.1.8 + type: 2.7.3 untildify: 4.0.0 uuid: 8.3.2 yaml-ast-parser: 0.0.43 @@ -10684,6 +10816,7 @@ packages: /set-blocking/2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: true /set-function-length/1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} @@ -10692,8 +10825,8 @@ packages: define-data-property: 1.1.4 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.0.1 + get-intrinsic: 1.2.6 + gopd: 1.2.0 has-property-descriptors: 1.0.2 /set-function-name/2.0.2: @@ -10734,17 +10867,9 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - /shell-quote/1.8.1: - resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} - - /shelljs/0.8.5: - resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} - engines: {node: '>=4'} - hasBin: true - dependencies: - glob: 7.2.3 - interpret: 1.4.0 - rechoir: 0.6.2 + /shell-quote/1.8.2: + resolution: {integrity: sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==} + engines: {node: '>= 0.4'} /shortid/2.2.16: resolution: {integrity: sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==} @@ -10753,14 +10878,41 @@ packages: nanoid: 2.1.11 dev: true - /side-channel/1.0.6: - resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + /side-channel-list/1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.3 + + /side-channel-map/1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.2 + es-errors: 1.3.0 + get-intrinsic: 1.2.6 + object-inspect: 1.13.3 + + /side-channel-weakmap/1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.2 + es-errors: 1.3.0 + get-intrinsic: 1.2.6 + object-inspect: 1.13.3 + side-channel-map: 1.0.1 + + /side-channel/1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 es-errors: 1.3.0 - get-intrinsic: 1.2.4 - object-inspect: 1.13.1 + object-inspect: 1.13.3 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 /signal-exit/3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -10779,12 +10931,12 @@ packages: once: 1.4.0 simple-concat: 1.0.1 - /simple-git/3.24.0_supports-color@8.1.1: - resolution: {integrity: sha512-QqAKee9Twv+3k8IFOFfPB2hnk6as6Y6ACUpwCtQvRYBAes23Wv3SZlHVobAzqcE8gfsisCvPw3HGW3HYM+VYYw==} + /simple-git/3.27.0_supports-color@8.1.1: + resolution: {integrity: sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA==} dependencies: '@kwsites/file-exists': 1.1.1_supports-color@8.1.1 '@kwsites/promise-deferred': 1.1.1 - debug: 4.3.4_supports-color@8.1.1 + debug: 4.4.0_supports-color@8.1.1 transitivePeerDependencies: - supports-color dev: true @@ -10816,7 +10968,7 @@ packages: dependencies: '@sinonjs/commons': 3.0.1 '@sinonjs/fake-timers': 10.3.0 - '@sinonjs/samsam': 8.0.0 + '@sinonjs/samsam': 8.0.2 diff: 5.2.0 nise: 5.1.9 supports-color: 7.2.0 @@ -10913,7 +11065,7 @@ packages: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.17 + spdx-license-ids: 3.0.20 dev: true /spdx-exceptions/2.5.0: @@ -10924,11 +11076,11 @@ packages: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} dependencies: spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.17 + spdx-license-ids: 3.0.20 dev: true - /spdx-license-ids/3.0.17: - resolution: {integrity: sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==} + /spdx-license-ids/3.0.20: + resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} dev: true /spdx-license-list/6.9.0: @@ -10944,8 +11096,9 @@ packages: /sprintf-js/1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - /sprintf-kit/2.0.1: - resolution: {integrity: sha512-2PNlcs3j5JflQKcg4wpdqpZ+AjhQJ2OZEo34NXDtlB0tIPG84xaaXhpA8XFacFiwjKA4m49UOYG83y3hbMn/gQ==} + /sprintf-kit/2.0.2: + resolution: {integrity: sha512-lnapdj6W4LflHZGKvl9eVkz5YF0xaTrqpRWVA4cNVOTedwqifIP8ooGImldzT/4IAN5KXFQAyXTdLidYVQdyag==} + engines: {node: '>=0.12'} dependencies: es5-ext: 0.10.64 dev: true @@ -10968,7 +11121,7 @@ packages: resolution: {integrity: sha512-Xnt9/HHHYfjZ7NeQLvuQDyL1LnbsbddgMFKCuaQKwGCdJm8LnstZIXop+uOY36UR1UXXoHXfMbC1KlVdVd2JLA==} engines: {node: '>=8.0.0'} dependencies: - debug: 4.3.4 + debug: 4.4.0 strip-ansi: 6.0.1 transitivePeerDependencies: - supports-color @@ -10985,15 +11138,15 @@ packages: engines: {node: '>=4', npm: '>=6'} dev: false - /stream-buffers/3.0.2: - resolution: {integrity: sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==} + /stream-buffers/3.0.3: + resolution: {integrity: sha512-pqMqwQCso0PBJt2PQmDO0cFj0lyqmiwOMiMSkVtRokl7e+ZTRYgDHKnuZNbqjiJXgsg4nuqtD/zxuo9KqTp0Yw==} engines: {node: '>= 0.10.0'} /stream-chain/2.2.5: resolution: {integrity: sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==} - /stream-json/1.8.0: - resolution: {integrity: sha512-HZfXngYHUAr1exT4fxlbc1IOce1RYxp2ldeaf97LYCOPSoOqY/1Psp7iGvpb+6JIOgkra9zDYnPX01hGAHzEPw==} + /stream-json/1.9.1: + resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==} dependencies: stream-chain: 2.2.5 @@ -11010,7 +11163,7 @@ packages: engines: {node: '>=8.0'} dependencies: date-format: 4.0.14 - debug: 4.3.4 + debug: 4.4.0 fs-extra: 8.1.0 transitivePeerDependencies: - supports-color @@ -11040,28 +11193,24 @@ packages: emoji-regex: 9.2.2 strip-ansi: 7.1.0 - /string.prototype.repeat/0.2.0: - resolution: {integrity: sha512-1BH+X+1hSthZFW+X+JaUkjkkUPwIlLEMJBLANN3hOob3RhEk5snLWNECDnYbgn/m5c5JV7Ersu1Yubaf+05cIA==} - - /string.prototype.repeat/1.0.0: - resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} - dependencies: - define-properties: 1.2.1 - es-abstract: 1.23.3 - - /string.prototype.trim/1.2.9: - resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + /string.prototype.trim/1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.2 + define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-object-atoms: 1.0.0 + has-property-descriptors: 1.0.2 - /string.prototype.trimend/1.0.8: - resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + /string.prototype.trimend/1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.2 define-properties: 1.2.1 es-object-atoms: 1.0.0 @@ -11069,7 +11218,7 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-object-atoms: 1.0.0 @@ -11102,7 +11251,7 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} dependencies: - ansi-regex: 6.0.1 + ansi-regex: 6.1.0 /strip-bom/3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} @@ -11153,7 +11302,7 @@ packages: peek-readable: 4.1.0 dev: true - /subscriptions-transport-ws/0.11.0_graphql@16.8.1: + /subscriptions-transport-ws/0.11.0_graphql@16.9.0: resolution: {integrity: sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ==} deprecated: The `subscriptions-transport-ws` package is no longer maintained. We recommend you use `graphql-ws` instead. For help migrating Apollo software to `graphql-ws`, see https://www.apollographql.com/docs/apollo-server/data/subscriptions/#switching-from-subscriptions-transport-ws For general help using `graphql-ws`, see https://github.com/enisdenjo/graphql-ws/blob/master/README.md peerDependencies: @@ -11161,10 +11310,10 @@ packages: dependencies: backo2: 1.0.2 eventemitter3: 3.1.2 - graphql: 16.8.1 + graphql: 16.9.0 iterall: 1.3.0 symbol-observable: 1.2.0 - ws: 7.5.9 + ws: 7.5.10 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -11172,19 +11321,19 @@ packages: /superagent/7.1.6_supports-color@8.1.1: resolution: {integrity: sha512-gZkVCQR1gy/oUXr+kxJMLDjla434KmSOKbx5iGD30Ql+AkJQ/YlPKECJy2nhqOsHLjGHzoDTXNSjhnvWhzKk7g==} engines: {node: '>=6.4.0 <13 || >=14'} - deprecated: Please downgrade to v7.1.5 if you need IE/ActiveXObject support OR upgrade to v8.0.0 as we no longer support IE and published an incorrect patch version (see https://github.com/visionmedia/superagent/issues/1731) + deprecated: Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.3.4_supports-color@8.1.1 + debug: 4.4.0_supports-color@8.1.1 fast-safe-stringify: 2.1.1 - form-data: 4.0.0 + form-data: 4.0.1 formidable: 2.1.2 methods: 1.1.2 mime: 2.6.0 - qs: 6.12.1 + qs: 6.13.1 readable-stream: 3.6.2 - semver: 7.6.0 + semver: 7.6.3 transitivePeerDependencies: - supports-color dev: true @@ -11243,11 +11392,11 @@ packages: string-width: 3.1.0 dev: true - /table/6.8.2: - resolution: {integrity: sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==} + /table/6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} dependencies: - ajv: 8.12.0 + ajv: 8.17.1 lodash.truncate: 4.4.2 slice-ansi: 4.0.0 string-width: 4.2.3 @@ -11259,7 +11408,7 @@ packages: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.0 + pump: 3.0.2 tar-stream: 2.2.0 /tar-stream/1.6.2: @@ -11322,8 +11471,9 @@ packages: readable-stream: 2.3.8 xtend: 4.0.2 - /timers-ext/0.1.7: - resolution: {integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==} + /timers-ext/0.1.8: + resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==} + engines: {node: '>=0.12'} dependencies: es5-ext: 0.10.64 next-tick: 1.1.0 @@ -11339,10 +11489,6 @@ packages: resolution: {integrity: sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==} dev: true - /to-fast-properties/2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - /to-regex-range/5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -11368,13 +11514,13 @@ packages: /tr46/0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - /traverse/0.6.9: - resolution: {integrity: sha512-7bBrcF+/LQzSgFmT0X5YclVqQxtv7TDJ1f8Wj7ibBu/U6BMLeOpUxuZjV7rMc44UtKxlnMFigdhFAIszSX1DMg==} + /traverse/0.6.10: + resolution: {integrity: sha512-hN4uFRxbK+PX56DxYiGHsTn2dME3TVr9vbNqlQGcGcPhJAn+tdP126iA+TArMpI4YSgnTkMWyoLl5bf81Hi5TA==} engines: {node: '>= 0.4'} dependencies: - gopd: 1.0.1 + gopd: 1.2.0 typedarray.prototype.slice: 1.0.3 - which-typed-array: 1.1.15 + which-typed-array: 1.1.16 dev: true /tree-kill/1.2.2: @@ -11393,7 +11539,7 @@ packages: resolution: {integrity: sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==} engines: {node: '>=8'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 /ts-morph/19.0.0: resolution: {integrity: sha512-D6qcpiJdn46tUqV45vr5UGM2dnIEuTGNxVhg0sk5NX11orcouwj6i1bMqZIz2mZTZB1Hcgy7C3oEVhAT+f6mbQ==} @@ -11402,7 +11548,7 @@ packages: code-block-writer: 12.0.0 dev: false - /ts-node/10.9.2_cwiqw7fmejhb47wvqtchhjxme4: + /ts-node/10.9.2_qnvbopyuzco2g5z7jdoebgqlma: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: @@ -11421,9 +11567,9 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 18.19.31 - acorn: 8.11.3 - acorn-walk: 8.3.2 + '@types/node': 18.19.68 + acorn: 8.14.0 + acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 @@ -11440,12 +11586,12 @@ packages: global-prefix: 3.0.0 minimist: 1.2.8 resolve: 1.22.8 - semver: 7.6.0 + semver: 7.6.3 strip-ansi: 6.0.1 dev: true - /tsconfck/3.0.3_typescript@5.1.6: - resolution: {integrity: sha512-4t0noZX9t6GcPTfBAbIbbIU4pfpCwh0ueq3S4O/5qXI1VwK1outmxhe9dOiEWqMz3MW2LKgDTpqWV+37IWuVbA==} + /tsconfck/3.1.4_typescript@5.1.6: + resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} engines: {node: ^18 || >=20} hasBin: true peerDependencies: @@ -11468,8 +11614,8 @@ packages: /tslib/1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - /tslib/2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + /tslib/2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} /tsutils/3.21.0_typescript@5.1.6: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} @@ -11502,6 +11648,10 @@ packages: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} + /type-detect/4.1.0: + resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} + engines: {node: '>=4'} + /type-fest/0.12.0: resolution: {integrity: sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==} engines: {node: '>=10'} @@ -11531,15 +11681,15 @@ packages: media-typer: 0.3.0 mime-types: 2.1.35 - /type/2.7.2: - resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} + /type/2.7.3: + resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} dev: true /typed-array-buffer/1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-typed-array: 1.1.13 @@ -11547,33 +11697,34 @@ packages: resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 + gopd: 1.2.0 + has-proto: 1.2.0 is-typed-array: 1.1.13 - /typed-array-byte-offset/1.0.2: - resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + /typed-array-byte-offset/1.0.3: + resolution: {integrity: sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==} engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 + gopd: 1.2.0 + has-proto: 1.2.0 is-typed-array: 1.1.13 + reflect.getprototypeof: 1.0.8 - /typed-array-length/1.0.6: - resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + /typed-array-length/1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 + gopd: 1.2.0 is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 + reflect.getprototypeof: 1.0.8 /typedarray-to-buffer/3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} @@ -11585,46 +11736,31 @@ packages: resolution: {integrity: sha512-8WbVAQAUlENo1q3c3zZYuy5k9VzBQvp8AX9WOtbvyWlLM1v5JaSRmjubLjzHF4JFtptjH/5c/i95yaElvcjC0A==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.5 es-errors: 1.3.0 typed-array-buffer: 1.0.2 - typed-array-byte-offset: 1.0.2 + typed-array-byte-offset: 1.0.3 dev: true - /typescript/3.9.10: - resolution: {integrity: sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==} - engines: {node: '>=4.2.0'} - hasBin: true - /typescript/5.1.6: resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} engines: {node: '>=14.17'} hasBin: true - /typescript/5.3.3: - resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} - engines: {node: '>=14.17'} - hasBin: true - - /typescript/5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} - engines: {node: '>=14.17'} - hasBin: true - - /typescript/5.6.0-dev.20240604: - resolution: {integrity: sha512-uwpkMy5U51ERVvVtQmDZwjYllREGrqP35JcdR5yWIoZ7ZE2I1oDsDs3mtLiiiccyHspCZ54Z741ibuP3NbACtg==} + /typescript/5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} engines: {node: '>=14.17'} hasBin: true /unbox-primitive/1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.0 /unbzip2-stream/1.4.3: resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} @@ -11636,21 +11772,20 @@ packages: /undici-types/5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - /undici/6.13.0: - resolution: {integrity: sha512-Q2rtqmZWrbP8nePMq7mOJIN98M0fYvSgV89vwl/BQRT4mDOeY2GXZngfGpcBBhtky3woM7G24wZV3Q304Bv6cw==} - engines: {node: '>=18.0'} + /undici-types/6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + /undici/6.21.0: + resolution: {integrity: sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==} + engines: {node: '>=18.17'} dev: false /uni-global/1.0.0: resolution: {integrity: sha512-WWM3HP+siTxzIWPNUg7hZ4XO8clKi6NoCAJJWnuRL+BAqyFXF8gC03WNyTefGoUXYc47uYgXxpKLIEvo65PEHw==} dependencies: - type: 2.7.2 + type: 2.7.3 dev: true - /universal-user-agent/6.0.1: - resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} - dev: false - /universalify/0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -11667,15 +11802,15 @@ packages: resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} engines: {node: '>=8'} - /update-browserslist-db/1.0.13_browserslist@4.23.0: - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + /update-browserslist-db/1.1.1_browserslist@4.24.2: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: - browserslist: 4.23.0 - escalade: 3.1.2 - picocolors: 1.0.0 + browserslist: 4.24.2 + escalade: 3.2.0 + picocolors: 1.1.1 dev: true /uri-js/4.4.1: @@ -11696,10 +11831,10 @@ packages: resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} dependencies: inherits: 2.0.4 - is-arguments: 1.1.1 + is-arguments: 1.2.0 is-generator-function: 1.0.10 is-typed-array: 1.1.13 - which-typed-array: 1.1.15 + which-typed-array: 1.1.16 /utils-merge/1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} @@ -11756,7 +11891,7 @@ packages: engines: {node: '>=0.8.0'} hasBin: true dependencies: - debug: 4.3.4 + debug: 4.4.0 transitivePeerDependencies: - supports-color dev: true @@ -11780,14 +11915,33 @@ packages: tr46: 0.0.3 webidl-conversions: 3.0.1 - /which-boxed-primitive/1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + /which-boxed-primitive/1.1.0: + resolution: {integrity: sha512-Ei7Miu/AXe2JJ4iNF5j/UphAgRoma4trE6PtisM09bPygb3egMH3YLW/befsWb1A1AxvNSFidOFTB18XtnIIng==} + engines: {node: '>= 0.4'} + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.1 + is-number-object: 1.1.0 + is-string: 1.1.0 + is-symbol: 1.1.1 + + /which-builtin-type/1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} dependencies: - is-bigint: 1.0.4 - is-boolean-object: 1.1.2 - is-number-object: 1.0.7 - is-string: 1.0.7 - is-symbol: 1.0.4 + call-bound: 1.0.2 + function.prototype.name: 1.1.6 + has-tostringtag: 1.0.2 + is-async-function: 2.0.0 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.0 + is-generator-function: 1.0.10 + is-regex: 1.2.1 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.1.0 + which-collection: 1.0.2 + which-typed-array: 1.1.16 /which-collection/1.0.2: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} @@ -11800,15 +11954,16 @@ packages: /which-module/2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + dev: true - /which-typed-array/1.1.15: - resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + /which-typed-array/1.1.16: + resolution: {integrity: sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ==} engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 - gopd: 1.0.1 + gopd: 1.2.0 has-tostringtag: 1.0.2 /which/1.3.1: @@ -11816,6 +11971,7 @@ packages: hasBin: true dependencies: isexe: 2.0.0 + dev: true /which/2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} @@ -11833,7 +11989,6 @@ packages: /word-wrap/1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - dev: true /wordwrap/1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} @@ -11905,8 +12060,8 @@ packages: mkdirp: 0.5.6 dev: true - /ws/7.5.9: - resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + /ws/7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} engines: {node: '>=8.3.0'} peerDependencies: bufferutil: ^4.0.1 @@ -11917,21 +12072,8 @@ packages: utf-8-validate: optional: true - /ws/8.12.0: - resolution: {integrity: sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: false - - /ws/8.16.0: - resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + /ws/8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -11947,7 +12089,7 @@ packages: resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==} hasBin: true dependencies: - sax: 1.3.0 + sax: 1.4.1 /xml2js/0.4.19: resolution: {integrity: sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==} @@ -11983,14 +12125,12 @@ packages: /y18n/4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + dev: true /y18n/5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - /yallist/2.1.2: - resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} - /yallist/3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} dev: true @@ -12007,8 +12147,8 @@ packages: engines: {node: '>= 6'} dev: false - /yaml/2.4.1: - resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} + /yaml/2.6.1: + resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} engines: {node: '>= 14'} hasBin: true dev: false @@ -12034,10 +12174,16 @@ packages: dependencies: camelcase: 5.3.1 decamelize: 1.2.0 + dev: true /yargs-parser/20.2.4: resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} engines: {node: '>=10'} + dev: true + + /yargs-parser/20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} /yargs-parser/21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} @@ -12083,25 +12229,26 @@ packages: which-module: 2.0.1 y18n: 4.0.3 yargs-parser: 18.1.3 + dev: true /yargs/16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} dependencies: cliui: 7.0.4 - escalade: 3.1.2 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 y18n: 5.0.8 - yargs-parser: 20.2.4 + yargs-parser: 20.2.9 /yargs/17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} dependencies: cliui: 8.0.1 - escalade: 3.1.2 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -12144,5 +12291,5 @@ packages: compress-commons: 4.1.2 readable-stream: 3.6.2 - /zod/3.22.4: - resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + /zod/3.24.1: + resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json index 60f7c00d68..a1b8103e10 100644 --- a/common/config/rush/version-policies.json +++ b/common/config/rush/version-policies.json @@ -103,6 +103,6 @@ "definitionName": "lockStepVersion", "policyName": "booster", "mainProject": "@boostercloud/framework-core", - "version": "2.12.1" + "version": "2.18.7" } ] diff --git a/packages/application-tester/package.json b/packages/application-tester/package.json index da61512cc7..cecf605fe7 100644 --- a/packages/application-tester/package.json +++ b/packages/application-tester/package.json @@ -1,6 +1,6 @@ { "name": "@boostercloud/application-tester", - "version": "2.12.1", + "version": "2.18.7", "description": "Contains Booster types related to the information extracted from the user project", "keywords": [ "application-tester" @@ -36,19 +36,19 @@ }, "dependencies": { "@apollo/client": "3.7.13", - "@boostercloud/framework-types": "workspace:^2.12.1", + "@boostercloud/framework-types": "workspace:^2.18.7", "cross-fetch": "3.1.5", "graphql": "^16.6.0", "jsonwebtoken": "9.0.1", "subscriptions-transport-ws": "0.11.0", "tslib": "^2.4.0", - "ws": "8.12.0", + "ws": "8.17.1", "@types/sinon": "10.0.0", "sinon": "9.2.3", "@effect-ts/core": "^0.60.4" }, "devDependencies": { - "@boostercloud/eslint-config": "workspace:^2.12.1", + "@boostercloud/eslint-config": "workspace:^2.18.7", "@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/parser": "^5.0.0", "eslint": "^8.23.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 0a44322b1c..ca6c97b76a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "@boostercloud/cli", "description": "CLI of the Booster Framework, the next level of abstraction for cloud-native applications", - "version": "2.12.1", + "version": "2.18.7", "author": "Boosterin Labs SLU", "homepage": "https://boosterframework.com", "publishConfig": { @@ -12,12 +12,11 @@ }, "bugs": "https://github.com/boostercloud/booster/issues", "dependencies": { - "@boostercloud/framework-core": "workspace:^2.12.1", - "@boostercloud/framework-types": "workspace:^2.12.1", + "@boostercloud/framework-core": "workspace:^2.18.7", + "@boostercloud/framework-types": "workspace:^2.18.7", "@oclif/core": "3.15.0", "@oclif/plugin-help": "^5", "chalk": "^2.4.2", - "child-process-promise": "^2.2.1", "execa": "^2.0.3", "fp-ts": "^2.11.0", "fs-extra": "^8.1.0", @@ -30,12 +29,11 @@ "@effect-ts/core": "^0.60.4" }, "devDependencies": { - "@boostercloud/eslint-config": "workspace:^2.12.1", - "@boostercloud/application-tester": "workspace:^2.12.1", + "@boostercloud/eslint-config": "workspace:^2.18.7", + "@boostercloud/application-tester": "workspace:^2.18.7", "@oclif/test": "^3.0.3", "@types/chai": "4.2.18", "@types/chai-as-promised": "7.1.4", - "@types/child-process-promise": "^2.2.1", "@types/faker": "5.1.5", "@types/fs-extra": "^9.0.13", "@types/inflected": "1.1.29", diff --git a/packages/cli/src/services/process/live.impl.ts b/packages/cli/src/services/process/live.impl.ts index 94a4e506fc..084a8baece 100644 --- a/packages/cli/src/services/process/live.impl.ts +++ b/packages/cli/src/services/process/live.impl.ts @@ -1,4 +1,4 @@ -import * as childProcess from 'child-process-promise' +import * as execa from 'execa' import * as process from 'process' import { ProcessError, ProcessService } from '.' import { Layer, tryCatch, tryCatchPromise } from '@boostercloud/framework-types/dist/effect' @@ -7,7 +7,7 @@ import { unknownToError } from '../../common/errors' const exec = (command: string, cwd?: string) => tryCatchPromise( async () => { - const { stdout, stderr } = await childProcess.exec(command, { cwd }) + const { stdout, stderr } = await execa.command(command, { cwd }) const result = ` ${stderr ? `There were some issues running the command: ${stderr}\n` : ''} ${stdout} diff --git a/packages/cli/src/services/project-initializer.ts b/packages/cli/src/services/project-initializer.ts index b848f3be86..79ea3fd975 100644 --- a/packages/cli/src/services/project-initializer.ts +++ b/packages/cli/src/services/project-initializer.ts @@ -1,5 +1,5 @@ import * as fs from 'fs-extra' -import { exec } from 'child-process-promise' +import { command } from 'execa' import * as Mustache from 'mustache' import * as path from 'path' import * as tsConfig from '../templates/project/tsconfig-json' @@ -59,7 +59,7 @@ export async function generateRootDirectory(config: ProjectInitializerConfig): P export async function initializeGit(config: ProjectInitializerConfig): Promise { try { - await exec('git init && git add -A && git commit -m "Initial commit"', { cwd: projectDir(config) }) + await command('git init && git add -A && git commit -m "Initial commit"', { cwd: projectDir(config), shell: true }) } catch (e) { throw wrapExecError(e, 'Could not initialize git repository') } diff --git a/packages/cli/test/commands/stub/publish.test.ts b/packages/cli/test/commands/stub/publish.test.ts index 1cb913ad39..a5c5a9061a 100644 --- a/packages/cli/test/commands/stub/publish.test.ts +++ b/packages/cli/test/commands/stub/publish.test.ts @@ -19,6 +19,7 @@ describe('stub', async () => { { name: 'fake-command.stub', path: '/someDir', + parentPath: '/someDir', isFile: () => true, isDirectory: () => false, isBlockDevice: () => false, @@ -30,6 +31,7 @@ describe('stub', async () => { { name: 'fake-event.stub', path: '/someDir', + parentPath: '/someDir', isFile: () => true, isDirectory: () => false, isBlockDevice: () => false, @@ -41,6 +43,7 @@ describe('stub', async () => { { name: 'fake-directory', path: '/someDir', + parentPath: '/someDir', isFile: () => false, isDirectory: () => true, isBlockDevice: () => false, diff --git a/packages/cli/test/services/process/live.test.ts b/packages/cli/test/services/process/live.test.ts index df10e361c1..9f7f214c92 100644 --- a/packages/cli/test/services/process/live.test.ts +++ b/packages/cli/test/services/process/live.test.ts @@ -1,5 +1,5 @@ import * as process from 'process' -import * as childProcessPromise from 'child-process-promise' +import * as execa from 'execa' import { fake, replace, restore } from 'sinon' import { Effect, gen, mapError, pipe, unsafeRunEffect } from '@boostercloud/framework-types/dist/effect' import { LiveProcess } from '../../../src/services/process/live.impl' @@ -10,7 +10,7 @@ import { ProcessService } from '../../../src/services/process' describe('Process - Live Implementation', () => { beforeEach(() => { replace(process, 'cwd', fake.returns('')) - replace(childProcessPromise, 'exec', fake.resolves({})) + replace(execa, 'command', fake.resolves({ stdout: '', stderr: '' })) }) afterEach(() => { @@ -35,7 +35,7 @@ describe('Process - Live Implementation', () => { expect(process.cwd).to.have.been.called }) - it('uses child-process-promise.exec', async () => { + it('uses execa.command', async () => { const command = 'command' const cwd = 'cwd' @@ -48,6 +48,6 @@ describe('Process - Live Implementation', () => { layer: LiveProcess, onError: guardError('An error ocurred'), }) - expect(childProcessPromise.exec).to.have.been.calledWith(command, { cwd }) + expect(execa.command).to.have.been.calledWith(command, { cwd }) }) }) diff --git a/packages/cli/test/services/project-initializer.test.ts b/packages/cli/test/services/project-initializer.test.ts index 37fe91130f..9d680d1656 100644 --- a/packages/cli/test/services/project-initializer.test.ts +++ b/packages/cli/test/services/project-initializer.test.ts @@ -1,13 +1,13 @@ import * as fs from 'fs-extra' -import * as childProcessPromise from 'child-process-promise' +import * as execa from 'execa' import { generateConfigFiles, - installDependencies, generateRootDirectory, initializeGit, + installDependencies, ProjectInitializerConfig, } from '../../src/services/project-initializer' -import { restore, replace, fake } from 'sinon' +import { fake, replace, restore } from 'sinon' import { expect } from '../expect' import { makeTestPackageManager } from './package-manager/test.impl' import * as PackageManager from '../../src/services/package-manager/live.impl' @@ -16,7 +16,7 @@ describe('project initializer', (): void => { beforeEach(() => { replace(fs, 'mkdirs', fake.resolves({})) replace(fs, 'outputFile', fake.resolves({})) - replace(childProcessPromise, 'exec', fake.resolves({})) + replace(execa, 'command', fake.resolves({ stdout: '', stderr: '' })) }) afterEach(() => { @@ -42,9 +42,7 @@ describe('project initializer', (): void => { it('initialize Git', async () => { await initializeGit(defaultProjectInitializerConfig) - expect(childProcessPromise.exec).to.have.been.calledWithMatch( - 'git init && git add -A && git commit -m "Initial commit"' - ) + expect(execa.command).to.have.been.calledWithMatch('git init && git add -A && git commit -m "Initial commit"') }) it('Generate root directory', async () => { diff --git a/packages/cli/test/services/stub-publisher.test.ts b/packages/cli/test/services/stub-publisher.test.ts index c85ab84da5..73a96ff27a 100644 --- a/packages/cli/test/services/stub-publisher.test.ts +++ b/packages/cli/test/services/stub-publisher.test.ts @@ -19,6 +19,7 @@ describe('stub publisher', () => { { name: 'fake-command.stub', path: '/someDir', + parentPath: '/someDir', isFile: () => true, isDirectory: () => false, isBlockDevice: () => false, @@ -30,6 +31,7 @@ describe('stub publisher', () => { { name: 'fake-event.stub', path: '/someDir', + parentPath: '/someDir', isFile: () => true, isDirectory: () => false, isBlockDevice: () => false, @@ -41,6 +43,7 @@ describe('stub publisher', () => { { name: 'fake-stub.ts', path: '/someDir', + parentPath: '/someDir', isFile: () => true, isDirectory: () => false, isBlockDevice: () => false, @@ -52,6 +55,7 @@ describe('stub publisher', () => { { name: 'fake-directory-1', path: '/someDir', + parentPath: '/someDir', isFile: () => false, isDirectory: () => true, isBlockDevice: () => false, @@ -63,6 +67,7 @@ describe('stub publisher', () => { { name: 'fake-directory-2', path: '/someDir', + parentPath: '/someDir', isFile: () => false, isDirectory: () => true, isBlockDevice: () => false, @@ -160,6 +165,7 @@ describe('stub publisher', () => { { name: 'fake-file-1.stub', path: '/someDir', + parentPath: '/someDir', isFile: () => true, isDirectory: () => false, isBlockDevice: () => false, @@ -171,6 +177,7 @@ describe('stub publisher', () => { { name: 'fake-file-2.stub', path: '/someDir', + parentPath: '/someDir', isFile: () => true, isDirectory: () => false, isBlockDevice: () => false, @@ -195,6 +202,7 @@ describe('stub publisher', () => { { name: 'fake-directory', path: '/someDir', + parentPath: '/someDir', isFile: () => false, isDirectory: () => true, isBlockDevice: () => false, @@ -213,6 +221,7 @@ describe('stub publisher', () => { { name: 'fake-stub.ts', path: '/someDir', + parentPath: '/someDir', isFile: () => true, isDirectory: () => false, isBlockDevice: () => false, diff --git a/packages/framework-common-helpers/package.json b/packages/framework-common-helpers/package.json index 0009ed83b9..849b6cae57 100644 --- a/packages/framework-common-helpers/package.json +++ b/packages/framework-common-helpers/package.json @@ -1,6 +1,6 @@ { "name": "@boostercloud/framework-common-helpers", - "version": "2.12.1", + "version": "2.18.7", "description": "Contains Booster common helpers used by the core and provider packages", "keywords": [ "framework-common-helpers" @@ -36,17 +36,16 @@ "node": ">=18.0.0 <19.0.0" }, "dependencies": { - "@boostercloud/framework-types": "workspace:^2.12.1", - "child-process-promise": "^2.2.1", + "@boostercloud/framework-types": "workspace:^2.18.7", "tslib": "^2.4.0", "@effect-ts/core": "^0.60.4", - "class-transformer": "~0.5.1" + "class-transformer": "~0.5.1", + "execa": "^2.0.3" }, "devDependencies": { - "@boostercloud/eslint-config": "workspace:^2.12.1", + "@boostercloud/eslint-config": "workspace:^2.18.7", "@types/chai": "4.2.18", "@types/chai-as-promised": "7.1.4", - "@types/child-process-promise": "^2.2.1", "@types/mocha": "10.0.1", "@types/node": "^18.18.2", "@types/rewire": "^2.5.28", @@ -70,7 +69,9 @@ "sinon-chai": "3.5.0", "ts-node": "^10.9.1", "typescript": "5.1.6", - "eslint-plugin-unicorn": "~44.0.2" + "eslint-plugin-unicorn": "~44.0.2", + "faker": "5.1.0", + "@types/faker": "5.1.5" }, "pnpm": { "overrides": { diff --git a/packages/framework-common-helpers/src/instances.ts b/packages/framework-common-helpers/src/instances.ts index 71c01efb33..8b2fafe7d5 100644 --- a/packages/framework-common-helpers/src/instances.ts +++ b/packages/framework-common-helpers/src/instances.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Class } from '@boostercloud/framework-types' +import { Class, ProjectionFor, ReadModelInterface } from '@boostercloud/framework-types' /** * Creates an instance of the given class from the given raw object. @@ -43,3 +43,98 @@ export function createInstance(instanceClass: Class, rawObject: Record(instanceClass: Class, rawObjects: Array>): T[] { return rawObjects.map((rawObject) => createInstance(instanceClass, rawObject)) } + +/** + * Creates an instance of the read model class with the calculated properties included + * @param instanceClass The read model class + * @param raw The raw read model data + * @param propertiesToInclude The properties to include in the response + * @private + */ +export async function createInstanceWithCalculatedProperties( + instanceClass: Class, + raw: Partial, + propertiesToInclude: ProjectionFor +): Promise { + const instance = new instanceClass() + Object.assign(instance, raw) + const result: T = {} as T + + const propertiesMap = buildPropertiesMap(propertiesToInclude) + + await processProperties(instance, result, propertiesMap) + + return result +} + +/** + * Builds a map of properties to include in the response + * @param properties The properties to include in the response + * @private + */ +function buildPropertiesMap(properties: ProjectionFor): any { + const map: any = {} + properties.forEach((property) => { + const parts = property.split('.') + let current = map + parts.forEach((part) => { + const isArray = part.endsWith('[]') + const key = isArray ? part.slice(0, -2) : part + if (!Object.prototype.hasOwnProperty.call(current, key)) { + current[key] = isArray ? { __isArray: true, __children: {} } : {} + } + current = isArray ? current[key].__children : current[key] + }) + }) + return map +} + +/** + * Processes the properties of the source object and adds them to the result object + * @param source The source object + * @param result The result object + * @param propertiesMap The map of properties to include in the response + * @private + */ +async function processProperties(source: any, result: any, propertiesMap: any): Promise { + for (const key of Object.keys(propertiesMap)) { + if (key === '__isArray' || key === '__children') continue + + if (source[key] !== undefined) { + if (propertiesMap[key].__isArray) { + result[key] = [] + for (const item of source[key]) { + const newItem: any = {} + await processProperties(item, newItem, propertiesMap[key].__children) + if (Object.keys(newItem).length > 0) { + result[key].push(newItem) + } + } + } else if (typeof propertiesMap[key] === 'object' && Object.keys(propertiesMap[key]).length > 0) { + const value = source[key] + const resolvedValue = isPromise(value) ? await value : value + if (resolvedValue === undefined || resolvedValue === null) { + result[key] = null + } else { + result[key] = {} + await processProperties(resolvedValue, result[key], propertiesMap[key]) + if (Object.keys(result[key]).length === 0) { + result[key] = null + } + } + } else { + const value = source[key] + result[key] = isPromise(value) ? await value : value + } + } else { + // Handle the case when the source property is undefined + if (typeof propertiesMap[key] === 'object' && Object.keys(propertiesMap[key]).length > 0) { + result[key] = null + } + } + } +} + +function isPromise(obj: any): obj is Promise { + return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function' +} diff --git a/packages/framework-common-helpers/src/retrier.ts b/packages/framework-common-helpers/src/retrier.ts index f3ae7fece8..f345b4aef7 100644 --- a/packages/framework-common-helpers/src/retrier.ts +++ b/packages/framework-common-helpers/src/retrier.ts @@ -10,7 +10,7 @@ import { Class, Logger } from '@boostercloud/framework-types' * @returns The result of the first successful retry. */ export async function retryIfError( - logicToRetry: () => Promise, + logicToRetry: (tryNumber?: number) => Promise, errorClassThatRetries: Class, logger?: Logger, maxRetries = 1000 @@ -20,7 +20,7 @@ export async function retryIfError( for (tryNumber = 1; tryNumber <= maxRetries; tryNumber++) { try { logger?.debug(`[retryIfError] Try number ${tryNumber}`) - const result = await logicToRetry() + const result = await logicToRetry(tryNumber) logger?.debug(`[retryIfError] Succeeded after ${tryNumber} retries`) return result } catch (e) { diff --git a/packages/framework-common-helpers/test/instances.test.ts b/packages/framework-common-helpers/test/instances.test.ts new file mode 100644 index 0000000000..144feb739b --- /dev/null +++ b/packages/framework-common-helpers/test/instances.test.ts @@ -0,0 +1,59 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { createInstanceWithCalculatedProperties } from '../src' +import { ProjectionFor, ReadModelInterface, UUID } from '@boostercloud/framework-types' +import { expect } from './helpers/expect' +import { random } from 'faker' + +describe('the `Instances` helper', () => { + class PersonReadModel implements ReadModelInterface { + public constructor( + readonly id: UUID, + readonly firstName: string, + readonly lastName: string, + readonly friends: Array + ) {} + + public get fullName(): Promise { + return Promise.resolve(`${this.firstName} ${this.lastName}`) + } + } + + let rawObject: any + + beforeEach(() => { + rawObject = { + id: random.uuid(), + firstName: random.word(), + lastName: random.word(), + friends: [ + { id: random.uuid(), firstName: random.word(), lastName: random.word() }, + { id: random.uuid(), firstName: random.word(), lastName: random.word() }, + ], + } + }) + + describe('the createInstanceWithCalculatedProperties method', () => { + it('creates an instance of the read model class with the calculated properties included', async () => { + const propertiesToInclude = ['id', 'fullName'] as ProjectionFor + + const instance = await createInstanceWithCalculatedProperties(PersonReadModel, rawObject, propertiesToInclude) + + expect(instance).to.deep.equal({ + id: rawObject.id, + fullName: `${rawObject.firstName} ${rawObject.lastName}`, + }) + }) + + it('correctly supports arrays and nested objects in `propertiesToInclude`', async () => { + const propertiesToInclude = ['id', 'fullName', 'friends[].id'] as ProjectionFor + + const instance = await createInstanceWithCalculatedProperties(PersonReadModel, rawObject, propertiesToInclude) + + expect(instance).to.deep.equal({ + id: rawObject.id, + fullName: `${rawObject.firstName} ${rawObject.lastName}`, + friends: [{ id: rawObject.friends[0].id }, { id: rawObject.friends[1].id }], + }) + }) + }) +}) diff --git a/packages/framework-core/CHANGELOG.json b/packages/framework-core/CHANGELOG.json index ff49243a77..8dfbcaaf8d 100644 --- a/packages/framework-core/CHANGELOG.json +++ b/packages/framework-core/CHANGELOG.json @@ -1,6 +1,398 @@ { "name": "@boostercloud/framework-core", "entries": [ + { + "version": "2.18.7", + "tag": "@boostercloud/framework-core_v2.18.7", + "date": "Mon, 09 Dec 2024 14:07:07 GMT", + "comments": { + "patch": [ + { + "comment": "Replace child-process-promise with execa", + "author": "Mario Castro Squella ", + "commit": "ab31b4957016f46b01d61e2399c044a6b7bd63e5" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.18.6` to `^2.18.7`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.18.6` to `^2.18.7`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.18.6` to `^2.18.7`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.18.6` to `^2.18.7`" + } + ] + } + }, + { + "version": "2.18.6", + "tag": "@boostercloud/framework-core_v2.18.6", + "date": "Mon, 25 Nov 2024 15:49:50 GMT", + "comments": { + "patch": [ + { + "comment": "Fixes optimistic concurrency issue found when projecting read models", + "author": "Mario Castro Squella ", + "commit": "55cc944003d23a62fec52ee945fc2bcd693f52aa" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.18.5` to `^2.18.6`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.18.5` to `^2.18.6`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.18.5` to `^2.18.6`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.18.5` to `^2.18.6`" + } + ] + } + }, + { + "version": "2.18.5", + "tag": "@boostercloud/framework-core_v2.18.5", + "date": "Tue, 29 Oct 2024 18:40:31 GMT", + "comments": { + "patch": [ + { + "comment": "Add mandatory subscriptionId property", + "author": "Mario Castro Squella ", + "commit": "cedee762449c2443fcc29901cd6e5d7a35d48d61" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.18.4` to `^2.18.5`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.18.4` to `^2.18.5`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.18.4` to `^2.18.5`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.18.4` to `^2.18.5`" + } + ] + } + }, + { + "version": "2.18.4", + "tag": "@boostercloud/framework-core_v2.18.4", + "date": "Tue, 08 Oct 2024 15:06:52 GMT", + "comments": { + "patch": [ + { + "comment": "Remove unnecessary @cdktf/provider-azurerm dependency from Azure provider package", + "author": "Mario Castro Squella ", + "commit": "1c97d6dcef1799207e21a8368827f02f2a0e0b77" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.18.3` to `^2.18.4`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.18.3` to `^2.18.4`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.18.3` to `^2.18.4`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.18.3` to `^2.18.4`" + } + ] + } + }, + { + "version": "2.18.3", + "tag": "@boostercloud/framework-core_v2.18.3", + "date": "Mon, 30 Sep 2024 19:09:52 GMT", + "comments": { + "patch": [ + { + "comment": "Fix handling of deeply-nested arrays an sub-array properties in Read Model queries in local provider", + "author": "Mario Castro Squella ", + "commit": "985272012a7183fb690ecdd7bcfafd42e3103539" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.18.2` to `^2.18.3`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.18.2` to `^2.18.3`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.18.2` to `^2.18.3`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.18.2` to `^2.18.3`" + } + ] + } + }, + { + "version": "2.18.2", + "tag": "@boostercloud/framework-core_v2.18.2", + "date": "Wed, 25 Sep 2024 18:23:11 GMT", + "comments": { + "patch": [ + { + "comment": "Correct handling of deeply-nested arrays and sub-array properties in Read Model queries", + "author": "Mario Castro Squella ", + "commit": "d5ed5375fe31d8a9ee055700f09d293b03af6809" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.18.1` to `^2.18.2`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.18.1` to `^2.18.2`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.18.1` to `^2.18.2`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.18.1` to `^2.18.2`" + } + ] + } + }, + { + "version": "2.18.1", + "tag": "@boostercloud/framework-core_v2.18.1", + "date": "Wed, 04 Sep 2024 18:51:46 GMT", + "comments": { + "patch": [ + { + "comment": "Fix types for Projects decorator", + "author": "Mario Castro Squella ", + "commit": "adf2902a7c508aab6782e29fa8e24c4e5cb105a4" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.18.0` to `^2.18.1`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.18.0` to `^2.18.1`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.18.0` to `^2.18.1`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.18.0` to `^2.18.1`" + } + ] + } + }, + { + "version": "2.18.0", + "tag": "@boostercloud/framework-core_v2.18.0", + "date": "Thu, 29 Aug 2024 21:39:42 GMT", + "comments": { + "minor": [ + { + "comment": "Add remove events", + "author": "gonzalojaubert <111118818+gonzalojaubert@users.noreply.github.com>", + "commit": "b791d832afddb29f65ee07ebb6b54b16d835810b" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.17.0` to `^2.18.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.17.0` to `^2.18.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.17.0` to `^2.18.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.17.0` to `^2.18.0`" + } + ] + } + }, + { + "version": "2.17.0", + "tag": "@boostercloud/framework-core_v2.17.0", + "date": "Wed, 21 Aug 2024 00:15:44 GMT", + "comments": { + "minor": [ + { + "comment": "Health sensors for Rockets", + "author": "Mario Castro Squella ", + "commit": "cb500c908e459897f7ab5f5d8acc46a71b310be6" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.16.0` to `^2.17.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.16.0` to `^2.17.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.16.0` to `^2.17.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.16.0` to `^2.17.0`" + } + ] + } + }, + { + "version": "2.16.0", + "tag": "@boostercloud/framework-core_v2.16.0", + "date": "Tue, 06 Aug 2024 20:59:53 GMT", + "comments": { + "minor": [ + { + "comment": "Improve GlobalErrorHandler", + "author": "gonzalojaubert <111118818+gonzalojaubert@users.noreply.github.com>", + "commit": "84b93bc513693f326b766678e423c2d669d18b94" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.15.0` to `^2.16.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.15.0` to `^2.16.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.15.0` to `^2.16.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.15.0` to `^2.16.0`" + } + ] + } + }, + { + "version": "2.15.0", + "tag": "@boostercloud/framework-core_v2.15.0", + "date": "Wed, 31 Jul 2024 14:54:27 GMT", + "comments": { + "minor": [ + { + "comment": "Handle non-found events with global error handler", + "author": "gonzalojaubert <111118818+gonzalojaubert@users.noreply.github.com>", + "commit": "c474f64af3439b15339cd2a6cef31969f568d52c" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.14.0` to `^2.15.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.14.0` to `^2.15.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.14.0` to `^2.15.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.14.0` to `^2.15.0`" + } + ] + } + }, + { + "version": "2.14.0", + "tag": "@boostercloud/framework-core_v2.14.0", + "date": "Tue, 30 Jul 2024 18:43:55 GMT", + "comments": { + "minor": [ + { + "comment": "Read Models projections by ReadModel query", + "author": "gonzalojaubert <111118818+gonzalojaubert@users.noreply.github.com>", + "commit": "2abba631c47a71d6b886f752ade48c0efe57accf" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.13.1` to `^2.14.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.13.1` to `^2.14.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.13.1` to `^2.14.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.13.1` to `^2.14.0`" + } + ] + } + }, + { + "version": "2.13.1", + "tag": "@boostercloud/framework-core_v2.13.1", + "date": "Fri, 26 Jul 2024 09:36:18 GMT", + "comments": { + "patch": [ + { + "comment": "Bump ws version (fixes CVE-2024-37890)", + "author": "Mario Castro Squella ", + "commit": "229be3f7a4326f3abe8bd95841dc771008c169e9" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.13.0` to `^2.13.1`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.13.0` to `^2.13.1`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.13.0` to `^2.13.1`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.13.0` to `^2.13.1`" + } + ] + } + }, + { + "version": "2.13.0", + "tag": "@boostercloud/framework-core_v2.13.0", + "date": "Fri, 19 Jul 2024 16:36:39 GMT", + "comments": { + "minor": [ + { + "comment": "Improve support for calculated fields and their dependencies on read models", + "author": "Mario Castro Squella ", + "commit": "177b0386069f6467a0fbe11857b403cc3cbc0f29" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@boostercloud/framework-common-helpers\" from `^2.12.1` to `^2.13.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/framework-types\" from `^2.12.1` to `^2.13.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/metadata-booster\" from `^2.12.1` to `^2.13.0`" + }, + { + "comment": "Updating dependency \"@boostercloud/eslint-config\" from `^2.12.1` to `^2.13.0`" + } + ] + } + }, { "version": "2.12.1", "tag": "@boostercloud/framework-core_v2.12.1", diff --git a/packages/framework-core/CHANGELOG.md b/packages/framework-core/CHANGELOG.md index 2612b3ccf3..e9e4ec269d 100644 --- a/packages/framework-core/CHANGELOG.md +++ b/packages/framework-core/CHANGELOG.md @@ -1,6 +1,104 @@ # Change Log - @boostercloud/framework-core -This log was last generated on Thu, 13 Jun 2024 16:17:26 GMT and should not be manually modified. +This log was last generated on Mon, 09 Dec 2024 14:07:07 GMT and should not be manually modified. + +## 2.18.7 +Mon, 09 Dec 2024 14:07:07 GMT + +### Patches + +- Replace child-process-promise with execa + +## 2.18.6 +Mon, 25 Nov 2024 15:49:50 GMT + +### Patches + +- Fixes optimistic concurrency issue found when projecting read models + +## 2.18.5 +Tue, 29 Oct 2024 18:40:31 GMT + +### Patches + +- Add mandatory subscriptionId property + +## 2.18.4 +Tue, 08 Oct 2024 15:06:52 GMT + +### Patches + +- Remove unnecessary @cdktf/provider-azurerm dependency from Azure provider package + +## 2.18.3 +Mon, 30 Sep 2024 19:09:52 GMT + +### Patches + +- Fix handling of deeply-nested arrays an sub-array properties in Read Model queries in local provider + +## 2.18.2 +Wed, 25 Sep 2024 18:23:11 GMT + +### Patches + +- Correct handling of deeply-nested arrays and sub-array properties in Read Model queries + +## 2.18.1 +Wed, 04 Sep 2024 18:51:46 GMT + +### Patches + +- Fix types for Projects decorator + +## 2.18.0 +Thu, 29 Aug 2024 21:39:42 GMT + +### Minor changes + +- Add remove events + +## 2.17.0 +Wed, 21 Aug 2024 00:15:44 GMT + +### Minor changes + +- Health sensors for Rockets + +## 2.16.0 +Tue, 06 Aug 2024 20:59:53 GMT + +### Minor changes + +- Improve GlobalErrorHandler + +## 2.15.0 +Wed, 31 Jul 2024 14:54:27 GMT + +### Minor changes + +- Handle non-found events with global error handler + +## 2.14.0 +Tue, 30 Jul 2024 18:43:55 GMT + +### Minor changes + +- Read Models projections by ReadModel query + +## 2.13.1 +Fri, 26 Jul 2024 09:36:18 GMT + +### Patches + +- Bump ws version (fixes CVE-2024-37890) + +## 2.13.0 +Fri, 19 Jul 2024 16:36:39 GMT + +### Minor changes + +- Improve support for calculated fields and their dependencies on read models ## 2.12.1 Thu, 13 Jun 2024 16:17:26 GMT diff --git a/packages/framework-core/package.json b/packages/framework-core/package.json index 6633a0c755..745e6f1a70 100644 --- a/packages/framework-core/package.json +++ b/packages/framework-core/package.json @@ -1,6 +1,6 @@ { "name": "@boostercloud/framework-core", - "version": "2.12.1", + "version": "2.18.7", "description": "Library for your Booster apps", "author": "Boosterin Labs SLU", "homepage": "https://boosterframework.com", @@ -37,8 +37,8 @@ "graphql": "^16.6.0" }, "dependencies": { - "@boostercloud/framework-common-helpers": "workspace:^2.12.1", - "@boostercloud/framework-types": "workspace:^2.12.1", + "@boostercloud/framework-common-helpers": "workspace:^2.18.7", + "@boostercloud/framework-types": "workspace:^2.18.7", "fp-ts": "^2.11.0", "graphql-scalars": "^1.17.0", "graphql-subscriptions": "2.0.0", @@ -58,11 +58,11 @@ "@effect/typeclass": "0.23.17", "@effect/printer-ansi": "0.32.26", "@effect/platform-node": "0.45.26", - "ws": "8.12.0" + "ws": "8.17.1" }, "devDependencies": { - "@boostercloud/metadata-booster": "workspace:^2.12.1", - "@boostercloud/eslint-config": "workspace:^2.12.1", + "@boostercloud/metadata-booster": "workspace:^2.18.7", + "@boostercloud/eslint-config": "workspace:^2.18.7", "@types/chai": "4.2.18", "@types/chai-as-promised": "7.1.4", "@types/faker": "5.1.5", diff --git a/packages/framework-core/src/booster-command-dispatcher.ts b/packages/framework-core/src/booster-command-dispatcher.ts index d36844480a..cf7fdc3b0b 100644 --- a/packages/framework-core/src/booster-command-dispatcher.ts +++ b/packages/framework-core/src/booster-command-dispatcher.ts @@ -63,7 +63,9 @@ export class BoosterCommandDispatcher { result = await commandClass.handle(commandInstance, register) } catch (err) { const e = err as Error - const error = await this.globalErrorDispatcher.dispatch(new CommandHandlerGlobalError(migratedCommandEnvelope, e)) + const error = await this.globalErrorDispatcher.dispatch( + new CommandHandlerGlobalError(migratedCommandEnvelope, commandMetadata, e) + ) if (error) throw error } logger.debug('Command dispatched with register: ', register) diff --git a/packages/framework-core/src/booster-delete-event-dispatcher.ts b/packages/framework-core/src/booster-delete-event-dispatcher.ts new file mode 100644 index 0000000000..2f92c7e544 --- /dev/null +++ b/packages/framework-core/src/booster-delete-event-dispatcher.ts @@ -0,0 +1,21 @@ +import { BoosterConfig, EventDeleteParameters } from '@boostercloud/framework-types' +import { ReadModelStore } from './services/read-model-store' + +export class BoosterDeleteEventDispatcher { + public static async deleteEvent(config: BoosterConfig, parameters: EventDeleteParameters): Promise { + const readModelStore = new ReadModelStore(config) + const events = await config.provider.events.findDeletableEvent(config, parameters) + if (!events || events.length === 0) { + return false + } + for (const event of events) { + const snapshots = await config.provider.events.findDeletableSnapshot(config, event) + for (const snapshot of snapshots) { + await readModelStore.project(snapshot, true) + } + await config.provider.events.deleteSnapshot(config, snapshots) + } + await config.provider.events.deleteEvent(config, events) + return true + } +} diff --git a/packages/framework-core/src/booster-event-dispatcher.ts b/packages/framework-core/src/booster-event-dispatcher.ts index 7db977dda2..4f9dd7709d 100644 --- a/packages/framework-core/src/booster-event-dispatcher.ts +++ b/packages/framework-core/src/booster-event-dispatcher.ts @@ -1,8 +1,8 @@ import { BoosterConfig, TraceActionTypes } from '@boostercloud/framework-types' import { EventStore } from './services/event-store' import { RawEventsParser } from './services/raw-events-parser' -import { ReadModelStore } from './services/read-model-store' import { getLogger } from '@boostercloud/framework-common-helpers' +import { ReadModelStore } from './services/read-model-store' import { Trace } from './instrumentation' import { BoosterEventProcessor } from './booster-event-processor' diff --git a/packages/framework-core/src/booster-event-processor.ts b/packages/framework-core/src/booster-event-processor.ts index 1bd71ec8e1..9abb8ec2d1 100644 --- a/packages/framework-core/src/booster-event-processor.ts +++ b/packages/framework-core/src/booster-event-processor.ts @@ -127,10 +127,14 @@ export class BoosterEventProcessor { ): Promise { const register = new Register(eventEnvelope.requestID, {}, RegisterHandler.flush, eventEnvelope.currentUser) try { + const logger = getLogger(config, 'BoosterEventProcessor#handleEvent') + logger.debug('Calling "handle" method on event handler: ', eventHandler) await eventHandler.handle(eventInstance, register) } catch (e) { const globalErrorDispatcher = new BoosterGlobalErrorDispatcher(config) - const error = await globalErrorDispatcher.dispatch(new EventHandlerGlobalError(eventInstance, e)) + const error = await globalErrorDispatcher.dispatch( + new EventHandlerGlobalError(eventEnvelope, eventInstance, e.eventHandlerMetadata, e) + ) if (error) throw error } await RegisterHandler.handle(config, register) diff --git a/packages/framework-core/src/booster-global-error-dispatcher.ts b/packages/framework-core/src/booster-global-error-dispatcher.ts index ed13ae7dbe..5bec87a697 100644 --- a/packages/framework-core/src/booster-global-error-dispatcher.ts +++ b/packages/framework-core/src/booster-global-error-dispatcher.ts @@ -9,6 +9,7 @@ import { ProjectionGlobalError, SnapshotPersistHandlerGlobalError, QueryHandlerGlobalError, + EventGlobalError, } from '@boostercloud/framework-types' import { getLogger } from '@boostercloud/framework-common-helpers' @@ -48,14 +49,14 @@ export class BoosterGlobalErrorDispatcher { case SnapshotPersistHandlerGlobalError: newError = await this.handleSnapshotPersistError(error) break + case EventGlobalError: + newError = await this.handleEventError(error) + break } newError = await this.handleGenericError(newError) } catch (e) { - logger.error( - `Unhandled error inside the global error handler. When handling error ${error.originalError}, another error occurred`, - e - ) + logger.error(`Unhandled error inside the global error handler. When handling error ${error.originalError}`, e) return e } if (newError) return newError @@ -65,7 +66,11 @@ export class BoosterGlobalErrorDispatcher { private async handleCommandError(error: GlobalErrorContainer): Promise { if (!this.errorHandler || !this.errorHandler.onCommandHandlerError) throw error.originalError const currentError = error as CommandHandlerGlobalError - return await this.errorHandler.onCommandHandlerError(currentError.originalError, currentError.command) + return await this.errorHandler.onCommandHandlerError( + currentError.originalError, + currentError.commandEnvelope, + currentError.commandMetadata + ) } private async handleQueryError(error: GlobalErrorContainer): Promise { @@ -77,20 +82,31 @@ export class BoosterGlobalErrorDispatcher { private async handleScheduleError(error: GlobalErrorContainer): Promise { if (!this.errorHandler || !this.errorHandler.onScheduledCommandHandlerError) throw error.originalError const currentError = error as ScheduleCommandGlobalError - return await this.errorHandler.onScheduledCommandHandlerError(currentError.originalError) + return await this.errorHandler.onScheduledCommandHandlerError( + currentError.originalError, + currentError.scheduleCommandEnvelope, + currentError.scheduleCommandMetadata + ) } private async handleEventHandlerError(error: GlobalErrorContainer): Promise { if (!this.errorHandler || !this.errorHandler.onDispatchEventHandlerError) throw error.originalError const currentError = error as EventHandlerGlobalError - return await this.errorHandler.onDispatchEventHandlerError(currentError.originalError, currentError.eventInstance) + return await this.errorHandler.onDispatchEventHandlerError( + currentError.originalError, + currentError.eventEnvelope, + currentError.eventHandlerMetadata, + currentError.eventInstance + ) } - private async handleReducerError(error: GlobalErrorContainer): Promise { + private async handleReducerError(error: GlobalErrorContainer): Promise { if (!this.errorHandler || !this.errorHandler.onReducerError) throw error.originalError const currentError = error as ReducerGlobalError return await this.errorHandler.onReducerError( currentError.originalError, + currentError.eventEnvelope, + currentError.reducerMetadata, currentError.eventInstance, currentError.snapshotInstance ) @@ -101,6 +117,8 @@ export class BoosterGlobalErrorDispatcher { const currentError = error as ProjectionGlobalError return await this.errorHandler.onProjectionError( currentError.originalError, + currentError.entityEnvelope, + currentError.projectionMetadata, currentError.entity, currentError.readModel ) @@ -112,6 +130,12 @@ export class BoosterGlobalErrorDispatcher { return this.errorHandler.onSnapshotPersistError(currentError.originalError, currentError.snapshot) } + private async handleEventError(error: GlobalErrorContainer): Promise { + if (!this.errorHandler || !this.errorHandler.onEventError) throw error.originalError + const currentError = error as EventGlobalError + return await this.errorHandler.onEventError(currentError.originalError, currentError.eventEnvelope) + } + private async handleGenericError(error: Error | undefined): Promise { if (!error) return undefined if (!this.errorHandler || !this.errorHandler.onError) throw error diff --git a/packages/framework-core/src/booster-read-models-reader.ts b/packages/framework-core/src/booster-read-models-reader.ts index 0792069526..0e9255871a 100644 --- a/packages/framework-core/src/booster-read-models-reader.ts +++ b/packages/framework-core/src/booster-read-models-reader.ts @@ -1,25 +1,34 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { - TraceActionTypes, AnyClass, BoosterConfig, FilterFor, GraphQLOperation, InvalidParameterError, NotFoundError, + ProjectionFor, ReadModelInterface, ReadModelListResult, + ReadModelMetadata, ReadModelRequestEnvelope, ReadOnlyNonEmptyArray, + SequenceKey, SortFor, SubscriptionEnvelope, - ProjectionFor, + TraceActionTypes, + UUID, } from '@boostercloud/framework-types' -import { createInstance, createInstances, getLogger } from '@boostercloud/framework-common-helpers' +import { + createInstance, + createInstances, + createInstanceWithCalculatedProperties, + getLogger, +} from '@boostercloud/framework-common-helpers' import { Booster } from './booster' import { applyReadModelRequestBeforeFunctions } from './services/filter-helpers' import { ReadModelSchemaMigrator } from './read-model-schema-migrator' import { Trace } from './instrumentation' +import { PropertyMetadata } from '@boostercloud/metadata-booster' export class BoosterReadModelsReader { public constructor(readonly config: BoosterConfig) {} @@ -88,6 +97,23 @@ export class BoosterReadModelsReader { select?: ProjectionFor ): Promise | ReadModelListResult> { const readModelName = readModelClass.name + + let selectWithDependencies: ProjectionFor | undefined = undefined + const calculatedFieldsDependencies = this.getCalculatedFieldsDependencies(readModelClass) + + if (select && Object.keys(calculatedFieldsDependencies).length > 0) { + const extendedSelect = new Set(select) + + select.forEach((field: any) => { + const topLevelField = field.split('.')[0].replace('[]', '') + if (calculatedFieldsDependencies[topLevelField]) { + calculatedFieldsDependencies[topLevelField].map((dependency) => extendedSelect.add(dependency)) + } + }) + + selectWithDependencies = Array.from(extendedSelect) as ProjectionFor + } + const searchResult = await this.config.provider.readModels.search( this.config, readModelName, @@ -96,16 +122,28 @@ export class BoosterReadModelsReader { limit, afterCursor, paginatedVersion ?? false, - select + selectWithDependencies ?? select ) + const readModels = this.createReadModelInstances(searchResult, readModelClass) if (select) { - return searchResult + return this.createReadModelInstancesWithCalculatedProperties(searchResult, readModelClass, select ?? []) } - const readModels = this.createReadModelInstances(searchResult, readModelClass) return this.migrateReadModels(readModels, readModelName) } + public async finderByIdFunction( + readModelClass: AnyClass, + id: UUID, + sequenceKey?: SequenceKey + ): Promise | TReadModel> { + const readModels = await this.config.provider.readModels.fetch(this.config, readModelClass.name, id, sequenceKey) + if (sequenceKey) { + return readModels as ReadOnlyNonEmptyArray + } + return readModels[0] as TReadModel + } + private async migrateReadModels( readModels: Array | ReadModelListResult, readModelName: string @@ -133,6 +171,34 @@ export class BoosterReadModelsReader { } } + /** + * Creates instances of the read model class with the calculated properties included + * @param searchResult The search result + * @param readModelClass The read model class + * @param propertiesToInclude The properties to include in the response + * @private + */ + private async createReadModelInstancesWithCalculatedProperties( + searchResult: Array | ReadModelListResult, + readModelClass: AnyClass, + propertiesToInclude: ProjectionFor + ): Promise | ReadModelListResult> { + const processInstance = async (raw: Partial): Promise => { + const instance = await createInstanceWithCalculatedProperties(readModelClass, raw, propertiesToInclude) + return instance as TReadModel + } + + if (Array.isArray(searchResult)) { + return await Promise.all(searchResult.map(processInstance)) + } else { + const processedItems = await Promise.all(searchResult.items.map(processInstance)) + return { + ...searchResult, + items: processedItems, + } + } + } + public async subscribe( connectionID: string, readModelRequest: ReadModelRequestEnvelope, @@ -216,4 +282,20 @@ export class BoosterReadModelsReader { } return this.config.provider.readModels.subscribe(this.config, subscription) } + + /** + * Returns the dependencies of the calculated fields of a read model + * @param readModelClass The read model class + * @private + */ + private getCalculatedFieldsDependencies(readModelClass: AnyClass): Record> { + const readModelMetadata: ReadModelMetadata = this.config.readModels[readModelClass.name] + + const dependenciesMap: Record> = {} + readModelMetadata?.properties.map((property: PropertyMetadata): void => { + dependenciesMap[property.name] = property.dependencies + }) + + return dependenciesMap + } } diff --git a/packages/framework-core/src/booster-scheduled-command-dispatcher.ts b/packages/framework-core/src/booster-scheduled-command-dispatcher.ts index 7d79e65862..3c953c8ea9 100644 --- a/packages/framework-core/src/booster-scheduled-command-dispatcher.ts +++ b/packages/framework-core/src/booster-scheduled-command-dispatcher.ts @@ -43,7 +43,9 @@ export class BoosterScheduledCommandDispatcher { logger.debug('Calling "handle" method on command: ', command) await command.handle(register) } catch (e) { - const error = await this.globalErrorDispatcher.dispatch(new ScheduleCommandGlobalError(e)) + const error = await this.globalErrorDispatcher.dispatch( + new ScheduleCommandGlobalError(commandEnvelope, commandMetadata, e) + ) if (error) throw error } logger.debug('Command dispatched with register: ', register) diff --git a/packages/framework-core/src/booster.ts b/packages/framework-core/src/booster.ts index 15fe1f26f3..eec3dc0b4c 100644 --- a/packages/framework-core/src/booster.ts +++ b/packages/framework-core/src/booster.ts @@ -1,19 +1,15 @@ import { createInstance } from '@boostercloud/framework-common-helpers' import { - AnyClass, BoosterConfig, BoosterConfigTag, Class, EntityInterface, + EventDeleteParameters, EventSearchParameters, EventSearchResponse, - FinderByKeyFunction, PaginatedEntitiesIdsResult, ReadModelInterface, - ReadOnlyNonEmptyArray, Searcher, - SearcherFunction, - SequenceKey, UUID, } from '@boostercloud/framework-types' import { Importer } from './importer' @@ -24,8 +20,9 @@ import { BoosterDataMigrationStarted } from './core-concepts/data-migration/even import { BoosterDataMigrationFinished } from './core-concepts/data-migration/events/booster-data-migration-finished' import { JwksUriTokenVerifier, JWT_ENV_VARS } from './services/token-verifiers' import { BoosterAuthorizer } from './booster-authorizer' -import { BoosterReadModelsReader } from './booster-read-models-reader' import { BoosterEntityTouched } from './core-concepts/touch-entity/events/booster-entity-touched' +import { readModelSearcher } from './services/read-model-searcher' +import { BoosterDeleteEventDispatcher } from './booster-delete-event-dispatcher' import { eventSearch } from './booster-event-search' import { Effect, pipe } from 'effect' import { Command } from '@effect/cli' @@ -107,22 +104,7 @@ export class Booster { public static readModel( readModelClass: Class ): Searcher { - const finderByIdFunction: FinderByKeyFunction = async ( - readModelClass: AnyClass, - id: UUID, - sequenceKey?: SequenceKey - ) => { - const readModels = await this.config.provider.readModels.fetch(this.config, readModelClass.name, id, sequenceKey) - if (sequenceKey) { - return readModels as ReadOnlyNonEmptyArray - } - return readModels[0] as TReadModel - } - const boosterReadModelsReader = new BoosterReadModelsReader(this.config) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const searcherFunction: SearcherFunction = - boosterReadModelsReader.readModelSearch.bind(boosterReadModelsReader) - return new Searcher(readModelClass, searcherFunction, finderByIdFunction) + return readModelSearcher(this.config, readModelClass) } public static async events(request: EventSearchParameters): Promise> { @@ -137,6 +119,10 @@ export class Booster { return await this.config.provider.events.searchEntitiesIDs(this.config, limit, afterCursor, entityTypeName) } + public static async deleteEvent(parameters: EventDeleteParameters): Promise { + return await BoosterDeleteEventDispatcher.deleteEvent(this.config, parameters) + } + /** * Fetches the last known version of an entity * @param entityClass Name of the entity class diff --git a/packages/framework-core/src/decorators/projects.ts b/packages/framework-core/src/decorators/projects.ts index 477bacd12e..e144470160 100644 --- a/packages/framework-core/src/decorators/projects.ts +++ b/packages/framework-core/src/decorators/projects.ts @@ -2,49 +2,130 @@ import { Booster } from '../booster' import { Class, EntityInterface, + ProjectionInfo, ProjectionMetadata, ProjectionResult, ReadModelInterface, + ReadModelJoinKeyFunction, UUID, } from '@boostercloud/framework-types' -type PropType = TObj[TProp] +type PropertyType = TObj[TProp] +type JoinKeyType = + | keyof TEntity + | ReadModelJoinKeyFunction +type UUIDLike = string | UUID /** * Decorator to register a read model method as a projection * for a specific entity * * @param originEntity The entity that this method will react to + * @param joinKey + * @param unProject */ -export function Projects( +export function Projects< + TEntity extends EntityInterface, + TJoinKey extends keyof TEntity, + TReadModel extends ReadModelInterface +>( originEntity: Class, - joinKey: TJoinKey -): ( - readModelClass: Class, + joinKey: JoinKeyType, + unProject?: UnprojectionMethod> +): ( + readModelClass: Class, methodName: string, - methodDescriptor: ProjectionMethod> + methodDescriptor: ProjectionMethod> ) => void { return (readModelClass, methodName) => { const projectionMetadata = { - joinKey, + joinKey: joinKey, class: readModelClass, methodName: methodName, - } as ProjectionMetadata + } as ProjectionMetadata registerProjection(originEntity.name, projectionMetadata) + if (unProject) { + const unProjectionMetadata = { + joinKey, + class: readModelClass, + methodName: unProject.name, + } as ProjectionMetadata + registerUnProjection(originEntity.name, unProjectionMetadata) + } } } -function registerProjection(originName: string, projectionMetadata: ProjectionMetadata): void { +function registerProjection( + originName: string, + projectionMetadata: ProjectionMetadata +): void { Booster.configureCurrentEnv((config): void => { - const entityProjections = config.projections[originName] || [] - if (entityProjections.indexOf(projectionMetadata) < 0) { - // Skip duplicate registrations - entityProjections.push(projectionMetadata) - config.projections[originName] = entityProjections - } + configure(originName, projectionMetadata, config.projections) + }) +} + +function registerUnProjection( + originName: string, + projectionMetadata: ProjectionMetadata +): void { + Booster.configureCurrentEnv((config): void => { + configure(originName, projectionMetadata, config.unProjections) }) } -type ProjectionMethod = TPropType extends Array - ? TypedPropertyDescriptor<(_: TEntity, readModelID: UUID, readModel?: TReadModel) => ProjectionResult> - : TypedPropertyDescriptor<(_: TEntity, readModel?: TReadModel) => ProjectionResult> +function configure( + originName: string, + projectionMetadata: ProjectionMetadata, + configuration: Record>> +): void { + const entityProjections = configuration[originName] || [] + if (entityProjections.indexOf(projectionMetadata) < 0) { + // Skip duplicate registrations + entityProjections.push(projectionMetadata) + configuration[originName] = entityProjections + } +} + +type ProjectionMethodDefinitionForArray = ( + _: TEntity, + readModelID: UUID, + readModel?: TReadModel, + projectionInfo?: ProjectionInfo +) => ProjectionResult + +type ProjectionMethodDefinition = ( + _: TEntity, + readModel?: TReadModel, + projectionInfo?: ProjectionInfo +) => ProjectionResult + +type ProjectionMethod< + TEntity extends EntityInterface, + TReadModel extends ReadModelInterface, + TJoinKeyType extends JoinKeyType +> = TJoinKeyType extends ReadModelJoinKeyFunction + ? ProjectionMethodWithEntityConditionalReadModelIdAndReadModel + : TJoinKeyType extends keyof TEntity + ? NonNullable> extends Array + ? ProjectionMethodWithEntityReadModelIdAndReadModel + : ProjectionMethodWithEntityAndReadModel + : never + +type ProjectionMethodWithEntityAndReadModel = + TypedPropertyDescriptor<(_: TEntity, readModel?: TReadModel) => ProjectionResult> + +type ProjectionMethodWithEntityConditionalReadModelIdAndReadModel< + TEntity extends EntityInterface, + TReadModel extends ReadModelInterface +> = TypedPropertyDescriptor< + (_: TEntity, readModelID: UUID | undefined, readModel?: TReadModel) => ProjectionResult +> + +type ProjectionMethodWithEntityReadModelIdAndReadModel< + TEntity extends EntityInterface, + TReadModel extends ReadModelInterface +> = TypedPropertyDescriptor<(_: TEntity, readModelID: UUID, readModel?: TReadModel) => ProjectionResult> + +type UnprojectionMethod = TPropType extends Array + ? ProjectionMethodDefinitionForArray + : ProjectionMethodDefinition diff --git a/packages/framework-core/src/decorators/read-model.ts b/packages/framework-core/src/decorators/read-model.ts index 4c32dd1c14..6c9fbfee5b 100644 --- a/packages/framework-core/src/decorators/read-model.ts +++ b/packages/framework-core/src/decorators/read-model.ts @@ -24,12 +24,39 @@ export function ReadModel( } const authorizer = BoosterAuthorizer.build(attributes) as ReadModelAuthorizer + const classMetadata = getClassMetadata(readModelClass) + const dynamicDependencies = Reflect.getMetadata('dynamic:dependencies', readModelClass) || {} + + // Combine properties with dynamic dependencies + const properties = classMetadata.fields.map((field: any) => { + return { + ...field, + dependencies: dynamicDependencies[field.name] || [], + } + }) + config.readModels[readModelClass.name] = { class: readModelClass, - properties: getClassMetadata(readModelClass).fields, + properties, authorizer, before: attributes.before ?? [], } }) } } + +interface CalculatedFieldOptions { + dependsOn: string[] +} + +/** + * Decorator to mark a property as a calculated field with dependencies. + * @param options - A `CalculatedFieldOptions` object indicating the dependencies. + */ +export function CalculatedField(options: CalculatedFieldOptions): PropertyDecorator { + return (target: object, propertyKey: string | symbol): void => { + const existingDependencies = Reflect.getMetadata('dynamic:dependencies', target.constructor) || {} + existingDependencies[propertyKey] = options.dependsOn + Reflect.defineMetadata('dynamic:dependencies', existingDependencies, target.constructor) + } +} diff --git a/packages/framework-core/src/sensor/health/booster-health-service.ts b/packages/framework-core/src/sensor/health/booster-health-service.ts index ad2e383a64..5bd68ac639 100644 --- a/packages/framework-core/src/sensor/health/booster-health-service.ts +++ b/packages/framework-core/src/sensor/health/booster-health-service.ts @@ -7,7 +7,7 @@ import { HealthIndicatorsResult, UserEnvelope, } from '@boostercloud/framework-types' -import { childrenHealthProviders, isEnabled, metadataFromId, rootHealthProviders } from './health-utils' +import { childHealthProviders, isEnabled, metadataFromId, rootHealthProviders } from './health-utils' import { createInstance } from '@boostercloud/framework-common-helpers' import { defaultBoosterHealthIndicators } from './health-indicators' import { BoosterTokenVerifier } from '../../booster-token-verifier' @@ -51,14 +51,14 @@ export class BoosterHealthService { if (!indicatorResult) { continue } - const childrens = childrenHealthProviders(current, healthProviders) + const children = childHealthProviders(current, healthProviders) const newResult: HealthIndicatorsResult = { ...indicatorResult, name: current.healthIndicatorConfiguration.name, id: current.healthIndicatorConfiguration.id, } - if (childrens && childrens?.length > 0) { - newResult.components = await this.boosterHealthProviderResolver(childrens, healthProviders) + if (children && children?.length > 0) { + newResult.components = await this.boosterHealthProviderResolver(children, healthProviders) } result.push(newResult) } diff --git a/packages/framework-core/src/sensor/health/health-indicators/default-booster-health-indicators.ts b/packages/framework-core/src/sensor/health/health-indicators/default-booster-health-indicators.ts index 05eca56113..3e2787cdd2 100644 --- a/packages/framework-core/src/sensor/health/health-indicators/default-booster-health-indicators.ts +++ b/packages/framework-core/src/sensor/health/health-indicators/default-booster-health-indicators.ts @@ -10,6 +10,7 @@ import { BoosterDatabaseHealthIndicator } from './booster-database-health-indica import { BoosterDatabaseEventsHealthIndicator } from './booster-database-events-health-indicator' import { BoosterFunctionHealthIndicator } from './booster-function-health-indicator' import { BoosterDatabaseReadModelsHealthIndicator } from './booster-database-read-models-health-indicator' +import { RocketsHealthIndicator } from './rockets-health-indicator' function buildMetadata( config: BoosterConfig, @@ -59,11 +60,18 @@ export function defaultBoosterHealthIndicators(config: BoosterConfig): Record { + const results = await config.provider.sensor.areRocketFunctionsUp(config) + if (Object.keys(results).length === 0) { + return { + name: 'Rockets', + id: BOOSTER_HEALTH_INDICATORS_IDS.ROCKETS, + status: HealthStatus.UNKNOWN, + details: { + reason: 'No Rockets found', + }, + } + } + return { + name: 'Rockets', + id: BOOSTER_HEALTH_INDICATORS_IDS.ROCKETS, + status: this.getOverAllHealthStatus(results), + components: Object.entries(results).map(([rocketFunctionApp, status]) => { + return { + name: rocketFunctionApp, + id: rocketFunctionApp, // @TODO: put the rocket's id instead of its name + status: status ? HealthStatus.UP : HealthStatus.DOWN, + } + }), + } + } + + private getOverAllHealthStatus(results: { [key: string]: boolean }): HealthStatus { + const statusValues = Object.values(results) + + if (statusValues.every((status) => status)) { + return HealthStatus.UP + } + + if (statusValues.every((status) => !status)) { + return HealthStatus.DOWN + } + + return HealthStatus.PARTIALLY_UP + } +} diff --git a/packages/framework-core/src/sensor/health/health-utils.ts b/packages/framework-core/src/sensor/health/health-utils.ts index 40d74542e3..a5373b566c 100644 --- a/packages/framework-core/src/sensor/health/health-utils.ts +++ b/packages/framework-core/src/sensor/health/health-utils.ts @@ -27,7 +27,7 @@ export function rootHealthProviders( ) } -export function childrenHealthProviders( +export function childHealthProviders( healthIndicatorMetadata: HealthIndicatorMetadata, healthProviders: Record ): Array { diff --git a/packages/framework-core/src/services/event-store.ts b/packages/framework-core/src/services/event-store.ts index abdbc50fd8..32aff8fce6 100644 --- a/packages/framework-core/src/services/event-store.ts +++ b/packages/framework-core/src/services/event-store.ts @@ -1,15 +1,19 @@ import { - TraceActionTypes, BOOSTER_SUPER_KIND, BoosterConfig, EntityInterface, EntitySnapshotEnvelope, EventEnvelope, + EventGlobalError, + EventInterface, + EventMetadata, Instance, + InvalidEventError, InvalidParameterError, + InvalidReducerError, NonPersistedEntitySnapshotEnvelope, ReducerGlobalError, - SnapshotPersistHandlerGlobalError, + TraceActionTypes, UUID, } from '@boostercloud/framework-types' import { createInstance, getLogger } from '@boostercloud/framework-common-helpers' @@ -18,9 +22,12 @@ import { SchemaMigrator } from '../schema-migrator' import { BoosterEntityMigrated } from '../core-concepts/data-migration/events/booster-entity-migrated' import { BoosterEntityTouched } from '../core-concepts/touch-entity/events/booster-entity-touched' import { Trace } from '../instrumentation' +import { ReducerMetadata } from '../../../framework-types' const originOfTime = new Date(0).toISOString() // Unix epoch +const boosterReducibleEventsTypesNames: Array = [BoosterEntityMigrated.name, BoosterEntityTouched.name] + export class EventStore { public constructor(readonly config: BoosterConfig) {} @@ -48,9 +55,27 @@ export class EventStore { // In this assignment we discard the `createdAt` field because it's not needed in the reduction process let newEntitySnapshot: NonPersistedEntitySnapshotEnvelope | undefined = latestSnapshotEnvelope for (const pendingEvent of pendingEvents) { - // We double check that what we are reducing is an event + // We double-check that what we are reducing is an event if (pendingEvent.kind === 'event') { - newEntitySnapshot = await this.entityReducer(pendingEvent, newEntitySnapshot) + try { + newEntitySnapshot = await this.entityReducer(pendingEvent, newEntitySnapshot) + } catch (e) { + if (e instanceof InvalidEventError) { + const globalErrorDispatcher = new BoosterGlobalErrorDispatcher(this.config) + const error = await globalErrorDispatcher.dispatch(new EventGlobalError(pendingEvent, e)) + if (error) throw error + continue + } else if (e instanceof InvalidReducerError) { + const globalErrorDispatcher = new BoosterGlobalErrorDispatcher(this.config) + const reducerMetadata = this.config.reducers[pendingEvent.typeName] + const error = await globalErrorDispatcher.dispatch( + new ReducerGlobalError(pendingEvent, e.eventInstance, e.snapshotInstance, reducerMetadata, e) + ) + if (error) throw error + continue + } + throw e + } } } @@ -80,7 +105,7 @@ export class EventStore { logger.debug('Storing event in the dispatched event store:', eventEnvelope) return await this.config.provider.events.storeDispatched(eventEnvelope, this.config) } catch (e) { - logger.debug('Could not store dispatched event. Continue its processing.', {error: e, eventEnvelope }) + logger.debug('Could not store dispatched event. Continue its processing.', { error: e, eventEnvelope }) return true } } @@ -94,15 +119,13 @@ export class EventStore { logger.debug('Storing snapshot in the event store:', snapshot) return await this.config.provider.events.storeSnapshot(snapshot, this.config) } catch (e) { - const globalErrorDispatcher = new BoosterGlobalErrorDispatcher(this.config) - const error = await globalErrorDispatcher.dispatch(new SnapshotPersistHandlerGlobalError(snapshot, e)) logger.error( `The snapshot for entity ${snapshot.typeName} with ID ${ snapshot.entityID } couldn't be stored (Tried on ${new Date()})`, snapshot, '\nError:', - error + e ) return } @@ -135,54 +158,91 @@ export class EventStore { eventEnvelope: EventEnvelope, latestSnapshot?: NonPersistedEntitySnapshotEnvelope ): Promise { - const logger = getLogger(this.config, 'EventStore#entityReducer') + const logger = getLogger(this.config, 'entityReducer') + logger.debug('Calling reducer with event: ', eventEnvelope, ' and entity snapshot ', latestSnapshot) + if (this.shouldReduceBoosterSuperKind(eventEnvelope)) { + return this.reduceSuperKind(eventEnvelope, latestSnapshot) + } + + const eventMetadata = this.eventMetadataFor(eventEnvelope) + const migratedEventEnvelope = await new SchemaMigrator(this.config).migrate(eventEnvelope) + const eventInstance = createInstance(eventMetadata.class, migratedEventEnvelope.value) + const entityMetadata = this.config.entities[migratedEventEnvelope.entityTypeName] + const reducerMetadata = this.config.reducers[eventEnvelope.typeName] + const snapshotInstance = latestSnapshot ? createInstance(entityMetadata.class, latestSnapshot.value) : null + return this.createNewSnapshot( + migratedEventEnvelope, + eventInstance, + snapshotInstance, + eventEnvelope, + reducerMetadata + ) + } + + private shouldReduceBoosterSuperKind(eventEnvelope: EventEnvelope) { + const reducible = boosterReducibleEventsTypesNames.includes(eventEnvelope.typeName) + return eventEnvelope.superKind && eventEnvelope.superKind === BOOSTER_SUPER_KIND && reducible + } + + private eventMetadataFor(eventEnvelope: EventEnvelope): EventMetadata { + const logger = getLogger(this.config, 'eventMetadataFor') + const eventMetadata = this.config.events[eventEnvelope.typeName] + if (!eventMetadata) { + logger.error(`No event registered for event ${eventEnvelope.typeName}`) + throw new InvalidEventError(`No event registered for event ${eventEnvelope.typeName}`) + } + return eventMetadata + } + + private async createNewSnapshot( + migratedEventEnvelope: EventEnvelope, + eventInstance: EventInterface, + snapshotInstance: EntityInterface | null, + eventEnvelope: EventEnvelope, + reducerMetadata: ReducerMetadata + ): Promise { + const logger = getLogger(this.config, 'createNewSnapshot') try { - if (eventEnvelope.superKind && eventEnvelope.superKind === BOOSTER_SUPER_KIND) { - if (eventEnvelope.typeName === BoosterEntityTouched.name) { - return this.reduceEntityTouched(eventEnvelope, latestSnapshot) - } - if (eventEnvelope.typeName === BoosterEntityMigrated.name) { - return this.reduceEntityMigrated(eventEnvelope) - } - } + const newEntity = this.reducerForEvent( + migratedEventEnvelope.typeName, + eventInstance, + snapshotInstance + )(eventInstance, snapshotInstance) - logger.debug('Calling reducer with event: ', eventEnvelope, ' and entity snapshot ', latestSnapshot) - const eventMetadata = this.config.events[eventEnvelope.typeName] - if (!eventMetadata) { - logger.error(`No event registered for event ${eventEnvelope.typeName}`) - throw new InvalidParameterError(`No event registered for event ${eventEnvelope.typeName}`) - } - const migratedEventEnvelope = await new SchemaMigrator(this.config).migrate(eventEnvelope) - const eventInstance = createInstance(eventMetadata.class, migratedEventEnvelope.value) - const entityMetadata = this.config.entities[migratedEventEnvelope.entityTypeName] - const snapshotInstance = latestSnapshot ? createInstance(entityMetadata.class, latestSnapshot.value) : null - try { - const newEntity = this.reducerForEvent(migratedEventEnvelope.typeName)(eventInstance, snapshotInstance) - - const newSnapshot: NonPersistedEntitySnapshotEnvelope = { - version: this.config.currentVersionFor(eventEnvelope.entityTypeName), - kind: 'snapshot', - superKind: migratedEventEnvelope.superKind, - requestID: migratedEventEnvelope.requestID, - entityID: migratedEventEnvelope.entityID, - entityTypeName: migratedEventEnvelope.entityTypeName, - typeName: migratedEventEnvelope.entityTypeName, - value: newEntity, - snapshottedEventCreatedAt: migratedEventEnvelope.createdAt, - } - logger.debug('Reducer result: ', newSnapshot) - return newSnapshot - } catch (e) { - const globalErrorDispatcher = new BoosterGlobalErrorDispatcher(this.config) - const error = await globalErrorDispatcher.dispatch(new ReducerGlobalError(eventInstance, snapshotInstance, e)) - throw error + const newSnapshot: NonPersistedEntitySnapshotEnvelope = { + version: this.config.currentVersionFor(eventEnvelope.entityTypeName), + kind: 'snapshot', + superKind: migratedEventEnvelope.superKind, + requestID: migratedEventEnvelope.requestID, + entityID: migratedEventEnvelope.entityID, + entityTypeName: migratedEventEnvelope.entityTypeName, + typeName: migratedEventEnvelope.entityTypeName, + value: newEntity, + snapshottedEventCreatedAt: migratedEventEnvelope.createdAt, } + logger.debug('Reducer result: ', newSnapshot) + return newSnapshot } catch (e) { - logger.error('Error when calling reducer', e) - throw e + const globalErrorDispatcher = new BoosterGlobalErrorDispatcher(this.config) + throw await globalErrorDispatcher.dispatch( + new ReducerGlobalError(migratedEventEnvelope, eventInstance, snapshotInstance, reducerMetadata, e) + ) } } + private async reduceSuperKind( + eventEnvelope: EventEnvelope, + latestSnapshot?: NonPersistedEntitySnapshotEnvelope + ): Promise { + if (eventEnvelope.typeName === BoosterEntityTouched.name) { + return this.reduceEntityTouched(eventEnvelope, latestSnapshot) + } + if (eventEnvelope.typeName === BoosterEntityMigrated.name) { + return this.reduceEntityMigrated(eventEnvelope) + } + throw new InvalidParameterError(`Unexpected super kind ${eventEnvelope.superKind} to be reduced`) + } + private reduceEntityMigrated(eventEnvelope: EventEnvelope): NonPersistedEntitySnapshotEnvelope { const event = eventEnvelope.value as BoosterEntityMigrated return this.toBoosterEntitySnapshot(eventEnvelope, event.newEntity, event.newEntityName) @@ -226,19 +286,22 @@ export class EventStore { return boosterMigratedSnapshot } - // eslint-disable-next-line @typescript-eslint/ban-types - private reducerForEvent(eventName: string): Function { + private reducerForEvent( + eventName: string, + eventInstance: EventInterface, + snapshotInstance: EntityInterface | null + // eslint-disable-next-line @typescript-eslint/ban-types + ): Function { const logger = getLogger(this.config, 'EventStore#reducerForEvent') const reducerMetadata = this.config.reducers[eventName] if (!reducerMetadata) { - throw new InvalidParameterError(`No reducer registered for event ${eventName}`) + throw new InvalidReducerError(`No reducer registered for event ${eventName}`, eventInstance, snapshotInstance) } else { try { // eslint-disable-next-line @typescript-eslint/no-explicit-any - const reducer = (reducerMetadata.class as any)[reducerMetadata.methodName] - logger.debug( - `Found reducer for event ${eventName}: "${reducerMetadata.class.name}.${reducerMetadata.methodName}"` - ) + const methodName = reducerMetadata.methodName + const reducer = (reducerMetadata.class as any)[methodName] + logger.debug(`Found reducer for event ${eventName}: "${reducerMetadata.class.name}.${methodName}"`) return reducer } catch { throw new Error(`Couldn't load the Entity class ${reducerMetadata.class.name}`) diff --git a/packages/framework-core/src/services/graphql/graphql-type-informer.ts b/packages/framework-core/src/services/graphql/graphql-type-informer.ts index 39fbc8347b..1bd9fada15 100644 --- a/packages/framework-core/src/services/graphql/graphql-type-informer.ts +++ b/packages/framework-core/src/services/graphql/graphql-type-informer.ts @@ -69,6 +69,7 @@ export class GraphQLTypeInformer { if (typeMetadata.typeName && typeMetadata.typeGroup === 'Class') { return typeMetadata.typeName + (inputType ? 'Input' : '') } + if (typeMetadata.typeGroup === 'Union') return typeMetadata.name return typeMetadata.typeName || null } @@ -87,20 +88,35 @@ export class GraphQLTypeInformer { const metadata = getClassMetadata(typeMetadata.type) return this.createObjectType(metadata, inputType) } - if (typeMetadata.typeGroup === 'Union' && typeMetadata.type && !isExternalType(typeMetadata)) { - const graphQLUnionClasses: GraphQLObjectType[] = this.getUnionClasses(typeMetadata, typeGroup, inputType); + if ( + typeMetadata.typeGroup === 'Union' && + !isExternalType(typeMetadata) && + !inputType && + this.validateUnionClasses(typeMetadata.parameters) + ) { + const graphQLUnionClasses: GraphQLObjectType[] = this.getUnionClasses(typeMetadata) return new GraphQLUnionType({ - name: typeMetadata.name, - types: graphQLUnionClasses, }); - } + name: typeMetadata.name, + types: graphQLUnionClasses, + resolveType(obj) { + return obj.constructor.name + }, + }) + } return GraphQLJSON } - private getUnionClasses(typeMetadata: TypeMetadata, typeGroup: string, inputType: boolean): GraphQLObjectType[] { + private validateUnionClasses(params: TypeMetadata[]): boolean { + return params.every( + (typeMetadata) => typeMetadata.typeGroup === 'Class' && typeMetadata.type && !isExternalType(typeMetadata) + ) + } + + private getUnionClasses(typeMetadata: TypeMetadata): GraphQLObjectType[] { return typeMetadata.parameters.map((param: TypeMetadata) => { - if (typeGroup === 'Class' && param.type && !isExternalType(typeMetadata) && !inputType) { + if (param.typeGroup === 'Class' && param.type && !isExternalType(typeMetadata)) { const metadata = getClassMetadata(param.type) - return this.createObjectTypeForUnion(metadata) as GraphQLObjectType + return this.getOrCreateObjectTypeForUnion(metadata) as GraphQLObjectType } else { throw new Error(`Union type ${typeMetadata.name} can only contain classes`) } @@ -150,35 +166,28 @@ export class GraphQLTypeInformer { }, {}), }) } + return this.createOutputObjectType(classMetadata, excludeProps) + } + + private getOrCreateObjectTypeForUnion(classMetadata: ClassMetadata, excludeProps?: Array): GraphQLType { + const typeName = classMetadata.name + if (typeName && this.graphQLTypes[typeName]) return this.graphQLTypes[typeName] + const createdGraphQLType = this.createOutputObjectType(classMetadata, excludeProps) + if (typeName) this.graphQLTypes[typeName] = createdGraphQLType + return createdGraphQLType + } + + private createOutputObjectType(classMetadata: ClassMetadata, excludeProps?: Array): GraphQLObjectType { + const finalFields: Array = nonExcludedFields(classMetadata.fields, excludeProps) return new GraphQLObjectType({ name: classMetadata.name, fields: finalFields?.reduce((obj, prop) => { this.logger.debug(`Get or create GraphQL output type for property ${prop.name}`) return { ...obj, - [prop.name]: { type: this.getOrCreateGraphQLType(prop.typeInfo, inputType) }, + [prop.name]: { type: this.getOrCreateGraphQLType(prop.typeInfo, false) }, } }, {}), }) } - - private createObjectTypeForUnion( - classMetadata: ClassMetadata, - excludeProps?: Array - ): GraphQLObjectType { - const finalFields: Array = nonExcludedFields(classMetadata.fields, excludeProps) - return new GraphQLObjectType({ - name: classMetadata.name, - isTypeOf: (value) => { - return value.constructor.name === classMetadata.type.name - }, - fields: finalFields?.reduce((obj, prop) => { - this.logger.debug(`Get or create GraphQL output type for property ${prop.name}`) - return { - ...obj, - [prop.name]: { type: this.getOrCreateGraphQLType(prop.typeInfo, false) }, - } - }, {}), - }) - } } diff --git a/packages/framework-core/src/services/graphql/query-generators/graphql-query-events-generator.ts b/packages/framework-core/src/services/graphql/query-generators/graphql-query-events-generator.ts index 7c2013c3a2..1c7e2ed37b 100644 --- a/packages/framework-core/src/services/graphql/query-generators/graphql-query-events-generator.ts +++ b/packages/framework-core/src/services/graphql/query-generators/graphql-query-events-generator.ts @@ -72,6 +72,7 @@ export class GraphqlQueryEventsGenerator { }, createdAt: { type: new GraphQLNonNull(GraphQLString) }, value: { type: new GraphQLNonNull(GraphQLJSON) }, + deletedAt: { type: GraphQLString }, }, }) ) diff --git a/packages/framework-core/src/services/raw-events-parser.ts b/packages/framework-core/src/services/raw-events-parser.ts index 1a470351ec..0715b23490 100644 --- a/packages/framework-core/src/services/raw-events-parser.ts +++ b/packages/framework-core/src/services/raw-events-parser.ts @@ -16,7 +16,10 @@ export class RawEventsParser { callbackFn: EventsStreamingCallback ): Promise { const logger = getLogger(config, 'RawEventsParser#streamPerEntityEvents') - const eventEnvelopesPerEntity = eventEnvelopes.filter(isEventKind).reduce(groupByEntity, {}) + const eventEnvelopesPerEntity = eventEnvelopes + .filter(isEventKind) + .filter(isNotDeleted) + .reduce(groupByEntity, {}) const processes = Object.values(eventEnvelopesPerEntity).map(async (entityEnvelopes) => { // All envelopes are for the same entity type/ID, so we get the first one to get those values @@ -43,6 +46,10 @@ function isEventKind(envelope: EventEnvelope): boolean { return envelope.kind == 'event' } +function isNotDeleted(envelope: EventEnvelope): boolean { + return !envelope?.deletedAt +} + function groupByEntity(envelopesPerEntity: EnvelopesPerEntity, envelope: EventEnvelope): EnvelopesPerEntity { const entityKey = `${envelope.entityTypeName}-${envelope.entityID}` if (!envelopesPerEntity[entityKey]) { diff --git a/packages/framework-core/src/services/read-model-searcher.ts b/packages/framework-core/src/services/read-model-searcher.ts new file mode 100644 index 0000000000..1fae992d5a --- /dev/null +++ b/packages/framework-core/src/services/read-model-searcher.ts @@ -0,0 +1,22 @@ +import { + BoosterConfig, + Class, + FinderByKeyFunction, + ReadModelInterface, + Searcher, + SearcherFunction, +} from '@boostercloud/framework-types' +import { BoosterReadModelsReader } from '../booster-read-models-reader' + +export function readModelSearcher( + config: BoosterConfig, + readModelClass: Class +): Searcher { + const boosterReadModelsReader = new BoosterReadModelsReader(config) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const searcherFunction: SearcherFunction = + boosterReadModelsReader.readModelSearch.bind(boosterReadModelsReader) + const finderByIdFunction: FinderByKeyFunction = + boosterReadModelsReader.finderByIdFunction.bind(boosterReadModelsReader) + return new Searcher(readModelClass, searcherFunction, finderByIdFunction) +} diff --git a/packages/framework-core/src/services/read-model-store.ts b/packages/framework-core/src/services/read-model-store.ts index d01d2b1991..2fbbf7f058 100644 --- a/packages/framework-core/src/services/read-model-store.ts +++ b/packages/framework-core/src/services/read-model-store.ts @@ -1,87 +1,196 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { BoosterConfig, - ReadModelInterface, - ProjectionMetadata, - UUID, + BoosterMetadata, EntityInterface, - ReadModelAction, + EntityMetadata, + EntitySnapshotEnvelope, + FilterFor, OptimisticConcurrencyUnexpectedVersionError, - SequenceKey, ProjectionGlobalError, - EntitySnapshotEnvelope, - BoosterMetadata, + ProjectionInfo, + ProjectionInfoReason, + ProjectionMetadata, + ProjectionResult, + ReadModelAction, + ReadModelInterface, + ReadModelJoinKeyFunction, + SequenceKey, + UUID, } from '@boostercloud/framework-types' -import { Promises, retryIfError, createInstance, getLogger } from '@boostercloud/framework-common-helpers' +import { createInstance, getLogger, Promises, retryIfError } from '@boostercloud/framework-common-helpers' import { BoosterGlobalErrorDispatcher } from '../booster-global-error-dispatcher' +import { readModelSearcher } from './read-model-searcher' import { ReadModelSchemaMigrator } from '../read-model-schema-migrator' export class ReadModelStore { public constructor(readonly config: BoosterConfig) {} - public async project(entitySnapshotEnvelope: EntitySnapshotEnvelope): Promise { + public async project(entitySnapshotEnvelope: EntitySnapshotEnvelope, deleteEvent = false): Promise { const logger = getLogger(this.config, 'ReadModelStore#project') - const projections = this.config.projections[entitySnapshotEnvelope.entityTypeName] + const projections = deleteEvent + ? this.getUnProjections(entitySnapshotEnvelope) + : this.entityProjections(entitySnapshotEnvelope) if (!projections) { - logger.debug( - `[ReadModelStore#project] No projections found for entity ${entitySnapshotEnvelope.entityTypeName}. Skipping...` - ) + logger.debug(`No projections found for entity ${entitySnapshotEnvelope.entityTypeName}. Skipping...`) return } + logger.debug( + `Projections found for entity ${entitySnapshotEnvelope.entityTypeName}: ${JSON.stringify(projections)}` + ) const entityMetadata = this.config.entities[entitySnapshotEnvelope.entityTypeName] - await Promises.allSettledAndFulfilled( - projections.flatMap((projectionMetadata: ProjectionMetadata) => { + const entityInstance = createInstance(entityMetadata.class, entitySnapshotEnvelope.value) + const projectReadModelPromises = projections.flatMap( + (projectionMetadata: ProjectionMetadata) => { + logger.debug( + `Projecting entity snapshot ${entitySnapshotEnvelope} to build new state of read model with projectionMetadata ${JSON.stringify( + projectionMetadata + )}` + ) const readModelName = projectionMetadata.class.name - const entityInstance = createInstance(entityMetadata.class, entitySnapshotEnvelope.value) - const readModelIDList = this.joinKeyForProjection(entityInstance, projectionMetadata) const sequenceKey = this.sequenceKeyForProjection(entityInstance, projectionMetadata) - if (!readModelIDList) { - logger.warn( - `Couldn't find the joinKey named ${projectionMetadata.joinKey} in entity snapshot of ${entityMetadata.class.name}. Skipping...` - ) - return - } - - return readModelIDList.map((readModelID: UUID) => { - logger.debug( - '[ReadModelStore#project] Projecting entity snapshot ', - entitySnapshotEnvelope, - ` to build new state of read model ${readModelName} with ID ${readModelID}`, - sequenceKey ? ` sequencing by ${sequenceKey.name} with value ${sequenceKey.value}` : '' - ) + return this.projectEntity( + entityInstance, + projectionMetadata, + entityMetadata, + entitySnapshotEnvelope, + readModelName, + deleteEvent, + sequenceKey + ) + } + ) + await Promises.allSettledAndFulfilled(projectReadModelPromises) + } - return retryIfError( - () => - this.applyProjectionToReadModel( - entityInstance, - projectionMetadata, - readModelName, - readModelID, - sequenceKey, - entitySnapshotEnvelope - ), - OptimisticConcurrencyUnexpectedVersionError, - logger - ) - }) - }) + /** + * Gets the read models for a given entity instance using the projection metadata + * @param {EntityInterface} entityInstance The entity instance to get the read models for + * @param {ProjectionMetadata} projectionMetadata The projection metadata to use to get the read models + * @param {EntityMetadata} entityMetadata The entity metadata for the entity instance + * @returns {Promise>} The read models for the entity instance + */ + public async getReadModels( + entityInstance: EntityInterface, + projectionMetadata: ProjectionMetadata, + entityMetadata: EntityMetadata + ): Promise> { + const logger = getLogger(this.config, 'ReadModelStore#getReadModels') + logger.debug( + `Looking for ReadModels for entity ${JSON.stringify(entityInstance)} using Filter ${projectionMetadata.joinKey}` + ) + const readModelName = projectionMetadata.class.name + const readModelMetadata = this.config.readModels[readModelName] + const filter = this.filterForProjection(entityInstance, projectionMetadata, entityMetadata) + if (!filter) { + return [] + } + logger.debug( + `Calling ReadModelSearcher searching for ReadModels for entity ${readModelMetadata.class.name} using Filter ${filter}` ) + const rawReadModels = (await readModelSearcher(this.config, readModelMetadata.class) + .filter(filter) + .paginatedVersion(false) + .search()) as Array + return this.instanceReadModels(readModelName, rawReadModels) } - private joinKeyForProjection( - entity: EntityInterface, - projectionMetadata: ProjectionMetadata - ): Array | undefined { - const joinKey = (entity as any)[projectionMetadata.joinKey] - if (!joinKey) { + /** + * Gets a specific read model instance referencing it by ID when it's a regular read model + * or by ID + sequenceKey when it's a sequenced read model + * @param {string} readModelName The name of the read model class + * @param {UUID | undefined} readModelID The ID of the read model instance + * @param {SequenceKey} sequenceKey The sequence key of the read model instance + * @returns {Promise} The read model instance or undefined if it doesn't exist + */ + async fetchReadModel( + readModelName: string, + readModelID: UUID | undefined, + sequenceKey?: SequenceKey + ): Promise { + if (!readModelID) { return undefined } - return Array.isArray(joinKey) ? joinKey : [joinKey] + const rawReadModels = await this.config.provider.readModels.fetch( + this.config, + readModelName, + readModelID, + sequenceKey + ) + if (rawReadModels?.length) { + if (rawReadModels.length > 1) { + throw 'Got multiple objects for a request by Id. If this is a sequenced read model you should also specify the sequenceKey field.' + } else if (rawReadModels.length === 1 && rawReadModels[0]) { + const readModelMetadata = this.config.readModels[readModelName] + return createInstance(readModelMetadata.class, rawReadModels[0]) + } + } + return undefined + } + + // eslint-disable-next-line @typescript-eslint/ban-types + getProjectionFunction(projectionMetadata: ProjectionMetadata): Function { + try { + return (projectionMetadata.class as any)[projectionMetadata.methodName] + } catch { + throw new Error(`Couldn't load the ReadModel class ${projectionMetadata.class.name}`) + } + } + + private getUnProjections( + entitySnapshotEnvelope: EntitySnapshotEnvelope + ): Array> { + const unProjections: Array> = + this.entityUnProjections(entitySnapshotEnvelope) + const projections: Array> = + this.entityProjections(entitySnapshotEnvelope) + if (projections?.length > 0) { + if (!unProjections) { + throw new Error(`Missing UnProjections for entity ${entitySnapshotEnvelope.entityTypeName}`) + } + const missingProjection = this.findFirstMissingProjection(projections, unProjections) + if (missingProjection) { + throw new Error( + `Missing UnProjection for ReadModel ${missingProjection.class.name} with joinKey ${missingProjection.joinKey} for entity ${entitySnapshotEnvelope.entityTypeName}` + ) + } + } + return unProjections + } + + private entityProjections( + entitySnapshotEnvelope: EntitySnapshotEnvelope + ): Array> { + return this.config.projections[entitySnapshotEnvelope.entityTypeName] + } + + private entityUnProjections( + entitySnapshotEnvelope: EntitySnapshotEnvelope + ): Array> { + return this.config.unProjections[entitySnapshotEnvelope.entityTypeName] + } + + private findFirstMissingProjection( + sources: Array>, + to: Array> + ): ProjectionMetadata | undefined { + return sources.find( + (source: ProjectionMetadata) => !this.someProjection(to, source) + ) + } + + private someProjection( + sources: Array>, + to: ProjectionMetadata + ): boolean { + const contains = (source: ProjectionMetadata) => + source.class.name === to.class.name && source.joinKey.toString() === to.joinKey.toString() + return sources.some(contains) } private sequenceKeyForProjection( entity: EntityInterface, - projectionMetadata: ProjectionMetadata + projectionMetadata: ProjectionMetadata ): SequenceKey | undefined { const sequenceKeyName = this.config.readModelSequenceKeys[projectionMetadata.class.name] const sequenceKeyValue = (entity as any)[sequenceKeyName] @@ -91,30 +200,207 @@ export class ReadModelStore { return undefined } + private async projectEntity( + entityInstance: EntityInterface, + projectionMetadata: ProjectionMetadata, + entityMetadata: EntityMetadata, + entitySnapshotEnvelope: EntitySnapshotEnvelope, + readModelName: string, + deleteEvent: boolean, + sequenceKey?: SequenceKey + ): Promise> | undefined> { + const currentReadModels: Array = await this.getReadModels( + entityInstance, + projectionMetadata, + entityMetadata + ) + if (currentReadModels && currentReadModels.length > 0) { + const existingReadModelsProjections: Array> = [] + for (const currentReadModel of currentReadModels) { + const newProjections: Array> = await this.projectionsForReadModels( + entitySnapshotEnvelope, + readModelName, + sequenceKey, + projectionMetadata, + entityInstance, + entityMetadata, + deleteEvent, + currentReadModel + ) + existingReadModelsProjections.push(...newProjections) + } + return Promises.allSettledAndFulfilled(existingReadModelsProjections) + } + const newProjections: Array> = await this.projectionsForReadModels( + entitySnapshotEnvelope, + readModelName, + sequenceKey, + projectionMetadata, + entityInstance, + entityMetadata, + deleteEvent + ) + return Promises.allSettledAndFulfilled(newProjections) + } + + private async projectionsForReadModels( + entitySnapshotEnvelope: EntitySnapshotEnvelope, + readModelName: string, + sequenceKey: any, + projectionMetadata: ProjectionMetadata, + entityInstance: EntityInterface, + entityMetadata: EntityMetadata, + deleteEvent: boolean, + currentReadModel?: ReadModelInterface + ): Promise>> { + const projections: Array> = [] + const logger = getLogger(this.config, 'ReadModelStore#projectionsForReadModels') + if (this.isJoinKeyByEntity(projectionMetadata.joinKey)) { + const entityJoinKey = (entityInstance as any)[projectionMetadata.joinKey] + if (!entityJoinKey) { + logger.warn( + `Couldn't find the joinKey named ${projectionMetadata} in entity snapshot of ${entityMetadata.class.name}. Skipping...` + ) + return [] + } + const entitiesJoinKeys: Array = Array.isArray(entityJoinKey) ? entityJoinKey : [entityJoinKey] + // A new Read Model with JoinKey by entity needs to be projected using a JoinKey with an entity query. We don't have a previous read model, but we have the new id from the entity + for (const readModelId of entitiesJoinKeys) { + const readModel = currentReadModel?.id === readModelId ? currentReadModel : undefined + projections.push( + this.projectAndStoreReadModelWithRetry( + entitySnapshotEnvelope, + readModelName, + sequenceKey, + entityInstance, + projectionMetadata, + deleteEvent, + readModelId, + readModel + ) + ) + } + } else { + // A new Read Model with JoinKey by ReadModel needs to be projected using a JoinKey with a read model query. We don't have a previous read model nor the new id as we don't have an entity field + projections.push( + this.projectAndStoreReadModelWithRetry( + entitySnapshotEnvelope, + readModelName, + sequenceKey, + entityInstance, + projectionMetadata, + deleteEvent, + currentReadModel?.id, + currentReadModel + ) + ) + } + return projections + } + + private async projectAndStoreReadModelWithRetry( + entitySnapshotEnvelope: EntitySnapshotEnvelope, + readModelName: string, + sequenceKey: SequenceKey | undefined, + entityInstance: EntityInterface, + projectionMetadata: ProjectionMetadata, + deleteEvent: boolean, + readModelId?: UUID, + currentReadModel?: ReadModelInterface + ): Promise { + const logger = getLogger(this.config, 'ReadModelStore#projectAndStoreReadModelWithRetry') + logger.debug( + 'Projecting entity snapshot ', + entitySnapshotEnvelope, + ` to build new state of read model ${readModelName} with ID ${currentReadModel?.id || readModelId}`, + sequenceKey ? ` sequencing by ${sequenceKey.name} with value ${sequenceKey.value}` : '' + ) + + return retryIfError( + (tryNumber?: number) => + this.applyProjectionToReadModel( + entitySnapshotEnvelope, + entityInstance, + projectionMetadata, + deleteEvent, + currentReadModel, + entitySnapshotEnvelope, + readModelId, + sequenceKey, + tryNumber + ), + OptimisticConcurrencyUnexpectedVersionError, + logger + ) + } + + private instanceReadModels( + readModelName: string, + rawReadModels: Array | undefined + ): Array { + if (!rawReadModels?.length) { + return [] + } + const readModelMetadata = this.config.readModels[readModelName] + return rawReadModels.map((rawReadModel) => createInstance(readModelMetadata.class, rawReadModel)) + } + private async applyProjectionToReadModel( + entitySnapshotEnvelope: EntitySnapshotEnvelope, entity: EntityInterface, - projectionMetadata: ProjectionMetadata, - readModelName: string, - readModelID: UUID, + projectionMetadata: ProjectionMetadata, + deleteEvent: boolean, + currentReadModel?: ReadModelInterface, + lastProjectedEntity?: EntitySnapshotEnvelope, + currentReadModelID?: UUID, sequenceKey?: SequenceKey, - lastProjectedEntity?: EntitySnapshotEnvelope + tryNumber?: number ): Promise { const logger = getLogger(this.config, 'ReadModelStore#applyProjectionToReadModel') - const readModel = await this.fetchReadModel(readModelName, readModelID, sequenceKey) + const readModelName = projectionMetadata.class.name + const readModelID = currentReadModelID ?? currentReadModel?.id + + if (tryNumber && tryNumber > 1) { + // In case of optimistic concurrency error, we need to fetch the current read model version and retry + logger.debug( + `OptimisticConcurrencyUnexpectedVersionError (version=${ + currentReadModel?.boosterMetadata?.version + } and expectedDatabaseVersion=${ + currentReadModel?.boosterMetadata?.version ?? 0 + }). Looking for an updated version of read model ${readModelName} with ID = ${readModelID}` + + (sequenceKey ? ` and sequence key ${sequenceKey.name} = ${sequenceKey.value}` : '') + ) + + currentReadModel = await this.fetchReadModel(readModelName, readModelID, sequenceKey) + logger.debug( + `Current read model ${readModelName} with ID ${readModelID} updated with version = ${currentReadModel?.boosterMetadata?.version}` + + (sequenceKey ? ` and sequence key ${sequenceKey.name} = ${sequenceKey.value}` : '') + ) + } let migratedReadModel: ReadModelInterface | undefined - if (readModel) { - migratedReadModel = await new ReadModelSchemaMigrator(this.config).migrate(readModel, readModelName) + if (currentReadModel) { + migratedReadModel = await new ReadModelSchemaMigrator(this.config).migrate(currentReadModel, readModelName) } - const currentReadModelVersion: number = migratedReadModel?.boosterMetadata?.version ?? 0 + const currentDatabaseVersion: number = migratedReadModel?.boosterMetadata?.version ?? 0 let newReadModel: any + const projectionInfo: ProjectionInfo = { + reason: deleteEvent ? ProjectionInfoReason.ENTITY_DELETED : ProjectionInfoReason.ENTITY_PROJECTED, + } try { - newReadModel = Array.isArray(entity[projectionMetadata.joinKey]) - ? this.projectionFunction(projectionMetadata)(entity, readModelID, migratedReadModel || null) - : this.projectionFunction(projectionMetadata)(entity, migratedReadModel || null) + newReadModel = await this.callProjectionFunction( + entitySnapshotEnvelope, + projectionMetadata, + entity, + migratedReadModel, + readModelID, + projectionInfo + ) } catch (e) { const globalErrorDispatcher = new BoosterGlobalErrorDispatcher(this.config) - const error = await globalErrorDispatcher.dispatch(new ProjectionGlobalError(entity, migratedReadModel, e)) + const error = await globalErrorDispatcher.dispatch( + new ProjectionGlobalError(entitySnapshotEnvelope, entity, migratedReadModel, projectionMetadata, e) + ) if (error) throw error } @@ -122,18 +408,40 @@ export class ReadModelStore { logger.debug(`Deleting read model ${readModelName} with ID ${readModelID}:`, migratedReadModel) return this.config.provider.readModels.delete(this.config, readModelName, migratedReadModel) } else if (newReadModel === ReadModelAction.Nothing) { - logger.debug( - `[ReadModelStore#project] Skipping actions for ${readModelName} with ID ${readModelID}:`, - newReadModel - ) + logger.debug(`Skipping actions for ${readModelName} with ID ${readModelID}:`, newReadModel) return } + + return await this.store( + entity, + projectionMetadata, + readModelID, + readModelName, + migratedReadModel, + newReadModel, + currentDatabaseVersion, + lastProjectedEntity + ) + } + + private async store( + entity: EntityInterface, + projectionMetadata: ProjectionMetadata, + readModelID: UUID | undefined, + readModelName: string, + migratedReadModel: ReadModelInterface | undefined, + newReadModel: any, + expectedCurrentDatabaseVersion: number, + lastProjectedEntity?: EntitySnapshotEnvelope + ): Promise { + const logger = getLogger(this.config, 'ReadModelStore#store') const schemaVersion: number = migratedReadModel?.boosterMetadata?.schemaVersion ?? this.config.currentVersionFor(readModelName) // Increment the read model version in 1 before storing + const newReadModelVersion = expectedCurrentDatabaseVersion + 1 newReadModel.boosterMetadata = { ...migratedReadModel?.boosterMetadata, - version: currentReadModelVersion + 1, + version: newReadModelVersion, schemaVersion: schemaVersion, lastUpdateAt: new Date().toISOString(), lastProjectionInfo: { @@ -144,50 +452,108 @@ export class ReadModelStore { }, } as BoosterMetadata logger.debug( - `[ReadModelStore#project] Storing new version of read model ${readModelName} with ID ${readModelID}:`, + `Storing new version of read model ${readModelName} with ID ${readModelID}, version ${newReadModel.boosterMetadata.version} and expected database version ${expectedCurrentDatabaseVersion}:`, newReadModel ) - - return this.config.provider.readModels.store(this.config, readModelName, newReadModel, currentReadModelVersion) - } - - /** - * Gets a specific read model instance referencing it by ID when it's a regular read model - * or by ID + sequenceKey when it's a sequenced read model - */ - public async fetchReadModel( - readModelName: string, - readModelID: UUID, - sequenceKey?: SequenceKey - ): Promise { - const logger = getLogger(this.config, 'ReadModelStore#fetchReadModel') - logger.debug( - `[ReadModelStore#fetchReadModel] Looking for existing version of read model ${readModelName} with ID = ${readModelID}` + - (sequenceKey ? ` and sequence key ${sequenceKey.name} = ${sequenceKey.value}` : '') - ) - const rawReadModels = await this.config.provider.readModels.fetch( + return this.config.provider.readModels.store( this.config, readModelName, - readModelID, - sequenceKey + newReadModel, + expectedCurrentDatabaseVersion ) - if (rawReadModels?.length) { - if (rawReadModels.length > 1) { - throw 'Got multiple objects for a request by Id. If this is a sequenced read model you should also specify the sequenceKey field.' - } else if (rawReadModels.length === 1 && rawReadModels[0]) { - const readModelMetadata = this.config.readModels[readModelName] - return createInstance(readModelMetadata.class, rawReadModels[0]) + } + + private async callProjectionFunction( + entitySnapshotEnvelope: EntitySnapshotEnvelope, + projectionMetadata: ProjectionMetadata, + entity: EntityInterface, + migratedReadModel: ReadModelInterface | undefined, + readModelID: UUID | undefined, + projectionInfo: ProjectionInfo + ): Promise | undefined> { + try { + const projectionMetadataJoinKey = projectionMetadata.joinKey + const projectionFunction = this.getProjectionFunction(projectionMetadata) + if (this.isJoinKeyByEntity(projectionMetadataJoinKey)) { + return Array.isArray(entity[projectionMetadataJoinKey]) + ? projectionFunction(entity, readModelID, migratedReadModel || null, projectionInfo) + : projectionFunction(entity, migratedReadModel || null, projectionInfo) } + return projectionFunction(entity, readModelID, migratedReadModel || null) + } catch (e) { + const globalErrorDispatcher = new BoosterGlobalErrorDispatcher(this.config) + const error = await globalErrorDispatcher.dispatch( + new ProjectionGlobalError(entitySnapshotEnvelope, entity, migratedReadModel, projectionMetadata, e) + ) + if (error) throw error } return undefined } - // eslint-disable-next-line @typescript-eslint/ban-types - public projectionFunction(projectionMetadata: ProjectionMetadata): Function { - try { - return (projectionMetadata.class as any)[projectionMetadata.methodName] - } catch { - throw new Error(`Couldn't load the ReadModel class ${projectionMetadata.class.name}`) + private filterForProjection( + entity: EntityInterface, + projectionMetadata: ProjectionMetadata, + entityMetadata: EntityMetadata + ): FilterFor | undefined { + const logger = getLogger(this.config, 'ReadModelStore#filterForProjection') + const projectionMetadataJoinKey = projectionMetadata.joinKey + logger.debug(`Calculating filter for projection for ReadModels using Filter ${projectionMetadataJoinKey}`) + if (this.isJoinKeyByEntity(projectionMetadataJoinKey)) { + return this.filterForEntityProjection(entity, projectionMetadata, entityMetadata) + } + + return this.filterForReadModelProjection(entity, projectionMetadata, entityMetadata) + } + + private filterForEntityProjection( + entity: EntityInterface, + projectionMetadata: ProjectionMetadata, + entityMetadata: EntityMetadata + ): FilterFor | undefined { + const logger = getLogger(this.config, 'ReadModelStore#filterForEntityProjection') + const projectionMetadataJoinKey = projectionMetadata.joinKey as keyof TEntity + const entityJoinKey = (entity as any)[projectionMetadataJoinKey] + if (!entityJoinKey) { + logger.warn( + `Couldn't find the joinKey ${projectionMetadata.joinKey} in entity snapshot of ${entityMetadata.class.name}. Skipping...` + ) + return } + const ids = Array.isArray(entityJoinKey) ? entityJoinKey : [entityJoinKey] + if (!ids || ids.length === 0) { + logger.debug('No ids found for entity projection. Skipping...') + return undefined + } + logger.debug(`Filtering for entity projection with ids ${ids}`) + return { + id: { + in: ids, + }, + } + } + + private filterForReadModelProjection( + entity: EntityInterface, + projectionMetadata: ProjectionMetadata, + entityMetadata: EntityMetadata + ): FilterFor | undefined { + const logger = getLogger(this.config, 'ReadModelStore#filterForReadModelProjection') + const joinKeyForProjection = projectionMetadata.joinKey as ReadModelJoinKeyFunction< + EntityInterface, + ReadModelInterface + > + if (!joinKeyForProjection) { + logger.warn( + `Couldn't find the joinKey ${projectionMetadata.joinKey} in entity snapshot of ${entityMetadata.class.name}. Skipping...` + ) + return + } + return joinKeyForProjection(entity) + } + + private isJoinKeyByEntity( + projectionMetadataJoinKey: keyof TEntity | ReadModelJoinKeyFunction + ): projectionMetadataJoinKey is keyof TEntity { + return typeof projectionMetadataJoinKey === 'string' } } diff --git a/packages/framework-core/test/booster-global-error-dispatcher.test.ts b/packages/framework-core/test/booster-global-error-dispatcher.test.ts index 0ccc3a2a5e..4c524c16fb 100644 --- a/packages/framework-core/test/booster-global-error-dispatcher.test.ts +++ b/packages/framework-core/test/booster-global-error-dispatcher.test.ts @@ -3,22 +3,28 @@ import { BoosterConfig, CommandEnvelope, CommandHandlerGlobalError, + CommandMetadata, EntityInterface, EntitySnapshotEnvelope, + EventEnvelope, EventHandlerGlobalError, EventInterface, GlobalErrorContainer, GlobalErrorHandlerMetadata, ProjectionGlobalError, + ProjectionMetadata, ReadModelInterface, ReducerGlobalError, + ReducerMetadata, ScheduleCommandGlobalError, - SnapshotPersistHandlerGlobalError, + ScheduledCommandEnvelope, + ScheduledCommandMetadata, } from '@boostercloud/framework-types' import { GlobalErrorHandler } from '../src' import { restore } from 'sinon' import { Booster } from '../src/booster' import { BoosterGlobalErrorDispatcher } from '../src/booster-global-error-dispatcher' +import 'mocha' describe('BoosterGlobalErrorDispatcher', () => { let config: BoosterConfig @@ -66,7 +72,11 @@ describe('BoosterGlobalErrorDispatcher', () => { it('should dispatch original error if there is an error processing them', async () => { @GlobalErrorHandler() class ErrorHandler { - public static async onScheduledCommandHandlerError(error: Error): Promise { + public static async onScheduledCommandHandlerError( + error: Error, + scheduledCommandEnvelope: ScheduledCommandEnvelope, + scheduledCommandMetadata: ScheduledCommandMetadata + ): Promise { throw new Error('failed') } @@ -75,7 +85,9 @@ describe('BoosterGlobalErrorDispatcher', () => { } } - const scheduleCommandGlobalError = new ScheduleCommandGlobalError(baseError) + const envelope: ScheduledCommandEnvelope = {} as ScheduledCommandEnvelope + const metadata: ScheduledCommandMetadata = {} as ScheduledCommandMetadata + const scheduleCommandGlobalError = new ScheduleCommandGlobalError(envelope, metadata, baseError) config.globalErrorsHandler = { class: ErrorHandler } as GlobalErrorHandlerMetadata const errorDispatcher = new BoosterGlobalErrorDispatcher(config) const result = await errorDispatcher.dispatch(scheduleCommandGlobalError) @@ -85,7 +97,11 @@ describe('BoosterGlobalErrorDispatcher', () => { it('should dispatch specific and generic handler if both are defined for a specific error', async () => { @GlobalErrorHandler() class ErrorHandler { - public static async onScheduledCommandHandlerError(error: Error): Promise { + public static async onScheduledCommandHandlerError( + error: Error, + scheduledCommandEnvelope: ScheduledCommandEnvelope, + scheduledCommandMetadata: ScheduledCommandMetadata + ): Promise { return new Error(`${error}.onScheduledCommandHandlerError`) } @@ -94,7 +110,9 @@ describe('BoosterGlobalErrorDispatcher', () => { } } - const scheduleCommandGlobalError = new ScheduleCommandGlobalError(baseError) + const envelope: ScheduledCommandEnvelope = {} as ScheduledCommandEnvelope + const metadata: ScheduledCommandMetadata = {} as ScheduledCommandMetadata + const scheduleCommandGlobalError = new ScheduleCommandGlobalError(envelope, metadata, baseError) config.globalErrorsHandler = { class: ErrorHandler } as GlobalErrorHandlerMetadata const errorDispatcher = new BoosterGlobalErrorDispatcher(config) const result = await errorDispatcher.dispatch(scheduleCommandGlobalError) @@ -111,7 +129,8 @@ describe('BoosterGlobalErrorDispatcher', () => { } } const mockCommand = {} as CommandEnvelope - const commandHandlerGlobalError = new CommandHandlerGlobalError(mockCommand, baseError) + const mockMetadata: CommandMetadata = {} as CommandMetadata + const commandHandlerGlobalError = new CommandHandlerGlobalError(mockCommand, mockMetadata, baseError) config.globalErrorsHandler = { class: ErrorHandler } as GlobalErrorHandlerMetadata const errorDispatcher = new BoosterGlobalErrorDispatcher(config) const result = await errorDispatcher.dispatch(commandHandlerGlobalError) @@ -129,7 +148,14 @@ describe('BoosterGlobalErrorDispatcher', () => { } } const mockEventInstance = {} as EventInterface - const eventHandlerGlobalError = new EventHandlerGlobalError(mockEventInstance, baseError) + const mockEventEnvelope: EventEnvelope = {} as EventEnvelope + const mockEventHandlerMetadata = {} + const eventHandlerGlobalError = new EventHandlerGlobalError( + mockEventEnvelope, + mockEventInstance, + mockEventHandlerMetadata, + baseError + ) config.globalErrorsHandler = { class: ErrorHandler } as GlobalErrorHandlerMetadata const errorDispatcher = new BoosterGlobalErrorDispatcher(config) const result = await errorDispatcher.dispatch(eventHandlerGlobalError) @@ -141,15 +167,25 @@ describe('BoosterGlobalErrorDispatcher', () => { class ErrorHandler { public static async onReducerError( error: Error, + eventEnvelope: EventEnvelope, + reducerMetadata: ReducerMetadata, eventInstance: EventInterface, snapshotInstance: EntityInterface | null - ): Promise { + ): Promise { return new Error(`${error}.onReducerError`) } } + const mockEventEnvelope: EventEnvelope = {} as EventEnvelope const mockEventInstance = {} as EventInterface const mockSnapshotInstance = {} as EntityInterface - const reducerGlobalError = new ReducerGlobalError(mockEventInstance, mockSnapshotInstance, baseError) + const reducerMetadata: ReducerMetadata = {} as ReducerMetadata + const reducerGlobalError = new ReducerGlobalError( + mockEventEnvelope, + mockEventInstance, + mockSnapshotInstance, + reducerMetadata, + baseError + ) config.globalErrorsHandler = { class: ErrorHandler } as GlobalErrorHandlerMetadata const errorDispatcher = new BoosterGlobalErrorDispatcher(config) const result = await errorDispatcher.dispatch(reducerGlobalError) @@ -161,53 +197,61 @@ describe('BoosterGlobalErrorDispatcher', () => { class ErrorHandler { public static async onProjectionError( error: Error, + entityEnvelope: EntitySnapshotEnvelope, + projectionMetadata: ProjectionMetadata, entity: EntityInterface, readModel: ReadModelInterface | undefined ): Promise { return new Error(`${error}.onProjectionError`) } } + const mockEntityEnvelope: EntitySnapshotEnvelope = {} as EntitySnapshotEnvelope const mockEntity = {} as EntityInterface const mockReadModel = {} as ReadModelInterface - const projectionGlobalError = new ProjectionGlobalError(mockEntity, mockReadModel, baseError) + const mockProjectionMetadata: ProjectionMetadata = {} as ProjectionMetadata< + EntityInterface, + ReadModelInterface + > + const projectionGlobalError = new ProjectionGlobalError( + mockEntityEnvelope, + mockEntity, + mockReadModel, + mockProjectionMetadata, + baseError + ) config.globalErrorsHandler = { class: ErrorHandler } as GlobalErrorHandlerMetadata const errorDispatcher = new BoosterGlobalErrorDispatcher(config) const result = await errorDispatcher.dispatch(projectionGlobalError) expect(result?.toString()).to.be.eq(`Error: Error: ${baseError.message}.onProjectionError`) }) - it('should dispatch SnapshotPersistHandlerGlobalError', async () => { - @GlobalErrorHandler() - class ErrorHandler { - public static async onSnapshotPersistError( - error: Error, - snapshot: EntitySnapshotEnvelope - ): Promise { - return new Error(`${error}.onSnapshotPersistError`) - } - } - const mockSnapshot = {} as EntitySnapshotEnvelope - const snapshotPersistHandlerGlobalError = new SnapshotPersistHandlerGlobalError(mockSnapshot, baseError) - config.globalErrorsHandler = { class: ErrorHandler } as GlobalErrorHandlerMetadata - const errorDispatcher = new BoosterGlobalErrorDispatcher(config) - const result = await errorDispatcher.dispatch(snapshotPersistHandlerGlobalError) - expect(result?.toString()).to.be.eq(`Error: Error: ${baseError.message}.onSnapshotPersistError`) - }) - it('should ignore errors on ProjectionGlobalError if undefined is returned', async () => { @GlobalErrorHandler() class ErrorHandler { public static async onProjectionError( error: Error, + entityEnvelope: EntitySnapshotEnvelope, + projectionMetadata: ProjectionMetadata, entity: EntityInterface, readModel: ReadModelInterface | undefined ): Promise { return undefined } } + const mockEntityEnvelope: EntitySnapshotEnvelope = {} as EntitySnapshotEnvelope const mockEntity = {} as EntityInterface const mockReadModel = {} as ReadModelInterface - const projectionGlobalError = new ProjectionGlobalError(mockEntity, mockReadModel, baseError) + const mockProjectionMetadata: ProjectionMetadata = {} as ProjectionMetadata< + EntityInterface, + ReadModelInterface + > + const projectionGlobalError = new ProjectionGlobalError( + mockEntityEnvelope, + mockEntity, + mockReadModel, + mockProjectionMetadata, + baseError + ) config.globalErrorsHandler = { class: ErrorHandler } as GlobalErrorHandlerMetadata const errorDispatcher = new BoosterGlobalErrorDispatcher(config) const result = await errorDispatcher.dispatch(projectionGlobalError) @@ -217,7 +261,11 @@ describe('BoosterGlobalErrorDispatcher', () => { it('should ignore erros if generic handler returns an undefined', async () => { @GlobalErrorHandler() class ErrorHandler { - public static async onScheduledCommandHandlerError(error: Error): Promise { + public static async onScheduledCommandHandlerError( + error: Error, + scheduledCommandEnvelope: ScheduledCommandEnvelope, + scheduledCommandMetadata: ScheduledCommandMetadata + ): Promise { return new Error(`${error}.onScheduledCommandHandlerError`) } @@ -226,7 +274,9 @@ describe('BoosterGlobalErrorDispatcher', () => { } } - const scheduleCommandGlobalError = new ScheduleCommandGlobalError(baseError) + const envelope: ScheduledCommandEnvelope = {} as ScheduledCommandEnvelope + const metadata: ScheduledCommandMetadata = {} as ScheduledCommandMetadata + const scheduleCommandGlobalError = new ScheduleCommandGlobalError(envelope, metadata, baseError) config.globalErrorsHandler = { class: ErrorHandler } as GlobalErrorHandlerMetadata const errorDispatcher = new BoosterGlobalErrorDispatcher(config) const result = await errorDispatcher.dispatch(scheduleCommandGlobalError) diff --git a/packages/framework-core/test/booster-read-models-reader.test.ts b/packages/framework-core/test/booster-read-models-reader.test.ts index 52b0ebff75..24c2bef83f 100644 --- a/packages/framework-core/test/booster-read-models-reader.test.ts +++ b/packages/framework-core/test/booster-read-models-reader.test.ts @@ -457,6 +457,7 @@ describe('BoosterReadModelReader', () => { filters, currentUser, select: ['id'], + skipInstance: false, } as any const expectedReadModels = [new TestReadModel(), new TestReadModel()] @@ -491,6 +492,7 @@ describe('BoosterReadModelReader', () => { filters, currentUser, select: ['id'], + skipInstance: false, } as any const expectedResult = [new TestReadModel(), new TestReadModel()] diff --git a/packages/framework-core/test/decorators/event-handler.test.ts b/packages/framework-core/test/decorators/event-handler.test.ts index 42789afbeb..3ed8ea809b 100644 --- a/packages/framework-core/test/decorators/event-handler.test.ts +++ b/packages/framework-core/test/decorators/event-handler.test.ts @@ -9,6 +9,9 @@ import { UUID, Register, BoosterConfig } from '@boostercloud/framework-types' describe('the `EventHandler` decorator', () => { afterEach(() => { Booster.configureCurrentEnv((config: BoosterConfig) => { + for (const propName in config.events) { + delete config.events[propName] + } for (const propName in config.eventHandlers) { delete config.eventHandlers[propName] } diff --git a/packages/framework-core/test/decorators/global-error-handler.test.ts b/packages/framework-core/test/decorators/global-error-handler.test.ts index 9a9ce54634..54d6a4557f 100644 --- a/packages/framework-core/test/decorators/global-error-handler.test.ts +++ b/packages/framework-core/test/decorators/global-error-handler.test.ts @@ -2,7 +2,20 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import { expect } from '../expect' import { GlobalErrorHandler, Booster } from '../../src' -import { CommandEnvelope, EntityInterface, EventInterface, ReadModelInterface } from '@boostercloud/framework-types' +import { + CommandEnvelope, + CommandMetadata, + EntityInterface, + EntitySnapshotEnvelope, + EventEnvelope, + EventInterface, + NotificationInterface, + ProjectionMetadata, + ReadModelInterface, + ReducerMetadata, + ScheduledCommandEnvelope, + ScheduledCommandMetadata, +} from '@boostercloud/framework-types' describe('the `GlobalErrorHandler` decorator', () => { afterEach(() => { @@ -27,16 +40,26 @@ describe('the `GlobalErrorHandler` decorator', () => { // Register command @GlobalErrorHandler() class ErrorHandler { - public static async onCommandHandlerError(error: Error, command: CommandEnvelope): Promise { + public static async onCommandHandlerError( + error: Error, + commandEnvelope: CommandEnvelope, + commandMetadata: CommandMetadata + ): Promise { return new Error('') } - public static async onScheduledCommandHandlerError(error: Error): Promise { + public static async onScheduledCommandHandlerError( + error: Error, + scheduledCommandEnvelope: ScheduledCommandEnvelope, + scheduledCommandMetadata: ScheduledCommandMetadata + ): Promise { return new Error('') } public static async onDispatchEventHandlerError( error: Error, + eventEnvelope: EventEnvelope | NotificationInterface, + eventHandlerMetadata: unknown, eventInstance: EventInterface ): Promise { return new Error('') @@ -44,6 +67,8 @@ describe('the `GlobalErrorHandler` decorator', () => { public static async onProjectionError( error: Error, + entityEnvelope: EntitySnapshotEnvelope, + projectionMetadata: ProjectionMetadata, entity: EntityInterface, readModel: ReadModelInterface | undefined ): Promise { @@ -52,6 +77,8 @@ describe('the `GlobalErrorHandler` decorator', () => { public static async onReducerError( error: Error, + eventEnvelope: EventEnvelope, + reducerMetadata: ReducerMetadata, eventInstance: EventInterface, snapshotInstance: EntityInterface | null ): Promise { diff --git a/packages/framework-core/test/decorators/read-model.test.ts b/packages/framework-core/test/decorators/read-model.test.ts index fe998dd272..9cc70c4221 100644 --- a/packages/framework-core/test/decorators/read-model.test.ts +++ b/packages/framework-core/test/decorators/read-model.test.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { expect } from '../expect' import { describe } from 'mocha' -import { ReadModel, Booster, Entity, Projects, sequencedBy, Role } from '../../src' +import { ReadModel, Booster, Entity, Projects, sequencedBy, Role, CalculatedField } from '../../src' import { UUID, ProjectionResult, UserEnvelope } from '@boostercloud/framework-types' import { BoosterAuthorizer } from '../../src/booster-authorizer' import { fake, restore } from 'sinon' @@ -40,6 +40,7 @@ describe('the `ReadModel` decorator', () => { typeGroup: 'Class', typeName: 'UUID', }, + dependencies: [], }, { name: 'title', @@ -52,6 +53,7 @@ describe('the `ReadModel` decorator', () => { typeGroup: 'String', typeName: 'String', }, + dependencies: [], }, ], }) @@ -108,6 +110,7 @@ describe('the `ReadModel` decorator', () => { typeGroup: 'Class', typeName: 'UUID', }, + dependencies: [], }, { name: 'aStringProp', @@ -120,6 +123,7 @@ describe('the `ReadModel` decorator', () => { typeGroup: 'String', typeName: 'String', }, + dependencies: [], }, { name: 'aNumberProp', @@ -132,6 +136,7 @@ describe('the `ReadModel` decorator', () => { typeGroup: 'Number', typeName: 'Number', }, + dependencies: [], }, { name: 'aReadonlyArray', @@ -154,6 +159,7 @@ describe('the `ReadModel` decorator', () => { typeGroup: 'ReadonlyArray', typeName: 'ReadonlyArray', }, + dependencies: [], }, ], }) @@ -295,3 +301,89 @@ describe('the `Projects` decorator', () => { }) }) }) + +describe('the `CalculatedField` decorator', () => { + afterEach(() => { + restore() + Booster.configure('test', (config) => { + for (const propName in config.readModels) { + delete config.readModels[propName] + } + }) + }) + + it('adds calculated field metadata to the read model class', () => { + @ReadModel({ + authorize: 'all', + }) + class PersonReadModel { + public constructor(readonly id: UUID, readonly firstName: string, readonly lastName: string) {} + + @CalculatedField({ dependsOn: ['firstName', 'lastName'] }) + public get fullName(): string { + return `${this.firstName} ${this.lastName}` + } + } + + expect(Booster.config.readModels['PersonReadModel']).to.be.deep.equal({ + class: PersonReadModel, + authorizer: BoosterAuthorizer.allowAccess, + before: [], + properties: [ + { + name: 'id', + typeInfo: { + importPath: '@boostercloud/framework-types', + isNullable: false, + isGetAccessor: false, + name: 'UUID', + parameters: [], + type: UUID, + typeGroup: 'Class', + typeName: 'UUID', + }, + dependencies: [], + }, + { + name: 'firstName', + typeInfo: { + isNullable: false, + isGetAccessor: false, + name: 'string', + parameters: [], + type: String, + typeGroup: 'String', + typeName: 'String', + }, + dependencies: [], + }, + { + name: 'lastName', + typeInfo: { + isNullable: false, + isGetAccessor: false, + name: 'string', + parameters: [], + type: String, + typeGroup: 'String', + typeName: 'String', + }, + dependencies: [], + }, + { + name: 'fullName', + typeInfo: { + isNullable: false, + isGetAccessor: true, + name: 'string', + parameters: [], + type: String, + typeGroup: 'String', + typeName: 'String', + }, + dependencies: ['firstName', 'lastName'], + }, + ], + }) + }) +}) diff --git a/packages/framework-core/test/sensor/health/booster-health-service.test.ts b/packages/framework-core/test/sensor/health/booster-health-service.test.ts index 2183b8effb..fcdc107d6d 100644 --- a/packages/framework-core/test/sensor/health/booster-health-service.test.ts +++ b/packages/framework-core/test/sensor/health/booster-health-service.test.ts @@ -223,6 +223,7 @@ function defaultSensor(token?: string, url?: string) { rawRequestToHealthEnvelope: fake(() => { return { token: token, componentPath: url } }), + areRocketFunctionsUp: fake(() => ''), } } @@ -289,24 +290,12 @@ function expectDatabaseEventsWithDetails(databaseEvents: any, status: string, de } function expectDatabaseReadModels(databaseReadModels: any, status: string): void { - expectDefaultResult( - databaseReadModels, - status, - 'booster/database/readmodels', - 'Booster Database ReadModels', - 0 - ) + expectDefaultResult(databaseReadModels, status, 'booster/database/readmodels', 'Booster Database ReadModels', 0) expect(databaseReadModels.details).to.be.undefined } function expectDatabaseReadModelsWithDetails(databaseReadModels: any, status: string, details: any): void { - expectDefaultResult( - databaseReadModels, - status, - 'booster/database/readmodels', - 'Booster Database ReadModels', - 0 - ) + expectDefaultResult(databaseReadModels, status, 'booster/database/readmodels', 'Booster Database ReadModels', 0) expect(databaseReadModels.details).to.be.deep.eq(details) } diff --git a/packages/framework-core/test/sensor/health/health-utils.test.ts b/packages/framework-core/test/sensor/health/health-utils.test.ts index ec5bec1abb..360537f0f6 100644 --- a/packages/framework-core/test/sensor/health/health-utils.test.ts +++ b/packages/framework-core/test/sensor/health/health-utils.test.ts @@ -1,7 +1,7 @@ import { HealthIndicatorMetadata } from '@boostercloud/framework-types' import 'mocha' import { - childrenHealthProviders, + childHealthProviders, isEnabled, metadataFromId, parentId, @@ -165,13 +165,13 @@ describe('Health utils', () => { }) it('childrenHealthProviders', () => { - expect(childrenHealthProviders(root, healthProviders)).to.be.deep.equal([rootChildren1, rootChildren2]) - expect(childrenHealthProviders(rootChildren1, healthProviders)).to.be.deep.equal([ + expect(childHealthProviders(root, healthProviders)).to.be.deep.equal([rootChildren1, rootChildren2]) + expect(childHealthProviders(rootChildren1, healthProviders)).to.be.deep.equal([ rootChildren1Children1, rootChildren1Children2, ]) - expect(childrenHealthProviders(rootChildren1Children1, healthProviders)).to.be.deep.equal([]) - expect(childrenHealthProviders(rootChildren1Children2, healthProviders)).to.be.deep.equal([]) - expect(childrenHealthProviders(rootChildren2, healthProviders)).to.be.deep.equal([]) + expect(childHealthProviders(rootChildren1Children1, healthProviders)).to.be.deep.equal([]) + expect(childHealthProviders(rootChildren1Children2, healthProviders)).to.be.deep.equal([]) + expect(childHealthProviders(rootChildren2, healthProviders)).to.be.deep.equal([]) }) }) diff --git a/packages/framework-core/test/services/event-store.test.ts b/packages/framework-core/test/services/event-store.test.ts index 3d29352d31..4e773181bb 100644 --- a/packages/framework-core/test/services/event-store.test.ts +++ b/packages/framework-core/test/services/event-store.test.ts @@ -801,7 +801,7 @@ describe('EventStore', () => { eventInstance.entityID = someEvent.entityID const entityInstance = new AnEntity(someEntity.id, someEntity.count) - expect(eventStore.reducerForEvent).to.have.been.calledOnceWith(AnEvent.name) + expect(eventStore.reducerForEvent).to.have.been.calledOnceWith(AnEvent.name, eventInstance) expect(fakeReducer).to.have.been.calledOnceWith(eventInstance, entityInstance) expect(newSnapshot).to.be.deep.equal({ @@ -837,7 +837,7 @@ describe('EventStore', () => { const eventInstance = new AnEvent(someEvent.id, someEvent.entityId, someEvent.delta) eventInstance.entityID = someEvent.entityID - expect(eventStore.reducerForEvent).to.have.been.calledOnceWith(AnEvent.name) + expect(eventStore.reducerForEvent).to.have.been.calledOnceWith(AnEvent.name, eventInstance) expect(fakeReducer).to.have.been.calledOnceWith(eventInstance, null) expect(newSnapshot).to.be.deep.equal({ @@ -926,20 +926,15 @@ describe('EventStore', () => { describe('reducerForEvent', () => { context('for an event with a registered reducer', () => { it('returns the proper reducer method for the event', () => { - const reducer = eventStore.reducerForEvent(AnEvent.name) + const reducer = eventStore.reducerForEvent(AnEvent.name, { + class: AnEntity, + methodName: 'reducerThatCallsEntityMethod', + }) expect(reducer).to.be.instanceOf(Function) expect(reducer).to.be.equal(eval('AnEntity')['reducerThatCallsEntityMethod']) }) }) - - context('for events without registered reducers', () => { - it('fails miserably', () => { - expect(() => eventStore.reducerForEvent('InventedEvent')).to.throw( - /No reducer registered for event InventedEvent/ - ) - }) - }) }) }) }) diff --git a/packages/framework-core/test/services/graphql/graphql-query-generator.test.ts b/packages/framework-core/test/services/graphql/graphql-query-generator.test.ts index 926def406a..eb90713691 100644 --- a/packages/framework-core/test/services/graphql/graphql-query-generator.test.ts +++ b/packages/framework-core/test/services/graphql/graphql-query-generator.test.ts @@ -167,6 +167,7 @@ describe('GraphQLQueryGenerator', () => { isNullable: false, isGetAccessor: false, }, + dependencies: [], }, ], methods: [ @@ -181,6 +182,7 @@ describe('GraphQLQueryGenerator', () => { isNullable: false, isGetAccessor: false, }, + dependencies: [], }, ], } as ClassMetadata @@ -282,6 +284,7 @@ describe('GraphQLQueryGenerator', () => { isNullable: false, isGetAccessor: false, }, + dependencies: [], }, ], methods: [], @@ -371,6 +374,7 @@ describe('GraphQLQueryGenerator', () => { isNullable: false, isGetAccessor: false, }, + dependencies: [], }, ], methods: [], @@ -523,7 +527,7 @@ describe('GraphQLQueryGenerator', () => { const returnElementType = (queryReturnType as GraphQLList).ofType expect(returnElementType.name).to.be.equal('EventQueryResponse') expect(new Set(Object.keys(returnElementType.getFields()))).to.be.deep.equal( - new Set(['type', 'entity', 'requestID', 'entityID', 'user', 'createdAt', 'value']) + new Set(['type', 'entity', 'requestID', 'entityID', 'user', 'createdAt', 'value', 'deletedAt']) ) const userType = returnElementType.getFields()['user'].type as GraphQLObjectType expect(new Set(Object.keys(userType.getFields()))).to.be.deep.equal(new Set(['id', 'username', 'roles'])) diff --git a/packages/framework-core/test/services/read-model-store.test.ts b/packages/framework-core/test/services/read-model-store.test.ts index 2dea5faf92..cb79692064 100644 --- a/packages/framework-core/test/services/read-model-store.test.ts +++ b/packages/framework-core/test/services/read-model-store.test.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { beforeEach, describe } from 'mocha' -import { fake, replace, restore, SinonFakeTimers, spy, useFakeTimers } from 'sinon' import { ReadModelStore } from '../../src/services/read-model-store' import { createInstance } from '@boostercloud/framework-common-helpers' import { @@ -17,6 +16,8 @@ import { } from '@boostercloud/framework-types' import { expect } from '../expect' import { BoosterAuthorizer } from '../../src/booster-authorizer' +import { fake, match, replace, restore, SinonFakeTimers, spy, useFakeTimers } from 'sinon' +import { Booster } from '../../src/booster' describe('ReadModelStore', () => { afterEach(() => { @@ -47,14 +48,14 @@ describe('ReadModelStore', () => { } class SomeReadModel { - public constructor(readonly id: UUID) {} + public constructor(readonly id: UUID, readonly count: number) {} - public static someObserver(entity: AnImportantEntity, obj: any): any { + public static someObserver(entity: AnImportantEntity, obj: SomeReadModel): any { const count = (obj?.count || 0) + entity.count return { id: entity.someKey, kind: 'some', count: count } } - public static someObserverArray(entity: AnImportantEntity, readModelID: UUID, obj: any): any { + public static someObserverArray(entity: AnImportantEntity, readModelID: UUID, obj: SomeReadModel): any { const count = (obj?.count || 0) + entity.count return { id: readModelID, kind: 'some', count: count } } @@ -82,9 +83,9 @@ describe('ReadModelStore', () => { } class AnotherReadModel { - public constructor(readonly id: UUID) {} + public constructor(readonly id: UUID, readonly count: number) {} - public static anotherObserver(entity: AnImportantEntity, obj: any): any { + public static anotherObserver(entity: AnImportantEntity, obj: AnotherReadModel): any { const count = (obj?.count || 0) + entity.count return { id: entity.someKey, kind: 'another', count: count } } @@ -96,6 +97,7 @@ describe('ReadModelStore', () => { store: () => {}, delete: () => {}, fetch: () => {}, + search: () => {}, }, } as unknown as ProviderLibrary config.entities[AnImportantEntity.name] = { @@ -127,31 +129,31 @@ describe('ReadModelStore', () => { class: SomeReadModel, methodName: 'someObserver', joinKey: 'someKey', - } as ProjectionMetadata, + } as ProjectionMetadata, { class: SomeReadModel, methodName: 'projectionThatCallsEntityMethod', joinKey: 'someKey', - } as ProjectionMetadata, + } as ProjectionMetadata, { class: AnotherReadModel, methodName: 'anotherObserver', joinKey: 'someKey', - } as ProjectionMetadata, + } as ProjectionMetadata, ] config.projections[AnImportantEntityWithArray.name] = [ { class: SomeReadModel, methodName: 'someObserverArray', joinKey: 'someKey', - } as ProjectionMetadata, + } as ProjectionMetadata, ] config.projections['AnEntity'] = [ { class: SomeReadModel, methodName: 'projectionThatCallsReadModelMethod', joinKey: 'someKey', - } as ProjectionMetadata, + } as ProjectionMetadata, ] function entitySnapshotEnvelopeFor(entityName: string): EntitySnapshotEnvelope { @@ -212,9 +214,11 @@ describe('ReadModelStore', () => { it('deletes the associated read model', async () => { replace(config.provider.readModels, 'store', fake()) replace(config.provider.readModels, 'delete', fake()) + replace(Booster, 'config', config) // Needed because the function `Booster.readModel` references `this.config` from `searchFunction` + replace(config.provider.readModels, 'search', fake.returns([])) replace( ReadModelStore.prototype, - 'projectionFunction', + 'getProjectionFunction', fake.returns(() => ReadModelAction.Delete) ) const readModelStore = new ReadModelStore(config) @@ -222,6 +226,7 @@ describe('ReadModelStore', () => { await readModelStore.project(entitySnapshotEnvelopeFor(AnImportantEntity.name)) expect(config.provider.readModels.store).not.to.have.been.called expect(config.provider.readModels.delete).to.have.been.calledThrice + expect(config.provider.readModels.search).to.have.been.called }) }) @@ -229,9 +234,11 @@ describe('ReadModelStore', () => { it('ignores the read model', async () => { replace(config.provider.readModels, 'store', fake()) replace(config.provider.readModels, 'delete', fake()) + replace(Booster, 'config', config) // Needed because the function `Booster.readModel` references `this.config` from `searchFunction` + replace(config.provider.readModels, 'search', fake.returns([])) replace( ReadModelStore.prototype, - 'projectionFunction', + 'getProjectionFunction', fake.returns(() => ReadModelAction.Nothing) ) const readModelStore = new ReadModelStore(config) @@ -239,6 +246,7 @@ describe('ReadModelStore', () => { await readModelStore.project(entitySnapshotEnvelopeFor(AnImportantEntity.name)) expect(config.provider.readModels.store).not.to.have.been.called expect(config.provider.readModels.delete).not.to.have.been.called + expect(config.provider.readModels.search).to.have.been.called }) }) @@ -254,6 +262,8 @@ describe('ReadModelStore', () => { it('creates new instances of the read models', async () => { replace(config.provider.readModels, 'store', fake()) + replace(Booster, 'config', config) // Needed because the function `Booster.readModel` references `this.config` from `searchFunction` + replace(config.provider.readModels, 'search', fake.returns([])) const readModelStore = new ReadModelStore(config) replace(readModelStore, 'fetchReadModel', fake.returns(null)) spy(SomeReadModel, 'someObserver') @@ -263,9 +273,6 @@ describe('ReadModelStore', () => { await readModelStore.project(entitySnapshotEnvelopeFor(AnImportantEntity.name)) - expect(readModelStore.fetchReadModel).to.have.been.calledThrice - expect(readModelStore.fetchReadModel).to.have.been.calledWith(SomeReadModel.name, 'joinColumnID') - expect(readModelStore.fetchReadModel).to.have.been.calledWith(AnotherReadModel.name, 'joinColumnID') expect(SomeReadModel.someObserver).to.have.been.calledOnceWith(anEntityInstance, null) expect(SomeReadModel.someObserver).to.have.returned({ id: 'joinColumnID', @@ -361,42 +368,47 @@ describe('ReadModelStore', () => { const readModelStore = new ReadModelStore(config) const someReadModelStoredVersion = 10 const anotherReadModelStoredVersion = 32 + replace(Booster, 'config', config) // Needed because the function `Booster.readModel` references `this.config` from `searchFunction` replace( - readModelStore, - 'fetchReadModel', - fake((className: string, id: UUID) => { + config.provider.readModels, + 'search', + fake((config: BoosterConfig, className: string) => { if (className == SomeReadModel.name) { - return { - id: id, - kind: 'some', - count: 77, - boosterMetadata: { - version: someReadModelStoredVersion, - lastUpdateAt: '1970-01-01T00:00:00.000Z', - lastProjectionInfo: { - entityId: 'importantEntityID', - entityName: 'AnImportantEntity', - entityUpdatedAt: '1970-01-01T00:00:00.000Z', - projectionMethod: 'SomeReadModel.someObserver', + return [ + { + id: 'joinColumnID', + kind: 'some', + count: 77, + boosterMetadata: { + version: someReadModelStoredVersion, + lastUpdateAt: '1970-01-01T00:00:00.000Z', + lastProjectionInfo: { + entityId: 'importantEntityID', + entityName: 'AnImportantEntity', + entityUpdatedAt: '1970-01-01T00:00:00.000Z', + projectionMethod: 'SomeReadModel.someObserver', + }, }, }, - } + ] } else { - return { - id: id, - kind: 'another', - count: 177, - boosterMetadata: { - version: anotherReadModelStoredVersion, - lastUpdateAt: '1970-01-01T00:00:00.000Z', - lastProjectionInfo: { - entityId: 'importantEntityID', - entityName: 'AnImportantEntity', - entityUpdatedAt: '1970-01-01T00:00:00.000Z', - projectionMethod: 'AnotherReadModel.anotherObserver', + return [ + { + id: 'joinColumnID', + kind: 'another', + count: 177, + boosterMetadata: { + version: anotherReadModelStoredVersion, + lastUpdateAt: '1970-01-01T00:00:00.000Z', + lastProjectionInfo: { + entityId: 'importantEntityID', + entityName: 'AnImportantEntity', + entityUpdatedAt: '1970-01-01T00:00:00.000Z', + projectionMethod: 'AnotherReadModel.anotherObserver', + }, }, }, - } + ] } }) ) @@ -407,24 +419,24 @@ describe('ReadModelStore', () => { const anEntityInstance = new AnImportantEntity(entityValue.id, entityValue.someKey, entityValue.count) await readModelStore.project(anEntitySnapshot) - expect(readModelStore.fetchReadModel).to.have.been.calledThrice - expect(readModelStore.fetchReadModel).to.have.been.calledWith(SomeReadModel.name, 'joinColumnID') - expect(readModelStore.fetchReadModel).to.have.been.calledWith(AnotherReadModel.name, 'joinColumnID') - expect(SomeReadModel.someObserver).to.have.been.calledOnceWith(anEntityInstance, { - id: 'joinColumnID', - kind: 'some', - count: 77, - boosterMetadata: { - version: someReadModelStoredVersion, - lastUpdateAt: '1970-01-01T00:00:00.000Z', - lastProjectionInfo: { - entityId: 'importantEntityID', - entityName: 'AnImportantEntity', - entityUpdatedAt: '1970-01-01T00:00:00.000Z', - projectionMethod: 'SomeReadModel.someObserver', + expect(SomeReadModel.someObserver).to.have.been.calledOnceWith( + anEntityInstance, + match({ + id: 'joinColumnID', + count: 77, + kind: 'some', + boosterMetadata: { + version: someReadModelStoredVersion, + lastUpdateAt: '1970-01-01T00:00:00.000Z', + lastProjectionInfo: { + entityId: 'importantEntityID', + entityName: 'AnImportantEntity', + entityUpdatedAt: '1970-01-01T00:00:00.000Z', + projectionMethod: 'SomeReadModel.someObserver', + }, }, - }, - }) + }) + ) expect(SomeReadModel.someObserver).to.have.returned({ id: 'joinColumnID', kind: 'some', @@ -441,21 +453,24 @@ describe('ReadModelStore', () => { }, }, }) - expect(AnotherReadModel.anotherObserver).to.have.been.calledOnceWith(anEntityInstance, { - id: 'joinColumnID', - kind: 'another', - count: 177, - boosterMetadata: { - version: anotherReadModelStoredVersion, - lastUpdateAt: '1970-01-01T00:00:00.000Z', - lastProjectionInfo: { - entityId: 'importantEntityID', - entityName: 'AnImportantEntity', - entityUpdatedAt: '1970-01-01T00:00:00.000Z', - projectionMethod: 'AnotherReadModel.anotherObserver', + expect(AnotherReadModel.anotherObserver).to.have.been.calledOnceWith( + anEntityInstance, + match({ + id: 'joinColumnID', + count: 177, + kind: 'another', + boosterMetadata: { + version: anotherReadModelStoredVersion, + lastUpdateAt: '1970-01-01T00:00:00.000Z', + lastProjectionInfo: { + entityId: 'importantEntityID', + entityName: 'AnImportantEntity', + entityUpdatedAt: '1970-01-01T00:00:00.000Z', + projectionMethod: 'AnotherReadModel.anotherObserver', + }, }, - }, - }) + }) + ) expect(AnotherReadModel.anotherObserver).to.have.returned({ id: 'joinColumnID', kind: 'another', @@ -521,6 +536,8 @@ describe('ReadModelStore', () => { context('when the projection calls an instance method in the entity', () => { it('is executed without failing', async () => { const readModelStore = new ReadModelStore(config) + replace(Booster, 'config', config) // Needed because the function `Booster.readModel` references `this.config` from `searchFunction` + replace(config.provider.readModels, 'search', fake.returns([])) const getPrefixedKeyFake = fake() replace(AnImportantEntity.prototype, 'getPrefixedKey', getPrefixedKeyFake) await readModelStore.project(entitySnapshotEnvelopeFor(AnImportantEntity.name)) @@ -531,7 +548,8 @@ describe('ReadModelStore', () => { context('when the projection calls an instance method in the read model', () => { it('is executed without failing', async () => { const readModelStore = new ReadModelStore(config) - replace(config.provider.readModels, 'fetch', fake.returns([{ id: 'joinColumnID', count: 31415 }])) + replace(Booster, 'config', config) // Needed because the function `Booster.readModel` references `this.config` from `searchFunction` + replace(config.provider.readModels, 'search', fake.returns([{ id: 'joinColumnID', count: 31415 }])) const getIdFake = fake() replace(SomeReadModel.prototype, 'getId', getIdFake) await readModelStore.project(entitySnapshotEnvelopeFor(AnEntity.name)) @@ -559,6 +577,8 @@ describe('ReadModelStore', () => { } return Promise.resolve() }) + replace(Booster, 'config', config) // Needed because the function `Booster.readModel` references `this.config` from `searchFunction` + replace(config.provider.readModels, 'search', fake.returns([])) replace(config.provider.readModels, 'store', fakeStore) const readModelStore = new ReadModelStore(config) await readModelStore.project(entitySnapshotEnvelopeFor(AnImportantEntity.name)) @@ -605,34 +625,29 @@ describe('ReadModelStore', () => { replace(config.provider.readModels, 'store', fake()) const readModelStore = new ReadModelStore(config) const someReadModelStoredVersion = 10 + replace(Booster, 'config', config) // Needed because the function `Booster.readModel` references `this.config` from `searchFunction` replace( - readModelStore, - 'fetchReadModel', - fake((className: string, id: UUID) => { - if (className == SomeReadModel.name) { - if (id == 'anotherJoinColumnID') { - return null - } else { - return { - id: id, - kind: 'some', - count: 77, - boosterMetadata: { - version: someReadModelStoredVersion, - lastUpdateAt: '1970-01-01T00:00:00.000Z', - lastProjectionInfo: { - entityId: 'importantEntityID', - entityName: 'AnImportantEntityWithArray', - entityUpdatedAt: '1970-01-01T00:00:00.000Z', - projectionMethod: 'SomeReadModel.someObserverArray', - }, - }, - } - } - } - return null - }) + config.provider.readModels, + 'search', + fake.returns([ + { + id: 'joinColumnID', + kind: 'some', + count: 77, + boosterMetadata: { + version: someReadModelStoredVersion, + lastUpdateAt: '1970-01-01T00:00:00.000Z', + lastProjectionInfo: { + entityId: 'importantEntityID', + entityName: 'AnImportantEntityWithArray', + entityUpdatedAt: '1970-01-01T00:00:00.000Z', + projectionMethod: 'SomeReadModel.someObserverArray', + }, + }, + }, + ]) ) + spy(SomeReadModel, 'someObserver') spy(SomeReadModel, 'someObserverArray') const anEntitySnapshot = entitySnapshotEnvelopeFor(AnImportantEntityWithArray.name) @@ -640,24 +655,25 @@ describe('ReadModelStore', () => { const anEntityInstance = new AnImportantEntityWithArray(entityValue.id, entityValue.someKey, entityValue.count) await readModelStore.project(anEntitySnapshot) - expect(readModelStore.fetchReadModel).to.have.been.calledTwice - expect(readModelStore.fetchReadModel).to.have.been.calledWith(SomeReadModel.name, 'joinColumnID') - expect(readModelStore.fetchReadModel).to.have.been.calledWith(SomeReadModel.name, 'anotherJoinColumnID') - expect(SomeReadModel.someObserverArray).to.have.been.calledWithMatch(anEntityInstance, 'joinColumnID', { - id: 'joinColumnID', - kind: 'some', - count: 77, - boosterMetadata: { - version: someReadModelStoredVersion, - lastUpdateAt: '1970-01-01T00:00:00.000Z', - lastProjectionInfo: { - entityId: 'importantEntityID', - entityName: 'AnImportantEntityWithArray', - entityUpdatedAt: '1970-01-01T00:00:00.000Z', - projectionMethod: 'SomeReadModel.someObserverArray', + expect(SomeReadModel.someObserverArray).to.have.been.calledWithMatch( + anEntityInstance, + 'joinColumnID', + match({ + id: 'joinColumnID', + kind: 'some', + count: 77, + boosterMetadata: { + version: someReadModelStoredVersion, + lastUpdateAt: '1970-01-01T00:00:00.000Z', + lastProjectionInfo: { + entityId: 'importantEntityID', + entityName: 'AnImportantEntityWithArray', + entityUpdatedAt: '1970-01-01T00:00:00.000Z', + projectionMethod: 'SomeReadModel.someObserverArray', + }, }, - }, - }) + }) + ) expect(SomeReadModel.someObserverArray).to.have.returned({ id: 'joinColumnID', kind: 'some', @@ -759,6 +775,8 @@ describe('ReadModelStore', () => { } ) replace(config.provider.readModels, 'store', fakeStore) + replace(Booster, 'config', config) // Needed because the function `Booster.readModel` references `this.config` from `searchFunction` + replace(config.provider.readModels, 'search', fake.returns([])) const readModelStore = new ReadModelStore(config) await readModelStore.project(entitySnapshotEnvelopeFor(AnImportantEntityWithArray.name)) @@ -813,6 +831,8 @@ describe('ReadModelStore', () => { const readModelStore = new ReadModelStore(config) const fakeApplyProjectionToReadModel = fake() replace(readModelStore as any, 'applyProjectionToReadModel', fakeApplyProjectionToReadModel) + replace(Booster, 'config', config) // Needed because the function `Booster.readModel` references `this.config` from `searchFunction` + replace(config.provider.readModels, 'search', fake.returns([])) await readModelStore.project(anEntitySnapshot) @@ -820,11 +840,15 @@ describe('ReadModelStore', () => { for (const projectionMetadata of config.projections[AnImportantEntity.name]) { const readModelClassName = projectionMetadata.class.name expect(fakeApplyProjectionToReadModel).to.have.been.calledWith( + anEntitySnapshot, anEntityInstance, projectionMetadata, - readModelClassName, - anEntityInstance[projectionMetadata.joinKey], - readModelClassName === 'AnotherReadModel' ? { name: 'count', value: 123 } : undefined + false, + undefined, + anEntitySnapshot, + 'joinColumnID', + readModelClassName === 'AnotherReadModel' ? { name: 'count', value: 123 } : undefined, + 1 ) } }) @@ -864,7 +888,7 @@ describe('ReadModelStore', () => { }) it('returns an instance of the current read model value when it exists', async () => { - replace(config.provider.readModels, 'fetch', fake.returns([{ id: 'joinColumnID' }])) + replace(config.provider.readModels, 'fetch', fake.returns([{ id: 'joinColumnID', count: 0 }])) const readModelStore = new ReadModelStore(config) const result = await readModelStore.fetchReadModel(SomeReadModel.name, 'joinColumnID') @@ -875,7 +899,7 @@ describe('ReadModelStore', () => { 'joinColumnID', undefined ) - expect(result).to.be.deep.equal(new SomeReadModel('joinColumnID')) + expect(result).to.be.deep.equal(new SomeReadModel('joinColumnID', 0)) }) }) @@ -899,29 +923,6 @@ describe('ReadModelStore', () => { }) }) - describe('the `joinKeyForProjection` private method', () => { - context('when the joinKey exists', () => { - it('returns the joinKey value', () => { - const anEntitySnapshot = entitySnapshotEnvelopeFor(AnImportantEntity.name) - const anEntityInstance = createInstance(AnImportantEntity, anEntitySnapshot.value) as any - const readModelStore = new ReadModelStore(config) as any - - expect(readModelStore.joinKeyForProjection(anEntityInstance, { joinKey: 'someKey' })).to.be.deep.equal([ - 'joinColumnID', - ]) - }) - }) - - context('when the joinkey does not exist', () => { - it('should not throw and error an skip', () => { - const anEntitySnapshot = entitySnapshotEnvelopeFor(AnImportantEntity.name) - const anEntityInstance = createInstance(AnImportantEntity, anEntitySnapshot.value) as any - const readModelStore = new ReadModelStore(config) as any - expect(readModelStore.joinKeyForProjection(anEntityInstance, { joinKey: 'whatever' })).to.be.undefined - }) - }) - }) - describe('the `sequenceKeyForProjection` private method', () => { context('when there is no sequence key for the read model in the config', () => { it('returns undefined', () => { diff --git a/packages/framework-integration-tests/integration/helper/deps-helper.ts b/packages/framework-integration-tests/integration/helper/deps-helper.ts index 6cef411634..51006d5c74 100644 --- a/packages/framework-integration-tests/integration/helper/deps-helper.ts +++ b/packages/framework-integration-tests/integration/helper/deps-helper.ts @@ -1,4 +1,4 @@ -import { exec } from 'child-process-promise' +import { command } from 'execa' import * as path from 'path' import * as fs from 'fs' @@ -35,5 +35,5 @@ function overrideWithLocalDeps(dependencies: Record): void { } export async function forceRepoRebuild(): Promise { - await exec('rush update && rush rebuild') + await command('rush update && rush rebuild') } diff --git a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.build.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.build.integration.ts index 5ef1e36a66..ee6094d73c 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.build.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.build.integration.ts @@ -1,7 +1,7 @@ import * as path from 'path' import { expect } from 'chai' -import { sandboxPathFor, removeFolders, fileExists } from '../../helper/file-helper' -import { exec } from 'child-process-promise' +import { fileExists, removeFolders, sandboxPathFor } from '../../helper/file-helper' +import { command } from 'execa' // Imported from another package to avoid duplication // It is OK-ish, since integration tests are always run in the context of the whole monorepo import { createSandboxProject } from '../../../../cli/src/common/sandbox' @@ -26,7 +26,7 @@ describe('Build', () => { ['boost build', 'Checking project structure', 'Building project', 'Build complete'].join('(.|\n)*') ) - const { stdout } = await exec(`${cliPath} build`, { cwd: buildSandboxDir }) + const { stdout } = await command(`${cliPath} build`, { cwd: buildSandboxDir }) expect(stdout).to.match(expectedOutputRegex) expect(fileExists(path.join(buildSandboxDir, 'dist', 'index.js'))).to.be.true @@ -64,7 +64,7 @@ describe('Compile fallback', () => { ['boost build', 'Checking project structure', 'Building project', 'Build complete'].join('(.|\n)*') ) - const { stdout } = await exec(`${cliPath} build`, { cwd: compileSandboxDir }) + const { stdout } = await command(`${cliPath} build`, { cwd: compileSandboxDir }) expect(stdout).to.match(expectedOutputRegex) expect(fileExists(path.join(compileSandboxDir, 'eureka'))).to.be.true diff --git a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.clean.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.clean.integration.ts index 82d1c22b60..22977ffb7d 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.clean.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.clean.integration.ts @@ -1,7 +1,7 @@ import * as path from 'path' import { expect } from 'chai' -import { sandboxPathFor, removeFolders, fileExists } from '../../helper/file-helper' -import { exec } from 'child-process-promise' +import { fileExists, removeFolders, sandboxPathFor } from '../../helper/file-helper' +import { command } from 'execa' // Imported from another package to avoid duplication // It is OK-ish, since integration tests are always run in the context of the whole monorepo import { createSandboxProject } from '../../../../cli/src/common/sandbox' @@ -21,19 +21,18 @@ describe('Clean', () => { context('Valid clean', () => { it('should clean the project after build', async () => { - - await exec(`${cliPath} build`, { cwd: cleanSandboxDir }) - - expect(fileExists(path.join(cleanSandboxDir,'dist'))).to.be.true - + await command(`${cliPath} build`, { cwd: cleanSandboxDir }) + + expect(fileExists(path.join(cleanSandboxDir, 'dist'))).to.be.true + const expectedCleanOutputRegex = new RegExp( ['boost clean', 'Checking project structure', 'Cleaning project', 'Clean complete'].join('(.|\n)*') ) - const { stdout } = await exec(`${cliPath} clean`, { cwd: cleanSandboxDir }) + const { stdout } = await command(`${cliPath} clean`, { cwd: cleanSandboxDir }) expect(stdout).to.match(expectedCleanOutputRegex) - expect(fileExists(path.join(cleanSandboxDir,'dist'))).to.be.false + expect(fileExists(path.join(cleanSandboxDir, 'dist'))).to.be.false }) }) -}) \ No newline at end of file +}) diff --git a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.command.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.command.integration.ts index 8838a62da4..96de3c7546 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.command.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.command.integration.ts @@ -1,7 +1,7 @@ import * as path from 'path' import { expect } from 'chai' import { loadFixture, readFileContent, removeFolders, sandboxPathFor, writeFileContent } from '../../helper/file-helper' -import { exec } from 'child-process-promise' +import { command } from 'execa' // Imported from another package to avoid duplication // It is OK-ish, since integration tests are always run in the context of the whole monorepo import { createSandboxProject } from '../../../../cli/src/common/sandbox' @@ -29,7 +29,7 @@ describe('Command', () => { ['boost new:command', 'Verifying project', 'Creating new command', 'Command generated'].join('(.|\n)*') ) - const { stdout } = await exec(`${cliPath} new:command ChangeCart`, { cwd: commandSandboxDir }) + const { stdout } = await command(`${cliPath} new:command ChangeCart`, { cwd: commandSandboxDir }) expect(stdout).to.match(expectedOutputRegex) const expectedCommandContent = loadFixture('commands/change-cart.ts') @@ -46,7 +46,7 @@ describe('Command', () => { it('should create a new command with fields', async () => { const changeCartWithFieldsCommandPath = `${commandSandboxDir}/src/commands/change-cart-with-fields.ts` - await exec(`${cliPath} new:command ChangeCartWithFields --fields cartId:UUID sku:string quantity:number`, { + await command(`${cliPath} new:command ChangeCartWithFields --fields cartId:UUID sku:string quantity:number`, { cwd: commandSandboxDir, }) @@ -65,7 +65,7 @@ describe('Command', () => { context('Invalid command', () => { describe('missing command name', () => { it('should fail', async () => { - const { stderr } = await exec(`${cliPath} new:command`, { cwd: commandSandboxDir }) + const { stderr } = await command(`${cliPath} new:command`, { cwd: commandSandboxDir }) expect(stderr).to.match(/You haven't provided a command name, but it is required, run with --help for usage/) }) diff --git a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.entity.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.entity.integration.ts index 90f67d7cc2..55592d3a55 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.entity.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.entity.integration.ts @@ -1,7 +1,7 @@ import { expect } from 'chai' -import { readFileContent, writeFileContent, loadFixture, removeFolders, sandboxPathFor } from '../../helper/file-helper' +import { loadFixture, readFileContent, removeFolders, sandboxPathFor, writeFileContent } from '../../helper/file-helper' import * as path from 'path' -import { exec } from 'child-process-promise' +import { command } from 'execa' // Imported from another package to avoid duplication // It is OK-ish, since integration tests are always run in the context of the whole monorepo import { createSandboxProject } from '../../../../cli/src/common/sandbox' @@ -29,7 +29,7 @@ describe('Entity', () => { ['boost new:entity', 'Verifying project', 'Creating new entity', 'Entity generated'].join('(.|\n)*'), 'm' ) - const { stdout } = await exec(`${cliPath} new:entity Post`, { cwd: entitySandboxDir }) + const { stdout } = await command(`${cliPath} new:entity Post`, { cwd: entitySandboxDir }) expect(stdout).to.match(expectedOutputRegex) const expectedEntityContent = readFileContent('integration/fixtures/entities/post.ts') @@ -44,7 +44,7 @@ describe('Entity', () => { ['boost new:entity', 'Verifying project', 'Creating new entity', 'Entity generated'].join('(.|\n)*'), 'm' ) - const { stdout } = await exec(`${cliPath} new:entity PostWithFields --fields title:string body:string`, { + const { stdout } = await command(`${cliPath} new:entity PostWithFields --fields title:string body:string`, { cwd: entitySandboxDir, }) expect(stdout).to.match(expectedOutputRegex) @@ -61,7 +61,7 @@ describe('Entity', () => { const FILE_POST_CREATED_EVENT = `${entitySandboxDir}/src/events/post-created.ts` // Create event - await exec(`${cliPath} new:event PostCreated --fields postId:UUID title:string body:string`, { + await command(`${cliPath} new:event PostCreated --fields postId:UUID title:string body:string`, { cwd: entitySandboxDir, }) @@ -75,7 +75,7 @@ describe('Entity', () => { writeFileContent(FILE_POST_CREATED_EVENT, updatedEventContent) // Create entity - await exec(`${cliPath} new:entity PostWithReducer --fields title:string body:string --reduces PostCreated`, { + await command(`${cliPath} new:entity PostWithReducer --fields title:string body:string --reduces PostCreated`, { cwd: entitySandboxDir, }) const expectedEntityContent = loadFixture('entities/post-with-reducer.ts') @@ -96,7 +96,7 @@ describe('Entity', () => { context('invalid entity', () => { describe('missing entity name', () => { it('should fail', async () => { - const { stderr } = await exec(`${cliPath} new:entity`, { cwd: entitySandboxDir }) + const { stderr } = await command(`${cliPath} new:entity`, { cwd: entitySandboxDir }) expect(stderr).to.match(/You haven't provided an entity name, but it is required, run with --help for usage/m) }) diff --git a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.event-handler.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.event-handler.integration.ts index 2108e3063b..78acb156de 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.event-handler.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.event-handler.integration.ts @@ -1,7 +1,7 @@ import * as path from 'path' import { expect } from 'chai' import { loadFixture, readFileContent, removeFolders, sandboxPathFor } from '../../helper/file-helper' -import { exec } from 'child-process-promise' +import { command } from 'execa' // Imported from another package to avoid duplication // It is OK-ish, since integration tests are always run in the context of the whole monorepo import { createSandboxProject } from '../../../../cli/src/common/sandbox' @@ -27,7 +27,7 @@ describe('Event handler', () => { ) ) - const { stdout } = await exec(`${cliPath} new:event-handler HandleCartChange -e CartItemChanged`, { + const { stdout } = await command(`${cliPath} new:event-handler HandleCartChange -e CartItemChanged`, { cwd: eventHandlerSandboxDir, }) expect(stdout).to.match(expectedOutputRegex) @@ -42,7 +42,7 @@ describe('Event handler', () => { describe('Invalid event handler', () => { context('without name and event', () => { it('should fail', async () => { - const { stderr } = await exec(`${cliPath} new:event-handler`, { cwd: eventHandlerSandboxDir }) + const { stderr } = await command(`${cliPath} new:event-handler`, { cwd: eventHandlerSandboxDir }) expect(stderr).to.match( /You haven't provided an event handler name, but it is required, run with --help for usage/ @@ -52,7 +52,7 @@ describe('Event handler', () => { context('Without name', () => { it('should fail', async () => { - const { stderr } = await exec(`${cliPath} new:event-handler -e CartPaid`, { cwd: eventHandlerSandboxDir }) + const { stderr } = await command(`${cliPath} new:event-handler -e CartPaid`, { cwd: eventHandlerSandboxDir }) expect(stderr).to.match( /You haven't provided an event handler name, but it is required, run with --help for usage/ @@ -62,7 +62,7 @@ describe('Event handler', () => { context('Without event', () => { it('should fail', async () => { - const { stderr } = await exec(`${cliPath} new:event-handler CartPaid`, { cwd: eventHandlerSandboxDir }) + const { stderr } = await command(`${cliPath} new:event-handler CartPaid`, { cwd: eventHandlerSandboxDir }) expect(stderr).to.match(/You haven't provided an event, but it is required, run with --help for usage/) }) diff --git a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.event.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.event.integration.ts index a2ef1adf6c..688626dc5a 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.event.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.event.integration.ts @@ -8,7 +8,7 @@ import { sandboxPathFor, writeFileContent, } from '../../helper/file-helper' -import { exec } from 'child-process-promise' +import { command } from 'execa' // Imported from another package to avoid duplication // It is OK-ish, since integration tests are always run in the context of the whole monorepo import { createSandboxProject } from '../../../../cli/src/common/sandbox' @@ -34,7 +34,7 @@ describe('Event', () => { ['boost new:event', 'Verifying project', 'Creating new event', 'Event generated'].join('(.|\n)*') ) - const { stdout } = await exec(`${cliPath} new:event CartChanged`, { cwd: eventSandboxDir }) + const { stdout } = await command(`${cliPath} new:event CartChanged`, { cwd: eventSandboxDir }) expect(stdout).to.match(expectedOutputRegex) }) @@ -43,7 +43,7 @@ describe('Event', () => { const FILE_CART_CHANGED_EVENT = `${eventSandboxDir}/src/events/cart-changed.ts` removeFiles([FILE_CART_CHANGED_EVENT]) - await exec(`${cliPath} new:event CartChanged`, { cwd: eventSandboxDir }) + await command(`${cliPath} new:event CartChanged`, { cwd: eventSandboxDir }) const expectedEventContent = loadFixture('events/cart-changed.ts') const eventContent = readFileContent(FILE_CART_CHANGED_EVENT) @@ -60,7 +60,7 @@ describe('Event', () => { it('should create new event', async () => { const FILE_CART_CHANGED_WITH_FIELDS_EVENT = `${eventSandboxDir}/src/events/cart-changed-with-fields.ts` - await exec(`${cliPath} new:event CartChangedWithFields --fields cartId:UUID sku:string quantity:number`, { + await command(`${cliPath} new:event CartChangedWithFields --fields cartId:UUID sku:string quantity:number`, { cwd: eventSandboxDir, }) @@ -79,7 +79,7 @@ describe('Event', () => { context('Invalid event', () => { describe('missing event name', () => { it('should fail', async () => { - const { stderr } = await exec(`${cliPath} new:event`, { cwd: eventSandboxDir }) + const { stderr } = await command(`${cliPath} new:event`, { cwd: eventSandboxDir }) expect(stderr).to.match(/You haven't provided an event name, but it is required, run with --help for usage/) }) diff --git a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.project.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.project.integration.ts index 45c4b2ef82..baeeed760a 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.project.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.project.integration.ts @@ -1,5 +1,5 @@ import * as path from 'path' -import { exec } from 'child-process-promise' +import { command } from 'execa' import { createFolder, dirContents, @@ -8,9 +8,9 @@ import { readFileContent, removeFolders, } from '../../helper/file-helper' -import { ChildProcess } from 'child_process' import { overrideWithBoosterLocalDependencies } from '../../helper/deps-helper' import { expect } from '../../helper/expect' +import { ChildProcess, exec as cpExec } from 'child_process' // The Booster CLI version used should match the integration tests' version const BOOSTER_VERSION = require('../../../package.json').version @@ -29,8 +29,10 @@ describe('Project', () => { before(async () => { // Required by Github actions CI/CD, because it doesn't have git configured - await exec('git config --global user.name || git config --global user.name "Booster Test"') - await exec('git config --global user.email || git config --global user.email "test@booster.cloud"') + await command('git config --global user.name || git config --global user.name "Booster Test"', { shell: true }) + await command('git config --global user.email || git config --global user.email "test@booster.cloud"', { + shell: true, + }) createFolder(SANDBOX_INTEGRATION_DIR) }) @@ -93,8 +95,21 @@ describe('Project', () => { }) cliProcess.stdout.on('end', () => { - cliProcess.stdin?.end() resolve() + // + // if (cliProcess.stdin) { + // console.log('Attempting to end stdin') + // try { + // cliProcess.stdin.end() + // console.log('stdin ended') + // } catch (error) { + // console.error('Error ending stdin:', error) + // } + // } else { + // resolve() + // } + // cliProcess.stdin?.end() + // resolve() }) cliProcess.stdout.on('error', () => { @@ -112,16 +127,22 @@ describe('Project', () => { flags: Array = [], promptAnswers?: PromptAnswers ): Promise<{ stdout: string; stderr: string }> => { - const cliProcess = exec(`${cliPath} new:project ${projectName} ${flags.join(' ')}`, { - cwd: SANDBOX_INTEGRATION_DIR, - }) - - if (promptAnswers) { - await handlePrompt(cliProcess.childProcess, promptAnswers) - } + return new Promise((resolve, reject) => { + const cliProcess = cpExec( + `${cliPath} new:project ${projectName} ${flags.join(' ')}`, + { + cwd: SANDBOX_INTEGRATION_DIR, + }, + (error, stdout, stderr) => { + if (error) reject(error) + else resolve({ stdout, stderr }) + } + ) - const { stdout, stderr } = await cliProcess - return { stdout, stderr } + if (promptAnswers) { + handlePrompt(cliProcess, promptAnswers).catch(reject) + } + }) } const packageJsonAssertions = ( @@ -240,13 +261,20 @@ describe('Project', () => { it('should create a new project using short flags to configure it', async () => { const projectName = 'cart-demo-short-flags' const flags = [ - `-a "${AUTHOR}"`, - `-d "${DESCRIPTION}"`, - `-H "${HOMEPAGE}"`, - `-l "${LICENSE}"`, - `-p "${PROVIDER}"`, - `-r "${REPO_URL}"`, - `-v "${VERSION}"`, + '-a', + `"${AUTHOR}"`, + '-d', + `"${DESCRIPTION}"`, + '-H', + `"${HOMEPAGE}"`, + '-l', + `"${LICENSE}"`, + '-p', + `"${PROVIDER}"`, + '-r', + `"${REPO_URL}"`, + '-v', + `"${VERSION}"`, // We skip dependencies and git installation to make this test faster '--skipInstall', '--skipGit', @@ -259,13 +287,20 @@ describe('Project', () => { it('should create a new project using long flags to configure it', async () => { const projectName = 'cart-demo-long-flags' const flags = [ - `--author "${AUTHOR}"`, - `--description "${DESCRIPTION}"`, - `--homepage "${HOMEPAGE}"`, - `--license "${LICENSE}"`, - `--providerPackageName "${PROVIDER}"`, - `--repository "${REPO_URL}"`, - `--version "${VERSION}"`, + '--author', + `"${AUTHOR}"`, + '--description', + `"${DESCRIPTION}"`, + '--homepage', + `"${HOMEPAGE}"`, + '--license', + `"${LICENSE}"`, + '--providerPackageName', + `"${PROVIDER}"`, + '--repository', + `"${REPO_URL}"`, + '--version', + `"${VERSION}"`, // We skip dependencies and git installation to make this test faster '--skipInstall', '--skipGit', @@ -297,8 +332,11 @@ describe('Project', () => { }) it('passes linter', async () => { - await expect(exec('npm run lint:check', { cwd: projectPath(projectName), capture: ['stderr', 'stdout'] })).to - .be.eventually.fulfilled + await expect( + command('npm run lint:check', { + cwd: projectPath(projectName), + }) + ).to.be.eventually.fulfilled }).timeout(TEST_TIMEOUT) // TODO: Remove the skip when there is at leas one version published of framework-common-helpers @@ -307,9 +345,9 @@ describe('Project', () => { // Rewrite dependencies to use local versions await overrideWithBoosterLocalDependencies(fullProjectPath) // Install those dependencies - await exec('npm install --omit=dev --omit=optional --no-bin-links', { cwd: fullProjectPath }) + await command('npm install --omit=dev --omit=optional --no-bin-links', { cwd: fullProjectPath }) - await expect(exec('npm run build', { cwd: fullProjectPath })).to.be.eventually.fulfilled + await expect(command('npm run build', { cwd: fullProjectPath })).to.be.eventually.fulfilled }) }) @@ -369,8 +407,10 @@ describe('Project', () => { license: LICENSE, } const flags = [ - `--providerPackageName "${PROVIDER}"`, - `--repository "${REPO_URL}"`, + '--providerPackageName', + `"${PROVIDER}"`, + '--repository', + `"${REPO_URL}"`, // We skip dependencies and git installation to make this test faster '--skipInstall', '--skipGit', @@ -385,7 +425,7 @@ describe('Project', () => { context('Invalid project', () => { describe('missing project name', () => { it('should fail', async () => { - const { stderr } = await exec(`${cliPath} new:project`, { cwd: SANDBOX_INTEGRATION_DIR }) + const { stderr } = await command(`${cliPath} new:project`, { cwd: SANDBOX_INTEGRATION_DIR }) expect(stderr).to.match(/You haven't provided a project name, but it is required, run with --help for usage/) }) @@ -398,13 +438,20 @@ describe('Project', () => { ) const flags = [ - `--author "${AUTHOR}"`, - `--description "${DESCRIPTION}"`, - `--homepage "${HOMEPAGE}"`, - `--license "${LICENSE}"`, - '--providerPackageName "invalid-provider"', - `--repository "${REPO_URL}"`, - `--version "${VERSION}"`, + '--author', + `"${AUTHOR}"`, + '--description', + `"${DESCRIPTION}"`, + '--homepage', + `"${HOMEPAGE}"`, + '--license', + `"${LICENSE}"`, + '--providerPackageName', + '"invalid-provider"', + '--repository', + `"${REPO_URL}"`, + '--version', + `"${VERSION}"`, // We skip dependencies and git installation to make this test faster '--skipInstall', '--skipGit', diff --git a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.readmodel.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.readmodel.integration.ts index cbb85190e2..e539f328e1 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.readmodel.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.readmodel.integration.ts @@ -8,7 +8,7 @@ import { sandboxPathFor, writeFileContent, } from '../../helper/file-helper' -import { exec } from 'child-process-promise' +import { command } from 'execa' // Imported from another package to avoid duplication // It is OK-ish, since integration tests are always run in the context of the whole monorepo import { createSandboxProject } from '../../../../cli/src/common/sandbox' @@ -38,7 +38,7 @@ describe('Read model', () => { const FILE_CART_READ_MODEL = `${readModelSandboxDir}/src/read-models/cart-read-model.ts` removeFiles([FILE_CART_READ_MODEL]) - const { stdout } = await exec(`${cliPath} new:read-model CartReadModel`, { cwd: readModelSandboxDir }) + const { stdout } = await command(`${cliPath} new:read-model CartReadModel`, { cwd: readModelSandboxDir }) expect(stdout).to.match(EXPECTED_OUTPUT_REGEX) const expectedEntityContent = loadFixture('read-models/cart-read-model.ts') @@ -56,9 +56,9 @@ describe('Read model', () => { it('should create new read model', async () => { const FILE_CART_WITH_FIELDS_READ_MODEL = `${readModelSandboxDir}/src/read-models/cart-with-fields-read-model.ts` - const { stdout } = await exec( + const { stdout } = await command( cliPath + " new:read-model CartWithFieldsReadModel --fields 'items:Array'", - { cwd: readModelSandboxDir } + { cwd: readModelSandboxDir, shell: true } ) expect(stdout).to.match(EXPECTED_OUTPUT_REGEX) @@ -80,9 +80,9 @@ describe('Read model', () => { it('should create new read model', async () => { const FILE_CART_WITH_PROJECTION_READ_MODEL = `${readModelSandboxDir}/src/read-models/cart-with-projection-read-model.ts` - const { stdout } = await exec( + const { stdout } = await command( cliPath + " new:read-model CartWithProjectionReadModel --fields 'items:Array' --projects Cart:id", - { cwd: readModelSandboxDir } + { cwd: readModelSandboxDir, shell: true } ) expect(stdout).to.match(EXPECTED_OUTPUT_REGEX) @@ -110,7 +110,7 @@ describe('Read model', () => { context('invalid read model', () => { describe('missing read model name', () => { it('should fail', async () => { - const { stderr } = await exec(`${cliPath} new:read-model`, { cwd: readModelSandboxDir }) + const { stderr } = await command(`${cliPath} new:read-model`, { cwd: readModelSandboxDir }) expect(stderr).to.match(/You haven't provided a read model name, but it is required, run with --help for usage/) }) diff --git a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.scheduled-command.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.scheduled-command.integration.ts index c9e7d2c5d3..2e3291ae6b 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.scheduled-command.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.scheduled-command.integration.ts @@ -1,7 +1,7 @@ import * as path from 'path' import { expect } from 'chai' import { loadFixture, readFileContent, removeFolders, sandboxPathFor } from '../../helper/file-helper' -import { exec } from 'child-process-promise' +import { command } from 'execa' // Imported from another package to avoid duplication // It is OK-ish, since integration tests are always run in the context of the whole monorepo import { createSandboxProject } from '../../../../cli/src/common/sandbox' @@ -30,7 +30,9 @@ describe('Scheduled Command', () => { ].join('(.|\n)*') ) - const { stdout } = await exec(`${cliPath} new:scheduled-command CheckCart`, { cwd: scheduledCommandSandboxDir }) + const { stdout } = await command(`${cliPath} new:scheduled-command CheckCart`, { + cwd: scheduledCommandSandboxDir, + }) expect(stdout).to.match(expectedOutputRegex) const expectedCommandContent = loadFixture('scheduled-commands/check-cart.ts') @@ -44,7 +46,7 @@ describe('Scheduled Command', () => { context('Invalid scheduled command', () => { describe('missing scheduled command name', () => { it('should fail', async () => { - const { stderr } = await exec(`${cliPath} new:scheduled-command`, { cwd: scheduledCommandSandboxDir }) + const { stderr } = await command(`${cliPath} new:scheduled-command`, { cwd: scheduledCommandSandboxDir }) expect(stderr).to.match( /You haven't provided a scheduled command name, but it is required, run with --help for usage/ diff --git a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.type.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.type.integration.ts index 8440417910..d3b121208a 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/cli/cli.type.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/cli/cli.type.integration.ts @@ -1,7 +1,7 @@ import * as path from 'path' import { expect } from 'chai' import { loadFixture, readFileContent, removeFolders, sandboxPathFor } from '../../helper/file-helper' -import { exec } from 'child-process-promise' +import { command } from 'execa' // Imported from another package to avoid duplication // It is OK-ish, since integration tests are always run in the context of the whole monorepo import { createSandboxProject } from '../../../../cli/src/common/sandbox' @@ -25,7 +25,7 @@ describe('Type', () => { ['boost new:type', 'Verifying project', 'Creating new type', 'Type generated'].join('(.|\n)*') ) - const { stdout } = await exec(`${cliPath} new:type Item`, { cwd: typeSandboxDir }) + const { stdout } = await command(`${cliPath} new:type Item`, { cwd: typeSandboxDir }) expect(stdout).to.match(expectedOutputRegex) const expectedTypeContent = loadFixture('common/item.ts') @@ -35,7 +35,7 @@ describe('Type', () => { describe('with fields', () => { it('should create a new type with fields', async () => { - await exec(`${cliPath} new:type ItemWithFields --fields sku:string quantity:number`, { + await command(`${cliPath} new:type ItemWithFields --fields sku:string quantity:number`, { cwd: typeSandboxDir, }) @@ -49,7 +49,7 @@ describe('Type', () => { context('Invalid type', () => { describe('missing type name', () => { it('should fail', async () => { - const { stderr } = await exec(`${cliPath} new:type`, { cwd: typeSandboxDir }) + const { stderr } = await command(`${cliPath} new:type`, { cwd: typeSandboxDir }) expect(stderr).to.match(/You haven't provided a type name, but it is required, run with --help for usage/) }) diff --git a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/cart.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/cart.integration.ts index 480b228d1e..71ba104476 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/cart.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/cart.integration.ts @@ -3,7 +3,7 @@ import { random, commerce, finance, lorem, internet } from 'faker' import { expect } from 'chai' import { CartItem } from '../../../src/common/cart-item' import { ProductType } from '../../../src/entities/product' -import { sleep, waitForIt } from '../../helper/sleep' +import { waitForIt } from '../../helper/sleep' import { applicationUnderTest } from './setup' import { beforeHookException, @@ -13,8 +13,6 @@ import { throwExceptionId, } from '../../../src/constants' -const secs = 10 - describe('Cart end-to-end tests', () => { let client: ApolloClient @@ -377,9 +375,6 @@ describe('Cart end-to-end tests', () => { `, }) - console.log(`Waiting ${secs} second${secs > 1 ? 's' : ''} for deletion to complete...`) - await sleep(secs * 1000) - client = applicationUnderTest.graphql.client(authToken) // Retrieve updated entity const queryResult = await waitForIt( @@ -406,7 +401,7 @@ describe('Cart end-to-end tests', () => { `, }) }, - () => true + (result) => !result?.data?.ProductReadModel ) const productData = queryResult.data.ProductReadModel diff --git a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/delete.events.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/delete.events.integration.ts new file mode 100644 index 0000000000..62b8e3e2ce --- /dev/null +++ b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/delete.events.integration.ts @@ -0,0 +1,485 @@ +import { ApolloClient, ApolloQueryResult, gql, NormalizedCacheObject } from '@apollo/client' +import { internet, random } from 'faker' +import { expect } from '../../helper/expect' +import { waitForIt } from '../../helper/sleep' +import { applicationUnderTest } from './setup' +import { + EventSearchResponse, + EventTimeParameterFilter, + PaginatedEntitiesIdsResult, +} from '@boostercloud/framework-types' +import 'mocha' + +describe('Remove Events end-to-end tests', async () => { + if (process.env.TESTED_PROVIDER === 'AWS') { + console.log('****************** Warning **********************') + console.log('AWS provider does not support remove events so these tests are skipped for AWS') + console.log('*************************************************') + return + } + let anonymousClient: ApolloClient + let loggedClient: ApolloClient + let adminTokenClient: ApolloClient + let specialTokenClient: ApolloClient + const firstCartId = random.uuid() + const firstProductId = random.uuid() + const firstProductSku = random.uuid() + const secondProductId = random.uuid() + const secondProductSku = random.uuid() + + before(async () => { + anonymousClient = applicationUnderTest.graphql.client() + const userEmail = internet.email() + const userToken = applicationUnderTest.token.forUser(userEmail, 'UserWithEmail') + loggedClient = applicationUnderTest.graphql.client(userToken) + const adminToken = applicationUnderTest.token.forUser('admin@example.com', 'Admin') + adminTokenClient = applicationUnderTest.graphql.client(adminToken) + const tokenWithSpecialAccess = applicationUnderTest.token.forUser(userEmail, undefined, { + customClaims: { + specialReportAccess: 'true', + }, + }) + specialTokenClient = applicationUnderTest.graphql.client(tokenWithSpecialAccess) + }) + + it('When there are not events to delete', async () => { + const deleted = await deleteEvent(anonymousClient, '1', 'Product', '') + expect(deleted).to.be.false + }) + + describe('When there are events to delete', async () => { + let firstCartReadModel + let firstProduct + let firstProductBySkuReadModel + let firstProductUpdatesReadModel + let firstSpecialReportsReadModel + let secondProduct + let secondProductBySkuReadModel + let secondProductUpdatesReadModel + let secondSpecialReportsReadModel + let events: Array + let productEvent + let firstProductEvent: any + let secondProductEvent: any + let firstCartEvent: any + + it('Create a cart', async () => { + await createCart(anonymousClient, firstCartId, firstProductId) + firstCartReadModel = await getCart(anonymousClient, firstCartId) + expect(firstCartReadModel.id).to.be.eq(firstCartId) + }) + + it('and create a first product', async () => { + await createProduct(loggedClient, firstProductId, firstProductSku) + }) + + it('then the related ReadModels are created', async () => { + firstProduct = await getProduct(loggedClient, firstProductId) + expect(firstProduct.id).to.be.eq(firstProductId) + const firstProductBySkuReadModel = await getProductBySku(loggedClient, firstProductSku) + expect(firstProductBySkuReadModel.id).to.be.eq(firstProductSku) + const firstProductUpdatesReadModel = await getProductUpdates(adminTokenClient, firstProductId) + expect(firstProductUpdatesReadModel.id).to.be.eq(firstProductId) + const firstSpecialReportsReadModel = await getSpecialReportsReadModel(specialTokenClient, firstProductId) + expect(firstSpecialReportsReadModel.id).to.be.eq(firstProductId) + }) + + it('when a second product is created', async () => { + await createProduct(loggedClient, secondProductId, secondProductSku) + }) + + it('then the related ReadModels for the second product are created', async () => { + secondProduct = await getProduct(loggedClient, secondProductId) + expect(secondProduct.id).to.be.eq(secondProductId) + const secondProductBySkuReadModel = await getProductBySku(loggedClient, secondProductSku) + expect(secondProductBySkuReadModel.id).to.be.eq(secondProductSku) + const secondProductUpdatesReadModel = await getProductUpdates(adminTokenClient, secondProductId) + expect(secondProductUpdatesReadModel.id).to.be.eq(secondProductId) + const secondSpecialReportsReadModel = await getSpecialReportsReadModel(specialTokenClient, secondProductId) + expect(secondSpecialReportsReadModel.id).to.be.eq(secondProductId) + }) + + it('when find the event for the first product', async () => { + events = await queryProductByEntity(loggedClient, firstProductId) + productEvent = events.filter((event) => event.entityID === firstProductId) + firstProductEvent = productEvent[0] + }) + + it('and delete it', async () => { + const deleted = await deleteEvent( + anonymousClient, + firstProductEvent.entityID.toString(), + firstProductEvent.entity, + firstProductEvent.createdAt + ) + expect(deleted).to.be.true + }) + + it('when find the event for the first product after delete', async () => { + events = await queryProductByEntity(loggedClient, firstProductId) + productEvent = events.filter((event) => event.entityID === firstProductId) + firstProductEvent = productEvent[0] + }) + + it('then the first event is set as deleted', async () => { + expect(firstProductEvent.deletedAt).not.to.be.undefined + expect(firstProductEvent.value.productId).to.be.undefined + }) + + it('and there are not ReadModels for first product id', async () => { + firstProduct = await getProductUndefined(loggedClient, firstProductId) + expect(firstProduct).to.be.null + firstProductBySkuReadModel = await getProductBySkuUndefined(loggedClient, firstProductSku) + expect(firstProductBySkuReadModel).to.be.null + firstProductUpdatesReadModel = await getProductUpdatesUndefined(adminTokenClient, firstProductId) + expect(firstProductUpdatesReadModel).to.be.null + firstSpecialReportsReadModel = await getSpecialReportsReadModelUndefined(specialTokenClient, firstProductId) + expect(firstSpecialReportsReadModel).to.be.null + }) + + it('when find the event for the second product', async () => { + events = await queryProductByEntity(loggedClient, secondProductId) + productEvent = events.filter((event) => event.entityID === secondProductId) + secondProductEvent = productEvent[0] + }) + + it('then the second event is not changed', async () => { + expect(secondProductEvent.deletedAt).to.be.null + expect(secondProductEvent.value.productId).to.be.eq(secondProductId) + }) + + it('and ReadModels for second product id are not deleted', async () => { + secondProduct = await getProduct(loggedClient, secondProductId) + expect(secondProduct.id).to.be.eq(secondProductId) + secondProductBySkuReadModel = await getProductBySku(loggedClient, secondProductSku) + expect(secondProductBySkuReadModel.id).to.be.eq(secondProductSku) + secondProductUpdatesReadModel = await getProductUpdates(adminTokenClient, secondProductId) + expect(secondProductUpdatesReadModel.id).to.be.eq(secondProductId) + secondSpecialReportsReadModel = await getSpecialReportsReadModel(specialTokenClient, secondProductId) + expect(secondSpecialReportsReadModel.id).to.be.eq(secondProductId) + }) + + it('and there are not entities for first product but for product 2', async () => { + const productsEntities = await findEntities(loggedClient, 'Product') + expect(productsEntities.items.some((product) => product.entityID === firstProductId)).to.be.false + expect(productsEntities.items.some((product) => product.entityID === secondProductId)).to.be.true + }) + + it('when find the event for the cart', async () => { + events = await queryCartByEntity(loggedClient, firstCartId) + const cartEvent = events.filter((event) => event.entityID === firstCartId) + firstCartEvent = cartEvent[0] + }) + + it('then the cart event is not changed', async () => { + expect(firstCartEvent.deletedAt).to.be.null + expect(firstCartEvent.value.cartId).to.be.eq(firstCartId) + }) + + it('and ReadModels for the cart id are not deleted', async () => { + firstCartReadModel = await getCart(loggedClient, firstCartId) + expect(firstCartReadModel.id).to.be.eq(firstCartId) + }) + }) +}) + +async function createCart(client: ApolloClient, cartId: string, productId: string): Promise { + await client.mutate({ + variables: { + cartId: cartId, + productId: productId, + }, + mutation: gql` + mutation ChangeCartItem($cartId: ID!, $productId: ID!) { + ChangeCartItem(input: { cartId: $cartId, productId: $productId, quantity: 1 }) + } + `, + }) +} + +async function createProduct(client: ApolloClient, productId: string, sku: string): Promise { + await client.mutate({ + variables: { + productId: productId, + sku: sku, + }, + mutation: gql` + mutation CreateProduct($productId: ID!, $sku: String!) { + CreateProduct( + input: { + productID: $productId + sku: $sku + displayName: "any" + description: "any" + currency: "any" + priceInCents: 1 + } + ) + } + `, + }) +} + +async function getCart(client: ApolloClient, id: string): Promise { + const result = await waitForIt( + () => { + return client.query({ + variables: { + id: id, + }, + query: gql` + query CartReadModel($id: ID!) { + CartReadModel(id: $id) { + id + } + } + `, + }) + }, + (result) => { + const resultId = result?.data?.CartReadModel?.id + return resultId === id + } + ) + return result.data.CartReadModel +} + +async function waitForProduct( + client: ApolloClient, + id: string, + checkFunction: (result: any) => boolean | string +): Promise { + return await waitForIt(() => { + return client.query({ + variables: { + id: id, + }, + query: gql` + query ProductReadModel($id: ID!) { + ProductReadModel(id: $id) { + id + } + } + `, + }) + }, checkFunction) +} + +async function getProduct(client: ApolloClient, id: string): Promise { + const product = await waitForProduct(client, id, (result) => { + const resultId = result?.data?.ProductReadModel?.id + return resultId === id + }) + return product.data.ProductReadModel +} + +async function getProductUndefined(client: ApolloClient, id: string): Promise { + const product = await waitForProduct(client, id, (result) => { + const resultId = result?.data?.ProductReadModel + return resultId === null + }) + return product.data.ProductReadModel +} + +async function awaitForProductUpdates( + client: ApolloClient, + id: string, + checkResult: (result: any) => boolean | string +) { + return await waitForIt(() => { + return client.query({ + variables: { + id: id, + }, + query: gql` + query ProductUpdatesReadModel($id: ID!) { + ProductUpdatesReadModel(id: $id) { + id + } + } + `, + }) + }, checkResult) +} + +async function getProductUpdates(client: ApolloClient, id: string): Promise { + const result = await awaitForProductUpdates(client, id, (result) => { + const resultId = result?.data?.ProductUpdatesReadModel?.id + return resultId === id + }) + return result.data.ProductUpdatesReadModel +} + +async function getProductUpdatesUndefined(client: ApolloClient, id: string): Promise { + const result = await awaitForProductUpdates(client, id, (result) => { + const resultId = result?.data?.ProductUpdatesReadModel + return resultId === null + }) + return result.data.ProductUpdatesReadModel +} + +async function waitForProductBySku( + client: ApolloClient, + id: string, + checkResult: (result: any) => boolean | string +) { + return await waitForIt(() => { + return client.query({ + variables: { + id: id, + }, + query: gql` + query ProductsBySKU($id: ID!) { + ProductsBySKU(id: $id) { + id + } + } + `, + }) + }, checkResult) +} + +async function getProductBySku(client: ApolloClient, id: string): Promise { + const result = await waitForProductBySku(client, id, (result) => { + const resultId = result?.data?.ProductsBySKU?.id + return resultId === id + }) + return result.data.ProductsBySKU +} + +async function getProductBySkuUndefined(client: ApolloClient, id: string): Promise { + const result = await waitForProductBySku(client, id, (result) => { + const resultId = result?.data?.ProductsBySKU + return resultId === null + }) + return result.data.ProductsBySKU +} + +async function waitForSpecialReports( + client: ApolloClient, + id: string, + checkResult: (result: any) => boolean | string +) { + return await waitForIt(() => { + return client.query({ + variables: { + id: id, + }, + query: gql` + query SpecialReportsReadModel($id: ID!) { + SpecialReportsReadModel(id: $id) { + id + } + } + `, + }) + }, checkResult) +} + +async function getSpecialReportsReadModel(client: ApolloClient, id: string): Promise { + const result = await waitForSpecialReports(client, id, (result) => { + const resultId = result?.data?.SpecialReportsReadModel?.id + return resultId === id + }) + return result.data.SpecialReportsReadModel +} + +async function getSpecialReportsReadModelUndefined(client: ApolloClient, id: string): Promise { + const result = await waitForSpecialReports(client, id, (result) => { + const resultId = result?.data?.SpecialReportsReadModel + return resultId === null + }) + return result.data.SpecialReportsReadModel +} + +async function deleteEvent( + client: ApolloClient, + entityId: string, + entityTypeName: string, + createdAt: string +): Promise { + const result = await client.mutate({ + variables: { + entityId: entityId, + entityTypeName: entityTypeName, + createdAt: createdAt, + }, + mutation: gql` + mutation HardDelete($entityId: String!, $entityTypeName: String!, $createdAt: String!) { + HardDelete(input: { entityId: $entityId, entityTypeName: $entityTypeName, createdAt: $createdAt }) + } + `, + }) + return result?.data.HardDelete +} + +function queryByEntity( + client: ApolloClient, + entity: string, + timeFilters?: EventTimeParameterFilter, + entityID?: string, + limit?: number +): Promise> { + const queryTimeFilters = timeFilters ? `, from:"${timeFilters.from}" to:"${timeFilters.to}"` : '' + const queryEntityID = entityID ? `, entityID:"${entityID}"` : '' + const queryLimit = limit ? `, limit:${limit}` : '' + return client.query({ + query: gql` + query { + eventsByEntity(entity: ${entity}${queryEntityID}${queryTimeFilters}${queryLimit}) { + createdAt + entity + entityID + requestID + type + user { + id + roles + username + } + value + deletedAt + } + } + `, + }) +} + +async function queryProductByEntity(client: ApolloClient, entityID: string): Promise { + const result = await waitForIt( + () => queryByEntity(client, 'Product', undefined, entityID), + (result) => { + const events: Array = result.data['eventsByEntity'] + const found = events?.find((event) => event.entityID === entityID) + return found !== undefined + } + ) + return result.data['eventsByEntity'] +} + +async function queryCartByEntity(client: ApolloClient, entityID: string): Promise { + const result = await waitForIt( + () => queryByEntity(client, 'Cart', undefined, entityID), + (result) => { + const events: Array = result.data['eventsByEntity'] + const found = events?.find((event) => event.entityID === entityID) + return found !== undefined + } + ) + return result.data['eventsByEntity'] +} + +async function findEntities(client: ApolloClient, entityName: string): Promise { + const result = await client.mutate({ + variables: { + entityName: entityName, + limit: 99999, + }, + mutation: gql` + mutation EntitiesIdsFinder($entityName: String!, $limit: Float!) { + EntitiesIdsFinder(input: { entityName: $entityName, limit: $limit }) + } + `, + }) + return result?.data?.EntitiesIdsFinder +} diff --git a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/queries.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/queries.integration.ts index 8a000269d4..d7337f5229 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/queries.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/queries.integration.ts @@ -143,6 +143,61 @@ describe('Queries end-to-end tests', () => { expect(response).not.to.be.null expect(response?.data?.CartTotalQuantity).to.be.eq(beforeHookQueryMultiply * quantity) }) + + it('accepts a union type', async () => { + const bookId = random.uuid() + const movieId = random.uuid() + await client.mutate({ + variables: { + bookId: bookId, + title: 'The Life Of J Robert Oppenheimer', + pages: 42, + }, + mutation: gql` + mutation AddBook($bookId: ID!, $title: String!, $pages: Float!) { + AddBook(input: { id: $bookId, title: $title, pages: $pages }) + } + `, + }) + await client.mutate({ + variables: { + movieId: movieId, + title: 'Oppenheimer (2023)', + }, + mutation: gql` + mutation AddMovie($movieId: ID!, $title: String!) { + AddMovie(input: { id: $movieId, title: $title }) + } + `, + }) + + const response = await waitForIt( + () => + client.query({ + variables: { + searchword: 'Oppenheimer', + }, + query: gql` + query SearchMedia($searchword: String!) { + SearchMedia(input: { searchword: $searchword }) { + results { + __typename + ... on BookReadModel { + title + pages + } + ... on MovieReadModel { + title + } + } + } + } + `, + }), + (result) => result?.data?.SearchMedia != undefined + ) + expect(response).not.to.be.null + }) }) context('when the query requires a specific role', () => { diff --git a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/read-models.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/read-models.integration.ts index 1505477fa6..a04bbd32dd 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/end-to-end/read-models.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/end-to-end/read-models.integration.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ -import { ApolloClient, gql, NormalizedCacheObject } from '@apollo/client' +import { ApolloClient, ApolloQueryResult, gql, NormalizedCacheObject } from '@apollo/client' import { commerce, finance, internet, lorem, random } from 'faker' import { expect } from '../../helper/expect' import { waitForIt } from '../../helper/sleep' @@ -8,9 +8,9 @@ import { applicationUnderTest } from './setup' import { beforeHookException, beforeHookProductId, throwExceptionId } from '../../../src/constants' import { UUID } from '@boostercloud/framework-types' -describe('Read models end-to-end tests', () => { - let client: ApolloClient +let client: ApolloClient +describe('Read models end-to-end tests', () => { before(async () => { client = applicationUnderTest.graphql.client() }) @@ -148,7 +148,10 @@ describe('Read models end-to-end tests', () => { context('several cart items', () => { let mockCartId: string let mockCartItemsCount: number - const mockCartItems: Array<{ productId: string; quantity: number }> = [] + const mockCartItems: Array<{ + productId: string + quantity: number + }> = [] beforeEach(async () => { mockCartId = random.uuid() @@ -220,7 +223,10 @@ describe('Read models end-to-end tests', () => { context('query lists of carts', () => { let mockCartId: string - const mockCartItems: Array<{ productId: string; quantity: number }> = [] + const mockCartItems: Array<{ + productId: string + quantity: number + }> = [] let mockProductId: string let mockQuantity: number const mockConfirmationToken: string = random.alphaNumeric(10) @@ -376,7 +382,9 @@ describe('Read models end-to-end tests', () => { }) it('should retrieve a list of carts using nested filters', async () => { - const filter = { shippingAddress: { firstName: { eq: mockAddress.firstName } } } + const filter = { + and: [{ id: { eq: mockCartId } }, { shippingAddress: { firstName: { eq: mockAddress.firstName } } }], + } const queryResult = await waitForIt( () => { return client.query({ @@ -392,7 +400,7 @@ describe('Read models end-to-end tests', () => { `, }) }, - (result) => result?.data?.CartReadModels?.length >= 1 + (result) => result?.data?.CartReadModels?.length >= 1 && result?.data?.CartReadModels[0].id === mockCartId ) const cartData = queryResult.data.CartReadModels @@ -1012,6 +1020,7 @@ describe('Read models end-to-end tests', () => { }, (result) => result?.data?.ListCartReadModels?.items.length >= 1 && + result?.data?.ListCartReadModels?.items[0]?.id === mockCartId && result?.data?.ListCartReadModels?.items[0]?.payment?.id !== undefined ) @@ -1188,7 +1197,12 @@ describe('Read models end-to-end tests', () => { }) context('query sorted lists of carts', () => { - const mockCartItems: Array<{ id: string; productId: string; quantity: number; firstName: string }> = [] + const mockCartItems: Array<{ + id: string + productId: string + quantity: number + firstName: string + }> = [] const cartItems = 5 let mockAddress: { firstName: string @@ -1429,7 +1443,10 @@ describe('Read models end-to-end tests', () => { context('query using pagination', () => { const mockCartIds: Array = [] - const mockCartItems: Array<{ productId: string; quantity: number }> = [] + const mockCartItems: Array<{ + productId: string + quantity: number + }> = [] let mockProductId: string let mockQuantity: number const changeCartPromises: Array> = [] @@ -1821,38 +1838,46 @@ describe('Read models end-to-end tests', () => { expect(currentPageCartData[0].cartItems[0].productId).to.equal(mockProductId) } }) + }) - it('should apply modified filter by before hooks', async () => { - // We create a cart with id 'before-fn-test-modified', but we query for - // 'before-fn-test', which will then change the filter after two "before" functions - // to return the original cart (id 'before-fn-test-modified') - const variables = { - cartId: 'before-fn-test-modified', - productId: beforeHookProductId, - quantity: 1, - } + context('projecting calculated fields', () => { + const mockCartId: string = random.uuid() + const mockProductId: string = random.uuid() + const mockQuantity: number = random.number({ min: 1 }) + const mockAddress = { + firstName: random.word(), + lastName: random.word(), + country: random.word(), + state: random.word(), + postalCode: random.word(), + address: random.word(), + } + + beforeEach(async () => { + // provisioning a cart await client.mutate({ - variables, + variables: { + cartId: mockCartId, + productId: mockProductId, + quantity: mockQuantity, + }, mutation: gql` mutation ChangeCartItem($cartId: ID!, $productId: ID!, $quantity: Float!) { ChangeCartItem(input: { cartId: $cartId, productId: $productId, quantity: $quantity }) } `, }) - const queryResult = await waitForIt( + + await waitForIt( () => { return client.query({ variables: { - cartId: 'before-fn-test', + cartId: mockCartId, }, query: gql` query CartReadModel($cartId: ID!) { CartReadModel(id: $cartId) { id - cartItems { - productId - quantity - } } } `, @@ -1861,359 +1886,544 @@ describe('Read models end-to-end tests', () => { (result) => result?.data?.CartReadModel != null ) - const cartData = queryResult.data.CartReadModel + // update shipping address + await client.mutate({ + variables: { + cartId: mockCartId, + address: mockAddress, + }, + mutation: gql` + mutation UpdateShippingAddress($cartId: ID!, $address: AddressInput!) { + UpdateShippingAddress(input: { cartId: $cartId, address: $address }) + } + `, + }) - expect(cartData.id).to.be.equal(variables.cartId) + await waitForIt( + () => { + return client.query({ + variables: { + cartId: mockCartId, + }, + query: gql` + query CartReadModel($cartId: ID!) { + CartReadModel(id: $cartId) { + id + shippingAddress { + firstName + } + } + } + `, + }) + }, + (result) => + result?.data?.CartReadModel != null && + result?.data?.CartReadModel?.shippingAddress?.firstName === mockAddress.firstName + ) }) - it('should return exceptions thrown by before functions', async () => { - try { - await waitForIt( - () => { - return client.query({ - variables: { - cartId: throwExceptionId, + it('should correctly fetch calculated fields via GraphQL query', async () => { + const queryResult = await waitForIt( + () => { + return client.query({ + variables: { + filter: { + id: { eq: mockCartId }, }, - query: gql` - query CartReadModel($cartId: ID!) { - CartReadModel(id: $cartId) { - id - cartItems { - productId - quantity - } + }, + query: gql` + query CartReadModels($filter: CartReadModelFilter) { + CartReadModels(filter: $filter) { + id + myAddress { + firstName + lastName + country + state + postalCode + address } } - `, - }) + } + `, + }) + }, + (result) => result?.data?.CartReadModels?.length >= 1 + ) + + const cartData = queryResult.data.CartReadModels + + expect(cartData).to.be.an('array') + expect(cartData.length).to.equal(1) + expect(cartData[0].id).to.be.equal(mockCartId) + expect(cartData[0].myAddress).to.deep.equal({ + ...mockAddress, + __typename: 'Address', + }) + }) + + it('should correctly fetch calculated fields via code', async () => { + const queryResult = await waitForIt( + () => { + return client.mutate({ + variables: { + cartId: mockCartId, + paginatedVersion: true, + }, + mutation: gql` + mutation CartMyAddress($cartId: ID!, $paginatedVersion: Boolean!) { + CartMyAddress(input: { cartId: $cartId, paginatedVersion: $paginatedVersion }) + } + `, + }) + }, + (result) => result?.data?.CartMyAddress != null + ) + + const cartMyAddress = queryResult.data.CartMyAddress + + expect(cartMyAddress).to.deep.equal({ + items: [ + { + id: mockCartId, + myAddress: { + firstName: mockAddress.firstName, + lastName: mockAddress.lastName, + country: mockAddress.country, + state: mockAddress.state, + postalCode: mockAddress.postalCode, + address: mockAddress.address, + }, }, - (_) => true - ) - } catch (e) { - expect(e.graphQLErrors[0].message).to.be.eq(beforeHookException) - expect(e.graphQLErrors[0].path).to.deep.eq(['CartReadModel']) - } + ], + count: 1, + cursor: { + id: '1', + }, + }) }) }) }) - describe('projecting two entities', () => { - const mockCartId: string = random.uuid() - const mockPaymentId: string = random.uuid() - const mockProductId: string = random.uuid() - const mockQuantity: number = random.number({ min: 1 }) - const mockConfirmationToken: string = random.alphaNumeric(10) + describe('projections', () => { + describe('projecting two entities', () => { + const mockCartId: string = random.uuid() + const mockPaymentId: string = random.uuid() + const mockProductId: string = random.uuid() + const mockQuantity: number = random.number({ min: 1 }) + const mockConfirmationToken: string = random.alphaNumeric(10) - beforeEach(async () => { - // provisioning a cart - await client.mutate({ - variables: { - cartId: mockCartId, - productId: mockProductId, - quantity: mockQuantity, - }, - mutation: gql` - mutation ChangeCartItem($cartId: ID!, $productId: ID!, $quantity: Float!) { - ChangeCartItem(input: { cartId: $cartId, productId: $productId, quantity: $quantity }) - } - `, + beforeEach(async () => { + // provisioning a cart + await client.mutate({ + variables: { + cartId: mockCartId, + productId: mockProductId, + quantity: mockQuantity, + }, + mutation: gql` + mutation ChangeCartItem($cartId: ID!, $productId: ID!, $quantity: Float!) { + ChangeCartItem(input: { cartId: $cartId, productId: $productId, quantity: $quantity }) + } + `, + }) }) - }) - it('should project changes for both entities', async () => { - const queryResult = await waitForIt( - () => { - return client.query({ - variables: { - cartId: mockCartId, - }, - query: gql` - query CartReadModel($cartId: ID!) { - CartReadModel(id: $cartId) { - id - cartItems { - productId - quantity + it('should project changes for both entities', async () => { + const queryResult = await waitForIt( + () => { + return client.query({ + variables: { + cartId: mockCartId, + }, + query: gql` + query CartReadModel($cartId: ID!) { + CartReadModel(id: $cartId) { + id + cartItems { + productId + quantity + } } } - } - `, - }) - }, - (result) => result?.data?.CartReadModel != null - ) - - const cartData = queryResult.data.CartReadModel - const expectedResult = { - __typename: 'CartReadModel', - id: mockCartId, - cartItems: [ - { - __typename: 'CartItem', - productId: mockProductId, - quantity: mockQuantity, + `, + }) }, - ], - } + (result) => result?.data?.CartReadModel != null + ) - expect(cartData).to.be.deep.equal(expectedResult) + const cartData = queryResult.data.CartReadModel + const expectedResult = { + __typename: 'CartReadModel', + id: mockCartId, + cartItems: [ + { + __typename: 'CartItem', + productId: mockProductId, + quantity: mockQuantity, + }, + ], + } - // Make payment - await client.mutate({ - variables: { - paymentId: mockPaymentId, - cartId: mockCartId, - confirmationToken: mockConfirmationToken, - }, - mutation: gql` - mutation ConfirmPayment($paymentId: ID!, $cartId: ID!, $confirmationToken: String!) { - ConfirmPayment(input: { paymentId: $paymentId, cartId: $cartId, confirmationToken: $confirmationToken }) - } - `, - }) + expect(cartData).to.be.deep.equal(expectedResult) - // Retrieve updated read model - const updatedQueryResult = await waitForIt( - () => { - return client.query({ - variables: { - cartId: mockCartId, - }, - query: gql` - query CartReadModel($cartId: ID!) { - CartReadModel(id: $cartId) { - id - cartItems { - productId - quantity - } - payment { - confirmationToken + // Make payment + await client.mutate({ + variables: { + paymentId: mockPaymentId, + cartId: mockCartId, + confirmationToken: mockConfirmationToken, + }, + mutation: gql` + mutation ConfirmPayment($paymentId: ID!, $cartId: ID!, $confirmationToken: String!) { + ConfirmPayment(input: { paymentId: $paymentId, cartId: $cartId, confirmationToken: $confirmationToken }) + } + `, + }) + + // Retrieve updated read model + const updatedQueryResult = await waitForIt( + () => { + return client.query({ + variables: { + cartId: mockCartId, + }, + query: gql` + query CartReadModel($cartId: ID!) { + CartReadModel(id: $cartId) { id - cartId + cartItems { + productId + quantity + } + payment { + confirmationToken + id + cartId + } } } - } - `, - }) - }, - (result) => result?.data?.CartReadModel?.payment != null - ) - - const updatedCartData = updatedQueryResult.data.CartReadModel - const expectedUpdatedResult = { - __typename: 'CartReadModel', - id: mockCartId, - cartItems: [ - { - __typename: 'CartItem', - productId: mockProductId, - quantity: mockQuantity, + `, + }) }, - ], - payment: { - __typename: 'Payment', - confirmationToken: mockConfirmationToken, - id: mockPaymentId, - cartId: mockCartId, - }, - } - - expect(updatedCartData).to.be.deep.equal(expectedUpdatedResult) - }) - }) + (result) => result?.data?.CartReadModel?.payment != null + ) - describe('projecting two entities with array joinKey', () => { - let client: ApolloClient - let userToken: string + const updatedCartData = updatedQueryResult.data.CartReadModel + const expectedUpdatedResult = { + __typename: 'CartReadModel', + id: mockCartId, + cartItems: [ + { + __typename: 'CartItem', + productId: mockProductId, + quantity: mockQuantity, + }, + ], + payment: { + __typename: 'Payment', + confirmationToken: mockConfirmationToken, + id: mockPaymentId, + cartId: mockCartId, + }, + } - before(async () => { - const userEmail = internet.email() - userToken = applicationUnderTest.token.forUser(userEmail, 'UserWithEmail') - client = applicationUnderTest.graphql.client(userToken) + expect(updatedCartData).to.be.deep.equal(expectedUpdatedResult) + }) }) - const oneMockProductId: string = random.uuid() - const twoMockProductId: string = random.uuid() + describe('projecting two entities with array joinKey', () => { + let client: ApolloClient + let userToken: string - beforeEach(async () => { - // Add item one - await client.mutate({ - variables: { - productID: oneMockProductId, - sku: random.uuid(), - displayName: commerce.productName(), - description: lorem.paragraph(), - priceInCents: random.number({ min: 1 }), - currency: finance.currencyCode(), - }, - mutation: gql` - mutation CreateProduct( - $productID: ID! - $sku: String! - $displayName: String! - $description: String! - $priceInCents: Float! - $currency: String! - ) { - CreateProduct( - input: { - productID: $productID - sku: $sku - displayName: $displayName - description: $description - priceInCents: $priceInCents - currency: $currency - } - ) - } - `, + before(async () => { + const userEmail = internet.email() + userToken = applicationUnderTest.token.forUser(userEmail, 'UserWithEmail') + client = applicationUnderTest.graphql.client(userToken) }) - // Add item two - await client.mutate({ - variables: { - productID: twoMockProductId, - sku: random.uuid(), - displayName: commerce.productName(), - description: lorem.paragraph(), - priceInCents: random.number({ min: 1 }), - currency: finance.currencyCode(), - }, - mutation: gql` - mutation CreateProduct( - $productID: ID! - $sku: String! - $displayName: String! - $description: String! - $priceInCents: Float! - $currency: String! - ) { - CreateProduct( - input: { - productID: $productID - sku: $sku - displayName: $displayName - description: $description - priceInCents: $priceInCents - currency: $currency - } - ) - } - `, + const oneMockProductId: string = random.uuid() + const twoMockProductId: string = random.uuid() + + beforeEach(async () => { + // Add item one + await client.mutate({ + variables: { + productID: oneMockProductId, + sku: random.uuid(), + displayName: commerce.productName(), + description: lorem.paragraph(), + priceInCents: random.number({ min: 1 }), + currency: finance.currencyCode(), + }, + mutation: gql` + mutation CreateProduct( + $productID: ID! + $sku: String! + $displayName: String! + $description: String! + $priceInCents: Float! + $currency: String! + ) { + CreateProduct( + input: { + productID: $productID + sku: $sku + displayName: $displayName + description: $description + priceInCents: $priceInCents + currency: $currency + } + ) + } + `, + }) + + // Add item two + await client.mutate({ + variables: { + productID: twoMockProductId, + sku: random.uuid(), + displayName: commerce.productName(), + description: lorem.paragraph(), + priceInCents: random.number({ min: 1 }), + currency: finance.currencyCode(), + }, + mutation: gql` + mutation CreateProduct( + $productID: ID! + $sku: String! + $displayName: String! + $description: String! + $priceInCents: Float! + $currency: String! + ) { + CreateProduct( + input: { + productID: $productID + sku: $sku + displayName: $displayName + description: $description + priceInCents: $priceInCents + currency: $currency + } + ) + } + `, + }) }) - }) - it('should project changes for both entities', async () => { - // Check that new product is available in read model - const products = await waitForIt( - () => { - return client.query({ - variables: { - products: [oneMockProductId, twoMockProductId], - }, - query: gql` - query ProductReadModels($products: [ID!]!) { - ProductReadModels(filter: { id: { in: $products } }) { - id - sku - displayName - description - price { - cents - currency - } - availability - deleted - packs { + it('should project changes for both entities', async () => { + // Check that new product is available in read model + const products = await waitForIt( + () => { + return client.query({ + variables: { + products: [oneMockProductId, twoMockProductId], + }, + query: gql` + query ProductReadModels($products: [ID!]!) { + ProductReadModels(filter: { id: { in: $products } }) { id + sku + displayName + description + price { + cents + currency + } + availability + deleted + packs { + id + } + productDetails + productType } - productDetails - productType } - } - `, - }) - }, - (result) => - result?.data?.ProductReadModels?.length == 2 && - result?.data?.ProductReadModels?.every( - (product: any) => Array.isArray(product.packs) && product.packs.length == 0 - ) - ) + `, + }) + }, + (result) => + result?.data?.ProductReadModels?.length == 2 && + result?.data?.ProductReadModels?.every( + (product: any) => Array.isArray(product.packs) && product.packs.length == 0 + ) + ) - expect(products.data.ProductReadModels.length).to.be.equal(2) + expect(products.data.ProductReadModels.length).to.be.equal(2) - const mockPackId: string = random.uuid() - const mockPackName: string = commerce.productName() - const mockPackProducts: Array = [oneMockProductId, twoMockProductId] + const mockPackId: string = random.uuid() + const mockPackName: string = commerce.productName() + const mockPackProducts: Array = [oneMockProductId, twoMockProductId] - // Create Pack - await client.mutate({ - variables: { - packID: mockPackId, - name: mockPackName, - products: mockPackProducts, - }, - mutation: gql` - mutation CreatePack($packID: ID!, $name: String!, $products: [ID!]!) { - CreatePack(input: { packID: $packID, name: $name, products: $products }) - } - `, - }) + // Create Pack + await client.mutate({ + variables: { + packID: mockPackId, + name: mockPackName, + products: mockPackProducts, + }, + mutation: gql` + mutation CreatePack($packID: ID!, $name: String!, $products: [ID!]!) { + CreatePack(input: { packID: $packID, name: $name, products: $products }) + } + `, + }) - const updatedQueryResults = await waitForIt( - () => { - return client.query({ - variables: { - products: [oneMockProductId, twoMockProductId], - }, - query: gql` - query ProductReadModels($products: [ID!]!) { - ProductReadModels(filter: { id: { in: $products } }) { - id - sku - displayName - description - price { - cents - currency - } - availability - deleted - packs { + const updatedQueryResults = await waitForIt( + () => { + return client.query({ + variables: { + products: [oneMockProductId, twoMockProductId], + }, + query: gql` + query ProductReadModels($products: [ID!]!) { + ProductReadModels(filter: { id: { in: $products } }) { id - name - products + sku + displayName + description + price { + cents + currency + } + availability + deleted + packs { + id + name + products + } + productDetails + productType } - productDetails - productType } - } - `, - }) - }, - (result) => - result?.data?.ProductReadModels?.length == 2 && - result?.data?.ProductReadModels?.every( - (product: any) => Array.isArray(product.packs) && product.packs.length == 1 - ) - ) + `, + }) + }, + (result) => + result?.data?.ProductReadModels?.length == 2 && + result?.data?.ProductReadModels?.every( + (product: any) => Array.isArray(product.packs) && product.packs.length == 1 + ) + ) - const updatedProducts = updatedQueryResults.data.ProductReadModels - expect(updatedProducts.length).to.be.equal(2) + const updatedProducts = updatedQueryResults.data.ProductReadModels + expect(updatedProducts.length).to.be.equal(2) - updatedProducts.forEach((product: { packs: Array }) => { - expect(product.packs).to.be.deep.equal([ - { - __typename: 'Pack', - id: mockPackId, - name: mockPackName, - products: mockPackProducts, - }, - ]) + updatedProducts.forEach((product: { packs: Array }) => { + expect(product.packs).to.be.deep.equal([ + { + __typename: 'Pack', + id: mockPackId, + name: mockPackName, + products: mockPackProducts, + }, + ]) + }) }) }) + + it('should project with "entity joinkey" and create a new read model', async () => { + await addModel() + }) + + it('should project with "entity joinkey" and update an existing read model', async () => { + const fiatId = await addModel() + await updateModel(fiatId) + + const johnId = await addOwner() + await updateOwner(johnId) + }) + + it('should project with array "entity joinkey" and create a new read model', async () => { + const fiatId = await addModel() + const johnId = await addOwner() + const johnFiatId = await buy(fiatId, johnId) + const offer1Id = await addOffer([johnFiatId]) + const offer = await getCarOfferById(offer1Id) + const johnFiat = await getPurchaseById(johnFiatId) + expect(johnFiat.data.CarPurchasesReadModel.offers.length).to.be.eql(1) + expect(johnFiat.data.CarPurchasesReadModel.offers[0].id).to.be.eql(offer.data.CarOfferReadModel.id) + }) + + it('should project with array "entity joinkey" and update an existing read model', async () => { + const fiatId = await addModel() + const johnId = await addOwner() + const lucasId = await addOwner() + const johnFiatId = await buy(fiatId, johnId) + const lucasFiatId = await buy(fiatId, lucasId) + const offer1Id = await addOffer([johnFiatId]) + const offer1 = await getCarOfferById(offer1Id) + const offer2Id = await addOffer([johnFiatId, lucasFiatId]) + const offer2 = await getCarOfferById(offer2Id) + const johnFiat = await getPurchaseById(johnFiatId) + const lucasFiat = await getPurchaseById(lucasFiatId) + expect(johnFiat.data.CarPurchasesReadModel.offers.length).to.be.eql(2) + expect(johnFiat.data.CarPurchasesReadModel.offers[0].id).to.be.eql(offer1.data.CarOfferReadModel.id) + expect(johnFiat.data.CarPurchasesReadModel.offers[1].id).to.be.eql(offer2.data.CarOfferReadModel.id) + expect(lucasFiat.data.CarPurchasesReadModel.offers.length).to.be.eql(1) + expect(johnFiat.data.CarPurchasesReadModel.offers[0].id).to.be.eql(offer1.data.CarOfferReadModel.id) + }) + + it('should project with "read model joinkey" and create a new read model', async () => { + const fiatId = await addModel() + const johnId = await addOwner() + const johnFiatId = await buy(fiatId, johnId) + const allPurchaseIds = [johnFiatId] + const allPurchases = await purchasesByIds(allPurchaseIds) + expect(allPurchases).to.be.lengthOf(1) + }) + + it('should project with "read model joinkey" and update an existing read model', async () => { + const fiatId = await addModel() + const johnId = await addOwner() + const lucasId = await addOwner() + const aliceId = await addOwner() + const johnFiatId = await buy(fiatId, johnId) + const lucasFiatId = await buy(fiatId, lucasId) + const aliceFiatId = await buy(fiatId, aliceId) + const allPurchaseIds = [johnFiatId, lucasFiatId, aliceFiatId] + const allPurchases = await purchasesByIds(allPurchaseIds) + expect(allPurchases).to.be.lengthOf(allPurchaseIds.length) + + await updateModel(fiatId) + await updateOwner(johnId) + const updatedPurchases = await purchasesByIds(allPurchaseIds) + + // All MODELS name should be updated + expectModelNamesUpdated(allPurchases, johnFiatId, updatedPurchases) + expectModelNamesUpdated(allPurchases, lucasFiatId, updatedPurchases) + expectModelNamesUpdated(allPurchases, aliceFiatId, updatedPurchases) + // Only John OWNER name should be updated + expectFirstOwnerNamesUpdated(allPurchases, johnFiatId, updatedPurchases) + expectFirstOwnerNamesNotUpdated(allPurchases, lucasFiatId, updatedPurchases) + expectFirstOwnerNamesNotUpdated(allPurchases, aliceFiatId, updatedPurchases) + }) + + it('should NOT project when "read model joinkey" is undefined', async () => { + const fiatId = await addModel() + const johnId = await addOwner() + const originalJohnOwner = await waitForId(johnId.toString(), 'CarOwnerReadModel', undefined, 'name') + const johnFiatId = await buy(fiatId, johnId) + const purchases = await purchasesByIds([johnFiatId]) + expect(purchases).to.be.lengthOf(1) + await updateOwner(johnId, 'SKIP') + const all = await allPurchases() + + // Owner name was updated in the CarOwnerReadModel + const newJohnOwner = await waitForId(johnId.toString(), 'CarOwnerReadModel', undefined, 'name') + expect(originalJohnOwner.data.CarOwnerReadModel.name).to.not.be.eql(newJohnOwner.data.CarOwnerReadModel.name) + + // Owner name was NOT updated in the Purchases read model + all.map((p) => p.carOwner.name).forEach((name) => expect(name).to.not.eql('SKIP')) + const purchaseWithOriginalJohnOwner = all + .map((p) => p.carOwner.name) + .filter((name) => name === originalJohnOwner.data.CarOwnerReadModel.name) + expect(purchaseWithOriginalJohnOwner.length).to.be.eql(1) + }) }) describe('read model authorization', () => { @@ -2419,3 +2629,302 @@ describe('Read models end-to-end tests', () => { }) }) }) + +async function addModel(name?: string, brand?: string): Promise { + const mockModelId = random.uuid() + const mockName: string = name ?? random.alphaNumeric(10) + const mockBrand: string = brand ?? random.alphaNumeric(10) + + await client.mutate({ + variables: { + id: mockModelId, + name: mockName, + brand: mockBrand, + }, + mutation: gql` + mutation AddCarModel($id: ID!, $name: String!, $brand: String!) { + AddCarModel(input: { id: $id, name: $name, brand: $brand }) + } + `, + }) + await getCarModelByIdAndName(mockModelId, mockName) + return mockModelId +} + +async function addOwner(name?: string): Promise { + const mockOwnerId = random.uuid() + const mockName: string = name ?? random.alphaNumeric(10) + + await client.mutate({ + variables: { + id: mockOwnerId, + name: mockName, + }, + mutation: gql` + mutation AddCarOwner($id: ID!, $name: String!) { + AddCarOwner(input: { id: $id, name: $name }) + } + `, + }) + await getCarOwnerByIdAndName(mockOwnerId, mockName) + return mockOwnerId +} + +async function addOffer(purchaseIds: Array, name?: string): Promise { + const mockOfferId = random.uuid() + const mockName: string = name ?? random.alphaNumeric(10) + + await client.mutate({ + variables: { + id: mockOfferId, + name: mockName, + purchaseIds: purchaseIds, + }, + mutation: gql` + mutation AddPurchaseOffer($id: ID!, $name: String!, $purchaseIds: [String!]!) { + AddPurchaseOffer(input: { id: $id, name: $name, purchaseIds: $purchaseIds }) + } + `, + }) + await getCarOfferByIdAndName(mockOfferId, mockName) + return mockOfferId +} + +async function buy(modelId: UUID, ownerId: UUID) { + const mockBuyId = random.uuid() + await client.mutate({ + variables: { + id: mockBuyId, + modelId: modelId, + ownerId: ownerId, + }, + mutation: gql` + mutation BuyCar($id: ID!, $modelId: ID!, $ownerId: ID!) { + BuyCar(input: { id: $id, modelId: $modelId, ownerId: $ownerId }) + } + `, + }) + await waitForId(mockBuyId, 'CarPurchasesReadModel') + return mockBuyId +} + +async function purchasesByIds(ids: Array): Promise> { + const result = await waitForIt( + () => { + return client.query({ + variables: { + filter: { + id: { in: [...ids] }, + }, + }, + query: gql` + query ListCarPurchasesReadModels($filter: ListCarPurchasesReadModelFilter) { + ListCarPurchasesReadModels(filter: $filter) { + items { + id + carModel { + id + name + brand + } + carOwner { + id + name + } + } + } + } + `, + }) + }, + (result) => result?.data?.ListCarPurchasesReadModels.items.length == ids.length + ) + return result.data.ListCarPurchasesReadModels.items +} + +async function allPurchases(): Promise> { + const result = await client.query({ + variables: { + filter: {}, + }, + query: gql` + query ListCarPurchasesReadModels($filter: ListCarPurchasesReadModelFilter) { + ListCarPurchasesReadModels(filter: $filter) { + items { + id + carModel { + id + name + brand + } + carOwner { + id + name + } + } + } + } + `, + }) + + return result.data.ListCarPurchasesReadModels.items +} + +async function updateModel(id: UUID, name?: string): Promise { + const mockName: string = name ?? random.alphaNumeric(10) + + await client.mutate({ + variables: { + id: id, + name: mockName, + }, + mutation: gql` + mutation UpdateCarModelName($id: ID!, $name: String!) { + UpdateCarModelName(input: { id: $id, name: $name }) + } + `, + }) + await getCarModelByIdAndName(id, mockName) + return id +} + +async function updateOwner(id: UUID, name?: string): Promise { + const mockName: string = name ?? random.alphaNumeric(10) + + await client.mutate({ + variables: { + id: id, + name: mockName, + }, + mutation: gql` + mutation UpdateCarOwnerName($id: ID!, $name: String!) { + UpdateCarOwnerName(input: { id: $id, name: $name }) + } + `, + }) + await getCarOwnerByIdAndName(id, mockName) + return id +} + +async function getCarModelByIdAndName(id: UUID, modelName: string) { + return await waitForId( + id.toString(), + 'CarModelReadModel', + (result) => { + const readModel = result?.data.CarModelReadModel + return readModel && readModel.name === modelName + }, + 'name' + ) +} + +async function getCarOfferByIdAndName(id: UUID, offerName: string) { + return await waitForId( + id.toString(), + 'CarOfferReadModel', + (result) => { + const readModel = result?.data.CarOfferReadModel + return readModel && readModel.name === offerName + }, + 'name' + ) +} + +async function getCarOfferById(id: UUID) { + return await waitForId(id.toString(), 'CarOfferReadModel', undefined, 'name purchasesIds') +} + +async function getPurchaseById(id: UUID) { + return await waitForId( + id.toString(), + 'CarPurchasesReadModel', + undefined, + 'carModel { id name brand } carOwner { id name } offers { id name purchasesIds } ' + ) +} + +async function getCarOwnerByIdAndName(id: UUID, ownerName: string) { + return await waitForId( + id.toString(), + 'CarOwnerReadModel', + (result) => { + const readModel = result?.data.CarOwnerReadModel + return readModel && readModel.name === ownerName + }, + 'name' + ) +} + +async function waitForId( + expectedId: string, + readModelName: string, + extraCheck?: (result: ApolloQueryResult) => void, + extraField?: string +): Promise { + return await waitForIt( + () => { + return client.query({ + variables: { + id: expectedId, + }, + query: gql` + query ${readModelName}($id: ID!) { + ${readModelName}(id: $id) { + id + ${extraField ? extraField : ''} + } + } + `, + }) + }, + (result) => { + const readModel = result?.data[readModelName] + if (extraCheck) { + return readModel && readModel.id === expectedId && extraCheck(result) + } + return readModel && readModel.id === expectedId + } + ) +} + +function expectModelNamesUpdated(allPurchases: Array, purchaseId: string, updatedPurchases: Array): void { + const firstPurchase = getFirstPurchase(allPurchases, purchaseId) + const firstUpdatedPurchase = getFirstPurchase(updatedPurchases, purchaseId) + // ids are the same + expect(firstPurchase.id).to.be.eq(firstUpdatedPurchase.id, 'same ids') + expect(firstPurchase.carModel.id).to.be.eq(firstUpdatedPurchase.carModel.id, 'same carModel ids') + // and Names were updated + expect(firstPurchase.carModel.name).to.not.be.eq(firstUpdatedPurchase.carModel.name, 'distinct carModel names') +} + +function expectFirstOwnerNamesUpdated( + allPurchases: Array, + purchaseId: string, + updatedPurchases: Array +): void { + const firstPurchase = getFirstPurchase(allPurchases, purchaseId) + const firstUpdatedPurchase = getFirstPurchase(updatedPurchases, purchaseId) + // ids are the same + expect(firstPurchase.id).to.be.eq(firstUpdatedPurchase.id, 'same ids') + expect(firstPurchase.carOwner.id).to.be.eq(firstUpdatedPurchase.carOwner.id, 'same carOwner ids') + // and Names were updated + expect(firstPurchase.carOwner.name).to.not.be.eq(firstUpdatedPurchase.carOwner.name, 'distinct carOwner names') +} + +function expectFirstOwnerNamesNotUpdated( + allPurchases: Array, + purchaseId: string, + updatedPurchases: Array +): void { + const firstPurchase = getFirstPurchase(allPurchases, purchaseId) + const firstUpdatedPurchase = getFirstPurchase(updatedPurchases, purchaseId) + // ids are the same + expect(firstPurchase.id).to.be.eq(firstUpdatedPurchase.id, 'same ids') + expect(firstPurchase.carOwner.id).to.be.eq(firstUpdatedPurchase.carOwner.id, 'same carOwner ids') + // and Names were NOT updated + expect(firstPurchase.carOwner.name).to.be.eq(firstUpdatedPurchase.carOwner.name, 'same carOwner names') +} + +function getFirstPurchase(purchases: Array, purchaseId: string) { + return purchases.filter((purchase) => purchase.id === purchaseId)[0] +} diff --git a/packages/framework-integration-tests/integration/provider-unaware/functionality/errors.integration.ts b/packages/framework-integration-tests/integration/provider-unaware/functionality/errors.integration.ts index e08bf3d9fc..de8760f740 100644 --- a/packages/framework-integration-tests/integration/provider-unaware/functionality/errors.integration.ts +++ b/packages/framework-integration-tests/integration/provider-unaware/functionality/errors.integration.ts @@ -11,6 +11,7 @@ import { queryHandlerErrorCartId, queryHandlerErrorCartMessage, } from '../../../src/constants' +import 'mocha' describe('Global error handler', async () => { let client: ApolloClient @@ -23,7 +24,7 @@ describe('Global error handler', async () => { context('CommandHandler', async () => { it('should update error object when handler fails', async () => { - const expectedErrorMessage = `${commandHandlerErrorCartMessage}-onCommandHandlerError-onError` + const expectedErrorMessage = `${commandHandlerErrorCartMessage}-onCommandHandlerError with metadata: {"before":[null,null],"properties":[{"name":"cartId","typeInfo":{"name":"UUID","typeGroup":"Class","isNullable":false,"isGetAccessor":false,"parameters":[],"importPath":"@boostercloud/framework-types","typeName":"UUID"}},{"name":"productId","typeInfo":{"name":"UUID","typeGroup":"Class","isNullable":false,"isGetAccessor":false,"parameters":[],"importPath":"@boostercloud/framework-types","typeName":"UUID"}},{"name":"quantity","typeInfo":{"name":"number","typeGroup":"Number","isNullable":false,"isGetAccessor":false,"parameters":[],"typeName":"Number"}},{"name":"test","typeInfo":{"name":"number","typeGroup":"Number","isNullable":false,"isGetAccessor":false,"parameters":[],"typeName":"Number"}}],"methods":[{"name":"beforeFn","typeInfo":{"name":"Promise","typeGroup":"Object","isNullable":false,"isGetAccessor":false,"parameters":[{"name":"CommandInput","typeGroup":"Type","isNullable":false,"isGetAccessor":false,"parameters":[]}],"typeName":"Promise"}},{"name":"beforeFnV2","typeInfo":{"name":"Promise","typeGroup":"Object","isNullable":false,"isGetAccessor":false,"parameters":[{"name":"CommandInput","typeGroup":"Type","isNullable":false,"isGetAccessor":false,"parameters":[]}],"typeName":"Promise"}},{"name":"handle","typeInfo":{"name":"Promise","typeGroup":"Object","isNullable":false,"isGetAccessor":false,"parameters":[{"name":"void","typeGroup":"Other","isNullable":false,"isGetAccessor":false,"parameters":[]}],"typeName":"Promise"}}]}-onError` await expect( client.mutate({ variables: { @@ -58,7 +59,7 @@ describe('Global error handler', async () => { }) it('should update error object when onBefore fails', async () => { - const expectedErrorMessage = `${commandHandlerBeforeErrorCartMessage}-onBeforeCommandHandlerError-onError` + const expectedErrorMessage = `${commandHandlerBeforeErrorCartMessage}-onBeforeCommandHandlerError with metadata: {"before":[null,null],"properties":[{"name":"cartId","typeInfo":{"name":"UUID","typeGroup":"Class","isNullable":false,"isGetAccessor":false,"parameters":[],"importPath":"@boostercloud/framework-types","typeName":"UUID"}},{"name":"productId","typeInfo":{"name":"UUID","typeGroup":"Class","isNullable":false,"isGetAccessor":false,"parameters":[],"importPath":"@boostercloud/framework-types","typeName":"UUID"}},{"name":"quantity","typeInfo":{"name":"number","typeGroup":"Number","isNullable":false,"isGetAccessor":false,"parameters":[],"typeName":"Number"}},{"name":"test","typeInfo":{"name":"number","typeGroup":"Number","isNullable":false,"isGetAccessor":false,"parameters":[],"typeName":"Number"}}],"methods":[{"name":"beforeFn","typeInfo":{"name":"Promise","typeGroup":"Object","isNullable":false,"isGetAccessor":false,"parameters":[{"name":"CommandInput","typeGroup":"Type","isNullable":false,"isGetAccessor":false,"parameters":[]}],"typeName":"Promise"}},{"name":"beforeFnV2","typeInfo":{"name":"Promise","typeGroup":"Object","isNullable":false,"isGetAccessor":false,"parameters":[{"name":"CommandInput","typeGroup":"Type","isNullable":false,"isGetAccessor":false,"parameters":[]}],"typeName":"Promise"}},{"name":"handle","typeInfo":{"name":"Promise","typeGroup":"Object","isNullable":false,"isGetAccessor":false,"parameters":[{"name":"void","typeGroup":"Other","isNullable":false,"isGetAccessor":false,"parameters":[]}],"typeName":"Promise"}}]}-onError` await expect( client.mutate({ variables: { diff --git a/packages/framework-integration-tests/package.json b/packages/framework-integration-tests/package.json index a0615f9d70..98add78562 100644 --- a/packages/framework-integration-tests/package.json +++ b/packages/framework-integration-tests/package.json @@ -1,7 +1,7 @@ { "name": "@boostercloud/framework-integration-tests", "description": "Example project for Booster", - "version": "2.12.1", + "version": "2.18.7", "author": "Boosterin Labs SLU", "homepage": "https://boosterframework.com", "publishConfig": { @@ -9,12 +9,12 @@ }, "bugs": "https://github.com/boostercloud/booster/issues", "dependencies": { - "@boostercloud/framework-common-helpers": "workspace:^2.12.1", - "@boostercloud/framework-core": "workspace:^2.12.1", - "@boostercloud/framework-provider-aws": "workspace:^2.12.1", - "@boostercloud/framework-provider-azure": "workspace:^2.12.1", - "@boostercloud/framework-provider-local": "workspace:^2.12.1", - "@boostercloud/framework-types": "workspace:^2.12.1", + "@boostercloud/framework-common-helpers": "workspace:^2.18.7", + "@boostercloud/framework-core": "workspace:^2.18.7", + "@boostercloud/framework-provider-aws": "workspace:^2.18.7", + "@boostercloud/framework-provider-azure": "workspace:^2.18.7", + "@boostercloud/framework-provider-local": "workspace:^2.18.7", + "@boostercloud/framework-types": "workspace:^2.18.7", "aws-sdk": "2.853.0", "graphql": "^16.6.0", "tslib": "^2.4.0", @@ -30,21 +30,21 @@ "@effect/printer-ansi": "0.32.26", "@effect/platform-node": "0.45.26", "fast-check": "^3.13.2", - "ws": "8.12.0" + "ws": "8.17.1", + "execa": "^2.0.3" }, "devDependencies": { - "@boostercloud/eslint-config": "workspace:^2.12.1", - "@boostercloud/application-tester": "workspace:^2.12.1", - "@boostercloud/cli": "workspace:^2.12.1", - "@boostercloud/framework-provider-aws-infrastructure": "workspace:^2.12.1", - "@boostercloud/framework-provider-azure-infrastructure": "workspace:^2.12.1", - "@boostercloud/framework-provider-local-infrastructure": "workspace:^2.12.1", - "@boostercloud/metadata-booster": "workspace:^2.12.1", + "@boostercloud/eslint-config": "workspace:^2.18.7", + "@boostercloud/application-tester": "workspace:^2.18.7", + "@boostercloud/cli": "workspace:^2.18.7", + "@boostercloud/framework-provider-aws-infrastructure": "workspace:^2.18.7", + "@boostercloud/framework-provider-azure-infrastructure": "workspace:^2.18.7", + "@boostercloud/framework-provider-local-infrastructure": "workspace:^2.18.7", + "@boostercloud/metadata-booster": "workspace:^2.18.7", "@types/aws-lambda": "8.10.48", "@types/chai": "4.2.18", "@types/chai-arrays": "2.0.0", "@types/chai-as-promised": "7.1.4", - "@types/child-process-promise": "^2.2.1", "@types/faker": "5.1.5", "@types/jsonwebtoken": "9.0.1", "@types/mocha": "10.0.1", @@ -62,7 +62,6 @@ "constructs": "^10.0.0", "chai": "4.2.0", "chai-as-promised": "7.1.1", - "child-process-promise": "^2.2.1", "cross-fetch": "3.1.5", "eslint": "^8.23.1", "eslint-config-prettier": "8.3.0", @@ -126,4 +125,4 @@ "integration/azure-func": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" TESTED_PROVIDER=AZURE BOOSTER_ENV=azure mocha --forbid-only --exit --config \"integration/provider-unaware/end-to-end/.mocharc.yml\" \"integration/provider-unaware/functionality/**/*.integration.ts\"" }, "types": "dist/index.d.ts" -} +} \ No newline at end of file diff --git a/packages/framework-integration-tests/src/commands/add-book.ts b/packages/framework-integration-tests/src/commands/add-book.ts new file mode 100644 index 0000000000..144a7a4651 --- /dev/null +++ b/packages/framework-integration-tests/src/commands/add-book.ts @@ -0,0 +1,14 @@ +import { Command } from '@boostercloud/framework-core' +import { Register, UUID } from '@boostercloud/framework-types' +import { BookAdded } from '../events/book-added' + +@Command({ + authorize: 'all', +}) +export class AddBook { + public constructor(readonly id: UUID, readonly title: string, readonly pages: number) {} + + public static async handle(command: AddBook, register: Register): Promise { + register.events(new BookAdded(command.id, command.title, command.pages)) + } +} diff --git a/packages/framework-integration-tests/src/commands/add-car-model.ts b/packages/framework-integration-tests/src/commands/add-car-model.ts new file mode 100644 index 0000000000..ddb888cabf --- /dev/null +++ b/packages/framework-integration-tests/src/commands/add-car-model.ts @@ -0,0 +1,14 @@ +import { Command } from '@boostercloud/framework-core' +import { Register, UUID } from '@boostercloud/framework-types' +import { CarModelAdded } from '../events/car-model-added' + +@Command({ + authorize: 'all', +}) +export class AddCarModel { + public constructor(readonly id: UUID, readonly name: string, readonly brand: string) {} + + public static async handle(command: AddCarModel, register: Register): Promise { + register.events(new CarModelAdded(command.id, command.name, command.brand)) + } +} diff --git a/packages/framework-integration-tests/src/commands/add-car-owner.ts b/packages/framework-integration-tests/src/commands/add-car-owner.ts new file mode 100644 index 0000000000..af7eceec31 --- /dev/null +++ b/packages/framework-integration-tests/src/commands/add-car-owner.ts @@ -0,0 +1,14 @@ +import { Command } from '@boostercloud/framework-core' +import { Register, UUID } from '@boostercloud/framework-types' +import { CarOwnerAdded } from '../events/car-owner-added' + +@Command({ + authorize: 'all', +}) +export class AddCarOwner { + public constructor(readonly id: UUID, readonly name: string) {} + + public static async handle(command: AddCarOwner, register: Register): Promise { + register.events(new CarOwnerAdded(command.id, command.name)) + } +} diff --git a/packages/framework-integration-tests/src/commands/add-movie.ts b/packages/framework-integration-tests/src/commands/add-movie.ts new file mode 100644 index 0000000000..97a3c3b1c4 --- /dev/null +++ b/packages/framework-integration-tests/src/commands/add-movie.ts @@ -0,0 +1,14 @@ +import { Command } from '@boostercloud/framework-core' +import { Register, UUID } from '@boostercloud/framework-types' +import { MovieAdded } from '../events/movie-added' + +@Command({ + authorize: 'all', +}) +export class AddMovie { + public constructor(readonly id: UUID, readonly title: string) {} + + public static async handle(command: AddMovie, register: Register): Promise { + register.events(new MovieAdded(command.id, command.title)) + } +} diff --git a/packages/framework-integration-tests/src/commands/add-purchase-offer.ts b/packages/framework-integration-tests/src/commands/add-purchase-offer.ts new file mode 100644 index 0000000000..2255e2b8f5 --- /dev/null +++ b/packages/framework-integration-tests/src/commands/add-purchase-offer.ts @@ -0,0 +1,14 @@ +import { Command } from '@boostercloud/framework-core' +import { Register, UUID } from '@boostercloud/framework-types' +import { CarOfferAdded } from '../events/car-offer-added' + +@Command({ + authorize: 'all', +}) +export class AddPurchaseOffer { + public constructor(readonly id: UUID, readonly name: string, readonly purchaseIds: Array) {} + + public static async handle(command: AddPurchaseOffer, register: Register): Promise { + register.events(new CarOfferAdded(command.id, command.name, command.purchaseIds)) + } +} diff --git a/packages/framework-integration-tests/src/commands/buy-car.ts b/packages/framework-integration-tests/src/commands/buy-car.ts new file mode 100644 index 0000000000..0caca70e14 --- /dev/null +++ b/packages/framework-integration-tests/src/commands/buy-car.ts @@ -0,0 +1,18 @@ +import { Booster, Command } from '@boostercloud/framework-core' +import { Register, UUID } from '@boostercloud/framework-types' +import { CarPurchased } from '../events/car-purchased' +import { CarModel } from '../entities/car-model' +import { CarOwner } from '../entities/car-owner' + +@Command({ + authorize: 'all', +}) +export class BuyCar { + public constructor(readonly id: UUID, readonly modelId: UUID, readonly ownerId: UUID) {} + + public static async handle(command: BuyCar, register: Register): Promise { + const model = await Booster.entity(CarModel, command.modelId) + const owner = await Booster.entity(CarOwner, command.ownerId) + register.events(new CarPurchased(command.id, owner!, model!)) + } +} diff --git a/packages/framework-integration-tests/src/commands/cart-my-address.ts b/packages/framework-integration-tests/src/commands/cart-my-address.ts new file mode 100644 index 0000000000..46312bd1f2 --- /dev/null +++ b/packages/framework-integration-tests/src/commands/cart-my-address.ts @@ -0,0 +1,22 @@ +import { Register, UUID } from '@boostercloud/framework-types' +import { Booster, Command } from '@boostercloud/framework-core' +import { CartReadModel } from '../read-models/cart-read-model' + +@Command({ + authorize: 'all', +}) +export class CartMyAddress { + public constructor(readonly cartId: UUID, readonly paginatedVersion: boolean) {} + + public static async handle(command: CartMyAddress, register: Register): Promise { + return (await Booster.readModel(CartReadModel) + .filter({ + id: { + eq: command.cartId, + }, + }) + .select(['id', 'myAddress']) + .paginatedVersion(command.paginatedVersion) + .search()) as Array + } +} diff --git a/packages/framework-integration-tests/src/commands/hard-delete.ts b/packages/framework-integration-tests/src/commands/hard-delete.ts new file mode 100644 index 0000000000..405edbef39 --- /dev/null +++ b/packages/framework-integration-tests/src/commands/hard-delete.ts @@ -0,0 +1,18 @@ +import { Booster, Command } from '@boostercloud/framework-core' +import { EventDeleteParameters } from '@boostercloud/framework-types' + +@Command({ + authorize: 'all', +}) +export class HardDelete { + public constructor(readonly entityId: string, readonly entityTypeName: string, readonly createdAt: string) {} + + public static async handle(command: HardDelete): Promise { + const parameters: EventDeleteParameters = { + entityID: command.entityId, + entityTypeName: command.entityTypeName, + createdAt: command.createdAt, + } + return await Booster.deleteEvent(parameters) + } +} diff --git a/packages/framework-integration-tests/src/commands/update-car-model-name.ts b/packages/framework-integration-tests/src/commands/update-car-model-name.ts new file mode 100644 index 0000000000..eef2f5b5de --- /dev/null +++ b/packages/framework-integration-tests/src/commands/update-car-model-name.ts @@ -0,0 +1,14 @@ +import { Command } from '@boostercloud/framework-core' +import { Register, UUID } from '@boostercloud/framework-types' +import { CarModelNameUpdated } from '../events/car-model-name-updated' + +@Command({ + authorize: 'all', +}) +export class UpdateCarModelName { + public constructor(readonly id: UUID, readonly name: string) {} + + public static async handle(command: UpdateCarModelName, register: Register): Promise { + register.events(new CarModelNameUpdated(command.id, command.name)) + } +} diff --git a/packages/framework-integration-tests/src/commands/update-car-owner-name.ts b/packages/framework-integration-tests/src/commands/update-car-owner-name.ts new file mode 100644 index 0000000000..e73acced54 --- /dev/null +++ b/packages/framework-integration-tests/src/commands/update-car-owner-name.ts @@ -0,0 +1,14 @@ +import { Command } from '@boostercloud/framework-core' +import { Register, UUID } from '@boostercloud/framework-types' +import { CarOwnerNameUpdated } from '../events/car-owner-name-updated' + +@Command({ + authorize: 'all', +}) +export class UpdateCarOwnerName { + public constructor(readonly id: UUID, readonly name: string) {} + + public static async handle(command: UpdateCarOwnerName, register: Register): Promise { + register.events(new CarOwnerNameUpdated(command.id, command.name)) + } +} diff --git a/packages/framework-integration-tests/src/common/app-error-handler.ts b/packages/framework-integration-tests/src/common/app-error-handler.ts index e62d62e86a..ffef06eacb 100644 --- a/packages/framework-integration-tests/src/common/app-error-handler.ts +++ b/packages/framework-integration-tests/src/common/app-error-handler.ts @@ -2,16 +2,26 @@ import { GlobalErrorHandler } from '@boostercloud/framework-core' import { CommandEnvelope, + CommandMetadata, EntityInterface, + EntitySnapshotEnvelope, + EventEnvelope, EventInterface, + NotificationInterface, + ProjectionMetadata, QueryEnvelope, ReadModelInterface, + ReducerMetadata, + ScheduledCommandEnvelope, + ScheduledCommandMetadata, } from '@boostercloud/framework-types' import { commandHandlerBeforeErrorCartId, commandHandlerErrorCartId, commandHandlerErrorIgnoredCartId, dispatchEventErrorCartId, + eventErrorCartId, + ignoreEventErrorCartId, projectionErrorCartId, queryHandlerErrorCartId, reducerErrorCartId, @@ -19,15 +29,21 @@ import { @GlobalErrorHandler() export class AppErrorHandler { - public static async onCommandHandlerError(error: Error, command: CommandEnvelope): Promise { - if (command.value.cartId === commandHandlerErrorIgnoredCartId) { + public static async onCommandHandlerError( + error: Error, + commandEnvelope: CommandEnvelope, + commandMetadata: CommandMetadata + ): Promise { + console.log(commandEnvelope) + console.log(commandMetadata) + if (commandEnvelope.value.cartId === commandHandlerErrorIgnoredCartId) { return undefined } - if (command.value.cartId === commandHandlerErrorCartId) { - return new Error(error.message + '-onCommandHandlerError') + if (commandEnvelope.value.cartId === commandHandlerErrorCartId) { + return new Error(`${error.message}-onCommandHandlerError with metadata: ${JSON.stringify(commandMetadata)}`) } - if (command.value.cartId === commandHandlerBeforeErrorCartId) { - return new Error(error.message + '-onBeforeCommandHandlerError') + if (commandEnvelope.value.cartId === commandHandlerBeforeErrorCartId) { + return new Error(`${error.message}-onBeforeCommandHandlerError with metadata: ${JSON.stringify(commandMetadata)}`) } return error } @@ -39,41 +55,75 @@ export class AppErrorHandler { return error } - public static async onScheduledCommandHandlerError(error: Error): Promise { + public static async onScheduledCommandHandlerError( + error: Error, + scheduledCommandEnvelope: ScheduledCommandEnvelope, + scheduledCommandMetadata: ScheduledCommandMetadata + ): Promise { console.log('onScheduledCommandHandlerError') - return error + console.log(scheduledCommandEnvelope) + console.log(scheduledCommandMetadata) + return new Error( + `${error.message}-onScheduledCommandHandlerError with metadata: ${JSON.stringify(scheduledCommandMetadata)}` + ) } public static async onDispatchEventHandlerError( error: Error, + eventEnvelope: EventEnvelope | NotificationInterface, + eventHandlerMetadata: unknown, eventInstance: EventInterface ): Promise { - const getEntityID = eventInstance?.entityID ?? (() => '') - if (getEntityID() === dispatchEventErrorCartId) { - return new Error(error.message + '-onDispatchEventHandlerError') + console.log(eventEnvelope) + console.log(eventHandlerMetadata) + const entityId = eventInstance?.entityID ? eventInstance.entityID() : '' + if (entityId === dispatchEventErrorCartId) { + return new Error( + `${error.message}-onDispatchEventHandlerError with metadata: ${JSON.stringify(eventHandlerMetadata)}` + ) } return error } public static async onReducerError( error: Error, + eventEnvelope: EventEnvelope, + reducerMetadata: ReducerMetadata, eventInstance: EventInterface, snapshotInstance: EntityInterface | null - ): Promise { - const getEntityID = eventInstance?.entityID ?? (() => '') - if (getEntityID() === reducerErrorCartId) { - return new Error(error.message + '-onReducerError') + ): Promise { + console.log(eventEnvelope) + console.log(reducerMetadata) + console.log(snapshotInstance) + const entityId = eventInstance?.entityID ? eventInstance.entityID() : '' + if (entityId === reducerErrorCartId) { + return new Error(`${error.message}-onReducerError with metadata: ${JSON.stringify(reducerMetadata)}`) } return error } public static async onProjectionError( error: Error, + entityEnvelope: EntitySnapshotEnvelope, + projectionMetadata: ProjectionMetadata, entity: EntityInterface, readModel: ReadModelInterface | undefined ): Promise { + console.log(entityEnvelope) + console.log(projectionMetadata) + console.log(readModel) if (entity?.id === projectionErrorCartId) { - return new Error(error.message + '-onProjectionError') + return new Error(`${error.message}-onProjectionError with metadata: ${JSON.stringify(projectionMetadata)}`) + } + return error + } + + public static async onEventError(error: Error, eventEnvelope: EventEnvelope): Promise { + if (eventEnvelope.entityID === eventErrorCartId) { + return new Error(error.message + '-onEventError') + } + if (eventEnvelope.entityID === ignoreEventErrorCartId) { + return undefined } return error } diff --git a/packages/framework-integration-tests/src/constants.ts b/packages/framework-integration-tests/src/constants.ts index 04b92b2d53..2b39ca8c52 100644 --- a/packages/framework-integration-tests/src/constants.ts +++ b/packages/framework-integration-tests/src/constants.ts @@ -19,6 +19,8 @@ export const dispatchErrorCartMessage = 'dispatchErrorCartMessage' export const projectionErrorCartId = 'projectionErrorCartId' export const projectionErrorCartMessage = 'projectionErrorCartMessage' export const reducerErrorCartId = 'reducerErrorCartId' +export const eventErrorCartId = 'eventErrorCartId' +export const ignoreEventErrorCartId = 'ignoreEventErrorCartId' export const reducerErrorCartMessage = 'reducerErrorCartMessage' export const QUANTITY_TO_MIGRATE_DATA = 1234 export const QUANTITY_AFTER_DATA_MIGRATION_V1 = 1234999 diff --git a/packages/framework-integration-tests/src/entities/book.ts b/packages/framework-integration-tests/src/entities/book.ts new file mode 100644 index 0000000000..ba1ab47d24 --- /dev/null +++ b/packages/framework-integration-tests/src/entities/book.ts @@ -0,0 +1,19 @@ +import { Entity, Reduces } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' +import { BookAdded } from '../events/book-added' + +@Entity({ + authorizeReadEvents: 'all', +}) +export class Book { + public constructor(readonly id: UUID, readonly title: string, readonly pages: number) {} + + public getId(): UUID { + return this.id + } + + @Reduces(BookAdded) + public static bookAdded(event: BookAdded, currentBook: Book): Book { + return new Book(event.id, event.title, event.pages) + } +} diff --git a/packages/framework-integration-tests/src/entities/car-model.ts b/packages/framework-integration-tests/src/entities/car-model.ts new file mode 100644 index 0000000000..fe6dd36498 --- /dev/null +++ b/packages/framework-integration-tests/src/entities/car-model.ts @@ -0,0 +1,27 @@ +import { Entity, Reduces } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' +import { CarModelAdded } from '../events/car-model-added' +import { CarModelNameUpdated } from '../events/car-model-name-updated' + +@Entity({ + authorizeReadEvents: 'all', +}) +export class CarModel { + public constructor(readonly id: UUID, public name: string, readonly brand: string) {} + public getId() { + return this.id + } + @Reduces(CarModelAdded) + public static reduceCarModelAdded(event: CarModelAdded, currentCarModel: CarModel): CarModel { + return new CarModel(event.id, event.name, event.brand) + } + + @Reduces(CarModelNameUpdated) + public static reduceCarModelNameUpdated(event: CarModelNameUpdated, currentCarModel: CarModel): CarModel { + if (!currentCarModel) { + throw new Error('CarModel not found') + } + currentCarModel.name = event.newModelName + return currentCarModel + } +} diff --git a/packages/framework-integration-tests/src/entities/car-offers.ts b/packages/framework-integration-tests/src/entities/car-offers.ts new file mode 100644 index 0000000000..4a031f7723 --- /dev/null +++ b/packages/framework-integration-tests/src/entities/car-offers.ts @@ -0,0 +1,17 @@ +import { Entity, Reduces } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' +import { CarOfferAdded } from '../events/car-offer-added' + +@Entity({ + authorizeReadEvents: 'all', +}) +export class CarOffers { + public constructor(readonly id: UUID, readonly name: string, readonly purchasesIds: Array) {} + public getId() { + return this.id + } + @Reduces(CarOfferAdded) + public static reduceCarOfferAdded(event: CarOfferAdded, currentCarDriver: CarOffers): CarOffers { + return new CarOffers(event.id, event.name, event.purchasesIds) + } +} diff --git a/packages/framework-integration-tests/src/entities/car-owner.ts b/packages/framework-integration-tests/src/entities/car-owner.ts new file mode 100644 index 0000000000..d72ff5e469 --- /dev/null +++ b/packages/framework-integration-tests/src/entities/car-owner.ts @@ -0,0 +1,27 @@ +import { Entity, Reduces } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' +import { CarOwnerAdded } from '../events/car-owner-added' +import { CarOwnerNameUpdated } from '../events/car-owner-name-updated' + +@Entity({ + authorizeReadEvents: 'all', +}) +export class CarOwner { + public constructor(readonly id: UUID, public name: string) {} + public getId() { + return this.id + } + @Reduces(CarOwnerAdded) + public static reduceCarOwnerAdded(event: CarOwnerAdded, currentCarOwner: CarOwner): CarOwner { + return new CarOwner(event.id, event.name) + } + + @Reduces(CarOwnerNameUpdated) + public static reduceCarOwnerNameUpdated(event: CarOwnerNameUpdated, currentCarOwner: CarOwner): CarOwner { + if (!currentCarOwner) { + throw new Error('CarOwner not found') + } + currentCarOwner.name = event.newOwnerName + return currentCarOwner + } +} diff --git a/packages/framework-integration-tests/src/entities/car-purchase.ts b/packages/framework-integration-tests/src/entities/car-purchase.ts new file mode 100644 index 0000000000..d2d09212a8 --- /dev/null +++ b/packages/framework-integration-tests/src/entities/car-purchase.ts @@ -0,0 +1,19 @@ +import { Entity, Reduces } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' +import { CarPurchased } from '../events/car-purchased' +import { CarModel } from './car-model' +import { CarOwner } from './car-owner' + +@Entity({ + authorizeReadEvents: 'all', +}) +export class CarPurchase { + public constructor(readonly id: UUID, readonly model: CarModel, readonly owner: CarOwner) {} + public getId() { + return this.id + } + @Reduces(CarPurchased) + public static reduceCarPurchase(event: CarPurchased, currentCarPurchase: CarPurchase): CarPurchase { + return new CarPurchase(event.id, event.model, event.owner) + } +} diff --git a/packages/framework-integration-tests/src/entities/movie.ts b/packages/framework-integration-tests/src/entities/movie.ts new file mode 100644 index 0000000000..347001ba64 --- /dev/null +++ b/packages/framework-integration-tests/src/entities/movie.ts @@ -0,0 +1,19 @@ +import { Entity, Reduces } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' +import { MovieAdded } from '../events/movie-added' + +@Entity({ + authorizeReadEvents: 'all', +}) +export class Movie { + public constructor(readonly id: UUID, readonly title: string) {} + + public getId(): UUID { + return this.id + } + + @Reduces(MovieAdded) + public static movieAdded(event: MovieAdded, currentMovie: Movie): Movie { + return new Movie(event.id, event.title) + } +} diff --git a/packages/framework-integration-tests/src/events/book-added.ts b/packages/framework-integration-tests/src/events/book-added.ts new file mode 100644 index 0000000000..80d8666df7 --- /dev/null +++ b/packages/framework-integration-tests/src/events/book-added.ts @@ -0,0 +1,11 @@ +import { Event } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' + +@Event +export class BookAdded { + public constructor(readonly id: UUID, readonly title: string, readonly pages: number) {} + + public entityID(): UUID { + return this.id + } +} diff --git a/packages/framework-integration-tests/src/events/car-model-added.ts b/packages/framework-integration-tests/src/events/car-model-added.ts new file mode 100644 index 0000000000..9e2b650ca1 --- /dev/null +++ b/packages/framework-integration-tests/src/events/car-model-added.ts @@ -0,0 +1,11 @@ +import { Event } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' + +@Event +export class CarModelAdded { + public constructor(readonly id: UUID, readonly name: string, readonly brand: string) {} + + public entityID(): UUID { + return this.id + } +} diff --git a/packages/framework-integration-tests/src/events/car-model-name-updated.ts b/packages/framework-integration-tests/src/events/car-model-name-updated.ts new file mode 100644 index 0000000000..1cdb4bd388 --- /dev/null +++ b/packages/framework-integration-tests/src/events/car-model-name-updated.ts @@ -0,0 +1,11 @@ +import { Event } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' + +@Event +export class CarModelNameUpdated { + public constructor(readonly carModelId: UUID, readonly newModelName: string) {} + + public entityID(): UUID { + return this.carModelId + } +} diff --git a/packages/framework-integration-tests/src/events/car-offer-added.ts b/packages/framework-integration-tests/src/events/car-offer-added.ts new file mode 100644 index 0000000000..5a6d57f44e --- /dev/null +++ b/packages/framework-integration-tests/src/events/car-offer-added.ts @@ -0,0 +1,11 @@ +import { Event } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' + +@Event +export class CarOfferAdded { + public constructor(readonly id: UUID, readonly name: string, readonly purchasesIds: Array) {} + + public entityID(): UUID { + return this.id + } +} diff --git a/packages/framework-integration-tests/src/events/car-owner-added.ts b/packages/framework-integration-tests/src/events/car-owner-added.ts new file mode 100644 index 0000000000..2742bb311c --- /dev/null +++ b/packages/framework-integration-tests/src/events/car-owner-added.ts @@ -0,0 +1,11 @@ +import { Event } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' + +@Event +export class CarOwnerAdded { + public constructor(readonly id: UUID, readonly name: string) {} + + public entityID(): UUID { + return this.id + } +} diff --git a/packages/framework-integration-tests/src/events/car-owner-name-updated.ts b/packages/framework-integration-tests/src/events/car-owner-name-updated.ts new file mode 100644 index 0000000000..5b096919fd --- /dev/null +++ b/packages/framework-integration-tests/src/events/car-owner-name-updated.ts @@ -0,0 +1,11 @@ +import { Event } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' + +@Event +export class CarOwnerNameUpdated { + public constructor(readonly carOwnerId: UUID, readonly newOwnerName: string) {} + + public entityID(): UUID { + return this.carOwnerId + } +} diff --git a/packages/framework-integration-tests/src/events/car-purchased.ts b/packages/framework-integration-tests/src/events/car-purchased.ts new file mode 100644 index 0000000000..ec6eab0a06 --- /dev/null +++ b/packages/framework-integration-tests/src/events/car-purchased.ts @@ -0,0 +1,13 @@ +import { Event } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' +import { CarOwner } from '../entities/car-owner' +import { CarModel } from '../entities/car-model' + +@Event +export class CarPurchased { + public constructor(readonly id: UUID, readonly owner: CarOwner, readonly model: CarModel) {} + + public entityID(): UUID { + return this.id + } +} diff --git a/packages/framework-integration-tests/src/events/movie-added.ts b/packages/framework-integration-tests/src/events/movie-added.ts new file mode 100644 index 0000000000..6be7d0bd8c --- /dev/null +++ b/packages/framework-integration-tests/src/events/movie-added.ts @@ -0,0 +1,11 @@ +import { Event } from '@boostercloud/framework-core' +import { UUID } from '@boostercloud/framework-types' + +@Event +export class MovieAdded { + public constructor(readonly id: UUID, readonly title: string) {} + + public entityID(): UUID { + return this.id + } +} diff --git a/packages/framework-integration-tests/src/queries/search-media.ts b/packages/framework-integration-tests/src/queries/search-media.ts new file mode 100644 index 0000000000..12ca4298a0 --- /dev/null +++ b/packages/framework-integration-tests/src/queries/search-media.ts @@ -0,0 +1,42 @@ +import { Booster, Query } from '@boostercloud/framework-core' +import { QueryInfo } from '@boostercloud/framework-types' +import { BookReadModel } from '../read-models/book-read-model' +import { MovieReadModel } from '../read-models/movie-read-model' + +export type MediaValue = BookReadModel | MovieReadModel +class SearchResult { + readonly results!: MediaValue[] + constructor(results: MediaValue[]) { + this.results = results + } +} +@Query({ + authorize: 'all', +}) +export class SearchMedia { + public constructor(readonly searchword: string) {} + + public static async handle(query: SearchMedia, queryInfo: QueryInfo): Promise { + const [books, movies] = await Promise.all([ + Booster.readModel(BookReadModel) + .filter({ + title: { + contains: query.searchword, + }, + }) + .search(), + Booster.readModel(MovieReadModel) + .filter({ + title: { + contains: query.searchword, + }, + }) + .search(), + ]) + const response = [...books, ...movies] + + return { + results: response, + } + } +} diff --git a/packages/framework-integration-tests/src/read-models/book-read-model.ts b/packages/framework-integration-tests/src/read-models/book-read-model.ts new file mode 100644 index 0000000000..68c346122f --- /dev/null +++ b/packages/framework-integration-tests/src/read-models/book-read-model.ts @@ -0,0 +1,15 @@ +import { Projects, ReadModel } from '@boostercloud/framework-core' +import { ProjectionResult, UUID } from '@boostercloud/framework-types' +import { Book } from '../entities/book' + +@ReadModel({ + authorize: 'all', +}) +export class BookReadModel { + public constructor(readonly id: UUID, readonly title: string, readonly pages: number) {} + + @Projects(Book, 'id') + public static updateBook(book: Book): ProjectionResult { + return new BookReadModel(book.id, book.title, book.pages) + } +} diff --git a/packages/framework-integration-tests/src/read-models/car-model-read-model.ts b/packages/framework-integration-tests/src/read-models/car-model-read-model.ts new file mode 100644 index 0000000000..1fd509dc6a --- /dev/null +++ b/packages/framework-integration-tests/src/read-models/car-model-read-model.ts @@ -0,0 +1,15 @@ +import { Projects, ReadModel } from '@boostercloud/framework-core' +import { ProjectionResult, UUID } from '@boostercloud/framework-types' +import { CarModel } from '../entities/car-model' + +@ReadModel({ + authorize: 'all', +}) +export class CarModelReadModel { + public constructor(readonly id: UUID, readonly name: string, readonly brand: string) {} + + @Projects(CarModel, 'id') + public static projectCarModel(model: CarModel, old?: CarModelReadModel): ProjectionResult { + return new CarModelReadModel(model.id, model.name, model.brand) + } +} diff --git a/packages/framework-integration-tests/src/read-models/car-offer-read-model.ts b/packages/framework-integration-tests/src/read-models/car-offer-read-model.ts new file mode 100644 index 0000000000..66c99dea2f --- /dev/null +++ b/packages/framework-integration-tests/src/read-models/car-offer-read-model.ts @@ -0,0 +1,15 @@ +import { Projects, ReadModel } from '@boostercloud/framework-core' +import { ProjectionResult, UUID } from '@boostercloud/framework-types' +import { CarOffers } from '../entities/car-offers' + +@ReadModel({ + authorize: 'all', +}) +export class CarOfferReadModel { + public constructor(readonly id: UUID, readonly name: string, readonly purchasesIds: Array) {} + + @Projects(CarOffers, 'id') + public static projectCarOffers(offer: CarOffers, old?: CarOfferReadModel): ProjectionResult { + return new CarOfferReadModel(offer.id, offer.name, offer.purchasesIds) + } +} diff --git a/packages/framework-integration-tests/src/read-models/car-owner-read-model.ts b/packages/framework-integration-tests/src/read-models/car-owner-read-model.ts new file mode 100644 index 0000000000..3d3d4cd22a --- /dev/null +++ b/packages/framework-integration-tests/src/read-models/car-owner-read-model.ts @@ -0,0 +1,15 @@ +import { Projects, ReadModel } from '@boostercloud/framework-core' +import { ProjectionResult, UUID } from '@boostercloud/framework-types' +import { CarOwner } from '../entities/car-owner' + +@ReadModel({ + authorize: 'all', +}) +export class CarOwnerReadModel { + public constructor(readonly id: UUID, readonly name: string) {} + + @Projects(CarOwner, 'id') + public static projectCarOwner(owner: CarOwner, old?: CarOwnerReadModel): ProjectionResult { + return new CarOwnerReadModel(owner.id, owner.name) + } +} diff --git a/packages/framework-integration-tests/src/read-models/car-purchases-read-model.ts b/packages/framework-integration-tests/src/read-models/car-purchases-read-model.ts new file mode 100644 index 0000000000..f68e37a5d9 --- /dev/null +++ b/packages/framework-integration-tests/src/read-models/car-purchases-read-model.ts @@ -0,0 +1,110 @@ +import { Projects, ReadModel } from '@boostercloud/framework-core' +import { FilterFor, ProjectionResult, ReadModelAction, UUID } from '@boostercloud/framework-types' +import { CarOwner } from '../entities/car-owner' +import { CarModel } from '../entities/car-model' +import { CarPurchase } from '../entities/car-purchase' +import { CarOffers } from '../entities/car-offers' + +/** + * CardModel neither CarOwner have the CarModelOwnerReadModel id as a field, + * so we need to use a ReadModel JoinKey to get all the CarOwnerModelReadModel instances for a given CarOwner or CarModel + */ +@ReadModel({ + authorize: 'all', +}) +export class CarPurchasesReadModel { + public constructor( + readonly id: UUID, + readonly carModel?: CarModel, + readonly carOwner?: CarOwner, + readonly offers?: Array + ) {} + + @Projects(CarPurchase, 'id') + public static projectWithPurchase( + purchase: CarPurchase, + oldCarPurchaseReadModel?: CarPurchasesReadModel + ): ProjectionResult { + return new CarPurchasesReadModel(purchase.id, purchase.model, purchase.owner, oldCarPurchaseReadModel?.offers) + } + + // A ReadModel JoinKey to get all the CarOwnerModelReadModel instances for a given CarOwner + @Projects(CarOwner, (carOwner: CarOwner): FilterFor | undefined => { + if (carOwner.name === 'SKIP') { + return + } + return { + carOwner: { + id: { + eq: carOwner.id, + }, + }, + } + }) + public static projectWithOwner( + owner: CarOwner, + readModelId: UUID | undefined, + oldCarPurchaseReadModel?: CarPurchasesReadModel + ): ProjectionResult { + if (!readModelId) { + return ReadModelAction.Nothing + } + return new CarPurchasesReadModel( + readModelId, + oldCarPurchaseReadModel?.carModel, + owner, + oldCarPurchaseReadModel?.offers + ) + } + + // A ReadModel JoinKey to get all the CarOwnerModelReadModel instances for a given CarModel + @Projects(CarModel, (carModel: CarModel): FilterFor => { + return { + carModel: { + id: { + eq: carModel.id, + }, + }, + } + }) + public static projectWithModel( + model: CarModel, + readModelId: UUID | undefined, + oldCarPurchaseReadModel?: CarPurchasesReadModel + ): ProjectionResult { + if (!readModelId) { + return ReadModelAction.Nothing + } + return new CarPurchasesReadModel( + readModelId, + model, + oldCarPurchaseReadModel?.carOwner, + oldCarPurchaseReadModel?.offers + ) + } + + @Projects(CarOffers, 'purchasesIds') + public static projectWithOffer( + carOffers: CarOffers, + readModelId: UUID, + oldCarPurchaseReadModel?: CarPurchasesReadModel + ): ProjectionResult { + if (!oldCarPurchaseReadModel) { + return ReadModelAction.Nothing + } + console.log(`Updating purchase ${readModelId} with offers ${JSON.stringify(carOffers)}`) + + let offers = oldCarPurchaseReadModel?.offers || [] + if (offers.find((existingOfferId) => existingOfferId.id == carOffers.id)) { + offers = offers.map((existingOffer) => (existingOffer.id == carOffers.id ? carOffers : existingOffer)) + } else { + offers.push(carOffers) + } + return new CarPurchasesReadModel( + oldCarPurchaseReadModel.id, + oldCarPurchaseReadModel?.carModel, + oldCarPurchaseReadModel?.carOwner, + offers + ) + } +} diff --git a/packages/framework-integration-tests/src/read-models/cart-read-model.ts b/packages/framework-integration-tests/src/read-models/cart-read-model.ts index 7938f62cf4..31cc2edd74 100644 --- a/packages/framework-integration-tests/src/read-models/cart-read-model.ts +++ b/packages/framework-integration-tests/src/read-models/cart-read-model.ts @@ -1,4 +1,4 @@ -import { Booster, NonExposed, Projects, ReadModel } from '@boostercloud/framework-core' +import { Booster, CalculatedField, NonExposed, Projects, ReadModel } from '@boostercloud/framework-core' import { ProjectionResult, ReadModelInterface, @@ -38,14 +38,17 @@ export class CartReadModel { return this.checks } + @CalculatedField({ dependsOn: ['cartItems'] }) public get cartItemsSize(): number | undefined { return this.cartItems ? this.cartItems.length : 0 } + @CalculatedField({ dependsOn: ['shippingAddress'] }) public get myAddress(): Promise
{ return Promise.resolve(this.shippingAddress || new Address('', '', '', '', '', '')) } + @CalculatedField({ dependsOn: ['cartItems'] }) public get lastProduct(): Promise { if (this.cartItemsSize === 0) { return Promise.resolve(undefined) diff --git a/packages/framework-integration-tests/src/read-models/movie-read-model.ts b/packages/framework-integration-tests/src/read-models/movie-read-model.ts new file mode 100644 index 0000000000..efff47a189 --- /dev/null +++ b/packages/framework-integration-tests/src/read-models/movie-read-model.ts @@ -0,0 +1,15 @@ +import { Projects, ReadModel } from '@boostercloud/framework-core' +import { ProjectionResult, UUID } from '@boostercloud/framework-types' +import { Movie } from '../entities/movie' + +@ReadModel({ + authorize: 'all', +}) +export class MovieReadModel { + public constructor(readonly id: UUID, readonly title: string) {} + + @Projects(Movie, 'id') + public static updateMovie(movie: Movie): ProjectionResult { + return new MovieReadModel(movie.id, movie.title) + } +} diff --git a/packages/framework-integration-tests/src/read-models/product-read-model.ts b/packages/framework-integration-tests/src/read-models/product-read-model.ts index 759e71db96..634dc65916 100644 --- a/packages/framework-integration-tests/src/read-models/product-read-model.ts +++ b/packages/framework-integration-tests/src/read-models/product-read-model.ts @@ -1,6 +1,12 @@ import { Projects, ReadModel } from '@boostercloud/framework-core' import { UserWithEmail } from '../roles' -import { ProjectionResult, ReadModelAction, UUID } from '@boostercloud/framework-types' +import { + ProjectionInfo, + ProjectionInfoReason, + ProjectionResult, + ReadModelAction, + UUID, +} from '@boostercloud/framework-types' import { Product, ProductType } from '../entities/product' import { Money } from '../common/money' import { Pack } from '../entities/pack' @@ -23,7 +29,7 @@ export class ProductReadModel { readonly packs?: Array ) {} - @Projects(Product, 'id') + @Projects(Product, 'id', ProductReadModel.unProjectWithProduct) public static updateWithProduct(product: Product): ProjectionResult { if (product.deleted) { return ReadModelAction.Delete @@ -43,12 +49,24 @@ export class ProductReadModel { } } - @Projects(Pack, 'products') + public static unProjectWithProduct( + _product: Product, + _currentProductReadModel?: ProductReadModel, + _projectionInfo?: ProjectionInfo + ): ProjectionResult { + return ReadModelAction.Delete + } + + @Projects(Pack, 'products', ProductReadModel.updateWithPack) public static updateWithPack( pack: Pack, readModelID: UUID, - currentProductReadModel?: ProductReadModel + currentProductReadModel?: ProductReadModel, + projectionInfo?: ProjectionInfo ): ProjectionResult { + if (projectionInfo?.reason === ProjectionInfoReason.ENTITY_DELETED) { + return ReadModelAction.Delete + } if (!currentProductReadModel) { return ReadModelAction.Nothing } else { diff --git a/packages/framework-integration-tests/src/read-models/product-updates-read-model.ts b/packages/framework-integration-tests/src/read-models/product-updates-read-model.ts index 90229454ab..0857770129 100644 --- a/packages/framework-integration-tests/src/read-models/product-updates-read-model.ts +++ b/packages/framework-integration-tests/src/read-models/product-updates-read-model.ts @@ -1,6 +1,12 @@ import { ReadModel, Projects } from '@boostercloud/framework-core' import { Admin } from '../roles' -import { ProjectionResult, UUID } from '@boostercloud/framework-types' +import { + ProjectionInfo, + ProjectionInfoReason, + ProjectionResult, + ReadModelAction, + UUID, +} from '@boostercloud/framework-types' import { Product } from '../entities/product' // This is an example read model for a possible admin-exclusive report to show last and previous updates to products @@ -15,11 +21,15 @@ export class ProductUpdatesReadModel { readonly previousUpdate?: Date ) {} - @Projects(Product, 'id') + @Projects(Product, 'id', ProductUpdatesReadModel.updateWithProduct) public static updateWithProduct( product: Product, - previous?: ProductUpdatesReadModel + previous?: ProductUpdatesReadModel, + projectionInfo?: ProjectionInfo ): ProjectionResult { + if (projectionInfo?.reason === ProjectionInfoReason.ENTITY_DELETED) { + return ReadModelAction.Delete + } return new ProductUpdatesReadModel(product.id, product.availability, new Date(), previous?.lastUpdate) } } diff --git a/packages/framework-integration-tests/src/read-models/products-by-sku.ts b/packages/framework-integration-tests/src/read-models/products-by-sku.ts index b19f610c06..a59ae84869 100644 --- a/packages/framework-integration-tests/src/read-models/products-by-sku.ts +++ b/packages/framework-integration-tests/src/read-models/products-by-sku.ts @@ -1,5 +1,11 @@ import { ReadModel, Projects } from '@boostercloud/framework-core' -import { UUID, ProjectionResult } from '@boostercloud/framework-types' +import { + UUID, + ProjectionResult, + ProjectionInfoReason, + ReadModelAction, + ProjectionInfo, +} from '@boostercloud/framework-types' import { Product } from '../entities/product' interface ProductIDWithPrice { @@ -18,8 +24,15 @@ export class ProductsBySKU { readonly record?: Record ) {} - @Projects(Product, 'sku') - public static projectProduct(entity: Product, currentProductsBySKU?: ProductsBySKU): ProjectionResult { + @Projects(Product, 'sku', ProductsBySKU.projectProduct) + public static projectProduct( + entity: Product, + currentProductsBySKU?: ProductsBySKU, + projectionInfo?: ProjectionInfo + ): ProjectionResult { + if (projectionInfo?.reason === ProjectionInfoReason.ENTITY_DELETED) { + return ReadModelAction.Delete + } // The purpose of this projection is to test the Optimistic concurrency. We have a read model that accumulates entities // with different IDs. One instance of this read model (with id == product sku) will be updated when multiple instances // of the product entity (with the same SKU but different id) are changed. diff --git a/packages/framework-integration-tests/src/read-models/special-reports-read-model.ts b/packages/framework-integration-tests/src/read-models/special-reports-read-model.ts index 78e9b9e792..8499d4f873 100644 --- a/packages/framework-integration-tests/src/read-models/special-reports-read-model.ts +++ b/packages/framework-integration-tests/src/read-models/special-reports-read-model.ts @@ -1,5 +1,12 @@ import { Projects, ReadModel } from '@boostercloud/framework-core' -import { ProjectionResult, UserEnvelope, UUID } from '@boostercloud/framework-types' +import { + ProjectionInfo, + ProjectionInfoReason, + ProjectionResult, + ReadModelAction, + UserEnvelope, + UUID, +} from '@boostercloud/framework-types' import { Product } from '../entities/product' @ReadModel({ @@ -13,12 +20,16 @@ import { Product } from '../entities/product' export class SpecialReportsReadModel { public constructor(readonly id: UUID, readonly luck: number) {} - @Projects(Product, 'id') + @Projects(Product, 'id', SpecialReportsReadModel.updateCounter) public static updateCounter( product: Product, // eslint-disable-next-line @typescript-eslint/no-unused-vars - _oldCounterReadModel?: SpecialReportsReadModel + _oldCounterReadModel?: SpecialReportsReadModel, + projectionInfo?: ProjectionInfo ): ProjectionResult { + if (projectionInfo?.reason === ProjectionInfoReason.ENTITY_DELETED) { + return ReadModelAction.Delete + } const luck = product.description.length + product.displayName.length + Math.random() return new SpecialReportsReadModel(product.id, luck) } diff --git a/packages/framework-provider-aws-infrastructure/package.json b/packages/framework-provider-aws-infrastructure/package.json index 9962aa0dd9..4b7739529e 100644 --- a/packages/framework-provider-aws-infrastructure/package.json +++ b/packages/framework-provider-aws-infrastructure/package.json @@ -1,7 +1,7 @@ { "name": "@boostercloud/framework-provider-aws-infrastructure", "deprecated": "Due to significant changes in recent versions of the AWS CDK, specifically the transition from CDKToolkit to a cli tool as noted [here](https://github.com/aws/aws-cdk-rfcs/issues/300), upgrading our current implementation would require a substantial rewrite. Given the open-source nature of our project without direct revenue streams, the ensuing maintenance costs are unfeasible. However, we are open to upgrading the AWS provider or creating an alternative implementation using other technologies like Terraform's CDKTF, with community contributions or sponsorships. If you're interested in supporting us, we welcome you to reach out via the official channels listed on the [Booster's website](https://boosterframework.com).", - "version": "2.12.1", + "version": "2.18.7", "description": "Handle the Booster deployment process to AWS", "keywords": [ "framework-provider-aws-infrastructure" @@ -41,9 +41,9 @@ "@aws-cdk/aws-s3-deployment": "^1.170.0", "@aws-cdk/core": "^1.170.0", "@aws-cdk/cx-api": "^1.170.0", - "@boostercloud/framework-common-helpers": "workspace:^2.12.1", - "@boostercloud/framework-provider-aws": "workspace:^2.12.1", - "@boostercloud/framework-types": "workspace:^2.12.1", + "@boostercloud/framework-common-helpers": "workspace:^2.18.7", + "@boostercloud/framework-provider-aws": "workspace:^2.18.7", + "@boostercloud/framework-types": "workspace:^2.18.7", "constructs": "^3.3.69", "aws-cdk": "^1.170.0", "aws-sdk": "2.853.0", @@ -69,7 +69,7 @@ "url": "https://github.com/boostercloud/booster/issues" }, "devDependencies": { - "@boostercloud/eslint-config": "workspace:^2.12.1", + "@boostercloud/eslint-config": "workspace:^2.18.7", "@types/aws-lambda": "8.10.48", "@types/aws-sdk": "2.7.0", "@types/chai": "4.2.18", diff --git a/packages/framework-provider-aws/package.json b/packages/framework-provider-aws/package.json index ef3d182a1f..62e3755fcd 100644 --- a/packages/framework-provider-aws/package.json +++ b/packages/framework-provider-aws/package.json @@ -1,7 +1,7 @@ { "name": "@boostercloud/framework-provider-aws", "deprecated": "Due to significant changes in recent versions of the AWS CDK, specifically the transition from CDKToolkit to a cli tool as noted [here](https://github.com/aws/aws-cdk-rfcs/issues/300), upgrading our current implementation would require a substantial rewrite. Given the open-source nature of our project without direct revenue streams, the ensuing maintenance costs are unfeasible. However, we are open to upgrading the AWS provider or creating an alternative implementation using other technologies like Terraform's CDKTF, with community contributions or sponsorships. If you're interested in supporting us, we welcome you to reach out via the official channels listed on the [Booster's website](https://boosterframework.com).", - "version": "2.12.1", + "version": "2.18.7", "description": "Handle Booster's integration with AWS", "keywords": [ "framework-provider-aws" @@ -24,8 +24,8 @@ "node": ">=18.0.0 <19.0.0" }, "dependencies": { - "@boostercloud/framework-common-helpers": "workspace:^2.12.1", - "@boostercloud/framework-types": "workspace:^2.12.1", + "@boostercloud/framework-common-helpers": "workspace:^2.18.7", + "@boostercloud/framework-types": "workspace:^2.18.7", "tslib": "^2.4.0", "@effect-ts/core": "^0.60.4" }, @@ -43,7 +43,7 @@ "url": "https://github.com/boostercloud/booster/issues" }, "devDependencies": { - "@boostercloud/eslint-config": "workspace:^2.12.1", + "@boostercloud/eslint-config": "workspace:^2.18.7", "@types/aws-lambda": "8.10.48", "@types/chai": "4.2.18", "@types/chai-arrays": "2.0.0", diff --git a/packages/framework-provider-aws/src/library/events-adapter.ts b/packages/framework-provider-aws/src/library/events-adapter.ts index 0ef0781e7e..b9c8be7912 100644 --- a/packages/framework-provider-aws/src/library/events-adapter.ts +++ b/packages/framework-provider-aws/src/library/events-adapter.ts @@ -48,11 +48,13 @@ export async function readEntityEventsSince( ScanIndexForward: true, // Ascending order (older timestamps first) }) .promise() + const resultItems: Array = result.Items as Array + const validEvents = resultItems.filter((item) => !item.deletedAt) logger.debug( `[EventsAdapter#readEntityEventsSince] Loaded events for entity ${entityTypeName} with ID ${entityID} with result:`, - result.Items + validEvents ) - return result.Items as Array + return validEvents } export async function readEntityLatestSnapshot( diff --git a/packages/framework-provider-aws/src/library/events-searcher-adapter.ts b/packages/framework-provider-aws/src/library/events-searcher-adapter.ts index 23a5419a10..5008ce751a 100644 --- a/packages/framework-provider-aws/src/library/events-searcher-adapter.ts +++ b/packages/framework-provider-aws/src/library/events-searcher-adapter.ts @@ -240,6 +240,7 @@ function convertToSearchResult(eventEnvelopes: Array): Array { diff --git a/packages/framework-provider-aws/src/setup.ts b/packages/framework-provider-aws/src/setup.ts index bd6cf1d182..afaf3b8095 100644 --- a/packages/framework-provider-aws/src/setup.ts +++ b/packages/framework-provider-aws/src/setup.ts @@ -77,6 +77,10 @@ export const Provider = (rockets?: RocketDescriptor[]): ProviderLibrary => { store: storeEvents.bind(null, dynamoDB), storeSnapshot: storeSnapshot.bind(null, dynamoDB), storeDispatched: storeDispatchedEvent, + findDeletableEvent: notImplementedResult as any, + findDeletableSnapshot: notImplementedResult as any, + deleteEvent: notImplementedResult as any, + deleteSnapshot: notImplementedResult as any, }, // ProviderReadModelsLibrary readModels: { @@ -124,6 +128,8 @@ export const Provider = (rockets?: RocketDescriptor[]): ProviderLibrary => { rawRequestToHealthEnvelope: (rawRequest: unknown): HealthEnvelope => { throw new Error('Not implemented') }, + areRocketFunctionsUp: async (config: BoosterConfig): Promise<{ [key: string]: boolean }> => + notImplementedResult(), }, // ProviderInfrastructureGetter infrastructure: () => { diff --git a/packages/framework-provider-aws/test/library/events-search-adapter.test.ts b/packages/framework-provider-aws/test/library/events-search-adapter.test.ts index 0883b9497d..5ae7c5a076 100644 --- a/packages/framework-provider-aws/test/library/events-search-adapter.test.ts +++ b/packages/framework-provider-aws/test/library/events-search-adapter.test.ts @@ -291,7 +291,16 @@ describe('Events searcher adapter', () => { expect(res.map((item) => item.entityID)).to.be.deep.equal([occurredThirdID, occurredSecondID, occurredFirstID]) // Check they have the right structure for (const item of res) { - expect(item).to.have.keys(['type', 'entity', 'entityID', 'requestID', 'user', 'createdAt', 'value']) + expect(item).to.have.keys([ + 'type', + 'entity', + 'entityID', + 'requestID', + 'user', + 'createdAt', + 'value', + 'deletedAt', + ]) } }) }) diff --git a/packages/framework-provider-azure-infrastructure/package.json b/packages/framework-provider-azure-infrastructure/package.json index 37e7526cd7..ab9f61298d 100644 --- a/packages/framework-provider-azure-infrastructure/package.json +++ b/packages/framework-provider-azure-infrastructure/package.json @@ -1,6 +1,6 @@ { "name": "@boostercloud/framework-provider-azure-infrastructure", - "version": "2.12.1", + "version": "2.18.7", "description": "Handle the Booster deployment process to Azure", "keywords": [ "framework-provider-azure-infrastructure" @@ -25,11 +25,11 @@ "dependencies": { "@azure/arm-appservice": "^13.0.0", "@azure/cosmos": "^4.0.0", - "@boostercloud/framework-common-helpers": "workspace:^2.12.1", - "@boostercloud/framework-core": "workspace:^2.12.1", - "@boostercloud/framework-provider-azure": "workspace:^2.12.1", - "@boostercloud/framework-types": "workspace:^2.12.1", - "@cdktf/provider-azurerm": "11.2.0", + "@boostercloud/framework-common-helpers": "workspace:^2.18.7", + "@boostercloud/framework-core": "workspace:^2.18.7", + "@boostercloud/framework-provider-azure": "workspace:^2.18.7", + "@boostercloud/framework-types": "workspace:^2.18.7", + "@cdktf/provider-azurerm": "13.3.0", "@cdktf/provider-time": "9.0.2", "@types/archiver": "5.1.0", "@types/needle": "^2.0.4", @@ -67,7 +67,7 @@ "url": "https://github.com/boostercloud/booster/issues" }, "devDependencies": { - "@boostercloud/eslint-config": "workspace:^2.12.1", + "@boostercloud/eslint-config": "workspace:^2.18.7", "@types/chai": "4.2.18", "@types/chai-as-promised": "7.1.4", "@types/faker": "5.1.5", diff --git a/packages/framework-provider-azure-infrastructure/src/infrastructure/application-builder.ts b/packages/framework-provider-azure-infrastructure/src/infrastructure/application-builder.ts index 472ad84d53..2d08080b48 100644 --- a/packages/framework-provider-azure-infrastructure/src/infrastructure/application-builder.ts +++ b/packages/framework-provider-azure-infrastructure/src/infrastructure/application-builder.ts @@ -30,6 +30,8 @@ export class ApplicationBuilder { const azureStack = await this.synthApplication(app, webPubSubBaseFile) const rocketBuilder = new RocketBuilder(this.config, azureStack.applicationStack, this.rockets) await rocketBuilder.synthRocket() + // add rocket-related env vars to main function app settings + azureStack.addAppSettingsToFunctionApp(this.rockets) app.synth() azureStack.applicationStack.functionDefinitions = FunctionZip.buildAzureFunctions(this.config) diff --git a/packages/framework-provider-azure-infrastructure/src/infrastructure/azure-stack.ts b/packages/framework-provider-azure-infrastructure/src/infrastructure/azure-stack.ts index b3982b7b83..1fcfb96076 100644 --- a/packages/framework-provider-azure-infrastructure/src/infrastructure/azure-stack.ts +++ b/packages/framework-provider-azure-infrastructure/src/infrastructure/azure-stack.ts @@ -1,15 +1,42 @@ import { Construct } from 'constructs' -import { TerraformStack } from 'cdktf' +import { Fn, TerraformStack } from 'cdktf' import { ApplicationSynth } from './synth/application-synth' import { ApplicationSynthStack } from './types/application-synth-stack' +import { InfrastructureRocket } from './rockets/infrastructure-rocket' +import { environmentVarNames } from '@boostercloud/framework-provider-azure' export class AzureStack extends TerraformStack { readonly applicationStack: ApplicationSynthStack + readonly defaultApplicationSettings: { [key: string]: string } constructor(scope: Construct, name: string, zipFile?: string) { super(scope, name) const applicationSynth = new ApplicationSynth(this) this.applicationStack = applicationSynth.synth(zipFile) + this.defaultApplicationSettings = applicationSynth.buildDefaultAppSettings( + this.applicationStack, + this.applicationStack.storageAccount!, + 'func' + ) + } + + public addAppSettingsToFunctionApp(rockets?: InfrastructureRocket[]): void { + if (!this.applicationStack.functionApp) { + throw new Error('Function app not defined') + } + + const functionAppNames = rockets + ? rockets + .map((rocket: InfrastructureRocket) => + rocket.getFunctionAppName ? rocket.getFunctionAppName(this.applicationStack) : '' + ) + .join(',') + : '' + + this.applicationStack.functionApp.appSettings = Fn.merge([ + this.defaultApplicationSettings, + { [environmentVarNames.rocketFunctionAppNames]: functionAppNames }, + ]) } } diff --git a/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/application-synth.ts b/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/application-synth.ts index ab5cf63bd2..ef13edd33f 100644 --- a/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/application-synth.ts +++ b/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/application-synth.ts @@ -25,7 +25,7 @@ import { TerraformWebPubsubHub } from './terraform-web-pubsub-hub' import { TerraformWebPubSubExtensionKey } from './terraform-web-pub-sub-extension-key' import { TerraformEventHubNamespace } from './terraform-event-hub-namespace' import { TerraformEventHub } from './terraform-event-hub' -import { windowsFunctionApp } from '@cdktf/provider-azurerm' +import { storageAccount, windowsFunctionApp } from '@cdktf/provider-azurerm' import { TerraformNetworkSecurityGroup } from './gateway/terraform-network-security-group' import { TerraformVirtualNetwork } from './gateway/terraform-virtual-network' import { TerraformPublicIp } from './gateway/terraform-public-ip' @@ -33,6 +33,8 @@ import { TerraformPublicIpData } from './gateway/terraform-public-ip-data' import { TerraformSubnet } from './gateway/terraform-subnet' import { TerraformSubnetSecurity } from './gateway/terraform-subnet-security' import { BASIC_SERVICE_PLAN } from '../constants' +import { TerraformFunctionAppSettings } from './terraform-function-app-settings' +import { configuration } from '../helper/params' export class ApplicationSynth { readonly config: BoosterConfig @@ -51,7 +53,8 @@ export class ApplicationSynth { public constructor(terraformStack: TerraformStack) { this.config = readProjectConfig(process.cwd()) const azurermProvider = new AzurermProvider(terraformStack, 'azureFeature', { - features: {}, + features: [{}], + subscriptionId: configuration.subscriptionId, }) const appPrefix = buildAppPrefix(this.config) const resourceGroupName = createResourceGroupName(this.config.appName, this.config.environmentName) @@ -121,7 +124,6 @@ export class ApplicationSynth { ): windowsFunctionApp.WindowsFunctionApp { return TerraformFunctionApp.build( stack, - this.config, stack.applicationServicePlan!, stack.storageAccount!, 'func', @@ -139,11 +141,12 @@ export class ApplicationSynth { stack.eventConsumerStorageAccount = TerraformStorageAccount.build(stack, 'sc') stack.eventConsumerFunctionApp = TerraformFunctionApp.build( stack, - this.config, stack.eventConsumerServicePlan, stack.eventConsumerStorageAccount, 'fhub', - stack.streamFunctionAppName + stack.streamFunctionAppName, + undefined, + this.buildDefaultAppSettings(stack, stack.eventConsumerStorageAccount, 'fhub') ) if (!stack.containers) { stack.containers = [] @@ -164,4 +167,12 @@ export class ApplicationSynth { stack.webPubSubHub = TerraformWebPubsubHub.build(stack) } } + + public buildDefaultAppSettings( + stack: ApplicationSynthStack, + storageAccount: storageAccount.StorageAccount, + suffixName: string + ) { + return TerraformFunctionAppSettings.build(stack, this.config, storageAccount!, suffixName) + } } diff --git a/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-containers.ts b/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-containers.ts index b2aa8e95ff..249deee8b7 100644 --- a/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-containers.ts +++ b/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-containers.ts @@ -85,7 +85,7 @@ export class TerraformContainers { resourceGroupName: cosmosdbDatabaseResource.resourceGroupName, accountName: cosmosdbDatabaseResource.name, databaseName: cosmosdbSqlDatabaseResource.name, - partitionKeyPath: `/${eventsStoreAttributes.partitionKey}`, + partitionKeyPaths: [`/${eventsStoreAttributes.partitionKey}`], partitionKeyVersion: 2, autoscaleSettings: { maxThroughput: MAX_CONTAINER_THROUGHPUT, @@ -108,7 +108,7 @@ export class TerraformContainers { resourceGroupName: cosmosdbDatabaseResource.resourceGroupName, accountName: cosmosdbDatabaseResource.name, databaseName: cosmosdbSqlDatabaseResource.name, - partitionKeyPath: '/eventId', + partitionKeyPaths: ['/eventId'], partitionKeyVersion: 2, uniqueKey: [{ paths: ['/eventId'] }], autoscaleSettings: { @@ -134,7 +134,7 @@ export class TerraformContainers { resourceGroupName: cosmosdbDatabaseResource.resourceGroupName, accountName: cosmosdbDatabaseResource.name, databaseName: cosmosdbSqlDatabaseResource.name, - partitionKeyPath: '/id', + partitionKeyPaths: ['/id'], partitionKeyVersion: 2, autoscaleSettings: { maxThroughput: MAX_CONTAINER_THROUGHPUT, @@ -157,7 +157,7 @@ export class TerraformContainers { resourceGroupName: cosmosdbDatabaseResource.resourceGroupName, accountName: cosmosdbDatabaseResource.name, databaseName: cosmosdbSqlDatabaseResource.name, - partitionKeyPath: `/${subscriptionsStoreAttributes.partitionKey}`, + partitionKeyPaths: [`/${subscriptionsStoreAttributes.partitionKey}`], partitionKeyVersion: 2, defaultTtl: -1, autoscaleSettings: { @@ -181,7 +181,7 @@ export class TerraformContainers { resourceGroupName: cosmosdbDatabaseResource.resourceGroupName, accountName: cosmosdbDatabaseResource.name, databaseName: cosmosdbSqlDatabaseResource.name, - partitionKeyPath: `/${connectionsStoreAttributes.partitionKey}`, + partitionKeyPaths: [`/${connectionsStoreAttributes.partitionKey}`], partitionKeyVersion: 2, defaultTtl: -1, autoscaleSettings: { @@ -207,7 +207,7 @@ export class TerraformContainers { resourceGroupName: cosmosdbDatabase.resourceGroupName, accountName: cosmosdbDatabase.name, databaseName: cosmosdbSqlDatabase.name, - partitionKeyPath: `/${dedupAttributes.partitionKey}`, + partitionKeyPaths: [`/${dedupAttributes.partitionKey}`], uniqueKey: [{ paths: [`/${dedupAttributes.partitionKey}`] }], partitionKeyVersion: 2, defaultTtl: -1, diff --git a/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-cosmosdb-database.ts b/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-cosmosdb-database.ts index f22ac7699b..14b8e92315 100644 --- a/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-cosmosdb-database.ts +++ b/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-cosmosdb-database.ts @@ -17,9 +17,9 @@ export class TerraformCosmosdbDatabase { resourceGroupName: resourceGroupName, offerType: 'Standard', kind: 'GlobalDocumentDB', - enableMultipleWriteLocations: false, + multipleWriteLocationsEnabled: false, isVirtualNetworkFilterEnabled: false, - enableAutomaticFailover: true, + automaticFailoverEnabled: true, geoLocation: [ { location: resourceGroup.location, diff --git a/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-function-app-settings.ts b/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-function-app-settings.ts new file mode 100644 index 0000000000..54907f4642 --- /dev/null +++ b/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-function-app-settings.ts @@ -0,0 +1,40 @@ +import { environmentVarNames } from '@boostercloud/framework-provider-azure' +import { ApplicationSynthStack } from '../types/application-synth-stack' +import { toTerraformName } from '../helper/utils' +import { BoosterConfig } from '@boostercloud/framework-types' +import { storageAccount } from '@cdktf/provider-azurerm' + +export class TerraformFunctionAppSettings { + static build( + { appPrefix, cosmosdbDatabase, domainNameLabel, eventHubNamespace, eventHub, webPubSub }: ApplicationSynthStack, + config: BoosterConfig, + storageAccount: storageAccount.StorageAccount, + suffixName: string + ): { [key: string]: string } { + if (!cosmosdbDatabase) { + throw new Error('Undefined cosmosdbDatabase resource') + } + const id = toTerraformName(appPrefix, suffixName) + const eventHubConnectionString = + eventHubNamespace?.defaultPrimaryConnectionString && eventHub?.name + ? `${eventHubNamespace.defaultPrimaryConnectionString};EntityPath=${eventHub.name}` + : '' + const region = (process.env['REGION'] ?? '').toLowerCase().replace(/ /g, '') + return { + WEBSITE_RUN_FROM_PACKAGE: '1', + WEBSITE_CONTENTSHARE: id, + ...config.env, + WebPubSubConnectionString: webPubSub?.primaryConnectionString || '', + BOOSTER_ENV: config.environmentName, + [environmentVarNames.restAPIURL]: `http://${domainNameLabel}.${region}.cloudapp.azure.com/${config.environmentName}`, + [environmentVarNames.eventHubConnectionString]: eventHubConnectionString, + [environmentVarNames.eventHubName]: config.resourceNames.streamTopic, + [environmentVarNames.eventHubMaxRetries]: + config.eventStreamConfiguration.parameters?.maxRetries?.toString() || '5', + [environmentVarNames.eventHubMode]: config.eventStreamConfiguration.parameters?.mode || 'exponential', + COSMOSDB_CONNECTION_STRING: `AccountEndpoint=https://${cosmosdbDatabase.name}.documents.azure.com:443/;AccountKey=${cosmosdbDatabase.primaryKey};`, + WEBSITE_CONTENTAZUREFILECONNECTIONSTRING: storageAccount.primaryConnectionString, // Terraform bug: https://github.com/hashicorp/terraform-provider-azurerm/issues/16650 + BOOSTER_APP_NAME: process.env['BOOSTER_APP_NAME'] ?? '', + } + } +} diff --git a/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-function-app.ts b/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-function-app.ts index 8e0628f996..13bc112a77 100644 --- a/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-function-app.ts +++ b/packages/framework-provider-azure-infrastructure/src/infrastructure/synth/terraform-function-app.ts @@ -1,8 +1,6 @@ import { servicePlan, storageAccount, windowsFunctionApp } from '@cdktf/provider-azurerm' import { toTerraformName } from '../helper/utils' -import { BoosterConfig } from '@boostercloud/framework-types' import { ApplicationSynthStack } from '../types/application-synth-stack' -import { environmentVarNames } from '@boostercloud/framework-provider-azure' import { WindowsFunctionAppConfig } from '@cdktf/provider-azurerm/lib/windows-function-app' export class TerraformFunctionApp { @@ -14,17 +12,13 @@ export class TerraformFunctionApp { resourceGroup, resourceGroupName, cosmosdbDatabase, - domainNameLabel, - eventHubNamespace, - eventHub, - webPubSub, }: ApplicationSynthStack, - config: BoosterConfig, applicationServicePlan: servicePlan.ServicePlan, storageAccount: storageAccount.StorageAccount, suffixName: string, functionAppName: string, - zipFile?: string + zipFile?: string, + appSettings?: { [key: string]: string } ): windowsFunctionApp.WindowsFunctionApp { if (!cosmosdbDatabase) { throw new Error('Undefined cosmosdbDatabase resource') @@ -33,32 +27,12 @@ export class TerraformFunctionApp { throw new Error('Undefined applicationServicePlan resource') } const id = toTerraformName(appPrefix, suffixName) - const eventHubConnectionString = - eventHubNamespace?.defaultPrimaryConnectionString && eventHub?.name - ? `${eventHubNamespace.defaultPrimaryConnectionString};EntityPath=${eventHub.name}` - : '' - const region = (process.env['REGION'] ?? '').toLowerCase().replace(/ /g, '') const functionConfig: Exclude = { name: functionAppName, location: resourceGroup.location, resourceGroupName: resourceGroupName, servicePlanId: applicationServicePlan.id, - appSettings: { - WEBSITE_RUN_FROM_PACKAGE: '1', - WEBSITE_CONTENTSHARE: id, - ...config.env, - WebPubSubConnectionString: webPubSub?.primaryConnectionString || '', - BOOSTER_ENV: config.environmentName, - [environmentVarNames.restAPIURL]: `http://${domainNameLabel}.${region}.cloudapp.azure.com/${config.environmentName}`, - [environmentVarNames.eventHubConnectionString]: eventHubConnectionString, - [environmentVarNames.eventHubName]: config.resourceNames.streamTopic, - [environmentVarNames.eventHubMaxRetries]: - config.eventStreamConfiguration.parameters?.maxRetries?.toString() || '5', - [environmentVarNames.eventHubMode]: config.eventStreamConfiguration.parameters?.mode || 'exponential', - COSMOSDB_CONNECTION_STRING: `AccountEndpoint=https://${cosmosdbDatabase.name}.documents.azure.com:443/;AccountKey=${cosmosdbDatabase.primaryKey};`, - WEBSITE_CONTENTAZUREFILECONNECTIONSTRING: storageAccount.primaryConnectionString, // Terraform bug: https://github.com/hashicorp/terraform-provider-azurerm/issues/16650 - BOOSTER_APP_NAME: process.env['BOOSTER_APP_NAME'] ?? '', - }, + appSettings: appSettings ?? {}, storageAccountName: storageAccount.name, storageAccountAccessKey: storageAccount.primaryAccessKey, dependsOn: [resourceGroup], diff --git a/packages/framework-provider-azure/package.json b/packages/framework-provider-azure/package.json index e6ac34dffa..62af3fba9d 100644 --- a/packages/framework-provider-azure/package.json +++ b/packages/framework-provider-azure/package.json @@ -1,6 +1,6 @@ { "name": "@boostercloud/framework-provider-azure", - "version": "2.12.1", + "version": "2.18.7", "description": "Handle Booster's integration with Azure", "keywords": [ "framework-provider-azure" @@ -27,14 +27,14 @@ "@azure/functions": "^1.2.2", "@azure/identity": "~2.1.0", "@azure/event-hubs": "5.11.1", - "@boostercloud/framework-common-helpers": "workspace:^2.12.1", - "@boostercloud/framework-types": "workspace:^2.12.1", + "@boostercloud/framework-common-helpers": "workspace:^2.18.7", + "@boostercloud/framework-types": "workspace:^2.18.7", "tslib": "^2.4.0", "@effect-ts/core": "^0.60.4", "@azure/web-pubsub": "~1.1.0" }, "devDependencies": { - "@boostercloud/eslint-config": "workspace:^2.12.1", + "@boostercloud/eslint-config": "workspace:^2.18.7", "@types/chai": "4.2.18", "@types/chai-as-promised": "7.1.4", "@types/faker": "5.1.5", diff --git a/packages/framework-provider-azure/src/constants.ts b/packages/framework-provider-azure/src/constants.ts index 8ef6c28caa..f3e6f5d0e2 100644 --- a/packages/framework-provider-azure/src/constants.ts +++ b/packages/framework-provider-azure/src/constants.ts @@ -32,6 +32,7 @@ export const environmentVarNames = { eventHubName: 'EVENTHUB_NAME', eventHubMaxRetries: 'EVENTHUB_MAX_RETRIES', eventHubMode: 'EVENTHUB_MODE', + rocketFunctionAppNames: 'ROCKET_FUNCTION_APP_NAMES', } as const // Azure special error codes diff --git a/packages/framework-provider-azure/src/helpers/query-helper.ts b/packages/framework-provider-azure/src/helpers/query-helper.ts index 987fda33fd..32e85a7789 100644 --- a/packages/framework-provider-azure/src/helpers/query-helper.ts +++ b/packages/framework-provider-azure/src/helpers/query-helper.ts @@ -1,4 +1,4 @@ -import { CosmosClient, SqlParameter, SqlQuerySpec } from '@azure/cosmos' +import { CosmosClient, ItemDefinition, SqlParameter, SqlQuerySpec } from '@azure/cosmos' import { BoosterConfig, FilterFor, @@ -10,6 +10,25 @@ import { } from '@boostercloud/framework-types' import { getLogger } from '@boostercloud/framework-common-helpers' +export async function replaceOrDeleteItem( + cosmosDb: CosmosClient, + container: string, + config: BoosterConfig, + id: string, + partitionKey: string, + newValue?: ItemDefinition +): Promise { + if (newValue) { + await cosmosDb + .database(config.resourceNames.applicationStack) + .container(container) + .item(id, partitionKey) + .replace(newValue) + } else { + await cosmosDb.database(config.resourceNames.applicationStack).container(container).item(id, partitionKey).delete() + } +} + export async function search( cosmosDb: CosmosClient, config: BoosterConfig, @@ -41,7 +60,7 @@ export async function search( parameters: buildExpressionAttributeValues(filters), } - logger.debug('Running search with the following params: \n', querySpec) + logger.debug('Running search with the following params: \n', JSON.stringify(querySpec)) let { resources } = await cosmosDb .database(config.resourceNames.applicationStack) .container(containerName) @@ -49,6 +68,13 @@ export async function search( .fetchAll() resources = nestProperties(resources) + resources = resources.map((resource) => ({ + ...resource, + boosterMetadata: { + ...resource.boosterMetadata, + optimisticConcurrencyValue: resource._etag, + }, + })) if (paginatedVersion) { return { @@ -224,6 +250,9 @@ function buildProjections(projections: ProjectionFor | string = '*'): s return projections } + // Preprocess the projections + const preprocessedProjections = preprocessProjections(projections) + // Helper function to convert dot notation to square-bracket notation const toSquareBracketsNotation = (path: string): string => { return path @@ -234,7 +263,7 @@ function buildProjections(projections: ProjectionFor | string = '*'): s // Group fields by the root property const groupedFields: { [key: string]: string[] } = {} - Object.values(projections).forEach((field: string) => { + Object.values(preprocessedProjections).forEach((field: string) => { const root: string = field.split('.')[0] if (!groupedFields[root]) { groupedFields[root] = [] @@ -295,6 +324,51 @@ function buildProjections(projections: ProjectionFor | string = '*'): s .join(', ') } +/** + * Preprocesses the projections to handle nested arrays and objects. + * + * @param {ProjectionFor} projections - The projections to preprocess. + * @returns {ProjectionFor} - The preprocessed projections. + */ +function preprocessProjections(projections: ProjectionFor): ProjectionFor { + const processed = new Set() + + Object.values(projections).forEach((field: string) => { + const parts = field.split('.') + const arrayIndices = parts.reduce((acc, part, index) => { + if (part.endsWith('[]')) acc.push(index) + return acc + }, [] as number[]) + + if ( + arrayIndices.length === 0 || + (arrayIndices[0] === 0 && arrayIndices.length === 1) || + (arrayIndices[0] === 1 && arrayIndices.length === 1) + ) { + // This block is accessed when one of the following occurs: + // - No arrays in the projection + // - Top-level array not followed by another array + // - Array nested within a top-level property, no arrays follow + processed.add(field) + } else { + // Cases with nested arrays or arrays deeper in the structure + const processToIndex = arrayIndices[0] === 0 || arrayIndices[0] === 1 ? arrayIndices[1] : arrayIndices[0] + const processedField = parts.slice(0, processToIndex + 1).join('.') + processed.add(processedField.slice(0, -2)) // Remove the '[]' from the last part + } + }) + + // Convert the Set back to the original type of projections + if (Array.isArray(projections)) { + return Array.from(processed) as ProjectionFor + } else { + return Array.from(processed).reduce((acc, field) => { + ;(acc as any)[field] = field + return acc + }, {} as ProjectionFor) + } +} + /** * Transforms the flat properties returned by Cosmos DB into a nested structure. For example, the following object: * diff --git a/packages/framework-provider-azure/src/index.ts b/packages/framework-provider-azure/src/index.ts index b40afbe107..cb7e653ad6 100644 --- a/packages/framework-provider-azure/src/index.ts +++ b/packages/framework-provider-azure/src/index.ts @@ -38,6 +38,7 @@ import { EventHubProducerClient, RetryMode } from '@azure/event-hubs' import { dedupEventStream, rawEventsStreamToEnvelopes } from './library/events-stream-consumer-adapter' import { areDatabaseReadModelsUp, + areRocketFunctionsUp, databaseEventsHealthDetails, databaseReadModelsHealthDetails, databaseUrl, @@ -46,6 +47,7 @@ import { isGraphQLFunctionUp, rawRequestToSensorHealth, } from './library/health-adapter' +import { deleteEvent, deleteSnapshot, findDeletableEvent, findDeletableSnapshot } from './library/event-delete-adapter' import { storeEvents } from './library/events-store-adapter' let cosmosClient: CosmosClient @@ -106,6 +108,10 @@ export const Provider = (rockets?: RocketDescriptor[]): ProviderLibrary => ({ search: searchEvents.bind(null, cosmosClient), searchEntitiesIDs: searchEntitiesIds.bind(null, cosmosClient), storeDispatched: storeDispatchedEvent.bind(null, cosmosClient), + findDeletableEvent: findDeletableEvent.bind(null, cosmosClient), + findDeletableSnapshot: findDeletableSnapshot.bind(null, cosmosClient), + deleteEvent: deleteEvent.bind(null, cosmosClient), + deleteSnapshot: deleteSnapshot.bind(null, cosmosClient), }, // ProviderReadModelsLibrary readModels: { @@ -151,6 +157,7 @@ export const Provider = (rockets?: RocketDescriptor[]): ProviderLibrary => ({ graphQLFunctionUrl: graphqlFunctionUrl, isGraphQLFunctionUp: isGraphQLFunctionUp, rawRequestToHealthEnvelope: rawRequestToSensorHealth, + areRocketFunctionsUp: areRocketFunctionsUp, }, // ProviderInfrastructureGetter infrastructure: () => { diff --git a/packages/framework-provider-azure/src/library/event-delete-adapter.ts b/packages/framework-provider-azure/src/library/event-delete-adapter.ts new file mode 100644 index 0000000000..31058c5f4c --- /dev/null +++ b/packages/framework-provider-azure/src/library/event-delete-adapter.ts @@ -0,0 +1,135 @@ +import { + BoosterConfig, + EventEnvelope, + EventDeleteParameters, + FilterFor, + SnapshotDeleteParameters, + UUID, + EventEnvelopeFromDatabase, + EntitySnapshotEnvelopeFromDatabase, +} from '@boostercloud/framework-types' +import { getLogger } from '@boostercloud/framework-common-helpers' +import { CosmosClient } from '@azure/cosmos' +import { replaceOrDeleteItem, search } from '../helpers/query-helper' + +export async function findDeletableEvent( + cosmosDb: CosmosClient, + config: BoosterConfig, + parameters: EventDeleteParameters +): Promise> { + const logger = getLogger(config, 'events-delete-adapter#findDeletableEvent') + const stringifyParameters = JSON.stringify(parameters) + logger.debug(`Initiating a deletable event search for ${stringifyParameters}`) + + const eventStore = config.resourceNames.eventsStore + const filter = buildDeleteEventFilter(parameters.entityTypeName, parameters.entityID, parameters.createdAt) + const result = (await search(cosmosDb, config, eventStore, filter)) as Array + logger.debug(`Finished deletable event search for ${stringifyParameters}`) + return result +} + +export async function findDeletableSnapshot( + cosmosDb: CosmosClient, + config: BoosterConfig, + parameters: SnapshotDeleteParameters +): Promise> { + const logger = getLogger(config, 'events-delete-adapter#findDeletableSnapshot') + const stringifyParameters = JSON.stringify(parameters) + logger.debug(`Initiating a deletable snapshot search for ${stringifyParameters}`) + + const eventStore = config.resourceNames.eventsStore + const filter = buildDeleteEntityFilter(parameters.entityTypeName, parameters.entityID, parameters.createdAt) + const result = (await search(cosmosDb, config, eventStore, filter)) as Array + logger.debug(`Finished deletable snapshot search for ${stringifyParameters}`) + return result +} + +export async function deleteEvent( + cosmosDb: CosmosClient, + config: BoosterConfig, + events: Array +): Promise { + const logger = getLogger(config, 'events-delete-adapter#deleteEvent') + const stringifyParameters = JSON.stringify(events) + logger.debug(`Initiating an event delete for ${stringifyParameters}`) + + const eventStore = config.resourceNames.eventsStore + if (!events || events.length === 0) { + logger.warn('Could not find events to delete') + return + } + for (const event of events) { + const newEvent = buildNewEvent(event) + const partitionKey = partitionKeyBuilder(event.entityTypeName, event.entityID, 'event') + await replaceOrDeleteItem(cosmosDb, eventStore, config, event.id, partitionKey, newEvent) + } + logger.debug(`Finished event delete for ${stringifyParameters}`) +} + +export async function deleteSnapshot( + cosmosDb: CosmosClient, + config: BoosterConfig, + snapshots: Array +): Promise { + const logger = getLogger(config, 'events-delete-adapter#deleteSnapshot') + const stringifyParameters = JSON.stringify(snapshots) + logger.debug(`Initiating a snapshot delete for ${stringifyParameters}`) + + const eventStore = config.resourceNames.eventsStore + if (!snapshots || snapshots.length === 0) { + logger.warn('Could not find snapshot to delete') + return + } + for (const snapshot of snapshots) { + const partitionKey = partitionKeyBuilder(snapshot.entityTypeName, snapshot.entityID, 'snapshot') + await replaceOrDeleteItem(cosmosDb, eventStore, config, snapshot.id, partitionKey) + } + logger.debug(`Finished snapshot delete for ${stringifyParameters}`) +} + +interface DeleteQueryFields { + createdAt: string + entityTypeName_entityID_kind: string + kind: string + deletedAt: string +} + +function buildNewEvent(existingEvent: EventEnvelopeFromDatabase): EventEnvelope { + return { + ...existingEvent, + deletedAt: new Date().toISOString(), + value: {}, + } +} + +function buildDeleteEventFilter( + entityTypeName: string, + entityId: UUID, + createdAt: string +): FilterFor { + const value = `${entityTypeName}-${entityId}-event` + return { + entityTypeName_entityID_kind: { eq: value }, + createdAt: { eq: createdAt }, + kind: { eq: 'event' }, + deletedAt: { isDefined: false }, + } +} + +function buildDeleteEntityFilter( + entityTypeName: string, + entityId: UUID, + createdAt: string +): FilterFor { + const value = `${entityTypeName}-${entityId}-snapshot` + return { + entityTypeName_entityID_kind: { eq: value }, + kind: { eq: 'snapshot' }, + createdAt: { eq: createdAt }, + deletedAt: { isDefined: false }, + } +} + +function partitionKeyBuilder(entityTypeName: string, entityID: UUID, kind: 'event' | 'snapshot'): string { + return `${entityTypeName}-${entityID}-${kind}` +} diff --git a/packages/framework-provider-azure/src/library/events-adapter.ts b/packages/framework-provider-azure/src/library/events-adapter.ts index 9ddf11886e..3ab740f564 100644 --- a/packages/framework-provider-azure/src/library/events-adapter.ts +++ b/packages/framework-provider-azure/src/library/events-adapter.ts @@ -24,11 +24,14 @@ export async function readEntityEventsSince( entityID: UUID, since?: string ): Promise> { + const logger = getLogger(config, 'events-adapter#readEntityEventsSince') const fromTime = since ? since : originOfTime const querySpec: SqlQuerySpec = { query: `SELECT * FROM c WHERE c["${eventsStoreAttributes.partitionKey}"] = @partitionKey ` + - `AND c["${eventsStoreAttributes.sortKey}"] > @fromTime ORDER BY c["${eventsStoreAttributes.sortKey}"] ASC`, + `AND c["${eventsStoreAttributes.sortKey}"] > @fromTime ` + + 'AND NOT IS_DEFINED(c["deletedAt"]) ' + + `ORDER BY c["${eventsStoreAttributes.sortKey}"] ASC`, parameters: [ { name: '@partitionKey', @@ -45,6 +48,7 @@ export async function readEntityEventsSince( .container(config.resourceNames.eventsStore) .items.query(querySpec) .fetchAll() + logger.debug(`Loaded events for entity ${entityTypeName} with ID ${entityID} with result:`, resources) return resources as Array } diff --git a/packages/framework-provider-azure/src/library/events-searcher-adapter.ts b/packages/framework-provider-azure/src/library/events-searcher-adapter.ts index 00f585ce3f..1d3872dabc 100644 --- a/packages/framework-provider-azure/src/library/events-searcher-adapter.ts +++ b/packages/framework-provider-azure/src/library/events-searcher-adapter.ts @@ -42,7 +42,11 @@ export async function searchEntitiesIds( afterCursor )}, entityTypeName: ${entityTypeName}` ) - const filterQuery = { kind: { eq: 'event' }, entityTypeName: { eq: entityTypeName } } + const filterQuery = { + kind: { eq: 'event' }, + entityTypeName: { eq: entityTypeName }, + deletedAt: { isDefined: false }, + } const eventStore = config.resourceNames.eventsStore const result = (await search( diff --git a/packages/framework-provider-azure/src/library/events-searcher-builder.ts b/packages/framework-provider-azure/src/library/events-searcher-builder.ts index 052e577734..3b38d0fcb3 100644 --- a/packages/framework-provider-azure/src/library/events-searcher-builder.ts +++ b/packages/framework-provider-azure/src/library/events-searcher-builder.ts @@ -57,6 +57,7 @@ export function resultToEventSearchResponse(result: any[]): Array { } } +export async function rocketFunctionAppUrl(functionAppName: string): Promise { + return `https://${functionAppName}.azurewebsites.net` +} + export async function isDatabaseEventUp(cosmosDb: CosmosClient, config: BoosterConfig): Promise { return await isContainerUp(cosmosDb, config, config.resourceNames.eventsStore) } @@ -71,6 +75,29 @@ export async function isGraphQLFunctionUp(): Promise { } } +export async function isRocketFunctionUp(rocketFunctionAppName: string): Promise { + try { + const functionAppUrl = await rocketFunctionAppUrl(rocketFunctionAppName) + const response = await request(functionAppUrl, 'GET') + return response.status === 200 + } catch (e) { + return false + } +} + +export async function areRocketFunctionsUp(): Promise<{ [key: string]: boolean }> { + const functionAppNames = + process.env[environmentVarNames.rocketFunctionAppNames]?.split(',').filter((str) => str.trim() !== '') || [] + const results = await Promise.all( + functionAppNames.map(async (functionAppName: string) => { + const isUp = await isRocketFunctionUp(functionAppName) + return { [functionAppName]: isUp } + }) + ) + + return results.reduce((acc, result) => ({ ...acc, ...result }), {}) +} + export function rawRequestToSensorHealthComponentPath(rawRequest: Context): string { const parameters = rawRequest.req?.url.replace(/^.*sensor\/health\/?/, '') return parameters ?? '' diff --git a/packages/framework-provider-azure/src/library/read-model-adapter.ts b/packages/framework-provider-azure/src/library/read-model-adapter.ts index 97f9d8bdcc..0a5f3d905f 100644 --- a/packages/framework-provider-azure/src/library/read-model-adapter.ts +++ b/packages/framework-provider-azure/src/library/read-model-adapter.ts @@ -137,13 +137,17 @@ export async function deleteReadModel( readModel: ReadModelInterface ): Promise { const logger = getLogger(config, 'read-model-adapter#deleteReadModel') - logger.debug(`[ReadModelAdapter#deleteReadModel] Entering to Read model deleted. ID = ${readModel.id}`) - await db - .database(config.resourceNames.applicationStack) - .container(config.resourceNames.forReadModel(readModelName)) - .item(readModel.id as string, readModel.id as string) - .delete() - logger.debug(`[ReadModelAdapter#deleteReadModel] Read model deleted. ID = ${readModel.id}`) + logger.debug(`Entering to Read model deleted. ${readModelName} ID = ${readModel.id}`) + try { + await db + .database(config.resourceNames.applicationStack) + .container(config.resourceNames.forReadModel(readModelName)) + .item(readModel.id as string, readModel.id as string) + .delete() + logger.debug(`Read model deleted. ${readModelName} ID = ${readModel.id}`) + } catch (e) { + logger.warn(`Read model to delete ${readModelName} ID = ${readModel.id} not found`) + } } export async function rawReadModelEventsToEnvelopes( diff --git a/packages/framework-provider-azure/test/helpers/query-helper.test.ts b/packages/framework-provider-azure/test/helpers/query-helper.test.ts index 57e1ce7618..723f358b93 100644 --- a/packages/framework-provider-azure/test/helpers/query-helper.test.ts +++ b/packages/framework-provider-azure/test/helpers/query-helper.test.ts @@ -169,6 +169,46 @@ describe('Query helper', () => { ) }) + it('Executes a SQL query with a projectionFor projection that has a deeply nested array of objects', async () => { + await search( + mockCosmosDbClient as any, + mockConfig, + mockReadModelName, + {}, + undefined, + undefined, + false, + undefined, + [ + 'id', + 'x.arr[].z', + 'foo.bar.items[].id', + 'foo.bar.baz.items[].id', + 'arr[].subArr[].id', + 'arr[].id', + ] as ProjectionFor + ) + + expect(mockCosmosDbClient.database).to.have.been.calledWithExactly(mockConfig.resourceNames.applicationStack) + expect( + mockCosmosDbClient.database(mockConfig.resourceNames.applicationStack).container + ).to.have.been.calledWithExactly(`${mockReadModelName}`) + expect( + mockCosmosDbClient.database(mockConfig.resourceNames.applicationStack).container(`${mockReadModelName}`).items + .query + ).to.have.been.calledWith( + match({ + query: + 'SELECT c["id"], ' + + 'ARRAY(SELECT item["z"] FROM item IN c["x"]["arr"]) AS "x.arr", ' + + 'c["foo"]["bar"]["items"] AS "foo.bar.items", c["foo"]["bar"]["baz"]["items"] AS "foo.bar.baz.items", ' + + 'ARRAY(SELECT item["subArr"], item["id"] FROM item IN c["arr"]) AS arr ' + + 'FROM c ', + parameters: [], + }) + ) + }) + it('Executes a SQL query with a star projection in the read model table', async () => { await search( mockCosmosDbClient as any, diff --git a/packages/framework-provider-azure/test/library/events-adapter.test.ts b/packages/framework-provider-azure/test/library/events-adapter.test.ts index e58b285c20..47019c1add 100644 --- a/packages/framework-provider-azure/test/library/events-adapter.test.ts +++ b/packages/framework-provider-azure/test/library/events-adapter.test.ts @@ -73,7 +73,7 @@ describe('Events adapter', () => { match({ query: `SELECT * FROM c WHERE c["${eventsStoreAttributes.partitionKey}"] = @partitionKey ` + - `AND c["${eventsStoreAttributes.sortKey}"] > @fromTime ORDER BY c["${eventsStoreAttributes.sortKey}"] ASC`, + `AND c["${eventsStoreAttributes.sortKey}"] > @fromTime AND NOT IS_DEFINED(c["deletedAt"]) ORDER BY c["${eventsStoreAttributes.sortKey}"] ASC`, parameters: [ { name: '@partitionKey', diff --git a/packages/framework-provider-azure/test/library/events-searcher-adapter.test.ts b/packages/framework-provider-azure/test/library/events-searcher-adapter.test.ts index 208028a1cd..933a2fe97b 100644 --- a/packages/framework-provider-azure/test/library/events-searcher-adapter.test.ts +++ b/packages/framework-provider-azure/test/library/events-searcher-adapter.test.ts @@ -205,7 +205,7 @@ describe('Events Searcher adapter', () => { mockCosmosDbClient, mockConfig, eventStoreName, - { kind: { eq: 'event' }, entityTypeName: { eq: 'entity' } }, + { kind: { eq: 'event' }, entityTypeName: { eq: 'entity' }, deletedAt: { isDefined: false } }, 1, { id: '1' }, true, @@ -225,7 +225,7 @@ describe('Events Searcher adapter', () => { mockCosmosDbClient, mockConfig, eventStoreName, - { kind: { eq: 'event' }, entityTypeName: { eq: 'entity' } }, + { kind: { eq: 'event' }, entityTypeName: { eq: 'entity' }, deletedAt: { isDefined: false } }, 1, undefined, true, diff --git a/packages/framework-provider-local-infrastructure/package.json b/packages/framework-provider-local-infrastructure/package.json index e528b0a19f..f8dd1d09f8 100644 --- a/packages/framework-provider-local-infrastructure/package.json +++ b/packages/framework-provider-local-infrastructure/package.json @@ -1,6 +1,6 @@ { "name": "@boostercloud/framework-provider-local-infrastructure", - "version": "2.12.1", + "version": "2.18.7", "description": "Handle the Booster running process of the local runtime", "keywords": [ "framework-provider-local-infrastructure" @@ -23,9 +23,9 @@ "node": ">=18.0.0 <19.0.0" }, "dependencies": { - "@boostercloud/framework-common-helpers": "workspace:^2.12.1", - "@boostercloud/framework-provider-local": "workspace:^2.12.1", - "@boostercloud/framework-types": "workspace:^2.12.1", + "@boostercloud/framework-common-helpers": "workspace:^2.18.7", + "@boostercloud/framework-provider-local": "workspace:^2.18.7", + "@boostercloud/framework-types": "workspace:^2.18.7", "cors": "2.8.5", "express": "^4.19.2", "node-schedule": "^2.1.0", @@ -46,7 +46,7 @@ "url": "https://github.com/boostercloud/booster/issues" }, "devDependencies": { - "@boostercloud/eslint-config": "workspace:^2.12.1", + "@boostercloud/eslint-config": "workspace:^2.18.7", "@types/chai": "4.2.18", "@types/chai-as-promised": "7.1.4", "@types/cors": "^2.8.12", diff --git a/packages/framework-provider-local/package.json b/packages/framework-provider-local/package.json index 0f2f8de8a2..a1dde80da4 100644 --- a/packages/framework-provider-local/package.json +++ b/packages/framework-provider-local/package.json @@ -1,6 +1,6 @@ { "name": "@boostercloud/framework-provider-local", - "version": "2.12.1", + "version": "2.18.7", "description": "Debug your Booster projects locally", "keywords": [ "framework-provider-local" @@ -23,12 +23,12 @@ "node": ">=18.0.0 <19.0.0" }, "dependencies": { - "@boostercloud/framework-common-helpers": "workspace:^2.12.1", - "@boostercloud/framework-types": "workspace:^2.12.1", + "@boostercloud/framework-common-helpers": "workspace:^2.18.7", + "@boostercloud/framework-types": "workspace:^2.18.7", "@seald-io/nedb": "4.0.2", "tslib": "^2.4.0", "@effect-ts/core": "^0.60.4", - "ws": "8.12.0" + "ws": "8.17.1" }, "scripts": { "format": "prettier --write --ext '.js,.ts' **/*.ts **/*/*.ts", @@ -44,7 +44,7 @@ "url": "https://github.com/boostercloud/booster/issues" }, "devDependencies": { - "@boostercloud/eslint-config": "workspace:^2.12.1", + "@boostercloud/eslint-config": "workspace:^2.18.7", "@types/chai": "4.2.18", "@types/chai-as-promised": "7.1.4", "@types/express": "^4.17.21", diff --git a/packages/framework-provider-local/src/index.ts b/packages/framework-provider-local/src/index.ts index eb1aec9a36..e7933d6f72 100644 --- a/packages/framework-provider-local/src/index.ts +++ b/packages/framework-provider-local/src/index.ts @@ -48,6 +48,7 @@ import { isGraphQLFunctionUp, rawRequestToSensorHealth, } from './library/health-adapter' +import { deleteEvent, deleteSnapshot, findDeletableEvent, findDeletableSnapshot } from './library/event-delete-adapter' import * as process from 'process' export * from './paths' @@ -82,6 +83,10 @@ export const Provider = (rocketDescriptors?: RocketDescriptor[]): ProviderLibrar search: searchEvents.bind(null, eventRegistry), searchEntitiesIDs: searchEntitiesIds.bind(null, eventRegistry), storeDispatched: storeDispatchedEvent, + findDeletableEvent: findDeletableEvent.bind(null, eventRegistry), + findDeletableSnapshot: findDeletableSnapshot.bind(null, eventRegistry), + deleteEvent: deleteEvent.bind(null, eventRegistry), + deleteSnapshot: deleteSnapshot.bind(null, eventRegistry), }, // ProviderReadModelsLibrary readModels: { @@ -127,6 +132,7 @@ export const Provider = (rocketDescriptors?: RocketDescriptor[]): ProviderLibrar isGraphQLFunctionUp: isGraphQLFunctionUp, graphQLFunctionUrl: graphqlFunctionUrl, rawRequestToHealthEnvelope: rawRequestToSensorHealth, + areRocketFunctionsUp: notImplemented as any, }, // ProviderInfrastructureGetter infrastructure: () => { diff --git a/packages/framework-provider-local/src/library/event-delete-adapter.ts b/packages/framework-provider-local/src/library/event-delete-adapter.ts new file mode 100644 index 0000000000..b6258304b7 --- /dev/null +++ b/packages/framework-provider-local/src/library/event-delete-adapter.ts @@ -0,0 +1,133 @@ +import { + BoosterConfig, + EventEnvelope, + EventDeleteParameters, + SnapshotDeleteParameters, + UUID, + EventEnvelopeFromDatabase, + EntitySnapshotEnvelopeFromDatabase, + EntitySnapshotEnvelope, +} from '@boostercloud/framework-types' +import { getLogger } from '@boostercloud/framework-common-helpers' +import { EventRegistry } from '../services' +import { QueryOperation, QueryValue } from './searcher-adapter' + +type DatabaseEventEnvelopeWithId = EventEnvelope & { _id: string } +type DatabaseEntitySnapshotEnvelopeWithId = EntitySnapshotEnvelope & { _id: string } + +export async function findDeletableEvent( + eventRegistry: EventRegistry, + config: BoosterConfig, + parameters: EventDeleteParameters +): Promise> { + const logger = getLogger(config, 'events-delete-adapter#findDeletableEvent') + const stringifyParameters = JSON.stringify(parameters) + logger.debug(`Initiating a deletable event search for ${stringifyParameters}`) + + const filter = buildDeleteEventFilter(parameters.entityTypeName, parameters.entityID, parameters.createdAt) + const events = (await eventRegistry.query(filter)) as Array + const result = events.map((event) => { + return { + ...event, + id: event._id, + } + }) as Array + logger.debug(`Finished deletable event search for ${stringifyParameters}`) + return result +} + +export async function findDeletableSnapshot( + eventRegistry: EventRegistry, + config: BoosterConfig, + parameters: SnapshotDeleteParameters +): Promise> { + const logger = getLogger(config, 'events-delete-adapter#findDeletableSnapshot') + const stringifyParameters = JSON.stringify(parameters) + logger.debug(`Initiating a deletable snapshot search for ${stringifyParameters}`) + + const filter = buildDeleteEntityFilter(parameters.entityTypeName, parameters.entityID, parameters.createdAt) + const snapshots = (await eventRegistry.query(filter)) as Array + const result: Array = snapshots.map((snapshot) => { + return { + ...snapshot, + id: snapshot._id, + } + }) + logger.debug(`Finished deletable snapshot search for ${stringifyParameters}`) + return result +} + +export async function deleteEvent( + eventRegistry: EventRegistry, + config: BoosterConfig, + events: Array +): Promise { + const logger = getLogger(config, 'events-delete-adapter#deleteEvent') + const stringifyParameters = JSON.stringify(events) + logger.debug(`Initiating an event delete for ${stringifyParameters}`) + + if (!events || events.length === 0) { + logger.warn('Could not find events to delete') + return + } + for (const event of events) { + const newEvent = buildNewEvent(event) + await eventRegistry.replaceOrDeleteItem(event.id, newEvent) + } + logger.debug(`Finished event delete for ${stringifyParameters}`) +} + +export async function deleteSnapshot( + eventRegistry: EventRegistry, + config: BoosterConfig, + snapshots: Array +): Promise { + const logger = getLogger(config, 'events-delete-adapter#deleteSnapshot') + const stringifyParameters = JSON.stringify(snapshots) + logger.debug(`Initiating a snapshot delete for ${stringifyParameters}`) + + if (!snapshots || snapshots.length === 0) { + logger.warn('Could not find snapshot to delete') + return + } + for (const snapshot of snapshots) { + await eventRegistry.replaceOrDeleteItem(snapshot.id) + } + logger.debug(`Finished snapshot delete for ${stringifyParameters}`) +} + +function buildNewEvent(existingEvent: EventEnvelopeFromDatabase): EventEnvelope { + return { + ...existingEvent, + deletedAt: new Date().toISOString(), + value: {}, + } +} + +function buildDeleteEventFilter( + entityTypeName: string, + entityId: UUID, + createdAt: string +): Record> { + return { + entityID: entityId.toString(), + entityTypeName: entityTypeName, + createdAt: createdAt, + kind: 'event', + deletedAt: { $exists: false }, + } +} + +function buildDeleteEntityFilter( + entityTypeName: string, + entityId: UUID, + createdAt: string +): Record> { + return { + entityTypeName: entityTypeName, + entityID: entityId.toString(), + kind: 'snapshot', + createdAt: createdAt, + deletedAt: { $exists: false }, + } +} diff --git a/packages/framework-provider-local/src/library/events-adapter.ts b/packages/framework-provider-local/src/library/events-adapter.ts index f722ab6db0..87fa1e0ecb 100644 --- a/packages/framework-provider-local/src/library/events-adapter.ts +++ b/packages/framework-provider-local/src/library/events-adapter.ts @@ -35,6 +35,7 @@ export async function readEntityEventsSince( createdAt: { $gt: fromTime, }, + deletedAt: { $exists: false }, } const result = await eventRegistry.query(query) diff --git a/packages/framework-provider-local/src/library/events-search-adapter.ts b/packages/framework-provider-local/src/library/events-search-adapter.ts index b704fab997..d77ac8e654 100644 --- a/packages/framework-provider-local/src/library/events-search-adapter.ts +++ b/packages/framework-provider-local/src/library/events-search-adapter.ts @@ -46,7 +46,11 @@ export async function searchEntitiesIds( afterCursor )}, entityTypeName: ${entityTypeName}` ) - const filterQuery = { ...DEFAULT_KIND_FILTER, entityTypeName: entityTypeName } + const filterQuery = { + ...DEFAULT_KIND_FILTER, + entityTypeName: entityTypeName, + deletedAt: { $exists: false }, + } const result = (await eventRegistry.query(filterQuery, DEFAULT_CREATED_AT_SORT_ORDER, undefined, { entityID: 1, diff --git a/packages/framework-provider-local/src/library/events-searcher-builder.ts b/packages/framework-provider-local/src/library/events-searcher-builder.ts index 206cfcf6fb..61f7a7038c 100644 --- a/packages/framework-provider-local/src/library/events-searcher-builder.ts +++ b/packages/framework-provider-local/src/library/events-searcher-builder.ts @@ -56,6 +56,7 @@ export function resultToEventSearchResponse(result: Array | null) user: item.currentUser, createdAt: item.createdAt, value: item.value, + deletedAt: item.deletedAt, } as EventSearchResponse }) return eventSearchResult ?? [] diff --git a/packages/framework-provider-local/src/library/read-model-adapter.ts b/packages/framework-provider-local/src/library/read-model-adapter.ts index 819a23d0f5..7dd32b8487 100644 --- a/packages/framework-provider-local/src/library/read-model-adapter.ts +++ b/packages/framework-provider-local/src/library/read-model-adapter.ts @@ -114,6 +114,10 @@ export async function deleteReadModel( ): Promise { const logger = getLogger(config, 'read-model-adapter#deleteReadModel') logger.debug(`Entering to Read model deleted. ID=${readModel.id}.Name=${readModelName}`) - await db.deleteById(readModel.id, readModelName) - logger.debug(`Read model deleted. ID=${readModel.id}. Name=${readModelName}`) + try { + await db.deleteById(readModel.id, readModelName) + logger.debug(`Read model deleted. ${readModelName} ID = ${readModel.id}`) + } catch (e) { + logger.warn(`Read model to delete ${readModelName} ID = ${readModel.id} not found`) + } } diff --git a/packages/framework-provider-local/src/library/searcher-adapter.ts b/packages/framework-provider-local/src/library/searcher-adapter.ts index 90828a02b4..05ac6e93d4 100644 --- a/packages/framework-provider-local/src/library/searcher-adapter.ts +++ b/packages/framework-provider-local/src/library/searcher-adapter.ts @@ -49,8 +49,8 @@ function filterToQuery(filter: FilterFor): QueryOperation { return query } -type QueryValue = number | string | boolean -type QueryOperation = +export type QueryValue = number | string | boolean +export type QueryOperation = // In the case that the operation is `eq`, NeDB matches directly | TValue // For these, the value must be single as a result diff --git a/packages/framework-provider-local/src/services/event-registry.ts b/packages/framework-provider-local/src/services/event-registry.ts index 0a3f9f3e9e..fd0284a000 100644 --- a/packages/framework-provider-local/src/services/event-registry.ts +++ b/packages/framework-provider-local/src/services/event-registry.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/ban-types */ import { EntitySnapshotEnvelope, EventEnvelope, EventStoreEntryEnvelope } from '@boostercloud/framework-types' import { eventsDatabase } from '../paths' + const DataStore = require('@seald-io/nedb') export class EventRegistry { @@ -37,6 +38,24 @@ export class EventRegistry { return await cursor.execAsync() } + public async replaceOrDeleteItem(id: string, newValue?: EventEnvelope | EntitySnapshotEnvelope): Promise { + if (newValue) { + await new Promise((resolve, reject) => + this.events.update({ _id: id }, newValue, { multi: true }, (err: any, numRemoved: number) => { + if (err) reject(err) + else resolve(numRemoved) + }) + ) + } else { + await new Promise((resolve, reject) => + this.events.remove({ _id: id }, { multi: true }, (err: any, numRemoved: number) => { + if (err) reject(err) + else resolve(numRemoved) + }) + ) + } + } + public async queryLatestSnapshot(query: object): Promise { await this.loadDatabaseIfNeeded() const cursor = this.events.findAsync({ ...query, kind: 'snapshot' }).sort({ snapshottedEventCreatedAt: -1 }) // Sort in descending order (newer timestamps first) diff --git a/packages/framework-provider-local/src/services/read-model-registry.ts b/packages/framework-provider-local/src/services/read-model-registry.ts index c2e578497d..68d9ff8dda 100644 --- a/packages/framework-provider-local/src/services/read-model-registry.ts +++ b/packages/framework-provider-local/src/services/read-model-registry.ts @@ -7,10 +7,6 @@ interface LocalSortedFor { [key: string]: number } -interface LocalSelectFor { - [key: string]: number -} - export type NedbError = Error & { [key: string | number | symbol]: unknown } export const UNIQUE_VIOLATED_ERROR_TYPE = 'uniqueViolated' @@ -39,7 +35,7 @@ export class ReadModelRegistry { select?: ProjectionFor ): Promise> { await this.loadDatabaseIfNeeded() - let cursor = this.readModels.find(query, this.toLocalSelectFor(select)) + let cursor = this.readModels.find(query) const sortByList = this.toLocalSortFor(sortBy) if (sortByList) { cursor = cursor.sort(sortByList) @@ -51,45 +47,15 @@ export class ReadModelRegistry { cursor = cursor.limit(limit) } - const arrayFields: { [key: string]: any } = {} - select?.forEach((field: string) => { - const parts = field.split('.') - let currentLevel = arrayFields - let isArrayField = false - for (let i = 0; i < parts.length; ++i) { - const part = parts[i] - if (part.endsWith('[]')) { - const arrayField = part.slice(0, -2) - if (!Object.prototype.hasOwnProperty.call(currentLevel, arrayField)) { - currentLevel[arrayField] = {} - } - currentLevel = currentLevel[arrayField] - isArrayField = true - } else { - if (i === parts.length - 1) { - if (isArrayField) { - if (!currentLevel['__fields']) { - currentLevel['__fields'] = [] - } - currentLevel['__fields'].push(part) - } - } else { - if (!Object.prototype.hasOwnProperty.call(currentLevel, part)) { - currentLevel[part] = {} - } - currentLevel = currentLevel[part] - } - } - } - }) - // Fetch results from the cursor const results = await cursor.execAsync() // Process each result to filter the array fields - results.forEach((result: any) => { - result.value = this.filterObjectByArrayFields(result.value, arrayFields) - }) + if (select && select.length > 0) { + results.forEach((result: any) => { + result.value = this.filterFields(result.value, select) + }) + } return results } @@ -139,7 +105,7 @@ export class ReadModelRegistry { toLocalSortFor( sortBy?: SortFor, parentKey = '', - sortedList: LocalSortedFor = {} + sortedList: LocalSortedFor = Object.create(null) ): undefined | LocalSortedFor { if (!sortBy || Object.keys(sortBy).length === 0) return const elements = sortBy! @@ -153,76 +119,59 @@ export class ReadModelRegistry { return sortedList } - toLocalSelectFor(select?: ProjectionFor): LocalSelectFor { - if (!select || select.length === 0) return {} + filterFields(obj: any, select: string[]): any { + const result: any = Object.create(null) - const result: LocalSelectFor = {} - const seenFields = new Set() - - select.forEach((field: string) => { + select.forEach((field) => { const parts = field.split('.') - const topLevelField = parts[0] - - if (topLevelField.endsWith('[]')) { - const arrayField = `value.${topLevelField.slice(0, -2)}` - if (!seenFields.has(arrayField)) { - seenFields.add(arrayField) - result[arrayField] = 1 - } - } else { - if (parts.some((part) => part.endsWith('[]'))) { - const arrayIndex = parts.findIndex((part) => part.endsWith('[]')) - const arrayField = `value.${parts - .slice(0, arrayIndex + 1) - .join('.') - .slice(0, -2)}` - if (!seenFields.has(arrayField)) { - seenFields.add(arrayField) - result[arrayField] = 1 - } - } else { - const fullPath = `value.${field}` - if (!seenFields.has(fullPath)) { - seenFields.add(fullPath) - result[fullPath] = 1 - } - } - } + this.setNestedValue(result, obj, parts) }) return result } - filterArrayFields(item: any, fields: { [key: string]: any; __fields?: string[] }): any { - const filteredItem: { [key: string]: any } = {} - if (fields.__fields) { - fields.__fields.forEach((field) => { - if (field in item) { - filteredItem[field] = item[field] - } - }) - } - Object.keys(fields).forEach((key) => { - if (key !== '__fields' && item[key] && Array.isArray(item[key])) { - filteredItem[key] = item[key].map((subItem: any) => this.filterArrayFields(subItem, fields[key])) - } - }) - return filteredItem - } + setNestedValue(result: any, source: any, parts: string[]): void { + let currentResult = result + let currentSource = source + + for (let i = 0; i < parts.length; i++) { + const part = parts[i] + const isLast = i === parts.length - 1 - filterObjectByArrayFields(obj: any, arrayFields: { [key: string]: any; __fields?: string[] }): any { - const filteredObj: { [key: string]: any } = {} - Object.keys(obj).forEach((key) => { - if (key in arrayFields) { - if (Array.isArray(obj[key])) { - filteredObj[key] = obj[key].map((item: any) => this.filterArrayFields(item, arrayFields[key])) + if (part.endsWith('[]')) { + const arrayField = part.slice(0, -2) + if (!Array.isArray(currentSource[arrayField])) { + return + } + if (!currentResult[arrayField]) { + currentResult[arrayField] = [] + } + if (isLast) { + currentResult[arrayField] = currentSource[arrayField] } else { - filteredObj[key] = this.filterObjectByArrayFields(obj[key], arrayFields[key]) + currentSource[arrayField].forEach((item: any, index: number) => { + if (!currentResult[arrayField][index]) { + currentResult[arrayField][index] = Object.create(null) + } + this.setNestedValue(currentResult[arrayField][index], item, parts.slice(i + 1)) + }) } } else { - filteredObj[key] = obj[key] + if (isLast) { + if (currentSource[part] !== undefined) { + currentResult[part] = currentSource[part] + } + } else { + if (!currentSource[part]) { + return + } + if (!currentResult[part]) { + currentResult[part] = Array.isArray(currentSource[part]) ? [] : Object.create(null) + } + currentResult = currentResult[part] + currentSource = currentSource[part] + } } - }) - return filteredObj + } } } diff --git a/packages/framework-provider-local/test/library/events-adapter.test.ts b/packages/framework-provider-local/test/library/events-adapter.test.ts index 029499e01f..e03dd0029d 100644 --- a/packages/framework-provider-local/test/library/events-adapter.test.ts +++ b/packages/framework-provider-local/test/library/events-adapter.test.ts @@ -123,6 +123,9 @@ describe('events-adapter', () => { kind: 'event', entityID: mockEntityID, entityTypeName: mockEntityTypeName, + deletedAt: { + $exists: false, + }, }) }) @@ -149,6 +152,9 @@ describe('events-adapter', () => { kind: 'event', entityID: mockEntityID, entityTypeName: mockEntityTypeName, + deletedAt: { + $exists: false, + }, }) }) diff --git a/packages/framework-provider-local/test/library/events-search-adapter.test.ts b/packages/framework-provider-local/test/library/events-search-adapter.test.ts index a34b8fb0fa..6f21b8befb 100644 --- a/packages/framework-provider-local/test/library/events-search-adapter.test.ts +++ b/packages/framework-provider-local/test/library/events-search-adapter.test.ts @@ -29,9 +29,14 @@ describe('The "searchEntitiesIDs" method', () => { const entityTypeName = 'entity' await searchEntitiesIds(mockEventRegistry as any, mockConfig, limit, afterCursor, entityTypeName) - expect(queryStub).to.have.been.calledWithExactly({ kind: 'event', entityTypeName: 'entity' }, -1, undefined, { - entityID: 1, - }) + expect(queryStub).to.have.been.calledWithExactly( + { kind: 'event', entityTypeName: 'entity', deletedAt: { $exists: false } }, + -1, + undefined, + { + entityID: 1, + } + ) }) it('Generate query for entityTypeName, limit has all fields', async () => { @@ -39,8 +44,13 @@ describe('The "searchEntitiesIDs" method', () => { const entityTypeName = 'entity' await searchEntitiesIds(mockEventRegistry as any, mockConfig, limit, undefined, entityTypeName) - expect(queryStub).to.have.been.calledWithExactly({ kind: 'event', entityTypeName: 'entity' }, -1, undefined, { - entityID: 1, - }) + expect(queryStub).to.have.been.calledWithExactly( + { kind: 'event', entityTypeName: 'entity', deletedAt: { $exists: false } }, + -1, + undefined, + { + entityID: 1, + } + ) }) }) diff --git a/packages/framework-provider-local/test/services/read-model-registry.test.ts b/packages/framework-provider-local/test/services/read-model-registry.test.ts index dbdadfda11..0c73e95003 100644 --- a/packages/framework-provider-local/test/services/read-model-registry.test.ts +++ b/packages/framework-provider-local/test/services/read-model-registry.test.ts @@ -225,6 +225,74 @@ describe('the read model registry', () => { } expect(result[0]).to.deep.include(expectedReadModel) }) + + it('should return only projected fields for complex read models', async () => { + const complexReadModel: ReadModelEnvelope = { + typeName: random.word(), + value: { + id: random.uuid(), + x: { + arr: [{ y: random.word(), z: random.number() }], + }, + foo: { + bar: { + items: [{ id: random.uuid(), name: random.word() }], + baz: { items: [{ id: random.uuid(), name: random.word() }] }, + }, + }, + arr: [ + { + id: random.uuid(), + subArr: [{ id: random.uuid(), name: random.word() }], + }, + ], + boosterMetadata: { + version: 1, + schemaVersion: 1, + }, + }, + } + + await readModelRegistry.store(complexReadModel, 1) + + const result = await readModelRegistry.query( + { + value: complexReadModel.value, + typeName: complexReadModel.typeName, + }, + undefined, + undefined, + undefined, + [ + 'id', + 'x.arr[].z', + 'foo.bar.items[].id', + 'foo.bar.baz.items[].id', + 'arr[].subArr[].id', + 'arr[].id', + ] as ProjectionFor + ) + + expect(result.length).to.be.equal(1) + const expectedReadModel = { + value: { + id: complexReadModel.value.id, + x: { + arr: complexReadModel.value.x.arr.map((item: any) => ({ z: item.z })), + }, + foo: { + bar: { + items: complexReadModel.value.foo.bar.items.map((item: any) => ({ id: item.id })), + baz: { items: complexReadModel.value.foo.bar.baz.items.map((item: any) => ({ id: item.id })) }, + }, + }, + arr: complexReadModel.value.arr.map((item: any) => { + return { id: item.id, subArr: item.subArr.map((subItem: any) => ({ id: subItem.id })) } + }), + }, + } + expect(result[0]).to.deep.include(expectedReadModel) + }) }) describe('delete by id', () => { diff --git a/packages/framework-types/package.json b/packages/framework-types/package.json index dbfdb09070..862f3dd56e 100644 --- a/packages/framework-types/package.json +++ b/packages/framework-types/package.json @@ -1,6 +1,6 @@ { "name": "@boostercloud/framework-types", - "version": "2.12.1", + "version": "2.18.7", "description": "Contains Booster types related to the information extracted from the user project", "keywords": [ "framework-types" @@ -51,11 +51,11 @@ "@effect/schema": "0.64.18", "@effect/typeclass": "0.23.17", "web-streams-polyfill": "~3.3.2", - "ws": "8.12.0" + "ws": "8.17.1" }, "devDependencies": { - "@boostercloud/eslint-config": "workspace:^2.12.1", - "@boostercloud/metadata-booster": "workspace:^2.12.1", + "@boostercloud/eslint-config": "workspace:^2.18.7", + "@boostercloud/metadata-booster": "workspace:^2.18.7", "@types/chai": "4.2.18", "@types/chai-as-promised": "7.1.4", "@types/mocha": "10.0.1", diff --git a/packages/framework-types/src/booster-app.ts b/packages/framework-types/src/booster-app.ts index 4cc9218ce1..b17fcaca41 100644 --- a/packages/framework-types/src/booster-app.ts +++ b/packages/framework-types/src/booster-app.ts @@ -8,6 +8,7 @@ import { EventSearchParameters, EventSearchResponse, PaginatedEntitiesIdsResult, + EventDeleteParameters, } from '.' /** @@ -27,5 +28,6 @@ export interface BoosterApp { limit: number, afterCursor: Record | undefined ): Promise + deleteEvent(parameters: EventDeleteParameters): Promise configuredEnvironments: Set } diff --git a/packages/framework-types/src/concepts/global-error-handler-metadata.ts b/packages/framework-types/src/concepts/global-error-handler-metadata.ts index 92bf1c3b15..876cf5e959 100644 --- a/packages/framework-types/src/concepts/global-error-handler-metadata.ts +++ b/packages/framework-types/src/concepts/global-error-handler-metadata.ts @@ -1,25 +1,55 @@ import { AnyClass } from '../typelevel' -import { CommandEnvelope, NonPersistedEntitySnapshotEnvelope, QueryEnvelope } from '../envelope' +import { + CommandEnvelope, + EntitySnapshotEnvelope, + EventEnvelope, + NonPersistedEntitySnapshotEnvelope, + QueryEnvelope, + ScheduledCommandEnvelope, +} from '../envelope' import { EventInterface } from './event' import { ReadModelInterface } from './read-model' import { EntityInterface } from './entity' +import { ReducerMetadata } from './reducer-metadata' +import { ScheduledCommandMetadata } from './scheduled-command' +import { CommandMetadata } from './command' +import { ProjectionMetadata } from './projection-metadata' +import { NotificationInterface } from './notification' export interface GlobalErrorHandlerInterface extends AnyClass { - onCommandHandlerError?(error: Error, command: CommandEnvelope): Promise + onCommandHandlerError?( + error: Error, + commandEnvelope: CommandEnvelope, + commandMetadata: CommandMetadata + ): Promise onQueryHandlerError?(error: Error, query: QueryEnvelope): Promise - onScheduledCommandHandlerError?(error: Error): Promise - onDispatchEventHandlerError?(error: Error, eventInstance: EventInterface): Promise + onScheduledCommandHandlerError?( + error: Error, + scheduledCommandEnvelope: ScheduledCommandEnvelope, + scheduledCommandMetadata: ScheduledCommandMetadata + ): Promise + onDispatchEventHandlerError?( + error: Error, + eventEnvelope: EventEnvelope | NotificationInterface, + eventHandlerMetadata: unknown, + eventInstance: EventInterface + ): Promise onReducerError?( error: Error, + eventEnvelope: EventEnvelope, + reducerMetadata: ReducerMetadata, eventInstance: EventInterface, snapshotInstance: EntityInterface | null - ): Promise + ): Promise onProjectionError?( error: Error, + entityEnvelope: EntitySnapshotEnvelope, + projectionMetadata: ProjectionMetadata, entity: EntityInterface, readModel: ReadModelInterface | undefined ): Promise onSnapshotPersistError?(error: Error, snapshot: NonPersistedEntitySnapshotEnvelope): Promise + onEventError?(error: Error, eventEnvelope: EventEnvelope): Promise onError?(error: Error | undefined): Promise } diff --git a/packages/framework-types/src/concepts/projection-metadata.ts b/packages/framework-types/src/concepts/projection-metadata.ts index 9a29439fed..5ce0b234ac 100644 --- a/packages/framework-types/src/concepts/projection-metadata.ts +++ b/packages/framework-types/src/concepts/projection-metadata.ts @@ -1,9 +1,16 @@ import { AnyClass } from '../typelevel' +import { ReadModelInterface } from './read-model' +import { EntityInterface } from './entity' +import { FilterFor } from '../searcher' -export interface ProjectionMetadata { +export type ReadModelJoinKeyFunction = ( + entity: TEntity +) => FilterFor | undefined + +export interface ProjectionMetadata { class: AnyClass methodName: string - joinKey: keyof TEntity + joinKey: keyof TEntity | ReadModelJoinKeyFunction } export type ProjectionResult = TReadModel | ReadModelAction diff --git a/packages/framework-types/src/concepts/read-model.ts b/packages/framework-types/src/concepts/read-model.ts index e4b96f08ea..3ee2e09774 100644 --- a/packages/framework-types/src/concepts/read-model.ts +++ b/packages/framework-types/src/concepts/read-model.ts @@ -28,3 +28,12 @@ export interface ReadModelMetadata['before']> } + +export enum ProjectionInfoReason { + ENTITY_PROJECTED, + ENTITY_DELETED, +} + +export interface ProjectionInfo { + reason: ProjectionInfoReason +} diff --git a/packages/framework-types/src/config.ts b/packages/framework-types/src/config.ts index 90fd762c7c..bc4bd8c72c 100644 --- a/packages/framework-types/src/config.ts +++ b/packages/framework-types/src/config.ts @@ -10,6 +10,7 @@ import { NotificationMetadata, ProjectionMetadata, QueryMetadata, + ReadModelInterface, ReadModelMetadata, ReducerMetadata, RoleMetadata, @@ -83,7 +84,8 @@ export class BoosterConfig { public readonly queryHandlers: Record = {} public readonly eventHandlers: Record> = {} public readonly readModels: Record = {} - public readonly projections: Record>> = {} + public readonly projections: Record>> = {} + public readonly unProjections: Record>> = {} public readonly readModelSequenceKeys: Record = {} public readonly roles: Record = {} public readonly schemaMigrations: Record> = {} diff --git a/packages/framework-types/src/envelope.ts b/packages/framework-types/src/envelope.ts index 348fdf772f..1130886509 100644 --- a/packages/framework-types/src/envelope.ts +++ b/packages/framework-types/src/envelope.ts @@ -58,6 +58,7 @@ export interface NonPersistedEventEnvelope extends EventStoreEntryEnvelope { export interface EventEnvelope extends NonPersistedEventEnvelope { id?: string createdAt: string + deletedAt?: string } export interface NonPersistedEntitySnapshotEnvelope extends EventStoreEntryEnvelope { @@ -104,6 +105,7 @@ export interface EventSearchResponse { user?: UserEnvelope createdAt: string value: EventInterface | NotificationInterface + deletedAt?: string } export interface ReadModelEnvelope { @@ -214,3 +216,16 @@ export interface ContextEnvelope { /** Provider-dependent raw request context object */ rawContext: unknown } + +export type EventEnvelopeFromDatabase = EventEnvelope & { id: string } +export type EntitySnapshotEnvelopeFromDatabase = EntitySnapshotEnvelope & { id: string } +export interface EventDeleteParameters { + entityTypeName: string + entityID: string + createdAt: string +} +export interface SnapshotDeleteParameters { + entityID: UUID + entityTypeName: string + createdAt: string +} diff --git a/packages/framework-types/src/errors.ts b/packages/framework-types/src/errors.ts index dbb81b1f32..e9f556924c 100644 --- a/packages/framework-types/src/errors.ts +++ b/packages/framework-types/src/errors.ts @@ -1,3 +1,5 @@ +import { EntityInterface, EventInterface } from './concepts' + export class BoosterError extends Error { readonly code: string constructor(message: string, code?: string, readonly data?: Record) { @@ -15,6 +17,18 @@ export class NotFoundError extends BoosterError {} export class InvalidVersionError extends BoosterError {} export class OptimisticConcurrencyUnexpectedVersionError extends BoosterError {} +export class InvalidEventError extends BoosterError {} +export class InvalidReducerError extends BoosterError { + readonly eventInstance: EventInterface + readonly snapshotInstance: EntityInterface | null + + constructor(message: string, eventInstance: EventInterface, snapshotInstance: EntityInterface | null) { + super(message) + this.eventInstance = eventInstance + this.snapshotInstance = snapshotInstance + } +} + export function httpStatusCodeFor(error: Error): number { const errorToHTTPCode: Record = { [InvalidParameterError.name]: 400, diff --git a/packages/framework-types/src/errors/command-handler-global-error.ts b/packages/framework-types/src/errors/command-handler-global-error.ts index a95ca7000d..04c148ff53 100644 --- a/packages/framework-types/src/errors/command-handler-global-error.ts +++ b/packages/framework-types/src/errors/command-handler-global-error.ts @@ -1,8 +1,13 @@ import { GlobalErrorContainer } from './global-error-container' import { CommandEnvelope } from '../envelope' +import { CommandMetadata } from '../concepts' export class CommandHandlerGlobalError extends GlobalErrorContainer { - constructor(readonly command: CommandEnvelope, originalError: Error) { + constructor( + readonly commandEnvelope: CommandEnvelope, + readonly commandMetadata: CommandMetadata, + originalError: Error + ) { super(originalError) } } diff --git a/packages/framework-types/src/errors/event-global-error.ts b/packages/framework-types/src/errors/event-global-error.ts new file mode 100644 index 0000000000..d5f461ee18 --- /dev/null +++ b/packages/framework-types/src/errors/event-global-error.ts @@ -0,0 +1,8 @@ +import { GlobalErrorContainer } from './global-error-container' +import { EventEnvelope } from '../envelope' + +export class EventGlobalError extends GlobalErrorContainer { + constructor(readonly eventEnvelope: EventEnvelope, originalError: Error) { + super(originalError) + } +} diff --git a/packages/framework-types/src/errors/event-handler-global-error.ts b/packages/framework-types/src/errors/event-handler-global-error.ts index 5f413cec47..4d20839bff 100644 --- a/packages/framework-types/src/errors/event-handler-global-error.ts +++ b/packages/framework-types/src/errors/event-handler-global-error.ts @@ -1,8 +1,14 @@ import { GlobalErrorContainer } from './global-error-container' -import { EventInterface } from '../concepts' +import { EventInterface, NotificationInterface } from '../concepts' +import { EventEnvelope } from '../envelope' export class EventHandlerGlobalError extends GlobalErrorContainer { - constructor(readonly eventInstance: EventInterface, originalError: Error) { + constructor( + readonly eventEnvelope: EventEnvelope | NotificationInterface, + readonly eventInstance: EventInterface, + readonly eventHandlerMetadata: unknown, + originalError: Error + ) { super(originalError) } } diff --git a/packages/framework-types/src/errors/index.ts b/packages/framework-types/src/errors/index.ts index 6dd96c6f7d..e9e67735fb 100644 --- a/packages/framework-types/src/errors/index.ts +++ b/packages/framework-types/src/errors/index.ts @@ -3,7 +3,7 @@ export * from './query-handler-global-error' export * from './event-handler-global-error' export * from './global-error-container' export * from './projection-global-error' -export * from './read-model-global-error' export * from './reducer-global-error' export * from './schedule-command-global-error' export * from './snapshot-persist-handler-global-error' +export * from './event-global-error' diff --git a/packages/framework-types/src/errors/projection-global-error.ts b/packages/framework-types/src/errors/projection-global-error.ts index 16e56735dd..3da2874445 100644 --- a/packages/framework-types/src/errors/projection-global-error.ts +++ b/packages/framework-types/src/errors/projection-global-error.ts @@ -1,10 +1,13 @@ import { GlobalErrorContainer } from './global-error-container' -import { EntityInterface, ReadModelInterface } from '../concepts' +import { EntityInterface, ProjectionMetadata, ReadModelInterface } from '../concepts' +import { EntitySnapshotEnvelope } from '../envelope' export class ProjectionGlobalError extends GlobalErrorContainer { constructor( + readonly entityEnvelope: EntitySnapshotEnvelope, readonly entity: EntityInterface, readonly readModel: ReadModelInterface | undefined, + readonly projectionMetadata: ProjectionMetadata, originalError: Error ) { super(originalError) diff --git a/packages/framework-types/src/errors/read-model-global-error.ts b/packages/framework-types/src/errors/read-model-global-error.ts deleted file mode 100644 index 24175f1d6e..0000000000 --- a/packages/framework-types/src/errors/read-model-global-error.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { GlobalErrorContainer } from './global-error-container' - -export class ReadModelGlobalError extends GlobalErrorContainer {} diff --git a/packages/framework-types/src/errors/reducer-global-error.ts b/packages/framework-types/src/errors/reducer-global-error.ts index 49f109ed53..7aed1ac05b 100644 --- a/packages/framework-types/src/errors/reducer-global-error.ts +++ b/packages/framework-types/src/errors/reducer-global-error.ts @@ -1,10 +1,13 @@ import { GlobalErrorContainer } from './global-error-container' -import { EntityInterface, EventInterface } from '../concepts' +import { EntityInterface, EventInterface, ReducerMetadata } from '../concepts' +import { EventEnvelope } from '../envelope' export class ReducerGlobalError extends GlobalErrorContainer { constructor( + readonly eventEnvelope: EventEnvelope, readonly eventInstance: EventInterface, readonly snapshotInstance: EntityInterface | null, + readonly reducerMetadata: ReducerMetadata, originalError: Error ) { super(originalError) diff --git a/packages/framework-types/src/errors/schedule-command-global-error.ts b/packages/framework-types/src/errors/schedule-command-global-error.ts index db900b0171..0c996e9cff 100644 --- a/packages/framework-types/src/errors/schedule-command-global-error.ts +++ b/packages/framework-types/src/errors/schedule-command-global-error.ts @@ -1,3 +1,13 @@ import { GlobalErrorContainer } from './global-error-container' +import { ScheduledCommandMetadata } from '../concepts' +import { ScheduledCommandEnvelope } from '../envelope' -export class ScheduleCommandGlobalError extends GlobalErrorContainer {} +export class ScheduleCommandGlobalError extends GlobalErrorContainer { + constructor( + readonly scheduleCommandEnvelope: ScheduledCommandEnvelope, + readonly scheduleCommandMetadata: ScheduledCommandMetadata, + originalError: Error + ) { + super(originalError) + } +} diff --git a/packages/framework-types/src/provider.ts b/packages/framework-types/src/provider.ts index 24dd618160..c5a96525b8 100644 --- a/packages/framework-types/src/provider.ts +++ b/packages/framework-types/src/provider.ts @@ -3,7 +3,10 @@ import { BoosterConfig } from './config' import { ConnectionDataEnvelope, EntitySnapshotEnvelope, + EntitySnapshotEnvelopeFromDatabase, + EventDeleteParameters, EventEnvelope, + EventEnvelopeFromDatabase, EventSearchParameters, EventSearchResponse, GraphQLRequestEnvelope, @@ -15,6 +18,7 @@ import { ReadModelEnvelope, ReadModelListResult, ScheduledCommandEnvelope, + SnapshotDeleteParameters, SubscriptionEnvelope, } from './envelope' import { FilterFor, ProjectionFor, SortFor } from './searcher' @@ -47,6 +51,7 @@ export interface ProviderSensorLibrary { isGraphQLFunctionUp(config: BoosterConfig): Promise graphQLFunctionUrl(config: BoosterConfig): Promise rawRequestToHealthEnvelope(rawRequest: unknown): HealthEnvelope + areRocketFunctionsUp(config: BoosterConfig): Promise<{ [key: string]: boolean }> } export interface ProviderEventsLibrary { @@ -154,6 +159,44 @@ export interface ProviderEventsLibrary { * table, throws an error on any other type of error. */ storeDispatched(eventEnvelope: EventEnvelope, config: BoosterConfig): Promise + + /** + * Find all events to be removed based on the parameters + * + * @param config + * @param parameters + */ + findDeletableEvent( + config: BoosterConfig, + parameters: EventDeleteParameters + ): Promise> + + /** + * Find all snapshots to be removed based on the parameters + * + * @param config + * @param parameters + */ + findDeletableSnapshot( + config: BoosterConfig, + parameters: SnapshotDeleteParameters + ): Promise> + + /** + * Delete events + * + * @param config + * @param events + */ + deleteEvent(config: BoosterConfig, events: Array): Promise + + /** + * Delete snapshots + * + * @param config + * @param snapshots + */ + deleteSnapshot(config: BoosterConfig, snapshots: Array): Promise } export interface ProviderReadModelsLibrary { diff --git a/packages/framework-types/src/sensor/health-indicator-configuration.ts b/packages/framework-types/src/sensor/health-indicator-configuration.ts index 3556a8aa02..351753cb71 100644 --- a/packages/framework-types/src/sensor/health-indicator-configuration.ts +++ b/packages/framework-types/src/sensor/health-indicator-configuration.ts @@ -4,6 +4,7 @@ import { Class } from '../typelevel' export enum HealthStatus { UP = 'UP', // The component or subsystem is working as expected + PARTIALLY_UP = 'PARTIALLY_UP', // The component is partially working or has reduced functionality DOWN = 'DOWN', // The component is not working OUT_OF_SERVICE = 'OUT_OF_SERVICE', // The component is out of service temporarily UNKNOWN = 'UNKNOWN', // The component state is unknown @@ -28,6 +29,7 @@ export enum BOOSTER_HEALTH_INDICATORS_IDS { DATABASE = 'booster/database', DATABASE_EVENTS = 'booster/database/events', DATABASE_READ_MODELS = 'booster/database/readmodels', + ROCKETS = 'rockets', } export const DEFAULT_HEALTH_CONFIGURATION_BOOSTER: SensorBoosterHealthConfigurationDetails = { @@ -45,6 +47,7 @@ export const DEFAULT_SENSOR_HEALTH_BOOSTER_CONFIGURATIONS: Record< [BOOSTER_HEALTH_INDICATORS_IDS.DATABASE]: { ...DEFAULT_HEALTH_CONFIGURATION_BOOSTER }, [BOOSTER_HEALTH_INDICATORS_IDS.DATABASE_EVENTS]: { ...DEFAULT_HEALTH_CONFIGURATION_BOOSTER }, [BOOSTER_HEALTH_INDICATORS_IDS.DATABASE_READ_MODELS]: { ...DEFAULT_HEALTH_CONFIGURATION_BOOSTER }, + [BOOSTER_HEALTH_INDICATORS_IDS.ROCKETS]: { ...DEFAULT_HEALTH_CONFIGURATION_BOOSTER }, } export type SensorBoosterHealthConfigurationDetails = HealthIndicatorConfigurationBase @@ -57,6 +60,7 @@ export interface SensorBoosterHealthConfiguration { [BOOSTER_HEALTH_INDICATORS_IDS.DATABASE]: SensorBoosterHealthConfigurationDetails [BOOSTER_HEALTH_INDICATORS_IDS.DATABASE_EVENTS]: SensorBoosterHealthConfigurationDetails [BOOSTER_HEALTH_INDICATORS_IDS.DATABASE_READ_MODELS]: SensorBoosterHealthConfigurationDetails + [BOOSTER_HEALTH_INDICATORS_IDS.ROCKETS]: SensorBoosterHealthConfigurationDetails } } diff --git a/packages/metadata-booster/package.json b/packages/metadata-booster/package.json index 06c80fb7ba..7fd4bab48d 100644 --- a/packages/metadata-booster/package.json +++ b/packages/metadata-booster/package.json @@ -1,6 +1,6 @@ { "name": "@boostercloud/metadata-booster", - "version": "2.12.1", + "version": "2.18.7", "description": "Emits detailed metadata of your types. You can then get it in runtime to deal with schema-aware operation, like defining GraphQL schemas, ORM operations, etc.", "repository": "https://github.com/boostercloud/booster.git", "keywords": [ @@ -38,7 +38,7 @@ "eslint-config-prettier": "8.3.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-prettier": "3.4.0", - "@boostercloud/eslint-config": "workspace:^2.12.1", + "@boostercloud/eslint-config": "workspace:^2.18.7", "@types/node": "^18.18.2", "ts-node": "^10.9.1", "ts-patch": "3.1.2", diff --git a/packages/metadata-booster/src/metadata-types.ts b/packages/metadata-booster/src/metadata-types.ts index 24e9c3d60a..131137256b 100644 --- a/packages/metadata-booster/src/metadata-types.ts +++ b/packages/metadata-booster/src/metadata-types.ts @@ -31,6 +31,7 @@ export interface TypeMetadata { export interface PropertyMetadata { name: string typeInfo: TypeMetadata + dependencies: Array } export interface ClassMetadata { diff --git a/tools/eslint-config/package.json b/tools/eslint-config/package.json index 06f4220318..89e10ae157 100644 --- a/tools/eslint-config/package.json +++ b/tools/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@boostercloud/eslint-config", - "version": "2.12.1", + "version": "2.18.7", "description": "Shared eslint rules", "main": "index.js", "publishConfig": { diff --git a/website/docs/03_architecture/06_read-model.mdx b/website/docs/03_architecture/06_read-model.mdx index afdbb919b7..e315359e5c 100644 --- a/website/docs/03_architecture/06_read-model.mdx +++ b/website/docs/03_architecture/06_read-model.mdx @@ -101,6 +101,77 @@ You can even select arrays of UUIDs as `joinKey`. Booster get each value on the } ``` +#### ReadModel queries + +You can use a read model query as a join key to get all the read models that match the query. For example, consider the following read model for car purchases: + +```typescript +@ReadModel +export class CarPurchasesReadModel { + public constructor( + readonly id: UUID, + readonly carModel?: string, + readonly carOwner?: string, + readonly offers?: Array + ) {} + + // rest of the code +} +``` + +If a car model changed its name (or any other property of such an entity that's projected in `CarPurchasesReadModel` changed its value) and there are many purchases associated to that model, then it would be necessary to update all read model instances associated to that specific model so that name change is reflected. The better alternative is to instead project a `CarModel` entity: + +```typescript +@ReadModel +export class CarPurchasesReadModel { + public constructor( + readonly id: UUID, + readonly carModel?: CarModel, + readonly carOwner?: CarOwner, + readonly offers?: Array + ) {} + + @Projects(CarModel, (carModel: CarModel): FilterFor => { + return { + carModel: { + id: { + eq: carModel.id, + }, + }, + } + }) + public static projectWithModel( + model: CarModel, + readModelId: UUID | undefined, + oldCarPurchaseReadModel?: CarPurchasesReadModel + ): ProjectionResult { + if (!readModelId) { + return ReadModelAction.Nothing + } + return new CarPurchasesReadModel( + readModelId, + model, + oldCarPurchaseReadModel?.carOwner, + oldCarPurchaseReadModel?.offers + ) + } +} +``` + +Since the `CarModel` entity doesn't have a field that matches the `id` field of `CarPurchasesReadModel`, this projection can use a read model query join key to get all the `CarPurchasesReadModel` instances for a given `CarModel`. + +In this case, the `projectWithModel` function will be called for each `CarPurchasesReadModel` instance that matches the query. The `readModelId` argument will be the `id` of the `CarPurchasesReadModel` instance. + +With this approach, every time there's a change in the `CarModel` entity it will be reflected in the read model without the need to manually update all read model instances. + +:::note +If no read model matches the query, the `projectWithModel` function will be called with `readModelId` set to `undefined`. +::: + +:::note +Take a look at the [Getting, filtering and projecting read models data at code level](/graphql#getting-filtering-and-projecting-read-models-data-at-code-level) section for more information on how to filter read models. +::: + ### Returning special values Projections usually return a new instance of the read model. However, there are some special cases where you may want to return a different value. @@ -151,7 +222,11 @@ Keeping the read model untouched higly recommended in favour of returning a new ## Nested queries and calculated values using getters -You can use TypeScript getters in your read models to allow nested queries and/or return calculated values. You can write arbitrary code in a getter, but you will tipically query for related read model objects or generate a value computed based on the current read model instance or context. This greatly improves the potential of customizing your read model responses. +You can use TypeScript getters in your read models to allow nested queries and/or return calculated values. You can write arbitrary code in a getter, but you will typically query for related read model objects or generate a value computed based on the current read model instance or context. This greatly improves the potential of customizing your read model responses. + +:::info +Starting version 2.13, getters for values which are calculated using other properties of the read model need to be annotated with the `@CalculatedField` decorator and a list of those properties as dependencies. +::: Here's an example of a getter in the `UserReadModel` class that returns all `PostReadModel`s that belong to a specific `UserReadModel`: @@ -160,6 +235,7 @@ Here's an example of a getter in the `UserReadModel` class that returns all `Pos export class UserReadModel { public constructor(readonly id: UUID, readonly name: string, private postIds: UUID[]) {} + @CalculatedField({ dependsOn: ['postIds'] }) public get posts(): Promise { return this.postIds.map((postId) => Booster.readModel(PostReadModel) .filter({ diff --git a/website/docs/03_architecture/08_queries.mdx b/website/docs/03_architecture/08_queries.mdx index 779f74979c..4f7f6a9a02 100644 --- a/website/docs/03_architecture/08_queries.mdx +++ b/website/docs/03_architecture/08_queries.mdx @@ -122,4 +122,77 @@ You will get the following GraphQL query and subscriptions: query CartTotalQuantityQuery($cartId: ID!): Float! ``` -> [!NOTE] Query subscriptions are not supported yet +:::note +Query subscriptions are not supported yet +::: + +### Returning union types +Booster supports returning graphql union types. For example, this `SearchMedia` query returning books and movies. + + +```typescript +export type MediaValue = BookReadModel | MovieReadModel + +class SearchResult { + readonly results!: MediaValue[] + constructor(results: MediaValue[]) { + this.results = results + } +} + +@Query({ + authorize: 'all', +}) +export class SearchMedia { + public constructor(readonly searchword: string) {} + + public static async handle(query: SearchMedia, queryInfo: QueryInfo): Promise { + const [books, movies] = await Promise.all([ + Booster.readModel(BookReadModel) + .filter({ + title: { + contains: query.searchword, + }, + }) + .search(), + Booster.readModel(MovieReadModel) + .filter({ + title: { + contains: query.searchword, + }, + }) + .search(), + ]) + const response = [...books, ...movies] + + return { + results: response, + } + } +} +``` + +This generates the following query + +```graphql +SearchMedia ( input SearchMediaInput! ) SearchResult! +``` + +The GraphQL union querying functionality can then be used. An example for the query above could be the following. + +```graphql +{ + SearchMedia(input: { searchword: "Oppenheimer" }) { + results { + __typename + ... on BookReadModel { + title + pages + } + ... on MovieReadModel { + title + } + } + } +} +``` \ No newline at end of file diff --git a/website/docs/03_features/05_error-handling.md b/website/docs/03_features/05_error-handling.md index 0480e99739..0899b07c1b 100644 --- a/website/docs/03_features/05_error-handling.md +++ b/website/docs/03_features/05_error-handling.md @@ -2,13 +2,13 @@ ## Error handling in Booster -Booster provides a default error handling mechanism that will try to catch all the errors that are thrown in the application and will log them. This is useful for debugging purposes, but you may want to customize the error handling in your application. For example, you may want to send an email to the administrator when an error occurs. +Booster provides a default error handling mechanism that will try to catch all the errors that are thrown in the application and will log them. This is useful for debugging purposes, but you may want to customize the error handling in your application. For example, you may want to email the administrator when an error occurs. ### Custom error handling To customize the error handling, you need to create a class decorated with the `@GlobalErrorHandler` decorator. This class will contain the methods that will be called when an error is thrown. There is one method for each component in the application where an error can be thrown. All these functions receive the error that was thrown and the information about the component that was being executed when the error occurred. -They must return a promise that resolves to an `Error` object or `undefined`. If the promise resolves to `undefined`, the error will be ignored and the application will continue working. If the promise resolves to an `Error` object, the error will be thrown. +They must return a promise that resolves to an `Error` object or `undefined`. If the promise resolves to `undefined`, the error will be ignored and **Booster** will continue working. If the promise resolves to an `Error` object, the error will be thrown and **Booster** will handle it on a case-by-case basis in the default way. ### Command handle errors @@ -17,13 +17,17 @@ These are the errors that are thrown in the `handle` method of the `@Command`. Y ```typescript @GlobalErrorHandler() export class MyErrorHandler { - public onCommandHandlerError(error: Error, command: CommandEnvelope): Promise { + public static async onCommandHandlerError( + error: Error, + commandEnvelope: CommandEnvelope, + commandMetadata: CommandMetadata + ): Promise { // Do something with the error } } ``` -Tis method receives the error that was thrown and the command that was being handled when the error occurred. +This method receives the error that was thrown and the command that was being handled when the error occurred. ### Scheduled command handle errors @@ -32,13 +36,17 @@ These are the errors that are thrown in the `handle` method of the `@ScheduledCo ```typescript @GlobalErrorHandler() export class MyErrorHandler { - public onScheduledCommandHandlerError(error: Error): Promise { + public static async onScheduledCommandHandlerError( + error: Error, + scheduledCommandEnvelope: ScheduledCommandEnvelope, + scheduledCommandMetadata: ScheduledCommandMetadata + ): Promise { // Do something with the error } } ``` -This method receives the error that was thrown. +Note that if an error is thrown on a ScheduleCommand, **Booster** will stop working. ### Event handler errors @@ -47,14 +55,17 @@ These are the errors that are thrown in the `handle` method of the `@Event`. You ```typescript @GlobalErrorHandler() export class MyErrorHandler { - public onEventHandlerError(error: Error, event: EventEnvelope): Promise { + public static async onDispatchEventHandlerError( + error: Error, + eventEnvelope: EventEnvelope | NotificationInterface, + eventHandlerMetadata: unknown, + eventInstance: EventInterface + ): Promise { // Do something with the error } } ``` -This method receives the error that was thrown and the event that was being handled when the error occurred. - ### Reducer errors These are the errors that are thrown in the `@Reduces` method of the `@Entity`. You can catch and return new errors in this function annotating a class with `@GlobalErrorHandler` and implementing the following method: @@ -62,13 +73,34 @@ These are the errors that are thrown in the `@Reduces` method of the `@Entity`. ```typescript @GlobalErrorHandler() export class MyErrorHandler { - public onReducerError(error: Error, entity: EntityInterface, snapshot: EntityInterface | null): Promise { + public static async onReducerError( + error: Error, + eventEnvelope: EventEnvelope, + reducerMetadata: ReducerMetadata, + eventInstance: EventInterface, + snapshotInstance: EntityInterface | null + ): Promise { + // Do something with the error + } +} +``` + +Note you can not ignore a Reducer error as the new entity could not be created + +### Event errors + +These are the errors that are thrown if the event doesn't exist. You can catch and return new errors in this function annotating a class with `@GlobalErrorHandler` and implementing the following method: + +```typescript +@GlobalErrorHandler() +export class MyErrorHandler { + public static async onEventError(error: Error, eventEnvelope: EventEnvelope): Promise { // Do something with the error } } ``` -This method receives the error that was thrown, the name of the entity, the ID of the entity, and the name of the reducer. +This method receives the error that was thrown and the event received. ### Projection errors @@ -77,14 +109,18 @@ These are the errors that are thrown in the `@Projects` method of the `@ReadMode ```typescript @GlobalErrorHandler() export class MyErrorHandler { - public onProjectionError(error: Error, readModel: ReadModelInterface, entity: EntityInterface): Promise { + public static async onProjectionError( + error: Error, + entityEnvelope: EntitySnapshotEnvelope, + projectionMetadata: ProjectionMetadata, + entity: EntityInterface, + readModel: ReadModelInterface | undefined + ): Promise { // Do something with the error } } ``` -This method receives the error that was thrown, the name of the read model, the ID of the read model, and the name of the projection. - ### All errors These are the errors that are thrown in any of the previous methods. You can catch and return new errors in this function annotating a class with `@GlobalErrorHandler` and implementing the following method: @@ -107,20 +143,35 @@ You can implement all error handling functions in the same class. Here is an exa ```typescript @GlobalErrorHandler() export class AppErrorHandler { - public static async onCommandHandlerError(error: Error, command: CommandEnvelope): Promise { + public static async onCommandHandlerError( + error: Error, + commandEnvelope: CommandEnvelope, + commandMetadata: CommandMetadata + ): Promise { return error } - public static async onScheduledCommandHandlerError(error: Error): Promise { + public static async onScheduledCommandHandlerError( + error: Error, + scheduledCommandEnvelope: ScheduledCommandEnvelope, + scheduledCommandMetadata: ScheduledCommandMetadata + ): Promise { return error } - public static async onDispatchEventHandlerError(error: Error, eventInstance: EventInterface): Promise { + public static async onDispatchEventHandlerError( + error: Error, + eventEnvelope: EventEnvelope | NotificationInterface, + eventHandlerMetadata: unknown, + eventInstance: EventInterface + ): Promise { return error } public static async onReducerError( error: Error, + eventEnvelope: EventEnvelope, + reducerMetadata: ReducerMetadata, eventInstance: EventInterface, snapshotInstance: EntityInterface | null ): Promise { @@ -129,12 +180,18 @@ export class AppErrorHandler { public static async onProjectionError( error: Error, + entityEnvelope: EntitySnapshotEnvelope, + projectionMetadata: ProjectionMetadata, entity: EntityInterface, readModel: ReadModelInterface | undefined ): Promise { return error } + public static async onEventError(error: Error, eventEnvelope: EventEnvelope): Promise { + return error + } + public static async onError(error: Error | undefined): Promise { return error } diff --git a/website/docs/06_graphql.md b/website/docs/06_graphql.md index 89eb480634..205ba40977 100644 --- a/website/docs/06_graphql.md +++ b/website/docs/06_graphql.md @@ -882,13 +882,21 @@ export class GetCartItems { The above search will return an array of carts with their `id` property, as well as an array of the `cartItems` of each cart with only the `productId` for each item. -> **Warning**: Only available for Azure and Local Providers. `select` will be ignored for AWS Provider. +:::warning +Only available for Azure and Local Providers. `select` will be ignored for AWS Provider. +::: -> **Warning**: Using `select` will skip any Read Models migrations that need to be applied to the result. If you need to apply migrations to the result, don't use `select`. +:::warning +Using `select` will skip any Read Models migrations that need to be applied to the result. If you need to apply migrations to the result, don't use `select`. +::: -> **Warning**: Support for selecting fields from objects inside arrays is limited to arrays that are at most nested inside another property, e.g., `['category.relatedCategories[].name']`. Selecting fields from arrays that are nested deeper than that (e.g., `['foo.bar.items[].id']`) is not expected to yield the expected results. +:::warning +Support for selecting fields from objects inside arrays is limited to arrays that are at most nested inside another property, e.g., `['category.relatedCategories[].name']`. Selecting fields from arrays that are nested deeper than that (e.g., `['foo.bar.items[].id']`) will return the entire object. +::: -> **Warning**: Notice that `ReadModel`s are eventually consistent objects that are calculated as all events in all entities that affect the read model are settled. You should not assume that a read model is a proper source of truth, so you shouldn't use this feature for data validations. If you need to query the most up-to-date current state, consider fetching your Entities, instead of ReadModels, with `Booster.entity` +:::warning +Notice that `ReadModel`s are eventually consistent objects that are calculated as all events in all entities that affect the read model are settled. You should not assume that a read model is a proper source of truth, so you shouldn't use this feature for data validations. If you need to query the most up-to-date current state, consider fetching your Entities, instead of ReadModels, with `Booster.entity` +::: ### Using sorting @@ -931,7 +939,9 @@ This is a preview feature available only for some Providers and with some limita - Nested fields supported. - Sort by more than one file: **unsupported**. -> **Warning**: It is not possible to sort by fields defined as Interface, only classes or primitives types. +:::warning +It is not possible to sort by fields defined as Interface, only classes or primitives types. +::: ### Using pagination diff --git a/website/docs/10_going-deeper/azure-scale.mdx b/website/docs/10_going-deeper/azure-scale.mdx index 91bf72a571..5a61b3dca8 100644 --- a/website/docs/10_going-deeper/azure-scale.mdx +++ b/website/docs/10_going-deeper/azure-scale.mdx @@ -10,7 +10,9 @@ With Booster EventStream functionality, we could define the number of physical p To enable EventStream, set the `EventStreamConfiguration` in the configuration object: -> **Warning**: Currently, only available for Azure provider. +:::warning +Currently, only available for Azure provider. +::: ```typescript config.eventStreamConfiguration = { diff --git a/website/docs/10_going-deeper/health/sensor-health.md b/website/docs/10_going-deeper/health/sensor-health.md index bdf4eb8af3..d10324b421 100644 --- a/website/docs/10_going-deeper/health/sensor-health.md +++ b/website/docs/10_going-deeper/health/sensor-health.md @@ -87,10 +87,11 @@ Booster provides the following endpoints to retrieve the enabled components: * https://your-application-url/sensor/health/booster/database/events: Events status * https://your-application-url/sensor/health/booster/database/readmodels: ReadModels status * https://your-application-url/sensor/health/booster/function: Functions status +* https://your-application-url/sensor/health/rockets: Rockets status * https://your-application-url/sensor/health/your-component-id: User defined status * https://your-application-url/sensor/health/your-component-id/your-component-child-id: User child component status -Depending on the `showChildren` configuration, children components will be included or not. +Depending on the `showChildren` configuration, child components will be included or not. ### Health Status Response @@ -100,7 +101,7 @@ Each component response will contain the following information: * name: component description * id: string. unique component identifier. You can request a component status using the id in the url * details: optional object. If `details` is true, specific details about this component. -* components: optional object. If `showChildren` is true, children components health status. +* components: optional object. If `showChildren` is true, child components health status. Example: @@ -150,6 +151,7 @@ Use the `id` field to get specific component health information. Booster provide * booster/database * booster/database/events * booster/database/readmodels +* rockets You can provide new components: ```typescript @@ -189,8 +191,8 @@ Health components are fully configurable, allowing you to display the informatio Configuration options: * enabled: If false, this indicator and the components of this indicator will be skipped * details: If false, the indicator will not include the details -* showChildren: If false, this indicator will not include children components in the tree. - * Children components will be shown through children urls +* showChildren: If false, this indicator will not include child components in the tree. + * Child components will be shown through child urls * authorize: Authorize configuration. [See security documentation](https://docs.boosterframework.com/security/security) #### Booster components default configuration @@ -314,14 +316,24 @@ export class ApplicationHealthIndicator { * file: Read Models database file * count: number of total rows -> **Note**: details will be included only if `details` is enabled +:::note +Details will be included only if `details` is enabled +::: +#### rockets + +* status: UP if and only if all rockets are UP, PARTIALLY_UP if not all rockets are UP + +:::note +Sensors for rockets is only available for the Azure provider +::: ### Health status Available status are * UP: The component or subsystem is working as expected +* PARTIALLY_UP: The component is partially working or has reduced functionality * DOWN: The component is not working * OUT_OF_SERVICE: The component is out of service temporarily * UNKNOWN: The component state is unknown @@ -370,7 +382,7 @@ If the request url is https://your-application-url/sensor/health/database, the c [Empty] ``` -And the children components will be disabled too using direct url https://your-application-url/sensor/health/database/events +And the child components will be disabled too using direct url https://your-application-url/sensor/health/database/events ```text [Empty] diff --git a/website/docs/10_going-deeper/remove-events.mdx b/website/docs/10_going-deeper/remove-events.mdx new file mode 100644 index 0000000000..96335bf402 --- /dev/null +++ b/website/docs/10_going-deeper/remove-events.mdx @@ -0,0 +1,95 @@ +# Remove events + +:::warning +This is an experimental functionality. Please note that this functionality is only supported by Azure and Local providers. +::: + +Booster allows to delete past events and their related entities as to update the affected ReadModels. + +By using the `Booster.deleteEvent` command it is possible to indicate the event to be deleted. To do so, you must indicate: + +* entityID: The `id` of the entity of the event to be deleted +* entityTypeName: The entity type name of the event entity to be deleted +* createdAt: The date of creation of the event. + +Example: +```typescript +import { Booster, Command } from '@boostercloud/framework-core' +import { EventDeleteParameters } from '@boostercloud/framework-types' + +@Command({ + authorize: 'all', +}) +export class HardDelete { + public constructor(readonly entityId: string, readonly entityTypeName: string, readonly createdAt: string) {} + + public static async handle(command: HardDelete): Promise { + const parameters: EventDeleteParameters = { + entityID: command.entityId, + entityTypeName: command.entityTypeName, + createdAt: command.createdAt, + } + return await Booster.deleteEvent(parameters) + } +} +``` + +When executing this command, Booster will update the selected event in the corresponding database with an empty value and a deletion date. +This way, it will be reflected in the system that there was an event that was subsequently deleted. + +Deleted events are ignored by Booster, but they can be accessed using the corresponding methods (`eventsByEntity` and `eventsByType`). + +The entities associated with a deleted event will be permanently removed from the database. + +ReadModels are not automatically modified or deleted and it is up to the user to act accordingly. +To do so, the methods annotated with `@Project` of the ReadModels have a third parameter `unProject` which allows to define a +function that will be executed when the entity defined in the projection and with the `joinKey` defined in the projection is deleted. + +This third parameter will be a static function with the same parameters as the method we are projecting. + +It is possible to use the same method that is used for projecting to resolve the deletions by simply specifying this +method as `unProject`. + +Example: +```typescript + @Projects(Pack, 'products', ProductReadModel.updateWithPack) + public static updateWithPack( + pack: Pack, + readModelID: UUID, + currentProductReadModel?: ProductReadModel, + projectionInfo?: ProjectionInfo + ): ProjectionResult { + if (projectionInfo?.reason === ProjectionInfoReason.ENTITY_DELETED) { + return ReadModelAction.Delete + } + // ... other code + } +``` + +In this case, if the `Pack` entity with the joinKey `products` is deleted, the `updateWithPack` method will be executed and will include a last parameter called `projectionInfo`. +This parameter contains the `reason` field, which in this case will be set to `ENTITY_DELETED` to indicate that the entity is being deleted. + +Another option is to define your own deletion method independent of the projection method. In case of deletion the method +called will be the newly defined method. + +Example: +```typescript + @Projects(Product, 'id', ProductReadModel.unProjectWithProduct) + public static updateWithProduct(product: Product): ProjectionResult { + // ... other code + } + + public static unProjectWithProduct( + _product: Product, + _currentProductReadModel?: ProductReadModel, + _projectionInfo?: ProjectionInfo + ): ProjectionResult { + return ReadModelAction.Delete + } +``` + +([See more details about how to delete a ReadModel in the docs](https://docs.boosterframework.com/architecture/read-model/#deleting-read-models)) + +:::warning +Please note that these changes are final and it is not possible to retrieve the information once they have been made. +::: diff --git a/website/docs/12_contributing.md b/website/docs/12_contributing.md index 2a428f3c09..5992ef3ff1 100644 --- a/website/docs/12_contributing.md +++ b/website/docs/12_contributing.md @@ -55,7 +55,9 @@ Contributing to an open source project is never just a matter of code, you can h Before creating a bug report, please search for similar issues to make sure that they're not already reported. If you don't find any, go ahead and create an issue including as many details as possible. Fill out the required template, the information requested helps us to resolve issues faster. -> **Note**: If you find a Closed issue that seems related to the issues that you're experiencing, make sure to reference it in the body of your new one by writing its number like this => #42 (Github will autolink it for you). +:::note +If you find a Closed issue that seems related to the issues that you're experiencing, make sure to reference it in the body of your new one by writing its number like this => #42 (Github will autolink it for you). +::: Bugs are tracked as GitHub issues. Explain the problem and include additional details to help maintainers reproduce the problem: diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 6a92b582fa..6e15654527 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -124,7 +124,7 @@ const config = { }, { label: 'Twitter', - to: 'https://twitter.com/boostthecloud', + to: 'https://twitter.com/theboosterway', }, { label: 'Linkedin', diff --git a/website/sidebars.js b/website/sidebars.js index 335f534cfe..377a95ca4d 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -113,6 +113,7 @@ const sidebars = { 'going-deeper/custom-templates', 'going-deeper/framework-packages', 'going-deeper/instrumentation', + 'going-deeper/remove-events', 'going-deeper/azure-scale' ], },