@openrails/contentkit-ui 0.103.2 → 0.104.0-rc.2

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 (253) hide show
  1. package/README.md +111 -49
  2. package/dist/client/beacons.d.ts +3 -13
  3. package/dist/client/beacons.js +8 -46
  4. package/dist/client/beacons.js.map +1 -1
  5. package/dist/client/client.d.ts +3 -0
  6. package/dist/client/client.js +45 -43
  7. package/dist/client/client.js.map +1 -1
  8. package/dist/client/content/favorites.d.ts +2 -0
  9. package/dist/client/content/favorites.js.map +1 -1
  10. package/dist/client/content/types.d.ts +3 -0
  11. package/dist/client/content/types.js.map +1 -1
  12. package/dist/client/contents.d.ts +7 -1
  13. package/dist/client/contents.js +8 -0
  14. package/dist/client/contents.js.map +1 -1
  15. package/dist/client/discovery.d.ts +34 -5
  16. package/dist/client/discovery.js +23 -2
  17. package/dist/client/discovery.js.map +1 -1
  18. package/dist/client/engagement.d.ts +70 -0
  19. package/dist/client/engagement.js +191 -0
  20. package/dist/client/engagement.js.map +1 -0
  21. package/dist/client/generated/routes.d.ts +74 -35
  22. package/dist/client/generated/routes.js +119 -60
  23. package/dist/client/generated/routes.js.map +1 -1
  24. package/dist/client/generated/wire.d.ts +88 -85
  25. package/dist/client/generated/wire.js.map +1 -1
  26. package/dist/client/guest-reading-history.d.ts +40 -0
  27. package/dist/client/guest-reading-history.js +144 -0
  28. package/dist/client/guest-reading-history.js.map +1 -0
  29. package/dist/client/index.d.ts +5 -3
  30. package/dist/client/media/windows.d.ts +2 -0
  31. package/dist/client/media/windows.js +4 -1
  32. package/dist/client/media/windows.js.map +1 -1
  33. package/dist/client/stats.d.ts +4 -20
  34. package/dist/client/stats.js +0 -11
  35. package/dist/client/stats.js.map +1 -1
  36. package/dist/client/versions.d.ts +8 -6
  37. package/dist/client/versions.js +15 -10
  38. package/dist/client/versions.js.map +1 -1
  39. package/dist/client.js +24 -22
  40. package/dist/components/admin/bulk-drafts.d.ts +17 -0
  41. package/dist/components/admin/bulk-drafts.js +41 -0
  42. package/dist/components/admin/bulk-drafts.js.map +1 -0
  43. package/dist/components/admin/content-admin.d.ts +1 -1
  44. package/dist/components/admin/content-admin.js.map +1 -1
  45. package/dist/components/admin/content-manager.d.ts +11 -3
  46. package/dist/components/admin/content-manager.js +751 -394
  47. package/dist/components/admin/content-manager.js.map +1 -1
  48. package/dist/components/admin/group-manager.d.ts +8 -3
  49. package/dist/components/admin/group-manager.js +218 -146
  50. package/dist/components/admin/group-manager.js.map +1 -1
  51. package/dist/components/admin/page-notices.d.ts +16 -0
  52. package/dist/components/admin/page-notices.js +113 -0
  53. package/dist/components/admin/page-notices.js.map +1 -0
  54. package/dist/components/admin/page-picker.d.ts +38 -0
  55. package/dist/components/admin/page-picker.js +159 -0
  56. package/dist/components/admin/page-picker.js.map +1 -0
  57. package/dist/components/admin/quick-search.d.ts +14 -0
  58. package/dist/components/admin/quick-search.js +60 -0
  59. package/dist/components/admin/quick-search.js.map +1 -0
  60. package/dist/components/admin/reader-content-editor.js +382 -321
  61. package/dist/components/admin/reader-content-editor.js.map +1 -1
  62. package/dist/components/admin/reader-manifest.js +181 -179
  63. package/dist/components/admin/reader-manifest.js.map +1 -1
  64. package/dist/components/admin/shell.d.ts +10 -2
  65. package/dist/components/admin/shell.js +114 -42
  66. package/dist/components/admin/shell.js.map +1 -1
  67. package/dist/components/admin/stats-dashboard.d.ts +4 -9
  68. package/dist/components/admin/stats-dashboard.js +303 -207
  69. package/dist/components/admin/stats-dashboard.js.map +1 -1
  70. package/dist/components/admin/upload-queue.d.ts +14 -0
  71. package/dist/components/admin/upload-queue.js +115 -98
  72. package/dist/components/admin/upload-queue.js.map +1 -1
  73. package/dist/components/content/card.d.ts +31 -3
  74. package/dist/components/content/card.js +324 -158
  75. package/dist/components/content/card.js.map +1 -1
  76. package/dist/components/content/daily-releases.js +144 -190
  77. package/dist/components/content/daily-releases.js.map +1 -1
  78. package/dist/components/content/editor-save.js +27 -25
  79. package/dist/components/content/editor-save.js.map +1 -1
  80. package/dist/components/content/editors.js +274 -253
  81. package/dist/components/content/editors.js.map +1 -1
  82. package/dist/components/content/favorites.d.ts +6 -0
  83. package/dist/components/content/favorites.js +47 -0
  84. package/dist/components/content/favorites.js.map +1 -0
  85. package/dist/components/content/filter-dialog.js +19 -15
  86. package/dist/components/content/filter-dialog.js.map +1 -1
  87. package/dist/components/content/filters.d.ts +2 -0
  88. package/dist/components/content/filters.js +5 -1
  89. package/dist/components/content/filters.js.map +1 -1
  90. package/dist/components/content/grid.d.ts +44 -16
  91. package/dist/components/content/grid.js +308 -270
  92. package/dist/components/content/grid.js.map +1 -1
  93. package/dist/components/content/history.d.ts +6 -0
  94. package/dist/components/content/history.js +111 -0
  95. package/dist/components/content/history.js.map +1 -0
  96. package/dist/components/content/index.d.ts +6 -3
  97. package/dist/components/content/listing.d.ts +14 -3
  98. package/dist/components/content/listing.js +65 -56
  99. package/dist/components/content/listing.js.map +1 -1
  100. package/dist/components/content/offer-fields.js +6 -6
  101. package/dist/components/content/paged-grid.d.ts +10 -0
  102. package/dist/components/content/paged-grid.js +116 -0
  103. package/dist/components/content/paged-grid.js.map +1 -0
  104. package/dist/components/content/pagination.d.ts +19 -0
  105. package/dist/components/content/pagination.js +97 -0
  106. package/dist/components/content/pagination.js.map +1 -0
  107. package/dist/components/content/paywall.d.ts +9 -0
  108. package/dist/components/content/paywall.js +27 -3
  109. package/dist/components/content/paywall.js.map +1 -1
  110. package/dist/components/content/post-list.d.ts +37 -0
  111. package/dist/components/content/post-list.js +203 -0
  112. package/dist/components/content/post-list.js.map +1 -0
  113. package/dist/components/content/reader-settings.d.ts +2 -0
  114. package/dist/components/content/reader-settings.js +1 -1
  115. package/dist/components/content/reader-settings.js.map +1 -1
  116. package/dist/components/content/search.d.ts +11 -4
  117. package/dist/components/content/search.js +22 -11
  118. package/dist/components/content/search.js.map +1 -1
  119. package/dist/components/content/summary-tile.d.ts +14 -0
  120. package/dist/components/content/summary-tile.js +63 -0
  121. package/dist/components/content/summary-tile.js.map +1 -0
  122. package/dist/components/groups/banner.d.ts +6 -2
  123. package/dist/components/groups/banner.js +79 -61
  124. package/dist/components/groups/banner.js.map +1 -1
  125. package/dist/components/groups/directory.d.ts +12 -2
  126. package/dist/components/groups/directory.js +168 -105
  127. package/dist/components/groups/directory.js.map +1 -1
  128. package/dist/components/groups/editor.js +10 -10
  129. package/dist/components/groups/editor.js.map +1 -1
  130. package/dist/components/groups/entity-chips.d.ts +61 -0
  131. package/dist/components/groups/entity-chips.js +382 -0
  132. package/dist/components/groups/entity-chips.js.map +1 -0
  133. package/dist/components/groups/group-members.d.ts +29 -0
  134. package/dist/components/groups/group-members.js +474 -0
  135. package/dist/components/groups/group-members.js.map +1 -0
  136. package/dist/components/groups/header.js +53 -45
  137. package/dist/components/groups/header.js.map +1 -1
  138. package/dist/components/groups/index.d.ts +3 -1
  139. package/dist/components/groups/memberships.d.ts +3 -36
  140. package/dist/components/groups/memberships.js +105 -480
  141. package/dist/components/groups/memberships.js.map +1 -1
  142. package/dist/components/groups/scoped.d.ts +23 -0
  143. package/dist/components/groups/scoped.js +92 -0
  144. package/dist/components/groups/scoped.js.map +1 -0
  145. package/dist/components/media-folder-editor.d.ts +5 -0
  146. package/dist/components/media-folder-editor.js +419 -231
  147. package/dist/components/media-folder-editor.js.map +1 -1
  148. package/dist/components/sortable-list.d.ts +5 -1
  149. package/dist/components/sortable-list.js +97 -81
  150. package/dist/components/sortable-list.js.map +1 -1
  151. package/dist/components/video-mini-player.d.ts +4 -1
  152. package/dist/components/video-mini-player.js +77 -71
  153. package/dist/components/video-mini-player.js.map +1 -1
  154. package/dist/components/video-player.d.ts +4 -1
  155. package/dist/components/video-player.js +280 -276
  156. package/dist/components/video-player.js.map +1 -1
  157. package/dist/index.d.ts +2 -1
  158. package/dist/index.js +41 -34
  159. package/dist/locales/admin/de.js +80 -47
  160. package/dist/locales/admin/de.js.map +1 -1
  161. package/dist/locales/admin/en.d.ts +74 -41
  162. package/dist/locales/admin/en.js +80 -47
  163. package/dist/locales/admin/en.js.map +1 -1
  164. package/dist/locales/admin/es.js +80 -47
  165. package/dist/locales/admin/es.js.map +1 -1
  166. package/dist/locales/admin/ja.js +80 -47
  167. package/dist/locales/admin/ja.js.map +1 -1
  168. package/dist/locales/admin/ko.js +80 -47
  169. package/dist/locales/admin/ko.js.map +1 -1
  170. package/dist/locales/admin/zh.js +80 -47
  171. package/dist/locales/admin/zh.js.map +1 -1
  172. package/dist/locales/de.js +1 -0
  173. package/dist/locales/de.js.map +1 -1
  174. package/dist/locales/discovery/de.js +25 -2
  175. package/dist/locales/discovery/de.js.map +1 -1
  176. package/dist/locales/discovery/en.d.ts +24 -1
  177. package/dist/locales/discovery/en.js +25 -2
  178. package/dist/locales/discovery/en.js.map +1 -1
  179. package/dist/locales/discovery/es.js +25 -2
  180. package/dist/locales/discovery/es.js.map +1 -1
  181. package/dist/locales/discovery/ja.js +25 -2
  182. package/dist/locales/discovery/ja.js.map +1 -1
  183. package/dist/locales/discovery/ko.js +25 -2
  184. package/dist/locales/discovery/ko.js.map +1 -1
  185. package/dist/locales/discovery/zh.js +25 -2
  186. package/dist/locales/discovery/zh.js.map +1 -1
  187. package/dist/locales/en.d.ts +119 -44
  188. package/dist/locales/en.js +1 -0
  189. package/dist/locales/en.js.map +1 -1
  190. package/dist/locales/es.js +1 -0
  191. package/dist/locales/es.js.map +1 -1
  192. package/dist/locales/groups/de.js +22 -4
  193. package/dist/locales/groups/de.js.map +1 -1
  194. package/dist/locales/groups/en.d.ts +20 -2
  195. package/dist/locales/groups/en.js +22 -4
  196. package/dist/locales/groups/en.js.map +1 -1
  197. package/dist/locales/groups/es.js +22 -4
  198. package/dist/locales/groups/es.js.map +1 -1
  199. package/dist/locales/groups/ja.js +22 -4
  200. package/dist/locales/groups/ja.js.map +1 -1
  201. package/dist/locales/groups/ko.js +22 -4
  202. package/dist/locales/groups/ko.js.map +1 -1
  203. package/dist/locales/groups/zh.js +22 -4
  204. package/dist/locales/groups/zh.js.map +1 -1
  205. package/dist/locales/ja.js +1 -0
  206. package/dist/locales/ja.js.map +1 -1
  207. package/dist/locales/ko.js +1 -0
  208. package/dist/locales/ko.js.map +1 -1
  209. package/dist/locales/zh.js +1 -0
  210. package/dist/locales/zh.js.map +1 -1
  211. package/dist/react/discovery.d.ts +36 -17
  212. package/dist/react/discovery.js +305 -221
  213. package/dist/react/discovery.js.map +1 -1
  214. package/dist/react/groups.d.ts +19 -3
  215. package/dist/react/groups.js +49 -22
  216. package/dist/react/groups.js.map +1 -1
  217. package/dist/react/index.d.ts +7 -4
  218. package/dist/react/page-notices.d.ts +13 -0
  219. package/dist/react/page-notices.js +38 -0
  220. package/dist/react/page-notices.js.map +1 -0
  221. package/dist/react/post-reads.d.ts +23 -0
  222. package/dist/react/post-reads.js +90 -0
  223. package/dist/react/post-reads.js.map +1 -0
  224. package/dist/react/remembered-sort.d.ts +5 -0
  225. package/dist/react/remembered-sort.js +29 -0
  226. package/dist/react/remembered-sort.js.map +1 -0
  227. package/dist/react/resources.d.ts +3 -1
  228. package/dist/react/resources.js +6 -2
  229. package/dist/react/resources.js.map +1 -1
  230. package/dist/react/stats.d.ts +3 -7
  231. package/dist/react/stats.js +2 -6
  232. package/dist/react/stats.js.map +1 -1
  233. package/dist/react/use-engagement.d.ts +28 -0
  234. package/dist/react/use-engagement.js +226 -0
  235. package/dist/react/use-engagement.js.map +1 -0
  236. package/dist/react/use-resource.d.ts +4 -3
  237. package/dist/react/use-resource.js +2 -1
  238. package/dist/react/use-resource.js.map +1 -1
  239. package/dist/react.js +29 -26
  240. package/dist/styles.css +1 -1
  241. package/dist/ui/dialog.d.ts +2 -1
  242. package/dist/ui/dialog.js +23 -20
  243. package/dist/ui/dialog.js.map +1 -1
  244. package/dist/urls/index.d.ts +1 -1
  245. package/dist/urls.js +2 -2
  246. package/dist/urls.js.map +1 -1
  247. package/package.json +1 -1
  248. package/dist/components/admin/page-review.d.ts +0 -13
  249. package/dist/components/admin/page-review.js +0 -225
  250. package/dist/components/admin/page-review.js.map +0 -1
  251. package/dist/react/page-review.d.ts +0 -14
  252. package/dist/react/page-review.js +0 -37
  253. package/dist/react/page-review.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"favorites.js","names":[],"sources":["../../../src/client/content/favorites.ts"],"sourcesContent":["import type { FavoriteState, InteractionPage } from \"../generated/wire.js\";\nimport type { Http } from \"../http.js\";\nimport { query, type AccessMode } from \"../discovery.js\";\nimport { call } from \"../route.js\";\nimport type { Target } from \"./types.js\";\n\n/** A page of the caller's favorites or reactions. */\nexport interface MineQuery {\n /** contents (the default) or groups. */\n target?: \"contents\" | \"entities\";\n /** One content kind or group kind. */\n kind?: string;\n /** The group kinds each card names; every kind with a page by default. */\n card_entities?: readonly string[];\n cursor?: string;\n limit?: number;\n language?: string;\n display_language?: string;\n mode?: AccessMode;\n}\n\n/** Favorites: the target's count for everyone, the signed-in caller's own. */\nexport class FavoritesClient {\n constructor(private readonly http: Http) {}\n\n /** The target's favorite count and whether the caller favorited it (never, signed out). */\n get(t: Target, signal?: AbortSignal): Promise<FavoriteState> {\n const o = { params: { id: t.id }, signal };\n return t.type === \"entities\" ? call(this.http, \"GET\", \"/entities/{id}/favorite\", o) : call(this.http, \"GET\", \"/contents/{id}/favorite\", { ...o, query: { version: t.version } });\n }\n /** Favorites or unfavorites the target (signed in); repeating is a no-op. Resolves with the new state and count. */\n async set(t: Target, favorited: boolean): Promise<FavoriteState> {\n const emit = this.http.captureChanges();\n const method = favorited ? \"POST\" : \"DELETE\";\n const o = { params: { id: t.id } };\n const state: FavoriteState =\n t.type === \"entities\" ? await call(this.http, method, \"/entities/{id}/favorite\", o) : await call(this.http, method, \"/contents/{id}/favorite\", { ...o, query: { version: t.version } });\n emit({ type: \"favorite.changed\", target: t, favorited: state.favorited, count: state.count });\n return state;\n }\n /** The caller's favorites, most recent first: content cards or groups. */\n mine(q: MineQuery = {}, signal?: AbortSignal): Promise<InteractionPage> {\n return call(this.http, \"GET\", \"/me/favorites\", { query: query(q) as never, signal });\n }\n}\n"],"mappings":";;;AAsBA,IAAa,IAAb,MAA6B;CACE;CAA7B,YAAY,GAA6B;EAAZ,KAAA,OAAA;CAAa;CAG1C,IAAI,GAAW,GAA8C;EAC3D,IAAM,IAAI;GAAE,QAAQ,EAAE,IAAI,EAAE,GAAG;GAAG;EAAO;EACzC,OAAO,EAAE,SAAS,aAAa,EAAK,KAAK,MAAM,OAAO,2BAA2B,CAAC,IAAI,EAAK,KAAK,MAAM,OAAO,2BAA2B;GAAE,GAAG;GAAG,OAAO,EAAE,SAAS,EAAE,QAAQ;EAAE,CAAC;CACjL;CAEA,MAAM,IAAI,GAAW,GAA4C;EAC/D,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAS,IAAY,SAAS,UAC9B,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,GAC3B,IACJ,EAAE,SAAS,aAAa,MAAM,EAAK,KAAK,MAAM,GAAQ,2BAA2B,CAAC,IAAI,MAAM,EAAK,KAAK,MAAM,GAAQ,2BAA2B;GAAE,GAAG;GAAG,OAAO,EAAE,SAAS,EAAE,QAAQ;EAAE,CAAC;EAExL,OADA,EAAK;GAAE,MAAM;GAAoB,QAAQ;GAAG,WAAW,EAAM;GAAW,OAAO,EAAM;EAAM,CAAC,GACrF;CACT;CAEA,KAAK,IAAe,CAAC,GAAG,GAAgD;EACtE,OAAO,EAAK,KAAK,MAAM,OAAO,iBAAiB;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACrF;AACF"}
