@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
@@ -0,0 +1,144 @@
1
+ //#region src/client/guest-reading-history.ts
2
+ var e = Object.freeze([]), t = 100, n = 2e3, r = (e, t = 2 ** 53 - 1) => typeof e == "number" && Number.isSafeInteger(e) && e >= 0 && e <= t, i = class {
3
+ prefix;
4
+ browser;
5
+ rows = e;
6
+ encoded = "[]";
7
+ memory = /* @__PURE__ */ new Map();
8
+ listeners = /* @__PURE__ */ new Set();
9
+ constructor(e, t) {
10
+ this.prefix = e, this.browser = t, this.sync();
11
+ }
12
+ snapshot = () => this.rows;
13
+ subscribe = (e) => (this.sync(), this.listeners.size || this.browser?.addEventListener("storage", this.storage), this.listeners.add(e), () => {
14
+ this.listeners.delete(e), this.listeners.size || this.browser?.removeEventListener("storage", this.storage);
15
+ });
16
+ record(e) {
17
+ if (!e.content_id || !e.visit_id || !e.segment_id || !r(e.revision) || !r(e.active_ms, 6e5) || !e.active_ms || (e.pages?.length ?? 0) > 128 || (e.watched?.length ?? 0) > 256 || e.pages?.some((e) => !r(e.index) || !r(e.active_ms, 6e5) || e.ranges.length > 16 || e.ranges.some((e) => !r(e.from, 1e4) || !r(e.to, 1e4) || e.from >= e.to)) || e.watched?.some((e) => !r(e.from_ms, 864e5) || !r(e.to_ms, 864e5) || e.from_ms >= e.to_ms)) return;
18
+ let { activity_token: t, ...n } = e, i = this.prefix + encodeURIComponent(JSON.stringify([
19
+ e.content_id,
20
+ e.version_id ?? "",
21
+ e.visit_id,
22
+ e.segment_id
23
+ ])), a = this.read().get(i);
24
+ if (a && a.revision >= e.revision) return;
25
+ let o = {
26
+ ...n,
27
+ saved_at: Date.now()
28
+ };
29
+ JSON.stringify(o).length > 65536 || (this.write(i, o), this.prune(), this.sync());
30
+ }
31
+ clear(e = {}) {
32
+ for (let [t, n] of this.read()) (!e.content_id || e.content_id === n.content_id) && (!e.kind || e.kind === n.kind) && this.remove(t);
33
+ this.sync();
34
+ }
35
+ storage = (e) => {
36
+ (e.key === null || e.key.startsWith(this.prefix)) && this.sync();
37
+ };
38
+ read() {
39
+ if (!this.browser) return new Map(this.memory);
40
+ let e = new Map(this.memory);
41
+ try {
42
+ for (let t = 0; t < this.browser.localStorage.length; t++) {
43
+ let n = this.browser.localStorage.key(t);
44
+ if (n?.startsWith(this.prefix)) try {
45
+ let t = this.browser.localStorage.getItem(n);
46
+ if (!t || t.length > 65536) continue;
47
+ let i = JSON.parse(t);
48
+ i && (!i.pages || Array.isArray(i.pages) && i.pages.length <= 128 && i.pages.every((e) => e && r(e.index) && r(e.active_ms, 6e5) && Array.isArray(e.ranges) && e.ranges.length <= 16 && e.ranges.every((e) => e && r(e.from, 1e4) && r(e.to, 1e4) && e.from < e.to))) && (!i.watched || Array.isArray(i.watched) && i.watched.length <= 256 && i.watched.every((e) => e && r(e.from_ms, 864e5) && r(e.to_ms, 864e5) && e.from_ms < e.to_ms)) && typeof i.content_id == "string" && typeof i.visit_id == "string" && typeof i.segment_id == "string" && r(i.revision) && r(i.saved_at) && r(i.active_ms, 6e5) && i.active_ms > 0 && e.set(n, i);
49
+ } catch {}
50
+ }
51
+ } catch {}
52
+ return e;
53
+ }
54
+ write(e, t) {
55
+ try {
56
+ if (this.browser) {
57
+ this.browser.localStorage.setItem(e, JSON.stringify(t)), this.memory.delete(e);
58
+ return;
59
+ }
60
+ } catch {}
61
+ this.memory.set(e, t);
62
+ }
63
+ remove(e) {
64
+ this.memory.delete(e);
65
+ try {
66
+ this.browser?.localStorage.removeItem(e);
67
+ } catch {}
68
+ }
69
+ prune() {
70
+ let e = /* @__PURE__ */ new Map();
71
+ for (let [t, n] of this.read()) {
72
+ let r = e.get(n.content_id) ?? {
73
+ keys: [],
74
+ at: n.saved_at
75
+ };
76
+ r.keys.push(t), r.at = Math.max(r.at, n.saved_at), e.set(n.content_id, r);
77
+ }
78
+ let r = 0, i = 0;
79
+ for (let a of [...e.values()].sort((e, t) => t.at - e.at)) if (r >= t || i + a.keys.length > n) for (let e of a.keys) this.remove(e);
80
+ else r++, i += a.keys.length;
81
+ }
82
+ sync() {
83
+ let e = /* @__PURE__ */ new Map();
84
+ for (let t of this.read().values()) {
85
+ let n = e.get(t.content_id) ?? {
86
+ id: t.content_id,
87
+ kind: t.kind,
88
+ at: t.saved_at,
89
+ checkpoints: []
90
+ };
91
+ n.at = Math.max(n.at, t.saved_at), n.checkpoints.push(t), e.set(n.id, n);
92
+ }
93
+ for (let t of e.values()) t.checkpoints.sort((e, t) => e.visit_id.localeCompare(t.visit_id) || e.segment_id.localeCompare(t.segment_id));
94
+ let t = [...e.values()].sort((e, t) => t.at - e.at || e.id.localeCompare(t.id)), n = JSON.stringify(t);
95
+ if (n !== this.encoded) {
96
+ this.encoded = n, this.rows = Object.freeze(t.map((e) => Object.freeze(e)));
97
+ for (let e of this.listeners) try {
98
+ e();
99
+ } catch {}
100
+ }
101
+ }
102
+ };
103
+ function a(e, t) {
104
+ let n = t.checkpoints.filter((t) => !t.version_id || t.version_id === e.version.id), r = /* @__PURE__ */ new Map(), i = [];
105
+ for (let e of n) {
106
+ for (let t of e.pages ?? []) {
107
+ let e = r.get(t.index) ?? {
108
+ active: 0,
109
+ ranges: []
110
+ };
111
+ e.active += t.active_ms, e.ranges.push(...t.ranges), r.set(t.index, e);
112
+ }
113
+ i.push(...(e.watched ?? []).map((e) => ({
114
+ from: e.from_ms,
115
+ to: e.to_ms
116
+ })));
117
+ }
118
+ let a = (e) => {
119
+ let t = 0, n = 0;
120
+ for (let r of e.sort((e, t) => e.from - t.from)) n += Math.max(0, r.to - Math.max(t, r.from)), t = Math.max(t, r.to);
121
+ return n;
122
+ }, o = e.version.pages ?? 0, s = o ? o * 100 : Math.ceil((e.version.duration_ms ?? 0) / 1e3), c = o ? [...r].reduce((e, [t, n]) => e + (t < o && n.active >= 1e3 ? a(n.ranges) / 100 : 0), 0) : a(i) / 1e3, l = n.toSorted((e, t) => t.saved_at - e.saved_at)[0];
123
+ return {
124
+ favorited: e.viewer?.favorited ?? !1,
125
+ seen: n.some((e) => e.active_ms > 0),
126
+ completed: s > 0 && c >= s * .9,
127
+ progress: Math.min(s, Math.floor(c)),
128
+ progress_max: s,
129
+ resume: l?.resume
130
+ };
131
+ }
132
+ var o = /* @__PURE__ */ new WeakMap();
133
+ function s(e) {
134
+ let t = typeof window > "u" ? void 0 : window, n = `contentkit.reading.v1:${encodeURIComponent(e)}:`;
135
+ if (!t) return new i(n);
136
+ let r = o.get(t);
137
+ r || (r = /* @__PURE__ */ new Map(), o.set(t, r));
138
+ let a = r.get(n);
139
+ return a || (a = new i(n, t), r.set(n, a)), a;
140
+ }
141
+ //#endregion
142
+ export { i as GuestReadingHistory, s as guestReadingHistory, a as guestStanding };
143
+
144
+ //# sourceMappingURL=guest-reading-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guest-reading-history.js","names":[],"sources":["../../src/client/guest-reading-history.ts"],"sourcesContent":["import type { Card, EngagementSnapshot, ViewerState } from \"./generated/wire.js\";\n\nexport type GuestReadingSnapshot = EngagementSnapshot & { kind?: string };\ninterface Checkpoint extends Omit<GuestReadingSnapshot, \"activity_token\"> { saved_at: number }\nexport interface GuestReadingItem { id: string; kind?: string; at: number; checkpoints: readonly Checkpoint[] }\nconst NONE: readonly GuestReadingItem[] = Object.freeze([]);\nconst MAX_CONTENTS = 100, MAX_SEGMENTS = 2000;\nconst integer = (n: unknown, max = Number.MAX_SAFE_INTEGER): n is number => typeof n === \"number\" && Number.isSafeInteger(n) && n >= 0 && n <= max;\n\n/** A separate key per cumulative segment avoids cross-tab read/modify/write loss. No titles, media URLs or account data are stored. */\nexport class GuestReadingHistory {\n private rows: readonly GuestReadingItem[] = NONE;\n private encoded = \"[]\";\n private memory = new Map<string, Checkpoint>();\n private readonly listeners = new Set<() => void>();\n constructor(private readonly prefix: string, private readonly browser?: Window) { this.sync(); }\n readonly snapshot = (): readonly GuestReadingItem[] => this.rows;\n readonly subscribe = (listener: () => void): (() => void) => {\n this.sync();\n if (!this.listeners.size) this.browser?.addEventListener(\"storage\", this.storage);\n this.listeners.add(listener);\n return () => { this.listeners.delete(listener); if (!this.listeners.size) this.browser?.removeEventListener(\"storage\", this.storage); };\n };\n record(snapshot: GuestReadingSnapshot): void {\n if (!snapshot.content_id || !snapshot.visit_id || !snapshot.segment_id || !integer(snapshot.revision) || !integer(snapshot.active_ms, 600_000) || !snapshot.active_ms) return;\n if ((snapshot.pages?.length ?? 0) > 128 || (snapshot.watched?.length ?? 0) > 256) return;\n if (snapshot.pages?.some(p => !integer(p.index) || !integer(p.active_ms, 600_000) || p.ranges.length > 16 || p.ranges.some(r => !integer(r.from, 10_000) || !integer(r.to, 10_000) || r.from >= r.to))) return;\n if (snapshot.watched?.some(r => !integer(r.from_ms, 86_400_000) || !integer(r.to_ms, 86_400_000) || r.from_ms >= r.to_ms)) return;\n const { activity_token: _token, ...local } = snapshot;\n const key = this.prefix + encodeURIComponent(JSON.stringify([snapshot.content_id, snapshot.version_id ?? \"\", snapshot.visit_id, snapshot.segment_id]));\n const existing = this.read().get(key);\n if (existing && existing.revision >= snapshot.revision) return;\n const value = { ...local, saved_at: Date.now() };\n if (JSON.stringify(value).length > 64 * 1024) return;\n this.write(key, value);\n this.prune(); this.sync();\n }\n clear(filter: { content_id?: string; kind?: string } = {}): void {\n for (const [key, row] of this.read()) if ((!filter.content_id || filter.content_id === row.content_id) && (!filter.kind || filter.kind === row.kind)) this.remove(key);\n this.sync();\n }\n private readonly storage = (event: StorageEvent): void => { if (event.key === null || event.key.startsWith(this.prefix)) this.sync(); };\n private read(): Map<string, Checkpoint> {\n if (!this.browser) return new Map(this.memory);\n const out = new Map(this.memory);\n try {\n for (let i = 0; i < this.browser.localStorage.length; i++) {\n const key = this.browser.localStorage.key(i);\n if (!key?.startsWith(this.prefix)) continue;\n try {\n const raw = this.browser.localStorage.getItem(key);\n if (!raw || raw.length > 64 * 1024) continue;\n const row = JSON.parse(raw) as Checkpoint | null;\n if (row && (!row.pages || Array.isArray(row.pages) && row.pages.length <= 128 && row.pages.every(p => p && integer(p.index) && integer(p.active_ms, 600_000) && Array.isArray(p.ranges) && p.ranges.length <= 16 && p.ranges.every(r => r && integer(r.from, 10_000) && integer(r.to, 10_000) && r.from < r.to))) && (!row.watched || Array.isArray(row.watched) && row.watched.length <= 256 && row.watched.every(r => r && integer(r.from_ms, 86_400_000) && integer(r.to_ms, 86_400_000) && r.from_ms < r.to_ms)) && typeof row.content_id === \"string\" && typeof row.visit_id === \"string\" && typeof row.segment_id === \"string\" && integer(row.revision) && integer(row.saved_at) && integer(row.active_ms, 600_000) && row.active_ms > 0) out.set(key, row);\n } catch { /* Ignore a malformed browser-only checkpoint. */ }\n }\n } catch { /* Storage can be unavailable; this client keeps bounded memory. */ }\n return out;\n }\n private write(key: string, row: Checkpoint): void {\n try { if (this.browser) { this.browser.localStorage.setItem(key, JSON.stringify(row)); this.memory.delete(key); return; } } catch { /* Quota/privacy mode. */ }\n this.memory.set(key, row);\n }\n private remove(key: string): void { this.memory.delete(key); try { this.browser?.localStorage.removeItem(key); } catch { /* Browser policy. */ } }\n private prune(): void {\n const groups = new Map<string, { keys: string[]; at: number }>();\n for (const [key, row] of this.read()) {\n const value = groups.get(row.content_id) ?? { keys: [], at: row.saved_at };\n value.keys.push(key); value.at = Math.max(value.at, row.saved_at); groups.set(row.content_id, value);\n }\n let contents = 0, segments = 0;\n for (const value of [...groups.values()].sort((a, b) => b.at - a.at)) {\n // Evict a whole older content item; never silently turn a retained history item into partial coverage.\n if (contents >= MAX_CONTENTS || segments + value.keys.length > MAX_SEGMENTS) {\n for (const key of value.keys) this.remove(key);\n } else { contents++; segments += value.keys.length; }\n }\n }\n\n private sync(): void {\n const byContent = new Map<string, { id: string; kind?: string; at: number; checkpoints: Checkpoint[] }>();\n for (const row of this.read().values()) {\n const item = byContent.get(row.content_id) ?? { id: row.content_id, kind: row.kind, at: row.saved_at, checkpoints: [] };\n item.at = Math.max(item.at, row.saved_at); item.checkpoints.push(row); byContent.set(item.id, item);\n }\n for (const row of byContent.values()) row.checkpoints.sort((a, b) => a.visit_id.localeCompare(b.visit_id) || a.segment_id.localeCompare(b.segment_id));\n const rows = [...byContent.values()].sort((a, b) => b.at - a.at || a.id.localeCompare(b.id));\n const encoded = JSON.stringify(rows);\n if (encoded === this.encoded) return;\n this.encoded = encoded; this.rows = Object.freeze(rows.map(row => Object.freeze(row)));\n for (const listener of this.listeners) { try { listener(); } catch { /* Observers do not own persistence. */ } }\n }\n}\n\n/** Hydrate through ordinary public discovery before applying local progress: cached IDs never bypass current domain/access restrictions. */\nexport function guestStanding(card: Card, item: GuestReadingItem): ViewerState {\n const rows = item.checkpoints.filter(row => !row.version_id || row.version_id === card.version.id);\n const pages = new Map<number, { active: number; ranges: { from: number; to: number }[] }>();\n const watched: { from: number; to: number }[] = [];\n for (const row of rows) {\n for (const page of row.pages ?? []) {\n const value = pages.get(page.index) ?? { active: 0, ranges: [] };\n value.active += page.active_ms; value.ranges.push(...page.ranges); pages.set(page.index, value);\n }\n watched.push(...(row.watched ?? []).map(r => ({ from: r.from_ms, to: r.to_ms })));\n }\n const unionLength = (ranges: { from: number; to: number }[]) => {\n let end = 0, n = 0;\n for (const r of ranges.sort((a, b) => a.from - b.from)) { n += Math.max(0, r.to - Math.max(end, r.from)); end = Math.max(end, r.to); }\n return n;\n };\n const pageCount = card.version.pages ?? 0;\n const total = pageCount ? pageCount * 100 : Math.ceil((card.version.duration_ms ?? 0) / 1000);\n const progress = pageCount ? [...pages].reduce((n, [index, page]) => n + (index < pageCount && page.active >= 1000 ? unionLength(page.ranges) / 100 : 0), 0) : unionLength(watched) / 1000;\n const newest = rows.toSorted((a, b) => b.saved_at - a.saved_at)[0];\n return { favorited: card.viewer?.favorited ?? false, seen: rows.some(row => row.active_ms > 0), completed: total > 0 && progress >= total * 0.9,\n progress: Math.min(total, Math.floor(progress)), progress_max: total, resume: newest?.resume };\n}\n\nconst stores = new WeakMap<Window, Map<string, GuestReadingHistory>>();\nexport function guestReadingHistory(mount: string): GuestReadingHistory {\n const browser = typeof window === \"undefined\" ? undefined : window;\n const key = `contentkit.reading.v1:${encodeURIComponent(mount)}:`;\n if (!browser) return new GuestReadingHistory(key);\n let scoped = stores.get(browser); if (!scoped) { scoped = new Map(); stores.set(browser, scoped); }\n let store = scoped.get(key); if (!store) { store = new GuestReadingHistory(key, browser); scoped.set(key, store); }\n return store;\n}\n"],"mappings":"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"}
@@ -11,12 +11,12 @@ export { BansClient } from './content/bans.js';
11
11
  export { ModerationClient, type HeldQuery } from './content/moderation.js';
