@x12i/catalox 5.2.0 → 5.9.7

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 (981) hide show
  1. package/CHANGELOG.md +147 -0
  2. package/README.md +90 -2
  3. package/package.json +38 -57
  4. package/packages/engine/dist/adapters/api/api-adapter.d.ts +22 -0
  5. package/packages/engine/dist/adapters/api/api-adapter.d.ts.map +1 -0
  6. package/packages/engine/dist/adapters/api/api-adapter.js +64 -0
  7. package/packages/engine/dist/adapters/api/api-adapter.js.map +1 -0
  8. package/packages/engine/dist/adapters/api/index.d.ts.map +1 -0
  9. package/packages/engine/dist/adapters/api/index.js.map +1 -0
  10. package/packages/engine/dist/adapters/mongo/index.d.ts.map +1 -0
  11. package/packages/engine/dist/adapters/mongo/index.js.map +1 -0
  12. package/packages/engine/dist/adapters/mongo/mongo-adapter.d.ts +21 -0
  13. package/packages/engine/dist/adapters/mongo/mongo-adapter.d.ts.map +1 -0
  14. package/packages/engine/dist/adapters/mongo/mongo-adapter.js +61 -0
  15. package/packages/engine/dist/adapters/mongo/mongo-adapter.js.map +1 -0
  16. package/packages/engine/dist/adapters/mongo/resolve-db.d.ts +4 -0
  17. package/packages/engine/dist/adapters/mongo/resolve-db.d.ts.map +1 -0
  18. package/packages/engine/dist/adapters/mongo/resolve-db.js.map +1 -0
  19. package/packages/engine/dist/bindings/index.d.ts.map +1 -0
  20. package/packages/engine/dist/bindings/index.js.map +1 -0
  21. package/packages/engine/dist/catalog-content/derived-items.d.ts +19 -0
  22. package/packages/engine/dist/catalog-content/derived-items.d.ts.map +1 -0
  23. package/packages/engine/dist/catalog-content/derived-items.js +59 -0
  24. package/packages/engine/dist/catalog-content/derived-items.js.map +1 -0
  25. package/packages/engine/dist/catalog-content/field-codec.d.ts +13 -0
  26. package/packages/engine/dist/catalog-content/field-codec.d.ts.map +1 -0
  27. package/packages/engine/dist/catalog-content/field-codec.js +24 -0
  28. package/packages/engine/dist/catalog-content/field-codec.js.map +1 -0
  29. package/packages/engine/dist/catalog-content/index.d.ts +4 -0
  30. package/packages/engine/dist/catalog-content/index.d.ts.map +1 -0
  31. package/packages/engine/dist/catalog-content/index.js +4 -0
  32. package/packages/engine/dist/catalog-content/index.js.map +1 -0
  33. package/packages/engine/dist/catalog-content/template-tokens.d.ts +10 -0
  34. package/packages/engine/dist/catalog-content/template-tokens.d.ts.map +1 -0
  35. package/packages/engine/dist/catalog-content/template-tokens.js +50 -0
  36. package/packages/engine/dist/catalog-content/template-tokens.js.map +1 -0
  37. package/packages/engine/dist/catalox/authorization.d.ts +20 -0
  38. package/packages/engine/dist/catalox/authorization.d.ts.map +1 -0
  39. package/packages/engine/dist/catalox/authorization.js +55 -0
  40. package/packages/engine/dist/catalox/authorization.js.map +1 -0
  41. package/packages/engine/dist/catalox/backup-data.d.ts +70 -0
  42. package/packages/engine/dist/catalox/backup-data.d.ts.map +1 -0
  43. package/packages/engine/dist/catalox/backup-data.js.map +1 -0
  44. package/packages/engine/dist/catalox/catalog-discovery.d.ts +9 -0
  45. package/packages/engine/dist/catalox/catalog-discovery.d.ts.map +1 -0
  46. package/packages/engine/dist/catalox/catalog-discovery.js.map +1 -0
  47. package/packages/engine/dist/catalox/catalog-lifecycle.d.ts +29 -0
  48. package/packages/engine/dist/catalox/catalog-lifecycle.d.ts.map +1 -0
  49. package/packages/engine/dist/catalox/catalog-lifecycle.js.map +1 -0
  50. package/packages/engine/dist/catalox/catalog-snapshot-export.d.ts +46 -0
  51. package/packages/engine/dist/catalox/catalog-snapshot-export.d.ts.map +1 -0
  52. package/packages/engine/dist/catalox/catalog-snapshot-export.js +103 -0
  53. package/packages/engine/dist/catalox/catalog-snapshot-export.js.map +1 -0
  54. package/packages/engine/dist/catalox/catalox-bound.d.ts +199 -0
  55. package/packages/engine/dist/catalox/catalox-bound.d.ts.map +1 -0
  56. package/packages/engine/dist/catalox/catalox-bound.js +256 -0
  57. package/packages/engine/dist/catalox/catalox-bound.js.map +1 -0
  58. package/packages/engine/dist/catalox/catalox-gcs-backup-export-manifest.d.ts +13 -0
  59. package/packages/engine/dist/catalox/catalox-gcs-backup-export-manifest.d.ts.map +1 -0
  60. package/packages/engine/dist/catalox/catalox-gcs-backup-export-manifest.js.map +1 -0
  61. package/packages/engine/dist/catalox/catalox.d.ts +382 -0
  62. package/packages/engine/dist/catalox/catalox.d.ts.map +1 -0
  63. package/packages/engine/dist/catalox/catalox.js +2892 -0
  64. package/packages/engine/dist/catalox/catalox.js.map +1 -0
  65. package/packages/engine/dist/catalox/context.d.ts +17 -0
  66. package/packages/engine/dist/catalox/context.d.ts.map +1 -0
  67. package/packages/engine/dist/catalox/context.js.map +1 -0
  68. package/packages/engine/dist/catalox/create-catalox.d.ts +45 -0
  69. package/packages/engine/dist/catalox/create-catalox.d.ts.map +1 -0
  70. package/packages/engine/dist/catalox/create-catalox.js +132 -0
  71. package/packages/engine/dist/catalox/create-catalox.js.map +1 -0
  72. package/packages/engine/dist/catalox/field-source-resolution.d.ts +16 -0
  73. package/packages/engine/dist/catalox/field-source-resolution.d.ts.map +1 -0
  74. package/packages/engine/dist/catalox/field-source-resolution.js.map +1 -0
  75. package/packages/engine/dist/catalox/firestore-gcs-compare.d.ts +15 -0
  76. package/packages/engine/dist/catalox/firestore-gcs-compare.d.ts.map +1 -0
  77. package/packages/engine/dist/catalox/firestore-gcs-compare.js.map +1 -0
  78. package/packages/engine/dist/catalox/firestore-gcs-transfer.d.ts +28 -0
  79. package/packages/engine/dist/catalox/firestore-gcs-transfer.d.ts.map +1 -0
  80. package/packages/engine/dist/catalox/firestore-gcs-transfer.js.map +1 -0
  81. package/packages/engine/dist/catalox/identity.d.ts +7 -0
  82. package/packages/engine/dist/catalox/identity.d.ts.map +1 -0
  83. package/packages/engine/dist/catalox/identity.js.map +1 -0
  84. package/packages/engine/dist/catalox/index.d.ts.map +1 -0
  85. package/packages/engine/dist/catalox/index.js.map +1 -0
  86. package/packages/engine/dist/catalox/item-scope-match.d.ts +39 -0
  87. package/packages/engine/dist/catalox/item-scope-match.d.ts.map +1 -0
  88. package/packages/engine/dist/catalox/item-scope-match.js.map +1 -0
  89. package/packages/engine/dist/catalox/item-scope.d.ts +36 -0
  90. package/packages/engine/dist/catalox/item-scope.d.ts.map +1 -0
  91. package/packages/engine/dist/catalox/item-scope.js +137 -0
  92. package/packages/engine/dist/catalox/item-scope.js.map +1 -0
  93. package/packages/engine/dist/catalox/json-io.d.ts.map +1 -0
  94. package/packages/engine/dist/catalox/json-io.js.map +1 -0
  95. package/packages/engine/dist/catalox/native-catalog-layout-diagnostics.d.ts +29 -0
  96. package/packages/engine/dist/catalox/native-catalog-layout-diagnostics.d.ts.map +1 -0
  97. package/packages/engine/dist/catalox/native-catalog-layout-diagnostics.js.map +1 -0
  98. package/packages/engine/dist/catalox/native-catalog-merge.d.ts +10 -0
  99. package/packages/engine/dist/catalox/native-catalog-merge.d.ts.map +1 -0
  100. package/packages/engine/dist/catalox/native-catalog-merge.js +40 -0
  101. package/packages/engine/dist/catalox/native-catalog-merge.js.map +1 -0
  102. package/packages/engine/dist/catalox/native-item-resolve.d.ts +28 -0
  103. package/packages/engine/dist/catalox/native-item-resolve.d.ts.map +1 -0
  104. package/packages/engine/dist/catalox/native-item-resolve.js.map +1 -0
  105. package/packages/engine/dist/catalox/record-history-field.d.ts +23 -0
  106. package/packages/engine/dist/catalox/record-history-field.d.ts.map +1 -0
  107. package/packages/engine/dist/catalox/record-history-field.js.map +1 -0
  108. package/packages/engine/dist/catalox/record-history.d.ts +53 -0
  109. package/packages/engine/dist/catalox/record-history.d.ts.map +1 -0
  110. package/packages/engine/dist/catalox/record-history.js.map +1 -0
  111. package/packages/engine/dist/catalox/reporting/render-inventory-report.d.ts +3 -0
  112. package/packages/engine/dist/catalox/reporting/render-inventory-report.d.ts.map +1 -0
  113. package/packages/engine/dist/catalox/reporting/render-inventory-report.js.map +1 -0
  114. package/packages/engine/dist/catalox/restore-firestore-backup-from-gcs.d.ts +21 -0
  115. package/packages/engine/dist/catalox/restore-firestore-backup-from-gcs.d.ts.map +1 -0
  116. package/packages/engine/dist/catalox/restore-firestore-backup-from-gcs.js.map +1 -0
  117. package/packages/engine/dist/catalox/restore-firestore-backup.d.ts +32 -0
  118. package/packages/engine/dist/catalox/restore-firestore-backup.d.ts.map +1 -0
  119. package/packages/engine/dist/catalox/restore-firestore-backup.js.map +1 -0
  120. package/packages/engine/dist/catalox/scope-legacy-convert.d.ts +19 -0
  121. package/packages/engine/dist/catalox/scope-legacy-convert.d.ts.map +1 -0
  122. package/packages/engine/dist/catalox/scope-legacy-convert.js.map +1 -0
  123. package/packages/engine/dist/catalox/seed-preset-resolve.d.ts.map +1 -0
  124. package/packages/engine/dist/catalox/seed-preset-resolve.js.map +1 -0
  125. package/packages/engine/dist/catalox/seed-preset.d.ts +85 -0
  126. package/packages/engine/dist/catalox/seed-preset.d.ts.map +1 -0
  127. package/packages/engine/dist/catalox/seed-preset.js.map +1 -0
  128. package/packages/engine/dist/catalox/smart-properties.d.ts +33 -0
  129. package/packages/engine/dist/catalox/smart-properties.d.ts.map +1 -0
  130. package/packages/engine/dist/catalox/smart-properties.js +242 -0
  131. package/packages/engine/dist/catalox/smart-properties.js.map +1 -0
  132. package/packages/engine/dist/cli/index.d.ts.map +1 -0
  133. package/packages/engine/dist/cli/index.js +1508 -0
  134. package/packages/engine/dist/cli/index.js.map +1 -0
  135. package/packages/engine/dist/cli/item-json.d.ts.map +1 -0
  136. package/packages/engine/dist/cli/item-json.js.map +1 -0
  137. package/packages/engine/dist/diagrams/render-catalog-diagram.d.ts +3 -0
  138. package/packages/engine/dist/diagrams/render-catalog-diagram.d.ts.map +1 -0
  139. package/packages/engine/dist/diagrams/render-catalog-diagram.js.map +1 -0
  140. package/packages/engine/dist/diagrams/render-item-diagram.d.ts +3 -0
  141. package/packages/engine/dist/diagrams/render-item-diagram.d.ts.map +1 -0
  142. package/packages/engine/dist/diagrams/render-item-diagram.js.map +1 -0
  143. package/packages/engine/dist/embedder.d.ts +29 -0
  144. package/packages/engine/dist/embedder.d.ts.map +1 -0
  145. package/packages/engine/dist/embedder.js +28 -0
  146. package/packages/engine/dist/embedder.js.map +1 -0
  147. package/packages/engine/dist/errors/index.d.ts.map +1 -0
  148. package/packages/engine/dist/errors/index.js.map +1 -0
  149. package/packages/engine/dist/firebase/adapter-store.d.ts +16 -0
  150. package/packages/engine/dist/firebase/adapter-store.d.ts.map +1 -0
  151. package/packages/engine/dist/firebase/adapter-store.js.map +1 -0
  152. package/packages/engine/dist/firebase/agent-store.d.ts +18 -0
  153. package/packages/engine/dist/firebase/agent-store.d.ts.map +1 -0
  154. package/packages/engine/dist/firebase/agent-store.js.map +1 -0
  155. package/packages/engine/dist/firebase/app-store.d.ts +11 -0
  156. package/packages/engine/dist/firebase/app-store.d.ts.map +1 -0
  157. package/packages/engine/dist/firebase/app-store.js.map +1 -0
  158. package/packages/engine/dist/firebase/binding-store.d.ts +15 -0
  159. package/packages/engine/dist/firebase/binding-store.d.ts.map +1 -0
  160. package/packages/engine/dist/firebase/binding-store.js.map +1 -0
  161. package/packages/engine/dist/firebase/bootstrap.d.ts.map +1 -0
  162. package/packages/engine/dist/firebase/bootstrap.js.map +1 -0
  163. package/packages/engine/dist/firebase/catalog-data-index-store.d.ts +15 -0
  164. package/packages/engine/dist/firebase/catalog-data-index-store.d.ts.map +1 -0
  165. package/packages/engine/dist/firebase/catalog-data-index-store.js.map +1 -0
  166. package/packages/engine/dist/firebase/catalog-data-paths.d.ts +14 -0
  167. package/packages/engine/dist/firebase/catalog-data-paths.d.ts.map +1 -0
  168. package/packages/engine/dist/firebase/catalog-data-paths.js.map +1 -0
  169. package/packages/engine/dist/firebase/catalog-item-history-store.d.ts +21 -0
  170. package/packages/engine/dist/firebase/catalog-item-history-store.d.ts.map +1 -0
  171. package/packages/engine/dist/firebase/catalog-item-history-store.js.map +1 -0
  172. package/packages/engine/dist/firebase/catalog-store.d.ts +13 -0
  173. package/packages/engine/dist/firebase/catalog-store.d.ts.map +1 -0
  174. package/packages/engine/dist/firebase/catalog-store.js.map +1 -0
  175. package/packages/engine/dist/firebase/catalog-type-store.d.ts +22 -0
  176. package/packages/engine/dist/firebase/catalog-type-store.d.ts.map +1 -0
  177. package/packages/engine/dist/firebase/catalog-type-store.js.map +1 -0
  178. package/packages/engine/dist/firebase/definition-store.d.ts +25 -0
  179. package/packages/engine/dist/firebase/definition-store.d.ts.map +1 -0
  180. package/packages/engine/dist/firebase/definition-store.js.map +1 -0
  181. package/packages/engine/dist/firebase/descriptor-store.d.ts +11 -0
  182. package/packages/engine/dist/firebase/descriptor-store.d.ts.map +1 -0
  183. package/packages/engine/dist/firebase/descriptor-store.js.map +1 -0
  184. package/packages/engine/dist/firebase/design-object-store.d.ts +15 -0
  185. package/packages/engine/dist/firebase/design-object-store.d.ts.map +1 -0
  186. package/packages/engine/dist/firebase/design-object-store.js.map +1 -0
  187. package/packages/engine/dist/firebase/domain-store.d.ts +18 -0
  188. package/packages/engine/dist/firebase/domain-store.d.ts.map +1 -0
  189. package/packages/engine/dist/firebase/domain-store.js.map +1 -0
  190. package/packages/engine/dist/firebase/firestore-collection-path.d.ts.map +1 -0
  191. package/packages/engine/dist/firebase/firestore-collection-path.js.map +1 -0
  192. package/packages/engine/dist/firebase/firestore-store.d.ts.map +1 -0
  193. package/packages/engine/dist/firebase/firestore-store.js.map +1 -0
  194. package/packages/engine/dist/firebase/identity-binding-store.d.ts +18 -0
  195. package/packages/engine/dist/firebase/identity-binding-store.d.ts.map +1 -0
  196. package/packages/engine/dist/firebase/identity-binding-store.js.map +1 -0
  197. package/packages/engine/dist/firebase/index.d.ts.map +1 -0
  198. package/packages/engine/dist/firebase/index.js.map +1 -0
  199. package/packages/engine/dist/firebase/mapping-store.d.ts +12 -0
  200. package/packages/engine/dist/firebase/mapping-store.d.ts.map +1 -0
  201. package/packages/engine/dist/firebase/mapping-store.js.map +1 -0
  202. package/packages/engine/dist/firebase/native-item-store.d.ts +41 -0
  203. package/packages/engine/dist/firebase/native-item-store.d.ts.map +1 -0
  204. package/packages/engine/dist/firebase/native-item-store.js +129 -0
  205. package/packages/engine/dist/firebase/native-item-store.js.map +1 -0
  206. package/packages/engine/dist/firebase/presentation-profile-store.d.ts +18 -0
  207. package/packages/engine/dist/firebase/presentation-profile-store.d.ts.map +1 -0
  208. package/packages/engine/dist/firebase/presentation-profile-store.js.map +1 -0
  209. package/packages/engine/dist/firebase/reference-store.d.ts +21 -0
  210. package/packages/engine/dist/firebase/reference-store.d.ts.map +1 -0
  211. package/packages/engine/dist/firebase/reference-store.js.map +1 -0
  212. package/packages/engine/dist/firebase/renderer-snippet-store.d.ts +15 -0
  213. package/packages/engine/dist/firebase/renderer-snippet-store.d.ts.map +1 -0
  214. package/packages/engine/dist/firebase/renderer-snippet-store.js.map +1 -0
  215. package/packages/engine/dist/firebase/snapshot-store.d.ts +19 -0
  216. package/packages/engine/dist/firebase/snapshot-store.d.ts.map +1 -0
  217. package/packages/engine/dist/firebase/snapshot-store.js.map +1 -0
  218. package/packages/engine/dist/firebase/store-app-binding-store.d.ts +14 -0
  219. package/packages/engine/dist/firebase/store-app-binding-store.d.ts.map +1 -0
  220. package/packages/engine/dist/firebase/store-app-binding-store.js.map +1 -0
  221. package/packages/engine/dist/index.d.ts.map +1 -0
  222. package/packages/engine/dist/index.js.map +1 -0
  223. package/packages/engine/dist/jsx/index.d.ts +70 -0
  224. package/packages/engine/dist/jsx/index.d.ts.map +1 -0
  225. package/packages/engine/dist/jsx/index.js +178 -0
  226. package/packages/engine/dist/jsx/index.js.map +1 -0
  227. package/packages/engine/dist/local/in-memory-native-item-store.d.ts +29 -0
  228. package/packages/engine/dist/local/in-memory-native-item-store.d.ts.map +1 -0
  229. package/packages/engine/dist/local/in-memory-native-item-store.js +117 -0
  230. package/packages/engine/dist/local/in-memory-native-item-store.js.map +1 -0
  231. package/packages/engine/dist/local/in-memory-stores.d.ts +35 -0
  232. package/packages/engine/dist/local/in-memory-stores.d.ts.map +1 -0
  233. package/packages/engine/dist/local/in-memory-stores.js.map +1 -0
  234. package/packages/engine/dist/local/index.d.ts +4 -0
  235. package/packages/engine/dist/local/index.d.ts.map +1 -0
  236. package/packages/engine/dist/local/index.js +4 -0
  237. package/packages/engine/dist/local/index.js.map +1 -0
  238. package/packages/engine/dist/local/local-file-store.d.ts +19 -0
  239. package/packages/engine/dist/local/local-file-store.d.ts.map +1 -0
  240. package/packages/engine/dist/local/local-file-store.js +25 -0
  241. package/packages/engine/dist/local/local-file-store.js.map +1 -0
  242. package/packages/engine/dist/local/local-store-error.d.ts +14 -0
  243. package/packages/engine/dist/local/local-store-error.d.ts.map +1 -0
  244. package/packages/engine/dist/local/local-store-error.js +22 -0
  245. package/packages/engine/dist/local/local-store-error.js.map +1 -0
  246. package/packages/engine/dist/local/snapshot.d.ts +36 -0
  247. package/packages/engine/dist/local/snapshot.d.ts.map +1 -0
  248. package/packages/engine/dist/local/snapshot.js +192 -0
  249. package/packages/engine/dist/local/snapshot.js.map +1 -0
  250. package/packages/engine/dist/local/stub-deps.d.ts.map +1 -0
  251. package/packages/engine/dist/local/stub-deps.js.map +1 -0
  252. package/packages/engine/dist/local/unavailable-firestore-store.d.ts.map +1 -0
  253. package/packages/engine/dist/local/unavailable-firestore-store.js.map +1 -0
  254. package/packages/engine/dist/local/wire-local-catalox.d.ts.map +1 -0
  255. package/packages/engine/dist/local/wire-local-catalox.js.map +1 -0
  256. package/packages/engine/dist/logging.d.ts.map +1 -0
  257. package/packages/engine/dist/logging.js.map +1 -0
  258. package/packages/engine/dist/mapping/execute-mapping.d.ts +8 -0
  259. package/packages/engine/dist/mapping/execute-mapping.d.ts.map +1 -0
  260. package/packages/engine/dist/mapping/execute-mapping.js.map +1 -0
  261. package/packages/engine/dist/mapping/helper-gap-report.d.ts.map +1 -0
  262. package/packages/engine/dist/mapping/helper-gap-report.js.map +1 -0
  263. package/packages/engine/dist/mapping/index.d.ts.map +1 -0
  264. package/packages/engine/dist/mapping/index.js.map +1 -0
  265. package/packages/engine/dist/mapping/validate-mapping.d.ts +3 -0
  266. package/packages/engine/dist/mapping/validate-mapping.d.ts.map +1 -0
  267. package/packages/engine/dist/mapping/validate-mapping.js.map +1 -0
  268. package/packages/engine/dist/markdown/render-item-markdown.d.ts +5 -0
  269. package/packages/engine/dist/markdown/render-item-markdown.d.ts.map +1 -0
  270. package/packages/engine/dist/markdown/render-item-markdown.js.map +1 -0
  271. package/packages/engine/dist/markdown/render-list-markdown.d.ts +5 -0
  272. package/packages/engine/dist/markdown/render-list-markdown.d.ts.map +1 -0
  273. package/packages/engine/dist/markdown/render-list-markdown.js.map +1 -0
  274. package/packages/engine/dist/migrations/backfill-catalog-model.d.ts +29 -0
  275. package/packages/engine/dist/migrations/backfill-catalog-model.d.ts.map +1 -0
  276. package/packages/engine/dist/migrations/backfill-catalog-model.js.map +1 -0
  277. package/packages/engine/dist/migrations/index.d.ts.map +1 -0
  278. package/packages/engine/dist/migrations/index.js.map +1 -0
  279. package/packages/engine/dist/migrations/migrate-native-catalog-layout.d.ts +51 -0
  280. package/packages/engine/dist/migrations/migrate-native-catalog-layout.d.ts.map +1 -0
  281. package/packages/engine/dist/migrations/migrate-native-catalog-layout.js.map +1 -0
  282. package/packages/engine/dist/migrations/migrate-native-item-scope.d.ts +36 -0
  283. package/packages/engine/dist/migrations/migrate-native-item-scope.d.ts.map +1 -0
  284. package/packages/engine/dist/migrations/migrate-native-item-scope.js.map +1 -0
  285. package/packages/engine/dist/migrations/renderer-metadata.d.ts +7 -0
  286. package/packages/engine/dist/migrations/renderer-metadata.d.ts.map +1 -0
  287. package/packages/engine/dist/migrations/renderer-metadata.js.map +1 -0
  288. package/packages/engine/dist/mongo/adapter-store.d.ts +15 -0
  289. package/packages/engine/dist/mongo/adapter-store.d.ts.map +1 -0
  290. package/packages/engine/dist/mongo/adapter-store.js +18 -0
  291. package/packages/engine/dist/mongo/adapter-store.js.map +1 -0
  292. package/packages/engine/dist/mongo/agent-store.d.ts +18 -0
  293. package/packages/engine/dist/mongo/agent-store.d.ts.map +1 -0
  294. package/packages/engine/dist/mongo/agent-store.js +45 -0
  295. package/packages/engine/dist/mongo/agent-store.js.map +1 -0
  296. package/packages/engine/dist/mongo/app-store.d.ts +10 -0
  297. package/packages/engine/dist/mongo/app-store.d.ts.map +1 -0
  298. package/packages/engine/dist/mongo/app-store.js +16 -0
  299. package/packages/engine/dist/mongo/app-store.js.map +1 -0
  300. package/packages/engine/dist/mongo/binding-store.d.ts +15 -0
  301. package/packages/engine/dist/mongo/binding-store.d.ts.map +1 -0
  302. package/packages/engine/dist/mongo/binding-store.js +28 -0
  303. package/packages/engine/dist/mongo/binding-store.js.map +1 -0
  304. package/packages/engine/dist/mongo/bootstrap.d.ts +37 -0
  305. package/packages/engine/dist/mongo/bootstrap.d.ts.map +1 -0
  306. package/packages/engine/dist/mongo/bootstrap.js +41 -0
  307. package/packages/engine/dist/mongo/bootstrap.js.map +1 -0
  308. package/packages/engine/dist/mongo/catalog-data-index-store.d.ts +14 -0
  309. package/packages/engine/dist/mongo/catalog-data-index-store.d.ts.map +1 -0
  310. package/packages/engine/dist/mongo/catalog-data-index-store.js +33 -0
  311. package/packages/engine/dist/mongo/catalog-data-index-store.js.map +1 -0
  312. package/packages/engine/dist/mongo/catalog-item-history-store.d.ts +14 -0
  313. package/packages/engine/dist/mongo/catalog-item-history-store.d.ts.map +1 -0
  314. package/packages/engine/dist/mongo/catalog-item-history-store.js +41 -0
  315. package/packages/engine/dist/mongo/catalog-item-history-store.js.map +1 -0
  316. package/packages/engine/dist/mongo/catalog-store.d.ts +12 -0
  317. package/packages/engine/dist/mongo/catalog-store.d.ts.map +1 -0
  318. package/packages/engine/dist/mongo/catalog-store.js +23 -0
  319. package/packages/engine/dist/mongo/catalog-store.js.map +1 -0
  320. package/packages/engine/dist/mongo/catalog-type-store.d.ts +18 -0
  321. package/packages/engine/dist/mongo/catalog-type-store.d.ts.map +1 -0
  322. package/packages/engine/dist/mongo/catalog-type-store.js +45 -0
  323. package/packages/engine/dist/mongo/catalog-type-store.js.map +1 -0
  324. package/packages/engine/dist/mongo/definition-store.d.ts +24 -0
  325. package/packages/engine/dist/mongo/definition-store.d.ts.map +1 -0
  326. package/packages/engine/dist/mongo/definition-store.js +15 -0
  327. package/packages/engine/dist/mongo/definition-store.js.map +1 -0
  328. package/packages/engine/dist/mongo/descriptor-store.d.ts +10 -0
  329. package/packages/engine/dist/mongo/descriptor-store.d.ts.map +1 -0
  330. package/packages/engine/dist/mongo/descriptor-store.js +15 -0
  331. package/packages/engine/dist/mongo/descriptor-store.js.map +1 -0
  332. package/packages/engine/dist/mongo/design-object-store.d.ts +11 -0
  333. package/packages/engine/dist/mongo/design-object-store.d.ts.map +1 -0
  334. package/packages/engine/dist/mongo/design-object-store.js +43 -0
  335. package/packages/engine/dist/mongo/design-object-store.js.map +1 -0
  336. package/packages/engine/dist/mongo/domain-store.d.ts +18 -0
  337. package/packages/engine/dist/mongo/domain-store.d.ts.map +1 -0
  338. package/packages/engine/dist/mongo/domain-store.js +45 -0
  339. package/packages/engine/dist/mongo/domain-store.js.map +1 -0
  340. package/packages/engine/dist/mongo/identity-binding-store.d.ts +13 -0
  341. package/packages/engine/dist/mongo/identity-binding-store.d.ts.map +1 -0
  342. package/packages/engine/dist/mongo/identity-binding-store.js +22 -0
  343. package/packages/engine/dist/mongo/identity-binding-store.js.map +1 -0
  344. package/packages/engine/dist/mongo/index.d.ts +9 -0
  345. package/packages/engine/dist/mongo/index.d.ts.map +1 -0
  346. package/packages/engine/dist/mongo/index.js +9 -0
  347. package/packages/engine/dist/mongo/index.js.map +1 -0
  348. package/packages/engine/dist/mongo/mapping-store.d.ts +11 -0
  349. package/packages/engine/dist/mongo/mapping-store.d.ts.map +1 -0
  350. package/packages/engine/dist/mongo/mapping-store.js +18 -0
  351. package/packages/engine/dist/mongo/mapping-store.js.map +1 -0
  352. package/packages/engine/dist/mongo/mongo-store.d.ts +43 -0
  353. package/packages/engine/dist/mongo/mongo-store.d.ts.map +1 -0
  354. package/packages/engine/dist/mongo/mongo-store.js +23 -0
  355. package/packages/engine/dist/mongo/mongo-store.js.map +1 -0
  356. package/packages/engine/dist/mongo/mongo-utils.d.ts +5 -0
  357. package/packages/engine/dist/mongo/mongo-utils.d.ts.map +1 -0
  358. package/packages/engine/dist/mongo/mongo-utils.js +21 -0
  359. package/packages/engine/dist/mongo/mongo-utils.js.map +1 -0
  360. package/packages/engine/dist/mongo/native-item-store.d.ts +29 -0
  361. package/packages/engine/dist/mongo/native-item-store.d.ts.map +1 -0
  362. package/packages/engine/dist/mongo/native-item-store.js +107 -0
  363. package/packages/engine/dist/mongo/native-item-store.js.map +1 -0
  364. package/packages/engine/dist/mongo/presentation-profile-store.d.ts +14 -0
  365. package/packages/engine/dist/mongo/presentation-profile-store.d.ts.map +1 -0
  366. package/packages/engine/dist/mongo/presentation-profile-store.js +33 -0
  367. package/packages/engine/dist/mongo/presentation-profile-store.js.map +1 -0
  368. package/packages/engine/dist/mongo/reference-store.d.ts +21 -0
  369. package/packages/engine/dist/mongo/reference-store.d.ts.map +1 -0
  370. package/packages/engine/dist/mongo/reference-store.js +35 -0
  371. package/packages/engine/dist/mongo/reference-store.js.map +1 -0
  372. package/packages/engine/dist/mongo/renderer-snippet-store.d.ts +14 -0
  373. package/packages/engine/dist/mongo/renderer-snippet-store.d.ts.map +1 -0
  374. package/packages/engine/dist/mongo/renderer-snippet-store.js +28 -0
  375. package/packages/engine/dist/mongo/renderer-snippet-store.js.map +1 -0
  376. package/packages/engine/dist/mongo/snapshot-store.d.ts +19 -0
  377. package/packages/engine/dist/mongo/snapshot-store.d.ts.map +1 -0
  378. package/packages/engine/dist/mongo/snapshot-store.js +43 -0
  379. package/packages/engine/dist/mongo/snapshot-store.js.map +1 -0
  380. package/packages/engine/dist/mongo/store-app-binding-store.d.ts +14 -0
  381. package/packages/engine/dist/mongo/store-app-binding-store.d.ts.map +1 -0
  382. package/packages/engine/dist/mongo/store-app-binding-store.js +25 -0
  383. package/packages/engine/dist/mongo/store-app-binding-store.js.map +1 -0
  384. package/packages/engine/dist/mongo/wire-mongo-catalox.d.ts +14 -0
  385. package/packages/engine/dist/mongo/wire-mongo-catalox.d.ts.map +1 -0
  386. package/packages/engine/dist/mongo/wire-mongo-catalox.js +84 -0
  387. package/packages/engine/dist/mongo/wire-mongo-catalox.js.map +1 -0
  388. package/packages/engine/dist/operator.d.ts.map +1 -0
  389. package/packages/engine/dist/operator.js.map +1 -0
  390. package/packages/engine/dist/validation/index.d.ts.map +1 -0
  391. package/packages/engine/dist/validation/index.js.map +1 -0
  392. package/packages/engine/dist/validation/payload-schema-registry.d.ts.map +1 -0
  393. package/packages/engine/dist/validation/payload-schema-registry.js.map +1 -0
  394. package/packages/engine/dist/validation/payload-schema.d.ts +30 -0
  395. package/packages/engine/dist/validation/payload-schema.d.ts.map +1 -0
  396. package/packages/engine/dist/validation/payload-schema.js.map +1 -0
  397. package/packages/engine/dist/validation/ui-spec-schema.d.ts.map +1 -0
  398. package/packages/engine/dist/validation/ui-spec-schema.js.map +1 -0
  399. package/packages/engine/dist/validation/ui-spec-validate.d.ts.map +1 -0
  400. package/packages/engine/dist/validation/ui-spec-validate.js.map +1 -0
  401. package/dist/src/adapters/api/api-adapter.d.ts +0 -22
  402. package/dist/src/adapters/api/api-adapter.d.ts.map +0 -1
  403. package/dist/src/adapters/api/api-adapter.js +0 -64
  404. package/dist/src/adapters/api/api-adapter.js.map +0 -1
  405. package/dist/src/adapters/api/index.d.ts.map +0 -1
  406. package/dist/src/adapters/api/index.js.map +0 -1
  407. package/dist/src/adapters/mongo/index.d.ts.map +0 -1
  408. package/dist/src/adapters/mongo/index.js.map +0 -1
  409. package/dist/src/adapters/mongo/mongo-adapter.d.ts +0 -21
  410. package/dist/src/adapters/mongo/mongo-adapter.d.ts.map +0 -1
  411. package/dist/src/adapters/mongo/mongo-adapter.js +0 -61
  412. package/dist/src/adapters/mongo/mongo-adapter.js.map +0 -1
  413. package/dist/src/adapters/mongo/resolve-db.d.ts +0 -4
  414. package/dist/src/adapters/mongo/resolve-db.d.ts.map +0 -1
  415. package/dist/src/adapters/mongo/resolve-db.js.map +0 -1
  416. package/dist/src/bindings/index.d.ts.map +0 -1
  417. package/dist/src/bindings/index.js.map +0 -1
  418. package/dist/src/catalox/authorization.d.ts +0 -20
  419. package/dist/src/catalox/authorization.d.ts.map +0 -1
  420. package/dist/src/catalox/authorization.js +0 -55
  421. package/dist/src/catalox/authorization.js.map +0 -1
  422. package/dist/src/catalox/backup-data.d.ts +0 -70
  423. package/dist/src/catalox/backup-data.d.ts.map +0 -1
  424. package/dist/src/catalox/backup-data.js.map +0 -1
  425. package/dist/src/catalox/catalog-discovery.d.ts +0 -9
  426. package/dist/src/catalox/catalog-discovery.d.ts.map +0 -1
  427. package/dist/src/catalox/catalog-discovery.js.map +0 -1
  428. package/dist/src/catalox/catalog-lifecycle.d.ts +0 -29
  429. package/dist/src/catalox/catalog-lifecycle.d.ts.map +0 -1
  430. package/dist/src/catalox/catalog-lifecycle.js.map +0 -1
  431. package/dist/src/catalox/catalog-snapshot-export.d.ts +0 -46
  432. package/dist/src/catalox/catalog-snapshot-export.d.ts.map +0 -1
  433. package/dist/src/catalox/catalog-snapshot-export.js +0 -103
  434. package/dist/src/catalox/catalog-snapshot-export.js.map +0 -1
  435. package/dist/src/catalox/catalox-bound.d.ts +0 -193
  436. package/dist/src/catalox/catalox-bound.d.ts.map +0 -1
  437. package/dist/src/catalox/catalox-bound.js +0 -247
  438. package/dist/src/catalox/catalox-bound.js.map +0 -1
  439. package/dist/src/catalox/catalox-gcs-backup-export-manifest.d.ts +0 -13
  440. package/dist/src/catalox/catalox-gcs-backup-export-manifest.d.ts.map +0 -1
  441. package/dist/src/catalox/catalox-gcs-backup-export-manifest.js.map +0 -1
  442. package/dist/src/catalox/catalox.d.ts +0 -358
  443. package/dist/src/catalox/catalox.d.ts.map +0 -1
  444. package/dist/src/catalox/catalox.js +0 -2701
  445. package/dist/src/catalox/catalox.js.map +0 -1
  446. package/dist/src/catalox/context.d.ts +0 -17
  447. package/dist/src/catalox/context.d.ts.map +0 -1
  448. package/dist/src/catalox/context.js.map +0 -1
  449. package/dist/src/catalox/create-catalox.d.ts +0 -44
  450. package/dist/src/catalox/create-catalox.d.ts.map +0 -1
  451. package/dist/src/catalox/create-catalox.js +0 -124
  452. package/dist/src/catalox/create-catalox.js.map +0 -1
  453. package/dist/src/catalox/field-source-resolution.d.ts +0 -16
  454. package/dist/src/catalox/field-source-resolution.d.ts.map +0 -1
  455. package/dist/src/catalox/field-source-resolution.js.map +0 -1
  456. package/dist/src/catalox/firestore-gcs-compare.d.ts +0 -15
  457. package/dist/src/catalox/firestore-gcs-compare.d.ts.map +0 -1
  458. package/dist/src/catalox/firestore-gcs-compare.js.map +0 -1
  459. package/dist/src/catalox/firestore-gcs-transfer.d.ts +0 -28
  460. package/dist/src/catalox/firestore-gcs-transfer.d.ts.map +0 -1
  461. package/dist/src/catalox/firestore-gcs-transfer.js.map +0 -1
  462. package/dist/src/catalox/identity.d.ts +0 -7
  463. package/dist/src/catalox/identity.d.ts.map +0 -1
  464. package/dist/src/catalox/identity.js.map +0 -1
  465. package/dist/src/catalox/index.d.ts.map +0 -1
  466. package/dist/src/catalox/index.js.map +0 -1
  467. package/dist/src/catalox/item-scope-match.d.ts +0 -39
  468. package/dist/src/catalox/item-scope-match.d.ts.map +0 -1
  469. package/dist/src/catalox/item-scope-match.js.map +0 -1
  470. package/dist/src/catalox/item-scope.d.ts +0 -36
  471. package/dist/src/catalox/item-scope.d.ts.map +0 -1
  472. package/dist/src/catalox/item-scope.js +0 -137
  473. package/dist/src/catalox/item-scope.js.map +0 -1
  474. package/dist/src/catalox/json-io.d.ts.map +0 -1
  475. package/dist/src/catalox/json-io.js.map +0 -1
  476. package/dist/src/catalox/native-catalog-layout-diagnostics.d.ts +0 -29
  477. package/dist/src/catalox/native-catalog-layout-diagnostics.d.ts.map +0 -1
  478. package/dist/src/catalox/native-catalog-layout-diagnostics.js.map +0 -1
  479. package/dist/src/catalox/native-catalog-merge.d.ts +0 -10
  480. package/dist/src/catalox/native-catalog-merge.d.ts.map +0 -1
  481. package/dist/src/catalox/native-catalog-merge.js +0 -40
  482. package/dist/src/catalox/native-catalog-merge.js.map +0 -1
  483. package/dist/src/catalox/native-item-resolve.d.ts +0 -28
  484. package/dist/src/catalox/native-item-resolve.d.ts.map +0 -1
  485. package/dist/src/catalox/native-item-resolve.js.map +0 -1
  486. package/dist/src/catalox/record-history-field.d.ts +0 -23
  487. package/dist/src/catalox/record-history-field.d.ts.map +0 -1
  488. package/dist/src/catalox/record-history-field.js.map +0 -1
  489. package/dist/src/catalox/record-history.d.ts +0 -53
  490. package/dist/src/catalox/record-history.d.ts.map +0 -1
  491. package/dist/src/catalox/record-history.js.map +0 -1
  492. package/dist/src/catalox/reporting/render-inventory-report.d.ts +0 -3
  493. package/dist/src/catalox/reporting/render-inventory-report.d.ts.map +0 -1
  494. package/dist/src/catalox/reporting/render-inventory-report.js.map +0 -1
  495. package/dist/src/catalox/restore-firestore-backup-from-gcs.d.ts +0 -21
  496. package/dist/src/catalox/restore-firestore-backup-from-gcs.d.ts.map +0 -1
  497. package/dist/src/catalox/restore-firestore-backup-from-gcs.js.map +0 -1
  498. package/dist/src/catalox/restore-firestore-backup.d.ts +0 -32
  499. package/dist/src/catalox/restore-firestore-backup.d.ts.map +0 -1
  500. package/dist/src/catalox/restore-firestore-backup.js.map +0 -1
  501. package/dist/src/catalox/scope-legacy-convert.d.ts +0 -19
  502. package/dist/src/catalox/scope-legacy-convert.d.ts.map +0 -1
  503. package/dist/src/catalox/scope-legacy-convert.js.map +0 -1
  504. package/dist/src/catalox/seed-preset-resolve.d.ts.map +0 -1
  505. package/dist/src/catalox/seed-preset-resolve.js.map +0 -1
  506. package/dist/src/catalox/seed-preset.d.ts +0 -85
  507. package/dist/src/catalox/seed-preset.d.ts.map +0 -1
  508. package/dist/src/catalox/seed-preset.js.map +0 -1
  509. package/dist/src/catalox/smart-properties.d.ts +0 -33
  510. package/dist/src/catalox/smart-properties.d.ts.map +0 -1
  511. package/dist/src/catalox/smart-properties.js +0 -242
  512. package/dist/src/catalox/smart-properties.js.map +0 -1
  513. package/dist/src/cli/index.d.ts.map +0 -1
  514. package/dist/src/cli/index.js +0 -1473
  515. package/dist/src/cli/index.js.map +0 -1
  516. package/dist/src/cli/item-json.d.ts.map +0 -1
  517. package/dist/src/cli/item-json.js.map +0 -1
  518. package/dist/src/contracts/adapters.d.ts +0 -40
  519. package/dist/src/contracts/adapters.d.ts.map +0 -1
  520. package/dist/src/contracts/adapters.js +0 -2
  521. package/dist/src/contracts/adapters.js.map +0 -1
  522. package/dist/src/contracts/agents.d.ts +0 -19
  523. package/dist/src/contracts/agents.d.ts.map +0 -1
  524. package/dist/src/contracts/agents.js +0 -2
  525. package/dist/src/contracts/agents.js.map +0 -1
  526. package/dist/src/contracts/apps.d.ts +0 -13
  527. package/dist/src/contracts/apps.d.ts.map +0 -1
  528. package/dist/src/contracts/apps.js +0 -2
  529. package/dist/src/contracts/apps.js.map +0 -1
  530. package/dist/src/contracts/backup.d.ts +0 -46
  531. package/dist/src/contracts/backup.d.ts.map +0 -1
  532. package/dist/src/contracts/backup.js +0 -2
  533. package/dist/src/contracts/backup.js.map +0 -1
  534. package/dist/src/contracts/bindings.d.ts +0 -52
  535. package/dist/src/contracts/bindings.d.ts.map +0 -1
  536. package/dist/src/contracts/bindings.js +0 -2
  537. package/dist/src/contracts/bindings.js.map +0 -1
  538. package/dist/src/contracts/bootstrap.d.ts +0 -33
  539. package/dist/src/contracts/bootstrap.d.ts.map +0 -1
  540. package/dist/src/contracts/bootstrap.js +0 -2
  541. package/dist/src/contracts/bootstrap.js.map +0 -1
  542. package/dist/src/contracts/catalog-data-index.d.ts +0 -13
  543. package/dist/src/contracts/catalog-data-index.d.ts.map +0 -1
  544. package/dist/src/contracts/catalog-data-index.js +0 -2
  545. package/dist/src/contracts/catalog-data-index.js.map +0 -1
  546. package/dist/src/contracts/catalog-lifecycle.d.ts +0 -70
  547. package/dist/src/contracts/catalog-lifecycle.d.ts.map +0 -1
  548. package/dist/src/contracts/catalog-lifecycle.js +0 -2
  549. package/dist/src/contracts/catalog-lifecycle.js.map +0 -1
  550. package/dist/src/contracts/catalog-snapshot-export.d.ts +0 -55
  551. package/dist/src/contracts/catalog-snapshot-export.d.ts.map +0 -1
  552. package/dist/src/contracts/catalog-snapshot-export.js +0 -3
  553. package/dist/src/contracts/catalog-snapshot-export.js.map +0 -1
  554. package/dist/src/contracts/catalog-types.d.ts +0 -31
  555. package/dist/src/contracts/catalog-types.d.ts.map +0 -1
  556. package/dist/src/contracts/catalog-types.js +0 -2
  557. package/dist/src/contracts/catalog-types.js.map +0 -1
  558. package/dist/src/contracts/catalogs.d.ts +0 -152
  559. package/dist/src/contracts/catalogs.d.ts.map +0 -1
  560. package/dist/src/contracts/catalogs.js +0 -19
  561. package/dist/src/contracts/catalogs.js.map +0 -1
  562. package/dist/src/contracts/config.d.ts +0 -14
  563. package/dist/src/contracts/config.d.ts.map +0 -1
  564. package/dist/src/contracts/config.js +0 -2
  565. package/dist/src/contracts/config.js.map +0 -1
  566. package/dist/src/contracts/context.d.ts +0 -50
  567. package/dist/src/contracts/context.d.ts.map +0 -1
  568. package/dist/src/contracts/context.js +0 -2
  569. package/dist/src/contracts/context.js.map +0 -1
  570. package/dist/src/contracts/custom-renderer-resolve.d.ts +0 -15
  571. package/dist/src/contracts/custom-renderer-resolve.d.ts.map +0 -1
  572. package/dist/src/contracts/custom-renderer-resolve.js +0 -55
  573. package/dist/src/contracts/custom-renderer-resolve.js.map +0 -1
  574. package/dist/src/contracts/descriptor-rules.d.ts +0 -76
  575. package/dist/src/contracts/descriptor-rules.d.ts.map +0 -1
  576. package/dist/src/contracts/descriptor-rules.js +0 -2
  577. package/dist/src/contracts/descriptor-rules.js.map +0 -1
  578. package/dist/src/contracts/descriptors.d.ts +0 -115
  579. package/dist/src/contracts/descriptors.d.ts.map +0 -1
  580. package/dist/src/contracts/descriptors.js +0 -2
  581. package/dist/src/contracts/descriptors.js.map +0 -1
  582. package/dist/src/contracts/design-objects.d.ts +0 -38
  583. package/dist/src/contracts/design-objects.d.ts.map +0 -1
  584. package/dist/src/contracts/design-objects.js +0 -2
  585. package/dist/src/contracts/design-objects.js.map +0 -1
  586. package/dist/src/contracts/diagram-map.d.ts +0 -24
  587. package/dist/src/contracts/diagram-map.d.ts.map +0 -1
  588. package/dist/src/contracts/diagram-map.js +0 -2
  589. package/dist/src/contracts/diagram-map.js.map +0 -1
  590. package/dist/src/contracts/discovery.d.ts +0 -99
  591. package/dist/src/contracts/discovery.d.ts.map +0 -1
  592. package/dist/src/contracts/discovery.js +0 -2
  593. package/dist/src/contracts/discovery.js.map +0 -1
  594. package/dist/src/contracts/domains.d.ts +0 -19
  595. package/dist/src/contracts/domains.d.ts.map +0 -1
  596. package/dist/src/contracts/domains.js +0 -2
  597. package/dist/src/contracts/domains.js.map +0 -1
  598. package/dist/src/contracts/errors.d.ts +0 -37
  599. package/dist/src/contracts/errors.d.ts.map +0 -1
  600. package/dist/src/contracts/errors.js +0 -64
  601. package/dist/src/contracts/errors.js.map +0 -1
  602. package/dist/src/contracts/field-source.d.ts +0 -43
  603. package/dist/src/contracts/field-source.d.ts.map +0 -1
  604. package/dist/src/contracts/field-source.js +0 -2
  605. package/dist/src/contracts/field-source.js.map +0 -1
  606. package/dist/src/contracts/filters.d.ts +0 -59
  607. package/dist/src/contracts/filters.d.ts.map +0 -1
  608. package/dist/src/contracts/filters.js +0 -2
  609. package/dist/src/contracts/filters.js.map +0 -1
  610. package/dist/src/contracts/gcs-firestore-compare.d.ts +0 -64
  611. package/dist/src/contracts/gcs-firestore-compare.d.ts.map +0 -1
  612. package/dist/src/contracts/gcs-firestore-compare.js +0 -2
  613. package/dist/src/contracts/gcs-firestore-compare.js.map +0 -1
  614. package/dist/src/contracts/gcs-firestore-transfer.d.ts +0 -108
  615. package/dist/src/contracts/gcs-firestore-transfer.d.ts.map +0 -1
  616. package/dist/src/contracts/gcs-firestore-transfer.js +0 -2
  617. package/dist/src/contracts/gcs-firestore-transfer.js.map +0 -1
  618. package/dist/src/contracts/ids.d.ts +0 -10
  619. package/dist/src/contracts/ids.d.ts.map +0 -1
  620. package/dist/src/contracts/ids.js +0 -2
  621. package/dist/src/contracts/ids.js.map +0 -1
  622. package/dist/src/contracts/index.d.ts +0 -53
  623. package/dist/src/contracts/index.d.ts.map +0 -1
  624. package/dist/src/contracts/index.js +0 -6
  625. package/dist/src/contracts/index.js.map +0 -1
  626. package/dist/src/contracts/inputs.d.ts +0 -51
  627. package/dist/src/contracts/inputs.d.ts.map +0 -1
  628. package/dist/src/contracts/inputs.js +0 -2
  629. package/dist/src/contracts/inputs.js.map +0 -1
  630. package/dist/src/contracts/inventory-export.d.ts +0 -40
  631. package/dist/src/contracts/inventory-export.d.ts.map +0 -1
  632. package/dist/src/contracts/inventory-export.js +0 -2
  633. package/dist/src/contracts/inventory-export.js.map +0 -1
  634. package/dist/src/contracts/inventory-report.d.ts +0 -61
  635. package/dist/src/contracts/inventory-report.d.ts.map +0 -1
  636. package/dist/src/contracts/inventory-report.js +0 -2
  637. package/dist/src/contracts/inventory-report.js.map +0 -1
  638. package/dist/src/contracts/item-validation.d.ts +0 -11
  639. package/dist/src/contracts/item-validation.d.ts.map +0 -1
  640. package/dist/src/contracts/item-validation.js +0 -2
  641. package/dist/src/contracts/item-validation.js.map +0 -1
  642. package/dist/src/contracts/items.d.ts +0 -63
  643. package/dist/src/contracts/items.d.ts.map +0 -1
  644. package/dist/src/contracts/items.js +0 -2
  645. package/dist/src/contracts/items.js.map +0 -1
  646. package/dist/src/contracts/mappings.d.ts +0 -35
  647. package/dist/src/contracts/mappings.d.ts.map +0 -1
  648. package/dist/src/contracts/mappings.js +0 -2
  649. package/dist/src/contracts/mappings.js.map +0 -1
  650. package/dist/src/contracts/markdown-map.d.ts +0 -42
  651. package/dist/src/contracts/markdown-map.d.ts.map +0 -1
  652. package/dist/src/contracts/markdown-map.js +0 -2
  653. package/dist/src/contracts/markdown-map.js.map +0 -1
  654. package/dist/src/contracts/presentation-binding.d.ts +0 -116
  655. package/dist/src/contracts/presentation-binding.d.ts.map +0 -1
  656. package/dist/src/contracts/presentation-binding.js +0 -215
  657. package/dist/src/contracts/presentation-binding.js.map +0 -1
  658. package/dist/src/contracts/presentation.d.ts +0 -225
  659. package/dist/src/contracts/presentation.d.ts.map +0 -1
  660. package/dist/src/contracts/presentation.js +0 -2
  661. package/dist/src/contracts/presentation.js.map +0 -1
  662. package/dist/src/contracts/query.d.ts +0 -10
  663. package/dist/src/contracts/query.d.ts.map +0 -1
  664. package/dist/src/contracts/query.js +0 -2
  665. package/dist/src/contracts/query.js.map +0 -1
  666. package/dist/src/contracts/record-history.d.ts +0 -105
  667. package/dist/src/contracts/record-history.d.ts.map +0 -1
  668. package/dist/src/contracts/record-history.js +0 -2
  669. package/dist/src/contracts/record-history.js.map +0 -1
  670. package/dist/src/contracts/references.d.ts +0 -51
  671. package/dist/src/contracts/references.d.ts.map +0 -1
  672. package/dist/src/contracts/references.js +0 -2
  673. package/dist/src/contracts/references.js.map +0 -1
  674. package/dist/src/contracts/render-map.d.ts +0 -173
  675. package/dist/src/contracts/render-map.d.ts.map +0 -1
  676. package/dist/src/contracts/render-map.js +0 -2
  677. package/dist/src/contracts/render-map.js.map +0 -1
  678. package/dist/src/contracts/renderer-snippets.d.ts +0 -45
  679. package/dist/src/contracts/renderer-snippets.d.ts.map +0 -1
  680. package/dist/src/contracts/renderer-snippets.js +0 -2
  681. package/dist/src/contracts/renderer-snippets.js.map +0 -1
  682. package/dist/src/contracts/restore.d.ts +0 -60
  683. package/dist/src/contracts/restore.d.ts.map +0 -1
  684. package/dist/src/contracts/restore.js +0 -2
  685. package/dist/src/contracts/restore.js.map +0 -1
  686. package/dist/src/contracts/search.d.ts +0 -20
  687. package/dist/src/contracts/search.d.ts.map +0 -1
  688. package/dist/src/contracts/search.js +0 -2
  689. package/dist/src/contracts/search.js.map +0 -1
  690. package/dist/src/contracts/snapshots.d.ts +0 -12
  691. package/dist/src/contracts/snapshots.d.ts.map +0 -1
  692. package/dist/src/contracts/snapshots.js +0 -2
  693. package/dist/src/contracts/snapshots.js.map +0 -1
  694. package/dist/src/contracts/stores.d.ts +0 -21
  695. package/dist/src/contracts/stores.d.ts.map +0 -1
  696. package/dist/src/contracts/stores.js +0 -2
  697. package/dist/src/contracts/stores.js.map +0 -1
  698. package/dist/src/contracts/sync.d.ts +0 -7
  699. package/dist/src/contracts/sync.d.ts.map +0 -1
  700. package/dist/src/contracts/sync.js +0 -2
  701. package/dist/src/contracts/sync.js.map +0 -1
  702. package/dist/src/contracts/validation.d.ts +0 -13
  703. package/dist/src/contracts/validation.d.ts.map +0 -1
  704. package/dist/src/contracts/validation.js +0 -2
  705. package/dist/src/contracts/validation.js.map +0 -1
  706. package/dist/src/diagrams/render-catalog-diagram.d.ts +0 -3
  707. package/dist/src/diagrams/render-catalog-diagram.d.ts.map +0 -1
  708. package/dist/src/diagrams/render-catalog-diagram.js.map +0 -1
  709. package/dist/src/diagrams/render-item-diagram.d.ts +0 -3
  710. package/dist/src/diagrams/render-item-diagram.d.ts.map +0 -1
  711. package/dist/src/diagrams/render-item-diagram.js.map +0 -1
  712. package/dist/src/embedder.d.ts +0 -26
  713. package/dist/src/embedder.d.ts.map +0 -1
  714. package/dist/src/embedder.js +0 -25
  715. package/dist/src/embedder.js.map +0 -1
  716. package/dist/src/errors/index.d.ts.map +0 -1
  717. package/dist/src/errors/index.js.map +0 -1
  718. package/dist/src/firebase/adapter-store.d.ts +0 -16
  719. package/dist/src/firebase/adapter-store.d.ts.map +0 -1
  720. package/dist/src/firebase/adapter-store.js.map +0 -1
  721. package/dist/src/firebase/agent-store.d.ts +0 -18
  722. package/dist/src/firebase/agent-store.d.ts.map +0 -1
  723. package/dist/src/firebase/agent-store.js.map +0 -1
  724. package/dist/src/firebase/app-store.d.ts +0 -11
  725. package/dist/src/firebase/app-store.d.ts.map +0 -1
  726. package/dist/src/firebase/app-store.js.map +0 -1
  727. package/dist/src/firebase/binding-store.d.ts +0 -15
  728. package/dist/src/firebase/binding-store.d.ts.map +0 -1
  729. package/dist/src/firebase/binding-store.js.map +0 -1
  730. package/dist/src/firebase/bootstrap.d.ts.map +0 -1
  731. package/dist/src/firebase/bootstrap.js.map +0 -1
  732. package/dist/src/firebase/catalog-data-index-store.d.ts +0 -15
  733. package/dist/src/firebase/catalog-data-index-store.d.ts.map +0 -1
  734. package/dist/src/firebase/catalog-data-index-store.js.map +0 -1
  735. package/dist/src/firebase/catalog-data-paths.d.ts +0 -14
  736. package/dist/src/firebase/catalog-data-paths.d.ts.map +0 -1
  737. package/dist/src/firebase/catalog-data-paths.js.map +0 -1
  738. package/dist/src/firebase/catalog-item-history-store.d.ts +0 -21
  739. package/dist/src/firebase/catalog-item-history-store.d.ts.map +0 -1
  740. package/dist/src/firebase/catalog-item-history-store.js.map +0 -1
  741. package/dist/src/firebase/catalog-store.d.ts +0 -13
  742. package/dist/src/firebase/catalog-store.d.ts.map +0 -1
  743. package/dist/src/firebase/catalog-store.js.map +0 -1
  744. package/dist/src/firebase/catalog-type-store.d.ts +0 -22
  745. package/dist/src/firebase/catalog-type-store.d.ts.map +0 -1
  746. package/dist/src/firebase/catalog-type-store.js.map +0 -1
  747. package/dist/src/firebase/definition-store.d.ts +0 -25
  748. package/dist/src/firebase/definition-store.d.ts.map +0 -1
  749. package/dist/src/firebase/definition-store.js.map +0 -1
  750. package/dist/src/firebase/descriptor-store.d.ts +0 -11
  751. package/dist/src/firebase/descriptor-store.d.ts.map +0 -1
  752. package/dist/src/firebase/descriptor-store.js.map +0 -1
  753. package/dist/src/firebase/design-object-store.d.ts +0 -15
  754. package/dist/src/firebase/design-object-store.d.ts.map +0 -1
  755. package/dist/src/firebase/design-object-store.js.map +0 -1
  756. package/dist/src/firebase/domain-store.d.ts +0 -18
  757. package/dist/src/firebase/domain-store.d.ts.map +0 -1
  758. package/dist/src/firebase/domain-store.js.map +0 -1
  759. package/dist/src/firebase/firestore-collection-path.d.ts.map +0 -1
  760. package/dist/src/firebase/firestore-collection-path.js.map +0 -1
  761. package/dist/src/firebase/firestore-store.d.ts.map +0 -1
  762. package/dist/src/firebase/firestore-store.js.map +0 -1
  763. package/dist/src/firebase/identity-binding-store.d.ts +0 -18
  764. package/dist/src/firebase/identity-binding-store.d.ts.map +0 -1
  765. package/dist/src/firebase/identity-binding-store.js.map +0 -1
  766. package/dist/src/firebase/index.d.ts.map +0 -1
  767. package/dist/src/firebase/index.js.map +0 -1
  768. package/dist/src/firebase/mapping-store.d.ts +0 -12
  769. package/dist/src/firebase/mapping-store.d.ts.map +0 -1
  770. package/dist/src/firebase/mapping-store.js.map +0 -1
  771. package/dist/src/firebase/native-item-store.d.ts +0 -38
  772. package/dist/src/firebase/native-item-store.d.ts.map +0 -1
  773. package/dist/src/firebase/native-item-store.js +0 -110
  774. package/dist/src/firebase/native-item-store.js.map +0 -1
  775. package/dist/src/firebase/presentation-profile-store.d.ts +0 -18
  776. package/dist/src/firebase/presentation-profile-store.d.ts.map +0 -1
  777. package/dist/src/firebase/presentation-profile-store.js.map +0 -1
  778. package/dist/src/firebase/reference-store.d.ts +0 -21
  779. package/dist/src/firebase/reference-store.d.ts.map +0 -1
  780. package/dist/src/firebase/reference-store.js.map +0 -1
  781. package/dist/src/firebase/renderer-snippet-store.d.ts +0 -15
  782. package/dist/src/firebase/renderer-snippet-store.d.ts.map +0 -1
  783. package/dist/src/firebase/renderer-snippet-store.js.map +0 -1
  784. package/dist/src/firebase/snapshot-store.d.ts +0 -19
  785. package/dist/src/firebase/snapshot-store.d.ts.map +0 -1
  786. package/dist/src/firebase/snapshot-store.js.map +0 -1
  787. package/dist/src/firebase/store-app-binding-store.d.ts +0 -14
  788. package/dist/src/firebase/store-app-binding-store.d.ts.map +0 -1
  789. package/dist/src/firebase/store-app-binding-store.js.map +0 -1
  790. package/dist/src/index.d.ts.map +0 -1
  791. package/dist/src/index.js.map +0 -1
  792. package/dist/src/jsx/index.d.ts +0 -70
  793. package/dist/src/jsx/index.d.ts.map +0 -1
  794. package/dist/src/jsx/index.js +0 -175
  795. package/dist/src/jsx/index.js.map +0 -1
  796. package/dist/src/local/in-memory-native-item-store.d.ts +0 -27
  797. package/dist/src/local/in-memory-native-item-store.d.ts.map +0 -1
  798. package/dist/src/local/in-memory-native-item-store.js +0 -107
  799. package/dist/src/local/in-memory-native-item-store.js.map +0 -1
  800. package/dist/src/local/in-memory-stores.d.ts +0 -35
  801. package/dist/src/local/in-memory-stores.d.ts.map +0 -1
  802. package/dist/src/local/in-memory-stores.js.map +0 -1
  803. package/dist/src/local/index.d.ts +0 -4
  804. package/dist/src/local/index.d.ts.map +0 -1
  805. package/dist/src/local/index.js +0 -4
  806. package/dist/src/local/index.js.map +0 -1
  807. package/dist/src/local/local-file-store.d.ts +0 -19
  808. package/dist/src/local/local-file-store.d.ts.map +0 -1
  809. package/dist/src/local/local-file-store.js +0 -25
  810. package/dist/src/local/local-file-store.js.map +0 -1
  811. package/dist/src/local/local-store-error.d.ts +0 -14
  812. package/dist/src/local/local-store-error.d.ts.map +0 -1
  813. package/dist/src/local/local-store-error.js +0 -22
  814. package/dist/src/local/local-store-error.js.map +0 -1
  815. package/dist/src/local/snapshot.d.ts +0 -36
  816. package/dist/src/local/snapshot.d.ts.map +0 -1
  817. package/dist/src/local/snapshot.js +0 -192
  818. package/dist/src/local/snapshot.js.map +0 -1
  819. package/dist/src/local/stub-deps.d.ts.map +0 -1
  820. package/dist/src/local/stub-deps.js.map +0 -1
  821. package/dist/src/local/unavailable-firestore-store.d.ts.map +0 -1
  822. package/dist/src/local/unavailable-firestore-store.js.map +0 -1
  823. package/dist/src/local/wire-local-catalox.d.ts.map +0 -1
  824. package/dist/src/local/wire-local-catalox.js.map +0 -1
  825. package/dist/src/logging.d.ts.map +0 -1
  826. package/dist/src/logging.js.map +0 -1
  827. package/dist/src/mapping/execute-mapping.d.ts +0 -8
  828. package/dist/src/mapping/execute-mapping.d.ts.map +0 -1
  829. package/dist/src/mapping/execute-mapping.js.map +0 -1
  830. package/dist/src/mapping/helper-gap-report.d.ts.map +0 -1
  831. package/dist/src/mapping/helper-gap-report.js.map +0 -1
  832. package/dist/src/mapping/index.d.ts.map +0 -1
  833. package/dist/src/mapping/index.js.map +0 -1
  834. package/dist/src/mapping/validate-mapping.d.ts +0 -3
  835. package/dist/src/mapping/validate-mapping.d.ts.map +0 -1
  836. package/dist/src/mapping/validate-mapping.js.map +0 -1
  837. package/dist/src/markdown/render-item-markdown.d.ts +0 -5
  838. package/dist/src/markdown/render-item-markdown.d.ts.map +0 -1
  839. package/dist/src/markdown/render-item-markdown.js.map +0 -1
  840. package/dist/src/markdown/render-list-markdown.d.ts +0 -5
  841. package/dist/src/markdown/render-list-markdown.d.ts.map +0 -1
  842. package/dist/src/markdown/render-list-markdown.js.map +0 -1
  843. package/dist/src/migrations/backfill-catalog-model.d.ts +0 -29
  844. package/dist/src/migrations/backfill-catalog-model.d.ts.map +0 -1
  845. package/dist/src/migrations/backfill-catalog-model.js.map +0 -1
  846. package/dist/src/migrations/index.d.ts.map +0 -1
  847. package/dist/src/migrations/index.js.map +0 -1
  848. package/dist/src/migrations/migrate-native-catalog-layout.d.ts +0 -51
  849. package/dist/src/migrations/migrate-native-catalog-layout.d.ts.map +0 -1
  850. package/dist/src/migrations/migrate-native-catalog-layout.js.map +0 -1
  851. package/dist/src/migrations/migrate-native-item-scope.d.ts +0 -36
  852. package/dist/src/migrations/migrate-native-item-scope.d.ts.map +0 -1
  853. package/dist/src/migrations/migrate-native-item-scope.js.map +0 -1
  854. package/dist/src/migrations/renderer-metadata.d.ts +0 -7
  855. package/dist/src/migrations/renderer-metadata.d.ts.map +0 -1
  856. package/dist/src/migrations/renderer-metadata.js.map +0 -1
  857. package/dist/src/operator.d.ts.map +0 -1
  858. package/dist/src/operator.js.map +0 -1
  859. package/dist/src/validation/index.d.ts.map +0 -1
  860. package/dist/src/validation/index.js.map +0 -1
  861. package/dist/src/validation/payload-schema-registry.d.ts.map +0 -1
  862. package/dist/src/validation/payload-schema-registry.js.map +0 -1
  863. package/dist/src/validation/payload-schema.d.ts +0 -30
  864. package/dist/src/validation/payload-schema.d.ts.map +0 -1
  865. package/dist/src/validation/payload-schema.js.map +0 -1
  866. package/dist/src/validation/ui-spec-schema.d.ts.map +0 -1
  867. package/dist/src/validation/ui-spec-schema.js.map +0 -1
  868. package/dist/src/validation/ui-spec-validate.d.ts.map +0 -1
  869. package/dist/src/validation/ui-spec-validate.js.map +0 -1
  870. package/docs/catalox-ui-contract.md +0 -132
  871. package/docs/cli-items.md +0 -94
  872. package/docs/cli-snapshot-export.md +0 -65
  873. package/docs/cli-toolbox.md +0 -166
  874. package/firestore.indexes.json +0 -39
  875. /package/{dist/src → packages/engine/dist}/adapters/api/index.d.ts +0 -0
  876. /package/{dist/src → packages/engine/dist}/adapters/api/index.js +0 -0
  877. /package/{dist/src → packages/engine/dist}/adapters/mongo/index.d.ts +0 -0
  878. /package/{dist/src → packages/engine/dist}/adapters/mongo/index.js +0 -0
  879. /package/{dist/src → packages/engine/dist}/adapters/mongo/resolve-db.js +0 -0
  880. /package/{dist/src → packages/engine/dist}/bindings/index.d.ts +0 -0
  881. /package/{dist/src → packages/engine/dist}/bindings/index.js +0 -0
  882. /package/{dist/src → packages/engine/dist}/catalox/backup-data.js +0 -0
  883. /package/{dist/src → packages/engine/dist}/catalox/catalog-discovery.js +0 -0
  884. /package/{dist/src → packages/engine/dist}/catalox/catalog-lifecycle.js +0 -0
  885. /package/{dist/src → packages/engine/dist}/catalox/catalox-gcs-backup-export-manifest.js +0 -0
  886. /package/{dist/src → packages/engine/dist}/catalox/context.js +0 -0
  887. /package/{dist/src → packages/engine/dist}/catalox/field-source-resolution.js +0 -0
  888. /package/{dist/src → packages/engine/dist}/catalox/firestore-gcs-compare.js +0 -0
  889. /package/{dist/src → packages/engine/dist}/catalox/firestore-gcs-transfer.js +0 -0
  890. /package/{dist/src → packages/engine/dist}/catalox/identity.js +0 -0
  891. /package/{dist/src → packages/engine/dist}/catalox/index.d.ts +0 -0
  892. /package/{dist/src → packages/engine/dist}/catalox/index.js +0 -0
  893. /package/{dist/src → packages/engine/dist}/catalox/item-scope-match.js +0 -0
  894. /package/{dist/src → packages/engine/dist}/catalox/json-io.d.ts +0 -0
  895. /package/{dist/src → packages/engine/dist}/catalox/json-io.js +0 -0
  896. /package/{dist/src → packages/engine/dist}/catalox/native-catalog-layout-diagnostics.js +0 -0
  897. /package/{dist/src → packages/engine/dist}/catalox/native-item-resolve.js +0 -0
  898. /package/{dist/src → packages/engine/dist}/catalox/record-history-field.js +0 -0
  899. /package/{dist/src → packages/engine/dist}/catalox/record-history.js +0 -0
  900. /package/{dist/src → packages/engine/dist}/catalox/reporting/render-inventory-report.js +0 -0
  901. /package/{dist/src → packages/engine/dist}/catalox/restore-firestore-backup-from-gcs.js +0 -0
  902. /package/{dist/src → packages/engine/dist}/catalox/restore-firestore-backup.js +0 -0
  903. /package/{dist/src → packages/engine/dist}/catalox/scope-legacy-convert.js +0 -0
  904. /package/{dist/src → packages/engine/dist}/catalox/seed-preset-resolve.d.ts +0 -0
  905. /package/{dist/src → packages/engine/dist}/catalox/seed-preset-resolve.js +0 -0
  906. /package/{dist/src → packages/engine/dist}/catalox/seed-preset.js +0 -0
  907. /package/{dist/src → packages/engine/dist}/cli/index.d.ts +0 -0
  908. /package/{dist/src → packages/engine/dist}/cli/item-json.d.ts +0 -0
  909. /package/{dist/src → packages/engine/dist}/cli/item-json.js +0 -0
  910. /package/{dist/src → packages/engine/dist}/diagrams/render-catalog-diagram.js +0 -0
  911. /package/{dist/src → packages/engine/dist}/diagrams/render-item-diagram.js +0 -0
  912. /package/{dist/src → packages/engine/dist}/errors/index.d.ts +0 -0
  913. /package/{dist/src → packages/engine/dist}/errors/index.js +0 -0
  914. /package/{dist/src → packages/engine/dist}/firebase/adapter-store.js +0 -0
  915. /package/{dist/src → packages/engine/dist}/firebase/agent-store.js +0 -0
  916. /package/{dist/src → packages/engine/dist}/firebase/app-store.js +0 -0
  917. /package/{dist/src → packages/engine/dist}/firebase/binding-store.js +0 -0
  918. /package/{dist/src → packages/engine/dist}/firebase/bootstrap.d.ts +0 -0
  919. /package/{dist/src → packages/engine/dist}/firebase/bootstrap.js +0 -0
  920. /package/{dist/src → packages/engine/dist}/firebase/catalog-data-index-store.js +0 -0
  921. /package/{dist/src → packages/engine/dist}/firebase/catalog-data-paths.js +0 -0
  922. /package/{dist/src → packages/engine/dist}/firebase/catalog-item-history-store.js +0 -0
  923. /package/{dist/src → packages/engine/dist}/firebase/catalog-store.js +0 -0
  924. /package/{dist/src → packages/engine/dist}/firebase/catalog-type-store.js +0 -0
  925. /package/{dist/src → packages/engine/dist}/firebase/definition-store.js +0 -0
  926. /package/{dist/src → packages/engine/dist}/firebase/descriptor-store.js +0 -0
  927. /package/{dist/src → packages/engine/dist}/firebase/design-object-store.js +0 -0
  928. /package/{dist/src → packages/engine/dist}/firebase/domain-store.js +0 -0
  929. /package/{dist/src → packages/engine/dist}/firebase/firestore-collection-path.d.ts +0 -0
  930. /package/{dist/src → packages/engine/dist}/firebase/firestore-collection-path.js +0 -0
  931. /package/{dist/src → packages/engine/dist}/firebase/firestore-store.d.ts +0 -0
  932. /package/{dist/src → packages/engine/dist}/firebase/firestore-store.js +0 -0
  933. /package/{dist/src → packages/engine/dist}/firebase/identity-binding-store.js +0 -0
  934. /package/{dist/src → packages/engine/dist}/firebase/index.d.ts +0 -0
  935. /package/{dist/src → packages/engine/dist}/firebase/index.js +0 -0
  936. /package/{dist/src → packages/engine/dist}/firebase/mapping-store.js +0 -0
  937. /package/{dist/src → packages/engine/dist}/firebase/presentation-profile-store.js +0 -0
  938. /package/{dist/src → packages/engine/dist}/firebase/reference-store.js +0 -0
  939. /package/{dist/src → packages/engine/dist}/firebase/renderer-snippet-store.js +0 -0
  940. /package/{dist/src → packages/engine/dist}/firebase/snapshot-store.js +0 -0
  941. /package/{dist/src → packages/engine/dist}/firebase/store-app-binding-store.js +0 -0
  942. /package/{dist/src → packages/engine/dist}/index.d.ts +0 -0
  943. /package/{dist/src → packages/engine/dist}/index.js +0 -0
  944. /package/{dist/src → packages/engine/dist}/local/in-memory-stores.js +0 -0
  945. /package/{dist/src → packages/engine/dist}/local/stub-deps.d.ts +0 -0
  946. /package/{dist/src → packages/engine/dist}/local/stub-deps.js +0 -0
  947. /package/{dist/src → packages/engine/dist}/local/unavailable-firestore-store.d.ts +0 -0
  948. /package/{dist/src → packages/engine/dist}/local/unavailable-firestore-store.js +0 -0
  949. /package/{dist/src → packages/engine/dist}/local/wire-local-catalox.d.ts +0 -0
  950. /package/{dist/src → packages/engine/dist}/local/wire-local-catalox.js +0 -0
  951. /package/{dist/src → packages/engine/dist}/logging.d.ts +0 -0
  952. /package/{dist/src → packages/engine/dist}/logging.js +0 -0
  953. /package/{dist/src → packages/engine/dist}/mapping/execute-mapping.js +0 -0
  954. /package/{dist/src → packages/engine/dist}/mapping/helper-gap-report.d.ts +0 -0
  955. /package/{dist/src → packages/engine/dist}/mapping/helper-gap-report.js +0 -0
  956. /package/{dist/src → packages/engine/dist}/mapping/index.d.ts +0 -0
  957. /package/{dist/src → packages/engine/dist}/mapping/index.js +0 -0
  958. /package/{dist/src → packages/engine/dist}/mapping/validate-mapping.js +0 -0
  959. /package/{dist/src → packages/engine/dist}/markdown/render-item-markdown.js +0 -0
  960. /package/{dist/src → packages/engine/dist}/markdown/render-list-markdown.js +0 -0
  961. /package/{dist/src → packages/engine/dist}/migrations/backfill-catalog-model.js +0 -0
  962. /package/{dist/src → packages/engine/dist}/migrations/index.d.ts +0 -0
  963. /package/{dist/src → packages/engine/dist}/migrations/index.js +0 -0
  964. /package/{dist/src → packages/engine/dist}/migrations/migrate-native-catalog-layout.js +0 -0
  965. /package/{dist/src → packages/engine/dist}/migrations/migrate-native-item-scope.js +0 -0
  966. /package/{dist/src → packages/engine/dist}/migrations/renderer-metadata.js +0 -0
  967. /package/{dist/src → packages/engine/dist}/operator.d.ts +0 -0
  968. /package/{dist/src → packages/engine/dist}/operator.js +0 -0
  969. /package/{dist/src → packages/engine/dist}/validation/index.d.ts +0 -0
  970. /package/{dist/src → packages/engine/dist}/validation/index.js +0 -0
  971. /package/{dist/src → packages/engine/dist}/validation/payload-schema-registry.d.ts +0 -0
  972. /package/{dist/src → packages/engine/dist}/validation/payload-schema-registry.js +0 -0
  973. /package/{dist/src → packages/engine/dist}/validation/payload-schema.js +0 -0
  974. /package/{dist/src → packages/engine/dist}/validation/ui-spec-schema.d.ts +0 -0
  975. /package/{dist/src → packages/engine/dist}/validation/ui-spec-schema.js +0 -0
  976. /package/{dist/src → packages/engine/dist}/validation/ui-spec-validate.d.ts +0 -0
  977. /package/{dist/src → packages/engine/dist}/validation/ui-spec-validate.js +0 -0
  978. /package/{presets → packages/engine/presets}/native-map-v1.json +0 -0
  979. /package/{presets → packages/engine/presets}/registry.json +0 -0
  980. /package/{schemas → packages/engine/schemas}/native-map-item/v1.json +0 -0
  981. /package/{schemas → packages/engine/schemas}/registry.json +0 -0
