@openrails/contentkit-ui 0.83.0 → 0.86.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 (219) hide show
  1. package/README.md +18 -7
  2. package/dist/client/beacons.d.ts +18 -6
  3. package/dist/client/beacons.js +26 -11
  4. package/dist/client/beacons.js.map +1 -1
  5. package/dist/client/client.d.ts +3 -0
  6. package/dist/client/client.js +29 -27
  7. package/dist/client/client.js.map +1 -1
  8. package/dist/client/codes.d.ts +6 -1
  9. package/dist/client/codes.js +4 -1
  10. package/dist/client/codes.js.map +1 -1
  11. package/dist/client/content/moderation.d.ts +14 -2
  12. package/dist/client/content/moderation.js +34 -0
  13. package/dist/client/content/moderation.js.map +1 -1
  14. package/dist/client/content/types.d.ts +13 -0
  15. package/dist/client/content/types.js.map +1 -1
  16. package/dist/client/discovery.d.ts +6 -0
  17. package/dist/client/discovery.js.map +1 -1
  18. package/dist/client/generated/error-codes.d.ts +1 -1
  19. package/dist/client/generated/error-codes.js +9 -1
  20. package/dist/client/generated/error-codes.js.map +1 -1
  21. package/dist/client/generated/routes.d.ts +91 -13
  22. package/dist/client/generated/routes.js +123 -2
  23. package/dist/client/generated/routes.js.map +1 -1
  24. package/dist/client/generated/wire.d.ts +81 -0
  25. package/dist/client/generated/wire.js.map +1 -1
  26. package/dist/client/index.d.ts +4 -2
  27. package/dist/client/media/queue.d.ts +4 -2
  28. package/dist/client/media/queue.js +18 -12
  29. package/dist/client/media/queue.js.map +1 -1
  30. package/dist/client/media/rules.d.ts +7 -1
  31. package/dist/client/media/rules.js +27 -21
  32. package/dist/client/media/rules.js.map +1 -1
  33. package/dist/client/reader-meta.d.ts +27 -0
  34. package/dist/client/reader-meta.js +99 -0
  35. package/dist/client/reader-meta.js.map +1 -0
  36. package/dist/client/stats.d.ts +32 -0
  37. package/dist/client/stats.js +35 -0
  38. package/dist/client/stats.js.map +1 -0
  39. package/dist/client/versions.d.ts +1 -1
  40. package/dist/client/versions.js +7 -2
  41. package/dist/client/versions.js.map +1 -1
  42. package/dist/client.js +30 -28
  43. package/dist/components/admin/content-manager.js +206 -206
  44. package/dist/components/admin/content-manager.js.map +1 -1
  45. package/dist/components/admin/group-manager.js +71 -70
  46. package/dist/components/admin/group-manager.js.map +1 -1
  47. package/dist/components/admin/media-item-panel.d.ts +24 -7
  48. package/dist/components/admin/media-item-panel.js +209 -197
  49. package/dist/components/admin/media-item-panel.js.map +1 -1
  50. package/dist/components/admin/poll-manager.js +25 -25
  51. package/dist/components/admin/reader-manifest.d.ts +18 -0
  52. package/dist/components/admin/reader-manifest.js +490 -0
  53. package/dist/components/admin/reader-manifest.js.map +1 -0
  54. package/dist/components/admin/stats-dashboard.d.ts +22 -0
  55. package/dist/components/admin/stats-dashboard.js +257 -0
  56. package/dist/components/admin/stats-dashboard.js.map +1 -0
  57. package/dist/components/content/card.js +43 -43
  58. package/dist/components/content/card.js.map +1 -1
  59. package/dist/components/content/editors.d.ts +2 -1
  60. package/dist/components/content/editors.js +479 -416
  61. package/dist/components/content/editors.js.map +1 -1
  62. package/dist/components/content/grid.js +47 -47
  63. package/dist/components/content/index.d.ts +2 -1
  64. package/dist/components/content/listing.js +34 -34
  65. package/dist/components/content/listing.js.map +1 -1
  66. package/dist/components/content/paywall.d.ts +17 -5
  67. package/dist/components/content/paywall.js +115 -100
  68. package/dist/components/content/paywall.js.map +1 -1
  69. package/dist/components/content/reader-stats.d.ts +12 -0
  70. package/dist/components/content/reader-stats.js +47 -0
  71. package/dist/components/content/reader-stats.js.map +1 -0
  72. package/dist/components/groups/banner.d.ts +1 -1
  73. package/dist/components/groups/banner.js +34 -34
  74. package/dist/components/groups/banner.js.map +1 -1
  75. package/dist/components/groups/directory.js +11 -11
  76. package/dist/components/groups/editor.js +294 -294
  77. package/dist/components/groups/editor.js.map +1 -1
  78. package/dist/components/groups/header.js +27 -27
  79. package/dist/components/groups/header.js.map +1 -1
  80. package/dist/components/groups/memberships.js +180 -180
  81. package/dist/components/groups/parts.d.ts +2 -4
  82. package/dist/components/groups/parts.js +69 -88
  83. package/dist/components/groups/parts.js.map +1 -1
  84. package/dist/components/media-folder-editor.js +239 -189
  85. package/dist/components/media-folder-editor.js.map +1 -1
  86. package/dist/components/notifications.js +17 -17
  87. package/dist/components/slot-upload.d.ts +2 -2
  88. package/dist/components/slot-upload.js +84 -79
  89. package/dist/components/slot-upload.js.map +1 -1
  90. package/dist/components/social/bans.js +34 -34
  91. package/dist/components/social/comments.js +59 -45
  92. package/dist/components/social/comments.js.map +1 -1
  93. package/dist/components/social/index.d.ts +1 -0
  94. package/dist/components/social/moderation.d.ts +5 -4
  95. package/dist/components/social/moderation.js +177 -160
  96. package/dist/components/social/moderation.js.map +1 -1
  97. package/dist/components/social/parts.js +22 -14
  98. package/dist/components/social/parts.js.map +1 -1
  99. package/dist/components/social/rules.d.ts +23 -0
  100. package/dist/components/social/rules.js +261 -0
  101. package/dist/components/social/rules.js.map +1 -0
  102. package/dist/components/video-player.d.ts +2 -0
  103. package/dist/components/video-player.js +318 -314
  104. package/dist/components/video-player.js.map +1 -1
  105. package/dist/i18n/context.d.ts +2 -0
  106. package/dist/i18n/context.js +23 -5
  107. package/dist/i18n/context.js.map +1 -1
  108. package/dist/index.d.ts +3 -1
  109. package/dist/index.js +28 -24
  110. package/dist/locales/admin/de.js +105 -0
  111. package/dist/locales/admin/de.js.map +1 -1
  112. package/dist/locales/admin/en.d.ts +105 -0
  113. package/dist/locales/admin/en.js +105 -0
  114. package/dist/locales/admin/en.js.map +1 -1
  115. package/dist/locales/admin/es.js +105 -0
  116. package/dist/locales/admin/es.js.map +1 -1
  117. package/dist/locales/admin/ja.js +105 -0
  118. package/dist/locales/admin/ja.js.map +1 -1
  119. package/dist/locales/admin/ko.js +105 -0
  120. package/dist/locales/admin/ko.js.map +1 -1
  121. package/dist/locales/admin/zh.js +105 -0
  122. package/dist/locales/admin/zh.js.map +1 -1
  123. package/dist/locales/content/de.js +6 -0
  124. package/dist/locales/content/de.js.map +1 -1
  125. package/dist/locales/content/en.d.ts +6 -0
  126. package/dist/locales/content/en.js +6 -0
  127. package/dist/locales/content/en.js.map +1 -1
  128. package/dist/locales/content/es.js +6 -0
  129. package/dist/locales/content/es.js.map +1 -1
  130. package/dist/locales/content/ja.js +6 -0
  131. package/dist/locales/content/ja.js.map +1 -1
  132. package/dist/locales/content/ko.js +6 -0
  133. package/dist/locales/content/ko.js.map +1 -1
  134. package/dist/locales/content/zh.js +6 -0
  135. package/dist/locales/content/zh.js.map +1 -1
  136. package/dist/locales/de.js +4 -1
  137. package/dist/locales/de.js.map +1 -1
  138. package/dist/locales/discovery/de.js +1 -0
  139. package/dist/locales/discovery/de.js.map +1 -1
  140. package/dist/locales/discovery/en.d.ts +1 -0
  141. package/dist/locales/discovery/en.js +1 -0
  142. package/dist/locales/discovery/en.js.map +1 -1
  143. package/dist/locales/discovery/es.js +1 -0
  144. package/dist/locales/discovery/es.js.map +1 -1
  145. package/dist/locales/discovery/ja.js +1 -0
  146. package/dist/locales/discovery/ja.js.map +1 -1
  147. package/dist/locales/discovery/ko.js +1 -0
  148. package/dist/locales/discovery/ko.js.map +1 -1
  149. package/dist/locales/discovery/zh.js +1 -0
  150. package/dist/locales/discovery/zh.js.map +1 -1
  151. package/dist/locales/en.d.ts +118 -0
  152. package/dist/locales/en.js +4 -1
  153. package/dist/locales/en.js.map +1 -1
  154. package/dist/locales/es.js +4 -1
  155. package/dist/locales/es.js.map +1 -1
  156. package/dist/locales/ja.js +4 -1
  157. package/dist/locales/ja.js.map +1 -1
  158. package/dist/locales/ko.js +4 -1
  159. package/dist/locales/ko.js.map +1 -1
  160. package/dist/locales/social/de.js +3 -0
  161. package/dist/locales/social/de.js.map +1 -1
  162. package/dist/locales/social/en.d.ts +3 -0
  163. package/dist/locales/social/en.js +3 -0
  164. package/dist/locales/social/en.js.map +1 -1
  165. package/dist/locales/social/es.js +3 -0
  166. package/dist/locales/social/es.js.map +1 -1
  167. package/dist/locales/social/ja.js +3 -0
  168. package/dist/locales/social/ja.js.map +1 -1
  169. package/dist/locales/social/ko.js +3 -0
  170. package/dist/locales/social/ko.js.map +1 -1
  171. package/dist/locales/social/zh.js +3 -0
  172. package/dist/locales/social/zh.js.map +1 -1
  173. package/dist/locales/zh.js +4 -1
  174. package/dist/locales/zh.js.map +1 -1
  175. package/dist/react/admin.d.ts +1 -1
  176. package/dist/react/admin.js +24 -23
  177. package/dist/react/admin.js.map +1 -1
  178. package/dist/react/canonical.d.ts +4 -3
  179. package/dist/react/canonical.js +34 -33
  180. package/dist/react/canonical.js.map +1 -1
  181. package/dist/react/comments.d.ts +29 -1
  182. package/dist/react/comments.js +30 -2
  183. package/dist/react/comments.js.map +1 -1
  184. package/dist/react/contents.js +144 -144
  185. package/dist/react/contents.js.map +1 -1
  186. package/dist/react/context.d.ts +1 -1
  187. package/dist/react/context.js.map +1 -1
  188. package/dist/react/detail.d.ts +12 -6
  189. package/dist/react/detail.js +31 -24
  190. package/dist/react/detail.js.map +1 -1
  191. package/dist/react/discovery.js +1 -1
  192. package/dist/react/discovery.js.map +1 -1
  193. package/dist/react/folder.d.ts +7 -2
  194. package/dist/react/folder.js +165 -147
  195. package/dist/react/folder.js.map +1 -1
  196. package/dist/react/groups.d.ts +0 -1
  197. package/dist/react/groups.js +13 -12
  198. package/dist/react/groups.js.map +1 -1
  199. package/dist/react/index.d.ts +5 -3
  200. package/dist/react/location.d.ts +11 -0
  201. package/dist/react/location.js +18 -0
  202. package/dist/react/location.js.map +1 -0
  203. package/dist/react/public.d.ts +8 -0
  204. package/dist/react/public.js +32 -27
  205. package/dist/react/public.js.map +1 -1
  206. package/dist/react/resources.js +6 -0
  207. package/dist/react/resources.js.map +1 -1
  208. package/dist/react/stats.d.ts +24 -0
  209. package/dist/react/stats.js +28 -0
  210. package/dist/react/stats.js.map +1 -0
  211. package/dist/react/use-resource.js +8 -7
  212. package/dist/react/use-resource.js.map +1 -1
  213. package/dist/react/versions.js +20 -20
  214. package/dist/react.js +26 -24
  215. package/dist/styles.css +1 -1
  216. package/dist/urls/index.d.ts +35 -10
  217. package/dist/urls.js +100 -70
  218. package/dist/urls.js.map +1 -1
  219. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"resources.js","names":[],"sources":["../../src/react/resources.ts"],"sourcesContent":["import type { ContentKitClient } from \"../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../client/errors.js\";\nimport { sameTarget, type Target } from \"../client/content/types.js\";\nimport type { Card, Comment, Content, Item, Poll } from \"../client/generated/wire.js\";\nimport type { ContentKitChange } from \"../client/http.js\";\n\n/** One shared read: its data, whether a fetch is in flight, and its last failure. */\nexport interface Resource<T> {\n data: T | undefined;\n loading: boolean;\n /** A fetch or set has completed. */\n loaded: boolean;\n /** A list's next page is in flight. */\n loadingMore?: boolean;\n error?: ContentKitError;\n}\n\n/** A page of a list and how to get the next one (null: no more). */\nexport interface Page<T> {\n items: T[];\n next: string | number | null;\n}\n\nexport type Fetcher<T> = (signal: AbortSignal) => Promise<T>;\n\n/** What a slot holds, for matching changes: its resource type and the ids it depends on. */\nexport interface Tag {\n type: string;\n readScope?: string;\n target?: Target;\n id?: string;\n scope?: string;\n}\n\ninterface Slot {\n tag: Tag;\n listeners: Set<() => void>;\n entry: Resource<unknown>;\n fetcher?: Fetcher<unknown>;\n more?: (cursor: string | number, signal: AbortSignal) => Promise<Page<unknown>>;\n ctl?: AbortController;\n moreCtl?: AbortController;\n /** Bumped by mark(): an optimistic write rolls back only if no newer one started. */\n version: number;\n /** Identifies the full read; item patches and appended pages retain it. */\n readVersion: number;\n}\n\nconst IDLE: Resource<never> = { data: undefined, loading: false, loaded: false };\n\n/**\n * The content reads hooks share, per client: one request per key while any\n * hook shows it, optimistic writes with rollback, and every change the client\n * makes applied in place (or refetched) for every hook showing it.\n */\nexport class ResourceStore {\n private readonly slots = new Map<string, Slot>();\n // Tokens must remain unique when a scope leaves and its slots are recreated.\n private version = 0;\n\n constructor(client: ContentKitClient) {\n client.subscribe((c, scope) => this.apply(c, scope));\n }\n\n subscribe(key: string, tag: Tag, listener: () => void): () => void {\n let s = this.slots.get(key);\n if (!s) this.slots.set(key, (s = { tag, listeners: new Set(), entry: IDLE, version: 0, readVersion: ++this.version }));\n const slot = s;\n slot.listeners.add(listener);\n return () => {\n slot.listeners.delete(listener);\n // Kept across a StrictMode remount; dropped once no hook shows it.\n queueMicrotask(() => {\n if (slot.listeners.size || this.slots.get(key) !== slot) return;\n slot.ctl?.abort();\n slot.moreCtl?.abort();\n this.slots.delete(key);\n });\n };\n }\n\n snapshot<T>(key: string): Resource<T> {\n return (this.slots.get(key)?.entry ?? IDLE) as Resource<T>;\n }\n\n /** The latest fetchers of a key: its first read, and a list's next page. */\n bind(key: string, fetcher: Fetcher<unknown>, more?: Slot[\"more\"]): void {\n const s = this.slots.get(key);\n if (s) Object.assign(s, { fetcher, more });\n }\n\n /** Fetches unless loaded or in flight; force refetches (a list from its first page). */\n load(key: string, force = false): void {\n const s = this.slots.get(key);\n if (!s?.fetcher || (!force && (s.entry.loaded || s.ctl))) return;\n s.ctl?.abort();\n s.moreCtl?.abort();\n s.moreCtl = undefined;\n const ctl = (s.ctl = new AbortController());\n this.update(s, { loading: true, loadingMore: false, error: undefined });\n s.fetcher(ctl.signal).then(\n (data) => {\n if (s.ctl !== ctl) return;\n s.ctl = undefined;\n s.readVersion = ++this.version;\n this.update(s, { data, loading: false, loaded: true, error: undefined });\n },\n (e) => {\n if (s.ctl !== ctl) return;\n s.ctl = undefined;\n const error = toContentKitError(e);\n if (error.code !== \"aborted\") this.update(s, { loading: false, loaded: true, error });\n },\n );\n }\n\n /** Appends a list's next page; resolves once it landed. */\n async loadMore(key: string): Promise<void> {\n const s = this.slots.get(key);\n const page = s?.entry.data as Page<{ id: string }> | undefined;\n if (!s?.more || !page || page.next === null || s.moreCtl || s.ctl) return;\n const ctl = (s.moreCtl = new AbortController());\n this.update(s, { loadingMore: true });\n try {\n const next = (await s.more(page.next, ctl.signal)) as Page<{ id: string }>;\n if (s.moreCtl !== ctl) return;\n const cur = s.entry.data as Page<{ id: string }>;\n const seen = new Set(cur.items.map((x) => x.id));\n this.update(s, { data: { items: [...cur.items, ...next.items.filter((x) => !seen.has(x.id))], next: next.next }, error: undefined });\n } catch (e) {\n const error = toContentKitError(e);\n if (s.moreCtl === ctl && error.code !== \"aborted\") this.update(s, { error });\n } finally {\n if (s.moreCtl === ctl) {\n s.moreCtl = undefined;\n this.update(s, { loadingMore: false });\n }\n }\n }\n\n /** Replaces a key's data for every hook showing it. */\n set<T>(key: string, data: T | ((prev: T | undefined) => T)): void {\n const s = this.slots.get(key);\n if (!s) return;\n const next = typeof data === \"function\" ? (data as (p: T | undefined) => T)(s.entry.data as T | undefined) : data;\n s.readVersion = ++this.version;\n this.update(s, { data: next, loaded: true, error: undefined });\n }\n\n /** Starts an optimistic write on key: the token rollback() checks. */\n mark(key: string): number {\n const s = this.slots.get(key);\n return s ? (s.version = ++this.version) : 0;\n }\n\n /** Restores data unless a newer optimistic write started since mark(). */\n rollback<T>(key: string, token: number, data: T): void {\n const s = this.slots.get(key);\n if (s && s.version === token) this.update(s, { data, loaded: true });\n }\n\n /** Applies fn to matching slots, with the read identity for scoped rollback. */\n patch<T>(match: (tag: Tag) => boolean, fn: (data: T, readVersion: number) => T): void {\n for (const s of this.slots.values()) {\n if (s.entry.data !== undefined && match(s.tag)) this.update(s, { data: fn(s.entry.data as T, s.readVersion) });\n }\n }\n\n /** Refetches every shown slot whose tag matches. */\n invalidate(match: (tag: Tag) => boolean): void {\n for (const [key, s] of this.slots) if (match(s.tag) && s.listeners.size) this.load(key, true);\n }\n\n private apply(c: ContentKitChange, scope: string | null): void {\n const patch = <T>(match: (tag: Tag) => boolean, fn: (data: T) => T) => {\n this.patch<T>((t) => match(t) && (t.readScope ?? \"{}\") === scope, fn);\n this.invalidate((t) => match(t) && (t.readScope ?? \"{}\") !== scope);\n };\n const items = <T extends { id: string }>(types: string[], fn: (item: T) => T | null) =>\n patch<Page<T>>(\n (t) => types.includes(t.type),\n (page) => {\n let changed = false;\n const out: T[] = [];\n for (const it of page.items) {\n const next = fn(it);\n if (next !== it) changed = true;\n if (next) out.push(next);\n }\n return changed ? { ...page, items: out } : page;\n },\n );\n const comments = [\"comments\", \"replies\", \"latest\", \"admin-comments\"];\n // Cards in lists (pages) and rails (arrays) show a content's counts and the viewer's state.\n const cards = (id: string, fn: (card: Card) => Card) =>\n patch<Page<Card> | Card[]>(\n (t) => t.type === \"cards\" || t.type === \"history\",\n (data) => {\n const each = (list: Card[]) => (list.some((x) => x.id === id) ? list.map((x) => (x.id === id ? fn(x) : x)) : list);\n if (Array.isArray(data)) return each(data);\n const items = each(data.items);\n return items === data.items ? data : { ...data, items };\n },\n );\n switch (c.type) {\n case \"notifications.updated\":\n this.updateNotification(c.item, scope);\n break;\n case \"notifications.changed\":\n this.invalidate((t) => t.type === \"notifications\");\n break;\n case \"comment.created\": {\n const parent = c.comment.reply_to_id;\n const published = !c.comment.moderation;\n const add = (t: Tag) => (parent ? t.type === \"replies\" && t.id === parent : t.type === \"comments\" && sameTarget(t.target, c.target));\n patch<Page<Comment>>(add, (p) => (p.items.some((x) => x.id === c.comment.id) ? p : { ...p, items: parent ? [...p.items, c.comment] : [c.comment, ...p.items] }));\n if (parent && published) items<Comment>([\"comments\"], (x) => (x.id === parent ? { ...x, reply_count: x.reply_count + 1 } : x));\n this.invalidate((t) => t.type === \"latest\" || t.type === \"admin-comments\");\n break;\n }\n case \"comment.updated\":\n items<Comment>(comments, (x) => (x.id === c.comment.id ? { ...x, ...c.comment, author: c.comment.author ?? x.author } : x));\n break;\n case \"comment.reacted\":\n items<Comment>(comments, (x) => (x.id === c.id ? { ...x, ...c.counts } : x));\n break;\n case \"comment.deleted\": {\n let parent: string | undefined;\n items<Comment>([\"comments\", \"replies\"], (x) => {\n if (x.id !== c.id || x.deleted) return x;\n if (!x.moderation) parent = x.reply_to_id;\n return { ...x, deleted: true, body: \"[deleted]\", author: undefined, user_id: undefined, anon_name: undefined };\n });\n if (parent) items<Comment>([\"comments\"], (x) => (x.id === parent ? { ...x, reply_count: Math.max(0, x.reply_count - 1) } : x));\n items<Comment>([\"latest\"], (x) => (x.id === c.id ? null : x));\n items<Comment & { deleted_at?: string }>([\"admin-comments\"], (x) => (x.id === c.id ? { ...x, deleted: true, deleted_at: new Date().toISOString() } : x));\n break;\n }\n case \"comment.restored\":\n this.invalidate((t) => comments.includes(t.type));\n break;\n case \"reaction.changed\":\n patch((t) => t.type === \"reaction\" && sameTarget(t.target, c.target), () => c.counts);\n if (c.target.type === \"contents\") cards(c.target.id, (x) => ({ ...x, counts: { ...x.counts, likes: c.counts.likes, dislikes: c.counts.dislikes } }));\n this.invalidate((t) => t.type === \"reactions\");\n break;\n case \"favorite.changed\":\n patch((t) => t.type === \"favorite\" && sameTarget(t.target, c.target), () => ({ favorited: c.favorited, count: c.count }));\n if (c.target.type === \"contents\")\n cards(c.target.id, (x) => ({ ...x, counts: { ...x.counts, favorites: c.count }, viewer: x.viewer && { ...x.viewer, favorited: c.favorited } }));\n this.invalidate((t) => t.type === \"favorites\");\n break;\n case \"content.saved\":\n patch<Content | null>((t) => t.type === \"content\" && t.id === c.content.id, () => c.content);\n // A state, kind or text change can move it between lists: refetch them.\n this.invalidate((t) => t.type === \"contents\" || t.type === \"cards\" || (t.type === \"content-detail\" && t.id === c.content.id));\n break;\n case \"content.changed\":\n this.invalidate((t) => ((t.type === \"content\" || t.type === \"content-detail\") && t.id === c.id) || t.type === \"contents\" || t.type === \"cards\");\n break;\n case \"content.deleted\":\n items<{ id: string }>([\"contents\", \"cards\", \"history\"], (x) => (x.id === c.id ? null : x));\n this.invalidate((t) => ((t.type === \"content\" || t.type === \"content-detail\") && t.id === c.id) || (t.type === \"contents\" && t.scope === \"deleted\"));\n break;\n case \"poll.created\":\n this.invalidate((t) => t.type === \"polls\" || (t.type === \"poll\" && !t.id));\n break;\n case \"poll.updated\":\n // A latest-poll slot has no id in its tag: match by the poll it holds.\n patch<Poll | null>((t) => t.type === \"poll\", (p) => (p?.id === c.poll.id ? c.poll : p));\n items<Poll>([\"polls\"], (x) => (x.id === c.poll.id ? c.poll : x));\n break;\n case \"poll.changed\":\n this.invalidate((t) => (t.type === \"poll\" && (t.id === c.id || !t.id)) || t.type === \"polls\");\n break;\n case \"poll.deleted\":\n items<Poll>([\"polls\"], (x) => (x.id === c.id ? null : x));\n this.invalidate((t) => t.type === \"poll\" && !t.id);\n break;\n case \"ban.saved\":\n case \"ban.lifted\":\n this.invalidate((t) => (t.type === \"bans\" && t.scope === c.scope) || t.type === \"standing\");\n break;\n case \"groups.changed\":\n this.invalidate((t) => t.type.startsWith(\"group\"));\n break;\n case \"contentFilters.changed\":\n this.invalidate((t) => t.type === \"cards\" || t.type === \"history\" || t.type === \"release-dates\");\n break;\n case \"access.changed\":\n this.invalidate((t) => t.type === \"cards\" || t.type === \"history\" || t.type === \"content-detail\" || t.type === \"reader-plan\" || t.type.startsWith(\"group\"));\n break;\n case \"history.changed\":\n this.invalidate((t) => t.type === \"history\" || t.type === \"cards\");\n break;\n case \"searches.changed\":\n this.invalidate((t) => t.type === \"searches\");\n break;\n case \"moderation.resolved\":\n items<{ id: string }>([\"held\"], (x) => (x.id === c.id ? null : x));\n if (c.kind === \"comment\") this.invalidate((t) => comments.includes(t.type));\n else this.invalidate((t) => (t.type === \"content\" && t.id === c.id) || t.type === \"contents\");\n break;\n }\n }\n\n // Preserve loaded pages and canonical receipt revisions. Reads that started\n // before a successful mutation cannot overwrite it when they finish later.\n private updateNotification(item: Item, scope: string | null): void {\n for (const [key, slot] of this.slots) {\n if (slot.tag.type !== \"notifications\" || !slot.listeners.size) continue;\n const page = slot.entry.data as Page<Item> | undefined;\n const cached = page?.items.find((n) => n.id === item.id);\n // Mutations from separate mounted views can complete out of order.\n // In particular, an old active receipt must not evict a newer archive.\n if ((slot.tag.readScope ?? \"{}\") === scope && cached && cached.revision > item.revision) continue;\n const archived = slot.tag.scope?.startsWith(\"archived:\") ?? false;\n const matches = archived === !!item.dismissed_at;\n if ((slot.tag.readScope ?? \"{}\") !== scope || !page || slot.tag.scope?.endsWith(\":unread\") || (matches && !page.items.some((n) => n.id === item.id))) {\n this.load(key, true);\n continue;\n }\n if (!matches && !page.items.some((n) => n.id === item.id)) continue;\n slot.ctl?.abort();\n slot.moreCtl?.abort();\n slot.ctl = slot.moreCtl = undefined;\n this.update(slot, { loading: false, loadingMore: false, data: { ...page, items: page.items.flatMap((n) => n.id === item.id ? matches ? [item] : [] : [n]) } });\n }\n }\n\n // A new entry per change: useSyncExternalStore compares snapshots by identity.\n private update(s: Slot, patch: Partial<Resource<unknown>>): void {\n s.entry = { ...s.entry, ...patch };\n for (const l of s.listeners) l();\n }\n}\n\nconst stores = new WeakMap<ContentKitClient, ResourceStore>();\n\n/** The client's shared content store. */\nexport function resourcesFor(client: ContentKitClient): ResourceStore {\n let s = stores.get(client);\n if (!s) stores.set(client, (s = new ResourceStore(client)));\n return s;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"resources.js","names":[],"sources":["../../src/react/resources.ts"],"sourcesContent":["import type { ContentKitClient } from \"../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../client/errors.js\";\nimport { sameTarget, type Target } from \"../client/content/types.js\";\nimport type { Card, Comment, Content, Item, Poll } from \"../client/generated/wire.js\";\nimport type { ContentKitChange } from \"../client/http.js\";\n\n/** One shared read: its data, whether a fetch is in flight, and its last failure. */\nexport interface Resource<T> {\n data: T | undefined;\n loading: boolean;\n /** A fetch or set has completed. */\n loaded: boolean;\n /** A list's next page is in flight. */\n loadingMore?: boolean;\n error?: ContentKitError;\n}\n\n/** A page of a list and how to get the next one (null: no more). */\nexport interface Page<T> {\n items: T[];\n next: string | number | null;\n}\n\nexport type Fetcher<T> = (signal: AbortSignal) => Promise<T>;\n\n/** What a slot holds, for matching changes: its resource type and the ids it depends on. */\nexport interface Tag {\n type: string;\n readScope?: string;\n target?: Target;\n id?: string;\n scope?: string;\n}\n\ninterface Slot {\n tag: Tag;\n listeners: Set<() => void>;\n entry: Resource<unknown>;\n fetcher?: Fetcher<unknown>;\n more?: (cursor: string | number, signal: AbortSignal) => Promise<Page<unknown>>;\n ctl?: AbortController;\n moreCtl?: AbortController;\n /** Bumped by mark(): an optimistic write rolls back only if no newer one started. */\n version: number;\n /** Identifies the full read; item patches and appended pages retain it. */\n readVersion: number;\n}\n\nconst IDLE: Resource<never> = { data: undefined, loading: false, loaded: false };\n\n/**\n * The content reads hooks share, per client: one request per key while any\n * hook shows it, optimistic writes with rollback, and every change the client\n * makes applied in place (or refetched) for every hook showing it.\n */\nexport class ResourceStore {\n private readonly slots = new Map<string, Slot>();\n // Tokens must remain unique when a scope leaves and its slots are recreated.\n private version = 0;\n\n constructor(client: ContentKitClient) {\n client.subscribe((c, scope) => this.apply(c, scope));\n }\n\n subscribe(key: string, tag: Tag, listener: () => void): () => void {\n let s = this.slots.get(key);\n if (!s) this.slots.set(key, (s = { tag, listeners: new Set(), entry: IDLE, version: 0, readVersion: ++this.version }));\n const slot = s;\n slot.listeners.add(listener);\n return () => {\n slot.listeners.delete(listener);\n // Kept across a StrictMode remount; dropped once no hook shows it.\n queueMicrotask(() => {\n if (slot.listeners.size || this.slots.get(key) !== slot) return;\n slot.ctl?.abort();\n slot.moreCtl?.abort();\n this.slots.delete(key);\n });\n };\n }\n\n snapshot<T>(key: string): Resource<T> {\n return (this.slots.get(key)?.entry ?? IDLE) as Resource<T>;\n }\n\n /** The latest fetchers of a key: its first read, and a list's next page. */\n bind(key: string, fetcher: Fetcher<unknown>, more?: Slot[\"more\"]): void {\n const s = this.slots.get(key);\n if (s) Object.assign(s, { fetcher, more });\n }\n\n /** Fetches unless loaded or in flight; force refetches (a list from its first page). */\n load(key: string, force = false): void {\n const s = this.slots.get(key);\n if (!s?.fetcher || (!force && (s.entry.loaded || s.ctl))) return;\n s.ctl?.abort();\n s.moreCtl?.abort();\n s.moreCtl = undefined;\n const ctl = (s.ctl = new AbortController());\n this.update(s, { loading: true, loadingMore: false, error: undefined });\n s.fetcher(ctl.signal).then(\n (data) => {\n if (s.ctl !== ctl) return;\n s.ctl = undefined;\n s.readVersion = ++this.version;\n this.update(s, { data, loading: false, loaded: true, error: undefined });\n },\n (e) => {\n if (s.ctl !== ctl) return;\n s.ctl = undefined;\n const error = toContentKitError(e);\n if (error.code !== \"aborted\") this.update(s, { loading: false, loaded: true, error });\n },\n );\n }\n\n /** Appends a list's next page; resolves once it landed. */\n async loadMore(key: string): Promise<void> {\n const s = this.slots.get(key);\n const page = s?.entry.data as Page<{ id: string }> | undefined;\n if (!s?.more || !page || page.next === null || s.moreCtl || s.ctl) return;\n const ctl = (s.moreCtl = new AbortController());\n this.update(s, { loadingMore: true });\n try {\n const next = (await s.more(page.next, ctl.signal)) as Page<{ id: string }>;\n if (s.moreCtl !== ctl) return;\n const cur = s.entry.data as Page<{ id: string }>;\n const seen = new Set(cur.items.map((x) => x.id));\n this.update(s, { data: { items: [...cur.items, ...next.items.filter((x) => !seen.has(x.id))], next: next.next }, error: undefined });\n } catch (e) {\n const error = toContentKitError(e);\n if (s.moreCtl === ctl && error.code !== \"aborted\") this.update(s, { error });\n } finally {\n if (s.moreCtl === ctl) {\n s.moreCtl = undefined;\n this.update(s, { loadingMore: false });\n }\n }\n }\n\n /** Replaces a key's data for every hook showing it. */\n set<T>(key: string, data: T | ((prev: T | undefined) => T)): void {\n const s = this.slots.get(key);\n if (!s) return;\n const next = typeof data === \"function\" ? (data as (p: T | undefined) => T)(s.entry.data as T | undefined) : data;\n s.readVersion = ++this.version;\n this.update(s, { data: next, loaded: true, error: undefined });\n }\n\n /** Starts an optimistic write on key: the token rollback() checks. */\n mark(key: string): number {\n const s = this.slots.get(key);\n return s ? (s.version = ++this.version) : 0;\n }\n\n /** Restores data unless a newer optimistic write started since mark(). */\n rollback<T>(key: string, token: number, data: T): void {\n const s = this.slots.get(key);\n if (s && s.version === token) this.update(s, { data, loaded: true });\n }\n\n /** Applies fn to matching slots, with the read identity for scoped rollback. */\n patch<T>(match: (tag: Tag) => boolean, fn: (data: T, readVersion: number) => T): void {\n for (const s of this.slots.values()) {\n if (s.entry.data !== undefined && match(s.tag)) this.update(s, { data: fn(s.entry.data as T, s.readVersion) });\n }\n }\n\n /** Refetches every shown slot whose tag matches. */\n invalidate(match: (tag: Tag) => boolean): void {\n for (const [key, s] of this.slots) if (match(s.tag) && s.listeners.size) this.load(key, true);\n }\n\n private apply(c: ContentKitChange, scope: string | null): void {\n const patch = <T>(match: (tag: Tag) => boolean, fn: (data: T) => T) => {\n this.patch<T>((t) => match(t) && (t.readScope ?? \"{}\") === scope, fn);\n this.invalidate((t) => match(t) && (t.readScope ?? \"{}\") !== scope);\n };\n const items = <T extends { id: string }>(types: string[], fn: (item: T) => T | null) =>\n patch<Page<T>>(\n (t) => types.includes(t.type),\n (page) => {\n let changed = false;\n const out: T[] = [];\n for (const it of page.items) {\n const next = fn(it);\n if (next !== it) changed = true;\n if (next) out.push(next);\n }\n return changed ? { ...page, items: out } : page;\n },\n );\n const comments = [\"comments\", \"replies\", \"latest\", \"admin-comments\"];\n // Cards in lists (pages) and rails (arrays) show a content's counts and the viewer's state.\n const cards = (id: string, fn: (card: Card) => Card) =>\n patch<Page<Card> | Card[]>(\n (t) => t.type === \"cards\" || t.type === \"history\",\n (data) => {\n const each = (list: Card[]) => (list.some((x) => x.id === id) ? list.map((x) => (x.id === id ? fn(x) : x)) : list);\n if (Array.isArray(data)) return each(data);\n const items = each(data.items);\n return items === data.items ? data : { ...data, items };\n },\n );\n switch (c.type) {\n case \"notifications.updated\":\n this.updateNotification(c.item, scope);\n break;\n case \"notifications.changed\":\n this.invalidate((t) => t.type === \"notifications\");\n break;\n case \"comment.created\": {\n const parent = c.comment.reply_to_id;\n const published = !c.comment.moderation;\n const add = (t: Tag) => (parent ? t.type === \"replies\" && t.id === parent : t.type === \"comments\" && sameTarget(t.target, c.target));\n patch<Page<Comment>>(add, (p) => (p.items.some((x) => x.id === c.comment.id) ? p : { ...p, items: parent ? [...p.items, c.comment] : [c.comment, ...p.items] }));\n if (parent && published) items<Comment>([\"comments\"], (x) => (x.id === parent ? { ...x, reply_count: x.reply_count + 1 } : x));\n this.invalidate((t) => t.type === \"latest\" || t.type === \"admin-comments\");\n break;\n }\n case \"comment.updated\":\n items<Comment>(comments, (x) => (x.id === c.comment.id ? { ...x, ...c.comment, author: c.comment.author ?? x.author } : x));\n break;\n case \"comment.reacted\":\n items<Comment>(comments, (x) => (x.id === c.id ? { ...x, ...c.counts } : x));\n break;\n case \"comment.deleted\": {\n let parent: string | undefined;\n items<Comment>([\"comments\", \"replies\"], (x) => {\n if (x.id !== c.id || x.deleted) return x;\n if (!x.moderation) parent = x.reply_to_id;\n return { ...x, deleted: true, body: \"[deleted]\", author: undefined, user_id: undefined, anon_name: undefined };\n });\n if (parent) items<Comment>([\"comments\"], (x) => (x.id === parent ? { ...x, reply_count: Math.max(0, x.reply_count - 1) } : x));\n items<Comment>([\"latest\"], (x) => (x.id === c.id ? null : x));\n items<Comment & { deleted_at?: string }>([\"admin-comments\"], (x) => (x.id === c.id ? { ...x, deleted: true, deleted_at: new Date().toISOString() } : x));\n break;\n }\n case \"comment.restored\":\n this.invalidate((t) => comments.includes(t.type));\n break;\n case \"reaction.changed\":\n patch((t) => t.type === \"reaction\" && sameTarget(t.target, c.target), () => c.counts);\n if (c.target.type === \"contents\") cards(c.target.id, (x) => ({ ...x, counts: { ...x.counts, likes: c.counts.likes, dislikes: c.counts.dislikes } }));\n this.invalidate((t) => t.type === \"reactions\");\n break;\n case \"favorite.changed\":\n patch((t) => t.type === \"favorite\" && sameTarget(t.target, c.target), () => ({ favorited: c.favorited, count: c.count }));\n if (c.target.type === \"contents\")\n cards(c.target.id, (x) => ({ ...x, counts: { ...x.counts, favorites: c.count }, viewer: x.viewer && { ...x.viewer, favorited: c.favorited } }));\n this.invalidate((t) => t.type === \"favorites\");\n break;\n case \"content.saved\":\n patch<Content | null>((t) => t.type === \"content\" && t.id === c.content.id, () => c.content);\n // A state, kind or text change can move it between lists: refetch them.\n this.invalidate((t) => t.type === \"contents\" || t.type === \"cards\" || (t.type === \"content-detail\" && t.id === c.content.id));\n break;\n case \"content.changed\":\n this.invalidate((t) => ((t.type === \"content\" || t.type === \"content-detail\") && t.id === c.id) || t.type === \"contents\" || t.type === \"cards\");\n break;\n case \"content.deleted\":\n items<{ id: string }>([\"contents\", \"cards\", \"history\"], (x) => (x.id === c.id ? null : x));\n this.invalidate((t) => ((t.type === \"content\" || t.type === \"content-detail\") && t.id === c.id) || (t.type === \"contents\" && t.scope === \"deleted\"));\n break;\n case \"poll.created\":\n this.invalidate((t) => t.type === \"polls\" || (t.type === \"poll\" && !t.id));\n break;\n case \"poll.updated\":\n // A latest-poll slot has no id in its tag: match by the poll it holds.\n patch<Poll | null>((t) => t.type === \"poll\", (p) => (p?.id === c.poll.id ? c.poll : p));\n items<Poll>([\"polls\"], (x) => (x.id === c.poll.id ? c.poll : x));\n break;\n case \"poll.changed\":\n this.invalidate((t) => (t.type === \"poll\" && (t.id === c.id || !t.id)) || t.type === \"polls\");\n break;\n case \"poll.deleted\":\n items<Poll>([\"polls\"], (x) => (x.id === c.id ? null : x));\n this.invalidate((t) => t.type === \"poll\" && !t.id);\n break;\n case \"ban.saved\":\n case \"ban.lifted\":\n this.invalidate((t) => (t.type === \"bans\" && t.scope === c.scope) || t.type === \"standing\");\n break;\n case \"groups.changed\":\n this.invalidate((t) => t.type.startsWith(\"group\"));\n break;\n case \"contentFilters.changed\":\n this.invalidate((t) => t.type === \"cards\" || t.type === \"history\" || t.type === \"release-dates\");\n break;\n case \"access.changed\":\n this.invalidate((t) => t.type === \"cards\" || t.type === \"history\" || t.type === \"content-detail\" || t.type === \"reader-plan\" || t.type.startsWith(\"group\"));\n break;\n case \"history.changed\":\n this.invalidate((t) => t.type === \"history\" || t.type === \"cards\");\n break;\n case \"searches.changed\":\n this.invalidate((t) => t.type === \"searches\");\n break;\n case \"rules.changed\":\n this.invalidate((t) => t.type === \"moderation-rules\" && t.scope === c.rules);\n break;\n case \"reader.changed\":\n this.invalidate((t) => t.type === \"reader-plan\" && t.id === c.version);\n break;\n case \"moderation.resolved\":\n items<{ id: string }>([\"held\"], (x) => (x.id === c.id ? null : x));\n if (c.kind === \"comment\") this.invalidate((t) => comments.includes(t.type));\n else this.invalidate((t) => (t.type === \"content\" && t.id === c.id) || t.type === \"contents\");\n break;\n }\n }\n\n // Preserve loaded pages and canonical receipt revisions. Reads that started\n // before a successful mutation cannot overwrite it when they finish later.\n private updateNotification(item: Item, scope: string | null): void {\n for (const [key, slot] of this.slots) {\n if (slot.tag.type !== \"notifications\" || !slot.listeners.size) continue;\n const page = slot.entry.data as Page<Item> | undefined;\n const cached = page?.items.find((n) => n.id === item.id);\n // Mutations from separate mounted views can complete out of order.\n // In particular, an old active receipt must not evict a newer archive.\n if ((slot.tag.readScope ?? \"{}\") === scope && cached && cached.revision > item.revision) continue;\n const archived = slot.tag.scope?.startsWith(\"archived:\") ?? false;\n const matches = archived === !!item.dismissed_at;\n if ((slot.tag.readScope ?? \"{}\") !== scope || !page || slot.tag.scope?.endsWith(\":unread\") || (matches && !page.items.some((n) => n.id === item.id))) {\n this.load(key, true);\n continue;\n }\n if (!matches && !page.items.some((n) => n.id === item.id)) continue;\n slot.ctl?.abort();\n slot.moreCtl?.abort();\n slot.ctl = slot.moreCtl = undefined;\n this.update(slot, { loading: false, loadingMore: false, data: { ...page, items: page.items.flatMap((n) => n.id === item.id ? matches ? [item] : [] : [n]) } });\n }\n }\n\n // A new entry per change: useSyncExternalStore compares snapshots by identity.\n private update(s: Slot, patch: Partial<Resource<unknown>>): void {\n s.entry = { ...s.entry, ...patch };\n for (const l of s.listeners) l();\n }\n}\n\nconst stores = new WeakMap<ContentKitClient, ResourceStore>();\n\n/** The client's shared content store. */\nexport function resourcesFor(client: ContentKitClient): ResourceStore {\n let s = stores.get(client);\n if (!s) stores.set(client, (s = new ResourceStore(client)));\n return s;\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { ContentKitClient } from '../client/client.js';
2
+ import { ContentKitError } from '../client/errors.js';
3
+ import { Activity, MyStats, TopContents } from '../client/generated/wire.js';
4
+ import { ActivityQuery, TopQuery } from '../client/stats.js';
5
+ export interface UseStats<T> {
6
+ data: T | null;
7
+ loading: boolean;
8
+ error?: ContentKitError;
9
+ /** The site runs without the signal plane (not_configured). */
10
+ unavailable: boolean;
11
+ reload: () => void;
12
+ }
13
+ /** Staff: a kind's views per UTC day, newest first; null reads nothing. */
14
+ export declare function useActivity(q: ActivityQuery | null, o?: {
15
+ client?: ContentKitClient;
16
+ }): UseStats<Activity>;
17
+ /** Staff: a kind's content ranked by views or comments over a period; null reads nothing. */
18
+ export declare function useTopContents(q: TopQuery | null, o?: {
19
+ client?: ContentKitClient;
20
+ }): UseStats<TopContents>;
21
+ /** The signed-in reader's statistics; nothing signed out. */
22
+ export declare function useMyStats(o?: {
23
+ client?: ContentKitClient;
24
+ }): UseStats<MyStats>;
@@ -0,0 +1,28 @@
1
+ import { keyOf as e, useContentScope as t, useResource as n } from "./use-resource.js";
2
+ //#region src/react/stats.ts
3
+ function r(e, r, i) {
4
+ let { client: a, store: o } = t(i.client), s = n(o, e, { type: "stats" }, (e) => r(a, e)), c = s.error?.code === "not_configured";
5
+ return {
6
+ data: s.data ?? null,
7
+ loading: !!e && (s.loading || !s.loaded),
8
+ error: c ? void 0 : s.error,
9
+ unavailable: c,
10
+ reload: s.reload
11
+ };
12
+ }
13
+ function i(n, i = {}) {
14
+ let { scope: a } = t(i.client);
15
+ return r(n ? e("stats", a, "activity", n.kind, n.days) : null, (e, t) => e.stats.activity(n, t), i);
16
+ }
17
+ function a(n, i = {}) {
18
+ let { scope: a } = t(i.client);
19
+ return r(n ? e("stats", a, "top", n) : null, (e, t) => e.stats.top(n, t), i);
20
+ }
21
+ function o(n = {}) {
22
+ let { scope: i, viewer: a } = t(n.client);
23
+ return r(a === null ? null : e("stats", i, "me"), (e, t) => e.stats.mine(t), n);
24
+ }
25
+ //#endregion
26
+ export { i as useActivity, o as useMyStats, a as useTopContents };
27
+
28
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","names":[],"sources":["../../src/react/stats.ts"],"sourcesContent":["import type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport type { Activity, MyStats, TopContents } from \"../client/generated/wire.js\";\nimport type { ActivityQuery, TopQuery } from \"../client/stats.js\";\nimport { keyOf, useContentScope, useResource } from \"./use-resource.js\";\n\nexport interface UseStats<T> {\n data: T | null;\n loading: boolean;\n error?: ContentKitError;\n /** The site runs without the signal plane (not_configured). */\n unavailable: boolean;\n reload: () => void;\n}\n\nfunction useStats<T>(key: string | null, fetch: (c: ContentKitClient, signal: AbortSignal) => Promise<T>, o: { client?: ContentKitClient }): UseStats<T> {\n const { client, store } = useContentScope(o.client);\n const r = useResource<T>(store, key, { type: \"stats\" }, (signal) => fetch(client, signal));\n const unavailable = r.error?.code === \"not_configured\";\n return { data: r.data ?? null, loading: !!key && (r.loading || !r.loaded), error: unavailable ? undefined : r.error, unavailable, reload: r.reload };\n}\n\n/** Staff: a kind's views per UTC day, newest first; null reads nothing. */\nexport function useActivity(q: ActivityQuery | null, o: { client?: ContentKitClient } = {}): UseStats<Activity> {\n const { scope } = useContentScope(o.client);\n return useStats(q ? keyOf(\"stats\", scope, \"activity\", q.kind, q.days) : null, (c, s) => c.stats.activity(q!, s), o);\n}\n\n/** Staff: a kind's content ranked by views or comments over a period; null reads nothing. */\nexport function useTopContents(q: TopQuery | null, o: { client?: ContentKitClient } = {}): UseStats<TopContents> {\n const { scope } = useContentScope(o.client);\n return useStats(q ? keyOf(\"stats\", scope, \"top\", q) : null, (c, s) => c.stats.top(q!, s), o);\n}\n\n/** The signed-in reader's statistics; nothing signed out. */\nexport function useMyStats(o: { client?: ContentKitClient } = {}): UseStats<MyStats> {\n const { scope, viewer } = useContentScope(o.client);\n return useStats(viewer === null ? null : keyOf(\"stats\", scope, \"me\"), (c, s) => c.stats.mine(s), o);\n}\n"],"mappings":";;AAeA,SAAS,EAAY,GAAoB,GAAiE,GAA+C;CACvJ,IAAM,EAAE,WAAQ,aAAU,EAAgB,EAAE,MAAM,GAC5C,IAAI,EAAe,GAAO,GAAK,EAAE,MAAM,QAAQ,IAAI,MAAW,EAAM,GAAQ,CAAM,CAAC,GACnF,IAAc,EAAE,OAAO,SAAS;CACtC,OAAO;EAAE,MAAM,EAAE,QAAQ;EAAM,SAAS,CAAC,CAAC,MAAQ,EAAE,WAAW,CAAC,EAAE;EAAS,OAAO,IAAc,KAAA,IAAY,EAAE;EAAO;EAAa,QAAQ,EAAE;CAAO;AACrJ;AAGA,SAAgB,EAAY,GAAyB,IAAmC,CAAC,GAAuB;CAC9G,IAAM,EAAE,aAAU,EAAgB,EAAE,MAAM;CAC1C,OAAO,EAAS,IAAI,EAAM,SAAS,GAAO,YAAY,EAAE,MAAM,EAAE,IAAI,IAAI,OAAO,GAAG,MAAM,EAAE,MAAM,SAAS,GAAI,CAAC,GAAG,CAAC;AACpH;AAGA,SAAgB,EAAe,GAAoB,IAAmC,CAAC,GAA0B;CAC/G,IAAM,EAAE,aAAU,EAAgB,EAAE,MAAM;CAC1C,OAAO,EAAS,IAAI,EAAM,SAAS,GAAO,OAAO,CAAC,IAAI,OAAO,GAAG,MAAM,EAAE,MAAM,IAAI,GAAI,CAAC,GAAG,CAAC;AAC7F;AAGA,SAAgB,EAAW,IAAmC,CAAC,GAAsB;CACnF,IAAM,EAAE,UAAO,cAAW,EAAgB,EAAE,MAAM;CAClD,OAAO,EAAS,MAAW,OAAO,OAAO,EAAM,SAAS,GAAO,IAAI,IAAI,GAAG,MAAM,EAAE,MAAM,KAAK,CAAC,GAAG,CAAC;AACpG"}
@@ -44,10 +44,11 @@ function f(e, t, r, a, l = {}) {
44
44
  reload: y
45
45
  };