12
12
  export { reactionVerb, sameTarget, type BanScope, type ContentChange, type Decision, type HeldKind, type Reaction, type RuleSet, type Sort, type Target } from './content/types.js';
13
13
  export { EntitiesClient, type EntityImageSlot, type EntityQuery, type ManageEntityQuery, type MemberQuery, type MyEntityQuery } from './entities.js';
14
- export { DiscoveryClient, popularQuery, popularBetween, type AccessMode, type CardQuery, type ContentFilterQuery, type ContentQuery, type HistoryQuery, type ListSort, type Period, type PopularPeriod, type PopularDateRange, type PopularQuery, type RailQuery, type ReaderQuery, type RecentSearchesQuery, type ReleaseDatesQuery, type DailyReleasesQuery, type SearchQuery, type TypeaheadQuery, } from './discovery.js';
14
+ export { DiscoveryClient, popularQuery, popularBetween, type AccessMode, type AdminSuggestionsQuery, type CardQuery, type ContentFilterQuery, type ContentQuery, type HistoryQuery, type ListSort, type Period, type PopularPeriod, type PopularDateRange, type PopularQuery, type RailQuery, type ReaderQuery, type RecentSearchesQuery, type ReleaseDatesQuery, type DailyReleasesQuery, type SearchQuery, type TypeaheadQuery, } from './discovery.js';
15
15
  export { VersionsClient, isPending } from './versions.js';
16
16
  export { emptyReaderMeta, matchAudio, readerMetaProblems, readerNames, type AudioMatch, type ReaderMetaProblem, type ReaderNames } from './reader-meta.js';