1
+ {"version":3,"file":"favorites.js","names":[],"sources":["../../../src/client/content/favorites.ts"],"sourcesContent":["import type { FavoriteState, InteractionPage } from \"../generated/wire.js\";\nimport type { Http } from \"../http.js\";\nimport { query, type AccessMode } from \"../discovery.js\";\nimport { call } from \"../route.js\";\nimport type { Target } from \"./types.js\";\n\n/** A page of the caller's favorites or reactions. */\nexport interface MineQuery {\n /** contents (the default) or groups. */\n target?: \"contents\" | \"entities\";\n /** One content kind or group kind. */\n kind?: string;\n /** The group kinds each card names; every kind with a page by default. */\n card_entities?: readonly string[];\n cursor?: string;\n limit?: number;\n language?: string;\n display_language?: string;\n mode?: AccessMode;\n /** Counts for the caller's matching content selection, on the first page. */\n summary?: boolean;\n}\n\n/** Favorites: the target's count for everyone, the signed-in caller's own. */\nexport class FavoritesClient {\n constructor(private readonly http: Http) {}\n\n /** The target's favorite count and whether the caller favorited it (never, signed out). */\n get(t: Target, signal?: AbortSignal): Promise<FavoriteState> {\n const o = { params: { id: t.id }, signal };\n return t.type === \"entities\" ? call(this.http, \"GET\", \"/entities/{id}/favorite\", o) : call(this.http, \"GET\", \"/contents/{id}/favorite\", { ...o, query: { version: t.version } });\n }\n /** Favorites or unfavorites the target (signed in); repeating is a no-op. Resolves with the new state and count. */\n async set(t: Target, favorited: boolean): Promise<FavoriteState> {\n const emit = this.http.captureChanges();\n const method = favorited ? \"POST\" : \"DELETE\";\n const o = { params: { id: t.id } };\n const state: FavoriteState =\n t.type === \"entities\" ? await call(this.http, method, \"/entities/{id}/favorite\", o) : await call(this.http, method, \"/contents/{id}/favorite\", { ...o, query: { version: t.version } });\n emit({ type: \"favorite.changed\", target: t, favorited: state.favorited, count: state.count });\n return state;\n }\n /** The caller's favorites, most recent first: content cards or groups. */\n mine(q: MineQuery = {}, signal?: AbortSignal): Promise<InteractionPage> {\n return call(this.http, \"GET\", \"/me/favorites\", { query: query(q) as never, signal });\n }\n}\n"],"mappings":";;;AAwBA,IAAa,IAAb,MAA6B;CACE;CAA7B,YAAY,GAA6B;EAAZ,KAAA,OAAA;CAAa;CAG1C,IAAI,GAAW,GAA8C;EAC3D,IAAM,IAAI;GAAE,QAAQ,EAAE,IAAI,EAAE,GAAG;GAAG;EAAO;EACzC,OAAO,EAAE,SAAS,aAAa,EAAK,KAAK,MAAM,OAAO,2BAA2B,CAAC,IAAI,EAAK,KAAK,MAAM,OAAO,2BAA2B;GAAE,GAAG;GAAG,OAAO,EAAE,SAAS,EAAE,QAAQ;EAAE,CAAC;CACjL;CAEA,MAAM,IAAI,GAAW,GAA4C;EAC/D,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAS,IAAY,SAAS,UAC9B,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,GAC3B,IACJ,EAAE,SAAS,aAAa,MAAM,EAAK,KAAK,MAAM,GAAQ,2BAA2B,CAAC,IAAI,MAAM,EAAK,KAAK,MAAM,GAAQ,2BAA2B;GAAE,GAAG;GAAG,OAAO,EAAE,SAAS,EAAE,QAAQ;EAAE,CAAC;EAExL,OADA,EAAK;GAAE,MAAM;GAAoB,QAAQ;GAAG,WAAW,EAAM;GAAW,OAAO,EAAM;EAAM,CAAC,GACrF;CACT;CAEA,KAAK,IAAe,CAAC,GAAG,GAAgD;EACtE,OAAO,EAAK,KAAK,MAAM,OAAO,iBAAiB;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACrF;AACF"}
@@ -114,6 +114,9 @@ export type ContentChange =
114
114
  type: "contentFilters.changed";
