@redocly/revel-reef 0.130.0-next.6 → 0.130.0-next.8

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 (72) hide show
  1. package/CHANGELOG.md +34 -5
  2. package/dist/cli/telemetry/index.d.ts +1 -1
  3. package/dist/client/browser-entry.js +3 -3
  4. package/dist/constants/common.d.ts +2 -1
  5. package/dist/constants/common.js +1 -1
  6. package/dist/constants/l10n/langs/ar.js +1 -1
  7. package/dist/constants/l10n/langs/de.js +1 -1
  8. package/dist/constants/l10n/langs/en.js +1 -1
  9. package/dist/constants/l10n/langs/es.js +1 -1
  10. package/dist/constants/l10n/langs/fr.js +1 -1
  11. package/dist/constants/l10n/langs/hi.js +1 -1
  12. package/dist/constants/l10n/langs/it.js +1 -1
  13. package/dist/constants/l10n/langs/ja.js +1 -1
  14. package/dist/constants/l10n/langs/ko.js +1 -1
  15. package/dist/constants/l10n/langs/pl.js +1 -1
  16. package/dist/constants/l10n/langs/pt-BR.js +1 -1
  17. package/dist/constants/l10n/langs/pt.js +1 -1
  18. package/dist/constants/l10n/langs/ru.js +1 -1
  19. package/dist/constants/l10n/langs/uk.js +1 -1
  20. package/dist/constants/l10n/langs/zh.js +1 -1
  21. package/dist/server/api-routes/run-api-routes-worker.js +1 -1
  22. package/dist/server/persistence/kv/repositories/kv-remote-repository.js +2 -2
  23. package/dist/server/plugins/catalog-entities/database/catalog-entities-service.d.ts +5 -6
  24. package/dist/server/plugins/catalog-entities/database/catalog-entities-service.js +1 -1
  25. package/dist/server/plugins/catalog-entities/database/mappers/create-entity-db-record.d.ts +1 -1
  26. package/dist/server/plugins/catalog-entities/database/repositories/common/revision-repository.d.ts +27 -0
  27. package/dist/server/plugins/catalog-entities/database/repositories/common/revision-repository.js +1 -0
  28. package/dist/server/plugins/catalog-entities/database/repositories/common/version-repository.d.ts +36 -0
  29. package/dist/server/plugins/catalog-entities/database/repositories/common/version-repository.js +1 -0
  30. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-bff-repository.js +30 -23
  31. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-local-read-repository.d.ts +3 -2
  32. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-local-read-repository.js +23 -12
  33. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-local-repository.d.ts +6 -4
  34. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-local-repository.js +1 -1
  35. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-local-write-repository.d.ts +1 -0
  36. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-local-write-repository.js +1 -1
  37. package/dist/server/plugins/catalog-entities/database/repositories/remote/catalog-entities-remote-repository.d.ts +2 -5
  38. package/dist/server/plugins/catalog-entities/database/repositories/remote/catalog-entities-remote-repository.js +1 -1
  39. package/dist/server/plugins/catalog-entities/database/repositories/utils/create-merged-entity-fields-for-select.d.ts +34 -0
  40. package/dist/server/plugins/catalog-entities/database/repositories/utils/create-merged-entity-fields-for-select.js +13 -0
  41. package/dist/server/plugins/catalog-entities/database/repositories/utils/normalize-revision-flags.d.ts +23 -0
  42. package/dist/server/plugins/catalog-entities/database/repositories/utils/normalize-revision-flags.js +1 -0
  43. package/dist/server/plugins/catalog-entities/database/repositories/utils/semantic-version-sort.d.ts +78 -0
  44. package/dist/server/plugins/catalog-entities/database/repositories/utils/semantic-version-sort.js +34 -0
  45. package/dist/server/plugins/catalog-entities/entities/validate-entity.d.ts +3 -1
  46. package/dist/server/plugins/catalog-entities/entities/validate-entity.js +1 -1
  47. package/dist/server/plugins/catalog-entities/plugin.js +1 -1
  48. package/dist/server/plugins/catalog-entities/schemas/dto-schemas.d.ts +3 -1
  49. package/dist/server/plugins/catalog-entities/utils/ajv-validator.js +1 -1
  50. package/dist/server/plugins/scorecard-classic/loaders/scorecard-config.js +1 -1
  51. package/dist/server/plugins/scorecards/database/scorecards-config-service.d.ts +1 -1
  52. package/dist/server/plugins/scorecards/database/scorecards-config-service.js +1 -1
  53. package/dist/server/plugins/scorecards/workers/run-scorecards-worker.js +1 -1
  54. package/dist/server/plugins/scorecards/workers/scorecards.d.ts +1 -14
  55. package/dist/server/plugins/scorecards/workers/scorecards.js +1 -1
  56. package/dist/server/providers/database/pagination/entities-to-filter.d.ts +15 -0
  57. package/dist/server/providers/database/pagination/entities-to-filter.js +1 -0
  58. package/dist/server/providers/database/pagination/utils/index.d.ts +4 -0
  59. package/dist/server/providers/database/pagination/utils/index.js +1 -1
  60. package/dist/server/providers/database/pagination/utils/is-nested-condition.d.ts +16 -0
  61. package/dist/server/providers/database/pagination/utils/is-nested-condition.js +1 -0
  62. package/dist/server/providers/database/pagination/utils/is-simple-condition.d.ts +18 -0
  63. package/dist/server/providers/database/pagination/utils/is-simple-condition.js +1 -0
  64. package/dist/server/providers/database/pagination/utils/map-operator.d.ts +10 -0
  65. package/dist/server/providers/database/pagination/utils/map-operator.js +1 -0
  66. package/dist/server/providers/database/pagination/utils/transform-condition.d.ts +12 -0
  67. package/dist/server/providers/database/pagination/utils/transform-condition.js +1 -0
  68. package/dist/server/types/plugins/scorecards.d.ts +30 -0
  69. package/dist/server/types/plugins/scorecards.js +0 -0
  70. package/dist/server/web-server/routes/catalog/catalog.js +1 -1
  71. package/dist/server/workers/types.d.ts +1 -1
  72. package/package.json +11 -14
