@agent-native/creative-context 0.1.0

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 (618) hide show
  1. package/README.md +108 -0
  2. package/agent-native.package.json +104 -0
  3. package/dist/actions/confirm-canonical-logo.d.ts +6 -0
  4. package/dist/actions/confirm-canonical-logo.d.ts.map +1 -0
  5. package/dist/actions/confirm-canonical-logo.js +19 -0
  6. package/dist/actions/confirm-canonical-logo.js.map +1 -0
  7. package/dist/actions/continue-context-import.d.ts +7 -0
  8. package/dist/actions/continue-context-import.d.ts.map +1 -0
  9. package/dist/actions/continue-context-import.js +10 -0
  10. package/dist/actions/continue-context-import.js.map +1 -0
  11. package/dist/actions/creative-context-a2a.d.ts +10 -0
  12. package/dist/actions/creative-context-a2a.d.ts.map +1 -0
  13. package/dist/actions/creative-context-a2a.js +66 -0
  14. package/dist/actions/creative-context-a2a.js.map +1 -0
  15. package/dist/actions/get-brand-profile.d.ts +33 -0
  16. package/dist/actions/get-brand-profile.d.ts.map +1 -0
  17. package/dist/actions/get-brand-profile.js +13 -0
  18. package/dist/actions/get-brand-profile.js.map +1 -0
  19. package/dist/actions/get-context-import-status.d.ts +22 -0
  20. package/dist/actions/get-context-import-status.d.ts.map +1 -0
  21. package/dist/actions/get-context-import-status.js +12 -0
  22. package/dist/actions/get-context-import-status.js.map +1 -0
  23. package/dist/actions/get-context-item.d.ts +2 -0
  24. package/dist/actions/get-context-item.d.ts.map +1 -0
  25. package/dist/actions/get-context-item.js +2 -0
  26. package/dist/actions/get-context-item.js.map +1 -0
  27. package/dist/actions/get-context-pack.d.ts +7 -0
  28. package/dist/actions/get-context-pack.d.ts.map +1 -0
  29. package/dist/actions/get-context-pack.js +12 -0
  30. package/dist/actions/get-context-pack.js.map +1 -0
  31. package/dist/actions/get-creative-context.d.ts +119 -0
  32. package/dist/actions/get-creative-context.d.ts.map +1 -0
  33. package/dist/actions/get-creative-context.js +112 -0
  34. package/dist/actions/get-creative-context.js.map +1 -0
  35. package/dist/actions/index.d.ts +3 -0
  36. package/dist/actions/index.d.ts.map +1 -0
  37. package/dist/actions/index.js +63 -0
  38. package/dist/actions/index.js.map +1 -0
  39. package/dist/actions/infer-brand-dna.d.ts +52 -0
  40. package/dist/actions/infer-brand-dna.d.ts.map +1 -0
  41. package/dist/actions/infer-brand-dna.js +13 -0
  42. package/dist/actions/infer-brand-dna.js.map +1 -0
  43. package/dist/actions/list-canonical-logo-candidates.d.ts +9 -0
  44. package/dist/actions/list-canonical-logo-candidates.d.ts.map +1 -0
  45. package/dist/actions/list-canonical-logo-candidates.js +82 -0
  46. package/dist/actions/list-canonical-logo-candidates.js.map +1 -0
  47. package/dist/actions/list-context-connections.d.ts +22 -0
  48. package/dist/actions/list-context-connections.d.ts.map +1 -0
  49. package/dist/actions/list-context-connections.js +43 -0
  50. package/dist/actions/list-context-connections.js.map +1 -0
  51. package/dist/actions/list-context-packs.d.ts +10 -0
  52. package/dist/actions/list-context-packs.d.ts.map +1 -0
  53. package/dist/actions/list-context-packs.js +16 -0
  54. package/dist/actions/list-context-packs.js.map +1 -0
  55. package/dist/actions/list-context-sources.d.ts +12 -0
  56. package/dist/actions/list-context-sources.d.ts.map +1 -0
  57. package/dist/actions/list-context-sources.js +20 -0
  58. package/dist/actions/list-context-sources.js.map +1 -0
  59. package/dist/actions/list-context-suggestions.d.ts +13 -0
  60. package/dist/actions/list-context-suggestions.d.ts.map +1 -0
  61. package/dist/actions/list-context-suggestions.js +28 -0
  62. package/dist/actions/list-context-suggestions.js.map +1 -0
  63. package/dist/actions/manage-brand-profile.d.ts +28 -0
  64. package/dist/actions/manage-brand-profile.d.ts.map +1 -0
  65. package/dist/actions/manage-brand-profile.js +47 -0
  66. package/dist/actions/manage-brand-profile.js.map +1 -0
  67. package/dist/actions/manage-context-pack.d.ts +33 -0
  68. package/dist/actions/manage-context-pack.d.ts.map +1 -0
  69. package/dist/actions/manage-context-pack.js +65 -0
  70. package/dist/actions/manage-context-pack.js.map +1 -0
  71. package/dist/actions/manage-context-source.d.ts +51 -0
  72. package/dist/actions/manage-context-source.d.ts.map +1 -0
  73. package/dist/actions/manage-context-source.js +137 -0
  74. package/dist/actions/manage-context-source.js.map +1 -0
  75. package/dist/actions/manage-layout-template.d.ts +13 -0
  76. package/dist/actions/manage-layout-template.d.ts.map +1 -0
  77. package/dist/actions/manage-layout-template.js +43 -0
  78. package/dist/actions/manage-layout-template.js.map +1 -0
  79. package/dist/actions/preview-context-import.d.ts +23 -0
  80. package/dist/actions/preview-context-import.d.ts.map +1 -0
  81. package/dist/actions/preview-context-import.js +57 -0
  82. package/dist/actions/preview-context-import.js.map +1 -0
  83. package/dist/actions/process-context-purge.d.ts +22 -0
  84. package/dist/actions/process-context-purge.d.ts.map +1 -0
  85. package/dist/actions/process-context-purge.js +19 -0
  86. package/dist/actions/process-context-purge.js.map +1 -0
  87. package/dist/actions/propose-brand-dna.d.ts +15 -0
  88. package/dist/actions/propose-brand-dna.d.ts.map +1 -0
  89. package/dist/actions/propose-brand-dna.js +19 -0
  90. package/dist/actions/propose-brand-dna.js.map +1 -0
  91. package/dist/actions/propose-canonical-logo.d.ts +9 -0
  92. package/dist/actions/propose-canonical-logo.d.ts.map +1 -0
  93. package/dist/actions/propose-canonical-logo.js +16 -0
  94. package/dist/actions/propose-canonical-logo.js.map +1 -0
  95. package/dist/actions/publish-brand-dna.d.ts +13 -0
  96. package/dist/actions/publish-brand-dna.d.ts.map +1 -0
  97. package/dist/actions/publish-brand-dna.js +23 -0
  98. package/dist/actions/publish-brand-dna.js.map +1 -0
  99. package/dist/actions/recommend-context-roots.d.ts +14 -0
  100. package/dist/actions/recommend-context-roots.d.ts.map +1 -0
  101. package/dist/actions/recommend-context-roots.js +22 -0
  102. package/dist/actions/recommend-context-roots.js.map +1 -0
  103. package/dist/actions/record-context-feedback.d.ts +10 -0
  104. package/dist/actions/record-context-feedback.d.ts.map +1 -0
  105. package/dist/actions/record-context-feedback.js +14 -0
  106. package/dist/actions/record-context-feedback.js.map +1 -0
  107. package/dist/actions/review-context-items.d.ts +35 -0
  108. package/dist/actions/review-context-items.d.ts.map +1 -0
  109. package/dist/actions/review-context-items.js +65 -0
  110. package/dist/actions/review-context-items.js.map +1 -0
  111. package/dist/actions/run-embedding-bakeoff.d.ts +15 -0
  112. package/dist/actions/run-embedding-bakeoff.d.ts.map +1 -0
  113. package/dist/actions/run-embedding-bakeoff.js +72 -0
  114. package/dist/actions/run-embedding-bakeoff.js.map +1 -0
  115. package/dist/actions/search-creative-context.d.ts +75 -0
  116. package/dist/actions/search-creative-context.d.ts.map +1 -0
  117. package/dist/actions/search-creative-context.js +41 -0
  118. package/dist/actions/search-creative-context.js.map +1 -0
  119. package/dist/actions/set-brand-dna.d.ts +15 -0
  120. package/dist/actions/set-brand-dna.d.ts.map +1 -0
  121. package/dist/actions/set-brand-dna.js +19 -0
  122. package/dist/actions/set-brand-dna.js.map +1 -0
  123. package/dist/actions/start-context-enrichment.d.ts +10 -0
  124. package/dist/actions/start-context-enrichment.d.ts.map +1 -0
  125. package/dist/actions/start-context-enrichment.js +46 -0
  126. package/dist/actions/start-context-enrichment.js.map +1 -0
  127. package/dist/actions/start-context-import.d.ts +9 -0
  128. package/dist/actions/start-context-import.d.ts.map +1 -0
  129. package/dist/actions/start-context-import.js +36 -0
  130. package/dist/actions/start-context-import.js.map +1 -0
  131. package/dist/client/CreativeContextChip.d.ts +13 -0
  132. package/dist/client/CreativeContextChip.d.ts.map +1 -0
  133. package/dist/client/CreativeContextChip.js +45 -0
  134. package/dist/client/CreativeContextChip.js.map +1 -0
  135. package/dist/client/CreativeContextPanel.d.ts +131 -0
  136. package/dist/client/CreativeContextPanel.d.ts.map +1 -0
  137. package/dist/client/CreativeContextPanel.js +778 -0
  138. package/dist/client/CreativeContextPanel.js.map +1 -0
  139. package/dist/client/CreativeContextSettingsLink.d.ts +4 -0
  140. package/dist/client/CreativeContextSettingsLink.d.ts.map +1 -0
  141. package/dist/client/CreativeContextSettingsLink.js +8 -0
  142. package/dist/client/CreativeContextSettingsLink.js.map +1 -0
  143. package/dist/client/actions.d.ts +256 -0
  144. package/dist/client/actions.d.ts.map +1 -0
  145. package/dist/client/actions.js +89 -0
  146. package/dist/client/actions.js.map +1 -0
  147. package/dist/client/agent-tab.d.ts +9 -0
  148. package/dist/client/agent-tab.d.ts.map +1 -0
  149. package/dist/client/agent-tab.js +32 -0
  150. package/dist/client/agent-tab.js.map +1 -0
  151. package/dist/client/application-state.d.ts +22 -0
  152. package/dist/client/application-state.d.ts.map +1 -0
  153. package/dist/client/application-state.js +88 -0
  154. package/dist/client/application-state.js.map +1 -0
  155. package/dist/client/index.d.ts +8 -0
  156. package/dist/client/index.d.ts.map +1 -0
  157. package/dist/client/index.js +8 -0
  158. package/dist/client/index.js.map +1 -0
  159. package/dist/client/messages.d.ts +5 -0
  160. package/dist/client/messages.d.ts.map +1 -0
  161. package/dist/client/messages.js +1059 -0
  162. package/dist/client/messages.js.map +1 -0
  163. package/dist/connectors/context.d.ts +9 -0
  164. package/dist/connectors/context.d.ts.map +1 -0
  165. package/dist/connectors/context.js +59 -0
  166. package/dist/connectors/context.js.map +1 -0
  167. package/dist/connectors/document-parser.d.ts +2 -0
  168. package/dist/connectors/document-parser.d.ts.map +1 -0
  169. package/dist/connectors/document-parser.js +2 -0
  170. package/dist/connectors/document-parser.js.map +1 -0
  171. package/dist/connectors/figma-native.d.ts +18 -0
  172. package/dist/connectors/figma-native.d.ts.map +1 -0
  173. package/dist/connectors/figma-native.js +883 -0
  174. package/dist/connectors/figma-native.js.map +1 -0
  175. package/dist/connectors/figma.d.ts +10 -0
  176. package/dist/connectors/figma.d.ts.map +1 -0
  177. package/dist/connectors/figma.js +166 -0
  178. package/dist/connectors/figma.js.map +1 -0
  179. package/dist/connectors/google-slides-native.d.ts +58 -0
  180. package/dist/connectors/google-slides-native.d.ts.map +1 -0
  181. package/dist/connectors/google-slides-native.js +1118 -0
  182. package/dist/connectors/google-slides-native.js.map +1 -0
  183. package/dist/connectors/google-slides.d.ts +15 -0
  184. package/dist/connectors/google-slides.d.ts.map +1 -0
  185. package/dist/connectors/google-slides.js +896 -0
  186. package/dist/connectors/google-slides.js.map +1 -0
  187. package/dist/connectors/index.d.ts +20 -0
  188. package/dist/connectors/index.d.ts.map +1 -0
  189. package/dist/connectors/index.js +44 -0
  190. package/dist/connectors/index.js.map +1 -0
  191. package/dist/connectors/manual.d.ts +9 -0
  192. package/dist/connectors/manual.d.ts.map +1 -0
  193. package/dist/connectors/manual.js +91 -0
  194. package/dist/connectors/manual.js.map +1 -0
  195. package/dist/connectors/normalize.d.ts +35 -0
  196. package/dist/connectors/normalize.d.ts.map +1 -0
  197. package/dist/connectors/normalize.js +216 -0
  198. package/dist/connectors/normalize.js.map +1 -0
  199. package/dist/connectors/notion.d.ts +10 -0
  200. package/dist/connectors/notion.d.ts.map +1 -0
  201. package/dist/connectors/notion.js +393 -0
  202. package/dist/connectors/notion.js.map +1 -0
  203. package/dist/connectors/private-artifacts.d.ts +39 -0
  204. package/dist/connectors/private-artifacts.d.ts.map +1 -0
  205. package/dist/connectors/private-artifacts.js +175 -0
  206. package/dist/connectors/private-artifacts.js.map +1 -0
  207. package/dist/connectors/provider-response.d.ts +20 -0
  208. package/dist/connectors/provider-response.d.ts.map +1 -0
  209. package/dist/connectors/provider-response.js +98 -0
  210. package/dist/connectors/provider-response.js.map +1 -0
  211. package/dist/connectors/recommendations.d.ts +25 -0
  212. package/dist/connectors/recommendations.d.ts.map +1 -0
  213. package/dist/connectors/recommendations.js +172 -0
  214. package/dist/connectors/recommendations.js.map +1 -0
  215. package/dist/connectors/registry.d.ts +10 -0
  216. package/dist/connectors/registry.d.ts.map +1 -0
  217. package/dist/connectors/registry.js +34 -0
  218. package/dist/connectors/registry.js.map +1 -0
  219. package/dist/connectors/rendered-page.d.ts +101 -0
  220. package/dist/connectors/rendered-page.d.ts.map +1 -0
  221. package/dist/connectors/rendered-page.js +504 -0
  222. package/dist/connectors/rendered-page.js.map +1 -0
  223. package/dist/connectors/smart-defaults.d.ts +9 -0
  224. package/dist/connectors/smart-defaults.d.ts.map +1 -0
  225. package/dist/connectors/smart-defaults.js +72 -0
  226. package/dist/connectors/smart-defaults.js.map +1 -0
  227. package/dist/connectors/types.d.ts +79 -0
  228. package/dist/connectors/types.d.ts.map +1 -0
  229. package/dist/connectors/types.js +2 -0
  230. package/dist/connectors/types.js.map +1 -0
  231. package/dist/connectors/upload.d.ts +9 -0
  232. package/dist/connectors/upload.d.ts.map +1 -0
  233. package/dist/connectors/upload.js +440 -0
  234. package/dist/connectors/upload.js.map +1 -0
  235. package/dist/connectors/website.d.ts +20 -0
  236. package/dist/connectors/website.d.ts.map +1 -0
  237. package/dist/connectors/website.js +616 -0
  238. package/dist/connectors/website.js.map +1 -0
  239. package/dist/embeddings/index.d.ts +3 -0
  240. package/dist/embeddings/index.d.ts.map +1 -0
  241. package/dist/embeddings/index.js +3 -0
  242. package/dist/embeddings/index.js.map +1 -0
  243. package/dist/embeddings/providers.d.ts +7 -0
  244. package/dist/embeddings/providers.d.ts.map +1 -0
  245. package/dist/embeddings/providers.js +176 -0
  246. package/dist/embeddings/providers.js.map +1 -0
  247. package/dist/embeddings/types.d.ts +19 -0
  248. package/dist/embeddings/types.d.ts.map +1 -0
  249. package/dist/embeddings/types.js +2 -0
  250. package/dist/embeddings/types.js.map +1 -0
  251. package/dist/eval/acceptance-fixtures.d.ts +3 -0
  252. package/dist/eval/acceptance-fixtures.d.ts.map +1 -0
  253. package/dist/eval/acceptance-fixtures.js +84 -0
  254. package/dist/eval/acceptance-fixtures.js.map +1 -0
  255. package/dist/eval/acceptance.d.ts +114 -0
  256. package/dist/eval/acceptance.d.ts.map +1 -0
  257. package/dist/eval/acceptance.js +260 -0
  258. package/dist/eval/acceptance.js.map +1 -0
  259. package/dist/eval/fixtures.d.ts +16 -0
  260. package/dist/eval/fixtures.d.ts.map +1 -0
  261. package/dist/eval/fixtures.js +119 -0
  262. package/dist/eval/fixtures.js.map +1 -0
  263. package/dist/eval/index.d.ts +63 -0
  264. package/dist/eval/index.d.ts.map +1 -0
  265. package/dist/eval/index.js +174 -0
  266. package/dist/eval/index.js.map +1 -0
  267. package/dist/index.d.ts +5 -0
  268. package/dist/index.d.ts.map +1 -0
  269. package/dist/index.js +5 -0
  270. package/dist/index.js.map +1 -0
  271. package/dist/jobs/background-worker.d.ts +31 -0
  272. package/dist/jobs/background-worker.d.ts.map +1 -0
  273. package/dist/jobs/background-worker.js +315 -0
  274. package/dist/jobs/background-worker.js.map +1 -0
  275. package/dist/jobs/import-runner.d.ts +3 -0
  276. package/dist/jobs/import-runner.d.ts.map +1 -0
  277. package/dist/jobs/import-runner.js +613 -0
  278. package/dist/jobs/import-runner.js.map +1 -0
  279. package/dist/jobs/index.d.ts +9 -0
  280. package/dist/jobs/index.d.ts.map +1 -0
  281. package/dist/jobs/index.js +8 -0
  282. package/dist/jobs/index.js.map +1 -0
  283. package/dist/jobs/progress.d.ts +3 -0
  284. package/dist/jobs/progress.d.ts.map +1 -0
  285. package/dist/jobs/progress.js +30 -0
  286. package/dist/jobs/progress.js.map +1 -0
  287. package/dist/jobs/rebuild.d.ts +13 -0
  288. package/dist/jobs/rebuild.d.ts.map +1 -0
  289. package/dist/jobs/rebuild.js +178 -0
  290. package/dist/jobs/rebuild.js.map +1 -0
  291. package/dist/jobs/server-worker.d.ts +16 -0
  292. package/dist/jobs/server-worker.d.ts.map +1 -0
  293. package/dist/jobs/server-worker.js +252 -0
  294. package/dist/jobs/server-worker.js.map +1 -0
  295. package/dist/jobs/store-adapter.d.ts +3 -0
  296. package/dist/jobs/store-adapter.d.ts.map +1 -0
  297. package/dist/jobs/store-adapter.js +37 -0
  298. package/dist/jobs/store-adapter.js.map +1 -0
  299. package/dist/jobs/types.d.ts +138 -0
  300. package/dist/jobs/types.d.ts.map +1 -0
  301. package/dist/jobs/types.js +2 -0
  302. package/dist/jobs/types.js.map +1 -0
  303. package/dist/jobs/worker.d.ts +27 -0
  304. package/dist/jobs/worker.d.ts.map +1 -0
  305. package/dist/jobs/worker.js +90 -0
  306. package/dist/jobs/worker.js.map +1 -0
  307. package/dist/media-url.d.ts +7 -0
  308. package/dist/media-url.d.ts.map +1 -0
  309. package/dist/media-url.js +15 -0
  310. package/dist/media-url.js.map +1 -0
  311. package/dist/native-artifact-reassembly.d.ts +25 -0
  312. package/dist/native-artifact-reassembly.d.ts.map +1 -0
  313. package/dist/native-artifact-reassembly.js +262 -0
  314. package/dist/native-artifact-reassembly.js.map +1 -0
  315. package/dist/native-artifact.d.ts +88 -0
  316. package/dist/native-artifact.d.ts.map +1 -0
  317. package/dist/native-artifact.js +86 -0
  318. package/dist/native-artifact.js.map +1 -0
  319. package/dist/schema/index.d.ts +5519 -0
  320. package/dist/schema/index.d.ts.map +1 -0
  321. package/dist/schema/index.js +374 -0
  322. package/dist/schema/index.js.map +1 -0
  323. package/dist/schema/migrations.d.ts +10 -0
  324. package/dist/schema/migrations.d.ts.map +1 -0
  325. package/dist/schema/migrations.js +253 -0
  326. package/dist/schema/migrations.js.map +1 -0
  327. package/dist/search/fusion.d.ts +15 -0
  328. package/dist/search/fusion.d.ts.map +1 -0
  329. package/dist/search/fusion.js +25 -0
  330. package/dist/search/fusion.js.map +1 -0
  331. package/dist/search/mode.d.ts +4 -0
  332. package/dist/search/mode.d.ts.map +1 -0
  333. package/dist/search/mode.js +13 -0
  334. package/dist/search/mode.js.map +1 -0
  335. package/dist/search/postgres-fts.d.ts +22 -0
  336. package/dist/search/postgres-fts.d.ts.map +1 -0
  337. package/dist/search/postgres-fts.js +83 -0
  338. package/dist/search/postgres-fts.js.map +1 -0
  339. package/dist/server/brand-context.d.ts +15 -0
  340. package/dist/server/brand-context.d.ts.map +1 -0
  341. package/dist/server/brand-context.js +149 -0
  342. package/dist/server/brand-context.js.map +1 -0
  343. package/dist/server/context.d.ts +77 -0
  344. package/dist/server/context.d.ts.map +1 -0
  345. package/dist/server/context.js +63 -0
  346. package/dist/server/context.js.map +1 -0
  347. package/dist/server/enrichment.d.ts +23 -0
  348. package/dist/server/enrichment.d.ts.map +1 -0
  349. package/dist/server/enrichment.js +136 -0
  350. package/dist/server/enrichment.js.map +1 -0
  351. package/dist/server/generation-artifact-access.d.ts +21 -0
  352. package/dist/server/generation-artifact-access.d.ts.map +1 -0
  353. package/dist/server/generation-artifact-access.js +111 -0
  354. package/dist/server/generation-artifact-access.js.map +1 -0
  355. package/dist/server/generation-context.d.ts +204 -0
  356. package/dist/server/generation-context.d.ts.map +1 -0
  357. package/dist/server/generation-context.js +310 -0
  358. package/dist/server/generation-context.js.map +1 -0
  359. package/dist/server/index.d.ts +22 -0
  360. package/dist/server/index.d.ts.map +1 -0
  361. package/dist/server/index.js +96 -0
  362. package/dist/server/index.js.map +1 -0
  363. package/dist/server/isolated-a2a.d.ts +172 -0
  364. package/dist/server/isolated-a2a.d.ts.map +1 -0
  365. package/dist/server/isolated-a2a.js +310 -0
  366. package/dist/server/isolated-a2a.js.map +1 -0
  367. package/dist/server/media.d.ts +15 -0
  368. package/dist/server/media.d.ts.map +1 -0
  369. package/dist/server/media.js +93 -0
  370. package/dist/server/media.js.map +1 -0
  371. package/dist/server/prompt-provider.d.ts +5 -0
  372. package/dist/server/prompt-provider.d.ts.map +1 -0
  373. package/dist/server/prompt-provider.js +59 -0
  374. package/dist/server/prompt-provider.js.map +1 -0
  375. package/dist/server/public-serialization.d.ts +160 -0
  376. package/dist/server/public-serialization.d.ts.map +1 -0
  377. package/dist/server/public-serialization.js +108 -0
  378. package/dist/server/public-serialization.js.map +1 -0
  379. package/dist/server/resource-paths.d.ts +3 -0
  380. package/dist/server/resource-paths.d.ts.map +1 -0
  381. package/dist/server/resource-paths.js +5 -0
  382. package/dist/server/resource-paths.js.map +1 -0
  383. package/dist/server/retrieval.d.ts +78 -0
  384. package/dist/server/retrieval.d.ts.map +1 -0
  385. package/dist/server/retrieval.js +443 -0
  386. package/dist/server/retrieval.js.map +1 -0
  387. package/dist/server/untrusted-reference.d.ts +8 -0
  388. package/dist/server/untrusted-reference.d.ts.map +1 -0
  389. package/dist/server/untrusted-reference.js +19 -0
  390. package/dist/server/untrusted-reference.js.map +1 -0
  391. package/dist/store/brand.d.ts +47 -0
  392. package/dist/store/brand.d.ts.map +1 -0
  393. package/dist/store/brand.js +360 -0
  394. package/dist/store/brand.js.map +1 -0
  395. package/dist/store/content.d.ts +120 -0
  396. package/dist/store/content.d.ts.map +1 -0
  397. package/dist/store/content.js +1437 -0
  398. package/dist/store/content.js.map +1 -0
  399. package/dist/store/generation.d.ts +28 -0
  400. package/dist/store/generation.d.ts.map +1 -0
  401. package/dist/store/generation.js +140 -0
  402. package/dist/store/generation.js.map +1 -0
  403. package/dist/store/helpers.d.ts +12 -0
  404. package/dist/store/helpers.d.ts.map +1 -0
  405. package/dist/store/helpers.js +41 -0
  406. package/dist/store/helpers.js.map +1 -0
  407. package/dist/store/index.d.ts +10 -0
  408. package/dist/store/index.d.ts.map +1 -0
  409. package/dist/store/index.js +10 -0
  410. package/dist/store/index.js.map +1 -0
  411. package/dist/store/inference.d.ts +57 -0
  412. package/dist/store/inference.d.ts.map +1 -0
  413. package/dist/store/inference.js +279 -0
  414. package/dist/store/inference.js.map +1 -0
  415. package/dist/store/jobs.d.ts +80 -0
  416. package/dist/store/jobs.d.ts.map +1 -0
  417. package/dist/store/jobs.js +428 -0
  418. package/dist/store/jobs.js.map +1 -0
  419. package/dist/store/packs.d.ts +33 -0
  420. package/dist/store/packs.d.ts.map +1 -0
  421. package/dist/store/packs.js +321 -0
  422. package/dist/store/packs.js.map +1 -0
  423. package/dist/store/purge.d.ts +16 -0
  424. package/dist/store/purge.d.ts.map +1 -0
  425. package/dist/store/purge.js +256 -0
  426. package/dist/store/purge.js.map +1 -0
  427. package/dist/store/sources.d.ts +76 -0
  428. package/dist/store/sources.d.ts.map +1 -0
  429. package/dist/store/sources.js +538 -0
  430. package/dist/store/sources.js.map +1 -0
  431. package/dist/store/suggestions.d.ts +28 -0
  432. package/dist/store/suggestions.d.ts.map +1 -0
  433. package/dist/store/suggestions.js +250 -0
  434. package/dist/store/suggestions.js.map +1 -0
  435. package/dist/types.d.ts +493 -0
  436. package/dist/types.d.ts.map +1 -0
  437. package/dist/types.js +2 -0
  438. package/dist/types.js.map +1 -0
  439. package/dist/vector/index.d.ts +2 -0
  440. package/dist/vector/index.d.ts.map +1 -0
  441. package/dist/vector/index.js +2 -0
  442. package/dist/vector/index.js.map +1 -0
  443. package/dist/vector/pgvector.d.ts +28 -0
  444. package/dist/vector/pgvector.d.ts.map +1 -0
  445. package/dist/vector/pgvector.js +117 -0
  446. package/dist/vector/pgvector.js.map +1 -0
  447. package/docs/evaluation.md +92 -0
  448. package/docs/llms-full.txt +168 -0
  449. package/docs/llms.txt +76 -0
  450. package/docs/skills/creative-context/SKILL.md +74 -0
  451. package/package.json +91 -0
  452. package/src/actions/agent-input-schemas.spec.ts +46 -0
  453. package/src/actions/confirm-canonical-logo.ts +20 -0
  454. package/src/actions/continue-context-import.ts +12 -0
  455. package/src/actions/creative-context-a2a.spec.ts +64 -0
  456. package/src/actions/creative-context-a2a.ts +88 -0
  457. package/src/actions/get-brand-profile.ts +16 -0
  458. package/src/actions/get-context-import-status.ts +13 -0
  459. package/src/actions/get-context-item.ts +1 -0
  460. package/src/actions/get-context-pack.ts +14 -0
  461. package/src/actions/get-creative-context.spec.ts +315 -0
  462. package/src/actions/get-creative-context.ts +148 -0
  463. package/src/actions/index.ts +65 -0
  464. package/src/actions/infer-brand-dna.ts +15 -0
  465. package/src/actions/list-canonical-logo-candidates.ts +121 -0
  466. package/src/actions/list-context-connections.spec.ts +23 -0
  467. package/src/actions/list-context-connections.ts +51 -0
  468. package/src/actions/list-context-packs.ts +17 -0
  469. package/src/actions/list-context-sources.ts +21 -0
  470. package/src/actions/list-context-suggestions.ts +30 -0
  471. package/src/actions/manage-brand-profile.ts +58 -0
  472. package/src/actions/manage-context-pack.ts +75 -0
  473. package/src/actions/manage-context-source.ts +154 -0
  474. package/src/actions/manage-layout-template.ts +51 -0
  475. package/src/actions/preview-context-import.spec.ts +64 -0
  476. package/src/actions/preview-context-import.ts +61 -0
  477. package/src/actions/process-context-purge.ts +25 -0
  478. package/src/actions/propose-brand-dna.ts +22 -0
  479. package/src/actions/propose-canonical-logo.ts +19 -0
  480. package/src/actions/publish-brand-dna.ts +25 -0
  481. package/src/actions/recommend-context-roots.ts +24 -0
  482. package/src/actions/record-context-feedback.ts +16 -0
  483. package/src/actions/review-context-items.ts +69 -0
  484. package/src/actions/run-embedding-bakeoff.ts +90 -0
  485. package/src/actions/search-creative-context.ts +47 -0
  486. package/src/actions/set-brand-dna.ts +22 -0
  487. package/src/actions/start-context-enrichment.ts +50 -0
  488. package/src/actions/start-context-import.ts +37 -0
  489. package/src/client/CreativeContextChip.tsx +162 -0
  490. package/src/client/CreativeContextPanel.tsx +2442 -0
  491. package/src/client/CreativeContextSettingsLink.tsx +30 -0
  492. package/src/client/actions.ts +438 -0
  493. package/src/client/agent-tab.tsx +58 -0
  494. package/src/client/application-state.spec.ts +41 -0
  495. package/src/client/application-state.ts +130 -0
  496. package/src/client/index.ts +62 -0
  497. package/src/client/messages.ts +1240 -0
  498. package/src/client/source-config.spec.ts +152 -0
  499. package/src/connectors/connectors.spec.ts +778 -0
  500. package/src/connectors/context.ts +83 -0
  501. package/src/connectors/document-parser.ts +5 -0
  502. package/src/connectors/figma-native.ts +1192 -0
  503. package/src/connectors/figma-native.visual.spec.ts +221 -0
  504. package/src/connectors/figma.spec.ts +812 -0
  505. package/src/connectors/figma.ts +257 -0
  506. package/src/connectors/fixtures/google-slides-native.json +353 -0
  507. package/src/connectors/google-slides-native.spec.ts +804 -0
  508. package/src/connectors/google-slides-native.ts +1656 -0
  509. package/src/connectors/google-slides-native.visual.spec.ts +119 -0
  510. package/src/connectors/google-slides.ts +1172 -0
  511. package/src/connectors/index.ts +103 -0
  512. package/src/connectors/manual.ts +132 -0
  513. package/src/connectors/normalize.ts +277 -0
  514. package/src/connectors/notion.ts +529 -0
  515. package/src/connectors/private-artifacts.spec.ts +95 -0
  516. package/src/connectors/private-artifacts.ts +248 -0
  517. package/src/connectors/provider-response.ts +144 -0
  518. package/src/connectors/recommendations.ts +237 -0
  519. package/src/connectors/registry.ts +48 -0
  520. package/src/connectors/rendered-page.ts +705 -0
  521. package/src/connectors/smart-defaults.spec.ts +135 -0
  522. package/src/connectors/smart-defaults.ts +87 -0
  523. package/src/connectors/types.ts +115 -0
  524. package/src/connectors/upload.spec.ts +175 -0
  525. package/src/connectors/upload.ts +548 -0
  526. package/src/connectors/website.spec.ts +509 -0
  527. package/src/connectors/website.ts +777 -0
  528. package/src/embeddings/index.ts +2 -0
  529. package/src/embeddings/providers.spec.ts +73 -0
  530. package/src/embeddings/providers.ts +228 -0
  531. package/src/embeddings/types.ts +24 -0
  532. package/src/eval/acceptance-fixtures.ts +97 -0
  533. package/src/eval/acceptance.spec.ts +92 -0
  534. package/src/eval/acceptance.ts +371 -0
  535. package/src/eval/connectors-golden.spec.ts +421 -0
  536. package/src/eval/eval.spec.ts +166 -0
  537. package/src/eval/fixtures/README.md +17 -0
  538. package/src/eval/fixtures/figma-brand-system-v1.json +140 -0
  539. package/src/eval/fixtures/figma-brand-system-v2.json +127 -0
  540. package/src/eval/fixtures/launch-hero.png +0 -0
  541. package/src/eval/fixtures/launch-system-v1.pptx +0 -0
  542. package/src/eval/fixtures/launch-system-v2.pptx +0 -0
  543. package/src/eval/fixtures/notion-brand-root.json +218 -0
  544. package/src/eval/fixtures/pricing-hero.png +0 -0
  545. package/src/eval/fixtures/rendered-brand-page.html +76 -0
  546. package/src/eval/fixtures.spec.ts +43 -0
  547. package/src/eval/fixtures.ts +136 -0
  548. package/src/eval/index.ts +291 -0
  549. package/src/eval/library-flow.acceptance.spec.tsx +141 -0
  550. package/src/index.ts +4 -0
  551. package/src/jobs/background-worker.ts +423 -0
  552. package/src/jobs/import-runner.spec.ts +582 -0
  553. package/src/jobs/import-runner.ts +792 -0
  554. package/src/jobs/index.ts +40 -0
  555. package/src/jobs/progress.ts +37 -0
  556. package/src/jobs/rebuild.ts +245 -0
  557. package/src/jobs/server-worker.spec.ts +159 -0
  558. package/src/jobs/server-worker.ts +344 -0
  559. package/src/jobs/store-adapter.ts +52 -0
  560. package/src/jobs/types.ts +147 -0
  561. package/src/jobs/worker.ts +152 -0
  562. package/src/manifest.spec.ts +26 -0
  563. package/src/media-url.ts +17 -0
  564. package/src/native-artifact-reassembly.spec.ts +386 -0
  565. package/src/native-artifact-reassembly.ts +406 -0
  566. package/src/native-artifact.ts +102 -0
  567. package/src/schema/index.ts +411 -0
  568. package/src/schema/migrations.spec.ts +41 -0
  569. package/src/schema/migrations.ts +258 -0
  570. package/src/search/fusion.spec.ts +21 -0
  571. package/src/search/fusion.ts +39 -0
  572. package/src/search/mode.spec.ts +28 -0
  573. package/src/search/mode.ts +21 -0
  574. package/src/search/postgres-fts.spec.ts +71 -0
  575. package/src/search/postgres-fts.ts +112 -0
  576. package/src/server/brand-context.spec.ts +43 -0
  577. package/src/server/brand-context.ts +160 -0
  578. package/src/server/context.ts +162 -0
  579. package/src/server/enrichment.ts +163 -0
  580. package/src/server/generation-artifact-access.ts +216 -0
  581. package/src/server/generation-context-a2a.spec.ts +131 -0
  582. package/src/server/generation-context-off.spec.ts +213 -0
  583. package/src/server/generation-context.spec.ts +124 -0
  584. package/src/server/generation-context.ts +493 -0
  585. package/src/server/index.ts +135 -0
  586. package/src/server/isolated-a2a.spec.ts +164 -0
  587. package/src/server/isolated-a2a.ts +413 -0
  588. package/src/server/media.spec.ts +92 -0
  589. package/src/server/media.ts +117 -0
  590. package/src/server/prompt-provider.spec.ts +78 -0
  591. package/src/server/prompt-provider.ts +73 -0
  592. package/src/server/public-serialization.spec.ts +149 -0
  593. package/src/server/public-serialization.ts +130 -0
  594. package/src/server/resource-paths.spec.ts +9 -0
  595. package/src/server/resource-paths.ts +5 -0
  596. package/src/server/retrieval-vector.spec.ts +180 -0
  597. package/src/server/retrieval.ts +587 -0
  598. package/src/server/untrusted-reference.spec.ts +22 -0
  599. package/src/server/untrusted-reference.ts +24 -0
  600. package/src/store/access.integration.spec.ts +1922 -0
  601. package/src/store/brand.ts +477 -0
  602. package/src/store/content.ts +1900 -0
  603. package/src/store/generation.ts +226 -0
  604. package/src/store/helpers.ts +53 -0
  605. package/src/store/index.ts +9 -0
  606. package/src/store/inference.spec.ts +84 -0
  607. package/src/store/inference.ts +339 -0
  608. package/src/store/invariants.spec.ts +119 -0
  609. package/src/store/jobs.ts +672 -0
  610. package/src/store/packs.ts +466 -0
  611. package/src/store/purge.ts +321 -0
  612. package/src/store/sources.spec.ts +102 -0
  613. package/src/store/sources.ts +708 -0
  614. package/src/store/suggestions.ts +333 -0
  615. package/src/types.ts +571 -0
  616. package/src/vector/index.ts +1 -0
  617. package/src/vector/pgvector.spec.ts +98 -0
  618. package/src/vector/pgvector.ts +164 -0