115
115
  } | {
116
116
  type: "history.changed";
117
+ } | {
118
+ type: "engagement.changed";
119
+ ids: string[];
117
120
  }
118
121
  /** A search ran or recent searches were cleared. */
119
122
  | {
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../../src/client/content/types.ts"],"sourcesContent":["import type { CommentBan, CommentStanding, Comment, Content, Poll, ReactionCounts, ResolveInput } from \"../generated/wire.js\";\n\n/** What an interaction targets: a content item (optionally one of its versions) or a group. */\nexport interface Target {\n type: \"contents\" | \"entities\";\n id: string;\n /** One version of a content item. */\n version?: string;\n}\n\n/** The same target. */\nexport function sameTarget(a?: Target, b?: Target): boolean {\n return !!a && !!b && a.type === b.type && a.id === b.id && (a.version ?? \"\") === (b.version ?? \"\");\n}\n\n/** A reaction: like 1, dislike -1, none 0. */\nexport type Reaction = -1 | 0 | 1;\n\n/** The route verb that sets a like or dislike; clearing is DELETE …/reaction. */\nexport function reactionVerb(value: -1 | 1): \"like\" | \"dislike\" {\n return value === 1 ? \"like\" : \"dislike\";\n}\n\n/** Comment order: newest (the default), likes (most liked) or best (Wilson lower bound). */\nexport type Sort = \"newest\" | \"likes\" | \"best\";\n\n/** A ban route family: \"owner\" bans from the caller's own content, \"global\" from the whole site. */\nexport type BanScope = CommentStanding[\"ban_scopes\"][number];\n\n/** What the review queue holds: comments and content items. */\nexport type HeldKind = \"comment\" | \"content\";\n\n/** The moderation rules: banned words or IP bans. */\nexport type RuleSet = \"words\" | \"ips\";\n\n/** A reviewer's decision on a held item. */\nexport type Decision = Exclude<ResolveInput[\"decision\"], \"review\">;\n\n/** A content-module mutation made through the client. */\nexport type ContentChange =\n /** Created or edited: the item as the server now answers it. */\n | { type: \"content.saved\"; content: Content }\n /** A version changed: refetch the item. */\n | { type: \"content.changed\"; id: string }\n | { type: \"content.deleted\"; id: string }\n /** target is the commented item. */\n | { type: \"comment.created\"; target: Target; comment: Comment }\n | { type: \"comment.updated\"; comment: Comment }\n | { type: \"comment.deleted\"; id: string }\n | { type: \"comment.restored\"; id: string }\n | { type: \"comment.reacted\"; id: string; counts: ReactionCounts }\n | { type: \"reaction.changed\"; target: Target; counts: ReactionCounts }\n /** count is absent where the target's kind's locked view hides it. */\n | { type: \"favorite.changed\"; target: Target; favorited: boolean; count?: number }\n /** Created, updated, voted or answered: the poll as the server now answers it. */\n | { type: \"poll.created\"; poll: Poll }\n | { type: \"poll.updated\"; poll: Poll }\n /** An option or image changed: refetch the poll. */\n | { type: \"poll.changed\"; id: string }\n | { type: \"poll.deleted\"; id: string }\n | { type: \"ban.saved\"; scope: BanScope; ban: CommentBan }\n | { type: \"ban.lifted\"; scope: BanScope; user: string }\n | { type: \"moderation.resolved\"; kind: HeldKind; id: string; decision: Decision }\n /** Banned words or IP bans changed. */\n | { type: \"rules.changed\"; rules: RuleSet }\n /** A version's reader metadata changed: its reader plan reads again. */\n | { type: \"reader.changed\"; content: string; version: string }\n | { type: \"entities.changed\" }\n /** The reader's content filters changed: every list reads again. */\n | { type: \"contentFilters.changed\" }\n | { type: \"history.changed\" }\n /** A search ran or recent searches were cleared. */\n | { type: \"searches.changed\" }\n /** The reader's keys changed (a join, a purchase the host reports): reads of access re-run. */\n | { type: \"access.changed\" };\n"],"mappings":";AAWA,SAAgB,EAAW,GAAY,GAAqB;CAC1D,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,SAAS,EAAE,WAAW;AACjG;AAMA,SAAgB,EAAa,GAAmC;CAC9D,OAAO,MAAU,IAAI,SAAS;AAChC"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../src/client/content/types.ts"],"sourcesContent":["import type { CommentBan, CommentStanding, Comment, Content, Poll, ReactionCounts, ResolveInput } from \"../generated/wire.js\";\n\n/** What an interaction targets: a content item (optionally one of its versions) or a group. */\nexport interface Target {\n type: \"contents\" | \"entities\";\n id: string;\n /** One version of a content item. */\n version?: string;\n}\n\n/** The same target. */\nexport function sameTarget(a?: Target, b?: Target): boolean {\n return !!a && !!b && a.type === b.type && a.id === b.id && (a.version ?? \"\") === (b.version ?? \"\");\n}\n\n/** A reaction: like 1, dislike -1, none 0. */\nexport type Reaction = -1 | 0 | 1;\n\n/** The route verb that sets a like or dislike; clearing is DELETE …/reaction. */\nexport function reactionVerb(value: -1 | 1): \"like\" | \"dislike\" {\n return value === 1 ? \"like\" : \"dislike\";\n}\n\n/** Comment order: newest (the default), likes (most liked) or best (Wilson lower bound). */\nexport type Sort = \"newest\" | \"likes\" | \"best\";\n\n/** A ban route family: \"owner\" bans from the caller's own content, \"global\" from the whole site. */\nexport type BanScope = CommentStanding[\"ban_scopes\"][number];\n\n/** What the review queue holds: comments and content items. */\nexport type HeldKind = \"comment\" | \"content\";\n\n/** The moderation rules: banned words or IP bans. */\nexport type RuleSet = \"words\" | \"ips\";\n\n/** A reviewer's decision on a held item. */\nexport type Decision = Exclude<ResolveInput[\"decision\"], \"review\">;\n\n/** A content-module mutation made through the client. */\nexport type ContentChange =\n /** Created or edited: the item as the server now answers it. */\n | { type: \"content.saved\"; content: Content }\n /** A version changed: refetch the item. */\n | { type: \"content.changed\"; id: string }\n | { type: \"content.deleted\"; id: string }\n /** target is the commented item. */\n | { type: \"comment.created\"; target: Target; comment: Comment }\n | { type: \"comment.updated\"; comment: Comment }\n | { type: \"comment.deleted\"; id: string }\n | { type: \"comment.restored\"; id: string }\n | { type: \"comment.reacted\"; id: string; counts: ReactionCounts }\n | { type: \"reaction.changed\"; target: Target; counts: ReactionCounts }\n /** count is absent where the target's kind's locked view hides it. */\n | { type: \"favorite.changed\"; target: Target; favorited: boolean; count?: number }\n /** Created, updated, voted or answered: the poll as the server now answers it. */\n | { type: \"poll.created\"; poll: Poll }\n | { type: \"poll.updated\"; poll: Poll }\n /** An option or image changed: refetch the poll. */\n | { type: \"poll.changed\"; id: string }\n | { type: \"poll.deleted\"; id: string }\n | { type: \"ban.saved\"; scope: BanScope; ban: CommentBan }\n | { type: \"ban.lifted\"; scope: BanScope; user: string }\n | { type: \"moderation.resolved\"; kind: HeldKind; id: string; decision: Decision }\n /** Banned words or IP bans changed. */\n | { type: \"rules.changed\"; rules: RuleSet }\n /** A version's reader metadata changed: its reader plan reads again. */\n | { type: \"reader.changed\"; content: string; version: string }\n | { type: \"entities.changed\" }\n /** The reader's content filters changed: every list reads again. */\n | { type: \"contentFilters.changed\" }\n | { type: \"history.changed\" }\n | { type: \"engagement.changed\"; ids: string[] }\n /** A search ran or recent searches were cleared. */\n | { type: \"searches.changed\" }\n /** The reader's keys changed (a join, a purchase the host reports): reads of access re-run. */\n | { type: \"access.changed\" };\n"],"mappings":";AAWA,SAAgB,EAAW,GAAY,GAAqB;CAC1D,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,SAAS,EAAE,WAAW;AACjG;AAMA,SAAgB,EAAa,GAAmC;CAC9D,OAAO,MAAU,IAAI,SAAS;AAChC"}
@@ -1,4 +1,4 @@
1
- import { CatalogText, Content, ContentInput, ContentPatch, Creator, InlineImage, Segment, Version, VersionInput } from './generated/wire.js';
1
+ import { CatalogText, Content, ContentInput, ContentPatch, Creator, InlineImage, ManageCount, Segment, Version, VersionInput } from './generated/wire.js';
2
2
  import { Http } from './http.js';
3
3
  import { RouteQuery } from './route.js';
4
4
  /** The URL scheme of an image reference in a content body. */
@@ -15,6 +15,10 @@ export declare const imageRefs: () => RegExp;
15
15
  export type ManageQuery = RouteQuery<"GET", "/manage"> & {
16
16
  kind?: string;
17
17
  };
18
+ /** The /manage/{kind} filters a count takes. */
19
+ export type ManageCountQuery = RouteQuery<"GET", "/manage/{kind}/count"> & {
20
+ kind: string;
21
+ };
18
22
  /**
19
23
  * Content items: a viewer's reads, and the writes of their creators, their
20
24
  * owner group's editors and root:content:write holders.
@@ -27,6 +31,8 @@ export declare class ContentsClient {
27
31
  version(id: string, vid: string, language?: string, signal?: AbortSignal): Promise<Version>;
28
32
  /** Items the caller manages, newest first: all for root:content:write holders, else theirs or an owner group's. */
29
33
  manage(q?: ManageQuery, signal?: AbortSignal): Promise<Content[]>;
34
+ /** How many items of a kind the caller manages under these filters: exact up to 10,000, then truncated. */
35
+ manageCount(q: ManageCountQuery, signal?: AbortSignal): Promise<ManageCount>;
30
36
  /** Creates a draft. */
31
37
  create(input: ContentInput): Promise<Content>;
32
38
  update(id: string, patch: ContentPatch): Promise<Content>;
@@ -33,6 +33,14 @@ var t = "contentkit:", n = (e) => t + e, r = () => /contentkit:(i-[0-9a-f]{8}-[0
33
33
  signal: n
34
34
  });
35
35
  }
