@redocly/redoc 0.130.1 → 0.131.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/bin.d.ts +1 -0
  3. package/dist/bin.js +1 -1
  4. package/dist/cli/develop.js +1 -1
  5. package/dist/cli/prepare/copy-env-files.js +1 -1
  6. package/dist/cli/prepare/index.js +1 -1
  7. package/dist/cli/telemetry/index.js +1 -1
  8. package/dist/client/App.js +1 -1
  9. package/dist/client/ErrorBoundary.js +1 -1
  10. package/dist/client/app/Sidebar/helpers/filter-out-versioned-items.js +1 -1
  11. package/dist/client/app/hooks/useRouteChangeTracker.js +1 -1
  12. package/dist/client/app/search/useAiSearch.js +1 -1
  13. package/dist/client/browser-entry.js +5 -5
  14. package/dist/client/providers/hooks.js +1 -1
  15. package/dist/client/runtime/loader.js +1 -1
  16. package/dist/config/env-config.d.ts +17 -0
  17. package/dist/config/env-config.js +1 -0
  18. package/dist/config/env-schema.d.ts +242 -0
  19. package/dist/config/env-schema.js +3 -0
  20. package/dist/config/env-schemas/api-urls.d.ts +24 -0
  21. package/dist/config/env-schemas/api-urls.js +1 -0
  22. package/dist/config/env-schemas/auth.d.ts +42 -0
  23. package/dist/config/env-schemas/auth.js +1 -0
  24. package/dist/config/env-schemas/catalog.d.ts +12 -0
  25. package/dist/config/env-schemas/catalog.js +1 -0
  26. package/dist/config/env-schemas/database.d.ts +15 -0
  27. package/dist/config/env-schemas/database.js +1 -0
  28. package/dist/config/env-schemas/environment-detection.d.ts +24 -0
  29. package/dist/config/env-schemas/environment-detection.js +1 -0
  30. package/dist/config/env-schemas/feature-flags.d.ts +24 -0
  31. package/dist/config/env-schemas/feature-flags.js +1 -0
  32. package/dist/config/env-schemas/organization-project.d.ts +27 -0
  33. package/dist/config/env-schemas/organization-project.js +1 -0
  34. package/dist/config/env-schemas/scorecards.d.ts +12 -0
  35. package/dist/config/env-schemas/scorecards.js +1 -0
  36. package/dist/config/env-schemas/search.d.ts +21 -0
  37. package/dist/config/env-schemas/search.js +1 -0
  38. package/dist/config/env-schemas/server-config.d.ts +51 -0
  39. package/dist/config/env-schemas/server-config.js +1 -0
  40. package/dist/config/env-schemas/site.d.ts +12 -0
  41. package/dist/config/env-schemas/site.js +1 -0
  42. package/dist/config/env-schemas/ssr.d.ts +18 -0
  43. package/dist/config/env-schemas/ssr.js +1 -0
  44. package/dist/config/env-schemas/telemetry.d.ts +15 -0
  45. package/dist/config/env-schemas/telemetry.js +1 -0
  46. package/dist/config/env-schemas/test.d.ts +22 -0
  47. package/dist/config/env-schemas/test.js +1 -0
  48. package/dist/constants/common.d.ts +1 -1
  49. package/dist/constants/common.js +1 -1
  50. package/dist/server/api-routes/import-api-routes-handlers.js +1 -1
  51. package/dist/server/api-routes/run-api-routes-worker.js +1 -1
  52. package/dist/server/constants/common.js +1 -1
  53. package/dist/server/entitlements/entitlements-provider.js +1 -1
  54. package/dist/server/esbuild/esbuild-logger.js +2 -2
  55. package/dist/server/esbuild/esbuild.js +2 -2
  56. package/dist/server/esbuild/plugins/assets-resolver.js +1 -1
  57. package/dist/server/esbuild/plugins/esbuild-compile-resolver.js +1 -1
  58. package/dist/server/esbuild/plugins/styled-components-ssr.js +1 -1
  59. package/dist/server/fs/last-modified-tracker.js +1 -1
  60. package/dist/server/fs/utils/is-loader-cache-enabled.js +1 -1
  61. package/dist/server/node-bundle-entry.js +1 -1
  62. package/dist/server/plugins/analytics/adobe/index.js +1 -1
  63. package/dist/server/plugins/analytics/amplitude/index.js +1 -1
  64. package/dist/server/plugins/analytics/fullstory/index.js +1 -1
  65. package/dist/server/plugins/analytics/ga/index.js +1 -1
  66. package/dist/server/plugins/analytics/gtm/browser-hooks.js +1 -1
  67. package/dist/server/plugins/analytics/gtm/index.js +1 -1
  68. package/dist/server/plugins/analytics/heap/index.js +1 -1
  69. package/dist/server/plugins/analytics/rudderstack/index.js +1 -1
  70. package/dist/server/plugins/analytics/segment/index.js +1 -1
  71. package/dist/server/plugins/catalog-entities/database/catalog-entities-service.d.ts +4 -52
  72. package/dist/server/plugins/catalog-entities/database/catalog-entities-service.js +1 -1
  73. package/dist/server/plugins/catalog-entities/database/mappers/create-entity-db-record.d.ts +1 -0
  74. package/dist/server/plugins/catalog-entities/database/mappers/create-entity-read-model.js +1 -1
  75. package/dist/server/plugins/catalog-entities/database/mappers/{create-entity-relation.d.ts → create-entity-relation-read-model.d.ts} +2 -2
  76. package/dist/server/plugins/catalog-entities/database/mappers/create-entity-relation-read-model.js +1 -0
  77. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-local-read-repository.js +3 -3
  78. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-local-repository.d.ts +5 -31
  79. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-local-write-repository.js +1 -1
  80. package/dist/server/plugins/catalog-entities/database/repositories/remote/catalog-entities-remote-repository.d.ts +3 -4
  81. package/dist/server/plugins/catalog-entities/database/repositories/remote/catalog-entities-remote-repository.js +1 -1
  82. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/asyncapi-entities-extractor.js +1 -1
  83. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/base.d.ts +2 -1
  84. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/base.js +1 -1
  85. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/openapi-entities-extractor.js +1 -1
  86. package/dist/server/plugins/catalog-entities/extensions/extractors/fs-entities-extractor.js +1 -1
  87. package/dist/server/plugins/catalog-entities/plugin.js +1 -1
  88. package/dist/server/plugins/catalog-entities/schemas/read-model-schemas.d.ts +25 -164
  89. package/dist/server/plugins/catalog-entities/schemas/read-model-schemas.js +0 -1
  90. package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.js +1 -1
  91. package/dist/server/plugins/default-theme/index.js +1 -1
  92. package/dist/server/plugins/entitlements/index.js +1 -1
  93. package/dist/server/plugins/lifecycle.js +2 -2
  94. package/dist/server/plugins/markdown/markdoc/import-user-tags.js +1 -1
  95. package/dist/server/plugins/markdown/markdoc/plugins/render-mermaid.js +1 -1
  96. package/dist/server/plugins/mcp/auth/auth-handlers.js +1 -1
  97. package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
  98. package/dist/server/plugins/nav-utils.js +1 -1
  99. package/dist/server/plugins/openapi-docs/index.js +1 -1
  100. package/dist/server/plugins/scorecard-classic/index.js +1 -1
  101. package/dist/server/plugins/scorecards/plugin.js +1 -1
  102. package/dist/server/plugins/scorecards/workers/run-scorecards-worker.js +1 -1
  103. package/dist/server/plugins/search/ai-indexer/prepare-ai-search-documents.js +1 -1
  104. package/dist/server/plugins/search/documents/search-documents.js +1 -1
  105. package/dist/server/plugins/search/engines/flexsearch/index.js +1 -1
  106. package/dist/server/plugins/search/engines/typesense/index.js +1 -1
  107. package/dist/server/plugins/search/index.js +1 -1
  108. package/dist/server/plugins/search/llmstxt/index.js +5 -5
  109. package/dist/server/plugins/search/utils.js +1 -1
  110. package/dist/server/plugins/sidebars/index.js +2 -2
  111. package/dist/server/plugins/sso/index.js +1 -1
  112. package/dist/server/providers/database/base-repository.js +1 -1
  113. package/dist/server/providers/database/database-connection-factory.js +1 -1
  114. package/dist/server/providers/database/database-preconnect-service.js +1 -1
  115. package/dist/server/providers/database/databases/sqld-sqlite/drizzle.config.js +1 -1
  116. package/dist/server/ssr/render.js +1 -1
  117. package/dist/server/ssr/server-side-props/get-server-props-from-user-handler.js +1 -1
  118. package/dist/server/ssr/utils.js +8 -8
  119. package/dist/server/store.d.ts +4 -4
  120. package/dist/server/store.js +1 -1
  121. package/dist/server/telemetry/index.js +1 -1
  122. package/dist/server/tools/notifiers/formatter.js +3 -3
  123. package/dist/server/tools/notifiers/helpers/colors.js +1 -1
  124. package/dist/server/tools/notifiers/logger.js +2 -2
  125. package/dist/server/tools/notifiers/reporter.js +6 -6
  126. package/dist/server/tools/notifiers/terminal-manager.js +4 -4
  127. package/dist/server/utils/envs/load-env-variables.js +1 -1
  128. package/dist/server/utils/is-catalog-entities-enabled.js +1 -1
  129. package/dist/server/utils/is-scorecards-enabled.js +1 -1
  130. package/dist/server/utils/lifecycle-hooks.js +1 -1
  131. package/dist/server/utils/report-all-errors.js +1 -1
  132. package/dist/server/utils/set-execution-mode.d.ts +5 -0
  133. package/dist/server/utils/set-execution-mode.js +1 -0
  134. package/dist/server/version.js +1 -1
  135. package/dist/server/web-server/handle-api-route-request.js +1 -1
  136. package/dist/server/web-server/http.js +2 -2
  137. package/dist/server/web-server/middleware/apiKeyMiddleware.js +1 -1
  138. package/dist/server/web-server/middleware/catalogAuthMiddleware.js +1 -1
  139. package/dist/server/web-server/middleware/corsMiddleware.js +1 -1
  140. package/dist/server/web-server/middleware/dynamic-middleware/dynamic-middleware.js +1 -1
  141. package/dist/server/web-server/middleware/idleTimeoutMiddleware.js +1 -1
  142. package/dist/server/web-server/routes/auth.js +1 -1
  143. package/dist/server/web-server/routes/catalog/catalog-relations.js +1 -1
  144. package/dist/server/web-server/routes/catalog/catalog.js +1 -1
  145. package/dist/server/web-server/routes/catalog/dto/read-entity-dto.d.ts +3 -0
  146. package/dist/server/web-server/routes/catalog/dto/read-entity-dto.js +0 -0
  147. package/dist/server/web-server/routes/catalog/helpers/create-entity-relation-update-schema.d.ts +43 -0
  148. package/dist/server/web-server/routes/catalog/helpers/create-entity-relation-update-schema.js +1 -0
  149. package/dist/server/web-server/routes/catalog/helpers/create-entity-schema.d.ts +6823 -0
  150. package/dist/server/web-server/routes/catalog/helpers/create-entity-schema.js +1 -0
  151. package/dist/server/web-server/routes/catalog/helpers/create-entity-update-schema.d.ts +1102 -0
  152. package/dist/server/web-server/routes/catalog/helpers/create-entity-update-schema.js +1 -0
  153. package/dist/server/web-server/routes/catalog/mappers/map-entity-read-model-schema-to-entity-read-dto.d.ts +4 -0
  154. package/dist/server/web-server/routes/catalog/mappers/map-entity-read-model-schema-to-entity-read-dto.js +1 -0
  155. package/dist/server/web-server/routes/catalog/parsers/entities/parse-entities.d.ts +4 -0
  156. package/dist/server/web-server/routes/catalog/parsers/entities/parse-entities.js +1 -0
  157. package/dist/server/web-server/routes/catalog/parsers/entities/parse-entity-update-data.d.ts +4 -0
  158. package/dist/server/web-server/routes/catalog/parsers/entities/parse-entity-update-data.js +1 -0
  159. package/dist/server/web-server/routes/catalog/parsers/entities/parse-entity.d.ts +4 -0
  160. package/dist/server/web-server/routes/catalog/parsers/entities/parse-entity.js +1 -0
  161. package/dist/server/web-server/routes/catalog/parsers/relations/parse-entities-relations.d.ts +13 -0
  162. package/dist/server/web-server/routes/catalog/parsers/relations/parse-entities-relations.js +1 -0
  163. package/dist/server/web-server/routes/catalog/parsers/relations/parse-entity-relation-update-data.d.ts +13 -0
  164. package/dist/server/web-server/routes/catalog/parsers/relations/parse-entity-relation-update-data.js +1 -0
  165. package/dist/server/web-server/routes/catalog/parsers/relations/parse-entity-relation.d.ts +13 -0
  166. package/dist/server/web-server/routes/catalog/parsers/relations/parse-entity-relation.js +1 -0
  167. package/dist/server/web-server/routes/dynamic-route.js +1 -1
  168. package/dist/server/web-server/routes/error.js +1 -1
  169. package/dist/server/web-server/routes/index.js +1 -1
  170. package/dist/server/web-server/routes/info.js +1 -1
  171. package/dist/server/web-server/routes/mcp-oauth.js +1 -1
  172. package/dist/server/web-server/routes/otel/otel.js +1 -1
  173. package/dist/server/web-server/routes/page-data.js +1 -1
  174. package/dist/server/web-server/routes/path-prefix-redirect.js +1 -1
  175. package/dist/server/workers/worker-pool.js +1 -1
  176. package/package.json +11 -10
  177. package/dist/server/plugins/catalog-entities/database/mappers/create-entity-relation.js +0 -1
  178. package/dist/server/plugins/catalog-entities/entities/validate-entity.d.ts +0 -8
  179. package/dist/server/plugins/catalog-entities/entities/validate-entity.js +0 -1
  180. package/dist/server/utils/envs/is-build-mode.d.ts +0 -2
  181. package/dist/server/utils/envs/is-build-mode.js +0 -1
  182. package/dist/server/utils/envs/is-develop-mode.d.ts +0 -7
  183. package/dist/server/utils/envs/is-develop-mode.js +0 -1
  184. package/dist/server/utils/envs/is-production-mode.d.ts +0 -10
  185. package/dist/server/utils/envs/is-production-mode.js +0 -1
  186. package/dist/utils/env/is-local-development.d.ts +0 -13
  187. package/dist/utils/env/is-local-development.js +0 -1
  188. package/dist/utils/env/is-production.d.ts +0 -13
  189. package/dist/utils/env/is-production.js +0 -1
  190. package/dist/utils/env/is-web-view.d.ts +0 -14
  191. package/dist/utils/env/is-web-view.js +0 -1