@@ -0,0 +1,2892 @@
1
+ import { compactCatalogFilter } from "@x12i/catalox-contracts/catalogs.js";
2
+ import { CatalogAccessDeniedError, CatalogAdapterError, CatalogBindingError, CatalogNotFoundError, CatalogValidationError, } from "@x12i/catalox-contracts/errors.js";
3
+ import { validateMappingSpec } from "../mapping/validate-mapping.js";
4
+ import { resolvePayloadSchema, validateNativeItemPayload, } from "../validation/payload-schema.js";
5
+ import { createBundledPayloadSchemaRegistry } from "../validation/payload-schema-registry.js";
6
+ import { executeMapping } from "../mapping/execute-mapping.js";
7
+ import { ApiCatalogAdapter } from "../adapters/api/api-adapter.js";
8
+ import { MongoCatalogAdapter } from "../adapters/mongo/mongo-adapter.js";
9
+ import { AuthorizationService } from "./authorization.js";
10
+ import { resolveCatalogItemId } from "./identity.js";
11
+ import { assertWriteScopeAllowed, indexedScopeFields, isGenericScope, metadataFromScope, normalizeItemScope, parseWriteScopeInput, scopeFromRecordField, } from "./item-scope.js";
12
+ import { isUnrestrictedScopeContext, mergeEffectiveScope, resolveCatalogScopeFetchMode, shouldIncludeItemInList, tokenScopeFromContext, } from "./item-scope-match.js";
13
+ import { mergeNativePhysicalRows, pickWinningPhysicalRow, toUnifiedNativeItem } from "./native-catalog-merge.js";
14
+ import { planNativeListFilters, resolveNativeRowsByLogicalItemId } from "./native-item-resolve.js";
15
+ import { deriveIndexedFromSmartProperties, resolveSmartPropertiesOnWrite, validateSmartPropertiesForItem, validateSmartPropertyRules, } from "./smart-properties.js";
16
+ import { parseJson, toJson } from "./json-io.js";
17
+ import { buildCataloxExportV1, filterCatalogEntries, listAllCatalogItemsForExport, stripItemData, } from "./catalog-snapshot-export.js";
18
+ import { createHash, randomUUID } from "node:crypto";
19
+ import { renderInventoryReportMarkdown } from "./reporting/render-inventory-report.js";
20
+ import { optionsFromCatalogItems, optionsFromStaticSource, resolveFilterBy } from "./field-source-resolution.js";
21
+ import { resolveCatalogPresentationBinding } from "@x12i/catalox-contracts/presentation-binding.js";
22
+ import { buildRendererSnippetDocId } from "../migrations/renderer-metadata.js";
23
+ import { backfillCatalogModel } from "../migrations/backfill-catalog-model.js";
24
+ import { AppStore } from "../firebase/app-store.js";
25
+ import { AdapterStore } from "../firebase/adapter-store.js";
26
+ import { BindingStore } from "../firebase/binding-store.js";
27
+ import { CatalogStore } from "../firebase/catalog-store.js";
28
+ import { CatalogDataIndexStore } from "../firebase/catalog-data-index-store.js";
29
+ import { CatalogTypeStore } from "../firebase/catalog-type-store.js";
30
+ import { DomainStore } from "../firebase/domain-store.js";
31
+ import { AgentStore } from "../firebase/agent-store.js";
32
+ import { DefinitionStore } from "../firebase/definition-store.js";
33
+ import { DescriptorStore } from "../firebase/descriptor-store.js";
34
+ import { FirestoreStore } from "../firebase/firestore-store.js";
35
+ import { MappingStore } from "../firebase/mapping-store.js";
36
+ import { NativeItemStore, storageDocIdForNativeRecord } from "../firebase/native-item-store.js";
37
+ import { ReferenceStore } from "../firebase/reference-store.js";
38
+ import { RendererSnippetStore } from "../firebase/renderer-snippet-store.js";
39
+ import { SnapshotStore } from "../firebase/snapshot-store.js";
40
+ import { StoreAppBindingStore } from "../firebase/store-app-binding-store.js";
41
+ import { IdentityBindingStore } from "../firebase/identity-binding-store.js";
42
+ import { nativeItemsCollectionId } from "../firebase/catalog-data-paths.js";
43
+ import { applyCatalogVisibilityFilter, filterCatalogsByText, summarizeCatalog, } from "./catalog-discovery.js";
44
+ import { runBackupData, pruneGcsBackupRuns } from "./backup-data.js";
45
+ import { runUndoFirestoreRestore } from "./restore-firestore-backup.js";
46
+ import { runRestoreFirestoreBackupFromGcs, runDeleteCataloxGcsBackupRun } from "./restore-firestore-backup-from-gcs.js";
47
+ import { cataloxGcsBackupManifestToFirestoreExportManifest } from "./catalox-gcs-backup-export-manifest.js";
48
+ import { migrateNativeCatalogLayout as runMigrateNativeCatalogLayout, } from "../migrations/migrate-native-catalog-layout.js";
49
+ import { migrateNativeItemScope as runMigrateNativeItemScope, } from "../migrations/migrate-native-item-scope.js";
50
+ import { reportNativeCatalogLayoutDiagnostics as runReportNativeCatalogLayoutDiagnostics, } from "./native-catalog-layout-diagnostics.js";
51
+ import { exportAllFirestoreCollectionsToGcs, exportFirestoreCollectionToGcs, restoreAllFirestoreCollectionsFromGcsManifest, restoreFirestoreCollectionFromGcs, } from "./firestore-gcs-transfer.js";
52
+ import { compareAllFirestoreCollectionsWithGcsManifest, compareFirestoreCollectionWithGcsNdjson, } from "./firestore-gcs-compare.js";
53
+ import { CataloxBound } from "./catalox-bound.js";
54
+ import { emitRecordHistoryEvent, readRecordHistoryEventPayload, } from "./record-history.js";
55
+ import { extractFieldChange, isItemFieldHistoryOp, normalizeRecordFieldPath, readRecordFieldPath, setAtRelativePath, } from "./record-history-field.js";
56
+ import { runDeleteCatalog, runRenameCatalog, runRestoreDeletedCatalog, } from "./catalog-lifecycle.js";
57
+ export class Catalox {
58
+ deps;
59
+ payloadSchemaRegistry;
60
+ constructor(deps) {
61
+ this.deps = deps;
62
+ this.payloadSchemaRegistry = deps.payloadSchemas ?? createBundledPayloadSchemaRegistry();
63
+ }
64
+ getPayloadSchemaRegistry() {
65
+ return this.payloadSchemaRegistry;
66
+ }
67
+ nativeItemSourceType() {
68
+ return this.deps.nativeSourceType ?? "firebase";
69
+ }
70
+ async resolveCatalogTypeRegistry(context) {
71
+ if (!this.deps.catalogTypes)
72
+ return null;
73
+ return this.deps.catalogTypes.resolveForContext({
74
+ ...(context.storeId ? { storeId: context.storeId } : {}),
75
+ ...(context.appId ? { appId: context.appId } : {}),
76
+ });
77
+ }
78
+ resolvePayloadSchemaForCatalog(catalog, catalogTypeRegistry) {
79
+ return resolvePayloadSchema({
80
+ catalog,
81
+ catalogTypeRegistry: catalogTypeRegistry ?? null,
82
+ registry: this.getPayloadSchemaRegistry(),
83
+ });
84
+ }
85
+ validateNativeItemData(data, catalog, catalogTypeRegistry) {
86
+ const resolved = this.resolvePayloadSchemaForCatalog(catalog, catalogTypeRegistry);
87
+ if (!resolved)
88
+ return { isValid: true, issues: [] };
89
+ return validateNativeItemPayload(data, resolved, this.getPayloadSchemaRegistry());
90
+ }
91
+ async assertNativeItemPayloadValid(context, catalogId, data, logicalItemId) {
92
+ if (!this.deps.catalogs)
93
+ return;
94
+ const catalog = await this.deps.catalogs.get(catalogId);
95
+ if (!catalog)
96
+ return;
97
+ const typeRegistry = await this.resolveCatalogTypeRegistry(context);
98
+ const report = this.validateNativeItemData(data, catalog, typeRegistry);
99
+ if (report.isValid)
100
+ return;
101
+ throw new CatalogValidationError({
102
+ reason: "invalid_payload",
103
+ catalogId: String(catalogId),
104
+ ...(logicalItemId != null ? { itemId: logicalItemId } : {}),
105
+ report,
106
+ });
107
+ }
108
+ encodeRefSegment(value) {
109
+ // Keep IDs stable and URL-safe for use as Firestore doc ids.
110
+ return encodeURIComponent(String(value));
111
+ }
112
+ buildReferenceId(input) {
113
+ const parts = [
114
+ "ref",
115
+ this.encodeRefSegment(input.fromCatalogId),
116
+ this.encodeRefSegment(input.fromItemId),
117
+ this.encodeRefSegment(input.relationType),
118
+ this.encodeRefSegment(input.toCatalogId),
119
+ this.encodeRefSegment(input.toItemId),
120
+ ];
121
+ return parts.join("|");
122
+ }
123
+ normalizeRelationWrites(value) {
124
+ if (!Array.isArray(value))
125
+ return [];
126
+ const out = [];
127
+ for (const v of value) {
128
+ if (!v || typeof v !== "object")
129
+ continue;
130
+ const r = v;
131
+ if (r.toCatalogId == null || r.toItemId == null || r.relationType == null)
132
+ continue;
133
+ out.push({
134
+ toCatalogId: String(r.toCatalogId),
135
+ toItemId: String(r.toItemId),
136
+ relationType: String(r.relationType),
137
+ ...(r.label != null ? { label: String(r.label) } : {}),
138
+ ...(r.metadata != null && typeof r.metadata === "object" ? { metadata: r.metadata } : {}),
139
+ });
140
+ }
141
+ return out;
142
+ }
143
+ async validateRelationsAgainstDescriptor(context, params) {
144
+ const rules = params.descriptor?.relationRules;
145
+ if (!rules?.length)
146
+ return { isValid: true, issues: [] };
147
+ const ruleByType = new Map();
148
+ for (const r of rules) {
149
+ if (r && typeof r === "object" && r.relationType != null) {
150
+ ruleByType.set(String(r.relationType), r);
151
+ }
152
+ }
153
+ const issues = [];
154
+ const counts = new Map();
155
+ for (const ref of params.refs) {
156
+ const rt = String(ref.relationType);
157
+ counts.set(rt, (counts.get(rt) ?? 0) + 1);
158
+ const rule = ruleByType.get(rt);
159
+ if (!rule) {
160
+ issues.push({
161
+ code: "relation.disallowed_type",
162
+ severity: "error",
163
+ message: `relationType "${rt}" is not allowed by descriptor for catalog "${String(params.catalogId)}".`,
164
+ path: "relations",
165
+ });
166
+ continue;
167
+ }
168
+ if (Array.isArray(rule.targetCatalogIds) && rule.targetCatalogIds.length) {
169
+ const allowed = new Set(rule.targetCatalogIds.map((x) => String(x)));
170
+ if (!allowed.has(String(ref.toCatalogId))) {
171
+ issues.push({
172
+ code: "relation.disallowed_target_catalog",
173
+ severity: "error",
174
+ message: `relationType "${rt}" cannot target catalog "${String(ref.toCatalogId)}".`,
175
+ path: "relations",
176
+ });
177
+ }
178
+ }
179
+ if (Array.isArray(rule.targetCatalogTypes) && rule.targetCatalogTypes.length) {
180
+ try {
181
+ const targetDescriptor = await this.getCatalogDescriptor(context, ref.toCatalogId);
182
+ const targetType = targetDescriptor?.catalogType ? String(targetDescriptor.catalogType) : undefined;
183
+ const allowedTypes = new Set(rule.targetCatalogTypes.map((x) => String(x)));
184
+ if (!targetType || !allowedTypes.has(targetType)) {
185
+ issues.push({
186
+ code: "relation.disallowed_target_type",
187
+ severity: "error",
188
+ message: `relationType "${rt}" cannot target catalogType "${String(targetType ?? "unknown")}".`,
189
+ path: "relations",
190
+ });
191
+ }
192
+ }
193
+ catch {
194
+ issues.push({
195
+ code: "relation.target_type_unverifiable",
196
+ severity: "warning",
197
+ message: `relationType "${rt}" target catalogType could not be verified for "${String(ref.toCatalogId)}".`,
198
+ path: "relations",
199
+ });
200
+ }
201
+ }
202
+ }
203
+ for (const [rt, rule] of ruleByType.entries()) {
204
+ const required = Boolean(rule.required);
205
+ const multiple = rule.multiple !== false;
206
+ const count = counts.get(rt) ?? 0;
207
+ if (required && count === 0) {
208
+ issues.push({
209
+ code: "relation.missing_required",
210
+ severity: "error",
211
+ message: `Missing required relationType "${rt}".`,
212
+ path: "relations",
213
+ });
214
+ }
215
+ if (!multiple && count > 1) {
216
+ issues.push({
217
+ code: "relation.too_many",
218
+ severity: "error",
219
+ message: `relationType "${rt}" allows only one relation, but found ${count}.`,
220
+ path: "relations",
221
+ });
222
+ }
223
+ }
224
+ return { isValid: issues.every((i) => i.severity !== "error"), issues };
225
+ }
226
+ async validateCatalogTypeForContext(context, catalogType) {
227
+ const registry = this.deps.catalogTypes
228
+ ? await this.deps.catalogTypes.resolveForContext({
229
+ ...(context.storeId ? { storeId: context.storeId } : {}),
230
+ ...(context.appId ? { appId: context.appId } : {}),
231
+ })
232
+ : null;
233
+ if (!registry)
234
+ return; // registry not configured or no entry exists yet
235
+ const allowed = new Set((registry.types ?? []).map((t) => String(t)));
236
+ if (!allowed.has(String(catalogType))) {
237
+ throw new CatalogAdapterError({
238
+ reason: "catalog_type_not_allowed",
239
+ message: `catalogType "${String(catalogType)}" is not allowed for scope ${JSON.stringify(registry.scope)}.`,
240
+ });
241
+ }
242
+ }
243
+ catalogLifecycleDeps() {
244
+ return {
245
+ firestoreStore: this.deps.firestoreStore,
246
+ catalogs: this.deps.catalogs,
247
+ bindings: this.deps.bindings,
248
+ definitions: this.deps.definitions,
249
+ descriptors: this.deps.descriptors,
250
+ mappings: this.deps.mappings,
251
+ adapters: this.deps.adapters,
252
+ references: this.deps.references,
253
+ nativeItems: this.deps.nativeItems,
254
+ snapshots: this.deps.snapshots,
255
+ catalogDataIndex: this.deps.catalogDataIndex,
256
+ ...(this.deps.rendererSnippets ? { rendererSnippets: this.deps.rendererSnippets } : {}),
257
+ };
258
+ }
259
+ async emitNativeItemHistory(context, params) {
260
+ const rh = this.deps.recordHistory;
261
+ if (!rh)
262
+ return;
263
+ const res = await emitRecordHistoryEvent(rh, context, {
264
+ catalogId: params.catalogId,
265
+ itemId: params.itemId,
266
+ ...(params.storageDocId != null ? { storageDocId: params.storageDocId } : {}),
267
+ op: params.op,
268
+ ...(params.before !== undefined ? { before: params.before } : {}),
269
+ ...(params.after !== undefined ? { after: params.after } : {}),
270
+ });
271
+ if (!res.ok && rh.failClosed)
272
+ throw new Error(`recordHistory: ${res.error}`);
273
+ }
274
+ resolveActorId(context) {
275
+ return context.userId ?? context.actor?.id;
276
+ }
277
+ stableStringify(value) {
278
+ const seen = new WeakSet();
279
+ const walk = (v) => {
280
+ if (v == null || typeof v !== "object")
281
+ return v;
282
+ if (seen.has(v))
283
+ return "[Circular]";
284
+ seen.add(v);
285
+ if (Array.isArray(v))
286
+ return v.map(walk);
287
+ const out = {};
288
+ for (const k of Object.keys(v).sort())
289
+ out[k] = walk(v[k]);
290
+ return out;
291
+ };
292
+ return JSON.stringify(walk(value));
293
+ }
294
+ fingerprint(value) {
295
+ return createHash("sha256").update(this.stableStringify(value)).digest("hex");
296
+ }
297
+ async resolveEffectiveAppIds(context, input) {
298
+ const storeId = input?.storeId ?? context.storeId;
299
+ if (input?.appIds?.length)
300
+ return { ...(storeId ? { storeId } : {}), appIds: input.appIds };
301
+ if (storeId && this.deps.storeAppBindings) {
302
+ const bindings = await this.deps.storeAppBindings.listAppsByStore(storeId);
303
+ const active = bindings.filter((b) => b.status === "active").map((b) => b.appId);
304
+ if (active.length)
305
+ return { storeId, appIds: active };
306
+ }
307
+ if (!context.appId) {
308
+ throw new CatalogBindingError({
309
+ reason: "missing_appId",
310
+ message: "App id is required unless storeId/appIds are provided.",
311
+ });
312
+ }
313
+ return { ...(storeId ? { storeId } : {}), appIds: [context.appId] };
314
+ }
315
+ async resolveAppIdForCatalogAccess(params) {
316
+ const { context, catalogId, required } = params;
317
+ if (context.appId)
318
+ return context.appId;
319
+ // Super-admin callers may omit appId; access is still evaluated with explicit elevation.
320
+ if (context.superAdmin)
321
+ return "_super";
322
+ // CatalogId-first: infer appId via active bindings if there is exactly one viable binding.
323
+ const bindings = await this.deps.bindings.listByCatalog(catalogId);
324
+ const active = bindings.filter((b) => b.status === "active");
325
+ const viable = active.filter((b) => {
326
+ if (required === "read")
327
+ return Boolean(b.access.canRead);
328
+ if (required === "write")
329
+ return Boolean(b.access.canWrite);
330
+ return Boolean(b.access.canAdmin);
331
+ });
332
+ const distinctApps = [...new Set(viable.map((b) => String(b.appId)))];
333
+ if (distinctApps.length === 1)
334
+ return viable[0].appId;
335
+ throw new CatalogBindingError({
336
+ reason: "cannot_resolve_appId_for_catalog",
337
+ catalogId: String(catalogId),
338
+ required,
339
+ matchingAppIds: distinctApps,
340
+ });
341
+ }
342
+ readPath(obj, path) {
343
+ if (!path)
344
+ return undefined;
345
+ const parts = path.split(".").filter(Boolean);
346
+ let cur = obj;
347
+ for (const p of parts) {
348
+ if (cur == null || typeof cur !== "object")
349
+ return undefined;
350
+ cur = cur[p];
351
+ }
352
+ return cur;
353
+ }
354
+ gatherDescriptorSources(descriptor) {
355
+ const out = {};
356
+ if (!descriptor)
357
+ return out;
358
+ const filterSpec = descriptor.filterSpec;
359
+ for (const f of filterSpec?.filters ?? []) {
360
+ if (f?.fieldPath && f.source)
361
+ out[String(f.fieldPath)] = f.source;
362
+ }
363
+ const presentationFields = descriptor.presentationSpec?.fields;
364
+ for (const fp of presentationFields ?? []) {
365
+ if (fp?.fieldPath && fp.source)
366
+ out[String(fp.fieldPath)] = fp.source;
367
+ }
368
+ return out;
369
+ }
370
+ async resolveFieldSourceOptions(params) {
371
+ const maxOptions = params.maxOptions ?? 200;
372
+ const source = params.source;
373
+ if (source.type === "static") {
374
+ return optionsFromStaticSource(source);
375
+ }
376
+ if (source.type === "field-distinct") {
377
+ // Distinct values for this field in the current catalog.
378
+ const list = await this.listCatalogItems(params.context, params.currentCatalogId, { limit: 500 });
379
+ const values = new Map();
380
+ for (const it of list.items) {
381
+ const v = this.readPath(it.data, params.fieldPath);
382
+ if (v == null)
383
+ continue;
384
+ const value = typeof v === "string" || typeof v === "number" ? v : String(v);
385
+ if (!values.has(value))
386
+ values.set(value, { value, label: String(value) });
387
+ }
388
+ return [...values.values()].slice(0, maxOptions);
389
+ }
390
+ if (source.type === "catalog") {
391
+ // Enforce authz: safest default is to require binding (unless god-mode).
392
+ const appId = await this.resolveAppIdForCatalogAccess({
393
+ context: params.context,
394
+ catalogId: source.catalogId,
395
+ required: "read",
396
+ });
397
+ await this.deps.authz.requireBindingAccess(params.context, appId, source.catalogId, "read");
398
+ const filterEq = resolveFilterBy(source.filterBy, params.currentItemData, (o, p) => this.readPath(o, p));
399
+ const sort = source.sortBy
400
+ ? { [source.sortBy.field]: source.sortBy.direction === "asc" ? 1 : -1 }
401
+ : undefined;
402
+ const list = await this.listCatalogItems(params.context, source.catalogId, {
403
+ limit: maxOptions,
404
+ ...(Object.keys(filterEq).length ? { filter: filterEq } : {}),
405
+ ...(sort ? { sort } : {}),
406
+ });
407
+ return optionsFromCatalogItems({
408
+ items: list.items.map((i) => ({ data: i.data })),
409
+ valueField: source.valueField,
410
+ labelField: source.labelField,
411
+ readPath: (o, p) => this.readPath(o, p),
412
+ });
413
+ }
414
+ return [];
415
+ }
416
+ async buildCatalogListRenderMap(context, catalogId, options) {
417
+ const descriptor = await this.getCatalogDescriptor(context, catalogId);
418
+ const list = await this.listCatalogItems(context, catalogId, { limit: options?.limit ?? 50 });
419
+ const sources = this.gatherDescriptorSources(descriptor);
420
+ const resolvedSources = {};
421
+ if (options?.resolveSources !== false) {
422
+ for (const [fieldPath, source] of Object.entries(sources)) {
423
+ // In list context we do not have current item data; $. paths in filterBy will be ignored.
424
+ resolvedSources[fieldPath] = await this.resolveFieldSourceOptions({
425
+ context,
426
+ currentCatalogId: catalogId,
427
+ fieldPath,
428
+ source,
429
+ ...(options?.maxSourceOptions != null ? { maxOptions: options.maxSourceOptions } : {}),
430
+ });
431
+ }
432
+ }
433
+ return {
434
+ catalogId: String(catalogId),
435
+ label: descriptor?.label ?? String(catalogId),
436
+ ...(descriptor?.itemLabel != null ? { itemLabel: descriptor.itemLabel } : {}),
437
+ items: list.items.map((i) => ({
438
+ itemId: String(i.itemId),
439
+ data: (i.data ?? {}),
440
+ ...(i.title != null ? { title: i.title } : {}),
441
+ ...(i.subtitle != null ? { subtitle: i.subtitle } : {}),
442
+ ...(i.metadata?.status != null ? { status: String(i.metadata.status) } : {}),
443
+ ...(i.metadata != null ? { metadata: i.metadata } : {}),
444
+ })),
445
+ ...(list.total != null ? { total: list.total } : {}),
446
+ resolvedSources,
447
+ filters: {
448
+ active: {},
449
+ ...(descriptor?.filterSpec ? { spec: descriptor.filterSpec } : {}),
450
+ },
451
+ sort: null,
452
+ pagination: { page: 1, pageSize: options?.limit ?? 50, hasMore: Boolean(list.nextCursor) },
453
+ selection: [],
454
+ ...(descriptor?.presentationSpec ? { presentation: descriptor.presentationSpec } : {}),
455
+ capabilities: descriptor?.capabilities ?? {
456
+ canList: true,
457
+ canGet: true,
458
+ canCreate: false,
459
+ canEdit: false,
460
+ canDelete: false,
461
+ },
462
+ context: { mode: "view", displayContext: options?.displayContext ?? "grid" },
463
+ actions: {},
464
+ };
465
+ }
466
+ async getDesignObject(context, designId) {
467
+ void context;
468
+ if (!this.deps.designObjects)
469
+ throw new Error("designObjects dependency is not configured");
470
+ return this.deps.designObjects.get(String(designId));
471
+ }
472
+ async listDesignObjects(context, scope) {
473
+ void context;
474
+ if (!this.deps.designObjects)
475
+ throw new Error("designObjects dependency is not configured");
476
+ return this.deps.designObjects.listByScope(scope);
477
+ }
478
+ async getCatalogPresentationBinding(context, catalogId, role, options) {
479
+ const descriptor = await this.getCatalogDescriptor(context, catalogId);
480
+ const profiles = options?.profiles
481
+ ? options.profiles
482
+ : this.deps.presentationProfiles
483
+ ? await this.deps.presentationProfiles.listForCatalog?.({
484
+ catalogId: String(catalogId),
485
+ ...(descriptor?.catalogType ? { catalogType: String(descriptor.catalogType) } : {}),
486
+ })
487
+ : [];
488
+ const bindingBase = resolveCatalogPresentationBinding({
489
+ descriptor,
490
+ profiles,
491
+ role: role,
492
+ ...(options?.mode ? { mode: options.mode } : {}),
493
+ ...(options?.displayContext ? { displayContext: options.displayContext } : {}),
494
+ ...(options?.designScope ? { designScope: options.designScope } : {}),
495
+ ...(options?.designObjects ? { designObjects: options.designObjects } : {}),
496
+ });
497
+ // Optionally fetch snippet metadata when a snippetRef is involved.
498
+ if (options?.includeSnippet && bindingBase.customRenderer?.entry?.snippetRef) {
499
+ const entry = bindingBase.customRenderer.entry;
500
+ const snippetId = entry.snippetRef?.snippetId;
501
+ const catalogScoped = entry.snippetRef?.catalogScoped !== false;
502
+ if (!this.deps.rendererSnippets)
503
+ throw new Error("rendererSnippets dependency is not configured");
504
+ // Support canonical catalog-scoped ids; for anything else, require host-side snippet resolution.
505
+ if (!snippetId) {
506
+ const rec = await this.getCatalogRendererSnippet(context, catalogId, role, options?.mode);
507
+ return { ...bindingBase, customRenderer: { ...bindingBase.customRenderer, snippet: rec } };
508
+ }
509
+ if (catalogScoped) {
510
+ const expected1 = buildRendererSnippetDocId({ catalogId: String(catalogId), role: role, ...(options?.mode ? { mode: options.mode } : {}) });
511
+ if (String(snippetId) !== expected1) {
512
+ throw new Error(`snippetRef.snippetId is not a canonical catalog-scoped id: ${String(snippetId)}`);
513
+ }
514
+ const rec = await this.getCatalogRendererSnippet(context, catalogId, role, options?.mode);
515
+ return { ...bindingBase, customRenderer: { ...bindingBase.customRenderer, snippet: rec } };
516
+ }
517
+ throw new Error("Global (non-catalog-scoped) snippetRef resolution is host-defined.");
518
+ }
519
+ // Optionally include design merge when requested and available.
520
+ if (options?.includeDesignObjects && !options?.designObjects) {
521
+ if (!this.deps.designObjects)
522
+ throw new Error("designObjects dependency is not configured");
523
+ const designObjects = await this.deps.designObjects.listByScope?.({
524
+ ...(options?.designScope?.storeId ? { storeId: options.designScope.storeId } : {}),
525
+ ...(options?.designScope?.appId ? { appId: options.designScope.appId } : {}),
526
+ ...(options?.designScope?.accountId ? { accountId: options.designScope.accountId } : {}),
527
+ ...(options?.designScope?.agentId ? { agentId: options.designScope.agentId } : {}),
528
+ });
529
+ return resolveCatalogPresentationBinding({
530
+ descriptor,
531
+ profiles,
532
+ role: role,
533
+ ...(options?.mode ? { mode: options.mode } : {}),
534
+ ...(options?.displayContext ? { displayContext: options.displayContext } : {}),
535
+ ...(options?.designScope ? { designScope: options.designScope } : {}),
536
+ designObjects,
537
+ // Preserve snippet result if caller already asked for it separately above.
538
+ ...(bindingBase.customRenderer?.snippet !== undefined ? { snippet: bindingBase.customRenderer.snippet } : {}),
539
+ });
540
+ }
541
+ return bindingBase;
542
+ }
543
+ async buildCatalogListPresentationSurface(context, catalogId, options) {
544
+ const map = await this.buildCatalogListRenderMap(context, catalogId, {
545
+ ...(options?.limit != null ? { limit: options.limit } : {}),
546
+ ...(options?.resolveSources != null ? { resolveSources: options.resolveSources } : {}),
547
+ ...(options?.maxSourceOptions != null ? { maxSourceOptions: options.maxSourceOptions } : {}),
548
+ ...(options?.displayContext != null ? { displayContext: options.displayContext } : {}),
549
+ });
550
+ const binding = await this.getCatalogPresentationBinding(context, catalogId, (options?.displayContext ?? "grid") === "grid" ? "grid" : "list", {
551
+ ...(options?.mode ? { mode: options.mode } : {}),
552
+ displayContext: options?.displayContext ?? "grid",
553
+ ...(options?.includeSnippet ? { includeSnippet: true } : {}),
554
+ ...(options?.includeDesignObjects ? { includeDesignObjects: true } : {}),
555
+ ...(options?.designScope ? { designScope: options.designScope } : {}),
556
+ ...(options?.profiles ? { profiles: options.profiles } : {}),
557
+ ...(options?.designObjects ? { designObjects: options.designObjects } : {}),
558
+ });
559
+ return { map, binding };
560
+ }
561
+ async buildCatalogItemPresentationSurface(context, catalogId, itemId, options) {
562
+ const map = await this.buildCatalogItemRenderMap(context, catalogId, itemId, {
563
+ ...(options?.includeReferences != null ? { includeReferences: options.includeReferences } : {}),
564
+ ...(options?.resolveSources != null ? { resolveSources: options.resolveSources } : {}),
565
+ ...(options?.maxSourceOptions != null ? { maxSourceOptions: options.maxSourceOptions } : {}),
566
+ ...(options?.displayContext != null ? { displayContext: options.displayContext } : {}),
567
+ });
568
+ const binding = await this.getCatalogPresentationBinding(context, catalogId, "item", {
569
+ ...(options?.mode ? { mode: options.mode } : {}),
570
+ displayContext: "form",
571
+ ...(options?.includeSnippet ? { includeSnippet: true } : {}),
572
+ ...(options?.includeDesignObjects ? { includeDesignObjects: true } : {}),
573
+ ...(options?.designScope ? { designScope: options.designScope } : {}),
574
+ ...(options?.profiles ? { profiles: options.profiles } : {}),
575
+ ...(options?.designObjects ? { designObjects: options.designObjects } : {}),
576
+ });
577
+ return { map, binding };
578
+ }
579
+ async buildCatalogItemRenderMap(context, catalogId, itemId, options) {
580
+ const descriptor = await this.getCatalogDescriptor(context, catalogId);
581
+ const got = await this.getCatalogItem(context, catalogId, itemId);
582
+ if (got.outcome === "mapping_blocked") {
583
+ throw new CatalogAdapterError({ catalogId, reason: "mapping_validation_failed", issues: got.issues });
584
+ }
585
+ if (got.outcome === "not_found")
586
+ throw new CatalogNotFoundError({ catalogId, itemId });
587
+ const item = got.item;
588
+ const sources = this.gatherDescriptorSources(descriptor);
589
+ const resolvedSources = {};
590
+ if (options?.resolveSources !== false) {
591
+ for (const [fieldPath, source] of Object.entries(sources)) {
592
+ resolvedSources[fieldPath] = await this.resolveFieldSourceOptions({
593
+ context,
594
+ currentCatalogId: catalogId,
595
+ fieldPath,
596
+ source,
597
+ currentItemData: (item.data ?? {}),
598
+ ...(options?.maxSourceOptions != null ? { maxOptions: options.maxSourceOptions } : {}),
599
+ });
600
+ }
601
+ }
602
+ const refs = options?.includeReferences
603
+ ? await this.getCatalogItemReferences(context, catalogId, itemId)
604
+ : [];
605
+ const referenceViews = refs.length
606
+ ? refs.map((r) => ({
607
+ toCatalogId: String(r.toCatalogId),
608
+ toItemId: String(r.toItemId),
609
+ relationType: String(r.relationType),
610
+ ...(r.label != null ? { label: r.label } : {}),
611
+ ...(r.metadata != null ? { metadata: r.metadata } : {}),
612
+ }))
613
+ : [];
614
+ return {
615
+ catalogId: String(catalogId),
616
+ itemId: String(itemId),
617
+ item: {
618
+ data: (item.data ?? {}),
619
+ ...(item.title != null ? { title: item.title } : {}),
620
+ ...(item.subtitle != null ? { subtitle: item.subtitle } : {}),
621
+ ...(item.metadata?.status != null ? { status: String(item.metadata.status) } : {}),
622
+ ...(item.metadata != null ? { metadata: item.metadata } : {}),
623
+ ...(item.metadata?.createdAt != null ? { createdAt: String(item.metadata.createdAt) } : {}),
624
+ ...(item.metadata?.lastUpdate != null ? { updatedAt: String(item.metadata.lastUpdate) } : {}),
625
+ },
626
+ resolvedSources,
627
+ ...(referenceViews.length ? { relations: referenceViews, references: referenceViews } : {}),
628
+ ...(descriptor?.presentationSpec ? { presentation: descriptor.presentationSpec } : {}),
629
+ capabilities: descriptor?.capabilities ?? {
630
+ canList: true,
631
+ canGet: true,
632
+ canCreate: false,
633
+ canEdit: false,
634
+ canDelete: false,
635
+ },
636
+ context: { mode: "view", displayContext: options?.displayContext ?? "form" },
637
+ actions: {},
638
+ };
639
+ }
640
+ deriveIndexed(descriptor, data) {
641
+ const out = {};
642
+ for (const f of descriptor.queryableFields ?? []) {
643
+ if (!f.indexed)
644
+ continue;
645
+ const v = this.readPath(data, f.path ?? f.key);
646
+ if (v !== undefined)
647
+ out[f.key] = v;
648
+ }
649
+ const smartIdx = deriveIndexedFromSmartProperties(descriptor, data);
650
+ if (smartIdx)
651
+ Object.assign(out, smartIdx);
652
+ return Object.keys(out).length ? out : undefined;
653
+ }
654
+ smartPropertyDeps() {
655
+ return {
656
+ catalogs: this.deps.catalogs,
657
+ descriptors: this.deps.descriptors,
658
+ nativeItems: this.deps.nativeItems,
659
+ authz: this.deps.authz,
660
+ resolveAppIdForCatalog: (input) => this.resolveAppIdForCatalogAccess(input),
661
+ };
662
+ }
663
+ assertNativeCatalogRecordEnvelope(catalogId, record) {
664
+ if (record.itemId == null || String(record.itemId).trim() === "") {
665
+ throw new CatalogValidationError({
666
+ reason: "missing_item_id",
667
+ catalogId: String(catalogId),
668
+ });
669
+ }
670
+ if (record.catalogId == null || String(record.catalogId).trim() === "") {
671
+ throw new CatalogValidationError({
672
+ reason: "missing_catalog_id",
673
+ catalogId: String(catalogId),
674
+ itemId: String(record.itemId),
675
+ });
676
+ }
677
+ if (String(record.catalogId) !== String(catalogId)) {
678
+ throw new CatalogValidationError({
679
+ reason: "catalog_id_mismatch",
680
+ catalogId: String(catalogId),
681
+ itemId: String(record.itemId),
682
+ });
683
+ }
684
+ if (!record.data || typeof record.data !== "object" || Array.isArray(record.data)) {
685
+ throw new CatalogValidationError({
686
+ reason: "missing_data",
687
+ catalogId: String(catalogId),
688
+ itemId: String(record.itemId),
689
+ });
690
+ }
691
+ if (!record.metadata || typeof record.metadata !== "object" || Array.isArray(record.metadata)) {
692
+ throw new CatalogValidationError({
693
+ reason: "missing_metadata",
694
+ catalogId: String(catalogId),
695
+ itemId: String(record.itemId),
696
+ });
697
+ }
698
+ }
699
+ buildReplaceNativeRecord(context, catalogId, record, appId, existing) {
700
+ const storedScope = normalizeItemScope(record.scope ?? {});
701
+ const now = new Date().toISOString();
702
+ const actorId = this.resolveActorId(context);
703
+ const scopeMeta = metadataFromScope(storedScope);
704
+ const metadata = {
705
+ ...record.metadata,
706
+ createdAt: String(existing?.metadata?.createdAt ?? record.metadata?.createdAt ?? now),
707
+ lastUpdate: now,
708
+ ...(scopeMeta.domainIds?.length ? { domainIds: scopeMeta.domainIds } : {}),
709
+ ...(scopeMeta.agentIds?.length ? { agentIds: scopeMeta.agentIds } : {}),
710
+ };
711
+ return {
712
+ itemId: record.itemId,
713
+ catalogId,
714
+ ...(record.scope != null ? { scope: storedScope } : {}),
715
+ appScopedOwnerId: appId,
716
+ ...(record.indexed != null ? { indexed: record.indexed } : {}),
717
+ data: record.data,
718
+ metadata,
719
+ version: (existing?.version ?? 0) + 1,
720
+ ...(existing?.createdBy
721
+ ? { createdBy: existing.createdBy }
722
+ : record.createdBy
723
+ ? { createdBy: record.createdBy }
724
+ : actorId
725
+ ? { createdBy: actorId }
726
+ : {}),
727
+ ...(actorId ? { updatedBy: actorId } : record.updatedBy ? { updatedBy: record.updatedBy } : {}),
728
+ };
729
+ }
730
+ stripReservedWriteFields(input) {
731
+ const { indexed, scope, relations, references, ...rest } = input;
732
+ const parsedScope = scope != null ? parseWriteScopeInput(scope) : undefined;
733
+ const parsedRelations = this.normalizeRelationWrites(relations ?? references);
734
+ return {
735
+ data: rest,
736
+ ...(indexed != null ? { indexed: indexed } : {}),
737
+ ...(parsedScope != null ? { scope: parsedScope } : {}),
738
+ ...(parsedRelations.length ? { relations: parsedRelations } : {}),
739
+ };
740
+ }
741
+ filterNativeCatalogRows(context, records, fetchOpts) {
742
+ const wantsSuperList = fetchOpts?.superAdmin === true && context.superAdmin === true;
743
+ if (wantsSuperList) {
744
+ return {
745
+ rows: records,
746
+ applied: {
747
+ effectiveScope: {},
748
+ includeGeneric: true,
749
+ genericOnly: false,
750
+ scopedOnly: false,
751
+ scopedAccessAllowed: true,
752
+ superAdmin: true,
753
+ },
754
+ };
755
+ }
756
+ const fetchMode = resolveCatalogScopeFetchMode(fetchOpts);
757
+ const unrestricted = isUnrestrictedScopeContext(context);
758
+ const token = tokenScopeFromContext(context);
759
+ const { effectiveScope, scopedAccessAllowed } = mergeEffectiveScope(token, fetchOpts?.scope, {
760
+ unrestricted,
761
+ });
762
+ const filtered = records.filter((r) => shouldIncludeItemInList({
763
+ itemScope: scopeFromRecordField(r.scope),
764
+ effectiveScope,
765
+ scopedAccessAllowed: unrestricted || scopedAccessAllowed,
766
+ fetchMode,
767
+ }));
768
+ return {
769
+ rows: filtered,
770
+ applied: {
771
+ effectiveScope,
772
+ includeGeneric: fetchMode.includeGeneric,
773
+ genericOnly: fetchMode.genericOnly,
774
+ scopedOnly: fetchMode.scopedOnly,
775
+ scopedAccessAllowed: unrestricted || scopedAccessAllowed,
776
+ superAdmin: false,
777
+ },
778
+ };
779
+ }
780
+ async decorateItem(catalogId, item) {
781
+ const descriptor = await this.deps.descriptors.get(catalogId);
782
+ if (!descriptor)
783
+ return item;
784
+ const identity = descriptor.descriptor.identity;
785
+ const data = item.data;
786
+ const title = identity.titleField ? data[identity.titleField] : undefined;
787
+ const subtitle = identity.subtitleField ? data[identity.subtitleField] : undefined;
788
+ const status = identity.statusField ? data[identity.statusField] : undefined;
789
+ const updatedAt = identity.updatedAtField ? data[identity.updatedAtField] : undefined;
790
+ return {
791
+ ...item,
792
+ ...(title != null ? { title: String(title) } : {}),
793
+ ...(subtitle != null ? { subtitle: String(subtitle) } : {}),
794
+ metadata: {
795
+ ...(item.metadata ?? {}),
796
+ ...(item.metadata?.domainIds == null ? { domainIds: [] } : {}),
797
+ ...(item.metadata?.agentIds == null ? { agentIds: [] } : {}),
798
+ ...(status != null ? { status: String(status) } : {}),
799
+ ...(updatedAt != null && item.metadata?.lastUpdate == null ? { lastUpdate: String(updatedAt) } : {}),
800
+ },
801
+ };
802
+ }
803
+ async listAppCatalogs(context, input) {
804
+ const appId = input?.appId ?? context.appId;
805
+ if (!appId) {
806
+ throw new CatalogBindingError({ reason: "missing_appId", message: "listAppCatalogs requires an appId." });
807
+ }
808
+ const bindings = await this.deps.bindings.listByApp(appId);
809
+ const catalogs = await this.deps.catalogs.listAll();
810
+ const byId = new Map(catalogs.map((c) => [c.catalogId, c]));
811
+ const out = [];
812
+ for (const b of bindings) {
813
+ const cat = byId.get(b.catalogId);
814
+ if (!cat)
815
+ continue;
816
+ if (!input?.includeDisabled && cat.metadata.status !== "active")
817
+ continue;
818
+ const descriptor = await this.deps.descriptors.get(cat.catalogId);
819
+ const description = descriptor?.descriptor.description ?? cat.description;
820
+ const itemLabel = descriptor?.descriptor.itemLabel ?? cat.itemLabel;
821
+ const visibility = descriptor?.descriptor.visibility;
822
+ const descriptorVersion = descriptor?.descriptorVersion;
823
+ const metadata = { ...cat.metadata, ...(descriptor?.descriptor.metadata ?? {}) };
824
+ out.push({
825
+ catalogId: cat.catalogId,
826
+ label: descriptor?.descriptor.label ?? cat.name,
827
+ ...(description != null ? { description } : {}),
828
+ ...(itemLabel != null ? { itemLabel } : {}),
829
+ catalogType: cat.catalogType,
830
+ sourceMode: cat.sourceMode,
831
+ ...(cat.mappedSourceType != null ? { mappedSourceType: cat.mappedSourceType } : {}),
832
+ ...(visibility != null ? { visibility } : {}),
833
+ access: b.access,
834
+ ...(descriptorVersion != null ? { descriptorVersion } : {}),
835
+ metadata,
836
+ });
837
+ }
838
+ return out.filter((e) => (input?.includeHidden ? true : e.visibility !== "hidden"));
839
+ }
840
+ identityBindingMatches(bindingIdentity, query) {
841
+ const pairs = [
842
+ ["accountId", "accountId"],
843
+ ["groupId", "groupId"],
844
+ ["userId", "userId"],
845
+ ["channelId", "channelId"],
846
+ ["visitorId", "visitorId"],
847
+ ["domainId", "domainId"],
848
+ ["agentId", "agentId"],
849
+ ];
850
+ for (const [bk, qk] of pairs) {
851
+ const b = bindingIdentity[bk];
852
+ if (b == null)
853
+ continue;
854
+ const q = query[qk];
855
+ if (q == null)
856
+ return false;
857
+ if (String(q) !== String(b))
858
+ return false;
859
+ }
860
+ return true;
861
+ }
862
+ /**
863
+ * vNext: identity-first discovery, backed by `catalogIdentityBindings`.
864
+ * This does not replace app bindings; host policy may intersect/union them.
865
+ */
866
+ async listCatalogsForIdentity(context, input) {
867
+ if (!this.deps.identityBindings) {
868
+ throw new Error("identityBindings dependency is not configured");
869
+ }
870
+ const bindings = await this.deps.identityBindings.listAll();
871
+ const catalogs = await this.deps.catalogs.listAll();
872
+ const byId = new Map(catalogs.map((c) => [c.catalogId, c]));
873
+ const out = [];
874
+ for (const b of bindings) {
875
+ if (b.status !== "active")
876
+ continue;
877
+ if (!this.identityBindingMatches(b.identity, input.identity))
878
+ continue;
879
+ const cat = byId.get(b.catalogId);
880
+ if (!cat)
881
+ continue;
882
+ if (!input.includeDisabled && cat.metadata.status !== "active")
883
+ continue;
884
+ const descriptor = await this.deps.descriptors.get(cat.catalogId);
885
+ const description = descriptor?.descriptor.description ?? cat.description;
886
+ const itemLabel = descriptor?.descriptor.itemLabel ?? cat.itemLabel;
887
+ const visibility = descriptor?.descriptor.visibility;
888
+ const descriptorVersion = descriptor?.descriptorVersion;
889
+ const metadata = { ...cat.metadata, ...(descriptor?.descriptor.metadata ?? {}) };
890
+ out.push({
891
+ catalogId: cat.catalogId,
892
+ label: descriptor?.descriptor.label ?? cat.name,
893
+ ...(description != null ? { description } : {}),
894
+ ...(itemLabel != null ? { itemLabel } : {}),
895
+ catalogType: cat.catalogType,
896
+ sourceMode: cat.sourceMode,
897
+ ...(cat.mappedSourceType != null ? { mappedSourceType: cat.mappedSourceType } : {}),
898
+ ...(visibility != null ? { visibility } : {}),
899
+ access: b.access,
900
+ ...(descriptorVersion != null ? { descriptorVersion } : {}),
901
+ metadata,
902
+ });
903
+ }
904
+ return out.filter((e) => (input.includeHidden ? true : e.visibility !== "hidden"));
905
+ }
906
+ /**
907
+ * App-agnostic discovery: list catalog metadata across all apps.
908
+ * Visibility default: hide hidden catalogs unless `context.superAdmin`.
909
+ */
910
+ async listAllCatalogs(context, input) {
911
+ const catalogs = await this.deps.catalogs.listAll();
912
+ const out = [];
913
+ for (const c of catalogs) {
914
+ const d = await this.deps.descriptors.get(c.catalogId);
915
+ out.push(summarizeCatalog(c, d));
916
+ }
917
+ return applyCatalogVisibilityFilter(out, context, input);
918
+ }
919
+ async findCatalogs(context, input) {
920
+ const all = await this.listAllCatalogs(context, {
921
+ ...(input.includeDisabled != null ? { includeDisabled: input.includeDisabled } : {}),
922
+ ...(input.includeHidden != null ? { includeHidden: input.includeHidden } : {}),
923
+ });
924
+ return filterCatalogsByText(all, input);
925
+ }
926
+ async getCatalogDescriptor(context, catalogId) {
927
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "read" });
928
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "read");
929
+ const rec = await this.deps.descriptors.get(catalogId);
930
+ return rec?.descriptor ?? null;
931
+ }
932
+ /**
933
+ * Writes or replaces the global descriptor for `catalogId` (same document as {@link DescriptorStore}).
934
+ * Requires {@link CataloxContext.superAdmin} because descriptors affect identity and behavior for all apps bound to the catalog.
935
+ */
936
+ async upsertCatalogDescriptor(context, catalogId, input) {
937
+ if (!context.superAdmin)
938
+ throw new CatalogAccessDeniedError({ reason: "super_admin_required" });
939
+ const existing = await this.deps.descriptors.get(catalogId);
940
+ const now = new Date().toISOString();
941
+ const mode = input.mode ?? "replace";
942
+ const base = mode === "merge" && existing?.descriptor
943
+ ? { ...existing.descriptor, ...input.descriptor }
944
+ : input.descriptor;
945
+ const nextDescriptor = {
946
+ ...base,
947
+ catalogId: String(catalogId),
948
+ };
949
+ await this.deps.descriptors.upsert({
950
+ catalogId: String(catalogId),
951
+ descriptorVersion: input.descriptorVersion,
952
+ descriptor: nextDescriptor,
953
+ createdAt: existing?.createdAt ?? now,
954
+ updatedAt: now,
955
+ });
956
+ }
957
+ async getCatalogRendererSnippet(context, catalogId, role, mode) {
958
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "read" });
959
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "read");
960
+ if (!this.deps.rendererSnippets) {
961
+ throw new Error("rendererSnippets dependency is not configured");
962
+ }
963
+ return this.deps.rendererSnippets.get(catalogId, role, mode);
964
+ }
965
+ async getAppCatalogBootstrap(context, appId) {
966
+ const resolved = appId ?? context.appId;
967
+ if (!resolved) {
968
+ throw new CatalogBindingError({ reason: "missing_appId", message: "getAppCatalogBootstrap requires an appId." });
969
+ }
970
+ const entries = await this.listAppCatalogs(context, { appId: resolved });
971
+ const descriptors = [];
972
+ for (const e of entries) {
973
+ const d = await this.deps.descriptors.get(e.catalogId);
974
+ if (d)
975
+ descriptors.push(d.descriptor);
976
+ }
977
+ return { appId: resolved, catalogs: descriptors };
978
+ }
979
+ /** vNext: store-first bootstrap (store -> apps -> catalog descriptors). */
980
+ async getStoreCatalogBootstrap(context, storeId) {
981
+ const apps = await this.listAppsForStore(context, storeId);
982
+ const activeApps = apps.filter((a) => a.status === "active").map((a) => a.appId);
983
+ const out = { storeId: String(storeId), apps: [] };
984
+ for (const appId of activeApps) {
985
+ const appCtx = { ...context, appId };
986
+ const bootstrap = await this.getAppCatalogBootstrap(appCtx, appId);
987
+ out.apps.push({ appId, catalogs: bootstrap.catalogs });
988
+ }
989
+ return out;
990
+ }
991
+ async listCatalogItems(context, catalogId, options) {
992
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "read" });
993
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "read");
994
+ const appCtx = context.appId ? context : { ...context, appId };
995
+ const catalog = await this.deps.catalogs.get(catalogId);
996
+ if (!catalog)
997
+ throw new CatalogNotFoundError({ catalogId });
998
+ const listQueryOptions = options == null
999
+ ? undefined
1000
+ : (() => {
1001
+ const { filter, ...rest } = options;
1002
+ const compacted = compactCatalogFilter(filter);
1003
+ return {
1004
+ ...rest,
1005
+ ...(Object.keys(compacted).length ? { filter: compacted } : {}),
1006
+ };
1007
+ })();
1008
+ if (catalog.sourceMode === "native") {
1009
+ const descRec = await this.deps.descriptors.get(catalogId);
1010
+ if (!descRec)
1011
+ throw new CatalogAdapterError({ catalogId, reason: "missing_descriptor" });
1012
+ const { filterEq, filterArrayContains } = planNativeListFilters(descRec.descriptor, (listQueryOptions?.filter ?? {}));
1013
+ const baseListOpts = {
1014
+ ...(listQueryOptions?.limit != null ? { limit: listQueryOptions.limit } : {}),
1015
+ ...(listQueryOptions?.offset != null ? { offset: listQueryOptions.offset } : {}),
1016
+ ...(Object.keys(filterEq).length ? { filterEq } : {}),
1017
+ ...(Object.keys(filterArrayContains).length ? { filterArrayContains } : {}),
1018
+ ...(listQueryOptions?.sort ? { sort: listQueryOptions.sort } : {}),
1019
+ };
1020
+ const fetchOpts = listQueryOptions?.scope;
1021
+ const includeScopeInResponse = fetchOpts?.includeScopeInResponse !== false;
1022
+ const poolLimit = Math.min(5000, Math.max((listQueryOptions?.limit ?? 100) + (listQueryOptions?.offset ?? 0), 500));
1023
+ const physical = await this.deps.nativeItems.list(catalogId, {
1024
+ ...baseListOpts,
1025
+ limit: poolLimit,
1026
+ offset: 0,
1027
+ });
1028
+ const { rows: filtered, applied } = this.filterNativeCatalogRows(context, physical, fetchOpts);
1029
+ const merged = mergeNativePhysicalRows(filtered, descRec.descriptor.identity, String(appId), includeScopeInResponse, undefined, this.nativeItemSourceType());
1030
+ const off = listQueryOptions?.offset ?? 0;
1031
+ const lim = listQueryOptions?.limit ?? 100;
1032
+ const sliced = merged.slice(off, off + lim);
1033
+ const decorated = await Promise.all(sliced.map((it) => this.decorateItem(catalogId, it)));
1034
+ return {
1035
+ listOutcome: "ok",
1036
+ items: decorated,
1037
+ appliedScope: applied,
1038
+ };
1039
+ }
1040
+ const def = await this.deps.definitions.get(catalogId);
1041
+ if (!def)
1042
+ throw new CatalogAdapterError({ catalogId, reason: "missing_definition" });
1043
+ if (def.catalogItems.providerType !== "external") {
1044
+ throw new CatalogAdapterError({ catalogId, reason: "missing_definition" });
1045
+ }
1046
+ const map = def.catalogItems.map;
1047
+ const mappingId = map?.mappingId;
1048
+ const adapterId = map?.adapterId;
1049
+ if (!mappingId)
1050
+ throw new CatalogAdapterError({ catalogId, reason: "missing_mapping" });
1051
+ if (!adapterId)
1052
+ throw new CatalogAdapterError({ catalogId, reason: "missing_adapter" });
1053
+ const mapping = await this.deps.mappings.get(mappingId);
1054
+ if (!mapping)
1055
+ throw new CatalogAdapterError({ catalogId, reason: "missing_mapping" });
1056
+ const mappingIssues = validateMappingSpec(mapping.mapping);
1057
+ if (mappingIssues.some((i) => i.severity === "error")) {
1058
+ return { listOutcome: "mapping_blocked", items: [], issues: mappingIssues };
1059
+ }
1060
+ const mappedListQueryOptions = listQueryOptions != null
1061
+ ? (() => {
1062
+ const { scope: _omitScope, ...rest } = listQueryOptions;
1063
+ return rest;
1064
+ })()
1065
+ : undefined;
1066
+ if (def.catalogItems.provider === "mongo") {
1067
+ if (!this.deps.mongoAdapter)
1068
+ throw new CatalogAdapterError({ catalogId, reason: "mongo_adapter_unconfigured" });
1069
+ const adapterConfig = await this.deps.adapters.get(adapterId);
1070
+ if (!adapterConfig)
1071
+ throw new CatalogAdapterError({ catalogId, reason: "missing_adapter" });
1072
+ const result = await this.deps.mongoAdapter.listItems(appCtx, catalogId, adapterConfig, { mapping: mapping.mapping, ...(mapping.options ? { options: mapping.options } : {}) }, mappedListQueryOptions);
1073
+ return result.issues?.length
1074
+ ? { listOutcome: "ok", items: result.items, issues: result.issues }
1075
+ : { listOutcome: "ok", items: result.items };
1076
+ }
1077
+ if (def.catalogItems.provider === "api") {
1078
+ if (!this.deps.apiAdapter)
1079
+ throw new CatalogAdapterError({ catalogId, reason: "api_adapter_unconfigured" });
1080
+ const adapterConfig = await this.deps.adapters.get(adapterId);
1081
+ if (!adapterConfig)
1082
+ throw new CatalogAdapterError({ catalogId, reason: "missing_adapter" });
1083
+ const result = await this.deps.apiAdapter.listItems(appCtx, catalogId, adapterConfig, { responseMapping: mapping.mapping, ...(mapping.options ? { options: mapping.options } : {}) }, mappedListQueryOptions);
1084
+ return {
1085
+ listOutcome: "ok",
1086
+ items: result.items,
1087
+ ...(result.nextCursor ? { nextCursor: result.nextCursor } : {}),
1088
+ ...(result.issues ? { issues: result.issues } : {}),
1089
+ };
1090
+ }
1091
+ throw new CatalogAdapterError({ catalogId, reason: "unknown_adapter_type" });
1092
+ }
1093
+ /**
1094
+ * vNext: same as `listCatalogItems` but returns a semantic outcome wrapper instead of throwing for common cases.
1095
+ * This is intended for embedders/BFFs that need to distinguish empty vs denied vs misconfigured.
1096
+ */
1097
+ async listCatalogItemsWithOutcome(context, catalogId, options) {
1098
+ try {
1099
+ const result = await this.listCatalogItems(context, catalogId, options);
1100
+ if (result.listOutcome === "mapping_blocked")
1101
+ return { outcome: "mapping_blocked", result };
1102
+ if (!result.items.length)
1103
+ return { outcome: "empty", result };
1104
+ return { outcome: "ok", result };
1105
+ }
1106
+ catch (e) {
1107
+ if (e instanceof CatalogAccessDeniedError)
1108
+ return { outcome: "denied", error: e };
1109
+ if (e instanceof CatalogNotFoundError)
1110
+ return { outcome: "misconfigured", error: e };
1111
+ if (e instanceof CatalogAdapterError)
1112
+ return { outcome: "misconfigured", error: e };
1113
+ throw e;
1114
+ }
1115
+ }
1116
+ async getCatalogItem(context, catalogId, itemId, options) {
1117
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "read" });
1118
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "read");
1119
+ const catalog = await this.deps.catalogs.get(catalogId);
1120
+ if (!catalog)
1121
+ throw new CatalogNotFoundError({ catalogId });
1122
+ if (catalog.sourceMode === "native") {
1123
+ if (options?.storageDocId) {
1124
+ const rec = await this.deps.nativeItems.get(catalogId, options.storageDocId);
1125
+ if (!rec)
1126
+ return { outcome: "not_found" };
1127
+ const { rows } = this.filterNativeCatalogRows(context, [rec], options?.scope);
1128
+ if (!rows.length)
1129
+ return { outcome: "not_found" };
1130
+ const includeScope = options?.scope?.includeScopeInResponse !== false;
1131
+ const base = toUnifiedNativeItem(rows[0], String(appId), includeScope, this.nativeItemSourceType());
1132
+ return { outcome: "found", item: await this.decorateItem(catalogId, base) };
1133
+ }
1134
+ const rows = await resolveNativeRowsByLogicalItemId(this.deps.nativeItems, catalogId, itemId);
1135
+ if (!rows.length)
1136
+ return { outcome: "not_found" };
1137
+ const { rows: filtered } = this.filterNativeCatalogRows(context, rows, options?.scope);
1138
+ if (!filtered.length)
1139
+ return { outcome: "not_found" };
1140
+ const includeScope = options?.scope?.includeScopeInResponse !== false;
1141
+ const base = toUnifiedNativeItem(filtered[0], String(appId), includeScope, this.nativeItemSourceType());
1142
+ return { outcome: "found", item: await this.decorateItem(catalogId, base) };
1143
+ }
1144
+ // For mapped catalogs, use list path with filter if adapter supports.
1145
+ const result = await this.listCatalogItems(context, catalogId, {
1146
+ limit: 1,
1147
+ filter: { itemId },
1148
+ });
1149
+ if (result.listOutcome === "mapping_blocked") {
1150
+ return { outcome: "mapping_blocked", issues: result.issues ?? [] };
1151
+ }
1152
+ const first = result.items[0];
1153
+ if (!first)
1154
+ return { outcome: "not_found" };
1155
+ return { outcome: "found", item: await this.decorateItem(catalogId, first) };
1156
+ }
1157
+ /**
1158
+ * Authenticated native read returning the stored {@link NativeCatalogItemRecord} envelope
1159
+ * (not the unified list/get projection). Resolves by logical `itemId`.
1160
+ */
1161
+ async getNativeCatalogItem(context, catalogId, itemId, options) {
1162
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "read" });
1163
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "read");
1164
+ const catalog = await this.deps.catalogs.get(catalogId);
1165
+ if (!catalog)
1166
+ throw new CatalogNotFoundError({ catalogId });
1167
+ if (catalog.sourceMode !== "native")
1168
+ return null;
1169
+ if (options?.storageDocId) {
1170
+ const rec = await this.deps.nativeItems.get(catalogId, options.storageDocId);
1171
+ if (!rec)
1172
+ return null;
1173
+ const { rows } = this.filterNativeCatalogRows(context, [rec], options?.scope);
1174
+ return rows[0] ?? null;
1175
+ }
1176
+ const rows = await resolveNativeRowsByLogicalItemId(this.deps.nativeItems, catalogId, itemId);
1177
+ if (!rows.length)
1178
+ return null;
1179
+ const { rows: filtered } = this.filterNativeCatalogRows(context, rows, options?.scope);
1180
+ return filtered[0] ?? null;
1181
+ }
1182
+ /** vNext: `getCatalogItem` wrapper with `CataloxOutcome` semantics. */
1183
+ async getCatalogItemWithOutcome(context, catalogId, itemId, options) {
1184
+ try {
1185
+ const result = await this.getCatalogItem(context, catalogId, itemId, options);
1186
+ if (result.outcome === "mapping_blocked")
1187
+ return { outcome: "mapping_blocked", result };
1188
+ if (result.outcome === "not_found")
1189
+ return { outcome: "empty", result };
1190
+ return { outcome: "ok", result };
1191
+ }
1192
+ catch (e) {
1193
+ if (e instanceof CatalogAccessDeniedError)
1194
+ return { outcome: "denied", error: e };
1195
+ if (e instanceof CatalogNotFoundError)
1196
+ return { outcome: "misconfigured", error: e };
1197
+ if (e instanceof CatalogAdapterError)
1198
+ return { outcome: "misconfigured", error: e };
1199
+ throw e;
1200
+ }
1201
+ }
1202
+ async validateCatalog(context, catalogId) {
1203
+ const issues = [];
1204
+ const catalog = await this.deps.catalogs.get(catalogId);
1205
+ if (!catalog) {
1206
+ issues.push({
1207
+ code: "catalog.not_found",
1208
+ severity: "error",
1209
+ message: `Catalog "${String(catalogId)}" was not found.`,
1210
+ });
1211
+ return { isValid: false, issues };
1212
+ }
1213
+ const descriptor = await this.deps.descriptors.get(catalogId);
1214
+ if (!descriptor) {
1215
+ issues.push({
1216
+ code: "catalog.missing_descriptor",
1217
+ severity: "error",
1218
+ message: `Descriptor missing for catalog "${String(catalogId)}".`,
1219
+ });
1220
+ }
1221
+ const definition = await this.deps.definitions.get(catalogId);
1222
+ if (catalog.sourceMode === "native") {
1223
+ if (!definition || definition.sourceMode !== "native") {
1224
+ issues.push({
1225
+ code: "catalog.missing_native_config",
1226
+ severity: "error",
1227
+ message: `Native definition missing for catalog "${String(catalogId)}".`,
1228
+ });
1229
+ }
1230
+ }
1231
+ else if (catalog.sourceMode === "mapped") {
1232
+ if (!definition || definition.sourceMode !== "mapped") {
1233
+ issues.push({
1234
+ code: "catalog.missing_mapped_config",
1235
+ severity: "error",
1236
+ message: `Mapped definition missing for catalog "${String(catalogId)}".`,
1237
+ });
1238
+ }
1239
+ else {
1240
+ const map = definition.catalogItems?.map;
1241
+ const mappingId = map?.mappingId != null ? String(map.mappingId) : "";
1242
+ if (!mappingId) {
1243
+ issues.push({
1244
+ code: "catalog.mapping_invalid",
1245
+ severity: "error",
1246
+ message: `Mapped catalog "${String(catalogId)}" has no mappingId.`,
1247
+ });
1248
+ }
1249
+ else {
1250
+ const mapping = await this.deps.mappings.get(mappingId);
1251
+ if (!mapping) {
1252
+ issues.push({
1253
+ code: "catalog.mapping_invalid",
1254
+ severity: "error",
1255
+ message: `Mapping "${mappingId}" not found for catalog "${String(catalogId)}".`,
1256
+ });
1257
+ }
1258
+ else {
1259
+ const mappingIssues = validateMappingSpec(mapping.mapping);
1260
+ for (const mi of mappingIssues) {
1261
+ issues.push({
1262
+ code: "catalog.mapping_invalid",
1263
+ severity: "error",
1264
+ message: mi.message ?? String(mi.code ?? "mapping_invalid"),
1265
+ });
1266
+ }
1267
+ }
1268
+ }
1269
+ }
1270
+ }
1271
+ if (this.deps.catalogTypes) {
1272
+ const registry = await this.resolveCatalogTypeRegistry(context);
1273
+ if (registry?.types?.length) {
1274
+ const allowed = new Set(registry.types.map((t) => String(t)));
1275
+ if (!allowed.has(String(catalog.catalogType))) {
1276
+ issues.push({
1277
+ code: "catalog.type_not_allowed",
1278
+ severity: "error",
1279
+ message: `catalogType "${String(catalog.catalogType)}" is not in the scoped registry.`,
1280
+ });
1281
+ }
1282
+ }
1283
+ }
1284
+ return { isValid: !issues.some((i) => i.severity === "error"), issues };
1285
+ }
1286
+ async validateCatalogItem(context, catalogId, itemId, options) {
1287
+ const issues = [];
1288
+ const descriptor = await this.getCatalogDescriptor(context, catalogId);
1289
+ if (!descriptor) {
1290
+ return {
1291
+ isValid: false,
1292
+ issues: [
1293
+ {
1294
+ code: "catalog.missing_descriptor",
1295
+ severity: "error",
1296
+ message: `Descriptor missing for catalog "${String(catalogId)}".`,
1297
+ },
1298
+ ],
1299
+ };
1300
+ }
1301
+ const refs = await this.getCatalogItemReferences(context, catalogId, itemId);
1302
+ const relationReport = await this.validateRelationsAgainstDescriptor(context, {
1303
+ catalogId,
1304
+ itemId,
1305
+ descriptor,
1306
+ refs,
1307
+ });
1308
+ issues.push(...relationReport.issues);
1309
+ const catalog = await this.deps.catalogs.get(catalogId);
1310
+ if (catalog?.sourceMode === "native") {
1311
+ const got = await this.getCatalogItem(context, catalogId, itemId);
1312
+ if (got.outcome === "found" && got.item?.data != null) {
1313
+ const typeRegistry = await this.resolveCatalogTypeRegistry(context);
1314
+ const payloadReport = this.validateNativeItemData(got.item.data, catalog, typeRegistry);
1315
+ issues.push(...payloadReport.issues);
1316
+ if (descriptor.smartProperties?.length) {
1317
+ const spReport = await validateSmartPropertiesForItem(this.smartPropertyDeps(), context, catalogId, descriptor, got.item.data, { autoCreate: options?.noAutoCreate ? false : true });
1318
+ issues.push(...spReport.issues);
1319
+ }
1320
+ }
1321
+ }
1322
+ return {
1323
+ isValid: !issues.some((i) => i.severity === "error"),
1324
+ issues,
1325
+ };
1326
+ }
1327
+ async getCatalogItemReferences(context, catalogId, itemId) {
1328
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "read" });
1329
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "read");
1330
+ const refs = await this.deps.references.listByItem(catalogId, itemId);
1331
+ return refs;
1332
+ }
1333
+ async listCatalogReferences(context, catalogId) {
1334
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "read" });
1335
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "read");
1336
+ const refs = await this.deps.references.listByCatalog(catalogId);
1337
+ return refs;
1338
+ }
1339
+ async upsertCatalogItemRelation(context, input) {
1340
+ const fromCatalogId = input.fromCatalogId;
1341
+ const toCatalogId = input.toCatalogId;
1342
+ const fromAppId = await this.resolveAppIdForCatalogAccess({ context, catalogId: fromCatalogId, required: "write" });
1343
+ await this.deps.authz.requireBindingAccess(context, fromAppId, fromCatalogId, "write");
1344
+ // Ensure target catalog is at least readable by the actor (prevents creating opaque links).
1345
+ const toAppId = await this.resolveAppIdForCatalogAccess({ context, catalogId: toCatalogId, required: "read" });
1346
+ await this.deps.authz.requireBindingAccess(context, toAppId, toCatalogId, "read");
1347
+ const now = new Date().toISOString();
1348
+ const referenceId = this.buildReferenceId({
1349
+ fromCatalogId: String(input.fromCatalogId),
1350
+ fromItemId: String(input.fromItemId),
1351
+ relationType: String(input.relationType),
1352
+ toCatalogId: String(input.toCatalogId),
1353
+ toItemId: String(input.toItemId),
1354
+ });
1355
+ await this.deps.references.upsert({
1356
+ referenceId,
1357
+ fromCatalogId,
1358
+ fromItemId: input.fromItemId,
1359
+ toCatalogId,
1360
+ toItemId: input.toItemId,
1361
+ relationType: String(input.relationType),
1362
+ ...(input.label != null ? { label: input.label } : {}),
1363
+ ...(input.metadata != null ? { metadata: input.metadata } : {}),
1364
+ createdAt: now,
1365
+ updatedAt: now,
1366
+ });
1367
+ return { referenceId };
1368
+ }
1369
+ async deleteCatalogItemRelation(context, input) {
1370
+ const referenceId = "referenceId" in input
1371
+ ? String(input.referenceId)
1372
+ : this.buildReferenceId({
1373
+ fromCatalogId: String(input.fromCatalogId),
1374
+ fromItemId: String(input.fromItemId),
1375
+ relationType: String(input.relationType),
1376
+ toCatalogId: String(input.toCatalogId),
1377
+ toItemId: String(input.toItemId),
1378
+ });
1379
+ // Best-effort access check: if the caller provides endpoints, enforce write on fromCatalog.
1380
+ if (!("referenceId" in input)) {
1381
+ const fromCatalogId = input.fromCatalogId;
1382
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId: fromCatalogId, required: "write" });
1383
+ await this.deps.authz.requireBindingAccess(context, appId, fromCatalogId, "write");
1384
+ }
1385
+ await this.deps.references.delete(referenceId);
1386
+ }
1387
+ async listCatalogItemRelationsToItem(context, catalogId, itemId) {
1388
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "read" });
1389
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "read");
1390
+ return this.deps.references.listToItem(catalogId, itemId);
1391
+ }
1392
+ // Spec methods below are stubs for now; filled in by later todos.
1393
+ async getApp(_context, appId) {
1394
+ const resolved = appId ?? _context.appId;
1395
+ if (!resolved)
1396
+ throw new CatalogBindingError({ reason: "missing_appId" });
1397
+ return this.deps.apps.get(resolved);
1398
+ }
1399
+ async createCatalog(_context, _input) {
1400
+ const now = new Date().toISOString();
1401
+ const catalogId = (_input.catalogId ?? randomUUID());
1402
+ await this.validateCatalogTypeForContext(_context, _input.catalogType);
1403
+ await this.deps.catalogs.upsert({
1404
+ catalogId,
1405
+ name: _input.name,
1406
+ ...(_input.description != null ? { description: _input.description } : {}),
1407
+ catalogType: _input.catalogType,
1408
+ ...(_input.schemaVersion != null ? { schemaVersion: String(_input.schemaVersion) } : {}),
1409
+ sourceMode: _input.sourceMode,
1410
+ ...(_input.sourceMode === "mapped" && _input.mapped?.sourceType
1411
+ ? { mappedSourceType: _input.mapped.sourceType }
1412
+ : {}),
1413
+ catalogItems: _input.sourceMode === "native"
1414
+ ? {
1415
+ providerType: "internal",
1416
+ ...(_input.native?.itemSchema != null ? { itemSchema: _input.native.itemSchema } : {}),
1417
+ metadata: {},
1418
+ }
1419
+ : {
1420
+ providerType: "external",
1421
+ provider: _input.mapped?.sourceType ?? "api",
1422
+ // map references existing adapter + mapping documents (see createCatalog mapped branch below)
1423
+ map: {},
1424
+ metadata: {},
1425
+ },
1426
+ metadata: {
1427
+ status: "active",
1428
+ createdAt: now,
1429
+ lastUpdate: now,
1430
+ ...(_input.metadata ?? {}),
1431
+ },
1432
+ });
1433
+ if (_input.sourceMode === "native") {
1434
+ if (!_input.native)
1435
+ throw new CatalogAdapterError({ catalogId, reason: "missing_native_config" });
1436
+ const collectionPath = _input.native.firestoreCollectionPath ?? nativeItemsCollectionId(catalogId);
1437
+ await this.deps.definitions.upsert({
1438
+ catalogId,
1439
+ sourceMode: "native",
1440
+ catalogItems: {
1441
+ providerType: "internal",
1442
+ ...(_input.native.itemSchema != null ? { itemSchema: _input.native.itemSchema } : {}),
1443
+ metadata: { firestoreCollectionPath: collectionPath },
1444
+ },
1445
+ createdAt: now,
1446
+ updatedAt: now,
1447
+ });
1448
+ await this.deps.catalogDataIndex.seedNativeCatalog(catalogId, now);
1449
+ }
1450
+ else {
1451
+ if (!_input.mapped)
1452
+ throw new CatalogAdapterError({ catalogId, reason: "missing_mapped_config" });
1453
+ const adapterId = randomUUID();
1454
+ const mappingId = randomUUID();
1455
+ await this.deps.adapters.upsert({
1456
+ adapterId,
1457
+ type: _input.mapped.sourceType,
1458
+ ..._input.mapped.adapter,
1459
+ });
1460
+ await this.deps.mappings.upsert({
1461
+ mappingId,
1462
+ mapping: _input.mapped.mapping,
1463
+ createdAt: now,
1464
+ updatedAt: now,
1465
+ });
1466
+ await this.deps.definitions.upsert({
1467
+ catalogId,
1468
+ sourceMode: "mapped",
1469
+ catalogItems: {
1470
+ providerType: "external",
1471
+ provider: _input.mapped.sourceType,
1472
+ map: { adapterId, mappingId },
1473
+ metadata: {},
1474
+ },
1475
+ ...(_input.mapped.syncMode ? { sync: { mode: _input.mapped.syncMode, syncStatus: "idle" } } : {}),
1476
+ createdAt: now,
1477
+ updatedAt: now,
1478
+ });
1479
+ // Update catalog record to point at the external map references.
1480
+ await this.deps.catalogs.upsert({
1481
+ ...(await this.deps.catalogs.get(catalogId)),
1482
+ catalogItems: {
1483
+ providerType: "external",
1484
+ provider: _input.mapped.sourceType,
1485
+ map: { adapterId, mappingId },
1486
+ metadata: {},
1487
+ },
1488
+ metadata: {
1489
+ ...(await this.deps.catalogs.get(catalogId)).metadata,
1490
+ lastUpdate: now,
1491
+ },
1492
+ });
1493
+ }
1494
+ // Seed a minimal descriptor if none exists.
1495
+ const existingDescriptor = await this.deps.descriptors.get(catalogId);
1496
+ if (!existingDescriptor) {
1497
+ await this.deps.descriptors.upsert({
1498
+ catalogId,
1499
+ descriptorVersion: "1",
1500
+ descriptor: {
1501
+ catalogId,
1502
+ label: _input.name,
1503
+ ...(_input.description != null ? { description: _input.description } : {}),
1504
+ sourceMode: _input.sourceMode,
1505
+ ...(_input.sourceMode === "mapped" && _input.mapped?.sourceType
1506
+ ? { mappedSourceType: _input.mapped.sourceType }
1507
+ : {}),
1508
+ status: "active",
1509
+ capabilities: {
1510
+ canList: true,
1511
+ canGet: true,
1512
+ canCreate: _input.sourceMode === "native",
1513
+ canEdit: _input.sourceMode === "native",
1514
+ canDelete: _input.sourceMode === "native",
1515
+ canImport: _input.sourceMode === "native",
1516
+ canExport: true,
1517
+ canSync: _input.sourceMode === "mapped",
1518
+ canValidate: true,
1519
+ canViewReferences: true,
1520
+ },
1521
+ queryableFields: [],
1522
+ identity: {
1523
+ itemIdStrategy: "generated",
1524
+ },
1525
+ },
1526
+ createdAt: now,
1527
+ updatedAt: now,
1528
+ });
1529
+ }
1530
+ const created = await this.deps.catalogs.get(catalogId);
1531
+ if (!created)
1532
+ throw new CatalogNotFoundError({ catalogId });
1533
+ return created;
1534
+ }
1535
+ async updateCatalog(_context, _catalogId, _patch) {
1536
+ const existing = await this.deps.catalogs.get(_catalogId);
1537
+ if (!existing)
1538
+ throw new CatalogNotFoundError({ catalogId: _catalogId });
1539
+ const now = new Date().toISOString();
1540
+ if (_patch.catalogType != null) {
1541
+ await this.validateCatalogTypeForContext(_context, String(_patch.catalogType));
1542
+ }
1543
+ await this.deps.catalogs.upsert({
1544
+ ...existing,
1545
+ ...(_patch.name != null ? { name: _patch.name } : {}),
1546
+ ...(_patch.description != null ? { description: _patch.description } : {}),
1547
+ ...(_patch.catalogType != null ? { catalogType: String(_patch.catalogType) } : {}),
1548
+ metadata: {
1549
+ ...existing.metadata,
1550
+ ...(_patch.metadata ?? {}),
1551
+ lastUpdate: now,
1552
+ },
1553
+ });
1554
+ return (await this.deps.catalogs.get(_catalogId));
1555
+ }
1556
+ async getCatalog(_context, catalogId) {
1557
+ return this.deps.catalogs.get(catalogId);
1558
+ }
1559
+ async listCatalogs(_context, _options) {
1560
+ return this.deps.catalogs.listAll();
1561
+ }
1562
+ async searchCatalogItems(context, catalogId, input) {
1563
+ const poolLimit = input.poolLimit ?? 200;
1564
+ const limit = input.limit ?? 50;
1565
+ const base = await this.listCatalogItems(context, catalogId, {
1566
+ limit: poolLimit,
1567
+ ...(input.scope ? { scope: input.scope } : {}),
1568
+ ...(input.filter ? { filter: input.filter } : {}),
1569
+ ...(input.sort ? { sort: input.sort } : {}),
1570
+ });
1571
+ if (base.listOutcome !== "ok")
1572
+ return base;
1573
+ const q = String(input.text ?? "").toLowerCase().trim();
1574
+ if (!q)
1575
+ return { ...base, items: [] };
1576
+ const textFields = input.textFields ?? [];
1577
+ const filtered = base.items.filter((it) => {
1578
+ const parts = [];
1579
+ if (it.title)
1580
+ parts.push(String(it.title));
1581
+ if (it.subtitle)
1582
+ parts.push(String(it.subtitle));
1583
+ const data = it.data;
1584
+ for (const p of textFields) {
1585
+ const v = this.readPath(data, p);
1586
+ if (v == null)
1587
+ continue;
1588
+ parts.push(typeof v === "string" || typeof v === "number" ? String(v) : JSON.stringify(v));
1589
+ }
1590
+ return parts.join(" ").toLowerCase().includes(q);
1591
+ });
1592
+ return { ...base, items: filtered.slice(0, limit) };
1593
+ }
1594
+ async bindCatalogToApp(_context, _input) {
1595
+ const existing = await this.deps.bindings.findByAppCatalog(_input.appId, _input.catalogId);
1596
+ if (existing)
1597
+ return existing;
1598
+ const now = new Date().toISOString();
1599
+ const record = {
1600
+ bindingId: `${String(_input.appId)}:${String(_input.catalogId)}`,
1601
+ appId: _input.appId,
1602
+ catalogId: _input.catalogId,
1603
+ access: {
1604
+ canRead: _input.access?.canRead ?? true,
1605
+ canWrite: _input.access?.canWrite ?? false,
1606
+ ...(_input.access?.canAdmin != null ? { canAdmin: _input.access.canAdmin } : {}),
1607
+ },
1608
+ status: "active",
1609
+ ...(_input.metadata != null ? { metadata: _input.metadata } : {}),
1610
+ createdAt: now,
1611
+ updatedAt: now,
1612
+ };
1613
+ await this.deps.bindings.upsert(record);
1614
+ return record;
1615
+ }
1616
+ async unbindCatalogFromApp(_context, _appId, _catalogId) {
1617
+ const existing = await this.deps.bindings.findByAppCatalog(_appId, _catalogId);
1618
+ if (!existing)
1619
+ return;
1620
+ await this.deps.bindings.upsert({
1621
+ ...existing,
1622
+ status: "disabled",
1623
+ updatedAt: new Date().toISOString(),
1624
+ });
1625
+ }
1626
+ async bindAppToStore(context, input) {
1627
+ if (!this.deps.storeAppBindings)
1628
+ throw new Error("storeAppBindings dependency is not configured");
1629
+ if (!context.superAdmin && (!context.appId || input.appId !== context.appId)) {
1630
+ throw new CatalogAccessDeniedError({ reason: "not_super_admin" });
1631
+ }
1632
+ const existing = await this.deps.storeAppBindings.findByStoreApp(input.storeId, input.appId);
1633
+ if (existing)
1634
+ return existing;
1635
+ const now = new Date().toISOString();
1636
+ const actorId = this.resolveActorId(context);
1637
+ const record = {
1638
+ bindingId: `${String(input.storeId)}:${String(input.appId)}`,
1639
+ storeId: input.storeId,
1640
+ appId: input.appId,
1641
+ status: "active",
1642
+ ...(input.metadata != null ? { metadata: input.metadata } : {}),
1643
+ createdAt: now,
1644
+ updatedAt: now,
1645
+ ...(actorId ? { createdBy: actorId, updatedBy: actorId } : {}),
1646
+ };
1647
+ await this.deps.storeAppBindings.upsert(record);
1648
+ return record;
1649
+ }
1650
+ async unbindAppFromStore(context, storeId, appId) {
1651
+ if (!this.deps.storeAppBindings)
1652
+ throw new Error("storeAppBindings dependency is not configured");
1653
+ if (!context.superAdmin && (!context.appId || appId !== context.appId)) {
1654
+ throw new CatalogAccessDeniedError({ reason: "not_super_admin" });
1655
+ }
1656
+ const existing = await this.deps.storeAppBindings.findByStoreApp(storeId, appId);
1657
+ if (!existing)
1658
+ return;
1659
+ const actorId = this.resolveActorId(context);
1660
+ await this.deps.storeAppBindings.upsert({
1661
+ ...existing,
1662
+ status: "disabled",
1663
+ updatedAt: new Date().toISOString(),
1664
+ ...(actorId ? { updatedBy: actorId } : {}),
1665
+ });
1666
+ }
1667
+ async listAppsForStore(context, storeId) {
1668
+ if (!this.deps.storeAppBindings)
1669
+ throw new Error("storeAppBindings dependency is not configured");
1670
+ // listing is allowed for any caller; super-admin sees all store memberships.
1671
+ const records = await this.deps.storeAppBindings.listAppsByStore(storeId);
1672
+ if (context.superAdmin)
1673
+ return records;
1674
+ // non-god: only reveal memberships that include the caller's own appId
1675
+ return context.appId ? records.filter((r) => r.appId === context.appId) : [];
1676
+ }
1677
+ async ensureCatalog(context, catalog) {
1678
+ const appId = await this.resolveAppIdForCatalogAccess({
1679
+ context,
1680
+ catalogId: catalog.catalogId,
1681
+ required: "admin",
1682
+ });
1683
+ await this.deps.authz.requireBindingAccess(context, appId, catalog.catalogId, "admin");
1684
+ const existing = await this.deps.catalogs.get(catalog.catalogId);
1685
+ const now = new Date().toISOString();
1686
+ if (existing)
1687
+ return;
1688
+ await this.deps.catalogs.upsert({
1689
+ catalogId: catalog.catalogId,
1690
+ name: catalog.name,
1691
+ catalogType: "generic",
1692
+ sourceMode: "native",
1693
+ catalogItems: { providerType: "internal", metadata: {} },
1694
+ metadata: {
1695
+ status: catalog.status ?? "active",
1696
+ createdAt: now,
1697
+ lastUpdate: now,
1698
+ },
1699
+ });
1700
+ }
1701
+ async resolveAllowedCatalogTypes(context) {
1702
+ if (!this.deps.catalogTypes)
1703
+ return null;
1704
+ return this.deps.catalogTypes.resolveForContext({
1705
+ ...(context.storeId ? { storeId: context.storeId } : {}),
1706
+ ...(context.appId ? { appId: context.appId } : {}),
1707
+ });
1708
+ }
1709
+ async upsertCatalogTypeRegistry(context, scope, input) {
1710
+ if (!context.superAdmin)
1711
+ throw new CatalogAccessDeniedError({ reason: "super_admin_required" });
1712
+ if (!this.deps.catalogTypes)
1713
+ throw new Error("catalogTypes dependency is not configured");
1714
+ await this.deps.catalogTypes.upsert(scope, input);
1715
+ }
1716
+ async resolveAllowedDomains(context) {
1717
+ if (!this.deps.domains)
1718
+ return null;
1719
+ return this.deps.domains.resolveForContext({
1720
+ ...(context.storeId ? { storeId: context.storeId } : {}),
1721
+ ...(context.appId ? { appId: context.appId } : {}),
1722
+ });
1723
+ }
1724
+ async upsertDomainRegistry(context, scope, input) {
1725
+ if (!context.superAdmin)
1726
+ throw new CatalogAccessDeniedError({ reason: "super_admin_required" });
1727
+ if (!this.deps.domains)
1728
+ throw new Error("domains dependency is not configured");
1729
+ await this.deps.domains.upsert(scope, input);
1730
+ }
1731
+ async resolveAllowedAgents(context) {
1732
+ if (!this.deps.agents)
1733
+ return null;
1734
+ return this.deps.agents.resolveForContext({
1735
+ ...(context.storeId ? { storeId: context.storeId } : {}),
1736
+ ...(context.appId ? { appId: context.appId } : {}),
1737
+ });
1738
+ }
1739
+ async upsertAgentRegistry(context, scope, input) {
1740
+ if (!context.superAdmin)
1741
+ throw new CatalogAccessDeniedError({ reason: "super_admin_required" });
1742
+ if (!this.deps.agents)
1743
+ throw new Error("agents dependency is not configured");
1744
+ await this.deps.agents.upsert(scope, input);
1745
+ }
1746
+ async backfillCatalogModel(context, input = {}) {
1747
+ if (!context.superAdmin)
1748
+ throw new CatalogAccessDeniedError({ reason: "super_admin_required" });
1749
+ const fs = this.deps.firestoreStore.firestore;
1750
+ return backfillCatalogModel(fs, input);
1751
+ }
1752
+ async ensureBinding(context, input) {
1753
+ // only super-admin apps can provision cross-app bindings.
1754
+ if (!context.superAdmin && (!context.appId || input.appId !== context.appId)) {
1755
+ throw new CatalogAccessDeniedError({ reason: "not_super_admin" });
1756
+ }
1757
+ const existing = await this.deps.bindings.findByAppCatalog(input.appId, input.catalogId);
1758
+ if (existing)
1759
+ return;
1760
+ const now = new Date().toISOString();
1761
+ await this.deps.bindings.upsert({
1762
+ bindingId: `${String(input.appId)}:${String(input.catalogId)}`,
1763
+ appId: input.appId,
1764
+ catalogId: input.catalogId,
1765
+ access: {
1766
+ canRead: input.access?.canRead ?? true,
1767
+ canWrite: input.access?.canWrite ?? false,
1768
+ ...(input.access?.canAdmin != null ? { canAdmin: input.access.canAdmin } : {}),
1769
+ },
1770
+ status: "active",
1771
+ createdAt: now,
1772
+ updatedAt: now,
1773
+ });
1774
+ }
1775
+ async createNativeCatalogItem(_context, _catalogId, _input) {
1776
+ return this.upsertNativeCatalogItem(_context, _catalogId, _input);
1777
+ }
1778
+ async updateNativeCatalogItem(_context, _catalogId, _itemId, _patch, _options) {
1779
+ const appId = await this.resolveAppIdForCatalogAccess({ context: _context, catalogId: _catalogId, required: "write" });
1780
+ await this.deps.authz.requireBindingAccess(_context, appId, _catalogId, "write");
1781
+ let existing = null;
1782
+ if (_options?.storageDocId) {
1783
+ existing = await this.deps.nativeItems.get(_catalogId, _options.storageDocId);
1784
+ }
1785
+ else {
1786
+ const rows = await resolveNativeRowsByLogicalItemId(this.deps.nativeItems, _catalogId, _itemId);
1787
+ existing = pickWinningPhysicalRow(rows);
1788
+ }
1789
+ if (!existing)
1790
+ throw new CatalogNotFoundError({ catalogId: _catalogId, itemId: _itemId });
1791
+ const { data: patchData, indexed: patchIndexed, scope: patchScope, relations: patchRelations } = this.stripReservedWriteFields(_patch);
1792
+ let nextScope = scopeFromRecordField(existing.scope);
1793
+ if (patchScope != null) {
1794
+ nextScope = normalizeItemScope(patchScope);
1795
+ assertWriteScopeAllowed(_context, nextScope);
1796
+ }
1797
+ // Validate relation rules using existing + provided relations (if any).
1798
+ const descriptorRec = await this.deps.descriptors.get(_catalogId);
1799
+ if (descriptorRec?.descriptor?.relationRules?.length) {
1800
+ const existingRefs = await this.deps.references.listByItem(_catalogId, _itemId);
1801
+ const nextRefs = [
1802
+ ...existingRefs,
1803
+ ...(patchRelations ?? []).map((r) => ({
1804
+ fromCatalogId: _catalogId,
1805
+ fromItemId: _itemId,
1806
+ toCatalogId: r.toCatalogId,
1807
+ toItemId: r.toItemId,
1808
+ relationType: r.relationType,
1809
+ ...(r.label != null ? { label: r.label } : {}),
1810
+ ...(r.metadata != null ? { metadata: r.metadata } : {}),
1811
+ })),
1812
+ ];
1813
+ const report = await this.validateRelationsAgainstDescriptor(_context, {
1814
+ catalogId: _catalogId,
1815
+ itemId: _itemId,
1816
+ descriptor: descriptorRec.descriptor,
1817
+ refs: nextRefs,
1818
+ });
1819
+ if (!report.isValid) {
1820
+ throw new CatalogValidationError({
1821
+ reason: "invalid_relations",
1822
+ catalogId: String(_catalogId),
1823
+ itemId: String(_itemId),
1824
+ report,
1825
+ });
1826
+ }
1827
+ }
1828
+ const updatedAt = new Date().toISOString();
1829
+ const mergedData = { ...(existing.data ?? {}), ...patchData };
1830
+ const desc = descriptorRec?.descriptor;
1831
+ if (desc?.smartProperties?.length) {
1832
+ const rulesOnly = validateSmartPropertyRules(desc, mergedData);
1833
+ if (!rulesOnly.isValid) {
1834
+ throw new CatalogValidationError({
1835
+ reason: "smart_properties",
1836
+ catalogId: String(_catalogId),
1837
+ itemId: String(_itemId),
1838
+ report: rulesOnly,
1839
+ });
1840
+ }
1841
+ await resolveSmartPropertiesOnWrite(this.smartPropertyDeps(), _context, _catalogId, desc, mergedData, nextScope);
1842
+ }
1843
+ const derived = desc ? this.deriveIndexed(desc, mergedData) : undefined;
1844
+ const idx = {
1845
+ ...(existing.indexed ?? {}),
1846
+ ...(patchIndexed ?? {}),
1847
+ ...(derived ?? {}),
1848
+ ...indexedScopeFields(nextScope),
1849
+ };
1850
+ const oldDocId = storageDocIdForNativeRecord(existing);
1851
+ const { scope: _dropScope, ...existingRest } = existing;
1852
+ const scopeMeta = metadataFromScope(nextScope);
1853
+ const nextRec = {
1854
+ ...existingRest,
1855
+ data: mergedData,
1856
+ indexed: idx,
1857
+ scope: nextScope,
1858
+ metadata: {
1859
+ ...(existing.metadata ?? {}),
1860
+ createdAt: String(existing.metadata?.createdAt ?? updatedAt),
1861
+ lastUpdate: updatedAt,
1862
+ domainIds: scopeMeta.domainIds,
1863
+ agentIds: scopeMeta.agentIds,
1864
+ },
1865
+ version: (existing.version ?? 0) + 1,
1866
+ ...(this.resolveActorId(_context) ? { updatedBy: this.resolveActorId(_context) } : {}),
1867
+ };
1868
+ const newDocId = storageDocIdForNativeRecord(nextRec);
1869
+ await this.deps.nativeItems.upsert(_catalogId, nextRec);
1870
+ if (newDocId !== oldDocId)
1871
+ await this.deps.nativeItems.delete(_catalogId, oldDocId);
1872
+ const persisted = (await this.deps.nativeItems.get(_catalogId, newDocId)) ?? nextRec;
1873
+ await this.emitNativeItemHistory(_context, {
1874
+ catalogId: _catalogId,
1875
+ itemId: String(persisted.itemId),
1876
+ storageDocId: newDocId,
1877
+ op: "update",
1878
+ before: existing,
1879
+ after: persisted,
1880
+ });
1881
+ const out = {
1882
+ itemId: nextRec.itemId,
1883
+ catalogId: _catalogId,
1884
+ appId,
1885
+ sourceMode: "native",
1886
+ sourceType: "firebase",
1887
+ data: mergedData,
1888
+ scope: nextScope,
1889
+ metadata: {
1890
+ createdAt: String(existing.metadata?.createdAt ?? updatedAt),
1891
+ lastUpdate: updatedAt,
1892
+ domainIds: scopeMeta.domainIds,
1893
+ agentIds: scopeMeta.agentIds,
1894
+ },
1895
+ };
1896
+ // Upsert any provided relations after the item is persisted.
1897
+ for (const r of patchRelations ?? []) {
1898
+ await this.upsertCatalogItemRelation(_context, {
1899
+ fromCatalogId: String(_catalogId),
1900
+ fromItemId: String(_itemId),
1901
+ toCatalogId: r.toCatalogId,
1902
+ toItemId: r.toItemId,
1903
+ relationType: r.relationType,
1904
+ ...(r.label != null ? { label: r.label } : {}),
1905
+ ...(r.metadata != null ? { metadata: r.metadata } : {}),
1906
+ });
1907
+ }
1908
+ return this.decorateItem(_catalogId, out);
1909
+ }
1910
+ async deleteNativeCatalogItem(_context, _catalogId, _itemId, _options) {
1911
+ const appId = await this.resolveAppIdForCatalogAccess({ context: _context, catalogId: _catalogId, required: "write" });
1912
+ await this.deps.authz.requireBindingAccess(_context, appId, _catalogId, "write");
1913
+ let docId = _options?.storageDocId;
1914
+ if (!docId) {
1915
+ const rows = await resolveNativeRowsByLogicalItemId(this.deps.nativeItems, _catalogId, _itemId);
1916
+ const winner = pickWinningPhysicalRow(rows);
1917
+ if (!winner)
1918
+ throw new CatalogNotFoundError({ catalogId: _catalogId, itemId: _itemId });
1919
+ docId = storageDocIdForNativeRecord(winner);
1920
+ }
1921
+ const beforeDel = await this.deps.nativeItems.get(_catalogId, docId);
1922
+ await this.deps.nativeItems.delete(_catalogId, docId);
1923
+ if (beforeDel) {
1924
+ await this.emitNativeItemHistory(_context, {
1925
+ catalogId: _catalogId,
1926
+ itemId: String(beforeDel.itemId),
1927
+ storageDocId: docId,
1928
+ op: "delete",
1929
+ before: beforeDel,
1930
+ after: null,
1931
+ });
1932
+ }
1933
+ }
1934
+ async moveNativeCatalogItemScope(context, catalogId, itemId, input) {
1935
+ if (!context.superAdmin) {
1936
+ throw new CatalogAccessDeniedError({ reason: "super_admin_required" });
1937
+ }
1938
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "write" });
1939
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "write");
1940
+ const fromDoc = input.fromStorageDocId ?? storageDocIdForNativeRecord({ itemId: String(itemId) });
1941
+ const rec = await this.deps.nativeItems.get(catalogId, fromDoc);
1942
+ if (!rec)
1943
+ throw new CatalogNotFoundError({ catalogId, itemId });
1944
+ const toScope = normalizeItemScope(input.toScope);
1945
+ assertWriteScopeAllowed(context, toScope);
1946
+ const scopeMeta = metadataFromScope(toScope);
1947
+ const nextRec = {
1948
+ ...rec,
1949
+ scope: toScope,
1950
+ indexed: { ...(rec.indexed ?? {}), ...indexedScopeFields(toScope) },
1951
+ metadata: {
1952
+ ...(rec.metadata ?? {}),
1953
+ domainIds: scopeMeta.domainIds,
1954
+ agentIds: scopeMeta.agentIds,
1955
+ lastUpdate: new Date().toISOString(),
1956
+ },
1957
+ };
1958
+ const toDoc = storageDocIdForNativeRecord(nextRec);
1959
+ await this.deps.nativeItems.upsert(catalogId, nextRec);
1960
+ if (toDoc !== fromDoc)
1961
+ await this.deps.nativeItems.delete(catalogId, fromDoc);
1962
+ const persisted = (await this.deps.nativeItems.get(catalogId, toDoc)) ?? nextRec;
1963
+ await this.emitNativeItemHistory(context, {
1964
+ catalogId,
1965
+ itemId: String(persisted.itemId),
1966
+ storageDocId: toDoc,
1967
+ op: "update",
1968
+ before: rec,
1969
+ after: persisted,
1970
+ });
1971
+ }
1972
+ async upsertNativeCatalogItem(context, catalogId, input) {
1973
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "write" });
1974
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "write");
1975
+ const descriptor = await this.deps.descriptors.get(catalogId);
1976
+ if (!descriptor)
1977
+ throw new CatalogAdapterError({ catalogId, reason: "missing_descriptor" });
1978
+ const { data, indexed: callerIndexed, scope: inputScope, relations: inputRelations } = this.stripReservedWriteFields(input);
1979
+ const storedScope = normalizeItemScope(inputScope ?? {});
1980
+ assertWriteScopeAllowed(context, storedScope);
1981
+ const logicalItemIdEarly = resolveCatalogItemId({ identity: descriptor.descriptor.identity, data });
1982
+ await this.assertNativeItemPayloadValid(context, catalogId, data, String(logicalItemIdEarly));
1983
+ const rulesOnly = validateSmartPropertyRules(descriptor.descriptor, data);
1984
+ if (!rulesOnly.isValid) {
1985
+ throw new CatalogValidationError({
1986
+ reason: "smart_properties",
1987
+ catalogId: String(catalogId),
1988
+ itemId: String(logicalItemIdEarly),
1989
+ report: rulesOnly,
1990
+ });
1991
+ }
1992
+ await resolveSmartPropertiesOnWrite(this.smartPropertyDeps(), context, catalogId, descriptor.descriptor, data, storedScope);
1993
+ const derived = this.deriveIndexed(descriptor.descriptor, data);
1994
+ const scopeIdx = indexedScopeFields(storedScope);
1995
+ const indexed = derived != null ? { ...derived, ...scopeIdx } : (Object.keys(scopeIdx).length ? scopeIdx : undefined);
1996
+ const logicalItemId = resolveCatalogItemId({ identity: descriptor.descriptor.identity, data });
1997
+ const storageDocId = storageDocIdForNativeRecord({ itemId: String(logicalItemId) });
1998
+ const scopeMeta = metadataFromScope(storedScope);
1999
+ const now = new Date().toISOString();
2000
+ const existing = await this.deps.nativeItems.get(catalogId, storageDocId);
2001
+ const actorId = this.resolveActorId(context);
2002
+ // Enforce relation rules on create/upsert when relationRules are declared.
2003
+ if (descriptor.descriptor?.relationRules?.length) {
2004
+ const existingRefs = await this.deps.references.listByItem(catalogId, logicalItemId);
2005
+ const nextRefs = [
2006
+ ...existingRefs,
2007
+ ...(inputRelations ?? []).map((r) => ({
2008
+ fromCatalogId: catalogId,
2009
+ fromItemId: logicalItemId,
2010
+ toCatalogId: r.toCatalogId,
2011
+ toItemId: r.toItemId,
2012
+ relationType: r.relationType,
2013
+ ...(r.label != null ? { label: r.label } : {}),
2014
+ ...(r.metadata != null ? { metadata: r.metadata } : {}),
2015
+ })),
2016
+ ];
2017
+ const report = await this.validateRelationsAgainstDescriptor(context, {
2018
+ catalogId,
2019
+ itemId: logicalItemId,
2020
+ descriptor: descriptor.descriptor,
2021
+ refs: nextRefs,
2022
+ });
2023
+ if (!report.isValid) {
2024
+ throw new CatalogValidationError({
2025
+ reason: "invalid_relations",
2026
+ catalogId: String(catalogId),
2027
+ itemId: String(logicalItemId),
2028
+ report,
2029
+ });
2030
+ }
2031
+ }
2032
+ await this.deps.nativeItems.upsert(catalogId, {
2033
+ itemId: logicalItemId,
2034
+ catalogId,
2035
+ scope: storedScope,
2036
+ appScopedOwnerId: appId,
2037
+ ...(indexed != null ? { indexed } : {}),
2038
+ data,
2039
+ metadata: {
2040
+ createdAt: String(existing?.metadata?.createdAt ?? now),
2041
+ lastUpdate: now,
2042
+ domainIds: scopeMeta.domainIds,
2043
+ agentIds: scopeMeta.agentIds,
2044
+ },
2045
+ version: (existing?.version ?? 0) + 1,
2046
+ ...(existing?.createdBy ? { createdBy: existing.createdBy } : actorId ? { createdBy: actorId } : {}),
2047
+ ...(actorId ? { updatedBy: actorId } : {}),
2048
+ });
2049
+ const persisted = (await this.deps.nativeItems.get(catalogId, storageDocId));
2050
+ await this.emitNativeItemHistory(context, {
2051
+ catalogId,
2052
+ itemId: String(logicalItemId),
2053
+ storageDocId,
2054
+ op: "update",
2055
+ before: existing ?? null,
2056
+ after: persisted,
2057
+ });
2058
+ // Upsert any provided relations after the item is persisted.
2059
+ for (const r of inputRelations ?? []) {
2060
+ await this.upsertCatalogItemRelation(context, {
2061
+ fromCatalogId: String(catalogId),
2062
+ fromItemId: String(logicalItemId),
2063
+ toCatalogId: r.toCatalogId,
2064
+ toItemId: r.toItemId,
2065
+ relationType: r.relationType,
2066
+ ...(r.label != null ? { label: r.label } : {}),
2067
+ ...(r.metadata != null ? { metadata: r.metadata } : {}),
2068
+ });
2069
+ }
2070
+ return {
2071
+ itemId: logicalItemId,
2072
+ catalogId,
2073
+ appId,
2074
+ sourceMode: "native",
2075
+ sourceType: "firebase",
2076
+ data,
2077
+ scope: storedScope,
2078
+ metadata: {
2079
+ createdAt: String(existing?.metadata?.createdAt ?? now),
2080
+ lastUpdate: now,
2081
+ domainIds: scopeMeta.domainIds,
2082
+ agentIds: scopeMeta.agentIds,
2083
+ },
2084
+ };
2085
+ }
2086
+ async batchUpsertNativeCatalogItems(context, catalogId, items) {
2087
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "write" });
2088
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "write");
2089
+ const descriptor = await this.deps.descriptors.get(catalogId);
2090
+ if (!descriptor)
2091
+ throw new CatalogAdapterError({ catalogId, reason: "missing_descriptor" });
2092
+ const now = new Date().toISOString();
2093
+ const actorId = this.resolveActorId(context);
2094
+ const catalog = await this.deps.catalogs.get(catalogId);
2095
+ const typeRegistry = catalog ? await this.resolveCatalogTypeRegistry(context) : null;
2096
+ const records = items.map((row) => {
2097
+ const stripped = this.stripReservedWriteFields(row);
2098
+ const storedScope = normalizeItemScope(stripped.scope ?? {});
2099
+ assertWriteScopeAllowed(context, storedScope);
2100
+ const scopeMeta = metadataFromScope(storedScope);
2101
+ if (catalog) {
2102
+ const report = this.validateNativeItemData(stripped.data, catalog, typeRegistry);
2103
+ if (!report.isValid) {
2104
+ const logicalItemId = resolveCatalogItemId({ identity: descriptor.descriptor.identity, data: stripped.data });
2105
+ throw new CatalogValidationError({
2106
+ reason: "invalid_payload",
2107
+ catalogId: String(catalogId),
2108
+ itemId: String(logicalItemId),
2109
+ report,
2110
+ });
2111
+ }
2112
+ }
2113
+ const derived = this.deriveIndexed(descriptor.descriptor, stripped.data);
2114
+ const scopeIdx = indexedScopeFields(storedScope);
2115
+ const indexed = derived != null ? { ...derived, ...scopeIdx } : (Object.keys(scopeIdx).length ? scopeIdx : undefined);
2116
+ const logicalItemId = resolveCatalogItemId({
2117
+ identity: descriptor.descriptor.identity,
2118
+ data: stripped.data,
2119
+ });
2120
+ return {
2121
+ itemId: logicalItemId,
2122
+ catalogId,
2123
+ scope: storedScope,
2124
+ appScopedOwnerId: appId,
2125
+ ...(indexed != null ? { indexed } : {}),
2126
+ data: stripped.data,
2127
+ metadata: { createdAt: now, lastUpdate: now, domainIds: scopeMeta.domainIds, agentIds: scopeMeta.agentIds },
2128
+ ...(actorId ? { updatedBy: actorId } : {}),
2129
+ };
2130
+ });
2131
+ const beforeRows = [];
2132
+ for (const r of records) {
2133
+ const docId = storageDocIdForNativeRecord(r);
2134
+ const ex = await this.deps.nativeItems.get(catalogId, docId);
2135
+ beforeRows.push({ docId, rec: ex });
2136
+ }
2137
+ await this.deps.nativeItems.batchUpsert(catalogId, records);
2138
+ for (let i = 0; i < records.length; i++) {
2139
+ const { docId, rec: before } = beforeRows[i];
2140
+ const after = (await this.deps.nativeItems.get(catalogId, docId));
2141
+ await this.emitNativeItemHistory(context, {
2142
+ catalogId,
2143
+ itemId: String(after.itemId),
2144
+ storageDocId: docId,
2145
+ op: "update",
2146
+ before,
2147
+ after,
2148
+ });
2149
+ }
2150
+ }
2151
+ /**
2152
+ * Full-document native replace (no field-level merge). Omitted keys in `data`, `indexed`, and
2153
+ * `metadata` are removed from the stored document. Use {@link upsertNativeCatalogItem} for
2154
+ * merge/patch persistence.
2155
+ */
2156
+ async replaceNativeCatalogItem(context, catalogId, record) {
2157
+ this.assertNativeCatalogRecordEnvelope(catalogId, record);
2158
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "write" });
2159
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "write");
2160
+ const descriptor = await this.deps.descriptors.get(catalogId);
2161
+ if (!descriptor)
2162
+ throw new CatalogAdapterError({ catalogId, reason: "missing_descriptor" });
2163
+ const storedScope = normalizeItemScope(record.scope ?? {});
2164
+ assertWriteScopeAllowed(context, storedScope);
2165
+ const catalog = await this.deps.catalogs.get(catalogId);
2166
+ const typeRegistry = catalog ? await this.resolveCatalogTypeRegistry(context) : null;
2167
+ if (catalog) {
2168
+ const report = this.validateNativeItemData(record.data, catalog, typeRegistry);
2169
+ if (!report.isValid) {
2170
+ throw new CatalogValidationError({
2171
+ reason: "invalid_payload",
2172
+ catalogId: String(catalogId),
2173
+ itemId: String(record.itemId),
2174
+ report,
2175
+ });
2176
+ }
2177
+ }
2178
+ const storageDocId = storageDocIdForNativeRecord(record);
2179
+ const existing = await this.deps.nativeItems.get(catalogId, storageDocId);
2180
+ const toPersist = this.buildReplaceNativeRecord(context, catalogId, record, appId, existing);
2181
+ await this.deps.nativeItems.replace(catalogId, toPersist);
2182
+ const persisted = (await this.deps.nativeItems.get(catalogId, storageDocId));
2183
+ await this.emitNativeItemHistory(context, {
2184
+ catalogId,
2185
+ itemId: String(record.itemId),
2186
+ storageDocId,
2187
+ op: "update",
2188
+ before: existing ?? null,
2189
+ after: persisted,
2190
+ });
2191
+ }
2192
+ /**
2193
+ * Batch variant of {@link replaceNativeCatalogItem}. When `options.atomic` is true, all rows
2194
+ * are validated before any write; each Firestore batch chunk (≤450 rows) commits atomically.
2195
+ */
2196
+ async replaceNativeCatalogItems(context, catalogId, records, options) {
2197
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "write" });
2198
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "write");
2199
+ const descriptor = await this.deps.descriptors.get(catalogId);
2200
+ if (!descriptor)
2201
+ throw new CatalogAdapterError({ catalogId, reason: "missing_descriptor" });
2202
+ const catalog = await this.deps.catalogs.get(catalogId);
2203
+ const typeRegistry = catalog ? await this.resolveCatalogTypeRegistry(context) : null;
2204
+ const prepared = [];
2205
+ const beforeRows = [];
2206
+ for (const record of records) {
2207
+ this.assertNativeCatalogRecordEnvelope(catalogId, record);
2208
+ const storedScope = normalizeItemScope(record.scope ?? {});
2209
+ assertWriteScopeAllowed(context, storedScope);
2210
+ if (catalog) {
2211
+ const report = this.validateNativeItemData(record.data, catalog, typeRegistry);
2212
+ if (!report.isValid) {
2213
+ throw new CatalogValidationError({
2214
+ reason: "invalid_payload",
2215
+ catalogId: String(catalogId),
2216
+ itemId: String(record.itemId),
2217
+ report,
2218
+ });
2219
+ }
2220
+ }
2221
+ const docId = storageDocIdForNativeRecord(record);
2222
+ const existing = await this.deps.nativeItems.get(catalogId, docId);
2223
+ beforeRows.push({ docId, rec: existing });
2224
+ prepared.push(this.buildReplaceNativeRecord(context, catalogId, record, appId, existing));
2225
+ }
2226
+ if (options?.atomic !== false) {
2227
+ await this.deps.nativeItems.batchReplace(catalogId, prepared);
2228
+ }
2229
+ else {
2230
+ for (const row of prepared) {
2231
+ await this.deps.nativeItems.replace(catalogId, row);
2232
+ }
2233
+ }
2234
+ for (let i = 0; i < prepared.length; i++) {
2235
+ const { docId, rec: before } = beforeRows[i];
2236
+ const after = (await this.deps.nativeItems.get(catalogId, docId));
2237
+ await this.emitNativeItemHistory(context, {
2238
+ catalogId,
2239
+ itemId: String(after.itemId),
2240
+ storageDocId: docId,
2241
+ op: "update",
2242
+ before,
2243
+ after,
2244
+ });
2245
+ }
2246
+ }
2247
+ importCatalogItemsFromJson(json) {
2248
+ return parseJson(json);
2249
+ }
2250
+ exportCatalogItemsToJson(value, pretty = true) {
2251
+ return toJson(value, pretty);
2252
+ }
2253
+ async exportInventory(context, input = {}) {
2254
+ const now = new Date().toISOString();
2255
+ const resolved = await this.resolveEffectiveAppIds(context, input);
2256
+ const out = {
2257
+ generatedAt: now,
2258
+ input,
2259
+ resolved: {
2260
+ ...(resolved.storeId != null ? { storeId: resolved.storeId } : {}),
2261
+ appIds: resolved.appIds,
2262
+ ...(input.catalogIds?.length ? { catalogIds: input.catalogIds } : {}),
2263
+ },
2264
+ apps: [],
2265
+ };
2266
+ for (const appId of resolved.appIds) {
2267
+ const appCtx = { ...context, appId };
2268
+ const catalogs = await this.listAppCatalogs(appCtx, {
2269
+ appId,
2270
+ ...(input.includeDisabledCatalogs != null ? { includeDisabled: input.includeDisabledCatalogs } : {}),
2271
+ ...(input.includeHiddenCatalogs != null ? { includeHidden: input.includeHiddenCatalogs } : {}),
2272
+ });
2273
+ const filteredCatalogs = catalogs.filter((c) => {
2274
+ if (input.catalogIds?.length && !input.catalogIds.includes(c.catalogId))
2275
+ return false;
2276
+ if (input.sourceModes?.length && !input.sourceModes.includes(c.sourceMode))
2277
+ return false;
2278
+ return true;
2279
+ });
2280
+ const exportedCatalogs = [];
2281
+ for (const c of filteredCatalogs) {
2282
+ if (!input.includeItems) {
2283
+ exportedCatalogs.push({ catalog: c });
2284
+ continue;
2285
+ }
2286
+ const list = await this.listCatalogItems(appCtx, c.catalogId, {
2287
+ limit: input.limitPerCatalog ?? 50,
2288
+ });
2289
+ const items = input.includeItemData === false
2290
+ ? list.items.map((it) => {
2291
+ const { data: _data, ...rest } = it;
2292
+ return rest;
2293
+ })
2294
+ : list.items;
2295
+ exportedCatalogs.push({
2296
+ catalog: c,
2297
+ items,
2298
+ ...(list.issues ? { issues: list.issues } : {}),
2299
+ });
2300
+ }
2301
+ out.apps.push({
2302
+ appId,
2303
+ catalogs: exportedCatalogs,
2304
+ });
2305
+ }
2306
+ return out;
2307
+ }
2308
+ async exportInventoryToJson(context, input = {}, pretty = true) {
2309
+ const data = await this.exportInventory(context, input);
2310
+ return toJson(data, pretty);
2311
+ }
2312
+ /**
2313
+ * Versioned full-catalog snapshot (`catalox-export/v1`) for backup and drift detection.
2314
+ * Paginates all items per catalog; catalogs and items are sorted deterministically.
2315
+ */
2316
+ async exportCatalogSnapshot(context, input = {}) {
2317
+ const appId = context.appId;
2318
+ if (!appId)
2319
+ throw new Error("exportCatalogSnapshot: missing context.appId");
2320
+ const appCtx = {
2321
+ ...context,
2322
+ appId,
2323
+ ...(input.storeId != null ? { storeId: input.storeId } : {}),
2324
+ };
2325
+ const catalogs = await this.listAppCatalogs(appCtx, {
2326
+ appId,
2327
+ ...(input.includeDisabledCatalogs != null ? { includeDisabled: input.includeDisabledCatalogs } : {}),
2328
+ ...(input.includeHiddenCatalogs != null ? { includeHidden: input.includeHiddenCatalogs } : {}),
2329
+ });
2330
+ const filtered = filterCatalogEntries(catalogs, input);
2331
+ const pageSize = input.pageSize ?? 200;
2332
+ const superList = input.includeAllNativeScopes !== false && Boolean(context.superAdmin);
2333
+ const includeItemData = input.includeItemData !== false;
2334
+ const exported = [];
2335
+ for (const c of filtered.sort((a, b) => String(a.catalogId).localeCompare(String(b.catalogId), "en"))) {
2336
+ const { items, truncated, listOutcome, issues } = await listAllCatalogItemsForExport(c.catalogId, (catalogId, opts) => this.listCatalogItems(appCtx, catalogId, {
2337
+ limit: opts.limit,
2338
+ ...(opts.offset != null ? { offset: opts.offset } : {}),
2339
+ ...(opts.cursor ? { cursor: opts.cursor } : {}),
2340
+ ...(opts.scope ? { scope: opts.scope } : {}),
2341
+ }), {
2342
+ pageSize,
2343
+ ...(input.maxItemsPerCatalog != null ? { maxItems: input.maxItemsPerCatalog } : {}),
2344
+ ...(superList && c.sourceMode === "native" ? { superList: true } : {}),
2345
+ });
2346
+ const payloadItems = includeItemData ? items : stripItemData(items);
2347
+ const catalogRecord = await this.deps.catalogs.get(c.catalogId);
2348
+ exported.push({
2349
+ catalogId: c.catalogId,
2350
+ catalog: c,
2351
+ ...(catalogRecord?.schemaVersion != null ? { schemaVersion: String(catalogRecord.schemaVersion) } : {}),
2352
+ itemCount: payloadItems.length,
2353
+ ...(truncated ? { truncated: true } : {}),
2354
+ listOutcome,
2355
+ ...(issues?.length ? { issues } : {}),
2356
+ items: payloadItems,
2357
+ });
2358
+ }
2359
+ return buildCataloxExportV1({ context: appCtx, input, catalogs: exported });
2360
+ }
2361
+ async exportCatalogSnapshotToJson(context, input = {}, pretty = true) {
2362
+ const data = await this.exportCatalogSnapshot(context, input);
2363
+ return toJson(data, pretty);
2364
+ }
2365
+ async generateInventoryReport(context, input = {}) {
2366
+ const now = new Date().toISOString();
2367
+ const top = input.top ?? 10;
2368
+ const resolved = await this.resolveEffectiveAppIds(context, input);
2369
+ const catalogsById = new Map();
2370
+ for (const appId of resolved.appIds) {
2371
+ const appCtx = { ...context, appId };
2372
+ const catalogs = await this.listAppCatalogs(appCtx, {
2373
+ appId,
2374
+ ...(input.includeDisabledCatalogs != null ? { includeDisabled: input.includeDisabledCatalogs } : {}),
2375
+ ...(input.includeHiddenCatalogs != null ? { includeHidden: input.includeHiddenCatalogs } : {}),
2376
+ });
2377
+ for (const c of catalogs) {
2378
+ if (input.catalogIds?.length && !input.catalogIds.includes(c.catalogId))
2379
+ continue;
2380
+ catalogsById.set(c.catalogId, c);
2381
+ }
2382
+ }
2383
+ const catalogIds = [...catalogsById.keys()].sort();
2384
+ const catalogStats = [];
2385
+ for (const catalogId of catalogIds) {
2386
+ const c = catalogsById.get(catalogId);
2387
+ // pick the first appId that has the binding for fetching examples
2388
+ const appId = resolved.appIds[0];
2389
+ const appCtx = { ...context, appId };
2390
+ const list = await this.listCatalogItems(appCtx, catalogId, { limit: top });
2391
+ const examples = list.items.slice(0, top).map((it) => ({
2392
+ catalogId,
2393
+ itemId: it.itemId,
2394
+ ...(it.title ? { title: it.title } : {}),
2395
+ ...(it.subtitle ? { subtitle: it.subtitle } : {}),
2396
+ ...(it.metadata?.lastUpdate ? { updatedAt: String(it.metadata.lastUpdate) } : {}),
2397
+ }));
2398
+ catalogStats.push({
2399
+ catalogId,
2400
+ label: c.label,
2401
+ sourceMode: c.sourceMode,
2402
+ status: c.metadata.status,
2403
+ ...(list.issues ? { mappingIssueCount: list.issues.length } : {}),
2404
+ topExamples: examples,
2405
+ });
2406
+ }
2407
+ const data = {
2408
+ generatedAt: now,
2409
+ input,
2410
+ resolved: {
2411
+ ...(resolved.storeId != null ? { storeId: resolved.storeId } : {}),
2412
+ appIds: resolved.appIds,
2413
+ ...(input.catalogIds?.length ? { catalogIds: input.catalogIds } : {}),
2414
+ },
2415
+ summary: {
2416
+ catalogCount: catalogStats.length,
2417
+ nativeCatalogCount: catalogStats.filter((c) => c.sourceMode === "native").length,
2418
+ mappedCatalogCount: catalogStats.filter((c) => c.sourceMode === "mapped").length,
2419
+ totalExamples: catalogStats.reduce((n, c) => n + (c.topExamples?.length ?? 0), 0),
2420
+ },
2421
+ catalogs: catalogStats,
2422
+ };
2423
+ if (input.includeDiff) {
2424
+ const diffCatalogs = [];
2425
+ for (const catalogId of catalogIds) {
2426
+ const runs = await this.deps.snapshots.listRuns(catalogId, 2);
2427
+ const latest = runs[0];
2428
+ const prev = runs[1];
2429
+ if (!latest || !prev) {
2430
+ diffCatalogs.push({ catalogId, added: 0, removed: 0, changed: 0 });
2431
+ continue;
2432
+ }
2433
+ const [newItems, oldItems] = await Promise.all([
2434
+ this.deps.snapshots.listRunItems(catalogId, latest.runId),
2435
+ this.deps.snapshots.listRunItems(catalogId, prev.runId),
2436
+ ]);
2437
+ const oldById = new Map(oldItems.map((r) => [r.itemId, r.sourceFingerprint ?? this.fingerprint(r.data)]));
2438
+ const newById = new Map(newItems.map((r) => [r.itemId, r.sourceFingerprint ?? this.fingerprint(r.data)]));
2439
+ const added = [];
2440
+ const removed = [];
2441
+ const changed = [];
2442
+ for (const id of newById.keys())
2443
+ if (!oldById.has(id))
2444
+ added.push(id);
2445
+ for (const id of oldById.keys())
2446
+ if (!newById.has(id))
2447
+ removed.push(id);
2448
+ for (const [id, fp] of newById) {
2449
+ const oldFp = oldById.get(id);
2450
+ if (oldFp && oldFp !== fp)
2451
+ changed.push(id);
2452
+ }
2453
+ const ex = (ids) => ids.slice(0, top).map((itemId) => ({ catalogId, itemId }));
2454
+ diffCatalogs.push({
2455
+ catalogId,
2456
+ added: added.length,
2457
+ removed: removed.length,
2458
+ changed: changed.length,
2459
+ examples: {
2460
+ ...(added.length ? { added: ex(added) } : {}),
2461
+ ...(removed.length ? { removed: ex(removed) } : {}),
2462
+ ...(changed.length ? { changed: ex(changed) } : {}),
2463
+ },
2464
+ });
2465
+ }
2466
+ data.diff = {
2467
+ baseline: { kind: "previous_snapshot_run" },
2468
+ catalogs: diffCatalogs,
2469
+ };
2470
+ }
2471
+ const markdown = renderInventoryReportMarkdown(data);
2472
+ return { markdown, data };
2473
+ }
2474
+ async syncMappedCatalog(_context, _catalogId) {
2475
+ const catalog = await this.deps.catalogs.get(_catalogId);
2476
+ if (!catalog)
2477
+ throw new CatalogNotFoundError({ catalogId: _catalogId });
2478
+ const def = await this.deps.definitions.get(_catalogId);
2479
+ if (!def || def.catalogItems.providerType !== "external") {
2480
+ throw new CatalogAdapterError({ catalogId: _catalogId, reason: "not_mapped" });
2481
+ }
2482
+ const mode = def.sync?.mode;
2483
+ if (mode !== "snapshot")
2484
+ return { syncStatus: "idle" };
2485
+ const now = new Date().toISOString();
2486
+ const runId = randomUUID();
2487
+ const actorId = this.resolveActorId(_context);
2488
+ await this.deps.snapshots.upsertRun(_catalogId, {
2489
+ runId,
2490
+ catalogId: _catalogId,
2491
+ startedAt: now,
2492
+ status: "running",
2493
+ ...(actorId ? { triggeredBy: actorId } : {}),
2494
+ });
2495
+ const list = await this.listCatalogItems(_context, _catalogId, { limit: 500 });
2496
+ for (const item of list.items) {
2497
+ const record = {
2498
+ itemId: item.itemId,
2499
+ catalogId: _catalogId,
2500
+ sourceFingerprint: this.fingerprint(item.data),
2501
+ ...(item.metadata?.lastUpdate ? { sourceUpdatedAt: String(item.metadata.lastUpdate) } : {}),
2502
+ data: item.data,
2503
+ sync: { lastSyncedAt: now, syncStatus: "success" },
2504
+ ...(actorId ? { metadata: { syncedBy: actorId } } : {}),
2505
+ };
2506
+ await this.deps.snapshots.upsert(_catalogId, record);
2507
+ await this.deps.snapshots.upsertRunItem(_catalogId, runId, record);
2508
+ }
2509
+ await this.deps.snapshots.upsertRun(_catalogId, {
2510
+ runId,
2511
+ catalogId: _catalogId,
2512
+ startedAt: now,
2513
+ finishedAt: new Date().toISOString(),
2514
+ status: "success",
2515
+ itemCount: list.items.length,
2516
+ ...(actorId ? { triggeredBy: actorId } : {}),
2517
+ });
2518
+ await this.deps.definitions.upsert({
2519
+ ...def,
2520
+ sync: {
2521
+ ...(def.sync ?? { mode: "snapshot" }),
2522
+ mode: "snapshot",
2523
+ lastSyncedAt: now,
2524
+ syncStatus: "success",
2525
+ },
2526
+ updatedAt: now,
2527
+ });
2528
+ return { syncStatus: "success", lastSyncedAt: now };
2529
+ }
2530
+ async backupData(_context, input) {
2531
+ return runBackupData({
2532
+ firestoreStore: this.deps.firestoreStore,
2533
+ catalogs: this.deps.catalogs,
2534
+ bindings: this.deps.bindings,
2535
+ }, input);
2536
+ }
2537
+ /** Revert a prior GCS restore using `backup-restoreSessions/{session}` and `{session}__preRestore-*` collections. */
2538
+ async undoFirestoreRestore(_context, input) {
2539
+ return runUndoFirestoreRestore({
2540
+ firestoreStore: this.deps.firestoreStore,
2541
+ catalogs: this.deps.catalogs,
2542
+ bindings: this.deps.bindings,
2543
+ nativeItems: this.deps.nativeItems,
2544
+ definitions: this.deps.definitions,
2545
+ catalogDataIndex: this.deps.catalogDataIndex,
2546
+ }, input);
2547
+ }
2548
+ /**
2549
+ * Restore live Firestore from one **`backupData` GCS** run (`metadata/`, `native/`, optional `snapshots/` NDJSON).
2550
+ * Captures pre-restore copies to `{session}__preRestore-*` first; **`undoFirestoreRestore`** works the same as for `restoreFirestoreBackup`.
2551
+ */
2552
+ async restoreFirestoreBackupFromGcs(_context, input) {
2553
+ return runRestoreFirestoreBackupFromGcs({
2554
+ firestoreStore: this.deps.firestoreStore,
2555
+ catalogs: this.deps.catalogs,
2556
+ bindings: this.deps.bindings,
2557
+ nativeItems: this.deps.nativeItems,
2558
+ definitions: this.deps.definitions,
2559
+ catalogDataIndex: this.deps.catalogDataIndex,
2560
+ }, input);
2561
+ }
2562
+ /** Delete oldest GCS Catalox backup **run folders** (children of the base prefix) until `keepLast` newest remain. */
2563
+ async pruneGcsBackupRuns(_context, input) {
2564
+ return pruneGcsBackupRuns(input);
2565
+ }
2566
+ /** Delete every object under one GCS backup run folder (operator cleanup). */
2567
+ async deleteCataloxGcsBackupRun(_context, input) {
2568
+ return runDeleteCataloxGcsBackupRun(input);
2569
+ }
2570
+ /**
2571
+ * Map a **`catalox-backup-manifest.json`** payload into the **`catalox-firestore-export-manifest.json`** shape
2572
+ * so `restoreAllFirestoreCollectionsFromGcsManifest` / CLI `import-gcs --restore-all` can consume the same NDJSON objects.
2573
+ */
2574
+ cataloxGcsBackupManifestToExportManifest(manifest, gcsRunFolder) {
2575
+ return cataloxGcsBackupManifestToFirestoreExportManifest(manifest, gcsRunFolder);
2576
+ }
2577
+ /**
2578
+ * For each discovered native catalog: counts in legacy `catalogData/{id}/items` vs flat `catalogData-{id}-items`,
2579
+ * and the resolver layout. Use when the console still shows the **legacy** subcollection `items` under `catalogData/{catalogId}`.
2580
+ */
2581
+ async reportNativeCatalogLayoutDiagnostics(_context, input) {
2582
+ return runReportNativeCatalogLayoutDiagnostics({
2583
+ firestoreStore: this.deps.firestoreStore,
2584
+ catalogs: this.deps.catalogs,
2585
+ bindings: this.deps.bindings,
2586
+ }, input);
2587
+ }
2588
+ async migrateNativeCatalogLayout(_context, input) {
2589
+ return runMigrateNativeCatalogLayout({
2590
+ firestoreStore: this.deps.firestoreStore,
2591
+ catalogs: this.deps.catalogs,
2592
+ bindings: this.deps.bindings,
2593
+ nativeItems: this.deps.nativeItems,
2594
+ catalogDataIndex: this.deps.catalogDataIndex,
2595
+ definitions: this.deps.definitions,
2596
+ }, input);
2597
+ }
2598
+ async migrateNativeItemScope(_context, input) {
2599
+ return runMigrateNativeItemScope({
2600
+ firestoreStore: this.deps.firestoreStore,
2601
+ catalogs: this.deps.catalogs,
2602
+ bindings: this.deps.bindings,
2603
+ nativeItems: this.deps.nativeItems,
2604
+ }, input);
2605
+ }
2606
+ /**
2607
+ * Export one Firestore collection (slash path) to a GCS object as NDJSON (`{ id, data }` per line).
2608
+ * Auth: uses Admin Firestore only; bucket IAM must allow the runtime credential.
2609
+ */
2610
+ async exportFirestoreCollectionToGcs(_context, input) {
2611
+ return exportFirestoreCollectionToGcs({
2612
+ ...input,
2613
+ firestore: this.deps.firestoreStore.firestore,
2614
+ });
2615
+ }
2616
+ /** Export every root collection, optionally recurse into all subcollections; writes a JSON manifest next to NDJSON files. */
2617
+ async exportAllFirestoreCollectionsToGcs(_context, input) {
2618
+ return exportAllFirestoreCollectionsToGcs({
2619
+ ...input,
2620
+ firestore: this.deps.firestoreStore.firestore,
2621
+ });
2622
+ }
2623
+ /** Restore one collection from an NDJSON object in GCS (non-merge writes per document id). */
2624
+ async restoreFirestoreCollectionFromGcs(_context, input) {
2625
+ return restoreFirestoreCollectionFromGcs({
2626
+ ...input,
2627
+ firestore: this.deps.firestoreStore.firestore,
2628
+ });
2629
+ }
2630
+ /** Restore every entry listed in a Catalox GCS export manifest. */
2631
+ async restoreAllFirestoreCollectionsFromGcsManifest(_context, input) {
2632
+ return restoreAllFirestoreCollectionsFromGcsManifest({
2633
+ ...input,
2634
+ firestore: this.deps.firestoreStore.firestore,
2635
+ });
2636
+ }
2637
+ /** Diff one live collection against an NDJSON object in GCS (same layout as `export-gcs`). */
2638
+ async compareFirestoreCollectionWithGcsNdjson(_context, input) {
2639
+ return compareFirestoreCollectionWithGcsNdjson({
2640
+ ...input,
2641
+ firestore: this.deps.firestoreStore.firestore,
2642
+ });
2643
+ }
2644
+ /** Run `compareFirestoreCollectionWithGcsNdjson` for every entry in an export manifest. */
2645
+ async compareAllFirestoreCollectionsWithGcsManifest(_context, input) {
2646
+ return compareAllFirestoreCollectionsWithGcsManifest({
2647
+ ...input,
2648
+ firestore: this.deps.firestoreStore.firestore,
2649
+ });
2650
+ }
2651
+ async listCatalogItemHistory(context, catalogId, input) {
2652
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "read" });
2653
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "read");
2654
+ const rh = this.deps.recordHistory;
2655
+ if (!rh)
2656
+ return { events: [] };
2657
+ return rh.store.listByCatalog(catalogId, input);
2658
+ }
2659
+ async getCatalogItemHistoryEvent(context, eventId) {
2660
+ const rh = this.deps.recordHistory;
2661
+ if (!rh)
2662
+ return null;
2663
+ const row = await rh.store.get(eventId);
2664
+ if (!row)
2665
+ return null;
2666
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId: row.catalogId, required: "read" });
2667
+ await this.deps.authz.requireBindingAccess(context, appId, row.catalogId, "read");
2668
+ const payload = await readRecordHistoryEventPayload(rh, row);
2669
+ return { index: row, payload };
2670
+ }
2671
+ async restoreCatalogItemFromHistory(context, eventId, input) {
2672
+ const rh = this.deps.recordHistory;
2673
+ if (!rh)
2674
+ throw new Error("recordHistory is not configured on Catalox");
2675
+ const row = await rh.store.get(eventId);
2676
+ if (!row)
2677
+ throw new Error(`catalogItemHistory event not found: ${eventId}`);
2678
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId: row.catalogId, required: "write" });
2679
+ await this.deps.authz.requireBindingAccess(context, appId, row.catalogId, "write");
2680
+ const payload = await readRecordHistoryEventPayload(rh, row);
2681
+ const rec = input.mode === "before" ? payload.before ?? undefined : payload.after ?? undefined;
2682
+ if (!rec)
2683
+ throw new CatalogNotFoundError({ catalogId: row.catalogId, itemId: row.itemId });
2684
+ const docId = storageDocIdForNativeRecord(rec);
2685
+ const liveBefore = await this.deps.nativeItems.get(row.catalogId, docId);
2686
+ await this.deps.nativeItems.upsert(row.catalogId, rec);
2687
+ const liveAfter = (await this.deps.nativeItems.get(row.catalogId, docId));
2688
+ await this.emitNativeItemHistory(context, {
2689
+ catalogId: row.catalogId,
2690
+ itemId: String(rec.itemId),
2691
+ storageDocId: docId,
2692
+ op: "restore",
2693
+ before: liveBefore ?? null,
2694
+ after: liveAfter,
2695
+ });
2696
+ return this.decorateItem(row.catalogId, {
2697
+ itemId: rec.itemId,
2698
+ catalogId: row.catalogId,
2699
+ appId,
2700
+ sourceMode: "native",
2701
+ sourceType: "firebase",
2702
+ data: liveAfter.data,
2703
+ metadata: liveAfter.metadata ?? {},
2704
+ });
2705
+ }
2706
+ /**
2707
+ * List changes to one field on a native item by diffing row-level history snapshots.
2708
+ * Bare field names (e.g. `instructions`) resolve under `item.data`.
2709
+ */
2710
+ async listCatalogItemFieldHistory(context, catalogId, input) {
2711
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "read" });
2712
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "read");
2713
+ const rh = this.deps.recordHistory;
2714
+ if (!rh)
2715
+ return { changes: [], scannedEvents: 0 };
2716
+ const normalized = normalizeRecordFieldPath(input.fieldPath);
2717
+ const limit = Math.min(Math.max(input.limit ?? 50, 1), 500);
2718
+ const maxScan = Math.min(Math.max(input.maxScan ?? 500, limit), 5000);
2719
+ const changes = [];
2720
+ let cursor = input.startAfterEventId;
2721
+ let scannedEvents = 0;
2722
+ let lastScannedEventId;
2723
+ let hasMoreEvents = false;
2724
+ while (changes.length < limit && scannedEvents < maxScan) {
2725
+ const pageSize = Math.min(100, maxScan - scannedEvents);
2726
+ const page = await rh.store.listByCatalog(catalogId, {
2727
+ itemId: input.itemId,
2728
+ ...(input.since ? { since: input.since } : {}),
2729
+ ...(input.until ? { until: input.until } : {}),
2730
+ limit: pageSize,
2731
+ ...(cursor ? { startAfterEventId: cursor } : {}),
2732
+ });
2733
+ if (!page.events.length)
2734
+ break;
2735
+ for (const idx of page.events) {
2736
+ scannedEvents += 1;
2737
+ lastScannedEventId = idx.eventId;
2738
+ if (!isItemFieldHistoryOp(idx.op))
2739
+ continue;
2740
+ const payload = await readRecordHistoryEventPayload(rh, idx);
2741
+ const { beforeValue, afterValue, changed } = extractFieldChange(payload, normalized.recordPath);
2742
+ if (!changed)
2743
+ continue;
2744
+ changes.push({
2745
+ eventId: idx.eventId,
2746
+ op: idx.op,
2747
+ ts: idx.ts,
2748
+ fieldPath: normalized.recordPath,
2749
+ beforeValue,
2750
+ afterValue,
2751
+ ...(idx.actorId ? { actorId: idx.actorId } : {}),
2752
+ });
2753
+ if (changes.length >= limit)
2754
+ break;
2755
+ }
2756
+ if (changes.length >= limit || scannedEvents >= maxScan) {
2757
+ hasMoreEvents = page.events.length === pageSize && !!page.nextCursor;
2758
+ break;
2759
+ }
2760
+ if (!page.nextCursor)
2761
+ break;
2762
+ cursor = page.nextCursor;
2763
+ }
2764
+ return {
2765
+ changes,
2766
+ scannedEvents,
2767
+ ...(hasMoreEvents && lastScannedEventId ? { nextCursor: lastScannedEventId } : {}),
2768
+ };
2769
+ }
2770
+ /**
2771
+ * Restore one field on a live native item from a history event (`before` or `after` snapshot).
2772
+ * Supports `data.*` and `indexed.*` paths; other roots require full-row restore.
2773
+ */
2774
+ async restoreCatalogItemFieldFromHistory(context, eventId, input) {
2775
+ const rh = this.deps.recordHistory;
2776
+ if (!rh)
2777
+ throw new Error("recordHistory is not configured on Catalox");
2778
+ const row = await rh.store.get(eventId);
2779
+ if (!row)
2780
+ throw new Error(`catalogItemHistory event not found: ${eventId}`);
2781
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId: row.catalogId, required: "write" });
2782
+ await this.deps.authz.requireBindingAccess(context, appId, row.catalogId, "write");
2783
+ const normalized = normalizeRecordFieldPath(input.fieldPath);
2784
+ if (normalized.restoreVia === "unsupported") {
2785
+ throw new Error(`Field restore is not supported for ${normalized.recordPath}; use restoreCatalogItemFromHistory for full-row restore.`);
2786
+ }
2787
+ const payload = await readRecordHistoryEventPayload(rh, row);
2788
+ const snapshot = input.mode === "before" ? payload.before ?? undefined : payload.after ?? undefined;
2789
+ const restoredValue = readRecordFieldPath(snapshot ?? null, normalized.recordPath);
2790
+ let existing = null;
2791
+ if (row.storageDocId) {
2792
+ existing = await this.deps.nativeItems.get(row.catalogId, row.storageDocId);
2793
+ }
2794
+ else {
2795
+ const rows = await resolveNativeRowsByLogicalItemId(this.deps.nativeItems, row.catalogId, row.itemId);
2796
+ existing = pickWinningPhysicalRow(rows);
2797
+ }
2798
+ if (!existing)
2799
+ throw new CatalogNotFoundError({ catalogId: row.catalogId, itemId: row.itemId });
2800
+ if (normalized.restoreVia === "data") {
2801
+ const nextData = setAtRelativePath((existing.data ?? {}), normalized.patchRelativePath, restoredValue);
2802
+ return this.updateNativeCatalogItem(context, row.catalogId, row.itemId, nextData);
2803
+ }
2804
+ const nextIndexed = setAtRelativePath((existing.indexed ?? {}), normalized.patchRelativePath, restoredValue);
2805
+ return this.updateNativeCatalogItem(context, row.catalogId, row.itemId, { indexed: nextIndexed });
2806
+ }
2807
+ async replayCatalogToPointInTime(context, catalogId, input) {
2808
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "write" });
2809
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "write");
2810
+ const rh = this.deps.recordHistory;
2811
+ if (!rh)
2812
+ throw new Error("recordHistory is not configured on Catalox");
2813
+ const rows = await rh.store.listByCatalogChronologicalUntil(catalogId, input.asOf);
2814
+ const state = new Map();
2815
+ for (const idx of rows) {
2816
+ const full = await readRecordHistoryEventPayload(rh, idx);
2817
+ const key = String(full.storageDocId ?? full.itemId);
2818
+ if (full.op === "catalog_delete_bulk") {
2819
+ state.clear();
2820
+ continue;
2821
+ }
2822
+ if (full.op === "catalog_rename")
2823
+ continue;
2824
+ if (full.op === "delete") {
2825
+ state.delete(key);
2826
+ continue;
2827
+ }
2828
+ if (full.after)
2829
+ state.set(key, full.after);
2830
+ else
2831
+ state.delete(key);
2832
+ }
2833
+ const live = [];
2834
+ let off = 0;
2835
+ const page = 400;
2836
+ while (true) {
2837
+ const chunk = await this.deps.nativeItems.list(catalogId, { limit: page, offset: off });
2838
+ if (!chunk.length)
2839
+ break;
2840
+ live.push(...chunk);
2841
+ off += chunk.length;
2842
+ if (chunk.length < page)
2843
+ break;
2844
+ }
2845
+ let upserted = 0;
2846
+ let deleted = 0;
2847
+ for (const rec of state.values()) {
2848
+ await this.deps.nativeItems.upsert(catalogId, rec);
2849
+ upserted += 1;
2850
+ }
2851
+ for (const r of live) {
2852
+ const k = storageDocIdForNativeRecord(r);
2853
+ if (!state.has(k)) {
2854
+ await this.deps.nativeItems.delete(catalogId, k);
2855
+ deleted += 1;
2856
+ }
2857
+ }
2858
+ return { upserted, deleted };
2859
+ }
2860
+ async deleteCatalog(context, catalogId, input) {
2861
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId, required: "admin" });
2862
+ await this.deps.authz.requireBindingAccess(context, appId, catalogId, "admin");
2863
+ return runDeleteCatalog(this.catalogLifecycleDeps(), this.deps.recordHistory, { ...context, appId }, catalogId, input);
2864
+ }
2865
+ async restoreDeletedCatalog(context, input) {
2866
+ if (!context.superAdmin) {
2867
+ throw new CatalogAccessDeniedError({ reason: "super_admin_required" });
2868
+ }
2869
+ const rh = this.deps.recordHistory;
2870
+ if (!rh) {
2871
+ return {
2872
+ ok: false,
2873
+ catalogId: "",
2874
+ issues: [{ code: "record_history_required", message: "recordHistory is not configured on Catalox" }],
2875
+ };
2876
+ }
2877
+ return runRestoreDeletedCatalog(this.catalogLifecycleDeps(), rh, input);
2878
+ }
2879
+ async renameCatalog(context, fromCatalogId, toCatalogId, input = {}) {
2880
+ const appId = await this.resolveAppIdForCatalogAccess({ context, catalogId: fromCatalogId, required: "admin" });
2881
+ await this.deps.authz.requireBindingAccess(context, appId, fromCatalogId, "admin");
2882
+ return runRenameCatalog(this.catalogLifecycleDeps(), this.deps.recordHistory, { ...context, appId }, fromCatalogId, toCatalogId, input);
2883
+ }
2884
+ /**
2885
+ * Fix {@link CataloxContext} for subsequent calls so embedders omit it on each method (no globals).
2886
+ */
2887
+ withContext(context) {
2888
+ return new CataloxBound(this, context);
2889
+ }
2890
+ }
2891
+ // (moved to `src/contracts/bootstrap.ts`)
2892
+ //# sourceMappingURL=catalox.js.map