17
17
  export { OffersClient } from './offers.js';
18
- export { StatsClient, type ActivityQuery, type TopQuery } from './stats.js';
19
- export { Beacons, eventId, readerSession, type Attribution, type BeaconOptions, type ViewSession } from './beacons.js';
18
+ export { StatsClient, type ActivityQuery } from './stats.js';
19
+ export { Beacons, eventId, readerSession, type Attribution, type BeaconOptions } from './beacons.js';
20
20
  export { LETTERS, attributeInput, fold, fromLocalInput, humanize, letterOf, parseAttribute, parseAttributes, slugify, toLocalInput } from './group-fields.js';
21
21
  export { CodesClient } from './codes.js';
22
22
  export { NotificationsClient, type NotificationItem } from './notifications.js';
@@ -42,3 +42,5 @@ export { formatDuration, galleryItems, isAudioType, isImageType, isVideoType, is
42
42
  export { ABR_DEFAULTS, NETWORK_FAILURES_BEFORE_ERROR, abrHlsConfig, capRung, classifyHlsError, classifyMediaError, hlsConfig, initialEstimate, expiryDelay, REFRESH_BEFORE_EXPIRY, refreshable, startRung, statusKind, type AbrPolicy, type ConnectionHint, type HlsErrorLike, type Rung, type PlaybackError, type PlaybackErrorKind, } from './playback.js';
43
43
  export { PLAYBACK_SPEEDS, PLAYER_TRACKS_KEY, PLAYER_VOLUME_KEY, parseSpriteVtt, playerKeyAction, resumeAt, type PlayerAction, type PlayerTrack, type SpriteCue, type TrackPrefs, type VolumePrefs, } from './player.js';
44
44
  export * from './generated/wire.js';
45
+ export { EngagementTracker, type EngagementTrackerOptions, type ReadingObservation, type VisiblePage } from './engagement.js';
46
+ export { GuestReadingHistory, guestStanding, type GuestReadingItem, type GuestReadingSnapshot } from './guest-reading-history.js';
@@ -13,3 +13,5 @@ export declare function mergeReads(reads: readonly (ReadResult | null | undefine
13
13
  export declare const isProcessing: (f: FileInfo) => boolean;
14
14
  /** An editor read with uploads still processing (not stalled because the item is full). */
15
15
  export declare function processing(read: ReadResult | null | undefined): boolean;
16
+ /** A page automatic processing removed (blank, duplicate or covered by a spread); a notice offers it back. */
17
+ export declare function pageRemoved(f: FileInfo): boolean;
@@ -33,7 +33,10 @@ var r = (e) => !!e.upload && !e.failed && (!!e.staged || (e.pending?.length ?? 0
33
33
  function i(e) {
34
34
  return !e || e.full ? !1 : e.state === "processing" || e.files.some(r);
35
35
  }
36
+ function a(e) {
37
+ return e.meta?.page?.included === !1;
38
+ }
36
39
  //#endregion
37
- export { e as READ_CHUNK, t as chunkOffsets, r as isProcessing, n as mergeReads, i as processing };
40
+ export { e as READ_CHUNK, t as chunkOffsets, r as isProcessing, n as mergeReads, a as pageRemoved, i as processing };
38
41
 
39
42
  //# sourceMappingURL=windows.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"windows.js","names":[],"sources":["../../../src/client/media/windows.ts"],"sourcesContent":["import type { FileInfo, ReadResult } from \"../generated/wire.js\";\n\n/** Files per window when a read is split into windows. */\nexport const READ_CHUNK = 50;\n\n/** Offsets of chunk-sized windows covering files [start, end), clipped to total when known. */\nexport function chunkOffsets(start: number, end: number, total?: number, chunk = READ_CHUNK): number[] {\n const out: number[] = [];\n const stop = total === undefined ? end : Math.min(end, total);\n if (start >= stop) return out;\n for (let o = Math.floor(Math.max(start, 0) / chunk) * chunk; o < stop; o += chunk) out.push(o);\n return out;\n}\n\n/**\n * One item's window reads as one read: the newest window's listing and\n * metadata, each file's URL from the newest window that signed it, and the\n * earliest expiry. Every window lists every file; only its range has URLs.\n */\nexport function mergeReads(reads: readonly (ReadResult | null | undefined)[]): ReadResult | null {\n const present = reads.filter((r): r is ReadResult => !!r);\n if (present.length === 0) return null;\n if (present.length === 1) return present[0]!;\n const newest = present.reduce((a, b) => (b.expires >= a.expires ? b : a));\n const urls = new Map<string, FileInfo>();\n for (const r of [...present].sort((a, b) => a.expires - b.expires)) for (const f of r.files) if (f.url) urls.set(f.path, f);\n const files = newest.files.map((f) => {\n if (f.url) return f;\n const signed = urls.get(f.path);\n return signed ? { ...f, url: signed.url, ...(signed.download ? { download: signed.download } : {}) } : f;\n });\n const start = Math.min(...present.map((r) => r.offset));\n const end = Math.max(...present.map((r) => r.offset + r.limit));\n return { ...newest, files, offset: start, limit: end - start, expires: Math.min(...present.map((r) => r.expires)) };\n}\n\n/** An upload the worker has not finished: staged, or with work pending, and not failed. */\nexport const isProcessing = (f: FileInfo) => !!f.upload && !f.failed && (!!f.staged || (f.pending?.length ?? 0) > 0);\n\n/** An editor read with uploads still processing (not stalled because the item is full). */\nexport function processing(read: ReadResult | null | undefined): boolean {\n if (!read || read.full) return false;\n return read.state === \"processing\" || read.files.some(isProcessing);\n}\n"],"mappings":";AAGA,IAAa,IAAa;AAG1B,SAAgB,EAAa,GAAe,GAAa,GAAgB,IAAA,IAA8B;CACrG,IAAM,IAAgB,CAAC,GACjB,IAAO,MAAU,KAAA,IAAY,IAAM,KAAK,IAAI,GAAK,CAAK;CAC5D,IAAI,KAAS,GAAM,OAAO;CAC1B,KAAK,IAAI,IAAI,KAAK,MAAM,KAAK,IAAI,GAAO,CAAC,IAAI,CAAK,IAAI,GAAO,IAAI,GAAM,KAAK,GAAO,EAAI,KAAK,CAAC;CAC7F,OAAO;AACT;AAOA,SAAgB,EAAW,GAAsE;CAC/F,IAAM,IAAU,EAAM,QAAQ,MAAuB,CAAC,CAAC,CAAC;CACxD,IAAI,EAAQ,WAAW,GAAG,OAAO;CACjC,IAAI,EAAQ,WAAW,GAAG,OAAO,EAAQ;CACzC,IAAM,IAAS,EAAQ,QAAQ,GAAG,MAAO,EAAE,WAAW,EAAE,UAAU,IAAI,CAAE,GAClE,oBAAO,IAAI,IAAsB;CACvC,KAAK,IAAM,KAAK,CAAC,GAAG,CAAO,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,KAAK,IAAM,KAAK,EAAE,OAAO,AAAI,EAAE,OAAK,EAAK,IAAI,EAAE,MAAM,CAAC;CAC1H,IAAM,IAAQ,EAAO,MAAM,KAAK,MAAM;EACpC,IAAI,EAAE,KAAK,OAAO;EAClB,IAAM,IAAS,EAAK,IAAI,EAAE,IAAI;EAC9B,OAAO,IAAS;GAAE,GAAG;GAAG,KAAK,EAAO;GAAK,GAAI,EAAO,WAAW,EAAE,UAAU,EAAO,SAAS,IAAI,CAAC;EAAG,IAAI;CACzG,CAAC,GACK,IAAQ,KAAK,IAAI,GAAG,EAAQ,KAAK,MAAM,EAAE,MAAM,CAAC,GAChD,IAAM,KAAK,IAAI,GAAG,EAAQ,KAAK,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC;CAC9D,OAAO;EAAE,GAAG;EAAQ;EAAO,QAAQ;EAAO,OAAO,IAAM;EAAO,SAAS,KAAK,IAAI,GAAG,EAAQ,KAAK,MAAM,EAAE,OAAO,CAAC;CAAE;AACpH;AAGA,IAAa,KAAgB,MAAgB,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,WAAW,EAAE,SAAS,UAAU,KAAK;AAGlH,SAAgB,EAAW,GAA8C;CAEvE,OADI,CAAC,KAAQ,EAAK,OAAa,KACxB,EAAK,UAAU,gBAAgB,EAAK,MAAM,KAAK,CAAY;AACpE"}
1
+ {"version":3,"file":"windows.js","names":[],"sources":["../../../src/client/media/windows.ts"],"sourcesContent":["import type { FileInfo, ReadResult } from \"../generated/wire.js\";\n\n/** Files per window when a read is split into windows. */\nexport const READ_CHUNK = 50;\n\n/** Offsets of chunk-sized windows covering files [start, end), clipped to total when known. */\nexport function chunkOffsets(start: number, end: number, total?: number, chunk = READ_CHUNK): number[] {\n const out: number[] = [];\n const stop = total === undefined ? end : Math.min(end, total);\n if (start >= stop) return out;\n for (let o = Math.floor(Math.max(start, 0) / chunk) * chunk; o < stop; o += chunk) out.push(o);\n return out;\n}\n\n/**\n * One item's window reads as one read: the newest window's listing and\n * metadata, each file's URL from the newest window that signed it, and the\n * earliest expiry. Every window lists every file; only its range has URLs.\n */\nexport function mergeReads(reads: readonly (ReadResult | null | undefined)[]): ReadResult | null {\n const present = reads.filter((r): r is ReadResult => !!r);\n if (present.length === 0) return null;\n if (present.length === 1) return present[0]!;\n const newest = present.reduce((a, b) => (b.expires >= a.expires ? b : a));\n const urls = new Map<string, FileInfo>();\n for (const r of [...present].sort((a, b) => a.expires - b.expires)) for (const f of r.files) if (f.url) urls.set(f.path, f);\n const files = newest.files.map((f) => {\n if (f.url) return f;\n const signed = urls.get(f.path);\n return signed ? { ...f, url: signed.url, ...(signed.download ? { download: signed.download } : {}) } : f;\n });\n const start = Math.min(...present.map((r) => r.offset));\n const end = Math.max(...present.map((r) => r.offset + r.limit));\n return { ...newest, files, offset: start, limit: end - start, expires: Math.min(...present.map((r) => r.expires)) };\n}\n\n/** An upload the worker has not finished: staged, or with work pending, and not failed. */\nexport const isProcessing = (f: FileInfo) => !!f.upload && !f.failed && (!!f.staged || (f.pending?.length ?? 0) > 0);\n\n/** An editor read with uploads still processing (not stalled because the item is full). */\nexport function processing(read: ReadResult | null | undefined): boolean {\n if (!read || read.full) return false;\n return read.state === \"processing\" || read.files.some(isProcessing);\n}\n\n/** A page automatic processing removed (blank, duplicate or covered by a spread); a notice offers it back. */\nexport function pageRemoved(f: FileInfo): boolean {\n return (f.meta?.page as { included?: boolean } | undefined)?.included === false;\n}\n"],"mappings":";AAGA,IAAa,IAAa;AAG1B,SAAgB,EAAa,GAAe,GAAa,GAAgB,IAAA,IAA8B;CACrG,IAAM,IAAgB,CAAC,GACjB,IAAO,MAAU,KAAA,IAAY,IAAM,KAAK,IAAI,GAAK,CAAK;CAC5D,IAAI,KAAS,GAAM,OAAO;CAC1B,KAAK,IAAI,IAAI,KAAK,MAAM,KAAK,IAAI,GAAO,CAAC,IAAI,CAAK,IAAI,GAAO,IAAI,GAAM,KAAK,GAAO,EAAI,KAAK,CAAC;CAC7F,OAAO;AACT;AAOA,SAAgB,EAAW,GAAsE;CAC/F,IAAM,IAAU,EAAM,QAAQ,MAAuB,CAAC,CAAC,CAAC;CACxD,IAAI,EAAQ,WAAW,GAAG,OAAO;CACjC,IAAI,EAAQ,WAAW,GAAG,OAAO,EAAQ;CACzC,IAAM,IAAS,EAAQ,QAAQ,GAAG,MAAO,EAAE,WAAW,EAAE,UAAU,IAAI,CAAE,GAClE,oBAAO,IAAI,IAAsB;CACvC,KAAK,IAAM,KAAK,CAAC,GAAG,CAAO,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,KAAK,IAAM,KAAK,EAAE,OAAO,AAAI,EAAE,OAAK,EAAK,IAAI,EAAE,MAAM,CAAC;CAC1H,IAAM,IAAQ,EAAO,MAAM,KAAK,MAAM;EACpC,IAAI,EAAE,KAAK,OAAO;EAClB,IAAM,IAAS,EAAK,IAAI,EAAE,IAAI;EAC9B,OAAO,IAAS;GAAE,GAAG;GAAG,KAAK,EAAO;GAAK,GAAI,EAAO,WAAW,EAAE,UAAU,EAAO,SAAS,IAAI,CAAC;EAAG,IAAI;CACzG,CAAC,GACK,IAAQ,KAAK,IAAI,GAAG,EAAQ,KAAK,MAAM,EAAE,MAAM,CAAC,GAChD,IAAM,KAAK,IAAI,GAAG,EAAQ,KAAK,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC;CAC9D,OAAO;EAAE,GAAG;EAAQ;EAAO,QAAQ;EAAO,OAAO,IAAM;EAAO,SAAS,KAAK,IAAI,GAAG,EAAQ,KAAK,MAAM,EAAE,OAAO,CAAC;CAAE;AACpH;AAGA,IAAa,KAAgB,MAAgB,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,WAAW,EAAE,SAAS,UAAU,KAAK;AAGlH,SAAgB,EAAW,GAA8C;CAEvE,OADI,CAAC,KAAQ,EAAK,OAAa,KACxB,EAAK,UAAU,gBAAgB,EAAK,MAAM,KAAK,CAAY;AACpE;AAGA,SAAgB,EAAY,GAAsB;CAChD,OAAQ,EAAE,MAAM,MAA6C,aAAa;AAC5E"}
@@ -1,32 +1,16 @@
1
- import { Activity, MyStats, TopContents } from './generated/wire.js';
2
- import { Period } from './discovery.js';
1
+ import { Activity, MyStats } from './generated/wire.js';
3
2
  import { Http } from './http.js';
4
3
  export interface ActivityQuery {
5
4
  kind: string;
6
- /** The last days, today included: 7 by default, at most 90. */
5
+ /** The last days, today included: 10 by default, at most 90. */
7
6
  days?: number;
8
7
  }
9
- export interface TopQuery {
10
- kind: string;
11
- /** views (the default) or comments. */
12
- metric?: "views" | "comments";
13
- /** 30d by default. */
14
- period?: Period;
15
- access?: readonly ("public" | "tier" | "group" | "ppv" | "group_ppv")[];
16
- tiers?: readonly string[];
17
- /** Titles and paths in this language; the site's first by default. */
18
- language?: string;
19
- /** 10 by default, at most 100. */
20
- limit?: number;
21
- }
22
- /** Content statistics: staff activity and rankings (root:content:view-restricted), and the signed-in reader's own. */
8
+ /** Content statistics: staff activity (content statistics permission) and the signed-in reader's own. */
23
9
  export declare class StatsClient {
24
10
  private readonly http;
25
11
  constructor(http: Http);
26
- /** A kind's views per UTC day, newest first: view sessions, distinct viewers and signed-in viewers. */
12
+ /** A kind's measured activity for every UTC day of the period, newest first: distinct people who read or played, by audience (anon, free, premium), and focused active milliseconds. */
27
13
  activity(q: ActivityQuery, signal?: AbortSignal): Promise<Activity>;
28
- /** A kind's live, listed content ranked by views or published comments over a period. */
29
- top(q: TopQuery, signal?: AbortSignal): Promise<TopContents>;
30
14
  /** The signed-in reader's statistics: contents finished per kind, comments, reactions received and elapsed access per tier when billing supplies its history. */
31
15
  mine(signal?: AbortSignal): Promise<MyStats>;
32
16
  }
@@ -14,17 +14,6 @@ var t = class {
14
14
  signal: n
15
15
  });
16
16
  }
17
- top(t, n) {
18
- let { access: r, tiers: i, ...a } = t;
19
- return e(this.http, "GET", "/stats/top", {
20
- query: {
21
- ...a,
22
- access: r?.join(","),
23
- tiers: i?.join(",")
24
- },
25
- signal: n
26
- });
27
- }
28
17
  mine(t) {
29
18
  return e(this.http, "GET", "/me/stats", { signal: t });
30
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"stats.js","names":[],"sources":["../../src/client/stats.ts"],"sourcesContent":["import type { Activity, MyStats, TopContents } from \"./generated/wire.js\";\nimport type { Period } from \"./discovery.js\";\nimport type { Http } from \"./http.js\";\nimport { call } from \"./route.js\";\n\nexport interface ActivityQuery {\n kind: string;\n /** The last days, today included: 7 by default, at most 90. */\n days?: number;\n}\n\nexport interface TopQuery {\n kind: string;\n /** views (the default) or comments. */\n metric?: \"views\" | \"comments\";\n /** 30d by default. */\n period?: Period;\n access?: readonly (\"public\" | \"tier\" | \"group\" | \"ppv\" | \"group_ppv\")[];\n tiers?: readonly string[];\n /** Titles and paths in this language; the site's first by default. */\n language?: string;\n /** 10 by default, at most 100. */\n limit?: number;\n}\n\n/** Content statistics: staff activity and rankings (root:content:view-restricted), and the signed-in reader's own. */\nexport class StatsClient {\n constructor(private readonly http: Http) {}\n\n /** A kind's views per UTC day, newest first: view sessions, distinct viewers and signed-in viewers. */\n activity(q: ActivityQuery, signal?: AbortSignal): Promise<Activity> {\n return call(this.http, \"GET\", \"/stats/activity\", { query: { kind: q.kind, days: q.days }, signal });\n }\n /** A kind's live, listed content ranked by views or published comments over a period. */\n top(q: TopQuery, signal?: AbortSignal): Promise<TopContents> {\n const { access, tiers, ...rest } = q;\n return call(this.http, \"GET\", \"/stats/top\", { query: { ...rest, access: access?.join(\",\"), tiers: tiers?.join(\",\") }, signal });\n }\n /** The signed-in reader's statistics: contents finished per kind, comments, reactions received and elapsed access per tier when billing supplies its history. */\n mine(signal?: AbortSignal): Promise<MyStats> {\n return call(this.http, \"GET\", \"/me/stats\", { signal });\n }\n}\n"],"mappings":";;AA0BA,IAAa,IAAb,MAAyB;CACM;CAA7B,YAAY,GAA6B;EAAZ,KAAA,OAAA;CAAa;CAG1C,SAAS,GAAkB,GAAyC;EAClE,OAAO,EAAK,KAAK,MAAM,OAAO,mBAAmB;GAAE,OAAO;IAAE,MAAM,EAAE;IAAM,MAAM,EAAE;GAAK;GAAG;EAAO,CAAC;CACpG;CAEA,IAAI,GAAa,GAA4C;EAC3D,IAAM,EAAE,WAAQ,UAAO,GAAG,MAAS;EACnC,OAAO,EAAK,KAAK,MAAM,OAAO,cAAc;GAAE,OAAO;IAAE,GAAG;IAAM,QAAQ,GAAQ,KAAK,GAAG;IAAG,OAAO,GAAO,KAAK,GAAG;GAAE;GAAG;EAAO,CAAC;CAChI;CAEA,KAAK,GAAwC;EAC3C,OAAO,EAAK,KAAK,MAAM,OAAO,aAAa,EAAE,UAAO,CAAC;CACvD;AACF"}
1
+ {"version":3,"file":"stats.js","names":[],"sources":["../../src/client/stats.ts"],"sourcesContent":["import type { Activity, MyStats } from \"./generated/wire.js\";\nimport type { Http } from \"./http.js\";\nimport { call } from \"./route.js\";\n\nexport interface ActivityQuery {\n kind: string;\n /** The last days, today included: 10 by default, at most 90. */\n days?: number;\n}\n\n/** Content statistics: staff activity (content statistics permission) and the signed-in reader's own. */\nexport class StatsClient {\n constructor(private readonly http: Http) {}\n\n /** A kind's measured activity for every UTC day of the period, newest first: distinct people who read or played, by audience (anon, free, premium), and focused active milliseconds. */\n activity(q: ActivityQuery, signal?: AbortSignal): Promise<Activity> {\n return call(this.http, \"GET\", \"/stats/activity\", { query: { kind: q.kind, days: q.days }, signal });\n }\n /** The signed-in reader's statistics: contents finished per kind, comments, reactions received and elapsed access per tier when billing supplies its history. */\n mine(signal?: AbortSignal): Promise<MyStats> {\n return call(this.http, \"GET\", \"/me/stats\", { signal });\n }\n}\n"],"mappings":";;AAWA,IAAa,IAAb,MAAyB;CACM;CAA7B,YAAY,GAA6B;EAAZ,KAAA,OAAA;CAAa;CAG1C,SAAS,GAAkB,GAAyC;EAClE,OAAO,EAAK,KAAK,MAAM,OAAO,mBAAmB;GAAE,OAAO;IAAE,MAAM,EAAE;IAAM,MAAM,EAAE;GAAK;GAAG;EAAO,CAAC;CACpG;CAEA,KAAK,GAAwC;EAC3C,OAAO,EAAK,KAAK,MAAM,OAAO,aAAa,EAAE,UAAO,CAAC;CACvD;AACF"}
@@ -1,15 +1,17 @@
1
- import { FileDownload, ForkBody, PageReview, PageReviewPatch, Pending, ReaderMeta, ReaderPlan } from './generated/wire.js';
1
+ import { FileDownload, ForkBody, PageNotices, Pending, ReaderMeta, ReaderPlan } from './generated/wire.js';
2
2
  import { Http } from './http.js';
3
3
  /** A version's answer while it is prepared (202). */
4
4
  export declare const isPending: (x: unknown) => x is Pending;
5
- /** Content versions: page review, reader plans, reader metadata, forks and downloads. */
5
+ /** Content versions: page notices, reader plans, reader metadata, forks and downloads. */
6
6
  export declare class VersionsClient {
7
7
  private readonly http;
8
8
  constructor(http: Http);
9
- /** Editors: retained page sources, automatic decisions and manual overrides. */
10
- pages(content: string, version: string, signal?: AbortSignal): Promise<PageReview>;
11
- /** Editors: changes choices or order against the review's current revision. */
12
- updatePages(content: string, version: string, patch: PageReviewPatch): Promise<PageReview>;
9
+ /** Editors: undismissed notes about automatic page changes (removed or reordered pages). */
10
+ pageNotices(content: string, version: string, signal?: AbortSignal): Promise<PageNotices>;
11
+ /** Editors: hides a page notice. */
12
+ dismissPageNotice(content: string, version: string, notice: string): Promise<void>;
13
+ /** Editors: puts a removed-pages notice's pages back where they were. */
14
+ restorePageNotice(content: string, version: string, notice: string): Promise<PageNotices>;
13
15
  /** The version's reader plan for this viewer; Pending while it has no current publication. */
14
16
  reader(content: string, version: string, signal?: AbortSignal): Promise<ReaderPlan | Pending>;
15
17
  /** Editors: replaces the version's reader metadata (anchors, audio cues, defaults). */
@@ -5,8 +5,8 @@ var n = (e) => !!e && typeof e == "object" && "status" in e && !("pages" in e) &
5
5
  constructor(e) {
6
6
  this.http = e;
7
7
  }
8
- pages(t, n, r) {
9
- return e(this.http, "GET", "/contents/{id}/versions/{version}/pages", {
8
+ pageNotices(t, n, r) {
9
+ return e(this.http, "GET", "/contents/{id}/versions/{version}/page-notices", {
10
10
  params: {
11
11
  id: t,
12
12
  version: n
@@ -14,14 +14,19 @@ var n = (e) => !!e && typeof e == "object" && "status" in e && !("pages" in e) &
14
14
  signal: r
15
15
  });
16
16
  }
17
- async updatePages(t, n, r) {
18
- let i = this.http.captureChanges(), a = await e(this.http, "PATCH", "/contents/{id}/versions/{version}/pages", {
19
- params: {
20
- id: t,
21
- version: n
22
- },
23
- body: r
24
- });
17
+ dismissPageNotice(t, n, r) {
18
+ return e(this.http, "POST", "/contents/{id}/versions/{version}/page-notices/{notice}/dismiss", { params: {
19
+ id: t,
20
+ version: n,
21
+ notice: r
22
+ } });
23
+ }
24
+ async restorePageNotice(t, n, r) {
25
+ let i = this.http.captureChanges(), a = await e(this.http, "POST", "/contents/{id}/versions/{version}/page-notices/{notice}/restore", { params: {
26
+ id: t,
27
+ version: n,
28
+ notice: r
29
+ } });
25
30
  return i({
26
31
  type: "content.changed",
27
32
  id: t
@@ -1 +1 @@
1
- {"version":3,"file":"versions.js","names":[],"sources":["../../src/client/versions.ts"],"sourcesContent":["import type { FileDownload, ForkBody, PageReview, PageReviewPatch, Pending, ReaderMeta, ReaderPlan } from \"./generated/wire.js\";\nimport type { Http } from \"./http.js\";\nimport { call, routeURL } from \"./route.js\";\n\n/** A version's answer while it is prepared (202). */\nexport const isPending = (x: unknown): x is Pending => !!x && typeof x === \"object\" && \"status\" in x && !(\"pages\" in x) && !(\"url\" in x);\n\n/** Content versions: page review, reader plans, reader metadata, forks and downloads. */\nexport class VersionsClient {\n constructor(private readonly http: Http) {}\n\n /** Editors: retained page sources, automatic decisions and manual overrides. */\n pages(content: string, version: string, signal?: AbortSignal): Promise<PageReview> {\n return call(this.http, \"GET\", \"/contents/{id}/versions/{version}/pages\", { params: { id: content, version }, signal });\n }\n /** Editors: changes choices or order against the review's current revision. */\n async updatePages(content: string, version: string, patch: PageReviewPatch): Promise<PageReview> {\n const emit = this.http.captureChanges();\n const next: PageReview = await call(this.http, \"PATCH\", \"/contents/{id}/versions/{version}/pages\", { params: { id: content, version }, body: patch });\n emit({ type: \"content.changed\", id: content });\n emit({ type: \"reader.changed\", content, version });\n return next;\n }\n /** The version's reader plan for this viewer; Pending while it has no current publication. */\n reader(content: string, version: string, signal?: AbortSignal): Promise<ReaderPlan | Pending> {\n return call(this.http, \"GET\", \"/contents/{id}/versions/{version}/reader\", { params: { id: content, version }, signal });\n }\n /** Editors: replaces the version's reader metadata (anchors, audio cues, defaults). */\n async setReader(content: string, version: string, meta: ReaderMeta): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"PUT\", \"/contents/{id}/versions/{version}/reader\", { params: { id: content, version }, body: meta });\n emit({ type: \"reader.changed\", content, version });\n }\n /** Editors: fills a version without media from a sibling, in a durable job. */\n fork(content: string, version: string, body: ForkBody): Promise<Pending> {\n return call(this.http, \"POST\", \"/contents/{id}/versions/{version}/fork\", { params: { id: content, version }, body });\n }\n /**\n * Grants the version's download, what its kind serves (the original, a\n * rendition, its pages as a zip), charged to the viewer's download quota:\n * `url` (absolute) serves it as an attachment until `expires_at`. Pending\n * while it is prepared (ask again).\n */\n async download(content: string, version: string, signal?: AbortSignal): Promise<FileDownload | Pending> {\n const url = routeURL(this.http, \"GET\", \"/contents/{id}/versions/{version}/download\", { params: { id: content, version } });\n const out = await this.http.request<FileDownload | Pending>(url, { signal });\n if (isPending(out)) return out;\n // A marked zip's URL is the archive route's, relative to this one.\n const base = new URL(url, globalThis.location?.href ?? \"http://localhost/\");\n return { ...out, url: new URL(out.url, base).toString() };\n }\n}\n"],"mappings":";;AAKA,IAAa,KAAa,MAA6B,CAAC,CAAC,KAAK,OAAO,KAAM,YAAY,YAAY,KAAK,EAAE,WAAW,MAAM,EAAE,SAAS,IAGzH,IAAb,MAA4B;CACG;CAA7B,YAAY,GAA6B;EAAZ,KAAA,OAAA;CAAa;CAG1C,MAAM,GAAiB,GAAiB,GAA2C;EACjF,OAAO,EAAK,KAAK,MAAM,OAAO,2CAA2C;GAAE,QAAQ;IAAE,IAAI;IAAS;GAAQ;GAAG;EAAO,CAAC;CACvH;CAEA,MAAM,YAAY,GAAiB,GAAiB,GAA6C;EAC/F,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAmB,MAAM,EAAK,KAAK,MAAM,SAAS,2CAA2C;GAAE,QAAQ;IAAE,IAAI;IAAS;GAAQ;GAAG,MAAM;EAAM,CAAC;EAGpJ,OAFA,EAAK;GAAE,MAAM;GAAmB,IAAI;EAAQ,CAAC,GAC7C,EAAK;GAAE,MAAM;GAAkB;GAAS;EAAQ,CAAC,GAC1C;CACT;CAEA,OAAO,GAAiB,GAAiB,GAAqD;EAC5F,OAAO,EAAK,KAAK,MAAM,OAAO,4CAA4C;GAAE,QAAQ;IAAE,IAAI;IAAS;GAAQ;GAAG;EAAO,CAAC;CACxH;CAEA,MAAM,UAAU,GAAiB,GAAiB,GAAiC;EACjF,IAAM,IAAO,KAAK,KAAK,eAAe;EAEtC,AADA,MAAM,EAAK,KAAK,MAAM,OAAO,4CAA4C;GAAE,QAAQ;IAAE,IAAI;IAAS;GAAQ;GAAG,MAAM;EAAK,CAAC,GACzH,EAAK;GAAE,MAAM;GAAkB;GAAS;EAAQ,CAAC;CACnD;CAEA,KAAK,GAAiB,GAAiB,GAAkC;EACvE,OAAO,EAAK,KAAK,MAAM,QAAQ,0CAA0C;GAAE,QAAQ;IAAE,IAAI;IAAS;GAAQ;GAAG;EAAK,CAAC;CACrH;CAOA,MAAM,SAAS,GAAiB,GAAiB,GAAuD;EACtG,IAAM,IAAM,EAAS,KAAK,MAAM,OAAO,8CAA8C,EAAE,QAAQ;GAAE,IAAI;GAAS;EAAQ,EAAE,CAAC,GACnH,IAAM,MAAM,KAAK,KAAK,QAAgC,GAAK,EAAE,UAAO,CAAC;EAC3E,IAAI,EAAU,CAAG,GAAG,OAAO;EAE3B,IAAM,IAAO,IAAI,IAAI,GAAK,WAAW,UAAU,QAAQ,mBAAmB;EAC1E,OAAO;GAAE,GAAG;GAAK,KAAK,IAAI,IAAI,EAAI,KAAK,CAAI,CAAC,CAAC,SAAS;EAAE;CAC1D;AACF"}
1
+ {"version":3,"file":"versions.js","names":[],"sources":["../../src/client/versions.ts"],"sourcesContent":["import type { FileDownload, ForkBody, PageNotices, Pending, ReaderMeta, ReaderPlan } from \"./generated/wire.js\";\nimport type { Http } from \"./http.js\";\nimport { call, routeURL } from \"./route.js\";\n\n/** A version's answer while it is prepared (202). */\nexport const isPending = (x: unknown): x is Pending => !!x && typeof x === \"object\" && \"status\" in x && !(\"pages\" in x) && !(\"url\" in x);\n\n/** Content versions: page notices, reader plans, reader metadata, forks and downloads. */\nexport class VersionsClient {\n constructor(private readonly http: Http) {}\n\n /** Editors: undismissed notes about automatic page changes (removed or reordered pages). */\n pageNotices(content: string, version: string, signal?: AbortSignal): Promise<PageNotices> {\n return call(this.http, \"GET\", \"/contents/{id}/versions/{version}/page-notices\", { params: { id: content, version }, signal });\n }\n /** Editors: hides a page notice. */\n dismissPageNotice(content: string, version: string, notice: string): Promise<void> {\n return call(this.http, \"POST\", \"/contents/{id}/versions/{version}/page-notices/{notice}/dismiss\", { params: { id: content, version, notice } });\n }\n /** Editors: puts a removed-pages notice's pages back where they were. */\n async restorePageNotice(content: string, version: string, notice: string): Promise<PageNotices> {\n const emit = this.http.captureChanges();\n const next: PageNotices = await call(this.http, \"POST\", \"/contents/{id}/versions/{version}/page-notices/{notice}/restore\", { params: { id: content, version, notice } });\n emit({ type: \"content.changed\", id: content });\n emit({ type: \"reader.changed\", content, version });\n return next;\n }\n /** The version's reader plan for this viewer; Pending while it has no current publication. */\n reader(content: string, version: string, signal?: AbortSignal): Promise<ReaderPlan | Pending> {\n return call(this.http, \"GET\", \"/contents/{id}/versions/{version}/reader\", { params: { id: content, version }, signal });\n }\n /** Editors: replaces the version's reader metadata (anchors, audio cues, defaults). */\n async setReader(content: string, version: string, meta: ReaderMeta): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"PUT\", \"/contents/{id}/versions/{version}/reader\", { params: { id: content, version }, body: meta });\n emit({ type: \"reader.changed\", content, version });\n }\n /** Editors: fills a version without media from a sibling, in a durable job. */\n fork(content: string, version: string, body: ForkBody): Promise<Pending> {\n return call(this.http, \"POST\", \"/contents/{id}/versions/{version}/fork\", { params: { id: content, version }, body });\n }\n /**\n * Grants the version's download, what its kind serves (the original, a\n * rendition, its pages as a zip), charged to the viewer's download quota:\n * `url` (absolute) serves it as an attachment until `expires_at`. Pending\n * while it is prepared (ask again).\n */\n async download(content: string, version: string, signal?: AbortSignal): Promise<FileDownload | Pending> {\n const url = routeURL(this.http, \"GET\", \"/contents/{id}/versions/{version}/download\", { params: { id: content, version } });\n const out = await this.http.request<FileDownload | Pending>(url, { signal });\n if (isPending(out)) return out;\n // A marked zip's URL is the archive route's, relative to this one.\n const base = new URL(url, globalThis.location?.href ?? \"http://localhost/\");\n return { ...out, url: new URL(out.url, base).toString() };\n }\n}\n"],"mappings":";;AAKA,IAAa,KAAa,MAA6B,CAAC,CAAC,KAAK,OAAO,KAAM,YAAY,YAAY,KAAK,EAAE,WAAW,MAAM,EAAE,SAAS,IAGzH,IAAb,MAA4B;CACG;CAA7B,YAAY,GAA6B;EAAZ,KAAA,OAAA;CAAa;CAG1C,YAAY,GAAiB,GAAiB,GAA4C;EACxF,OAAO,EAAK,KAAK,MAAM,OAAO,kDAAkD;GAAE,QAAQ;IAAE,IAAI;IAAS;GAAQ;GAAG;EAAO,CAAC;CAC9H;CAEA,kBAAkB,GAAiB,GAAiB,GAA+B;EACjF,OAAO,EAAK,KAAK,MAAM,QAAQ,mEAAmE,EAAE,QAAQ;GAAE,IAAI;GAAS;GAAS;EAAO,EAAE,CAAC;CAChJ;CAEA,MAAM,kBAAkB,GAAiB,GAAiB,GAAsC;EAC9F,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAoB,MAAM,EAAK,KAAK,MAAM,QAAQ,mEAAmE,EAAE,QAAQ;GAAE,IAAI;GAAS;GAAS;EAAO,EAAE,CAAC;EAGvK,OAFA,EAAK;GAAE,MAAM;GAAmB,IAAI;EAAQ,CAAC,GAC7C,EAAK;GAAE,MAAM;GAAkB;GAAS;EAAQ,CAAC,GAC1C;CACT;CAEA,OAAO,GAAiB,GAAiB,GAAqD;EAC5F,OAAO,EAAK,KAAK,MAAM,OAAO,4CAA4C;GAAE,QAAQ;IAAE,IAAI;IAAS;GAAQ;GAAG;EAAO,CAAC;CACxH;CAEA,MAAM,UAAU,GAAiB,GAAiB,GAAiC;EACjF,IAAM,IAAO,KAAK,KAAK,eAAe;EAEtC,AADA,MAAM,EAAK,KAAK,MAAM,OAAO,4CAA4C;GAAE,QAAQ;IAAE,IAAI;IAAS;GAAQ;GAAG,MAAM;EAAK,CAAC,GACzH,EAAK;GAAE,MAAM;GAAkB;GAAS;EAAQ,CAAC;CACnD;CAEA,KAAK,GAAiB,GAAiB,GAAkC;EACvE,OAAO,EAAK,KAAK,MAAM,QAAQ,0CAA0C;GAAE,QAAQ;IAAE,IAAI;IAAS;GAAQ;GAAG;EAAK,CAAC;CACrH;CAOA,MAAM,SAAS,GAAiB,GAAiB,GAAuD;EACtG,IAAM,IAAM,EAAS,KAAK,MAAM,OAAO,8CAA8C,EAAE,QAAQ;GAAE,IAAI;GAAS;EAAQ,EAAE,CAAC,GACnH,IAAM,MAAM,KAAK,KAAK,QAAgC,GAAK,EAAE,UAAO,CAAC;EAC3E,IAAI,EAAU,CAAG,GAAG,OAAO;EAE3B,IAAM,IAAO,IAAI,IAAI,GAAK,WAAW,UAAU,QAAQ,mBAAmB;EAC1E,OAAO;GAAE,GAAG;GAAK,KAAK,IAAI,IAAI,EAAI,KAAK,CAAI,CAAC,CAAC,SAAS;EAAE;CAC1D;AACF"}
package/dist/client.js CHANGED
@@ -20,25 +20,27 @@ import { READ_CHUNK as ue, chunkOffsets as de, isProcessing as fe, mergeReads as
20
20
  import { ABR_DEFAULTS as he, NETWORK_FAILURES_BEFORE_ERROR as ge, REFRESH_BEFORE_EXPIRY as _e, abrHlsConfig as ve, capRung as ye, classifyHlsError as be, classifyMediaError as xe, expiryDelay as Se, hlsConfig as Ce, initialEstimate as we, refreshable as Te, startRung as Ee, statusKind as De } from "./client/playback.js";
21
21
  import { formatDuration as Oe, galleryItems as ke, isAudioType as Ae, isImageType as je, isSubtitleType as Me, isVideoType as Ne, stageAspect as Pe } from "./client/gallery.js";
22
22
  import { PLAYBACK_SPEEDS as Fe, PLAYER_TRACKS_KEY as Ie, PLAYER_VOLUME_KEY as Le, parseSpriteVtt as Re, playerKeyAction as ze, resumeAt as Be } from "./client/player.js";
23
- import { CatalogClient as Ve } from "./client/catalog.js";
24
- import { CodesClient as He } from "./client/codes.js";
25
- import { ContentsClient as Ue, IMAGE_SCHEME as We, imageRef as Ge, imageRefs as Ke } from "./client/contents.js";
26
- import { BansClient as qe } from "./client/content/bans.js";
27
- import { CommentsClient as Je } from "./client/content/comments.js";
28
- import { DiscoveryClient as Ye, popularBetween as Xe, popularQuery as Ze } from "./client/discovery.js";
29
- import { FavoritesClient as Qe } from "./client/content/favorites.js";
30
- import { ModerationClient as $e } from "./client/content/moderation.js";
31
- import { PollsClient as et } from "./client/content/polls.js";
32
- import { ReactionsClient as tt } from "./client/content/reactions.js";
33
- import { EntitiesClient as nt } from "./client/entities.js";
34
- import { OffersClient as rt } from "./client/offers.js";
35
- import { StatsClient as it } from "./client/stats.js";
36
- import { VersionsClient as at, isPending as ot } from "./client/versions.js";
37
- import { BrowserReaderPreferences as st } from "./client/browser-reader-preferences.js";
38
- import { NotificationsClient as ct } from "./client/notifications.js";
39
- import { ReaderPreferencesClient as lt } from "./client/reader-preferences.js";
40
- import { createContentKitClient as ut } from "./client/client.js";
41
- import { LETTERS as dt, attributeInput as ft, fold as pt, fromLocalInput as mt, humanize as ht, letterOf as gt, parseAttribute as _t, parseAttributes as vt, slugify as yt, toLocalInput as bt } from "./client/group-fields.js";
42
- import { Beacons as xt, eventId as St, readerSession as Ct } from "./client/beacons.js";
43
- import { emptyReaderMeta as wt, matchAudio as Tt, readerMetaProblems as Et, readerNames as Dt } from "./client/reader-meta.js";
44
- export { he as ABR_DEFAULTS, qe as BansClient, xt as Beacons, st as BrowserReaderPreferences, i as CLIENT_ERROR_CODES, Ve as CatalogClient, He as CodesClient, Je as CommentsClient, a as ContentKitError, Ue as ContentsClient, e as DEFAULT_DENSITY, Ye as DiscoveryClient, o as ERROR_CODES, nt as EntitiesClient, Qe as FavoritesClient, We as IMAGE_SCHEME, ae as ItemUploadQueue, dt as LETTERS, T as MAX_PART_SIZE, E as MAX_SINGLE_PUT, D as MIN_PART_SIZE, w as MediaApi, N as MediaClient, $e as ModerationClient, ge as NETWORK_FAILURES_BEFORE_ERROR, ct as NotificationsClient, rt as OffersClient, Fe as PLAYBACK_SPEEDS, Ie as PLAYER_TRACKS_KEY, Le as PLAYER_VOLUME_KEY, k as Pacer, et as PollsClient, ue as READ_CHUNK, _e as REFRESH_BEFORE_EXPIRY, tt as ReactionsClient, lt as ReaderPreferencesClient, it as StatsClient, at as VersionsClient, ve as abrHlsConfig, L as acceptOf, g as aspectOf, ft as attributeInput, P as backoff, v as call, ye as capRung, Y as centeredCrop, b as checkRef, de as chunkOffsets, be as classifyHlsError, xe as classifyMediaError, X as constrainCrop, ut as createContentKitClient, oe as decodeImage, R as defaultImage, A as defaultTransport, t as densityFor, Z as editOf, Q as editedSize, wt as emptyReaderMeta, ie as encodeRemaining, St as eventId, Se as expiryDelay, s as failureError, j as fetchTransport, z as filesFor, f as fill, pt as fold, Oe as formatDuration, mt as fromLocalInput, $ as fromRotated, ke as galleryItems, Ce as hlsConfig, ht as humanize, Ge as imageRef, Ke as imageRefs, we as initialEstimate, se as isAnimatedImage, Ae as isAudioType, x as isContentId, c as isContentKitError, je as isImageType, B as isPattern, ot as isPending, fe as isProcessing, Me as isSubtitleType, Ne as isVideoType, S as itemKey, gt as letterOf, Tt as matchAudio, pe as mergeReads, _t as parseAttribute, vt as parseAttributes, Re as parseSpriteVtt, n as pickRendition, ze as playerKeyAction, Xe as popularBetween, Ze as popularQuery, me as processing, p as publicRenditions, m as publicURL, _ as ratio, V as ratioLabel, ce as reactionVerb, l as readContentKitError, Et as readerMetaProblems, Dt as readerNames, Ct as readerSession, Te as refreshable, Be as resumeAt, ee as rotation, y as routeURL, H as ruleDir, U as ruleFor, te as sameEdit, C as sameItem, F as samePath, le as sameTarget, W as screenFiles, O as sha256Hex, yt as slugify, r as sortRenditions, h as srcSet, G as stableImage, Pe as stageAspect, Ee as startRung, De as statusKind, I as stem, u as toContentKitError, bt as toLocalInput, ne as toOriginal, re as toRotated, d as transportFailure, K as uniqueName, q as uploadRules, J as withMediaType, M as xhrTransport };
23
+ import { GuestReadingHistory as Ve, guestStanding as He } from "./client/guest-reading-history.js";
24
+ import { CatalogClient as Ue } from "./client/catalog.js";
25
+ import { CodesClient as We } from "./client/codes.js";
26
+ import { ContentsClient as Ge, IMAGE_SCHEME as Ke, imageRef as qe, imageRefs as Je } from "./client/contents.js";
27
+ import { BansClient as Ye } from "./client/content/bans.js";
28
+ import { CommentsClient as Xe } from "./client/content/comments.js";
29
+ import { DiscoveryClient as Ze, popularBetween as Qe, popularQuery as $e } from "./client/discovery.js";
30
+ import { FavoritesClient as et } from "./client/content/favorites.js";
31
+ import { ModerationClient as tt } from "./client/content/moderation.js";
32
+ import { PollsClient as nt } from "./client/content/polls.js";
33
+ import { ReactionsClient as rt } from "./client/content/reactions.js";
34
+ import { EntitiesClient as it } from "./client/entities.js";
35
+ import { OffersClient as at } from "./client/offers.js";
36
+ import { StatsClient as ot } from "./client/stats.js";
37
+ import { VersionsClient as st, isPending as ct } from "./client/versions.js";
38
+ import { BrowserReaderPreferences as lt } from "./client/browser-reader-preferences.js";
39
+ import { NotificationsClient as ut } from "./client/notifications.js";
40
+ import { ReaderPreferencesClient as dt } from "./client/reader-preferences.js";
41
+ import { createContentKitClient as ft } from "./client/client.js";
42
+ import { LETTERS as pt, attributeInput as mt, fold as ht, fromLocalInput as gt, humanize as _t, letterOf as vt, parseAttribute as yt, parseAttributes as bt, slugify as xt, toLocalInput as St } from "./client/group-fields.js";
43
+ import { Beacons as Ct, eventId as wt, readerSession as Tt } from "./client/beacons.js";
44
+ import { emptyReaderMeta as Et, matchAudio as Dt, readerMetaProblems as Ot, readerNames as kt } from "./client/reader-meta.js";
45
+ import { EngagementTracker as At } from "./client/engagement.js";
46
+ export { he as ABR_DEFAULTS, Ye as BansClient, Ct as Beacons, lt as BrowserReaderPreferences, i as CLIENT_ERROR_CODES, Ue as CatalogClient, We as CodesClient, Xe as CommentsClient, a as ContentKitError, Ge as ContentsClient, e as DEFAULT_DENSITY, Ze as DiscoveryClient, o as ERROR_CODES, At as EngagementTracker, it as EntitiesClient, et as FavoritesClient, Ve as GuestReadingHistory, Ke as IMAGE_SCHEME, ae as ItemUploadQueue, pt as LETTERS, T as MAX_PART_SIZE, E as MAX_SINGLE_PUT, D as MIN_PART_SIZE, w as MediaApi, N as MediaClient, tt as ModerationClient, ge as NETWORK_FAILURES_BEFORE_ERROR, ut as NotificationsClient, at as OffersClient, Fe as PLAYBACK_SPEEDS, Ie as PLAYER_TRACKS_KEY, Le as PLAYER_VOLUME_KEY, k as Pacer, nt as PollsClient, ue as READ_CHUNK, _e as REFRESH_BEFORE_EXPIRY, rt as ReactionsClient, dt as ReaderPreferencesClient, ot as StatsClient, st as VersionsClient, ve as abrHlsConfig, L as acceptOf, g as aspectOf, mt as attributeInput, P as backoff, v as call, ye as capRung, Y as centeredCrop, b as checkRef, de as chunkOffsets, be as classifyHlsError, xe as classifyMediaError, X as constrainCrop, ft as createContentKitClient, oe as decodeImage, R as defaultImage, A as defaultTransport, t as densityFor, Z as editOf, Q as editedSize, Et as emptyReaderMeta, ie as encodeRemaining, wt as eventId, Se as expiryDelay, s as failureError, j as fetchTransport, z as filesFor, f as fill, ht as fold, Oe as formatDuration, gt as fromLocalInput, $ as fromRotated, ke as galleryItems, He as guestStanding, Ce as hlsConfig, _t as humanize, qe as imageRef, Je as imageRefs, we as initialEstimate, se as isAnimatedImage, Ae as isAudioType, x as isContentId, c as isContentKitError, je as isImageType, B as isPattern, ct as isPending, fe as isProcessing, Me as isSubtitleType, Ne as isVideoType, S as itemKey, vt as letterOf, Dt as matchAudio, pe as mergeReads, yt as parseAttribute, bt as parseAttributes, Re as parseSpriteVtt, n as pickRendition, ze as playerKeyAction, Qe as popularBetween, $e as popularQuery, me as processing, p as publicRenditions, m as publicURL, _ as ratio, V as ratioLabel, ce as reactionVerb, l as readContentKitError, Ot as readerMetaProblems, kt as readerNames, Tt as readerSession, Te as refreshable, Be as resumeAt, ee as rotation, y as routeURL, H as ruleDir, U as ruleFor, te as sameEdit, C as sameItem, F as samePath, le as sameTarget, W as screenFiles, O as sha256Hex, xt as slugify, r as sortRenditions, h as srcSet, G as stableImage, Pe as stageAspect, Ee as startRung, De as statusKind, I as stem, u as toContentKitError, St as toLocalInput, ne as toOriginal, re as toRotated, d as transportFailure, K as uniqueName, q as uploadRules, J as withMediaType, M as xhrTransport };
@@ -0,0 +1,17 @@
1
+ import { ContentKitClient } from '../../client/client.js';
2
+ import { Content, RefBody } from '../../client/generated/wire.js';
3
+ /** A file name as a title: no extension, separators as spaces. */
4
+ export declare const fileTitle: (name: string) => string;
5
+ /** A draft of kind titled from file, and the ref of its first version (uploads land there). */
6
+ export declare function createDraft(client: ContentKitClient, kind: string, language: string, file: File, untitled: string): Promise<{
7
+ content: Content;
8
+ ref: RefBody;
9
+ }>;
10
+ /**
11
+ * Where file uploads in ref, by the item's own upload rules: a page archive to
12
+ * its import path (expanded into pages server-side), a video to its source.
13
+ */
14
+ export declare function uploadTarget(client: ContentKitClient, ref: RefBody, file: File, signal?: AbortSignal): Promise<{
15
+ path: string;
16
+ type: string;
17
+ }>;
@@ -0,0 +1,41 @@
1
+ import { ContentKitError as e } from "../../client/errors.js";
2
+ import { isPattern as t, ruleDir as n, screenFiles as r } from "../../client/media/rules.js";
3
+ //#region src/components/admin/bulk-drafts.ts
4
+ var i = (e) => e.replace(/\.[^.]+$/, "").replace(/[_-]+/g, " ").trim().slice(0, 300);
5
+ async function a(t, n, r, a, o) {
6
+ let s = await t.contents.create({
7
+ kind: n,
8
+ text: { [r]: { title: i(a.name) || o } }
9
+ }), c = [...s.versions ?? []].sort((e, t) => e.position - t.position)[0];
10
+ if (!c) throw new e("invalid_request", `kind ${n} made a draft without a version`);
11
+ return {
12
+ content: s,
13
+ ref: {
14
+ kind: n,
15
+ id: s.id,
16
+ version: c.id
17
+ }
18
+ };
19
+ }
20
+ async function o(i, a, o, s) {
21
+ let { uploads: c } = await i.media.read(a, {
22
+ editor: !0,
23
+ limit: 1,
24
+ signal: s
25
+ });
26
+ if (!c) throw new e("forbidden", `only editors of ${a.kind} ${a.id} upload to it`);
27
+ let l = c.filter((e) => t(e.path) && !e.named), u = c.filter((e) => !t(e.path)), { accepted: d, refused: f } = r([o], [
28
+ ...l.filter((e) => e.page),
29
+ ...l.filter((e) => !e.page),
30
+ ...u
31
+ ]), p = d[0];
32
+ if (!p) throw f[0]?.error ?? new e("type_not_allowed", `${o.name}: type not allowed`);
33
+ return {
34
+ path: t(p.rule.path) ? n(p.rule.path) + o.name : p.rule.path,
35
+ type: p.file.type
36
+ };
37
+ }
38
+ //#endregion
39
+ export { a as createDraft, i as fileTitle, o as uploadTarget };
40
+
41
+ //# sourceMappingURL=bulk-drafts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bulk-drafts.js","names":[],"sources":["../../../src/components/admin/bulk-drafts.ts"],"sourcesContent":["import type { ContentKitClient } from \"../../client/client.js\";\nimport { ContentKitError } from \"../../client/errors.js\";\nimport type { Content, RefBody } from \"../../client/generated/wire.js\";\nimport { isPattern, ruleDir, screenFiles } from \"../../client/media/rules.js\";\n\n/** A file name as a title: no extension, separators as spaces. */\nexport const fileTitle = (name: string) =>\n name\n .replace(/\\.[^.]+$/, \"\")\n .replace(/[_-]+/g, \" \")\n .trim()\n .slice(0, 300);\n\n/** A draft of kind titled from file, and the ref of its first version (uploads land there). */\nexport async function createDraft(client: ContentKitClient, kind: string, language: string, file: File, untitled: string): Promise<{ content: Content; ref: RefBody }> {\n const content = await client.contents.create({ kind, text: { [language]: { title: fileTitle(file.name) || untitled } } });\n const version = [...(content.versions ?? [])].sort((a, b) => a.position - b.position)[0];\n if (!version) throw new ContentKitError(\"invalid_request\", `kind ${kind} made a draft without a version`);\n return { content, ref: { kind, id: content.id, version: version.id } };\n}\n\n/**\n * Where file uploads in ref, by the item's own upload rules: a page archive to\n * its import path (expanded into pages server-side), a video to its source.\n */\nexport async function uploadTarget(client: ContentKitClient, ref: RefBody, file: File, signal?: AbortSignal): Promise<{ path: string; type: string }> {\n const { uploads } = await client.media.read(ref, { editor: true, limit: 1, signal });\n if (!uploads) throw new ContentKitError(\"forbidden\", `only editors of ${ref.kind} ${ref.id} upload to it`);\n // Pages first (not covers), then other {name} paths, then literal ones such as a video's source.\n const paths = uploads.filter((r) => isPattern(r.path) && !r.named);\n const literal = uploads.filter((r) => !isPattern(r.path));\n const { accepted, refused } = screenFiles([file], [...paths.filter((r) => r.page), ...paths.filter((r) => !r.page), ...literal]);\n const pick = accepted[0];\n if (!pick) throw refused[0]?.error ?? new ContentKitError(\"type_not_allowed\", `${file.name}: type not allowed`);\n return { path: isPattern(pick.rule.path) ? ruleDir(pick.rule.path) + file.name : pick.rule.path, type: pick.file.type };\n}\n"],"mappings":";;;AAMA,IAAa,KAAa,MACxB,EACG,QAAQ,YAAY,EAAE,CAAC,CACvB,QAAQ,UAAU,GAAG,CAAC,CACtB,KAAK,CAAC,CACN,MAAM,GAAG,GAAG;AAGjB,eAAsB,EAAY,GAA0B,GAAc,GAAkB,GAAY,GAA+D;CACrK,IAAM,IAAU,MAAM,EAAO,SAAS,OAAO;EAAE;EAAM,MAAM,GAAG,IAAW,EAAE,OAAO,EAAU,EAAK,IAAI,KAAK,EAAS,EAAE;CAAE,CAAC,GAClH,IAAU,CAAC,GAAI,EAAQ,YAAY,CAAC,CAAE,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;CACtF,IAAI,CAAC,GAAS,MAAM,IAAI,EAAgB,mBAAmB,QAAQ,EAAK,gCAAgC;CACxG,OAAO;EAAE;EAAS,KAAK;GAAE;GAAM,IAAI,EAAQ;GAAI,SAAS,EAAQ;EAAG;CAAE;AACvE;AAMA,eAAsB,EAAa,GAA0B,GAAc,GAAY,GAA+D;CACpJ,IAAM,EAAE,eAAY,MAAM,EAAO,MAAM,KAAK,GAAK;EAAE,QAAQ;EAAM,OAAO;EAAG;CAAO,CAAC;CACnF,IAAI,CAAC,GAAS,MAAM,IAAI,EAAgB,aAAa,mBAAmB,EAAI,KAAK,GAAG,EAAI,GAAG,cAAc;CAEzG,IAAM,IAAQ,EAAQ,QAAQ,MAAM,EAAU,EAAE,IAAI,KAAK,CAAC,EAAE,KAAK,GAC3D,IAAU,EAAQ,QAAQ,MAAM,CAAC,EAAU,EAAE,IAAI,CAAC,GAClD,EAAE,aAAU,eAAY,EAAY,CAAC,CAAI,GAAG;EAAC,GAAG,EAAM,QAAQ,MAAM,EAAE,IAAI;EAAG,GAAG,EAAM,QAAQ,MAAM,CAAC,EAAE,IAAI;EAAG,GAAG;CAAO,CAAC,GACzH,IAAO,EAAS;CACtB,IAAI,CAAC,GAAM,MAAM,EAAQ,EAAE,EAAE,SAAS,IAAI,EAAgB,oBAAoB,GAAG,EAAK,KAAK,mBAAmB;CAC9G,OAAO;EAAE,MAAM,EAAU,EAAK,KAAK,IAAI,IAAI,EAAQ,EAAK,KAAK,IAAI,IAAI,EAAK,OAAO,EAAK,KAAK;EAAM,MAAM,EAAK,KAAK;CAAK;AACxH"}
@@ -15,7 +15,7 @@ export interface ContentAdminProps extends AdminFlowProps, AdminRouteProps {
15
15
  groupKinds?: readonly string[];
16
16
  labels?: Labels;
17
17
  content?: Pick<ContentManagerProps, "renderEditor" | "contentHref">;
18
- groups?: Pick<GroupManagerProps, "renderContent">;
18
+ groups?: Pick<GroupManagerProps, "renderContent" | "contentHref">;
19
19
  moderation?: Pick<CommentModerationProps, "itemHref" | "userHref" | "sections">;
20
20
  polls?: Pick<PollManagerProps, "freeText" | "maxOptions">;
21
21
  }