36
+ manageCount(t, n) {
37
+ let { kind: r, ...i } = t;
38
+ return e(this.http, "GET", "/manage/{kind}/count", {
39
+ params: { kind: r },
40
+ query: i,
41
+ signal: n
42
+ });
43
+ }
36
44
  create(t) {
37
45
  return this.write(e(this.http, "POST", "/contents", { body: t }));
38
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"contents.js","names":[],"sources":["../../src/client/contents.ts"],"sourcesContent":["import type {\n CatalogText,\n Content,\n ContentInput,\n ContentPatch,\n Creator,\n InlineImage,\n Segment,\n Version,\n VersionInput,\n} from \"./generated/wire.js\";\nimport type { Http } from \"./http.js\";\nimport { call, type RouteQuery } from \"./route.js\";\n\n/** The URL scheme of an image reference in a content body. */\nexport const IMAGE_SCHEME = \"contentkit:\";\n\n/**\n * The reference a body stores for one of its images, by name\n * (\"contentkit:i-{uuid}\"), where the image's URL would go: reads resolve it to\n * the image's current public file (`Content.images`).\n */\nexport const imageRef = (name: string) => IMAGE_SCHEME + name;\n\n/** Matches every image reference; the name is group 1. */\nexport const imageRefs = () => /contentkit:(i-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/g;\n\n/** Management filters; kind selects /manage/{kind}, otherwise /manage. */\nexport type ManageQuery = RouteQuery<\"GET\", \"/manage\"> & { kind?: string };\n\n/**\n * Content items: a viewer's reads, and the writes of their creators, their\n * owner group's editors and root:content:write holders.\n */\nexport class ContentsClient {\n constructor(private readonly http: Http) {}\n\n /** The item as the caller sees it; text in language, else the site's first, else any. */\n get(id: string, language?: string, signal?: AbortSignal): Promise<Content> {\n return call(this.http, \"GET\", \"/contents/{id}\", { params: { id }, query: { language }, signal });\n }\n version(id: string, vid: string, language?: string, signal?: AbortSignal): Promise<Version> {\n return call(this.http, \"GET\", \"/contents/{id}/versions/{vid}\", { params: { id, vid }, query: { language }, signal });\n }\n /** Items the caller manages, newest first: all for root:content:write holders, else theirs or an owner group's. */\n manage(q: ManageQuery = {}, signal?: AbortSignal): Promise<Content[]> {\n const { kind, ...query } = q;\n return kind\n ? call(this.http, \"GET\", \"/manage/{kind}\", { params: { kind }, query, signal })\n : call(this.http, \"GET\", \"/manage\", { query, signal });\n }\n /** Creates a draft. */\n create(input: ContentInput): Promise<Content> {\n return this.write(call(this.http, \"POST\", \"/contents\", { body: input }));\n }\n update(id: string, patch: ContentPatch): Promise<Content> {\n return this.write(call(this.http, \"PATCH\", \"/contents/{id}\", { params: { id }, body: patch }));\n }\n /** Sets the text in one language; moderation \"held\" when the moderator holds the edit. */\n putText(id: string, language: string, text: CatalogText): Promise<Content> {\n return this.write(call(this.http, \"PUT\", \"/contents/{id}/text/{language}\", { params: { id, language }, body: text }));\n }\n deleteText(id: string, language: string): Promise<Content> {\n return this.write(call(this.http, \"DELETE\", \"/contents/{id}/text/{language}\", { params: { id, language } }));\n }\n setCreators(id: string, creators: Creator[]): Promise<Content> {\n return this.write(call(this.http, \"PUT\", \"/contents/{id}/creators\", { params: { id }, body: { creators } }));\n }\n /** Publishes now, or schedules for at; moderation \"held\" when the moderator holds it. */\n publish(id: string, at?: string): Promise<Content> {\n return this.write(call(this.http, \"POST\", \"/contents/{id}/publish\", { params: { id }, body: { publish_at: at } }));\n }\n unpublish(id: string): Promise<Content> {\n return this.write(call(this.http, \"POST\", \"/contents/{id}/unpublish\", { params: { id } }));\n }\n async remove(id: string): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/contents/{id}\", { params: { id } });\n emit({ type: \"content.deleted\", id });\n }\n restore(id: string): Promise<Content> {\n return this.write(call(this.http, \"POST\", \"/contents/{id}/restore\", { params: { id } }));\n }\n /** Selects a version's cover by the name (\"i-{uuid}\") of one of its cover uploads; null returns to its first. */\n setCover(id: string, vid: string, image: string | null): Promise<Version> {\n return this.updateVersion(id, vid, { cover: image ?? \"\" });\n }\n /**\n * A body image uploaded to version vid (its private files), copied into\n * every other version: the reference to store in the body and a URL that shows\n * it to the editor now (null while none exists).\n */\n inlineImage(id: string, vid: string, image: string, signal?: AbortSignal): Promise<InlineImage> {\n return call(this.http, \"POST\", \"/contents/{id}/images\", { params: { id }, body: { image, version: vid }, signal });\n }\n addVersion(id: string, input: VersionInput): Promise<Version> {\n return this.writeVersion(id, call(this.http, \"POST\", \"/contents/{id}/versions\", { params: { id }, body: input }));\n }\n updateVersion(id: string, vid: string, input: VersionInput): Promise<Version> {\n return this.writeVersion(id, call(this.http, \"PATCH\", \"/contents/{id}/versions/{vid}\", { params: { id, vid }, body: input }));\n }\n async removeVersion(id: string, vid: string): Promise<void> {\n await this.writeVersion(id, call(this.http, \"DELETE\", \"/contents/{id}/versions/{vid}\", { params: { id, vid } }));\n }\n /** Orders the versions: ids lists each version that is not deleted, first first. */\n orderVersions(id: string, ids: string[]): Promise<Content> {\n return this.write(call(this.http, \"PUT\", \"/contents/{id}/versions/order\", { params: { id }, body: { ids } }));\n }\n /** Replaces a version's segments (chapters). */\n setSegments(id: string, vid: string, segments: Segment[]): Promise<Version> {\n return this.writeVersion(id, call(this.http, \"PUT\", \"/contents/{id}/versions/{vid}/segments\", { params: { id, vid }, body: { segments } }));\n }\n\n private async write(p: Promise<Content>): Promise<Content> {\n const emit = this.http.captureChanges();\n const content = await p;\n emit({ type: \"content.saved\", content });\n return content;\n }\n\n private async writeVersion<T>(id: string, p: Promise<T>): Promise<T> {\n const emit = this.http.captureChanges();\n const out = await p;\n emit({ type: \"content.changed\", id });\n return out;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"contents.js","names":[],"sources":["../../src/client/contents.ts"],"sourcesContent":["import type {\n CatalogText,\n Content,\n ContentInput,\n ContentPatch,\n Creator,\n InlineImage,\n ManageCount,\n Segment,\n Version,\n VersionInput,\n} from \"./generated/wire.js\";\nimport type { Http } from \"./http.js\";\nimport { call, type RouteQuery } from \"./route.js\";\n\n/** The URL scheme of an image reference in a content body. */\nexport const IMAGE_SCHEME = \"contentkit:\";\n\n/**\n * The reference a body stores for one of its images, by name\n * (\"contentkit:i-{uuid}\"), where the image's URL would go: reads resolve it to\n * the image's current public file (`Content.images`).\n */\nexport const imageRef = (name: string) => IMAGE_SCHEME + name;\n\n/** Matches every image reference; the name is group 1. */\nexport const imageRefs = () => /contentkit:(i-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/g;\n\n/** Management filters; kind selects /manage/{kind}, otherwise /manage. */\nexport type ManageQuery = RouteQuery<\"GET\", \"/manage\"> & { kind?: string };\n\n/** The /manage/{kind} filters a count takes. */\nexport type ManageCountQuery = RouteQuery<\"GET\", \"/manage/{kind}/count\"> & { kind: string };\n\n/**\n * Content items: a viewer's reads, and the writes of their creators, their\n * owner group's editors and root:content:write holders.\n */\nexport class ContentsClient {\n constructor(private readonly http: Http) {}\n\n /** The item as the caller sees it; text in language, else the site's first, else any. */\n get(id: string, language?: string, signal?: AbortSignal): Promise<Content> {\n return call(this.http, \"GET\", \"/contents/{id}\", { params: { id }, query: { language }, signal });\n }\n version(id: string, vid: string, language?: string, signal?: AbortSignal): Promise<Version> {\n return call(this.http, \"GET\", \"/contents/{id}/versions/{vid}\", { params: { id, vid }, query: { language }, signal });\n }\n /** Items the caller manages, newest first: all for root:content:write holders, else theirs or an owner group's. */\n manage(q: ManageQuery = {}, signal?: AbortSignal): Promise<Content[]> {\n const { kind, ...query } = q;\n return kind\n ? call(this.http, \"GET\", \"/manage/{kind}\", { params: { kind }, query, signal })\n : call(this.http, \"GET\", \"/manage\", { query, signal });\n }\n /** How many items of a kind the caller manages under these filters: exact up to 10,000, then truncated. */\n manageCount(q: ManageCountQuery, signal?: AbortSignal): Promise<ManageCount> {\n const { kind, ...query } = q;\n return call(this.http, \"GET\", \"/manage/{kind}/count\", { params: { kind }, query, signal });\n }\n /** Creates a draft. */\n create(input: ContentInput): Promise<Content> {\n return this.write(call(this.http, \"POST\", \"/contents\", { body: input }));\n }\n update(id: string, patch: ContentPatch): Promise<Content> {\n return this.write(call(this.http, \"PATCH\", \"/contents/{id}\", { params: { id }, body: patch }));\n }\n /** Sets the text in one language; moderation \"held\" when the moderator holds the edit. */\n putText(id: string, language: string, text: CatalogText): Promise<Content> {\n return this.write(call(this.http, \"PUT\", \"/contents/{id}/text/{language}\", { params: { id, language }, body: text }));\n }\n deleteText(id: string, language: string): Promise<Content> {\n return this.write(call(this.http, \"DELETE\", \"/contents/{id}/text/{language}\", { params: { id, language } }));\n }\n setCreators(id: string, creators: Creator[]): Promise<Content> {\n return this.write(call(this.http, \"PUT\", \"/contents/{id}/creators\", { params: { id }, body: { creators } }));\n }\n /** Publishes now, or schedules for at; moderation \"held\" when the moderator holds it. */\n publish(id: string, at?: string): Promise<Content> {\n return this.write(call(this.http, \"POST\", \"/contents/{id}/publish\", { params: { id }, body: { publish_at: at } }));\n }\n unpublish(id: string): Promise<Content> {\n return this.write(call(this.http, \"POST\", \"/contents/{id}/unpublish\", { params: { id } }));\n }\n async remove(id: string): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/contents/{id}\", { params: { id } });\n emit({ type: \"content.deleted\", id });\n }\n restore(id: string): Promise<Content> {\n return this.write(call(this.http, \"POST\", \"/contents/{id}/restore\", { params: { id } }));\n }\n /** Selects a version's cover by the name (\"i-{uuid}\") of one of its cover uploads; null returns to its first. */\n setCover(id: string, vid: string, image: string | null): Promise<Version> {\n return this.updateVersion(id, vid, { cover: image ?? \"\" });\n }\n /**\n * A body image uploaded to version vid (its private files), copied into\n * every other version: the reference to store in the body and a URL that shows\n * it to the editor now (null while none exists).\n */\n inlineImage(id: string, vid: string, image: string, signal?: AbortSignal): Promise<InlineImage> {\n return call(this.http, \"POST\", \"/contents/{id}/images\", { params: { id }, body: { image, version: vid }, signal });\n }\n addVersion(id: string, input: VersionInput): Promise<Version> {\n return this.writeVersion(id, call(this.http, \"POST\", \"/contents/{id}/versions\", { params: { id }, body: input }));\n }\n updateVersion(id: string, vid: string, input: VersionInput): Promise<Version> {\n return this.writeVersion(id, call(this.http, \"PATCH\", \"/contents/{id}/versions/{vid}\", { params: { id, vid }, body: input }));\n }\n async removeVersion(id: string, vid: string): Promise<void> {\n await this.writeVersion(id, call(this.http, \"DELETE\", \"/contents/{id}/versions/{vid}\", { params: { id, vid } }));\n }\n /** Orders the versions: ids lists each version that is not deleted, first first. */\n orderVersions(id: string, ids: string[]): Promise<Content> {\n return this.write(call(this.http, \"PUT\", \"/contents/{id}/versions/order\", { params: { id }, body: { ids } }));\n }\n /** Replaces a version's segments (chapters). */\n setSegments(id: string, vid: string, segments: Segment[]): Promise<Version> {\n return this.writeVersion(id, call(this.http, \"PUT\", \"/contents/{id}/versions/{vid}/segments\", { params: { id, vid }, body: { segments } }));\n }\n\n private async write(p: Promise<Content>): Promise<Content> {\n const emit = this.http.captureChanges();\n const content = await p;\n emit({ type: \"content.saved\", content });\n return content;\n }\n\n private async writeVersion<T>(id: string, p: Promise<T>): Promise<T> {\n const emit = this.http.captureChanges();\n const out = await p;\n emit({ type: \"content.changed\", id });\n return out;\n }\n}\n"],"mappings":"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"}
@@ -1,15 +1,17 @@
1
- import { ActivityContexts, ActivityTarget, ContentFilters, ContentFiltersUpdate, ContentPage, DailyReleases, ExposureInput, RecentSearches, ReleaseDates, SignalInput, Typeahead } from './generated/wire.js';
1
+ import { ActivityContexts, ActivityTarget, ContentFilters, ContentFiltersUpdate, ContentPage, DailyReleases, EngagementSnapshot, ExposureInput, RecentSearches, ReleaseDates, SignalInput, Typeahead } from './generated/wire.js';
2
2
  import { Http } from './http.js';