@@ -1,4 +1,15 @@
1
- import{and as l,count as L,eq as n,isNotNull as v,notExists as y,or as D,sql as e}from"drizzle-orm";import{unionAll as f}from"drizzle-orm/sqlite-core";import{logger as b}from"../../../../../tools/notifiers/logger.js";import{VERSION_NOT_SPECIFIED as k}from"@redocly/theme/core/constants";import{applyPagination as S}from"../../../../../providers/database/pagination/index.js";import{FIELDS_TO_SELECT_FOR_ENTITY as c,FIELDS_TO_SELECT_FOR_ENTITY_RELATION as m}from"../utils.js";import{createEntityReadModel as O}from"../../mappers/create-entity-read-model.js";import{createEntityRelation as C}from"../../mappers/create-entity-relation.js";import{entitiesTable as t}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-table.js";import{entitiesRelationsTable as E}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-relations-table.js";import{CatalogEntitiesRelationsRepository as I}from"./catalog-entities-relations-repository.js";import{CatalogEntitiesBffRepository as g}from"./catalog-entities-bff-repository.js";class j{#e;#t=void 0;#i;#s;constructor(i){this.#e=i,this.#i=new I(this.#e,this.#t||""),this.#s=new g(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 I(this.#e,i),this.#s=new g(this.#e,i))}async getEntities(i={}){const s=this.#t?f(this.#e.client.select(c).from(e`remote.entities`),this.#e.client.select(c).from(t).where(y(this.#e.client.select({id:c.id}).from(e`remote.entities as remote`).where(e`remote.key = ${t.key}`)))):this.#e.client.select(c).from(t),r=this.#e.client.select(c).from(s.as("combined_entities")),o=this.#e.client.select(c).from(s.as("combined_entities")).$dynamic(),_=S(o,{...i,limit:void 0,skip:void 0,after:void 0,before:void 0}),a=this.#e.client.$count(_),u=r.$dynamic(),d=i.limit||10,h=S(u,{...i,limit:d+1}),[T,N]=await Promise.all([h.run(),a]),p=T.rows,w=p.length>d;return{items:p.slice(0,d).map(R=>O(R)).filter(R=>R!==null),hasMore:w,total:N}}async getEntityKeysAndVersionsBySourceFile(i){const s=this.#t?f(this.#e.client.select({keyVersion:e`key || ':' || COALESCE(version, ${k})`.as("keyVersion")}).from(e`remote.entities`).where(l(e`source_file = ${i}`,e`source = 'file'`,e`key IS NOT NULL`)),this.#e.client.select({keyVersion:e`${t.key} || ':' || COALESCE(${t.version}, ${k})`.as("keyVersion")}).from(t).where(l(n(t.sourceFile,i),n(t.source,"file"),e`${t.key} IS NOT NULL`,y(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}, ${k})`.as("keyVersion")}).from(t).where(l(n(t.sourceFile,i),n(t.source,"file"),v(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(o=>o.keyVersion))}async listEntityRevisions(i,s){const r=[n(t.key,i),n(t.isDeleted,!1),...s?[n(t.version,s)]:[]],o=this.#t?f(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(e`remote.entities`).where(l(e`key = ${i}`,s?e`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(l(...r,y(this.#e.client.select({version:e.raw("version")}).from(e`remote.entities as remote`).where(l(e`remote.key = ${t.key}`,e`remote.version = ${t.version}`,e`remote.revision = ${t.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(l(...r));return(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.raw("is_current DESC"),e.raw("updated_at DESC"),e.raw("created_at DESC")).run()).rows.map(a=>({version:a.version||null,revision:a.revision??"",isCurrent:a.is_current!==null?!!a.is_current:!1,createdAt:a.created_at||null,updatedAt:a.updated_at||null,isDefaultVersion:a.is_default_version!==null?!!a.is_default_version:!1}))}async getEntitiesCountByTypes(){const i=this.#t?f(this.#e.client.select({type:e`type`}).from(e`remote.entities`).where(l(n(e.raw("is_current"),1),n(e.raw("is_deleted"),!1))),this.#e.client.select({type:t.type}).from(t).where(l(n(t.isCurrent,!0),n(t.isDeleted,!1),y(this.#e.client.select({id:e.raw("id")}).from(e`remote.entities as remote`).where(l(e`remote.key = ${t.key}`,e`remote.is_current = 1`)))))):this.#e.client.select({type:t.type}).from(t).where(l(n(t.isCurrent,!0),n(t.isDeleted,!1)));return this.#e.client.select({type:t.type,count:L()}).from(i.as("combined_entities")).groupBy(t.type).where(n(t.isDeleted,!1))}async getEntityByKey(i){const o=(await(this.#t?f(this.#e.client.select(c).from(e`remote.entities`).where(l(n(t.key,i),n(e.raw("is_current"),1),n(e.raw("is_deleted"),!1))),this.#e.client.select(c).from(t).where(l(n(t.key,i),n(t.isCurrent,!0),n(t.isDeleted,!1),y(this.#e.client.select({id:c.id}).from(e`remote.entities as remote`).where(l(e`remote.key = ${t.key}`,e`remote.is_current = 1`)))))):this.#e.client.select(c).from(t).where(l(n(t.key,i),n(t.isCurrent,!0),n(t.isDeleted,!1)))).run()).rows[0];return o?O(o):null}async getOneOutdatedEntity(){const i=this.#t?f(this.#e.client.select(c).from(e`remote.entities`),this.#e.client.select(c).from(t).where(y(this.#e.client.select({id:c.id}).from(e`remote.entities as remote`).where(e`remote.key = ${t.key}`)))):this.#e.client.select(c).from(t),r=(await this.#e.client.select(c).from(i.as("combined_entities")).where(D(e`combined_entities.scorecards_status = 'OUTDATED'`,e`combined_entities.scorecards_status IS NULL`)).orderBy(e`combined_entities.updated_at ASC`).limit(1).run()).rows[0];return r?O(r):null}async getEntitiesRelations(i={}){const s=this.#t?f(this.#e.client.select(m).from(e`remote.entities_relations`),this.#e.client.select(m).from(E).where(y(this.#e.client.select({id:m.id}).from(e`remote.entities_relations as remote`).where(e`remote.source_key = ${E.sourceKey}`)))):this.#e.client.select(m).from(E),r=this.#e.client.select(m).from(s.as("combined_entities_relations")).$dynamic(),o=this.#e.client.select(m).from(s.as("combined_entities_relations")).$dynamic(),_=S(o,{...i,limit:void 0,skip:void 0,after:void 0,before:void 0}),a=this.#e.client.$count(_),u=i.limit||10,d=S(r,{...i,limit:u+1}),[h,T]=await Promise.all([d.run(),a]),N=h.rows,p=N.length>u;return{items:N.slice(0,u).map(w=>C(w)).filter(w=>w!==null),hasMore:p,total:T}}async getEntityRelationById(i){const o=(await(this.#t?f(this.#e.client.select(m).from(e`remote.entities_relations`).where(n(E.id,i)),this.#e.client.select(m).from(E).where(l(n(E.id,i),y(this.#e.client.select({id:m.id}).from(e`remote.entities_relations as remote`).where(e`remote.id = ${E.id}`))))):this.#e.client.select(m).from(E).where(n(E.id,i))).run()).rows[0];return o?C(o):null}async getEntitiesWithRelations(i={},s){return this.#s.getEntitiesWithRelations(i,s)}async getEntityWithRelationsByKey(i,s,r){return this.#s.getEntityWithRelationsByKey(i,s,r)}async getRelationsForEntity(i,s,r){return this.#i.getRelationsForEntity(i,s,r)}async getRelatedEntities(i,s={}){return this.#i.getRelatedEntities(i,s)}async getCatalogFilters({entitiesTypes:i=[],emptyFilters:s=[]}){if(!s.length)return{};try{return await this.#r(i),(s.includes("domains")||s.includes("owners"))&&await this.#n(),await this.#o(s)}catch(r){return console.error("Error fetching catalog filters:",r),{}}finally{await this.#l()}}async#r(i){if(this.#t?await this.#e.client.run(e`
1
+ import{and as c,count as v,eq as u,isNotNull as D,notExists as y,or as $,sql as e}from"drizzle-orm";import{unionAll as f}from"drizzle-orm/sqlite-core";import{logger as F}from"../../../../../tools/notifiers/logger.js";import{VERSION_NOT_SPECIFIED as A}from"@redocly/theme/core/constants";import{applyPagination as S}from"../../../../../providers/database/pagination/index.js";import{applyFilter as B}from"../../../../../providers/database/pagination/filter.js";import{FIELDS_TO_SELECT_FOR_ENTITY as _,FIELDS_TO_SELECT_FOR_ENTITY_RELATION as m}from"../utils.js";import{createEntityReadModel as k}from"../../mappers/create-entity-read-model.js";import{createEntityRelation as C}from"../../mappers/create-entity-relation.js";import{entitiesTable as i}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-table.js";import{entitiesRelationsTable as E}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-relations-table.js";import{CatalogEntitiesRelationsRepository as I}from"./catalog-entities-relations-repository.js";import{CatalogEntitiesBffRepository as g}from"./catalog-entities-bff-repository.js";import{createMergedEntityFieldsForSelect as b}from"../utils/create-merged-entity-fields-for-select.js";import{buildSemanticVersionSortExpr as L}from"../utils/semantic-version-sort.js";import{normalizeRevisionFlags as M}from"../utils/normalize-revision-flags.js";class te{#e;#t=void 0;#i;#r;constructor(t){this.#e=t,this.#i=new I(this.#e,this.#t||""),this.#r=new g(this.#e,this.#t||"")}async attachDatabase(t){this.#t!==t&&(this.#t=t,await this.#e.client.run(e`ATTACH DATABASE ${t} AS remote`),this.#i=new I(this.#e,t),this.#r=new g(this.#e,t))}async getEntities(t={}){const r=this.#t?f(this.#e.client.select(_).from(e`remote.entities`).where(y(this.#e.client.select({id:_.id}).from(i).where(c(e`${i.key} = remote.entities.key`,e`${i.version} = remote.entities.version`,e`${i.revision} = remote.entities.revision`)))),this.#e.client.select(_).from(i).where(y(this.#e.client.select({id:e.raw("id")}).from(e`remote.entities as r`).where(c(e`r.key = ${i.key}`,e`r.version = ${i.version}`,e`r.revision = ${i.revision}`)))),this.#e.client.select(b("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`)):this.#e.client.select(_).from(i),s=this.#e.client.select(_).from(r.as("combined_entities")),n=this.#e.client.select(_).from(r.as("combined_entities")).$dynamic(),d=S(n,{...t,limit:void 0,skip:void 0,after:void 0,before:void 0}),l=this.#e.client.$count(d),a=s.$dynamic(),o=t.limit||10,h=S(a,{...t,limit:o+1}),[N,p]=await Promise.all([h.run(),l]),w=N.rows,T=w.length>o;return{items:w.slice(0,o).map(R=>k(R)).filter(R=>R!==null),hasMore:T,total:p}}async getEntityKeysAndVersionsBySourceFile(t){const r=this.#t?f(this.#e.client.select({keyVersion:e`key || ':' || COALESCE(version, ${A})`.as("keyVersion")}).from(e`remote.entities`).where(c(e`source_file = ${t}`,e`source = 'file'`,e`key IS NOT NULL`)),this.#e.client.select({keyVersion:e`${i.key} || ':' || COALESCE(${i.version}, ${A})`.as("keyVersion")}).from(i).where(c(u(i.sourceFile,t),u(i.source,"file"),e`${i.key} IS NOT NULL`,y(this.#e.client.select({key:e.raw("key")}).from(e`remote.entities as remote`).where(e`remote.key = ${i.key}`))))):this.#e.client.select({keyVersion:e`${i.key} || ':' || COALESCE(${i.version}, ${A})`.as("keyVersion")}).from(i).where(c(u(i.sourceFile,t),u(i.source,"file"),D(i.key))),s=await this.#e.client.selectDistinct({keyVersion:e`combined_keys_versions.keyVersion`}).from(r.as("combined_keys_versions")).run();return new Set(s.rows.map(n=>n.keyVersion))}async listEntityRevisions(t,r){const s=[u(i.key,t),u(i.isDeleted,!1),...r?[u(i.version,r)]:[]],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")},d=this.#t?f(this.#e.client.select(n).from(e`remote.entities`).where(c(e`key = ${t}`,e`is_deleted = 0`,r?e`version = ${r}`:void 0,y(this.#e.client.select({id:e.raw("id")}).from(i).where(c(e`${i.key} = remote.entities.key`,e`${i.version} = remote.entities.version`,e`${i.revision} = remote.entities.revision`))))),this.#e.client.select({version:i.version,revision:i.revision,isCurrent:i.isCurrent,createdAt:i.createdAt,updatedAt:i.updatedAt,isDefaultVersion:i.isDefaultVersion}).from(i).where(c(...s,y(this.#e.client.select({id:e.raw("id")}).from(e`remote.entities as r`).where(c(e`r.key = ${i.key}`,e`r.version = ${i.version}`,e`r.revision = ${i.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(c(e`r.key = ${t}`,e`r.is_deleted = 0`,e`l.is_deleted = 0`,r?e`r.version = ${r}`:void 0))):this.#e.client.select({version:i.version,revision:i.revision,isCurrent:i.isCurrent,createdAt:i.createdAt,updatedAt:i.updatedAt,isDefaultVersion:i.isDefaultVersion}).from(i).where(c(...s)),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(d.as("combined_revisions")).orderBy(e`${L("version")} DESC`,e.raw("revision DESC")).run()).rows.map(o=>({version:o.version||null,revision:o.revision??"",isCurrent:o.is_current!==null?!!o.is_current:!1,createdAt:o.created_at||null,updatedAt:o.updated_at||null,isDefaultVersion:o.is_default_version!==null?!!o.is_default_version:!1}));return M(a),a}async getEntitiesCountByTypes(){if(this.#t){const t=e`
2
+ SELECT key, type, version,
3
+ ROW_NUMBER() OVER (
4
+ PARTITION BY key
5
+ ORDER BY ${L("version")} DESC
6
+ ) as rn
7
+ FROM (
8
+ SELECT key, type, version FROM remote.entities WHERE is_current = 1 AND is_deleted = 0
9
+ UNION ALL
10
+ SELECT key, type, version FROM entities WHERE is_current = 1 AND is_deleted = 0
11
+ )
12
+ `;return this.#e.client.select({type:e`type`,count:v()}).from(e`(SELECT * FROM (${t}) WHERE rn = 1) as highest_version_entities`).groupBy(e`type`)}return this.#e.client.select({type:i.type,count:v()}).from(i).where(c(u(i.isCurrent,!0),u(i.isDeleted,!1))).groupBy(i.type)}async getEntityById(t){const n=(await(this.#t?f(this.#e.client.select(_).from(e`remote.entities`).where(e`id = ${t}`),this.#e.client.select(_).from(i).where(u(i.id,t))):this.#e.client.select(_).from(i).where(u(i.id,t))).run()).rows[0];return n?k(n):null}async getOutdatedEntities(t){const r=this.#t?f(this.#e.client.select(_).from(e`remote.entities`),this.#e.client.select(_).from(i).where(y(this.#e.client.select({id:_.id}).from(e`remote.entities as remote`).where(e`remote.key = ${i.key}`)))):this.#e.client.select(_).from(i),s=this.#e.client.select(_).from(r.as("combined_entities")).$dynamic(),{whereCondition:n}=B(s,t),d=$(e`combined_entities.scorecards_status = 'OUTDATED'`,e`combined_entities.scorecards_status IS NULL`),l=n?c(n,d):d;return(await s.where(l).run()).rows.map(o=>k(o)).filter(o=>o!==null)}async getEntitiesRelations(t={}){const r=this.#t?f(this.#e.client.select(m).from(e`remote.entities_relations`),this.#e.client.select(m).from(E).where(y(this.#e.client.select({id:m.id}).from(e`remote.entities_relations as remote`).where(e`remote.source_key = ${E.sourceKey}`)))):this.#e.client.select(m).from(E),s=this.#e.client.select(m).from(r.as("combined_entities_relations")).$dynamic(),n=this.#e.client.select(m).from(r.as("combined_entities_relations")).$dynamic(),d=S(n,{...t,limit:void 0,skip:void 0,after:void 0,before:void 0}),l=this.#e.client.$count(d),a=t.limit||10,o=S(s,{...t,limit:a+1}),[h,N]=await Promise.all([o.run(),l]),p=h.rows,w=p.length>a;return{items:p.slice(0,a).map(T=>C(T)).filter(T=>T!==null),hasMore:w,total:N}}async getEntityRelationById(t){const n=(await(this.#t?f(this.#e.client.select(m).from(e`remote.entities_relations`).where(u(E.id,t)),this.#e.client.select(m).from(E).where(c(u(E.id,t),y(this.#e.client.select({id:m.id}).from(e`remote.entities_relations as remote`).where(e`remote.id = ${E.id}`))))):this.#e.client.select(m).from(E).where(u(E.id,t))).run()).rows[0];return n?C(n):null}async getEntitiesWithRelations(t={},r){return this.#r.getEntitiesWithRelations(t,r)}async getEntityWithRelationsByKey(t,r,s){return this.#r.getEntityWithRelationsByKey(t,r,s)}async getRelationsForEntity(t,r,s){return this.#i.getRelationsForEntity(t,r,s)}async getRelatedEntities(t,r={}){return this.#i.getRelatedEntities(t,r)}async getCatalogFilters({entitiesTypes:t=[],emptyFilters:r=[]}){if(!r.length)return{};try{return await this.#s(t),(r.includes("domains")||r.includes("owners"))&&await this.#n(),await this.#o(r)}catch(s){return console.error("Error fetching catalog filters:",s),{}}finally{await this.#l()}}async#s(t){if(this.#t?await this.#e.client.run(e`
2
13
  CREATE TEMP TABLE IF NOT EXISTS temp_combined_entities AS
3
14
  SELECT
4
15
  e.key,
@@ -25,10 +36,10 @@ import{and as l,count as L,eq as n,isNotNull as v,notExists as y,or as D,sql as
25
36
  metadata
26
37
  FROM entities
27
38
  WHERE is_current = 1
28
- `),i.length){const s=i.map(r=>`'${r.replace(/'/g,"''")}'`).join(",");await this.#e.client.run(e.raw(`
39
+ `),t.length){const r=t.map(s=>`'${s.replace(/'/g,"''")}'`).join(",");await this.#e.client.run(e.raw(`
29
40
  CREATE TEMP TABLE IF NOT EXISTS temp_filtered_entities AS