46
46
  }
47
- function p(e, t, n, r) {
47
+ var p = [];
48
+ function m(e, t, n, r) {
48
49
  let a = f(e, t, n, (e) => r(void 0, e), { more: (e, t) => r(e, t) }), o = i(() => t ? e.loadMore(t) : Promise.resolve(), [e, t]);
49
50
  return {
50
- items: a.data?.items ?? [],
51
+ items: a.data?.items ?? p,
51
52
  loading: a.loading || !!t && !a.loaded,
52
53
  loadingMore: !!a.loadingMore,
53
54
  error: a.error,
@@ -56,7 +57,7 @@ function p(e, t, n, r) {
56
57
  reload: a.reload
57
58
  };
58
59
  }
59
- function m(e, t, n = !1) {
60
+ function h(e, t, n = !1) {
60
61
  return async (r, i) => {
61
62
  let a = typeof r == "number" ? r : 0, o = await t({
62
63
  limit: e,
@@ -68,8 +69,8 @@ function m(e, t, n = !1) {
68
69
  };
69
70
  };
70
71
  }
71
- var h = (...e) => JSON.stringify(e);
72
- function g(e, t, n, r, i, a) {
72
+ var g = (...e) => JSON.stringify(e);
73
+ function _(e, t, n, r, i, a) {
73
74
  let o = (Math.max(1, r) - 1) * i, s = f(e, t === null ? null : `${t}#${o}`, n, async (e) => {
74
75
  let t = await a({
75
76
  limit: i + 1,
@@ -81,7 +82,7 @@ function g(e, t, n, r, i, a) {
81
82
  };
82
83
  });
83
84
  return {
84
- items: s.data?.items ?? [],
85
+ items: s.data?.items ?? p,
85
86
  loading: s.loading || !!t && !s.loaded,
86
87
  error: s.error,
87
88
  hasNext: s.data ? s.data.next !== null : !1,
@@ -89,6 +90,6 @@ function g(e, t, n, r, i, a) {
89
90
  };
90
91
  }
91
92
  //#endregion
92
- export { h as keyOf, m as offsetPages, l as useContentScope, p as useList, g as usePaged, f as useResource };
93
+ export { g as keyOf, h as offsetPages, l as useContentScope, m as useList, _ as usePaged, f as useResource };
93
94
 
94
95
  //# sourceMappingURL=use-resource.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-resource.js","names":[],"sources":["../../src/react/use-resource.ts"],"sourcesContent":["import { useCallback, useContext, useEffect, useRef, useSyncExternalStore } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport { ContentKitContext, useContentKitClient, useReadScope } from \"./context.js\";\nimport { resourcesFor, type Fetcher, type Page, type Resource, type ResourceStore, type Tag } from \"./resources.js\";\n\n/** The client, its shared store, and the provider's viewer, language and sign-in. */\nexport function useContentScope(own?: ContentKitClient | null) {\n const ctx = useContext(ContentKitContext);\n const client = useContentKitClient(own);\n return { client, store: resourcesFor(client), scope: useReadScope(), viewer: ctx?.viewer, language: ctx?.language, onSignIn: ctx?.onSignIn };\n}\n\nconst IDLE: Resource<never> = { data: undefined, loading: false, loaded: false };\nconst none = () => () => {};\n\n/** A shared read: fetched once per key while shown; initial is shown (and seeds the store) until it loads. */\nexport function useResource<T>(\n store: ResourceStore,\n key: string | null,\n tag: Tag,\n fetcher: Fetcher<T>,\n o: { initial?: T; more?: (cursor: string | number, signal: AbortSignal) => Promise<Page<unknown>> } = {},\n): Resource<T> & { reload: () => void } {\n const scope = useReadScope();\n const fetch = useRef(fetcher);\n const more = useRef(o.more);\n const initial = useRef(o.initial);\n useEffect(() => {\n fetch.current = fetcher;\n more.current = o.more;\n initial.current = o.initial;\n });\n const subscribe = useCallback(\n (l: () => void) => (key ? store.subscribe(key, { ...tag, readScope: scope }, l) : none()),\n // The tag is part of the key.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [store, key, scope],\n );\n const snapshot = useCallback(() => (key ? store.snapshot<T>(key) : IDLE), [store, key]);\n const entry = useSyncExternalStore(subscribe, snapshot, snapshot);\n useEffect(() => {\n if (!key) return;\n store.bind(key, (s) => fetch.current(s), more.current && ((c, s) => more.current!(c, s)));\n if (initial.current !== undefined && !store.snapshot(key).loaded && !store.snapshot(key).loading) store.set(key, initial.current);\n else store.load(key);\n }, [store, key]);\n const reload = useCallback(() => key && store.load(key, true), [store, key]);\n if (!entry.loaded && o.initial !== undefined) return { ...entry, data: o.initial, reload };\n return { ...entry, reload };\n}\n\n/** A shared list, a page at a time. */\nexport interface UseList<T> {\n items: T[];\n /** The first page is loading (also on reload). */\n loading: boolean;\n loadingMore: boolean;\n error?: ContentKitError;\n hasMore: boolean;\n loadMore: () => Promise<void>;\n reload: () => void;\n}\n\nexport type PageFetcher<T> = (cursor: string | number | undefined, signal: AbortSignal) => Promise<Page<T>>;\n\nexport function useList<T extends { id: string }>(store: ResourceStore, key: string | null, tag: Tag, page: PageFetcher<T>): UseList<T> {\n const r = useResource<Page<T>>(store, key, tag, (s) => page(undefined, s), { more: (c, s) => page(c, s) });\n const loadMore = useCallback(() => (key ? store.loadMore(key) : Promise.resolve()), [store, key]);\n return {\n items: r.data?.items ?? [],\n loading: r.loading || (!!key && !r.loaded),\n loadingMore: !!r.loadingMore,\n error: r.error,\n hasMore: r.data ? r.data.next !== null : false,\n loadMore,\n reload: r.reload,\n };\n}\n\n/**\n * A limit/offset list as pages. A full page means more may follow; with\n * underfill (the latest feed drops items the caller may not see) only an\n * empty page ends it.\n */\nexport function offsetPages<T>(limit: number, list: (q: { limit: number; offset: number }, signal: AbortSignal) => Promise<T[]>, underfill = false): PageFetcher<T> {\n return async (cursor, signal) => {\n const offset = typeof cursor === \"number\" ? cursor : 0;\n const items = await list({ limit, offset }, signal);\n const end = underfill ? items.length === 0 : items.length < limit;\n return { items, next: end ? null : offset + limit };\n };\n}\n\n/** A stable store key. */\nexport const keyOf = (...parts: unknown[]) => JSON.stringify(parts);\n\n/** One numbered page of a list. */\nexport interface UsePaged<T> {\n items: T[];\n loading: boolean;\n error?: ContentKitError;\n /** Another page follows. */\n hasNext: boolean;\n reload: () => void;\n}\n\n/** Page `page` (from 1) of a limit/offset list: one read of limit + 1 tells whether another follows. */\nexport function usePaged<T extends { id: string }>(\n store: ResourceStore,\n key: string | null,\n tag: Tag,\n page: number,\n limit: number,\n list: (q: { limit: number; offset: number }, signal: AbortSignal) => Promise<T[]>,\n): UsePaged<T> {\n const offset = (Math.max(1, page) - 1) * limit;\n const r = useResource<Page<T>>(store, key === null ? null : `${key}#${offset}`, tag, async (signal) => {\n const items = await list({ limit: limit + 1, offset }, signal);\n return { items: items.slice(0, limit), next: items.length > limit ? offset + limit : null };\n });\n return { items: r.data?.items ?? [], loading: r.loading || (!!key && !r.loaded), error: r.error, hasNext: r.data ? r.data.next !== null : false, reload: r.reload };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-resource.js","names":[],"sources":["../../src/react/use-resource.ts"],"sourcesContent":["import { useCallback, useContext, useEffect, useRef, useSyncExternalStore } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport { ContentKitContext, useContentKitClient, useReadScope } from \"./context.js\";\nimport { resourcesFor, type Fetcher, type Page, type Resource, type ResourceStore, type Tag } from \"./resources.js\";\n\n/** The client, its shared store, and the provider's viewer, language and sign-in. */\nexport function useContentScope(own?: ContentKitClient | null) {\n const ctx = useContext(ContentKitContext);\n const client = useContentKitClient(own);\n return { client, store: resourcesFor(client), scope: useReadScope(), viewer: ctx?.viewer, language: ctx?.language, onSignIn: ctx?.onSignIn };\n}\n\nconst IDLE: Resource<never> = { data: undefined, loading: false, loaded: false };\nconst none = () => () => {};\n\n/** A shared read: fetched once per key while shown; initial is shown (and seeds the store) until it loads. */\nexport function useResource<T>(\n store: ResourceStore,\n key: string | null,\n tag: Tag,\n fetcher: Fetcher<T>,\n o: { initial?: T; more?: (cursor: string | number, signal: AbortSignal) => Promise<Page<unknown>> } = {},\n): Resource<T> & { reload: () => void } {\n const scope = useReadScope();\n const fetch = useRef(fetcher);\n const more = useRef(o.more);\n const initial = useRef(o.initial);\n useEffect(() => {\n fetch.current = fetcher;\n more.current = o.more;\n initial.current = o.initial;\n });\n const subscribe = useCallback(\n (l: () => void) => (key ? store.subscribe(key, { ...tag, readScope: scope }, l) : none()),\n // The tag is part of the key.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [store, key, scope],\n );\n const snapshot = useCallback(() => (key ? store.snapshot<T>(key) : IDLE), [store, key]);\n const entry = useSyncExternalStore(subscribe, snapshot, snapshot);\n useEffect(() => {\n if (!key) return;\n store.bind(key, (s) => fetch.current(s), more.current && ((c, s) => more.current!(c, s)));\n if (initial.current !== undefined && !store.snapshot(key).loaded && !store.snapshot(key).loading) store.set(key, initial.current);\n else store.load(key);\n }, [store, key]);\n const reload = useCallback(() => key && store.load(key, true), [store, key]);\n if (!entry.loaded && o.initial !== undefined) return { ...entry, data: o.initial, reload };\n return { ...entry, reload };\n}\n\n/** A shared list, a page at a time. */\nexport interface UseList<T> {\n items: T[];\n /** The first page is loading (also on reload). */\n loading: boolean;\n loadingMore: boolean;\n error?: ContentKitError;\n hasMore: boolean;\n loadMore: () => Promise<void>;\n reload: () => void;\n}\n\nexport type PageFetcher<T> = (cursor: string | number | undefined, signal: AbortSignal) => Promise<Page<T>>;\n\n// The items of a list not loaded: one array, so effects keyed on items don't run every render.\nconst NO_ITEMS: never[] = [];\n\nexport function useList<T extends { id: string }>(store: ResourceStore, key: string | null, tag: Tag, page: PageFetcher<T>): UseList<T> {\n const r = useResource<Page<T>>(store, key, tag, (s) => page(undefined, s), { more: (c, s) => page(c, s) });\n const loadMore = useCallback(() => (key ? store.loadMore(key) : Promise.resolve()), [store, key]);\n return {\n items: r.data?.items ?? NO_ITEMS,\n loading: r.loading || (!!key && !r.loaded),\n loadingMore: !!r.loadingMore,\n error: r.error,\n hasMore: r.data ? r.data.next !== null : false,\n loadMore,\n reload: r.reload,\n };\n}\n\n/**\n * A limit/offset list as pages. A full page means more may follow; with\n * underfill (the latest feed drops items the caller may not see) only an\n * empty page ends it.\n */\nexport function offsetPages<T>(limit: number, list: (q: { limit: number; offset: number }, signal: AbortSignal) => Promise<T[]>, underfill = false): PageFetcher<T> {\n return async (cursor, signal) => {\n const offset = typeof cursor === \"number\" ? cursor : 0;\n const items = await list({ limit, offset }, signal);\n const end = underfill ? items.length === 0 : items.length < limit;\n return { items, next: end ? null : offset + limit };\n };\n}\n\n/** A stable store key. */\nexport const keyOf = (...parts: unknown[]) => JSON.stringify(parts);\n\n/** One numbered page of a list. */\nexport interface UsePaged<T> {\n items: T[];\n loading: boolean;\n error?: ContentKitError;\n /** Another page follows. */\n hasNext: boolean;\n reload: () => void;\n}\n\n/** Page `page` (from 1) of a limit/offset list: one read of limit + 1 tells whether another follows. */\nexport function usePaged<T extends { id: string }>(\n store: ResourceStore,\n key: string | null,\n tag: Tag,\n page: number,\n limit: number,\n list: (q: { limit: number; offset: number }, signal: AbortSignal) => Promise<T[]>,\n): UsePaged<T> {\n const offset = (Math.max(1, page) - 1) * limit;\n const r = useResource<Page<T>>(store, key === null ? null : `${key}#${offset}`, tag, async (signal) => {\n const items = await list({ limit: limit + 1, offset }, signal);\n return { items: items.slice(0, limit), next: items.length > limit ? offset + limit : null };\n });\n return { items: r.data?.items ?? NO_ITEMS, loading: r.loading || (!!key && !r.loaded), error: r.error, hasNext: r.data ? r.data.next !== null : false, reload: r.reload };\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { toContentKitError as e } from "../client/errors.js";
2
- import { useMediaRead as t } from "./read.js";
3
- import { keyOf as n, useContentScope as r, useResource as i } from "./use-resource.js";
2
+ import { keyOf as t, useContentScope as n, useResource as r } from "./use-resource.js";
3
+ import { useMediaRead as i } from "./read.js";
4
4
  import { isPending as a } from "../client/versions.js";
5
5
  import { useCallback as o, useEffect as s, useMemo as c, useState as l } from "react";
6
6
  //#region src/react/versions.ts
@@ -9,11 +9,11 @@ function d(e, t = Date.now()) {
9
9
  let n = (e?.segments ?? []).flatMap((e) => !e.released && e.release_at ? [Date.parse(e.release_at)] : []).filter((e) => e > t);
10
10
  return n.length ? Math.min(...n) : null;
11
11
  }
12
- function f(e, t, o = {}) {
13
- let { client: c, store: l, scope: f } = r(o.client), p = e && t ? n("reader-plan", f, e, t) : null, m = i(l, p, {
12
+ function f(e, i, o = {}) {
13
+ let { client: c, store: l, scope: f } = n(o.client), p = e && i ? t("reader-plan", f, e, i) : null, m = r(l, p, {
14
14
  type: "reader-plan",
15
- id: t ?? void 0
16
- }, (n) => c.versions.reader(e, t, n)), h = a(m.data), g = m.data && !h ? m.data : null, { data: _, reload: v } = m;
15
+ id: i ?? void 0
16
+ }, (t) => c.versions.reader(e, i, t)), h = a(m.data), g = m.data && !h ? m.data : null, { data: _, reload: v } = m;
17
17
  return s(() => {
18
18
  let e = a(_) ? Date.now() + (o.poll ?? 5e3) : d(_ || null);
19
19
  if (e === null) return;
@@ -31,44 +31,44 @@ function f(e, t, o = {}) {
31
31
  reload: v
32
32
  };
33
33
  }
34
- function p(e, n, r = {}) {
35
- let i = e?.item ?? null, a = t(i ?? {
34
+ function p(e, t, n = {}) {
35
+ let r = e?.item ?? null, a = i(r ?? {
36
36
  kind: "",
37
37
  id: ""
38
38
  }, {
39
- window: r.window,
40
- read: i ? void 0 : null,
41
- client: r.client
39
+ window: n.window,
40
+ read: r ? void 0 : null,
41
+ client: n.client
42
42
  });
43
43
  return {
44
44
  pages: c(() => {
45
- let t = new Map((a.read?.files ?? []).flatMap((e) => e.url ? [[e.path, e.url]] : []));
45
+ let n = new Map((a.read?.files ?? []).flatMap((e) => e.url ? [[e.path, e.url]] : []));
46
46
  return (e?.pages ?? []).map((e) => {
47
- let r = e.files[n];
47
+ let r = e.files[t];
48
48
  return {
49
49
  name: e.name,
50
50
  w: e.w,
51
51
  h: e.h,
52
- url: r ? t.get(r) : void 0
52
+ url: r ? n.get(r) : void 0
53
53
  };
54
54
  });
55
55
  }, [
56
56
  e,
57
- n,
57
+ t,
58
58
  a.read
59
59
  ]),
60
- loading: !!i && a.loading,
60
+ loading: !!r && a.loading,
61
61
  error: a.error
62
62
  };
63
63
  }
64
- function m(t, n, i = {}) {
65
- let { client: s } = r(i.client), [c, u] = l(!1), [d, f] = l();
64
+ function m(t, r, i = {}) {
65
+ let { client: s } = n(i.client), [c, u] = l(!1), [d, f] = l();
66
66
  return {
67
67
  download: o(async () => {
68
68
  f(void 0), u(!0);
69
69
  try {
70
70
  for (;;) {
71
- let e = await s.versions.download(t, n);
71
+ let e = await s.versions.download(t, r);
72
72
  if (!a(e)) return e;
73
73
  await new Promise((e) => setTimeout(e, i.poll ?? 3e3));
74
74
  }
@@ -81,7 +81,7 @@ function m(t, n, i = {}) {
81
81
  }, [
82
82
  s,
83
83
  t,
84
- n,
84
+ r,
85
85
  i.poll
86
86
  ]),
87
87
  preparing: c,
package/dist/react.js CHANGED
@@ -1,27 +1,29 @@
1
1
  import { HOVER_DELAY as e, InlinePreviewContext as t, useInlinePreview as n, useReducedMotion as r } from "./react/inline-preview.js";
2
2
  import { GuardContext as i, useContentKit as a, useContentKitClient as o, useContentURLs as s, useErrorReporter as c, useGuarded as l, useOptionalContentKitClient as u } from "./react/context.js";
3
3
  import { useCrop as d, useEncodeProgress as f, useUpload as p, useUploadQueue as m } from "./react/upload.js";
4
- import { useMediaRead as h } from "./react/read.js";
5
- import { usePresets as g, usePublicImage as _ } from "./react/public.js";
6
- import { editOutput as v, useSlotCrop as y, useSlotImage as b } from "./react/slot.js";
7
- import { round3 as x, useFrameStrip as S, useVideoFrame as C, useVideoImages as w, useVideoPoster as T } from "./react/video.js";
8
- import { GALLERY_VIEW_KEY as E, PLAYER_QUALITY_KEY as D, useCarousel as O, useGalleryView as k, useHlsPlayer as A, useRefreshBeforeExpiry as j } from "./react/gallery.js";
9
- import { useEditorCrop as M } from "./react/crop.js";
10
- import { nameIn as N, thumbnailOf as P, useMediaFolder as F } from "./react/folder.js";
11
- import { useNearViewport as I } from "./react/viewport.js";
12
- import { ResourceStore as L, resourcesFor as R } from "./react/resources.js";
13
- import { useContentScope as z, usePaged as B } from "./react/use-resource.js";
14
- import { useAdminComments as V, useCanComment as H, useCommentBans as U, useCommentReplies as W, useComments as G, useGlobalCommentBan as K, useLatestComments as q, useModerationQueue as J, withReaction as Y } from "./react/comments.js";
15
- import { useContentConfig as X } from "./react/config.js";
16
- import { useFavorite as Z, useReaction as Q } from "./react/engagement.js";
17
- import { usePoll as $, usePollEditor as ee, usePolls as te, withVote as ne } from "./react/polls.js";
18
- import { useAdminLocation as re, useFlowClient as ie, useStaffAccess as ae } from "./react/admin.js";
19
- import { memberId as oe, useContentGroups as se, useGroup as ce, useGroupMembers as le, useGroups as ue, useKinds as de, useMyGroups as fe } from "./react/groups.js";
20
- import { beaconsFor as pe, useBeacons as me, useContentFilters as he, useContents as ge, useExposure as _e, useHistory as ve, useMyFavorites as ye, useMyReactions as be, useRecentSearches as xe, useRecommendations as Se, useReleaseDates as Ce, useSearch as we, useSimilar as Te, useTypeahead as Ee, useViewSignal as De } from "./react/discovery.js";
21
- import { useContent as Oe, useManagedContents as ke } from "./react/contents.js";
22
- import { useNotificationUnread as Ae, useNotifications as je } from "./react/notifications.js";
23
- import { ContentKitProvider as Me } from "./react/provider.js";
24
- import { useCanonicalContent as Ne } from "./react/canonical.js";
25
- import { defaultVersion as Pe, liveVersions as Fe, useContentDetail as Ie } from "./react/detail.js";
26
- import { nextRelease as Le, useReaderPlan as Re, useSegmentPages as ze, useVersionDownload as Be } from "./react/versions.js";
27
- export { Me as ContentKitProvider, E as GALLERY_VIEW_KEY, i as GuardContext, e as HOVER_DELAY, t as InlinePreviewContext, D as PLAYER_QUALITY_KEY, L as ResourceStore, pe as beaconsFor, Pe as defaultVersion, v as editOutput, Fe as liveVersions, oe as memberId, N as nameIn, Le as nextRelease, R as resourcesFor, x as round3, P as thumbnailOf, V as useAdminComments, re as useAdminLocation, me as useBeacons, H as useCanComment, Ne as useCanonicalContent, O as useCarousel, U as useCommentBans, W as useCommentReplies, G as useComments, Oe as useContent, X as useContentConfig, Ie as useContentDetail, he as useContentFilters, se as useContentGroups, a as useContentKit, o as useContentKitClient, z as useContentScope, s as useContentURLs, ge as useContents, d as useCrop, M as useEditorCrop, f as useEncodeProgress, c as useErrorReporter, _e as useExposure, Z as useFavorite, ie as useFlowClient, S as useFrameStrip, k as useGalleryView, K as useGlobalCommentBan, ce as useGroup, le as useGroupMembers, ue as useGroups, l as useGuarded, ve as useHistory, A as useHlsPlayer, n as useInlinePreview, de as useKinds, q as useLatestComments, ke as useManagedContents, F as useMediaFolder, h as useMediaRead, J as useModerationQueue, ye as useMyFavorites, fe as useMyGroups, be as useMyReactions, I as useNearViewport, Ae as useNotificationUnread, je as useNotifications, u as useOptionalContentKitClient, B as usePaged, $ as usePoll, ee as usePollEditor, te as usePolls, g as usePresets, _ as usePublicImage, Q as useReaction, Re as useReaderPlan, xe as useRecentSearches, Se as useRecommendations, r as useReducedMotion, j as useRefreshBeforeExpiry, Ce as useReleaseDates, we as useSearch, ze as useSegmentPages, Te as useSimilar, y as useSlotCrop, b as useSlotImage, ae as useStaffAccess, Ee as useTypeahead, p as useUpload, m as useUploadQueue, Be as useVersionDownload, C as useVideoFrame, w as useVideoImages, T as useVideoPoster, De as useViewSignal, Y as withReaction, ne as withVote };
4
+ import { ResourceStore as h, resourcesFor as g } from "./react/resources.js";
5
+ import { useContentScope as _, usePaged as v } from "./react/use-resource.js";
6
+ import { memberId as y, useContentGroups as b, useGroup as x, useGroupMembers as S, useGroups as C, useKinds as w, useMyGroups as T } from "./react/groups.js";
7
+ import { useMediaRead as E } from "./react/read.js";
8
+ import { useAvatar as D, usePresets as O, usePublicImage as k } from "./react/public.js";
9
+ import { editOutput as A, useSlotCrop as j, useSlotImage as M } from "./react/slot.js";
10
+ import { round3 as N, useFrameStrip as P, useVideoFrame as F, useVideoImages as I, useVideoPoster as L } from "./react/video.js";
11
+ import { GALLERY_VIEW_KEY as R, PLAYER_QUALITY_KEY as z, useCarousel as B, useGalleryView as V, useHlsPlayer as H, useRefreshBeforeExpiry as U } from "./react/gallery.js";
12
+ import { useEditorCrop as W } from "./react/crop.js";
13
+ import { nameIn as G, thumbnailOf as K, useMediaFolder as q } from "./react/folder.js";
14
+ import { useNearViewport as J } from "./react/viewport.js";
15
+ import { useAdminComments as Y, useBannedWords as X, useCanComment as Z, useCommentBans as Q, useCommentReplies as $, useComments as ee, useGlobalCommentBan as te, useIPBans as ne, useLatestComments as re, useModerationQueue as ie, withReaction as ae } from "./react/comments.js";
16
+ import { useContentConfig as oe } from "./react/config.js";
17
+ import { useFavorite as se, useReaction as ce } from "./react/engagement.js";
18
+ import { usePoll as le, usePollEditor as ue, usePolls as de, withVote as fe } from "./react/polls.js";
19
+ import { useVersionParam as pe } from "./react/location.js";
20
+ import { useAdminLocation as me, useFlowClient as he, useStaffAccess as ge } from "./react/admin.js";
21
+ import { beaconsFor as _e, useBeacons as ve, useContentFilters as ye, useContents as be, useExposure as xe, useHistory as Se, useMyFavorites as Ce, useMyReactions as we, useRecentSearches as Te, useRecommendations as Ee, useReleaseDates as De, useSearch as Oe, useSimilar as ke, useTypeahead as Ae, useViewSignal as je } from "./react/discovery.js";
22
+ import { defaultVersion as Me, findVersion as Ne, liveVersions as Pe, useContentDetail as Fe } from "./react/detail.js";
23
+ import { nextRelease as Ie, useReaderPlan as Le, useSegmentPages as Re, useVersionDownload as ze } from "./react/versions.js";
24
+ import { useActivity as Be, useMyStats as Ve, useTopContents as He } from "./react/stats.js";
25
+ import { useContent as Ue, useManagedContents as We } from "./react/contents.js";
26
+ import { useNotificationUnread as Ge, useNotifications as Ke } from "./react/notifications.js";
27
+ import { ContentKitProvider as qe } from "./react/provider.js";
28
+ import { useCanonicalContent as Je } from "./react/canonical.js";
29
+ export { qe as ContentKitProvider, R as GALLERY_VIEW_KEY, i as GuardContext, e as HOVER_DELAY, t as InlinePreviewContext, z as PLAYER_QUALITY_KEY, h as ResourceStore, _e as beaconsFor, Me as defaultVersion, A as editOutput, Ne as findVersion, Pe as liveVersions, y as memberId, G as nameIn, Ie as nextRelease, g as resourcesFor, N as round3, K as thumbnailOf, Be as useActivity, Y as useAdminComments, me as useAdminLocation, D as useAvatar, X as useBannedWords, ve as useBeacons, Z as useCanComment, Je as useCanonicalContent, B as useCarousel, Q as useCommentBans, $ as useCommentReplies, ee as useComments, Ue as useContent, oe as useContentConfig, Fe as useContentDetail, ye as useContentFilters, b as useContentGroups, a as useContentKit, o as useContentKitClient, _ as useContentScope, s as useContentURLs, be as useContents, d as useCrop, W as useEditorCrop, f as useEncodeProgress, c as useErrorReporter, xe as useExposure, se as useFavorite, he as useFlowClient, P as useFrameStrip, V as useGalleryView, te as useGlobalCommentBan, x as useGroup, S as useGroupMembers, C as useGroups, l as useGuarded, Se as useHistory, H as useHlsPlayer, ne as useIPBans, n as useInlinePreview, w as useKinds, re as useLatestComments, We as useManagedContents, q as useMediaFolder, E as useMediaRead, ie as useModerationQueue, Ce as useMyFavorites, T as useMyGroups, we as useMyReactions, Ve as useMyStats, J as useNearViewport, Ge as useNotificationUnread, Ke as useNotifications, u as useOptionalContentKitClient, v as usePaged, le as usePoll, ue as usePollEditor, de as usePolls, O as usePresets, k as usePublicImage, ce as useReaction, Le as useReaderPlan, Te as useRecentSearches, Ee as useRecommendations, r as useReducedMotion, U as useRefreshBeforeExpiry, De as useReleaseDates, Oe as useSearch, Re as useSegmentPages, ke as useSimilar, j as useSlotCrop, M as useSlotImage, ge as useStaffAccess, He as useTopContents, Ae as useTypeahead, p as useUpload, m as useUploadQueue, ze as useVersionDownload, pe as useVersionParam, F as useVideoFrame, I as useVideoImages, L as useVideoPoster, je as useViewSignal, ae as withReaction, fe as withVote };