@@ -0,0 +1,1437 @@
1
+ import { getDbExec } from "@agent-native/core/db";
2
+ import { buildSearchSnippet, escapeLikeTerm, normalizeSearchTerms, scoreSearchText, } from "@agent-native/core/search-utils";
3
+ import { accessFilter, assertAccess } from "@agent-native/core/sharing";
4
+ import { and, asc, count, desc, eq, gt, gte, inArray, lte, ne, or, sql, } from "drizzle-orm";
5
+ import { matchesCreativeSearchMode } from "../search/mode.js";
6
+ import { getCreativeContext } from "../server/context.js";
7
+ import { newId, nextOffsetCursor, nowIso, parseJson, parseOffsetCursor, requireActor, sha256, stringifyJson, } from "./helpers.js";
8
+ import { createJob, enqueueContextRebuildJob } from "./jobs.js";
9
+ function mapItem(row) {
10
+ return {
11
+ id: row.id,
12
+ sourceId: row.sourceId,
13
+ externalId: row.externalId,
14
+ kind: row.kind,
15
+ title: row.title,
16
+ canonicalUrl: row.canonicalUrl ?? null,
17
+ mimeType: row.mimeType ?? null,
18
+ currentVersionId: row.currentVersionId,
19
+ status: row.status,
20
+ upstreamAccess: row.upstreamAccess,
21
+ curationStatus: row.curationStatus,
22
+ curationRank: row.curationRank,
23
+ starred: Boolean(row.starred),
24
+ inventoryState: row.inventoryState,
25
+ indexState: row.indexState,
26
+ tags: parseJson(row.tags, []),
27
+ colors: parseJson(row.colors, []),
28
+ sortOrder: row.sortOrder,
29
+ parentItemId: row.parentItemId ?? null,
30
+ provenance: parseJson(row.provenance, {}),
31
+ thumbnailBlobRef: row.thumbnailBlobRef ?? null,
32
+ createdAt: row.createdAt,
33
+ updatedAt: row.updatedAt,
34
+ };
35
+ }
36
+ function mapVersion(row) {
37
+ return {
38
+ id: row.id,
39
+ itemId: row.itemId,
40
+ versionNumber: row.versionNumber,
41
+ contentHash: row.contentHash,
42
+ title: row.title,
43
+ content: row.content,
44
+ summary: row.summary ?? null,
45
+ mimeType: row.mimeType ?? null,
46
+ sourceModifiedAt: row.sourceModifiedAt ?? null,
47
+ sourceVersion: row.sourceVersion ?? null,
48
+ rawSnapshotBlobRef: row.rawSnapshotBlobRef ?? null,
49
+ parseStatus: row.parseStatus,
50
+ parseError: row.parseError ?? null,
51
+ metadata: parseJson(row.metadata, {}),
52
+ createdAt: row.createdAt,
53
+ };
54
+ }
55
+ function mapChunk(row) {
56
+ return {
57
+ id: row.id,
58
+ itemId: row.itemId,
59
+ itemVersionId: row.itemVersionId,
60
+ ordinal: row.ordinal,
61
+ kind: row.kind,
62
+ text: row.text,
63
+ startOffset: row.startOffset ?? null,
64
+ endOffset: row.endOffset ?? null,
65
+ tokenCount: row.tokenCount ?? null,
66
+ metadata: parseJson(row.metadata, {}),
67
+ };
68
+ }
69
+ function mapMedia(row) {
70
+ return {
71
+ id: row.id,
72
+ itemId: row.itemId,
73
+ itemVersionId: row.itemVersionId,
74
+ kind: row.kind,
75
+ mimeType: row.mimeType ?? null,
76
+ accessMode: row.accessMode,
77
+ url: row.url ?? null,
78
+ storageKey: row.storageKey ?? null,
79
+ provenanceUrl: row.provenanceUrl ?? null,
80
+ altText: row.altText ?? null,
81
+ caption: row.caption ?? null,
82
+ captionStatus: row.captionStatus,
83
+ ocrText: row.ocrText ?? null,
84
+ palette: parseJson(row.palette, []),
85
+ contentHash: row.contentHash ?? null,
86
+ width: row.width ?? null,
87
+ height: row.height ?? null,
88
+ durationMs: row.durationMs ?? null,
89
+ metadata: parseJson(row.metadata, {}),
90
+ };
91
+ }
92
+ function mapEdge(row) {
93
+ return {
94
+ id: row.id,
95
+ fromItemId: row.fromItemId,
96
+ fromItemVersionId: row.fromItemVersionId,
97
+ toItemId: row.toItemId ?? null,
98
+ toItemVersionId: row.toItemVersionId ?? null,
99
+ toExternalId: row.toExternalId ?? null,
100
+ relation: row.relation,
101
+ metadata: parseJson(row.metadata, {}),
102
+ };
103
+ }
104
+ export function assertImmutableContextVersion(operation) {
105
+ throw new Error(`Creative context item versions are immutable; ${operation} must create a new version`);
106
+ }
107
+ function isUniqueConstraintError(error) {
108
+ let current = error;
109
+ for (let depth = 0; current && depth < 4; depth += 1) {
110
+ if (typeof current !== "object")
111
+ break;
112
+ const candidate = current;
113
+ const code = String(candidate.code ?? candidate.errno ?? "").toUpperCase();
114
+ const message = String(candidate.message ?? "");
115
+ if (code === "23505" ||
116
+ code.includes("SQLITE_CONSTRAINT") ||
117
+ /unique constraint|unique violation|duplicate key/i.test(message)) {
118
+ return true;
119
+ }
120
+ current = candidate.cause;
121
+ }
122
+ return false;
123
+ }
124
+ export async function ingestItems(batch) {
125
+ return ingestItemsAttempt(batch, true);
126
+ }
127
+ async function ingestItemsAttempt(batch, allowUniqueConflictRetry) {
128
+ await assertAccess("creative-context-source", batch.sourceId, "editor", undefined, { skipResourceBody: true });
129
+ const { getDb, schema } = getCreativeContext();
130
+ const actor = requireActor();
131
+ const timestamp = batch.completedAt ?? nowIso();
132
+ const externalIds = Array.from(new Set(batch.items.map((item) => item.externalId)));
133
+ if (externalIds.length !== batch.items.length) {
134
+ throw new Error("An ingest batch cannot contain duplicate externalId values");
135
+ }
136
+ const existingRows = externalIds.length
137
+ ? await getDb()
138
+ .select()
139
+ .from(schema.contextItems)
140
+ .where(and(eq(schema.contextItems.sourceId, batch.sourceId), inArray(schema.contextItems.externalId, externalIds)))
141
+ : [];
142
+ const existingByExternalId = new Map(existingRows.map((row) => [row.externalId, row]));
143
+ const currentVersionIds = existingRows.map((row) => row.currentVersionId);
144
+ const currentVersionRows = currentVersionIds.length
145
+ ? await getDb()
146
+ .select({
147
+ id: schema.contextItemVersions.id,
148
+ versionNumber: schema.contextItemVersions.versionNumber,
149
+ })
150
+ .from(schema.contextItemVersions)
151
+ .where(inArray(schema.contextItemVersions.id, currentVersionIds))
152
+ : [];
153
+ const versionNumberById = new Map(currentVersionRows.map((row) => [row.id, row.versionNumber]));
154
+ const newItems = [];
155
+ const itemUpdates = [];
156
+ const versions = [];
157
+ const chunks = [];
158
+ const media = [];
159
+ const edges = [];
160
+ const itemIds = [];
161
+ const batchVersionTargets = new Map();
162
+ let created = 0;
163
+ let versioned = 0;
164
+ let unchanged = 0;
165
+ for (const input of batch.items) {
166
+ const existing = existingByExternalId.get(input.externalId);
167
+ if (existing?.currentContentHash === input.contentHash) {
168
+ batchVersionTargets.set(input.externalId, {
169
+ itemId: existing.id,
170
+ itemVersionId: existing.currentVersionId,
171
+ });
172
+ const upstreamAccess = input.upstreamAccess ?? existing.upstreamAccess;
173
+ const newlyRestricted = upstreamAccess === "restricted" &&
174
+ existing.upstreamAccess !== "restricted";
175
+ itemUpdates.push({
176
+ id: existing.id,
177
+ values: {
178
+ kind: input.kind,
179
+ title: input.title,
180
+ canonicalUrl: input.canonicalUrl ?? null,
181
+ mimeType: input.mimeType ?? null,
182
+ upstreamAccess,
183
+ curationStatus: newlyRestricted ? "review" : existing.curationStatus,
184
+ tags: stringifyJson(input.tags ?? parseJson(existing.tags, [])),
185
+ colors: stringifyJson(input.colors ??
186
+ (input.color ? [input.color] : parseJson(existing.colors, []))),
187
+ provenance: stringifyJson(input.provenance ?? parseJson(existing.provenance, {})),
188
+ updatedAt: timestamp,
189
+ },
190
+ });
191
+ unchanged += 1;
192
+ itemIds.push(existing.id);
193
+ continue;
194
+ }
195
+ const itemId = existing?.id ?? newId("cci");
196
+ const itemVersionId = newId("ccv");
197
+ batchVersionTargets.set(input.externalId, { itemId, itemVersionId });
198
+ const versionNumber = existing
199
+ ? (versionNumberById.get(existing.currentVersionId) ?? 0) + 1
200
+ : 1;
201
+ const upstreamAccess = input.upstreamAccess ?? "unknown";
202
+ const curationStatus = existing
203
+ ? upstreamAccess === "restricted" &&
204
+ existing.upstreamAccess !== "restricted"
205
+ ? "review"
206
+ : existing.curationStatus
207
+ : (input.curationStatus ??
208
+ (upstreamAccess === "restricted" ? "review" : "included"));
209
+ itemIds.push(itemId);
210
+ versions.push({
211
+ id: itemVersionId,
212
+ itemId,
213
+ versionNumber,
214
+ contentHash: input.contentHash,
215
+ title: input.title,
216
+ content: input.content,
217
+ summary: input.summary ?? null,
218
+ mimeType: input.mimeType ?? null,
219
+ sourceModifiedAt: input.sourceModifiedAt ?? null,
220
+ sourceVersion: input.sourceVersion ?? null,
221
+ rawSnapshotBlobRef: input.rawSnapshotBlobRef ?? null,
222
+ parseStatus: input.parseStatus ?? "parsed",
223
+ parseError: input.parseError ?? null,
224
+ metadata: stringifyJson(input.metadata),
225
+ createdAt: timestamp,
226
+ ownerEmail: actor.ownerEmail,
227
+ orgId: actor.orgId,
228
+ });
229
+ if (existing) {
230
+ versioned += 1;
231
+ itemUpdates.push({
232
+ id: itemId,
233
+ values: {
234
+ kind: input.kind,
235
+ title: input.title,
236
+ canonicalUrl: input.canonicalUrl ?? null,
237
+ mimeType: input.mimeType ?? null,
238
+ currentVersionId: itemVersionId,
239
+ currentContentHash: input.contentHash,
240
+ status: "active",
241
+ upstreamAccess,
242
+ curationStatus,
243
+ curationRank: input.curationRank ?? "normal",
244
+ starred: input.starred ? 1 : 0,
245
+ inventoryState: input.inventoryState ?? "available",
246
+ indexState: input.indexState ?? "pending",
247
+ tags: stringifyJson(input.tags ?? []),
248
+ colors: stringifyJson(input.colors ?? (input.color ? [input.color] : [])),
249
+ sortOrder: input.sortOrder ?? 0,
250
+ parentItemId: input.parentItemId ?? null,
251
+ provenance: stringifyJson(input.provenance),
252
+ thumbnailBlobRef: input.thumbnailBlobRef ?? null,
253
+ metadata: stringifyJson(input.metadata),
254
+ updatedAt: timestamp,
255
+ },
256
+ });
257
+ }
258
+ else {
259
+ created += 1;
260
+ newItems.push({
261
+ id: itemId,
262
+ sourceId: batch.sourceId,
263
+ externalId: input.externalId,
264
+ kind: input.kind,
265
+ title: input.title,
266
+ canonicalUrl: input.canonicalUrl ?? null,
267
+ mimeType: input.mimeType ?? null,
268
+ currentVersionId: itemVersionId,
269
+ currentContentHash: input.contentHash,
270
+ status: "active",
271
+ upstreamAccess,
272
+ curationStatus,
273
+ curationRank: input.curationRank ?? "normal",
274
+ starred: input.starred ? 1 : 0,
275
+ inventoryState: input.inventoryState ?? "available",
276
+ indexState: input.indexState ?? "pending",
277
+ tags: stringifyJson(input.tags ?? []),
278
+ colors: stringifyJson(input.colors ?? (input.color ? [input.color] : [])),
279
+ sortOrder: input.sortOrder ?? 0,
280
+ parentItemId: input.parentItemId ?? null,
281
+ provenance: stringifyJson(input.provenance),
282
+ thumbnailBlobRef: input.thumbnailBlobRef ?? null,
283
+ metadata: stringifyJson(input.metadata),
284
+ createdAt: timestamp,
285
+ updatedAt: timestamp,
286
+ ownerEmail: actor.ownerEmail,
287
+ orgId: actor.orgId,
288
+ });
289
+ }
290
+ const normalizedChunks = input.chunks?.length && input.chunks.length > 0
291
+ ? input.chunks
292
+ : [{ ordinal: 0, kind: "text", text: input.content }];
293
+ chunks.push(...normalizedChunks.map((chunk) => ({
294
+ id: chunk.id ?? newId("ccc"),
295
+ itemId,
296
+ itemVersionId,
297
+ ordinal: chunk.ordinal,
298
+ kind: chunk.kind ?? "text",
299
+ text: chunk.text,
300
+ startOffset: chunk.startOffset ?? null,
301
+ endOffset: chunk.endOffset ?? null,
302
+ tokenCount: chunk.tokenCount ?? null,
303
+ metadata: stringifyJson(chunk.metadata),
304
+ createdAt: timestamp,
305
+ ownerEmail: actor.ownerEmail,
306
+ orgId: actor.orgId,
307
+ })));
308
+ media.push(...(input.media ?? []).map((entry) => {
309
+ const accessMode = entry.accessMode ?? "public";
310
+ if (!entry.url && !entry.storageKey) {
311
+ throw new Error("Context media requires a URL or storage key");
312
+ }
313
+ if (accessMode !== "public" && !entry.storageKey) {
314
+ throw new Error("Private or expiring media must be copied to private blob storage; provider URLs may be kept only as provenanceUrl");
315
+ }
316
+ return {
317
+ id: entry.id ?? newId("ccm"),
318
+ itemId,
319
+ itemVersionId,
320
+ kind: entry.kind,
321
+ mimeType: entry.mimeType ?? null,
322
+ accessMode,
323
+ url: accessMode === "public" ? (entry.url ?? null) : null,
324
+ storageKey: entry.storageKey ?? null,
325
+ provenanceUrl: entry.provenanceUrl ?? entry.url ?? null,
326
+ altText: entry.altText ?? null,
327
+ caption: entry.caption ?? null,
328
+ captionStatus: entry.captionStatus ?? "pending",
329
+ ocrText: entry.ocrText ?? null,
330
+ palette: stringifyJson(entry.palette ?? []),
331
+ contentHash: entry.contentHash ?? null,
332
+ width: entry.width ?? null,
333
+ height: entry.height ?? null,
334
+ durationMs: entry.durationMs ?? null,
335
+ metadata: stringifyJson(entry.metadata),
336
+ createdAt: timestamp,
337
+ ownerEmail: actor.ownerEmail,
338
+ orgId: actor.orgId,
339
+ };
340
+ }));
341
+ if (existing) {
342
+ edges.push({
343
+ id: newId("cce"),
344
+ fromItemId: itemId,
345
+ fromItemVersionId: itemVersionId,
346
+ toItemId: itemId,
347
+ toItemVersionId: existing.currentVersionId,
348
+ toExternalId: existing.externalId,
349
+ relation: "revision-of",
350
+ metadata: stringifyJson({ automatic: true }),
351
+ createdAt: timestamp,
352
+ ownerEmail: actor.ownerEmail,
353
+ orgId: actor.orgId,
354
+ });
355
+ }
356
+ edges.push(...(input.edges ?? []).map((edge) => {
357
+ if (!edge.toItemId && !edge.toExternalId) {
358
+ throw new Error("Context edges require toItemId or toExternalId");
359
+ }
360
+ if (edge.toItemVersionId && !edge.toItemId) {
361
+ throw new Error("Pinned edge target versions require toItemId");
362
+ }
363
+ return {
364
+ id: edge.id ?? newId("cce"),
365
+ fromItemId: itemId,
366
+ fromItemVersionId: itemVersionId,
367
+ toItemId: edge.toItemId ?? null,
368
+ toItemVersionId: edge.toItemVersionId ?? null,
369
+ toExternalId: edge.toExternalId ?? null,
370
+ relation: edge.relation,
371
+ metadata: stringifyJson(edge.metadata),
372
+ createdAt: timestamp,
373
+ ownerEmail: actor.ownerEmail,
374
+ orgId: actor.orgId,
375
+ };
376
+ }));
377
+ }
378
+ for (const edge of edges) {
379
+ if (edge.toItemId || !edge.toExternalId)
380
+ continue;
381
+ const target = batchVersionTargets.get(edge.toExternalId);
382
+ if (!target)
383
+ continue;
384
+ edge.toItemId = target.itemId;
385
+ edge.toItemVersionId = target.itemVersionId;
386
+ }
387
+ try {
388
+ await getDb().transaction(async (tx) => {
389
+ if (newItems.length)
390
+ await tx.insert(schema.contextItems).values(newItems);
391
+ if (versions.length)
392
+ await tx.insert(schema.contextItemVersions).values(versions);
393
+ if (chunks.length)
394
+ await tx.insert(schema.contextChunks).values(chunks);
395
+ if (media.length)
396
+ await tx.insert(schema.contextMedia).values(media);
397
+ if (edges.length)
398
+ await tx.insert(schema.contextEdges).values(edges);
399
+ for (const update of itemUpdates) {
400
+ await tx
401
+ .update(schema.contextItems)
402
+ .set(update.values)
403
+ .where(eq(schema.contextItems.id, update.id));
404
+ }
405
+ const [total] = await tx
406
+ .select({ value: count() })
407
+ .from(schema.contextItems)
408
+ .where(and(eq(schema.contextItems.sourceId, batch.sourceId), eq(schema.contextItems.status, "active")));
409
+ const [restricted] = await tx
410
+ .select({ value: count() })
411
+ .from(schema.contextItems)
412
+ .where(and(eq(schema.contextItems.sourceId, batch.sourceId), eq(schema.contextItems.upstreamAccess, "restricted")));
413
+ await tx
414
+ .update(schema.contextSources)
415
+ .set({
416
+ syncCursor: batch.syncCursor ?? undefined,
417
+ itemCount: Number(total?.value ?? 0),
418
+ restrictedItemCount: Number(restricted?.value ?? 0),
419
+ lastSyncedAt: timestamp,
420
+ lastError: null,
421
+ status: "active",
422
+ healthStatus: "healthy",
423
+ updatedAt: timestamp,
424
+ })
425
+ .where(eq(schema.contextSources.id, batch.sourceId));
426
+ });
427
+ }
428
+ catch (error) {
429
+ if (allowUniqueConflictRetry && isUniqueConstraintError(error)) {
430
+ return ingestItemsAttempt(batch, false);
431
+ }
432
+ throw error;
433
+ }
434
+ if (chunks.length) {
435
+ await enqueueContextRebuildJob({
436
+ sourceId: batch.sourceId,
437
+ operation: "rebuild-fts",
438
+ itemIds: [...new Set(chunks.map((chunk) => chunk.itemId))],
439
+ });
440
+ }
441
+ const mediaProjection = getCreativeContext().projections?.media;
442
+ if (mediaProjection) {
443
+ const eager = media.slice(0, 5);
444
+ const queued = media.slice(5).map((row) => row.id);
445
+ for (const row of eager) {
446
+ try {
447
+ await mediaProjection.project({
448
+ sourceId: batch.sourceId,
449
+ itemId: row.itemId,
450
+ itemVersionId: row.itemVersionId,
451
+ media: mapMedia(row),
452
+ sourceType: "brand-import",
453
+ dedupeKey: `${row.id}:${row.itemVersionId}`,
454
+ });
455
+ }
456
+ catch {
457
+ queued.push(row.id);
458
+ }
459
+ }
460
+ if (queued.length) {
461
+ await createJob({
462
+ sourceId: batch.sourceId,
463
+ kind: "enrich-media",
464
+ request: {
465
+ operation: "project-media",
466
+ mediaIds: [...new Set(queued)],
467
+ },
468
+ progressTotal: new Set(queued).size,
469
+ budget: {
470
+ eagerLimit: 25,
471
+ remainingMode: "durable-continuation",
472
+ },
473
+ });
474
+ }
475
+ }
476
+ return {
477
+ sourceId: batch.sourceId,
478
+ received: batch.items.length,
479
+ created,
480
+ versioned,
481
+ unchanged,
482
+ itemIds,
483
+ mediaIds: media.map((entry) => entry.id),
484
+ };
485
+ }
486
+ export async function upsertSourceInventory(input) {
487
+ return upsertSourceInventoryAttempt(input, true);
488
+ }
489
+ async function upsertSourceInventoryAttempt(input, allowUniqueConflictRetry) {
490
+ const access = await assertAccess("creative-context-source", input.sourceId, "editor");
491
+ const externalIds = input.items.map((item) => item.externalId);
492
+ if (new Set(externalIds).size !== externalIds.length) {
493
+ throw new Error("An inventory page cannot contain duplicate external ids");
494
+ }
495
+ const { getDb, schema } = getCreativeContext();
496
+ const actor = requireActor();
497
+ const timestamp = input.completedAt ?? nowIso();
498
+ const existing = externalIds.length
499
+ ? await getDb()
500
+ .select()
501
+ .from(schema.contextItems)
502
+ .where(and(eq(schema.contextItems.sourceId, input.sourceId), inArray(schema.contextItems.externalId, externalIds)))
503
+ : [];
504
+ const existingByExternalId = new Map(existing.map((row) => [row.externalId, row]));
505
+ const newItems = [];
506
+ const newVersions = [];
507
+ const newChunks = [];
508
+ const updates = [];
509
+ const itemIds = [];
510
+ for (const item of input.items) {
511
+ const prior = existingByExternalId.get(item.externalId);
512
+ if (prior) {
513
+ const upstreamAccess = item.upstreamAccess ?? access.resource.upstreamAccess ?? "unknown";
514
+ const newlyRestricted = upstreamAccess === "restricted" &&
515
+ prior.upstreamAccess !== "restricted";
516
+ itemIds.push(prior.id);
517
+ updates.push({
518
+ id: prior.id,
519
+ values: {
520
+ kind: item.kind,
521
+ title: item.title,
522
+ canonicalUrl: item.canonicalUrl ?? null,
523
+ mimeType: item.mimeType ?? null,
524
+ inventoryState: "available",
525
+ upstreamAccess,
526
+ ...(newlyRestricted ? { curationStatus: "review" } : {}),
527
+ status: prior.status === "unavailable" ? "active" : prior.status,
528
+ metadata: stringifyJson({
529
+ ...parseJson(prior.metadata, {}),
530
+ inventory: item.metadata ?? {},
531
+ sizeBytes: item.sizeBytes ?? null,
532
+ }),
533
+ updatedAt: timestamp,
534
+ },
535
+ });
536
+ continue;
537
+ }
538
+ const itemId = newId("cci");
539
+ const itemVersionId = newId("ccv");
540
+ const content = [item.title, item.summary].filter(Boolean).join("\n");
541
+ const contentHash = await sha256(stringifyJson({
542
+ inventory: true,
543
+ externalId: item.externalId,
544
+ title: item.title,
545
+ sourceModifiedAt: item.sourceModifiedAt,
546
+ }));
547
+ const upstreamAccess = item.upstreamAccess ?? access.resource.upstreamAccess ?? "unknown";
548
+ itemIds.push(itemId);
549
+ newItems.push({
550
+ id: itemId,
551
+ sourceId: input.sourceId,
552
+ externalId: item.externalId,
553
+ kind: item.kind,
554
+ title: item.title,
555
+ canonicalUrl: item.canonicalUrl ?? null,
556
+ mimeType: item.mimeType ?? null,
557
+ currentVersionId: itemVersionId,
558
+ currentContentHash: contentHash,
559
+ status: "active",
560
+ upstreamAccess,
561
+ curationStatus: upstreamAccess === "restricted" ? "review" : "included",
562
+ curationRank: "normal",
563
+ starred: 0,
564
+ inventoryState: "discovered",
565
+ indexState: "pending",
566
+ tags: "[]",
567
+ colors: "[]",
568
+ sortOrder: 0,
569
+ parentItemId: null,
570
+ provenance: stringifyJson({ inventory: item.metadata ?? {} }),
571
+ thumbnailBlobRef: null,
572
+ metadata: stringifyJson({
573
+ inventoryOnly: true,
574
+ sizeBytes: item.sizeBytes ?? null,
575
+ }),
576
+ createdAt: timestamp,
577
+ updatedAt: timestamp,
578
+ ownerEmail: actor.ownerEmail,
579
+ orgId: actor.orgId,
580
+ });
581
+ newVersions.push({
582
+ id: itemVersionId,
583
+ itemId,
584
+ versionNumber: 1,
585
+ contentHash,
586
+ title: item.title,
587
+ content,
588
+ summary: item.summary ?? null,
589
+ mimeType: item.mimeType ?? null,
590
+ sourceModifiedAt: item.sourceModifiedAt ?? null,
591
+ sourceVersion: null,
592
+ rawSnapshotBlobRef: null,
593
+ parseStatus: "pending",
594
+ parseError: null,
595
+ metadata: stringifyJson({ inventoryOnly: true }),
596
+ createdAt: timestamp,
597
+ ownerEmail: actor.ownerEmail,
598
+ orgId: actor.orgId,
599
+ });
600
+ newChunks.push({
601
+ id: newId("ccc"),
602
+ itemId,
603
+ itemVersionId,
604
+ ordinal: 0,
605
+ kind: "inventory",
606
+ text: content,
607
+ startOffset: null,
608
+ endOffset: null,
609
+ tokenCount: null,
610
+ metadata: stringifyJson({ inventoryOnly: true }),
611
+ createdAt: timestamp,
612
+ ownerEmail: actor.ownerEmail,
613
+ orgId: actor.orgId,
614
+ });
615
+ }
616
+ try {
617
+ await getDb().transaction(async (tx) => {
618
+ if (newItems.length)
619
+ await tx.insert(schema.contextItems).values(newItems);
620
+ if (newVersions.length) {
621
+ await tx.insert(schema.contextItemVersions).values(newVersions);
622
+ }
623
+ if (newChunks.length)
624
+ await tx.insert(schema.contextChunks).values(newChunks);
625
+ for (const update of updates) {
626
+ await tx
627
+ .update(schema.contextItems)
628
+ .set(update.values)
629
+ .where(eq(schema.contextItems.id, update.id));
630
+ }
631
+ const [total] = await tx
632
+ .select({ value: count() })
633
+ .from(schema.contextItems)
634
+ .where(eq(schema.contextItems.sourceId, input.sourceId));
635
+ const [restricted] = await tx
636
+ .select({ value: count() })
637
+ .from(schema.contextItems)
638
+ .where(and(eq(schema.contextItems.sourceId, input.sourceId), eq(schema.contextItems.upstreamAccess, "restricted")));
639
+ await tx
640
+ .update(schema.contextSources)
641
+ .set({
642
+ itemCount: Number(total?.value ?? 0),
643
+ restrictedItemCount: Number(restricted?.value ?? 0),
644
+ lastSyncedAt: timestamp,
645
+ updatedAt: timestamp,
646
+ })
647
+ .where(eq(schema.contextSources.id, input.sourceId));
648
+ });
649
+ }
650
+ catch (error) {
651
+ if (allowUniqueConflictRetry && isUniqueConstraintError(error)) {
652
+ return upsertSourceInventoryAttempt(input, false);
653
+ }
654
+ throw error;
655
+ }
656
+ return {
657
+ sourceId: input.sourceId,
658
+ received: input.items.length,
659
+ created: newItems.length,
660
+ updated: updates.length,
661
+ itemIds,
662
+ };
663
+ }
664
+ export async function reconcileSourceInventory(input) {
665
+ await assertAccess("creative-context-source", input.sourceId, "editor", undefined, { skipResourceBody: true });
666
+ const { getDb, schema } = getCreativeContext();
667
+ const rows = await getDb()
668
+ .select({
669
+ id: schema.contextItems.id,
670
+ externalId: schema.contextItems.externalId,
671
+ status: schema.contextItems.status,
672
+ inventoryState: schema.contextItems.inventoryState,
673
+ upstreamAccess: schema.contextItems.upstreamAccess,
674
+ })
675
+ .from(schema.contextItems)
676
+ .where(eq(schema.contextItems.sourceId, input.sourceId));
677
+ const present = new Set(input.presentExternalIds);
678
+ const removedIds = rows
679
+ .filter((row) => !present.has(row.externalId) &&
680
+ (row.status !== "unavailable" || row.inventoryState !== "removed"))
681
+ .map((row) => row.id);
682
+ const restoredIds = rows
683
+ .filter((row) => present.has(row.externalId) &&
684
+ row.status === "unavailable" &&
685
+ row.inventoryState === "removed")
686
+ .map((row) => row.id);
687
+ const timestamp = input.completedAt ?? nowIso();
688
+ await getDb().transaction(async (tx) => {
689
+ for (let index = 0; index < removedIds.length; index += 500) {
690
+ await tx
691
+ .update(schema.contextItems)
692
+ .set({
693
+ status: "unavailable",
694
+ inventoryState: "removed",
695
+ updatedAt: timestamp,
696
+ })
697
+ .where(inArray(schema.contextItems.id, removedIds.slice(index, index + 500)));
698
+ }
699
+ for (let index = 0; index < restoredIds.length; index += 500) {
700
+ await tx
701
+ .update(schema.contextItems)
702
+ .set({
703
+ status: "active",
704
+ inventoryState: "available",
705
+ updatedAt: timestamp,
706
+ })
707
+ .where(inArray(schema.contextItems.id, restoredIds.slice(index, index + 500)));
708
+ }
709
+ await tx
710
+ .update(schema.contextSources)
711
+ .set({
712
+ itemCount: present.size,
713
+ restrictedItemCount: rows.filter((row) => present.has(row.externalId) && row.upstreamAccess === "restricted").length,
714
+ lastSyncedAt: timestamp,
715
+ updatedAt: timestamp,
716
+ })
717
+ .where(eq(schema.contextSources.id, input.sourceId));
718
+ });
719
+ return { removed: removedIds.length, restored: restoredIds.length };
720
+ }
721
+ function searchableItemStatuses(statuses) {
722
+ if (!statuses?.length)
723
+ return ["active"];
724
+ const safe = statuses.filter((status) => status === "active" || status === "deprecated");
725
+ if (safe.length !== statuses.length) {
726
+ throw new Error("Creative context search cannot include removed items");
727
+ }
728
+ return [...new Set(safe)];
729
+ }
730
+ async function accessiblePackVersionIds(packId) {
731
+ await assertAccess("creative-context-pack", packId, "viewer", undefined, {
732
+ skipResourceBody: true,
733
+ });
734
+ const { getDb, schema } = getCreativeContext();
735
+ const members = await getDb()
736
+ .select({ itemVersionId: schema.contextPackMembers.itemVersionId })
737
+ .from(schema.contextPackMembers)
738
+ .where(eq(schema.contextPackMembers.packId, packId));
739
+ return members.map((member) => member.itemVersionId);
740
+ }
741
+ export async function listAccessibleSearchDocuments(input) {
742
+ const { getDb, schema } = getCreativeContext();
743
+ const packVersionIds = input.packId
744
+ ? await accessiblePackVersionIds(input.packId)
745
+ : null;
746
+ if (packVersionIds && !packVersionIds.length)
747
+ return [];
748
+ const filters = [
749
+ accessFilter(schema.contextSources, schema.contextSourceShares),
750
+ ne(schema.contextSources.upstreamAccess, "restricted"),
751
+ ne(schema.contextSources.status, "archived"),
752
+ ...(packVersionIds
753
+ ? [inArray(schema.contextChunks.itemVersionId, packVersionIds)]
754
+ : [
755
+ eq(schema.contextItems.currentVersionId, schema.contextChunks.itemVersionId),
756
+ ]),
757
+ eq(schema.contextItems.curationStatus, "included"),
758
+ ne(schema.contextItems.curationRank, "ignored"),
759
+ inArray(schema.contextItems.status, searchableItemStatuses(input.statuses)),
760
+ ];
761
+ if (input.sourceIds?.length) {
762
+ filters.push(inArray(schema.contextSources.id, input.sourceIds));
763
+ }
764
+ if (input.itemIds?.length) {
765
+ filters.push(inArray(schema.contextItems.id, input.itemIds));
766
+ }
767
+ if (input.chunkIds?.length) {
768
+ filters.push(inArray(schema.contextChunks.id, input.chunkIds));
769
+ }
770
+ if (input.kinds?.length) {
771
+ filters.push(inArray(schema.contextItems.kind, input.kinds));
772
+ }
773
+ if (input.updatedAfter) {
774
+ filters.push(gte(schema.contextItems.updatedAt, input.updatedAfter));
775
+ }
776
+ if (input.updatedBefore) {
777
+ filters.push(lte(schema.contextItems.updatedAt, input.updatedBefore));
778
+ }
779
+ const rowLimit = Math.max(1, Math.min(5_000, input.limit * 100));
780
+ const rows = [];
781
+ let afterChunkId = input.afterChunkId;
782
+ while (rows.length < rowLimit) {
783
+ const page = await getDb()
784
+ .select({
785
+ itemId: schema.contextItems.id,
786
+ externalId: schema.contextItems.externalId,
787
+ itemVersionId: schema.contextChunks.itemVersionId,
788
+ chunkId: schema.contextChunks.id,
789
+ chunkOrdinal: schema.contextChunks.ordinal,
790
+ sourceId: schema.contextSources.id,
791
+ sourceName: schema.contextSources.name,
792
+ kind: schema.contextItems.kind,
793
+ title: schema.contextItems.title,
794
+ body: sql `substr(${schema.contextChunks.text}, 1, 12000)`,
795
+ summary: schema.contextItemVersions.summary,
796
+ tags: schema.contextItems.tags,
797
+ colors: schema.contextItems.colors,
798
+ updatedAt: schema.contextItems.updatedAt,
799
+ curationRank: schema.contextItems.curationRank,
800
+ starred: schema.contextItems.starred,
801
+ indexState: schema.contextItems.indexState,
802
+ parseStatus: schema.contextItemVersions.parseStatus,
803
+ canonicalUrl: schema.contextItems.canonicalUrl,
804
+ mimeType: schema.contextItems.mimeType,
805
+ })
806
+ .from(schema.contextChunks)
807
+ .innerJoin(schema.contextItems, eq(schema.contextItems.id, schema.contextChunks.itemId))
808
+ .innerJoin(schema.contextSources, eq(schema.contextSources.id, schema.contextItems.sourceId))
809
+ .innerJoin(schema.contextItemVersions, eq(schema.contextItemVersions.id, schema.contextChunks.itemVersionId))
810
+ .where(and(...filters, ...(afterChunkId ? [gt(schema.contextChunks.id, afterChunkId)] : [])))
811
+ .orderBy(asc(schema.contextChunks.id))
812
+ .limit(1_000);
813
+ for (const row of page) {
814
+ const tags = parseJson(row.tags, []);
815
+ const colors = parseJson(row.colors, []);
816
+ if (!(input.tags?.every((tag) => tags.includes(tag)) ?? true) ||
817
+ !(input.colors?.every((color) => colors.includes(color)) ?? true)) {
818
+ continue;
819
+ }
820
+ rows.push({ ...row, tags, colors });
821
+ if (rows.length === rowLimit)
822
+ break;
823
+ }
824
+ if (page.length < 1_000)
825
+ break;
826
+ afterChunkId = String(page.at(-1).chunkId);
827
+ }
828
+ const documents = rows.map((row) => ({
829
+ itemId: row.itemId,
830
+ externalId: row.externalId,
831
+ itemVersionId: row.itemVersionId,
832
+ chunkId: row.chunkId,
833
+ chunkOrdinal: row.chunkOrdinal,
834
+ sourceId: row.sourceId,
835
+ sourceName: row.sourceName,
836
+ kind: row.kind,
837
+ title: row.title,
838
+ body: row.body,
839
+ summary: row.summary ?? null,
840
+ tags: row.tags,
841
+ colors: row.colors,
842
+ updatedAt: row.updatedAt,
843
+ curationRank: row.curationRank,
844
+ starred: Boolean(row.starred),
845
+ indexState: row.indexState,
846
+ inventoryOnly: row.parseStatus === "pending",
847
+ priorReuseCount: 0,
848
+ helpfulFeedbackCount: 0,
849
+ excerpt: row.summary ?? row.body.slice(0, 600),
850
+ score: 0,
851
+ canonicalUrl: row.canonicalUrl ?? null,
852
+ mimeType: row.mimeType ?? null,
853
+ }));
854
+ if (!documents.length)
855
+ return documents;
856
+ const actor = requireActor();
857
+ const versionIds = [
858
+ ...new Set(documents.map((row) => row.itemVersionId)),
859
+ ];
860
+ const [reuseRows, feedbackRows] = await Promise.all([
861
+ getDb()
862
+ .select({ itemVersionId: schema.contextPackMembers.itemVersionId })
863
+ .from(schema.contextPackMembers)
864
+ .where(and(inArray(schema.contextPackMembers.itemVersionId, versionIds), eq(schema.contextPackMembers.ownerEmail, actor.ownerEmail))),
865
+ getDb()
866
+ .select({ itemVersionId: schema.contextFeedback.itemVersionId })
867
+ .from(schema.contextFeedback)
868
+ .where(and(inArray(schema.contextFeedback.itemVersionId, versionIds), eq(schema.contextFeedback.ownerEmail, actor.ownerEmail), eq(schema.contextFeedback.signal, "helpful"))),
869
+ ]);
870
+ const reuseCounts = new Map();
871
+ const helpfulCounts = new Map();
872
+ for (const row of reuseRows) {
873
+ reuseCounts.set(row.itemVersionId, (reuseCounts.get(row.itemVersionId) ?? 0) + 1);
874
+ }
875
+ for (const row of feedbackRows) {
876
+ helpfulCounts.set(row.itemVersionId, (helpfulCounts.get(row.itemVersionId) ?? 0) + 1);
877
+ }
878
+ return documents.map((document) => ({
879
+ ...document,
880
+ priorReuseCount: reuseCounts.get(document.itemVersionId) ?? 0,
881
+ helpfulFeedbackCount: helpfulCounts.get(document.itemVersionId) ?? 0,
882
+ }));
883
+ }
884
+ export async function listAccessibleLexicalCandidates(input) {
885
+ const { getDb, schema } = getCreativeContext();
886
+ const offset = parseOffsetCursor(input.cursor);
887
+ const packVersionIds = input.packId
888
+ ? await accessiblePackVersionIds(input.packId)
889
+ : null;
890
+ if (packVersionIds && !packVersionIds.length)
891
+ return { results: [] };
892
+ const matchMode = input.matchMode ?? "allTerms";
893
+ const terms = normalizeSearchTerms(input.query);
894
+ if (!terms.length && matchMode !== "regex")
895
+ return { results: [] };
896
+ const [phraseTerm, ...tokenTerms] = terms;
897
+ const matchTerms = tokenTerms.length
898
+ ? tokenTerms
899
+ : phraseTerm
900
+ ? [phraseTerm]
901
+ : [];
902
+ const likeClauses = matchTerms.map((term) => {
903
+ const pattern = `%${escapeLikeTerm(term)}%`;
904
+ return or(sql `lower(${schema.contextItems.title}) like ${pattern} escape '\\'`, sql `lower(${schema.contextChunks.text}) like ${pattern} escape '\\'`);
905
+ });
906
+ const filters = [
907
+ accessFilter(schema.contextSources, schema.contextSourceShares),
908
+ ne(schema.contextSources.upstreamAccess, "restricted"),
909
+ ne(schema.contextSources.status, "archived"),
910
+ ...(packVersionIds
911
+ ? [inArray(schema.contextChunks.itemVersionId, packVersionIds)]
912
+ : [
913
+ eq(schema.contextItems.currentVersionId, schema.contextChunks.itemVersionId),
914
+ ]),
915
+ eq(schema.contextItems.curationStatus, "included"),
916
+ ne(schema.contextItems.curationRank, "ignored"),
917
+ inArray(schema.contextItems.status, searchableItemStatuses(input.statuses)),
918
+ ];
919
+ if (matchMode !== "regex") {
920
+ if (matchMode === "phrase") {
921
+ const phrasePattern = `%${escapeLikeTerm(input.query.trim().toLocaleLowerCase())}%`;
922
+ filters.push(or(sql `lower(${schema.contextItems.title}) like ${phrasePattern} escape '\\'`, sql `lower(${schema.contextChunks.text}) like ${phrasePattern} escape '\\'`));
923
+ }
924
+ else {
925
+ filters.push(matchMode === "allTerms" ? and(...likeClauses) : or(...likeClauses));
926
+ }
927
+ }
928
+ if (input.sourceIds?.length) {
929
+ filters.push(inArray(schema.contextSources.id, input.sourceIds));
930
+ }
931
+ if (input.kinds?.length) {
932
+ filters.push(inArray(schema.contextItems.kind, input.kinds));
933
+ }
934
+ if (input.updatedAfter) {
935
+ filters.push(gte(schema.contextItems.updatedAt, input.updatedAfter));
936
+ }
937
+ if (input.updatedBefore) {
938
+ filters.push(lte(schema.contextItems.updatedAt, input.updatedBefore));
939
+ }
940
+ const pageSize = 1000;
941
+ const keep = offset + input.limit + 1;
942
+ const scored = [];
943
+ let afterChunkId;
944
+ while (true) {
945
+ const rows = await getDb()
946
+ .select({
947
+ itemId: schema.contextItems.id,
948
+ itemVersionId: schema.contextChunks.itemVersionId,
949
+ chunkId: schema.contextChunks.id,
950
+ sourceId: schema.contextSources.id,
951
+ sourceName: schema.contextSources.name,
952
+ kind: schema.contextItems.kind,
953
+ title: schema.contextItems.title,
954
+ body: sql `substr(${schema.contextChunks.text}, 1, 12000)`,
955
+ summary: schema.contextItemVersions.summary,
956
+ metadata: schema.contextItems.metadata,
957
+ tags: schema.contextItems.tags,
958
+ colors: schema.contextItems.colors,
959
+ curationRank: schema.contextItems.curationRank,
960
+ starred: schema.contextItems.starred,
961
+ canonicalUrl: schema.contextItems.canonicalUrl,
962
+ mimeType: schema.contextItems.mimeType,
963
+ })
964
+ .from(schema.contextChunks)
965
+ .innerJoin(schema.contextItems, eq(schema.contextItems.id, schema.contextChunks.itemId))
966
+ .innerJoin(schema.contextSources, eq(schema.contextSources.id, schema.contextItems.sourceId))
967
+ .innerJoin(schema.contextItemVersions, eq(schema.contextItemVersions.id, schema.contextChunks.itemVersionId))
968
+ .where(and(...filters, ...(afterChunkId ? [gt(schema.contextChunks.id, afterChunkId)] : [])))
969
+ .orderBy(asc(schema.contextChunks.id))
970
+ .limit(pageSize);
971
+ for (const row of rows) {
972
+ const tags = new Set(parseJson(row.tags, []));
973
+ const colors = new Set(parseJson(row.colors, []));
974
+ if (!(input.tags?.every((tag) => tags.has(tag)) ?? true) ||
975
+ !(input.colors?.every((color) => colors.has(color)) ?? true) ||
976
+ !matchesCreativeSearchMode(`${row.title}\n${row.summary ?? ""}\n${row.body}`, input.query, matchMode)) {
977
+ continue;
978
+ }
979
+ scored.push({
980
+ itemId: row.itemId,
981
+ itemVersionId: row.itemVersionId,
982
+ chunkId: row.chunkId,
983
+ sourceId: row.sourceId,
984
+ sourceName: row.sourceName,
985
+ kind: row.kind,
986
+ title: row.title,
987
+ excerpt: buildSearchSnippet(row.body, terms, 600),
988
+ score: scoreSearchText({
989
+ title: row.title,
990
+ summary: row.summary,
991
+ body: row.body,
992
+ metadata: row.metadata,
993
+ }, terms) +
994
+ (row.starred
995
+ ? 2
996
+ : row.curationRank === "canonical"
997
+ ? 1.5
998
+ : row.curationRank === "exemplar"
999
+ ? 1
1000
+ : 0),
1001
+ canonicalUrl: row.canonicalUrl ?? null,
1002
+ mimeType: row.mimeType ?? null,
1003
+ });
1004
+ }
1005
+ scored.sort((a, b) => b.score - a.score || (a.chunkId ?? "").localeCompare(b.chunkId ?? ""));
1006
+ if (scored.length > keep)
1007
+ scored.length = keep;
1008
+ if (rows.length < pageSize)
1009
+ break;
1010
+ afterChunkId = String(rows.at(-1).chunkId);
1011
+ }
1012
+ const page = scored.slice(offset, offset + input.limit + 1);
1013
+ const hasMore = page.length > input.limit;
1014
+ return {
1015
+ results: page.slice(0, input.limit),
1016
+ nextCursor: nextOffsetCursor(offset, input.limit, hasMore),
1017
+ };
1018
+ }
1019
+ export async function getCreativeContextItem(itemId, itemVersionId) {
1020
+ const { getDb, schema } = getCreativeContext();
1021
+ const itemRows = await getDb()
1022
+ .select({ item: schema.contextItems })
1023
+ .from(schema.contextItems)
1024
+ .innerJoin(schema.contextSources, eq(schema.contextSources.id, schema.contextItems.sourceId))
1025
+ .where(and(eq(schema.contextItems.id, itemId), accessFilter(schema.contextSources, schema.contextSourceShares), ne(schema.contextSources.upstreamAccess, "restricted"), ne(schema.contextSources.status, "archived"), eq(schema.contextItems.curationStatus, "included"), ne(schema.contextItems.curationRank, "ignored"), eq(schema.contextItems.status, "active")))
1026
+ .limit(1);
1027
+ const itemRow = itemRows[0]?.item;
1028
+ if (!itemRow)
1029
+ return null;
1030
+ const targetVersionId = itemVersionId ?? itemRow.currentVersionId;
1031
+ const versionRows = await getDb()
1032
+ .select()
1033
+ .from(schema.contextItemVersions)
1034
+ .where(and(eq(schema.contextItemVersions.id, targetVersionId), eq(schema.contextItemVersions.itemId, itemId)))
1035
+ .limit(1);
1036
+ if (!versionRows[0])
1037
+ return null;
1038
+ const [chunkRows, mediaRows, edgeRows] = await Promise.all([
1039
+ getDb()
1040
+ .select()
1041
+ .from(schema.contextChunks)
1042
+ .where(eq(schema.contextChunks.itemVersionId, targetVersionId))
1043
+ .orderBy(asc(schema.contextChunks.ordinal)),
1044
+ getDb()
1045
+ .select()
1046
+ .from(schema.contextMedia)
1047
+ .where(eq(schema.contextMedia.itemVersionId, targetVersionId)),
1048
+ getDb()
1049
+ .select()
1050
+ .from(schema.contextEdges)
1051
+ .where(eq(schema.contextEdges.fromItemVersionId, targetVersionId)),
1052
+ ]);
1053
+ return {
1054
+ item: mapItem(itemRow),
1055
+ version: mapVersion(versionRows[0]),
1056
+ chunks: chunkRows.map(mapChunk),
1057
+ media: mediaRows.map(mapMedia),
1058
+ edges: edgeRows.map(mapEdge),
1059
+ };
1060
+ }
1061
+ export async function getCreativeContextItemByExternalId(input) {
1062
+ if (Boolean(input.itemId) !== Boolean(input.itemVersionId))
1063
+ return null;
1064
+ if (input.itemId && input.itemVersionId) {
1065
+ const pinned = await getCreativeContextItem(input.itemId, input.itemVersionId);
1066
+ return pinned?.item.sourceId === input.sourceId &&
1067
+ pinned.item.externalId === input.externalId
1068
+ ? pinned
1069
+ : null;
1070
+ }
1071
+ const { getDb, schema } = getCreativeContext();
1072
+ const itemRows = await getDb()
1073
+ .select({ id: schema.contextItems.id })
1074
+ .from(schema.contextItems)
1075
+ .where(and(eq(schema.contextItems.sourceId, input.sourceId), eq(schema.contextItems.externalId, input.externalId)))
1076
+ .limit(1);
1077
+ const itemId = itemRows[0]?.id;
1078
+ if (!itemId)
1079
+ return null;
1080
+ if (!input.sourceVersion)
1081
+ return getCreativeContextItem(itemId);
1082
+ const versionRows = await getDb()
1083
+ .select({ id: schema.contextItemVersions.id })
1084
+ .from(schema.contextItemVersions)
1085
+ .where(and(eq(schema.contextItemVersions.itemId, itemId), eq(schema.contextItemVersions.sourceVersion, input.sourceVersion)))
1086
+ .orderBy(desc(schema.contextItemVersions.versionNumber))
1087
+ .limit(1);
1088
+ const versionId = versionRows[0]?.id;
1089
+ return versionId ? getCreativeContextItem(itemId, versionId) : null;
1090
+ }
1091
+ export async function createEmbeddingSet(input) {
1092
+ const { getDb, schema } = getCreativeContext();
1093
+ const actor = requireActor();
1094
+ if (actor.orgId) {
1095
+ const membership = await getDbExec().execute({
1096
+ sql: "SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1",
1097
+ args: [actor.orgId, actor.ownerEmail.toLowerCase()],
1098
+ });
1099
+ const role = String(membership.rows[0]?.role ?? "").toLowerCase();
1100
+ if (role !== "owner" && role !== "admin") {
1101
+ throw new Error("Only organization owners or admins can activate an organization embedding family.");
1102
+ }
1103
+ }
1104
+ const row = {
1105
+ id: newId("cces"),
1106
+ name: input.name,
1107
+ provider: input.provider,
1108
+ family: input.family,
1109
+ model: input.model,
1110
+ version: input.version,
1111
+ dimensions: input.dimensions,
1112
+ metric: input.metric ?? "cosine",
1113
+ status: "active",
1114
+ metadata: stringifyJson(input.metadata),
1115
+ createdAt: nowIso(),
1116
+ ownerEmail: actor.ownerEmail,
1117
+ orgId: actor.orgId,
1118
+ };
1119
+ await getDb().transaction(async (tx) => {
1120
+ await tx
1121
+ .update(schema.embeddingSets)
1122
+ .set({ status: "retired" })
1123
+ .where(and(actor.orgId
1124
+ ? eq(schema.embeddingSets.orgId, actor.orgId)
1125
+ : eq(schema.embeddingSets.ownerEmail, actor.ownerEmail), eq(schema.embeddingSets.status, "active")));
1126
+ await tx.insert(schema.embeddingSets).values(row);
1127
+ });
1128
+ return { ...row, metadata: parseJson(row.metadata, {}) };
1129
+ }
1130
+ export async function getActiveEmbeddingSet(input = {}) {
1131
+ const { getDb, schema } = getCreativeContext();
1132
+ const actor = requireActor();
1133
+ const filters = [
1134
+ actor.orgId
1135
+ ? eq(schema.embeddingSets.orgId, actor.orgId)
1136
+ : eq(schema.embeddingSets.ownerEmail, actor.ownerEmail),
1137
+ eq(schema.embeddingSets.status, "active"),
1138
+ ];
1139
+ if (input.family)
1140
+ filters.push(eq(schema.embeddingSets.family, input.family));
1141
+ if (input.model)
1142
+ filters.push(eq(schema.embeddingSets.model, input.model));
1143
+ if (input.version)
1144
+ filters.push(eq(schema.embeddingSets.version, input.version));
1145
+ const rows = await getDb()
1146
+ .select()
1147
+ .from(schema.embeddingSets)
1148
+ .where(and(...filters))
1149
+ .orderBy(desc(schema.embeddingSets.createdAt), desc(schema.embeddingSets.id))
1150
+ .limit(1);
1151
+ const row = rows[0];
1152
+ return row
1153
+ ? {
1154
+ id: row.id,
1155
+ name: row.name,
1156
+ provider: row.provider,
1157
+ family: row.family,
1158
+ model: row.model,
1159
+ version: row.version,
1160
+ dimensions: row.dimensions,
1161
+ metric: row.metric,
1162
+ status: row.status,
1163
+ metadata: parseJson(row.metadata, {}),
1164
+ createdAt: row.createdAt,
1165
+ }
1166
+ : null;
1167
+ }
1168
+ export async function recordEmbeddingMetadata(input) {
1169
+ const { getDb, schema } = getCreativeContext();
1170
+ const actor = requireActor();
1171
+ const detail = await getCreativeContextItem(input.itemId, input.itemVersionId);
1172
+ if (!detail)
1173
+ throw new Error("Context item version not found or not accessible");
1174
+ if (input.chunkId) {
1175
+ const chunk = detail.chunks.find((entry) => entry.id === input.chunkId);
1176
+ if (!chunk)
1177
+ throw new Error("Embedding chunk must belong to item version");
1178
+ }
1179
+ const targetType = input.targetType ?? (input.chunkId ? "chunk" : "item");
1180
+ const targetId = input.targetId ?? input.chunkId ?? input.itemVersionId;
1181
+ if (targetType === "chunk" &&
1182
+ !detail.chunks.some((entry) => entry.id === targetId)) {
1183
+ throw new Error("Embedding chunk target must belong to item version");
1184
+ }
1185
+ if (targetType === "media" &&
1186
+ !detail.media.some((entry) => entry.id === targetId)) {
1187
+ throw new Error("Embedding media target must belong to item version");
1188
+ }
1189
+ if (targetType === "item" && targetId !== input.itemVersionId) {
1190
+ throw new Error("Item embeddings target the exact item version id");
1191
+ }
1192
+ const sets = await getDb()
1193
+ .select()
1194
+ .from(schema.embeddingSets)
1195
+ .where(and(eq(schema.embeddingSets.id, input.embeddingSetId), actor.orgId
1196
+ ? eq(schema.embeddingSets.orgId, actor.orgId)
1197
+ : eq(schema.embeddingSets.ownerEmail, actor.ownerEmail)))
1198
+ .limit(1);
1199
+ const set = sets[0];
1200
+ if (!set || set.status !== "active") {
1201
+ throw new Error("Active embedding set not found");
1202
+ }
1203
+ if (set.dimensions !== input.dimensions) {
1204
+ throw new Error("Embedding dimensions do not match embedding set");
1205
+ }
1206
+ const existing = await getDb()
1207
+ .select({
1208
+ id: schema.embeddings.id,
1209
+ vectorKey: schema.embeddings.vectorKey,
1210
+ dimensions: schema.embeddings.dimensions,
1211
+ })
1212
+ .from(schema.embeddings)
1213
+ .where(and(eq(schema.embeddings.embeddingSetId, input.embeddingSetId), eq(schema.embeddings.targetType, targetType), eq(schema.embeddings.targetId, targetId)))
1214
+ .limit(1);
1215
+ const row = {
1216
+ id: existing[0]?.id ?? newId("cce"),
1217
+ embeddingSetId: input.embeddingSetId,
1218
+ family: set.family,
1219
+ model: set.model,
1220
+ version: set.version,
1221
+ itemId: input.itemId,
1222
+ itemVersionId: input.itemVersionId,
1223
+ chunkId: input.chunkId ?? null,
1224
+ targetType,
1225
+ targetId,
1226
+ vectorKey: input.vectorKey,
1227
+ dimensions: input.dimensions,
1228
+ checksum: input.checksum ?? null,
1229
+ createdAt: nowIso(),
1230
+ ownerEmail: actor.ownerEmail,
1231
+ orgId: actor.orgId,
1232
+ };
1233
+ await getDb()
1234
+ .insert(schema.embeddings)
1235
+ .values(row)
1236
+ .onConflictDoUpdate({
1237
+ target: [
1238
+ schema.embeddings.embeddingSetId,
1239
+ schema.embeddings.targetType,
1240
+ schema.embeddings.targetId,
1241
+ ],
1242
+ set: {
1243
+ family: row.family,
1244
+ model: row.model,
1245
+ version: row.version,
1246
+ itemId: row.itemId,
1247
+ itemVersionId: row.itemVersionId,
1248
+ chunkId: row.chunkId,
1249
+ vectorKey: row.vectorKey,
1250
+ dimensions: row.dimensions,
1251
+ checksum: row.checksum,
1252
+ createdAt: row.createdAt,
1253
+ ownerEmail: row.ownerEmail,
1254
+ orgId: row.orgId,
1255
+ },
1256
+ });
1257
+ if (existing[0] && existing[0].vectorKey !== input.vectorKey) {
1258
+ await getCreativeContext().vectorAdapter?.delete(existing[0]);
1259
+ }
1260
+ return row;
1261
+ }
1262
+ export async function listEmbeddingMetadata(input) {
1263
+ const { getDb, schema } = getCreativeContext();
1264
+ if (input.itemVersionIds && !input.itemVersionIds.length)
1265
+ return [];
1266
+ const packVersionIds = input.packId
1267
+ ? await accessiblePackVersionIds(input.packId)
1268
+ : null;
1269
+ if (packVersionIds && !packVersionIds.length)
1270
+ return [];
1271
+ const filters = [
1272
+ eq(schema.embeddings.embeddingSetId, input.embeddingSetId),
1273
+ ...(packVersionIds
1274
+ ? [inArray(schema.embeddings.itemVersionId, packVersionIds)]
1275
+ : [
1276
+ eq(schema.contextItems.currentVersionId, schema.embeddings.itemVersionId),
1277
+ ]),
1278
+ accessFilter(schema.contextSources, schema.contextSourceShares),
1279
+ ne(schema.contextSources.upstreamAccess, "restricted"),
1280
+ ne(schema.contextSources.status, "archived"),
1281
+ eq(schema.contextItems.curationStatus, "included"),
1282
+ ne(schema.contextItems.curationRank, "ignored"),
1283
+ inArray(schema.contextItems.status, searchableItemStatuses(input.statuses)),
1284
+ ];
1285
+ if (input.itemVersionIds) {
1286
+ filters.push(inArray(schema.embeddings.itemVersionId, input.itemVersionIds));
1287
+ }
1288
+ if (input.sourceIds?.length) {
1289
+ filters.push(inArray(schema.contextSources.id, input.sourceIds));
1290
+ }
1291
+ if (input.kinds?.length) {
1292
+ filters.push(inArray(schema.contextItems.kind, input.kinds));
1293
+ }
1294
+ if (input.updatedAfter) {
1295
+ filters.push(gte(schema.contextItems.updatedAt, input.updatedAfter));
1296
+ }
1297
+ if (input.updatedBefore) {
1298
+ filters.push(lte(schema.contextItems.updatedAt, input.updatedBefore));
1299
+ }
1300
+ const rows = await getDb()
1301
+ .select({
1302
+ id: schema.embeddings.id,
1303
+ embeddingSetId: schema.embeddings.embeddingSetId,
1304
+ family: schema.embeddings.family,
1305
+ model: schema.embeddings.model,
1306
+ version: schema.embeddings.version,
1307
+ itemId: schema.embeddings.itemId,
1308
+ itemVersionId: schema.embeddings.itemVersionId,
1309
+ chunkId: schema.embeddings.chunkId,
1310
+ targetType: schema.embeddings.targetType,
1311
+ targetId: schema.embeddings.targetId,
1312
+ vectorKey: schema.embeddings.vectorKey,
1313
+ dimensions: schema.embeddings.dimensions,
1314
+ checksum: schema.embeddings.checksum,
1315
+ createdAt: schema.embeddings.createdAt,
1316
+ tags: schema.contextItems.tags,
1317
+ colors: schema.contextItems.colors,
1318
+ })
1319
+ .from(schema.embeddings)
1320
+ .innerJoin(schema.contextItems, eq(schema.contextItems.id, schema.embeddings.itemId))
1321
+ .innerJoin(schema.contextSources, eq(schema.contextSources.id, schema.contextItems.sourceId))
1322
+ .where(and(...filters));
1323
+ return rows
1324
+ .filter((row) => {
1325
+ const tags = parseJson(row.tags, []);
1326
+ const colors = parseJson(row.colors, []);
1327
+ return ((input.tags?.every((tag) => tags.includes(tag)) ?? true) &&
1328
+ (input.colors?.every((color) => colors.includes(color)) ?? true));
1329
+ })
1330
+ .map(({ tags: _tags, colors: _colors, ...row }) => row);
1331
+ }
1332
+ export async function recordContextFeedback(input) {
1333
+ const detail = await getCreativeContextItem(input.itemId, input.itemVersionId);
1334
+ if (!detail)
1335
+ throw new Error("Context item version not found or not accessible");
1336
+ const { getDb, schema } = getCreativeContext();
1337
+ const actor = requireActor();
1338
+ await getDb()
1339
+ .insert(schema.contextFeedback)
1340
+ .values({
1341
+ id: newId("ccf"),
1342
+ itemId: input.itemId,
1343
+ itemVersionId: detail.version.id,
1344
+ signal: input.signal,
1345
+ note: input.note ?? null,
1346
+ createdAt: nowIso(),
1347
+ ownerEmail: actor.ownerEmail,
1348
+ orgId: actor.orgId,
1349
+ });
1350
+ return { recorded: true };
1351
+ }
1352
+ export async function reviewContextItems(input) {
1353
+ const { getDb, schema } = getCreativeContext();
1354
+ await assertAccess("creative-context-source", input.sourceId, input.operation === "list" ? "viewer" : "editor", undefined, { skipResourceBody: true });
1355
+ const pendingFilter = and(eq(schema.contextItems.sourceId, input.sourceId), eq(schema.contextItems.upstreamAccess, "restricted"), eq(schema.contextItems.curationStatus, "review"));
1356
+ if (input.operation !== "list") {
1357
+ const itemIds = Array.from(new Set(input.itemIds ?? []));
1358
+ if (!itemIds.length)
1359
+ throw new Error("itemIds are required for review");
1360
+ const eligibleFilter = input.operation === "approve" || input.operation === "exclude"
1361
+ ? and(eq(schema.contextItems.sourceId, input.sourceId), eq(schema.contextItems.upstreamAccess, "restricted"), inArray(schema.contextItems.curationStatus, [
1362
+ "review",
1363
+ "included",
1364
+ "excluded",
1365
+ ]), inArray(schema.contextItems.id, itemIds))
1366
+ : and(eq(schema.contextItems.sourceId, input.sourceId), inArray(schema.contextItems.id, itemIds));
1367
+ const eligible = await getDb()
1368
+ .select({ id: schema.contextItems.id })
1369
+ .from(schema.contextItems)
1370
+ .where(eligibleFilter);
1371
+ if (eligible.length !== itemIds.length) {
1372
+ throw new Error("All curated items must belong to the accessible source and be eligible for the operation");
1373
+ }
1374
+ const valuesByOperation = {
1375
+ approve: { curationStatus: "included" },
1376
+ exclude: { curationStatus: "excluded" },
1377
+ exemplar: { curationRank: "exemplar" },
1378
+ normal: { curationRank: "normal" },
1379
+ ignore: { curationRank: "ignored" },
1380
+ star: { starred: 1 },
1381
+ unstar: { starred: 0 },
1382
+ deprecate: { status: "deprecated" },
1383
+ restore: { status: "active" },
1384
+ };
1385
+ const mutationValues = valuesByOperation[input.operation];
1386
+ const timestamp = nowIso();
1387
+ await getDb().transaction(async (tx) => {
1388
+ await tx
1389
+ .update(schema.contextItems)
1390
+ .set({ ...mutationValues, updatedAt: timestamp })
1391
+ .where(inArray(schema.contextItems.id, itemIds));
1392
+ });
1393
+ return { items: [], updated: itemIds.length };
1394
+ }
1395
+ const rows = await getDb()
1396
+ .select({
1397
+ id: schema.contextItems.id,
1398
+ currentVersionId: schema.contextItems.currentVersionId,
1399
+ sourceId: schema.contextItems.sourceId,
1400
+ externalId: schema.contextItems.externalId,
1401
+ kind: schema.contextItems.kind,
1402
+ title: schema.contextItems.title,
1403
+ canonicalUrl: schema.contextItems.canonicalUrl,
1404
+ upstreamAccess: schema.contextItems.upstreamAccess,
1405
+ curationStatus: schema.contextItems.curationStatus,
1406
+ curationRank: schema.contextItems.curationRank,
1407
+ starred: schema.contextItems.starred,
1408
+ status: schema.contextItems.status,
1409
+ inventoryState: schema.contextItems.inventoryState,
1410
+ tags: schema.contextItems.tags,
1411
+ colors: schema.contextItems.colors,
1412
+ parentItemId: schema.contextItems.parentItemId,
1413
+ provenance: schema.contextItems.provenance,
1414
+ thumbnailBlobRef: schema.contextItems.thumbnailBlobRef,
1415
+ updatedAt: schema.contextItems.updatedAt,
1416
+ })
1417
+ .from(schema.contextItems)
1418
+ .where(input.queue === "all"
1419
+ ? and(eq(schema.contextItems.sourceId, input.sourceId), ne(schema.contextItems.status, "deleted"))
1420
+ : pendingFilter)
1421
+ .orderBy(desc(schema.contextItems.updatedAt))
1422
+ .limit(input.limit ?? 100);
1423
+ return {
1424
+ items: rows.map((row) => ({
1425
+ ...row,
1426
+ canonicalUrl: row.canonicalUrl ?? null,
1427
+ starred: Boolean(row.starred),
1428
+ tags: parseJson(row.tags, []),
1429
+ colors: parseJson(row.colors, []),
1430
+ parentItemId: row.parentItemId ?? null,
1431
+ provenance: parseJson(row.provenance, {}),
1432
+ thumbnailBlobRef: row.thumbnailBlobRef ?? null,
1433
+ })),
1434
+ updated: 0,
1435
+ };
1436
+ }
1437
+ //# sourceMappingURL=content.js.map