3
3
  import { BrowserSearchHistory } from './browser-search-history.js';
4
4
  /** A popularity period. */
5
5
  export type Period = "7d" | "30d" | "90d" | "365d" | "all";
6
6
  /** A list's order; position orders by the first of `groups` (an ordered group). */
7
- export type ListSort = "newest" | "oldest" | "title" | "popular" | `popular:${Period}` | "top_rated" | `top_rated:${Period}` | "most_favorited" | "most_viewed" | "position" | "random";
7
+ export type ListSort = "newest" | "oldest" | "title" | "popular" | `popular:${Period}` | "top_rated" | `top_rated:${Period}` | "most_favorited" | "position" | "random";
8
8
  /** How locked contents list: marked (lock, the default) or left out (hide). */
9
9
  export type AccessMode = "lock" | "hide";
10
10
  /** Which contents a list holds. */
11
11
  export interface ContentFilterQuery {
12
12
  kind?: string;
13
+ /** Public card hydration under current domain/access/preferences; at most 100. */
14
+ ids?: readonly string[];
13
15
  /** Group ids every listed version is in. */
14
16
  groups?: readonly string[];
15
17
  /** Group ids no listed version is in. */
@@ -51,7 +53,13 @@ export interface PageQuery {
51
53
  cursor?: string;
52
54
  limit?: number;
53
55
  }
54
- export type ContentQuery = ContentFilterQuery & ReaderQuery & CardQuery & PageQuery & {
56
+ /** A numbered page from 1 instead of cursor; its summary then comes with every page. */
57
+ export interface NumberedPageQuery {
58
+ page?: number;
59
+ }
60
+ export type ContentQuery = ContentFilterQuery & ReaderQuery & CardQuery & PageQuery & NumberedPageQuery & {
61
+ /** Selection-wide metadata; requested only on the first page. */
62
+ summary?: boolean;
55
63
  sort?: ListSort;
56
64
  /** Inclusive UTC date (YYYY-MM-DD); requires activity_until, kind and sort=popular. */
57
65
  activity_from?: string;
@@ -71,10 +79,11 @@ export declare function popularQuery(period?: PopularPeriod | PopularDateRange,
71
79
  export declare function popularBetween(from: string, until: string, filters: PopularQuery & {
72
80
  kind: string;
73
81
  }): ContentQuery;
74
- export type SearchQuery = ContentFilterQuery & ReaderQuery & CardQuery & PageQuery & {
82
+ export type SearchQuery = ContentFilterQuery & ReaderQuery & CardQuery & PageQuery & NumberedPageQuery & {
75
83
  q: string;
76
84
  sort?: "relevance" | ListSort;
77
85
  personalize?: boolean;
86
+ summary?: boolean;
78
87
  /** Explicit legacy server-side anonymous history. Omit for public search without server history. */
79
88
  session?: string;
80
89
  };
@@ -86,6 +95,7 @@ export interface RecentSearchesQuery {
86
95
  }
87
96
  export type RailQuery = ContentFilterQuery & ReaderQuery & CardQuery & {
88
97
  limit?: number;
98
+ summary?: boolean;
89
99
  };
90
100
  export type ReleaseDatesQuery = ContentFilterQuery & ReaderQuery & PageQuery & {
91
101
  by?: "month" | "day";
@@ -100,6 +110,7 @@ export type DailyReleasesQuery = Omit<ContentFilterQuery, "released_on" | "tz">
100
110
  export type HistoryQuery = ReaderQuery & CardQuery & PageQuery & {
101
111
  kind?: string;
102
112
  status?: "seen" | "in_progress" | "completed";
113
+ summary?: boolean;
103
114
  };
104
115
  export interface TypeaheadQuery extends ReaderQuery {
105
116
  q: string;
@@ -110,6 +121,17 @@ export interface TypeaheadQuery extends ReaderQuery {
110
121
  /** Per section: 8 by default, at most 20. */
111
122
  limit?: number;
112
123
  }
124
+ /** Private editor navigation. Each requested section must be chosen explicitly. */
125
+ export interface AdminSuggestionsQuery {
126
+ q: string;
127
+ display_language?: string;
128
+ content_kinds?: readonly string[];
129
+ entity_kinds?: readonly string[];
130
+ include_contents: boolean;
131
+ include_entities: boolean;
132
+ /** Per section: 8 by default, at most 20. */
133
+ limit?: number;
134
+ }
113
135
  /** A query with its list parameters comma-joined, as discovery routes read them. */
114
136
  export declare function query(q: object): Record<string, string | number | boolean | readonly string[] | undefined>;
115
137
  /**
@@ -134,6 +156,8 @@ export declare class DiscoveryClient {
134
156
  }): Promise<void>;
135
157
  /** Contents and groups while the reader types. */
136
158
  typeahead(q: TypeaheadQuery, signal?: AbortSignal): Promise<Typeahead>;
159
+ /** Current names of authorized draft/hidden content and entities; no public search fallback. */
160
+ adminSuggestions(q: AdminSuggestionsQuery, signal?: AbortSignal): Promise<Typeahead>;
137
161
  /** Contents like one, of its kind unless q.kind names another. */
138
162
  similar(id: string, q?: RailQuery, signal?: AbortSignal): Promise<ContentPage>;
139
163
  /** For the signed-in reader. */
@@ -155,7 +179,12 @@ export declare class DiscoveryClient {
155
179
  }): Promise<void>;
156
180
  /** Capture server-owned access and eligibility at an observation's start. */
157
181
  activityContexts(targets: readonly ActivityTarget[], session?: string, language?: string | undefined): Promise<ActivityContexts>;
158
- /** Views and clicks; signed out, of the session named. */
182
+ /** Cumulative measured attention. Successful checkpoints refresh history/progress caches. */
183
+ engagement(snapshots: EngagementSnapshot[], o?: {
184
+ session?: string;
185
+ keepalive?: boolean;
186
+ }): Promise<void>;
187
+ /** Clicks and explicit feedback; signed out, of the visitor named. */
159
188
  signals(signals: SignalInput[], session?: string, o?: {
160
189
  keepalive?: boolean;
161
190
  }): Promise<void>;
@@ -19,6 +19,7 @@ function i(e, t, n) {
19
19
  }, n);
20
20
  }
21
21
  var a = /* @__PURE__ */ new Set([
22
+ "ids",
22
23
  "groups",
23
24
  "exclude_groups",
24
25
  "creators",
@@ -26,7 +27,8 @@ var a = /* @__PURE__ */ new Set([
26
27
  "tiers",
27
28
  "traits",
28
29
  "card_entities",
29
- "entity_kinds"
30
+ "entity_kinds",
31
+ "content_kinds"
30
32
  ]);
31
33
  function o(e) {
32
34
  let t = {};
@@ -46,7 +48,7 @@ var s = class {
46
48
  });
47
49
  }
48
50
  async search(t, n) {
49
- let r = t.cursor ? null : this.http.captureChanges(), i = await e(this.http, "GET", "/search", {
51
+ let r = t.cursor || (t.page ?? 1) > 1 ? null : this.http.captureChanges(), i = await e(this.http, "GET", "/search", {
50
52
  query: o(t),
51
53
  signal: n
52
54
  });
@@ -68,6 +70,12 @@ var s = class {
68
70
  signal: n
69
71
  });
70
72
  }
73
+ adminSuggestions(t, n) {
74
+ return e(this.http, "GET", "/manage/search-suggestions", {
75
+ query: o(t),
76
+ signal: n
77
+ });
78
+ }
71
79
  similar(t, n = {}, r) {
72
80
  return e(this.http, "GET", "/contents/{id}/similar", {
73
81
  params: { id: t },
@@ -125,6 +133,19 @@ var s = class {
125
133
  };
126
134
  return e(this.http, "POST", "/activity-contexts", { body: i });
127
135
  }
136
+ async engagement(t, n = {}) {
137
+ let r = this.http.captureChanges(), i = {
138
+ session: n.session,
139
+ snapshots: t
140
+ };
141
+ await e(this.http, "POST", "/engagement", {
142
+ body: i,
143
+ keepalive: n.keepalive
144
+ }), r({
145
+ type: "engagement.changed",
146
+ ids: [...new Set(t.map((e) => e.content_id))]
147
+ });
148
+ }
128
149
  signals(t, n, r = {}) {
129
150
  let i = {
130
151
  session: n,
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.js","names":[],"sources":["../../src/client/discovery.ts"],"sourcesContent":["import type {\n ActivityContexts,\n ActivityContextsInput,\n ActivityTarget,\n ContentFilters,\n ContentFiltersUpdate,\n ContentPage,\n DailyReleases,\n ExposureInput,\n Exposures,\n RecentSearches,\n ReleaseDates,\n SignalInput,\n Signals,\n Typeahead,\n} from \"./generated/wire.js\";\nimport type { Http } from \"./http.js\";\nimport { call, routeURL } from \"./route.js\";\nimport { browserSearchHistory, type BrowserSearchHistory } from \"./browser-search-history.js\";\n\n/** A popularity period. */\nexport type Period = \"7d\" | \"30d\" | \"90d\" | \"365d\" | \"all\";\n/** A list's order; position orders by the first of `groups` (an ordered group). */\nexport type ListSort = \"newest\" | \"oldest\" | \"title\" | \"popular\" | `popular:${Period}` | \"top_rated\" | `top_rated:${Period}` | \"most_favorited\" | \"most_viewed\" | \"position\" | \"random\";\n/** How locked contents list: marked (lock, the default) or left out (hide). */\nexport type AccessMode = \"lock\" | \"hide\";\n\n/** Which contents a list holds. */\nexport interface ContentFilterQuery {\n kind?: string;\n /** Group ids every listed version is in. */\n groups?: readonly string[];\n /** Group ids no listed version is in. */\n exclude_groups?: readonly string[];\n /** Only contents this group owns: a channel's feed. */\n owner_group?: string;\n /** User ids: only contents one of them is credited on. */\n creators?: readonly string[];\n /** public (anyone opens it now) or the level it stays locked at. */\n access?: readonly (\"public\" | \"tier\" | \"group\" | \"ppv\" | \"group_ppv\")[];\n /** Only contents locked behind one of these tiers. */\n tiers?: readonly string[];\n /** Version traits every listed version has. */\n traits?: readonly string[];\n /** \"name:value\" of the kind's filterable attributes. */\n attribute?: readonly string[];\n /** Published on this day (YYYY-MM-DD) or month (YYYY-MM). */\n released_on?: string;\n /** Only contents published within this age window; independent of the popularity score window. */\n published_within?: Period;\n /** IANA time zone of released_on and release dates; UTC by default. */\n tz?: string;\n /** The signed-in reader's unseen, in-progress or completed contents. */\n view_status?: \"unseen\" | \"in_progress\" | \"completed\";\n}\n\n/** How a list reads to its reader. */\nexport interface ReaderQuery {\n /** Only content with a live version in this language. */\n language?: string;\n /** Titles, names and paths in this language, and each card's preferred version's; language by default. */\n display_language?: string;\n mode?: AccessMode;\n}\n\n/** The group kinds cards name; every kind with a page by default. */\nexport interface CardQuery {\n card_entities?: readonly string[];\n}\n\nexport interface PageQuery {\n cursor?: string;\n limit?: number;\n}\n\nexport type ContentQuery = ContentFilterQuery & ReaderQuery & CardQuery & PageQuery & {\n sort?: ListSort;\n /** Inclusive UTC date (YYYY-MM-DD); requires activity_until, kind and sort=popular. */\n activity_from?: string;\n /** Exclusive UTC date (YYYY-MM-DD); requires activity_from, kind and sort=popular. */\n activity_until?: string;\n};\nexport type PopularPeriod = \"7d\" | \"90d\" | \"365d\" | \"all\";\n/** Whole UTC dates: from inclusive, until exclusive. */\nexport interface PopularDateRange {\n from: string;\n until: string;\n}\nexport type PopularQuery = Omit<ContentQuery, \"sort\" | \"activity_from\" | \"activity_until\">;\n\n/** Rank activity in the selected window; publication age is an optional separate filter. */\nexport function popularQuery(period: PopularPeriod | PopularDateRange = \"7d\", filters: PopularQuery = {}): ContentQuery {\n return typeof period === \"string\"\n ? { ...filters, sort: `popular:${period}` }\n : { ...filters, sort: \"popular\", activity_from: period.from, activity_until: period.until };\n}\n\n/** Rank activity between two UTC dates: from inclusive, until exclusive. */\nexport function popularBetween(from: string, until: string, filters: PopularQuery & { kind: string }): ContentQuery {\n return popularQuery({ from, until }, filters);\n}\n\nexport type SearchQuery = ContentFilterQuery &\n ReaderQuery &\n CardQuery &\n PageQuery & {\n q: string;\n sort?: \"relevance\" | ListSort;\n personalize?: boolean;\n /** Explicit legacy server-side anonymous history. Omit for public search without server history. */\n session?: string;\n };\nexport interface RecentSearchesQuery {\n /** Explicit legacy server-side anonymous history; no anonymous session is created by default. */\n session?: string;\n /** 10 by default, at most 100. */\n limit?: number;\n}\nexport type RailQuery = ContentFilterQuery & ReaderQuery & CardQuery & { limit?: number };\nexport type ReleaseDatesQuery = ContentFilterQuery & ReaderQuery & PageQuery & { by?: \"month\" | \"day\" };\n/** Complete daily metadata for one calendar window, without pagination. */\nexport type DailyReleasesQuery = Omit<ContentFilterQuery, \"released_on\" | \"tz\"> & ReaderQuery & CardQuery & {\n days?: number;\n /** Inclusive YYYY-MM-DD in time_zone; today by default. Future dates are rejected. */\n end_date?: string;\n time_zone?: string;\n};\nexport type HistoryQuery = ReaderQuery & CardQuery & PageQuery & { kind?: string; status?: \"seen\" | \"in_progress\" | \"completed\" };\nexport interface TypeaheadQuery extends ReaderQuery {\n q: string;\n /** Only contents of this kind. */\n kind?: string;\n /** The group kinds suggested; every kind with a page by default. */\n entity_kinds?: readonly string[];\n /** Per section: 8 by default, at most 20. */\n limit?: number;\n}\n\n// Comma-joined list parameters; `attribute` repeats instead.\nconst LISTS = new Set([\"groups\", \"exclude_groups\", \"creators\", \"access\", \"tiers\", \"traits\", \"card_entities\", \"entity_kinds\"]);\n\n/** A query with its list parameters comma-joined, as discovery routes read them. */\nexport function query(q: object): Record<string, string | number | boolean | readonly string[] | undefined> {\n const out: Record<string, string | number | boolean | readonly string[] | undefined> = {};\n for (const [k, v] of Object.entries(q)) out[k] = LISTS.has(k) && Array.isArray(v) ? (v.length ? v.join(\",\") : undefined) : v;\n return out;\n}\n\n/**\n * Discovery: lists, search, typeahead, similar and recommended contents,\n * release dates, the reader's content filters and history, signals and exposures.\n */\nexport class DiscoveryClient {\n /** Local anonymous history, isolated from authenticated server history. */\n readonly browserSearches: BrowserSearchHistory;\n\n constructor(private readonly http: Http) {\n this.browserSearches = browserSearchHistory(http.mount(\"discovery\"));\n }\n\n /** Contents as cards, one per content item with the version that fits the reader. */\n list(q: ContentQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/contents\", { query: query(q) as never, signal });\n }\n /** A first page is kept among the reader's recent searches. */\n async search(q: SearchQuery, signal?: AbortSignal): Promise<ContentPage> {\n const emit = q.cursor ? null : this.http.captureChanges();\n const out: ContentPage = await call(this.http, \"GET\", \"/search\", { query: query(q) as never, signal });\n emit?.({ type: \"searches.changed\" });\n return out;\n }\n /** The reader's recent searches, newest first, since they last cleared them. */\n recentSearches(q: RecentSearchesQuery = {}, signal?: AbortSignal): Promise<RecentSearches> {\n return call(this.http, \"GET\", \"/me/searches\", { query: q, signal });\n }\n /** Clears one recent search, or all of them. */\n async clearSearches(o: { query?: string; session?: string } = {}): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/me/searches\", { query: o });\n emit({ type: \"searches.changed\" });\n }\n /** Contents and groups while the reader types. */\n typeahead(q: TypeaheadQuery, signal?: AbortSignal): Promise<Typeahead> {\n return call(this.http, \"GET\", \"/typeahead\", { query: query(q) as never, signal });\n }\n /** Contents like one, of its kind unless q.kind names another. */\n similar(id: string, q: RailQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/contents/{id}/similar\", { params: { id }, query: query(q) as never, signal });\n }\n /** For the signed-in reader. */\n recommendations(q: RailQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/recommendations\", { query: query(q) as never, signal });\n }\n /** Per month or day, newest first: how many contents the reader's listing shows released then, and how many are free. */\n releaseDates(q: ReleaseDatesQuery = {}, signal?: AbortSignal): Promise<ReleaseDates> {\n return call(this.http, \"GET\", \"/release-dates\", { query: query(q) as never, signal });\n }\n /** Every visible card in each day; opening or expanding a day needs no further request. */\n releases(q: DailyReleasesQuery = {}, signal?: AbortSignal): Promise<DailyReleases> {\n return call(this.http, \"GET\", \"/releases\", { query: query(q) as never, signal });\n }\n /** Only the current domain's reader-toggleable entities, named in the requested language. */\n async contentFilters(language?: string, signal?: AbortSignal): Promise<ContentFilters> {\n const result = await this.http.request<ContentFilters>(routeURL(this.http, \"GET\", \"/content-filters\", { query: { language } }), { signal, guestPreferences: false });\n this.http.acceptGuestFilters(result.filters);\n return result;\n }\n /** Atomically changes submitted shared choices; omitted settings remain intact. */\n async setContentFilters(update: ContentFiltersUpdate, language?: string): Promise<ContentFilters> {\n const emit = this.http.captureChanges();\n const out: ContentFilters = await call(this.http, \"PATCH\", \"/me/content-filters\", { query: { language }, body: update });\n emit({ type: \"contentFilters.changed\" });\n return out;\n }\n /** What the reader engaged with, most recent first. */\n history(q: HistoryQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/me/history\", { query: query(q) as never, signal });\n }\n /** Erases the reader's history: of one content item, one kind or everything. */\n async forgetHistory(o: { kind?: string; content_id?: string } = {}): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/me/history\", { query: o });\n emit({ type: \"history.changed\" });\n }\n /** Capture server-owned access and eligibility at an observation's start. */\n activityContexts(targets: readonly ActivityTarget[], session?: string, language = this.http.language()): Promise<ActivityContexts> {\n const body: ActivityContextsInput = { targets: [...targets], session, language };\n return call(this.http, \"POST\", \"/activity-contexts\", { body });\n }\n /** Views and clicks; signed out, of the session named. */\n signals(signals: SignalInput[], session?: string, o: { keepalive?: boolean } = {}): Promise<void> {\n const body: Signals = { session, signals };\n return call(this.http, \"POST\", \"/signals\", { body, keepalive: o.keepalive });\n }\n /** Result lists served, rendered or shown, for click attribution. */\n exposures(exposures: ExposureInput[], session?: string, o: { keepalive?: boolean } = {}): Promise<void> {\n const body: Exposures = { session, exposures };\n return call(this.http, \"POST\", \"/exposures\", { body, keepalive: o.keepalive });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"discovery.js","names":[],"sources":["../../src/client/discovery.ts"],"sourcesContent":["import type {\n ActivityContexts,\n ActivityContextsInput,\n ActivityTarget,\n ContentFilters,\n ContentFiltersUpdate,\n ContentPage,\n DailyReleases,\n EngagementBatch,\n EngagementSnapshot,\n ExposureInput,\n Exposures,\n RecentSearches,\n ReleaseDates,\n SignalInput,\n Signals,\n Typeahead,\n} from \"./generated/wire.js\";\nimport type { Http } from \"./http.js\";\nimport { call, routeURL } from \"./route.js\";\nimport { browserSearchHistory, type BrowserSearchHistory } from \"./browser-search-history.js\";\n\n/** A popularity period. */\nexport type Period = \"7d\" | \"30d\" | \"90d\" | \"365d\" | \"all\";\n/** A list's order; position orders by the first of `groups` (an ordered group). */\nexport type ListSort = \"newest\" | \"oldest\" | \"title\" | \"popular\" | `popular:${Period}` | \"top_rated\" | `top_rated:${Period}` | \"most_favorited\" | \"position\" | \"random\";\n/** How locked contents list: marked (lock, the default) or left out (hide). */\nexport type AccessMode = \"lock\" | \"hide\";\n\n/** Which contents a list holds. */\nexport interface ContentFilterQuery {\n kind?: string;\n /** Public card hydration under current domain/access/preferences; at most 100. */\n ids?: readonly string[];\n /** Group ids every listed version is in. */\n groups?: readonly string[];\n /** Group ids no listed version is in. */\n exclude_groups?: readonly string[];\n /** Only contents this group owns: a channel's feed. */\n owner_group?: string;\n /** User ids: only contents one of them is credited on. */\n creators?: readonly string[];\n /** public (anyone opens it now) or the level it stays locked at. */\n access?: readonly (\"public\" | \"tier\" | \"group\" | \"ppv\" | \"group_ppv\")[];\n /** Only contents locked behind one of these tiers. */\n tiers?: readonly string[];\n /** Version traits every listed version has. */\n traits?: readonly string[];\n /** \"name:value\" of the kind's filterable attributes. */\n attribute?: readonly string[];\n /** Published on this day (YYYY-MM-DD) or month (YYYY-MM). */\n released_on?: string;\n /** Only contents published within this age window; independent of the popularity score window. */\n published_within?: Period;\n /** IANA time zone of released_on and release dates; UTC by default. */\n tz?: string;\n /** The signed-in reader's unseen, in-progress or completed contents. */\n view_status?: \"unseen\" | \"in_progress\" | \"completed\";\n}\n\n/** How a list reads to its reader. */\nexport interface ReaderQuery {\n /** Only content with a live version in this language. */\n language?: string;\n /** Titles, names and paths in this language, and each card's preferred version's; language by default. */\n display_language?: string;\n mode?: AccessMode;\n}\n\n/** The group kinds cards name; every kind with a page by default. */\nexport interface CardQuery {\n card_entities?: readonly string[];\n}\n\nexport interface PageQuery {\n cursor?: string;\n limit?: number;\n}\n\n/** A numbered page from 1 instead of cursor; its summary then comes with every page. */\nexport interface NumberedPageQuery {\n page?: number;\n}\n\nexport type ContentQuery = ContentFilterQuery & ReaderQuery & CardQuery & PageQuery & NumberedPageQuery & {\n /** Selection-wide metadata; requested only on the first page. */\n summary?: boolean;\n sort?: ListSort;\n /** Inclusive UTC date (YYYY-MM-DD); requires activity_until, kind and sort=popular. */\n activity_from?: string;\n /** Exclusive UTC date (YYYY-MM-DD); requires activity_from, kind and sort=popular. */\n activity_until?: string;\n};\nexport type PopularPeriod = \"7d\" | \"90d\" | \"365d\" | \"all\";\n/** Whole UTC dates: from inclusive, until exclusive. */\nexport interface PopularDateRange {\n from: string;\n until: string;\n}\nexport type PopularQuery = Omit<ContentQuery, \"sort\" | \"activity_from\" | \"activity_until\">;\n\n/** Rank activity in the selected window; publication age is an optional separate filter. */\nexport function popularQuery(period: PopularPeriod | PopularDateRange = \"7d\", filters: PopularQuery = {}): ContentQuery {\n return typeof period === \"string\"\n ? { ...filters, sort: `popular:${period}` }\n : { ...filters, sort: \"popular\", activity_from: period.from, activity_until: period.until };\n}\n\n/** Rank activity between two UTC dates: from inclusive, until exclusive. */\nexport function popularBetween(from: string, until: string, filters: PopularQuery & { kind: string }): ContentQuery {\n return popularQuery({ from, until }, filters);\n}\n\nexport type SearchQuery = ContentFilterQuery &\n ReaderQuery &\n CardQuery &\n PageQuery &\n NumberedPageQuery & {\n q: string;\n sort?: \"relevance\" | ListSort;\n personalize?: boolean;\n summary?: boolean;\n /** Explicit legacy server-side anonymous history. Omit for public search without server history. */\n session?: string;\n };\nexport interface RecentSearchesQuery {\n /** Explicit legacy server-side anonymous history; no anonymous session is created by default. */\n session?: string;\n /** 10 by default, at most 100. */\n limit?: number;\n}\nexport type RailQuery = ContentFilterQuery & ReaderQuery & CardQuery & { limit?: number; summary?: boolean };\nexport type ReleaseDatesQuery = ContentFilterQuery & ReaderQuery & PageQuery & { by?: \"month\" | \"day\" };\n/** Complete daily metadata for one calendar window, without pagination. */\nexport type DailyReleasesQuery = Omit<ContentFilterQuery, \"released_on\" | \"tz\"> & ReaderQuery & CardQuery & {\n days?: number;\n /** Inclusive YYYY-MM-DD in time_zone; today by default. Future dates are rejected. */\n end_date?: string;\n time_zone?: string;\n};\nexport type HistoryQuery = ReaderQuery & CardQuery & PageQuery & { kind?: string; status?: \"seen\" | \"in_progress\" | \"completed\"; summary?: boolean };\nexport interface TypeaheadQuery extends ReaderQuery {\n q: string;\n /** Only contents of this kind. */\n kind?: string;\n /** The group kinds suggested; every kind with a page by default. */\n entity_kinds?: readonly string[];\n /** Per section: 8 by default, at most 20. */\n limit?: number;\n}\n\n/** Private editor navigation. Each requested section must be chosen explicitly. */\nexport interface AdminSuggestionsQuery {\n q: string;\n display_language?: string;\n content_kinds?: readonly string[];\n entity_kinds?: readonly string[];\n include_contents: boolean;\n include_entities: boolean;\n /** Per section: 8 by default, at most 20. */\n limit?: number;\n}\n\n// Comma-joined list parameters; `attribute` repeats instead.\nconst LISTS = new Set([\"ids\", \"groups\", \"exclude_groups\", \"creators\", \"access\", \"tiers\", \"traits\", \"card_entities\", \"entity_kinds\", \"content_kinds\"]);\n\n/** A query with its list parameters comma-joined, as discovery routes read them. */\nexport function query(q: object): Record<string, string | number | boolean | readonly string[] | undefined> {\n const out: Record<string, string | number | boolean | readonly string[] | undefined> = {};\n for (const [k, v] of Object.entries(q)) out[k] = LISTS.has(k) && Array.isArray(v) ? (v.length ? v.join(\",\") : undefined) : v;\n return out;\n}\n\n/**\n * Discovery: lists, search, typeahead, similar and recommended contents,\n * release dates, the reader's content filters and history, signals and exposures.\n */\nexport class DiscoveryClient {\n /** Local anonymous history, isolated from authenticated server history. */\n readonly browserSearches: BrowserSearchHistory;\n\n constructor(private readonly http: Http) {\n this.browserSearches = browserSearchHistory(http.mount(\"discovery\"));\n }\n\n /** Contents as cards, one per content item with the version that fits the reader. */\n list(q: ContentQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/contents\", { query: query(q) as never, signal });\n }\n /** A first page is kept among the reader's recent searches. */\n async search(q: SearchQuery, signal?: AbortSignal): Promise<ContentPage> {\n const emit = q.cursor || (q.page ?? 1) > 1 ? null : this.http.captureChanges();\n const out: ContentPage = await call(this.http, \"GET\", \"/search\", { query: query(q) as never, signal });\n emit?.({ type: \"searches.changed\" });\n return out;\n }\n /** The reader's recent searches, newest first, since they last cleared them. */\n recentSearches(q: RecentSearchesQuery = {}, signal?: AbortSignal): Promise<RecentSearches> {\n return call(this.http, \"GET\", \"/me/searches\", { query: q, signal });\n }\n /** Clears one recent search, or all of them. */\n async clearSearches(o: { query?: string; session?: string } = {}): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/me/searches\", { query: o });\n emit({ type: \"searches.changed\" });\n }\n /** Contents and groups while the reader types. */\n typeahead(q: TypeaheadQuery, signal?: AbortSignal): Promise<Typeahead> {\n return call(this.http, \"GET\", \"/typeahead\", { query: query(q) as never, signal });\n }\n /** Current names of authorized draft/hidden content and entities; no public search fallback. */\n adminSuggestions(q: AdminSuggestionsQuery, signal?: AbortSignal): Promise<Typeahead> {\n return call(this.http, \"GET\", \"/manage/search-suggestions\", { query: query(q) as never, signal });\n }\n /** Contents like one, of its kind unless q.kind names another. */\n similar(id: string, q: RailQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/contents/{id}/similar\", { params: { id }, query: query(q) as never, signal });\n }\n /** For the signed-in reader. */\n recommendations(q: RailQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/recommendations\", { query: query(q) as never, signal });\n }\n /** Per month or day, newest first: how many contents the reader's listing shows released then, and how many are free. */\n releaseDates(q: ReleaseDatesQuery = {}, signal?: AbortSignal): Promise<ReleaseDates> {\n return call(this.http, \"GET\", \"/release-dates\", { query: query(q) as never, signal });\n }\n /** Every visible card in each day; opening or expanding a day needs no further request. */\n releases(q: DailyReleasesQuery = {}, signal?: AbortSignal): Promise<DailyReleases> {\n return call(this.http, \"GET\", \"/releases\", { query: query(q) as never, signal });\n }\n /** Only the current domain's reader-toggleable entities, named in the requested language. */\n async contentFilters(language?: string, signal?: AbortSignal): Promise<ContentFilters> {\n const result = await this.http.request<ContentFilters>(routeURL(this.http, \"GET\", \"/content-filters\", { query: { language } }), { signal, guestPreferences: false });\n this.http.acceptGuestFilters(result.filters);\n return result;\n }\n /** Atomically changes submitted shared choices; omitted settings remain intact. */\n async setContentFilters(update: ContentFiltersUpdate, language?: string): Promise<ContentFilters> {\n const emit = this.http.captureChanges();\n const out: ContentFilters = await call(this.http, \"PATCH\", \"/me/content-filters\", { query: { language }, body: update });\n emit({ type: \"contentFilters.changed\" });\n return out;\n }\n /** What the reader engaged with, most recent first. */\n history(q: HistoryQuery = {}, signal?: AbortSignal): Promise<ContentPage> {\n return call(this.http, \"GET\", \"/me/history\", { query: query(q) as never, signal });\n }\n /** Erases the reader's history: of one content item, one kind or everything. */\n async forgetHistory(o: { kind?: string; content_id?: string } = {}): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/me/history\", { query: o });\n emit({ type: \"history.changed\" });\n }\n /** Capture server-owned access and eligibility at an observation's start. */\n activityContexts(targets: readonly ActivityTarget[], session?: string, language = this.http.language()): Promise<ActivityContexts> {\n const body: ActivityContextsInput = { targets: [...targets], session, language };\n return call(this.http, \"POST\", \"/activity-contexts\", { body });\n }\n /** Cumulative measured attention. Successful checkpoints refresh history/progress caches. */\n async engagement(snapshots: EngagementSnapshot[], o: { session?: string; keepalive?: boolean } = {}): Promise<void> {\n const emit = this.http.captureChanges();\n const body: EngagementBatch = { session: o.session, snapshots };\n await call(this.http, \"POST\", \"/engagement\", { body, keepalive: o.keepalive });\n emit({ type: \"engagement.changed\", ids: [...new Set(snapshots.map(s => s.content_id))] });\n }\n /** Clicks and explicit feedback; signed out, of the visitor named. */\n signals(signals: SignalInput[], session?: string, o: { keepalive?: boolean } = {}): Promise<void> {\n const body: Signals = { session, signals };\n return call(this.http, \"POST\", \"/signals\", { body, keepalive: o.keepalive });\n }\n /** Result lists served, rendered or shown, for click attribution. */\n exposures(exposures: ExposureInput[], session?: string, o: { keepalive?: boolean } = {}): Promise<void> {\n const body: Exposures = { session, exposures };\n return call(this.http, \"POST\", \"/exposures\", { body, keepalive: o.keepalive });\n }\n}\n"],"mappings":";;;AAsGA,SAAgB,EAAa,IAA2C,MAAM,IAAwB,CAAC,GAAiB;CACtH,OAAO,OAAO,KAAW,WACrB;EAAE,GAAG;EAAS,MAAM,WAAW;CAAS,IACxC;EAAE,GAAG;EAAS,MAAM;EAAW,eAAe,EAAO;EAAM,gBAAgB,EAAO;CAAM;AAC9F;AAGA,SAAgB,EAAe,GAAc,GAAe,GAAwD;CAClH,OAAO,EAAa;EAAE;EAAM;CAAM,GAAG,CAAO;AAC9C;AAqDA,IAAM,oBAAQ,IAAI,IAAI;CAAC;CAAO;CAAU;CAAkB;CAAY;CAAU;CAAS;CAAU;CAAiB;CAAgB;AAAe,CAAC;AAGpJ,SAAgB,EAAM,GAAsF;CAC1G,IAAM,IAAiF,CAAC;CACxF,KAAK,IAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,CAAC,GAAG,EAAI,KAAK,EAAM,IAAI,CAAC,KAAK,MAAM,QAAQ,CAAC,IAAK,EAAE,SAAS,EAAE,KAAK,GAAG,IAAI,KAAA,IAAa;CAC3H,OAAO;AACT;AAMA,IAAa,IAAb,MAA6B;CAIE;CAF7B;CAEA,YAAY,GAA6B;EACvC,AAD2B,KAAA,OAAA,GAC3B,KAAK,kBAAkB,EAAqB,EAAK,MAAM,WAAW,CAAC;CACrE;CAGA,KAAK,IAAkB,CAAC,GAAG,GAA4C;EACrE,OAAO,EAAK,KAAK,MAAM,OAAO,aAAa;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACjF;CAEA,MAAM,OAAO,GAAgB,GAA4C;EACvE,IAAM,IAAO,EAAE,WAAW,EAAE,QAAQ,KAAK,IAAI,OAAO,KAAK,KAAK,eAAe,GACvE,IAAmB,MAAM,EAAK,KAAK,MAAM,OAAO,WAAW;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;EAErG,OADA,IAAO,EAAE,MAAM,mBAAmB,CAAC,GAC5B;CACT;CAEA,eAAe,IAAyB,CAAC,GAAG,GAA+C;EACzF,OAAO,EAAK,KAAK,MAAM,OAAO,gBAAgB;GAAE,OAAO;GAAG;EAAO,CAAC;CACpE;CAEA,MAAM,cAAc,IAA0C,CAAC,GAAkB;EAC/E,IAAM,IAAO,KAAK,KAAK,eAAe;EAEtC,AADA,MAAM,EAAK,KAAK,MAAM,UAAU,gBAAgB,EAAE,OAAO,EAAE,CAAC,GAC5D,EAAK,EAAE,MAAM,mBAAmB,CAAC;CACnC;CAEA,UAAU,GAAmB,GAA0C;EACrE,OAAO,EAAK,KAAK,MAAM,OAAO,cAAc;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CAClF;CAEA,iBAAiB,GAA0B,GAA0C;EACnF,OAAO,EAAK,KAAK,MAAM,OAAO,8BAA8B;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CAClG;CAEA,QAAQ,GAAY,IAAe,CAAC,GAAG,GAA4C;EACjF,OAAO,EAAK,KAAK,MAAM,OAAO,0BAA0B;GAAE,QAAQ,EAAE,MAAG;GAAG,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CAC9G;CAEA,gBAAgB,IAAe,CAAC,GAAG,GAA4C;EAC7E,OAAO,EAAK,KAAK,MAAM,OAAO,oBAAoB;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACxF;CAEA,aAAa,IAAuB,CAAC,GAAG,GAA6C;EACnF,OAAO,EAAK,KAAK,MAAM,OAAO,kBAAkB;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACtF;CAEA,SAAS,IAAwB,CAAC,GAAG,GAA8C;EACjF,OAAO,EAAK,KAAK,MAAM,OAAO,aAAa;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACjF;CAEA,MAAM,eAAe,GAAmB,GAA+C;EACrF,IAAM,IAAS,MAAM,KAAK,KAAK,QAAwB,EAAS,KAAK,MAAM,OAAO,oBAAoB,EAAE,OAAO,EAAE,YAAS,EAAE,CAAC,GAAG;GAAE;GAAQ,kBAAkB;EAAM,CAAC;EAEnK,OADA,KAAK,KAAK,mBAAmB,EAAO,OAAO,GACpC;CACT;CAEA,MAAM,kBAAkB,GAA8B,GAA4C;EAChG,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAsB,MAAM,EAAK,KAAK,MAAM,SAAS,uBAAuB;GAAE,OAAO,EAAE,YAAS;GAAG,MAAM;EAAO,CAAC;EAEvH,OADA,EAAK,EAAE,MAAM,yBAAyB,CAAC,GAChC;CACT;CAEA,QAAQ,IAAkB,CAAC,GAAG,GAA4C;EACxE,OAAO,EAAK,KAAK,MAAM,OAAO,eAAe;GAAE,OAAO,EAAM,CAAC;GAAY;EAAO,CAAC;CACnF;CAEA,MAAM,cAAc,IAA4C,CAAC,GAAkB;EACjF,IAAM,IAAO,KAAK,KAAK,eAAe;EAEtC,AADA,MAAM,EAAK,KAAK,MAAM,UAAU,eAAe,EAAE,OAAO,EAAE,CAAC,GAC3D,EAAK,EAAE,MAAM,kBAAkB,CAAC;CAClC;CAEA,iBAAiB,GAAoC,GAAkB,IAAW,KAAK,KAAK,SAAS,GAA8B;EACjI,IAAM,IAA8B;GAAE,SAAS,CAAC,GAAG,CAAO;GAAG;GAAS;EAAS;EAC/E,OAAO,EAAK,KAAK,MAAM,QAAQ,sBAAsB,EAAE,QAAK,CAAC;CAC/D;CAEA,MAAM,WAAW,GAAiC,IAA+C,CAAC,GAAkB;EAClH,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAwB;GAAE,SAAS,EAAE;GAAS;EAAU;EAE9D,AADA,MAAM,EAAK,KAAK,MAAM,QAAQ,eAAe;GAAE;GAAM,WAAW,EAAE;EAAU,CAAC,GAC7E,EAAK;GAAE,MAAM;GAAsB,KAAK,CAAC,GAAG,IAAI,IAAI,EAAU,KAAI,MAAK,EAAE,UAAU,CAAC,CAAC;EAAE,CAAC;CAC1F;CAEA,QAAQ,GAAwB,GAAkB,IAA6B,CAAC,GAAkB;EAChG,IAAM,IAAgB;GAAE;GAAS;EAAQ;EACzC,OAAO,EAAK,KAAK,MAAM,QAAQ,YAAY;GAAE;GAAM,WAAW,EAAE;EAAU,CAAC;CAC7E;CAEA,UAAU,GAA4B,GAAkB,IAA6B,CAAC,GAAkB;EACtG,IAAM,IAAkB;GAAE;GAAS;EAAU;EAC7C,OAAO,EAAK,KAAK,MAAM,QAAQ,cAAc;GAAE;GAAM,WAAW,EAAE;EAAU,CAAC;CAC/E;AACF"}
@@ -0,0 +1,70 @@
1
+ import { ActivityContext, CoverageRange, EngagementSnapshot } from './generated/wire.js';
2
+ export interface VisiblePage {
3
+ /** Zero-based index in the version's reading order. */
4
+ index: number;
5
+ /** The part actually on screen, in 0..10000 basis points of page height. */
6
+ ranges: readonly CoverageRange[];
7
+ }
8
+ export interface ReadingObservation {
9
+ pages?: readonly VisiblePage[];
10
+ video?: {
11
+ positionMs: number;
12
+ playing: boolean;
13
+ seeking?: boolean;
14
+ };
15
+ resume?: string;
16
+ }
17
+ export interface EngagementTrackerOptions {
18
+ contentId: string;
19
+ versionId?: string;
20
+ /** Acquired when attention begins, never by preloading or opening a route. */
21
+ begin: () => Promise<ActivityContext | null>;
22
+ submit: (snapshot: EngagementSnapshot, options: {
23
+ keepalive: boolean;
24
+ }) => Promise<void>;
25
+ onSnapshot?: (snapshot: EngagementSnapshot) => void;
26
+ idleAfter?: number;
27
+ checkpointInterval?: number;
28
+ now?: () => number;
29
+ id?: () => string;
30
+ }
31
+ /**
32
+ * One content visit, represented by cumulative, bounded attention snapshots.
33
+ * The clock and transport are injected so ownership and browser lifecycle stay
34
+ * outside the accounting. Repeated snapshots replace a revision, not add views.
35
+ */
36
+ export declare class EngagementTracker {
37
+ private readonly options;
38
+ readonly visitId: string;
39
+ private readonly now;
40
+ private readonly id;
41
+ private readonly idleAfter;
42
+ private readonly interval;
43
+ private last;
44
+ private lastActivity;
45
+ private attentive;
46
+ private observation;
47
+ private segment?;
48
+ private pending;
49
+ private tail;
50
+ private stopped;
51
+ private keepaliveRequested;
52
+ constructor(options: EngagementTrackerOptions);
53
+ /** Genuine input extends the reading window; a timer or preload does not. */
54
+ activity(): void;
55
+ attention(attentive: boolean): void;
56
+ observe(observation: ReadingObservation): void;
57
+ /** Tick even while the geometry is unchanged, so idle and checkpoint bounds hold. */
58
+ tick(): void;
59
+ /** Send accumulated attention; failed packets retain their exact revision for retry. */
60
+ flush(keepalive?: boolean): Promise<void>;
61
+ /** Account changes discard old ownership instead of sending under new credentials. */
62
+ discard(): void;
63
+ private startObservedSegment;
64
+ private receipt;
65
+ private createSegment;
66
+ private advance;
67
+ private record;
68
+ private capture;
69
+ private send;
70
+ }