@@ -1 +1 @@
1
- import{isProductionMode as t}from"../../../utils/envs/is-production-mode.js";import{buildScript as i}from"./build-script.js";import{resolveBrowserHooksPath as e}from"./resolve-browser-hooks.js";async function l(){return{id:"Adobe Analytics",requiredEntitlements:["analytics"],async processContent(n,{getConfig:r}){const o=(await r())?.analytics?.adobe;!o?.scriptUrl||!t()&&!o.includeInDevelopment||(n.addSsrComponents([i(o.scriptUrl)],"head"),n.addBrowserPlugin(e()))}}}export{l as adobeAnalyticsPlugin};
1
+ import{envConfig as r}from"../../../../config/env-config.js";import{buildScript as t}from"./build-script.js";import{resolveBrowserHooksPath as e}from"./resolve-browser-hooks.js";async function d(){return{id:"Adobe Analytics",requiredEntitlements:["analytics"],async processContent(o,{getConfig:i}){const n=(await i())?.analytics?.adobe;!n?.scriptUrl||!r.isProductionEnv&&!n.includeInDevelopment||(o.addSsrComponents([t(n.scriptUrl)],"head"),o.addBrowserPlugin(e()))}}}export{d as adobeAnalyticsPlugin};
@@ -1 +1 @@
1
- import{Minimatch as p}from"minimatch";import{isProductionMode as m}from"../../../utils/envs/is-production-mode.js";import{buildScripts as a}from"./build-scripts.js";import{resolveBrowserHooksPath as l}from"./resolve-browser-hooks.js";async function g(){return{id:"Amplitude Analytics",requiredEntitlements:["analytics"],async processContent(o,{getConfig:n}){const e=(await n())?.analytics?.amplitude;if(!e?.apiKey||!m()&&!e.includeInDevelopment)return;let t=[];typeof e.exclude<"u"&&e.exclude.map(d=>{const r=new p(d);t.push(r.makeRe())});const{headComponents:i,postBodyComponents:s}=a(e,t);o.addSsrComponents(i,"head"),o.addSsrComponents(s,"postBody"),o.addBrowserPlugin(l())}}}export{g as amplitudeAnalyticsPlugin};
1
+ import{Minimatch as p}from"minimatch";import{envConfig as m}from"../../../../config/env-config.js";import{buildScripts as a}from"./build-scripts.js";import{resolveBrowserHooksPath as l}from"./resolve-browser-hooks.js";async function h(){return{id:"Amplitude Analytics",requiredEntitlements:["analytics"],async processContent(n,{getConfig:t}){const e=(await t())?.analytics?.amplitude;if(!e?.apiKey||!m.isProductionEnv&&!e.includeInDevelopment)return;let o=[];typeof e.exclude<"u"&&e.exclude.map(r=>{const d=new p(r);o.push(d.makeRe())});const{headComponents:i,postBodyComponents:s}=a(e,o);n.addSsrComponents(i,"head"),n.addSsrComponents(s,"postBody"),n.addBrowserPlugin(l())}}}export{h as amplitudeAnalyticsPlugin};
@@ -1 +1 @@
1
- import{isProductionMode as r}from"../../../utils/envs/is-production-mode.js";import{buildScript as s}from"./build-script.js";async function a(){return{id:"Fullstory Analytics",requiredEntitlements:["analytics"],async processContent(t,{getConfig:o}){const n=(await o())?.analytics?.fullstory;if(!n?.orgId||!r()&&!n.includeInDevelopment)return;const i=[s(n.orgId)];t.addSsrComponents(i,"head")}}}export{a as fullstoryAnalyticsPlugin};
1
+ import{envConfig as r}from"../../../../config/env-config.js";import{buildScript as s}from"./build-script.js";async function a(){return{id:"Fullstory Analytics",requiredEntitlements:["analytics"],async processContent(t,{getConfig:o}){const n=(await o())?.analytics?.fullstory;if(!n?.orgId||!r.isProductionEnv&&!n.includeInDevelopment)return;const i=[s(n.orgId)];t.addSsrComponents(i,"head")}}}export{a as fullstoryAnalyticsPlugin};
@@ -1 +1 @@
1
- import{withPathPrefix as s}from"@redocly/theme/core/utils";import{isProductionMode as c}from"../../../utils/envs/is-production-mode.js";import{buildScripts as l}from"./build-scripts.js";import{resolveBrowserHooksPath as u}from"./resolve-browser-hooks.js";async function I(){const r=c();return{id:"Google Analytics",requiredEntitlements:["analytics"],afterRoutesCreated(t){const n=t.getGlobalData()||{},o=n.analytics?.ga||{trackingId:""};o?.exclude||(o.exclude=[]),o.trackers={};for(const i of Object.values(n.products||{})){const e=i.configOverride?.analytics?.ga;!e||!r&&!e.includeInDevelopment||(e.exclude?.length&&o.exclude.push(...e.exclude),o.trackers[i.slug]=e)}if(o.trackingId&&(r||o.includeInDevelopment)&&(o.trackers[s("/")]={trackingId:o.trackingId,conversionId:o.conversionId,floodlightId:o.floodlightId,optimizeId:o.optimizeId}),t.setGlobalData({...n,analytics:{...n?.analytics,ga:o}}),!Object.keys(o.trackers).length)return;const{headComponents:a,postBodyComponents:d}=l(o);t.addSsrComponents(a,"head"),t.addSsrComponents(d,"postBody"),t.addBrowserPlugin(u())}}}export{I as googleAnalyticsPlugin};
1
+ import{withPathPrefix as s}from"@redocly/theme/core/utils";import{envConfig as c}from"../../../../config/env-config.js";import{buildScripts as l}from"./build-scripts.js";import{resolveBrowserHooksPath as g}from"./resolve-browser-hooks.js";async function I(){const r=c.isProductionEnv;return{id:"Google Analytics",requiredEntitlements:["analytics"],afterRoutesCreated(t){const n=t.getGlobalData()||{},o=n.analytics?.ga||{trackingId:""};o?.exclude||(o.exclude=[]),o.trackers={};for(const i of Object.values(n.products||{})){const e=i.configOverride?.analytics?.ga;!e||!r&&!e.includeInDevelopment||(e.exclude?.length&&o.exclude.push(...e.exclude),o.trackers[i.slug]=e)}if(o.trackingId&&(r||o.includeInDevelopment)&&(o.trackers[s("/")]={trackingId:o.trackingId,conversionId:o.conversionId,floodlightId:o.floodlightId,optimizeId:o.optimizeId}),t.setGlobalData({...n,analytics:{...n?.analytics,ga:o}}),!Object.keys(o.trackers).length)return;const{headComponents:a,postBodyComponents:d}=l(o);t.addSsrComponents(a,"head"),t.addSsrComponents(d,"postBody"),t.addBrowserPlugin(g())}}}export{I as googleAnalyticsPlugin};
@@ -1 +1 @@
1
- import{onCLS as d,onFID as u,onLCP as m}from"web-vitals";import{debounce as s}from"../../../../utils/time/debounce.js";const c=new Set,b=(n,t)=>{const e=t?.analytics?.gtm;if(!e||process.env.NODE_ENV!=="production"&&!e.includeInDevelopment)return;e.enableWebVitalsTracking&&!n.prevLocation&&p(e.dataLayerName);const a=e.dataLayerName?window[e.dataLayerName]:window.dataLayer,o=e.pageViewEventName?e.pageViewEventName:"pageView";a.push({event:o})};function p(n="dataLayer"){const t=window;function e(i){c.has(i.name)||(c.add(i.name),w(i,t[n]))}const a=s(e,3e3),o=e,r=s(e,3e3);d(a),u(o),m(r)}function w({name:n,value:t,id:e},a){a.push({event:"core-web-vitals",webVitalsMeasurement:{name:n,id:e,value:Math.round(n==="CLS"?t*1e3:t),nonInteraction:!0}})}export{b as onRouteChange};
1
+ import{onCLS as d,onFID as u,onLCP as m}from"web-vitals";import{envConfig as p}from"../../../../config/env-config.js";import{debounce as r}from"../../../../utils/time/debounce.js";const c=new Set,v=(n,t)=>{const e=t?.analytics?.gtm;if(!e||p.NODE_ENV!=="production"&&!e.includeInDevelopment)return;e.enableWebVitalsTracking&&!n.prevLocation&&w(e.dataLayerName);const o=e.dataLayerName?window[e.dataLayerName]:window.dataLayer,a=e.pageViewEventName?e.pageViewEventName:"pageView";o.push({event:a})};function w(n="dataLayer"){const t=window;function e(i){c.has(i.name)||(c.add(i.name),f(i,t[n]))}const o=r(e,3e3),a=e,s=r(e,3e3);d(o),u(a),m(s)}function f({name:n,value:t,id:e},o){o.push({event:"core-web-vitals",webVitalsMeasurement:{name:n,id:e,value:Math.round(n==="CLS"?t*1e3:t),nonInteraction:!0}})}export{v as onRouteChange};
@@ -1 +1 @@
1
- import{isProductionMode as i}from"../../../utils/envs/is-production-mode.js";import{buildScripts as s}from"./build-scripts.js";import{resolveBrowserHooksPath as a}from"./resolve-browser-hooks.js";async function l(){return{id:"Google Tag Manager Analytics",requiredEntitlements:["analytics"],async processContent(n,{getConfig:t}){const o=(await t())?.analytics?.gtm;if(!o?.trackingId||!i&&!o.includeInDevelopment)return;const{headComponents:e,preBodyComponents:r}=s(o);n.addSsrComponents(e,"head"),n.addSsrComponents(r,"preBody"),n.addBrowserPlugin(a())}}}export{l as gtmAnalyticsPlugin};
1
+ import{envConfig as i}from"../../../../config/env-config.js";import{buildScripts as s}from"./build-scripts.js";import{resolveBrowserHooksPath as a}from"./resolve-browser-hooks.js";async function l(){return{id:"Google Tag Manager Analytics",requiredEntitlements:["analytics"],async processContent(n,{getConfig:t}){const o=(await t())?.analytics?.gtm;if(!o?.trackingId||!i.isProductionEnv&&!o.includeInDevelopment)return;const{headComponents:e,preBodyComponents:r}=s(o);n.addSsrComponents(e,"head"),n.addSsrComponents(r,"preBody"),n.addBrowserPlugin(a())}}}export{l as gtmAnalyticsPlugin};
@@ -1 +1 @@
1
- import{isProductionMode as e}from"../../../utils/envs/is-production-mode.js";import{resolveBrowserHooksPath as i}from"./resolve-browser-hooks.js";async function c(){return{id:"Heap Analytics",requiredEntitlements:["analytics"],async processContent(o,{getConfig:t}){const n=(await t())?.analytics?.heap;!n?.appId||!e()&&!n.includeInDevelopment||o.addBrowserPlugin(i())}}}export{c as heapAnalyticsPlugin};
1
+ import{envConfig as t}from"../../../../config/env-config.js";import{resolveBrowserHooksPath as e}from"./resolve-browser-hooks.js";async function c(){return{id:"Heap Analytics",requiredEntitlements:["analytics"],async processContent(i,{getConfig:o}){const n=(await o())?.analytics?.heap;!n?.appId||!t.isProductionEnv&&!n.includeInDevelopment||i.addBrowserPlugin(e())}}}export{c as heapAnalyticsPlugin};
@@ -1 +1 @@
1
- import{isProductionMode as e}from"../../../utils/envs/is-production-mode.js";import{buildScript as o}from"./build-script.js";import{resolveBrowserHooksPath as i}from"./resolve-browser-hooks.js";async function u(){return{id:"Rudderstack Analytics",requiredEntitlements:["analytics"],async processContent(t,{getConfig:n}){const r=(await n())?.analytics?.rudderstack;!r?.writeKey||!e()&&!r.includeInDevelopment||(t.addSsrComponents([o(r)],"head"),t.addBrowserPlugin(i()))}}}export{u as rudderstackAnalyticsPlugin};
1
+ import{envConfig as e}from"../../../../config/env-config.js";import{buildScript as i}from"./build-script.js";import{resolveBrowserHooksPath as o}from"./resolve-browser-hooks.js";async function u(){return{id:"Rudderstack Analytics",requiredEntitlements:["analytics"],async processContent(r,{getConfig:t}){const n=(await t())?.analytics?.rudderstack;!n?.writeKey||!e.isProductionEnv&&!n.includeInDevelopment||(r.addSsrComponents([i(n)],"head"),r.addBrowserPlugin(o()))}}}export{u as rudderstackAnalyticsPlugin};
@@ -1 +1 @@
1
- import{isProductionMode as o}from"../../../utils/envs/is-production-mode.js";import{buildScript as i}from"./build-script.js";import{resolveBrowserHooksPath as r}from"./resolve-browser-hooks.js";async function m(){return{id:"Segment Analytics",requiredEntitlements:["analytics"],async processContent(e,{getConfig:t}){const n=(await t())?.analytics?.segment;!n?.writeKey||!o()&&!n.includeInDevelopment||(e.addSsrComponents([i(n)],"head"),e.addBrowserPlugin(r()))}}}export{m as segmentAnalyticsPlugin};
1
+ import{envConfig as i}from"../../../../config/env-config.js";import{buildScript as o}from"./build-script.js";import{resolveBrowserHooksPath as r}from"./resolve-browser-hooks.js";async function m(){return{id:"Segment Analytics",requiredEntitlements:["analytics"],async processContent(e,{getConfig:t}){const n=(await t())?.analytics?.segment;!n?.writeKey||!i.isProductionEnv&&!n.includeInDevelopment||(e.addSsrComponents([o(n)],"head"),e.addBrowserPlugin(r()))}}}export{m as segmentAnalyticsPlugin};
@@ -2,7 +2,6 @@ import type { PaginationParams } from '../../../providers/database/pagination/sc
2
2
  import type { EntityReadModelSchema, EntityRelationReadModelSchema } from '../schemas/read-model-schemas.js';
3
3
  import type { CatalogFiltersParams } from './repositories/local/catalog-entities-local-read-repository.js';
4
4
  import type { BffCatalogEntity, BffCatalogEntityList, BffCatalogRelatedEntityList } from '@redocly/theme/core/types';
5
- import type { DatabaseEntityRelation } from '../../../providers/database/databases/catalog-sqlite/schemas/entities-relations-table.js';
6
5
  import type { ServiceInstanceOptions } from '../../../providers/database/types.js';
7
6
  import type { TransactionsManager } from '../../../providers/database/transactions-manager.js';
8
7
  import type { CreateEntityParams } from './repositories/local/catalog-entities-local-write-repository.js';
