From caeb44bd0e97959a4521656a943bcf38bac4a144 Mon Sep 17 00:00:00 2001 From: flaviostutz Date: Fri, 25 Oct 2024 16:53:19 +0200 Subject: [PATCH 1/4] feat: API Lifecycle status control initial implementation. Needs unit tests --- .mailmap | 8 + examples/package.json | 2 +- examples/pnpm-lock.yaml | 340 ++++++++++++----------- lib/src/wso2/wso2-api/handler/index.ts | 6 +- lib/src/wso2/wso2-api/handler/wso2-v1.ts | 144 ++++++---- lib/src/wso2/wso2-api/types.ts | 7 + lib/src/wso2/wso2-api/v1/types.ts | 2 +- lib/src/wso2/wso2-api/wso2-api.ts | 3 +- 8 files changed, 287 insertions(+), 225 deletions(-) create mode 100644 .mailmap diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..99ce6a4 --- /dev/null +++ b/.mailmap @@ -0,0 +1,8 @@ +# This is used to normalise git reports +# The format is "Proper Name Commit Name " +# for more info, https://git-scm.com/docs/gitmailmap + +Marcio Meier marcio meier + +Flavio Stutz flaviostutz +Flavio Stutz Flávio Stutz diff --git a/examples/package.json b/examples/package.json index 7a047a8..95cdad0 100644 --- a/examples/package.json +++ b/examples/package.json @@ -30,4 +30,4 @@ "openapi3-ts": "^4.2.1", "zod": "^3.23.8" } -} \ No newline at end of file +} diff --git a/examples/pnpm-lock.yaml b/examples/pnpm-lock.yaml index 7ee3ba0..67bc4f2 100644 --- a/examples/pnpm-lock.yaml +++ b/examples/pnpm-lock.yaml @@ -33,7 +33,7 @@ dependencies: devDependencies: '@stutzlab/eslint-config': specifier: ^3.1.1 - version: 3.1.1(@typescript-eslint/eslint-plugin@7.18.0)(@typescript-eslint/parser@7.18.0)(eslint-config-airbnb-base@15.0.0)(eslint-config-airbnb-typescript@18.0.0)(eslint-config-prettier@9.1.0)(eslint-import-resolver-typescript@3.6.3)(eslint-plugin-fp@2.3.0)(eslint-plugin-import@2.29.1)(eslint-plugin-jest@28.8.1)(eslint-plugin-prettier@5.2.1)(eslint-plugin-promise@6.6.0)(eslint@8.57.0)(prettier@3.3.3) + version: 3.1.1(@typescript-eslint/eslint-plugin@7.18.0)(@typescript-eslint/parser@7.18.0)(eslint-config-airbnb-base@15.0.0)(eslint-config-airbnb-typescript@18.0.0)(eslint-config-prettier@9.1.0)(eslint-import-resolver-typescript@3.6.3)(eslint-plugin-fp@2.3.0)(eslint-plugin-import@2.31.0)(eslint-plugin-jest@28.8.3)(eslint-plugin-prettier@5.2.1)(eslint-plugin-promise@6.6.0)(eslint@8.57.0)(prettier@3.3.3) '@tsconfig/node20': specifier: ^20.1.4 version: 20.1.4 @@ -1155,8 +1155,8 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true - /@eslint-community/regexpp@4.11.0: - resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} + /@eslint-community/regexpp@4.11.1: + resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true @@ -1549,23 +1549,23 @@ packages: engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} dev: true - /@rollup/plugin-commonjs@22.0.2(rollup@2.79.1): + /@rollup/plugin-commonjs@22.0.2(rollup@2.79.2): resolution: {integrity: sha512-//NdP6iIwPbMTcazYsiBMbJW7gfmpHom33u1beiIoHDEM0Q9clvtQB1T0efvMqHeKsGohiHo97BCPCkBXdscwg==} engines: {node: '>= 12.0.0'} peerDependencies: rollup: ^2.68.0 dependencies: - '@rollup/pluginutils': 3.1.0(rollup@2.79.1) + '@rollup/pluginutils': 3.1.0(rollup@2.79.2) commondir: 1.0.1 estree-walker: 2.0.2 glob: 7.2.3 is-reference: 1.2.1 magic-string: 0.25.9 resolve: 1.22.8 - rollup: 2.79.1 + rollup: 2.79.2 dev: false - /@rollup/pluginutils@3.1.0(rollup@2.79.1): + /@rollup/pluginutils@3.1.0(rollup@2.79.2): resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} engines: {node: '>= 8.0.0'} peerDependencies: @@ -1574,9 +1574,13 @@ packages: '@types/estree': 0.0.39 estree-walker: 1.0.1 picomatch: 2.3.1 - rollup: 2.79.1 + rollup: 2.79.2 dev: false + /@rtsao/scc@1.1.0: + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + dev: true + /@sinclair/typebox@0.27.8: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} dev: true @@ -2029,7 +2033,7 @@ packages: resolution: {integrity: sha512-YNcWv3R3n3U6iQYBsFOiWSuRGE5su1tJSiX6pAPRVk7dP0L7lqCteXGzuVRQ0gMZqUl8v1P0+fAKxF6PLo9B5A==} engines: {node: '>=8.3.0'} dependencies: - '@stoplight/json': 3.21.6 + '@stoplight/json': 3.21.7 '@stoplight/path': 1.3.2 '@stoplight/types': 13.20.0 '@types/urijs': 1.19.25 @@ -2037,12 +2041,12 @@ packages: fast-memoize: 2.5.2 immer: 9.0.21 lodash: 4.17.21 - tslib: 2.7.0 + tslib: 2.8.0 urijs: 1.19.11 dev: false - /@stoplight/json@3.21.6: - resolution: {integrity: sha512-KGisXfNigoYdWIj1jA4p3IAAIW5YFpU9BdoECdjyDLBbhWGGHzs77e0STSCBmXQ/K3ApxfED2R7mQ79ymjzlvQ==} + /@stoplight/json@3.21.7: + resolution: {integrity: sha512-xcJXgKFqv/uCEgtGlPxy3tPA+4I+ZI4vAuMJ885+ThkTHFVkC+0Fm58lA9NlsyjnkpxFh4YiQWpH+KefHdbA0A==} engines: {node: '>=8.3.0'} dependencies: '@stoplight/ordered-object-literal': 1.0.5 @@ -2063,20 +2067,20 @@ packages: engines: {node: '>=8'} dev: false - /@stoplight/spectral-cli@6.11.1: - resolution: {integrity: sha512-1zqsQ0TOuVSnxxZ9mHBfC0IygV6ex7nAY6Mp59mLmw5fW103U9yPVK5ZcX9ZngCmr3PdteAnMDUIIaoDGso6nA==} + /@stoplight/spectral-cli@6.13.1: + resolution: {integrity: sha512-v6ipX4w6wRhtbOotwdPL7RrEkP0m1OwHTIyqzVrAPi932F/zkee24jmf1CHNrTynonmfGoU6/XpeqUHtQdKDFw==} engines: {node: ^12.20 || >= 14.13} hasBin: true dependencies: - '@stoplight/json': 3.21.6 + '@stoplight/json': 3.21.7 '@stoplight/path': 1.3.2 - '@stoplight/spectral-core': 1.18.3 - '@stoplight/spectral-formatters': 1.3.0 + '@stoplight/spectral-core': 1.19.1 + '@stoplight/spectral-formatters': 1.4.0 '@stoplight/spectral-parsers': 1.0.4 '@stoplight/spectral-ref-resolver': 1.0.4 - '@stoplight/spectral-ruleset-bundler': 1.5.2 - '@stoplight/spectral-ruleset-migrator': 1.9.5 - '@stoplight/spectral-rulesets': 1.19.1 + '@stoplight/spectral-ruleset-bundler': 1.6.0 + '@stoplight/spectral-ruleset-migrator': 1.10.0 + '@stoplight/spectral-rulesets': 1.20.2 '@stoplight/spectral-runtime': 1.1.2 '@stoplight/types': 13.20.0 chalk: 4.1.2 @@ -2085,18 +2089,18 @@ packages: lodash: 4.17.21 pony-cause: 1.1.1 stacktracey: 2.1.8 - tslib: 2.7.0 + tslib: 2.8.0 yargs: 17.7.2 transitivePeerDependencies: - encoding dev: false - /@stoplight/spectral-core@1.18.3: - resolution: {integrity: sha512-YY8x7X2SWJIhGTLPol+eFiQpWPz0D0mJdkK2i4A0QJG68KkNhypP6+JBC7/Kz3XWjqr0L/RqAd+N5cQLPOKZGQ==} + /@stoplight/spectral-core@1.19.1: + resolution: {integrity: sha512-YiWhXdjyjn4vCl3102ywzwCEJzncxapFcj4dxcj1YP/bZ62DFeGJ8cEaMP164vSw2kI3rX7EMMzI/c8XOUnTfQ==} engines: {node: ^12.20 || >= 14.13} dependencies: '@stoplight/better-ajv-errors': 1.0.3(ajv@8.17.1) - '@stoplight/json': 3.21.6 + '@stoplight/json': 3.21.7 '@stoplight/path': 1.3.2 '@stoplight/spectral-parsers': 1.0.4 '@stoplight/spectral-ref-resolver': 1.0.4 @@ -2115,57 +2119,59 @@ packages: nimma: 0.2.2 pony-cause: 1.1.1 simple-eval: 1.0.0 - tslib: 2.7.0 + tslib: 2.8.0 transitivePeerDependencies: - encoding dev: false - /@stoplight/spectral-formats@1.6.0: - resolution: {integrity: sha512-X27qhUfNluiduH0u/QwJqhOd8Wk5YKdxVmKM03Aijlx0AH1H5mYt3l9r7t2L4iyJrsBaFPnMGt7UYJDGxszbNA==} + /@stoplight/spectral-formats@1.7.0: + resolution: {integrity: sha512-vJ1vIkA2s96fdJp0d3AJBGuPAW3sj8yMamyzR+dquEFO6ZAoYBo/BVsKKQskYzZi/nwljlRqUmGVmcf2PncIaA==} engines: {node: '>=12'} dependencies: - '@stoplight/json': 3.21.6 - '@stoplight/spectral-core': 1.18.3 + '@stoplight/json': 3.21.7 + '@stoplight/spectral-core': 1.19.1 '@types/json-schema': 7.0.15 - tslib: 2.7.0 + tslib: 2.8.0 transitivePeerDependencies: - encoding dev: false - /@stoplight/spectral-formatters@1.3.0: - resolution: {integrity: sha512-ryuMwlzbPUuyn7ybSEbFYsljYmvTaTyD51wyCQs4ROzgfm3Yo5QDD0IsiJUzUpKK/Ml61ZX8ebgiPiRFEJtBpg==} + /@stoplight/spectral-formatters@1.4.0: + resolution: {integrity: sha512-nxYQldDzVg32pxQ4cMX27eMtB1A39ea+GSf0wIJ20mqkSBfIgLnRZ+GKkBxhgF9JzSolc4YtweydsubGQGd7ag==} engines: {node: ^12.20 || >=14.13} dependencies: '@stoplight/path': 1.3.2 - '@stoplight/spectral-core': 1.18.3 + '@stoplight/spectral-core': 1.19.1 '@stoplight/spectral-runtime': 1.1.2 '@stoplight/types': 13.20.0 + '@types/markdown-escape': 1.1.3 chalk: 4.1.2 cliui: 7.0.4 lodash: 4.17.21 + markdown-escape: 2.0.0 node-sarif-builder: 2.0.3 strip-ansi: 6.0.1 text-table: 0.2.0 - tslib: 2.7.0 + tslib: 2.8.0 transitivePeerDependencies: - encoding dev: false - /@stoplight/spectral-functions@1.8.0: - resolution: {integrity: sha512-ZrAkYA/ZGbuQ6EyG1gisF4yQ5nWP/+glcqVoGmS6kH6ekaynz2Yp6FL0oIamWj3rWedFUN7ppwTRUdo+9f/uCw==} + /@stoplight/spectral-functions@1.9.0: + resolution: {integrity: sha512-T+xl93ji8bpus4wUsTq8Qr2DSu2X9PO727rbxW61tTCG0s17CbsXOLYI+Ezjg5P6aaQlgXszGX8khtc57xk8Yw==} engines: {node: '>=12'} dependencies: '@stoplight/better-ajv-errors': 1.0.3(ajv@8.17.1) - '@stoplight/json': 3.21.6 - '@stoplight/spectral-core': 1.18.3 - '@stoplight/spectral-formats': 1.6.0 + '@stoplight/json': 3.21.7 + '@stoplight/spectral-core': 1.19.1 + '@stoplight/spectral-formats': 1.7.0 '@stoplight/spectral-runtime': 1.1.2 ajv: 8.17.1 ajv-draft-04: 1.0.0(ajv@8.17.1) ajv-errors: 3.0.0(ajv@8.17.1) ajv-formats: 2.1.1(ajv@8.17.1) lodash: 4.17.21 - tslib: 2.7.0 + tslib: 2.8.0 transitivePeerDependencies: - encoding dev: false @@ -2174,10 +2180,10 @@ packages: resolution: {integrity: sha512-nCTVvtX6q71M8o5Uvv9kxU31Gk1TRmgD6/k8HBhdCmKG6FWcwgjiZouA/R3xHLn/VwTI/9k8SdG5Mkdy0RBqbQ==} engines: {node: ^12.20 || >=14.13} dependencies: - '@stoplight/json': 3.21.6 + '@stoplight/json': 3.21.7 '@stoplight/types': 14.1.1 '@stoplight/yaml': 4.3.0 - tslib: 2.7.0 + tslib: 2.8.0 dev: false /@stoplight/spectral-ref-resolver@1.0.4: @@ -2188,43 +2194,43 @@ packages: '@stoplight/json-ref-resolver': 3.1.6 '@stoplight/spectral-runtime': 1.1.2 dependency-graph: 0.11.0 - tslib: 2.7.0 + tslib: 2.8.0 transitivePeerDependencies: - encoding dev: false - /@stoplight/spectral-ruleset-bundler@1.5.2: - resolution: {integrity: sha512-4QUVUFAU+S7IQ9XeCu+0TQMYxKFpKnkOAfa9unRQ1iPL2cviaipEN6witpbAptdHJD3UUjx4OnwlX8WwmXSq9w==} + /@stoplight/spectral-ruleset-bundler@1.6.0: + resolution: {integrity: sha512-8CU7e4aEGdfU9ncVDtlnJSawg/6epzAHrQTjuNu1QfKAOoiwyG7oUk2XUTHWcvq6Q67iUctb0vjOokR+MPVg0Q==} engines: {node: ^12.20 || >= 14.13} dependencies: - '@rollup/plugin-commonjs': 22.0.2(rollup@2.79.1) + '@rollup/plugin-commonjs': 22.0.2(rollup@2.79.2) '@stoplight/path': 1.3.2 - '@stoplight/spectral-core': 1.18.3 - '@stoplight/spectral-formats': 1.6.0 - '@stoplight/spectral-functions': 1.8.0 + '@stoplight/spectral-core': 1.19.1 + '@stoplight/spectral-formats': 1.7.0 + '@stoplight/spectral-functions': 1.9.0 '@stoplight/spectral-parsers': 1.0.4 '@stoplight/spectral-ref-resolver': 1.0.4 - '@stoplight/spectral-ruleset-migrator': 1.9.5 - '@stoplight/spectral-rulesets': 1.19.1 + '@stoplight/spectral-ruleset-migrator': 1.10.0 + '@stoplight/spectral-rulesets': 1.20.2 '@stoplight/spectral-runtime': 1.1.2 '@stoplight/types': 13.20.0 '@types/node': 20.16.2 pony-cause: 1.1.1 - rollup: 2.79.1 - tslib: 2.7.0 + rollup: 2.79.2 + tslib: 2.8.0 validate-npm-package-name: 3.0.0 transitivePeerDependencies: - encoding dev: false - /@stoplight/spectral-ruleset-migrator@1.9.5: - resolution: {integrity: sha512-76n/HETr3UinVl/xLNldrH9p0JNoD8Gz4K75J6E4OHp4xD0P+BA2e8+W30HjIvqm1LJdLU2BNma0ioy+q3B9RA==} + /@stoplight/spectral-ruleset-migrator@1.10.0: + resolution: {integrity: sha512-nDfkVfYeWWv0UvILC4TWZSnRqQ4rHgeOJO1/lHQ7XHeG5iONanQ639B1aK6ZS6vuUc8gwuyQsrPF67b4sHIyYw==} engines: {node: '>=12'} dependencies: - '@stoplight/json': 3.21.6 + '@stoplight/json': 3.21.7 '@stoplight/ordered-object-literal': 1.0.5 '@stoplight/path': 1.3.2 - '@stoplight/spectral-functions': 1.8.0 + '@stoplight/spectral-functions': 1.9.0 '@stoplight/spectral-runtime': 1.1.2 '@stoplight/types': 13.20.0 '@stoplight/yaml': 4.2.3 @@ -2233,22 +2239,22 @@ packages: ast-types: 0.14.2 astring: 1.9.0 reserved: 0.1.2 - tslib: 2.7.0 + tslib: 2.8.0 validate-npm-package-name: 3.0.0 transitivePeerDependencies: - encoding dev: false - /@stoplight/spectral-rulesets@1.19.1: - resolution: {integrity: sha512-rfGK87Y1JJCEeLC8MVdLkjUkRH+Y6VnSF388D+UWihfU9xuq2eNB9phWpTFkG+AG4HLRyGx963BmO6PyM9dBag==} + /@stoplight/spectral-rulesets@1.20.2: + resolution: {integrity: sha512-7Y8orZuNyGyeHr9n50rMfysgUJ+/zzIEHMptt66jiy82GUWl+0nr865DkMuXdC5GryfDYhtjoRTUCVsXu80Nkg==} engines: {node: '>=12'} dependencies: '@asyncapi/specs': 4.3.1 '@stoplight/better-ajv-errors': 1.0.3(ajv@8.17.1) - '@stoplight/json': 3.21.6 - '@stoplight/spectral-core': 1.18.3 - '@stoplight/spectral-formats': 1.6.0 - '@stoplight/spectral-functions': 1.8.0 + '@stoplight/json': 3.21.7 + '@stoplight/spectral-core': 1.19.1 + '@stoplight/spectral-formats': 1.7.0 + '@stoplight/spectral-functions': 1.9.0 '@stoplight/spectral-runtime': 1.1.2 '@stoplight/types': 13.20.0 '@types/json-schema': 7.0.15 @@ -2257,7 +2263,7 @@ packages: json-schema-traverse: 1.0.0 leven: 3.1.0 lodash: 4.17.21 - tslib: 2.7.0 + tslib: 2.8.0 transitivePeerDependencies: - encoding dev: false @@ -2266,13 +2272,13 @@ packages: resolution: {integrity: sha512-fr5zRceXI+hrl82yAVoME+4GvJie8v3wmOe9tU+ZLRRNonizthy8qDi0Z/z4olE+vGreSDcuDOZ7JjRxFW5kTw==} engines: {node: '>=12'} dependencies: - '@stoplight/json': 3.21.6 + '@stoplight/json': 3.21.7 '@stoplight/path': 1.3.2 '@stoplight/types': 12.5.0 abort-controller: 3.0.0 lodash: 4.17.21 node-fetch: 2.7.0 - tslib: 2.7.0 + tslib: 2.8.0 transitivePeerDependencies: - encoding dev: false @@ -2324,7 +2330,7 @@ packages: '@stoplight/ordered-object-literal': 1.0.5 '@stoplight/types': 13.20.0 '@stoplight/yaml-ast-parser': 0.0.48 - tslib: 2.7.0 + tslib: 2.8.0 dev: false /@stoplight/yaml@4.3.0: @@ -2334,10 +2340,10 @@ packages: '@stoplight/ordered-object-literal': 1.0.5 '@stoplight/types': 14.1.1 '@stoplight/yaml-ast-parser': 0.0.50 - tslib: 2.7.0 + tslib: 2.8.0 dev: false - /@stutzlab/eslint-config@3.1.1(@typescript-eslint/eslint-plugin@7.18.0)(@typescript-eslint/parser@7.18.0)(eslint-config-airbnb-base@15.0.0)(eslint-config-airbnb-typescript@18.0.0)(eslint-config-prettier@9.1.0)(eslint-import-resolver-typescript@3.6.3)(eslint-plugin-fp@2.3.0)(eslint-plugin-import@2.29.1)(eslint-plugin-jest@28.8.1)(eslint-plugin-prettier@5.2.1)(eslint-plugin-promise@6.6.0)(eslint@8.57.0)(prettier@3.3.3): + /@stutzlab/eslint-config@3.1.1(@typescript-eslint/eslint-plugin@7.18.0)(@typescript-eslint/parser@7.18.0)(eslint-config-airbnb-base@15.0.0)(eslint-config-airbnb-typescript@18.0.0)(eslint-config-prettier@9.1.0)(eslint-import-resolver-typescript@3.6.3)(eslint-plugin-fp@2.3.0)(eslint-plugin-import@2.31.0)(eslint-plugin-jest@28.8.3)(eslint-plugin-prettier@5.2.1)(eslint-plugin-promise@6.6.0)(eslint@8.57.0)(prettier@3.3.3): resolution: {integrity: sha512-XmwQJE6UkSBmr2ZFGOprxVO/8Yioxu0vTzoLDm/0dB9E2RwGp1r6N4cyRT0MI8PCyYSUOz2kBH1aL5qpJkfFwQ==} peerDependencies: '@typescript-eslint/eslint-plugin': ^7.15.0 @@ -2357,13 +2363,13 @@ packages: '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0)(eslint@8.57.0)(typescript@5.5.4) '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) eslint: 8.57.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0) - eslint-config-airbnb-typescript: 18.0.0(@typescript-eslint/eslint-plugin@7.18.0)(@typescript-eslint/parser@7.18.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.31.0)(eslint@8.57.0) + eslint-config-airbnb-typescript: 18.0.0(@typescript-eslint/eslint-plugin@7.18.0)(@typescript-eslint/parser@7.18.0)(eslint-plugin-import@2.31.0)(eslint@8.57.0) eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.18.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.18.0)(eslint-plugin-import@2.31.0)(eslint@8.57.0) eslint-plugin-fp: 2.3.0(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) - eslint-plugin-jest: 28.8.1(@typescript-eslint/eslint-plugin@7.18.0)(eslint@8.57.0)(jest@29.7.0)(typescript@5.5.4) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) + eslint-plugin-jest: 28.8.3(@typescript-eslint/eslint-plugin@7.18.0)(eslint@8.57.0)(jest@29.7.0)(typescript@5.5.4) eslint-plugin-prettier: 5.2.1(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.3.3) eslint-plugin-promise: 6.6.0(eslint@8.57.0) prettier: 3.3.3 @@ -2432,8 +2438,8 @@ packages: resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} dev: false - /@types/estree@1.0.5: - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + /@types/estree@1.0.6: + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} dev: false /@types/graceful-fs@4.1.9: @@ -2473,6 +2479,10 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true + /@types/markdown-escape@1.1.3: + resolution: {integrity: sha512-JIc1+s3y5ujKnt/+N+wq6s/QdL2qZ11fP79MijrVXsAAnzSxCbT2j/3prHRouJdZ2yFLN3vkP0HytfnoCczjOw==} + dev: false + /@types/node@20.16.2: resolution: {integrity: sha512-91s/n4qUPV/wg8eE9KHYW1kouTfDk2FPGjXbBMfRWP/2vg1rCXNQL1OCabwGs0XSdukuK+MwCDXE30QpSeMUhQ==} dependencies: @@ -2527,7 +2537,7 @@ packages: typescript: optional: true dependencies: - '@eslint-community/regexpp': 4.11.0 + '@eslint-community/regexpp': 4.11.1 '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) '@typescript-eslint/scope-manager': 7.18.0 '@typescript-eslint/type-utils': 7.18.0(eslint@8.57.0)(typescript@5.5.4) @@ -2557,7 +2567,7 @@ packages: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4) '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.3.6 + debug: 4.3.7 eslint: 8.57.0 typescript: 5.5.4 transitivePeerDependencies: @@ -2572,12 +2582,12 @@ packages: '@typescript-eslint/visitor-keys': 7.18.0 dev: true - /@typescript-eslint/scope-manager@8.3.0: - resolution: {integrity: sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==} + /@typescript-eslint/scope-manager@8.11.0: + resolution: {integrity: sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/types': 8.3.0 - '@typescript-eslint/visitor-keys': 8.3.0 + '@typescript-eslint/types': 8.11.0 + '@typescript-eslint/visitor-keys': 8.11.0 dev: true /@typescript-eslint/type-utils@7.18.0(eslint@8.57.0)(typescript@5.5.4): @@ -2592,7 +2602,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4) '@typescript-eslint/utils': 7.18.0(eslint@8.57.0)(typescript@5.5.4) - debug: 4.3.6 + debug: 4.3.7 eslint: 8.57.0 ts-api-utils: 1.3.0(typescript@5.5.4) typescript: 5.5.4 @@ -2605,8 +2615,8 @@ packages: engines: {node: ^18.18.0 || >=20.0.0} dev: true - /@typescript-eslint/types@8.3.0: - resolution: {integrity: sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==} + /@typescript-eslint/types@8.11.0: + resolution: {integrity: sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true @@ -2621,7 +2631,7 @@ packages: dependencies: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.3.6 + debug: 4.3.7 globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 @@ -2632,8 +2642,8 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree@8.3.0(typescript@5.5.4): - resolution: {integrity: sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==} + /@typescript-eslint/typescript-estree@8.11.0(typescript@5.5.4): + resolution: {integrity: sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -2641,9 +2651,9 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 8.3.0 - '@typescript-eslint/visitor-keys': 8.3.0 - debug: 4.3.6 + '@typescript-eslint/types': 8.11.0 + '@typescript-eslint/visitor-keys': 8.11.0 + debug: 4.3.7 fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 @@ -2670,16 +2680,16 @@ packages: - typescript dev: true - /@typescript-eslint/utils@8.3.0(eslint@8.57.0)(typescript@5.5.4): - resolution: {integrity: sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==} + /@typescript-eslint/utils@8.11.0(eslint@8.57.0)(typescript@5.5.4): + resolution: {integrity: sha512-CYiX6WZcbXNJV7UNB4PLDIBtSdRmRI/nb0FMyqHPTQD1rMjA0foPLaPUV39C/MxkTd/QKSeX+Gb34PPsDVC35g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 8.3.0 - '@typescript-eslint/types': 8.3.0 - '@typescript-eslint/typescript-estree': 8.3.0(typescript@5.5.4) + '@typescript-eslint/scope-manager': 8.11.0 + '@typescript-eslint/types': 8.11.0 + '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.5.4) eslint: 8.57.0 transitivePeerDependencies: - supports-color @@ -2694,11 +2704,11 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@8.3.0: - resolution: {integrity: sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==} + /@typescript-eslint/visitor-keys@8.11.0: + resolution: {integrity: sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/types': 8.3.0 + '@typescript-eslint/types': 8.11.0 eslint-visitor-keys: 3.4.3 dev: true @@ -2775,7 +2785,7 @@ packages: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.0.1 + fast-uri: 3.0.3 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 dev: false @@ -2942,7 +2952,7 @@ packages: resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==} engines: {node: '>=4'} dependencies: - tslib: 2.7.0 + tslib: 2.8.0 dev: false /astring@1.9.0: @@ -3580,8 +3590,8 @@ packages: ms: 2.1.2 dev: true - /debug@4.3.6: - resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} + /debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -3589,7 +3599,7 @@ packages: supports-color: optional: true dependencies: - ms: 2.1.2 + ms: 2.1.3 dev: true /decode-uri-component@0.2.2: @@ -3774,7 +3784,7 @@ packages: object-inspect: 1.13.2 object-keys: 1.1.1 object.assign: 4.1.5 - regexp.prototype.flags: 1.5.2 + regexp.prototype.flags: 1.5.3 safe-array-concat: 1.1.2 safe-regex-test: 1.0.3 string.prototype.trim: 1.2.9 @@ -3887,10 +3897,9 @@ packages: engines: {node: '>=6'} 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'} - dev: false /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} @@ -3915,7 +3924,7 @@ packages: lodash.zip: 4.2.0 dev: true - /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0): + /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.31.0)(eslint@8.57.0): resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -3924,13 +3933,13 @@ packages: dependencies: confusing-browser-globals: 1.0.11 eslint: 8.57.0 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) object.assign: 4.1.5 object.entries: 1.1.8 semver: 6.3.1 dev: true - /eslint-config-airbnb-typescript@18.0.0(@typescript-eslint/eslint-plugin@7.18.0)(@typescript-eslint/parser@7.18.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0): + /eslint-config-airbnb-typescript@18.0.0(@typescript-eslint/eslint-plugin@7.18.0)(@typescript-eslint/parser@7.18.0)(eslint-plugin-import@2.31.0)(eslint@8.57.0): resolution: {integrity: sha512-oc+Lxzgzsu8FQyFVa4QFaVKiitTYiiW3frB9KYW5OWdPrqFc7FzxgB20hP4cHMlr+MBzGcLl3jnCOVOydL9mIg==} peerDependencies: '@typescript-eslint/eslint-plugin': ^7.0.0 @@ -3940,7 +3949,7 @@ packages: '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0)(eslint@8.57.0)(typescript@5.5.4) '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) eslint: 8.57.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.31.0)(eslint@8.57.0) transitivePeerDependencies: - eslint-plugin-import dev: true @@ -3964,7 +3973,7 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.18.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0): + /eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.18.0)(eslint-plugin-import@2.31.0)(eslint@8.57.0): resolution: {integrity: sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -3978,14 +3987,14 @@ packages: optional: true dependencies: '@nolyfill/is-core-module': 1.0.39 - debug: 4.3.6 + debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.57.0 - eslint-module-utils: 2.8.2(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) fast-glob: 3.3.2 - get-tsconfig: 4.8.0 - is-bun-module: 1.1.0 + get-tsconfig: 4.8.1 + is-bun-module: 1.2.1 is-glob: 4.0.3 transitivePeerDependencies: - '@typescript-eslint/parser' @@ -3994,8 +4003,8 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.2(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0): - resolution: {integrity: sha512-3XnC5fDyc8M4J2E8pt8pmSVRX2M+5yWMCfI/kDZwauQeFgzQOuhcRBFKjTeJagqgk4sFKxe1mvNVnaWwImx/Tg==} + /eslint-module-utils@2.12.0(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0): + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -4019,13 +4028,13 @@ packages: debug: 3.2.7 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.18.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.18.0)(eslint-plugin-import@2.31.0)(eslint@8.57.0) transitivePeerDependencies: - supports-color dev: true - /eslint-module-utils@2.8.2(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0): - resolution: {integrity: sha512-3XnC5fDyc8M4J2E8pt8pmSVRX2M+5yWMCfI/kDZwauQeFgzQOuhcRBFKjTeJagqgk4sFKxe1mvNVnaWwImx/Tg==} + /eslint-module-utils@2.12.0(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0): + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -4048,7 +4057,7 @@ packages: '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) debug: 3.2.7 eslint: 8.57.0 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.18.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.18.0)(eslint-plugin-import@2.31.0)(eslint@8.57.0) transitivePeerDependencies: - supports-color dev: true @@ -4066,16 +4075,17 @@ packages: req-all: 0.1.0 dev: true - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0): - resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} + /eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0): + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 peerDependenciesMeta: '@typescript-eslint/parser': optional: true dependencies: + '@rtsao/scc': 1.1.0 '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -4085,7 +4095,7 @@ packages: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.2(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -4094,6 +4104,7 @@ packages: object.groupby: 1.0.3 object.values: 1.2.0 semver: 6.3.1 + string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 transitivePeerDependencies: - eslint-import-resolver-typescript @@ -4101,8 +4112,8 @@ packages: - supports-color dev: true - /eslint-plugin-jest@28.8.1(@typescript-eslint/eslint-plugin@7.18.0)(eslint@8.57.0)(jest@29.7.0)(typescript@5.5.4): - resolution: {integrity: sha512-G46XMyYu6PtSNJUkQ0hsPjzXYpzq/O4vpCciMizTKRJG8kNsRreGoMRDG6H9FIB/xVgfFuclVnuX4XRvFUzrZQ==} + /eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@7.18.0)(eslint@8.57.0)(jest@29.7.0)(typescript@5.5.4): + resolution: {integrity: sha512-HIQ3t9hASLKm2IhIOqnu+ifw7uLZkIlR7RYNv7fMcEi/p0CIiJmfriStQS2LDkgtY4nyLbIZAD+JL347Yc2ETQ==} engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} peerDependencies: '@typescript-eslint/eslint-plugin': ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -4115,7 +4126,7 @@ packages: optional: true dependencies: '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0)(eslint@8.57.0)(typescript@5.5.4) - '@typescript-eslint/utils': 8.3.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/utils': 8.11.0(eslint@8.57.0)(typescript@5.5.4) eslint: 8.57.0 jest: 29.7.0(@types/node@20.16.2)(ts-node@10.9.2) transitivePeerDependencies: @@ -4141,7 +4152,7 @@ packages: eslint-config-prettier: 9.1.0(eslint@8.57.0) prettier: 3.3.3 prettier-linter-helpers: 1.0.0 - synckit: 0.9.1 + synckit: 0.9.2 dev: true /eslint-plugin-promise@6.6.0(eslint@8.57.0): @@ -4408,8 +4419,8 @@ packages: resolution: {integrity: sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==} dev: false - /fast-uri@3.0.1: - resolution: {integrity: sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==} + /fast-uri@3.0.3: + resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==} dev: false /fast-xml-parser@4.4.1: @@ -4587,6 +4598,7 @@ packages: has-proto: 1.0.1 has-symbols: 1.0.3 hasown: 2.0.0 + dev: false /get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} @@ -4630,8 +4642,8 @@ packages: es-errors: 1.3.0 get-intrinsic: 1.2.4 - /get-tsconfig@4.8.0: - resolution: {integrity: sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==} + /get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} dependencies: resolve-pkg-maps: 1.0.0 dev: true @@ -4660,6 +4672,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 @@ -4702,7 +4715,7 @@ packages: /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.4 /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -4731,6 +4744,7 @@ packages: /has-proto@1.0.1: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} engines: {node: '>= 0.4'} + dev: false /has-proto@1.0.3: resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} @@ -4789,6 +4803,7 @@ packages: engines: {node: '>= 0.4'} dependencies: function-bind: 1.1.2 + dev: false /hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} @@ -4852,6 +4867,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 @@ -4871,7 +4887,7 @@ packages: resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==} engines: {node: '>= 0.10'} dependencies: - hasown: 2.0.0 + hasown: 2.0.2 dev: true /is-arguments@1.1.1: @@ -4909,8 +4925,8 @@ packages: resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} dev: true - /is-bun-module@1.1.0: - resolution: {integrity: sha512-4mTAVPlrXpaN3jtF0lsnPCMGnq4+qZjVIKq0HCpfcqf8OC1SM5oATCIAPM5V5FN05qp2NNnFndphmdZS9CV3hA==} + /is-bun-module@1.2.1: + resolution: {integrity: sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==} dependencies: semver: 7.6.3 dev: true @@ -4926,23 +4942,17 @@ packages: ci-info: 2.0.0 dev: true - /is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} - dependencies: - hasown: 2.0.0 - /is-core-module@2.15.1: resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} engines: {node: '>= 0.4'} dependencies: hasown: 2.0.2 - dev: true /is-data-descriptor@1.0.1: resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} engines: {node: '>= 0.4'} dependencies: - hasown: 2.0.0 + hasown: 2.0.2 dev: true /is-data-view@1.0.1: @@ -5047,7 +5057,7 @@ packages: /is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 dev: false /is-regex@1.1.4: @@ -5897,6 +5907,10 @@ packages: object-visit: 1.0.1 dev: true + /markdown-escape@2.0.0: + resolution: {integrity: sha512-Trz4v0+XWlwy68LJIyw3bLbsJiC8XAbRCKF9DbEtZjyndKOGVx6n+wNB0VfoRmY2LKboQLeniap3xrb6LGSJ8A==} + dev: false + /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} dev: true @@ -6443,8 +6457,8 @@ packages: safe-regex: 1.1.0 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 @@ -6520,7 +6534,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 @@ -6539,8 +6553,8 @@ packages: dependencies: glob: 7.2.3 - /rollup@2.79.1: - resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} + /rollup@2.79.2: + resolution: {integrity: sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==} engines: {node: '>=10.0.0'} hasBin: true optionalDependencies: @@ -6950,12 +6964,12 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - /synckit@0.9.1: - resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} + /synckit@0.9.2: + resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} engines: {node: ^14.18.0 || >=16.0.0} dependencies: '@pkgr/core': 0.1.1 - tslib: 2.7.0 + tslib: 2.8.0 dev: true /tapable@2.2.1: @@ -7087,8 +7101,8 @@ packages: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} dev: false - /tslib@2.7.0: - resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + /tslib@2.8.0: + resolution: {integrity: sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==} /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -7211,7 +7225,7 @@ packages: browserslist: '>= 4.21.0' dependencies: browserslist: 4.22.2 - escalade: 3.1.1 + escalade: 3.2.0 picocolors: 1.0.0 dev: true @@ -7435,7 +7449,7 @@ packages: 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 @@ -7458,7 +7472,7 @@ packages: dev: false file:../lib/dist/cdk-practical-constructs-0.0.1.tgz(@asteasolutions/zod-to-openapi@7.0.0)(aws-cdk-lib@2.155.0)(zod@3.23.8): - resolution: {integrity: sha512-ZKTk0nCY2DMvvSi0dPxlUXITsd2ahY6cN4GIXyRs+EB65HSmAQj/ftDJtOyy26zJ3MeVW/fzrGo2/5e5xROuNA==, tarball: file:../lib/dist/cdk-practical-constructs-0.0.1.tgz} + resolution: {integrity: sha512-3yWg1yl6MHO+fsqQuDq4tkrCbDZzn0nN+1RwI99WoqgoGz2ARawXiPQ6a3dsX8rhq+q3ySujmlu5mYAOLrRVRw==, tarball: file:../lib/dist/cdk-practical-constructs-0.0.1.tgz} id: file:../lib/dist/cdk-practical-constructs-0.0.1.tgz name: cdk-practical-constructs version: 0.0.1 @@ -7470,7 +7484,7 @@ packages: '@apiture/openapi-down-convert': 0.9.0 '@asteasolutions/zod-to-openapi': 7.0.0(zod@3.23.8) '@aws-sdk/client-secrets-manager': 3.624.0 - '@stoplight/spectral-cli': 6.11.1 + '@stoplight/spectral-cli': 6.13.1 aws-cdk-lib: 2.155.0(constructs@10.3.0) aws-lambda: 1.0.7 axios: 1.7.5 diff --git a/lib/src/wso2/wso2-api/handler/index.ts b/lib/src/wso2/wso2-api/handler/index.ts index 2b070ef..a6a799e 100644 --- a/lib/src/wso2/wso2-api/handler/index.ts +++ b/lib/src/wso2/wso2-api/handler/index.ts @@ -7,7 +7,7 @@ import { Wso2ApiCustomResourceProperties } from '../types'; import { prepareAxiosForWso2Calls } from '../../wso2-utils'; import { applyRetryDefaults, truncateStr } from '../../utils'; -import { createUpdateAndPublishApiInWso2, findWso2Api, removeApiInWso2 } from './wso2-v1'; +import { createUpdateAndChangeLifecycleStatusInWso2, findWso2Api, removeApiInWso2 } from './wso2-v1'; export type Wso2ApiCustomResourceEvent = CdkCustomResourceEvent & { ResourceProperties: Wso2ApiCustomResourceProperties; @@ -45,7 +45,6 @@ export const handler = async ( try { console.log('>>> Prepare WSO2 API client...'); - // const wso2Client = await prepareWso2ApiClient(event.ResourceProperties.wso2Config); const wso2Axios = await prepareAxiosForWso2Calls(event.ResourceProperties.wso2Config); if (event.RequestType === 'Create' || event.RequestType === 'Update') { @@ -122,13 +121,14 @@ const createOrUpdateWso2Api = async ( } if (event.RequestType === 'Create' || event.RequestType === 'Update') { - return createUpdateAndPublishApiInWso2({ + return createUpdateAndChangeLifecycleStatusInWso2({ wso2Axios, apiDefinition: event.ResourceProperties.apiDefinition, openapiDocument: event.ResourceProperties.openapiDocument, wso2Tenant: event.ResourceProperties.wso2Config.tenant ?? '', apiBeforeUpdate, retryOptions: applyRetryDefaults(event.ResourceProperties.retryOptions), + lifecycleStatus: event.ResourceProperties.lifecycleStatus, }); } diff --git a/lib/src/wso2/wso2-api/handler/wso2-v1.ts b/lib/src/wso2/wso2-api/handler/wso2-v1.ts index 0c06e9e..c290847 100644 --- a/lib/src/wso2/wso2-api/handler/wso2-v1.ts +++ b/lib/src/wso2/wso2-api/handler/wso2-v1.ts @@ -19,6 +19,7 @@ import { objectWithContentOrUndefined, } from '../utils'; import { RetryOptions } from '../../types'; +import { Wso2ApiProps } from '../types'; export const findWso2Api = async (args: { wso2Axios: AxiosInstance; @@ -74,16 +75,13 @@ export const findWso2Api = async (args: { ); }; -export type UpsertWso2Args = { +export type UpsertWso2Args = Pick & Required> & { wso2Axios: AxiosInstance; wso2Tenant: string; apiBeforeUpdate?: { id?: string; lastUpdatedTime?: string; }; - apiDefinition: Wso2ApiDefinitionV1; - openapiDocument: OpenAPIObject; - retryOptions: RetryOptions; }; /** @@ -101,10 +99,10 @@ export const removeApiInWso2 = async (args: { /** * Perform calls in WSO2 API to create or update an API, update Openapi definitions - * and change the API lifecycle to PUBLISHED + * and change the API lifecycle to the desired status (if defined) * @returns {string} Id of the API in WSO2 */ -export const createUpdateAndPublishApiInWso2 = async ( +export const createUpdateAndChangeLifecycleStatusInWso2 = async ( args: UpsertWso2Args, ): Promise<{ wso2ApiId: string; endpointUrl?: string }> => { const needWaitBeforeUpdateOpenapiDocument = await checkApiDefAndOpenapiOverlap(args); @@ -117,6 +115,8 @@ export const createUpdateAndPublishApiInWso2 = async ( args.retryOptions.mutationRetries, ); + console.log(`API created/updated in WSO2. apiId='${wso2ApiId}'`); + if (needWaitBeforeUpdateOpenapiDocument) { console.log(''); console.log( @@ -138,47 +138,97 @@ export const createUpdateAndPublishApiInWso2 = async ( args.retryOptions.mutationRetries, ); - console.log(''); - console.log(`>>> Change api status to 'PUBLISHED'...`); - // will retry changing to PUBLISHED if fails - const endpointUrl = await backOff(async () => - publishApiInWso2AndCheck({ - wso2Axios: args.wso2Axios, - wso2ApiId, - apiDefinition: args.apiDefinition, - wso2Tenant: args.wso2Tenant, - retryOptions: args.retryOptions, - }), - ); + if(!args.lifecycleStatus) { + console.log(''); + console.log(`>>> Changing lifecycle status to '${args.lifecycleStatus}'...`); + // will retry changing to PUBLISHED if fails + const endpointUrl = await backOff(async () => + changeLifecycleStatusInWso2AndCheck({ + wso2Axios: args.wso2Axios, + wso2ApiId, + apiDefinition: args.apiDefinition, + wso2Tenant: args.wso2Tenant, + retryOptions: args.retryOptions, + lifecycleStatus: args.lifecycleStatus, + }), + ); + } - console.log('API created/updated and published successfully on WSO2 server'); + // get endpoint url + console.log(`Getting API endpoint url`); + const apir = await args.wso2Axios.get(`/api/am/store/v1/apis/${wso2ApiId}`); + + // find the endpoint URL of the environment that was defined in this API + const apid = apir.data as DevPortalAPIv1; + const endpointUrl = apid.endpointURLs?.reduce((acc, elem) => { + if ( + elem.environmentName && + args.apiDefinition.gatewayEnvironments?.includes(elem.environmentName) + ) { + if (elem.URLs?.https) { + return elem.URLs?.https; + } + if (elem.defaultVersionURLs?.https) { + return elem.defaultVersionURLs?.https; + } + } + return acc; + }, ''); + + console.log('API created/updated successfully on WSO2 server'); return { wso2ApiId, endpointUrl }; }; -export const publishApiInWso2AndCheck = async (args: { +export const changeLifecycleStatusInWso2AndCheck = async (args: Pick & Required> & { wso2Axios: AxiosInstance; - apiDefinition: Wso2ApiDefinitionV1; wso2ApiId: string; wso2Tenant: string; - retryOptions: RetryOptions; -}): Promise => { - console.log(`Changing API status to PUBLISHED in WSO2`); +}): Promise => { + + console.log(`Changing API status to '${args.lifecycleStatus}' in WSO2`); + + // define the action to be taken based on target lifecycle status + let action = ''; + switch (args.lifecycleStatus) { + case 'PUBLISHED': + action = 'Publish'; + break; + case 'CREATED': + action = 'Demote to created'; + break; + case 'DEPRECATED': + action = 'Deprecate'; + break; + case 'BLOCKED': + action = 'Block'; + break; + case 'RETIRED': + action = 'Retire'; + break; + case 'PROTOTYPED': + action = 'Deploy as a Prototype'; + break; + default: + throw new Error(`Lifecycle status '${args.lifecycleStatus}' is not supported`); + } + + console.log(`Using action '${action}' for lifecycle change`); await args.wso2Axios.post( '/api/am/publisher/v1/apis/change-lifecycle', {}, { params: { apiId: args.wso2ApiId, - action: 'Publish', + action, }, }, ); - // wait for API to be created by retrying checks + // wait for API to have the desired status by retrying checks await backOff(async () => { console.log(''); - console.log('Checking if API is PUBLISHED...'); + console.log(`Checking if API is in lifecycle status '${args.lifecycleStatus}'...`); const fapi = await findWso2Api({ apiDefinition: args.apiDefinition, wso2Axios: args.wso2Axios, @@ -188,43 +238,25 @@ export const publishApiInWso2AndCheck = async (args: { if (!fapi) { throw new Error(`API ${args.wso2ApiId} could not be found`); } - if (fapi.lifeCycleStatus !== 'PUBLISHED') { - throw new Error(`API ${args.wso2ApiId} is in status ${fapi.lifeCycleStatus} (not PUBLISHED)`); - } - console.log('API status PUBLISHED check OK'); - }, args.retryOptions.checkRetries); - // get endpoint url - console.log(`Getting API endpoint url`); - const apir = await args.wso2Axios.get(`/api/am/store/v1/apis/${args.wso2ApiId}`); - - // find the endpoint URL of the environment that was defined in this API - const apid = apir.data as DevPortalAPIv1; - const endpointUrl = apid.endpointURLs?.reduce((acc, elem) => { - if ( - elem.environmentName && - args.apiDefinition.gatewayEnvironments?.includes(elem.environmentName) - ) { - if (elem.URLs?.https) { - return elem.URLs?.https; - } - if (elem.defaultVersionURLs?.https) { - return elem.defaultVersionURLs?.https; - } + // Workflow trigger detected. It might indicate the need for manual approval or a slow process + // so we will ignore checking the API lifecycle status check for now + if(fapi.workflowStatus !== '' && fapi.workflowStatus !== 'APPROVED') { + console.log(`API lifecycle status check SKIPPED. API ${args.wso2ApiId} has workflow status '${fapi.workflowStatus}', which might require manual approval before the actual lifecycle status is changed`); + return } - return acc; - }, ''); - return endpointUrl; + if (fapi.lifeCycleStatus !== args.lifecycleStatus) { + throw new Error(`API ${args.wso2ApiId} is in status ${fapi.lifeCycleStatus} (not '${args.lifecycleStatus}')`); + } + console.log(`API lifecycle status check OK. lifecycleStatus='${args.lifecycleStatus}'`); + }, args.retryOptions.checkRetries); }; -export const updateOpenapiInWso2AndCheck = async (args: { +export const updateOpenapiInWso2AndCheck = async (args: Required> & { wso2Axios: AxiosInstance; wso2ApiId: string; wso2Tenant: string; - openapiDocument: oas30.OpenAPIObject; - apiDefinition: Wso2ApiDefinitionV1; - retryOptions: RetryOptions; }): Promise => { console.log('Updating Openapi document in WSO2'); const fdata = new FormData(); diff --git a/lib/src/wso2/wso2-api/types.ts b/lib/src/wso2/wso2-api/types.ts index 3b77595..fcc7fd6 100644 --- a/lib/src/wso2/wso2-api/types.ts +++ b/lib/src/wso2/wso2-api/types.ts @@ -17,4 +17,11 @@ export type Wso2ApiProps = Wso2BaseProperties & { * The paths/operations in this document will be used to configure routes in WSO2 */ openapiDocument: oas30.OpenAPIObject; + /** + * The desired lifecycle status of the API in WSO2. + * If not defined, the status of the API won't be checked and no changes to the status will be performed. + * If a workflow trigger is detected during the lifecycle change (e.g for manual approval), we skip the status change check + * as the workflow might take a long time to complete. + */ + lifecycleStatus?: 'CREATED' | 'PUBLISHED' | 'DEPRECATED' | 'BLOCKED' | 'RETIRED' | 'PROTOTYPED'; }; diff --git a/lib/src/wso2/wso2-api/v1/types.ts b/lib/src/wso2/wso2-api/v1/types.ts index 29cc128..e152b28 100644 --- a/lib/src/wso2/wso2-api/v1/types.ts +++ b/lib/src/wso2/wso2-api/v1/types.ts @@ -33,5 +33,5 @@ export type Wso2ApiListV1 = { export type ApiFromListV1 = Pick< PublisherPortalAPIv1, - 'id' | 'name' | 'type' | 'context' | 'version' | 'provider' | 'lifeCycleStatus' + 'id' | 'name' | 'type' | 'context' | 'version' | 'provider' | 'lifeCycleStatus' | 'workflowStatus' >; diff --git a/lib/src/wso2/wso2-api/wso2-api.ts b/lib/src/wso2/wso2-api/wso2-api.ts index bd511f4..7fa0523 100644 --- a/lib/src/wso2/wso2-api/wso2-api.ts +++ b/lib/src/wso2/wso2-api/wso2-api.ts @@ -58,6 +58,7 @@ export class Wso2Api extends Construct { apiDefinition: wso2ApiDefs, openapiDocument: props.openapiDocument, retryOptions: props.retryOptions, + lifecycleStatus: props.lifecycleStatus, } satisfies Wso2ApiCustomResourceProperties, resourceType: 'Custom::Wso2Api', removalPolicy: props.removalPolicy ?? RemovalPolicy.RETAIN, @@ -73,7 +74,7 @@ export const validateProps = (props: Wso2ApiProps): void => { if (!props.wso2Config) throw new Error('wso2Config is required'); if (!props.wso2Config.baseApiUrl) throw new Error('wso2Config.baseApiUrl is required'); if (!props.wso2Config.credentialsSecretId) { - throw new Error('wso2Config.credentialsSecretManagerPath is required'); + throw new Error('wso2Config.credentialsSecretId is required'); } validateWso2ApiDefs(props.apiDefinition); if (!props.openapiDocument.openapi.startsWith('3.0')) { From b5a2e4adef485b217c17202bb86a8e1ddcc3d8e6 Mon Sep 17 00:00:00 2001 From: flaviostutz Date: Mon, 11 Nov 2024 18:13:47 +0100 Subject: [PATCH 2/4] chore: fixing unit tests --- lib/src/wso2/wso2-api/handler/index.test.ts | 135 +++++++++++++++----- lib/src/wso2/wso2-api/handler/index.ts | 6 +- lib/src/wso2/wso2-api/handler/wso2-v1.ts | 59 +++++---- lib/src/wso2/wso2-api/types.ts | 2 +- 4 files changed, 144 insertions(+), 58 deletions(-) diff --git a/lib/src/wso2/wso2-api/handler/index.test.ts b/lib/src/wso2/wso2-api/handler/index.test.ts index 438a4ff..e00c2a0 100644 --- a/lib/src/wso2/wso2-api/handler/index.test.ts +++ b/lib/src/wso2/wso2-api/handler/index.test.ts @@ -63,12 +63,48 @@ describe('wso2 custom resource lambda', () => { .post(/.*\/publisher\/v1\/apis\?.*$/) .reply(201, testDefs); + // api get mock + nock(baseWso2Url) + .get(/.*\/publisher\/v1\/apis\/[^\\/]*$/) + .times(2) // check if content matches + .reply(200, { ...testDefs, lastUpdatedTime: '2020-10-10' }); + + const nocksUpdateCreate = nockAfterCreateUpdateAndChangeLifecycleStatusInWso2(testDefs); + + const eres = await handler( + testCFNEventCreate({ + ...testEvent, + }), + ); + expect(eres.PhysicalResourceId).toBe('123-456'); + expect(eres.Status).toBe('SUCCESS'); + + // check if the correct endpoints were invoked during update/create process + // eslint-disable-next-line no-restricted-syntax + for (const n of nocksUpdateCreate) { + n.done(); + } + }); + + it('wso2 api create and PUBLISH', async () => { + nockBasicWso2SDK(); + // api list mock nock(baseWso2Url) .get(/.*\/publisher\/v1\/apis$/) .query(true) - .times(2) // check if updated, check if published - .reply(200, toResultList(testDefs)); + .times(1) // check create or update + .reply(200, { list: [] }); + + const testDefs: Wso2ApiDefinitionV1 = { + ...testBasicWso2ApiDefs(), + id: '123-456', + }; + + // api create mock + nock(baseWso2Url) + .post(/.*\/publisher\/v1\/apis\?.*$/) + .reply(201, testDefs); // api get mock nock(baseWso2Url) @@ -76,15 +112,25 @@ describe('wso2 custom resource lambda', () => { .times(2) // check if content matches .reply(200, { ...testDefs, lastUpdatedTime: '2020-10-10' }); - nockAfterUpdateCreate(testDefs); + const nocksUpdateCreate = nockAfterCreateUpdateAndChangeLifecycleStatusInWso2( + testDefs, + 'Publish', + ); const eres = await handler( testCFNEventCreate({ ...testEvent, + lifecycleStatus: 'PUBLISHED', }), ); expect(eres.PhysicalResourceId).toBe('123-456'); expect(eres.Status).toBe('SUCCESS'); + + // check if the correct endpoints were invoked during update/create process + // eslint-disable-next-line no-restricted-syntax + for (const n of nocksUpdateCreate) { + n.done(); + } }); it('basic wso2 api update', async () => { @@ -124,7 +170,7 @@ describe('wso2 custom resource lambda', () => { .times(1) // check if content matches .reply(200, { ...testDefs, lastUpdatedTime: '2020-10-11' }); - nockAfterUpdateCreate(testDefs); + nockAfterCreateUpdateAndChangeLifecycleStatusInWso2(testDefs); const eres = await handler( testCFNEventCreate({ @@ -165,7 +211,7 @@ describe('wso2 custom resource lambda', () => { .put(/.*\/publisher\/v1\/apis\/.*$/) .reply(201, testDefs); - nockAfterUpdateCreate(testDefs); + nockAfterCreateUpdateAndChangeLifecycleStatusInWso2(testDefs); const eres = await handler( testCFNEventUpdate( @@ -231,7 +277,7 @@ describe('wso2 custom resource lambda', () => { .times(1) // check if content matches .reply(200, { ...testDefs, lastUpdatedTime: '2020-10-11' }); - nockAfterUpdateCreate(testDefs); + nockAfterCreateUpdateAndChangeLifecycleStatusInWso2(testDefs); const eres = await handler( testCFNEventUpdate( @@ -441,37 +487,66 @@ describe('wso2 custom resource lambda', () => { ); }; - const nockAfterUpdateCreate = (testDefs: Wso2ApiDefinitionV1): void => { + const nockAfterCreateUpdateAndChangeLifecycleStatusInWso2 = ( + testDefs: Wso2ApiDefinitionV1, + lifecycleAction?: string, + ): nock.Scope[] => { + const nocks: nock.Scope[] = []; + // api openapi update mock - nock(baseWso2Url) - .put(/.*\/publisher\/v1\/apis\/123-456\/swagger/) - .times(1) - .reply(200); + nocks.push( + nock(baseWso2Url) + .put(/.*\/publisher\/v1\/apis\/123-456\/swagger/) + .times(1) + .reply(200), + ); // api openapi get mock - nock(baseWso2Url) - .get(/.*\/publisher\/v1\/apis\/123-456\/swagger/) - .times(1) - .reply(200, JSON.stringify(testEvent.openapiDocument), ['Content-Type', 'text/plain']); + nocks.push( + nock(baseWso2Url) + .get(/.*\/publisher\/v1\/apis\/123-456\/swagger/) + .times(1) + .reply(200, JSON.stringify(testEvent.openapiDocument), ['Content-Type', 'text/plain']), + ); - // api change to published mock - nock(baseWso2Url) - .post(/.*\/publisher\/v1\/apis\/change-lifecycle/) - .query({ apiId: '123-456', action: 'Publish' }) - .times(1) - .reply(200); + if (lifecycleAction) { + console.log('NOCK CHANGE LIFE CYCLE'); + // api change to published mock + nocks.push( + nock(baseWso2Url) + .post(/.*\/publisher\/v1\/apis\/change-lifecycle/) + .query({ apiId: '123-456', action: lifecycleAction }) + .times(1) + .reply(200), + ); + + // api get apis mock for checking if lifecycle was changed + nocks.push( + nock(baseWso2Url) + .get(/.*\/publisher\/v1\/apis$/) + .query(true) + .times(1) // check if it is published + .reply(200, toResultList(testDefs)), + ); + } // api get endpoint urls mock - nock(baseWso2Url) - .get(/.*\/store\/v1\/apis\/123-456$/) - .times(1) - .reply(200, testDefs); + nocks.push( + nock(baseWso2Url) + .get(/.*\/store\/v1\/apis\/123-456$/) + .times(1) + .reply(200, testDefs), + ); // api get apis mock - nock(baseWso2Url) - .get(/.*\/publisher\/v1\/apis$/) - .query(true) - .times(1) // check if it is published - .reply(200, toResultList(testDefs)); + nocks.push( + nock(baseWso2Url) + .get(/.*\/publisher\/v1\/apis$/) + .query(true) + .times(1) // check if it is published + .reply(200, toResultList(testDefs)), + ); + + return nocks; }; }); diff --git a/lib/src/wso2/wso2-api/handler/index.ts b/lib/src/wso2/wso2-api/handler/index.ts index a6a799e..47e2859 100644 --- a/lib/src/wso2/wso2-api/handler/index.ts +++ b/lib/src/wso2/wso2-api/handler/index.ts @@ -7,7 +7,11 @@ import { Wso2ApiCustomResourceProperties } from '../types'; import { prepareAxiosForWso2Calls } from '../../wso2-utils'; import { applyRetryDefaults, truncateStr } from '../../utils'; -import { createUpdateAndChangeLifecycleStatusInWso2, findWso2Api, removeApiInWso2 } from './wso2-v1'; +import { + createUpdateAndChangeLifecycleStatusInWso2, + findWso2Api, + removeApiInWso2, +} from './wso2-v1'; export type Wso2ApiCustomResourceEvent = CdkCustomResourceEvent & { ResourceProperties: Wso2ApiCustomResourceProperties; diff --git a/lib/src/wso2/wso2-api/handler/wso2-v1.ts b/lib/src/wso2/wso2-api/handler/wso2-v1.ts index c290847..8b22c84 100644 --- a/lib/src/wso2/wso2-api/handler/wso2-v1.ts +++ b/lib/src/wso2/wso2-api/handler/wso2-v1.ts @@ -1,5 +1,4 @@ /* eslint-disable no-console */ -import { OpenAPIObject } from 'openapi3-ts/oas30'; import { oas30 } from 'openapi3-ts'; import FormData from 'form-data'; import { backOff } from 'exponential-backoff'; @@ -18,7 +17,6 @@ import { normalizeCorsConfigurationValues, objectWithContentOrUndefined, } from '../utils'; -import { RetryOptions } from '../../types'; import { Wso2ApiProps } from '../types'; export const findWso2Api = async (args: { @@ -75,14 +73,15 @@ export const findWso2Api = async (args: { ); }; -export type UpsertWso2Args = Pick & Required> & { - wso2Axios: AxiosInstance; - wso2Tenant: string; - apiBeforeUpdate?: { - id?: string; - lastUpdatedTime?: string; +export type UpsertWso2Args = Pick & + Required> & { + wso2Axios: AxiosInstance; + wso2Tenant: string; + apiBeforeUpdate?: { + id?: string; + lastUpdatedTime?: string; + }; }; -}; /** * Delete API in WSO2 server @@ -138,11 +137,11 @@ export const createUpdateAndChangeLifecycleStatusInWso2 = async ( args.retryOptions.mutationRetries, ); - if(!args.lifecycleStatus) { + if (args.lifecycleStatus) { console.log(''); console.log(`>>> Changing lifecycle status to '${args.lifecycleStatus}'...`); // will retry changing to PUBLISHED if fails - const endpointUrl = await backOff(async () => + await backOff(async () => changeLifecycleStatusInWso2AndCheck({ wso2Axios: args.wso2Axios, wso2ApiId, @@ -180,12 +179,14 @@ export const createUpdateAndChangeLifecycleStatusInWso2 = async ( return { wso2ApiId, endpointUrl }; }; -export const changeLifecycleStatusInWso2AndCheck = async (args: Pick & Required> & { - wso2Axios: AxiosInstance; - wso2ApiId: string; - wso2Tenant: string; -}): Promise => { - +export const changeLifecycleStatusInWso2AndCheck = async ( + args: Pick & + Required> & { + wso2Axios: AxiosInstance; + wso2ApiId: string; + wso2Tenant: string; + }, +): Promise => { console.log(`Changing API status to '${args.lifecycleStatus}' in WSO2`); // define the action to be taken based on target lifecycle status @@ -241,23 +242,29 @@ export const changeLifecycleStatusInWso2AndCheck = async (args: Pick> & { - wso2Axios: AxiosInstance; - wso2ApiId: string; - wso2Tenant: string; -}): Promise => { +export const updateOpenapiInWso2AndCheck = async ( + args: Required> & { + wso2Axios: AxiosInstance; + wso2ApiId: string; + wso2Tenant: string; + }, +): Promise => { console.log('Updating Openapi document in WSO2'); const fdata = new FormData(); const openapiDocumentStr = JSON.stringify(args.openapiDocument); diff --git a/lib/src/wso2/wso2-api/types.ts b/lib/src/wso2/wso2-api/types.ts index fcc7fd6..93a6bfd 100644 --- a/lib/src/wso2/wso2-api/types.ts +++ b/lib/src/wso2/wso2-api/types.ts @@ -18,7 +18,7 @@ export type Wso2ApiProps = Wso2BaseProperties & { */ openapiDocument: oas30.OpenAPIObject; /** - * The desired lifecycle status of the API in WSO2. + * The desired lifecycle status of the API in WSO2. * If not defined, the status of the API won't be checked and no changes to the status will be performed. * If a workflow trigger is detected during the lifecycle change (e.g for manual approval), we skip the status change check * as the workflow might take a long time to complete. From 84ba80eef5e5e7e49c2bddcba9bfd7ddbdf9e234 Mon Sep 17 00:00:00 2001 From: flaviostutz Date: Mon, 11 Nov 2024 18:26:41 +0100 Subject: [PATCH 3/4] chore: improve test coverge --- examples/pnpm-lock.yaml | 40 ++++++++++++------------ lib/src/wso2/wso2-api/handler/wso2-v1.ts | 35 ++++++++------------- 2 files changed, 33 insertions(+), 42 deletions(-) diff --git a/examples/pnpm-lock.yaml b/examples/pnpm-lock.yaml index 2e551b8..8664a34 100644 --- a/examples/pnpm-lock.yaml +++ b/examples/pnpm-lock.yaml @@ -2592,12 +2592,12 @@ packages: '@typescript-eslint/visitor-keys': 7.18.0 dev: true - /@typescript-eslint/scope-manager@8.13.0: - resolution: {integrity: sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA==} + /@typescript-eslint/scope-manager@8.14.0: + resolution: {integrity: sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/types': 8.13.0 - '@typescript-eslint/visitor-keys': 8.13.0 + '@typescript-eslint/types': 8.14.0 + '@typescript-eslint/visitor-keys': 8.14.0 dev: true /@typescript-eslint/type-utils@7.18.0(eslint@8.57.0)(typescript@5.5.4): @@ -2625,8 +2625,8 @@ packages: engines: {node: ^18.18.0 || >=20.0.0} dev: true - /@typescript-eslint/types@8.13.0: - resolution: {integrity: sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng==} + /@typescript-eslint/types@8.14.0: + resolution: {integrity: sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true @@ -2652,8 +2652,8 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree@8.13.0(typescript@5.5.4): - resolution: {integrity: sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g==} + /@typescript-eslint/typescript-estree@8.14.0(typescript@5.5.4): + resolution: {integrity: sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -2661,8 +2661,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 8.13.0 - '@typescript-eslint/visitor-keys': 8.13.0 + '@typescript-eslint/types': 8.14.0 + '@typescript-eslint/visitor-keys': 8.14.0 debug: 4.3.7 fast-glob: 3.3.2 is-glob: 4.0.3 @@ -2690,16 +2690,16 @@ packages: - typescript dev: true - /@typescript-eslint/utils@8.13.0(eslint@8.57.0)(typescript@5.5.4): - resolution: {integrity: sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ==} + /@typescript-eslint/utils@8.14.0(eslint@8.57.0)(typescript@5.5.4): + resolution: {integrity: sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.0) - '@typescript-eslint/scope-manager': 8.13.0 - '@typescript-eslint/types': 8.13.0 - '@typescript-eslint/typescript-estree': 8.13.0(typescript@5.5.4) + '@typescript-eslint/scope-manager': 8.14.0 + '@typescript-eslint/types': 8.14.0 + '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.5.4) eslint: 8.57.0 transitivePeerDependencies: - supports-color @@ -2714,11 +2714,11 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@8.13.0: - resolution: {integrity: sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw==} + /@typescript-eslint/visitor-keys@8.14.0: + resolution: {integrity: sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/types': 8.13.0 + '@typescript-eslint/types': 8.14.0 eslint-visitor-keys: 3.4.3 dev: true @@ -4136,7 +4136,7 @@ packages: optional: true dependencies: '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0)(eslint@8.57.0)(typescript@5.5.4) - '@typescript-eslint/utils': 8.13.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/utils': 8.14.0(eslint@8.57.0)(typescript@5.5.4) eslint: 8.57.0 jest: 29.7.0(@types/node@20.16.2)(ts-node@10.9.2) transitivePeerDependencies: @@ -7482,7 +7482,7 @@ packages: dev: false file:../lib/dist/cdk-practical-constructs-0.0.1.tgz(@asteasolutions/zod-to-openapi@7.0.0)(aws-cdk-lib@2.155.0)(zod@3.23.8): - resolution: {integrity: sha512-5H/Y7HRg2tf0OEC6ec5v9o4shBUJOg2YdekWB2qC0Du/Rwv9cL/iH9SYJCevv9sv2wqZ+Pg/skYEHczgUenm8Q==, tarball: file:../lib/dist/cdk-practical-constructs-0.0.1.tgz} + resolution: {integrity: sha512-Ib21RU+8A6//9zs0vzK1E9sSEyOmYPwgV4kx5HW6oGFeBtfqkrYbn2Xyvb09BWW6u1fYQiXxMzRjvknlLYTdkg==, tarball: file:../lib/dist/cdk-practical-constructs-0.0.1.tgz} id: file:../lib/dist/cdk-practical-constructs-0.0.1.tgz name: cdk-practical-constructs version: 0.0.1 diff --git a/lib/src/wso2/wso2-api/handler/wso2-v1.ts b/lib/src/wso2/wso2-api/handler/wso2-v1.ts index 8b22c84..b5af323 100644 --- a/lib/src/wso2/wso2-api/handler/wso2-v1.ts +++ b/lib/src/wso2/wso2-api/handler/wso2-v1.ts @@ -179,6 +179,15 @@ export const createUpdateAndChangeLifecycleStatusInWso2 = async ( return { wso2ApiId, endpointUrl }; }; +const actionMap = { + PUBLISHED: 'Publish', + CREATED: 'Demote to created', + DEPRECATED: 'Deprecate', + BLOCKED: 'Block', + RETIRED: 'Retire', + PROTOTYPED: 'Deploy as a Prototype', +}; + export const changeLifecycleStatusInWso2AndCheck = async ( args: Pick & Required> & { @@ -187,31 +196,13 @@ export const changeLifecycleStatusInWso2AndCheck = async ( wso2Tenant: string; }, ): Promise => { + if (!args.lifecycleStatus) throw new Error(`'lifecycleStatus' is required`); console.log(`Changing API status to '${args.lifecycleStatus}' in WSO2`); // define the action to be taken based on target lifecycle status - let action = ''; - switch (args.lifecycleStatus) { - case 'PUBLISHED': - action = 'Publish'; - break; - case 'CREATED': - action = 'Demote to created'; - break; - case 'DEPRECATED': - action = 'Deprecate'; - break; - case 'BLOCKED': - action = 'Block'; - break; - case 'RETIRED': - action = 'Retire'; - break; - case 'PROTOTYPED': - action = 'Deploy as a Prototype'; - break; - default: - throw new Error(`Lifecycle status '${args.lifecycleStatus}' is not supported`); + const action = actionMap[args.lifecycleStatus]; + if (!action) { + throw new Error(`Lifecycle status '${args.lifecycleStatus}' is not supported`); } console.log(`Using action '${action}' for lifecycle change`); From d7d762d76ce5d24dd802179d3d45bb5b50828dbc Mon Sep 17 00:00:00 2001 From: flaviostutz Date: Tue, 12 Nov 2024 11:18:26 +0100 Subject: [PATCH 4/4] chore: fix --- .mailmap | 2 -- 1 file changed, 2 deletions(-) diff --git a/.mailmap b/.mailmap index 99ce6a4..08715e6 100644 --- a/.mailmap +++ b/.mailmap @@ -2,7 +2,5 @@ # The format is "Proper Name Commit Name " # for more info, https://git-scm.com/docs/gitmailmap -Marcio Meier marcio meier - Flavio Stutz flaviostutz Flavio Stutz Flávio Stutz