30
41
  SELECT * FROM temp_combined_entities
31
- WHERE type IN (${s})
42
+ WHERE type IN (${r})
32
43
  `))}else await this.#e.client.run(e`
33
44
  CREATE TEMP TABLE IF NOT EXISTS temp_filtered_entities AS
34
45
  SELECT * FROM temp_combined_entities
@@ -64,12 +75,12 @@ import{and as l,count as L,eq as n,isNotNull as v,notExists as y,or as D,sql as
64
75
  CREATE INDEX IF NOT EXISTS idx_temp_rel_target ON temp_combined_relations(target_key)
65
76
  `),await this.#e.client.run(e`
66
77
  CREATE INDEX IF NOT EXISTS idx_temp_rel_relation ON temp_combined_relations(source_to_target_relation)
67
- `)}async#o(i){const s={},r=[],o=i.filter(u=>u.startsWith("metadata."));i.includes("type")&&r.push(`
78
+ `)}async#o(t){const r={},s=[],n=t.filter(a=>a.startsWith("metadata."));t.includes("type")&&s.push(`
68
79
  SELECT 'type' as filter_name, type as value, COUNT(*) as count
69
80
  FROM temp_filtered_entities
70
81
  WHERE type IS NOT NULL
71
82
  GROUP BY type
72
- `),i.includes("tags")&&r.push(`
83
+ `),t.includes("tags")&&s.push(`
73
84
  SELECT 'tags' as filter_name, tag.value as value, COUNT(DISTINCT tfe.key) as count
74
85
  FROM temp_filtered_entities tfe,
75
86
  json_each(COALESCE(tfe.tags, json_array())) as tag
@@ -78,7 +89,7 @@ import{and as l,count as L,eq as n,isNotNull as v,notExists as y,or as D,sql as
78
89
  AND tag.value IS NOT NULL
79
90
  AND tag.value != ''
80
91
  GROUP BY tag.value
81
- `),i.includes("domains")&&r.push(`
92
+ `),t.includes("domains")&&s.push(`
82
93
  SELECT 'domains' as filter_name, tcr.source_key as value, COUNT(DISTINCT tfe.key) as count
83
94
  FROM temp_combined_relations tcr
84
95
  INNER JOIN temp_filtered_entities tfe ON tfe.key = tcr.target_key
@@ -86,7 +97,7 @@ import{and as l,count as L,eq as n,isNotNull as v,notExists as y,or as D,sql as
86
97
  WHERE tce.type = 'domain'
87
98
  AND tcr.source_to_target_relation = 'hasParts'
88
99
  GROUP BY tcr.source_key
89
- `),i.includes("owners")&&r.push(`
100
+ `),t.includes("owners")&&s.push(`
90
101
  SELECT 'owners' as filter_name, owner_key as value, COUNT(DISTINCT entity_key) as count
91
102
  FROM (
92
103
  SELECT
@@ -106,12 +117,12 @@ import{and as l,count as L,eq as n,isNotNull as v,notExists as y,or as D,sql as
106
117
  INNER JOIN temp_combined_entities tce ON tce.key = owner_key
107
118
  WHERE owner_key IS NOT NULL
108
119
  GROUP BY owner_key
109
- `);for(const u of o)await this.#a(u,s);if(r.length===0)return s;const _=r.join(" UNION ALL "),a=await this.#e.client.run(e.raw(_));if(a?.rows)for(const u of a.rows){const d=u.filter_name,h=u.value,T=Number(u.count)||0;s[d]||(s[d]=[]),h&&s[d].push({value:h,count:T})}return s}async#a(i,s){const r=i.substring(9),o=`$.${$(r)}`,_=await this.#e.client.run(e.raw(`
110
- SELECT json_extract(metadata, '${o}') as value, COUNT(*) as count
120
+ `);for(const a of n)await this.#a(a,r);if(s.length===0)return r;const d=s.join(" UNION ALL "),l=await this.#e.client.run(e.raw(d));if(l?.rows)for(const a of l.rows){const o=a.filter_name,h=a.value,N=Number(a.count)||0;r[o]||(r[o]=[]),h&&r[o].push({value:h,count:N})}return r}async#a(t,r){const s=t.substring(9),n=`$.${U(s)}`,d=await this.#e.client.run(e.raw(`
121
+ SELECT json_extract(metadata, '${n}') as value, COUNT(*) as count
111
122
  FROM temp_filtered_entities
112
123
  WHERE metadata IS NOT NULL
113
124
  AND metadata != ''
114
- AND json_extract(metadata, '${o}') IS NOT NULL
115
- AND json_extract(metadata, '${o}') != ''
125
+ AND json_extract(metadata, '${n}') IS NOT NULL
126
+ AND json_extract(metadata, '${n}') != ''
116
127
  GROUP BY value
117
- `));_?.rows&&(s[i]=_.rows.map(a=>({value:a.value,count:Number(a.count)||0})).filter(a=>a.value))}async#l(){try{await this.#e.client.run(e`DROP TABLE IF EXISTS temp_combined_entities`),await this.#e.client.run(e`DROP TABLE IF EXISTS temp_filtered_entities`),await this.#e.client.run(e`DROP TABLE IF EXISTS temp_combined_relations`)}catch(i){b.error("Error cleaning up temp tables:",i)}}}function $(A){return A.replace(/[^a-zA-Z0-9._-]/g,"")}export{j as CatalogEntitiesLocalReadRepository};
128
+ `));d?.rows&&(r[t]=d.rows.map(l=>({value:l.value,count:Number(l.count)||0})).filter(l=>l.value))}async#l(){try{await this.#e.client.run(e`DROP TABLE IF EXISTS temp_combined_entities`),await this.#e.client.run(e`DROP TABLE IF EXISTS temp_filtered_entities`),await this.#e.client.run(e`DROP TABLE IF EXISTS temp_combined_relations`)}catch(t){F.error("Error cleaning up temp tables:",t)}}}function U(O){return O.replace(/[^a-zA-Z0-9._-]/g,"")}export{te as CatalogEntitiesLocalReadRepository};
@@ -5,6 +5,7 @@ import type { ScorecardsStatus } from '../../../../../plugins/catalog-entities/e
5
5
  import type { DatabaseConnection, RepositoryInstanceOptions } from '../../../../../providers/database/types.js';
6
6
  import type { CatalogFiltersParams } from './catalog-entities-local-read-repository.js';
7
7
  import type { SidebarConnectedEntity } from '@redocly/theme/core/types';
8
+ import type { EntityReadModelSchema } from '../../../../../plugins/catalog-entities/schemas/read-model-schemas.js';
8
9
  import { BaseRepository } from '../../../../../providers/database/base-repository.js';
9
10
  import { type CreateEntityParams, type CreateEntityResult } from './catalog-entities-local-write-repository.js';
10
11
  export declare class CatalogEntitiesLocalRepository extends BaseRepository {
@@ -14,8 +15,8 @@ export declare class CatalogEntitiesLocalRepository extends BaseRepository {
14
15
  getEntitySources(): Record<string, SidebarConnectedEntity>;
15
16
  static getInstance(options: RepositoryInstanceOptions): Promise<CatalogEntitiesLocalRepository>;
16
17
  attachDatabase(databasePath: string): Promise<void>;
17
- getEntities(paginationParams?: PaginationParams): Promise<import("./catalog-entities-local-read-repository.js").ListResult<import("../../../schemas/read-model-schemas.js").EntityReadModelSchema>>;
18
- getEntityByKey(key: string): Promise<import("../../../schemas/read-model-schemas.js").EntityReadModelSchema | null>;
18
+ getEntities(paginationParams?: PaginationParams): Promise<import("./catalog-entities-local-read-repository.js").ListResult<EntityReadModelSchema>>;
19
+ getEntityById(id: string): Promise<EntityReadModelSchema | null>;
19
20
  getEntityKeysAndVersionsBySourceFile(sourceFile: string): Promise<Set<string>>;
20
21
  getEntitiesCountByTypes(): Promise<{
21
22
  type: string;
@@ -87,9 +88,10 @@ export declare class CatalogEntitiesLocalRepository extends BaseRepository {
87
88
  deleteEntityRelation(id: string): Promise<string | null>;
88
89
  deleteEntityRelations(filter: Filter): Promise<boolean>;
89
90
  getCatalogFilters(params: CatalogFiltersParams): Promise<Record<string, import("./catalog-entities-local-read-repository.js").FilterOption[]>>;
90
- listEntityRevisions(entityKey: string, version?: string | null): Promise<import("../../../schemas/read-model-schemas.js").EntityRevisionSummary[]>;
91
+ listEntityRevisions(entityKey: string, version?: string | null): Promise<import("../../../../../plugins/catalog-entities/schemas/read-model-schemas.js").EntityRevisionSummary[]>;
91
92
  updateEntityScorecardsStatus(entityId: string, status: ScorecardsStatus): Promise<boolean>;
92
93
  updateEntityScorecardsStatusIfCalculating(entityId: string, status: Extract<ScorecardsStatus, 'UP_TO_DATE' | 'OUTDATED'>): Promise<boolean>;
93
- getOneOutdatedEntity(): Promise<import("../../../schemas/read-model-schemas.js").EntityReadModelSchema | null>;
94
+ getOutdatedEntities(filter?: Filter): Promise<EntityReadModelSchema[]>;
95
+ setEntitiesAsOutdated(filter: Filter): Promise<void>;
94
96
  }
95
97
  //# sourceMappingURL=catalog-entities-local-repository.d.ts.map
@@ -1 +1 @@
1
- import{promiseMapLimit as o}from"../../../../../utils/async/promise-map-limit.js";import{logger as R}from"../../../../../tools/notifiers/logger.js";import{DatabaseConnectionFactory as f}from"../../../../../providers/database/database-connection-factory.js";import{BaseRepository as p}from"../../../../../providers/database/base-repository.js";import{CatalogEntitiesLocalReadRepository as m}from"./catalog-entities-local-read-repository.js";import{CatalogEntitiesLocalWriteRepository as w}from"./catalog-entities-local-write-repository.js";import{createEntityRelationDbRecordFromDto as E}from"../../mappers/create-entity-relation-db-record-from-dto.js";import{hasOptionsChanged as C}from"../../../utils/has-options-changed.js";const l=50;class s extends p{static#i;static#n;#t;#e;#s={};constructor(t){super(t),this.#t=new m(this.databaseClient),this.#e=new w(this.databaseClient,this.organizationId,this.projectId)}get transactionsManager(){return this.databaseClient.transactionsManager}getEntitySources(){return this.#s}static async getInstance(t){const e=C(s.#n,t);if(!s.#i||e){const n=await f.create("catalog-local",t);if(!n)throw new Error("Failed to create db connection for catalog entities local repository");s.#i=new s(n),s.#n=t}return s.#i}async attachDatabase(t){await this.#t.attachDatabase(t)}getEntities(t={}){return this.#t.getEntities(t)}getEntityByKey(t){return this.#t.getEntityByKey(t)}getEntityKeysAndVersionsBySourceFile(t){return this.#t.getEntityKeysAndVersionsBySourceFile(t)}getEntitiesCountByTypes(){return this.#t.getEntitiesCountByTypes()}getEntitiesRelations(t={}){return this.#t.getEntitiesRelations(t)}getEntityRelationById(t){return this.#t.getEntityRelationById(t)}getEntitiesWithRelations(t={},e){return this.#t.getEntitiesWithRelations(t,e)}getEntityWithRelationsByKey(t,e,n){return this.#t.getEntityWithRelationsByKey(t,e,n)}getRelatedEntities(t,e={}){return this.#t.getRelatedEntities(t,e)}createEntity(t){return t.isRootEntity&&(this.#s[t.sourceFile]={key:t.entity.key,version:t.entity.version??void 0}),this.#e.createEntity(t)}async createEntities(t){await o(t,l,async e=>this.createEntity(e))}createEntityRelation(t){const e=E(t,this.organizationId,this.projectId);return this.#e.upsertEntityRelation(e)}async createEntityRelations(t){await o(t,l,async e=>this.createEntityRelation(e))}deleteEntity(t){return this.#e.deleteEntity(t)}async softDeleteEntities({filter:t,revision:e,fileHash:n}){const c=await this.getEntities({filter:t}),i=await this.#e.softDeleteEntities(c.items,e,n);await this.softDeleteEntitiesRelations(i,e)}async softDeleteEntitiesRelations(t,e){try{const n=t.filter(i=>i.result==="created");if(n.length===0)return!0;const c=await o(n,l,async i=>(await this.#t.getRelationsForEntity(i.entityKey,i.entityVersion,e)).map(r=>{if(!r)return null;const y=r.direction,a=r.sourceToTargetRelation,u=r.targetKey,d=y==="outgoing"?i.entityKey:u,h=y==="outgoing"?u:i.entityKey,g=y==="outgoing"?a:a.startsWith("reverse:")?a.slice(8):a;return!g||!d||!h?null:E({type:g,sourceKey:d,targetKey:h,sourceVersion:i.entityVersion,targetVersion:i.entityVersion,sourceRevision:e,targetRevision:e,isDeleted:!0},this.organizationId,this.projectId)}).filter(r=>r!==null));return await o(c.flat(),l,async i=>this.#e.upsertEntityRelation(i)),!0}catch(n){return R.error("Error soft deleting entity relations",n),!1}}deleteEntities(t){return this.#e.deleteEntities(t)}deleteEntityRelation(t){return this.#e.deleteEntityRelation(t)}deleteEntityRelations(t){return this.#e.deleteEntityRelations(t)}getCatalogFilters(t){return this.#t.getCatalogFilters(t)}listEntityRevisions(t,e){return this.#t.listEntityRevisions(t,e)}updateEntityScorecardsStatus(t,e){return this.#e.updateEntityScorecardsStatus(t,e)}updateEntityScorecardsStatusIfCalculating(t,e){return this.#e.updateEntityScorecardsStatusIfCalculating(t,e)}getOneOutdatedEntity(){return this.#t.getOneOutdatedEntity()}}export{s as CatalogEntitiesLocalRepository};
1
+ import{promiseMapLimit as o}from"../../../../../utils/async/promise-map-limit.js";import{logger as R}from"../../../../../tools/notifiers/logger.js";import{DatabaseConnectionFactory as f}from"../../../../../providers/database/database-connection-factory.js";import{BaseRepository as p}from"../../../../../providers/database/base-repository.js";import{CatalogEntitiesLocalReadRepository as m}from"./catalog-entities-local-read-repository.js";import{CatalogEntitiesLocalWriteRepository as w}from"./catalog-entities-local-write-repository.js";import{createEntityRelationDbRecordFromDto as g}from"../../mappers/create-entity-relation-db-record-from-dto.js";import{hasOptionsChanged as I}from"../../../utils/has-options-changed.js";const l=50;class s extends p{static#i;static#n;#t;#e;#s={};constructor(t){super(t),this.#t=new m(this.databaseClient),this.#e=new w(this.databaseClient,this.organizationId,this.projectId)}get transactionsManager(){return this.databaseClient.transactionsManager}getEntitySources(){return this.#s}static async getInstance(t){const e=I(s.#n,t);if(!s.#i||e){const n=await f.create("catalog-local",t);if(!n)throw new Error("Failed to create db connection for catalog entities local repository");s.#i=new s(n),s.#n=t}return s.#i}async attachDatabase(t){await this.#t.attachDatabase(t)}getEntities(t={}){return this.#t.getEntities(t)}getEntityById(t){return this.#t.getEntityById(t)}getEntityKeysAndVersionsBySourceFile(t){return this.#t.getEntityKeysAndVersionsBySourceFile(t)}getEntitiesCountByTypes(){return this.#t.getEntitiesCountByTypes()}getEntitiesRelations(t={}){return this.#t.getEntitiesRelations(t)}getEntityRelationById(t){return this.#t.getEntityRelationById(t)}getEntitiesWithRelations(t={},e){return this.#t.getEntitiesWithRelations(t,e)}getEntityWithRelationsByKey(t,e,n){return this.#t.getEntityWithRelationsByKey(t,e,n)}getRelatedEntities(t,e={}){return this.#t.getRelatedEntities(t,e)}createEntity(t){return t.isRootEntity&&(this.#s[t.sourceFile]={key:t.entity.key,version:t.entity.version??void 0}),this.#e.createEntity(t)}async createEntities(t){await o(t,l,async e=>this.createEntity(e))}createEntityRelation(t){const e=g(t,this.organizationId,this.projectId);return this.#e.upsertEntityRelation(e)}async createEntityRelations(t){await o(t,l,async e=>this.createEntityRelation(e))}deleteEntity(t){return this.#e.deleteEntity(t)}async softDeleteEntities({filter:t,revision:e,fileHash:n}){const c=await this.getEntities({filter:t}),i=await this.#e.softDeleteEntities(c.items,e,n);await this.softDeleteEntitiesRelations(i,e)}async softDeleteEntitiesRelations(t,e){try{const n=t.filter(i=>i.result==="created");if(n.length===0)return!0;const c=await o(n,l,async i=>(await this.#t.getRelationsForEntity(i.entityKey,i.entityVersion,e)).map(r=>{if(!r)return null;const y=r.direction,a=r.sourceToTargetRelation,u=r.targetKey,d=y==="outgoing"?i.entityKey:u,h=y==="outgoing"?u:i.entityKey,E=y==="outgoing"?a:a.startsWith("reverse:")?a.slice(8):a;return!E||!d||!h?null:g({type:E,sourceKey:d,targetKey:h,sourceVersion:i.entityVersion,targetVersion:i.entityVersion,sourceRevision:e,targetRevision:e,isDeleted:!0},this.organizationId,this.projectId)}).filter(r=>r!==null));return await o(c.flat(),l,async i=>this.#e.upsertEntityRelation(i)),!0}catch(n){return R.error("Error soft deleting entity relations",n),!1}}deleteEntities(t){return this.#e.deleteEntities(t)}deleteEntityRelation(t){return this.#e.deleteEntityRelation(t)}deleteEntityRelations(t){return this.#e.deleteEntityRelations(t)}getCatalogFilters(t){return this.#t.getCatalogFilters(t)}listEntityRevisions(t,e){return this.#t.listEntityRevisions(t,e)}updateEntityScorecardsStatus(t,e){return this.#e.updateEntityScorecardsStatus(t,e)}updateEntityScorecardsStatusIfCalculating(t,e){return this.#e.updateEntityScorecardsStatusIfCalculating(t,e)}getOutdatedEntities(t){return this.#t.getOutdatedEntities(t)}async setEntitiesAsOutdated(t){await this.#e.setEntitiesAsOutdated(t)}}export{s as CatalogEntitiesLocalRepository};
@@ -38,5 +38,6 @@ export declare class CatalogEntitiesLocalWriteRepository {
38
38
  upsertEntityRelation(entityRelation: DatabaseEntityRelationDto): Promise<DatabaseEntityRelation | null>;
39
39
  updateEntityScorecardsStatus(entityId: string, status: ScorecardsStatus): Promise<boolean>;
40
40
  updateEntityScorecardsStatusIfCalculating(entityId: string, status: Extract<ScorecardsStatus, 'UP_TO_DATE' | 'OUTDATED'>): Promise<boolean>;
41
+ setEntitiesAsOutdated(filter: Filter): Promise<void>;
41
42
  }
42
43
  //# sourceMappingURL=catalog-entities-local-write-repository.d.ts.map
@@ -1 +1 @@
1
- import{and as d,desc as I,eq as u,isNull as v,or as K,sql as k}from"drizzle-orm";import{logger as f}from"../../../../../tools/notifiers/logger.js";import{promiseMapLimit as w}from"../../../../../utils/async/promise-map-limit.js";import{sha1 as U}from"../../../../../utils/crypto/sha1.js";import{isWebView as x}from"../../../../../../utils/env/is-web-view.js";import{VERSION_NOT_SPECIFIED as S}from"@redocly/theme/core/constants";import{entitiesAttributesTable as E}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-attributes-table.js";import{createEntityDbRecord as z}from"../../mappers/create-entity-db-record.js";import{createEntityRelationDbRecordFromFileSchema as A}from"../../mappers/create-entity-relation-db-record-from-file-schema.js";import{entitiesTable as e}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-table.js";import{entitiesRelationsTable as o}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-relations-table.js";import{convertFilterToWhereCondition as T}from"../../../../../providers/database/pagination/filter.js";import{compareVersionsDescending as L}from"../../../utils/version-compare.js";import{createEntityAttributesDbRecord as F}from"../../mappers/create-entity-attributes-db-record.js";const D=15;class ie{#e;#t;#r;constructor(t,r,i){this.#e=t,this.#t=r,this.#r=i}async createEntity({entity:t,fileHash:r,sourceFile:i,revision:a=new Date().toISOString(),isRootEntity:n=!1,isDeleted:s=!1,rbacTeams:c=[]}){try{const{relations:l=[],...m}=t,V=U(JSON.stringify(m)),h=t.version??S;if(await this.#i(t.key,h,V,n,s))return{result:"skipped",entityKey:t.key};const{shouldBeCurrent:p,shouldBeDefaultVersion:y}=await this.#o(t.key,h),g=z({entity:{...t,revision:a,hash:V,isCurrent:p,isDefaultVersion:y,isDeleted:s,version:h},sourceFile:i,organizationId:this.#t,projectId:this.#r,source:"file",fileHash:r}),{key:N,source:j,...b}=g;if(await this.#a({key:N,isCurrent:p,isDefaultVersion:y}),x())return await this.#c(g,l,c),{result:"created",entityKey:t.key,entityRevision:a,entityVersion:h};const O=this.#e.client.insert(e).values(g).onConflictDoUpdate({target:[e.key,e.source,e.revision,e.version],set:b}),B=this.#e.client.insert(E).values(F({rbacTeams:c,entityKey:t.key,organizationId:this.#t,projectId:this.#r})).onConflictDoUpdate({target:[E.entityKey],set:{rbacTeams:JSON.stringify(c)}}),P=l?.length&&l.length>0?this.#e.client.insert(o).values(l.map(C=>A({relation:C,sourceFile:i,fileHash:r,sourceKey:t.key,sourceVersion:h,sourceRevision:a??null,organizationId:this.#t,projectId:this.#r}))).onConflictDoNothing({target:[o.sourceKey,o.targetKey,o.sourceVersion,o.targetVersion,o.sourceRevision,o.targetRevision,o.sourceToTargetRelation]}).run():Promise.resolve();return await w([O,P,B],D,async C=>C),{result:"created",entityKey:t.key,entityRevision:a,entityVersion:h}}catch(l){return f.error("Error adding entity",l),{result:"error",entityKey:t.key}}}async deleteEntity(t){try{return await this.#e.client.delete(e).where(u(e.key,t)),t}catch(r){return f.error("Error deleting entity",r),null}}async deleteEntities(t){try{const r=T(t);if(!r)return!1;const i=await this.#e.client.delete(e).where(r).returning({key:e.key,source:e.source,isCurrent:e.isCurrent,isDefaultVersion:e.isDefaultVersion,version:e.version});if(i.length===0)return!0;const a=i.reduce((n,s)=>((s.isCurrent||s.isDefaultVersion)&&n.add(s.key),n),new Set);if(a.size===0)return!0;await w(Array.from(a),D,async n=>this.#u(n));for(const n of i)await this.#e.client.delete(o).where(K(d(u(o.sourceKey,n.key),...n.version?[u(o.sourceVersion,n.version)]:[v(o.sourceVersion)]),d(u(o.targetKey,n.key),...n.version?[u(o.targetVersion,n.version)]:[v(o.targetVersion)])));return!0}catch(r){return f.error("Error deleting entities",r),!1}}async deleteEntityRelation(t){try{return await this.#e.client.delete(o).where(u(o.id,t)),t}catch{return null}}async softDeleteEntities(t,r,i){try{const a=t.map(s=>{const c={type:s.type,key:s.key,title:s.title,summary:s.summary??void 0,tags:s.tags??void 0,metadata:s.metadata??void 0,git:s.git??void 0,contact:s.contact??void 0,links:s.links??void 0,version:s.version??void 0};return this.createEntity({entity:c,revision:r,sourceFile:s.sourceFile??"",fileHash:i,isDeleted:!0})});return await w(a,D,async s=>s)}catch(a){return f.error("Error soft deleting entities",a),[]}}async deleteEntityRelations(t){try{const r=T(t);return r?(await this.#e.client.delete(o).where(r),!0):!1}catch(r){return f.error("Error deleting entity relations",r),!1}}async upsertEntityRelation(t){if(!t)return null;try{const{sourceKey:r,targetKey:i,sourceVersion:a,targetVersion:n,sourceRevision:s,targetRevision:c,...l}=t,m=await this.#e.client.insert(o).values(t).onConflictDoUpdate({target:[o.sourceKey,o.targetKey,o.sourceVersion,o.targetVersion,o.sourceRevision,o.targetRevision,o.sourceToTargetRelation],set:l}).returning();return m?.length?m[0]:null}catch(r){return f.error("Error creating entity relation",r),null}}async#i(t,r,i,a,n){if(a||n)return!1;const s=await this.#e.client.select({hash:e.hash,isDeleted:e.isDeleted}).from(e).where(d(u(e.key,t),u(e.source,"file"),r?u(e.version,r):v(e.version))).orderBy(I(e.revision)).limit(1).run();if(s.rows.length===0)return!1;const c=s.rows[0];return c.is_deleted?!1:c.hash===i}async#s(t){return(await this.#e.client.select({version:e.version,isDefaultVersion:e.isDefaultVersion,revision:e.revision,createdAt:e.createdAt}).from(e).where(d(u(e.key,t),u(e.source,"file"))).orderBy(I(e.createdAt)).run()).rows.map(i=>({version:i.version,isDefaultVersion:!!i.isDefaultVersion,revision:i.revision,createdAt:new Date(i.createdAt)}))}#n(t){const r=t.find(n=>n.isDefaultVersion);if(r)return r;const{versionedEntities:i,unversionedEntities:a}=t.reduce((n,s)=>(s.version!==null&&s.version!==S?n.versionedEntities.push(s):n.unversionedEntities.push(s),n),{versionedEntities:[],unversionedEntities:[]});if(i.length>0){i.sort((c,l)=>L(c.version,l.version));const n=i[0].version,s=i.filter(c=>c.version===n);return s.sort((c,l)=>l.createdAt.getTime()-c.createdAt.getTime()),s[0]}return a.length>0?(a.sort((n,s)=>s.createdAt.getTime()-n.createdAt.getTime()),a[0]):null}async#o(t,r){const i=await this.#e.client.select({currentDefaultVersion:k`max(case when ${e.isDefaultVersion} = 1 then ${e.version} else null end)`,versionMatchCount:k`count(case when ${e.version} = ${r} then 1 else null end)`}).from(e).where(d(u(e.key,t),u(e.source,"file"))).get(),a=i?.currentDefaultVersion,n=(i?.versionMatchCount??0)>0;return r&&r===a?{shouldBeCurrent:!0,shouldBeDefaultVersion:!1}:{shouldBeCurrent:!n,shouldBeDefaultVersion:!n}}async#a({key:t,isCurrent:r,isDefaultVersion:i}){if(!r&&!i)return;const a={},n=[];r&&(a.isCurrent=!1,n.push(u(e.isCurrent,!0))),i&&(a.isDefaultVersion=!1,n.push(u(e.isDefaultVersion,!0))),await this.#e.client.update(e).set(a).where(d(u(e.key,t),u(e.source,"file"),K(...n))).run()}#u=async t=>{const r=await this.#s(t),i=this.#n(r);i&&await this.#e.client.update(e).set({isDefaultVersion:!0,isCurrent:!0}).where(d(u(e.key,t),u(e.revision,i.revision),i.version?u(e.version,i.version):v(e.version))).run()};async#c(t,r,i){const{key:a,source:n,version:s,isDefaultVersion:c,...l}=t,h=(await this.#e.client.select({id:e.id}).from(e).where(d(u(e.key,a),u(e.source,n??"file"),s?u(e.version,s):v(e.version))).limit(1).run()).rows.length>0?this.#e.client.update(e).set(l).where(d(u(e.key,a),u(e.source,n??"file"),s?u(e.version,s):v(e.version))).run():this.#e.client.insert(e).values(t).onConflictDoUpdate({target:[e.key,e.source,e.revision,e.version],set:l}).run(),R=r?.map(y=>{const g=A({relation:y,sourceFile:t.sourceFile??"",fileHash:t.fileHash??"",sourceKey:t.key,sourceVersion:t.version??null,sourceRevision:t.revision??null,organizationId:this.#t,projectId:this.#r});return this.#e.client.insert(o).values(g).onConflictDoUpdate({target:[o.sourceKey,o.targetKey,o.sourceVersion,o.targetVersion,o.sourceRevision,o.targetRevision,o.sourceToTargetRelation],set:g}).run()})??[],p=this.#e.client.insert(E).values(F({rbacTeams:i,entityKey:t.key,organizationId:this.#t,projectId:this.#r})).onConflictDoUpdate({target:[E.entityKey],set:{rbacTeams:JSON.stringify(i)}});await w([h,...R,p],D,async y=>y)}async updateEntityScorecardsStatus(t,r){try{return(await this.#e.client.update(e).set({scorecardsStatus:r}).where(u(e.id,t)).returning()).length>0}catch(i){return f.error("Error updating entity scorecards status",i),!1}}async updateEntityScorecardsStatusIfCalculating(t,r){try{return(await this.#e.client.update(e).set({scorecardsStatus:r}).where(k`${e.id} = ${t} AND ${e.scorecardsStatus} = 'CALCULATING'`).returning()).length>0}catch(i){return f.error("Error updating entity scorecards status if calculating",i),!1}}}export{ie as CatalogEntitiesLocalWriteRepository};
1
+ import{and as m,eq as c,isNull as v,or as A,sql as N}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:y=[]}){try{const{relations:l=[],...f}=e,p=F(JSON.stringify(f)),d=e.version??O,g=await this.#i.shouldSkipRevisionCreation(e.key,d,p,o,n);if(await this.#o({entityKey:e.key,rbacTeams:y}),g)return{result:"skipped",entityKey:e.key};const h=await this.#i.shouldSetNewCurrentRevision({key:e.key,version:d,revision:a}),R=U({entity:{...e,revision:a,hash:p,isCurrent:h,isDefaultVersion:h,isDeleted:n,version:d},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:d};const S=this.#e.client.insert(r).values(R).onConflictDoUpdate({target:[r.key,r.source,r.revision,r.version],set:K}),T=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:d,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,T],w,async k=>k),{result:"created",entityKey:e.key,entityRevision:a,entityVersion:d}}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(A(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 y={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:y,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:y,...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,...y}=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(y).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:y}).run(),d=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,...d],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(N`${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};
@@ -11,11 +11,8 @@ export declare class CatalogEntitiesRemoteRepository extends BaseRepository {
11
11
  sync(): Promise<void>;
12
12
  static getInstance(options: RepositoryInstanceOptions): Promise<CatalogEntitiesRemoteRepository | null>;
13
13
  createEntity(entity: EntityDtoSchema): Promise<EntityReadModelSchema | null>;
14
- updateEntity(entity: EntityDtoSchema & {
15
- id?: string;
16
- createdAt?: string;
17
- }): Promise<EntityReadModelSchema | null>;
18
- deleteEntity(entityKey: string): Promise<string | null>;
14
+ updateEntity(incomingEntity: Partial<EntityDtoSchema>, entityToBeUpdated: EntityReadModelSchema): Promise<EntityReadModelSchema | null>;
15
+ deleteEntity(id: string): Promise<string | null>;
19
16
  createEntityRelations(relations: EntityRelationDtoSchema[]): Promise<(DatabaseEntityRelation | null)[]>;
20
17
  createEntityRelation(entityRelation: EntityRelationDtoSchema): Promise<DatabaseEntityRelation | null>;
21
18
  deleteEntityRelation(id: string): Promise<string | null>;
@@ -1 +1 @@
1
- import{eq as h,sql as f}from"drizzle-orm";import{convertFilterToWhereCondition as w}from"../../../../../providers/database/pagination/filter.js";import{promiseMapLimit as b}from"../../../../../utils/async/promise-map-limit.js";import{logger as n}from"../../../../../tools/notifiers/logger.js";import{entitiesTable as r}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-table.js";import{telemetryTraceStep as i}from"../../../../../telemetry/helpers/trace-step.js";import{BaseRepository as E}from"../../../../../providers/database/base-repository.js";import{DatabaseConnectionFactory as _}from"../../../../../providers/database/database-connection-factory.js";import{entitiesRelationsTable as a}from"../../../../../providers/database/databases/catalog-sqlite/schemas/entities-relations-table.js";import{createEntityDbRecord as g}from"../../mappers/create-entity-db-record.js";import{createEntityReadModel as m}from"../../mappers/create-entity-read-model.js";import{createEntityRelationDbRecordFromDto as C}from"../../mappers/create-entity-relation-db-record-from-dto.js";const D=15;class s extends E{static#t;#r=!1;get transactionsManager(){return this.databaseClient.transactionsManager}constructor(t){super(t)}async sync(){if(!this.#r&&this.isNonRemoteDatabaseMode()){n.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.#r=!0;return}return i("catalog_entities.remote_repository.sync",async()=>{await this.#e(),await this.databaseClient.sync()})}static async getInstance(t){return await i("catalog_entities.remote_repository.get_instance",async e=>{if(!s.#t)try{const o=await _.create("sqld-remote",t);if(!o)return n.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")),s.#t=null,null;s.#t=new s(o)}catch(o){return n.error("Error creating db connection for catalog entities remote repository",o),e?.error(o),s.#t=null,null}return s.#t})}async createEntity(t){return i("catalog_entities.remote_repository.create_entity",async()=>{await this.#e();try{n.info(`Adding entity ${t.key} to remote database`);const e=g({entity:t,organizationId:this.organizationId,projectId:this.projectId,source:"remote",sourceFile:null,fileHash:null}),{key:o,source:u,...d}=e,l=await this.databaseClient.client.insert(r).values(e).onConflictDoUpdate({target:[r.key,r.source,r.revision,r.version],set:d}).returning();return l.length?(t.relations&&await this.createEntityRelations(t.relations.map(c=>({...c,sourceKey:t.key,targetKey:c.key}))),m(l[0])):null}catch(e){throw n.error("Error adding entity",e),e}})}async updateEntity(t){return i("catalog_entities.remote_repository.update_entity",async()=>{await this.#e();try{n.info(`Updating entity ${t.key} in remote database`);const e=g({entity:t,organizationId:this.organizationId,projectId:this.projectId,source:"remote",sourceFile:null,fileHash:null}),{key:o,source:u,scorecardsStatus:d,...l}=e,c=await this.databaseClient.client.insert(r).values(e).onConflictDoUpdate({target:[r.key,r.source,r.revision,r.version],set:{...l,scorecardsStatus:f`CASE WHEN ${r.scorecardsStatus} = 'CALCULATING' THEN 'CANCELLED' ELSE 'OUTDATED' END`}}).returning();return c.length?m(c[0]):null}catch(e){return n.error("Error updating entity",e),null}})}async deleteEntity(t){return i("catalog_entities.remote_repository.delete_entity",async()=>{await this.#e();try{return await this.databaseClient.client.delete(r).where(h(r.key,t)),t}catch(e){return n.error("Error deleting entity",e),null}})}async createEntityRelations(t){return i("catalog_entities.remote_repository.create_entity_relations",async()=>(await this.#e(),await b(t,D,async e=>this.createEntityRelation(e))))}async createEntityRelation(t){return i("catalog_entities.remote_repository.create_entity_relation",async()=>{if(await this.#e(),!t)return null;try{const e=C(t,this.organizationId,this.projectId),{sourceKey:o,targetKey:u,sourceVersion:d,targetVersion:l,sourceRevision:c,targetRevision:I,...p}=e,y=await this.databaseClient.client.insert(a).values(e).onConflictDoUpdate({target:[a.sourceKey,a.targetKey,a.sourceVersion,a.targetVersion,a.sourceRevision,a.targetRevision,a.sourceToTargetRelation],set:p}).returning();return y.length?y[0]:null}catch(e){throw n.error("Error creating entity relation",e),e}})}async deleteEntityRelation(t){return i("catalog_entities.remote_repository.delete_entity_relation",async()=>{await this.#e();try{return await this.databaseClient.client.delete(a).where(h(a.id,t)),t}catch(e){return n.error("Error deleting entity relation",e),null}})}async deleteEntitiesRelations(t){return i("catalog_entities.remote_repository.delete_entities_relations",async()=>{await this.#e();try{const e=w(t);return e?(await this.databaseClient.client.delete(a).where(e),!0):!1}catch(e){return n.error("Error deleting entities relations",e),!1}})}#e(){return i("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{s as CatalogEntitiesRemoteRepository};
1
+ import{and as f,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";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(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:g,...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{const e=await this.databaseClient.client.select().from(i).where(n(i.id,t)).get();return e?(await this.#o(e),await this.databaseClient.client.delete(i).where(n(i.id,t)),e&&this.#t.ensureDefaultAndCurrentRevisionForKey(e.key),t):null}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:g,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(f(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(f(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(f(n(r.sourceKey,e),n(r.sourceVersion,s)),f(n(r.targetKey,e),n(r.targetVersion,s))));return}await this.databaseClient.client.delete(r).where(w(f(n(r.sourceKey,e),n(r.sourceVersion,s),n(r.sourceRevision,y)),f(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};
@@ -0,0 +1,34 @@
1
+ import type { SQL } from 'drizzle-orm';
2
+ /**
3
+ * Creates merged entity fields for SELECT when joining remote and local entities.
4
+ * JSON fields (metadata, git, contact, links, tags) are merged using json_patch.
5
+ * Simple fields prefer the newer value based on updated_at.
6
+ * @param remoteAlias - Alias for remote table (default: 'r')
7
+ * @param localAlias - Alias for local table (default: 'l')
8
+ */
9
+ export declare function createMergedEntityFieldsForSelect(remoteAlias?: string, localAlias?: string): {
10
+ id: SQL<unknown>;
11
+ organizationId: SQL<unknown>;
12
+ projectId: SQL<unknown>;
13
+ key: SQL<unknown>;
14
+ type: SQL<unknown>;
15
+ title: SQL<unknown>;
16
+ summary: SQL<unknown>;
17
+ tags: SQL<unknown>;
18
+ metadata: SQL<unknown>;
19
+ git: SQL<unknown>;
20
+ contact: SQL<unknown>;
21
+ links: SQL<unknown>;
22
+ createdAt: SQL<unknown>;
23
+ updatedAt: SQL<unknown>;
24
+ source: SQL<unknown>;
25
+ sourceFile: SQL<unknown>;
26
+ fileHash: SQL<unknown>;
27
+ version: SQL<unknown>;
28
+ revision: SQL<unknown>;
29
+ hash: SQL<unknown>;
30
+ isCurrent: SQL<unknown>;
31
+ isDeleted: SQL<unknown>;
32
+ scorecardsStatus: SQL<unknown>;
33
+ };
34
+ //# sourceMappingURL=create-merged-entity-fields-for-select.d.ts.map
@@ -0,0 +1,13 @@
1
+ import{sql as u}from"drizzle-orm";function p(t="r",d="l"){return{id:$("id","id",t,d),organizationId:$("organization_id","organization_id",t,d),projectId:$("project_id","project_id",t,d),key:u.raw(`${t}.key AS key`),type:$("type","type",t,d),title:$("title","title",t,d),summary:$("summary","summary",t,d),tags:_("tags","tags",t,d),metadata:_("metadata","metadata",t,d),git:_("git","git",t,d),contact:_("contact","contact",t,d),links:_("links","links",t,d),createdAt:u.raw(`MIN(${t}.created_at, ${d}.created_at) AS created_at`),updatedAt:u.raw(`MAX(${t}.updated_at, ${d}.updated_at) AS updated_at`),source:$("source","source",t,d),sourceFile:$("source_file","source_file",t,d),fileHash:$("file_hash","file_hash",t,d),version:u.raw(`${t}.version AS version`),revision:u.raw(`${t}.revision AS revision`),hash:$("hash","hash",t,d),isCurrent:$("is_current","is_current",t,d),isDeleted:$("is_deleted","is_deleted",t,d),scorecardsStatus:$("scorecards_status","scorecards_status",t,d)}}function _(t,d,n="r",r="l"){return u.raw(`
2
+ CASE
3
+ WHEN ${n}.${t} IS NULL THEN ${r}.${t}
4
+ WHEN ${r}.${t} IS NULL THEN ${n}.${t}
5
+ WHEN ${n}.updated_at >= ${r}.updated_at THEN json_patch(${r}.${t}, ${n}.${t})
6
+ ELSE json_patch(${n}.${t}, ${r}.${t})
7
+ END AS ${d}
8
+ `)}function $(t,d,n="r",r="l"){return u.raw(`
9
+ CASE
10
+ WHEN ${n}.updated_at >= ${r}.updated_at THEN COALESCE(${n}.${t}, ${r}.${t})
11
+ ELSE COALESCE(${r}.${t}, ${n}.${t})
12
+ END AS ${d}
13
+ `)}export{p as createMergedEntityFieldsForSelect};
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Represents a revision with flags that can be normalized.
3
+ */
4
+ export type RevisionWithFlags = {
5
+ version: string | null;
6
+ revision: string;
7
+ isCurrent: boolean;
8
+ isDefaultVersion: boolean;
9
+ };
10
+ /**
11
+ * Normalizes revision flags to ensure only one revision is marked as current/default.
12
+ *
13
+ * When multiple revisions are flagged (isCurrent or isDefaultVersion), the one with
14
+ * the highest semantic version wins. If versions are equal, the highest revision string wins.
15
+ * All other flagged revisions have their flags reset to false.
16
+ *
17
+ * Note: In this system, isCurrent and isDefaultVersion are coupled - if a revision
18
+ * is current, it is also the default version.
19
+ *
20
+ * @param revisions - Array of revisions to normalize (mutated in place)
21
+ */
22
+ export declare function normalizeRevisionFlags<T extends RevisionWithFlags>(revisions: T[]): void;
23
+ //# sourceMappingURL=normalize-revision-flags.d.ts.map
@@ -0,0 +1 @@
1
+ import{VERSION_NOT_SPECIFIED as t}from"@redocly/theme/core/constants";import{compareVersionsDescending as f}from"../../../utils/version-compare.js";function s(n){return!n||n===t}function c(n,i){const e=s(n.version),r=s(i.version);if(e&&!r)return 1;if(!e&&r)return-1;const o=f(n.version??"",i.version??"");return o!==0?o:(i.revision??"").localeCompare(n.revision??"")}function a(n){const i=n.filter(e=>e.isCurrent||e.isDefaultVersion);if(!(i.length<=1)){i.sort(c);for(let e=1;e<i.length;e++)i[e].isCurrent=!1,i[e].isDefaultVersion=!1}}export{a as normalizeRevisionFlags};
@@ -0,0 +1,78 @@
1
+ import type { SQL } from 'drizzle-orm';
2
+ /**
3
+ * ============================================================================
4
+ * SEMANTIC VERSION SORTING IN SQLITE
5
+ * ============================================================================
6
+ *
7
+ * SQLite lacks native semantic version comparison, so we convert versions
8
+ * into sortable strings. The key insight is that string comparison uses
9
+ * ASCII/Unicode ordering, so we can control sort order through prefixes
10
+ * and zero-padding.
11
+ *
12
+ * ## Sort Strategy (for descending order)
13
+ *
14
+ * We transform versions into strings that sort correctly when compared lexicographically:
15
+ *
16
+ * | Version Type | Transformation | Example Result |
17
+ * |----------------------|-------------------------------------|-------------------------|
18
+ * | not_specified_version| Prefix with '!' | '!not_specified' |
19
+ * | null/empty | Padded zeros | '0000000000.0000...' |
20
+ * | Numeric (1.2.3) | Zero-padded to 10 digits per part | '0000000001.0000000002.0000000003' |
21
+ * | Text (latest) | Prefix with 'Z' | 'ZZZZZZZZZZ.latest' |
22
+ *
23
+ * ASCII ordering ensures: '!' < '0' < 'Z', giving us:
24
+ * latest > 10.0.0 > 3.1 > 1 > null > not_specified_version
25
+ *
26
+ * ## Why Zero-Padding?
27
+ *
28
+ * Without padding, string comparison fails for multi-digit numbers:
29
+ * '9' > '10' (wrong!) vs '0000000009' < '0000000010' (correct!)
30
+ *
31
+ * We use 10 digits to support versions up to 9,999,999,999 per component.
32
+ */
33
+ /**
34
+ * Builds SQL expression for semantic version sorting in SQLite.
35
+ * Handles versions like: 1, 1.0, 1.0.0, 10.2.3, latest, etc.
36
+ *
37
+ * @param versionColumn - The column name or expression containing the version
38
+ * @returns SQL expression that can be used in ORDER BY for descending version sort
39
+ *
40
+ * @example
41
+ * ```sql
42
+ * ORDER BY ${buildSemanticVersionSortExpr('version')} DESC
43
+ * -- Sorts: latest, 10.0.0, 3.1, 3, 2.0.1, 1, not_specified_version
44
+ * ```
45
+ */
46
+ export declare function buildSemanticVersionSortExpr(versionColumn: string): SQL;
47
+ /**
48
+ * ============================================================================
49
+ * VERSION COMPARISON FILTER
50
+ * ============================================================================
51
+ */
52
+ /**
53
+ * Builds a SQL condition that checks no higher semantic version exists
54
+ * for the same key in either local or remote database.
55
+ *
56
+ * This is used to find the "current" version of an entity when multiple
57
+ * versions exist across local and remote databases.
58
+ *
59
+ * ## Logic
60
+ *
61
+ * Returns TRUE if there is NO other entity with the same key that has:
62
+ * 1. A higher semantic version, OR
63
+ * 2. The same version but a higher revision number
64
+ *
65
+ * ## Example
66
+ *
67
+ * Given entities with key='my-api':
68
+ * - Local: version='1.0.0', revision=1
69
+ * - Remote: version='1.0.0', revision=2 ← This one wins (same version, higher revision)
70
+ * - Remote: version='2.0.0', revision=1 ← This one wins (higher version)
71
+ *
72
+ * @param keyExpr - SQL expression for the entity's key (e.g., 'entities.key')
73
+ * @param versionExpr - SQL expression for the entity's version (e.g., 'entities.version')
74
+ * @param revisionExpr - SQL expression for the entity's revision (e.g., 'entities.revision')
75
+ * @returns SQL expression that evaluates to TRUE if this is the highest version
76
+ */
77
+ export declare function buildNoHigherVersionExistsFilter(keyExpr: string, versionExpr: string, revisionExpr: string): SQL;
78
+ //# sourceMappingURL=semantic-version-sort.d.ts.map
@@ -0,0 +1,34 @@
1
+ import{sql as o}from"drizzle-orm";const $="not_specified_version";function h(e){return o.raw(`
2
+ CASE
3
+ ${s(e)}
4
+ ${S(e)}
5
+ ${a(e)}
6
+ ${E(e)}
7
+ END
8
+ `)}function s(e){return`WHEN ${e} = '${$}' THEN '!not_specified'`}function S(e){return`WHEN ${e} IS NULL OR ${e} = '' THEN '0000000000.0000000000.0000000000'`}function a(e){return`WHEN ${e} GLOB '*[^0-9.]*' THEN 'ZZZZZZZZZZ.' || ${e}`}function E(e){return`ELSE ${c(e)}`}function c(e){const r=u(e),i=N(e),t=T(e);return`PRINTF('%010d.%010d.%010d', ${r}, ${i}, ${t})`}function u(e){const r=`${e} || '.0.0'`;return`CAST(COALESCE(NULLIF(SUBSTR(${r}, 1, INSTR(${r}, '.') - 1), ''), '0') AS INTEGER)`}function N(e){const r=`${e} || '.0.0'`,i=`SUBSTR(${r}, INSTR(${r}, '.') + 1) || '.0'`;return`CAST(COALESCE(NULLIF(SUBSTR(${i}, 1, INSTR(${i}, '.') - 1), ''), '0') AS INTEGER)`}function T(e){const r=`${e} || '.0.0'`,i=`SUBSTR(${r}, INSTR(${r}, '.') + 1) || '.0'`,t=`SUBSTR(${i}, INSTR(${i}, '.') + 1) || '.0'`;return`CAST(COALESCE(NULLIF(SUBSTR(${t}, 1, INSTR(${t}, '.') - 1), ''), '0') AS INTEGER)`}function d(e){return`
9
+ CASE
10
+ ${s(e)}
11
+ ${S(e)}
12
+ ${a(e)}
13
+ ${E(e)}
14
+ END
15
+ `}function l(e,r,i){const t=d("higher_version.version"),n=d(r);return o.raw(`
16
+ NOT EXISTS (
17
+ SELECT 1 FROM (
18
+ -- Combine all current, non-deleted entities from both databases
19
+ SELECT key, version, revision FROM remote.entities WHERE is_current = 1 AND is_deleted = 0
20
+ UNION ALL
21
+ SELECT key, version, revision FROM entities WHERE is_current = 1 AND is_deleted = 0
22
+ ) higher_version
23
+ WHERE higher_version.key = ${e}
24
+ AND (
25
+ -- Case 1: Another entity has a strictly higher version
26
+ (${t}) > (${n})
27
+ OR (
28
+ -- Case 2: Same version, but another entity has a higher revision
29
+ (${t}) = (${n})
30
+ AND higher_version.revision > ${i}
31
+ )
32
+ )
33
+ )
34
+ `)}export{l as buildNoHigherVersionExistsFilter,h as buildSemanticVersionSortExpr};
@@ -1,6 +1,8 @@
1
1
  import { type EntityRelationFileSchema, type EntityBaseFileSchema } from '@redocly/config';
2
2
  import type { EntitiesCatalogConfig } from '@redocly/config';
3
+ import type { EntityDtoSchema } from '../schemas/dto-schemas.js';
3
4
  export declare function validateEntityRelation(relation: unknown): asserts relation is EntityRelationFileSchema;
4
5
  export declare function parseAndValidateEntity(entity: unknown, catalogConfig: EntitiesCatalogConfig): EntityBaseFileSchema;
5
- export declare function parseAndValidateEntities(entities: unknown[], catalogConfig: EntitiesCatalogConfig): EntityBaseFileSchema[];
6
+ export declare function parseAndValidateEntityUpdate(entity: unknown, catalogConfig: EntitiesCatalogConfig, entityType: string): Partial<EntityDtoSchema>;
7
+ export declare function parseAndValidateEntities(entities: unknown[], catalogConfig: EntitiesCatalogConfig): EntityDtoSchema[];
6
8
  //# sourceMappingURL=validate-entity.d.ts.map
@@ -1 +1 @@
1
- import{entityFileSchema as r,entityRelationFileSchema as d,entityBaseProperties as l}from"@redocly/config";import{createValidator as n}from"../utils/ajv-validator.js";const s=n(d,{errorPrefix:"Entity relation validation failed:",dataVar:"relation"});function p(t){s(t)}function m(t,e){const i=o(e);return n(i,{errorPrefix:"Entity validation failed:",dataVar:"entity"})(t)}function f(t,e){const i={type:"array",items:o(e)};return n(i,{errorPrefix:"Entity validation failed:",dataVar:"entity"})(t)}function o(t){const e=Object.entries(t.entityTypes??{}).map(([i,a])=>({type:"object",properties:{...l,type:{const:i},metadata:{additionalProperties:!0,...a.metadataSchema}},required:["key","title","type"],additionalProperties:!1}));return{...r,oneOf:[...r.oneOf,...e]}}export{f as parseAndValidateEntities,m as parseAndValidateEntity,p as validateEntityRelation};
1
+ import{entityFileSchema as o,entityRelationFileSchema as y,entityBaseProperties as s}from"@redocly/config";import{createValidator as a}from"../utils/ajv-validator.js";const d=a(y,{errorPrefix:"Entity relation validation failed:",dataVar:"relation"});function f(e){d(e)}function u(e,i){const t=p(i);return a(t,{errorPrefix:"Entity validation failed:",dataVar:"entity"})(e)}function E(e,i,t){const r=c(i,t);return a(r,{errorPrefix:"Entity validation failed:",dataVar:"entity"})(e)}function V(e,i){const t={type:"array",items:p(i)};return a(t,{errorPrefix:"Entity validation failed:",dataVar:"entity"})(e)}function p(e){const i=Object.entries(e.entityTypes??{}).map(([t,r])=>({type:"object",properties:{...s,type:{const:t},metadata:{additionalProperties:!0,...r.metadataSchema},revision:{type:"string"}},required:["key","title","type"],additionalProperties:!1}));return{type:"object",discriminator:{propertyName:"type"},oneOf:[...o.oneOf.map(t=>({...t,properties:{...t.properties,revision:{type:"string"}}})),...i]}}function c(e,i){const t=o.oneOf.find(r=>r.properties.type.const===i);if(!t){const r=Object.keys(e.entityTypes??{}).find(n=>n===i);if(!r)throw new Error(`Entity type: ${i} not found`);return{type:"object",properties:{...s,type:{const:r},metadata:{additionalProperties:!0,...e.entityTypes?.[r].metadataSchema},revision:{type:"string"}},additionalProperties:!1}}return{properties:{...t.properties,revision:{type:"string"}},additionalProperties:!1}}export{V as parseAndValidateEntities,u as parseAndValidateEntity,E as parseAndValidateEntityUpdate,f as validateEntityRelation};
@@ -1 +1 @@
1
- import{FileType as u}from"../../persistence/file-hashes/types.js";import{deepEqual as O}from"../../../utils/object/deep-equal.js";import{telemetryTraceStep as P}from"../../../cli/telemetry/helpers/trace-step.js";import{catalogDataCollector as I}from"./utils/catalog-data-collector.js";import{CATALOG_BASE_SLUG as m,CATALOG_FILTERS_CACHE_NAMESPACE as _,ENTITIES_MAP_GLOBAL_DATA_KEY as b}from"../../constants/plugins/catalog-entities.js";import{CacheService as v}from"../../persistence/cache/services/cache-service.js";import{getTemplatePath as f}from"./utils/get-template-path.js";import{getCompleteCatalogConfig as C}from"./get-complete-catalog-config.js";import{AsyncApiEntitiesExtractor as w}from"./extensions/extractors/api-description/asyncapi-entities-extractor.js";import{GraphqlEntitiesExtractor as N}from"./extensions/extractors/api-description/graphql-entities-extractor.js";import{FileHashesService as R}from"../../persistence/file-hashes/services/file-hashes-service.js";import{CatalogEntitiesService as L}from"./database/catalog-entities-service.js";import{ArazzoEntitiesExtractor as G}from"./extensions/extractors/api-description/arazzo-entities-extractor.js";import{FsEntitiesExtractor as x}from"./extensions/extractors/fs-entities-extractor.js";import{HashManager as F}from"./utils/hash-manager.js";import{OpenApiEntitiesExtractor as H}from"./extensions/extractors/api-description/openapi-entities-extractor.js";const B="catalog-entity-template",M="catalog-entity";let d=!0,A;async function Y(){return{id:"CatalogEntities",requiredEntitlements:["catalog"],async processContent(t,e){const i=await e.getConfig(),r=C(i.entitiesCatalog);if(!r.show)return;const{logger:o}=e,n=t.registerServerPropsGetter(M,f("../get-server-props.js")),p=t.createTemplate(B,f("../template/index.js"));t.addRoute({duplicateInAllLocales:!0,slug:m,fsPath:"",templateId:p,excludeFromSidebar:!0,hasClientRoutes:!0,serverPropsGetterIds:[n],getNavText:()=>Promise.resolve("Catalog"),getStaticData:async()=>({props:{catalogConfig:r}})});const[g]=Object.entries(r.catalogs??{}).find(([E,s])=>!s?.hide)||[];g&&t.addRedirect(m,{type:302,to:`${m}/${g}`}),o.info("Catalog Entities plugin finished")},async afterRoutesCreated(t,e){await P("build.plugin.catalog_entities",async i=>{const r=await e.getConfig(),o=C(r.entitiesCatalog);if(i?.setAttribute("config",JSON.stringify(o)),!o.show)return;const{logger:n}=e,p=process.env.NODE_ENV==="development"||process.env.REDOCLY_LOCAL_DEV==="true",g=d&&p,E=!O(A,r.rbac);A=r.rbac;const s=g&&E,a=await L.getInstance({baseDbDir:t.serverOutDir,removeExisting:!0,runOnlyLocalDatabase:!0,runWithPragmaWalWriteOptimization:!0}),T=await R.getInstance({baseDbDir:t.serverOutDir}),l=new F(T),y=[new x({fileHashManager:l,context:e,catalogEntitiesService:a,catalogConfig:o,shouldCalculateEntities:s}),new H({actions:t,context:e,catalogEntitiesService:a,fileHashManager:l,fileType:u.OPENAPI_DESCRIPTION,shouldCalculateEntities:s}),new w({actions:t,context:e,catalogEntitiesService:a,fileHashManager:l,fileType:u.ASYNCAPI_DESCRIPTION,shouldCalculateEntities:s}),new N({actions:t,context:e,catalogEntitiesService:a,fileHashManager:l,fileType:u.GRAPHQL_DESCRIPTION,shouldCalculateEntities:s}),new G({actions:t,context:e,catalogEntitiesService:a,fileHashManager:l,fileType:u.ARAZZO_DESCRIPTION,shouldCalculateEntities:s})];n.info("Starting entities extractors...");const h=n.startTiming();await a.transaction(async()=>{await Promise.all(y.map(async D=>D.extract()))});const S=a.getEntitySources();t.setGlobalData({[b]:S}),await(await v.getInstance({baseDbDir:t.serverOutDir})).deleteByNamespace(_),n.infoTime(h,"Entities extractors finished");const c=await I.getCatalogEntitiesData(a);i?.setAttribute("totalEntities",c.totalEntitiesCount),i?.setAttribute("entitiesCountByType",JSON.stringify(c.countOfEntitiesByType)),i?.setAttribute("totalFilesSkippedByHash",c.totalFilesSkippedByHash),i?.setAttribute("totalProcessedFiles",c.totalProcessedFiles),i?.setAttribute("extractors",c.extractors),d=!1})}}}var rt=Y;export{Y as catalogEntitiesPlugin,rt as default};
1
+ import{FileType as u}from"../../persistence/file-hashes/types.js";import{deepEqual as O}from"../../../utils/object/deep-equal.js";import{telemetryTraceStep as P}from"../../../cli/telemetry/helpers/trace-step.js";import{catalogDataCollector as I}from"./utils/catalog-data-collector.js";import{CATALOG_BASE_SLUG as m,CATALOG_FILTERS_CACHE_NAMESPACE as _,ENTITIES_MAP_GLOBAL_DATA_KEY as b}from"../../constants/plugins/catalog-entities.js";import{CacheService as v}from"../../persistence/cache/services/cache-service.js";import{getTemplatePath as f}from"./utils/get-template-path.js";import{getCompleteCatalogConfig as C}from"./get-complete-catalog-config.js";import{AsyncApiEntitiesExtractor as w}from"./extensions/extractors/api-description/asyncapi-entities-extractor.js";import{GraphqlEntitiesExtractor as N}from"./extensions/extractors/api-description/graphql-entities-extractor.js";import{FileHashesService as R}from"../../persistence/file-hashes/services/file-hashes-service.js";import{CatalogEntitiesService as L}from"./database/catalog-entities-service.js";import{ArazzoEntitiesExtractor as G}from"./extensions/extractors/api-description/arazzo-entities-extractor.js";import{FsEntitiesExtractor as x}from"./extensions/extractors/fs-entities-extractor.js";import{HashManager as F}from"./utils/hash-manager.js";import{OpenApiEntitiesExtractor as H}from"./extensions/extractors/api-description/openapi-entities-extractor.js";const B="catalog-entity-template",M="catalog-entity";let d=!0,A;async function Y(){return{id:"CatalogEntities",requiredEntitlements:["catalog"],async processContent(t,e){const i=await e.getConfig(),r=C(i.entitiesCatalog);if(!r.show)return;const{logger:o}=e,n=t.registerServerPropsGetter(M,f("../get-server-props.js")),p=t.createTemplate(B,f("../template/index.js"));t.addRoute({duplicateInAllLocales:!0,slug:m,fsPath:"",templateId:p,excludeFromSidebar:!0,hasClientRoutes:!0,serverPropsGetterIds:[n],getNavText:()=>Promise.resolve("Catalog"),getStaticData:async()=>({props:{catalogConfig:r}})});const[l]=Object.entries(r.catalogs??{}).find(([E,s])=>!s?.hide)||[];l&&t.addRedirect(m,{type:302,to:`${m}/${l}`}),o.info("Catalog Entities plugin finished")},async afterRoutesCreated(t,e){await P("build.plugin.catalog_entities",async i=>{const r=await e.getConfig(),o=C(r.entitiesCatalog);if(i?.setAttribute("config",JSON.stringify(o)),!o.show)return;const{logger:n}=e,p=process.env.NODE_ENV==="development"||process.env.REDOCLY_LOCAL_DEV==="true",l=d&&p,E=!O(A,r.rbac);A=r.rbac;const s=l||E,a=await L.getInstance({baseDbDir:t.serverOutDir,removeExisting:l,runOnlyLocalDatabase:!0,runWithPragmaWalWriteOptimization:!0}),T=await R.getInstance({baseDbDir:t.serverOutDir}),c=new F(T),y=[new x({fileHashManager:c,context:e,catalogEntitiesService:a,catalogConfig:o,shouldCalculateEntities:s}),new H({actions:t,context:e,catalogEntitiesService:a,fileHashManager:c,fileType:u.OPENAPI_DESCRIPTION,shouldCalculateEntities:s}),new w({actions:t,context:e,catalogEntitiesService:a,fileHashManager:c,fileType:u.ASYNCAPI_DESCRIPTION,shouldCalculateEntities:s}),new N({actions:t,context:e,catalogEntitiesService:a,fileHashManager:c,fileType:u.GRAPHQL_DESCRIPTION,shouldCalculateEntities:s}),new G({actions:t,context:e,catalogEntitiesService:a,fileHashManager:c,fileType:u.ARAZZO_DESCRIPTION,shouldCalculateEntities:s})];n.info("Starting entities extractors...");const h=n.startTiming();await a.transaction(async()=>{await Promise.all(y.map(async D=>D.extract()))});const S=a.getEntitySources();t.setGlobalData({[b]:S}),await(await v.getInstance({baseDbDir:t.serverOutDir})).deleteByNamespace(_),n.infoTime(h,"Entities extractors finished");const g=await I.getCatalogEntitiesData(a);i?.setAttribute("totalEntities",g.totalEntitiesCount),i?.setAttribute("entitiesCountByType",JSON.stringify(g.countOfEntitiesByType)),i?.setAttribute("totalFilesSkippedByHash",g.totalFilesSkippedByHash),i?.setAttribute("totalProcessedFiles",g.totalProcessedFiles),i?.setAttribute("extractors",g.extractors),d=!1})}}}var rt=Y;export{Y as catalogEntitiesPlugin,rt as default};
@@ -100,6 +100,8 @@ export declare const entitiesRelationsDtoSchema: {
100
100
  };
101
101
  export type EntityRelationDtoSchema = FromSchema<typeof entityRelationDtoSchema>;
102
102
  export type EntitiesRelationsDtoSchema = FromSchema<typeof entitiesRelationsDtoSchema>;
103
- export type EntityDtoSchema = EntityBaseFileSchema;
103
+ export type EntityDtoSchema = EntityBaseFileSchema & {
104
+ revision?: string;
105
+ };
104
106
  export type EntityAttributesDtoSchema = FromSchema<typeof entityAttributesDtoSchema>;
105
107
  //# sourceMappingURL=dto-schemas.d.ts.map
@@ -1 +1 @@
1
- import d from"@redocly/ajv";const o=new d({coerceTypes:!0,removeAdditional:!0,discriminator:!0,allErrors:!0});o.addFormat("uri",{type:"string",validate:e=>{try{return new URL(e),!0}catch{return!1}}}),o.addFormat("email",{type:"string",validate:e=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)});function f(e,t){const{errorPrefix:n,dataVar:a="data"}=t??{},r=o.compile(e);return function(i){if(!r(i)){const c=r.errors?.length?r.errors.map(s=>{const u=s.instancePath.replaceAll("/",".");return`'${a}${u}' ${s.message}`}).join(", "):"unknown error",l=n?`${n} `:"";throw new Error(`${l}${c}`)}return i}}function h(e,t){const n=o.compile(e),a=n(t);return{success:a,data:a?t:void 0,error:a?void 0:n.errors?.map(r=>`${r.instancePath} ${r.message}`).join(", ")}}export{f as createValidator,h as validateWithResult};
1
+ import u from"@redocly/ajv";const o=new u({coerceTypes:!0,removeAdditional:!0,discriminator:!0,allErrors:!0});o.addKeyword({keyword:"nodeTypeName",schemaType:"string"}),o.addFormat("uri",{type:"string",validate:e=>{try{return new URL(e),!0}catch{return!1}}}),o.addFormat("email",{type:"string",validate:e=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)});function f(e,t){const{errorPrefix:a,dataVar:n="data"}=t??{},r=o.compile(e);return function(i){if(!r(i)){const c=r.errors?.length?r.errors.map(s=>{const l=s.instancePath.replaceAll("/",".");return`'${n}${l}' ${s.message}`}).join(", "):"unknown error",d=a?`${a} `:"";throw new Error(`${d}${c}`)}return i}}function h(e,t){const a=o.compile(e),n=a(t);return{success:n,data:n?t:void 0,error:n?void 0:a.errors?.map(r=>`${r.instancePath} ${r.message}`).join(", ")}}export{f as createValidator,h as validateWithResult};
@@ -1 +1 @@
1
- import a from"node:path";import{createConfig as g}from"@redocly/openapi-core";import{ruleTypes as l}from"@redocly/config";import{deepMerge as u}from"../../../../utils/object/deep-merge.js";import{CONFIG_FILE_NAME as m}from"../../../../constants/common.js";import{getScorecardConfig as p}from"../get-scorecard-config.js";async function E(t,n){const o=await n.getConfig(),e=p(o),r=e.levels??[],i=a.join(n.fs.cwd,m),s=await c(r,o.plugins,i),f=await d(e.targets,r,o.plugins,i);return{levelsConfig:r,configs:s,targets:f}}async function c(t,n=[],o){const e={};for(const r of t)e[r.name]=await g({...r,plugins:n},{configPath:o});return e}async function d(t,n,o=[],e){return t?Promise.all(t?.filter(r=>!!r.rules).map(async r=>{const i=n.map(s=>({...s,...C(s,r.rules)}));return{...r,configs:await c(i,o,e)}})||[]):[]}function C(t,n){return l.reduce((o,e)=>(o[e]=u(t[e]??{},n??{}),o),{})}export{E as scorecardConfigLoader};
1
+ import l from"node:path";import{createConfig as m,loadIgnoreConfig as u}from"@redocly/openapi-core";import{ruleTypes as p}from"@redocly/config";import{ExternalResolver as C}from"../../../fs/utils/external-ref-resolver.js";import{deepMerge as d}from"../../../../utils/object/deep-merge.js";import{CONFIG_FILE_NAME as v}from"../../../../constants/common.js";import{getScorecardConfig as w}from"../get-scorecard-config.js";async function N(i,r){const e=await r.getConfig(),n=w(e),t=n.levels??[],o=l.join(r.fs.cwd,v),f=new C(r.fs),s=await u(o,f),c=await a(t,e.plugins,o,s),g=await y(n.targets,t,e.plugins,o,s);return{levelsConfig:t,configs:c,targets:g}}async function a(i,r=[],e,n){const t={};for(const o of i)t[o.name]=await m({...o,plugins:r},{configPath:e,ignore:n});return t}async function y(i,r,e=[],n,t){return i?Promise.all(i?.filter(o=>!!o.rules).map(async o=>{const f=r.map(s=>({...s,...L(s,o.rules)}));return{...o,configs:await a(f,e,n,t)}})||[]):[]}function L(i,r){return p.reduce((e,n)=>(e[n]=d(i[n]??{},r??{}),e),{})}export{N as scorecardConfigLoader};