@@ -70,57 +69,10 @@ export declare class CatalogEntitiesService {
70
69
  */
71
70
  deleteEntitiesInLocalDatabase(filter: Filter): Promise<void>;
72
71
  getEntityRelationById(id: string): Promise<EntityRelationReadModelSchema | null>;
73
- getEntitiesRelations(paginationParams?: PaginationParams): Promise<ListResponseResult<{
74
- createdAt?: string | null | undefined;
75
- updatedAt?: string | null | undefined;
76
- sourceVersion?: string | null | undefined;
77
- sourceRevision?: string | null | undefined;
78
- targetVersion?: string | null | undefined;
79
- targetRevision?: string | null | undefined;
80
- type: string;
81
- id: string;
82
- organizationId: string;
83
- projectId: string;
84
- sourceKey: string;
85
- targetKey: string;
86
- }>>;
87
- createEntityRelation(relation: EntityRelationDtoSchema): Promise<{
88
- id: string;
89
- createdAt: string;
90
- updatedAt: string;
91
- organizationId: string;
92
- projectId: string;
93
- sourceFile: string | null;
94
- isDeleted: boolean | null;
95
- sourceKey: string;
96
- targetKey: string;
97
- sourceVersion: string;
98
- sourceRevision: string;
99
- targetVersion: string;
100
- targetRevision: string;
101
- fileHash: string | null;
102
- sourceToTargetRelation: string;
103
- targetToSourceRelation: string;
104
- } | null | undefined>;
105
- createEntitiesRelations(entities: EntityRelationDtoSchema[]): Promise<BulkSyncResult<DatabaseEntityRelation>>;
106
- updateEntityRelation(id: string, relation: EntityRelationDtoSchema): Promise<{
107
- id: string;
108
- createdAt: string;
109
- updatedAt: string;
110
- organizationId: string;
111
- projectId: string;
112
- sourceFile: string | null;
113
- isDeleted: boolean | null;
114
- sourceKey: string;
115
- targetKey: string;
116
- sourceVersion: string;
117
- sourceRevision: string;
118
- targetVersion: string;
119
- targetRevision: string;
120
- fileHash: string | null;
121
- sourceToTargetRelation: string;
122
- targetToSourceRelation: string;
123
- } | null | undefined>;
72
+ getEntitiesRelations(paginationParams?: PaginationParams): Promise<ListResponseResult<EntityRelationReadModelSchema>>;
73
+ createEntityRelation(relation: EntityRelationDtoSchema): Promise<EntityRelationReadModelSchema | null | undefined>;
74
+ createEntitiesRelations(entities: EntityRelationDtoSchema[]): Promise<BulkSyncResult<EntityRelationReadModelSchema>>;
75
+ updateEntityRelation(incomingRelationData: Partial<EntityRelationDtoSchema>, relationToBeUpdated: EntityRelationReadModelSchema): Promise<EntityRelationReadModelSchema | null | undefined>;
124
76
  deleteEntityRelation(id: string): Promise<string | null>;
125
77
  /**
126
78
  * Use only internally, everything that is created via API should be created in the remote database.
@@ -1 +1 @@
1
- import{deepMerge as w}from"../../../../utils/object/deep-merge.js";import{promiseMapLimit as u}from"../../../utils/async/promise-map-limit.js";import{logger as c}from"../../../tools/notifiers/logger.js";import{isWebView as y}from"../../../../utils/env/is-web-view.js";import{entityRelationDtoSchema as m}from"../schemas/dto-schemas.js";import{CatalogEntitiesLocalRepository as R}from"./repositories/local/catalog-entities-local-repository.js";import{CatalogEntitiesRemoteRepository as p}from"./repositories/remote/catalog-entities-remote-repository.js";import{prepareListResponse as l}from"../../../web-server/utils/prepare-list-response.js";import{ENTITY_RELATION_FROM_DATABASE as E}from"./mappers/field-transformations.js";import{createValidator as f}from"../utils/ajv-validator.js";import{hasOptionsChanged as g}from"../utils/has-options-changed.js";const h=15,I=f(m,{errorPrefix:"Entity relation validation failed:",dataVar:"entity relation"});class s{static#a;static#i;#t;#e;constructor(t,e){this.#t=t,this.#e=e}static async#n(t){const[e,a]=await Promise.all([R.getInstance(t),t.runOnlyLocalDatabase?null:p.getInstance(t)]),i=new s(e,a);a&&(process.env.NODE_ENV==="development"&&c.info("Attaching remote database to local database"),await i.#t.attachDatabase(a.path)),s.#a=i,s.#i=t}static async getInstance(t){return t.runOnlyLocalDatabase===void 0&&(t.runOnlyLocalDatabase=process.env.REDOCLY_LOCAL_DEV==="true"||process.env.CI==="true"),t.removeExisting===void 0&&(t.removeExisting=!1),(!s.#a||g(s.#i,t))&&await s.#n(t),s.#a}async transaction(...t){return this.#t.transactionsManager.transaction(...t)}async getEntities({paginationParams:t,rbacTeams:e,excludedTypes:a,excludedEntities:i}){await this.#e?.sync();const{items:n,total:r,hasMore:o}=await this.#t.getEntities({paginationParams:t,rbacTeams:e,excludedTypes:a,excludedEntities:i});return l({data:n,params:t,totalCount:r,hasMore:o})}async getEntityById(t,e){return await this.#e?.sync(),await this.#t.getEntityById(t,e)}async getEntityKeysAndVersionsBySourceFile(t){return await this.#e?.sync(),this.#t.getEntityKeysAndVersionsBySourceFile(t)}async getEntitiesCountByTypes(){return await this.#e?.sync(),this.#t.getEntitiesCountByTypes()}async getCatalogFilters(t){return await this.#e?.sync(),this.#t.getCatalogFilters(t)}async createEntity(t){if(y())throw new Error("Entity creation is not supported in the WebView");return this.#e?this.#e.createEntity(t):(c.warn("No remote database found"),null)}async createEntities(t){if(y())throw new Error("Entity creation is not supported in the WebView");const e=this.#e;return e?await u(t,h,async a=>e.createEntity(a).then(i=>({status:"ok",resource:i})).catch(i=>({key:a.key,status:"error",error:i}))):(c.warn("No remote database found"),[])}getEntitySources(){return this.#t.getEntitySources()}async createEntityInLocalDatabase(t){return this.#t.createEntity(t)}async createEntitiesInLocalDatabase(t){await this.#t.createEntities(t)}async createEntityRelationInLocalDatabase(t){await this.#t.createEntityRelation(t)}async createEntityRelationsInLocalDatabase(t){await this.#t.createEntityRelations(t)}async updateEntity(t,e){if(y())throw new Error("Entity update is not supported in the WebView");return await this.#e?.updateEntity(t,e)}async deleteEntity(t){if(y())throw new Error("Entity deletion is not supported in the WebView");return await this.#e?.deleteEntity(t)}async deleteEntitiesInLocalDatabase(t){await this.#t.deleteEntities(t)}async getEntityRelationById(t){return await this.#e?.sync(),await this.#t.getEntityRelationById(t)}async getEntitiesRelations(t={}){await this.#e?.sync();const{items:e,total:a,hasMore:i}=await this.#t.getEntitiesRelations(t);return l({data:e,params:t,totalCount:a,nameTransformationsFromDatabase:E,hasMore:i})}async createEntityRelation(t){return this.#e?.createEntityRelation(t)}async createEntitiesRelations(t){const e=this.#e;return e?await u(t,h,async a=>e.createEntityRelation(a).then(i=>({status:"ok",resource:i})).catch(i=>({key:a.sourceKey,status:"error",error:i}))):(c.warn("No remote database found"),[])}async updateEntityRelation(t,e){const a=await this.#t.getEntityRelationById(t);if(!a)throw new Error(`Entity relation with id ${t} not found`);const i=w(a,e),n=I(i);return this.#e?.createEntityRelation(n)}async deleteEntityRelation(t){let e=await this.#e?.deleteEntityRelation(t);return e||(e=await this.#t.deleteEntityRelation(t)),e}async deleteEntityRelationsInLocalDatabase(t){await this.#t.deleteEntityRelations(t)}async getEntitiesWithRelations({paginationParams:t,rbacTeams:e,excludedTypes:a,excludedEntities:i}){await this.#e?.sync();const{items:n,total:r,hasMore:o}=await this.#t.getEntitiesWithRelations({paginationParams:t,rbacTeams:e,excludedTypes:a,excludedEntities:i});return l({data:n,params:t,totalCount:r,hasMore:o})}async getEntityWithRelationsByKey({entityKey:t,filter:e,rbacTeams:a,excludedTypes:i,excludedEntities:n}){return this.#t.getEntityWithRelationsByKey({entityKey:t,filter:e,rbacTeams:a,excludedTypes:i,excludedEntities:n})}async getRelatedEntities({entityKey:t,paginationParams:e,rbacTeams:a,excludedTypes:i,excludedEntities:n}){await this.#e?.sync();const{items:r,total:o,hasMore:d}=await this.#t.getRelatedEntities({key:t,paginationParams:e,rbacTeams:a,excludedTypes:i,excludedEntities:n});return l({data:r,params:e,totalCount:o,nameTransformationsFromDatabase:E,hasMore:d})}async softDeleteEntitiesInLocalDatabase({filter:t,revision:e,fileHash:a}){await this.#t.softDeleteEntities({filter:t,revision:e,fileHash:a})}async listEntityRevisions(t,e){return await this.#e?.sync(),this.#t.listEntityRevisions(t,e)}async updateEntityScorecardsStatus(t,e){return await this.#e?.sync(),this.#t.updateEntityScorecardsStatus(t,e)}async updateEntityScorecardsStatusIfCalculating(t,e){return await this.#e?.sync(),this.#t.updateEntityScorecardsStatusIfCalculating(t,e)}async getOutdatedEntities(t){return await this.#e?.sync(),this.#t.getOutdatedEntities(t)}async setEntitiesAsOutdated(t){await this.#e?.sync(),await this.#t.setEntitiesAsOutdated(t)}}export{s as CatalogEntitiesService};
1
+ import{promiseMapLimit as u}from"../../../utils/async/promise-map-limit.js";import{logger as c}from"../../../tools/notifiers/logger.js";import{envConfig as r}from"../../../../config/env-config.js";import{CatalogEntitiesLocalRepository as w}from"./repositories/local/catalog-entities-local-repository.js";import{CatalogEntitiesRemoteRepository as p}from"./repositories/remote/catalog-entities-remote-repository.js";import{prepareListResponse as l}from"../../../web-server/utils/prepare-list-response.js";import{ENTITY_RELATION_FROM_DATABASE as d}from"./mappers/field-transformations.js";import{hasOptionsChanged as m}from"../utils/has-options-changed.js";const h=15;class n{static#a;static#i;#t;#e;constructor(t,e){this.#t=t,this.#e=e}static async#n(t){const[e,a]=await Promise.all([w.getInstance(t),t.runOnlyLocalDatabase?null:p.getInstance(t)]),i=new n(e,a);a&&(r.isDevelopMode&&c.info("Attaching remote database to local database"),await i.#t.attachDatabase(a.path)),n.#a=i,n.#i=t}static async getInstance(t){return t.runOnlyLocalDatabase===void 0&&(t.runOnlyLocalDatabase=r.isDevelopMode),t.removeExisting===void 0&&(t.removeExisting=!1),(!n.#a||m(n.#i,t))&&await n.#n(t),n.#a}async transaction(...t){return this.#t.transactionsManager.transaction(...t)}async getEntities({paginationParams:t,rbacTeams:e,excludedTypes:a,excludedEntities:i}){await this.#e?.sync();const{items:s,total:o,hasMore:y}=await this.#t.getEntities({paginationParams:t,rbacTeams:e,excludedTypes:a,excludedEntities:i});return l({data:s,params:t,totalCount:o,hasMore:y})}async getEntityById(t,e){return await this.#e?.sync(),await this.#t.getEntityById(t,e)}async getEntityKeysAndVersionsBySourceFile(t){return await this.#e?.sync(),this.#t.getEntityKeysAndVersionsBySourceFile(t)}async getEntitiesCountByTypes(){return await this.#e?.sync(),this.#t.getEntitiesCountByTypes()}async getCatalogFilters(t){return await this.#e?.sync(),this.#t.getCatalogFilters(t)}async createEntity(t){if(r.isDevelopMode)throw new Error("Entity creation is not supported in the develop mode");return this.#e?this.#e.createEntity(t):(c.warn("No remote database found"),null)}async createEntities(t){if(r.isDevelopMode)throw new Error("Entity creation is not supported in the develop mode");const e=this.#e;return e?await u(t,h,async a=>e.createEntity(a).then(i=>({status:"ok",resource:i})).catch(i=>({key:a.key,status:"error",error:i}))):(c.warn("No remote database found"),[])}getEntitySources(){return this.#t.getEntitySources()}async createEntityInLocalDatabase(t){return this.#t.createEntity(t)}async createEntitiesInLocalDatabase(t){await this.#t.createEntities(t)}async createEntityRelationInLocalDatabase(t){await this.#t.createEntityRelation(t)}async createEntityRelationsInLocalDatabase(t){await this.#t.createEntityRelations(t)}async updateEntity(t,e){if(r.isDevelopMode)throw new Error("Entity update is not supported in the develop mode");return await this.#e?.updateEntity(t,e)}async deleteEntity(t){if(r.isDevelopMode)throw new Error("Entity deletion is not supported in the develop mode");return await this.#e?.deleteEntity(t)}async deleteEntitiesInLocalDatabase(t){await this.#t.deleteEntities(t)}async getEntityRelationById(t){return await this.#e?.sync(),await this.#t.getEntityRelationById(t)}async getEntitiesRelations(t={}){await this.#e?.sync();const{items:e,total:a,hasMore:i}=await this.#t.getEntitiesRelations(t);return l({data:e,params:t,totalCount:a,nameTransformationsFromDatabase:d,hasMore:i})}async createEntityRelation(t){return this.#e?.createEntityRelation(t)}async createEntitiesRelations(t){const e=this.#e;return e?await u(t,h,async a=>e.createEntityRelation(a).then(i=>({status:"ok",resource:i})).catch(i=>({key:a.sourceKey,status:"error",error:i}))):(c.warn("No remote database found"),[])}async updateEntityRelation(t,e){const a={...e,...t,type:t.type??e.type};return this.#e?.createEntityRelation(a)}async deleteEntityRelation(t){let e=await this.#e?.deleteEntityRelation(t);return e||(e=await this.#t.deleteEntityRelation(t)),e}async deleteEntityRelationsInLocalDatabase(t){await this.#t.deleteEntityRelations(t)}async getEntitiesWithRelations({paginationParams:t,rbacTeams:e,excludedTypes:a,excludedEntities:i}){await this.#e?.sync();const{items:s,total:o,hasMore:y}=await this.#t.getEntitiesWithRelations({paginationParams:t,rbacTeams:e,excludedTypes:a,excludedEntities:i});return l({data:s,params:t,totalCount:o,hasMore:y})}async getEntityWithRelationsByKey({entityKey:t,filter:e,rbacTeams:a,excludedTypes:i,excludedEntities:s}){return this.#t.getEntityWithRelationsByKey({entityKey:t,filter:e,rbacTeams:a,excludedTypes:i,excludedEntities:s})}async getRelatedEntities({entityKey:t,paginationParams:e,rbacTeams:a,excludedTypes:i,excludedEntities:s}){await this.#e?.sync();const{items:o,total:y,hasMore:E}=await this.#t.getRelatedEntities({key:t,paginationParams:e,rbacTeams:a,excludedTypes:i,excludedEntities:s});return l({data:o,params:e,totalCount:y,nameTransformationsFromDatabase:d,hasMore:E})}async softDeleteEntitiesInLocalDatabase({filter:t,revision:e,fileHash:a}){await this.#t.softDeleteEntities({filter:t,revision:e,fileHash:a})}async listEntityRevisions(t,e){return await this.#e?.sync(),this.#t.listEntityRevisions(t,e)}async updateEntityScorecardsStatus(t,e){return await this.#e?.sync(),this.#t.updateEntityScorecardsStatus(t,e)}async updateEntityScorecardsStatusIfCalculating(t,e){return await this.#e?.sync(),this.#t.updateEntityScorecardsStatusIfCalculating(t,e)}async getOutdatedEntities(t){return await this.#e?.sync(),this.#t.getOutdatedEntities(t)}async setEntitiesAsOutdated(t){await this.#e?.sync(),await this.#t.setEntitiesAsOutdated(t)}}export{n as CatalogEntitiesService};
@@ -8,6 +8,7 @@ export declare function createEntityDbRecord({ entity, organizationId, projectId
8
8
  isCurrent?: boolean;
9
9
  isDefaultVersion?: boolean;
10
10
  isDeleted?: boolean | null;
11
+ revision?: string;
11
12
  };
12
13
  organizationId: string;
13
14
  projectId: string;
@@ -1 +1 @@
1
- import{logger as r}from"../../../../tools/notifiers/logger.js";import{entityDatabaseSchema as l}from"../../schemas/database-schemas.js";import{validateWithResult as t}from"../../utils/ajv-validator.js";const o=e=>"project_id"in e&&"organization_id"in e&&"created_at"in e;function d(e){if(o(e)){const s=t(l,e);if(!s.success)return r.warn(`Invalid database catalog entity for entity ${e.key}, error: ${s.error}`),null;const a=s.data||{};return{id:a.id,type:a.type,key:a.key||"",title:a.title||"",summary:a.summary||null,tags:a.tags?JSON.parse(a.tags):null,metadata:a.metadata?JSON.parse(a.metadata):null,git:a.git?JSON.parse(a.git):null,contact:a.contact?JSON.parse(a.contact):null,links:a.links?JSON.parse(a.links):null,source:a.source||"file",sourceFile:a.source_file||null,version:a.version||null,revision:a.revision??"",hash:a.hash||null,isCurrent:a.is_current,isDefaultVersion:a.is_default_version??!1,createdAt:a.created_at||null,updatedAt:a.updated_at||null,isDeleted:a.is_deleted??!1,object:"catalogEntity",rbacTeams:a.rbac_teams?JSON.parse(a.rbac_teams):[]}}return{...e,tags:e.tags?JSON.parse(e.tags):null,metadata:e.metadata?JSON.parse(e.metadata):null,git:e.git?JSON.parse(e.git):null,contact:e.contact?JSON.parse(e.contact):null,links:e.links?JSON.parse(e.links):null,source:e.source||"file",version:e.version||null,revision:e.revision??"",hash:e.hash||null,isCurrent:e.isCurrent,isDefaultVersion:e.isDefaultVersion??!1,isDeleted:e.isDeleted??!1,object:"catalogEntity"}}export{d as createEntityReadModel};
1
+ import{logger as r}from"../../../../tools/notifiers/logger.js";import{VERSION_NOT_SPECIFIED as t}from"@redocly/theme/core/constants";import{entityDatabaseSchema as l}from"../../schemas/database-schemas.js";import{validateWithResult as o}from"../../utils/ajv-validator.js";const i=e=>"project_id"in e&&"organization_id"in e&&"created_at"in e;function m(e){if(i(e)){const s=o(l,e);if(!s.success)return r.warn(`Invalid database catalog entity for entity ${e.key}, error: ${s.error}`),null;const a=s.data||{};return{id:a.id,organizationId:a.organization_id,projectId:a.project_id,type:a.type,key:a.key||"",title:a.title||"",summary:a.summary||null,tags:a.tags?JSON.parse(a.tags):null,metadata:a.metadata?JSON.parse(a.metadata):null,git:a.git?JSON.parse(a.git):null,contact:a.contact?JSON.parse(a.contact):null,links:a.links?JSON.parse(a.links):null,source:a.source||"file",sourceFile:a.source_file||null,version:a.version||t,revision:a.revision??"",hash:a.hash||null,isCurrent:a.is_current??!1,isDefaultVersion:a.is_default_version??!1,createdAt:a.created_at,updatedAt:a.updated_at,isDeleted:a.is_deleted??!1,object:"catalogEntity",rbacTeams:a.rbac_teams?JSON.parse(a.rbac_teams):[]}}return{...e,tags:e.tags?JSON.parse(e.tags):null,metadata:e.metadata?JSON.parse(e.metadata):null,git:e.git?JSON.parse(e.git):null,contact:e.contact?JSON.parse(e.contact):null,links:e.links?JSON.parse(e.links):null,source:e.source||"file",version:e.version,revision:e.revision??"",hash:e.hash||null,isCurrent:e.isCurrent??!1,isDefaultVersion:e.isDefaultVersion??!1,isDeleted:e.isDeleted??!1,object:"catalogEntity"}}export{m as createEntityReadModel};
@@ -1,7 +1,7 @@
1
1
  import type { Row } from '@libsql/client';
2
2
  import type { DatabaseEntityRelation } from '../../../../providers/database/databases/catalog-sqlite/schemas/entities-relations-table.js';
3
3
  import type { EntityRelationReadModelSchema } from '../../schemas/read-model-schemas.js';
4
- export declare function createEntityRelation(relation: DatabaseEntityRelation | Row): (EntityRelationReadModelSchema & {
4
+ export declare function createEntityRelationReadModel(relation: DatabaseEntityRelation | Row | null): (EntityRelationReadModelSchema & {
5
5
  object: 'catalogEntityRelation';
6
6
  }) | null;
7
- //# sourceMappingURL=create-entity-relation.d.ts.map
7
+ //# sourceMappingURL=create-entity-relation-read-model.d.ts.map
@@ -0,0 +1 @@
1
+ import{logger as r}from"../../../../tools/notifiers/logger.js";import{entityRelationDatabaseSchema as i}from"../../schemas/database-schemas.js";import{validateWithResult as a}from"../../utils/ajv-validator.js";const n=e=>"project_id"in e&&"organization_id"in e&&"source_key"in e;function g(e){if(!e)return null;if(n(e)){const o=a(i,e);if(!o.success)return r.warn(`Invalid database catalog entity relation, error: ${o.error}`),null;const t=o.data||{};return{id:t.id,organizationId:t.organization_id,projectId:t.project_id,sourceKey:t.source_key,targetKey:t.target_key,sourceVersion:t.source_version??null,sourceRevision:t.source_revision??null,targetVersion:t.target_version??null,targetRevision:t.target_revision??null,type:t.source_to_target_relation,createdAt:t.created_at,updatedAt:t.updated_at,object:"catalogEntityRelation"}}return{id:e.id,organizationId:e.organizationId,projectId:e.projectId,sourceKey:e.sourceKey,targetKey:e.targetKey,sourceVersion:e.sourceVersion??null,sourceRevision:e.sourceRevision??null,targetVersion:e.targetVersion??null,targetRevision:e.targetRevision??null,type:e.sourceToTargetRelation,createdAt:e.createdAt,updatedAt:e.updatedAt,object:"catalogEntityRelation"}}export{g as createEntityRelationReadModel};
@@ -1,15 +1,15 @@
1
- import{and as u,count as F,eq as _,isNotNull as X,notExists as f,or as J,sql as e}from"drizzle-orm";import{unionAll as p}from"drizzle-orm/sqlite-core";import{logger as q}from"../../../../../tools/notifiers/logger.js";import{VERSION_NOT_SPECIFIED as v}from"@redocly/theme/core/constants";import{applyPagination as R}from"../../../../../providers/database/pagination/index.js";import{applyFilter as P}from"../../../../../providers/database/pagination/filter.js";import{createEntityFieldsForSelect as S,FIELDS_TO_SELECT_FOR_ENTITY as h,FIELDS_TO_SELECT_FOR_ENTITY_RELATION as m}from"../utils.js";import{createEntityReadModel as g}from"../../mappers/create-entity-read-model.js";import{createEntityRelation as b}from"../../mappers/create-entity-relation.js";import{entitiesTable as t}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-table.js";import{entitiesRelationsTable as y}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-relations-table.js";import{entitiesAttributesTable as d}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-attributes-table.js";import{CatalogEntitiesRelationsRepository as $}from"./catalog-entities-relations-repository.js";import{CatalogEntitiesBffRepository as B}from"./catalog-entities-bff-repository.js";import{createMergedEntityFieldsForSelect as j}from"../utils/create-merged-entity-fields-for-select.js";import{buildSemanticVersionSortExpr as M}from"../utils/semantic-version-sort.js";import{normalizeRevisionFlags as x}from"../utils/normalize-revision-flags.js";import{buildEntitiesExclusionFilter as A}from"../utils/build-entities-exclusion-filter.js";import{buildRbacFilter as T,buildRbacFilterRaw as Y}from"../utils/build-rbac-filter.js";class Ee{#e;#t=void 0;#i;#s;constructor(i){this.#e=i,this.#i=new $(this.#e,this.#t||""),this.#s=new B(this.#e,this.#t||"")}async attachDatabase(i){this.#t!==i&&(this.#t=i,await this.#e.client.run(e`ATTACH DATABASE ${i} AS remote`),this.#i=new $(this.#e,i),this.#s=new B(this.#e,i))}async getEntities({paginationParams:i,rbacTeams:s,excludedTypes:r,excludedEntities:n}){const o=A(r,n,"remote.entities"),c=A(r,n,"entities"),a=A(r,n,"r"),l=this.#t?p(this.#e.client.select(S("remote.entities")).from(e`remote.entities`).leftJoin(e`remote.entities_attributes`,_(t.key,d.entityKey)).where(u(T(s,"remote.entities_attributes"),o,f(this.#e.client.select({id:h.id}).from(t).where(u(e`${t.key} = remote.entities.key`,e`${t.version} = remote.entities.version`,e`${t.revision} = remote.entities.revision`))))),this.#e.client.select(S("entities")).from(t).leftJoin(d,_(t.key,d.entityKey)).where(u(T(s,"entities_attributes"),c,f(this.#e.client.select({id:e.raw("id")}).from(e`remote.entities as r`).where(u(e`r.key = ${t.key}`,e`r.version = ${t.version}`,e`r.revision = ${t.revision}`))))),this.#e.client.select(j("r","l")).from(e`remote.entities as r`).innerJoin(e`entities as l`,e`l.key = r.key AND l.version = r.version AND l.revision = r.revision`).leftJoin(e`entities_attributes as ea`,e`l.key = ea.entity_key`).where(u(T(s,"ea"),a))):this.#e.client.select(S("entities")).from(t).leftJoin(d,_(t.key,d.entityKey)).where(u(T(s,"entities_attributes"),c)),N=this.#e.client.select(h).from(l.as("combined_entities")),E=this.#e.client.select(h).from(l.as("combined_entities")).$dynamic(),k=R(E,{...i,limit:void 0,skip:void 0,after:void 0,before:void 0}),O=this.#e.client.$count(k),w=N.$dynamic(),I=i.limit||10,U=R(w,{...i,limit:I+1}),[W,V]=await Promise.all([U.run(),O]),D=W.rows,H=D.length>I;return{items:D.slice(0,I).map(C=>g(C)).filter(C=>C!==null),hasMore:H,total:V}}async getEntityKeysAndVersionsBySourceFile(i){const s=this.#t?p(this.#e.client.select({keyVersion:e`key || ':' || COALESCE(version, ${v})`.as("keyVersion")}).from(e`remote.entities`).where(u(e`source_file = ${i}`,e`source = 'file'`,e`key IS NOT NULL`)),this.#e.client.select({keyVersion:e`${t.key} || ':' || COALESCE(${t.version}, ${v})`.as("keyVersion")}).from(t).where(u(_(t.sourceFile,i),_(t.source,"file"),e`${t.key} IS NOT NULL`,f(this.#e.client.select({key:e.raw("key")}).from(e`remote.entities as remote`).where(e`remote.key = ${t.key}`))))):this.#e.client.select({keyVersion:e`${t.key} || ':' || COALESCE(${t.version}, ${v})`.as("keyVersion")}).from(t).where(u(_(t.sourceFile,i),_(t.source,"file"),X(t.key))),r=await this.#e.client.selectDistinct({keyVersion:e`combined_keys_versions.keyVersion`}).from(s.as("combined_keys_versions")).run();return new Set(r.rows.map(n=>n.keyVersion))}async listEntityRevisions(i,s){const r=[_(t.key,i),_(t.isDeleted,!1),...s?[_(t.version,s)]:[]],n={version:e.raw("version"),revision:e.raw("revision"),isCurrent:e.raw("is_current"),createdAt:e.raw("created_at"),updatedAt:e.raw("updated_at"),isDefaultVersion:e.raw("is_default_version")},o=this.#t?p(this.#e.client.select(n).from(e`remote.entities`).where(u(e`key = ${i}`,e`is_deleted = 0`,s?e`version = ${s}`:void 0,f(this.#e.client.select({id:e.raw("id")}).from(t).where(u(e`${t.key} = remote.entities.key`,e`${t.version} = remote.entities.version`,e`${t.revision} = remote.entities.revision`))))),this.#e.client.select({version:t.version,revision:t.revision,isCurrent:t.isCurrent,createdAt:t.createdAt,updatedAt:t.updatedAt,isDefaultVersion:t.isDefaultVersion}).from(t).where(u(...r,f(this.#e.client.select({id:e.raw("id")}).from(e`remote.entities as r`).where(u(e`r.key = ${t.key}`,e`r.version = ${t.version}`,e`r.revision = ${t.revision}`))))),this.#e.client.select({version:e.raw("r.version AS version"),revision:e.raw("r.revision AS revision"),isCurrent:e.raw("MAX(r.is_current, l.is_current) AS is_current"),createdAt:e.raw("MIN(r.created_at, l.created_at) AS created_at"),updatedAt:e.raw("MAX(r.updated_at, l.updated_at) AS updated_at"),isDefaultVersion:e.raw("MAX(r.is_default_version, l.is_default_version) AS is_default_version")}).from(e`remote.entities as r`).innerJoin(e`entities as l`,e`l.key = r.key AND l.version = r.version AND l.revision = r.revision`).where(u(e`r.key = ${i}`,e`r.is_deleted = 0`,e`l.is_deleted = 0`,s?e`r.version = ${s}`:void 0))):this.#e.client.select({version:t.version,revision:t.revision,isCurrent:t.isCurrent,createdAt:t.createdAt,updatedAt:t.updatedAt,isDefaultVersion:t.isDefaultVersion}).from(t).where(u(...r)),a=(await this.#e.client.select({version:e.raw("version"),revision:e.raw("revision"),isCurrent:e.raw("is_current"),createdAt:e.raw("created_at"),updatedAt:e.raw("updated_at"),isDefaultVersion:e.raw("is_default_version")}).from(o.as("combined_revisions")).orderBy(e`${M("version")} DESC`,e.raw("revision DESC")).run()).rows.map(l=>({version:l.version||null,revision:l.revision??"",isCurrent:l.is_current!==null?!!l.is_current:!1,createdAt:l.created_at||null,updatedAt:l.updated_at||null,isDefaultVersion:l.is_default_version!==null?!!l.is_default_version:!1}));return x(a),a}async getEntitiesCountByTypes(){if(this.#t){const i=e`
1
+ import{and as u,count as F,eq as _,isNotNull as X,notExists as f,or as J,sql as e}from"drizzle-orm";import{unionAll as p}from"drizzle-orm/sqlite-core";import{logger as q}from"../../../../../tools/notifiers/logger.js";import{VERSION_NOT_SPECIFIED as v}from"@redocly/theme/core/constants";import{applyPagination as R}from"../../../../../providers/database/pagination/index.js";import{applyFilter as P}from"../../../../../providers/database/pagination/filter.js";import{createEntityFieldsForSelect as S,FIELDS_TO_SELECT_FOR_ENTITY as h,FIELDS_TO_SELECT_FOR_ENTITY_RELATION as m}from"../utils.js";import{createEntityReadModel as g}from"../../mappers/create-entity-read-model.js";import{entitiesTable as t}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-table.js";import{entitiesRelationsTable as y}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-relations-table.js";import{entitiesAttributesTable as d}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-attributes-table.js";import{CatalogEntitiesRelationsRepository as b}from"./catalog-entities-relations-repository.js";import{CatalogEntitiesBffRepository as $}from"./catalog-entities-bff-repository.js";import{createMergedEntityFieldsForSelect as j}from"../utils/create-merged-entity-fields-for-select.js";import{buildSemanticVersionSortExpr as B}from"../utils/semantic-version-sort.js";import{normalizeRevisionFlags as x}from"../utils/normalize-revision-flags.js";import{buildEntitiesExclusionFilter as A}from"../utils/build-entities-exclusion-filter.js";import{buildRbacFilter as T,buildRbacFilterRaw as Y}from"../utils/build-rbac-filter.js";import{createEntityRelationReadModel as M}from"../../mappers/create-entity-relation-read-model.js";class Ee{#e;#t=void 0;#i;#s;constructor(i){this.#e=i,this.#i=new b(this.#e,this.#t||""),this.#s=new $(this.#e,this.#t||"")}async attachDatabase(i){this.#t!==i&&(this.#t=i,await this.#e.client.run(e`ATTACH DATABASE ${i} AS remote`),this.#i=new b(this.#e,i),this.#s=new $(this.#e,i))}async getEntities({paginationParams:i,rbacTeams:s,excludedTypes:r,excludedEntities:n}){const o=A(r,n,"remote.entities"),c=A(r,n,"entities"),a=A(r,n,"r"),l=this.#t?p(this.#e.client.select(S("remote.entities")).from(e`remote.entities`).leftJoin(e`remote.entities_attributes`,_(t.key,d.entityKey)).where(u(T(s,"remote.entities_attributes"),o,f(this.#e.client.select({id:h.id}).from(t).where(u(e`${t.key} = remote.entities.key`,e`${t.version} = remote.entities.version`,e`${t.revision} = remote.entities.revision`))))),this.#e.client.select(S("entities")).from(t).leftJoin(d,_(t.key,d.entityKey)).where(u(T(s,"entities_attributes"),c,f(this.#e.client.select({id:e.raw("id")}).from(e`remote.entities as r`).where(u(e`r.key = ${t.key}`,e`r.version = ${t.version}`,e`r.revision = ${t.revision}`))))),this.#e.client.select(j("r","l")).from(e`remote.entities as r`).innerJoin(e`entities as l`,e`l.key = r.key AND l.version = r.version AND l.revision = r.revision`).leftJoin(e`entities_attributes as ea`,e`l.key = ea.entity_key`).where(u(T(s,"ea"),a))):this.#e.client.select(S("entities")).from(t).leftJoin(d,_(t.key,d.entityKey)).where(u(T(s,"entities_attributes"),c)),N=this.#e.client.select(h).from(l.as("combined_entities")),E=this.#e.client.select(h).from(l.as("combined_entities")).$dynamic(),k=R(E,{...i,limit:void 0,skip:void 0,after:void 0,before:void 0}),O=this.#e.client.$count(k),w=N.$dynamic(),I=i.limit||10,U=R(w,{...i,limit:I+1}),[W,V]=await Promise.all([U.run(),O]),D=W.rows,H=D.length>I;return{items:D.slice(0,I).map(C=>g(C)).filter(C=>C!==null),hasMore:H,total:V}}async getEntityKeysAndVersionsBySourceFile(i){const s=this.#t?p(this.#e.client.select({keyVersion:e`key || ':' || COALESCE(version, ${v})`.as("keyVersion")}).from(e`remote.entities`).where(u(e`source_file = ${i}`,e`source = 'file'`,e`key IS NOT NULL`)),this.#e.client.select({keyVersion:e`${t.key} || ':' || COALESCE(${t.version}, ${v})`.as("keyVersion")}).from(t).where(u(_(t.sourceFile,i),_(t.source,"file"),e`${t.key} IS NOT NULL`,f(this.#e.client.select({key:e.raw("key")}).from(e`remote.entities as remote`).where(e`remote.key = ${t.key}`))))):this.#e.client.select({keyVersion:e`${t.key} || ':' || COALESCE(${t.version}, ${v})`.as("keyVersion")}).from(t).where(u(_(t.sourceFile,i),_(t.source,"file"),X(t.key))),r=await this.#e.client.selectDistinct({keyVersion:e`combined_keys_versions.keyVersion`}).from(s.as("combined_keys_versions")).run();return new Set(r.rows.map(n=>n.keyVersion))}async listEntityRevisions(i,s){const r=[_(t.key,i),_(t.isDeleted,!1),...s?[_(t.version,s)]:[]],n={version:e.raw("version"),revision:e.raw("revision"),isCurrent:e.raw("is_current"),createdAt:e.raw("created_at"),updatedAt:e.raw("updated_at"),isDefaultVersion:e.raw("is_default_version")},o=this.#t?p(this.#e.client.select(n).from(e`remote.entities`).where(u(e`key = ${i}`,e`is_deleted = 0`,s?e`version = ${s}`:void 0,f(this.#e.client.select({id:e.raw("id")}).from(t).where(u(e`${t.key} = remote.entities.key`,e`${t.version} = remote.entities.version`,e`${t.revision} = remote.entities.revision`))))),this.#e.client.select({version:t.version,revision:t.revision,isCurrent:t.isCurrent,createdAt:t.createdAt,updatedAt:t.updatedAt,isDefaultVersion:t.isDefaultVersion}).from(t).where(u(...r,f(this.#e.client.select({id:e.raw("id")}).from(e`remote.entities as r`).where(u(e`r.key = ${t.key}`,e`r.version = ${t.version}`,e`r.revision = ${t.revision}`))))),this.#e.client.select({version:e.raw("r.version AS version"),revision:e.raw("r.revision AS revision"),isCurrent:e.raw("MAX(r.is_current, l.is_current) AS is_current"),createdAt:e.raw("MIN(r.created_at, l.created_at) AS created_at"),updatedAt:e.raw("MAX(r.updated_at, l.updated_at) AS updated_at"),isDefaultVersion:e.raw("MAX(r.is_default_version, l.is_default_version) AS is_default_version")}).from(e`remote.entities as r`).innerJoin(e`entities as l`,e`l.key = r.key AND l.version = r.version AND l.revision = r.revision`).where(u(e`r.key = ${i}`,e`r.is_deleted = 0`,e`l.is_deleted = 0`,s?e`r.version = ${s}`:void 0))):this.#e.client.select({version:t.version,revision:t.revision,isCurrent:t.isCurrent,createdAt:t.createdAt,updatedAt:t.updatedAt,isDefaultVersion:t.isDefaultVersion}).from(t).where(u(...r)),a=(await this.#e.client.select({version:e.raw("version"),revision:e.raw("revision"),isCurrent:e.raw("is_current"),createdAt:e.raw("created_at"),updatedAt:e.raw("updated_at"),isDefaultVersion:e.raw("is_default_version")}).from(o.as("combined_revisions")).orderBy(e`${B("version")} DESC`,e.raw("revision DESC")).run()).rows.map(l=>({version:l.version,revision:l.revision??"",isCurrent:l.is_current!==null?!!l.is_current:!1,createdAt:l.created_at,updatedAt:l.updated_at,isDefaultVersion:l.is_default_version!==null?!!l.is_default_version:!1}));return x(a),a}async getEntitiesCountByTypes(){if(this.#t){const i=e`
2
2
  SELECT key, type, version,
3
3
  ROW_NUMBER() OVER (
4
4
  PARTITION BY key
5
- ORDER BY ${M("version")} DESC
5
+ ORDER BY ${B("version")} DESC
6
6
  ) as rn
7
7
  FROM (
8
8
  SELECT key, type, version FROM remote.entities WHERE is_current = 1 AND is_deleted = 0
9
9
  UNION ALL
10
10
  SELECT key, type, version FROM entities WHERE is_current = 1 AND is_deleted = 0
11
11
  )
12
- `;return this.#e.client.select({type:e`type`,count:F()}).from(e`(SELECT * FROM (${i}) WHERE rn = 1) as highest_version_entities`).groupBy(e`type`)}return this.#e.client.select({type:t.type,count:F()}).from(t).where(u(_(t.isCurrent,!0),_(t.isDeleted,!1))).groupBy(t.type)}async getEntityById(i,s){const{rbacTeams:r,excludedTypes:n,excludedEntities:o}=s||{},c=A(n,o,"remote.entities"),a=A(n,o,"entities"),E=(await(this.#t?p(this.#e.client.select(S("remote.entities")).from(e`remote.entities`).leftJoin(e`remote.entities_attributes`,_(t.key,d.entityKey)).where(u(e`remote.entities.id = ${i}`,T(r,"remote.entities_attributes"),c)),this.#e.client.select(S("entities")).from(t).leftJoin(d,_(t.key,d.entityKey)).where(u(_(t.id,i),T(r,"entities_attributes"),a))):this.#e.client.select(S("entities")).from(t).leftJoin(d,_(t.key,d.entityKey)).where(u(_(t.id,i),T(r,"entities_attributes"),a))).run()).rows[0];return E?g(E):null}async getOutdatedEntities(i){const s=this.#t?p(this.#e.client.select(h).from(e`remote.entities`),this.#e.client.select(h).from(t).where(f(this.#e.client.select({id:h.id}).from(e`remote.entities as remote`).where(e`remote.key = ${t.key}`)))):this.#e.client.select(h).from(t),r=this.#e.client.select(h).from(s.as("combined_entities")).$dynamic(),{whereCondition:n}=P(r,i),o=J(e`combined_entities.scorecards_status = 'OUTDATED'`,e`combined_entities.scorecards_status IS NULL`),c=n?u(n,o):o;return(await r.where(c).run()).rows.map(l=>g(l)).filter(l=>l!==null)}async getEntitiesRelations(i={}){const s=this.#t?p(this.#e.client.select(m).from(e`remote.entities_relations`),this.#e.client.select(m).from(y).where(f(this.#e.client.select({id:m.id}).from(e`remote.entities_relations as remote`).where(e`remote.source_key = ${y.sourceKey}`)))):this.#e.client.select(m).from(y),r=this.#e.client.select(m).from(s.as("combined_entities_relations")).$dynamic(),n=this.#e.client.select(m).from(s.as("combined_entities_relations")).$dynamic(),o=R(n,{...i,limit:void 0,skip:void 0,after:void 0,before:void 0}),c=this.#e.client.$count(o),a=i.limit||10,l=R(r,{...i,limit:a+1}),[N,E]=await Promise.all([l.run(),c]),k=N.rows,O=k.length>a;return{items:k.slice(0,a).map(w=>b(w)).filter(w=>w!==null),hasMore:O,total:E}}async getEntityRelationById(i){const n=(await(this.#t?p(this.#e.client.select(m).from(e`remote.entities_relations`).where(_(y.id,i)),this.#e.client.select(m).from(y).where(u(_(y.id,i),f(this.#e.client.select({id:m.id}).from(e`remote.entities_relations as remote`).where(e`remote.id = ${y.id}`))))):this.#e.client.select(m).from(y).where(_(y.id,i))).run()).rows[0];return n?b(n):null}async getEntitiesWithRelations({paginationParams:i,rbacTeams:s,excludedEntities:r,excludedTypes:n}){return this.#s.getEntitiesWithRelations({paginationParams:i,rbacTeams:s,excludedEntities:r,excludedTypes:n})}async getEntityWithRelationsByKey({entityKey:i,filter:s,rbacTeams:r,excludedTypes:n,excludedEntities:o}){return this.#s.getEntityWithRelationsByKey({entityKey:i,filter:s,rbacTeams:r,excludedTypes:n,excludedEntities:o})}async getRelationsForEntity(i,s,r){return this.#i.getRelationsForEntity(i,s,r)}async getRelatedEntities({key:i,paginationParams:s,rbacTeams:r,excludedTypes:n,excludedEntities:o}){return this.#i.getRelatedEntities({key:i,paginationParams:s,rbacTeams:r,excludedTypes:n,excludedEntities:o})}async getCatalogFilters({entitiesTypes:i=[],emptyFilters:s=[],rbacTeams:r,excludedTypes:n,excludedEntities:o}){if(!s.length)return{};try{return await this.#r({entitiesTypes:i,rbacTeams:r,excludedTypes:n,excludedEntities:o}),(s.includes("domains")||s.includes("owners"))&&await this.#o(),await this.#a(s)}catch(c){return console.error("Error fetching catalog filters:",c),{}}finally{await this.#c()}}async#r({entitiesTypes:i,rbacTeams:s,excludedTypes:r,excludedEntities:n}){const o=Y(s,"ea"),c=this.#n(r,n);if(this.#t){const a=["e.is_current = 1","e.is_deleted = 0"];o&&a.push(o),c&&a.push(c.replace(/ENTITY_ALIAS/g,"e"));const l=["r.key IS NULL","e.is_current = 1","e.is_deleted = 0"];o&&l.push(o),c&&l.push(c.replace(/ENTITY_ALIAS/g,"e")),await this.#e.client.run(e.raw(`
12
+ `;return this.#e.client.select({type:e`type`,count:F()}).from(e`(SELECT * FROM (${i}) WHERE rn = 1) as highest_version_entities`).groupBy(e`type`)}return this.#e.client.select({type:t.type,count:F()}).from(t).where(u(_(t.isCurrent,!0),_(t.isDeleted,!1))).groupBy(t.type)}async getEntityById(i,s){const{rbacTeams:r,excludedTypes:n,excludedEntities:o}=s||{},c=A(n,o,"remote.entities"),a=A(n,o,"entities"),E=(await(this.#t?p(this.#e.client.select(S("remote.entities")).from(e`remote.entities`).leftJoin(e`remote.entities_attributes`,_(t.key,d.entityKey)).where(u(e`remote.entities.id = ${i}`,T(r,"remote.entities_attributes"),c)),this.#e.client.select(S("entities")).from(t).leftJoin(d,_(t.key,d.entityKey)).where(u(_(t.id,i),T(r,"entities_attributes"),a))):this.#e.client.select(S("entities")).from(t).leftJoin(d,_(t.key,d.entityKey)).where(u(_(t.id,i),T(r,"entities_attributes"),a))).run()).rows[0];return E?g(E):null}async getOutdatedEntities(i){const s=this.#t?p(this.#e.client.select(h).from(e`remote.entities`),this.#e.client.select(h).from(t).where(f(this.#e.client.select({id:h.id}).from(e`remote.entities as remote`).where(e`remote.key = ${t.key}`)))):this.#e.client.select(h).from(t),r=this.#e.client.select(h).from(s.as("combined_entities")).$dynamic(),{whereCondition:n}=P(r,i),o=J(e`combined_entities.scorecards_status = 'OUTDATED'`,e`combined_entities.scorecards_status IS NULL`),c=n?u(n,o):o;return(await r.where(c).run()).rows.map(l=>g(l)).filter(l=>l!==null)}async getEntitiesRelations(i={}){const s=this.#t?p(this.#e.client.select(m).from(e`remote.entities_relations`),this.#e.client.select(m).from(y).where(f(this.#e.client.select({id:m.id}).from(e`remote.entities_relations as remote`).where(e`remote.source_key = ${y.sourceKey}`)))):this.#e.client.select(m).from(y),r=this.#e.client.select(m).from(s.as("combined_entities_relations")).$dynamic(),n=this.#e.client.select(m).from(s.as("combined_entities_relations")).$dynamic(),o=R(n,{...i,limit:void 0,skip:void 0,after:void 0,before:void 0}),c=this.#e.client.$count(o),a=i.limit||10,l=R(r,{...i,limit:a+1}),[N,E]=await Promise.all([l.run(),c]),k=N.rows,O=k.length>a;return{items:k.slice(0,a).map(w=>M(w)).filter(w=>w!==null),hasMore:O,total:E}}async getEntityRelationById(i){const n=(await(this.#t?p(this.#e.client.select(m).from(e`remote.entities_relations`).where(_(y.id,i)),this.#e.client.select(m).from(y).where(u(_(y.id,i),f(this.#e.client.select({id:m.id}).from(e`remote.entities_relations as remote`).where(e`remote.id = ${y.id}`))))):this.#e.client.select(m).from(y).where(_(y.id,i))).run()).rows[0];return n?M(n):null}async getEntitiesWithRelations({paginationParams:i,rbacTeams:s,excludedEntities:r,excludedTypes:n}){return this.#s.getEntitiesWithRelations({paginationParams:i,rbacTeams:s,excludedEntities:r,excludedTypes:n})}async getEntityWithRelationsByKey({entityKey:i,filter:s,rbacTeams:r,excludedTypes:n,excludedEntities:o}){return this.#s.getEntityWithRelationsByKey({entityKey:i,filter:s,rbacTeams:r,excludedTypes:n,excludedEntities:o})}async getRelationsForEntity(i,s,r){return this.#i.getRelationsForEntity(i,s,r)}async getRelatedEntities({key:i,paginationParams:s,rbacTeams:r,excludedTypes:n,excludedEntities:o}){return this.#i.getRelatedEntities({key:i,paginationParams:s,rbacTeams:r,excludedTypes:n,excludedEntities:o})}async getCatalogFilters({entitiesTypes:i=[],emptyFilters:s=[],rbacTeams:r,excludedTypes:n,excludedEntities:o}){if(!s.length)return{};try{return await this.#r({entitiesTypes:i,rbacTeams:r,excludedTypes:n,excludedEntities:o}),(s.includes("domains")||s.includes("owners"))&&await this.#o(),await this.#a(s)}catch(c){return console.error("Error fetching catalog filters:",c),{}}finally{await this.#c()}}async#r({entitiesTypes:i,rbacTeams:s,excludedTypes:r,excludedEntities:n}){const o=Y(s,"ea"),c=this.#n(r,n);if(this.#t){const a=["e.is_current = 1","e.is_deleted = 0"];o&&a.push(o),c&&a.push(c.replace(/ENTITY_ALIAS/g,"e"));const l=["r.key IS NULL","e.is_current = 1","e.is_deleted = 0"];o&&l.push(o),c&&l.push(c.replace(/ENTITY_ALIAS/g,"e")),await this.#e.client.run(e.raw(`
13
13
  CREATE TEMP TABLE IF NOT EXISTS temp_combined_entities AS
14
14
  SELECT
15
15
  e.key,
@@ -28,34 +28,8 @@ export declare class CatalogEntitiesLocalRepository extends BaseRepository {
28
28
  type: string;
29
29
  count: number;
30
30
  }[]>;
31
- getEntitiesRelations(paginationParams?: PaginationParams): Promise<import("./catalog-entities-local-read-repository.js").ListResult<{
32
- createdAt?: string | null | undefined;
33
- updatedAt?: string | null | undefined;
34
- sourceVersion?: string | null | undefined;
35
- sourceRevision?: string | null | undefined;
36
- targetVersion?: string | null | undefined;
37
- targetRevision?: string | null | undefined;
38
- type: string;
39
- id: string;
40
- organizationId: string;
41
- projectId: string;
42
- sourceKey: string;
43
- targetKey: string;
44
- }>>;
45
- getEntityRelationById(id: string): Promise<{
46
- createdAt?: string | null | undefined;
47
- updatedAt?: string | null | undefined;
48
- sourceVersion?: string | null | undefined;
49
- sourceRevision?: string | null | undefined;
50
- targetVersion?: string | null | undefined;
51
- targetRevision?: string | null | undefined;
52
- type: string;
53
- id: string;
54
- organizationId: string;
55
- projectId: string;
56
- sourceKey: string;
57
- targetKey: string;
58
- } | null>;
31
+ getEntitiesRelations(paginationParams?: PaginationParams): Promise<import("./catalog-entities-local-read-repository.js").ListResult<import("../../../../../plugins/catalog-entities/schemas/read-model-schemas.js").EntityRelationReadModelSchema>>;
32
+ getEntityRelationById(id: string): Promise<import("../../../../../plugins/catalog-entities/schemas/read-model-schemas.js").EntityRelationReadModelSchema | null>;
59
33
  getEntitiesWithRelations({ paginationParams, rbacTeams, excludedTypes, excludedEntities, }: {
60
34
  paginationParams: PaginationParams;
61
35
  rbacTeams?: string[];
@@ -89,14 +63,14 @@ export declare class CatalogEntitiesLocalRepository extends BaseRepository {
89
63
  projectId: string;
90
64
  sourceFile: string | null;
91
65
  isDeleted: boolean | null;
66
+ fileHash: string | null;
92
67
  sourceKey: string;
93
- targetKey: string;
94
68
  sourceVersion: string;
95
69
  sourceRevision: string;
70
+ sourceToTargetRelation: string;
71
+ targetKey: string;
96
72
  targetVersion: string;
97
73
  targetRevision: string;
98
- fileHash: string | null;
99
- sourceToTargetRelation: string;
100
74
  targetToSourceRelation: string;
101
75
  } | null>;
102
76
  createEntityRelations(relations: EntityRelationDtoSchema[]): Promise<void>;
@@ -1 +1 @@
1
- import{and as m,eq as c,isNull as v,or as N,sql as T}from"drizzle-orm";import{logger as u}from"../../../../../tools/notifiers/logger.js";import{promiseMapLimit as E}from"../../../../../utils/async/promise-map-limit.js";import{sha1 as F}from"../../../../../utils/crypto/sha1.js";import{isWebView as b}from"../../../../../../utils/env/is-web-view.js";import{VERSION_NOT_SPECIFIED as O}from"@redocly/theme/core/constants";import{entitiesAttributesTable as D}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-attributes-table.js";import{createEntityDbRecord as U}from"../../mappers/create-entity-db-record.js";import{createEntityRelationDbRecordFromFileSchema as I}from"../../mappers/create-entity-relation-db-record-from-file-schema.js";import{entitiesTable as r}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-table.js";import{entitiesRelationsTable as i}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-relations-table.js";import{convertFilterToWhereCondition as C}from"../../../../../providers/database/pagination/filter.js";import{createEntityAttributesDbRecord as z}from"../../mappers/create-entity-attributes-db-record.js";import{RevisionRepository as P}from"../common/revision-repository.js";import{VersionRepository as j}from"../common/version-repository.js";const w=15;class re{#e;#t;#r;#i;#s;constructor(e,t,s){this.#e=e,this.#t=t,this.#r=s,this.#i=new P(e),this.#s=new j(e)}async createEntity({entity:e,fileHash:t,sourceFile:s,revision:a=new Date().toISOString(),isRootEntity:o=!1,isDeleted:n=!1,rbacTeams:d}){try{const{relations:l=[],...f}=e,p=F(JSON.stringify(f)),y=e.version??O,g=await this.#i.shouldSkipRevisionCreation(e.key,y,p,o,n);if(Array.isArray(d)&&await this.#o({entityKey:e.key,rbacTeams:d}),g)return{result:"skipped",entityKey:e.key};const h=await this.#i.shouldSetNewCurrentRevision({key:e.key,version:y,revision:a}),R=U({entity:{...e,revision:a,hash:p,isCurrent:h,isDefaultVersion:h,isDeleted:n,version:y},sourceFile:s,organizationId:this.#t,projectId:this.#r,source:"file",fileHash:t}),{key:V,source:L,...K}=R;if(h&&(await this.#i.markAllRevisionsAsNotCurrent(V),await this.#s.markAllVersionsAsNotDefault(V)),b())return await this.#n(R,l),{result:"created",entityKey:e.key,entityRevision:a,entityVersion:y};const S=this.#e.client.insert(r).values(R).onConflictDoUpdate({target:[r.key,r.source,r.revision,r.version],set:K}),A=l?.length&&l.length>0?this.#e.client.insert(i).values(l.map(k=>I({relation:k,sourceFile:s,fileHash:t,sourceKey:e.key,sourceVersion:y,sourceRevision:a??null,organizationId:this.#t,projectId:this.#r}))).onConflictDoNothing({target:[i.sourceKey,i.targetKey,i.sourceVersion,i.targetVersion,i.sourceRevision,i.targetRevision,i.sourceToTargetRelation]}).run():Promise.resolve();return await E([S,A],w,async k=>k),{result:"created",entityKey:e.key,entityRevision:a,entityVersion:y}}catch(l){return u.error("Error adding entity",l),{result:"error",entityKey:e.key}}}async deleteEntity(e){try{return await this.#e.client.delete(r).where(c(r.key,e)),e}catch(t){return u.error("Error deleting entity",t),null}}async deleteEntities(e){try{const t=C(e);if(!t)return!1;const s=await this.#e.client.delete(r).where(t).returning({key:r.key,source:r.source,isCurrent:r.isCurrent,isDefaultVersion:r.isDefaultVersion,version:r.version});if(s.length===0)return!0;const a=s.reduce((o,n)=>((n.isCurrent||n.isDefaultVersion)&&o.add(n.key),o),new Set);if(a.size===0)return!0;await E(Array.from(a),w,async o=>this.#i.ensureDefaultAndCurrentRevisionForKey(o));for(const o of s)await this.#e.client.delete(i).where(N(m(c(i.sourceKey,o.key),...o.version?[c(i.sourceVersion,o.version)]:[v(i.sourceVersion)]),m(c(i.targetKey,o.key),...o.version?[c(i.targetVersion,o.version)]:[v(i.targetVersion)])));return!0}catch(t){return u.error("Error deleting entities",t),!1}}async deleteEntityRelation(e){try{return await this.#e.client.delete(i).where(c(i.id,e)),e}catch{return null}}async softDeleteEntities(e,t,s){try{const a=e.map(n=>{const d={type:n.type,key:n.key,title:n.title,summary:n.summary??void 0,tags:n.tags??void 0,metadata:n.metadata??void 0,git:n.git??void 0,contact:n.contact??void 0,links:n.links??void 0,version:n.version??void 0};return this.createEntity({entity:d,revision:t,sourceFile:n.sourceFile??"",fileHash:s,isDeleted:!0})});return await E(a,w,async n=>n)}catch(a){return u.error("Error soft deleting entities",a),[]}}async deleteEntityRelations(e){try{const t=C(e);return t?(await this.#e.client.delete(i).where(t),!0):!1}catch(t){return u.error("Error deleting entity relations",t),!1}}async upsertEntityRelation(e){if(!e)return null;try{const{sourceKey:t,targetKey:s,sourceVersion:a,targetVersion:o,sourceRevision:n,targetRevision:d,...l}=e,f=await this.#e.client.insert(i).values(e).onConflictDoUpdate({target:[i.sourceKey,i.targetKey,i.sourceVersion,i.targetVersion,i.sourceRevision,i.targetRevision,i.sourceToTargetRelation],set:l}).returning();return f?.length?f[0]:null}catch(t){return u.error("Error creating entity relation",t),null}}async#n(e,t){const{key:s,source:a,version:o,isDefaultVersion:n,...d}=e,p=(await this.#e.client.select({id:r.id}).from(r).where(m(c(r.key,s),c(r.source,a??"file"),o?c(r.version,o):v(r.version))).limit(1).run()).rows.length>0?this.#e.client.update(r).set(d).where(m(c(r.key,s),c(r.source,a??"file"),o?c(r.version,o):v(r.version))).run():this.#e.client.insert(r).values(e).onConflictDoUpdate({target:[r.key,r.source,r.revision,r.version],set:d}).run(),y=t?.map(g=>{const h=I({relation:g,sourceFile:e.sourceFile??"",fileHash:e.fileHash??"",sourceKey:e.key,sourceVersion:e.version??null,sourceRevision:e.revision??null,organizationId:this.#t,projectId:this.#r});return this.#e.client.insert(i).values(h).onConflictDoUpdate({target:[i.sourceKey,i.targetKey,i.sourceVersion,i.targetVersion,i.sourceRevision,i.targetRevision,i.sourceToTargetRelation],set:h}).run()})??[];await E([p,...y],w,async g=>g)}async updateEntityScorecardsStatus(e,t){try{return(await this.#e.client.update(r).set({scorecardsStatus:t}).where(c(r.id,e)).returning()).length>0}catch(s){return u.error("Error updating entity scorecards status",s),!1}}async updateEntityScorecardsStatusIfCalculating(e,t){try{return(await this.#e.client.update(r).set({scorecardsStatus:t}).where(T`${r.id} = ${e} AND ${r.scorecardsStatus} = 'CALCULATING'`).returning()).length>0}catch(s){return u.error("Error updating entity scorecards status if calculating",s),!1}}async#o({entityKey:e,rbacTeams:t}){try{await this.#e.client.insert(D).values(z({rbacTeams:t,entityKey:e,organizationId:this.#t,projectId:this.#r})).onConflictDoUpdate({target:[D.entityKey],set:{rbacTeams:JSON.stringify(t)}}).run()}catch(s){u.error("Error saving entity attributes",s)}}async setEntitiesAsOutdated(e){try{const t=C(e);await this.#e.client.update(r).set({scorecardsStatus:"OUTDATED"}).where(t)}catch(t){u.error("Error updating entities as outdated",t)}}}export{re as CatalogEntitiesLocalWriteRepository};
1
+ import{and as m,eq as c,isNull as v,or as T,sql as F}from"drizzle-orm";import{logger as u}from"../../../../../tools/notifiers/logger.js";import{promiseMapLimit as E}from"../../../../../utils/async/promise-map-limit.js";import{sha1 as O}from"../../../../../utils/crypto/sha1.js";import{envConfig as V}from"../../../../../../config/env-config.js";import{VERSION_NOT_SPECIFIED as U}from"@redocly/theme/core/constants";import{entitiesAttributesTable as I}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-attributes-table.js";import{createEntityDbRecord as b}from"../../mappers/create-entity-db-record.js";import{createEntityRelationDbRecordFromFileSchema as K}from"../../mappers/create-entity-relation-db-record-from-file-schema.js";import{entitiesTable as r}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-table.js";import{entitiesRelationsTable as i}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-relations-table.js";import{convertFilterToWhereCondition as C}from"../../../../../providers/database/pagination/filter.js";import{createEntityAttributesDbRecord as z}from"../../mappers/create-entity-attributes-db-record.js";import{RevisionRepository as L}from"../common/revision-repository.js";import{VersionRepository as P}from"../common/version-repository.js";const w=15;class re{#e;#t;#r;#i;#s;constructor(e,t,s){this.#e=e,this.#t=t,this.#r=s,this.#i=new L(e),this.#s=new P(e)}async createEntity({entity:e,fileHash:t,sourceFile:s,revision:a=new Date().toISOString(),isRootEntity:o=!1,isDeleted:n=!1,rbacTeams:d}){try{const{relations:l=[],...f}=e,p=O(JSON.stringify(f)),y=e.version??U,g=await this.#i.shouldSkipRevisionCreation(e.key,y,p,o,n);if(Array.isArray(d)&&await this.#o({entityKey:e.key,rbacTeams:d}),g)return{result:"skipped",entityKey:e.key};const h=await this.#i.shouldSetNewCurrentRevision({key:e.key,version:y,revision:a}),R=b({entity:{...e,revision:a,hash:p,isCurrent:h,isDefaultVersion:h,isDeleted:n,version:y},sourceFile:s,organizationId:this.#t,projectId:this.#r,source:"file",fileHash:t}),{key:D,source:x,...S}=R;if(h&&(await this.#i.markAllRevisionsAsNotCurrent(D),await this.#s.markAllVersionsAsNotDefault(D)),V.isDevelopMode&&V.REDOCLY_INTERNAL_DEV!=="true")return await this.#n(R,l),{result:"created",entityKey:e.key,entityRevision:a,entityVersion:y};const A=this.#e.client.insert(r).values(R).onConflictDoUpdate({target:[r.key,r.source,r.revision,r.version],set:S}),N=l?.length&&l.length>0?this.#e.client.insert(i).values(l.map(k=>K({relation:k,sourceFile:s,fileHash:t,sourceKey:e.key,sourceVersion:y,sourceRevision:a??null,organizationId:this.#t,projectId:this.#r}))).onConflictDoNothing({target:[i.sourceKey,i.targetKey,i.sourceVersion,i.targetVersion,i.sourceRevision,i.targetRevision,i.sourceToTargetRelation]}).run():Promise.resolve();return await E([A,N],w,async k=>k),{result:"created",entityKey:e.key,entityRevision:a,entityVersion:y}}catch(l){return u.error("Error adding entity",l),{result:"error",entityKey:e.key}}}async deleteEntity(e){try{return await this.#e.client.delete(r).where(c(r.key,e)),e}catch(t){return u.error("Error deleting entity",t),null}}async deleteEntities(e){try{const t=C(e);if(!t)return!1;const s=await this.#e.client.delete(r).where(t).returning({key:r.key,source:r.source,isCurrent:r.isCurrent,isDefaultVersion:r.isDefaultVersion,version:r.version});if(s.length===0)return!0;const a=s.reduce((o,n)=>((n.isCurrent||n.isDefaultVersion)&&o.add(n.key),o),new Set);if(a.size===0)return!0;await E(Array.from(a),w,async o=>this.#i.ensureDefaultAndCurrentRevisionForKey(o));for(const o of s)await this.#e.client.delete(i).where(T(m(c(i.sourceKey,o.key),...o.version?[c(i.sourceVersion,o.version)]:[v(i.sourceVersion)]),m(c(i.targetKey,o.key),...o.version?[c(i.targetVersion,o.version)]:[v(i.targetVersion)])));return!0}catch(t){return u.error("Error deleting entities",t),!1}}async deleteEntityRelation(e){try{return await this.#e.client.delete(i).where(c(i.id,e)),e}catch{return null}}async softDeleteEntities(e,t,s){try{const a=e.map(n=>{const d={type:n.type,key:n.key,title:n.title,summary:n.summary??void 0,tags:n.tags??void 0,metadata:n.metadata??void 0,git:n.git??void 0,contact:n.contact??void 0,links:n.links??void 0,version:n.version??void 0};return this.createEntity({entity:d,revision:t,sourceFile:n.sourceFile??"",fileHash:s,isDeleted:!0})});return await E(a,w,async n=>n)}catch(a){return u.error("Error soft deleting entities",a),[]}}async deleteEntityRelations(e){try{const t=C(e);return t?(await this.#e.client.delete(i).where(t),!0):!1}catch(t){return u.error("Error deleting entity relations",t),!1}}async upsertEntityRelation(e){if(!e)return null;try{const{sourceKey:t,targetKey:s,sourceVersion:a,targetVersion:o,sourceRevision:n,targetRevision:d,...l}=e,f=await this.#e.client.insert(i).values(e).onConflictDoUpdate({target:[i.sourceKey,i.targetKey,i.sourceVersion,i.targetVersion,i.sourceRevision,i.targetRevision,i.sourceToTargetRelation],set:l}).returning();return f?.length?f[0]:null}catch(t){return u.error("Error creating entity relation",t),null}}async#n(e,t){const{key:s,source:a,version:o,isDefaultVersion:n,...d}=e,p=(await this.#e.client.select({id:r.id}).from(r).where(m(c(r.key,s),c(r.source,a??"file"),o?c(r.version,o):v(r.version))).limit(1).run()).rows.length>0?this.#e.client.update(r).set(d).where(m(c(r.key,s),c(r.source,a??"file"),o?c(r.version,o):v(r.version))).run():this.#e.client.insert(r).values(e).onConflictDoUpdate({target:[r.key,r.source,r.revision,r.version],set:d}).run(),y=t?.map(g=>{const h=K({relation:g,sourceFile:e.sourceFile??"",fileHash:e.fileHash??"",sourceKey:e.key,sourceVersion:e.version??null,sourceRevision:e.revision??null,organizationId:this.#t,projectId:this.#r});return this.#e.client.insert(i).values(h).onConflictDoUpdate({target:[i.sourceKey,i.targetKey,i.sourceVersion,i.targetVersion,i.sourceRevision,i.targetRevision,i.sourceToTargetRelation],set:h}).run()})??[];await E([p,...y],w,async g=>g)}async updateEntityScorecardsStatus(e,t){try{return(await this.#e.client.update(r).set({scorecardsStatus:t}).where(c(r.id,e)).returning()).length>0}catch(s){return u.error("Error updating entity scorecards status",s),!1}}async updateEntityScorecardsStatusIfCalculating(e,t){try{return(await this.#e.client.update(r).set({scorecardsStatus:t}).where(F`${r.id} = ${e} AND ${r.scorecardsStatus} = 'CALCULATING'`).returning()).length>0}catch(s){return u.error("Error updating entity scorecards status if calculating",s),!1}}async#o({entityKey:e,rbacTeams:t}){try{await this.#e.client.insert(I).values(z({rbacTeams:t,entityKey:e,organizationId:this.#t,projectId:this.#r})).onConflictDoUpdate({target:[I.entityKey],set:{rbacTeams:JSON.stringify(t)}}).run()}catch(s){u.error("Error saving entity attributes",s)}}async setEntitiesAsOutdated(e){try{const t=C(e);await this.#e.client.update(r).set({scorecardsStatus:"OUTDATED"}).where(t)}catch(t){u.error("Error updating entities as outdated",t)}}}export{re as CatalogEntitiesLocalWriteRepository};
@@ -1,8 +1,7 @@
1
- import type { EntityReadModelSchema } from '../../../schemas/read-model-schemas.js';
1
+ import type { EntityReadModelSchema, EntityRelationReadModelSchema } from '../../../schemas/read-model-schemas.js';
2
2
  import type { EntityDtoSchema, EntityRelationDtoSchema } from '../../../schemas/dto-schemas.js';
3
3
  import type { Filter } from '../../../../../providers/database/pagination/types.js';
4
4
  import type { DatabaseConnection, RepositoryInstanceOptions } from '../../../../../providers/database/types.js';
5
- import type { DatabaseEntityRelation } from '../../../../../providers/database/databases/catalog-sqlite/schemas/entities-relations-table.js';
6
5
  import { BaseRepository } from '../../../../../providers/database/base-repository.js';
7
6
  export declare class CatalogEntitiesRemoteRepository extends BaseRepository {
8
7
  #private;
@@ -13,8 +12,8 @@ export declare class CatalogEntitiesRemoteRepository extends BaseRepository {
13
12
  createEntity(entity: EntityDtoSchema): Promise<EntityReadModelSchema | null>;
14
13
  updateEntity(incomingEntity: Partial<EntityDtoSchema>, entityToBeUpdated: EntityReadModelSchema): Promise<EntityReadModelSchema | null>;
15
14
  deleteEntity(entityToBeRemoved: EntityReadModelSchema): Promise<string | null>;
16
- createEntityRelations(relations: EntityRelationDtoSchema[]): Promise<(DatabaseEntityRelation | null)[]>;
17
- createEntityRelation(entityRelation: EntityRelationDtoSchema): Promise<DatabaseEntityRelation | null>;
15
+ createEntityRelations(relations: EntityRelationDtoSchema[]): Promise<(EntityRelationReadModelSchema | null)[]>;
16
+ createEntityRelation(entityRelation: EntityRelationDtoSchema): Promise<EntityRelationReadModelSchema | null>;
18
17
  deleteEntityRelation(id: string): Promise<string | null>;
19
18
  deleteEntitiesRelations(filter: Filter): Promise<boolean>;
20
19
  }
@@ -1 +1 @@
1
- import{and as g,eq as n,ne as R,or as f,sql as p}from"drizzle-orm";import{convertFilterToWhereCondition as D}from"../../../../../providers/database/pagination/filter.js";import{promiseMapLimit as V}from"../../../../../utils/async/promise-map-limit.js";import{sha1 as E}from"../../../../../utils/crypto/sha1.js";import{logger as a}from"../../../../../tools/notifiers/logger.js";import{entitiesTable as i}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-table.js";import{telemetryTraceStep as c}from"../../../../../telemetry/helpers/trace-step.js";import{BaseRepository as A}from"../../../../../providers/database/base-repository.js";import{DatabaseConnectionFactory as I}from"../../../../../providers/database/database-connection-factory.js";import{entitiesRelationsTable as r}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-relations-table.js";import{VERSION_NOT_SPECIFIED as b}from"@redocly/theme/core/constants";import{createEntityDbRecord as _}from"../../mappers/create-entity-db-record.js";import{createEntityReadModel as k}from"../../mappers/create-entity-read-model.js";import{createEntityRelationDbRecordFromDto as O}from"../../mappers/create-entity-relation-db-record-from-dto.js";import{RevisionRepository as K}from"../common/revision-repository.js";import{VersionRepository as F}from"../common/version-repository.js";const S=15;class h extends A{static#r;#t;#i;#n=!1;get transactionsManager(){return this.databaseClient.transactionsManager}constructor(t){super(t),this.#t=new K(t.client),this.#i=new F(t.client)}async sync(){if(!this.#n&&this.isNonRemoteDatabaseMode()){a.warn("Catalog entities database is currently operating in local mode: not connected to the remote database. All changes and data will only persist locally and will not be synced remotely."),this.#n=!0;return}return c("catalog_entities.remote_repository.sync",async()=>{await this.#e(),await this.databaseClient.sync()})}static async getInstance(t){return await c("catalog_entities.remote_repository.get_instance",async e=>{if(!h.#r)try{const o=await I.create("sqld-remote",t);if(!o)return a.error("Failed to create db connection for catalog entities remote repository"),e?.error(new Error("Failed to create db connection for catalog entities remote repository")),h.#r=null,null;h.#r=new h(o)}catch(o){return a.error("Error creating db connection for catalog entities remote repository",o),e?.error(o),h.#r=null,null}return h.#r})}async createEntity(t){return c("catalog_entities.remote_repository.create_entity",async()=>{await this.#e();try{a.info(`Adding entity ${t.key} to remote database`);const{relations:e=[],...o}=t,l=E(JSON.stringify(o)),s=t.version??b,y=t.revision??new Date().toISOString();if(await this.#t.shouldSkipRevisionCreation(t.key,s,l))throw new Error("Entity validation failed: entity already exists");const d=await this.#t.shouldSetNewCurrentRevision({key:t.key,version:s,revision:y}),u=_({entity:{...t,revision:y,hash:l,isCurrent:d,isDefaultVersion:d,version:s},organizationId:this.organizationId,projectId:this.projectId,source:"remote",sourceFile:null,fileHash:null}),{key:m,source:L,...N}=u;d&&(await this.#t.markAllRevisionsAsNotCurrent(m),await this.#i.markAllVersionsAsNotDefault(m));const v=await this.databaseClient.client.insert(i).values(u).onConflictDoUpdate({target:[i.key,i.source,i.revision,i.version],set:N}).returning();return v.length?(e&&await this.createEntityRelations(e.map(C=>({...C,sourceKey:t.key,targetKey:C.key}))),k(v[0])):null}catch(e){throw a.error("Error adding entity",e),e}})}async updateEntity(t,e){return c("catalog_entities.remote_repository.update_entity",async()=>{await this.#e();try{a.info(`Updating entity ${e.key} in remote database`);const o=await this.#t.shouldSetNewCurrentRevision({key:e.key,version:t.version??e.version??b,revision:e.revision});o&&(await this.#t.markAllRevisionsAsNotCurrent(e.key),await this.#i.markAllVersionsAsNotDefault(e.key));const l=_({entity:{...e,...t,hash:E(JSON.stringify({...e,...t})),isCurrent:o,isDefaultVersion:o,createdAt:e.createdAt??void 0},organizationId:this.organizationId,projectId:this.projectId,source:"remote",sourceFile:null,fileHash:null}),{key:s,source:y,scorecardsStatus:w,...d}=l,u=await this.databaseClient.client.insert(i).values(l).onConflictDoUpdate({target:[i.key,i.source,i.revision,i.version],set:{...d,scorecardsStatus:p`CASE WHEN ${i.scorecardsStatus} = 'CALCULATING' THEN 'CANCELLED' ELSE 'OUTDATED' END`}}).returning();return u.length?k(u[0]):null}catch(o){return a.error("Error updating entity",o),null}})}async deleteEntity(t){return c("catalog_entities.remote_repository.delete_entity",async()=>{await this.#e();try{return await this.#o(t),await this.databaseClient.client.delete(i).where(n(i.id,t.id)),await this.#t.ensureDefaultAndCurrentRevisionForKey(t.key),t.id}catch(e){return a.error("Error deleting entity",e),null}})}async createEntityRelations(t){return c("catalog_entities.remote_repository.create_entity_relations",async()=>(await this.#e(),await V(t,S,async e=>this.createEntityRelation(e))))}async createEntityRelation(t){return c("catalog_entities.remote_repository.create_entity_relation",async()=>{if(await this.#e(),!t)return null;try{const e=O(t,this.organizationId,this.projectId),{sourceKey:o,targetKey:l,sourceVersion:s,targetVersion:y,sourceRevision:w,targetRevision:d,...u}=e,m=await this.databaseClient.client.insert(r).values(e).onConflictDoUpdate({target:[r.sourceKey,r.targetKey,r.sourceVersion,r.targetVersion,r.sourceRevision,r.targetRevision,r.sourceToTargetRelation],set:u}).returning();return m.length?m[0]:null}catch(e){throw a.error("Error creating entity relation",e),e}})}async deleteEntityRelation(t){return c("catalog_entities.remote_repository.delete_entity_relation",async()=>{await this.#e();try{return await this.databaseClient.client.delete(r).where(n(r.id,t)),t}catch(e){return a.error("Error deleting entity relation",e),null}})}async deleteEntitiesRelations(t){return c("catalog_entities.remote_repository.delete_entities_relations",async()=>{await this.#e();try{const e=D(t);return e?(await this.databaseClient.client.delete(r).where(e),!0):!1}catch(e){return a.error("Error deleting entities relations",e),!1}})}async#o(t){const{key:e,version:o,revision:l}=t,s=o??"",y=l??"";if(((await this.databaseClient.client.select({count:p`COUNT(*)`}).from(i).where(g(n(i.key,e),R(i.id,t.id))).get())?.count??0)===0){await this.databaseClient.client.delete(r).where(f(n(r.sourceKey,e),n(r.targetKey,e)));return}if(((await this.databaseClient.client.select({count:p`COUNT(*)`}).from(i).where(g(n(i.key,e),n(i.version,s),R(i.id,t.id))).get())?.count??0)===0){await this.databaseClient.client.delete(r).where(f(g(n(r.sourceKey,e),n(r.sourceVersion,s)),g(n(r.targetKey,e),n(r.targetVersion,s))));return}await this.databaseClient.client.delete(r).where(f(g(n(r.sourceKey,e),n(r.sourceVersion,s),n(r.sourceRevision,y)),g(n(r.targetKey,e),n(r.targetVersion,s),n(r.targetRevision,y))))}#e(){return c("catalog_entities.remote_repository.db_health",async t=>{if(this.databaseClient.dbClient.$client.closed){const e=new Error("The remote database connection is closed!");throw t?.error(e),e}})}}export{h as CatalogEntitiesRemoteRepository};
1
+ import{and as g,eq as n,ne as C,or as w,sql as p}from"drizzle-orm";import{convertFilterToWhereCondition as D}from"../../../../../providers/database/pagination/filter.js";import{promiseMapLimit as V}from"../../../../../utils/async/promise-map-limit.js";import{sha1 as E}from"../../../../../utils/crypto/sha1.js";import{logger as a}from"../../../../../tools/notifiers/logger.js";import{entitiesTable as i}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-table.js";import{telemetryTraceStep as c}from"../../../../../telemetry/helpers/trace-step.js";import{BaseRepository as A}from"../../../../../providers/database/base-repository.js";import{DatabaseConnectionFactory as I}from"../../../../../providers/database/database-connection-factory.js";import{entitiesRelationsTable as r}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-relations-table.js";import{VERSION_NOT_SPECIFIED as b}from"@redocly/theme/core/constants";import{createEntityDbRecord as _}from"../../mappers/create-entity-db-record.js";import{createEntityReadModel as k}from"../../mappers/create-entity-read-model.js";import{createEntityRelationDbRecordFromDto as O}from"../../mappers/create-entity-relation-db-record-from-dto.js";import{RevisionRepository as K}from"../common/revision-repository.js";import{VersionRepository as F}from"../common/version-repository.js";import{createEntityRelationReadModel as S}from"../../mappers/create-entity-relation-read-model.js";const L=15;class h extends A{static#r;#t;#i;#n=!1;get transactionsManager(){return this.databaseClient.transactionsManager}constructor(t){super(t),this.#t=new K(t.client),this.#i=new F(t.client)}async sync(){if(!this.#n&&this.isNonRemoteDatabaseMode()){a.warn("Catalog entities database is currently operating in local mode: not connected to the remote database. All changes and data will only persist locally and will not be synced remotely."),this.#n=!0;return}return c("catalog_entities.remote_repository.sync",async()=>{await this.#e(),await this.databaseClient.sync()})}static async getInstance(t){return await c("catalog_entities.remote_repository.get_instance",async e=>{if(!h.#r)try{const o=await I.create("sqld-remote",t);if(!o)return a.error("Failed to create db connection for catalog entities remote repository"),e?.error(new Error("Failed to create db connection for catalog entities remote repository")),h.#r=null,null;h.#r=new h(o)}catch(o){return a.error("Error creating db connection for catalog entities remote repository",o),e?.error(o),h.#r=null,null}return h.#r})}async createEntity(t){return c("catalog_entities.remote_repository.create_entity",async()=>{await this.#e();try{a.info(`Adding entity ${t.key} to remote database`);const{relations:e=[],...o}=t,l=E(JSON.stringify(o)),s=t.version??b,y=t.revision??new Date().toISOString();if(await this.#t.shouldSkipRevisionCreation(t.key,s,l))throw new Error("Entity validation failed: entity already exists");const d=await this.#t.shouldSetNewCurrentRevision({key:t.key,version:s,revision:y}),u=_({entity:{...t,revision:y,hash:l,isCurrent:d,isDefaultVersion:d,version:s},organizationId:this.organizationId,projectId:this.projectId,source:"remote",sourceFile:null,fileHash:null}),{key:m,source:M,...N}=u;d&&(await this.#t.markAllRevisionsAsNotCurrent(m),await this.#i.markAllVersionsAsNotDefault(m));const v=await this.databaseClient.client.insert(i).values(u).onConflictDoUpdate({target:[i.key,i.source,i.revision,i.version],set:N}).returning();return v.length?(e&&await this.createEntityRelations(e.map(R=>({...R,sourceKey:t.key,targetKey:R.key}))),k(v[0])):null}catch(e){throw a.error("Error adding entity",e),e}})}async updateEntity(t,e){return c("catalog_entities.remote_repository.update_entity",async()=>{await this.#e();try{a.info(`Updating entity ${e.key} in remote database`);const o=await this.#t.shouldSetNewCurrentRevision({key:e.key,version:t.version??e.version??b,revision:e.revision});o&&(await this.#t.markAllRevisionsAsNotCurrent(e.key),await this.#i.markAllVersionsAsNotDefault(e.key));const l=_({entity:{...e,...t,hash:E(JSON.stringify({...e,...t})),isCurrent:o,isDefaultVersion:o,createdAt:e.createdAt??void 0},organizationId:this.organizationId,projectId:this.projectId,source:"remote",sourceFile:null,fileHash:null}),{key:s,source:y,scorecardsStatus:f,...d}=l,u=await this.databaseClient.client.insert(i).values(l).onConflictDoUpdate({target:[i.key,i.source,i.revision,i.version],set:{...d,scorecardsStatus:p`CASE WHEN ${i.scorecardsStatus} = 'CALCULATING' THEN 'CANCELLED' ELSE 'OUTDATED' END`}}).returning();return u.length?k(u[0]):null}catch(o){return a.error("Error updating entity",o),null}})}async deleteEntity(t){return c("catalog_entities.remote_repository.delete_entity",async()=>{await this.#e();try{return await this.#o(t),await this.databaseClient.client.delete(i).where(n(i.id,t.id)),await this.#t.ensureDefaultAndCurrentRevisionForKey(t.key),t.id}catch(e){return a.error("Error deleting entity",e),null}})}async createEntityRelations(t){return c("catalog_entities.remote_repository.create_entity_relations",async()=>(await this.#e(),await V(t,L,async e=>this.createEntityRelation(e))))}async createEntityRelation(t){return c("catalog_entities.remote_repository.create_entity_relation",async()=>{if(await this.#e(),!t)return null;try{const e=O(t,this.organizationId,this.projectId),{sourceKey:o,targetKey:l,sourceVersion:s,targetVersion:y,sourceRevision:f,targetRevision:d,...u}=e,m=await this.databaseClient.client.insert(r).values(e).onConflictDoUpdate({target:[r.sourceKey,r.targetKey,r.sourceVersion,r.targetVersion,r.sourceRevision,r.targetRevision,r.sourceToTargetRelation],set:u}).returning();return m.length?S(m[0]):null}catch(e){throw a.error("Error creating entity relation",e),e}})}async deleteEntityRelation(t){return c("catalog_entities.remote_repository.delete_entity_relation",async()=>{await this.#e();try{return await this.databaseClient.client.delete(r).where(n(r.id,t)),t}catch(e){return a.error("Error deleting entity relation",e),null}})}async deleteEntitiesRelations(t){return c("catalog_entities.remote_repository.delete_entities_relations",async()=>{await this.#e();try{const e=D(t);return e?(await this.databaseClient.client.delete(r).where(e),!0):!1}catch(e){return a.error("Error deleting entities relations",e),!1}})}async#o(t){const{key:e,version:o,revision:l}=t,s=o??"",y=l??"";if(((await this.databaseClient.client.select({count:p`COUNT(*)`}).from(i).where(g(n(i.key,e),C(i.id,t.id))).get())?.count??0)===0){await this.databaseClient.client.delete(r).where(w(n(r.sourceKey,e),n(r.targetKey,e)));return}if(((await this.databaseClient.client.select({count:p`COUNT(*)`}).from(i).where(g(n(i.key,e),n(i.version,s),C(i.id,t.id))).get())?.count??0)===0){await this.databaseClient.client.delete(r).where(w(g(n(r.sourceKey,e),n(r.sourceVersion,s)),g(n(r.targetKey,e),n(r.targetVersion,s))));return}await this.databaseClient.client.delete(r).where(w(g(n(r.sourceKey,e),n(r.sourceVersion,s),n(r.sourceRevision,y)),g(n(r.targetKey,e),n(r.targetVersion,s),n(r.targetRevision,y))))}#e(){return c("catalog_entities.remote_repository.db_health",async t=>{if(this.databaseClient.dbClient.$client.closed){const e=new Error("The remote database connection is closed!");throw t?.error(e),e}})}}export{h as CatalogEntitiesRemoteRepository};
@@ -1 +1 @@
1
- import{removeLeadingSlash as d}from"@redocly/theme/core/utils";import{toKebabCase as m}from"../../../../../../utils/string/to-kebab-case.js";import{promiseMapLimit as g}from"../../../../../utils/async/promise-map-limit.js";import{promiseMapLimitWithStatus as $}from"../../../../../utils/async/promise-map-limit-with-status.js";import{removeMarkdocTags as R}from"../../../../markdown/markdoc/helpers/remove-markdoc-tags.js";import{BaseApiEntitiesExtractor as E}from"./base.js";import{extractPartsFromComponentsRef as f}from"../../../utils/extract-parts-from-components-ref.js";import{validateEntityRelation as w}from"../../../entities/validate-entity.js";import{extractPartsFromChannelsMessageRef as S}from"../../../utils/extract-parts-from-channels-message-ref.js";const u=15;class L extends E{constructor(e){super("asyncapi",e)}mapApiDescriptionToEntity(e,a){const s=d(e.realRelativePath),r=e.document.info.title,t=s.replace(/\.[^.]+$/,""),n=m(t.replace(/[\\/]/g,"-")),c=e.document["x-redocly-catalog-key"],o=typeof c=="string"&&c.trim()?m(c.trim()):n;return{type:this.type,key:o,title:r,summary:R(e.document.info.description),tags:e.document.info.tags?.map(i=>i.name),metadata:{specType:this.specType,descriptionFile:s},version:a}}async loadApiDescriptions(){return(await this.context.cache.load(".","asyncapi-docs")).data}async processApiDescription(e,a,s,r){const t=this.getRbacTeamsForDefinition(e.relativePath),n=this.mapApiDescriptionToEntity(e,s);await this.catalogEntitiesService.createEntityInLocalDatabase({entity:n,sourceFile:e.realRelativePath,fileHash:e.hash,isRootEntity:!0,revision:a,rbacTeams:t}),r.delete(`${n.key}:${s}`);const c=this.#a(e),[o,i]=await Promise.allSettled([this.#s(e,n.key,n.version,s,a,r,t),this.#r(c,e,n.key,n.version,s,a,r,t)]);o.status!=="fulfilled"&&this.context.logger.error("Schema processing failed:",o.reason),i.status!=="fulfilled"&&this.context.logger.error("Operation processing failed:",i.reason)}#a=e=>{const a=e.documentWithReferences.operations;return a?Object.entries(a).map(([s,r])=>({operationName:s,operation:r})):[]};#s=async(e,a,s,r,t,n,c)=>{const o=e.document.components?.schemas;if(!o)return;const i=Object.entries(o);if(i.length===0)return;const l=await $(i,u,async([h,y])=>{const p=await this.#n({schemaName:h,schema:y,description:e,parentKey:a,parentVersion:s,parentRevision:t,rbacTeams:c});n.delete(`${p.entityKey}:${r}`),p.result==="created"&&await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:a,type:"uses",targetKey:p.entityKey,fileHash:e.hash,sourceVersion:s,targetVersion:s,sourceRevision:t,targetRevision:t})},this.context.logger);l.count.failed>0&&this.context.logger.warn(`Schema processing completed with ${l.count.failed} failures out of ${i.length} schemas for ${e.realRelativePath}`)};#n=async({schemaName:e,schema:a,description:s,parentKey:r,parentVersion:t,parentRevision:n,rbacTeams:c})=>{const o=`${r}-${m(e)}`,i="title"in a?a.title??a.description:null,l=JSON.stringify(a),h={type:"data-schema",key:o,title:e,summary:i,tags:[],metadata:{specType:this.specType,schema:l},version:t};return await this.catalogEntitiesService.createEntityInLocalDatabase({entity:h,sourceFile:s.realRelativePath,fileHash:s.hash,revision:n,rbacTeams:c})};#r=async(e,a,s,r,t,n,c,o)=>{if(!e.length)return;const i=await $(e,u,async({operationName:l,operation:h})=>{const y=await this.#c(h,l,a,s,r,n,o);y&&c.delete(`${y}:${t}`)},this.context.logger);i.count.failed>0&&this.context.logger.warn(`Operation processing completed with ${i.count.failed} failures out of ${e.length} operations for ${a.realRelativePath}`)};#c=async(e,a,s,r,t,n,c)=>{const o=await this.#o(e.messages??[],s,r),i=await this.#i(a,e,o,s,r,t,n,c);return i.result==="created"&&await this.#l({apiOperationKey:i.entityKey,operation:e,descriptionUniqueKey:r,description:s,descriptionVersion:t,parentRevision:n}),i.entityKey??null};#o=async(e,a,s)=>{if(!e||e.length===0)return[];const r=new Set;for(const t of e){let n=null;if("$ref"in t){const c=t.$ref.startsWith("#/channels/")?this.#e(t.$ref,a):t.$ref;if(c){const o=f(c);if(o?.componentName&&o.componentType==="messages"){const i=a.documentWithReferences.components?.messages[o.componentName];i?.payload&&"$ref"in i.payload&&i.payload.$ref&&(n=i.payload.$ref)}}}else t.payload&&"$ref"in t.payload&&t.payload.$ref&&(n=t.payload.$ref);if(n){const c=f(n);c?.componentName&&c.componentType==="schemas"&&r.add(`${s}-${m(c.componentName)}`)}}return Array.from(r)};#i=async(e,a,s,r,t,n,c,o)=>{const i={type:"api-operation",key:`${t}-${m(e)}`,title:a.title||e,summary:a.summary??"",tags:a.tags?.map(h=>h.name)??[],metadata:{method:a.action==="send"?"PUBLISH":"SUBSCRIBE",path:a.channel.address??"",payload:a.action==="receive"?s:[],responses:a.action==="send"?s:[]},version:n};return await this.catalogEntitiesService.createEntityInLocalDatabase({entity:i,sourceFile:r.realRelativePath,fileHash:r.hash,revision:c,rbacTeams:o})};#l=async({apiOperationKey:e,operation:a,descriptionUniqueKey:s,description:r,descriptionVersion:t,parentRevision:n})=>(await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:e,type:"partOf",targetKey:s,fileHash:r.hash,sourceVersion:t,targetVersion:t,sourceRevision:n,targetRevision:n}),await this.#h(a,e,t,n),!Array.isArray(a.messages)||!a.messages?.length?[]:await this.#m(a.messages,e,r,s,t,n));#h=async(e,a,s,r)=>{e["x-catalog-relations"]?.length&&await g(e["x-catalog-relations"],u,async t=>{try{w(t),await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:a,type:t.type,targetKey:t.key,sourceVersion:s,targetVersion:"",sourceRevision:r,targetRevision:""})}catch(n){this.context.logger.warn(`Error creating entity relation for operation ${a} based on custom property: ${n instanceof Error?n.message:"Unknown error"}`)}})};#m=async(e,a,s,r,t,n)=>e.length===0?[]:(await g(e,u,async o=>await this.#y(o,a,s,r,t,n)??"")).filter(o=>!!o);#y=async(e,a,s,r,t,n)=>"$ref"in e?this.#f(e,a,s,r,t,n):e.payload?this.#u(e,a,s,r,t,n):null;#f=async(e,a,s,r,t,n)=>{const c=e.$ref.startsWith("#/channels/")?this.#e(e.$ref,s):e.$ref;if(!c)return null;const o=f(c);if(!o||!o.componentName||o.componentType!=="messages")return null;const i=s.documentWithReferences.components?.messages[o.componentName];return!i?.payload||!("$ref"in i.payload)||!i.payload.$ref?null:this.#t(i.payload.$ref,a,s,r,t,n)};#e=(e,a)=>{const s=S(e);if(!s||!s.channelName||!s.messageName)return null;const r=a.documentWithReferences.channels?.[s.channelName];if(!r?.messages)return null;const t=r.messages[s.messageName];return!t||!("$ref"in t)||typeof t.$ref!="string"||!t.$ref.startsWith("#/components/messages/")?null:t.$ref};#u=async(e,a,s,r,t,n)=>!e.payload||!("$ref"in e.payload)||!e.payload.$ref?null:this.#t(e.payload.$ref,a,s,r,t,n);#t=async(e,a,s,r,t,n)=>{const c=f(e);if(!c||!c.componentName||c.componentType!=="schemas")return null;const o=`${r}-${m(c.componentName)}`;return await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:a,type:"uses",targetKey:o,fileHash:s.hash,sourceVersion:t,targetVersion:t,sourceRevision:n,targetRevision:n}),o}}export{L as AsyncApiEntitiesExtractor};
1
+ import{removeLeadingSlash as d}from"@redocly/theme/core/utils";import{toKebabCase as m}from"../../../../../../utils/string/to-kebab-case.js";import{promiseMapLimit as p}from"../../../../../utils/async/promise-map-limit.js";import{promiseMapLimitWithStatus as $}from"../../../../../utils/async/promise-map-limit-with-status.js";import{removeMarkdocTags as R}from"../../../../markdown/markdoc/helpers/remove-markdoc-tags.js";import{BaseApiEntitiesExtractor as E}from"./base.js";import{extractPartsFromComponentsRef as f}from"../../../utils/extract-parts-from-components-ref.js";import{extractPartsFromChannelsMessageRef as w}from"../../../utils/extract-parts-from-channels-message-ref.js";const u=15;class N extends E{constructor(e){super("asyncapi",e)}mapApiDescriptionToEntity(e,a){const s=d(e.realRelativePath),r=e.document.info.title,t=s.replace(/\.[^.]+$/,""),n=m(t.replace(/[\\/]/g,"-")),c=e.document["x-redocly-catalog-key"],o=typeof c=="string"&&c.trim()?m(c.trim()):n;return{type:this.type,key:o,title:r,summary:R(e.document.info.description),tags:e.document.info.tags?.map(i=>i.name),metadata:{specType:this.specType,descriptionFile:s},version:a}}async loadApiDescriptions(){return(await this.context.cache.load(".","asyncapi-docs")).data}async processApiDescription(e,a,s,r){const t=this.getRbacTeamsForDefinition(e.relativePath),n=this.mapApiDescriptionToEntity(e,s);await this.catalogEntitiesService.createEntityInLocalDatabase({entity:n,sourceFile:e.realRelativePath,fileHash:e.hash,isRootEntity:!0,revision:a,rbacTeams:t}),r.delete(`${n.key}:${s}`);const c=this.#a(e),[o,i]=await Promise.allSettled([this.#s(e,n.key,n.version,s,a,r,t),this.#r(c,e,n.key,n.version,s,a,r,t)]);o.status!=="fulfilled"&&this.context.logger.error("Schema processing failed:",o.reason),i.status!=="fulfilled"&&this.context.logger.error("Operation processing failed:",i.reason)}#a=e=>{const a=e.documentWithReferences.operations;return a?Object.entries(a).map(([s,r])=>({operationName:s,operation:r})):[]};#s=async(e,a,s,r,t,n,c)=>{const o=e.document.components?.schemas;if(!o)return;const i=Object.entries(o);if(i.length===0)return;const l=await $(i,u,async([h,y])=>{const g=await this.#n({schemaName:h,schema:y,description:e,parentKey:a,parentVersion:s,parentRevision:t,rbacTeams:c});n.delete(`${g.entityKey}:${r}`),g.result==="created"&&await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:a,type:"uses",targetKey:g.entityKey,fileHash:e.hash,sourceVersion:s,targetVersion:s,sourceRevision:t,targetRevision:t})},this.context.logger);l.count.failed>0&&this.context.logger.warn(`Schema processing completed with ${l.count.failed} failures out of ${i.length} schemas for ${e.realRelativePath}`)};#n=async({schemaName:e,schema:a,description:s,parentKey:r,parentVersion:t,parentRevision:n,rbacTeams:c})=>{const o=`${r}-${m(e)}`,i="title"in a?a.title??a.description:null,l=JSON.stringify(a),h={type:"data-schema",key:o,title:e,summary:i,tags:[],metadata:{specType:this.specType,schema:l},version:t};return await this.catalogEntitiesService.createEntityInLocalDatabase({entity:h,sourceFile:s.realRelativePath,fileHash:s.hash,revision:n,rbacTeams:c})};#r=async(e,a,s,r,t,n,c,o)=>{if(!e.length)return;const i=await $(e,u,async({operationName:l,operation:h})=>{const y=await this.#c(h,l,a,s,r,n,o);y&&c.delete(`${y}:${t}`)},this.context.logger);i.count.failed>0&&this.context.logger.warn(`Operation processing completed with ${i.count.failed} failures out of ${e.length} operations for ${a.realRelativePath}`)};#c=async(e,a,s,r,t,n,c)=>{const o=await this.#o(e.messages??[],s,r),i=await this.#i(a,e,o,s,r,t,n,c);return i.result==="created"&&await this.#l({apiOperationKey:i.entityKey,operation:e,descriptionUniqueKey:r,description:s,descriptionVersion:t,parentRevision:n}),i.entityKey??null};#o=async(e,a,s)=>{if(!e||e.length===0)return[];const r=new Set;for(const t of e){let n=null;if("$ref"in t){const c=t.$ref.startsWith("#/channels/")?this.#e(t.$ref,a):t.$ref;if(c){const o=f(c);if(o?.componentName&&o.componentType==="messages"){const i=a.documentWithReferences.components?.messages[o.componentName];i?.payload&&"$ref"in i.payload&&i.payload.$ref&&(n=i.payload.$ref)}}}else t.payload&&"$ref"in t.payload&&t.payload.$ref&&(n=t.payload.$ref);if(n){const c=f(n);c?.componentName&&c.componentType==="schemas"&&r.add(`${s}-${m(c.componentName)}`)}}return Array.from(r)};#i=async(e,a,s,r,t,n,c,o)=>{const i={type:"api-operation",key:`${t}-${m(e)}`,title:a.title||e,summary:a.summary??"",tags:a.tags?.map(h=>h.name)??[],metadata:{method:a.action==="send"?"PUBLISH":"SUBSCRIBE",path:a.channel.address??"",payload:a.action==="receive"?s:[],responses:a.action==="send"?s:[]},version:n};return await this.catalogEntitiesService.createEntityInLocalDatabase({entity:i,sourceFile:r.realRelativePath,fileHash:r.hash,revision:c,rbacTeams:o})};#l=async({apiOperationKey:e,operation:a,descriptionUniqueKey:s,description:r,descriptionVersion:t,parentRevision:n})=>(await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:e,type:"partOf",targetKey:s,fileHash:r.hash,sourceVersion:t,targetVersion:t,sourceRevision:n,targetRevision:n}),await this.#h(a,e,t,n),!Array.isArray(a.messages)||!a.messages?.length?[]:await this.#m(a.messages,e,r,s,t,n));#h=async(e,a,s,r)=>{e["x-catalog-relations"]?.length&&await p(e["x-catalog-relations"],u,async t=>{try{this.validateEntityRelationFileSchema(t),await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:a,type:t.type,targetKey:t.key,sourceVersion:s,targetVersion:"",sourceRevision:r,targetRevision:""})}catch(n){this.context.logger.warn(`Error creating entity relation for operation ${a} based on custom property: ${n instanceof Error?n.message:"Unknown error"}`)}})};#m=async(e,a,s,r,t,n)=>e.length===0?[]:(await p(e,u,async o=>await this.#y(o,a,s,r,t,n)??"")).filter(o=>!!o);#y=async(e,a,s,r,t,n)=>"$ref"in e?this.#f(e,a,s,r,t,n):e.payload?this.#u(e,a,s,r,t,n):null;#f=async(e,a,s,r,t,n)=>{const c=e.$ref.startsWith("#/channels/")?this.#e(e.$ref,s):e.$ref;if(!c)return null;const o=f(c);if(!o||!o.componentName||o.componentType!=="messages")return null;const i=s.documentWithReferences.components?.messages[o.componentName];return!i?.payload||!("$ref"in i.payload)||!i.payload.$ref?null:this.#t(i.payload.$ref,a,s,r,t,n)};#e=(e,a)=>{const s=w(e);if(!s||!s.channelName||!s.messageName)return null;const r=a.documentWithReferences.channels?.[s.channelName];if(!r?.messages)return null;const t=r.messages[s.messageName];return!t||!("$ref"in t)||typeof t.$ref!="string"||!t.$ref.startsWith("#/components/messages/")?null:t.$ref};#u=async(e,a,s,r,t,n)=>!e.payload||!("$ref"in e.payload)||!e.payload.$ref?null:this.#t(e.payload.$ref,a,s,r,t,n);#t=async(e,a,s,r,t,n)=>{const c=f(e);if(!c||!c.componentName||c.componentType!=="schemas")return null;const o=`${r}-${m(c.componentName)}`;return await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:a,type:"uses",targetKey:o,fileHash:s.hash,sourceVersion:t,targetVersion:t,sourceRevision:n,targetRevision:n}),o}}export{N as AsyncApiEntitiesExtractor};
@@ -1,6 +1,6 @@
1
+ import { type EntityFileSchema } from '@redocly/config';
1
2
  import type { AfterRoutesCreatedActions, FileInfo, LifecycleContext } from '../../../../../types';
2
3
  import type { CatalogEntitiesService } from '../../../database/catalog-entities-service.js';
3
- import type { EntityFileSchema } from '@redocly/config';
4
4
  import type { BaseEntitiesExtractor } from '../base';
5
5
  import type { FileType } from '../../../../../persistence/file-hashes/types.js';
6
6
  import type { HashManager } from '../../../utils/hash-manager.js';
@@ -17,6 +17,7 @@ export declare abstract class BaseApiEntitiesExtractor<BundledApiDefinition exte
17
17
  protected entitySources: Record<string, string>;
18
18
  constructor(specType: SpecType, params: BaseApiEntitiesExtractorParams);
19
19
  extract(): Promise<void>;
20
+ protected validateEntityRelationFileSchema(relation: unknown): void;
20
21
  protected getRbacTeamsForDefinition(relativePath: string): string[];
21
22
  protected abstract loadApiDescriptions(): Promise<BundledApiDefinition[]>;
22
23
  protected abstract mapApiDescriptionToEntity(definition: BundledApiDefinition, version: string, rbacTeams: string[]): EntityFileSchema;
@@ -1 +1 @@
1
- import{FileHashStatus as c}from"../../../../../persistence/file-hashes/types.js";import{promiseMapLimit as E}from"../../../../../utils/async/promise-map-limit.js";import{OPERATORS as u}from"../../../../../providers/database/pagination/constants.js";import{VERSION_NOT_SPECIFIED as f}from"@redocly/theme/core/constants";import{getRbacTeamsListForResource as g}from"../../../../../utils/rbac.js";import{resolveEntityVersion as v}from"../../../utils/resolve-entity-version.js";import{catalogDataCollector as h}from"../../../utils/catalog-data-collector.js";const m=3;class _{type="api-description";specType;fileType;actions;context;catalogEntitiesService;fileHashManager;entitySources={};#e;constructor(t,e){this.specType=t,this.fileType=e.fileType,this.actions=e.actions,this.context=e.context,this.catalogEntitiesService=e.catalogEntitiesService,this.fileHashManager=e.fileHashManager,this.#e=e.shouldCalculateEntities??!1}async extract(){const t=await this.loadApiDescriptions();await this.fileHashManager.markAllAsOutdated(this.fileType),t.length&&h.addExtractor(this.specType),await E(t,m,async e=>{try{if(e.isVirtual||!e.hash)return;if(!((await this.fileHashManager.getByPath(e.realRelativePath))?.hash!==e.hash||this.#e||process.env.FORCE_CATALOG_CACHE_REVALIDATE==="true")){h.increaseSkippedFilesCount(),await this.fileHashManager.upsert(this.fileType,e.realRelativePath,e.hash,c.UP_TO_DATE);return}const a=await this.catalogEntitiesService.getEntityKeysAndVersionsBySourceFile(e.realRelativePath);process.env.FORCE_CATALOG_CACHE_REVALIDATE==="true"&&(await this.catalogEntitiesService.deleteEntitiesInLocalDatabase({field:"key",operator:"in",value:Array.from(a).map(s=>s.split(":")[0])}),a.clear());const o=new Date().toISOString(),n=this.#a(e);await this.processApiDescription(e,o,n,a),await this.#i(a,e.realRelativePath,o,e.hash),h.increaseProcessedFilesCount(),await this.fileHashManager.upsert(this.fileType,e.realRelativePath,e.hash,c.UP_TO_DATE)}catch(i){this.context.logger.warn(`Error extracting entities from ${this.specType} description: ${e.realRelativePath}`),this.context.logger.warn(i)}}),await this.#t()}#t=async()=>{const t=await this.fileHashManager.getAllOutdated(this.fileType);if(!t||t.length===0)return;const e=await this.catalogEntitiesService.getEntities({paginationParams:{limit:1e3,filter:{op:"AND",conditions:[{field:"source_file",operator:"in",value:t.map(({filePath:i})=>i)},{field:"is_current",operator:"equal",value:!0}]}}});e&&e.items.length>0&&await this.catalogEntitiesService.deleteEntitiesInLocalDatabase({field:"key",operator:"in",value:e.items.map(({key:i})=>i)}),await this.fileHashManager.deleteFileHashes({op:"AND",conditions:[{field:"file_type",operator:"equal",value:this.fileType},{field:"status",operator:"equal",value:c.OUTDATED}]})};#i=async(t,e,i,r)=>{if(t.size===0||process.env.FORCE_CATALOG_CACHE_REVALIDATE==="true")return;const a=Array.from(t).map(s=>{const[l,p]=s.split(":");return{key:l,version:p}}),o=Array.from(new Set(a.map(({key:s})=>s))),n=a.map(({key:s,version:l})=>({op:u.AND,conditions:[{field:"key",operator:"equal",value:s},{field:"version",operator:"equal",value:l}]}));await this.catalogEntitiesService.softDeleteEntitiesInLocalDatabase({revision:i,fileHash:r,filter:{op:"AND",conditions:[{field:"key",operator:"in",value:o},{op:u.OR,conditions:n},{field:"source",operator:"equal",value:"file"},{field:"source_file",operator:"equal",value:e}]}})};#a(t){const e=t.document?.info?.version??t.definition?.info?.version??null,i=v(e,t.realRelativePath);return i.success?i.version??f:f}getRbacTeamsForDefinition(t){const e=this.actions.getConfig().rbac,i=this.actions.getRouteByFsPath(t);return g(i||{fsPath:t},e||{})}}export{_ as BaseApiEntitiesExtractor};
1
+ import{entityRelationFileSchema as g}from"@redocly/config";import{FileHashStatus as c}from"../../../../../persistence/file-hashes/types.js";import{promiseMapLimit as m}from"../../../../../utils/async/promise-map-limit.js";import{OPERATORS as u}from"../../../../../providers/database/pagination/constants.js";import{VERSION_NOT_SPECIFIED as p}from"@redocly/theme/core/constants";import{getRbacTeamsListForResource as v}from"../../../../../utils/rbac.js";import{envConfig as h}from"../../../../../../config/env-config.js";import{resolveEntityVersion as y}from"../../../utils/resolve-entity-version.js";import{catalogDataCollector as f}from"../../../utils/catalog-data-collector.js";import{createValidator as d}from"../../../utils/ajv-validator.js";const R=3;class x{type="api-description";specType;fileType;actions;context;catalogEntitiesService;fileHashManager;entitySources={};#e;constructor(t,e){this.specType=t,this.fileType=e.fileType,this.actions=e.actions,this.context=e.context,this.catalogEntitiesService=e.catalogEntitiesService,this.fileHashManager=e.fileHashManager,this.#e=e.shouldCalculateEntities??!1}async extract(){const t=await this.loadApiDescriptions();await this.fileHashManager.markAllAsOutdated(this.fileType),t.length&&f.addExtractor(this.specType),await m(t,R,async e=>{try{if(e.isVirtual||!e.hash)return;if(!((await this.fileHashManager.getByPath(e.realRelativePath))?.hash!==e.hash||this.#e||h.FORCE_CATALOG_CACHE_REVALIDATE==="true")){f.increaseSkippedFilesCount(),await this.fileHashManager.upsert(this.fileType,e.realRelativePath,e.hash,c.UP_TO_DATE);return}const a=await this.catalogEntitiesService.getEntityKeysAndVersionsBySourceFile(e.realRelativePath);h.FORCE_CATALOG_CACHE_REVALIDATE==="true"&&(await this.catalogEntitiesService.deleteEntitiesInLocalDatabase({field:"key",operator:"in",value:Array.from(a).map(o=>o.split(":")[0])}),a.clear());const s=new Date().toISOString(),n=this.#a(e);await this.processApiDescription(e,s,n,a),await this.#i(a,e.realRelativePath,s,e.hash),f.increaseProcessedFilesCount(),await this.fileHashManager.upsert(this.fileType,e.realRelativePath,e.hash,c.UP_TO_DATE)}catch(i){this.context.logger.warn(`Error extracting entities from ${this.specType} description: ${e.realRelativePath}`),this.context.logger.warn(i)}}),await this.#t()}#t=async()=>{const t=await this.fileHashManager.getAllOutdated(this.fileType);if(!t||t.length===0)return;const e=await this.catalogEntitiesService.getEntities({paginationParams:{limit:1e3,filter:{op:"AND",conditions:[{field:"source_file",operator:"in",value:t.map(({filePath:i})=>i)},{field:"is_current",operator:"equal",value:!0}]}}});e&&e.items.length>0&&await this.catalogEntitiesService.deleteEntitiesInLocalDatabase({field:"key",operator:"in",value:e.items.map(({key:i})=>i)}),await this.fileHashManager.deleteFileHashes({op:"AND",conditions:[{field:"file_type",operator:"equal",value:this.fileType},{field:"status",operator:"equal",value:c.OUTDATED}]})};#i=async(t,e,i,r)=>{if(t.size===0||h.FORCE_CATALOG_CACHE_REVALIDATE==="true")return;const a=Array.from(t).map(o=>{const[l,E]=o.split(":");return{key:l,version:E}}),s=Array.from(new Set(a.map(({key:o})=>o))),n=a.map(({key:o,version:l})=>({op:u.AND,conditions:[{field:"key",operator:"equal",value:o},{field:"version",operator:"equal",value:l}]}));await this.catalogEntitiesService.softDeleteEntitiesInLocalDatabase({revision:i,fileHash:r,filter:{op:"AND",conditions:[{field:"key",operator:"in",value:s},{op:u.OR,conditions:n},{field:"source",operator:"equal",value:"file"},{field:"source_file",operator:"equal",value:e}]}})};#a(t){const e=t.document?.info?.version??t.definition?.info?.version??null,i=y(e,t.realRelativePath);return i.success?i.version??p:p}validateEntityRelationFileSchema(t){d(g,{errorPrefix:"Entity relation validation failed:",dataVar:"relation"})(t)}getRbacTeamsForDefinition(t){const e=this.actions.getConfig().rbac,i=this.actions.getRouteByFsPath(t);return v(i||{fsPath:t},e||{})}}export{x as BaseApiEntitiesExtractor};
@@ -1 +1 @@
1
- import{REDOCLY_TEAMS_RBAC as $}from"@redocly/config";import{removeLeadingSlash as x}from"@redocly/theme/core/utils";import{toKebabCase as p}from"../../../../../../utils/string/to-kebab-case.js";import{promiseMapLimit as E}from"../../../../../utils/async/promise-map-limit.js";import{promiseMapLimitWithStatus as T}from"../../../../../utils/async/promise-map-limit-with-status.js";import{extractTeamsFromScopeItems as R}from"../../../../../utils/rbac.js";import{removeMarkdocTags as w}from"../../../../markdown/markdoc/helpers/remove-markdoc-tags.js";import{BaseApiEntitiesExtractor as N}from"./base.js";import{OpenapiSchemaResolver as S}from"../../../utils/openapi-schema-resolver.js";import{extractPartsFromComponentsRef as v}from"../../../utils/extract-parts-from-components-ref.js";import{validateEntityRelation as A}from"../../../entities/validate-entity.js";import{isValidTagName as O}from"../../../utils/is-valid-tag-name.js";const D=["get","post","put","delete","patch"],b=15,d=15;class U extends N{#e;constructor(e){super("openapi",e),this.#e=e.context.logger}async loadApiDescriptions(){return await this.actions.loadOpenApiDefinitions(this.context)}mapApiDescriptionToEntity(e,o){const s=x(e.realRelativePath),n=e.definition.info.title,t=s.replace(/\.[^.]+$/,""),a=p(t.replace(/[\\/]/g,"-")),r=e.definition["x-redocly-catalog-key"],i=typeof r=="string"&&r.trim()?p(r.trim()):a;return{type:this.type,key:i,title:n,summary:w(e.definition.info.description),tags:e.definition.tags?.filter(c=>c.name&&O(c.name)).map(c=>c.name),metadata:{specType:this.specType,descriptionFile:s},version:o}}async processApiDescription(e,o,s,n){if(S.clearSchemaCache(),!e?.definition?.paths)return;const t=this.getRbacTeamsForDefinition(e.relativePath),a=this.mapApiDescriptionToEntity(e,s);await this.catalogEntitiesService.createEntityInLocalDatabase({entity:a,sourceFile:e.realRelativePath,fileHash:e.hash,isRootEntity:!0,revision:o,rbacTeams:t}),n.delete(`${a.key}:${s}`),await this.#n(e,a.key,a.version,s,o,n,t);const r=this.#s(e.definition.paths);if(r.length!==0){const c=(await T(r,b,async({operation:h,path:m,method:l})=>{if(!h.operationId)return;const f=await this.#r(h,m,l,e,a.key,a.version,o,t);f&&n.delete(`${f}:${s}`)},this.#e)).count.failed;c>0&&this.#e.warn(`Extraction completed with ${c} failures out of ${r.length} operations for ${a.key}`)}}#s(e){return Object.entries(e).flatMap(([o,s])=>D.filter(n=>s[n]).map(n=>{const t=s[n];if(!t)throw new Error(`Operation not found for method ${n} on path ${o}`);return{operation:t,path:o,method:n.toUpperCase()}}))}async#n(e,o,s,n,t,a,r){const i=e.definition.components?.schemas;if(!i)return;const c=Object.entries(i);c.length!==0&&await E(c,d,async([h,m])=>{const l=await this.#o({schemaName:h,schema:m,description:e,parentKey:o,parentVersion:s,parentRevision:t,rbacTeams:r});a.delete(`${l.entityKey}:${n}`),l.result==="created"&&await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:o,sourceVersion:s,sourceRevision:t,type:"uses",targetKey:l.entityKey,targetVersion:s,targetRevision:t,fileHash:e.hash})})}async#o({schemaName:e,schema:o,description:s,parentKey:n,parentVersion:t,parentRevision:a,rbacTeams:r}){const i=S.resolveSchemaRefs(o,s),c=JSON.stringify(i),h=i[$]?R(i[$]):r,m=R(i["x-rbac"]),l={type:"data-schema",key:`${n}-${p(e)}`,title:e,summary:i.description??i.title??null,tags:[],metadata:{specType:this.specType,schema:c},version:t};return await this.catalogEntitiesService.createEntityInLocalDatabase({entity:l,sourceFile:s.realRelativePath,fileHash:s.hash,revision:a,rbacTeams:m.length?m:h})}async#r(e,o,s,n,t,a,r,i){const c=await Promise.all([this.#m(e.requestBody??null,n),this.#h(e.responses??{},n)]),h=c[0].schemaNames,m=c[1].schemaNames;c[0].errors.length>0&&this.#e.warn(`Schema extraction errors for operation ${e.operationId}: ${c[0].errors.join(", ")}`),c[1].errors.length>0&&this.#e.warn(`Response schema extraction errors for operation ${e.operationId}: ${c[1].errors.join(", ")}`);const l=h.map(g=>`${t}-${p(g)}`),f=m.map(g=>`${t}-${p(g)}`),y=await this.#p({path:o,method:s,operation:e,requestBodySchemasKeys:l,responseSchemasKeys:f,description:n,parentKey:t,parentVersion:a,parentRevision:r,rbacTeams:i});return y.result==="created"&&await Promise.all([this.#i(h,e.operationId??"",n.hash,t,a,r),this.#c(m,e.operationId??"",n.hash,t,a,r),this.#f({apiOperationKey:y.entityKey,operationRelations:e["x-catalog-relations"],descriptionUniqueKey:t,description:n,parentVersion:a,parentRevision:r})]),y.entityKey??null}async#i(e,o,s,n,t,a){return e.length===0||!o?[]:await this.#a(e,o,s,n,t,a)}async#c(e,o,s,n,t,a){return e.length===0||!o?[]:await this.#a(e,o,s,n,t,a)}#m(e,o){const s=[],n=[];try{if(e&&"content"in e&&e.content)for(const t of Object.values(e.content)){if(!t.schema?.$ref)continue;const a=this.#t(t.schema.$ref);a?.componentType==="schemas"&&a.componentName&&s.push(a.componentName)}if(e&&e.$ref){const t=this.#t(e.$ref);if(t?.componentType==="requestBodies"&&t.componentName){const a=o.definition.components?.requestBodies?.[t.componentName];if(a&&"content"in a)for(const r of Object.values(a.content??{})){if(!r.schema?.$ref)continue;const i=this.#t(r.schema.$ref);i?.componentType==="schemas"&&i.componentName&&s.push(i.componentName)}}}}catch(t){n.push(`Failed to extract request body schemas: ${t instanceof Error?t.message:"Unknown error"}`)}return{schemaNames:[...new Set(s)],errors:n}}#h(e,o){const s=[],n=[];try{for(const t of Object.values(e)){if(t&&"content"in t&&t.content)for(const a of Object.values(t.content)){if(!a.schema?.$ref)continue;const r=this.#t(a.schema.$ref);r?.componentType==="schemas"&&r.componentName&&s.push(r.componentName)}if(t&&t.$ref){const a=this.#t(t.$ref);if(a?.componentType==="responses"&&a.componentName){const r=o.definition.components?.responses?.[a.componentName];if(r&&"content"in r)for(const i of Object.values(r.content??{})){if(!i.schema?.$ref)continue;const c=this.#t(i.schema.$ref);c?.componentType==="schemas"&&c.componentName&&s.push(c.componentName)}}}}}catch(t){n.push(`Failed to extract response schemas: ${t instanceof Error?t.message:"Unknown error"}`)}return{schemaNames:[...new Set(s)],errors:n}}#t(e){try{return v(e)}catch{return{componentType:"",componentName:null}}}async#a(e,o,s,n,t,a){return e.length===0?[]:await E(e,d,async r=>await this.#l({operationId:o,schemaName:r,descriptionHash:s,parentKey:n,parentVersion:t,parentRevision:a}))}async#l({operationId:e,schemaName:o,descriptionHash:s,parentKey:n,parentVersion:t,parentRevision:a}){const r=`${n}-${p(o)}`;try{return await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:`${n}-${p(e)}`,type:"uses",targetKey:r,fileHash:s,sourceVersion:t,targetVersion:t,sourceRevision:a,targetRevision:a}),r}catch(i){throw this.#e.error(`Failed to create relation between operation ${e} and schema ${o}: ${i instanceof Error?i.message:"Unknown error"}`),i}}async#p({path:e,method:o,operation:s,requestBodySchemasKeys:n,responseSchemasKeys:t,description:a,parentKey:r,parentVersion:i,parentRevision:c,rbacTeams:h}){const m=`${s.operationId}`,l=`${r}-${p(m)}`,f=s[$]?R(s[$]):h,y=R(s["x-rbac"]),g={type:"api-operation",key:l,title:m,summary:w(s.summary),tags:s.tags?.filter(u=>O(u)),metadata:{path:e,method:o,payload:n,responses:t},version:i};try{return await this.catalogEntitiesService.createEntityInLocalDatabase({entity:g,sourceFile:a.realRelativePath,fileHash:a.hash,revision:c,rbacTeams:y.length>0?y:f})}catch(u){throw this.#e.error(`Failed to create API operation entity for ${m}: ${u instanceof Error?u.message:"Unknown error"}`),u}}async#f({apiOperationKey:e,operationRelations:o,descriptionUniqueKey:s,description:n,parentVersion:t,parentRevision:a}){try{await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:e,type:"partOf",targetKey:s,fileHash:n.hash,sourceVersion:t,targetVersion:t,sourceRevision:a,targetRevision:a}),await this.#y(e,o,t,a)}catch(r){this.#e.error(`Failed to create API operation relations for ${e}: ${r instanceof Error?r.message:"Unknown error"}`)}}async#y(e,o,s,n){o?.length&&await E(o,b,async t=>{try{A(t),await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:e,type:t.type,targetKey:t.key,sourceVersion:s,targetVersion:"",sourceRevision:n,targetRevision:""})}catch(a){this.context.logger.warn(`Error creating entity relation for operation ${e} based on custom property: ${a instanceof Error?a.message:"Unknown error"}`)}})}}export{U as OpenApiEntitiesExtractor};
1
+ import{REDOCLY_TEAMS_RBAC as $}from"@redocly/config";import{removeLeadingSlash as x}from"@redocly/theme/core/utils";import{toKebabCase as p}from"../../../../../../utils/string/to-kebab-case.js";import{promiseMapLimit as E}from"../../../../../utils/async/promise-map-limit.js";import{promiseMapLimitWithStatus as T}from"../../../../../utils/async/promise-map-limit-with-status.js";import{extractTeamsFromScopeItems as R}from"../../../../../utils/rbac.js";import{removeMarkdocTags as w}from"../../../../markdown/markdoc/helpers/remove-markdoc-tags.js";import{BaseApiEntitiesExtractor as N}from"./base.js";import{OpenapiSchemaResolver as S}from"../../../utils/openapi-schema-resolver.js";import{extractPartsFromComponentsRef as v}from"../../../utils/extract-parts-from-components-ref.js";import{isValidTagName as O}from"../../../utils/is-valid-tag-name.js";const A=["get","post","put","delete","patch"],b=15,d=15;class _ extends N{#e;constructor(e){super("openapi",e),this.#e=e.context.logger}async loadApiDescriptions(){return await this.actions.loadOpenApiDefinitions(this.context)}mapApiDescriptionToEntity(e,o){const s=x(e.realRelativePath),n=e.definition.info.title,t=s.replace(/\.[^.]+$/,""),a=p(t.replace(/[\\/]/g,"-")),r=e.definition["x-redocly-catalog-key"],i=typeof r=="string"&&r.trim()?p(r.trim()):a;return{type:this.type,key:i,title:n,summary:w(e.definition.info.description),tags:e.definition.tags?.filter(c=>c.name&&O(c.name)).map(c=>c.name),metadata:{specType:this.specType,descriptionFile:s},version:o}}async processApiDescription(e,o,s,n){if(S.clearSchemaCache(),!e?.definition?.paths)return;const t=this.getRbacTeamsForDefinition(e.relativePath),a=this.mapApiDescriptionToEntity(e,s);await this.catalogEntitiesService.createEntityInLocalDatabase({entity:a,sourceFile:e.realRelativePath,fileHash:e.hash,isRootEntity:!0,revision:o,rbacTeams:t}),n.delete(`${a.key}:${s}`),await this.#n(e,a.key,a.version,s,o,n,t);const r=this.#s(e.definition.paths);if(r.length!==0){const c=(await T(r,b,async({operation:h,path:m,method:l})=>{if(!h.operationId)return;const f=await this.#r(h,m,l,e,a.key,a.version,o,t);f&&n.delete(`${f}:${s}`)},this.#e)).count.failed;c>0&&this.#e.warn(`Extraction completed with ${c} failures out of ${r.length} operations for ${a.key}`)}}#s(e){return Object.entries(e).flatMap(([o,s])=>A.filter(n=>s[n]).map(n=>{const t=s[n];if(!t)throw new Error(`Operation not found for method ${n} on path ${o}`);return{operation:t,path:o,method:n.toUpperCase()}}))}async#n(e,o,s,n,t,a,r){const i=e.definition.components?.schemas;if(!i)return;const c=Object.entries(i);c.length!==0&&await E(c,d,async([h,m])=>{const l=await this.#o({schemaName:h,schema:m,description:e,parentKey:o,parentVersion:s,parentRevision:t,rbacTeams:r});a.delete(`${l.entityKey}:${n}`),l.result==="created"&&await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:o,sourceVersion:s,sourceRevision:t,type:"uses",targetKey:l.entityKey,targetVersion:s,targetRevision:t,fileHash:e.hash})})}async#o({schemaName:e,schema:o,description:s,parentKey:n,parentVersion:t,parentRevision:a,rbacTeams:r}){const i=S.resolveSchemaRefs(o,s),c=JSON.stringify(i),h=i[$]?R(i[$]):r,m=R(i["x-rbac"]),l={type:"data-schema",key:`${n}-${p(e)}`,title:e,summary:i.description??i.title??null,tags:[],metadata:{specType:this.specType,schema:c},version:t};return await this.catalogEntitiesService.createEntityInLocalDatabase({entity:l,sourceFile:s.realRelativePath,fileHash:s.hash,revision:a,rbacTeams:m.length?m:h})}async#r(e,o,s,n,t,a,r,i){const c=await Promise.all([this.#m(e.requestBody??null,n),this.#h(e.responses??{},n)]),h=c[0].schemaNames,m=c[1].schemaNames;c[0].errors.length>0&&this.#e.warn(`Schema extraction errors for operation ${e.operationId}: ${c[0].errors.join(", ")}`),c[1].errors.length>0&&this.#e.warn(`Response schema extraction errors for operation ${e.operationId}: ${c[1].errors.join(", ")}`);const l=h.map(g=>`${t}-${p(g)}`),f=m.map(g=>`${t}-${p(g)}`),y=await this.#p({path:o,method:s,operation:e,requestBodySchemasKeys:l,responseSchemasKeys:f,description:n,parentKey:t,parentVersion:a,parentRevision:r,rbacTeams:i});return y.result==="created"&&await Promise.all([this.#i(h,e.operationId??"",n.hash,t,a,r),this.#c(m,e.operationId??"",n.hash,t,a,r),this.#f({apiOperationKey:y.entityKey,operationRelations:e["x-catalog-relations"],descriptionUniqueKey:t,description:n,parentVersion:a,parentRevision:r})]),y.entityKey??null}async#i(e,o,s,n,t,a){return e.length===0||!o?[]:await this.#a(e,o,s,n,t,a)}async#c(e,o,s,n,t,a){return e.length===0||!o?[]:await this.#a(e,o,s,n,t,a)}#m(e,o){const s=[],n=[];try{if(e&&"content"in e&&e.content)for(const t of Object.values(e.content)){if(!t.schema?.$ref)continue;const a=this.#t(t.schema.$ref);a?.componentType==="schemas"&&a.componentName&&s.push(a.componentName)}if(e&&e.$ref){const t=this.#t(e.$ref);if(t?.componentType==="requestBodies"&&t.componentName){const a=o.definition.components?.requestBodies?.[t.componentName];if(a&&"content"in a)for(const r of Object.values(a.content??{})){if(!r.schema?.$ref)continue;const i=this.#t(r.schema.$ref);i?.componentType==="schemas"&&i.componentName&&s.push(i.componentName)}}}}catch(t){n.push(`Failed to extract request body schemas: ${t instanceof Error?t.message:"Unknown error"}`)}return{schemaNames:[...new Set(s)],errors:n}}#h(e,o){const s=[],n=[];try{for(const t of Object.values(e)){if(t&&"content"in t&&t.content)for(const a of Object.values(t.content)){if(!a.schema?.$ref)continue;const r=this.#t(a.schema.$ref);r?.componentType==="schemas"&&r.componentName&&s.push(r.componentName)}if(t&&t.$ref){const a=this.#t(t.$ref);if(a?.componentType==="responses"&&a.componentName){const r=o.definition.components?.responses?.[a.componentName];if(r&&"content"in r)for(const i of Object.values(r.content??{})){if(!i.schema?.$ref)continue;const c=this.#t(i.schema.$ref);c?.componentType==="schemas"&&c.componentName&&s.push(c.componentName)}}}}}catch(t){n.push(`Failed to extract response schemas: ${t instanceof Error?t.message:"Unknown error"}`)}return{schemaNames:[...new Set(s)],errors:n}}#t(e){try{return v(e)}catch{return{componentType:"",componentName:null}}}async#a(e,o,s,n,t,a){return e.length===0?[]:await E(e,d,async r=>await this.#l({operationId:o,schemaName:r,descriptionHash:s,parentKey:n,parentVersion:t,parentRevision:a}))}async#l({operationId:e,schemaName:o,descriptionHash:s,parentKey:n,parentVersion:t,parentRevision:a}){const r=`${n}-${p(o)}`;try{return await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:`${n}-${p(e)}`,type:"uses",targetKey:r,fileHash:s,sourceVersion:t,targetVersion:t,sourceRevision:a,targetRevision:a}),r}catch(i){throw this.#e.error(`Failed to create relation between operation ${e} and schema ${o}: ${i instanceof Error?i.message:"Unknown error"}`),i}}async#p({path:e,method:o,operation:s,requestBodySchemasKeys:n,responseSchemasKeys:t,description:a,parentKey:r,parentVersion:i,parentRevision:c,rbacTeams:h}){const m=`${s.operationId}`,l=`${r}-${p(m)}`,f=s[$]?R(s[$]):h,y=R(s["x-rbac"]),g={type:"api-operation",key:l,title:m,summary:w(s.summary),tags:s.tags?.filter(u=>O(u)),metadata:{path:e,method:o,payload:n,responses:t},version:i};try{return await this.catalogEntitiesService.createEntityInLocalDatabase({entity:g,sourceFile:a.realRelativePath,fileHash:a.hash,revision:c,rbacTeams:y.length>0?y:f})}catch(u){throw this.#e.error(`Failed to create API operation entity for ${m}: ${u instanceof Error?u.message:"Unknown error"}`),u}}async#f({apiOperationKey:e,operationRelations:o,descriptionUniqueKey:s,description:n,parentVersion:t,parentRevision:a}){try{await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:e,type:"partOf",targetKey:s,fileHash:n.hash,sourceVersion:t,targetVersion:t,sourceRevision:a,targetRevision:a}),await this.#y(e,o,t,a)}catch(r){this.#e.error(`Failed to create API operation relations for ${e}: ${r instanceof Error?r.message:"Unknown error"}`)}}async#y(e,o,s,n){o?.length&&await E(o,b,async t=>{try{this.validateEntityRelationFileSchema(t),await this.catalogEntitiesService.createEntityRelationInLocalDatabase({sourceKey:e,type:t.type,targetKey:t.key,sourceVersion:s,targetVersion:"",sourceRevision:n,targetRevision:""})}catch(a){this.context.logger.warn(`Error creating entity relation for operation ${e} based on custom property: ${a instanceof Error?a.message:"Unknown error"}`)}})}}export{_ as OpenApiEntitiesExtractor};